summaryrefslogtreecommitdiff
path: root/cleopatre/linux-2.6.25.10-spc300/arch/s390
diff options
context:
space:
mode:
authorlefranc2009-03-19 08:34:57 +0000
committerlefranc2009-03-19 08:34:57 +0000
commitade8df59a0d7d3ac394b61f3096b5963d18dcfcc (patch)
tree486cec51f00d138ab08352a6f5611f4a0323b1ca /cleopatre/linux-2.6.25.10-spc300/arch/s390
parenta49226f2d9f26b70584f3bea9388e2d753663c91 (diff)
[kernel] changed linux-2.6.25.10 to linux-2.6.25.10-spc300
[bundle] add bundle creation functionnality git-svn-id: svn+ssh://pessac/svn/cesar/trunk@4255 017c9cb6-072f-447c-8318-d5b54f68fe89
Diffstat (limited to 'cleopatre/linux-2.6.25.10-spc300/arch/s390')
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/Kconfig551
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/Kconfig.debug17
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/Makefile117
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/Makefile8
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata.h61
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_base.c582
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_mem.c197
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_net_sum.c192
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_os.c276
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/boot/Makefile18
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/boot/install.sh38
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/Makefile9
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/aes_s390.c558
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/crypt_s390.h323
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/crypto_des.h18
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/des_check_key.c132
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/des_s390.c635
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/prng.c213
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/sha1_s390.c159
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/sha256_s390.c155
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/defconfig847
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/Makefile7
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs.h39
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs_diag.c703
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs_vm.c231
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/inode.c542
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/Makefile38
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/asm-offsets.c48
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/audit.c78
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/audit.h15
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/base.S150
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/binfmt_elf32.c214
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/bitmap.S56
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_audit.c44
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_exec_domain.c29
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_linux.c978
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_linux.h165
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_ptrace.h83
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_signal.c586
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_wrapper.S1734
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/cpcmd.c123
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/crash.c16
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/debug.c1539
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/diag.c102
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/dis.c1280
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/early.c297
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ebcdic.c401
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/entry.S1104
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/entry64.S1045
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head.S468
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head31.S188
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head64.S261
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/init_task.c45
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ipl.c1488
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/irq.c105
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/kprobes.c672
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/machine_kexec.c71
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/module.c408
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/process.c429
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ptrace.c754
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/reipl.S86
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/reipl64.S113
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/relocate_kernel.S117
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/relocate_kernel64.S120
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/s390_ext.c140
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/s390_ksyms.c52
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/semaphore.c108
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/setup.c928
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/signal.c522
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/smp.c1103
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/stacktrace.c95
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/sys_s390.c288
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/syscalls.S332
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/time.c1403
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/traps.c744
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/vmlinux.lds.S166
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/vtime.c569
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/Makefile10
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/delay.c74
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/div64.c149
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/qrnnd.S77
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/spinlock.c172
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/string.c381
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess.h23
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_mvcos.c229
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_pt.c441
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_std.c317
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/math-emu/Makefile8
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/math-emu/math.c2255
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/Makefile7
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/cmm.c479
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/extmem.c589
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/fault.c618
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/init.c226
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/mmap.c151
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/pgtable.c230
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/vmem.c412
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/Makefile9
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/backtrace.c79
-rw-r--r--cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/init.c26
100 files changed, 35490 insertions, 0 deletions
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/Kconfig b/cleopatre/linux-2.6.25.10-spc300/arch/s390/Kconfig
new file mode 100644
index 0000000000..1831833c43
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/Kconfig
@@ -0,0 +1,551 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+config MMU
+ def_bool y
+
+config ZONE_DMA
+ def_bool y
+ depends on 64BIT
+
+config LOCKDEP_SUPPORT
+ def_bool y
+
+config STACKTRACE_SUPPORT
+ def_bool y
+
+config HAVE_LATENCYTOP_SUPPORT
+ def_bool y
+
+config RWSEM_GENERIC_SPINLOCK
+ bool
+
+config RWSEM_XCHGADD_ALGORITHM
+ def_bool y
+
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
+config GENERIC_HWEIGHT
+ def_bool y
+
+config GENERIC_TIME
+ def_bool y
+
+config GENERIC_BUG
+ bool
+ depends on BUG
+ default y
+
+config NO_IOMEM
+ def_bool y
+
+config NO_DMA
+ def_bool y
+
+config GENERIC_LOCKBREAK
+ bool
+ default y
+ depends on SMP && PREEMPT
+
+mainmenu "Linux Kernel Configuration"
+
+config S390
+ def_bool y
+ select HAVE_OPROFILE
+ select HAVE_KPROBES
+ select HAVE_KRETPROBES
+
+source "init/Kconfig"
+
+menu "Base setup"
+
+comment "Processor type and features"
+
+config 64BIT
+ bool "64 bit kernel"
+ help
+ Select this option if you have a 64 bit IBM zSeries machine
+ and want to use the 64 bit addressing mode.
+
+config 32BIT
+ bool
+ default y if !64BIT
+
+config SMP
+ bool "Symmetric multi-processing support"
+ ---help---
+ This enables support for systems with more than one CPU. If you have
+ a system with only one CPU, like most personal computers, say N. If
+ you have a system with more than one CPU, say Y.
+
+ If you say N here, the kernel will run on single and multiprocessor
+ machines, but will use only one CPU of a multiprocessor machine. If
+ you say Y here, the kernel will run on many, but not all,
+ singleprocessor machines. On a singleprocessor machine, the kernel
+ will run faster if you say N here.
+
+ See also the SMP-HOWTO available at
+ <http://www.tldp.org/docs.html#howto>.
+
+ Even if you don't know what to do here, say Y.
+
+config NR_CPUS
+ int "Maximum number of CPUs (2-64)"
+ range 2 64
+ depends on SMP
+ default "32" if !64BIT
+ default "64" if 64BIT
+ help
+ This allows you to specify the maximum number of CPUs which this
+ kernel will support. The maximum supported value is 64 and the
+ minimum value which makes sense is 2.
+
+ This is purely to save memory - each supported CPU adds
+ approximately sixteen kilobytes to the kernel image.
+
+config HOTPLUG_CPU
+ bool "Support for hot-pluggable CPUs"
+ depends on SMP
+ select HOTPLUG
+ default n
+ help
+ Say Y here to be able to turn CPUs off and on. CPUs
+ can be controlled through /sys/devices/system/cpu/cpu#.
+ Say N if you want to disable CPU hotplug.
+
+config MATHEMU
+ bool "IEEE FPU emulation"
+ depends on MARCH_G5
+ help
+ This option is required for IEEE compliant floating point arithmetic
+ on older S/390 machines. Say Y unless you know your machine doesn't
+ need this.
+
+config COMPAT
+ bool "Kernel support for 31 bit emulation"
+ depends on 64BIT
+ help
+ Select this option if you want to enable your system kernel to
+ handle system-calls from ELF binaries for 31 bit ESA. This option
+ (and some other stuff like libraries and such) is needed for
+ executing 31 bit applications. It is safe to say "Y".
+
+config SYSVIPC_COMPAT
+ bool
+ depends on COMPAT && SYSVIPC
+ default y
+
+config AUDIT_ARCH
+ bool
+ default y
+
+config S390_SWITCH_AMODE
+ bool "Switch kernel/user addressing modes"
+ help
+ This option allows to switch the addressing modes of kernel and user
+ space. The kernel parameter switch_amode=on will enable this feature,
+ default is disabled. Enabling this (via kernel parameter) on machines
+ earlier than IBM System z9-109 EC/BC will reduce system performance.
+
+ Note that this option will also be selected by selecting the execute
+ protection option below. Enabling the execute protection via the
+ noexec kernel parameter will also switch the addressing modes,
+ independent of the switch_amode kernel parameter.
+
+
+config S390_EXEC_PROTECT
+ bool "Data execute protection"
+ select S390_SWITCH_AMODE
+ help
+ This option allows to enable a buffer overflow protection for user
+ space programs and it also selects the addressing mode option above.
+ The kernel parameter noexec=on will enable this feature and also
+ switch the addressing modes, default is disabled. Enabling this (via
+ kernel parameter) on machines earlier than IBM System z9-109 EC/BC
+ will reduce system performance.
+
+comment "Code generation options"
+
+choice
+ prompt "Processor type"
+ default MARCH_G5
+
+config MARCH_G5
+ bool "S/390 model G5 and G6"
+ depends on !64BIT
+ help
+ Select this to build a 31 bit kernel that works
+ on all S/390 and zSeries machines.
+
+config MARCH_Z900
+ bool "IBM eServer zSeries model z800 and z900"
+ help
+ Select this to optimize for zSeries machines. This
+ will enable some optimizations that are not available
+ on older 31 bit only CPUs.
+
+config MARCH_Z990
+ bool "IBM eServer zSeries model z890 and z990"
+ help
+ Select this enable optimizations for model z890/z990.
+ This will be slightly faster but does not work on
+ older machines such as the z900.
+
+config MARCH_Z9_109
+ bool "IBM System z9"
+ help
+ Select this to enable optimizations for IBM System z9-109, IBM
+ System z9 Enterprise Class (z9 EC), and IBM System z9 Business
+ Class (z9 BC). The kernel will be slightly faster but will not
+ work on older machines such as the z990, z890, z900, and z800.
+
+endchoice
+
+config PACK_STACK
+ bool "Pack kernel stack"
+ help
+ This option enables the compiler option -mkernel-backchain if it
+ is available. If the option is available the compiler supports
+ the new stack layout which dramatically reduces the minimum stack
+ frame size. With an old compiler a non-leaf function needs a
+ minimum of 96 bytes on 31 bit and 160 bytes on 64 bit. With
+ -mkernel-backchain the minimum size drops to 16 byte on 31 bit
+ and 24 byte on 64 bit.
+
+ Say Y if you are unsure.
+
+config SMALL_STACK
+ bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb"
+ depends on PACK_STACK && !LOCKDEP
+ help
+ If you say Y here and the compiler supports the -mkernel-backchain
+ option the kernel will use a smaller kernel stack size. For 31 bit
+ the reduced size is 4kb instead of 8kb and for 64 bit it is 8kb
+ instead of 16kb. This allows to run more thread on a system and
+ reduces the pressure on the memory management for higher order
+ page allocations.
+
+ Say N if you are unsure.
+
+
+config CHECK_STACK
+ bool "Detect kernel stack overflow"
+ help
+ This option enables the compiler option -mstack-guard and
+ -mstack-size if they are available. If the compiler supports them
+ it will emit additional code to each function prolog to trigger
+ an illegal operation if the kernel stack is about to overflow.
+
+ Say N if you are unsure.
+
+config STACK_GUARD
+ int "Size of the guard area (128-1024)"
+ range 128 1024
+ depends on CHECK_STACK
+ default "256"
+ help
+ This allows you to specify the size of the guard area at the lower
+ end of the kernel stack. If the kernel stack points into the guard
+ area on function entry an illegal operation is triggered. The size
+ needs to be a power of 2. Please keep in mind that the size of an
+ interrupt frame is 184 bytes for 31 bit and 328 bytes on 64 bit.
+ The minimum size for the stack guard should be 256 for 31 bit and
+ 512 for 64 bit.
+
+config WARN_STACK
+ bool "Emit compiler warnings for function with broken stack usage"
+ help
+ This option enables the compiler options -mwarn-framesize and
+ -mwarn-dynamicstack. If the compiler supports these options it
+ will generate warnings for function which either use alloca or
+ create a stack frame bigger then CONFIG_WARN_STACK_SIZE.
+
+ Say N if you are unsure.
+
+config WARN_STACK_SIZE
+ int "Maximum frame size considered safe (128-2048)"
+ range 128 2048
+ depends on WARN_STACK
+ default "256"
+ help
+ This allows you to specify the maximum frame size a function may
+ have without the compiler complaining about it.
+
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
+
+comment "Kernel preemption"
+
+source "kernel/Kconfig.preempt"
+
+source "mm/Kconfig"
+
+comment "I/O subsystem configuration"
+
+config MACHCHK_WARNING
+ bool "Process warning machine checks"
+ help
+ Select this option if you want the machine check handler on IBM S/390 or
+ zSeries to process warning machine checks (e.g. on power failures).
+ If unsure, say "Y".
+
+config QDIO
+ tristate "QDIO support"
+ ---help---
+ This driver provides the Queued Direct I/O base support for
+ IBM mainframes.
+
+ For details please refer to the documentation provided by IBM at
+ <http://www10.software.ibm.com/developerworks/opensource/linux390>
+
+ To compile this driver as a module, choose M here: the
+ module will be called qdio.
+
+ If unsure, say Y.
+
+config QDIO_DEBUG
+ bool "Extended debugging information"
+ depends on QDIO
+ help
+ Say Y here to get extended debugging output in
+ /sys/kernel/debug/s390dbf/qdio...
+ Warning: this option reduces the performance of the QDIO module.
+
+ If unsure, say N.
+
+comment "Misc"
+
+config IPL
+ bool "Builtin IPL record support"
+ help
+ If you want to use the produced kernel to IPL directly from a
+ device, you have to merge a bootsector specific to the device
+ into the first bytes of the kernel. You will have to select the
+ IPL device.
+
+choice
+ prompt "IPL method generated into head.S"
+ depends on IPL
+ default IPL_TAPE
+ help
+ Select "tape" if you want to IPL the image from a Tape.
+
+ Select "vm_reader" if you are running under VM/ESA and want
+ to IPL the image from the emulated card reader.
+
+config IPL_TAPE
+ bool "tape"
+
+config IPL_VM
+ bool "vm_reader"
+
+endchoice
+
+source "fs/Kconfig.binfmt"
+
+config FORCE_MAX_ZONEORDER
+ int
+ default "9"
+
+config PROCESS_DEBUG
+ bool "Show crashed user process info"
+ help
+ Say Y to print all process fault locations to the console. This is
+ a debugging option; you probably do not want to set it unless you
+ are an S390 port maintainer.
+
+config PFAULT
+ bool "Pseudo page fault support"
+ help
+ Select this option, if you want to use PFAULT pseudo page fault
+ handling under VM. If running native or in LPAR, this option
+ has no effect. If your VM does not support PFAULT, PAGEEX
+ pseudo page fault handling will be used.
+ Note that VM 4.2 supports PFAULT but has a bug in its
+ implementation that causes some problems.
+ Everybody who wants to run Linux under VM != VM4.2 should select
+ this option.
+
+config SHARED_KERNEL
+ bool "VM shared kernel support"
+ help
+ Select this option, if you want to share the text segment of the
+ Linux kernel between different VM guests. This reduces memory
+ usage with lots of guests but greatly increases kernel size.
+ Also if a kernel was IPL'ed from a shared segment the kexec system
+ call will not work.
+ You should only select this option if you know what you are
+ doing and want to exploit this feature.
+
+config CMM
+ tristate "Cooperative memory management"
+ help
+ Select this option, if you want to enable the kernel interface
+ to reduce the memory size of the system. This is accomplished
+ by allocating pages of memory and put them "on hold". This only
+ makes sense for a system running under VM where the unused pages
+ will be reused by VM for other guest systems. The interface
+ allows an external monitor to balance memory of many systems.
+ Everybody who wants to run Linux under VM should select this
+ option.
+
+config CMM_PROC
+ bool "/proc interface to cooperative memory management"
+ depends on CMM
+ help
+ Select this option to enable the /proc interface to the
+ cooperative memory management.
+
+config CMM_IUCV
+ bool "IUCV special message interface to cooperative memory management"
+ depends on CMM && (SMSGIUCV=y || CMM=SMSGIUCV)
+ help
+ Select this option to enable the special message interface to
+ the cooperative memory management.
+
+config VIRT_TIMER
+ bool "Virtual CPU timer support"
+ help
+ This provides a kernel interface for virtual CPU timers.
+ Default is disabled.
+
+config VIRT_CPU_ACCOUNTING
+ bool "Base user process accounting on virtual cpu timer"
+ depends on VIRT_TIMER
+ help
+ Select this option to use CPU timer deltas to do user
+ process accounting.
+
+config APPLDATA_BASE
+ bool "Linux - VM Monitor Stream, base infrastructure"
+ depends on PROC_FS && VIRT_TIMER=y
+ help
+ This provides a kernel interface for creating and updating z/VM APPLDATA
+ monitor records. The monitor records are updated at certain time
+ intervals, once the timer is started.
+ Writing 1 or 0 to /proc/appldata/timer starts(1) or stops(0) the timer,
+ i.e. enables or disables monitoring on the Linux side.
+ A custom interval value (in seconds) can be written to
+ /proc/appldata/interval.
+
+ Defaults are 60 seconds interval and timer off.
+ The /proc entries can also be read from, showing the current settings.
+
+config APPLDATA_MEM
+ tristate "Monitor memory management statistics"
+ depends on APPLDATA_BASE && VM_EVENT_COUNTERS
+ help
+ This provides memory management related data to the Linux - VM Monitor
+ Stream, like paging/swapping rate, memory utilisation, etc.
+ Writing 1 or 0 to /proc/appldata/memory creates(1) or removes(0) a z/VM
+ APPLDATA monitor record, i.e. enables or disables monitoring this record
+ on the z/VM side.
+
+ Default is disabled.
+ The /proc entry can also be read from, showing the current settings.
+
+ This can also be compiled as a module, which will be called
+ appldata_mem.o.
+
+config APPLDATA_OS
+ tristate "Monitor OS statistics"
+ depends on APPLDATA_BASE
+ help
+ This provides OS related data to the Linux - VM Monitor Stream, like
+ CPU utilisation, etc.
+ Writing 1 or 0 to /proc/appldata/os creates(1) or removes(0) a z/VM
+ APPLDATA monitor record, i.e. enables or disables monitoring this record
+ on the z/VM side.
+
+ Default is disabled.
+ This can also be compiled as a module, which will be called
+ appldata_os.o.
+
+config APPLDATA_NET_SUM
+ tristate "Monitor overall network statistics"
+ depends on APPLDATA_BASE
+ help
+ This provides network related data to the Linux - VM Monitor Stream,
+ currently there is only a total sum of network I/O statistics, no
+ per-interface data.
+ Writing 1 or 0 to /proc/appldata/net_sum creates(1) or removes(0) a z/VM
+ APPLDATA monitor record, i.e. enables or disables monitoring this record
+ on the z/VM side.
+
+ Default is disabled.
+ This can also be compiled as a module, which will be called
+ appldata_net_sum.o.
+
+source kernel/Kconfig.hz
+
+config NO_IDLE_HZ
+ bool "No HZ timer ticks in idle"
+ help
+ Switches the regular HZ timer off when the system is going idle.
+ This helps z/VM to detect that the Linux system is idle. VM can
+ then "swap-out" this guest which reduces memory usage. It also
+ reduces the overhead of idle systems.
+
+ The HZ timer can be switched on/off via /proc/sys/kernel/hz_timer.
+ hz_timer=0 means HZ timer is disabled. hz_timer=1 means HZ
+ timer is active.
+
+config NO_IDLE_HZ_INIT
+ bool "HZ timer in idle off by default"
+ depends on NO_IDLE_HZ
+ help
+ The HZ timer is switched off in idle by default. That means the
+ HZ timer is already disabled at boot time.
+
+config S390_HYPFS_FS
+ bool "s390 hypervisor file system support"
+ select SYS_HYPERVISOR
+ default y
+ help
+ This is a virtual file system intended to provide accounting
+ information in an s390 hypervisor environment.
+
+config KEXEC
+ bool "kexec system call"
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but is independent of hardware/microcode support.
+
+config ZFCPDUMP
+ tristate "zfcpdump support"
+ select SMP
+ default n
+ help
+ Select this option if you want to build an zfcpdump enabled kernel.
+ Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
+
+endmenu
+
+source "net/Kconfig"
+
+config PCMCIA
+ def_bool n
+
+config CCW
+ def_bool y
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/s390/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/Kconfig.debug b/cleopatre/linux-2.6.25.10-spc300/arch/s390/Kconfig.debug
new file mode 100644
index 0000000000..4599fa06bd
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/Kconfig.debug
@@ -0,0 +1,17 @@
+menu "Kernel hacking"
+
+config TRACE_IRQFLAGS_SUPPORT
+ bool
+ default y
+
+source "lib/Kconfig.debug"
+
+config DEBUG_PAGEALLOC
+ bool "Debug page memory allocations"
+ depends on DEBUG_KERNEL
+ help
+ Unmap pages from the kernel linear mapping after free_pages().
+ This results in a slowdown, but helps to find certain types of
+ memory corruptions.
+
+endmenu
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/Makefile
new file mode 100644
index 0000000000..f708be367b
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/Makefile
@@ -0,0 +1,117 @@
+#
+# s390/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+
+ifndef CONFIG_64BIT
+LDFLAGS := -m elf_s390
+KBUILD_CFLAGS += -m31
+KBUILD_AFLAGS += -m31
+UTS_MACHINE := s390
+STACK_SIZE := 8192
+CHECKFLAGS += -D__s390__ -msize-long
+else
+LDFLAGS := -m elf64_s390
+MODFLAGS += -fpic -D__PIC__
+KBUILD_CFLAGS += -m64
+KBUILD_AFLAGS += -m64
+UTS_MACHINE := s390x
+STACK_SIZE := 16384
+CHECKFLAGS += -D__s390__ -D__s390x__
+endif
+
+cflags-$(CONFIG_MARCH_G5) += $(call cc-option,-march=g5)
+cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900)
+cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
+cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109)
+
+#KBUILD_IMAGE is necessary for make rpm
+KBUILD_IMAGE :=arch/s390/boot/image
+
+#
+# Prevent tail-call optimizations, to get clearer backtraces:
+#
+cflags-$(CONFIG_FRAME_POINTER) += -fno-optimize-sibling-calls
+
+# old style option for packed stacks
+ifeq ($(call cc-option-yn,-mkernel-backchain),y)
+cflags-$(CONFIG_PACK_STACK) += -mkernel-backchain -D__PACK_STACK
+aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK
+cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
+aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
+ifdef CONFIG_SMALL_STACK
+STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) )
+endif
+endif
+
+# new style option for packed stacks
+ifeq ($(call cc-option-yn,-mpacked-stack),y)
+cflags-$(CONFIG_PACK_STACK) += -mpacked-stack -D__PACK_STACK
+aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK
+cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
+aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
+ifdef CONFIG_SMALL_STACK
+STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) )
+endif
+endif
+
+ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y)
+cflags-$(CONFIG_CHECK_STACK) += -mstack-size=$(STACK_SIZE)
+ifneq ($(call cc-option-yn,-mstack-size=8192),y)
+cflags-$(CONFIG_CHECK_STACK) += -mstack-guard=$(CONFIG_STACK_GUARD)
+endif
+endif
+
+ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
+cflags-$(CONFIG_WARN_STACK) += -mwarn-dynamicstack
+cflags-$(CONFIG_WARN_STACK) += -mwarn-framesize=$(CONFIG_WARN_STACK_SIZE)
+endif
+
+KBUILD_CFLAGS += -mbackchain -msoft-float $(cflags-y)
+KBUILD_CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare
+KBUILD_AFLAGS += $(aflags-y)
+
+OBJCOPYFLAGS := -O binary
+LDFLAGS_vmlinux := -e start
+
+head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
+
+core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
+ arch/s390/appldata/ arch/s390/hypfs/
+libs-y += arch/s390/lib/
+drivers-y += drivers/s390/
+drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/
+
+# must be linked after kernel
+drivers-$(CONFIG_OPROFILE) += arch/s390/oprofile/
+
+boot := arch/s390/boot
+
+all: image
+
+install: vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $@
+
+image: vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+zfcpdump:
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+archclean:
+ $(Q)$(MAKE) $(clean)=$(boot)
+
+# Don't use tabs in echo arguments
+define archhelp
+ echo '* image - Kernel image for IPL ($(boot)/image)'
+endef
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/Makefile
new file mode 100644
index 0000000000..99f1cf0713
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Linux - z/VM Monitor Stream.
+#
+
+obj-$(CONFIG_APPLDATA_BASE) += appldata_base.o
+obj-$(CONFIG_APPLDATA_MEM) += appldata_mem.o
+obj-$(CONFIG_APPLDATA_OS) += appldata_os.o
+obj-$(CONFIG_APPLDATA_NET_SUM) += appldata_net_sum.o
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata.h b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata.h
new file mode 100644
index 0000000000..db3ae85051
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata.h
@@ -0,0 +1,61 @@
+/*
+ * arch/s390/appldata/appldata.h
+ *
+ * Definitions and interface for Linux - z/VM Monitor Stream.
+ *
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ *
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ */
+
+//#define APPLDATA_DEBUG /* Debug messages on/off */
+
+#define APPLDATA_MAX_REC_SIZE 4024 /* Maximum size of the */
+ /* data buffer */
+#define APPLDATA_MAX_PROCS 100
+
+#define APPLDATA_PROC_NAME_LENGTH 16 /* Max. length of /proc name */
+
+#define APPLDATA_RECORD_MEM_ID 0x01 /* IDs to identify the */
+#define APPLDATA_RECORD_OS_ID 0x02 /* individual records, */
+#define APPLDATA_RECORD_NET_SUM_ID 0x03 /* must be < 256 ! */
+#define APPLDATA_RECORD_PROC_ID 0x04
+
+#define CTL_APPLDATA_TIMER 2121 /* sysctl IDs, must be unique */
+#define CTL_APPLDATA_INTERVAL 2122
+#define CTL_APPLDATA_MEM 2123
+#define CTL_APPLDATA_OS 2124
+#define CTL_APPLDATA_NET_SUM 2125
+#define CTL_APPLDATA_PROC 2126
+
+#define P_INFO(x...) printk(KERN_INFO MY_PRINT_NAME " info: " x)
+#define P_ERROR(x...) printk(KERN_ERR MY_PRINT_NAME " error: " x)
+#define P_WARNING(x...) printk(KERN_WARNING MY_PRINT_NAME " status: " x)
+
+#ifdef APPLDATA_DEBUG
+#define P_DEBUG(x...) printk(KERN_DEBUG MY_PRINT_NAME " debug: " x)
+#else
+#define P_DEBUG(x...) do {} while (0)
+#endif
+
+struct appldata_ops {
+ struct list_head list;
+ struct ctl_table_header *sysctl_header;
+ struct ctl_table *ctl_table;
+ int active; /* monitoring status */
+
+ /* fill in from here */
+ char name[APPLDATA_PROC_NAME_LENGTH]; /* name of /proc fs node */
+ unsigned char record_nr; /* Record Nr. for Product ID */
+ void (*callback)(void *data); /* callback function */
+ void *data; /* record data */
+ unsigned int size; /* size of record */
+ struct module *owner; /* THIS_MODULE */
+ char mod_lvl[2]; /* modification level, EBCDIC */
+};
+
+extern int appldata_register_ops(struct appldata_ops *ops);
+extern void appldata_unregister_ops(struct appldata_ops *ops);
+extern int appldata_diag(char record_nr, u16 function, unsigned long buffer,
+ u16 length, char *mod_lvl);
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_base.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_base.c
new file mode 100644
index 0000000000..655d52543e
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_base.c
@@ -0,0 +1,582 @@
+/*
+ * arch/s390/appldata/appldata_base.c
+ *
+ * Base infrastructure for Linux-z/VM Monitor Stream, Stage 1.
+ * Exports appldata_register_ops() and appldata_unregister_ops() for the
+ * data gathering modules.
+ *
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ *
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/pagemap.h>
+#include <linux/sysctl.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/workqueue.h>
+#include <asm/appldata.h>
+#include <asm/timer.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+
+#include "appldata.h"
+
+
+#define MY_PRINT_NAME "appldata" /* for debug messages, etc. */
+#define APPLDATA_CPU_INTERVAL 10000 /* default (CPU) time for
+ sampling interval in
+ milliseconds */
+
+#define TOD_MICRO 0x01000 /* nr. of TOD clock units
+ for 1 microsecond */
+/*
+ * /proc entries (sysctl)
+ */
+static const char appldata_proc_name[APPLDATA_PROC_NAME_LENGTH] = "appldata";
+static int appldata_timer_handler(ctl_table *ctl, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+static int appldata_interval_handler(ctl_table *ctl, int write,
+ struct file *filp,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos);
+
+static struct ctl_table_header *appldata_sysctl_header;
+static struct ctl_table appldata_table[] = {
+ {
+ .procname = "timer",
+ .mode = S_IRUGO | S_IWUSR,
+ .proc_handler = &appldata_timer_handler,
+ },
+ {
+ .procname = "interval",
+ .mode = S_IRUGO | S_IWUSR,
+ .proc_handler = &appldata_interval_handler,
+ },
+ { },
+};
+
+static struct ctl_table appldata_dir_table[] = {
+ {
+ .procname = appldata_proc_name,
+ .maxlen = 0,
+ .mode = S_IRUGO | S_IXUGO,
+ .child = appldata_table,
+ },
+ { },
+};
+
+/*
+ * Timer
+ */
+static DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
+static atomic_t appldata_expire_count = ATOMIC_INIT(0);
+
+static DEFINE_SPINLOCK(appldata_timer_lock);
+static int appldata_interval = APPLDATA_CPU_INTERVAL;
+static int appldata_timer_active;
+
+/*
+ * Work queue
+ */
+static struct workqueue_struct *appldata_wq;
+static void appldata_work_fn(struct work_struct *work);
+static DECLARE_WORK(appldata_work, appldata_work_fn);
+
+
+/*
+ * Ops list
+ */
+static DEFINE_SPINLOCK(appldata_ops_lock);
+static LIST_HEAD(appldata_ops_list);
+
+
+/*************************** timer, work, DIAG *******************************/
+/*
+ * appldata_timer_function()
+ *
+ * schedule work and reschedule timer
+ */
+static void appldata_timer_function(unsigned long data)
+{
+ P_DEBUG(" -= Timer =-\n");
+ P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(),
+ atomic_read(&appldata_expire_count));
+ if (atomic_dec_and_test(&appldata_expire_count)) {
+ atomic_set(&appldata_expire_count, num_online_cpus());
+ queue_work(appldata_wq, (struct work_struct *) data);
+ }
+}
+
+/*
+ * appldata_work_fn()
+ *
+ * call data gathering function for each (active) module
+ */
+static void appldata_work_fn(struct work_struct *work)
+{
+ struct list_head *lh;
+ struct appldata_ops *ops;
+ int i;
+
+ P_DEBUG(" -= Work Queue =-\n");
+ i = 0;
+ spin_lock(&appldata_ops_lock);
+ list_for_each(lh, &appldata_ops_list) {
+ ops = list_entry(lh, struct appldata_ops, list);
+ P_DEBUG("list_for_each loop: %i) active = %u, name = %s\n",
+ ++i, ops->active, ops->name);
+ if (ops->active == 1) {
+ ops->callback(ops->data);
+ }
+ }
+ spin_unlock(&appldata_ops_lock);
+}
+
+/*
+ * appldata_diag()
+ *
+ * prepare parameter list, issue DIAG 0xDC
+ */
+int appldata_diag(char record_nr, u16 function, unsigned long buffer,
+ u16 length, char *mod_lvl)
+{
+ struct appldata_product_id id = {
+ .prod_nr = {0xD3, 0xC9, 0xD5, 0xE4,
+ 0xE7, 0xD2, 0xD9}, /* "LINUXKR" */
+ .prod_fn = 0xD5D3, /* "NL" */
+ .version_nr = 0xF2F6, /* "26" */
+ .release_nr = 0xF0F1, /* "01" */
+ };
+
+ id.record_nr = record_nr;
+ id.mod_lvl = (mod_lvl[0]) << 8 | mod_lvl[1];
+ return appldata_asm(&id, function, (void *) buffer, length);
+}
+/************************ timer, work, DIAG <END> ****************************/
+
+
+/****************************** /proc stuff **********************************/
+
+/*
+ * appldata_mod_vtimer_wrap()
+ *
+ * wrapper function for mod_virt_timer(), because smp_call_function_single()
+ * accepts only one parameter.
+ */
+static void __appldata_mod_vtimer_wrap(void *p) {
+ struct {
+ struct vtimer_list *timer;
+ u64 expires;
+ } *args = p;
+ mod_virt_timer(args->timer, args->expires);
+}
+
+#define APPLDATA_ADD_TIMER 0
+#define APPLDATA_DEL_TIMER 1
+#define APPLDATA_MOD_TIMER 2
+
+/*
+ * __appldata_vtimer_setup()
+ *
+ * Add, delete or modify virtual timers on all online cpus.
+ * The caller needs to get the appldata_timer_lock spinlock.
+ */
+static void
+__appldata_vtimer_setup(int cmd)
+{
+ u64 per_cpu_interval;
+ int i;
+
+ switch (cmd) {
+ case APPLDATA_ADD_TIMER:
+ if (appldata_timer_active)
+ break;
+ per_cpu_interval = (u64) (appldata_interval*1000 /
+ num_online_cpus()) * TOD_MICRO;
+ for_each_online_cpu(i) {
+ per_cpu(appldata_timer, i).expires = per_cpu_interval;
+ smp_call_function_single(i, add_virt_timer_periodic,
+ &per_cpu(appldata_timer, i),
+ 0, 1);
+ }
+ appldata_timer_active = 1;
+ P_INFO("Monitoring timer started.\n");
+ break;
+ case APPLDATA_DEL_TIMER:
+ for_each_online_cpu(i)
+ del_virt_timer(&per_cpu(appldata_timer, i));
+ if (!appldata_timer_active)
+ break;
+ appldata_timer_active = 0;
+ atomic_set(&appldata_expire_count, num_online_cpus());
+ P_INFO("Monitoring timer stopped.\n");
+ break;
+ case APPLDATA_MOD_TIMER:
+ per_cpu_interval = (u64) (appldata_interval*1000 /
+ num_online_cpus()) * TOD_MICRO;
+ if (!appldata_timer_active)
+ break;
+ for_each_online_cpu(i) {
+ struct {
+ struct vtimer_list *timer;
+ u64 expires;
+ } args;
+ args.timer = &per_cpu(appldata_timer, i);
+ args.expires = per_cpu_interval;
+ smp_call_function_single(i, __appldata_mod_vtimer_wrap,
+ &args, 0, 1);
+ }
+ }
+}
+
+/*
+ * appldata_timer_handler()
+ *
+ * Start/Stop timer, show status of timer (0 = not active, 1 = active)
+ */
+static int
+appldata_timer_handler(ctl_table *ctl, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ int len;
+ char buf[2];
+
+ if (!*lenp || *ppos) {
+ *lenp = 0;
+ return 0;
+ }
+ if (!write) {
+ len = sprintf(buf, appldata_timer_active ? "1\n" : "0\n");
+ if (len > *lenp)
+ len = *lenp;
+ if (copy_to_user(buffer, buf, len))
+ return -EFAULT;
+ goto out;
+ }
+ len = *lenp;
+ if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len))
+ return -EFAULT;
+ spin_lock(&appldata_timer_lock);
+ if (buf[0] == '1')
+ __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
+ else if (buf[0] == '0')
+ __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
+ spin_unlock(&appldata_timer_lock);
+out:
+ *lenp = len;
+ *ppos += len;
+ return 0;
+}
+
+/*
+ * appldata_interval_handler()
+ *
+ * Set (CPU) timer interval for collection of data (in milliseconds), show
+ * current timer interval.
+ */
+static int
+appldata_interval_handler(ctl_table *ctl, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ int len, interval;
+ char buf[16];
+
+ if (!*lenp || *ppos) {
+ *lenp = 0;
+ return 0;
+ }
+ if (!write) {
+ len = sprintf(buf, "%i\n", appldata_interval);
+ if (len > *lenp)
+ len = *lenp;
+ if (copy_to_user(buffer, buf, len))
+ return -EFAULT;
+ goto out;
+ }
+ len = *lenp;
+ if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) {
+ return -EFAULT;
+ }
+ interval = 0;
+ sscanf(buf, "%i", &interval);
+ if (interval <= 0) {
+ P_ERROR("Timer CPU interval has to be > 0!\n");
+ return -EINVAL;
+ }
+
+ spin_lock(&appldata_timer_lock);
+ appldata_interval = interval;
+ __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
+ spin_unlock(&appldata_timer_lock);
+
+ P_INFO("Monitoring CPU interval set to %u milliseconds.\n",
+ interval);
+out:
+ *lenp = len;
+ *ppos += len;
+ return 0;
+}
+
+/*
+ * appldata_generic_handler()
+ *
+ * Generic start/stop monitoring and DIAG, show status of
+ * monitoring (0 = not in process, 1 = in process)
+ */
+static int
+appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct appldata_ops *ops = NULL, *tmp_ops;
+ int rc, len, found;
+ char buf[2];
+ struct list_head *lh;
+
+ found = 0;
+ spin_lock(&appldata_ops_lock);
+ list_for_each(lh, &appldata_ops_list) {
+ tmp_ops = list_entry(lh, struct appldata_ops, list);
+ if (&tmp_ops->ctl_table[2] == ctl) {
+ found = 1;
+ }
+ }
+ if (!found) {
+ spin_unlock(&appldata_ops_lock);
+ return -ENODEV;
+ }
+ ops = ctl->data;
+ if (!try_module_get(ops->owner)) { // protect this function
+ spin_unlock(&appldata_ops_lock);
+ return -ENODEV;
+ }
+ spin_unlock(&appldata_ops_lock);
+
+ if (!*lenp || *ppos) {
+ *lenp = 0;
+ module_put(ops->owner);
+ return 0;
+ }
+ if (!write) {
+ len = sprintf(buf, ops->active ? "1\n" : "0\n");
+ if (len > *lenp)
+ len = *lenp;
+ if (copy_to_user(buffer, buf, len)) {
+ module_put(ops->owner);
+ return -EFAULT;
+ }
+ goto out;
+ }
+ len = *lenp;
+ if (copy_from_user(buf, buffer,
+ len > sizeof(buf) ? sizeof(buf) : len)) {
+ module_put(ops->owner);
+ return -EFAULT;
+ }
+
+ spin_lock(&appldata_ops_lock);
+ if ((buf[0] == '1') && (ops->active == 0)) {
+ // protect work queue callback
+ if (!try_module_get(ops->owner)) {
+ spin_unlock(&appldata_ops_lock);
+ module_put(ops->owner);
+ return -ENODEV;
+ }
+ ops->callback(ops->data); // init record
+ rc = appldata_diag(ops->record_nr,
+ APPLDATA_START_INTERVAL_REC,
+ (unsigned long) ops->data, ops->size,
+ ops->mod_lvl);
+ if (rc != 0) {
+ P_ERROR("START DIAG 0xDC for %s failed, "
+ "return code: %d\n", ops->name, rc);
+ module_put(ops->owner);
+ } else {
+ P_INFO("Monitoring %s data enabled, "
+ "DIAG 0xDC started.\n", ops->name);
+ ops->active = 1;
+ }
+ } else if ((buf[0] == '0') && (ops->active == 1)) {
+ ops->active = 0;
+ rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
+ (unsigned long) ops->data, ops->size,
+ ops->mod_lvl);
+ if (rc != 0) {
+ P_ERROR("STOP DIAG 0xDC for %s failed, "
+ "return code: %d\n", ops->name, rc);
+ } else {
+ P_INFO("Monitoring %s data disabled, "
+ "DIAG 0xDC stopped.\n", ops->name);
+ }
+ module_put(ops->owner);
+ }
+ spin_unlock(&appldata_ops_lock);
+out:
+ *lenp = len;
+ *ppos += len;
+ module_put(ops->owner);
+ return 0;
+}
+
+/*************************** /proc stuff <END> *******************************/
+
+
+/************************* module-ops management *****************************/
+/*
+ * appldata_register_ops()
+ *
+ * update ops list, register /proc/sys entries
+ */
+int appldata_register_ops(struct appldata_ops *ops)
+{
+ if ((ops->size > APPLDATA_MAX_REC_SIZE) || (ops->size < 0))
+ return -EINVAL;
+
+ ops->ctl_table = kzalloc(4 * sizeof(struct ctl_table), GFP_KERNEL);
+ if (!ops->ctl_table)
+ return -ENOMEM;
+
+ spin_lock(&appldata_ops_lock);
+ list_add(&ops->list, &appldata_ops_list);
+ spin_unlock(&appldata_ops_lock);
+
+ ops->ctl_table[0].procname = appldata_proc_name;
+ ops->ctl_table[0].maxlen = 0;
+ ops->ctl_table[0].mode = S_IRUGO | S_IXUGO;
+ ops->ctl_table[0].child = &ops->ctl_table[2];
+
+ ops->ctl_table[2].procname = ops->name;
+ ops->ctl_table[2].mode = S_IRUGO | S_IWUSR;
+ ops->ctl_table[2].proc_handler = appldata_generic_handler;
+ ops->ctl_table[2].data = ops;
+
+ ops->sysctl_header = register_sysctl_table(ops->ctl_table);
+ if (!ops->sysctl_header)
+ goto out;
+ P_INFO("%s-ops registered!\n", ops->name);
+ return 0;
+out:
+ spin_lock(&appldata_ops_lock);
+ list_del(&ops->list);
+ spin_unlock(&appldata_ops_lock);
+ kfree(ops->ctl_table);
+ return -ENOMEM;
+}
+
+/*
+ * appldata_unregister_ops()
+ *
+ * update ops list, unregister /proc entries, stop DIAG if necessary
+ */
+void appldata_unregister_ops(struct appldata_ops *ops)
+{
+ spin_lock(&appldata_ops_lock);
+ list_del(&ops->list);
+ spin_unlock(&appldata_ops_lock);
+ unregister_sysctl_table(ops->sysctl_header);
+ kfree(ops->ctl_table);
+ P_INFO("%s-ops unregistered!\n", ops->name);
+}
+/********************** module-ops management <END> **************************/
+
+
+/******************************* init / exit *********************************/
+
+static void __cpuinit appldata_online_cpu(int cpu)
+{
+ init_virt_timer(&per_cpu(appldata_timer, cpu));
+ per_cpu(appldata_timer, cpu).function = appldata_timer_function;
+ per_cpu(appldata_timer, cpu).data = (unsigned long)
+ &appldata_work;
+ atomic_inc(&appldata_expire_count);
+ spin_lock(&appldata_timer_lock);
+ __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
+ spin_unlock(&appldata_timer_lock);
+}
+
+static void __cpuinit appldata_offline_cpu(int cpu)
+{
+ del_virt_timer(&per_cpu(appldata_timer, cpu));
+ if (atomic_dec_and_test(&appldata_expire_count)) {
+ atomic_set(&appldata_expire_count, num_online_cpus());
+ queue_work(appldata_wq, &appldata_work);
+ }
+ spin_lock(&appldata_timer_lock);
+ __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
+ spin_unlock(&appldata_timer_lock);
+}
+
+static int __cpuinit appldata_cpu_notify(struct notifier_block *self,
+ unsigned long action,
+ void *hcpu)
+{
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ appldata_online_cpu((long) hcpu);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ appldata_offline_cpu((long) hcpu);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata appldata_nb = {
+ .notifier_call = appldata_cpu_notify,
+};
+
+/*
+ * appldata_init()
+ *
+ * init timer, register /proc entries
+ */
+static int __init appldata_init(void)
+{
+ int i;
+
+ P_DEBUG("sizeof(parameter_list) = %lu\n",
+ sizeof(struct appldata_parameter_list));
+
+ appldata_wq = create_singlethread_workqueue("appldata");
+ if (!appldata_wq) {
+ P_ERROR("Could not create work queue\n");
+ return -ENOMEM;
+ }
+
+ for_each_online_cpu(i)
+ appldata_online_cpu(i);
+
+ /* Register cpu hotplug notifier */
+ register_hotcpu_notifier(&appldata_nb);
+
+ appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
+
+ P_DEBUG("Base interface initialized.\n");
+ return 0;
+}
+
+__initcall(appldata_init);
+
+/**************************** init / exit <END> ******************************/
+
+EXPORT_SYMBOL_GPL(appldata_register_ops);
+EXPORT_SYMBOL_GPL(appldata_unregister_ops);
+EXPORT_SYMBOL_GPL(appldata_diag);
+
+EXPORT_SYMBOL_GPL(si_swapinfo);
+EXPORT_SYMBOL_GPL(nr_threads);
+EXPORT_SYMBOL_GPL(nr_running);
+EXPORT_SYMBOL_GPL(nr_iowait);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_mem.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_mem.c
new file mode 100644
index 0000000000..51181ccdb8
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_mem.c
@@ -0,0 +1,197 @@
+/*
+ * arch/s390/appldata/appldata_mem.c
+ *
+ * Data gathering module for Linux-VM Monitor Stream, Stage 1.
+ * Collects data related to memory management.
+ *
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ *
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <asm/io.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+
+#include "appldata.h"
+
+
+#define MY_PRINT_NAME "appldata_mem" /* for debug messages, etc. */
+#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* Converts #Pages to KB */
+
+/*
+ * Memory data
+ *
+ * This is accessed as binary data by z/VM. If changes to it can't be avoided,
+ * the structure version (product ID, see appldata_base.c) needs to be changed
+ * as well and all documentation and z/VM applications using it must be
+ * updated.
+ *
+ * The record layout is documented in the Linux for zSeries Device Drivers
+ * book:
+ * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
+ */
+static struct appldata_mem_data {
+ u64 timestamp;
+ u32 sync_count_1; /* after VM collected the record data, */
+ u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
+ same. If not, the record has been updated on
+ the Linux side while VM was collecting the
+ (possibly corrupt) data */
+
+ u64 pgpgin; /* data read from disk */
+ u64 pgpgout; /* data written to disk */
+ u64 pswpin; /* pages swapped in */
+ u64 pswpout; /* pages swapped out */
+
+ u64 sharedram; /* sharedram is currently set to 0 */
+
+ u64 totalram; /* total main memory size */
+ u64 freeram; /* free main memory size */
+ u64 totalhigh; /* total high memory size */
+ u64 freehigh; /* free high memory size */
+
+ u64 bufferram; /* memory reserved for buffers, free cache */
+ u64 cached; /* size of (used) cache, w/o buffers */
+ u64 totalswap; /* total swap space size */
+ u64 freeswap; /* free swap space */
+
+// New in 2.6 -->
+ u64 pgalloc; /* page allocations */
+ u64 pgfault; /* page faults (major+minor) */
+ u64 pgmajfault; /* page faults (major only) */
+// <-- New in 2.6
+
+} __attribute__((packed)) appldata_mem_data;
+
+
+static inline void appldata_debug_print(struct appldata_mem_data *mem_data)
+{
+ P_DEBUG("--- MEM - RECORD ---\n");
+ P_DEBUG("pgpgin = %8lu KB\n", mem_data->pgpgin);
+ P_DEBUG("pgpgout = %8lu KB\n", mem_data->pgpgout);
+ P_DEBUG("pswpin = %8lu Pages\n", mem_data->pswpin);
+ P_DEBUG("pswpout = %8lu Pages\n", mem_data->pswpout);
+ P_DEBUG("pgalloc = %8lu \n", mem_data->pgalloc);
+ P_DEBUG("pgfault = %8lu \n", mem_data->pgfault);
+ P_DEBUG("pgmajfault = %8lu \n", mem_data->pgmajfault);
+ P_DEBUG("sharedram = %8lu KB\n", mem_data->sharedram);
+ P_DEBUG("totalram = %8lu KB\n", mem_data->totalram);
+ P_DEBUG("freeram = %8lu KB\n", mem_data->freeram);
+ P_DEBUG("totalhigh = %8lu KB\n", mem_data->totalhigh);
+ P_DEBUG("freehigh = %8lu KB\n", mem_data->freehigh);
+ P_DEBUG("bufferram = %8lu KB\n", mem_data->bufferram);
+ P_DEBUG("cached = %8lu KB\n", mem_data->cached);
+ P_DEBUG("totalswap = %8lu KB\n", mem_data->totalswap);
+ P_DEBUG("freeswap = %8lu KB\n", mem_data->freeswap);
+ P_DEBUG("sync_count_1 = %u\n", mem_data->sync_count_1);
+ P_DEBUG("sync_count_2 = %u\n", mem_data->sync_count_2);
+ P_DEBUG("timestamp = %lX\n", mem_data->timestamp);
+}
+
+/*
+ * appldata_get_mem_data()
+ *
+ * gather memory data
+ */
+static void appldata_get_mem_data(void *data)
+{
+ /*
+ * don't put large structures on the stack, we are
+ * serialized through the appldata_ops_lock and can use static
+ */
+ static struct sysinfo val;
+ unsigned long ev[NR_VM_EVENT_ITEMS];
+ struct appldata_mem_data *mem_data;
+
+ mem_data = data;
+ mem_data->sync_count_1++;
+
+ all_vm_events(ev);
+ mem_data->pgpgin = ev[PGPGIN] >> 1;
+ mem_data->pgpgout = ev[PGPGOUT] >> 1;
+ mem_data->pswpin = ev[PSWPIN];
+ mem_data->pswpout = ev[PSWPOUT];
+ mem_data->pgalloc = ev[PGALLOC_NORMAL];
+#ifdef CONFIG_ZONE_DMA
+ mem_data->pgalloc += ev[PGALLOC_DMA];
+#endif
+ mem_data->pgfault = ev[PGFAULT];
+ mem_data->pgmajfault = ev[PGMAJFAULT];
+
+ si_meminfo(&val);
+ mem_data->sharedram = val.sharedram;
+ mem_data->totalram = P2K(val.totalram);
+ mem_data->freeram = P2K(val.freeram);
+ mem_data->totalhigh = P2K(val.totalhigh);
+ mem_data->freehigh = P2K(val.freehigh);
+ mem_data->bufferram = P2K(val.bufferram);
+ mem_data->cached = P2K(global_page_state(NR_FILE_PAGES)
+ - val.bufferram);
+
+ si_swapinfo(&val);
+ mem_data->totalswap = P2K(val.totalswap);
+ mem_data->freeswap = P2K(val.freeswap);
+
+ mem_data->timestamp = get_clock();
+ mem_data->sync_count_2++;
+#ifdef APPLDATA_DEBUG
+ appldata_debug_print(mem_data);
+#endif
+}
+
+
+static struct appldata_ops ops = {
+ .name = "mem",
+ .record_nr = APPLDATA_RECORD_MEM_ID,
+ .size = sizeof(struct appldata_mem_data),
+ .callback = &appldata_get_mem_data,
+ .data = &appldata_mem_data,
+ .owner = THIS_MODULE,
+ .mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */
+};
+
+
+/*
+ * appldata_mem_init()
+ *
+ * init_data, register ops
+ */
+static int __init appldata_mem_init(void)
+{
+ int rc;
+
+ P_DEBUG("sizeof(mem) = %lu\n", sizeof(struct appldata_mem_data));
+
+ rc = appldata_register_ops(&ops);
+ if (rc != 0) {
+ P_ERROR("Error registering ops, rc = %i\n", rc);
+ } else {
+ P_DEBUG("%s-ops registered!\n", ops.name);
+ }
+ return rc;
+}
+
+/*
+ * appldata_mem_exit()
+ *
+ * unregister ops
+ */
+static void __exit appldata_mem_exit(void)
+{
+ appldata_unregister_ops(&ops);
+ P_DEBUG("%s-ops unregistered!\n", ops.name);
+}
+
+
+module_init(appldata_mem_init);
+module_exit(appldata_mem_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gerald Schaefer");
+MODULE_DESCRIPTION("Linux-VM Monitor Stream, MEMORY statistics");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_net_sum.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_net_sum.c
new file mode 100644
index 0000000000..4d83443360
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_net_sum.c
@@ -0,0 +1,192 @@
+/*
+ * arch/s390/appldata/appldata_net_sum.c
+ *
+ * Data gathering module for Linux-VM Monitor Stream, Stage 1.
+ * Collects accumulated network statistics (Packets received/transmitted,
+ * dropped, errors, ...).
+ *
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ *
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/netdevice.h>
+#include <net/net_namespace.h>
+
+#include "appldata.h"
+
+
+#define MY_PRINT_NAME "appldata_net_sum" /* for debug messages, etc. */
+
+
+/*
+ * Network data
+ *
+ * This is accessed as binary data by z/VM. If changes to it can't be avoided,
+ * the structure version (product ID, see appldata_base.c) needs to be changed
+ * as well and all documentation and z/VM applications using it must be updated.
+ *
+ * The record layout is documented in the Linux for zSeries Device Drivers
+ * book:
+ * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
+ */
+static struct appldata_net_sum_data {
+ u64 timestamp;
+ u32 sync_count_1; /* after VM collected the record data, */
+ u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
+ same. If not, the record has been updated on
+ the Linux side while VM was collecting the
+ (possibly corrupt) data */
+
+ u32 nr_interfaces; /* nr. of network interfaces being monitored */
+
+ u32 padding; /* next value is 64-bit aligned, so these */
+ /* 4 byte would be padded out by compiler */
+
+ u64 rx_packets; /* total packets received */
+ u64 tx_packets; /* total packets transmitted */
+ u64 rx_bytes; /* total bytes received */
+ u64 tx_bytes; /* total bytes transmitted */
+ u64 rx_errors; /* bad packets received */
+ u64 tx_errors; /* packet transmit problems */
+ u64 rx_dropped; /* no space in linux buffers */
+ u64 tx_dropped; /* no space available in linux */
+ u64 collisions; /* collisions while transmitting */
+} __attribute__((packed)) appldata_net_sum_data;
+
+
+static inline void appldata_print_debug(struct appldata_net_sum_data *net_data)
+{
+ P_DEBUG("--- NET - RECORD ---\n");
+
+ P_DEBUG("nr_interfaces = %u\n", net_data->nr_interfaces);
+ P_DEBUG("rx_packets = %8lu\n", net_data->rx_packets);
+ P_DEBUG("tx_packets = %8lu\n", net_data->tx_packets);
+ P_DEBUG("rx_bytes = %8lu\n", net_data->rx_bytes);
+ P_DEBUG("tx_bytes = %8lu\n", net_data->tx_bytes);
+ P_DEBUG("rx_errors = %8lu\n", net_data->rx_errors);
+ P_DEBUG("tx_errors = %8lu\n", net_data->tx_errors);
+ P_DEBUG("rx_dropped = %8lu\n", net_data->rx_dropped);
+ P_DEBUG("tx_dropped = %8lu\n", net_data->tx_dropped);
+ P_DEBUG("collisions = %8lu\n", net_data->collisions);
+
+ P_DEBUG("sync_count_1 = %u\n", net_data->sync_count_1);
+ P_DEBUG("sync_count_2 = %u\n", net_data->sync_count_2);
+ P_DEBUG("timestamp = %lX\n", net_data->timestamp);
+}
+
+/*
+ * appldata_get_net_sum_data()
+ *
+ * gather accumulated network statistics
+ */
+static void appldata_get_net_sum_data(void *data)
+{
+ int i;
+ struct appldata_net_sum_data *net_data;
+ struct net_device *dev;
+ struct net_device_stats *stats;
+ unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes, rx_errors,
+ tx_errors, rx_dropped, tx_dropped, collisions;
+
+ net_data = data;
+ net_data->sync_count_1++;
+
+ i = 0;
+ rx_packets = 0;
+ tx_packets = 0;
+ rx_bytes = 0;
+ tx_bytes = 0;
+ rx_errors = 0;
+ tx_errors = 0;
+ rx_dropped = 0;
+ tx_dropped = 0;
+ collisions = 0;
+ read_lock(&dev_base_lock);
+ for_each_netdev(&init_net, dev) {
+ stats = dev->get_stats(dev);
+ rx_packets += stats->rx_packets;
+ tx_packets += stats->tx_packets;
+ rx_bytes += stats->rx_bytes;
+ tx_bytes += stats->tx_bytes;
+ rx_errors += stats->rx_errors;
+ tx_errors += stats->tx_errors;
+ rx_dropped += stats->rx_dropped;
+ tx_dropped += stats->tx_dropped;
+ collisions += stats->collisions;
+ i++;
+ }
+ read_unlock(&dev_base_lock);
+ net_data->nr_interfaces = i;
+ net_data->rx_packets = rx_packets;
+ net_data->tx_packets = tx_packets;
+ net_data->rx_bytes = rx_bytes;
+ net_data->tx_bytes = tx_bytes;
+ net_data->rx_errors = rx_errors;
+ net_data->tx_errors = tx_errors;
+ net_data->rx_dropped = rx_dropped;
+ net_data->tx_dropped = tx_dropped;
+ net_data->collisions = collisions;
+
+ net_data->timestamp = get_clock();
+ net_data->sync_count_2++;
+#ifdef APPLDATA_DEBUG
+ appldata_print_debug(net_data);
+#endif
+}
+
+
+static struct appldata_ops ops = {
+ .name = "net_sum",
+ .record_nr = APPLDATA_RECORD_NET_SUM_ID,
+ .size = sizeof(struct appldata_net_sum_data),
+ .callback = &appldata_get_net_sum_data,
+ .data = &appldata_net_sum_data,
+ .owner = THIS_MODULE,
+ .mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */
+};
+
+
+/*
+ * appldata_net_init()
+ *
+ * init data, register ops
+ */
+static int __init appldata_net_init(void)
+{
+ int rc;
+
+ P_DEBUG("sizeof(net) = %lu\n", sizeof(struct appldata_net_sum_data));
+
+ rc = appldata_register_ops(&ops);
+ if (rc != 0) {
+ P_ERROR("Error registering ops, rc = %i\n", rc);
+ } else {
+ P_DEBUG("%s-ops registered!\n", ops.name);
+ }
+ return rc;
+}
+
+/*
+ * appldata_net_exit()
+ *
+ * unregister ops
+ */
+static void __exit appldata_net_exit(void)
+{
+ appldata_unregister_ops(&ops);
+ P_DEBUG("%s-ops unregistered!\n", ops.name);
+}
+
+
+module_init(appldata_net_init);
+module_exit(appldata_net_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gerald Schaefer");
+MODULE_DESCRIPTION("Linux-VM Monitor Stream, accumulated network statistics");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_os.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_os.c
new file mode 100644
index 0000000000..6b3eafe104
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/appldata/appldata_os.c
@@ -0,0 +1,276 @@
+/*
+ * arch/s390/appldata/appldata_os.c
+ *
+ * Data gathering module for Linux-VM Monitor Stream, Stage 1.
+ * Collects misc. OS related data (CPU utilization, running processes).
+ *
+ * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ *
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <asm/appldata.h>
+#include <asm/smp.h>
+
+#include "appldata.h"
+
+
+#define MY_PRINT_NAME "appldata_os" /* for debug messages, etc. */
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+
+/*
+ * OS data
+ *
+ * This is accessed as binary data by z/VM. If changes to it can't be avoided,
+ * the structure version (product ID, see appldata_base.c) needs to be changed
+ * as well and all documentation and z/VM applications using it must be
+ * updated.
+ *
+ * The record layout is documented in the Linux for zSeries Device Drivers
+ * book:
+ * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
+ */
+struct appldata_os_per_cpu {
+ u32 per_cpu_user; /* timer ticks spent in user mode */
+ u32 per_cpu_nice; /* ... spent with modified priority */
+ u32 per_cpu_system; /* ... spent in kernel mode */
+ u32 per_cpu_idle; /* ... spent in idle mode */
+
+ /* New in 2.6 */
+ u32 per_cpu_irq; /* ... spent in interrupts */
+ u32 per_cpu_softirq; /* ... spent in softirqs */
+ u32 per_cpu_iowait; /* ... spent while waiting for I/O */
+
+ /* New in modification level 01 */
+ u32 per_cpu_steal; /* ... stolen by hypervisor */
+ u32 cpu_id; /* number of this CPU */
+} __attribute__((packed));
+
+struct appldata_os_data {
+ u64 timestamp;
+ u32 sync_count_1; /* after VM collected the record data, */
+ u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
+ same. If not, the record has been updated on
+ the Linux side while VM was collecting the
+ (possibly corrupt) data */
+
+ u32 nr_cpus; /* number of (virtual) CPUs */
+ u32 per_cpu_size; /* size of the per-cpu data struct */
+ u32 cpu_offset; /* offset of the first per-cpu data struct */
+
+ u32 nr_running; /* number of runnable threads */
+ u32 nr_threads; /* number of threads */
+ u32 avenrun[3]; /* average nr. of running processes during */
+ /* the last 1, 5 and 15 minutes */
+
+ /* New in 2.6 */
+ u32 nr_iowait; /* number of blocked threads
+ (waiting for I/O) */
+
+ /* per cpu data */
+ struct appldata_os_per_cpu os_cpu[0];
+} __attribute__((packed));
+
+static struct appldata_os_data *appldata_os_data;
+
+static struct appldata_ops ops = {
+ .name = "os",
+ .record_nr = APPLDATA_RECORD_OS_ID,
+ .owner = THIS_MODULE,
+ .mod_lvl = {0xF0, 0xF1}, /* EBCDIC "01" */
+};
+
+
+static inline void appldata_print_debug(struct appldata_os_data *os_data)
+{
+ int a0, a1, a2, i;
+
+ P_DEBUG("--- OS - RECORD ---\n");
+ P_DEBUG("nr_threads = %u\n", os_data->nr_threads);
+ P_DEBUG("nr_running = %u\n", os_data->nr_running);
+ P_DEBUG("nr_iowait = %u\n", os_data->nr_iowait);
+ P_DEBUG("avenrun(int) = %8x / %8x / %8x\n", os_data->avenrun[0],
+ os_data->avenrun[1], os_data->avenrun[2]);
+ a0 = os_data->avenrun[0];
+ a1 = os_data->avenrun[1];
+ a2 = os_data->avenrun[2];
+ P_DEBUG("avenrun(float) = %d.%02d / %d.%02d / %d.%02d\n",
+ LOAD_INT(a0), LOAD_FRAC(a0), LOAD_INT(a1), LOAD_FRAC(a1),
+ LOAD_INT(a2), LOAD_FRAC(a2));
+
+ P_DEBUG("nr_cpus = %u\n", os_data->nr_cpus);
+ for (i = 0; i < os_data->nr_cpus; i++) {
+ P_DEBUG("cpu%u : user = %u, nice = %u, system = %u, "
+ "idle = %u, irq = %u, softirq = %u, iowait = %u, "
+ "steal = %u\n",
+ os_data->os_cpu[i].cpu_id,
+ os_data->os_cpu[i].per_cpu_user,
+ os_data->os_cpu[i].per_cpu_nice,
+ os_data->os_cpu[i].per_cpu_system,
+ os_data->os_cpu[i].per_cpu_idle,
+ os_data->os_cpu[i].per_cpu_irq,
+ os_data->os_cpu[i].per_cpu_softirq,
+ os_data->os_cpu[i].per_cpu_iowait,
+ os_data->os_cpu[i].per_cpu_steal);
+ }
+
+ P_DEBUG("sync_count_1 = %u\n", os_data->sync_count_1);
+ P_DEBUG("sync_count_2 = %u\n", os_data->sync_count_2);
+ P_DEBUG("timestamp = %lX\n", os_data->timestamp);
+}
+
+/*
+ * appldata_get_os_data()
+ *
+ * gather OS data
+ */
+static void appldata_get_os_data(void *data)
+{
+ int i, j, rc;
+ struct appldata_os_data *os_data;
+ unsigned int new_size;
+
+ os_data = data;
+ os_data->sync_count_1++;
+
+ os_data->nr_threads = nr_threads;
+ os_data->nr_running = nr_running();
+ os_data->nr_iowait = nr_iowait();
+ os_data->avenrun[0] = avenrun[0] + (FIXED_1/200);
+ os_data->avenrun[1] = avenrun[1] + (FIXED_1/200);
+ os_data->avenrun[2] = avenrun[2] + (FIXED_1/200);
+
+ j = 0;
+ for_each_online_cpu(i) {
+ os_data->os_cpu[j].per_cpu_user =
+ cputime_to_jiffies(kstat_cpu(i).cpustat.user);
+ os_data->os_cpu[j].per_cpu_nice =
+ cputime_to_jiffies(kstat_cpu(i).cpustat.nice);
+ os_data->os_cpu[j].per_cpu_system =
+ cputime_to_jiffies(kstat_cpu(i).cpustat.system);
+ os_data->os_cpu[j].per_cpu_idle =
+ cputime_to_jiffies(kstat_cpu(i).cpustat.idle);
+ os_data->os_cpu[j].per_cpu_irq =
+ cputime_to_jiffies(kstat_cpu(i).cpustat.irq);
+ os_data->os_cpu[j].per_cpu_softirq =
+ cputime_to_jiffies(kstat_cpu(i).cpustat.softirq);
+ os_data->os_cpu[j].per_cpu_iowait =
+ cputime_to_jiffies(kstat_cpu(i).cpustat.iowait);
+ os_data->os_cpu[j].per_cpu_steal =
+ cputime_to_jiffies(kstat_cpu(i).cpustat.steal);
+ os_data->os_cpu[j].cpu_id = i;
+ j++;
+ }
+
+ os_data->nr_cpus = j;
+
+ new_size = sizeof(struct appldata_os_data) +
+ (os_data->nr_cpus * sizeof(struct appldata_os_per_cpu));
+ if (ops.size != new_size) {
+ if (ops.active) {
+ rc = appldata_diag(APPLDATA_RECORD_OS_ID,
+ APPLDATA_START_INTERVAL_REC,
+ (unsigned long) ops.data, new_size,
+ ops.mod_lvl);
+ if (rc != 0) {
+ P_ERROR("os: START NEW DIAG 0xDC failed, "
+ "return code: %d, new size = %i\n", rc,
+ new_size);
+ P_INFO("os: stopping old record now\n");
+ } else
+ P_INFO("os: new record size = %i\n", new_size);
+
+ rc = appldata_diag(APPLDATA_RECORD_OS_ID,
+ APPLDATA_STOP_REC,
+ (unsigned long) ops.data, ops.size,
+ ops.mod_lvl);
+ if (rc != 0)
+ P_ERROR("os: STOP OLD DIAG 0xDC failed, "
+ "return code: %d, old size = %i\n", rc,
+ ops.size);
+ else
+ P_INFO("os: old record size = %i stopped\n",
+ ops.size);
+ }
+ ops.size = new_size;
+ }
+ os_data->timestamp = get_clock();
+ os_data->sync_count_2++;
+#ifdef APPLDATA_DEBUG
+ appldata_print_debug(os_data);
+#endif
+}
+
+
+/*
+ * appldata_os_init()
+ *
+ * init data, register ops
+ */
+static int __init appldata_os_init(void)
+{
+ int rc, max_size;
+
+ max_size = sizeof(struct appldata_os_data) +
+ (NR_CPUS * sizeof(struct appldata_os_per_cpu));
+ if (max_size > APPLDATA_MAX_REC_SIZE) {
+ P_ERROR("Max. size of OS record = %i, bigger than maximum "
+ "record size (%i)\n", max_size, APPLDATA_MAX_REC_SIZE);
+ rc = -ENOMEM;
+ goto out;
+ }
+ P_DEBUG("max. sizeof(os) = %i, sizeof(os_cpu) = %lu\n", max_size,
+ sizeof(struct appldata_os_per_cpu));
+
+ appldata_os_data = kzalloc(max_size, GFP_DMA);
+ if (appldata_os_data == NULL) {
+ P_ERROR("No memory for %s!\n", ops.name);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu);
+ appldata_os_data->cpu_offset = offsetof(struct appldata_os_data,
+ os_cpu);
+ P_DEBUG("cpu offset = %u\n", appldata_os_data->cpu_offset);
+
+ ops.data = appldata_os_data;
+ ops.callback = &appldata_get_os_data;
+ rc = appldata_register_ops(&ops);
+ if (rc != 0) {
+ P_ERROR("Error registering ops, rc = %i\n", rc);
+ kfree(appldata_os_data);
+ } else {
+ P_DEBUG("%s-ops registered!\n", ops.name);
+ }
+out:
+ return rc;
+}
+
+/*
+ * appldata_os_exit()
+ *
+ * unregister ops
+ */
+static void __exit appldata_os_exit(void)
+{
+ appldata_unregister_ops(&ops);
+ kfree(appldata_os_data);
+ P_DEBUG("%s-ops unregistered!\n", ops.name);
+}
+
+
+module_init(appldata_os_init);
+module_exit(appldata_os_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gerald Schaefer");
+MODULE_DESCRIPTION("Linux-VM Monitor Stream, OS statistics");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/boot/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/boot/Makefile
new file mode 100644
index 0000000000..4d97eef36b
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/boot/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the linux s390-specific parts of the memory manager.
+#
+
+COMPILE_VERSION := __linux_compile_version_id__`hostname | \
+ tr -c '[0-9A-Za-z]' '_'`__`date | \
+ tr -c '[0-9A-Za-z]' '_'`_t
+
+EXTRA_CFLAGS := -DCOMPILE_VERSION=$(COMPILE_VERSION) -gstabs -I.
+
+targets := image
+
+$(obj)/image: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+install: $(CONFIGURE) $(obj)/image
+ sh -x $(srctree)/$(obj)/install.sh $(KERNELRELEASE) $(obj)/image \
+ System.map Kerntypes "$(INSTALL_PATH)"
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/boot/install.sh b/cleopatre/linux-2.6.25.10-spc300/arch/s390/boot/install.sh
new file mode 100644
index 0000000000..d4026f62cb
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/boot/install.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# arch/s390x/boot/install.sh
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install" script for s390 architecture
+#
+# Arguments:
+# $1 - kernel version
+# $2 - kernel image file
+# $3 - kernel map file
+# $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+
+if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi
+if [ -x /sbin/${CROSS_COMPILE}installkernel ]; then exec /sbin/${CROSS_COMPILE}installkernel "$@"; fi
+
+# Default install - same as make zlilo
+
+if [ -f $4/vmlinuz ]; then
+ mv $4/vmlinuz $4/vmlinuz.old
+fi
+
+if [ -f $4/System.map ]; then
+ mv $4/System.map $4/System.old
+fi
+
+cat $2 > $4/vmlinuz
+cp $3 $4/System.map
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/Makefile
new file mode 100644
index 0000000000..14e552c5cc
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/Makefile
@@ -0,0 +1,9 @@
+#
+# Cryptographic API
+#
+
+obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o
+obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o
+obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
+obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
+obj-$(CONFIG_S390_PRNG) += prng.o
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/aes_s390.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/aes_s390.c
new file mode 100644
index 0000000000..a3f67f8b54
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/aes_s390.c
@@ -0,0 +1,558 @@
+/*
+ * Cryptographic API.
+ *
+ * s390 implementation of the AES Cipher Algorithm.
+ *
+ * s390 Version:
+ * Copyright IBM Corp. 2005,2007
+ * Author(s): Jan Glauber (jang@de.ibm.com)
+ * Sebastian Siewior (sebastian@breakpoint.cc> SW-Fallback
+ *
+ * Derived from "crypto/aes_generic.c"
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include "crypt_s390.h"
+
+#define AES_KEYLEN_128 1
+#define AES_KEYLEN_192 2
+#define AES_KEYLEN_256 4
+
+static char keylen_flag = 0;
+
+struct s390_aes_ctx {
+ u8 iv[AES_BLOCK_SIZE];
+ u8 key[AES_MAX_KEY_SIZE];
+ long enc;
+ long dec;
+ int key_len;
+ union {
+ struct crypto_blkcipher *blk;
+ struct crypto_cipher *cip;
+ } fallback;
+};
+
+/*
+ * Check if the key_len is supported by the HW.
+ * Returns 0 if it is, a positive number if it is not and software fallback is
+ * required or a negative number in case the key size is not valid
+ */
+static int need_fallback(unsigned int key_len)
+{
+ switch (key_len) {
+ case 16:
+ if (!(keylen_flag & AES_KEYLEN_128))
+ return 1;
+ break;
+ case 24:
+ if (!(keylen_flag & AES_KEYLEN_192))
+ return 1;
+ break;
+ case 32:
+ if (!(keylen_flag & AES_KEYLEN_256))
+ return 1;
+ break;
+ default:
+ return -1;
+ break;
+ }
+ return 0;
+}
+
+static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+ sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+ sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
+ CRYPTO_TFM_REQ_MASK);
+
+ ret = crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len);
+ if (ret) {
+ tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+ tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
+ CRYPTO_TFM_RES_MASK);
+ }
+ return ret;
+}
+
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ u32 *flags = &tfm->crt_flags;
+ int ret;
+
+ ret = need_fallback(key_len);
+ if (ret < 0) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+ sctx->key_len = key_len;
+ if (!ret) {
+ memcpy(sctx->key, in_key, key_len);
+ return 0;
+ }
+
+ return setkey_fallback_cip(tfm, in_key, key_len);
+}
+
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ if (unlikely(need_fallback(sctx->key_len))) {
+ crypto_cipher_encrypt_one(sctx->fallback.cip, out, in);
+ return;
+ }
+
+ switch (sctx->key_len) {
+ case 16:
+ crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in,
+ AES_BLOCK_SIZE);
+ break;
+ case 24:
+ crypt_s390_km(KM_AES_192_ENCRYPT, &sctx->key, out, in,
+ AES_BLOCK_SIZE);
+ break;
+ case 32:
+ crypt_s390_km(KM_AES_256_ENCRYPT, &sctx->key, out, in,
+ AES_BLOCK_SIZE);
+ break;
+ }
+}
+
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ const struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ if (unlikely(need_fallback(sctx->key_len))) {
+ crypto_cipher_decrypt_one(sctx->fallback.cip, out, in);
+ return;
+ }
+
+ switch (sctx->key_len) {
+ case 16:
+ crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in,
+ AES_BLOCK_SIZE);
+ break;
+ case 24:
+ crypt_s390_km(KM_AES_192_DECRYPT, &sctx->key, out, in,
+ AES_BLOCK_SIZE);
+ break;
+ case 32:
+ crypt_s390_km(KM_AES_256_DECRYPT, &sctx->key, out, in,
+ AES_BLOCK_SIZE);
+ break;
+ }
+}
+
+static int fallback_init_cip(struct crypto_tfm *tfm)
+{
+ const char *name = tfm->__crt_alg->cra_name;
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ sctx->fallback.cip = crypto_alloc_cipher(name, 0,
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+ if (IS_ERR(sctx->fallback.cip)) {
+ printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+ return PTR_ERR(sctx->fallback.blk);
+ }
+
+ return 0;
+}
+
+static void fallback_exit_cip(struct crypto_tfm *tfm)
+{
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ crypto_free_cipher(sctx->fallback.cip);
+ sctx->fallback.cip = NULL;
+}
+
+static struct crypto_alg aes_alg = {
+ .cra_name = "aes",
+ .cra_driver_name = "aes-s390",
+ .cra_priority = CRYPT_S390_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s390_aes_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
+ .cra_init = fallback_init_cip,
+ .cra_exit = fallback_exit_cip,
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = AES_MIN_KEY_SIZE,
+ .cia_max_keysize = AES_MAX_KEY_SIZE,
+ .cia_setkey = aes_set_key,
+ .cia_encrypt = aes_encrypt,
+ .cia_decrypt = aes_decrypt,
+ }
+ }
+};
+
+static int setkey_fallback_blk(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int len)
+{
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ unsigned int ret;
+
+ sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+ sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags &
+ CRYPTO_TFM_REQ_MASK);
+
+ ret = crypto_blkcipher_setkey(sctx->fallback.blk, key, len);
+ if (ret) {
+ tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+ tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags &
+ CRYPTO_TFM_RES_MASK);
+ }
+ return ret;
+}
+
+static int fallback_blk_dec(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ unsigned int ret;
+ struct crypto_blkcipher *tfm;
+ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+
+ tfm = desc->tfm;
+ desc->tfm = sctx->fallback.blk;
+
+ ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
+
+ desc->tfm = tfm;
+ return ret;
+}
+
+static int fallback_blk_enc(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ unsigned int ret;
+ struct crypto_blkcipher *tfm;
+ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+
+ tfm = desc->tfm;
+ desc->tfm = sctx->fallback.blk;
+
+ ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+
+ desc->tfm = tfm;
+ return ret;
+}
+
+static int ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+ ret = need_fallback(key_len);
+ if (ret > 0) {
+ sctx->key_len = key_len;
+ return setkey_fallback_blk(tfm, in_key, key_len);
+ }
+
+ switch (key_len) {
+ case 16:
+ sctx->enc = KM_AES_128_ENCRYPT;
+ sctx->dec = KM_AES_128_DECRYPT;
+ break;
+ case 24:
+ sctx->enc = KM_AES_192_ENCRYPT;
+ sctx->dec = KM_AES_192_DECRYPT;
+ break;
+ case 32:
+ sctx->enc = KM_AES_256_ENCRYPT;
+ sctx->dec = KM_AES_256_DECRYPT;
+ break;
+ }
+
+ return aes_set_key(tfm, in_key, key_len);
+}
+
+static int ecb_aes_crypt(struct blkcipher_desc *desc, long func, void *param,
+ struct blkcipher_walk *walk)
+{
+ int ret = blkcipher_walk_virt(desc, walk);
+ unsigned int nbytes;
+
+ while ((nbytes = walk->nbytes)) {
+ /* only use complete blocks */
+ unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
+ u8 *out = walk->dst.virt.addr;
+ u8 *in = walk->src.virt.addr;
+
+ ret = crypt_s390_km(func, param, out, in, n);
+ BUG_ON((ret < 0) || (ret != n));
+
+ nbytes &= AES_BLOCK_SIZE - 1;
+ ret = blkcipher_walk_done(desc, walk, nbytes);
+ }
+
+ return ret;
+}
+
+static int ecb_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ if (unlikely(need_fallback(sctx->key_len)))
+ return fallback_blk_enc(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk);
+}
+
+static int ecb_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ if (unlikely(need_fallback(sctx->key_len)))
+ return fallback_blk_dec(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk);
+}
+
+static int fallback_init_blk(struct crypto_tfm *tfm)
+{
+ const char *name = tfm->__crt_alg->cra_name;
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ sctx->fallback.blk = crypto_alloc_blkcipher(name, 0,
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+ if (IS_ERR(sctx->fallback.blk)) {
+ printk(KERN_ERR "Error allocating fallback algo %s\n", name);
+ return PTR_ERR(sctx->fallback.blk);
+ }
+
+ return 0;
+}
+
+static void fallback_exit_blk(struct crypto_tfm *tfm)
+{
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ crypto_free_blkcipher(sctx->fallback.blk);
+ sctx->fallback.blk = NULL;
+}
+
+static struct crypto_alg ecb_aes_alg = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s390_aes_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list),
+ .cra_init = fallback_init_blk,
+ .cra_exit = fallback_exit_blk,
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = ecb_aes_set_key,
+ .encrypt = ecb_aes_encrypt,
+ .decrypt = ecb_aes_decrypt,
+ }
+ }
+};
+
+static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+ ret = need_fallback(key_len);
+ if (ret > 0) {
+ sctx->key_len = key_len;
+ return setkey_fallback_blk(tfm, in_key, key_len);
+ }
+
+ switch (key_len) {
+ case 16:
+ sctx->enc = KMC_AES_128_ENCRYPT;
+ sctx->dec = KMC_AES_128_DECRYPT;
+ break;
+ case 24:
+ sctx->enc = KMC_AES_192_ENCRYPT;
+ sctx->dec = KMC_AES_192_DECRYPT;
+ break;
+ case 32:
+ sctx->enc = KMC_AES_256_ENCRYPT;
+ sctx->dec = KMC_AES_256_DECRYPT;
+ break;
+ }
+
+ return aes_set_key(tfm, in_key, key_len);
+}
+
+static int cbc_aes_crypt(struct blkcipher_desc *desc, long func, void *param,
+ struct blkcipher_walk *walk)
+{
+ int ret = blkcipher_walk_virt(desc, walk);
+ unsigned int nbytes = walk->nbytes;
+
+ if (!nbytes)
+ goto out;
+
+ memcpy(param, walk->iv, AES_BLOCK_SIZE);
+ do {
+ /* only use complete blocks */
+ unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
+ u8 *out = walk->dst.virt.addr;
+ u8 *in = walk->src.virt.addr;
+
+ ret = crypt_s390_kmc(func, param, out, in, n);
+ BUG_ON((ret < 0) || (ret != n));
+
+ nbytes &= AES_BLOCK_SIZE - 1;
+ ret = blkcipher_walk_done(desc, walk, nbytes);
+ } while ((nbytes = walk->nbytes));
+ memcpy(walk->iv, param, AES_BLOCK_SIZE);
+
+out:
+ return ret;
+}
+
+static int cbc_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ if (unlikely(need_fallback(sctx->key_len)))
+ return fallback_blk_enc(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk);
+}
+
+static int cbc_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ if (unlikely(need_fallback(sctx->key_len)))
+ return fallback_blk_dec(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk);
+}
+
+static struct crypto_alg cbc_aes_alg = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s390_aes_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list),
+ .cra_init = fallback_init_blk,
+ .cra_exit = fallback_exit_blk,
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = cbc_aes_set_key,
+ .encrypt = cbc_aes_encrypt,
+ .decrypt = cbc_aes_decrypt,
+ }
+ }
+};
+
+static int __init aes_init(void)
+{
+ int ret;
+
+ if (crypt_s390_func_available(KM_AES_128_ENCRYPT))
+ keylen_flag |= AES_KEYLEN_128;
+ if (crypt_s390_func_available(KM_AES_192_ENCRYPT))
+ keylen_flag |= AES_KEYLEN_192;
+ if (crypt_s390_func_available(KM_AES_256_ENCRYPT))
+ keylen_flag |= AES_KEYLEN_256;
+
+ if (!keylen_flag)
+ return -EOPNOTSUPP;
+
+ /* z9 109 and z9 BC/EC only support 128 bit key length */
+ if (keylen_flag == AES_KEYLEN_128)
+ printk(KERN_INFO
+ "aes_s390: hardware acceleration only available for "
+ "128 bit keys\n");
+
+ ret = crypto_register_alg(&aes_alg);
+ if (ret)
+ goto aes_err;
+
+ ret = crypto_register_alg(&ecb_aes_alg);
+ if (ret)
+ goto ecb_aes_err;
+
+ ret = crypto_register_alg(&cbc_aes_alg);
+ if (ret)
+ goto cbc_aes_err;
+
+out:
+ return ret;
+
+cbc_aes_err:
+ crypto_unregister_alg(&ecb_aes_alg);
+ecb_aes_err:
+ crypto_unregister_alg(&aes_alg);
+aes_err:
+ goto out;
+}
+
+static void __exit aes_fini(void)
+{
+ crypto_unregister_alg(&cbc_aes_alg);
+ crypto_unregister_alg(&ecb_aes_alg);
+ crypto_unregister_alg(&aes_alg);
+}
+
+module_init(aes_init);
+module_exit(aes_fini);
+
+MODULE_ALIAS("aes");
+
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
+MODULE_LICENSE("GPL");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/crypt_s390.h b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/crypt_s390.h
new file mode 100644
index 0000000000..95f5160df2
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/crypt_s390.h
@@ -0,0 +1,323 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for s390 cryptographic instructions.
+ *
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Thomas Spatzier
+ * Jan Glauber (jan.glauber@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#ifndef _CRYPTO_ARCH_S390_CRYPT_S390_H
+#define _CRYPTO_ARCH_S390_CRYPT_S390_H
+
+#include <asm/errno.h>
+
+#define CRYPT_S390_OP_MASK 0xFF00
+#define CRYPT_S390_FUNC_MASK 0x00FF
+
+#define CRYPT_S390_PRIORITY 300
+#define CRYPT_S390_COMPOSITE_PRIORITY 400
+
+/* s390 cryptographic operations */
+enum crypt_s390_operations {
+ CRYPT_S390_KM = 0x0100,
+ CRYPT_S390_KMC = 0x0200,
+ CRYPT_S390_KIMD = 0x0300,
+ CRYPT_S390_KLMD = 0x0400,
+ CRYPT_S390_KMAC = 0x0500
+};
+
+/*
+ * function codes for KM (CIPHER MESSAGE) instruction
+ * 0x80 is the decipher modifier bit
+ */
+enum crypt_s390_km_func {
+ KM_QUERY = CRYPT_S390_KM | 0x0,
+ KM_DEA_ENCRYPT = CRYPT_S390_KM | 0x1,
+ KM_DEA_DECRYPT = CRYPT_S390_KM | 0x1 | 0x80,
+ KM_TDEA_128_ENCRYPT = CRYPT_S390_KM | 0x2,
+ KM_TDEA_128_DECRYPT = CRYPT_S390_KM | 0x2 | 0x80,
+ KM_TDEA_192_ENCRYPT = CRYPT_S390_KM | 0x3,
+ KM_TDEA_192_DECRYPT = CRYPT_S390_KM | 0x3 | 0x80,
+ KM_AES_128_ENCRYPT = CRYPT_S390_KM | 0x12,
+ KM_AES_128_DECRYPT = CRYPT_S390_KM | 0x12 | 0x80,
+ KM_AES_192_ENCRYPT = CRYPT_S390_KM | 0x13,
+ KM_AES_192_DECRYPT = CRYPT_S390_KM | 0x13 | 0x80,
+ KM_AES_256_ENCRYPT = CRYPT_S390_KM | 0x14,
+ KM_AES_256_DECRYPT = CRYPT_S390_KM | 0x14 | 0x80,
+};
+
+/*
+ * function codes for KMC (CIPHER MESSAGE WITH CHAINING)
+ * instruction
+ */
+enum crypt_s390_kmc_func {
+ KMC_QUERY = CRYPT_S390_KMC | 0x0,
+ KMC_DEA_ENCRYPT = CRYPT_S390_KMC | 0x1,
+ KMC_DEA_DECRYPT = CRYPT_S390_KMC | 0x1 | 0x80,
+ KMC_TDEA_128_ENCRYPT = CRYPT_S390_KMC | 0x2,
+ KMC_TDEA_128_DECRYPT = CRYPT_S390_KMC | 0x2 | 0x80,
+ KMC_TDEA_192_ENCRYPT = CRYPT_S390_KMC | 0x3,
+ KMC_TDEA_192_DECRYPT = CRYPT_S390_KMC | 0x3 | 0x80,
+ KMC_AES_128_ENCRYPT = CRYPT_S390_KMC | 0x12,
+ KMC_AES_128_DECRYPT = CRYPT_S390_KMC | 0x12 | 0x80,
+ KMC_AES_192_ENCRYPT = CRYPT_S390_KMC | 0x13,
+ KMC_AES_192_DECRYPT = CRYPT_S390_KMC | 0x13 | 0x80,
+ KMC_AES_256_ENCRYPT = CRYPT_S390_KMC | 0x14,
+ KMC_AES_256_DECRYPT = CRYPT_S390_KMC | 0x14 | 0x80,
+ KMC_PRNG = CRYPT_S390_KMC | 0x43,
+};
+
+/*
+ * function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
+ * instruction
+ */
+enum crypt_s390_kimd_func {
+ KIMD_QUERY = CRYPT_S390_KIMD | 0,
+ KIMD_SHA_1 = CRYPT_S390_KIMD | 1,
+ KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
+};
+
+/*
+ * function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
+ * instruction
+ */
+enum crypt_s390_klmd_func {
+ KLMD_QUERY = CRYPT_S390_KLMD | 0,
+ KLMD_SHA_1 = CRYPT_S390_KLMD | 1,
+ KLMD_SHA_256 = CRYPT_S390_KLMD | 2,
+};
+
+/*
+ * function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
+ * instruction
+ */
+enum crypt_s390_kmac_func {
+ KMAC_QUERY = CRYPT_S390_KMAC | 0,
+ KMAC_DEA = CRYPT_S390_KMAC | 1,
+ KMAC_TDEA_128 = CRYPT_S390_KMAC | 2,
+ KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
+};
+
+/**
+ * crypt_s390_km:
+ * @func: the function code passed to KM; see crypt_s390_km_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Executes the KM (CIPHER MESSAGE) operation of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
+ */
+static inline int crypt_s390_km(long func, void *param,
+ u8 *dest, const u8 *src, long src_len)
+{
+ register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
+ register long __src_len asm("3") = src_len;
+ register u8 *__dest asm("4") = dest;
+ int ret;
+
+ asm volatile(
+ "0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+}
+
+/**
+ * crypt_s390_kmc:
+ * @func: the function code passed to KM; see crypt_s390_kmc_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
+ */
+static inline int crypt_s390_kmc(long func, void *param,
+ u8 *dest, const u8 *src, long src_len)
+{
+ register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
+ register long __src_len asm("3") = src_len;
+ register u8 *__dest asm("4") = dest;
+ int ret;
+
+ asm volatile(
+ "0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+}
+
+/**
+ * crypt_s390_kimd:
+ * @func: the function code passed to KM; see crypt_s390_kimd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
+ * of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
+ */
+static inline int crypt_s390_kimd(long func, void *param,
+ const u8 *src, long src_len)
+{
+ register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
+ register long __src_len asm("3") = src_len;
+ int ret;
+
+ asm volatile(
+ "0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len)
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+}
+
+/**
+ * crypt_s390_klmd:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
+ */
+static inline int crypt_s390_klmd(long func, void *param,
+ const u8 *src, long src_len)
+{
+ register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
+ register long __src_len asm("3") = src_len;
+ int ret;
+
+ asm volatile(
+ "0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len)
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+}
+
+/**
+ * crypt_s390_kmac:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
+ * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
+ * of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
+ */
+static inline int crypt_s390_kmac(long func, void *param,
+ const u8 *src, long src_len)
+{
+ register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
+ register long __src_len asm("3") = src_len;
+ int ret;
+
+ asm volatile(
+ "0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len)
+ : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+}
+
+/**
+ * crypt_s390_func_available:
+ * @func: the function code of the specific function; 0 if op in general
+ *
+ * Tests if a specific crypto function is implemented on the machine.
+ *
+ * Returns 1 if func available; 0 if func or op in general not available
+ */
+static inline int crypt_s390_func_available(int func)
+{
+ unsigned char status[16];
+ int ret;
+
+ switch (func & CRYPT_S390_OP_MASK) {
+ case CRYPT_S390_KM:
+ ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
+ break;
+ case CRYPT_S390_KMC:
+ ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
+ break;
+ case CRYPT_S390_KIMD:
+ ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
+ break;
+ case CRYPT_S390_KLMD:
+ ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
+ break;
+ case CRYPT_S390_KMAC:
+ ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
+ break;
+ default:
+ return 0;
+ }
+ if (ret < 0)
+ return 0;
+ func &= CRYPT_S390_FUNC_MASK;
+ func &= 0x7f; /* mask modifier bit */
+ return (status[func >> 3] & (0x80 >> (func & 7))) != 0;
+}
+
+#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/crypto_des.h b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/crypto_des.h
new file mode 100644
index 0000000000..c964b64111
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/crypto_des.h
@@ -0,0 +1,18 @@
+/*
+ * Cryptographic API.
+ *
+ * Function for checking keys for the DES and Tripple DES Encryption
+ * algorithms.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#ifndef __CRYPTO_DES_H__
+#define __CRYPTO_DES_H__
+
+extern int crypto_des_check_key(const u8*, unsigned int, u32*);
+
+#endif //__CRYPTO_DES_H__
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/des_check_key.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/des_check_key.c
new file mode 100644
index 0000000000..5706af2664
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/des_check_key.c
@@ -0,0 +1,132 @@
+/*
+ * Cryptographic API.
+ *
+ * Function for checking keys for the DES and Tripple DES Encryption
+ * algorithms.
+ *
+ * Originally released as descore by Dana L. How <how@isl.stanford.edu>.
+ * Modified by Raimar Falke <rf13@inf.tu-dresden.de> for the Linux-Kernel.
+ * Derived from Cryptoapi and Nettle implementations, adapted for in-place
+ * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL.
+ *
+ * s390 Version:
+ * Copyright IBM Corp. 2003
+ * Author(s): Thomas Spatzier
+ * Jan Glauber (jan.glauber@de.ibm.com)
+ *
+ * Derived from "crypto/des.c"
+ * Copyright (c) 1992 Dana L. How.
+ * Copyright (c) Raimar Falke <rf13@inf.tu-dresden.de>
+ * Copyright (c) Gisle Sflensminde <gisle@ii.uib.no>
+ * Copyright (C) 2001 Niels Mvller.
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include "crypto_des.h"
+
+#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o))
+
+static const u8 parity[] = {
+ 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3,
+ 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
+ 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
+ 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
+ 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
+ 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
+ 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
+ 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8,
+};
+
+/*
+ * RFC2451: Weak key checks SHOULD be performed.
+ */
+int
+crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags)
+{
+ u32 n, w;
+
+ n = parity[key[0]]; n <<= 4;
+ n |= parity[key[1]]; n <<= 4;
+ n |= parity[key[2]]; n <<= 4;
+ n |= parity[key[3]]; n <<= 4;
+ n |= parity[key[4]]; n <<= 4;
+ n |= parity[key[5]]; n <<= 4;
+ n |= parity[key[6]]; n <<= 4;
+ n |= parity[key[7]];
+ w = 0x88888888L;
+
+ if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY)
+ && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */
+ if (n < 0x41415151) {
+ if (n < 0x31312121) {
+ if (n < 0x14141515) {
+ /* 01 01 01 01 01 01 01 01 */
+ if (n == 0x11111111) goto weak;
+ /* 01 1F 01 1F 01 0E 01 0E */
+ if (n == 0x13131212) goto weak;
+ } else {
+ /* 01 E0 01 E0 01 F1 01 F1 */
+ if (n == 0x14141515) goto weak;
+ /* 01 FE 01 FE 01 FE 01 FE */
+ if (n == 0x16161616) goto weak;
+ }
+ } else {
+ if (n < 0x34342525) {
+ /* 1F 01 1F 01 0E 01 0E 01 */
+ if (n == 0x31312121) goto weak;
+ /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */
+ if (n == 0x33332222) goto weak;
+ } else {
+ /* 1F E0 1F E0 0E F1 0E F1 */
+ if (n == 0x34342525) goto weak;
+ /* 1F FE 1F FE 0E FE 0E FE */
+ if (n == 0x36362626) goto weak;
+ }
+ }
+ } else {
+ if (n < 0x61616161) {
+ if (n < 0x44445555) {
+ /* E0 01 E0 01 F1 01 F1 01 */
+ if (n == 0x41415151) goto weak;
+ /* E0 1F E0 1F F1 0E F1 0E */
+ if (n == 0x43435252) goto weak;
+ } else {
+ /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */
+ if (n == 0x44445555) goto weak;
+ /* E0 FE E0 FE F1 FE F1 FE */
+ if (n == 0x46465656) goto weak;
+ }
+ } else {
+ if (n < 0x64646565) {
+ /* FE 01 FE 01 FE 01 FE 01 */
+ if (n == 0x61616161) goto weak;
+ /* FE 1F FE 1F FE 0E FE 0E */
+ if (n == 0x63636262) goto weak;
+ } else {
+ /* FE E0 FE E0 FE F1 FE F1 */
+ if (n == 0x64646565) goto weak;
+ /* FE FE FE FE FE FE FE FE */
+ if (n == 0x66666666) goto weak;
+ }
+ }
+ }
+ }
+ return 0;
+weak:
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL(crypto_des_check_key);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Key Check function for DES & DES3 Cipher Algorithms");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/des_s390.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/des_s390.c
new file mode 100644
index 0000000000..ea22707f43
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/des_s390.c
@@ -0,0 +1,635 @@
+/*
+ * Cryptographic API.
+ *
+ * s390 implementation of the DES Cipher Algorithm.
+ *
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Thomas Spatzier
+ * Jan Glauber (jan.glauber@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include "crypt_s390.h"
+#include "crypto_des.h"
+
+#define DES_BLOCK_SIZE 8
+#define DES_KEY_SIZE 8
+
+#define DES3_128_KEY_SIZE (2 * DES_KEY_SIZE)
+#define DES3_128_BLOCK_SIZE DES_BLOCK_SIZE
+
+#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE)
+#define DES3_192_BLOCK_SIZE DES_BLOCK_SIZE
+
+struct crypt_s390_des_ctx {
+ u8 iv[DES_BLOCK_SIZE];
+ u8 key[DES_KEY_SIZE];
+};
+
+struct crypt_s390_des3_128_ctx {
+ u8 iv[DES_BLOCK_SIZE];
+ u8 key[DES3_128_KEY_SIZE];
+};
+
+struct crypt_s390_des3_192_ctx {
+ u8 iv[DES_BLOCK_SIZE];
+ u8 key[DES3_192_KEY_SIZE];
+};
+
+static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
+ u32 *flags = &tfm->crt_flags;
+ int ret;
+
+ /* test if key is valid (not a weak key) */
+ ret = crypto_des_check_key(key, keylen, flags);
+ if (ret == 0)
+ memcpy(dctx->key, key, keylen);
+ return ret;
+}
+
+static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
+
+ crypt_s390_km(KM_DEA_ENCRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
+}
+
+static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+ struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
+
+ crypt_s390_km(KM_DEA_DECRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
+}
+
+static struct crypto_alg des_alg = {
+ .cra_name = "des",
+ .cra_driver_name = "des-s390",
+ .cra_priority = CRYPT_S390_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(des_alg.cra_list),
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = DES_KEY_SIZE,
+ .cia_max_keysize = DES_KEY_SIZE,
+ .cia_setkey = des_setkey,
+ .cia_encrypt = des_encrypt,
+ .cia_decrypt = des_decrypt,
+ }
+ }
+};
+
+static int ecb_desall_crypt(struct blkcipher_desc *desc, long func,
+ void *param, struct blkcipher_walk *walk)
+{
+ int ret = blkcipher_walk_virt(desc, walk);
+ unsigned int nbytes;
+
+ while ((nbytes = walk->nbytes)) {
+ /* only use complete blocks */
+ unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1);
+ u8 *out = walk->dst.virt.addr;
+ u8 *in = walk->src.virt.addr;
+
+ ret = crypt_s390_km(func, param, out, in, n);
+ BUG_ON((ret < 0) || (ret != n));
+
+ nbytes &= DES_BLOCK_SIZE - 1;
+ ret = blkcipher_walk_done(desc, walk, nbytes);
+ }
+
+ return ret;
+}
+
+static int cbc_desall_crypt(struct blkcipher_desc *desc, long func,
+ void *param, struct blkcipher_walk *walk)
+{
+ int ret = blkcipher_walk_virt(desc, walk);
+ unsigned int nbytes = walk->nbytes;
+
+ if (!nbytes)
+ goto out;
+
+ memcpy(param, walk->iv, DES_BLOCK_SIZE);
+ do {
+ /* only use complete blocks */
+ unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1);
+ u8 *out = walk->dst.virt.addr;
+ u8 *in = walk->src.virt.addr;
+
+ ret = crypt_s390_kmc(func, param, out, in, n);
+ BUG_ON((ret < 0) || (ret != n));
+
+ nbytes &= DES_BLOCK_SIZE - 1;
+ ret = blkcipher_walk_done(desc, walk, nbytes);
+ } while ((nbytes = walk->nbytes));
+ memcpy(walk->iv, param, DES_BLOCK_SIZE);
+
+out:
+ return ret;
+}
+
+static int ecb_des_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ecb_desall_crypt(desc, KM_DEA_ENCRYPT, sctx->key, &walk);
+}
+
+static int ecb_des_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ecb_desall_crypt(desc, KM_DEA_DECRYPT, sctx->key, &walk);
+}
+
+static struct crypto_alg ecb_des_alg = {
+ .cra_name = "ecb(des)",
+ .cra_driver_name = "ecb-des-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = des_setkey,
+ .encrypt = ecb_des_encrypt,
+ .decrypt = ecb_des_decrypt,
+ }
+ }
+};
+
+static int cbc_des_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, sctx->iv, &walk);
+}
+
+static int cbc_des_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, sctx->iv, &walk);
+}
+
+static struct crypto_alg cbc_des_alg = {
+ .cra_name = "cbc(des)",
+ .cra_driver_name = "cbc-des-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .setkey = des_setkey,
+ .encrypt = cbc_des_encrypt,
+ .decrypt = cbc_des_decrypt,
+ }
+ }
+};
+
+/*
+ * RFC2451:
+ *
+ * For DES-EDE3, there is no known need to reject weak or
+ * complementation keys. Any weakness is obviated by the use of
+ * multiple keys.
+ *
+ * However, if the two independent 64-bit keys are equal,
+ * then the DES3 operation is simply the same as DES.
+ * Implementers MUST reject keys that exhibit this property.
+ *
+ */
+static int des3_128_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ int i, ret;
+ struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
+ const u8 *temp_key = key;
+ u32 *flags = &tfm->crt_flags;
+
+ if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
+ return -EINVAL;
+ }
+ for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) {
+ ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
+ if (ret < 0)
+ return ret;
+ }
+ memcpy(dctx->key, key, keylen);
+ return 0;
+}
+
+static void des3_128_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+ struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
+
+ crypt_s390_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src,
+ DES3_128_BLOCK_SIZE);
+}
+
+static void des3_128_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+ struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
+
+ crypt_s390_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src,
+ DES3_128_BLOCK_SIZE);
+}
+
+static struct crypto_alg des3_128_alg = {
+ .cra_name = "des3_ede128",
+ .cra_driver_name = "des3_ede128-s390",
+ .cra_priority = CRYPT_S390_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = DES3_128_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list),
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = DES3_128_KEY_SIZE,
+ .cia_max_keysize = DES3_128_KEY_SIZE,
+ .cia_setkey = des3_128_setkey,
+ .cia_encrypt = des3_128_encrypt,
+ .cia_decrypt = des3_128_decrypt,
+ }
+ }
+};
+
+static int ecb_des3_128_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ecb_desall_crypt(desc, KM_TDEA_128_ENCRYPT, sctx->key, &walk);
+}
+
+static int ecb_des3_128_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ecb_desall_crypt(desc, KM_TDEA_128_DECRYPT, sctx->key, &walk);
+}
+
+static struct crypto_alg ecb_des3_128_alg = {
+ .cra_name = "ecb(des3_ede128)",
+ .cra_driver_name = "ecb-des3_ede128-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = DES3_128_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(
+ ecb_des3_128_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = DES3_128_KEY_SIZE,
+ .max_keysize = DES3_128_KEY_SIZE,
+ .setkey = des3_128_setkey,
+ .encrypt = ecb_des3_128_encrypt,
+ .decrypt = ecb_des3_128_decrypt,
+ }
+ }
+};
+
+static int cbc_des3_128_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return cbc_desall_crypt(desc, KMC_TDEA_128_ENCRYPT, sctx->iv, &walk);
+}
+
+static int cbc_des3_128_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return cbc_desall_crypt(desc, KMC_TDEA_128_DECRYPT, sctx->iv, &walk);
+}
+
+static struct crypto_alg cbc_des3_128_alg = {
+ .cra_name = "cbc(des3_ede128)",
+ .cra_driver_name = "cbc-des3_ede128-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = DES3_128_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(
+ cbc_des3_128_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = DES3_128_KEY_SIZE,
+ .max_keysize = DES3_128_KEY_SIZE,
+ .ivsize = DES3_128_BLOCK_SIZE,
+ .setkey = des3_128_setkey,
+ .encrypt = cbc_des3_128_encrypt,
+ .decrypt = cbc_des3_128_decrypt,
+ }
+ }
+};
+
+/*
+ * RFC2451:
+ *
+ * For DES-EDE3, there is no known need to reject weak or
+ * complementation keys. Any weakness is obviated by the use of
+ * multiple keys.
+ *
+ * However, if the first two or last two independent 64-bit keys are
+ * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
+ * same as DES. Implementers MUST reject keys that exhibit this
+ * property.
+ *
+ */
+static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ int i, ret;
+ struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
+ const u8 *temp_key = key;
+ u32 *flags = &tfm->crt_flags;
+
+ if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
+ memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
+ DES_KEY_SIZE))) {
+
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
+ return -EINVAL;
+ }
+ for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
+ ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
+ if (ret < 0)
+ return ret;
+ }
+ memcpy(dctx->key, key, keylen);
+ return 0;
+}
+
+static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+ struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
+
+ crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src,
+ DES3_192_BLOCK_SIZE);
+}
+
+static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+ struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
+
+ crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src,
+ DES3_192_BLOCK_SIZE);
+}
+
+static struct crypto_alg des3_192_alg = {
+ .cra_name = "des3_ede",
+ .cra_driver_name = "des3_ede-s390",
+ .cra_priority = CRYPT_S390_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list),
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = DES3_192_KEY_SIZE,
+ .cia_max_keysize = DES3_192_KEY_SIZE,
+ .cia_setkey = des3_192_setkey,
+ .cia_encrypt = des3_192_encrypt,
+ .cia_decrypt = des3_192_decrypt,
+ }
+ }
+};
+
+static int ecb_des3_192_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ecb_desall_crypt(desc, KM_TDEA_192_ENCRYPT, sctx->key, &walk);
+}
+
+static int ecb_des3_192_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ecb_desall_crypt(desc, KM_TDEA_192_DECRYPT, sctx->key, &walk);
+}
+
+static struct crypto_alg ecb_des3_192_alg = {
+ .cra_name = "ecb(des3_ede)",
+ .cra_driver_name = "ecb-des3_ede-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(
+ ecb_des3_192_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = DES3_192_KEY_SIZE,
+ .max_keysize = DES3_192_KEY_SIZE,
+ .setkey = des3_192_setkey,
+ .encrypt = ecb_des3_192_encrypt,
+ .decrypt = ecb_des3_192_decrypt,
+ }
+ }
+};
+
+static int cbc_des3_192_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, sctx->iv, &walk);
+}
+
+static int cbc_des3_192_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src, unsigned int nbytes)
+{
+ struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, sctx->iv, &walk);
+}
+
+static struct crypto_alg cbc_des3_192_alg = {
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "cbc-des3_ede-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(
+ cbc_des3_192_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = DES3_192_KEY_SIZE,
+ .max_keysize = DES3_192_KEY_SIZE,
+ .ivsize = DES3_192_BLOCK_SIZE,
+ .setkey = des3_192_setkey,
+ .encrypt = cbc_des3_192_encrypt,
+ .decrypt = cbc_des3_192_decrypt,
+ }
+ }
+};
+
+static int init(void)
+{
+ int ret = 0;
+
+ if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
+ !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
+ !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
+ return -EOPNOTSUPP;
+
+ ret = crypto_register_alg(&des_alg);
+ if (ret)
+ goto des_err;
+ ret = crypto_register_alg(&ecb_des_alg);
+ if (ret)
+ goto ecb_des_err;
+ ret = crypto_register_alg(&cbc_des_alg);
+ if (ret)
+ goto cbc_des_err;
+
+ ret = crypto_register_alg(&des3_128_alg);
+ if (ret)
+ goto des3_128_err;
+ ret = crypto_register_alg(&ecb_des3_128_alg);
+ if (ret)
+ goto ecb_des3_128_err;
+ ret = crypto_register_alg(&cbc_des3_128_alg);
+ if (ret)
+ goto cbc_des3_128_err;
+
+ ret = crypto_register_alg(&des3_192_alg);
+ if (ret)
+ goto des3_192_err;
+ ret = crypto_register_alg(&ecb_des3_192_alg);
+ if (ret)
+ goto ecb_des3_192_err;
+ ret = crypto_register_alg(&cbc_des3_192_alg);
+ if (ret)
+ goto cbc_des3_192_err;
+
+out:
+ return ret;
+
+cbc_des3_192_err:
+ crypto_unregister_alg(&ecb_des3_192_alg);
+ecb_des3_192_err:
+ crypto_unregister_alg(&des3_192_alg);
+des3_192_err:
+ crypto_unregister_alg(&cbc_des3_128_alg);
+cbc_des3_128_err:
+ crypto_unregister_alg(&ecb_des3_128_alg);
+ecb_des3_128_err:
+ crypto_unregister_alg(&des3_128_alg);
+des3_128_err:
+ crypto_unregister_alg(&cbc_des_alg);
+cbc_des_err:
+ crypto_unregister_alg(&ecb_des_alg);
+ecb_des_err:
+ crypto_unregister_alg(&des_alg);
+des_err:
+ goto out;
+}
+
+static void __exit fini(void)
+{
+ crypto_unregister_alg(&cbc_des3_192_alg);
+ crypto_unregister_alg(&ecb_des3_192_alg);
+ crypto_unregister_alg(&des3_192_alg);
+ crypto_unregister_alg(&cbc_des3_128_alg);
+ crypto_unregister_alg(&ecb_des3_128_alg);
+ crypto_unregister_alg(&des3_128_alg);
+ crypto_unregister_alg(&cbc_des_alg);
+ crypto_unregister_alg(&ecb_des_alg);
+ crypto_unregister_alg(&des_alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_ALIAS("des");
+MODULE_ALIAS("des3_ede");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/prng.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/prng.c
new file mode 100644
index 0000000000..0cfefddd83
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/prng.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright IBM Corp. 2006,2007
+ * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
+ * Driver for the s390 pseudo random number generator
+ */
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/random.h>
+#include <asm/debug.h>
+#include <asm/uaccess.h>
+
+#include "crypt_s390.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>");
+MODULE_DESCRIPTION("s390 PRNG interface");
+
+static int prng_chunk_size = 256;
+module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes");
+
+static int prng_entropy_limit = 4096;
+module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
+MODULE_PARM_DESC(prng_entropy_limit,
+ "PRNG add entropy after that much bytes were produced");
+
+/*
+ * Any one who considers arithmetical methods of producing random digits is,
+ * of course, in a state of sin. -- John von Neumann
+ */
+
+struct s390_prng_data {
+ unsigned long count; /* how many bytes were produced */
+ char *buf;
+};
+
+static struct s390_prng_data *p;
+
+/* copied from libica, use a non-zero initial parameter block */
+static unsigned char parm_block[32] = {
+0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4,
+0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0,
+};
+
+static int prng_open(struct inode *inode, struct file *file)
+{
+ return nonseekable_open(inode, file);
+}
+
+static void prng_add_entropy(void)
+{
+ __u64 entropy[4];
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < 16; i++) {
+ ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy,
+ (char *)entropy, sizeof(entropy));
+ BUG_ON(ret < 0 || ret != sizeof(entropy));
+ memcpy(parm_block, entropy, sizeof(entropy));
+ }
+}
+
+static void prng_seed(int nbytes)
+{
+ char buf[16];
+ int i = 0;
+
+ BUG_ON(nbytes > 16);
+ get_random_bytes(buf, nbytes);
+
+ /* Add the entropy */
+ while (nbytes >= 8) {
+ *((__u64 *)parm_block) ^= *((__u64 *)buf+i*8);
+ prng_add_entropy();
+ i += 8;
+ nbytes -= 8;
+ }
+ prng_add_entropy();
+}
+
+static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
+ loff_t *ppos)
+{
+ int chunk, n;
+ int ret = 0;
+ int tmp;
+
+ /* nbytes can be arbitrary length, we split it into chunks */
+ while (nbytes) {
+ /* same as in extract_entropy_user in random.c */
+ if (need_resched()) {
+ if (signal_pending(current)) {
+ if (ret == 0)
+ ret = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+
+ /*
+ * we lose some random bytes if an attacker issues
+ * reads < 8 bytes, but we don't care
+ */
+ chunk = min_t(int, nbytes, prng_chunk_size);
+
+ /* PRNG only likes multiples of 8 bytes */
+ n = (chunk + 7) & -8;
+
+ if (p->count > prng_entropy_limit)
+ prng_seed(8);
+
+ /* if the CPU supports PRNG stckf is present too */
+ asm volatile(".insn s,0xb27c0000,%0"
+ : "=m" (*((unsigned long long *)p->buf)) : : "cc");
+
+ /*
+ * Beside the STCKF the input for the TDES-EDE is the output
+ * of the last operation. We differ here from X9.17 since we
+ * only store one timestamp into the buffer. Padding the whole
+ * buffer with timestamps does not improve security, since
+ * successive stckf have nearly constant offsets.
+ * If an attacker knows the first timestamp it would be
+ * trivial to guess the additional values. One timestamp
+ * is therefore enough and still guarantees unique input values.
+ *
+ * Note: you can still get strict X9.17 conformity by setting
+ * prng_chunk_size to 8 bytes.
+ */
+ tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n);
+ BUG_ON((tmp < 0) || (tmp != n));
+
+ p->count += n;
+
+ if (copy_to_user(ubuf, p->buf, chunk))
+ return -EFAULT;
+
+ nbytes -= chunk;
+ ret += chunk;
+ ubuf += chunk;
+ }
+ return ret;
+}
+
+static const struct file_operations prng_fops = {
+ .owner = THIS_MODULE,
+ .open = &prng_open,
+ .release = NULL,
+ .read = &prng_read,
+};
+
+static struct miscdevice prng_dev = {
+ .name = "prandom",
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &prng_fops,
+};
+
+static int __init prng_init(void)
+{
+ int ret;
+
+ /* check if the CPU has a PRNG */
+ if (!crypt_s390_func_available(KMC_PRNG))
+ return -EOPNOTSUPP;
+
+ if (prng_chunk_size < 8)
+ return -EINVAL;
+
+ p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+ p->count = 0;
+
+ p->buf = kmalloc(prng_chunk_size, GFP_KERNEL);
+ if (!p->buf) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ /* initialize the PRNG, add 128 bits of entropy */
+ prng_seed(16);
+
+ ret = misc_register(&prng_dev);
+ if (ret) {
+ printk(KERN_WARNING
+ "Could not register misc device for PRNG.\n");
+ goto out_buf;
+ }
+ return 0;
+
+out_buf:
+ kfree(p->buf);
+out_free:
+ kfree(p);
+ return ret;
+}
+
+static void __exit prng_exit(void)
+{
+ /* wipe me */
+ memset(p->buf, 0, prng_chunk_size);
+ kfree(p->buf);
+ kfree(p);
+
+ misc_deregister(&prng_dev);
+}
+
+module_init(prng_init);
+module_exit(prng_exit);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/sha1_s390.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/sha1_s390.c
new file mode 100644
index 0000000000..5a834f6578
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/sha1_s390.c
@@ -0,0 +1,159 @@
+/*
+ * Cryptographic API.
+ *
+ * s390 implementation of the SHA1 Secure Hash Algorithm.
+ *
+ * Derived from cryptoapi implementation, adapted for in-place
+ * scatterlist interface. Originally based on the public domain
+ * implementation written by Steve Reid.
+ *
+ * s390 Version:
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Thomas Spatzier
+ * Jan Glauber (jan.glauber@de.ibm.com)
+ *
+ * Derived from "crypto/sha1_generic.c"
+ * Copyright (c) Alan Smithee.
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <crypto/sha.h>
+
+#include "crypt_s390.h"
+
+struct s390_sha1_ctx {
+ u64 count; /* message length */
+ u32 state[5];
+ u8 buf[2 * SHA1_BLOCK_SIZE];
+};
+
+static void sha1_init(struct crypto_tfm *tfm)
+{
+ struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ sctx->state[0] = SHA1_H0;
+ sctx->state[1] = SHA1_H1;
+ sctx->state[2] = SHA1_H2;
+ sctx->state[3] = SHA1_H3;
+ sctx->state[4] = SHA1_H4;
+ sctx->count = 0;
+}
+
+static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
+ unsigned int len)
+{
+ struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+ unsigned int index;
+ int ret;
+
+ /* how much is already in the buffer? */
+ index = sctx->count & 0x3f;
+
+ sctx->count += len;
+
+ if (index + len < SHA1_BLOCK_SIZE)
+ goto store;
+
+ /* process one stored block */
+ if (index) {
+ memcpy(sctx->buf + index, data, SHA1_BLOCK_SIZE - index);
+ ret = crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buf,
+ SHA1_BLOCK_SIZE);
+ BUG_ON(ret != SHA1_BLOCK_SIZE);
+ data += SHA1_BLOCK_SIZE - index;
+ len -= SHA1_BLOCK_SIZE - index;
+ }
+
+ /* process as many blocks as possible */
+ if (len >= SHA1_BLOCK_SIZE) {
+ ret = crypt_s390_kimd(KIMD_SHA_1, sctx->state, data,
+ len & ~(SHA1_BLOCK_SIZE - 1));
+ BUG_ON(ret != (len & ~(SHA1_BLOCK_SIZE - 1)));
+ data += ret;
+ len -= ret;
+ }
+
+store:
+ /* anything left? */
+ if (len)
+ memcpy(sctx->buf + index , data, len);
+}
+
+/* Add padding and return the message digest. */
+static void sha1_final(struct crypto_tfm *tfm, u8 *out)
+{
+ struct s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+ u64 bits;
+ unsigned int index, end;
+ int ret;
+
+ /* must perform manual padding */
+ index = sctx->count & 0x3f;
+ end = (index < 56) ? SHA1_BLOCK_SIZE : (2 * SHA1_BLOCK_SIZE);
+
+ /* start pad with 1 */
+ sctx->buf[index] = 0x80;
+
+ /* pad with zeros */
+ index++;
+ memset(sctx->buf + index, 0x00, end - index - 8);
+
+ /* append message length */
+ bits = sctx->count * 8;
+ memcpy(sctx->buf + end - 8, &bits, sizeof(bits));
+
+ ret = crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buf, end);
+ BUG_ON(ret != end);
+
+ /* copy digest to out */
+ memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
+
+ /* wipe context */
+ memset(sctx, 0, sizeof *sctx);
+}
+
+static struct crypto_alg alg = {
+ .cra_name = "sha1",
+ .cra_driver_name= "sha1-s390",
+ .cra_priority = CRYPT_S390_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s390_sha1_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(alg.cra_list),
+ .cra_u = { .digest = {
+ .dia_digestsize = SHA1_DIGEST_SIZE,
+ .dia_init = sha1_init,
+ .dia_update = sha1_update,
+ .dia_final = sha1_final } }
+};
+
+static int __init init(void)
+{
+ if (!crypt_s390_func_available(KIMD_SHA_1))
+ return -EOPNOTSUPP;
+
+ return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+ crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_ALIAS("sha1");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/sha256_s390.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/sha256_s390.c
new file mode 100644
index 0000000000..ccf8633c4f
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/crypto/sha256_s390.c
@@ -0,0 +1,155 @@
+/*
+ * Cryptographic API.
+ *
+ * s390 implementation of the SHA256 Secure Hash Algorithm.
+ *
+ * s390 Version:
+ * Copyright IBM Corp. 2005,2007
+ * Author(s): Jan Glauber (jang@de.ibm.com)
+ *
+ * Derived from "crypto/sha256_generic.c"
+ * and "arch/s390/crypto/sha1_s390.c"
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <crypto/sha.h>
+
+#include "crypt_s390.h"
+
+struct s390_sha256_ctx {
+ u64 count; /* message length */
+ u32 state[8];
+ u8 buf[2 * SHA256_BLOCK_SIZE];
+};
+
+static void sha256_init(struct crypto_tfm *tfm)
+{
+ struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ sctx->state[0] = SHA256_H0;
+ sctx->state[1] = SHA256_H1;
+ sctx->state[2] = SHA256_H2;
+ sctx->state[3] = SHA256_H3;
+ sctx->state[4] = SHA256_H4;
+ sctx->state[5] = SHA256_H5;
+ sctx->state[6] = SHA256_H6;
+ sctx->state[7] = SHA256_H7;
+ sctx->count = 0;
+}
+
+static void sha256_update(struct crypto_tfm *tfm, const u8 *data,
+ unsigned int len)
+{
+ struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+ unsigned int index;
+ int ret;
+
+ /* how much is already in the buffer? */
+ index = sctx->count & 0x3f;
+
+ sctx->count += len;
+
+ if ((index + len) < SHA256_BLOCK_SIZE)
+ goto store;
+
+ /* process one stored block */
+ if (index) {
+ memcpy(sctx->buf + index, data, SHA256_BLOCK_SIZE - index);
+ ret = crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf,
+ SHA256_BLOCK_SIZE);
+ BUG_ON(ret != SHA256_BLOCK_SIZE);
+ data += SHA256_BLOCK_SIZE - index;
+ len -= SHA256_BLOCK_SIZE - index;
+ }
+
+ /* process as many blocks as possible */
+ if (len >= SHA256_BLOCK_SIZE) {
+ ret = crypt_s390_kimd(KIMD_SHA_256, sctx->state, data,
+ len & ~(SHA256_BLOCK_SIZE - 1));
+ BUG_ON(ret != (len & ~(SHA256_BLOCK_SIZE - 1)));
+ data += ret;
+ len -= ret;
+ }
+
+store:
+ /* anything left? */
+ if (len)
+ memcpy(sctx->buf + index , data, len);
+}
+
+/* Add padding and return the message digest */
+static void sha256_final(struct crypto_tfm *tfm, u8 *out)
+{
+ struct s390_sha256_ctx *sctx = crypto_tfm_ctx(tfm);
+ u64 bits;
+ unsigned int index, end;
+ int ret;
+
+ /* must perform manual padding */
+ index = sctx->count & 0x3f;
+ end = (index < 56) ? SHA256_BLOCK_SIZE : (2 * SHA256_BLOCK_SIZE);
+
+ /* start pad with 1 */
+ sctx->buf[index] = 0x80;
+
+ /* pad with zeros */
+ index++;
+ memset(sctx->buf + index, 0x00, end - index - 8);
+
+ /* append message length */
+ bits = sctx->count * 8;
+ memcpy(sctx->buf + end - 8, &bits, sizeof(bits));
+
+ ret = crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf, end);
+ BUG_ON(ret != end);
+
+ /* copy digest to out */
+ memcpy(out, sctx->state, SHA256_DIGEST_SIZE);
+
+ /* wipe context */
+ memset(sctx, 0, sizeof *sctx);
+}
+
+static struct crypto_alg alg = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-s390",
+ .cra_priority = CRYPT_S390_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s390_sha256_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(alg.cra_list),
+ .cra_u = { .digest = {
+ .dia_digestsize = SHA256_DIGEST_SIZE,
+ .dia_init = sha256_init,
+ .dia_update = sha256_update,
+ .dia_final = sha256_final } }
+};
+
+static int init(void)
+{
+ if (!crypt_s390_func_available(KIMD_SHA_256))
+ return -EOPNOTSUPP;
+
+ return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+ crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_ALIAS("sha256");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/defconfig b/cleopatre/linux-2.6.25.10-spc300/arch/s390/defconfig
new file mode 100644
index 0000000000..62f6b5a606
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/defconfig
@@ -0,0 +1,847 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.25-rc4
+# Wed Mar 5 11:22:59 2008
+#
+CONFIG_MMU=y
+CONFIG_ZONE_DMA=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_BUG=y
+CONFIG_NO_IOMEM=y
+CONFIG_NO_DMA=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_S390=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_NS=y
+# CONFIG_CPUSETS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_RESOURCE_COUNTERS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLOCK_COMPAT=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+
+#
+# Base setup
+#
+
+#
+# Processor type and features
+#
+CONFIG_64BIT=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=32
+CONFIG_HOTPLUG_CPU=y
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_S390_SWITCH_AMODE=y
+CONFIG_S390_EXEC_PROTECT=y
+
+#
+# Code generation options
+#
+# CONFIG_MARCH_G5 is not set
+CONFIG_MARCH_Z900=y
+# CONFIG_MARCH_Z990 is not set
+# CONFIG_MARCH_Z9_109 is not set
+CONFIG_PACK_STACK=y
+# CONFIG_SMALL_STACK is not set
+CONFIG_CHECK_STACK=y
+CONFIG_STACK_GUARD=256
+# CONFIG_WARN_STACK is not set
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+
+#
+# Kernel preemption
+#
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+# CONFIG_RCU_TRACE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+
+#
+# I/O subsystem configuration
+#
+CONFIG_MACHCHK_WARNING=y
+CONFIG_QDIO=y
+# CONFIG_QDIO_DEBUG is not set
+
+#
+# Misc
+#
+CONFIG_IPL=y
+# CONFIG_IPL_TAPE is not set
+CONFIG_IPL_VM=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_FORCE_MAX_ZONEORDER=9
+# CONFIG_PROCESS_DEBUG is not set
+CONFIG_PFAULT=y
+# CONFIG_SHARED_KERNEL is not set
+# CONFIG_CMM is not set
+CONFIG_VIRT_TIMER=y
+CONFIG_VIRT_CPU_ACCOUNTING=y
+# CONFIG_APPLDATA_BASE is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_NO_IDLE_HZ=y
+CONFIG_NO_IDLE_HZ_INIT=y
+CONFIG_S390_HYPFS_FS=y
+CONFIG_KEXEC=y
+# CONFIG_ZFCPDUMP is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_IUCV=m
+CONFIG_AFIUCV=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=m
+# CONFIG_NF_CT_ACCT is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_CONNTRACK_IPV4 is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP_DCCP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RR=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_INGRESS is not set
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+# CONFIG_NET_EMATCH is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+CONFIG_NET_ACT_NAT=m
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_SCH_FIFO=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=m
+# CONFIG_CAN_DEBUG_DEVICES is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_PCMCIA is not set
+CONFIG_CCW=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+CONFIG_SYS_HYPERVISOR=y
+# CONFIG_CONNECTOR is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_XIP=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# S/390 block device drivers
+#
+CONFIG_BLK_DEV_XPRAM=m
+# CONFIG_DCSSBLK is not set
+CONFIG_DASD=y
+CONFIG_DASD_PROFILE=y
+CONFIG_DASD_ECKD=y
+CONFIG_DASD_FBA=y
+CONFIG_DASD_DIAG=y
+CONFIG_DASD_EER=y
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HAVE_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_NETLINK=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_ZFCP=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+# CONFIG_MD_RAID456 is not set
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=y
+CONFIG_DM_SNAPSHOT=y
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
+CONFIG_DM_MULTIPATH=y
+# CONFIG_DM_MULTIPATH_EMC is not set
+# CONFIG_DM_MULTIPATH_RDAC is not set
+# CONFIG_DM_MULTIPATH_HP is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_IFB is not set
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+CONFIG_VETH=m
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_E1000E_ENABLED is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_TR is not set
+# CONFIG_WAN is not set
+
+#
+# S/390 network device drivers
+#
+CONFIG_LCS=m
+CONFIG_CTC=m
+# CONFIG_NETIUCV is not set
+# CONFIG_SMSGIUCV is not set
+# CONFIG_CLAW is not set
+CONFIG_QETH=y
+
+#
+# Gigabit Ethernet default settings
+#
+# CONFIG_QETH_IPV6 is not set
+CONFIG_CCWGROUP=y
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_HW_RANDOM=m
+# CONFIG_R3964 is not set
+CONFIG_RAW_DRIVER=m
+CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# S/390 character device drivers
+#
+CONFIG_TN3270=y
+CONFIG_TN3270_TTY=y
+CONFIG_TN3270_FS=m
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
+CONFIG_CCW_CONSOLE=y
+CONFIG_SCLP_TTY=y
+CONFIG_SCLP_CONSOLE=y
+CONFIG_SCLP_VT220_TTY=y
+CONFIG_SCLP_VT220_CONSOLE=y
+CONFIG_SCLP_CPI=m
+CONFIG_S390_TAPE=m
+
+#
+# S/390 tape interface support
+#
+CONFIG_S390_TAPE_BLOCK=y
+
+#
+# S/390 tape hardware support
+#
+CONFIG_S390_TAPE_34XX=m
+# CONFIG_S390_TAPE_3590 is not set
+# CONFIG_VMLOGRDR is not set
+# CONFIG_VMCP is not set
+# CONFIG_MONREADER is not set
+CONFIG_MONWRITER=m
+CONFIG_S390_VMUR=m
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_MEMSTICK is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_IBM_PARTITION=y
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_NLS is not set
+CONFIG_DLM=m
+# CONFIG_DLM_DEBUG is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SAMPLES=y
+# CONFIG_SAMPLE_KOBJECT is not set
+# CONFIG_SAMPLE_KPROBES is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_SEQIV=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_XTS is not set
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_CCM=m
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_DES is not set
+CONFIG_CRYPTO_FCRYPT=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SALSA20=m
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+CONFIG_CRYPTO_CAMELLIA=m
+# CONFIG_CRYPTO_TEST is not set
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRYPTO_HW=y
+CONFIG_ZCRYPT=m
+# CONFIG_ZCRYPT_MONOLITHIC is not set
+# CONFIG_CRYPTO_SHA1_S390 is not set
+# CONFIG_CRYPTO_SHA256_S390 is not set
+# CONFIG_CRYPTO_DES_S390 is not set
+# CONFIG_CRYPTO_AES_S390 is not set
+CONFIG_S390_PRNG=m
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=m
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=m
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+CONFIG_PLIST=y
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/Makefile
new file mode 100644
index 0000000000..b08d2abf61
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the linux hypfs filesystem routines.
+#
+
+obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
+
+s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs.h b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs.h
new file mode 100644
index 0000000000..aea572009d
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs.h
@@ -0,0 +1,39 @@
+/*
+ * arch/s390/hypfs/hypfs.h
+ * Hypervisor filesystem for Linux on s390.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#ifndef _HYPFS_H_
+#define _HYPFS_H_
+
+#include <linux/fs.h>
+#include <linux/types.h>
+
+#define REG_FILE_MODE 0440
+#define UPDATE_FILE_MODE 0220
+#define DIR_MODE 0550
+
+extern struct dentry *hypfs_mkdir(struct super_block *sb, struct dentry *parent,
+ const char *name);
+
+extern struct dentry *hypfs_create_u64(struct super_block *sb,
+ struct dentry *dir, const char *name,
+ __u64 value);
+
+extern struct dentry *hypfs_create_str(struct super_block *sb,
+ struct dentry *dir, const char *name,
+ char *string);
+
+/* LPAR Hypervisor */
+extern int hypfs_diag_init(void);
+extern void hypfs_diag_exit(void);
+extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
+
+/* VM Hypervisor */
+extern int hypfs_vm_init(void);
+extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root);
+
+#endif /* _HYPFS_H_ */
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs_diag.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs_diag.c
new file mode 100644
index 0000000000..b9a1ce1f28
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs_diag.c
@@ -0,0 +1,703 @@
+/*
+ * arch/s390/hypfs/hypfs_diag.c
+ * Hypervisor filesystem for Linux on s390. Diag 204 and 224
+ * implementation.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <asm/ebcdic.h>
+#include "hypfs.h"
+
+#define LPAR_NAME_LEN 8 /* lpar name len in diag 204 data */
+#define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */
+#define TMP_SIZE 64 /* size of temporary buffers */
+
+/* diag 204 subcodes */
+enum diag204_sc {
+ SUBC_STIB4 = 4,
+ SUBC_RSI = 5,
+ SUBC_STIB6 = 6,
+ SUBC_STIB7 = 7
+};
+
+/* The two available diag 204 data formats */
+enum diag204_format {
+ INFO_SIMPLE = 0,
+ INFO_EXT = 0x00010000
+};
+
+/* bit is set in flags, when physical cpu info is included in diag 204 data */
+#define LPAR_PHYS_FLG 0x80
+
+static char *diag224_cpu_names; /* diag 224 name table */
+static enum diag204_sc diag204_store_sc; /* used subcode for store */
+static enum diag204_format diag204_info_type; /* used diag 204 data format */
+
+static void *diag204_buf; /* 4K aligned buffer for diag204 data */
+static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */
+static int diag204_buf_pages; /* number of pages for diag204 data */
+
+/*
+ * DIAG 204 data structures and member access functions.
+ *
+ * Since we have two different diag 204 data formats for old and new s390
+ * machines, we do not access the structs directly, but use getter functions for
+ * each struct member instead. This should make the code more readable.
+ */
+
+/* Time information block */
+
+struct info_blk_hdr {
+ __u8 npar;
+ __u8 flags;
+ __u16 tslice;
+ __u16 phys_cpus;
+ __u16 this_part;
+ __u64 curtod;
+} __attribute__ ((packed));
+
+struct x_info_blk_hdr {
+ __u8 npar;
+ __u8 flags;
+ __u16 tslice;
+ __u16 phys_cpus;
+ __u16 this_part;
+ __u64 curtod1;
+ __u64 curtod2;
+ char reserved[40];
+} __attribute__ ((packed));
+
+static inline int info_blk_hdr__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct info_blk_hdr);
+ else /* INFO_EXT */
+ return sizeof(struct x_info_blk_hdr);
+}
+
+static inline __u8 info_blk_hdr__npar(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct info_blk_hdr *)hdr)->npar;
+ else /* INFO_EXT */
+ return ((struct x_info_blk_hdr *)hdr)->npar;
+}
+
+static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct info_blk_hdr *)hdr)->flags;
+ else /* INFO_EXT */
+ return ((struct x_info_blk_hdr *)hdr)->flags;
+}
+
+static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct info_blk_hdr *)hdr)->phys_cpus;
+ else /* INFO_EXT */
+ return ((struct x_info_blk_hdr *)hdr)->phys_cpus;
+}
+
+/* Partition header */
+
+struct part_hdr {
+ __u8 pn;
+ __u8 cpus;
+ char reserved[6];
+ char part_name[LPAR_NAME_LEN];
+} __attribute__ ((packed));
+
+struct x_part_hdr {
+ __u8 pn;
+ __u8 cpus;
+ __u8 rcpus;
+ __u8 pflag;
+ __u32 mlu;
+ char part_name[LPAR_NAME_LEN];
+ char lpc_name[8];
+ char os_name[8];
+ __u64 online_cs;
+ __u64 online_es;
+ __u8 upid;
+ char reserved1[3];
+ __u32 group_mlu;
+ char group_name[8];
+ char reserved2[32];
+} __attribute__ ((packed));
+
+static inline int part_hdr__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct part_hdr);
+ else /* INFO_EXT */
+ return sizeof(struct x_part_hdr);
+}
+
+static inline __u8 part_hdr__rcpus(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct part_hdr *)hdr)->cpus;
+ else /* INFO_EXT */
+ return ((struct x_part_hdr *)hdr)->rcpus;
+}
+
+static inline void part_hdr__part_name(enum diag204_format type, void *hdr,
+ char *name)
+{
+ if (type == INFO_SIMPLE)
+ memcpy(name, ((struct part_hdr *)hdr)->part_name,
+ LPAR_NAME_LEN);
+ else /* INFO_EXT */
+ memcpy(name, ((struct x_part_hdr *)hdr)->part_name,
+ LPAR_NAME_LEN);
+ EBCASC(name, LPAR_NAME_LEN);
+ name[LPAR_NAME_LEN] = 0;
+ strstrip(name);
+}
+
+struct cpu_info {
+ __u16 cpu_addr;
+ char reserved1[2];
+ __u8 ctidx;
+ __u8 cflag;
+ __u16 weight;
+ __u64 acc_time;
+ __u64 lp_time;
+} __attribute__ ((packed));
+
+struct x_cpu_info {
+ __u16 cpu_addr;
+ char reserved1[2];
+ __u8 ctidx;
+ __u8 cflag;
+ __u16 weight;
+ __u64 acc_time;
+ __u64 lp_time;
+ __u16 min_weight;
+ __u16 cur_weight;
+ __u16 max_weight;
+ char reseved2[2];
+ __u64 online_time;
+ __u64 wait_time;
+ __u32 pma_weight;
+ __u32 polar_weight;
+ char reserved3[40];
+} __attribute__ ((packed));
+
+/* CPU info block */
+
+static inline int cpu_info__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct cpu_info);
+ else /* INFO_EXT */
+ return sizeof(struct x_cpu_info);
+}
+
+static inline __u8 cpu_info__ctidx(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct cpu_info *)hdr)->ctidx;
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->ctidx;
+}
+
+static inline __u16 cpu_info__cpu_addr(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct cpu_info *)hdr)->cpu_addr;
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->cpu_addr;
+}
+
+static inline __u64 cpu_info__acc_time(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct cpu_info *)hdr)->acc_time;
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->acc_time;
+}
+
+static inline __u64 cpu_info__lp_time(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct cpu_info *)hdr)->lp_time;
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->lp_time;
+}
+
+static inline __u64 cpu_info__online_time(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return 0; /* online_time not available in simple info */
+ else /* INFO_EXT */
+ return ((struct x_cpu_info *)hdr)->online_time;
+}
+
+/* Physical header */
+
+struct phys_hdr {
+ char reserved1[1];
+ __u8 cpus;
+ char reserved2[6];
+ char mgm_name[8];
+} __attribute__ ((packed));
+
+struct x_phys_hdr {
+ char reserved1[1];
+ __u8 cpus;
+ char reserved2[6];
+ char mgm_name[8];
+ char reserved3[80];
+} __attribute__ ((packed));
+
+static inline int phys_hdr__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct phys_hdr);
+ else /* INFO_EXT */
+ return sizeof(struct x_phys_hdr);
+}
+
+static inline __u8 phys_hdr__cpus(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct phys_hdr *)hdr)->cpus;
+ else /* INFO_EXT */
+ return ((struct x_phys_hdr *)hdr)->cpus;
+}
+
+/* Physical CPU info block */
+
+struct phys_cpu {
+ __u16 cpu_addr;
+ char reserved1[2];
+ __u8 ctidx;
+ char reserved2[3];
+ __u64 mgm_time;
+ char reserved3[8];
+} __attribute__ ((packed));
+
+struct x_phys_cpu {
+ __u16 cpu_addr;
+ char reserved1[2];
+ __u8 ctidx;
+ char reserved2[3];
+ __u64 mgm_time;
+ char reserved3[80];
+} __attribute__ ((packed));
+
+static inline int phys_cpu__size(enum diag204_format type)
+{
+ if (type == INFO_SIMPLE)
+ return sizeof(struct phys_cpu);
+ else /* INFO_EXT */
+ return sizeof(struct x_phys_cpu);
+}
+
+static inline __u16 phys_cpu__cpu_addr(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct phys_cpu *)hdr)->cpu_addr;
+ else /* INFO_EXT */
+ return ((struct x_phys_cpu *)hdr)->cpu_addr;
+}
+
+static inline __u64 phys_cpu__mgm_time(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct phys_cpu *)hdr)->mgm_time;
+ else /* INFO_EXT */
+ return ((struct x_phys_cpu *)hdr)->mgm_time;
+}
+
+static inline __u64 phys_cpu__ctidx(enum diag204_format type, void *hdr)
+{
+ if (type == INFO_SIMPLE)
+ return ((struct phys_cpu *)hdr)->ctidx;
+ else /* INFO_EXT */
+ return ((struct x_phys_cpu *)hdr)->ctidx;
+}
+
+/* Diagnose 204 functions */
+
+static int diag204(unsigned long subcode, unsigned long size, void *addr)
+{
+ register unsigned long _subcode asm("0") = subcode;
+ register unsigned long _size asm("1") = size;
+
+ asm volatile(
+ " diag %2,%0,0x204\n"
+ "0:\n"
+ EX_TABLE(0b,0b)
+ : "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory");
+ if (_subcode)
+ return -1;
+ return _size;
+}
+
+/*
+ * For the old diag subcode 4 with simple data format we have to use real
+ * memory. If we use subcode 6 or 7 with extended data format, we can (and
+ * should) use vmalloc, since we need a lot of memory in that case. Currently
+ * up to 93 pages!
+ */
+
+static void diag204_free_buffer(void)
+{
+ if (!diag204_buf)
+ return;
+ if (diag204_buf_vmalloc) {
+ vfree(diag204_buf_vmalloc);
+ diag204_buf_vmalloc = NULL;
+ } else {
+ free_pages((unsigned long) diag204_buf, 0);
+ }
+ diag204_buf_pages = 0;
+ diag204_buf = NULL;
+}
+
+static void *diag204_alloc_vbuf(int pages)
+{
+ /* The buffer has to be page aligned! */
+ diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1));
+ if (!diag204_buf_vmalloc)
+ return ERR_PTR(-ENOMEM);
+ diag204_buf = (void*)((unsigned long)diag204_buf_vmalloc
+ & ~0xfffUL) + 0x1000;
+ diag204_buf_pages = pages;
+ return diag204_buf;
+}
+
+static void *diag204_alloc_rbuf(void)
+{
+ diag204_buf = (void*)__get_free_pages(GFP_KERNEL,0);
+ if (!diag204_buf)
+ return ERR_PTR(-ENOMEM);
+ diag204_buf_pages = 1;
+ return diag204_buf;
+}
+
+static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
+{
+ if (diag204_buf) {
+ *pages = diag204_buf_pages;
+ return diag204_buf;
+ }
+ if (fmt == INFO_SIMPLE) {
+ *pages = 1;
+ return diag204_alloc_rbuf();
+ } else {/* INFO_EXT */
+ *pages = diag204((unsigned long)SUBC_RSI |
+ (unsigned long)INFO_EXT, 0, NULL);
+ if (*pages <= 0)
+ return ERR_PTR(-ENOSYS);
+ else
+ return diag204_alloc_vbuf(*pages);
+ }
+}
+
+/*
+ * diag204_probe() has to find out, which type of diagnose 204 implementation
+ * we have on our machine. Currently there are three possible scanarios:
+ * - subcode 4 + simple data format (only one page)
+ * - subcode 4-6 + extended data format
+ * - subcode 4-7 + extended data format
+ *
+ * Subcode 5 is used to retrieve the size of the data, provided by subcodes
+ * 6 and 7. Subcode 7 basically has the same function as subcode 6. In addition
+ * to subcode 6 it provides also information about secondary cpus.
+ * In order to get as much information as possible, we first try
+ * subcode 7, then 6 and if both fail, we use subcode 4.
+ */
+
+static int diag204_probe(void)
+{
+ void *buf;
+ int pages, rc;
+
+ buf = diag204_get_buffer(INFO_EXT, &pages);
+ if (!IS_ERR(buf)) {
+ if (diag204((unsigned long)SUBC_STIB7 |
+ (unsigned long)INFO_EXT, pages, buf) >= 0) {
+ diag204_store_sc = SUBC_STIB7;
+ diag204_info_type = INFO_EXT;
+ goto out;
+ }
+ if (diag204((unsigned long)SUBC_STIB6 |
+ (unsigned long)INFO_EXT, pages, buf) >= 0) {
+ diag204_store_sc = SUBC_STIB7;
+ diag204_info_type = INFO_EXT;
+ goto out;
+ }
+ diag204_free_buffer();
+ }
+
+ /* subcodes 6 and 7 failed, now try subcode 4 */
+
+ buf = diag204_get_buffer(INFO_SIMPLE, &pages);
+ if (IS_ERR(buf)) {
+ rc = PTR_ERR(buf);
+ goto fail_alloc;
+ }
+ if (diag204((unsigned long)SUBC_STIB4 |
+ (unsigned long)INFO_SIMPLE, pages, buf) >= 0) {
+ diag204_store_sc = SUBC_STIB4;
+ diag204_info_type = INFO_SIMPLE;
+ goto out;
+ } else {
+ rc = -ENOSYS;
+ goto fail_store;
+ }
+out:
+ rc = 0;
+fail_store:
+ diag204_free_buffer();
+fail_alloc:
+ return rc;
+}
+
+static void *diag204_store(void)
+{
+ void *buf;
+ int pages;
+
+ buf = diag204_get_buffer(diag204_info_type, &pages);
+ if (IS_ERR(buf))
+ goto out;
+ if (diag204((unsigned long)diag204_store_sc |
+ (unsigned long)diag204_info_type, pages, buf) < 0)
+ return ERR_PTR(-ENOSYS);
+out:
+ return buf;
+}
+
+/* Diagnose 224 functions */
+
+static int diag224(void *ptr)
+{
+ int rc = -ENOTSUPP;
+
+ asm volatile(
+ " diag %1,%2,0x224\n"
+ "0: lhi %0,0x0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (rc) :"d" (0), "d" (ptr) : "memory");
+ return rc;
+}
+
+static int diag224_get_name_table(void)
+{
+ /* memory must be below 2GB */
+ diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!diag224_cpu_names)
+ return -ENOMEM;
+ if (diag224(diag224_cpu_names)) {
+ kfree(diag224_cpu_names);
+ return -ENOTSUPP;
+ }
+ EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
+ return 0;
+}
+
+static void diag224_delete_name_table(void)
+{
+ kfree(diag224_cpu_names);
+}
+
+static int diag224_idx2name(int index, char *name)
+{
+ memcpy(name, diag224_cpu_names + ((index + 1) * CPU_NAME_LEN),
+ CPU_NAME_LEN);
+ name[CPU_NAME_LEN] = 0;
+ strstrip(name);
+ return 0;
+}
+
+__init int hypfs_diag_init(void)
+{
+ int rc;
+
+ if (diag204_probe()) {
+ printk(KERN_ERR "hypfs: diag 204 not working.");
+ return -ENODATA;
+ }
+ rc = diag224_get_name_table();
+ if (rc) {
+ diag204_free_buffer();
+ printk(KERN_ERR "hypfs: could not get name table.\n");
+ }
+ return rc;
+}
+
+void hypfs_diag_exit(void)
+{
+ diag224_delete_name_table();
+ diag204_free_buffer();
+}
+
+/*
+ * Functions to create the directory structure
+ * *******************************************
+ */
+
+static int hypfs_create_cpu_files(struct super_block *sb,
+ struct dentry *cpus_dir, void *cpu_info)
+{
+ struct dentry *cpu_dir;
+ char buffer[TMP_SIZE];
+ void *rc;
+
+ snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_info_type,
+ cpu_info));
+ cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer);
+ rc = hypfs_create_u64(sb, cpu_dir, "mgmtime",
+ cpu_info__acc_time(diag204_info_type, cpu_info) -
+ cpu_info__lp_time(diag204_info_type, cpu_info));
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ rc = hypfs_create_u64(sb, cpu_dir, "cputime",
+ cpu_info__lp_time(diag204_info_type, cpu_info));
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ if (diag204_info_type == INFO_EXT) {
+ rc = hypfs_create_u64(sb, cpu_dir, "onlinetime",
+ cpu_info__online_time(diag204_info_type,
+ cpu_info));
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ }
+ diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
+ rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ return 0;
+}
+
+static void *hypfs_create_lpar_files(struct super_block *sb,
+ struct dentry *systems_dir, void *part_hdr)
+{
+ struct dentry *cpus_dir;
+ struct dentry *lpar_dir;
+ char lpar_name[LPAR_NAME_LEN + 1];
+ void *cpu_info;
+ int i;
+
+ part_hdr__part_name(diag204_info_type, part_hdr, lpar_name);
+ lpar_name[LPAR_NAME_LEN] = 0;
+ lpar_dir = hypfs_mkdir(sb, systems_dir, lpar_name);
+ if (IS_ERR(lpar_dir))
+ return lpar_dir;
+ cpus_dir = hypfs_mkdir(sb, lpar_dir, "cpus");
+ if (IS_ERR(cpus_dir))
+ return cpus_dir;
+ cpu_info = part_hdr + part_hdr__size(diag204_info_type);
+ for (i = 0; i < part_hdr__rcpus(diag204_info_type, part_hdr); i++) {
+ int rc;
+ rc = hypfs_create_cpu_files(sb, cpus_dir, cpu_info);
+ if (rc)
+ return ERR_PTR(rc);
+ cpu_info += cpu_info__size(diag204_info_type);
+ }
+ return cpu_info;
+}
+
+static int hypfs_create_phys_cpu_files(struct super_block *sb,
+ struct dentry *cpus_dir, void *cpu_info)
+{
+ struct dentry *cpu_dir;
+ char buffer[TMP_SIZE];
+ void *rc;
+
+ snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_info_type,
+ cpu_info));
+ cpu_dir = hypfs_mkdir(sb, cpus_dir, buffer);
+ if (IS_ERR(cpu_dir))
+ return PTR_ERR(cpu_dir);
+ rc = hypfs_create_u64(sb, cpu_dir, "mgmtime",
+ phys_cpu__mgm_time(diag204_info_type, cpu_info));
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
+ rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
+ if (IS_ERR(rc))
+ return PTR_ERR(rc);
+ return 0;
+}
+
+static void *hypfs_create_phys_files(struct super_block *sb,
+ struct dentry *parent_dir, void *phys_hdr)
+{
+ int i;
+ void *cpu_info;
+ struct dentry *cpus_dir;
+
+ cpus_dir = hypfs_mkdir(sb, parent_dir, "cpus");
+ if (IS_ERR(cpus_dir))
+ return cpus_dir;
+ cpu_info = phys_hdr + phys_hdr__size(diag204_info_type);
+ for (i = 0; i < phys_hdr__cpus(diag204_info_type, phys_hdr); i++) {
+ int rc;
+ rc = hypfs_create_phys_cpu_files(sb, cpus_dir, cpu_info);
+ if (rc)
+ return ERR_PTR(rc);
+ cpu_info += phys_cpu__size(diag204_info_type);
+ }
+ return cpu_info;
+}
+
+int hypfs_diag_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *systems_dir, *hyp_dir;
+ void *time_hdr, *part_hdr;
+ int i, rc;
+ void *buffer, *ptr;
+
+ buffer = diag204_store();
+ if (IS_ERR(buffer))
+ return PTR_ERR(buffer);
+
+ systems_dir = hypfs_mkdir(sb, root, "systems");
+ if (IS_ERR(systems_dir)) {
+ rc = PTR_ERR(systems_dir);
+ goto err_out;
+ }
+ time_hdr = (struct x_info_blk_hdr *)buffer;
+ part_hdr = time_hdr + info_blk_hdr__size(diag204_info_type);
+ for (i = 0; i < info_blk_hdr__npar(diag204_info_type, time_hdr); i++) {
+ part_hdr = hypfs_create_lpar_files(sb, systems_dir, part_hdr);
+ if (IS_ERR(part_hdr)) {
+ rc = PTR_ERR(part_hdr);
+ goto err_out;
+ }
+ }
+ if (info_blk_hdr__flags(diag204_info_type, time_hdr) & LPAR_PHYS_FLG) {
+ ptr = hypfs_create_phys_files(sb, root, part_hdr);
+ if (IS_ERR(ptr)) {
+ rc = PTR_ERR(ptr);
+ goto err_out;
+ }
+ }
+ hyp_dir = hypfs_mkdir(sb, root, "hyp");
+ if (IS_ERR(hyp_dir)) {
+ rc = PTR_ERR(hyp_dir);
+ goto err_out;
+ }
+ ptr = hypfs_create_str(sb, hyp_dir, "type", "LPAR Hypervisor");
+ if (IS_ERR(ptr)) {
+ rc = PTR_ERR(ptr);
+ goto err_out;
+ }
+ rc = 0;
+
+err_out:
+ return rc;
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs_vm.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs_vm.c
new file mode 100644
index 0000000000..d01fc8f799
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/hypfs_vm.c
@@ -0,0 +1,231 @@
+/*
+ * Hypervisor filesystem for Linux on s390. z/VM implementation.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <asm/ebcdic.h>
+#include "hypfs.h"
+
+#define NAME_LEN 8
+
+static char local_guest[] = " ";
+static char all_guests[] = "* ";
+static char *guest_query;
+
+struct diag2fc_data {
+ __u32 version;
+ __u32 flags;
+ __u64 used_cpu;
+ __u64 el_time;
+ __u64 mem_min_kb;
+ __u64 mem_max_kb;
+ __u64 mem_share_kb;
+ __u64 mem_used_kb;
+ __u32 pcpus;
+ __u32 lcpus;
+ __u32 vcpus;
+ __u32 cpu_min;
+ __u32 cpu_max;
+ __u32 cpu_shares;
+ __u32 cpu_use_samp;
+ __u32 cpu_delay_samp;
+ __u32 page_wait_samp;
+ __u32 idle_samp;
+ __u32 other_samp;
+ __u32 total_samp;
+ char guest_name[NAME_LEN];
+};
+
+struct diag2fc_parm_list {
+ char userid[NAME_LEN];
+ char aci_grp[NAME_LEN];
+ __u64 addr;
+ __u32 size;
+ __u32 fmt;
+};
+
+static int diag2fc(int size, char* query, void *addr)
+{
+ unsigned long residual_cnt;
+ unsigned long rc;
+ struct diag2fc_parm_list parm_list;
+
+ memcpy(parm_list.userid, query, NAME_LEN);
+ ASCEBC(parm_list.userid, NAME_LEN);
+ parm_list.addr = (unsigned long) addr ;
+ parm_list.size = size;
+ parm_list.fmt = 0x02;
+ memset(parm_list.aci_grp, 0x40, NAME_LEN);
+ rc = -1;
+
+ asm volatile(
+ " diag %0,%1,0x2fc\n"
+ "0:\n"
+ EX_TABLE(0b,0b)
+ : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
+
+ if ((rc != 0 ) && (rc != -2))
+ return rc;
+ else
+ return -residual_cnt;
+}
+
+static struct diag2fc_data *diag2fc_store(char *query, int *count)
+{
+ int size;
+ struct diag2fc_data *data;
+
+ do {
+ size = diag2fc(0, query, NULL);
+ if (size < 0)
+ return ERR_PTR(-EACCES);
+ data = vmalloc(size);
+ if (!data)
+ return ERR_PTR(-ENOMEM);
+ if (diag2fc(size, query, data) == 0)
+ break;
+ vfree(data);
+ } while (1);
+ *count = (size / sizeof(*data));
+
+ return data;
+}
+
+static void diag2fc_free(void *data)
+{
+ vfree(data);
+}
+
+#define ATTRIBUTE(sb, dir, name, member) \
+do { \
+ void *rc; \
+ rc = hypfs_create_u64(sb, dir, name, member); \
+ if (IS_ERR(rc)) \
+ return PTR_ERR(rc); \
+} while(0)
+
+static int hpyfs_vm_create_guest(struct super_block *sb,
+ struct dentry *systems_dir,
+ struct diag2fc_data *data)
+{
+ char guest_name[NAME_LEN + 1] = {};
+ struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
+ int dedicated_flag, capped_value;
+
+ capped_value = (data->flags & 0x00000006) >> 1;
+ dedicated_flag = (data->flags & 0x00000008) >> 3;
+
+ /* guest dir */
+ memcpy(guest_name, data->guest_name, NAME_LEN);
+ EBCASC(guest_name, NAME_LEN);
+ strstrip(guest_name);
+ guest_dir = hypfs_mkdir(sb, systems_dir, guest_name);
+ if (IS_ERR(guest_dir))
+ return PTR_ERR(guest_dir);
+ ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time);
+
+ /* logical cpu information */
+ cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus");
+ if (IS_ERR(cpus_dir))
+ return PTR_ERR(cpus_dir);
+ ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu);
+ ATTRIBUTE(sb, cpus_dir, "capped", capped_value);
+ ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag);
+ ATTRIBUTE(sb, cpus_dir, "count", data->vcpus);
+ ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min);
+ ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max);
+ ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares);
+
+ /* memory information */
+ mem_dir = hypfs_mkdir(sb, guest_dir, "mem");
+ if (IS_ERR(mem_dir))
+ return PTR_ERR(mem_dir);
+ ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb);
+ ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb);
+ ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb);
+ ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb);
+
+ /* samples */
+ samples_dir = hypfs_mkdir(sb, guest_dir, "samples");
+ if (IS_ERR(samples_dir))
+ return PTR_ERR(samples_dir);
+ ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp);
+ ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp);
+ ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp);
+ ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp);
+ ATTRIBUTE(sb, samples_dir, "other", data->other_samp);
+ ATTRIBUTE(sb, samples_dir, "total", data->total_samp);
+ return 0;
+}
+
+int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
+{
+ struct dentry *dir, *file;
+ struct diag2fc_data *data;
+ int rc, i, count = 0;
+
+ data = diag2fc_store(guest_query, &count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ /* Hpervisor Info */
+ dir = hypfs_mkdir(sb, root, "hyp");
+ if (IS_ERR(dir)) {
+ rc = PTR_ERR(dir);
+ goto failed;
+ }
+ file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor");
+ if (IS_ERR(file)) {
+ rc = PTR_ERR(file);
+ goto failed;
+ }
+
+ /* physical cpus */
+ dir = hypfs_mkdir(sb, root, "cpus");
+ if (IS_ERR(dir)) {
+ rc = PTR_ERR(dir);
+ goto failed;
+ }
+ file = hypfs_create_u64(sb, dir, "count", data->lcpus);
+ if (IS_ERR(file)) {
+ rc = PTR_ERR(file);
+ goto failed;
+ }
+
+ /* guests */
+ dir = hypfs_mkdir(sb, root, "systems");
+ if (IS_ERR(dir)) {
+ rc = PTR_ERR(dir);
+ goto failed;
+ }
+
+ for (i = 0; i < count; i++) {
+ rc = hpyfs_vm_create_guest(sb, dir, &(data[i]));
+ if (rc)
+ goto failed;
+ }
+ diag2fc_free(data);
+ return 0;
+
+failed:
+ diag2fc_free(data);
+ return rc;
+}
+
+int hypfs_vm_init(void)
+{
+ if (diag2fc(0, all_guests, NULL) > 0)
+ guest_query = all_guests;
+ else if (diag2fc(0, local_guest, NULL) > 0)
+ guest_query = local_guest;
+ else
+ return -EACCES;
+
+ return 0;
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/inode.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/inode.c
new file mode 100644
index 0000000000..4b010ff814
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/hypfs/inode.c
@@ -0,0 +1,542 @@
+/*
+ * arch/s390/hypfs/inode.c
+ * Hypervisor filesystem for Linux on s390.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/vfs.h>
+#include <linux/pagemap.h>
+#include <linux/gfp.h>
+#include <linux/time.h>
+#include <linux/parser.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
+#include <asm/ebcdic.h>
+#include "hypfs.h"
+
+#define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */
+#define TMP_SIZE 64 /* size of temporary buffers */
+
+static struct dentry *hypfs_create_update_file(struct super_block *sb,
+ struct dentry *dir);
+
+struct hypfs_sb_info {
+ uid_t uid; /* uid used for files and dirs */
+ gid_t gid; /* gid used for files and dirs */
+ struct dentry *update_file; /* file to trigger update */
+ time_t last_update; /* last update time in secs since 1970 */
+ struct mutex lock; /* lock to protect update process */
+};
+
+static const struct file_operations hypfs_file_ops;
+static struct file_system_type hypfs_type;
+static struct super_operations hypfs_s_ops;
+
+/* start of list of all dentries, which have to be deleted on update */
+static struct dentry *hypfs_last_dentry;
+
+static void hypfs_update_update(struct super_block *sb)
+{
+ struct hypfs_sb_info *sb_info = sb->s_fs_info;
+ struct inode *inode = sb_info->update_file->d_inode;
+
+ sb_info->last_update = get_seconds();
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+}
+
+/* directory tree removal functions */
+
+static void hypfs_add_dentry(struct dentry *dentry)
+{
+ dentry->d_fsdata = hypfs_last_dentry;
+ hypfs_last_dentry = dentry;
+}
+
+static inline int hypfs_positive(struct dentry *dentry)
+{
+ return dentry->d_inode && !d_unhashed(dentry);
+}
+
+static void hypfs_remove(struct dentry *dentry)
+{
+ struct dentry *parent;
+
+ parent = dentry->d_parent;
+ if (!parent || !parent->d_inode)
+ return;
+ mutex_lock(&parent->d_inode->i_mutex);
+ if (hypfs_positive(dentry)) {
+ if (S_ISDIR(dentry->d_inode->i_mode))
+ simple_rmdir(parent->d_inode, dentry);
+ else
+ simple_unlink(parent->d_inode, dentry);
+ }
+ d_delete(dentry);
+ dput(dentry);
+ mutex_unlock(&parent->d_inode->i_mutex);
+}
+
+static void hypfs_delete_tree(struct dentry *root)
+{
+ while (hypfs_last_dentry) {
+ struct dentry *next_dentry;
+ next_dentry = hypfs_last_dentry->d_fsdata;
+ hypfs_remove(hypfs_last_dentry);
+ hypfs_last_dentry = next_dentry;
+ }
+}
+
+static struct inode *hypfs_make_inode(struct super_block *sb, int mode)
+{
+ struct inode *ret = new_inode(sb);
+
+ if (ret) {
+ struct hypfs_sb_info *hypfs_info = sb->s_fs_info;
+ ret->i_mode = mode;
+ ret->i_uid = hypfs_info->uid;
+ ret->i_gid = hypfs_info->gid;
+ ret->i_blocks = 0;
+ ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
+ if (mode & S_IFDIR)
+ ret->i_nlink = 2;
+ else
+ ret->i_nlink = 1;
+ }
+ return ret;
+}
+
+static void hypfs_drop_inode(struct inode *inode)
+{
+ kfree(inode->i_private);
+ generic_delete_inode(inode);
+}
+
+static int hypfs_open(struct inode *inode, struct file *filp)
+{
+ char *data = filp->f_path.dentry->d_inode->i_private;
+ struct hypfs_sb_info *fs_info;
+
+ if (filp->f_mode & FMODE_WRITE) {
+ if (!(inode->i_mode & S_IWUGO))
+ return -EACCES;
+ }
+ if (filp->f_mode & FMODE_READ) {
+ if (!(inode->i_mode & S_IRUGO))
+ return -EACCES;
+ }
+
+ fs_info = inode->i_sb->s_fs_info;
+ if(data) {
+ mutex_lock(&fs_info->lock);
+ filp->private_data = kstrdup(data, GFP_KERNEL);
+ if (!filp->private_data) {
+ mutex_unlock(&fs_info->lock);
+ return -ENOMEM;
+ }
+ mutex_unlock(&fs_info->lock);
+ }
+ return 0;
+}
+
+static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
+{
+ char *data;
+ size_t len;
+ struct file *filp = iocb->ki_filp;
+ /* XXX: temporary */
+ char __user *buf = iov[0].iov_base;
+ size_t count = iov[0].iov_len;
+
+ if (nr_segs != 1) {
+ count = -EINVAL;
+ goto out;
+ }
+
+ data = filp->private_data;
+ len = strlen(data);
+ if (offset > len) {
+ count = 0;
+ goto out;
+ }
+ if (count > len - offset)
+ count = len - offset;
+ if (copy_to_user(buf, data + offset, count)) {
+ count = -EFAULT;
+ goto out;
+ }
+ iocb->ki_pos += count;
+ file_accessed(filp);
+out:
+ return count;
+}
+static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
+{
+ int rc;
+ struct super_block *sb;
+ struct hypfs_sb_info *fs_info;
+ size_t count = iov_length(iov, nr_segs);
+
+ sb = iocb->ki_filp->f_path.dentry->d_inode->i_sb;
+ fs_info = sb->s_fs_info;
+ /*
+ * Currently we only allow one update per second for two reasons:
+ * 1. diag 204 is VERY expensive
+ * 2. If several processes do updates in parallel and then read the
+ * hypfs data, the likelihood of collisions is reduced, if we restrict
+ * the minimum update interval. A collision occurs, if during the
+ * data gathering of one process another process triggers an update
+ * If the first process wants to ensure consistent data, it has
+ * to restart data collection in this case.
+ */
+ mutex_lock(&fs_info->lock);
+ if (fs_info->last_update == get_seconds()) {
+ rc = -EBUSY;
+ goto out;
+ }
+ hypfs_delete_tree(sb->s_root);
+ if (MACHINE_IS_VM)
+ rc = hypfs_vm_create_files(sb, sb->s_root);
+ else
+ rc = hypfs_diag_create_files(sb, sb->s_root);
+ if (rc) {
+ printk(KERN_ERR "hypfs: Update failed\n");
+ hypfs_delete_tree(sb->s_root);
+ goto out;
+ }
+ hypfs_update_update(sb);
+ rc = count;
+out:
+ mutex_unlock(&fs_info->lock);
+ return rc;
+}
+
+static int hypfs_release(struct inode *inode, struct file *filp)
+{
+ kfree(filp->private_data);
+ return 0;
+}
+
+enum { opt_uid, opt_gid, opt_err };
+
+static match_table_t hypfs_tokens = {
+ {opt_uid, "uid=%u"},
+ {opt_gid, "gid=%u"},
+ {opt_err, NULL}
+};
+
+static int hypfs_parse_options(char *options, struct super_block *sb)
+{
+ char *str;
+ substring_t args[MAX_OPT_ARGS];
+
+ if (!options)
+ return 0;
+ while ((str = strsep(&options, ",")) != NULL) {
+ int token, option;
+ struct hypfs_sb_info *hypfs_info = sb->s_fs_info;
+
+ if (!*str)
+ continue;
+ token = match_token(str, hypfs_tokens, args);
+ switch (token) {
+ case opt_uid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ hypfs_info->uid = option;
+ break;
+ case opt_gid:
+ if (match_int(&args[0], &option))
+ return -EINVAL;
+ hypfs_info->gid = option;
+ break;
+ case opt_err:
+ default:
+ printk(KERN_ERR "hypfs: Unrecognized mount option "
+ "\"%s\" or missing value\n", str);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int hypfs_show_options(struct seq_file *s, struct vfsmount *mnt)
+{
+ struct hypfs_sb_info *hypfs_info = mnt->mnt_sb->s_fs_info;
+
+ seq_printf(s, ",uid=%u", hypfs_info->uid);
+ seq_printf(s, ",gid=%u", hypfs_info->gid);
+ return 0;
+}
+
+static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct inode *root_inode;
+ struct dentry *root_dentry;
+ int rc = 0;
+ struct hypfs_sb_info *sbi;
+
+ sbi = kzalloc(sizeof(struct hypfs_sb_info), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ mutex_init(&sbi->lock);
+ sbi->uid = current->uid;
+ sbi->gid = current->gid;
+ sb->s_fs_info = sbi;
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = HYPFS_MAGIC;
+ sb->s_op = &hypfs_s_ops;
+ if (hypfs_parse_options(data, sb)) {
+ rc = -EINVAL;
+ goto err_alloc;
+ }
+ root_inode = hypfs_make_inode(sb, S_IFDIR | 0755);
+ if (!root_inode) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ root_inode->i_op = &simple_dir_inode_operations;
+ root_inode->i_fop = &simple_dir_operations;
+ root_dentry = d_alloc_root(root_inode);
+ if (!root_dentry) {
+ iput(root_inode);
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ if (MACHINE_IS_VM)
+ rc = hypfs_vm_create_files(sb, root_dentry);
+ else
+ rc = hypfs_diag_create_files(sb, root_dentry);
+ if (rc)
+ goto err_tree;
+ sbi->update_file = hypfs_create_update_file(sb, root_dentry);
+ if (IS_ERR(sbi->update_file)) {
+ rc = PTR_ERR(sbi->update_file);
+ goto err_tree;
+ }
+ hypfs_update_update(sb);
+ sb->s_root = root_dentry;
+ printk(KERN_INFO "hypfs: Hypervisor filesystem mounted\n");
+ return 0;
+
+err_tree:
+ hypfs_delete_tree(root_dentry);
+ d_genocide(root_dentry);
+ dput(root_dentry);
+err_alloc:
+ kfree(sbi);
+ return rc;
+}
+
+static int hypfs_get_super(struct file_system_type *fst, int flags,
+ const char *devname, void *data, struct vfsmount *mnt)
+{
+ return get_sb_single(fst, flags, data, hypfs_fill_super, mnt);
+}
+
+static void hypfs_kill_super(struct super_block *sb)
+{
+ struct hypfs_sb_info *sb_info = sb->s_fs_info;
+
+ if (sb->s_root) {
+ hypfs_delete_tree(sb->s_root);
+ hypfs_remove(sb_info->update_file);
+ kfree(sb->s_fs_info);
+ sb->s_fs_info = NULL;
+ }
+ kill_litter_super(sb);
+}
+
+static struct dentry *hypfs_create_file(struct super_block *sb,
+ struct dentry *parent, const char *name,
+ char *data, mode_t mode)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+ struct qstr qname;
+
+ qname.name = name;
+ qname.len = strlen(name);
+ qname.hash = full_name_hash(name, qname.len);
+ mutex_lock(&parent->d_inode->i_mutex);
+ dentry = lookup_one_len(name, parent, strlen(name));
+ if (IS_ERR(dentry)) {
+ dentry = ERR_PTR(-ENOMEM);
+ goto fail;
+ }
+ inode = hypfs_make_inode(sb, mode);
+ if (!inode) {
+ dput(dentry);
+ dentry = ERR_PTR(-ENOMEM);
+ goto fail;
+ }
+ if (mode & S_IFREG) {
+ inode->i_fop = &hypfs_file_ops;
+ if (data)
+ inode->i_size = strlen(data);
+ else
+ inode->i_size = 0;
+ } else if (mode & S_IFDIR) {
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ parent->d_inode->i_nlink++;
+ } else
+ BUG();
+ inode->i_private = data;
+ d_instantiate(dentry, inode);
+ dget(dentry);
+fail:
+ mutex_unlock(&parent->d_inode->i_mutex);
+ return dentry;
+}
+
+struct dentry *hypfs_mkdir(struct super_block *sb, struct dentry *parent,
+ const char *name)
+{
+ struct dentry *dentry;
+
+ dentry = hypfs_create_file(sb, parent, name, NULL, S_IFDIR | DIR_MODE);
+ if (IS_ERR(dentry))
+ return dentry;
+ hypfs_add_dentry(dentry);
+ return dentry;
+}
+
+static struct dentry *hypfs_create_update_file(struct super_block *sb,
+ struct dentry *dir)
+{
+ struct dentry *dentry;
+
+ dentry = hypfs_create_file(sb, dir, "update", NULL,
+ S_IFREG | UPDATE_FILE_MODE);
+ /*
+ * We do not put the update file on the 'delete' list with
+ * hypfs_add_dentry(), since it should not be removed when the tree
+ * is updated.
+ */
+ return dentry;
+}
+
+struct dentry *hypfs_create_u64(struct super_block *sb, struct dentry *dir,
+ const char *name, __u64 value)
+{
+ char *buffer;
+ char tmp[TMP_SIZE];
+ struct dentry *dentry;
+
+ snprintf(tmp, TMP_SIZE, "%lld\n", (unsigned long long int)value);
+ buffer = kstrdup(tmp, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+ dentry =
+ hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE);
+ if (IS_ERR(dentry)) {
+ kfree(buffer);
+ return ERR_PTR(-ENOMEM);
+ }
+ hypfs_add_dentry(dentry);
+ return dentry;
+}
+
+struct dentry *hypfs_create_str(struct super_block *sb, struct dentry *dir,
+ const char *name, char *string)
+{
+ char *buffer;
+ struct dentry *dentry;
+
+ buffer = kmalloc(strlen(string) + 2, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+ sprintf(buffer, "%s\n", string);
+ dentry =
+ hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE);
+ if (IS_ERR(dentry)) {
+ kfree(buffer);
+ return ERR_PTR(-ENOMEM);
+ }
+ hypfs_add_dentry(dentry);
+ return dentry;
+}
+
+static const struct file_operations hypfs_file_ops = {
+ .open = hypfs_open,
+ .release = hypfs_release,
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = hypfs_aio_read,
+ .aio_write = hypfs_aio_write,
+};
+
+static struct file_system_type hypfs_type = {
+ .owner = THIS_MODULE,
+ .name = "s390_hypfs",
+ .get_sb = hypfs_get_super,
+ .kill_sb = hypfs_kill_super
+};
+
+static struct super_operations hypfs_s_ops = {
+ .statfs = simple_statfs,
+ .drop_inode = hypfs_drop_inode,
+ .show_options = hypfs_show_options,
+};
+
+static struct kobject *s390_kobj;
+
+static int __init hypfs_init(void)
+{
+ int rc;
+
+ if (MACHINE_IS_VM) {
+ if (hypfs_vm_init())
+ /* no diag 2fc, just exit */
+ return -ENODATA;
+ } else {
+ if (hypfs_diag_init()) {
+ rc = -ENODATA;
+ goto fail_diag;
+ }
+ }
+ s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
+ if (!s390_kobj) {
+ rc = -ENOMEM;;
+ goto fail_sysfs;
+ }
+ rc = register_filesystem(&hypfs_type);
+ if (rc)
+ goto fail_filesystem;
+ return 0;
+
+fail_filesystem:
+ kobject_put(s390_kobj);
+fail_sysfs:
+ if (!MACHINE_IS_VM)
+ hypfs_diag_exit();
+fail_diag:
+ printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
+ return rc;
+}
+
+static void __exit hypfs_exit(void)
+{
+ if (!MACHINE_IS_VM)
+ hypfs_diag_exit();
+ unregister_filesystem(&hypfs_type);
+ kobject_put(s390_kobj);
+}
+
+module_init(hypfs_init)
+module_exit(hypfs_exit)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Holzheu <holzheu@de.ibm.com>");
+MODULE_DESCRIPTION("s390 Hypervisor Filesystem");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/Makefile
new file mode 100644
index 0000000000..4d3e38392c
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/Makefile
@@ -0,0 +1,38 @@
+#
+# Makefile for the linux kernel.
+#
+
+EXTRA_AFLAGS := -traditional
+
+#
+# Passing null pointers is ok for smp code, since we access the lowcore here.
+#
+CFLAGS_smp.o := -Wno-nonnull
+
+obj-y := bitmap.o traps.o time.o process.o base.o early.o \
+ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
+ semaphore.o s390_ext.o debug.o irq.o ipl.o dis.o diag.o
+
+obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
+obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
+
+extra-y += head.o init_task.o vmlinux.lds
+
+obj-$(CONFIG_MODULES) += s390_ksyms.o module.o
+obj-$(CONFIG_SMP) += smp.o
+
+obj-$(CONFIG_AUDIT) += audit.o
+compat-obj-$(CONFIG_AUDIT) += compat_audit.o
+obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \
+ compat_wrapper.o compat_exec_domain.o \
+ binfmt_elf32.o $(compat-obj-y)
+
+obj-$(CONFIG_VIRT_TIMER) += vtime.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
+obj-$(CONFIG_KPROBES) += kprobes.o
+
+# Kexec part
+S390_KEXEC_OBJS := machine_kexec.o crash.o
+S390_KEXEC_OBJS += $(if $(CONFIG_64BIT),relocate_kernel64.o,relocate_kernel.o)
+obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/asm-offsets.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/asm-offsets.c
new file mode 100644
index 0000000000..1375f8a446
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/asm-offsets.c
@@ -0,0 +1,48 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#include <linux/sched.h>
+
+/* Use marker if you need to separate the values later */
+
+#define DEFINE(sym, val, marker) \
+ asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+ DEFINE(__THREAD_info, offsetof(struct task_struct, stack),);
+ DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
+ DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
+ DEFINE(__THREAD_mm_segment,
+ offsetof(struct task_struct, thread.mm_segment),);
+ BLANK();
+ DEFINE(__TASK_pid, offsetof(struct task_struct, pid),);
+ BLANK();
+ DEFINE(__PER_atmid, offsetof(per_struct, lowcore.words.perc_atmid),);
+ DEFINE(__PER_address, offsetof(per_struct, lowcore.words.address),);
+ DEFINE(__PER_access_id, offsetof(per_struct, lowcore.words.access_id),);
+ BLANK();
+ DEFINE(__TI_task, offsetof(struct thread_info, task),);
+ DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain),);
+ DEFINE(__TI_flags, offsetof(struct thread_info, flags),);
+ DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),);
+ DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),);
+ BLANK();
+ DEFINE(__PT_ARGS, offsetof(struct pt_regs, args),);
+ DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),);
+ DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),);
+ DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),);
+ DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc),);
+ DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap),);
+ DEFINE(__PT_SIZE, sizeof(struct pt_regs),);
+ BLANK();
+ DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain),);
+ DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs),);
+ DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1),);
+ return 0;
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/audit.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/audit.c
new file mode 100644
index 0000000000..f4932c22eb
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/audit.c
@@ -0,0 +1,78 @@
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/audit.h>
+#include <asm/unistd.h>
+#include "audit.h"
+
+static unsigned dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+static unsigned read_class[] = {
+#include <asm-generic/audit_read.h>
+~0U
+};
+
+static unsigned write_class[] = {
+#include <asm-generic/audit_write.h>
+~0U
+};
+
+static unsigned chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_COMPAT
+ if (arch == AUDIT_ARCH_S390)
+ return 1;
+#endif
+ return 0;
+}
+
+int audit_classify_syscall(int abi, unsigned syscall)
+{
+#ifdef CONFIG_COMPAT
+ if (abi == AUDIT_ARCH_S390)
+ return s390_classify_syscall(syscall);
+#endif
+ switch(syscall) {
+ case __NR_open:
+ return 2;
+ case __NR_openat:
+ return 3;
+ case __NR_socketcall:
+ return 4;
+ case __NR_execve:
+ return 5;
+ default:
+ return 0;
+ }
+}
+
+static int __init audit_classes_init(void)
+{
+#ifdef CONFIG_COMPAT
+ audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class);
+ audit_register_class(AUDIT_CLASS_READ_32, s390_read_class);
+ audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR_32, s390_chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL_32, s390_signal_class);
+#endif
+ audit_register_class(AUDIT_CLASS_WRITE, write_class);
+ audit_register_class(AUDIT_CLASS_READ, read_class);
+ audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
+ return 0;
+}
+
+__initcall(audit_classes_init);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/audit.h b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/audit.h
new file mode 100644
index 0000000000..12b56f4b5a
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/audit.h
@@ -0,0 +1,15 @@
+#ifndef __ARCH_S390_KERNEL_AUDIT_H
+#define __ARCH_S390_KERNEL_AUDIT_H
+
+#include <linux/types.h>
+
+#ifdef CONFIG_COMPAT
+extern int s390_classify_syscall(unsigned);
+extern __u32 s390_dir_class[];
+extern __u32 s390_write_class[];
+extern __u32 s390_read_class[];
+extern __u32 s390_chattr_class[];
+extern __u32 s390_signal_class[];
+#endif /* CONFIG_COMPAT */
+
+#endif /* __ARCH_S390_KERNEL_AUDIT_H */
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/base.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/base.S
new file mode 100644
index 0000000000..dc7e525977
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/base.S
@@ -0,0 +1,150 @@
+/*
+ * arch/s390/kernel/base.S
+ *
+ * Copyright IBM Corp. 2006,2007
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ * Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <asm/ptrace.h>
+#include <asm/lowcore.h>
+
+#ifdef CONFIG_64BIT
+
+ .globl s390_base_mcck_handler
+s390_base_mcck_handler:
+ basr %r13,0
+0: lg %r15,__LC_PANIC_STACK # load panic stack
+ aghi %r15,-STACK_FRAME_OVERHEAD
+ larl %r1,s390_base_mcck_handler_fn
+ lg %r1,0(%r1)
+ ltgr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+1: la %r1,4095
+ lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
+ lpswe __LC_MCK_OLD_PSW
+
+ .section .bss
+ .globl s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+ .quad 0
+ .previous
+
+ .globl s390_base_ext_handler
+s390_base_ext_handler:
+ stmg %r0,%r15,__LC_SAVE_AREA
+ basr %r13,0
+0: aghi %r15,-STACK_FRAME_OVERHEAD
+ larl %r1,s390_base_ext_handler_fn
+ lg %r1,0(%r1)
+ ltgr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+1: lmg %r0,%r15,__LC_SAVE_AREA
+ ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit
+ lpswe __LC_EXT_OLD_PSW
+
+ .section .bss
+ .globl s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+ .quad 0
+ .previous
+
+ .globl s390_base_pgm_handler
+s390_base_pgm_handler:
+ stmg %r0,%r15,__LC_SAVE_AREA
+ basr %r13,0
+0: aghi %r15,-STACK_FRAME_OVERHEAD
+ larl %r1,s390_base_pgm_handler_fn
+ lg %r1,0(%r1)
+ ltgr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+ lmg %r0,%r15,__LC_SAVE_AREA
+ lpswe __LC_PGM_OLD_PSW
+1: lpswe disabled_wait_psw-0b(%r13)
+
+ .align 8
+disabled_wait_psw:
+ .quad 0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler
+
+ .section .bss
+ .globl s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+ .quad 0
+ .previous
+
+#else /* CONFIG_64BIT */
+
+ .globl s390_base_mcck_handler
+s390_base_mcck_handler:
+ basr %r13,0
+0: l %r15,__LC_PANIC_STACK # load panic stack
+ ahi %r15,-STACK_FRAME_OVERHEAD
+ l %r1,2f-0b(%r13)
+ l %r1,0(%r1)
+ ltr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA
+ lpsw __LC_MCK_OLD_PSW
+
+2: .long s390_base_mcck_handler_fn
+
+ .section .bss
+ .globl s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+ .long 0
+ .previous
+
+ .globl s390_base_ext_handler
+s390_base_ext_handler:
+ stm %r0,%r15,__LC_SAVE_AREA
+ basr %r13,0
+0: ahi %r15,-STACK_FRAME_OVERHEAD
+ l %r1,2f-0b(%r13)
+ l %r1,0(%r1)
+ ltr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+1: lm %r0,%r15,__LC_SAVE_AREA
+ ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit
+ lpsw __LC_EXT_OLD_PSW
+
+2: .long s390_base_ext_handler_fn
+
+ .section .bss
+ .globl s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+ .long 0
+ .previous
+
+ .globl s390_base_pgm_handler
+s390_base_pgm_handler:
+ stm %r0,%r15,__LC_SAVE_AREA
+ basr %r13,0
+0: ahi %r15,-STACK_FRAME_OVERHEAD
+ l %r1,2f-0b(%r13)
+ l %r1,0(%r1)
+ ltr %r1,%r1
+ jz 1f
+ basr %r14,%r1
+ lm %r0,%r15,__LC_SAVE_AREA
+ lpsw __LC_PGM_OLD_PSW
+
+1: lpsw disabled_wait_psw-0b(%r13)
+
+2: .long s390_base_pgm_handler_fn
+
+disabled_wait_psw:
+ .align 8
+ .long 0x000a0000,0x00000000 + s390_base_pgm_handler
+
+ .section .bss
+ .globl s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+ .long 0
+ .previous
+
+#endif /* CONFIG_64BIT */
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/binfmt_elf32.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/binfmt_elf32.c
new file mode 100644
index 0000000000..3e1c315b73
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/binfmt_elf32.c
@@ -0,0 +1,214 @@
+/*
+ * Support for 32-bit Linux for S390 ELF binaries.
+ *
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Gerhard Tonn (ton@de.ibm.com)
+ *
+ * Heavily inspired by the 32-bit Sparc compat code which is
+ * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#define __ASMS390_ELF_H
+
+#include <linux/time.h>
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#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)
+
+/* ELF register definitions */
+#define NUM_GPRS 16
+#define NUM_FPRS 16
+#define NUM_ACRS 16
+
+/* For SVR4/S390 the function pointer to be registered with `atexit` is
+ passed in R14. */
+#define ELF_PLAT_INIT(_r, load_addr) \
+ do { \
+ _r->gprs[14] = 0; \
+ } while(0)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ use of this is to invoke "./ld.so someprog" to test out a new version of
+ the loader. We need to make sure that it is out of the way of the program
+ that it will "exec", and that there is sufficient room for the brk. */
+
+#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
+
+/* Wow, the "main" arch needs arch dependent functions too.. :) */
+
+/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
+ now struct_user_regs, they are different) */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs32(regs, &pr_reg);
+
+#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs32(tsk, regs)
+
+#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs)
+
+/* This yields a mask that user programs can use to figure out what
+ instruction set this CPU supports. */
+
+#define ELF_HWCAP (0)
+
+/* This yields a string that ld.so will use to load implementation
+ specific libraries for optimization. This is more specific in
+ intent than poking at uname or /proc/cpuinfo.
+
+ For the moment, we have only optimizations for the Intel generations,
+ but that could change... */
+
+#define ELF_PLATFORM (NULL)
+
+#define SET_PERSONALITY(ex, ibcs2) \
+do { \
+ if (ibcs2) \
+ set_personality(PER_SVR4); \
+ else if (current->personality != PER_LINUX32) \
+ set_personality(PER_LINUX); \
+ set_thread_flag(TIF_31BIT); \
+} while (0)
+
+#include "compat_linux.h"
+
+typedef _s390_fp_regs32 elf_fpregset_t;
+
+typedef struct
+{
+
+ _psw_t32 psw;
+ __u32 gprs[__NUM_GPRS];
+ __u32 acrs[__NUM_ACRS];
+ __u32 orig_gpr2;
+} s390_regs32;
+typedef s390_regs32 elf_gregset_t;
+
+static inline int dump_regs32(struct pt_regs *ptregs, elf_gregset_t *regs)
+{
+ int i;
+
+ memcpy(&regs->psw.mask, &ptregs->psw.mask, 4);
+ memcpy(&regs->psw.addr, (char *)&ptregs->psw.addr + 4, 4);
+ for (i = 0; i < NUM_GPRS; i++)
+ regs->gprs[i] = ptregs->gprs[i];
+ save_access_regs(regs->acrs);
+ regs->orig_gpr2 = ptregs->orig_gpr2;
+ return 1;
+}
+
+static inline int dump_task_regs32(struct task_struct *tsk, elf_gregset_t *regs)
+{
+ struct pt_regs *ptregs = task_pt_regs(tsk);
+ int i;
+
+ memcpy(&regs->psw.mask, &ptregs->psw.mask, 4);
+ memcpy(&regs->psw.addr, (char *)&ptregs->psw.addr + 4, 4);
+ for (i = 0; i < NUM_GPRS; i++)
+ regs->gprs[i] = ptregs->gprs[i];
+ memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs));
+ regs->orig_gpr2 = ptregs->orig_gpr2;
+ return 1;
+}
+
+static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
+{
+ if (tsk == current)
+ save_fp_regs((s390_fp_regs *) fpregs);
+ else
+ memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t));
+ return 1;
+}
+
+#include <asm/processor.h>
+#include <asm/pgalloc.h>
+#include <linux/module.h>
+#include <linux/elfcore.h>
+#include <linux/binfmts.h>
+#include <linux/compat.h>
+
+#define elf_prstatus elf_prstatus32
+struct elf_prstatus32
+{
+ struct elf_siginfo pr_info; /* Info associated with signal */
+ short pr_cursig; /* Current signal */
+ u32 pr_sigpend; /* Set of pending signals */
+ u32 pr_sighold; /* Set of held signals */
+ pid_t pr_pid;
+ pid_t pr_ppid;
+ pid_t pr_pgrp;
+ pid_t pr_sid;
+ struct compat_timeval pr_utime; /* User time */
+ struct compat_timeval pr_stime; /* System time */
+ struct compat_timeval pr_cutime; /* Cumulative user time */
+ struct compat_timeval pr_cstime; /* Cumulative system time */
+ elf_gregset_t pr_reg; /* GP registers */
+ int pr_fpvalid; /* True if math co-processor being used. */
+};
+
+#define elf_prpsinfo elf_prpsinfo32
+struct elf_prpsinfo32
+{
+ char pr_state; /* numeric process state */
+ char pr_sname; /* char for pr_state */
+ char pr_zomb; /* zombie */
+ char pr_nice; /* nice val */
+ u32 pr_flag; /* flags */
+ u16 pr_uid;
+ u16 pr_gid;
+ pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
+ /* Lots missing */
+ char pr_fname[16]; /* filename of executable */
+ char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+#include <linux/highuid.h>
+
+/*
+#define init_elf_binfmt init_elf32_binfmt
+*/
+
+#undef start_thread
+#define start_thread start_thread31
+
+static inline void start_thread31(struct pt_regs *regs, unsigned long new_psw,
+ unsigned long new_stackp)
+{
+ set_fs(USER_DS);
+ regs->psw.mask = psw_user32_bits;
+ regs->psw.addr = new_psw;
+ regs->gprs[15] = new_stackp;
+ crst_table_downgrade(current->mm, 1UL << 31);
+}
+
+MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries,"
+ " Copyright 2000 IBM Corporation");
+MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
+
+#undef MODULE_DESCRIPTION
+#undef MODULE_AUTHOR
+
+#undef cputime_to_timeval
+#define cputime_to_timeval cputime_to_compat_timeval
+static inline void
+cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
+{
+ value->tv_usec = cputime % 1000000;
+ value->tv_sec = cputime / 1000000;
+}
+
+#include "../../../fs/binfmt_elf.c"
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/bitmap.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/bitmap.S
new file mode 100644
index 0000000000..dfb41f946e
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/bitmap.S
@@ -0,0 +1,56 @@
+/*
+ * arch/s390/kernel/bitmap.S
+ * Bitmaps for set_bit, clear_bit, test_and_set_bit, ...
+ * See include/asm-s390/{bitops.h|posix_types.h} for details
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+ .globl _oi_bitmap
+_oi_bitmap:
+ .byte 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
+
+ .globl _ni_bitmap
+_ni_bitmap:
+ .byte 0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F
+
+ .globl _zb_findmap
+_zb_findmap:
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8
+
+ .globl _sb_findmap
+_sb_findmap:
+ .byte 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+ .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_audit.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_audit.c
new file mode 100644
index 0000000000..d6487bf879
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_audit.c
@@ -0,0 +1,44 @@
+#undef __s390x__
+#include <asm/unistd.h>
+#include "audit.h"
+
+unsigned s390_dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+unsigned s390_chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+unsigned s390_write_class[] = {
+#include <asm-generic/audit_write.h>
+~0U
+};
+
+unsigned s390_read_class[] = {
+#include <asm-generic/audit_read.h>
+~0U
+};
+
+unsigned s390_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int s390_classify_syscall(unsigned syscall)
+{
+ switch(syscall) {
+ case __NR_open:
+ return 2;
+ case __NR_openat:
+ return 3;
+ case __NR_socketcall:
+ return 4;
+ case __NR_execve:
+ return 5;
+ default:
+ return 1;
+ }
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_exec_domain.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_exec_domain.c
new file mode 100644
index 0000000000..914d49444f
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_exec_domain.c
@@ -0,0 +1,29 @@
+/*
+ * Support for 32-bit Linux for S390 personality.
+ *
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Gerhard Tonn (ton@de.ibm.com)
+ *
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/personality.h>
+#include <linux/sched.h>
+
+static struct exec_domain s390_exec_domain;
+
+static int __init s390_init (void)
+{
+ s390_exec_domain.name = "Linux/s390";
+ s390_exec_domain.handler = NULL;
+ s390_exec_domain.pers_low = PER_LINUX32;
+ s390_exec_domain.pers_high = PER_LINUX32;
+ s390_exec_domain.signal_map = default_exec_domain.signal_map;
+ s390_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
+ register_exec_domain(&s390_exec_domain);
+ return 0;
+}
+
+__initcall(s390_init);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_linux.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_linux.c
new file mode 100644
index 0000000000..50b85d07dd
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_linux.c
@@ -0,0 +1,978 @@
+/*
+ * arch/s390x/kernel/linux32.c
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Gerhard Tonn (ton@de.ibm.com)
+ * Thomas Spatzier (tspat@de.ibm.com)
+ *
+ * Conversion between 31bit and 64bit native syscalls.
+ *
+ * Heavily inspired by the 32-bit Sparc compat code which is
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ *
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/signal.h>
+#include <linux/resource.h>
+#include <linux/times.h>
+#include <linux/utsname.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/slab.h>
+#include <linux/uio.h>
+#include <linux/nfs_fs.h>
+#include <linux/quota.h>
+#include <linux/module.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/cache.h>
+#include <linux/nfsd/xdr.h>
+#include <linux/nfsd/syscall.h>
+#include <linux/poll.h>
+#include <linux/personality.h>
+#include <linux/stat.h>
+#include <linux/filter.h>
+#include <linux/highmem.h>
+#include <linux/highuid.h>
+#include <linux/mman.h>
+#include <linux/ipv6.h>
+#include <linux/in.h>
+#include <linux/icmpv6.h>
+#include <linux/syscalls.h>
+#include <linux/sysctl.h>
+#include <linux/binfmts.h>
+#include <linux/capability.h>
+#include <linux/compat.h>
+#include <linux/vfs.h>
+#include <linux/ptrace.h>
+#include <linux/fadvise.h>
+#include <linux/ipc.h>
+
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include <net/scm.h>
+#include <net/sock.h>
+
+#include "compat_linux.h"
+
+long psw_user32_bits = (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+ PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
+long psw32_user_bits = (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME |
+ PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+ PSW32_MASK_PSTATE);
+
+/* For this source file, we want overflow handling. */
+
+#undef high2lowuid
+#undef high2lowgid
+#undef low2highuid
+#undef low2highgid
+#undef SET_UID16
+#undef SET_GID16
+#undef NEW_TO_OLD_UID
+#undef NEW_TO_OLD_GID
+#undef SET_OLDSTAT_UID
+#undef SET_OLDSTAT_GID
+#undef SET_STAT_UID
+#undef SET_STAT_GID
+
+#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
+#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
+#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
+#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
+#define SET_UID16(var, uid) var = high2lowuid(uid)
+#define SET_GID16(var, gid) var = high2lowgid(gid)
+#define NEW_TO_OLD_UID(uid) high2lowuid(uid)
+#define NEW_TO_OLD_GID(gid) high2lowgid(gid)
+#define SET_OLDSTAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
+#define SET_OLDSTAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
+#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
+#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
+
+asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
+{
+ return sys_chown(filename, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group)
+{
+ return sys_lchown(filename, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
+{
+ return sys_fchown(fd, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
+{
+ return sys_setregid(low2highgid(rgid), low2highgid(egid));
+}
+
+asmlinkage long sys32_setgid16(u16 gid)
+{
+ return sys_setgid((gid_t)gid);
+}
+
+asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
+{
+ return sys_setreuid(low2highuid(ruid), low2highuid(euid));
+}
+
+asmlinkage long sys32_setuid16(u16 uid)
+{
+ return sys_setuid((uid_t)uid);
+}
+
+asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
+{
+ return sys_setresuid(low2highuid(ruid), low2highuid(euid),
+ low2highuid(suid));
+}
+
+asmlinkage long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid)
+{
+ int retval;
+
+ if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
+ !(retval = put_user(high2lowuid(current->euid), euid)))
+ retval = put_user(high2lowuid(current->suid), suid);
+
+ return retval;
+}
+
+asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
+{
+ return sys_setresgid(low2highgid(rgid), low2highgid(egid),
+ low2highgid(sgid));
+}
+
+asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid)
+{
+ int retval;
+
+ if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
+ !(retval = put_user(high2lowgid(current->egid), egid)))
+ retval = put_user(high2lowgid(current->sgid), sgid);
+
+ return retval;
+}
+
+asmlinkage long sys32_setfsuid16(u16 uid)
+{
+ return sys_setfsuid((uid_t)uid);
+}
+
+asmlinkage long sys32_setfsgid16(u16 gid)
+{
+ return sys_setfsgid((gid_t)gid);
+}
+
+static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
+{
+ int i;
+ u16 group;
+
+ for (i = 0; i < group_info->ngroups; i++) {
+ group = (u16)GROUP_AT(group_info, i);
+ if (put_user(group, grouplist+i))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
+{
+ int i;
+ u16 group;
+
+ for (i = 0; i < group_info->ngroups; i++) {
+ if (get_user(group, grouplist+i))
+ return -EFAULT;
+ GROUP_AT(group_info, i) = (gid_t)group;
+ }
+
+ return 0;
+}
+
+asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
+{
+ int i;
+
+ if (gidsetsize < 0)
+ return -EINVAL;
+
+ get_group_info(current->group_info);
+ i = current->group_info->ngroups;
+ if (gidsetsize) {
+ if (i > gidsetsize) {
+ i = -EINVAL;
+ goto out;
+ }
+ if (groups16_to_user(grouplist, current->group_info)) {
+ i = -EFAULT;
+ goto out;
+ }
+ }
+out:
+ put_group_info(current->group_info);
+ return i;
+}
+
+asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist)
+{
+ struct group_info *group_info;
+ int retval;
+
+ if (!capable(CAP_SETGID))
+ return -EPERM;
+ if ((unsigned)gidsetsize > NGROUPS_MAX)
+ return -EINVAL;
+
+ group_info = groups_alloc(gidsetsize);
+ if (!group_info)
+ return -ENOMEM;
+ retval = groups16_from_user(group_info, grouplist);
+ if (retval) {
+ put_group_info(group_info);
+ return retval;
+ }
+
+ retval = set_current_groups(group_info);
+ put_group_info(group_info);
+
+ return retval;
+}
+
+asmlinkage long sys32_getuid16(void)
+{
+ return high2lowuid(current->uid);
+}
+
+asmlinkage long sys32_geteuid16(void)
+{
+ return high2lowuid(current->euid);
+}
+
+asmlinkage long sys32_getgid16(void)
+{
+ return high2lowgid(current->gid);
+}
+
+asmlinkage long sys32_getegid16(void)
+{
+ return high2lowgid(current->egid);
+}
+
+/* 32-bit timeval and related flotsam. */
+
+static inline long get_tv32(struct timeval *o, struct compat_timeval __user *i)
+{
+ return (!access_ok(VERIFY_READ, o, sizeof(*o)) ||
+ (__get_user(o->tv_sec, &i->tv_sec) ||
+ __get_user(o->tv_usec, &i->tv_usec)));
+}
+
+static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
+{
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+ (__put_user(i->tv_sec, &o->tv_sec) ||
+ __put_user(i->tv_usec, &o->tv_usec)));
+}
+
+/*
+ * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.
+ *
+ * This is really horribly ugly.
+ */
+#ifdef CONFIG_SYSVIPC
+asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr)
+{
+ if (call >> 16) /* hack for backward compatibility */
+ return -EINVAL;
+
+ call &= 0xffff;
+
+ switch (call) {
+ case SEMTIMEDOP:
+ return compat_sys_semtimedop(first, compat_ptr(ptr),
+ second, compat_ptr(third));
+ case SEMOP:
+ /* struct sembuf is the same on 32 and 64bit :)) */
+ return sys_semtimedop(first, compat_ptr(ptr),
+ second, NULL);
+ case SEMGET:
+ return sys_semget(first, second, third);
+ case SEMCTL:
+ return compat_sys_semctl(first, second, third,
+ compat_ptr(ptr));
+ case MSGSND:
+ return compat_sys_msgsnd(first, second, third,
+ compat_ptr(ptr));
+ case MSGRCV:
+ return compat_sys_msgrcv(first, second, 0, third,
+ 0, compat_ptr(ptr));
+ case MSGGET:
+ return sys_msgget((key_t) first, second);
+ case MSGCTL:
+ return compat_sys_msgctl(first, second, compat_ptr(ptr));
+ case SHMAT:
+ return compat_sys_shmat(first, second, third,
+ 0, compat_ptr(ptr));
+ case SHMDT:
+ return sys_shmdt(compat_ptr(ptr));
+ case SHMGET:
+ return sys_shmget(first, (unsigned)second, third);
+ case SHMCTL:
+ return compat_sys_shmctl(first, second, compat_ptr(ptr));
+ }
+
+ return -ENOSYS;
+}
+#endif
+
+asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
+{
+ if ((int)high < 0)
+ return -EINVAL;
+ else
+ return sys_truncate(path, (high << 32) | low);
+}
+
+asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
+{
+ if ((int)high < 0)
+ return -EINVAL;
+ else
+ return sys_ftruncate(fd, (high << 32) | low);
+}
+
+int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
+{
+ compat_ino_t ino;
+ int err;
+
+ if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
+ return -EOVERFLOW;
+
+ ino = stat->ino;
+ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+ return -EOVERFLOW;
+
+ err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
+ err |= put_user(stat->ino, &statbuf->st_ino);
+ err |= put_user(stat->mode, &statbuf->st_mode);
+ err |= put_user(stat->nlink, &statbuf->st_nlink);
+ err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
+ err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
+ err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
+ err |= put_user(stat->size, &statbuf->st_size);
+ err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
+ err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
+ err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
+ err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
+ err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
+ err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
+ err |= put_user(stat->blksize, &statbuf->st_blksize);
+ err |= put_user(stat->blocks, &statbuf->st_blocks);
+/* fixme
+ err |= put_user(0, &statbuf->__unused4[0]);
+ err |= put_user(0, &statbuf->__unused4[1]);
+*/
+ return err;
+}
+
+asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
+ struct compat_timespec __user *interval)
+{
+ struct timespec t;
+ int ret;
+ mm_segment_t old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+ ret = sys_sched_rr_get_interval(pid,
+ (struct timespec __force __user *) &t);
+ set_fs (old_fs);
+ if (put_compat_timespec(&t, interval))
+ return -EFAULT;
+ return ret;
+}
+
+asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
+ compat_sigset_t __user *oset, size_t sigsetsize)
+{
+ sigset_t s;
+ compat_sigset_t s32;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ if (set) {
+ if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
+ return -EFAULT;
+ switch (_NSIG_WORDS) {
+ case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
+ case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
+ case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
+ case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+ }
+ }
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigprocmask(how,
+ set ? (sigset_t __force __user *) &s : NULL,
+ oset ? (sigset_t __force __user *) &s : NULL,
+ sigsetsize);
+ set_fs (old_fs);
+ if (ret) return ret;
+ if (oset) {
+ switch (_NSIG_WORDS) {
+ case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+ case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+ case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+ case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+ }
+ if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
+ size_t sigsetsize)
+{
+ sigset_t s;
+ compat_sigset_t s32;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize);
+ set_fs (old_fs);
+ if (!ret) {
+ switch (_NSIG_WORDS) {
+ case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+ case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+ case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+ case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+ }
+ if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+asmlinkage long
+sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
+{
+ siginfo_t info;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ if (copy_siginfo_from_user32(&info, uinfo))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info);
+ set_fs (old_fs);
+ return ret;
+}
+
+/*
+ * sys32_execve() executes a new program after the asm stub has set
+ * things up for us. This should basically do what I want it to.
+ */
+asmlinkage long sys32_execve(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ char *filename;
+ unsigned long result;
+ int rc;
+
+ filename = getname(compat_ptr(regs->orig_gpr2));
+ if (IS_ERR(filename)) {
+ result = PTR_ERR(filename);
+ goto out;
+ }
+ rc = compat_do_execve(filename, compat_ptr(regs->gprs[3]),
+ compat_ptr(regs->gprs[4]), regs);
+ if (rc) {
+ result = rc;
+ goto out_putname;
+ }
+ task_lock(current);
+ current->ptrace &= ~PT_DTRACE;
+ task_unlock(current);
+ current->thread.fp_regs.fpc=0;
+ asm volatile("sfpc %0,0" : : "d" (0));
+ result = regs->gprs[2];
+out_putname:
+ putname(filename);
+out:
+ return result;
+}
+
+
+#ifdef CONFIG_MODULES
+
+asmlinkage long
+sys32_init_module(void __user *umod, unsigned long len,
+ const char __user *uargs)
+{
+ return sys_init_module(umod, len, uargs);
+}
+
+asmlinkage long
+sys32_delete_module(const char __user *name_user, unsigned int flags)
+{
+ return sys_delete_module(name_user, flags);
+}
+
+#else /* CONFIG_MODULES */
+
+asmlinkage long
+sys32_init_module(void __user *umod, unsigned long len,
+ const char __user *uargs)
+{
+ return -ENOSYS;
+}
+
+asmlinkage long
+sys32_delete_module(const char __user *name_user, unsigned int flags)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_MODULES */
+
+/* Translations due to time_t size differences. Which affects all
+ sorts of things, like timeval and itimerval. */
+
+extern struct timezone sys_tz;
+
+asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
+{
+ if (tv) {
+ struct timeval ktv;
+ do_gettimeofday(&ktv);
+ if (put_tv32(tv, &ktv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
+{
+ long usec;
+
+ if (!access_ok(VERIFY_READ, i, sizeof(*i)))
+ return -EFAULT;
+ if (__get_user(o->tv_sec, &i->tv_sec))
+ return -EFAULT;
+ if (__get_user(usec, &i->tv_usec))
+ return -EFAULT;
+ o->tv_nsec = usec * 1000;
+ return 0;
+}
+
+asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
+{
+ struct timespec kts;
+ struct timezone ktz;
+
+ if (tv) {
+ if (get_ts32(&kts, tv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_from_user(&ktz, tz, sizeof(ktz)))
+ return -EFAULT;
+ }
+
+ return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
+}
+
+/* These are here just in case some old sparc32 binary calls it. */
+asmlinkage long sys32_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
+
+asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
+ size_t count, u32 poshi, u32 poslo)
+{
+ if ((compat_ssize_t) count < 0)
+ return -EINVAL;
+ return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+asmlinkage long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
+ size_t count, u32 poshi, u32 poslo)
+{
+ if ((compat_ssize_t) count < 0)
+ return -EINVAL;
+ return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
+{
+ return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
+}
+
+asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, size_t count)
+{
+ mm_segment_t old_fs = get_fs();
+ int ret;
+ off_t of;
+
+ if (offset && get_user(of, offset))
+ return -EFAULT;
+
+ set_fs(KERNEL_DS);
+ ret = sys_sendfile(out_fd, in_fd,
+ offset ? (off_t __force __user *) &of : NULL, count);
+ set_fs(old_fs);
+
+ if (offset && put_user(of, offset))
+ return -EFAULT;
+
+ return ret;
+}
+
+asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
+ compat_loff_t __user *offset, s32 count)
+{
+ mm_segment_t old_fs = get_fs();
+ int ret;
+ loff_t lof;
+
+ if (offset && get_user(lof, offset))
+ return -EFAULT;
+
+ set_fs(KERNEL_DS);
+ ret = sys_sendfile64(out_fd, in_fd,
+ offset ? (loff_t __force __user *) &lof : NULL,
+ count);
+ set_fs(old_fs);
+
+ if (offset && put_user(lof, offset))
+ return -EFAULT;
+
+ return ret;
+}
+
+#ifdef CONFIG_SYSCTL_SYSCALL
+struct __sysctl_args32 {
+ u32 name;
+ int nlen;
+ u32 oldval;
+ u32 oldlenp;
+ u32 newval;
+ u32 newlen;
+ u32 __unused[4];
+};
+
+asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
+{
+ struct __sysctl_args32 tmp;
+ int error;
+ size_t oldlen;
+ size_t __user *oldlenp = NULL;
+ unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
+
+ if (copy_from_user(&tmp, args, sizeof(tmp)))
+ return -EFAULT;
+
+ if (tmp.oldval && tmp.oldlenp) {
+ /* Duh, this is ugly and might not work if sysctl_args
+ is in read-only memory, but do_sysctl does indirectly
+ a lot of uaccess in both directions and we'd have to
+ basically copy the whole sysctl.c here, and
+ glibc's __sysctl uses rw memory for the structure
+ anyway. */
+ if (get_user(oldlen, (u32 __user *)compat_ptr(tmp.oldlenp)) ||
+ put_user(oldlen, (size_t __user *)addr))
+ return -EFAULT;
+ oldlenp = (size_t __user *)addr;
+ }
+
+ lock_kernel();
+ error = do_sysctl(compat_ptr(tmp.name), tmp.nlen, compat_ptr(tmp.oldval),
+ oldlenp, compat_ptr(tmp.newval), tmp.newlen);
+ unlock_kernel();
+ if (oldlenp) {
+ if (!error) {
+ if (get_user(oldlen, (size_t __user *)addr) ||
+ put_user(oldlen, (u32 __user *)compat_ptr(tmp.oldlenp)))
+ error = -EFAULT;
+ }
+ if (copy_to_user(args->__unused, tmp.__unused,
+ sizeof(tmp.__unused)))
+ error = -EFAULT;
+ }
+ return error;
+}
+#endif
+
+struct stat64_emu31 {
+ unsigned long long st_dev;
+ unsigned int __pad1;
+#define STAT64_HAS_BROKEN_ST_INO 1
+ u32 __st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+ u32 st_uid;
+ u32 st_gid;
+ unsigned long long st_rdev;
+ unsigned int __pad3;
+ long st_size;
+ u32 st_blksize;
+ unsigned char __pad4[4];
+ u32 __pad5; /* future possible st_blocks high bits */
+ u32 st_blocks; /* Number 512-byte blocks allocated. */
+ u32 st_atime;
+ u32 __pad6;
+ u32 st_mtime;
+ u32 __pad7;
+ u32 st_ctime;
+ u32 __pad8; /* will be high 32 bits of ctime someday */
+ unsigned long st_ino;
+};
+
+static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat)
+{
+ struct stat64_emu31 tmp;
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ tmp.st_dev = huge_encode_dev(stat->dev);
+ tmp.st_ino = stat->ino;
+ tmp.__st_ino = (u32)stat->ino;
+ tmp.st_mode = stat->mode;
+ tmp.st_nlink = (unsigned int)stat->nlink;
+ tmp.st_uid = stat->uid;
+ tmp.st_gid = stat->gid;
+ tmp.st_rdev = huge_encode_dev(stat->rdev);
+ tmp.st_size = stat->size;
+ tmp.st_blksize = (u32)stat->blksize;
+ tmp.st_blocks = (u32)stat->blocks;
+ tmp.st_atime = (u32)stat->atime.tv_sec;
+ tmp.st_mtime = (u32)stat->mtime.tv_sec;
+ tmp.st_ctime = (u32)stat->ctime.tv_sec;
+
+ return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
+
+asmlinkage long sys32_stat64(char __user * filename, struct stat64_emu31 __user * statbuf)
+{
+ struct kstat stat;
+ int ret = vfs_stat(filename, &stat);
+ if (!ret)
+ ret = cp_stat64(statbuf, &stat);
+ return ret;
+}
+
+asmlinkage long sys32_lstat64(char __user * filename, struct stat64_emu31 __user * statbuf)
+{
+ struct kstat stat;
+ int ret = vfs_lstat(filename, &stat);
+ if (!ret)
+ ret = cp_stat64(statbuf, &stat);
+ return ret;
+}
+
+asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 __user * statbuf)
+{
+ struct kstat stat;
+ int ret = vfs_fstat(fd, &stat);
+ if (!ret)
+ ret = cp_stat64(statbuf, &stat);
+ return ret;
+}
+
+asmlinkage long sys32_fstatat64(unsigned int dfd, char __user *filename,
+ struct stat64_emu31 __user* statbuf, int flag)
+{
+ struct kstat stat;
+ int error = -EINVAL;
+
+ if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+ goto out;
+
+ if (flag & AT_SYMLINK_NOFOLLOW)
+ error = vfs_lstat_fd(dfd, filename, &stat);
+ else
+ error = vfs_stat_fd(dfd, filename, &stat);
+
+ if (!error)
+ error = cp_stat64(statbuf, &stat);
+out:
+ return error;
+}
+
+/*
+ * Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct_emu31 {
+ u32 addr;
+ u32 len;
+ u32 prot;
+ u32 flags;
+ u32 fd;
+ u32 offset;
+};
+
+/* common code for old and new mmaps */
+static inline long do_mmap2(
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+{
+ struct file * file = NULL;
+ unsigned long error = -EBADF;
+
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ if (!(flags & MAP_ANONYMOUS)) {
+ file = fget(fd);
+ if (!file)
+ goto out;
+ }
+
+ down_write(&current->mm->mmap_sem);
+ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) {
+ /* Result is out of bounds. */
+ do_munmap(current->mm, addr, len);
+ error = -ENOMEM;
+ }
+ up_write(&current->mm->mmap_sem);
+
+ if (file)
+ fput(file);
+out:
+ return error;
+}
+
+
+asmlinkage unsigned long
+old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
+{
+ struct mmap_arg_struct_emu31 a;
+ int error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+
+ error = -EINVAL;
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+out:
+ return error;
+}
+
+asmlinkage long
+sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
+{
+ struct mmap_arg_struct_emu31 a;
+ int error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+out:
+ return error;
+}
+
+asmlinkage long sys32_read(unsigned int fd, char __user * buf, size_t count)
+{
+ if ((compat_ssize_t) count < 0)
+ return -EINVAL;
+
+ return sys_read(fd, buf, count);
+}
+
+asmlinkage long sys32_write(unsigned int fd, char __user * buf, size_t count)
+{
+ if ((compat_ssize_t) count < 0)
+ return -EINVAL;
+
+ return sys_write(fd, buf, count);
+}
+
+asmlinkage long sys32_clone(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ unsigned long clone_flags;
+ unsigned long newsp;
+ int __user *parent_tidptr, *child_tidptr;
+
+ clone_flags = regs->gprs[3] & 0xffffffffUL;
+ newsp = regs->orig_gpr2 & 0x7fffffffUL;
+ parent_tidptr = compat_ptr(regs->gprs[4]);
+ child_tidptr = compat_ptr(regs->gprs[5]);
+ if (!newsp)
+ newsp = regs->gprs[15];
+ return do_fork(clone_flags, newsp, regs, 0,
+ parent_tidptr, child_tidptr);
+}
+
+/*
+ * 31 bit emulation wrapper functions for sys_fadvise64/fadvise64_64.
+ * These need to rewrite the advise values for POSIX_FADV_{DONTNEED,NOREUSE}
+ * because the 31 bit values differ from the 64 bit values.
+ */
+
+asmlinkage long
+sys32_fadvise64(int fd, loff_t offset, size_t len, int advise)
+{
+ if (advise == 4)
+ advise = POSIX_FADV_DONTNEED;
+ else if (advise == 5)
+ advise = POSIX_FADV_NOREUSE;
+ return sys_fadvise64(fd, offset, len, advise);
+}
+
+struct fadvise64_64_args {
+ int fd;
+ long long offset;
+ long long len;
+ int advice;
+};
+
+asmlinkage long
+sys32_fadvise64_64(struct fadvise64_64_args __user *args)
+{
+ struct fadvise64_64_args a;
+
+ if ( copy_from_user(&a, args, sizeof(a)) )
+ return -EFAULT;
+ if (a.advice == 4)
+ a.advice = POSIX_FADV_DONTNEED;
+ else if (a.advice == 5)
+ a.advice = POSIX_FADV_NOREUSE;
+ return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_linux.h b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_linux.h
new file mode 100644
index 0000000000..e89f8c0c42
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_linux.h
@@ -0,0 +1,165 @@
+#ifndef _ASM_S390X_S390_H
+#define _ASM_S390X_S390_H
+
+#include <linux/compat.h>
+#include <linux/socket.h>
+#include <linux/syscalls.h>
+#include <linux/nfs_fs.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/export.h>
+
+/* Macro that masks the high order bit of an 32 bit pointer and converts it*/
+/* to a 64 bit pointer */
+#define A(__x) ((unsigned long)((__x) & 0x7FFFFFFFUL))
+#define AA(__x) \
+ ((unsigned long)(__x))
+
+/* Now 32bit compatibility types */
+struct ipc_kludge_32 {
+ __u32 msgp; /* pointer */
+ __s32 msgtyp;
+};
+
+struct old_sigaction32 {
+ __u32 sa_handler; /* Really a pointer, but need to deal with 32 bits */
+ compat_old_sigset_t sa_mask; /* A 32 bit mask */
+ __u32 sa_flags;
+ __u32 sa_restorer; /* Another 32 bit pointer */
+};
+
+typedef struct compat_siginfo {
+ int si_signo;
+ int si_errno;
+ int si_code;
+
+ union {
+ int _pad[((128/sizeof(int)) - 3)];
+
+ /* kill() */
+ struct {
+ pid_t _pid; /* sender's pid */
+ uid_t _uid; /* sender's uid */
+ } _kill;
+
+ /* POSIX.1b timers */
+ struct {
+ compat_timer_t _tid; /* timer id */
+ int _overrun; /* overrun count */
+ compat_sigval_t _sigval; /* same as below */
+ int _sys_private; /* not to be passed to user */
+ } _timer;
+
+ /* POSIX.1b signals */
+ struct {
+ pid_t _pid; /* sender's pid */
+ uid_t _uid; /* sender's uid */
+ compat_sigval_t _sigval;
+ } _rt;
+
+ /* SIGCHLD */
+ struct {
+ pid_t _pid; /* which child */
+ uid_t _uid; /* sender's uid */
+ int _status;/* exit code */
+ compat_clock_t _utime;
+ compat_clock_t _stime;
+ } _sigchld;
+
+ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+ struct {
+ __u32 _addr; /* faulting insn/memory ref. - pointer */
+ } _sigfault;
+
+ /* SIGPOLL */
+ struct {
+ int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ int _fd;
+ } _sigpoll;
+ } _sifields;
+} compat_siginfo_t;
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid _sifields._kill._pid
+#define si_uid _sifields._kill._uid
+#define si_status _sifields._sigchld._status
+#define si_utime _sifields._sigchld._utime
+#define si_stime _sifields._sigchld._stime
+#define si_value _sifields._rt._sigval
+#define si_int _sifields._rt._sigval.sival_int
+#define si_ptr _sifields._rt._sigval.sival_ptr
+#define si_addr _sifields._sigfault._addr
+#define si_band _sifields._sigpoll._band
+#define si_fd _sifields._sigpoll._fd
+#define si_tid _sifields._timer._tid
+#define si_overrun _sifields._timer._overrun
+
+/* asm/sigcontext.h */
+typedef union
+{
+ __u64 d;
+ __u32 f;
+} freg_t32;
+
+typedef struct
+{
+ unsigned int fpc;
+ freg_t32 fprs[__NUM_FPRS];
+} _s390_fp_regs32;
+
+typedef struct
+{
+ __u32 mask;
+ __u32 addr;
+} _psw_t32 __attribute__ ((aligned(8)));
+
+typedef struct
+{
+ _psw_t32 psw;
+ __u32 gprs[__NUM_GPRS];
+ __u32 acrs[__NUM_ACRS];
+} _s390_regs_common32;
+
+typedef struct
+{
+ _s390_regs_common32 regs;
+ _s390_fp_regs32 fpregs;
+} _sigregs32;
+
+#define _SIGCONTEXT_NSIG32 64
+#define _SIGCONTEXT_NSIG_BPW32 32
+#define __SIGNAL_FRAMESIZE32 96
+#define _SIGMASK_COPY_SIZE32 (sizeof(u32)*2)
+
+struct sigcontext32
+{
+ __u32 oldmask[_COMPAT_NSIG_WORDS];
+ __u32 sregs; /* pointer */
+};
+
+/* asm/signal.h */
+struct sigaction32 {
+ __u32 sa_handler; /* pointer */
+ __u32 sa_flags;
+ __u32 sa_restorer; /* pointer */
+ compat_sigset_t sa_mask; /* mask last for extensibility */
+};
+
+typedef struct {
+ __u32 ss_sp; /* pointer */
+ int ss_flags;
+ compat_size_t ss_size;
+} stack_t32;
+
+/* asm/ucontext.h */
+struct ucontext32 {
+ __u32 uc_flags;
+ __u32 uc_link; /* pointer */
+ stack_t32 uc_stack;
+ _sigregs32 uc_mcontext;
+ compat_sigset_t uc_sigmask; /* mask last for extensibility */
+};
+
+#endif /* _ASM_S390X_S390_H */
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_ptrace.h b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_ptrace.h
new file mode 100644
index 0000000000..419aef913e
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_ptrace.h
@@ -0,0 +1,83 @@
+#ifndef _PTRACE32_H
+#define _PTRACE32_H
+
+#include "compat_linux.h" /* needed for _psw_t32 */
+
+typedef struct {
+ __u32 cr[3];
+} per_cr_words32;
+
+typedef struct {
+ __u16 perc_atmid; /* 0x096 */
+ __u32 address; /* 0x098 */
+ __u8 access_id; /* 0x0a1 */
+} per_lowcore_words32;
+
+typedef struct {
+ union {
+ per_cr_words32 words;
+ } control_regs;
+ /*
+ * Use these flags instead of setting em_instruction_fetch
+ * directly they are used so that single stepping can be
+ * switched on & off while not affecting other tracing
+ */
+ unsigned single_step : 1;
+ unsigned instruction_fetch : 1;
+ unsigned : 30;
+ /*
+ * These addresses are copied into cr10 & cr11 if single
+ * stepping is switched off
+ */
+ __u32 starting_addr;
+ __u32 ending_addr;
+ union {
+ per_lowcore_words32 words;
+ } lowcore;
+} per_struct32;
+
+struct user_regs_struct32
+{
+ _psw_t32 psw;
+ u32 gprs[NUM_GPRS];
+ u32 acrs[NUM_ACRS];
+ u32 orig_gpr2;
+ s390_fp_regs fp_regs;
+ /*
+ * These per registers are in here so that gdb can modify them
+ * itself as there is no "official" ptrace interface for hardware
+ * watchpoints. This is the way intel does it.
+ */
+ per_struct32 per_info;
+ u32 ieee_instruction_pointer;
+ /* Used to give failing instruction back to user for ieee exceptions */
+};
+
+struct user32 {
+ /* We start with the registers, to mimic the way that "memory"
+ is returned from the ptrace(3,...) function. */
+ struct user_regs_struct32 regs; /* Where the registers are actually stored */
+ /* The rest of this junk is to help gdb figure out what goes where */
+ u32 u_tsize; /* Text segment size (pages). */
+ u32 u_dsize; /* Data segment size (pages). */
+ u32 u_ssize; /* Stack segment size (pages). */
+ u32 start_code; /* Starting virtual address of text. */
+ u32 start_stack; /* Starting virtual address of stack area.
+ This is actually the bottom of the stack,
+ the top of the stack is always found in the
+ esp register. */
+ s32 signal; /* Signal that caused the core dump. */
+ u32 u_ar0; /* Used by gdb to help find the values for */
+ /* the registers. */
+ u32 magic; /* To uniquely identify a core file */
+ char u_comm[32]; /* User command that was responsible */
+};
+
+typedef struct
+{
+ __u32 len;
+ __u32 kernel_addr;
+ __u32 process_addr;
+} ptrace_area_emu31;
+
+#endif /* _PTRACE32_H */
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_signal.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_signal.c
new file mode 100644
index 0000000000..a5692c460b
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_signal.c
@@ -0,0 +1,586 @@
+/*
+ * arch/s390/kernel/compat_signal.c
+ *
+ * Copyright (C) IBM Corp. 2000,2006
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ * Gerhard Tonn (ton@de.ibm.com)
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
+ */
+
+#include <linux/compat.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/tty.h>
+#include <linux/personality.h>
+#include <linux/binfmts.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/lowcore.h>
+#include "compat_linux.h"
+#include "compat_ptrace.h"
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+typedef struct
+{
+ __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
+ struct sigcontext32 sc;
+ _sigregs32 sregs;
+ int signo;
+ __u8 retcode[S390_SYSCALL_SIZE];
+} sigframe32;
+
+typedef struct
+{
+ __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
+ __u8 retcode[S390_SYSCALL_SIZE];
+ compat_siginfo_t info;
+ struct ucontext32 uc;
+} rt_sigframe32;
+
+int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
+{
+ int err;
+
+ if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
+ return -EFAULT;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member.
+ This routine must convert siginfo from 64bit to 32bit as well
+ at the same time. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ if (from->si_code < 0)
+ err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+ else {
+ switch (from->si_code >> 16) {
+ case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ >> 16:
+ err |= __put_user(from->si_int, &to->si_int);
+ /* fallthrough */
+ case __SI_KILL >> 16:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ break;
+ case __SI_FAULT >> 16:
+ err |= __put_user((unsigned long) from->si_addr,
+ &to->si_addr);
+ break;
+ case __SI_POLL >> 16:
+ err |= __put_user(from->si_band, &to->si_band);
+ err |= __put_user(from->si_fd, &to->si_fd);
+ break;
+ case __SI_TIMER >> 16:
+ err |= __put_user(from->si_tid, &to->si_tid);
+ err |= __put_user(from->si_overrun, &to->si_overrun);
+ err |= __put_user(from->si_int, &to->si_int);
+ break;
+ default:
+ break;
+ }
+ }
+ return err;
+}
+
+int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
+{
+ int err;
+ u32 tmp;
+
+ if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
+ return -EFAULT;
+
+ err = __get_user(to->si_signo, &from->si_signo);
+ err |= __get_user(to->si_errno, &from->si_errno);
+ err |= __get_user(to->si_code, &from->si_code);
+
+ if (to->si_code < 0)
+ err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+ else {
+ switch (to->si_code >> 16) {
+ case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ >> 16:
+ err |= __get_user(to->si_int, &from->si_int);
+ /* fallthrough */
+ case __SI_KILL >> 16:
+ err |= __get_user(to->si_pid, &from->si_pid);
+ err |= __get_user(to->si_uid, &from->si_uid);
+ break;
+ case __SI_CHLD >> 16:
+ err |= __get_user(to->si_pid, &from->si_pid);
+ err |= __get_user(to->si_uid, &from->si_uid);
+ err |= __get_user(to->si_utime, &from->si_utime);
+ err |= __get_user(to->si_stime, &from->si_stime);
+ err |= __get_user(to->si_status, &from->si_status);
+ break;
+ case __SI_FAULT >> 16:
+ err |= __get_user(tmp, &from->si_addr);
+ to->si_addr = (void __user *)(u64) (tmp & PSW32_ADDR_INSN);
+ break;
+ case __SI_POLL >> 16:
+ err |= __get_user(to->si_band, &from->si_band);
+ err |= __get_user(to->si_fd, &from->si_fd);
+ break;
+ case __SI_TIMER >> 16:
+ err |= __get_user(to->si_tid, &from->si_tid);
+ err |= __get_user(to->si_overrun, &from->si_overrun);
+ err |= __get_user(to->si_int, &from->si_int);
+ break;
+ default:
+ break;
+ }
+ }
+ return err;
+}
+
+asmlinkage long
+sys32_sigaction(int sig, const struct old_sigaction32 __user *act,
+ struct old_sigaction32 __user *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ unsigned long sa_handler, sa_restorer;
+ int ret;
+
+ if (act) {
+ compat_old_sigset_t mask;
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(sa_handler, &act->sa_handler) ||
+ __get_user(sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
+ return -EFAULT;
+ new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
+ new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer;
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ sa_handler = (unsigned long) old_ka.sa.sa_handler;
+ sa_restorer = (unsigned long) old_ka.sa.sa_restorer;
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(sa_handler, &oact->sa_handler) ||
+ __put_user(sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+asmlinkage long
+sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
+ struct sigaction32 __user *oact, size_t sigsetsize)
+{
+ struct k_sigaction new_ka, old_ka;
+ unsigned long sa_handler;
+ int ret;
+ compat_sigset_t set32;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(compat_sigset_t))
+ return -EINVAL;
+
+ if (act) {
+ ret = get_user(sa_handler, &act->sa_handler);
+ ret |= __copy_from_user(&set32, &act->sa_mask,
+ sizeof(compat_sigset_t));
+ switch (_NSIG_WORDS) {
+ case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
+ | (((long)set32.sig[7]) << 32);
+ case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
+ | (((long)set32.sig[5]) << 32);
+ case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
+ | (((long)set32.sig[3]) << 32);
+ case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
+ | (((long)set32.sig[1]) << 32);
+ }
+ ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+
+ if (ret)
+ return -EFAULT;
+ new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ switch (_NSIG_WORDS) {
+ case 4:
+ set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
+ set32.sig[6] = old_ka.sa.sa_mask.sig[3];
+ case 3:
+ set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
+ set32.sig[4] = old_ka.sa.sa_mask.sig[2];
+ case 2:
+ set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
+ set32.sig[2] = old_ka.sa.sa_mask.sig[1];
+ case 1:
+ set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
+ set32.sig[0] = old_ka.sa.sa_mask.sig[0];
+ }
+ ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler);
+ ret |= __copy_to_user(&oact->sa_mask, &set32,
+ sizeof(compat_sigset_t));
+ ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ }
+
+ return ret;
+}
+
+asmlinkage long
+sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ stack_t kss, koss;
+ unsigned long ss_sp;
+ int ret, err = 0;
+ mm_segment_t old_fs = get_fs();
+
+ if (uss) {
+ if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
+ return -EFAULT;
+ err |= __get_user(ss_sp, &uss->ss_sp);
+ err |= __get_user(kss.ss_size, &uss->ss_size);
+ err |= __get_user(kss.ss_flags, &uss->ss_flags);
+ if (err)
+ return -EFAULT;
+ kss.ss_sp = (void __user *) ss_sp;
+ }
+
+ set_fs (KERNEL_DS);
+ ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
+ (stack_t __force __user *) (uoss ? &koss : NULL),
+ regs->gprs[15]);
+ set_fs (old_fs);
+
+ if (!ret && uoss) {
+ if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
+ return -EFAULT;
+ ss_sp = (unsigned long) koss.ss_sp;
+ err |= __put_user(ss_sp, &uoss->ss_sp);
+ err |= __put_user(koss.ss_size, &uoss->ss_size);
+ err |= __put_user(koss.ss_flags, &uoss->ss_flags);
+ if (err)
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
+{
+ _s390_regs_common32 regs32;
+ int err, i;
+
+ regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits,
+ (__u32)(regs->psw.mask >> 32));
+ regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
+ for (i = 0; i < NUM_GPRS; i++)
+ regs32.gprs[i] = (__u32) regs->gprs[i];
+ save_access_regs(current->thread.acrs);
+ memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs));
+ err = __copy_to_user(&sregs->regs, &regs32, sizeof(regs32));
+ if (err)
+ return err;
+ save_fp_regs(&current->thread.fp_regs);
+ /* s390_fp_regs and _s390_fp_regs32 are the same ! */
+ return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
+ sizeof(_s390_fp_regs32));
+}
+
+static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
+{
+ _s390_regs_common32 regs32;
+ int err, i;
+
+ /* Alwys make any pending restarted system call return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+ err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
+ if (err)
+ return err;
+ regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask,
+ (__u64)regs32.psw.mask << 32);
+ regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
+ for (i = 0; i < NUM_GPRS; i++)
+ regs->gprs[i] = (__u64) regs32.gprs[i];
+ memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs));
+ restore_access_regs(current->thread.acrs);
+
+ err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
+ sizeof(_s390_fp_regs32));
+ current->thread.fp_regs.fpc &= FPC_VALID_MASK;
+ if (err)
+ return err;
+
+ restore_fp_regs(&current->thread.fp_regs);
+ regs->trap = -1; /* disable syscall checks */
+ return 0;
+}
+
+asmlinkage long sys32_sigreturn(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
+ sigset_t set;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (restore_sigregs32(regs, &frame->sregs))
+ goto badframe;
+
+ return regs->gprs[2];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+asmlinkage long sys32_rt_sigreturn(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
+ sigset_t set;
+ stack_t st;
+ __u32 ss_sp;
+ int err;
+ mm_segment_t old_fs = get_fs();
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
+ goto badframe;
+
+ err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
+ st.ss_sp = compat_ptr(ss_sp);
+ err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
+ if (err)
+ goto badframe;
+
+ set_fs (KERNEL_DS);
+ do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
+ set_fs (old_fs);
+
+ return regs->gprs[2];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+
+/*
+ * Determine which stack to use..
+ */
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+ unsigned long sp;
+
+ /* Default to using normal stack */
+ sp = (unsigned long) A(regs->gprs[15]);
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (! sas_ss_flags(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+ }
+
+ /* This is the legacy signal stack switching. */
+ else if (!user_mode(regs) &&
+ !(ka->sa.sa_flags & SA_RESTORER) &&
+ ka->sa.sa_restorer) {
+ sp = (unsigned long) ka->sa.sa_restorer;
+ }
+
+ return (void __user *)((sp - frame_size) & -8ul);
+}
+
+static inline int map_signal(int sig)
+{
+ if (current_thread_info()->exec_domain
+ && current_thread_info()->exec_domain->signal_invmap
+ && sig < 32)
+ return current_thread_info()->exec_domain->signal_invmap[sig];
+ else
+ return sig;
+}
+
+static int setup_frame32(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs * regs)
+{
+ sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
+ goto give_sigsegv;
+
+ if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
+ goto give_sigsegv;
+
+ if (save_sigregs32(regs, &frame->sregs))
+ goto give_sigsegv;
+ if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ regs->gprs[14] = (__u64) ka->sa.sa_restorer;
+ } else {
+ regs->gprs[14] = (__u64) frame->retcode;
+ if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
+ (u16 __user *)(frame->retcode)))
+ goto give_sigsegv;
+ }
+
+ /* Set up backchain. */
+ if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
+ goto give_sigsegv;
+
+ /* Set up registers for signal handler */
+ regs->gprs[15] = (__u64) frame;
+ regs->psw.addr = (__u64) ka->sa.sa_handler;
+
+ regs->gprs[2] = map_signal(sig);
+ regs->gprs[3] = (__u64) &frame->sc;
+
+ /* We forgot to include these in the sigcontext.
+ To avoid breaking binary compatibility, they are passed as args. */
+ regs->gprs[4] = current->thread.trap_no;
+ regs->gprs[5] = current->thread.prot_addr;
+
+ /* Place signal number on stack to allow backtrace from handler. */
+ if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
+ goto give_sigsegv;
+ return 0;
+
+give_sigsegv:
+ force_sigsegv(sig, current);
+ return -EFAULT;
+}
+
+static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs * regs)
+{
+ int err = 0;
+ rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
+ goto give_sigsegv;
+
+ if (copy_siginfo_to_user32(&frame->info, info))
+ goto give_sigsegv;
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->gprs[15]),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ regs->gprs[14] = (__u64) ka->sa.sa_restorer;
+ } else {
+ regs->gprs[14] = (__u64) frame->retcode;
+ err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
+ (u16 __user *)(frame->retcode));
+ }
+
+ /* Set up backchain. */
+ if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
+ goto give_sigsegv;
+
+ /* Set up registers for signal handler */
+ regs->gprs[15] = (__u64) frame;
+ regs->psw.addr = (__u64) ka->sa.sa_handler;
+
+ regs->gprs[2] = map_signal(sig);
+ regs->gprs[3] = (__u64) &frame->info;
+ regs->gprs[4] = (__u64) &frame->uc;
+ return 0;
+
+give_sigsegv:
+ force_sigsegv(sig, current);
+ return -EFAULT;
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+int
+handle_signal32(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+{
+ int ret;
+
+ /* Set up the stack frame */
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ ret = setup_rt_frame32(sig, ka, info, oldset, regs);
+ else
+ ret = setup_frame32(sig, ka, oldset, regs);
+
+ if (ret == 0) {
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ }
+ return ret;
+}
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_wrapper.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_wrapper.S
new file mode 100644
index 0000000000..743d54f0b8
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/compat_wrapper.S
@@ -0,0 +1,1734 @@
+/*
+* arch/s390/kernel/compat_wrapper.S
+* wrapper for 31 bit compatible system calls.
+*
+* Copyright (C) IBM Corp. 2000,2006
+* Author(s): Gerhard Tonn (ton@de.ibm.com),
+* Thomas Spatzier (tspat@de.ibm.com)
+*/
+
+ .globl sys32_exit_wrapper
+sys32_exit_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_exit # branch to sys_exit
+
+ .globl sys32_read_wrapper
+sys32_read_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # char *
+ llgfr %r4,%r4 # size_t
+ jg sys32_read # branch to sys_read
+
+ .globl sys32_write_wrapper
+sys32_write_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # size_t
+ jg sys32_write # branch to system call
+
+ .globl sys32_open_wrapper
+sys32_open_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ jg sys_open # branch to system call
+
+ .globl sys32_close_wrapper
+sys32_close_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_close # branch to system call
+
+ .globl sys32_creat_wrapper
+sys32_creat_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_creat # branch to system call
+
+ .globl sys32_link_wrapper
+sys32_link_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_link # branch to system call
+
+ .globl sys32_unlink_wrapper
+sys32_unlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_unlink # branch to system call
+
+ .globl sys32_chdir_wrapper
+sys32_chdir_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_chdir # branch to system call
+
+ .globl sys32_time_wrapper
+sys32_time_wrapper:
+ llgtr %r2,%r2 # int *
+ jg compat_sys_time # branch to system call
+
+ .globl sys32_mknod_wrapper
+sys32_mknod_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ llgfr %r4,%r4 # dev
+ jg sys_mknod # branch to system call
+
+ .globl sys32_chmod_wrapper
+sys32_chmod_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # mode_t
+ jg sys_chmod # branch to system call
+
+ .globl sys32_lchown16_wrapper
+sys32_lchown16_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_uid_emu31_t
+ jg sys32_lchown16 # branch to system call
+
+ .globl sys32_lseek_wrapper
+sys32_lseek_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ lgfr %r3,%r3 # off_t
+ llgfr %r4,%r4 # unsigned int
+ jg sys_lseek # branch to system call
+
+#sys32_getpid_wrapper # void
+
+ .globl sys32_mount_wrapper
+sys32_mount_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # char *
+ llgfr %r5,%r5 # unsigned long
+ llgtr %r6,%r6 # void *
+ jg compat_sys_mount # branch to system call
+
+ .globl sys32_oldumount_wrapper
+sys32_oldumount_wrapper:
+ llgtr %r2,%r2 # char *
+ jg sys_oldumount # branch to system call
+
+ .globl sys32_setuid16_wrapper
+sys32_setuid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ jg sys32_setuid16 # branch to system call
+
+#sys32_getuid16_wrapper # void
+
+ .globl sys32_ptrace_wrapper
+sys32_ptrace_wrapper:
+ lgfr %r2,%r2 # long
+ lgfr %r3,%r3 # long
+ llgtr %r4,%r4 # long
+ llgfr %r5,%r5 # long
+ jg sys_ptrace # branch to system call
+
+ .globl sys32_alarm_wrapper
+sys32_alarm_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_alarm # branch to system call
+
+#sys32_pause_wrapper # void
+
+ .globl compat_sys_utime_wrapper
+compat_sys_utime_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct compat_utimbuf *
+ jg compat_sys_utime # branch to system call
+
+ .globl sys32_access_wrapper
+sys32_access_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_access # branch to system call
+
+ .globl sys32_nice_wrapper
+sys32_nice_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_nice # branch to system call
+
+#sys32_sync_wrapper # void
+
+ .globl sys32_kill_wrapper
+sys32_kill_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ jg sys_kill # branch to system call
+
+ .globl sys32_rename_wrapper
+sys32_rename_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_rename # branch to system call
+
+ .globl sys32_mkdir_wrapper
+sys32_mkdir_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_mkdir # branch to system call
+
+ .globl sys32_rmdir_wrapper
+sys32_rmdir_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_rmdir # branch to system call
+
+ .globl sys32_dup_wrapper
+sys32_dup_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_dup # branch to system call
+
+ .globl sys32_pipe_wrapper
+sys32_pipe_wrapper:
+ llgtr %r2,%r2 # u32 *
+ jg sys_pipe # branch to system call
+
+ .globl compat_sys_times_wrapper
+compat_sys_times_wrapper:
+ llgtr %r2,%r2 # struct compat_tms *
+ jg compat_sys_times # branch to system call
+
+ .globl sys32_brk_wrapper
+sys32_brk_wrapper:
+ llgtr %r2,%r2 # unsigned long
+ jg sys_brk # branch to system call
+
+ .globl sys32_setgid16_wrapper
+sys32_setgid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ jg sys32_setgid16 # branch to system call
+
+#sys32_getgid16_wrapper # void
+
+ .globl sys32_signal_wrapper
+sys32_signal_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # __sighandler_t
+ jg sys_signal
+
+#sys32_geteuid16_wrapper # void
+
+#sys32_getegid16_wrapper # void
+
+ .globl sys32_acct_wrapper
+sys32_acct_wrapper:
+ llgtr %r2,%r2 # char *
+ jg sys_acct # branch to system call
+
+ .globl sys32_umount_wrapper
+sys32_umount_wrapper:
+ llgtr %r2,%r2 # char *
+ lgfr %r3,%r3 # int
+ jg sys_umount # branch to system call
+
+ .globl compat_sys_ioctl_wrapper
+compat_sys_ioctl_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ llgfr %r4,%r4 # unsigned int
+ jg compat_sys_ioctl # branch to system call
+
+ .globl compat_sys_fcntl_wrapper
+compat_sys_fcntl_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ llgfr %r4,%r4 # unsigned long
+ jg compat_sys_fcntl # branch to system call
+
+ .globl sys32_setpgid_wrapper
+sys32_setpgid_wrapper:
+ lgfr %r2,%r2 # pid_t
+ lgfr %r3,%r3 # pid_t
+ jg sys_setpgid # branch to system call
+
+ .globl sys32_umask_wrapper
+sys32_umask_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_umask # branch to system call
+
+ .globl sys32_chroot_wrapper
+sys32_chroot_wrapper:
+ llgtr %r2,%r2 # char *
+ jg sys_chroot # branch to system call
+
+ .globl sys32_ustat_wrapper
+sys32_ustat_wrapper:
+ llgfr %r2,%r2 # dev_t
+ llgtr %r3,%r3 # struct ustat *
+ jg sys_ustat
+
+ .globl sys32_dup2_wrapper
+sys32_dup2_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ jg sys_dup2 # branch to system call
+
+#sys32_getppid_wrapper # void
+
+#sys32_getpgrp_wrapper # void
+
+#sys32_setsid_wrapper # void
+
+ .globl sys32_sigaction_wrapper
+sys32_sigaction_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct old_sigaction *
+ llgtr %r4,%r4 # struct old_sigaction32 *
+ jg sys32_sigaction # branch to system call
+
+ .globl sys32_setreuid16_wrapper
+sys32_setreuid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ jg sys32_setreuid16 # branch to system call
+
+ .globl sys32_setregid16_wrapper
+sys32_setregid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_gid_emu31_t
+ jg sys32_setregid16 # branch to system call
+
+ .globl sys_sigsuspend_wrapper
+sys_sigsuspend_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ llgfr %r4,%r4 # old_sigset_t
+ jg sys_sigsuspend
+
+ .globl compat_sys_sigpending_wrapper
+compat_sys_sigpending_wrapper:
+ llgtr %r2,%r2 # compat_old_sigset_t *
+ jg compat_sys_sigpending # branch to system call
+
+ .globl sys32_sethostname_wrapper
+sys32_sethostname_wrapper:
+ llgtr %r2,%r2 # char *
+ lgfr %r3,%r3 # int
+ jg sys_sethostname # branch to system call
+
+ .globl compat_sys_setrlimit_wrapper
+compat_sys_setrlimit_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct rlimit_emu31 *
+ jg compat_sys_setrlimit # branch to system call
+
+ .globl compat_sys_old_getrlimit_wrapper
+compat_sys_old_getrlimit_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct rlimit_emu31 *
+ jg compat_sys_old_getrlimit # branch to system call
+
+ .globl compat_sys_getrlimit_wrapper
+compat_sys_getrlimit_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct rlimit_emu31 *
+ jg compat_sys_getrlimit # branch to system call
+
+ .globl sys32_mmap2_wrapper
+sys32_mmap2_wrapper:
+ llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
+ jg sys32_mmap2 # branch to system call
+
+ .globl compat_sys_getrusage_wrapper
+compat_sys_getrusage_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct rusage_emu31 *
+ jg compat_sys_getrusage # branch to system call
+
+ .globl sys32_gettimeofday_wrapper
+sys32_gettimeofday_wrapper:
+ llgtr %r2,%r2 # struct timeval_emu31 *
+ llgtr %r3,%r3 # struct timezone *
+ jg sys32_gettimeofday # branch to system call
+
+ .globl sys32_settimeofday_wrapper
+sys32_settimeofday_wrapper:
+ llgtr %r2,%r2 # struct timeval_emu31 *
+ llgtr %r3,%r3 # struct timezone *
+ jg sys32_settimeofday # branch to system call
+
+ .globl sys32_getgroups16_wrapper
+sys32_getgroups16_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
+ jg sys32_getgroups16 # branch to system call
+
+ .globl sys32_setgroups16_wrapper
+sys32_setgroups16_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
+ jg sys32_setgroups16 # branch to system call
+
+ .globl sys32_symlink_wrapper
+sys32_symlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_symlink # branch to system call
+
+ .globl sys32_readlink_wrapper
+sys32_readlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # char *
+ lgfr %r4,%r4 # int
+ jg sys_readlink # branch to system call
+
+ .globl sys32_uselib_wrapper
+sys32_uselib_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_uselib # branch to system call
+
+ .globl sys32_swapon_wrapper
+sys32_swapon_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_swapon # branch to system call
+
+ .globl sys32_reboot_wrapper
+sys32_reboot_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ llgfr %r4,%r4 # unsigned int
+ llgtr %r5,%r5 # void *
+ jg sys_reboot # branch to system call
+
+ .globl old32_readdir_wrapper
+old32_readdir_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # void *
+ llgfr %r4,%r4 # unsigned int
+ jg compat_sys_old_readdir # branch to system call
+
+ .globl old32_mmap_wrapper
+old32_mmap_wrapper:
+ llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
+ jg old32_mmap # branch to system call
+
+ .globl sys32_munmap_wrapper
+sys32_munmap_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ jg sys_munmap # branch to system call
+
+ .globl sys32_truncate_wrapper
+sys32_truncate_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # unsigned long
+ jg sys_truncate # branch to system call
+
+ .globl sys32_ftruncate_wrapper
+sys32_ftruncate_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned long
+ jg sys_ftruncate # branch to system call
+
+ .globl sys32_fchmod_wrapper
+sys32_fchmod_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # mode_t
+ jg sys_fchmod # branch to system call
+
+ .globl sys32_fchown16_wrapper
+sys32_fchown16_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # compat_uid_t
+ llgfr %r4,%r4 # compat_uid_t
+ jg sys32_fchown16 # branch to system call
+
+ .globl sys32_getpriority_wrapper
+sys32_getpriority_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ jg sys_getpriority # branch to system call
+
+ .globl sys32_setpriority_wrapper
+sys32_setpriority_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ jg sys_setpriority # branch to system call
+
+ .globl compat_sys_statfs_wrapper
+compat_sys_statfs_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct compat_statfs *
+ jg compat_sys_statfs # branch to system call
+
+ .globl compat_sys_fstatfs_wrapper
+compat_sys_fstatfs_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct compat_statfs *
+ jg compat_sys_fstatfs # branch to system call
+
+ .globl compat_sys_socketcall_wrapper
+compat_sys_socketcall_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # u32 *
+ jg compat_sys_socketcall # branch to system call
+
+ .globl sys32_syslog_wrapper
+sys32_syslog_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # char *
+ lgfr %r4,%r4 # int
+ jg sys_syslog # branch to system call
+
+ .globl compat_sys_setitimer_wrapper
+compat_sys_setitimer_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct itimerval_emu31 *
+ llgtr %r4,%r4 # struct itimerval_emu31 *
+ jg compat_sys_setitimer # branch to system call
+
+ .globl compat_sys_getitimer_wrapper
+compat_sys_getitimer_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct itimerval_emu31 *
+ jg compat_sys_getitimer # branch to system call
+
+ .globl compat_sys_newstat_wrapper
+compat_sys_newstat_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct stat_emu31 *
+ jg compat_sys_newstat # branch to system call
+
+ .globl compat_sys_newlstat_wrapper
+compat_sys_newlstat_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct stat_emu31 *
+ jg compat_sys_newlstat # branch to system call
+
+ .globl compat_sys_newfstat_wrapper
+compat_sys_newfstat_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct stat_emu31 *
+ jg compat_sys_newfstat # branch to system call
+
+#sys32_vhangup_wrapper # void
+
+ .globl compat_sys_wait4_wrapper
+compat_sys_wait4_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # unsigned int *
+ lgfr %r4,%r4 # int
+ llgtr %r5,%r5 # struct rusage *
+ jg compat_sys_wait4 # branch to system call
+
+ .globl sys32_swapoff_wrapper
+sys32_swapoff_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_swapoff # branch to system call
+
+ .globl compat_sys_sysinfo_wrapper
+compat_sys_sysinfo_wrapper:
+ llgtr %r2,%r2 # struct sysinfo_emu31 *
+ jg compat_sys_sysinfo # branch to system call
+
+ .globl sys32_ipc_wrapper
+sys32_ipc_wrapper:
+ llgfr %r2,%r2 # uint
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ lgfr %r5,%r5 # int
+ llgfr %r6,%r6 # u32
+ jg sys32_ipc # branch to system call
+
+ .globl sys32_fsync_wrapper
+sys32_fsync_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_fsync # branch to system call
+
+#sys32_sigreturn_wrapper # done in sigreturn_glue
+
+#sys32_clone_wrapper # done in clone_glue
+
+ .globl sys32_setdomainname_wrapper
+sys32_setdomainname_wrapper:
+ llgtr %r2,%r2 # char *
+ lgfr %r3,%r3 # int
+ jg sys_setdomainname # branch to system call
+
+ .globl sys32_newuname_wrapper
+sys32_newuname_wrapper:
+ llgtr %r2,%r2 # struct new_utsname *
+ jg s390x_newuname # branch to system call
+
+ .globl compat_sys_adjtimex_wrapper
+compat_sys_adjtimex_wrapper:
+ llgtr %r2,%r2 # struct compat_timex *
+ jg compat_sys_adjtimex # branch to system call
+
+ .globl sys32_mprotect_wrapper
+sys32_mprotect_wrapper:
+ llgtr %r2,%r2 # unsigned long (actually pointer
+ llgfr %r3,%r3 # size_t
+ llgfr %r4,%r4 # unsigned long
+ jg sys_mprotect # branch to system call
+
+ .globl compat_sys_sigprocmask_wrapper
+compat_sys_sigprocmask_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # compat_old_sigset_t *
+ llgtr %r4,%r4 # compat_old_sigset_t *
+ jg compat_sys_sigprocmask # branch to system call
+
+ .globl sys32_init_module_wrapper
+sys32_init_module_wrapper:
+ llgtr %r2,%r2 # void *
+ llgfr %r3,%r3 # unsigned long
+ llgtr %r4,%r4 # char *
+ jg sys32_init_module # branch to system call
+
+ .globl sys32_delete_module_wrapper
+sys32_delete_module_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # unsigned int
+ jg sys32_delete_module # branch to system call
+
+ .globl sys32_quotactl_wrapper
+sys32_quotactl_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # qid_t
+ llgtr %r5,%r5 # caddr_t
+ jg sys_quotactl # branch to system call
+
+ .globl sys32_getpgid_wrapper
+sys32_getpgid_wrapper:
+ lgfr %r2,%r2 # pid_t
+ jg sys_getpgid # branch to system call
+
+ .globl sys32_fchdir_wrapper
+sys32_fchdir_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_fchdir # branch to system call
+
+ .globl sys32_bdflush_wrapper
+sys32_bdflush_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # long
+ jg sys_bdflush # branch to system call
+
+ .globl sys32_sysfs_wrapper
+sys32_sysfs_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ jg sys_sysfs # branch to system call
+
+ .globl sys32_personality_wrapper
+sys32_personality_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ jg s390x_personality # branch to system call
+
+ .globl sys32_setfsuid16_wrapper
+sys32_setfsuid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ jg sys32_setfsuid16 # branch to system call
+
+ .globl sys32_setfsgid16_wrapper
+sys32_setfsgid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ jg sys32_setfsgid16 # branch to system call
+
+ .globl sys32_llseek_wrapper
+sys32_llseek_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ llgtr %r5,%r5 # loff_t *
+ llgfr %r6,%r6 # unsigned int
+ jg sys_llseek # branch to system call
+
+ .globl sys32_getdents_wrapper
+sys32_getdents_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # void *
+ llgfr %r4,%r4 # unsigned int
+ jg compat_sys_getdents # branch to system call
+
+ .globl compat_sys_select_wrapper
+compat_sys_select_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # compat_fd_set *
+ llgtr %r4,%r4 # compat_fd_set *
+ llgtr %r5,%r5 # compat_fd_set *
+ llgtr %r6,%r6 # struct compat_timeval *
+ jg compat_sys_select # branch to system call
+
+ .globl sys32_flock_wrapper
+sys32_flock_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ jg sys_flock # branch to system call
+
+ .globl sys32_msync_wrapper
+sys32_msync_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ lgfr %r4,%r4 # int
+ jg sys_msync # branch to system call
+
+ .globl compat_sys_readv_wrapper
+compat_sys_readv_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct compat_iovec *
+ llgfr %r4,%r4 # unsigned long
+ jg compat_sys_readv # branch to system call
+
+ .globl compat_sys_writev_wrapper
+compat_sys_writev_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct compat_iovec *
+ llgfr %r4,%r4 # unsigned long
+ jg compat_sys_writev # branch to system call
+
+ .globl sys32_getsid_wrapper
+sys32_getsid_wrapper:
+ lgfr %r2,%r2 # pid_t
+ jg sys_getsid # branch to system call
+
+ .globl sys32_fdatasync_wrapper
+sys32_fdatasync_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_fdatasync # branch to system call
+
+#sys32_sysctl_wrapper # tbd
+
+ .globl sys32_mlock_wrapper
+sys32_mlock_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ jg sys_mlock # branch to system call
+
+ .globl sys32_munlock_wrapper
+sys32_munlock_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ jg sys_munlock # branch to system call
+
+ .globl sys32_mlockall_wrapper
+sys32_mlockall_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_mlockall # branch to system call
+
+#sys32_munlockall_wrapper # void
+
+ .globl sys32_sched_setparam_wrapper
+sys32_sched_setparam_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # struct sched_param *
+ jg sys_sched_setparam # branch to system call
+
+ .globl sys32_sched_getparam_wrapper
+sys32_sched_getparam_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # struct sched_param *
+ jg sys_sched_getparam # branch to system call
+
+ .globl sys32_sched_setscheduler_wrapper
+sys32_sched_setscheduler_wrapper:
+ lgfr %r2,%r2 # pid_t
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # struct sched_param *
+ jg sys_sched_setscheduler # branch to system call
+
+ .globl sys32_sched_getscheduler_wrapper
+sys32_sched_getscheduler_wrapper:
+ lgfr %r2,%r2 # pid_t
+ jg sys_sched_getscheduler # branch to system call
+
+#sys32_sched_yield_wrapper # void
+
+ .globl sys32_sched_get_priority_max_wrapper
+sys32_sched_get_priority_max_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_sched_get_priority_max # branch to system call
+
+ .globl sys32_sched_get_priority_min_wrapper
+sys32_sched_get_priority_min_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_sched_get_priority_min # branch to system call
+
+ .globl sys32_sched_rr_get_interval_wrapper
+sys32_sched_rr_get_interval_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # struct compat_timespec *
+ jg sys32_sched_rr_get_interval # branch to system call
+
+ .globl compat_sys_nanosleep_wrapper
+compat_sys_nanosleep_wrapper:
+ llgtr %r2,%r2 # struct compat_timespec *
+ llgtr %r3,%r3 # struct compat_timespec *
+ jg compat_sys_nanosleep # branch to system call
+
+ .globl sys32_mremap_wrapper
+sys32_mremap_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ llgfr %r5,%r5 # unsigned long
+ llgfr %r6,%r6 # unsigned long
+ jg sys_mremap # branch to system call
+
+ .globl sys32_setresuid16_wrapper
+sys32_setresuid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_uid_emu31_t
+ jg sys32_setresuid16 # branch to system call
+
+ .globl sys32_getresuid16_wrapper
+sys32_getresuid16_wrapper:
+ llgtr %r2,%r2 # __kernel_old_uid_emu31_t *
+ llgtr %r3,%r3 # __kernel_old_uid_emu31_t *
+ llgtr %r4,%r4 # __kernel_old_uid_emu31_t *
+ jg sys32_getresuid16 # branch to system call
+
+ .globl sys32_poll_wrapper
+sys32_poll_wrapper:
+ llgtr %r2,%r2 # struct pollfd *
+ llgfr %r3,%r3 # unsigned int
+ lgfr %r4,%r4 # long
+ jg sys_poll # branch to system call
+
+ .globl compat_sys_nfsservctl_wrapper
+compat_sys_nfsservctl_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct compat_nfsctl_arg*
+ llgtr %r4,%r4 # union compat_nfsctl_res*
+ jg compat_sys_nfsservctl # branch to system call
+
+ .globl sys32_setresgid16_wrapper
+sys32_setresgid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_gid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_gid_emu31_t
+ jg sys32_setresgid16 # branch to system call
+
+ .globl sys32_getresgid16_wrapper
+sys32_getresgid16_wrapper:
+ llgtr %r2,%r2 # __kernel_old_gid_emu31_t *
+ llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
+ llgtr %r4,%r4 # __kernel_old_gid_emu31_t *
+ jg sys32_getresgid16 # branch to system call
+
+ .globl sys32_prctl_wrapper
+sys32_prctl_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ llgfr %r5,%r5 # unsigned long
+ llgfr %r6,%r6 # unsigned long
+ jg sys_prctl # branch to system call
+
+#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
+
+ .globl sys32_rt_sigaction_wrapper
+sys32_rt_sigaction_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct sigaction_emu31 *
+ llgtr %r4,%r4 # const struct sigaction_emu31 *
+ llgfr %r5,%r5 # size_t
+ jg sys32_rt_sigaction # branch to system call
+
+ .globl sys32_rt_sigprocmask_wrapper
+sys32_rt_sigprocmask_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # old_sigset_emu31 *
+ llgtr %r4,%r4 # old_sigset_emu31 *
+ llgfr %r5,%r5 # size_t
+ jg sys32_rt_sigprocmask # branch to system call
+
+ .globl sys32_rt_sigpending_wrapper
+sys32_rt_sigpending_wrapper:
+ llgtr %r2,%r2 # sigset_emu31 *
+ llgfr %r3,%r3 # size_t
+ jg sys32_rt_sigpending # branch to system call
+
+ .globl compat_sys_rt_sigtimedwait_wrapper
+compat_sys_rt_sigtimedwait_wrapper:
+ llgtr %r2,%r2 # const sigset_emu31_t *
+ llgtr %r3,%r3 # siginfo_emu31_t *
+ llgtr %r4,%r4 # const struct compat_timespec *
+ llgfr %r5,%r5 # size_t
+ jg compat_sys_rt_sigtimedwait # branch to system call
+
+ .globl sys32_rt_sigqueueinfo_wrapper
+sys32_rt_sigqueueinfo_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # siginfo_emu31_t *
+ jg sys32_rt_sigqueueinfo # branch to system call
+
+ .globl compat_sys_rt_sigsuspend_wrapper
+compat_sys_rt_sigsuspend_wrapper:
+ llgtr %r2,%r2 # compat_sigset_t *
+ llgfr %r3,%r3 # compat_size_t
+ jg compat_sys_rt_sigsuspend
+
+ .globl sys32_pread64_wrapper
+sys32_pread64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # char *
+ llgfr %r4,%r4 # size_t
+ llgfr %r5,%r5 # u32
+ llgfr %r6,%r6 # u32
+ jg sys32_pread64 # branch to system call
+
+ .globl sys32_pwrite64_wrapper
+sys32_pwrite64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # size_t
+ llgfr %r5,%r5 # u32
+ llgfr %r6,%r6 # u32
+ jg sys32_pwrite64 # branch to system call
+
+ .globl sys32_chown16_wrapper
+sys32_chown16_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_gid_emu31_t
+ jg sys32_chown16 # branch to system call
+
+ .globl sys32_getcwd_wrapper
+sys32_getcwd_wrapper:
+ llgtr %r2,%r2 # char *
+ llgfr %r3,%r3 # unsigned long
+ jg sys_getcwd # branch to system call
+
+ .globl sys32_capget_wrapper
+sys32_capget_wrapper:
+ llgtr %r2,%r2 # cap_user_header_t
+ llgtr %r3,%r3 # cap_user_data_t
+ jg sys_capget # branch to system call
+
+ .globl sys32_capset_wrapper
+sys32_capset_wrapper:
+ llgtr %r2,%r2 # cap_user_header_t
+ llgtr %r3,%r3 # const cap_user_data_t
+ jg sys_capset # branch to system call
+
+ .globl sys32_sigaltstack_wrapper
+sys32_sigaltstack_wrapper:
+ llgtr %r2,%r2 # const stack_emu31_t *
+ llgtr %r3,%r3 # stack_emu31_t *
+ jg sys32_sigaltstack
+
+ .globl sys32_sendfile_wrapper
+sys32_sendfile_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # __kernel_off_emu31_t *
+ llgfr %r5,%r5 # size_t
+ jg sys32_sendfile # branch to system call
+
+#sys32_vfork_wrapper # done in vfork_glue
+
+ .globl sys32_truncate64_wrapper
+sys32_truncate64_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ jg sys32_truncate64 # branch to system call
+
+ .globl sys32_ftruncate64_wrapper
+sys32_ftruncate64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ jg sys32_ftruncate64 # branch to system call
+
+ .globl sys32_lchown_wrapper
+sys32_lchown_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_lchown # branch to system call
+
+#sys32_getuid_wrapper # void
+#sys32_getgid_wrapper # void
+#sys32_geteuid_wrapper # void
+#sys32_getegid_wrapper # void
+
+ .globl sys32_setreuid_wrapper
+sys32_setreuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ llgfr %r3,%r3 # uid_t
+ jg sys_setreuid # branch to system call
+
+ .globl sys32_setregid_wrapper
+sys32_setregid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ llgfr %r3,%r3 # gid_t
+ jg sys_setregid # branch to system call
+
+ .globl sys32_getgroups_wrapper
+sys32_getgroups_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # gid_t *
+ jg sys_getgroups # branch to system call
+
+ .globl sys32_setgroups_wrapper
+sys32_setgroups_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # gid_t *
+ jg sys_setgroups # branch to system call
+
+ .globl sys32_fchown_wrapper
+sys32_fchown_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_fchown # branch to system call
+
+ .globl sys32_setresuid_wrapper
+sys32_setresuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # uid_t
+ jg sys_setresuid # branch to system call
+
+ .globl sys32_getresuid_wrapper
+sys32_getresuid_wrapper:
+ llgtr %r2,%r2 # uid_t *
+ llgtr %r3,%r3 # uid_t *
+ llgtr %r4,%r4 # uid_t *
+ jg sys_getresuid # branch to system call
+
+ .globl sys32_setresgid_wrapper
+sys32_setresgid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ llgfr %r3,%r3 # gid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_setresgid # branch to system call
+
+ .globl sys32_getresgid_wrapper
+sys32_getresgid_wrapper:
+ llgtr %r2,%r2 # gid_t *
+ llgtr %r3,%r3 # gid_t *
+ llgtr %r4,%r4 # gid_t *
+ jg sys_getresgid # branch to system call
+
+ .globl sys32_chown_wrapper
+sys32_chown_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_chown # branch to system call
+
+ .globl sys32_setuid_wrapper
+sys32_setuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ jg sys_setuid # branch to system call
+
+ .globl sys32_setgid_wrapper
+sys32_setgid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ jg sys_setgid # branch to system call
+
+ .globl sys32_setfsuid_wrapper
+sys32_setfsuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ jg sys_setfsuid # branch to system call
+
+ .globl sys32_setfsgid_wrapper
+sys32_setfsgid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ jg sys_setfsgid # branch to system call
+
+ .globl sys32_pivot_root_wrapper
+sys32_pivot_root_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_pivot_root # branch to system call
+
+ .globl sys32_mincore_wrapper
+sys32_mincore_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ llgtr %r4,%r4 # unsigned char *
+ jg sys_mincore # branch to system call
+
+ .globl sys32_madvise_wrapper
+sys32_madvise_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ lgfr %r4,%r4 # int
+ jg sys_madvise # branch to system call
+
+ .globl sys32_getdents64_wrapper
+sys32_getdents64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # void *
+ llgfr %r4,%r4 # unsigned int
+ jg sys_getdents64 # branch to system call
+
+ .globl compat_sys_fcntl64_wrapper
+compat_sys_fcntl64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ llgfr %r4,%r4 # unsigned long
+ jg compat_sys_fcntl64 # branch to system call
+
+ .globl sys32_stat64_wrapper
+sys32_stat64_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct stat64 *
+ jg sys32_stat64 # branch to system call
+
+ .globl sys32_lstat64_wrapper
+sys32_lstat64_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct stat64 *
+ jg sys32_lstat64 # branch to system call
+
+ .globl sys32_stime_wrapper
+sys32_stime_wrapper:
+ llgtr %r2,%r2 # long *
+ jg compat_sys_stime # branch to system call
+
+ .globl sys32_sysctl_wrapper
+sys32_sysctl_wrapper:
+ llgtr %r2,%r2 # struct __sysctl_args32 *
+ jg sys32_sysctl
+
+ .globl sys32_fstat64_wrapper
+sys32_fstat64_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgtr %r3,%r3 # struct stat64 *
+ jg sys32_fstat64 # branch to system call
+
+ .globl compat_sys_futex_wrapper
+compat_sys_futex_wrapper:
+ llgtr %r2,%r2 # u32 *
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ llgtr %r5,%r5 # struct compat_timespec *
+ llgtr %r6,%r6 # u32 *
+ lgf %r0,164(%r15) # int
+ stg %r0,160(%r15)
+ jg compat_sys_futex # branch to system call
+
+ .globl sys32_setxattr_wrapper
+sys32_setxattr_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # void *
+ llgfr %r5,%r5 # size_t
+ lgfr %r6,%r6 # int
+ jg sys_setxattr
+
+ .globl sys32_lsetxattr_wrapper
+sys32_lsetxattr_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # void *
+ llgfr %r5,%r5 # size_t
+ lgfr %r6,%r6 # int
+ jg sys_lsetxattr
+
+ .globl sys32_fsetxattr_wrapper
+sys32_fsetxattr_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # void *
+ llgfr %r5,%r5 # size_t
+ lgfr %r6,%r6 # int
+ jg sys_fsetxattr
+
+ .globl sys32_getxattr_wrapper
+sys32_getxattr_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # void *
+ llgfr %r5,%r5 # size_t
+ jg sys_getxattr
+
+ .globl sys32_lgetxattr_wrapper
+sys32_lgetxattr_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # void *
+ llgfr %r5,%r5 # size_t
+ jg sys_lgetxattr
+
+ .globl sys32_fgetxattr_wrapper
+sys32_fgetxattr_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # void *
+ llgfr %r5,%r5 # size_t
+ jg sys_fgetxattr
+
+ .globl sys32_listxattr_wrapper
+sys32_listxattr_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ llgfr %r4,%r4 # size_t
+ jg sys_listxattr
+
+ .globl sys32_llistxattr_wrapper
+sys32_llistxattr_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ llgfr %r4,%r4 # size_t
+ jg sys_llistxattr
+
+ .globl sys32_flistxattr_wrapper
+sys32_flistxattr_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # char *
+ llgfr %r4,%r4 # size_t
+ jg sys_flistxattr
+
+ .globl sys32_removexattr_wrapper
+sys32_removexattr_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ jg sys_removexattr
+
+ .globl sys32_lremovexattr_wrapper
+sys32_lremovexattr_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ jg sys_lremovexattr
+
+ .globl sys32_fremovexattr_wrapper
+sys32_fremovexattr_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # char *
+ jg sys_fremovexattr
+
+ .globl sys32_sched_setaffinity_wrapper
+sys32_sched_setaffinity_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # unsigned int
+ llgtr %r4,%r4 # unsigned long *
+ jg compat_sys_sched_setaffinity
+
+ .globl sys32_sched_getaffinity_wrapper
+sys32_sched_getaffinity_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # unsigned int
+ llgtr %r4,%r4 # unsigned long *
+ jg compat_sys_sched_getaffinity
+
+ .globl sys32_exit_group_wrapper
+sys32_exit_group_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_exit_group # branch to system call
+
+ .globl sys32_set_tid_address_wrapper
+sys32_set_tid_address_wrapper:
+ llgtr %r2,%r2 # int *
+ jg sys_set_tid_address # branch to system call
+
+ .globl sys_epoll_create_wrapper
+sys_epoll_create_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_epoll_create # branch to system call
+
+ .globl sys_epoll_ctl_wrapper
+sys_epoll_ctl_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ llgtr %r5,%r5 # struct epoll_event *
+ jg sys_epoll_ctl # branch to system call
+
+ .globl sys_epoll_wait_wrapper
+sys_epoll_wait_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct epoll_event *
+ lgfr %r4,%r4 # int
+ lgfr %r5,%r5 # int
+ jg sys_epoll_wait # branch to system call
+
+ .globl sys32_lookup_dcookie_wrapper
+sys32_lookup_dcookie_wrapper:
+ sllg %r2,%r2,32 # get high word of 64bit dcookie
+ or %r2,%r3 # get low word of 64bit dcookie
+ llgtr %r3,%r4 # char *
+ llgfr %r4,%r5 # size_t
+ jg sys_lookup_dcookie
+
+ .globl sys32_fadvise64_wrapper
+sys32_fadvise64_wrapper:
+ lgfr %r2,%r2 # int
+ sllg %r3,%r3,32 # get high word of 64bit loff_t
+ or %r3,%r4 # get low word of 64bit loff_t
+ llgfr %r4,%r5 # size_t (unsigned long)
+ lgfr %r5,%r6 # int
+ jg sys32_fadvise64
+
+ .globl sys32_fadvise64_64_wrapper
+sys32_fadvise64_64_wrapper:
+ llgtr %r2,%r2 # struct fadvise64_64_args *
+ jg sys32_fadvise64_64
+
+ .globl sys32_clock_settime_wrapper
+sys32_clock_settime_wrapper:
+ lgfr %r2,%r2 # clockid_t (int)
+ llgtr %r3,%r3 # struct compat_timespec *
+ jg compat_sys_clock_settime
+
+ .globl sys32_clock_gettime_wrapper
+sys32_clock_gettime_wrapper:
+ lgfr %r2,%r2 # clockid_t (int)
+ llgtr %r3,%r3 # struct compat_timespec *
+ jg compat_sys_clock_gettime
+
+ .globl sys32_clock_getres_wrapper
+sys32_clock_getres_wrapper:
+ lgfr %r2,%r2 # clockid_t (int)
+ llgtr %r3,%r3 # struct compat_timespec *
+ jg compat_sys_clock_getres
+
+ .globl sys32_clock_nanosleep_wrapper
+sys32_clock_nanosleep_wrapper:
+ lgfr %r2,%r2 # clockid_t (int)
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # struct compat_timespec *
+ llgtr %r5,%r5 # struct compat_timespec *
+ jg compat_sys_clock_nanosleep
+
+ .globl sys32_timer_create_wrapper
+sys32_timer_create_wrapper:
+ lgfr %r2,%r2 # timer_t (int)
+ llgtr %r3,%r3 # struct compat_sigevent *
+ llgtr %r4,%r4 # timer_t *
+ jg compat_sys_timer_create
+
+ .globl sys32_timer_settime_wrapper
+sys32_timer_settime_wrapper:
+ lgfr %r2,%r2 # timer_t (int)
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # struct compat_itimerspec *
+ llgtr %r5,%r5 # struct compat_itimerspec *
+ jg compat_sys_timer_settime
+
+ .globl sys32_timer_gettime_wrapper
+sys32_timer_gettime_wrapper:
+ lgfr %r2,%r2 # timer_t (int)
+ llgtr %r3,%r3 # struct compat_itimerspec *
+ jg compat_sys_timer_gettime
+
+ .globl sys32_timer_getoverrun_wrapper
+sys32_timer_getoverrun_wrapper:
+ lgfr %r2,%r2 # timer_t (int)
+ jg sys_timer_getoverrun
+
+ .globl sys32_timer_delete_wrapper
+sys32_timer_delete_wrapper:
+ lgfr %r2,%r2 # timer_t (int)
+ jg sys_timer_delete
+
+ .globl sys32_io_setup_wrapper
+sys32_io_setup_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # u32 *
+ jg compat_sys_io_setup
+
+ .globl sys32_io_destroy_wrapper
+sys32_io_destroy_wrapper:
+ llgfr %r2,%r2 # (aio_context_t) u32
+ jg sys_io_destroy
+
+ .globl sys32_io_getevents_wrapper
+sys32_io_getevents_wrapper:
+ llgfr %r2,%r2 # (aio_context_t) u32
+ lgfr %r3,%r3 # long
+ lgfr %r4,%r4 # long
+ llgtr %r5,%r5 # struct io_event *
+ llgtr %r6,%r6 # struct compat_timespec *
+ jg compat_sys_io_getevents
+
+ .globl sys32_io_submit_wrapper
+sys32_io_submit_wrapper:
+ llgfr %r2,%r2 # (aio_context_t) u32
+ lgfr %r3,%r3 # long
+ llgtr %r4,%r4 # struct iocb **
+ jg compat_sys_io_submit
+
+ .globl sys32_io_cancel_wrapper
+sys32_io_cancel_wrapper:
+ llgfr %r2,%r2 # (aio_context_t) u32
+ llgtr %r3,%r3 # struct iocb *
+ llgtr %r4,%r4 # struct io_event *
+ jg sys_io_cancel
+
+ .globl compat_sys_statfs64_wrapper
+compat_sys_statfs64_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # compat_size_t
+ llgtr %r4,%r4 # struct compat_statfs64 *
+ jg compat_sys_statfs64
+
+ .globl compat_sys_fstatfs64_wrapper
+compat_sys_fstatfs64_wrapper:
+ llgfr %r2,%r2 # unsigned int fd
+ llgfr %r3,%r3 # compat_size_t
+ llgtr %r4,%r4 # struct compat_statfs64 *
+ jg compat_sys_fstatfs64
+
+ .globl compat_sys_mq_open_wrapper
+compat_sys_mq_open_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ llgfr %r4,%r4 # mode_t
+ llgtr %r5,%r5 # struct compat_mq_attr *
+ jg compat_sys_mq_open
+
+ .globl sys32_mq_unlink_wrapper
+sys32_mq_unlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_mq_unlink
+
+ .globl compat_sys_mq_timedsend_wrapper
+compat_sys_mq_timedsend_wrapper:
+ lgfr %r2,%r2 # mqd_t
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # size_t
+ llgfr %r5,%r5 # unsigned int
+ llgtr %r6,%r6 # const struct compat_timespec *
+ jg compat_sys_mq_timedsend
+
+ .globl compat_sys_mq_timedreceive_wrapper
+compat_sys_mq_timedreceive_wrapper:
+ lgfr %r2,%r2 # mqd_t
+ llgtr %r3,%r3 # char *
+ llgfr %r4,%r4 # size_t
+ llgtr %r5,%r5 # unsigned int *
+ llgtr %r6,%r6 # const struct compat_timespec *
+ jg compat_sys_mq_timedreceive
+
+ .globl compat_sys_mq_notify_wrapper
+compat_sys_mq_notify_wrapper:
+ lgfr %r2,%r2 # mqd_t
+ llgtr %r3,%r3 # struct compat_sigevent *
+ jg compat_sys_mq_notify
+
+ .globl compat_sys_mq_getsetattr_wrapper
+compat_sys_mq_getsetattr_wrapper:
+ lgfr %r2,%r2 # mqd_t
+ llgtr %r3,%r3 # struct compat_mq_attr *
+ llgtr %r4,%r4 # struct compat_mq_attr *
+ jg compat_sys_mq_getsetattr
+
+ .globl compat_sys_add_key_wrapper
+compat_sys_add_key_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ llgtr %r4,%r4 # const void *
+ llgfr %r5,%r5 # size_t
+ llgfr %r6,%r6 # (key_serial_t) u32
+ jg sys_add_key
+
+ .globl compat_sys_request_key_wrapper
+compat_sys_request_key_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ llgtr %r4,%r4 # const void *
+ llgfr %r5,%r5 # (key_serial_t) u32
+ jg sys_request_key
+
+ .globl sys32_remap_file_pages_wrapper
+sys32_remap_file_pages_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ llgfr %r5,%r5 # unsigned long
+ llgfr %r6,%r6 # unsigned long
+ jg sys_remap_file_pages
+
+ .globl compat_sys_waitid_wrapper
+compat_sys_waitid_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # pid_t
+ llgtr %r4,%r4 # siginfo_emu31_t *
+ lgfr %r5,%r5 # int
+ llgtr %r6,%r6 # struct rusage_emu31 *
+ jg compat_sys_waitid
+
+ .globl compat_sys_kexec_load_wrapper
+compat_sys_kexec_load_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # unsigned long
+ llgtr %r4,%r4 # struct kexec_segment *
+ llgfr %r5,%r5 # unsigned long
+ jg compat_sys_kexec_load
+
+ .globl sys_ioprio_set_wrapper
+sys_ioprio_set_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ jg sys_ioprio_set
+
+ .globl sys_ioprio_get_wrapper
+sys_ioprio_get_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ jg sys_ioprio_get
+
+ .globl sys_inotify_add_watch_wrapper
+sys_inotify_add_watch_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # u32
+ jg sys_inotify_add_watch
+
+ .globl sys_inotify_rm_watch_wrapper
+sys_inotify_rm_watch_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # u32
+ jg sys_inotify_rm_watch
+
+ .globl compat_sys_openat_wrapper
+compat_sys_openat_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # const char *
+ lgfr %r4,%r4 # int
+ lgfr %r5,%r5 # int
+ jg compat_sys_openat
+
+ .globl sys_mkdirat_wrapper
+sys_mkdirat_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ lgfr %r4,%r4 # int
+ jg sys_mkdirat
+
+ .globl sys_mknodat_wrapper
+sys_mknodat_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ lgfr %r4,%r4 # int
+ llgfr %r5,%r5 # unsigned int
+ jg sys_mknodat
+
+ .globl sys_fchownat_wrapper
+sys_fchownat_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # uid_t
+ llgfr %r5,%r5 # gid_t
+ lgfr %r6,%r6 # int
+ jg sys_fchownat
+
+ .globl compat_sys_futimesat_wrapper
+compat_sys_futimesat_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # struct timeval *
+ jg compat_sys_futimesat
+
+ .globl sys32_fstatat64_wrapper
+sys32_fstatat64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # struct stat64 *
+ lgfr %r5,%r5 # int
+ jg sys32_fstatat64
+
+ .globl sys_unlinkat_wrapper
+sys_unlinkat_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ lgfr %r4,%r4 # int
+ jg sys_unlinkat
+
+ .globl sys_renameat_wrapper
+sys_renameat_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ lgfr %r4,%r4 # int
+ llgtr %r5,%r5 # const char *
+ jg sys_renameat
+
+ .globl sys_linkat_wrapper
+sys_linkat_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ lgfr %r4,%r4 # int
+ llgtr %r5,%r5 # const char *
+ lgfr %r6,%r6 # int
+ jg sys_linkat
+
+ .globl sys_symlinkat_wrapper
+sys_symlinkat_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # const char *
+ jg sys_symlinkat
+
+ .globl sys_readlinkat_wrapper
+sys_readlinkat_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ llgtr %r4,%r4 # char *
+ lgfr %r5,%r5 # int
+ jg sys_readlinkat
+
+ .globl sys_fchmodat_wrapper
+sys_fchmodat_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # mode_t
+ jg sys_fchmodat
+
+ .globl sys_faccessat_wrapper
+sys_faccessat_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ lgfr %r4,%r4 # int
+ jg sys_faccessat
+
+ .globl compat_sys_pselect6_wrapper
+compat_sys_pselect6_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # fd_set *
+ llgtr %r4,%r4 # fd_set *
+ llgtr %r5,%r5 # fd_set *
+ llgtr %r6,%r6 # struct timespec *
+ llgt %r0,164(%r15) # void *
+ stg %r0,160(%r15)
+ jg compat_sys_pselect6
+
+ .globl compat_sys_ppoll_wrapper
+compat_sys_ppoll_wrapper:
+ llgtr %r2,%r2 # struct pollfd *
+ llgfr %r3,%r3 # unsigned int
+ llgtr %r4,%r4 # struct timespec *
+ llgtr %r5,%r5 # const sigset_t *
+ llgfr %r6,%r6 # size_t
+ jg compat_sys_ppoll
+
+ .globl sys_unshare_wrapper
+sys_unshare_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ jg sys_unshare
+
+ .globl compat_sys_set_robust_list_wrapper
+compat_sys_set_robust_list_wrapper:
+ llgtr %r2,%r2 # struct compat_robust_list_head *
+ llgfr %r3,%r3 # size_t
+ jg compat_sys_set_robust_list
+
+ .globl compat_sys_get_robust_list_wrapper
+compat_sys_get_robust_list_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # compat_uptr_t_t *
+ llgtr %r4,%r4 # compat_size_t *
+ jg compat_sys_get_robust_list
+
+ .globl sys_splice_wrapper
+sys_splice_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # loff_t *
+ lgfr %r4,%r4 # int
+ llgtr %r5,%r5 # loff_t *
+ llgfr %r6,%r6 # size_t
+ llgf %r0,164(%r15) # unsigned int
+ stg %r0,160(%r15)
+ jg sys_splice
+
+ .globl sys_sync_file_range_wrapper
+sys_sync_file_range_wrapper:
+ lgfr %r2,%r2 # int
+ sllg %r3,%r3,32 # get high word of 64bit loff_t
+ or %r3,%r4 # get low word of 64bit loff_t
+ sllg %r4,%r5,32 # get high word of 64bit loff_t
+ or %r4,%r6 # get low word of 64bit loff_t
+ llgf %r5,164(%r15) # unsigned int
+ jg sys_sync_file_range
+
+ .globl sys_tee_wrapper
+sys_tee_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ llgfr %r4,%r4 # size_t
+ llgfr %r5,%r5 # unsigned int
+ jg sys_tee
+
+ .globl compat_sys_vmsplice_wrapper
+compat_sys_vmsplice_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # compat_iovec *
+ llgfr %r4,%r4 # unsigned int
+ llgfr %r5,%r5 # unsigned int
+ jg compat_sys_vmsplice
+
+ .globl sys_getcpu_wrapper
+sys_getcpu_wrapper:
+ llgtr %r2,%r2 # unsigned *
+ llgtr %r3,%r3 # unsigned *
+ llgtr %r4,%r4 # struct getcpu_cache *
+ jg sys_getcpu
+
+ .globl compat_sys_epoll_pwait_wrapper
+compat_sys_epoll_pwait_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct compat_epoll_event *
+ lgfr %r4,%r4 # int
+ lgfr %r5,%r5 # int
+ llgtr %r6,%r6 # compat_sigset_t *
+ llgf %r0,164(%r15) # compat_size_t
+ stg %r0,160(%r15)
+ jg compat_sys_epoll_pwait
+
+ .globl compat_sys_utimes_wrapper
+compat_sys_utimes_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct compat_timeval *
+ jg compat_sys_utimes
+
+ .globl compat_sys_utimensat_wrapper
+compat_sys_utimensat_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # struct compat_timespec *
+ lgfr %r5,%r5 # int
+ jg compat_sys_utimensat
+
+ .globl compat_sys_signalfd_wrapper
+compat_sys_signalfd_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # compat_sigset_t *
+ llgfr %r4,%r4 # compat_size_t
+ jg compat_sys_signalfd
+
+ .globl sys_eventfd_wrapper
+sys_eventfd_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_eventfd
+
+ .globl sys_fallocate_wrapper
+sys_fallocate_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ sllg %r4,%r4,32 # get high word of 64bit loff_t
+ lr %r4,%r5 # get low word of 64bit loff_t
+ sllg %r5,%r6,32 # get high word of 64bit loff_t
+ l %r5,164(%r15) # get low word of 64bit loff_t
+ jg sys_fallocate
+
+ .globl sys_timerfd_create_wrapper
+sys_timerfd_create_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ jg sys_timerfd_create
+
+ .globl compat_sys_timerfd_settime_wrapper
+compat_sys_timerfd_settime_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # struct compat_itimerspec *
+ llgtr %r5,%r5 # struct compat_itimerspec *
+ jg compat_sys_timerfd_settime
+
+ .globl compat_sys_timerfd_gettime_wrapper
+compat_sys_timerfd_gettime_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct compat_itimerspec *
+ jg compat_sys_timerfd_gettime
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/cpcmd.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/cpcmd.c
new file mode 100644
index 0000000000..d8c1131e08
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/cpcmd.c
@@ -0,0 +1,123 @@
+/*
+ * arch/s390/kernel/cpcmd.c
+ *
+ * S390 version
+ * Copyright IBM Corp. 1999,2007
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Christian Borntraeger (cborntra@de.ibm.com),
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <asm/ebcdic.h>
+#include <asm/cpcmd.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+static DEFINE_SPINLOCK(cpcmd_lock);
+static char cpcmd_buf[241];
+
+static int diag8_noresponse(int cmdlen)
+{
+ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+ register unsigned long reg3 asm ("3") = cmdlen;
+
+ asm volatile(
+#ifndef CONFIG_64BIT
+ " diag %1,%0,0x8\n"
+#else /* CONFIG_64BIT */
+ " sam31\n"
+ " diag %1,%0,0x8\n"
+ " sam64\n"
+#endif /* CONFIG_64BIT */
+ : "+d" (reg3) : "d" (reg2) : "cc");
+ return reg3;
+}
+
+static int diag8_response(int cmdlen, char *response, int *rlen)
+{
+ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+ register unsigned long reg3 asm ("3") = (addr_t) response;
+ register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
+ register unsigned long reg5 asm ("5") = *rlen;
+
+ asm volatile(
+#ifndef CONFIG_64BIT
+ " diag %2,%0,0x8\n"
+ " brc 8,1f\n"
+ " ar %1,%4\n"
+#else /* CONFIG_64BIT */
+ " sam31\n"
+ " diag %2,%0,0x8\n"
+ " sam64\n"
+ " brc 8,1f\n"
+ " agr %1,%4\n"
+#endif /* CONFIG_64BIT */
+ "1:\n"
+ : "+d" (reg4), "+d" (reg5)
+ : "d" (reg2), "d" (reg3), "d" (*rlen) : "cc");
+ *rlen = reg5;
+ return reg4;
+}
+
+/*
+ * __cpcmd has some restrictions over cpcmd
+ * - the response buffer must reside below 2GB (if any)
+ * - __cpcmd is unlocked and therefore not SMP-safe
+ */
+int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
+{
+ int cmdlen;
+ int rc;
+ int response_len;
+
+ cmdlen = strlen(cmd);
+ BUG_ON(cmdlen > 240);
+ memcpy(cpcmd_buf, cmd, cmdlen);
+ ASCEBC(cpcmd_buf, cmdlen);
+
+ if (response) {
+ memset(response, 0, rlen);
+ response_len = rlen;
+ rc = diag8_response(cmdlen, response, &rlen);
+ EBCASC(response, response_len);
+ } else {
+ rc = diag8_noresponse(cmdlen);
+ }
+ if (response_code)
+ *response_code = rc;
+ return rlen;
+}
+EXPORT_SYMBOL(__cpcmd);
+
+int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
+{
+ char *lowbuf;
+ int len;
+ unsigned long flags;
+
+ if ((virt_to_phys(response) != (unsigned long) response) ||
+ (((unsigned long)response + rlen) >> 31)) {
+ lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
+ if (!lowbuf) {
+ printk(KERN_WARNING
+ "cpcmd: could not allocate response buffer\n");
+ return -ENOMEM;
+ }
+ spin_lock_irqsave(&cpcmd_lock, flags);
+ len = __cpcmd(cmd, lowbuf, rlen, response_code);
+ spin_unlock_irqrestore(&cpcmd_lock, flags);
+ memcpy(response, lowbuf, rlen);
+ kfree(lowbuf);
+ } else {
+ spin_lock_irqsave(&cpcmd_lock, flags);
+ len = __cpcmd(cmd, response, rlen, response_code);
+ spin_unlock_irqrestore(&cpcmd_lock, flags);
+ }
+ return len;
+}
+EXPORT_SYMBOL(cpcmd);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/crash.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/crash.c
new file mode 100644
index 0000000000..8cc7c9fa64
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/crash.c
@@ -0,0 +1,16 @@
+/*
+ * arch/s390/kernel/crash.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+#include <linux/threads.h>
+#include <linux/kexec.h>
+#include <linux/reboot.h>
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/debug.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/debug.c
new file mode 100644
index 0000000000..1b2f5ce453
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/debug.c
@@ -0,0 +1,1539 @@
+/*
+ * arch/s390/kernel/debug.c
+ * S/390 debug facility
+ *
+ * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
+ * IBM Corporation
+ * Author(s): Michael Holzheu (holzheu@de.ibm.com),
+ * Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ *
+ * Bugreports to: <Linux390@de.ibm.com>
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/sysctl.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+
+#include <asm/debug.h>
+
+#define DEBUG_PROLOG_ENTRY -1
+
+#define ALL_AREAS 0 /* copy all debug areas */
+#define NO_AREAS 1 /* copy no debug areas */
+
+/* typedefs */
+
+typedef struct file_private_info {
+ loff_t offset; /* offset of last read in file */
+ int act_area; /* number of last formated area */
+ int act_page; /* act page in given area */
+ int act_entry; /* last formated entry (offset */
+ /* relative to beginning of last */
+ /* formated page) */
+ size_t act_entry_offset; /* up to this offset we copied */
+ /* in last read the last formated */
+ /* entry to userland */
+ char temp_buf[2048]; /* buffer for output */
+ debug_info_t *debug_info_org; /* original debug information */
+ debug_info_t *debug_info_snap; /* snapshot of debug information */
+ struct debug_view *view; /* used view of debug info */
+} file_private_info_t;
+
+typedef struct
+{
+ char *string;
+ /*
+ * This assumes that all args are converted into longs
+ * on L/390 this is the case for all types of parameter
+ * except of floats, and long long (32 bit)
+ *
+ */
+ long args[0];
+} debug_sprintf_entry_t;
+
+
+extern void tod_to_timeval(uint64_t todval, struct timespec *xtime);
+
+/* internal function prototyes */
+
+static int debug_init(void);
+static ssize_t debug_output(struct file *file, char __user *user_buf,
+ size_t user_len, loff_t * offset);
+static ssize_t debug_input(struct file *file, const char __user *user_buf,
+ size_t user_len, loff_t * offset);
+static int debug_open(struct inode *inode, struct file *file);
+static int debug_close(struct inode *inode, struct file *file);
+static debug_info_t* debug_info_create(char *name, int pages_per_area,
+ int nr_areas, int buf_size);
+static void debug_info_get(debug_info_t *);
+static void debug_info_put(debug_info_t *);
+static int debug_prolog_level_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf);
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_buf_size, loff_t * offset);
+static int debug_prolog_pages_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf);
+static int debug_input_pages_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_buf_size, loff_t * offset);
+static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_buf_size, loff_t * offset);
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf);
+static int debug_raw_format_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf,
+ const char *in_buf);
+static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf);
+
+static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, debug_sprintf_entry_t *curr_event);
+
+/* globals */
+
+struct debug_view debug_raw_view = {
+ "raw",
+ NULL,
+ &debug_raw_header_fn,
+ &debug_raw_format_fn,
+ NULL,
+ NULL
+};
+
+struct debug_view debug_hex_ascii_view = {
+ "hex_ascii",
+ NULL,
+ &debug_dflt_header_fn,
+ &debug_hex_ascii_format_fn,
+ NULL,
+ NULL
+};
+
+static struct debug_view debug_level_view = {
+ "level",
+ &debug_prolog_level_fn,
+ NULL,
+ NULL,
+ &debug_input_level_fn,
+ NULL
+};
+
+static struct debug_view debug_pages_view = {
+ "pages",
+ &debug_prolog_pages_fn,
+ NULL,
+ NULL,
+ &debug_input_pages_fn,
+ NULL
+};
+
+static struct debug_view debug_flush_view = {
+ "flush",
+ NULL,
+ NULL,
+ NULL,
+ &debug_input_flush_fn,
+ NULL
+};
+
+struct debug_view debug_sprintf_view = {
+ "sprintf",
+ NULL,
+ &debug_dflt_header_fn,
+ (debug_format_proc_t*)&debug_sprintf_format_fn,
+ NULL,
+ NULL
+};
+
+/* used by dump analysis tools to determine version of debug feature */
+unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
+
+/* static globals */
+
+static debug_info_t *debug_area_first = NULL;
+static debug_info_t *debug_area_last = NULL;
+static DEFINE_MUTEX(debug_mutex);
+
+static int initialized;
+
+static const struct file_operations debug_file_ops = {
+ .owner = THIS_MODULE,
+ .read = debug_output,
+ .write = debug_input,
+ .open = debug_open,
+ .release = debug_close,
+};
+
+static struct dentry *debug_debugfs_root_entry;
+
+/* functions */
+
+/*
+ * debug_areas_alloc
+ * - Debug areas are implemented as a threedimensonal array:
+ * areas[areanumber][pagenumber][pageoffset]
+ */
+
+static debug_entry_t***
+debug_areas_alloc(int pages_per_area, int nr_areas)
+{
+ debug_entry_t*** areas;
+ int i,j;
+
+ areas = kmalloc(nr_areas *
+ sizeof(debug_entry_t**),
+ GFP_KERNEL);
+ if (!areas)
+ goto fail_malloc_areas;
+ for (i = 0; i < nr_areas; i++) {
+ areas[i] = kmalloc(pages_per_area *
+ sizeof(debug_entry_t*),GFP_KERNEL);
+ if (!areas[i]) {
+ goto fail_malloc_areas2;
+ }
+ for(j = 0; j < pages_per_area; j++) {
+ areas[i][j] = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if(!areas[i][j]) {
+ for(j--; j >=0 ; j--) {
+ kfree(areas[i][j]);
+ }
+ kfree(areas[i]);
+ goto fail_malloc_areas2;
+ }
+ }
+ }
+ return areas;
+
+fail_malloc_areas2:
+ for(i--; i >= 0; i--){
+ for(j=0; j < pages_per_area;j++){
+ kfree(areas[i][j]);
+ }
+ kfree(areas[i]);
+ }
+ kfree(areas);
+fail_malloc_areas:
+ return NULL;
+
+}
+
+
+/*
+ * debug_info_alloc
+ * - alloc new debug-info
+ */
+
+static debug_info_t*
+debug_info_alloc(char *name, int pages_per_area, int nr_areas, int buf_size,
+ int level, int mode)
+{
+ debug_info_t* rc;
+
+ /* alloc everything */
+
+ rc = kmalloc(sizeof(debug_info_t), GFP_KERNEL);
+ if(!rc)
+ goto fail_malloc_rc;
+ rc->active_entries = kcalloc(nr_areas, sizeof(int), GFP_KERNEL);
+ if(!rc->active_entries)
+ goto fail_malloc_active_entries;
+ rc->active_pages = kcalloc(nr_areas, sizeof(int), GFP_KERNEL);
+ if(!rc->active_pages)
+ goto fail_malloc_active_pages;
+ if((mode == ALL_AREAS) && (pages_per_area != 0)){
+ rc->areas = debug_areas_alloc(pages_per_area, nr_areas);
+ if(!rc->areas)
+ goto fail_malloc_areas;
+ } else {
+ rc->areas = NULL;
+ }
+
+ /* initialize members */
+
+ spin_lock_init(&rc->lock);
+ rc->pages_per_area = pages_per_area;
+ rc->nr_areas = nr_areas;
+ rc->active_area = 0;
+ rc->level = level;
+ rc->buf_size = buf_size;
+ rc->entry_size = sizeof(debug_entry_t) + buf_size;
+ strlcpy(rc->name, name, sizeof(rc->name));
+ memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+ memset(rc->debugfs_entries, 0 ,DEBUG_MAX_VIEWS *
+ sizeof(struct dentry*));
+ atomic_set(&(rc->ref_count), 0);
+
+ return rc;
+
+fail_malloc_areas:
+ kfree(rc->active_pages);
+fail_malloc_active_pages:
+ kfree(rc->active_entries);
+fail_malloc_active_entries:
+ kfree(rc);
+fail_malloc_rc:
+ return NULL;
+}
+
+/*
+ * debug_areas_free
+ * - free all debug areas
+ */
+
+static void
+debug_areas_free(debug_info_t* db_info)
+{
+ int i,j;
+
+ if(!db_info->areas)
+ return;
+ for (i = 0; i < db_info->nr_areas; i++) {
+ for(j = 0; j < db_info->pages_per_area; j++) {
+ kfree(db_info->areas[i][j]);
+ }
+ kfree(db_info->areas[i]);
+ }
+ kfree(db_info->areas);
+ db_info->areas = NULL;
+}
+
+/*
+ * debug_info_free
+ * - free memory debug-info
+ */
+
+static void
+debug_info_free(debug_info_t* db_info){
+ debug_areas_free(db_info);
+ kfree(db_info->active_entries);
+ kfree(db_info->active_pages);
+ kfree(db_info);
+}
+
+/*
+ * debug_info_create
+ * - create new debug-info
+ */
+
+static debug_info_t*
+debug_info_create(char *name, int pages_per_area, int nr_areas, int buf_size)
+{
+ debug_info_t* rc;
+
+ rc = debug_info_alloc(name, pages_per_area, nr_areas, buf_size,
+ DEBUG_DEFAULT_LEVEL, ALL_AREAS);
+ if(!rc)
+ goto out;
+
+ /* create root directory */
+ rc->debugfs_root_entry = debugfs_create_dir(rc->name,
+ debug_debugfs_root_entry);
+
+ /* append new element to linked list */
+ if (!debug_area_first) {
+ /* first element in list */
+ debug_area_first = rc;
+ rc->prev = NULL;
+ } else {
+ /* append element to end of list */
+ debug_area_last->next = rc;
+ rc->prev = debug_area_last;
+ }
+ debug_area_last = rc;
+ rc->next = NULL;
+
+ debug_info_get(rc);
+out:
+ return rc;
+}
+
+/*
+ * debug_info_copy
+ * - copy debug-info
+ */
+
+static debug_info_t*
+debug_info_copy(debug_info_t* in, int mode)
+{
+ int i,j;
+ debug_info_t* rc;
+ unsigned long flags;
+
+ /* get a consistent copy of the debug areas */
+ do {
+ rc = debug_info_alloc(in->name, in->pages_per_area,
+ in->nr_areas, in->buf_size, in->level, mode);
+ spin_lock_irqsave(&in->lock, flags);
+ if(!rc)
+ goto out;
+ /* has something changed in the meantime ? */
+ if((rc->pages_per_area == in->pages_per_area) &&
+ (rc->nr_areas == in->nr_areas)) {
+ break;
+ }
+ spin_unlock_irqrestore(&in->lock, flags);
+ debug_info_free(rc);
+ } while (1);
+
+ if(!rc || (mode == NO_AREAS))
+ goto out;
+
+ for(i = 0; i < in->nr_areas; i++){
+ for(j = 0; j < in->pages_per_area; j++) {
+ memcpy(rc->areas[i][j], in->areas[i][j],PAGE_SIZE);
+ }
+ }
+out:
+ spin_unlock_irqrestore(&in->lock, flags);
+ return rc;
+}
+
+/*
+ * debug_info_get
+ * - increments reference count for debug-info
+ */
+
+static void
+debug_info_get(debug_info_t * db_info)
+{
+ if (db_info)
+ atomic_inc(&db_info->ref_count);
+}
+
+/*
+ * debug_info_put:
+ * - decreases reference count for debug-info and frees it if necessary
+ */
+
+static void
+debug_info_put(debug_info_t *db_info)
+{
+ int i;
+
+ if (!db_info)
+ return;
+ if (atomic_dec_and_test(&db_info->ref_count)) {
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (!db_info->views[i])
+ continue;
+ debugfs_remove(db_info->debugfs_entries[i]);
+ }
+ debugfs_remove(db_info->debugfs_root_entry);
+ if(db_info == debug_area_first)
+ debug_area_first = db_info->next;
+ if(db_info == debug_area_last)
+ debug_area_last = db_info->prev;
+ if(db_info->prev) db_info->prev->next = db_info->next;
+ if(db_info->next) db_info->next->prev = db_info->prev;
+ debug_info_free(db_info);
+ }
+}
+
+/*
+ * debug_format_entry:
+ * - format one debug entry and return size of formated data
+ */
+
+static int
+debug_format_entry(file_private_info_t *p_info)
+{
+ debug_info_t *id_snap = p_info->debug_info_snap;
+ struct debug_view *view = p_info->view;
+ debug_entry_t *act_entry;
+ size_t len = 0;
+ if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
+ /* print prolog */
+ if (view->prolog_proc)
+ len += view->prolog_proc(id_snap,view,p_info->temp_buf);
+ goto out;
+ }
+ if (!id_snap->areas) /* this is true, if we have a prolog only view */
+ goto out; /* or if 'pages_per_area' is 0 */
+ act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area]
+ [p_info->act_page] + p_info->act_entry);
+
+ if (act_entry->id.stck == 0LL)
+ goto out; /* empty entry */
+ if (view->header_proc)
+ len += view->header_proc(id_snap, view, p_info->act_area,
+ act_entry, p_info->temp_buf + len);
+ if (view->format_proc)
+ len += view->format_proc(id_snap, view, p_info->temp_buf + len,
+ DEBUG_DATA(act_entry));
+out:
+ return len;
+}
+
+/*
+ * debug_next_entry:
+ * - goto next entry in p_info
+ */
+
+static inline int
+debug_next_entry(file_private_info_t *p_info)
+{
+ debug_info_t *id;
+
+ id = p_info->debug_info_snap;
+ if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
+ p_info->act_entry = 0;
+ p_info->act_page = 0;
+ goto out;
+ }
+ if(!id->areas)
+ return 1;
+ p_info->act_entry += id->entry_size;
+ /* switch to next page, if we reached the end of the page */
+ if (p_info->act_entry > (PAGE_SIZE - id->entry_size)){
+ /* next page */
+ p_info->act_entry = 0;
+ p_info->act_page += 1;
+ if((p_info->act_page % id->pages_per_area) == 0) {
+ /* next area */
+ p_info->act_area++;
+ p_info->act_page=0;
+ }
+ if(p_info->act_area >= id->nr_areas)
+ return 1;
+ }
+out:
+ return 0;
+}
+
+/*
+ * debug_output:
+ * - called for user read()
+ * - copies formated debug entries to the user buffer
+ */
+
+static ssize_t
+debug_output(struct file *file, /* file descriptor */
+ char __user *user_buf, /* user buffer */
+ size_t len, /* length of buffer */
+ loff_t *offset) /* offset in the file */
+{
+ size_t count = 0;
+ size_t entry_offset;
+ file_private_info_t *p_info;
+
+ p_info = ((file_private_info_t *) file->private_data);
+ if (*offset != p_info->offset)
+ return -EPIPE;
+ if(p_info->act_area >= p_info->debug_info_snap->nr_areas)
+ return 0;
+ entry_offset = p_info->act_entry_offset;
+ while(count < len){
+ int formatted_line_size;
+ int formatted_line_residue;
+ int user_buf_residue;
+ size_t copy_size;
+
+ formatted_line_size = debug_format_entry(p_info);
+ formatted_line_residue = formatted_line_size - entry_offset;
+ user_buf_residue = len-count;
+ copy_size = min(user_buf_residue, formatted_line_residue);
+ if(copy_size){
+ if (copy_to_user(user_buf + count, p_info->temp_buf
+ + entry_offset, copy_size))
+ return -EFAULT;
+ count += copy_size;
+ entry_offset += copy_size;
+ }
+ if(copy_size == formatted_line_residue){
+ entry_offset = 0;
+ if(debug_next_entry(p_info))
+ goto out;
+ }
+ }
+out:
+ p_info->offset = *offset + count;
+ p_info->act_entry_offset = entry_offset;
+ *offset = p_info->offset;
+ return count;
+}
+
+/*
+ * debug_input:
+ * - called for user write()
+ * - calls input function of view
+ */
+
+static ssize_t
+debug_input(struct file *file, const char __user *user_buf, size_t length,
+ loff_t *offset)
+{
+ int rc = 0;
+ file_private_info_t *p_info;
+
+ mutex_lock(&debug_mutex);
+ p_info = ((file_private_info_t *) file->private_data);
+ if (p_info->view->input_proc)
+ rc = p_info->view->input_proc(p_info->debug_info_org,
+ p_info->view, file, user_buf,
+ length, offset);
+ else
+ rc = -EPERM;
+ mutex_unlock(&debug_mutex);
+ return rc; /* number of input characters */
+}
+
+/*
+ * debug_open:
+ * - called for user open()
+ * - copies formated output to private_data area of the file
+ * handle
+ */
+
+static int
+debug_open(struct inode *inode, struct file *file)
+{
+ int i = 0, rc = 0;
+ file_private_info_t *p_info;
+ debug_info_t *debug_info, *debug_info_snapshot;
+
+ mutex_lock(&debug_mutex);
+ debug_info = file->f_path.dentry->d_inode->i_private;
+ /* find debug view */
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (!debug_info->views[i])
+ continue;
+ else if (debug_info->debugfs_entries[i] ==
+ file->f_path.dentry) {
+ goto found; /* found view ! */
+ }
+ }
+ /* no entry found */
+ rc = -EINVAL;
+ goto out;
+
+found:
+
+ /* Make snapshot of current debug areas to get it consistent. */
+ /* To copy all the areas is only needed, if we have a view which */
+ /* formats the debug areas. */
+
+ if(!debug_info->views[i]->format_proc &&
+ !debug_info->views[i]->header_proc){
+ debug_info_snapshot = debug_info_copy(debug_info, NO_AREAS);
+ } else {
+ debug_info_snapshot = debug_info_copy(debug_info, ALL_AREAS);
+ }
+
+ if(!debug_info_snapshot){
+ rc = -ENOMEM;
+ goto out;
+ }
+ p_info = kmalloc(sizeof(file_private_info_t),
+ GFP_KERNEL);
+ if(!p_info){
+ if(debug_info_snapshot)
+ debug_info_free(debug_info_snapshot);
+ rc = -ENOMEM;
+ goto out;
+ }
+ p_info->offset = 0;
+ p_info->debug_info_snap = debug_info_snapshot;
+ p_info->debug_info_org = debug_info;
+ p_info->view = debug_info->views[i];
+ p_info->act_area = 0;
+ p_info->act_page = 0;
+ p_info->act_entry = DEBUG_PROLOG_ENTRY;
+ p_info->act_entry_offset = 0;
+ file->private_data = p_info;
+ debug_info_get(debug_info);
+out:
+ mutex_unlock(&debug_mutex);
+ return rc;
+}
+
+/*
+ * debug_close:
+ * - called for user close()
+ * - deletes private_data area of the file handle
+ */
+
+static int
+debug_close(struct inode *inode, struct file *file)
+{
+ file_private_info_t *p_info;
+ p_info = (file_private_info_t *) file->private_data;
+ if(p_info->debug_info_snap)
+ debug_info_free(p_info->debug_info_snap);
+ debug_info_put(p_info->debug_info_org);
+ kfree(file->private_data);
+ return 0; /* success */
+}
+
+/*
+ * debug_register:
+ * - creates and initializes debug area for the caller
+ * - returns handle for debug area
+ */
+
+debug_info_t*
+debug_register (char *name, int pages_per_area, int nr_areas, int buf_size)
+{
+ debug_info_t *rc = NULL;
+
+ if (!initialized)
+ BUG();
+ mutex_lock(&debug_mutex);
+
+ /* create new debug_info */
+
+ rc = debug_info_create(name, pages_per_area, nr_areas, buf_size);
+ if(!rc)
+ goto out;
+ debug_register_view(rc, &debug_level_view);
+ debug_register_view(rc, &debug_flush_view);
+ debug_register_view(rc, &debug_pages_view);
+out:
+ if (!rc){
+ printk(KERN_ERR "debug: debug_register failed for %s\n",name);
+ }
+ mutex_unlock(&debug_mutex);
+ return rc;
+}
+
+/*
+ * debug_unregister:
+ * - give back debug area
+ */
+
+void
+debug_unregister(debug_info_t * id)
+{
+ if (!id)
+ goto out;
+ mutex_lock(&debug_mutex);
+ debug_info_put(id);
+ mutex_unlock(&debug_mutex);
+
+out:
+ return;
+}
+
+/*
+ * debug_set_size:
+ * - set area size (number of pages) and number of areas
+ */
+static int
+debug_set_size(debug_info_t* id, int nr_areas, int pages_per_area)
+{
+ unsigned long flags;
+ debug_entry_t *** new_areas;
+ int rc=0;
+
+ if(!id || (nr_areas <= 0) || (pages_per_area < 0))
+ return -EINVAL;
+ if(pages_per_area > 0){
+ new_areas = debug_areas_alloc(pages_per_area, nr_areas);
+ if(!new_areas) {
+ printk(KERN_WARNING "debug: could not allocate memory "\
+ "for pagenumber: %i\n",pages_per_area);
+ rc = -ENOMEM;
+ goto out;
+ }
+ } else {
+ new_areas = NULL;
+ }
+ spin_lock_irqsave(&id->lock,flags);
+ debug_areas_free(id);
+ id->areas = new_areas;
+ id->nr_areas = nr_areas;
+ id->pages_per_area = pages_per_area;
+ id->active_area = 0;
+ memset(id->active_entries,0,sizeof(int)*id->nr_areas);
+ memset(id->active_pages, 0, sizeof(int)*id->nr_areas);
+ spin_unlock_irqrestore(&id->lock,flags);
+ printk(KERN_INFO "debug: %s: set new size (%i pages)\n"\
+ ,id->name, pages_per_area);
+out:
+ return rc;
+}
+
+/*
+ * debug_set_level:
+ * - set actual debug level
+ */
+
+void
+debug_set_level(debug_info_t* id, int new_level)
+{
+ unsigned long flags;
+ if(!id)
+ return;
+ spin_lock_irqsave(&id->lock,flags);
+ if(new_level == DEBUG_OFF_LEVEL){
+ id->level = DEBUG_OFF_LEVEL;
+ printk(KERN_INFO "debug: %s: switched off\n",id->name);
+ } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
+ printk(KERN_INFO
+ "debug: %s: level %i is out of range (%i - %i)\n",
+ id->name, new_level, 0, DEBUG_MAX_LEVEL);
+ } else {
+ id->level = new_level;
+ }
+ spin_unlock_irqrestore(&id->lock,flags);
+}
+
+
+/*
+ * proceed_active_entry:
+ * - set active entry to next in the ring buffer
+ */
+
+static inline void
+proceed_active_entry(debug_info_t * id)
+{
+ if ((id->active_entries[id->active_area] += id->entry_size)
+ > (PAGE_SIZE - id->entry_size)){
+ id->active_entries[id->active_area] = 0;
+ id->active_pages[id->active_area] =
+ (id->active_pages[id->active_area] + 1) %
+ id->pages_per_area;
+ }
+}
+
+/*
+ * proceed_active_area:
+ * - set active area to next in the ring buffer
+ */
+
+static inline void
+proceed_active_area(debug_info_t * id)
+{
+ id->active_area++;
+ id->active_area = id->active_area % id->nr_areas;
+}
+
+/*
+ * get_active_entry:
+ */
+
+static inline debug_entry_t*
+get_active_entry(debug_info_t * id)
+{
+ return (debug_entry_t *) (((char *) id->areas[id->active_area]
+ [id->active_pages[id->active_area]]) +
+ id->active_entries[id->active_area]);
+}
+
+/*
+ * debug_finish_entry:
+ * - set timestamp, caller address, cpu number etc.
+ */
+
+static inline void
+debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
+ int exception)
+{
+ active->id.stck = get_clock();
+ active->id.fields.cpuid = smp_processor_id();
+ active->caller = __builtin_return_address(0);
+ active->id.fields.exception = exception;
+ active->id.fields.level = level;
+ proceed_active_entry(id);
+ if(exception)
+ proceed_active_area(id);
+}
+
+static int debug_stoppable=1;
+static int debug_active=1;
+
+#define CTL_S390DBF_STOPPABLE 5678
+#define CTL_S390DBF_ACTIVE 5679
+
+/*
+ * proc handler for the running debug_active sysctl
+ * always allow read, allow write only if debug_stoppable is set or
+ * if debug_active is already off
+ */
+static int
+s390dbf_procactive(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ if (!write || debug_stoppable || !debug_active)
+ return proc_dointvec(table, write, filp, buffer, lenp, ppos);
+ else
+ return 0;
+}
+
+
+static struct ctl_table s390dbf_table[] = {
+ {
+ .ctl_name = CTL_S390DBF_STOPPABLE,
+ .procname = "debug_stoppable",
+ .data = &debug_stoppable,
+ .maxlen = sizeof(int),
+ .mode = S_IRUGO | S_IWUSR,
+ .proc_handler = &proc_dointvec,
+ .strategy = &sysctl_intvec,
+ },
+ {
+ .ctl_name = CTL_S390DBF_ACTIVE,
+ .procname = "debug_active",
+ .data = &debug_active,
+ .maxlen = sizeof(int),
+ .mode = S_IRUGO | S_IWUSR,
+ .proc_handler = &s390dbf_procactive,
+ .strategy = &sysctl_intvec,
+ },
+ { .ctl_name = 0 }
+};
+
+static struct ctl_table s390dbf_dir_table[] = {
+ {
+ .ctl_name = CTL_S390DBF,
+ .procname = "s390dbf",
+ .maxlen = 0,
+ .mode = S_IRUGO | S_IXUGO,
+ .child = s390dbf_table,
+ },
+ { .ctl_name = 0 }
+};
+
+static struct ctl_table_header *s390dbf_sysctl_header;
+
+void
+debug_stop_all(void)
+{
+ if (debug_stoppable)
+ debug_active = 0;
+}
+
+
+/*
+ * debug_event_common:
+ * - write debug entry with given size
+ */
+
+debug_entry_t*
+debug_event_common(debug_info_t * id, int level, const void *buf, int len)
+{
+ unsigned long flags;
+ debug_entry_t *active;
+
+ if (!debug_active || !id->areas)
+ return NULL;
+ spin_lock_irqsave(&id->lock, flags);
+ active = get_active_entry(id);
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
+ debug_finish_entry(id, active, level, 0);
+ spin_unlock_irqrestore(&id->lock, flags);
+
+ return active;
+}
+
+/*
+ * debug_exception_common:
+ * - write debug entry with given size and switch to next debug area
+ */
+
+debug_entry_t
+*debug_exception_common(debug_info_t * id, int level, const void *buf, int len)
+{
+ unsigned long flags;
+ debug_entry_t *active;
+
+ if (!debug_active || !id->areas)
+ return NULL;
+ spin_lock_irqsave(&id->lock, flags);
+ active = get_active_entry(id);
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
+ debug_finish_entry(id, active, level, 1);
+ spin_unlock_irqrestore(&id->lock, flags);
+
+ return active;
+}
+
+/*
+ * counts arguments in format string for sprintf view
+ */
+
+static inline int
+debug_count_numargs(char *string)
+{
+ int numargs=0;
+
+ while(*string) {
+ if(*string++=='%')
+ numargs++;
+ }
+ return(numargs);
+}
+
+/*
+ * debug_sprintf_event:
+ */
+
+debug_entry_t*
+debug_sprintf_event(debug_info_t* id, int level,char *string,...)
+{
+ va_list ap;
+ int numargs,idx;
+ unsigned long flags;
+ debug_sprintf_entry_t *curr_event;
+ debug_entry_t *active;
+
+ if((!id) || (level > id->level))
+ return NULL;
+ if (!debug_active || !id->areas)
+ return NULL;
+ numargs=debug_count_numargs(string);
+
+ spin_lock_irqsave(&id->lock, flags);
+ active = get_active_entry(id);
+ curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active);
+ va_start(ap,string);
+ curr_event->string=string;
+ for(idx=0;idx<min(numargs,(int)(id->buf_size / sizeof(long))-1);idx++)
+ curr_event->args[idx]=va_arg(ap,long);
+ va_end(ap);
+ debug_finish_entry(id, active, level, 0);
+ spin_unlock_irqrestore(&id->lock, flags);
+
+ return active;
+}
+
+/*
+ * debug_sprintf_exception:
+ */
+
+debug_entry_t*
+debug_sprintf_exception(debug_info_t* id, int level,char *string,...)
+{
+ va_list ap;
+ int numargs,idx;
+ unsigned long flags;
+ debug_sprintf_entry_t *curr_event;
+ debug_entry_t *active;
+
+ if((!id) || (level > id->level))
+ return NULL;
+ if (!debug_active || !id->areas)
+ return NULL;
+
+ numargs=debug_count_numargs(string);
+
+ spin_lock_irqsave(&id->lock, flags);
+ active = get_active_entry(id);
+ curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active);
+ va_start(ap,string);
+ curr_event->string=string;
+ for(idx=0;idx<min(numargs,(int)(id->buf_size / sizeof(long))-1);idx++)
+ curr_event->args[idx]=va_arg(ap,long);
+ va_end(ap);
+ debug_finish_entry(id, active, level, 1);
+ spin_unlock_irqrestore(&id->lock, flags);
+
+ return active;
+}
+
+/*
+ * debug_init:
+ * - is called exactly once to initialize the debug feature
+ */
+
+static int
+__init debug_init(void)
+{
+ int rc = 0;
+
+ s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table);
+ mutex_lock(&debug_mutex);
+ debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL);
+ printk(KERN_INFO "debug: Initialization complete\n");
+ initialized = 1;
+ mutex_unlock(&debug_mutex);
+
+ return rc;
+}
+
+/*
+ * debug_register_view:
+ */
+
+int
+debug_register_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ unsigned long flags;
+ mode_t mode = S_IFREG;
+ struct dentry *pde;
+
+ if (!id)
+ goto out;
+ if (view->prolog_proc || view->format_proc || view->header_proc)
+ mode |= S_IRUSR;
+ if (view->input_proc)
+ mode |= S_IWUSR;
+ pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry,
+ id , &debug_file_ops);
+ if (!pde){
+ printk(KERN_WARNING "debug: debugfs_create_file() failed!"\
+ " Cannot register view %s/%s\n", id->name,view->name);
+ rc = -1;
+ goto out;
+ }
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (!id->views[i])
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS) {
+ printk(KERN_WARNING "debug: cannot register view %s/%s\n",
+ id->name,view->name);
+ printk(KERN_WARNING
+ "debug: maximum number of views reached (%i)!\n", i);
+ debugfs_remove(pde);
+ rc = -1;
+ } else {
+ id->views[i] = view;
+ id->debugfs_entries[i] = pde;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+out:
+ return rc;
+}
+
+/*
+ * debug_unregister_view:
+ */
+
+int
+debug_unregister_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ unsigned long flags;
+
+ if (!id)
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (id->views[i] == view)
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS)
+ rc = -1;
+ else {
+ debugfs_remove(id->debugfs_entries[i]);
+ id->views[i] = NULL;
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+out:
+ return rc;
+}
+
+static inline char *
+debug_get_user_string(const char __user *user_buf, size_t user_len)
+{
+ char* buffer;
+
+ buffer = kmalloc(user_len + 1, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+ if (copy_from_user(buffer, user_buf, user_len) != 0) {
+ kfree(buffer);
+ return ERR_PTR(-EFAULT);
+ }
+ /* got the string, now strip linefeed. */
+ if (buffer[user_len - 1] == '\n')
+ buffer[user_len - 1] = 0;
+ else
+ buffer[user_len] = 0;
+ return buffer;
+}
+
+static inline int
+debug_get_uint(char *buf)
+{
+ int rc;
+
+ for(; isspace(*buf); buf++);
+ rc = simple_strtoul(buf, &buf, 10);
+ if(*buf){
+ printk("debug: no integer specified!\n");
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+/*
+ * functions for debug-views
+ ***********************************
+*/
+
+/*
+ * prints out actual debug level
+ */
+
+static int
+debug_prolog_pages_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf)
+{
+ return sprintf(out_buf, "%i\n", id->pages_per_area);
+}
+
+/*
+ * reads new size (number of pages per debug area)
+ */
+
+static int
+debug_input_pages_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_len, loff_t * offset)
+{
+ char *str;
+ int rc,new_pages;
+
+ if (user_len > 0x10000)
+ user_len = 0x10000;
+ if (*offset != 0){
+ rc = -EPIPE;
+ goto out;
+ }
+ str = debug_get_user_string(user_buf,user_len);
+ if(IS_ERR(str)){
+ rc = PTR_ERR(str);
+ goto out;
+ }
+ new_pages = debug_get_uint(str);
+ if(new_pages < 0){
+ rc = -EINVAL;
+ goto free_str;
+ }
+ rc = debug_set_size(id,id->nr_areas, new_pages);
+ if(rc != 0){
+ rc = -EINVAL;
+ goto free_str;
+ }
+ rc = user_len;
+free_str:
+ kfree(str);
+out:
+ *offset += user_len;
+ return rc; /* number of input characters */
+}
+
+/*
+ * prints out actual debug level
+ */
+
+static int
+debug_prolog_level_fn(debug_info_t * id, struct debug_view *view, char *out_buf)
+{
+ int rc = 0;
+
+ if(id->level == DEBUG_OFF_LEVEL) {
+ rc = sprintf(out_buf,"-\n");
+ }
+ else {
+ rc = sprintf(out_buf, "%i\n", id->level);
+ }
+ return rc;
+}
+
+/*
+ * reads new debug level
+ */
+
+static int
+debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_len, loff_t * offset)
+{
+ char *str;
+ int rc,new_level;
+
+ if (user_len > 0x10000)
+ user_len = 0x10000;
+ if (*offset != 0){
+ rc = -EPIPE;
+ goto out;
+ }
+ str = debug_get_user_string(user_buf,user_len);
+ if(IS_ERR(str)){
+ rc = PTR_ERR(str);
+ goto out;
+ }
+ if(str[0] == '-'){
+ debug_set_level(id, DEBUG_OFF_LEVEL);
+ rc = user_len;
+ goto free_str;
+ } else {
+ new_level = debug_get_uint(str);
+ }
+ if(new_level < 0) {
+ printk(KERN_INFO "debug: level `%s` is not valid\n", str);
+ rc = -EINVAL;
+ } else {
+ debug_set_level(id, new_level);
+ rc = user_len;
+ }
+free_str:
+ kfree(str);
+out:
+ *offset += user_len;
+ return rc; /* number of input characters */
+}
+
+
+/*
+ * flushes debug areas
+ */
+
+static void debug_flush(debug_info_t* id, int area)
+{
+ unsigned long flags;
+ int i,j;
+
+ if(!id || !id->areas)
+ return;
+ spin_lock_irqsave(&id->lock,flags);
+ if(area == DEBUG_FLUSH_ALL){
+ id->active_area = 0;
+ memset(id->active_entries, 0, id->nr_areas * sizeof(int));
+ for (i = 0; i < id->nr_areas; i++) {
+ id->active_pages[i] = 0;
+ for(j = 0; j < id->pages_per_area; j++) {
+ memset(id->areas[i][j], 0, PAGE_SIZE);
+ }
+ }
+ printk(KERN_INFO "debug: %s: all areas flushed\n",id->name);
+ } else if(area >= 0 && area < id->nr_areas) {
+ id->active_entries[area] = 0;
+ id->active_pages[area] = 0;
+ for(i = 0; i < id->pages_per_area; i++) {
+ memset(id->areas[area][i],0,PAGE_SIZE);
+ }
+ printk(KERN_INFO "debug: %s: area %i has been flushed\n",
+ id->name, area);
+ } else {
+ printk(KERN_INFO
+ "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
+ id->name, area, 0, id->nr_areas-1);
+ }
+ spin_unlock_irqrestore(&id->lock,flags);
+}
+
+/*
+ * view function: flushes debug areas
+ */
+
+static int
+debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_len, loff_t * offset)
+{
+ char input_buf[1];
+ int rc = user_len;
+
+ if (user_len > 0x10000)
+ user_len = 0x10000;
+ if (*offset != 0){
+ rc = -EPIPE;
+ goto out;
+ }
+ if (copy_from_user(input_buf, user_buf, 1)){
+ rc = -EFAULT;
+ goto out;
+ }
+ if(input_buf[0] == '-') {
+ debug_flush(id, DEBUG_FLUSH_ALL);
+ goto out;
+ }
+ if (isdigit(input_buf[0])) {
+ int area = ((int) input_buf[0] - (int) '0');
+ debug_flush(id, area);
+ goto out;
+ }
+
+ printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]);
+
+out:
+ *offset += user_len;
+ return rc; /* number of input characters */
+}
+
+/*
+ * prints debug header in raw format
+ */
+
+static int
+debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
+{
+ int rc;
+
+ rc = sizeof(debug_entry_t);
+ memcpy(out_buf,entry,sizeof(debug_entry_t));
+ return rc;
+}
+
+/*
+ * prints debug data in raw format
+ */
+
+static int
+debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int rc;
+
+ rc = id->buf_size;
+ memcpy(out_buf, in_buf, id->buf_size);
+ return rc;
+}
+
+/*
+ * prints debug data in hex/ascii format
+ */
+
+static int
+debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int i, rc = 0;
+
+ for (i = 0; i < id->buf_size; i++) {
+ rc += sprintf(out_buf + rc, "%02x ",
+ ((unsigned char *) in_buf)[i]);
+ }
+ rc += sprintf(out_buf + rc, "| ");
+ for (i = 0; i < id->buf_size; i++) {
+ unsigned char c = in_buf[i];
+ if (!isprint(c))
+ rc += sprintf(out_buf + rc, ".");
+ else
+ rc += sprintf(out_buf + rc, "%c", c);
+ }
+ rc += sprintf(out_buf + rc, "\n");
+ return rc;
+}
+
+/*
+ * prints header for debug entry
+ */
+
+int
+debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
+{
+ struct timespec time_spec;
+ unsigned long long time;
+ char *except_str;
+ unsigned long caller;
+ int rc = 0;
+ unsigned int level;
+
+ level = entry->id.fields.level;
+ time = entry->id.stck;
+ /* adjust todclock to 1970 */
+ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
+ tod_to_timeval(time, &time_spec);
+
+ if (entry->id.fields.exception)
+ except_str = "*";
+ else
+ except_str = "-";
+ caller = ((unsigned long) entry->caller) & PSW_ADDR_INSN;
+ rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %p ",
+ area, time_spec.tv_sec, time_spec.tv_nsec / 1000, level,
+ except_str, entry->id.fields.cpuid, (void *) caller);
+ return rc;
+}
+
+/*
+ * prints debug data sprintf-formated:
+ * debug_sprinf_event/exception calls must be used together with this view
+ */
+
+#define DEBUG_SPRINTF_MAX_ARGS 10
+
+static int
+debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, debug_sprintf_entry_t *curr_event)
+{
+ int num_longs, num_used_args = 0,i, rc = 0;
+ int index[DEBUG_SPRINTF_MAX_ARGS];
+
+ /* count of longs fit into one entry */
+ num_longs = id->buf_size / sizeof(long);
+
+ if(num_longs < 1)
+ goto out; /* bufsize of entry too small */
+ if(num_longs == 1) {
+ /* no args, we use only the string */
+ strcpy(out_buf, curr_event->string);
+ rc = strlen(curr_event->string);
+ goto out;
+ }
+
+ /* number of arguments used for sprintf (without the format string) */
+ num_used_args = min(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1));
+
+ memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int));
+
+ for(i = 0; i < num_used_args; i++)
+ index[i] = i;
+
+ rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]],
+ curr_event->args[index[1]], curr_event->args[index[2]],
+ curr_event->args[index[3]], curr_event->args[index[4]],
+ curr_event->args[index[5]], curr_event->args[index[6]],
+ curr_event->args[index[7]], curr_event->args[index[8]],
+ curr_event->args[index[9]]);
+
+out:
+
+ return rc;
+}
+
+/*
+ * clean up module
+ */
+static void __exit debug_exit(void)
+{
+ debugfs_remove(debug_debugfs_root_entry);
+ unregister_sysctl_table(s390dbf_sysctl_header);
+ return;
+}
+
+/*
+ * module definitions
+ */
+postcore_initcall(debug_init);
+module_exit(debug_exit);
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(debug_register);
+EXPORT_SYMBOL(debug_unregister);
+EXPORT_SYMBOL(debug_set_level);
+EXPORT_SYMBOL(debug_stop_all);
+EXPORT_SYMBOL(debug_register_view);
+EXPORT_SYMBOL(debug_unregister_view);
+EXPORT_SYMBOL(debug_event_common);
+EXPORT_SYMBOL(debug_exception_common);
+EXPORT_SYMBOL(debug_hex_ascii_view);
+EXPORT_SYMBOL(debug_raw_view);
+EXPORT_SYMBOL(debug_dflt_header_fn);
+EXPORT_SYMBOL(debug_sprintf_view);
+EXPORT_SYMBOL(debug_sprintf_exception);
+EXPORT_SYMBOL(debug_sprintf_event);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/diag.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/diag.c
new file mode 100644
index 0000000000..c032d11da8
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/diag.c
@@ -0,0 +1,102 @@
+/*
+ * Implementation of s390 diagnose codes
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <asm/diag.h>
+
+/*
+ * Diagnose 10: Release pages
+ */
+void diag10(unsigned long addr)
+{
+ if (addr >= 0x7ff00000)
+ return;
+ asm volatile(
+#ifdef CONFIG_64BIT
+ " sam31\n"
+ " diag %0,%0,0x10\n"
+ "0: sam64\n"
+#else
+ " diag %0,%0,0x10\n"
+ "0:\n"
+#endif
+ EX_TABLE(0b, 0b)
+ : : "a" (addr));
+}
+EXPORT_SYMBOL(diag10);
+
+/*
+ * Diagnose 14: Input spool file manipulation
+ */
+int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode)
+{
+ register unsigned long _ry1 asm("2") = ry1;
+ register unsigned long _ry2 asm("3") = subcode;
+ int rc = 0;
+
+ asm volatile(
+#ifdef CONFIG_64BIT
+ " sam31\n"
+ " diag %2,2,0x14\n"
+ " sam64\n"
+#else
+ " diag %2,2,0x14\n"
+#endif
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (rc), "+d" (_ry2)
+ : "d" (rx), "d" (_ry1)
+ : "cc");
+
+ return rc;
+}
+EXPORT_SYMBOL(diag14);
+
+/*
+ * Diagnose 210: Get information about a virtual device
+ */
+int diag210(struct diag210 *addr)
+{
+ /*
+ * diag 210 needs its data below the 2GB border, so we
+ * use a static data area to be sure
+ */
+ static struct diag210 diag210_tmp;
+ static DEFINE_SPINLOCK(diag210_lock);
+ unsigned long flags;
+ int ccode;
+
+ spin_lock_irqsave(&diag210_lock, flags);
+ diag210_tmp = *addr;
+
+#ifdef CONFIG_64BIT
+ asm volatile(
+ " lhi %0,-1\n"
+ " sam31\n"
+ " diag %1,0,0x210\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1: sam64\n"
+ EX_TABLE(0b, 1b)
+ : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory");
+#else
+ asm volatile(
+ " lhi %0,-1\n"
+ " diag %1,0,0x210\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory");
+#endif
+
+ *addr = diag210_tmp;
+ spin_unlock_irqrestore(&diag210_lock, flags);
+
+ return ccode;
+}
+EXPORT_SYMBOL(diag210);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/dis.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/dis.c
new file mode 100644
index 0000000000..c14a336f63
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/dis.c
@@ -0,0 +1,1280 @@
+/*
+ * arch/s390/kernel/dis.c
+ *
+ * Disassemble s390 instructions.
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/reboot.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/mathemu.h>
+#include <asm/cpcmd.h>
+#include <asm/s390_ext.h>
+#include <asm/lowcore.h>
+#include <asm/debug.h>
+
+#ifndef CONFIG_64BIT
+#define ONELONG "%08lx: "
+#else /* CONFIG_64BIT */
+#define ONELONG "%016lx: "
+#endif /* CONFIG_64BIT */
+
+#define OPERAND_GPR 0x1 /* Operand printed as %rx */
+#define OPERAND_FPR 0x2 /* Operand printed as %fx */
+#define OPERAND_AR 0x4 /* Operand printed as %ax */
+#define OPERAND_CR 0x8 /* Operand printed as %cx */
+#define OPERAND_DISP 0x10 /* Operand printed as displacement */
+#define OPERAND_BASE 0x20 /* Operand printed as base register */
+#define OPERAND_INDEX 0x40 /* Operand printed as index register */
+#define OPERAND_PCREL 0x80 /* Operand printed as pc-relative symbol */
+#define OPERAND_SIGNED 0x100 /* Operand printed as signed value */
+#define OPERAND_LENGTH 0x200 /* Operand printed as length (+1) */
+
+enum {
+ UNUSED, /* Indicates the end of the operand list */
+ R_8, /* GPR starting at position 8 */
+ R_12, /* GPR starting at position 12 */
+ R_16, /* GPR starting at position 16 */
+ R_20, /* GPR starting at position 20 */
+ R_24, /* GPR starting at position 24 */
+ R_28, /* GPR starting at position 28 */
+ R_32, /* GPR starting at position 32 */
+ F_8, /* FPR starting at position 8 */
+ F_12, /* FPR starting at position 12 */
+ F_16, /* FPR starting at position 16 */
+ F_20, /* FPR starting at position 16 */
+ F_24, /* FPR starting at position 24 */
+ F_28, /* FPR starting at position 28 */
+ F_32, /* FPR starting at position 32 */
+ A_8, /* Access reg. starting at position 8 */
+ A_12, /* Access reg. starting at position 12 */
+ A_24, /* Access reg. starting at position 24 */
+ A_28, /* Access reg. starting at position 28 */
+ C_8, /* Control reg. starting at position 8 */
+ C_12, /* Control reg. starting at position 12 */
+ B_16, /* Base register starting at position 16 */
+ B_32, /* Base register starting at position 32 */
+ X_12, /* Index register starting at position 12 */
+ D_20, /* Displacement starting at position 20 */
+ D_36, /* Displacement starting at position 36 */
+ D20_20, /* 20 bit displacement starting at 20 */
+ L4_8, /* 4 bit length starting at position 8 */
+ L4_12, /* 4 bit length starting at position 12 */
+ L8_8, /* 8 bit length starting at position 8 */
+ U4_8, /* 4 bit unsigned value starting at 8 */
+ U4_12, /* 4 bit unsigned value starting at 12 */
+ U4_16, /* 4 bit unsigned value starting at 16 */
+ U4_20, /* 4 bit unsigned value starting at 20 */
+ U8_8, /* 8 bit unsigned value starting at 8 */
+ U8_16, /* 8 bit unsigned value starting at 16 */
+ I16_16, /* 16 bit signed value starting at 16 */
+ U16_16, /* 16 bit unsigned value starting at 16 */
+ J16_16, /* PC relative jump offset at 16 */
+ J32_16, /* PC relative long offset at 16 */
+ I32_16, /* 32 bit signed value starting at 16 */
+ U32_16, /* 32 bit unsigned value starting at 16 */
+ M_16, /* 4 bit optional mask starting at 16 */
+ RO_28, /* optional GPR starting at position 28 */
+};
+
+/*
+ * Enumeration of the different instruction formats.
+ * For details consult the principles of operation.
+ */
+enum {
+ INSTR_INVALID,
+ INSTR_E, INSTR_RIE_RRP, INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU,
+ INSTR_RIL_UP, INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP,
+ INSTR_RRE_00, INSTR_RRE_0R, INSTR_RRE_AA, INSTR_RRE_AR, INSTR_RRE_F0,
+ INSTR_RRE_FF, INSTR_RRE_R0, INSTR_RRE_RA, INSTR_RRE_RF, INSTR_RRE_RR,
+ INSTR_RRE_RR_OPT, INSTR_RRF_F0FF, INSTR_RRF_FUFF, INSTR_RRF_M0RR,
+ INSTR_RRF_R0RR, INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF,
+ INSTR_RR_FF, INSTR_RR_R0, INSTR_RR_RR, INSTR_RR_U0, INSTR_RR_UR,
+ INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD, INSTR_RSI_RRP,
+ INSTR_RSL_R0RD, INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD,
+ INSTR_RSY_RURD, INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD,
+ INSTR_RS_RRRD, INSTR_RS_RURD, INSTR_RXE_FRRD, INSTR_RXE_RRRD,
+ INSTR_RXF_FRRDF, INSTR_RXY_FRRD, INSTR_RXY_RRRD, INSTR_RX_FRRD,
+ INSTR_RX_RRRD, INSTR_RX_URRD, INSTR_SIY_URD, INSTR_SI_URD,
+ INSTR_SSE_RDRD, INSTR_SSF_RRDRD, INSTR_SS_L0RDRD, INSTR_SS_LIRDRD,
+ INSTR_SS_LLRDRD, INSTR_SS_RRRDRD, INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3,
+ INSTR_S_00, INSTR_S_RD,
+};
+
+struct operand {
+ int bits; /* The number of bits in the operand. */
+ int shift; /* The number of bits to shift. */
+ int flags; /* One bit syntax flags. */
+};
+
+struct insn {
+ const char name[5];
+ unsigned char opfrag;
+ unsigned char format;
+};
+
+static const struct operand operands[] =
+{
+ [UNUSED] = { 0, 0, 0 },
+ [R_8] = { 4, 8, OPERAND_GPR },
+ [R_12] = { 4, 12, OPERAND_GPR },
+ [R_16] = { 4, 16, OPERAND_GPR },
+ [R_20] = { 4, 20, OPERAND_GPR },
+ [R_24] = { 4, 24, OPERAND_GPR },
+ [R_28] = { 4, 28, OPERAND_GPR },
+ [R_32] = { 4, 32, OPERAND_GPR },
+ [F_8] = { 4, 8, OPERAND_FPR },
+ [F_12] = { 4, 12, OPERAND_FPR },
+ [F_16] = { 4, 16, OPERAND_FPR },
+ [F_20] = { 4, 16, OPERAND_FPR },
+ [F_24] = { 4, 24, OPERAND_FPR },
+ [F_28] = { 4, 28, OPERAND_FPR },
+ [F_32] = { 4, 32, OPERAND_FPR },
+ [A_8] = { 4, 8, OPERAND_AR },
+ [A_12] = { 4, 12, OPERAND_AR },
+ [A_24] = { 4, 24, OPERAND_AR },
+ [A_28] = { 4, 28, OPERAND_AR },
+ [C_8] = { 4, 8, OPERAND_CR },
+ [C_12] = { 4, 12, OPERAND_CR },
+ [B_16] = { 4, 16, OPERAND_BASE | OPERAND_GPR },
+ [B_32] = { 4, 32, OPERAND_BASE | OPERAND_GPR },
+ [X_12] = { 4, 12, OPERAND_INDEX | OPERAND_GPR },
+ [D_20] = { 12, 20, OPERAND_DISP },
+ [D_36] = { 12, 36, OPERAND_DISP },
+ [D20_20] = { 20, 20, OPERAND_DISP | OPERAND_SIGNED },
+ [L4_8] = { 4, 8, OPERAND_LENGTH },
+ [L4_12] = { 4, 12, OPERAND_LENGTH },
+ [L8_8] = { 8, 8, OPERAND_LENGTH },
+ [U4_8] = { 4, 8, 0 },
+ [U4_12] = { 4, 12, 0 },
+ [U4_16] = { 4, 16, 0 },
+ [U4_20] = { 4, 20, 0 },
+ [U8_8] = { 8, 8, 0 },
+ [U8_16] = { 8, 16, 0 },
+ [I16_16] = { 16, 16, OPERAND_SIGNED },
+ [U16_16] = { 16, 16, 0 },
+ [J16_16] = { 16, 16, OPERAND_PCREL },
+ [J32_16] = { 32, 16, OPERAND_PCREL },
+ [I32_16] = { 32, 16, OPERAND_SIGNED },
+ [U32_16] = { 32, 16, 0 },
+ [M_16] = { 4, 16, 0 },
+ [RO_28] = { 4, 28, OPERAND_GPR }
+};
+
+static const unsigned char formats[][7] = {
+ [INSTR_E] = { 0xff, 0,0,0,0,0,0 }, /* e.g. pr */
+ [INSTR_RIE_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, /* e.g. brxhg */
+ [INSTR_RIL_RP] = { 0x0f, R_8,J32_16,0,0,0,0 }, /* e.g. brasl */
+ [INSTR_RIL_UP] = { 0x0f, U4_8,J32_16,0,0,0,0 }, /* e.g. brcl */
+ [INSTR_RIL_RI] = { 0x0f, R_8,I32_16,0,0,0,0 }, /* e.g. afi */
+ [INSTR_RIL_RU] = { 0x0f, R_8,U32_16,0,0,0,0 }, /* e.g. alfi */
+ [INSTR_RI_RI] = { 0x0f, R_8,I16_16,0,0,0,0 }, /* e.g. ahi */
+ [INSTR_RI_RP] = { 0x0f, R_8,J16_16,0,0,0,0 }, /* e.g. brct */
+ [INSTR_RI_RU] = { 0x0f, R_8,U16_16,0,0,0,0 }, /* e.g. tml */
+ [INSTR_RI_UP] = { 0x0f, U4_8,J16_16,0,0,0,0 }, /* e.g. brc */
+ [INSTR_RRE_00] = { 0xff, 0,0,0,0,0,0 }, /* e.g. palb */
+ [INSTR_RRE_0R] = { 0xff, R_28,0,0,0,0,0 }, /* e.g. tb */
+ [INSTR_RRE_AA] = { 0xff, A_24,A_28,0,0,0,0 }, /* e.g. cpya */
+ [INSTR_RRE_AR] = { 0xff, A_24,R_28,0,0,0,0 }, /* e.g. sar */
+ [INSTR_RRE_F0] = { 0xff, F_24,0,0,0,0,0 }, /* e.g. sqer */
+ [INSTR_RRE_FF] = { 0xff, F_24,F_28,0,0,0,0 }, /* e.g. debr */
+ [INSTR_RRE_R0] = { 0xff, R_24,0,0,0,0,0 }, /* e.g. ipm */
+ [INSTR_RRE_RA] = { 0xff, R_24,A_28,0,0,0,0 }, /* e.g. ear */
+ [INSTR_RRE_RF] = { 0xff, R_24,F_28,0,0,0,0 }, /* e.g. cefbr */
+ [INSTR_RRE_RR] = { 0xff, R_24,R_28,0,0,0,0 }, /* e.g. lura */
+ [INSTR_RRE_RR_OPT]= { 0xff, R_24,RO_28,0,0,0,0 }, /* efpc, sfpc */
+ [INSTR_RRF_F0FF] = { 0xff, F_16,F_24,F_28,0,0,0 }, /* e.g. madbr */
+ [INSTR_RRF_FUFF] = { 0xff, F_24,F_16,F_28,U4_20,0,0 },/* e.g. didbr */
+ [INSTR_RRF_RURR] = { 0xff, R_24,R_28,R_16,U4_20,0,0 },/* e.g. .insn */
+ [INSTR_RRF_R0RR] = { 0xff, R_24,R_28,R_16,0,0,0 }, /* e.g. idte */
+ [INSTR_RRF_U0FF] = { 0xff, F_24,U4_16,F_28,0,0,0 }, /* e.g. fixr */
+ [INSTR_RRF_U0RF] = { 0xff, R_24,U4_16,F_28,0,0,0 }, /* e.g. cfebr */
+ [INSTR_RRF_M0RR] = { 0xff, R_24,R_28,M_16,0,0,0 }, /* e.g. sske */
+ [INSTR_RR_FF] = { 0xff, F_8,F_12,0,0,0,0 }, /* e.g. adr */
+ [INSTR_RR_R0] = { 0xff, R_8, 0,0,0,0,0 }, /* e.g. spm */
+ [INSTR_RR_RR] = { 0xff, R_8,R_12,0,0,0,0 }, /* e.g. lr */
+ [INSTR_RR_U0] = { 0xff, U8_8, 0,0,0,0,0 }, /* e.g. svc */
+ [INSTR_RR_UR] = { 0xff, U4_8,R_12,0,0,0,0 }, /* e.g. bcr */
+ [INSTR_RSE_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, /* e.g. lmh */
+ [INSTR_RSE_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, /* e.g. lmh */
+ [INSTR_RSE_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icmh */
+ [INSTR_RSL_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, /* e.g. tp */
+ [INSTR_RSI_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, /* e.g. brxh */
+ [INSTR_RSY_RRRD] = { 0xff, R_8,R_12,D20_20,B_16,0,0 },/* e.g. stmy */
+ [INSTR_RSY_RURD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 },
+ /* e.g. icmh */
+ [INSTR_RSY_AARD] = { 0xff, A_8,A_12,D20_20,B_16,0,0 },/* e.g. lamy */
+ [INSTR_RSY_CCRD] = { 0xff, C_8,C_12,D20_20,B_16,0,0 },/* e.g. lamy */
+ [INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 }, /* e.g. lam */
+ [INSTR_RS_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, /* e.g. lctl */
+ [INSTR_RS_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, /* e.g. sll */
+ [INSTR_RS_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, /* e.g. cs */
+ [INSTR_RS_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icm */
+ [INSTR_RXE_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, /* e.g. axbr */
+ [INSTR_RXE_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, /* e.g. lg */
+ [INSTR_RXF_FRRDF] = { 0xff, F_32,F_8,D_20,X_12,B_16,0 },
+ /* e.g. madb */
+ [INSTR_RXY_RRRD] = { 0xff, R_8,D20_20,X_12,B_16,0,0 },/* e.g. ly */
+ [INSTR_RXY_FRRD] = { 0xff, F_8,D20_20,X_12,B_16,0,0 },/* e.g. ley */
+ [INSTR_RX_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, /* e.g. ae */
+ [INSTR_RX_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, /* e.g. l */
+ [INSTR_RX_URRD] = { 0xff, U4_8,D_20,X_12,B_16,0,0 }, /* e.g. bc */
+ [INSTR_SI_URD] = { 0xff, D_20,B_16,U8_8,0,0,0 }, /* e.g. cli */
+ [INSTR_SIY_URD] = { 0xff, D20_20,B_16,U8_8,0,0,0 }, /* e.g. tmy */
+ [INSTR_SSE_RDRD] = { 0xff, D_20,B_16,D_36,B_32,0,0 }, /* e.g. mvsdk */
+ [INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 },
+ /* e.g. mvc */
+ [INSTR_SS_LIRDRD] = { 0xff, D_20,L4_8,B_16,D_36,B_32,U4_12 },
+ /* e.g. srp */
+ [INSTR_SS_LLRDRD] = { 0xff, D_20,L4_8,B_16,D_36,L4_12,B_32 },
+ /* e.g. pack */
+ [INSTR_SS_RRRDRD] = { 0xff, D_20,R_8,B_16,D_36,B_32,R_12 },
+ /* e.g. mvck */
+ [INSTR_SS_RRRDRD2]= { 0xff, R_8,D_20,B_16,R_12,D_36,B_32 },
+ /* e.g. plo */
+ [INSTR_SS_RRRDRD3]= { 0xff, R_8,R_12,D_20,B_16,D_36,B_32 },
+ /* e.g. lmd */
+ [INSTR_S_00] = { 0xff, 0,0,0,0,0,0 }, /* e.g. hsch */
+ [INSTR_S_RD] = { 0xff, D_20,B_16,0,0,0,0 }, /* e.g. lpsw */
+ [INSTR_SSF_RRDRD] = { 0x00, D_20,B_16,D_36,B_32,R_8,0 },
+ /* e.g. mvcos */
+};
+
+static struct insn opcode[] = {
+#ifdef CONFIG_64BIT
+ { "lmd", 0xef, INSTR_SS_RRRDRD3 },
+#endif
+ { "spm", 0x04, INSTR_RR_R0 },
+ { "balr", 0x05, INSTR_RR_RR },
+ { "bctr", 0x06, INSTR_RR_RR },
+ { "bcr", 0x07, INSTR_RR_UR },
+ { "svc", 0x0a, INSTR_RR_U0 },
+ { "bsm", 0x0b, INSTR_RR_RR },
+ { "bassm", 0x0c, INSTR_RR_RR },
+ { "basr", 0x0d, INSTR_RR_RR },
+ { "mvcl", 0x0e, INSTR_RR_RR },
+ { "clcl", 0x0f, INSTR_RR_RR },
+ { "lpr", 0x10, INSTR_RR_RR },
+ { "lnr", 0x11, INSTR_RR_RR },
+ { "ltr", 0x12, INSTR_RR_RR },
+ { "lcr", 0x13, INSTR_RR_RR },
+ { "nr", 0x14, INSTR_RR_RR },
+ { "clr", 0x15, INSTR_RR_RR },
+ { "or", 0x16, INSTR_RR_RR },
+ { "xr", 0x17, INSTR_RR_RR },
+ { "lr", 0x18, INSTR_RR_RR },
+ { "cr", 0x19, INSTR_RR_RR },
+ { "ar", 0x1a, INSTR_RR_RR },
+ { "sr", 0x1b, INSTR_RR_RR },
+ { "mr", 0x1c, INSTR_RR_RR },
+ { "dr", 0x1d, INSTR_RR_RR },
+ { "alr", 0x1e, INSTR_RR_RR },
+ { "slr", 0x1f, INSTR_RR_RR },
+ { "lpdr", 0x20, INSTR_RR_FF },
+ { "lndr", 0x21, INSTR_RR_FF },
+ { "ltdr", 0x22, INSTR_RR_FF },
+ { "lcdr", 0x23, INSTR_RR_FF },
+ { "hdr", 0x24, INSTR_RR_FF },
+ { "ldxr", 0x25, INSTR_RR_FF },
+ { "lrdr", 0x25, INSTR_RR_FF },
+ { "mxr", 0x26, INSTR_RR_FF },
+ { "mxdr", 0x27, INSTR_RR_FF },
+ { "ldr", 0x28, INSTR_RR_FF },
+ { "cdr", 0x29, INSTR_RR_FF },
+ { "adr", 0x2a, INSTR_RR_FF },
+ { "sdr", 0x2b, INSTR_RR_FF },
+ { "mdr", 0x2c, INSTR_RR_FF },
+ { "ddr", 0x2d, INSTR_RR_FF },
+ { "awr", 0x2e, INSTR_RR_FF },
+ { "swr", 0x2f, INSTR_RR_FF },
+ { "lper", 0x30, INSTR_RR_FF },
+ { "lner", 0x31, INSTR_RR_FF },
+ { "lter", 0x32, INSTR_RR_FF },
+ { "lcer", 0x33, INSTR_RR_FF },
+ { "her", 0x34, INSTR_RR_FF },
+ { "ledr", 0x35, INSTR_RR_FF },
+ { "lrer", 0x35, INSTR_RR_FF },
+ { "axr", 0x36, INSTR_RR_FF },
+ { "sxr", 0x37, INSTR_RR_FF },
+ { "ler", 0x38, INSTR_RR_FF },
+ { "cer", 0x39, INSTR_RR_FF },
+ { "aer", 0x3a, INSTR_RR_FF },
+ { "ser", 0x3b, INSTR_RR_FF },
+ { "mder", 0x3c, INSTR_RR_FF },
+ { "mer", 0x3c, INSTR_RR_FF },
+ { "der", 0x3d, INSTR_RR_FF },
+ { "aur", 0x3e, INSTR_RR_FF },
+ { "sur", 0x3f, INSTR_RR_FF },
+ { "sth", 0x40, INSTR_RX_RRRD },
+ { "la", 0x41, INSTR_RX_RRRD },
+ { "stc", 0x42, INSTR_RX_RRRD },
+ { "ic", 0x43, INSTR_RX_RRRD },
+ { "ex", 0x44, INSTR_RX_RRRD },
+ { "bal", 0x45, INSTR_RX_RRRD },
+ { "bct", 0x46, INSTR_RX_RRRD },
+ { "bc", 0x47, INSTR_RX_URRD },
+ { "lh", 0x48, INSTR_RX_RRRD },
+ { "ch", 0x49, INSTR_RX_RRRD },
+ { "ah", 0x4a, INSTR_RX_RRRD },
+ { "sh", 0x4b, INSTR_RX_RRRD },
+ { "mh", 0x4c, INSTR_RX_RRRD },
+ { "bas", 0x4d, INSTR_RX_RRRD },
+ { "cvd", 0x4e, INSTR_RX_RRRD },
+ { "cvb", 0x4f, INSTR_RX_RRRD },
+ { "st", 0x50, INSTR_RX_RRRD },
+ { "lae", 0x51, INSTR_RX_RRRD },
+ { "n", 0x54, INSTR_RX_RRRD },
+ { "cl", 0x55, INSTR_RX_RRRD },
+ { "o", 0x56, INSTR_RX_RRRD },
+ { "x", 0x57, INSTR_RX_RRRD },
+ { "l", 0x58, INSTR_RX_RRRD },
+ { "c", 0x59, INSTR_RX_RRRD },
+ { "a", 0x5a, INSTR_RX_RRRD },
+ { "s", 0x5b, INSTR_RX_RRRD },
+ { "m", 0x5c, INSTR_RX_RRRD },
+ { "d", 0x5d, INSTR_RX_RRRD },
+ { "al", 0x5e, INSTR_RX_RRRD },
+ { "sl", 0x5f, INSTR_RX_RRRD },
+ { "std", 0x60, INSTR_RX_FRRD },
+ { "mxd", 0x67, INSTR_RX_FRRD },
+ { "ld", 0x68, INSTR_RX_FRRD },
+ { "cd", 0x69, INSTR_RX_FRRD },
+ { "ad", 0x6a, INSTR_RX_FRRD },
+ { "sd", 0x6b, INSTR_RX_FRRD },
+ { "md", 0x6c, INSTR_RX_FRRD },
+ { "dd", 0x6d, INSTR_RX_FRRD },
+ { "aw", 0x6e, INSTR_RX_FRRD },
+ { "sw", 0x6f, INSTR_RX_FRRD },
+ { "ste", 0x70, INSTR_RX_FRRD },
+ { "ms", 0x71, INSTR_RX_RRRD },
+ { "le", 0x78, INSTR_RX_FRRD },
+ { "ce", 0x79, INSTR_RX_FRRD },
+ { "ae", 0x7a, INSTR_RX_FRRD },
+ { "se", 0x7b, INSTR_RX_FRRD },
+ { "mde", 0x7c, INSTR_RX_FRRD },
+ { "me", 0x7c, INSTR_RX_FRRD },
+ { "de", 0x7d, INSTR_RX_FRRD },
+ { "au", 0x7e, INSTR_RX_FRRD },
+ { "su", 0x7f, INSTR_RX_FRRD },
+ { "ssm", 0x80, INSTR_S_RD },
+ { "lpsw", 0x82, INSTR_S_RD },
+ { "diag", 0x83, INSTR_RS_RRRD },
+ { "brxh", 0x84, INSTR_RSI_RRP },
+ { "brxle", 0x85, INSTR_RSI_RRP },
+ { "bxh", 0x86, INSTR_RS_RRRD },
+ { "bxle", 0x87, INSTR_RS_RRRD },
+ { "srl", 0x88, INSTR_RS_R0RD },
+ { "sll", 0x89, INSTR_RS_R0RD },
+ { "sra", 0x8a, INSTR_RS_R0RD },
+ { "sla", 0x8b, INSTR_RS_R0RD },
+ { "srdl", 0x8c, INSTR_RS_R0RD },
+ { "sldl", 0x8d, INSTR_RS_R0RD },
+ { "srda", 0x8e, INSTR_RS_R0RD },
+ { "slda", 0x8f, INSTR_RS_R0RD },
+ { "stm", 0x90, INSTR_RS_RRRD },
+ { "tm", 0x91, INSTR_SI_URD },
+ { "mvi", 0x92, INSTR_SI_URD },
+ { "ts", 0x93, INSTR_S_RD },
+ { "ni", 0x94, INSTR_SI_URD },
+ { "cli", 0x95, INSTR_SI_URD },
+ { "oi", 0x96, INSTR_SI_URD },
+ { "xi", 0x97, INSTR_SI_URD },
+ { "lm", 0x98, INSTR_RS_RRRD },
+ { "trace", 0x99, INSTR_RS_RRRD },
+ { "lam", 0x9a, INSTR_RS_AARD },
+ { "stam", 0x9b, INSTR_RS_AARD },
+ { "mvcle", 0xa8, INSTR_RS_RRRD },
+ { "clcle", 0xa9, INSTR_RS_RRRD },
+ { "stnsm", 0xac, INSTR_SI_URD },
+ { "stosm", 0xad, INSTR_SI_URD },
+ { "sigp", 0xae, INSTR_RS_RRRD },
+ { "mc", 0xaf, INSTR_SI_URD },
+ { "lra", 0xb1, INSTR_RX_RRRD },
+ { "stctl", 0xb6, INSTR_RS_CCRD },
+ { "lctl", 0xb7, INSTR_RS_CCRD },
+ { "cs", 0xba, INSTR_RS_RRRD },
+ { "cds", 0xbb, INSTR_RS_RRRD },
+ { "clm", 0xbd, INSTR_RS_RURD },
+ { "stcm", 0xbe, INSTR_RS_RURD },
+ { "icm", 0xbf, INSTR_RS_RURD },
+ { "mvn", 0xd1, INSTR_SS_L0RDRD },
+ { "mvc", 0xd2, INSTR_SS_L0RDRD },
+ { "mvz", 0xd3, INSTR_SS_L0RDRD },
+ { "nc", 0xd4, INSTR_SS_L0RDRD },
+ { "clc", 0xd5, INSTR_SS_L0RDRD },
+ { "oc", 0xd6, INSTR_SS_L0RDRD },
+ { "xc", 0xd7, INSTR_SS_L0RDRD },
+ { "mvck", 0xd9, INSTR_SS_RRRDRD },
+ { "mvcp", 0xda, INSTR_SS_RRRDRD },
+ { "mvcs", 0xdb, INSTR_SS_RRRDRD },
+ { "tr", 0xdc, INSTR_SS_L0RDRD },
+ { "trt", 0xdd, INSTR_SS_L0RDRD },
+ { "ed", 0xde, INSTR_SS_L0RDRD },
+ { "edmk", 0xdf, INSTR_SS_L0RDRD },
+ { "pku", 0xe1, INSTR_SS_L0RDRD },
+ { "unpku", 0xe2, INSTR_SS_L0RDRD },
+ { "mvcin", 0xe8, INSTR_SS_L0RDRD },
+ { "pka", 0xe9, INSTR_SS_L0RDRD },
+ { "unpka", 0xea, INSTR_SS_L0RDRD },
+ { "plo", 0xee, INSTR_SS_RRRDRD2 },
+ { "srp", 0xf0, INSTR_SS_LIRDRD },
+ { "mvo", 0xf1, INSTR_SS_LLRDRD },
+ { "pack", 0xf2, INSTR_SS_LLRDRD },
+ { "unpk", 0xf3, INSTR_SS_LLRDRD },
+ { "zap", 0xf8, INSTR_SS_LLRDRD },
+ { "cp", 0xf9, INSTR_SS_LLRDRD },
+ { "ap", 0xfa, INSTR_SS_LLRDRD },
+ { "sp", 0xfb, INSTR_SS_LLRDRD },
+ { "mp", 0xfc, INSTR_SS_LLRDRD },
+ { "dp", 0xfd, INSTR_SS_LLRDRD },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_01[] = {
+#ifdef CONFIG_64BIT
+ { "sam64", 0x0e, INSTR_E },
+#endif
+ { "pr", 0x01, INSTR_E },
+ { "upt", 0x02, INSTR_E },
+ { "sckpf", 0x07, INSTR_E },
+ { "tam", 0x0b, INSTR_E },
+ { "sam24", 0x0c, INSTR_E },
+ { "sam31", 0x0d, INSTR_E },
+ { "trap2", 0xff, INSTR_E },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_a5[] = {
+#ifdef CONFIG_64BIT
+ { "iihh", 0x00, INSTR_RI_RU },
+ { "iihl", 0x01, INSTR_RI_RU },
+ { "iilh", 0x02, INSTR_RI_RU },
+ { "iill", 0x03, INSTR_RI_RU },
+ { "nihh", 0x04, INSTR_RI_RU },
+ { "nihl", 0x05, INSTR_RI_RU },
+ { "nilh", 0x06, INSTR_RI_RU },
+ { "nill", 0x07, INSTR_RI_RU },
+ { "oihh", 0x08, INSTR_RI_RU },
+ { "oihl", 0x09, INSTR_RI_RU },
+ { "oilh", 0x0a, INSTR_RI_RU },
+ { "oill", 0x0b, INSTR_RI_RU },
+ { "llihh", 0x0c, INSTR_RI_RU },
+ { "llihl", 0x0d, INSTR_RI_RU },
+ { "llilh", 0x0e, INSTR_RI_RU },
+ { "llill", 0x0f, INSTR_RI_RU },
+#endif
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_a7[] = {
+#ifdef CONFIG_64BIT
+ { "tmhh", 0x02, INSTR_RI_RU },
+ { "tmhl", 0x03, INSTR_RI_RU },
+ { "brctg", 0x07, INSTR_RI_RP },
+ { "lghi", 0x09, INSTR_RI_RI },
+ { "aghi", 0x0b, INSTR_RI_RI },
+ { "mghi", 0x0d, INSTR_RI_RI },
+ { "cghi", 0x0f, INSTR_RI_RI },
+#endif
+ { "tmlh", 0x00, INSTR_RI_RU },
+ { "tmll", 0x01, INSTR_RI_RU },
+ { "brc", 0x04, INSTR_RI_UP },
+ { "bras", 0x05, INSTR_RI_RP },
+ { "brct", 0x06, INSTR_RI_RP },
+ { "lhi", 0x08, INSTR_RI_RI },
+ { "ahi", 0x0a, INSTR_RI_RI },
+ { "mhi", 0x0c, INSTR_RI_RI },
+ { "chi", 0x0e, INSTR_RI_RI },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_b2[] = {
+#ifdef CONFIG_64BIT
+ { "sske", 0x2b, INSTR_RRF_M0RR },
+ { "stckf", 0x7c, INSTR_S_RD },
+ { "cu21", 0xa6, INSTR_RRF_M0RR },
+ { "cuutf", 0xa6, INSTR_RRF_M0RR },
+ { "cu12", 0xa7, INSTR_RRF_M0RR },
+ { "cutfu", 0xa7, INSTR_RRF_M0RR },
+ { "stfle", 0xb0, INSTR_S_RD },
+ { "lpswe", 0xb2, INSTR_S_RD },
+#endif
+ { "stidp", 0x02, INSTR_S_RD },
+ { "sck", 0x04, INSTR_S_RD },
+ { "stck", 0x05, INSTR_S_RD },
+ { "sckc", 0x06, INSTR_S_RD },
+ { "stckc", 0x07, INSTR_S_RD },
+ { "spt", 0x08, INSTR_S_RD },
+ { "stpt", 0x09, INSTR_S_RD },
+ { "spka", 0x0a, INSTR_S_RD },
+ { "ipk", 0x0b, INSTR_S_00 },
+ { "ptlb", 0x0d, INSTR_S_00 },
+ { "spx", 0x10, INSTR_S_RD },
+ { "stpx", 0x11, INSTR_S_RD },
+ { "stap", 0x12, INSTR_S_RD },
+ { "sie", 0x14, INSTR_S_RD },
+ { "pc", 0x18, INSTR_S_RD },
+ { "sac", 0x19, INSTR_S_RD },
+ { "cfc", 0x1a, INSTR_S_RD },
+ { "ipte", 0x21, INSTR_RRE_RR },
+ { "ipm", 0x22, INSTR_RRE_R0 },
+ { "ivsk", 0x23, INSTR_RRE_RR },
+ { "iac", 0x24, INSTR_RRE_R0 },
+ { "ssar", 0x25, INSTR_RRE_R0 },
+ { "epar", 0x26, INSTR_RRE_R0 },
+ { "esar", 0x27, INSTR_RRE_R0 },
+ { "pt", 0x28, INSTR_RRE_RR },
+ { "iske", 0x29, INSTR_RRE_RR },
+ { "rrbe", 0x2a, INSTR_RRE_RR },
+ { "sske", 0x2b, INSTR_RRE_RR },
+ { "tb", 0x2c, INSTR_RRE_0R },
+ { "dxr", 0x2d, INSTR_RRE_F0 },
+ { "pgin", 0x2e, INSTR_RRE_RR },
+ { "pgout", 0x2f, INSTR_RRE_RR },
+ { "csch", 0x30, INSTR_S_00 },
+ { "hsch", 0x31, INSTR_S_00 },
+ { "msch", 0x32, INSTR_S_RD },
+ { "ssch", 0x33, INSTR_S_RD },
+ { "stsch", 0x34, INSTR_S_RD },
+ { "tsch", 0x35, INSTR_S_RD },
+ { "tpi", 0x36, INSTR_S_RD },
+ { "sal", 0x37, INSTR_S_00 },
+ { "rsch", 0x38, INSTR_S_00 },
+ { "stcrw", 0x39, INSTR_S_RD },
+ { "stcps", 0x3a, INSTR_S_RD },
+ { "rchp", 0x3b, INSTR_S_00 },
+ { "schm", 0x3c, INSTR_S_00 },
+ { "bakr", 0x40, INSTR_RRE_RR },
+ { "cksm", 0x41, INSTR_RRE_RR },
+ { "sqdr", 0x44, INSTR_RRE_F0 },
+ { "sqer", 0x45, INSTR_RRE_F0 },
+ { "stura", 0x46, INSTR_RRE_RR },
+ { "msta", 0x47, INSTR_RRE_R0 },
+ { "palb", 0x48, INSTR_RRE_00 },
+ { "ereg", 0x49, INSTR_RRE_RR },
+ { "esta", 0x4a, INSTR_RRE_RR },
+ { "lura", 0x4b, INSTR_RRE_RR },
+ { "tar", 0x4c, INSTR_RRE_AR },
+ { "cpya", 0x4d, INSTR_RRE_AA },
+ { "sar", 0x4e, INSTR_RRE_AR },
+ { "ear", 0x4f, INSTR_RRE_RA },
+ { "csp", 0x50, INSTR_RRE_RR },
+ { "msr", 0x52, INSTR_RRE_RR },
+ { "mvpg", 0x54, INSTR_RRE_RR },
+ { "mvst", 0x55, INSTR_RRE_RR },
+ { "cuse", 0x57, INSTR_RRE_RR },
+ { "bsg", 0x58, INSTR_RRE_RR },
+ { "bsa", 0x5a, INSTR_RRE_RR },
+ { "clst", 0x5d, INSTR_RRE_RR },
+ { "srst", 0x5e, INSTR_RRE_RR },
+ { "cmpsc", 0x63, INSTR_RRE_RR },
+ { "cmpsc", 0x63, INSTR_RRE_RR },
+ { "siga", 0x74, INSTR_S_RD },
+ { "xsch", 0x76, INSTR_S_00 },
+ { "rp", 0x77, INSTR_S_RD },
+ { "stcke", 0x78, INSTR_S_RD },
+ { "sacf", 0x79, INSTR_S_RD },
+ { "stsi", 0x7d, INSTR_S_RD },
+ { "srnm", 0x99, INSTR_S_RD },
+ { "stfpc", 0x9c, INSTR_S_RD },
+ { "lfpc", 0x9d, INSTR_S_RD },
+ { "tre", 0xa5, INSTR_RRE_RR },
+ { "cuutf", 0xa6, INSTR_RRE_RR },
+ { "cutfu", 0xa7, INSTR_RRE_RR },
+ { "stfl", 0xb1, INSTR_S_RD },
+ { "trap4", 0xff, INSTR_S_RD },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_b3[] = {
+#ifdef CONFIG_64BIT
+ { "maylr", 0x38, INSTR_RRF_F0FF },
+ { "mylr", 0x39, INSTR_RRF_F0FF },
+ { "mayr", 0x3a, INSTR_RRF_F0FF },
+ { "myr", 0x3b, INSTR_RRF_F0FF },
+ { "mayhr", 0x3c, INSTR_RRF_F0FF },
+ { "myhr", 0x3d, INSTR_RRF_F0FF },
+ { "cegbr", 0xa4, INSTR_RRE_RR },
+ { "cdgbr", 0xa5, INSTR_RRE_RR },
+ { "cxgbr", 0xa6, INSTR_RRE_RR },
+ { "cgebr", 0xa8, INSTR_RRF_U0RF },
+ { "cgdbr", 0xa9, INSTR_RRF_U0RF },
+ { "cgxbr", 0xaa, INSTR_RRF_U0RF },
+ { "cfer", 0xb8, INSTR_RRF_U0RF },
+ { "cfdr", 0xb9, INSTR_RRF_U0RF },
+ { "cfxr", 0xba, INSTR_RRF_U0RF },
+ { "cegr", 0xc4, INSTR_RRE_RR },
+ { "cdgr", 0xc5, INSTR_RRE_RR },
+ { "cxgr", 0xc6, INSTR_RRE_RR },
+ { "cger", 0xc8, INSTR_RRF_U0RF },
+ { "cgdr", 0xc9, INSTR_RRF_U0RF },
+ { "cgxr", 0xca, INSTR_RRF_U0RF },
+#endif
+ { "lpebr", 0x00, INSTR_RRE_FF },
+ { "lnebr", 0x01, INSTR_RRE_FF },
+ { "ltebr", 0x02, INSTR_RRE_FF },
+ { "lcebr", 0x03, INSTR_RRE_FF },
+ { "ldebr", 0x04, INSTR_RRE_FF },
+ { "lxdbr", 0x05, INSTR_RRE_FF },
+ { "lxebr", 0x06, INSTR_RRE_FF },
+ { "mxdbr", 0x07, INSTR_RRE_FF },
+ { "kebr", 0x08, INSTR_RRE_FF },
+ { "cebr", 0x09, INSTR_RRE_FF },
+ { "aebr", 0x0a, INSTR_RRE_FF },
+ { "sebr", 0x0b, INSTR_RRE_FF },
+ { "mdebr", 0x0c, INSTR_RRE_FF },
+ { "debr", 0x0d, INSTR_RRE_FF },
+ { "maebr", 0x0e, INSTR_RRF_F0FF },
+ { "msebr", 0x0f, INSTR_RRF_F0FF },
+ { "lpdbr", 0x10, INSTR_RRE_FF },
+ { "lndbr", 0x11, INSTR_RRE_FF },
+ { "ltdbr", 0x12, INSTR_RRE_FF },
+ { "lcdbr", 0x13, INSTR_RRE_FF },
+ { "sqebr", 0x14, INSTR_RRE_FF },
+ { "sqdbr", 0x15, INSTR_RRE_FF },
+ { "sqxbr", 0x16, INSTR_RRE_FF },
+ { "meebr", 0x17, INSTR_RRE_FF },
+ { "kdbr", 0x18, INSTR_RRE_FF },
+ { "cdbr", 0x19, INSTR_RRE_FF },
+ { "adbr", 0x1a, INSTR_RRE_FF },
+ { "sdbr", 0x1b, INSTR_RRE_FF },
+ { "mdbr", 0x1c, INSTR_RRE_FF },
+ { "ddbr", 0x1d, INSTR_RRE_FF },
+ { "madbr", 0x1e, INSTR_RRF_F0FF },
+ { "msdbr", 0x1f, INSTR_RRF_F0FF },
+ { "lder", 0x24, INSTR_RRE_FF },
+ { "lxdr", 0x25, INSTR_RRE_FF },
+ { "lxer", 0x26, INSTR_RRE_FF },
+ { "maer", 0x2e, INSTR_RRF_F0FF },
+ { "mser", 0x2f, INSTR_RRF_F0FF },
+ { "sqxr", 0x36, INSTR_RRE_FF },
+ { "meer", 0x37, INSTR_RRE_FF },
+ { "madr", 0x3e, INSTR_RRF_F0FF },
+ { "msdr", 0x3f, INSTR_RRF_F0FF },
+ { "lpxbr", 0x40, INSTR_RRE_FF },
+ { "lnxbr", 0x41, INSTR_RRE_FF },
+ { "ltxbr", 0x42, INSTR_RRE_FF },
+ { "lcxbr", 0x43, INSTR_RRE_FF },
+ { "ledbr", 0x44, INSTR_RRE_FF },
+ { "ldxbr", 0x45, INSTR_RRE_FF },
+ { "lexbr", 0x46, INSTR_RRE_FF },
+ { "fixbr", 0x47, INSTR_RRF_U0FF },
+ { "kxbr", 0x48, INSTR_RRE_FF },
+ { "cxbr", 0x49, INSTR_RRE_FF },
+ { "axbr", 0x4a, INSTR_RRE_FF },
+ { "sxbr", 0x4b, INSTR_RRE_FF },
+ { "mxbr", 0x4c, INSTR_RRE_FF },
+ { "dxbr", 0x4d, INSTR_RRE_FF },
+ { "tbedr", 0x50, INSTR_RRF_U0FF },
+ { "tbdr", 0x51, INSTR_RRF_U0FF },
+ { "diebr", 0x53, INSTR_RRF_FUFF },
+ { "fiebr", 0x57, INSTR_RRF_U0FF },
+ { "thder", 0x58, INSTR_RRE_RR },
+ { "thdr", 0x59, INSTR_RRE_RR },
+ { "didbr", 0x5b, INSTR_RRF_FUFF },
+ { "fidbr", 0x5f, INSTR_RRF_U0FF },
+ { "lpxr", 0x60, INSTR_RRE_FF },
+ { "lnxr", 0x61, INSTR_RRE_FF },
+ { "ltxr", 0x62, INSTR_RRE_FF },
+ { "lcxr", 0x63, INSTR_RRE_FF },
+ { "lxr", 0x65, INSTR_RRE_RR },
+ { "lexr", 0x66, INSTR_RRE_FF },
+ { "fixr", 0x67, INSTR_RRF_U0FF },
+ { "cxr", 0x69, INSTR_RRE_FF },
+ { "lzer", 0x74, INSTR_RRE_R0 },
+ { "lzdr", 0x75, INSTR_RRE_R0 },
+ { "lzxr", 0x76, INSTR_RRE_R0 },
+ { "fier", 0x77, INSTR_RRF_U0FF },
+ { "fidr", 0x7f, INSTR_RRF_U0FF },
+ { "sfpc", 0x84, INSTR_RRE_RR_OPT },
+ { "efpc", 0x8c, INSTR_RRE_RR_OPT },
+ { "cefbr", 0x94, INSTR_RRE_RF },
+ { "cdfbr", 0x95, INSTR_RRE_RF },
+ { "cxfbr", 0x96, INSTR_RRE_RF },
+ { "cfebr", 0x98, INSTR_RRF_U0RF },
+ { "cfdbr", 0x99, INSTR_RRF_U0RF },
+ { "cfxbr", 0x9a, INSTR_RRF_U0RF },
+ { "cefr", 0xb4, INSTR_RRE_RF },
+ { "cdfr", 0xb5, INSTR_RRE_RF },
+ { "cxfr", 0xb6, INSTR_RRE_RF },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_b9[] = {
+#ifdef CONFIG_64BIT
+ { "lpgr", 0x00, INSTR_RRE_RR },
+ { "lngr", 0x01, INSTR_RRE_RR },
+ { "ltgr", 0x02, INSTR_RRE_RR },
+ { "lcgr", 0x03, INSTR_RRE_RR },
+ { "lgr", 0x04, INSTR_RRE_RR },
+ { "lurag", 0x05, INSTR_RRE_RR },
+ { "lgbr", 0x06, INSTR_RRE_RR },
+ { "lghr", 0x07, INSTR_RRE_RR },
+ { "agr", 0x08, INSTR_RRE_RR },
+ { "sgr", 0x09, INSTR_RRE_RR },
+ { "algr", 0x0a, INSTR_RRE_RR },
+ { "slgr", 0x0b, INSTR_RRE_RR },
+ { "msgr", 0x0c, INSTR_RRE_RR },
+ { "dsgr", 0x0d, INSTR_RRE_RR },
+ { "eregg", 0x0e, INSTR_RRE_RR },
+ { "lrvgr", 0x0f, INSTR_RRE_RR },
+ { "lpgfr", 0x10, INSTR_RRE_RR },
+ { "lngfr", 0x11, INSTR_RRE_RR },
+ { "ltgfr", 0x12, INSTR_RRE_RR },
+ { "lcgfr", 0x13, INSTR_RRE_RR },
+ { "lgfr", 0x14, INSTR_RRE_RR },
+ { "llgfr", 0x16, INSTR_RRE_RR },
+ { "llgtr", 0x17, INSTR_RRE_RR },
+ { "agfr", 0x18, INSTR_RRE_RR },
+ { "sgfr", 0x19, INSTR_RRE_RR },
+ { "algfr", 0x1a, INSTR_RRE_RR },
+ { "slgfr", 0x1b, INSTR_RRE_RR },
+ { "msgfr", 0x1c, INSTR_RRE_RR },
+ { "dsgfr", 0x1d, INSTR_RRE_RR },
+ { "cgr", 0x20, INSTR_RRE_RR },
+ { "clgr", 0x21, INSTR_RRE_RR },
+ { "sturg", 0x25, INSTR_RRE_RR },
+ { "lbr", 0x26, INSTR_RRE_RR },
+ { "lhr", 0x27, INSTR_RRE_RR },
+ { "cgfr", 0x30, INSTR_RRE_RR },
+ { "clgfr", 0x31, INSTR_RRE_RR },
+ { "bctgr", 0x46, INSTR_RRE_RR },
+ { "ngr", 0x80, INSTR_RRE_RR },
+ { "ogr", 0x81, INSTR_RRE_RR },
+ { "xgr", 0x82, INSTR_RRE_RR },
+ { "flogr", 0x83, INSTR_RRE_RR },
+ { "llgcr", 0x84, INSTR_RRE_RR },
+ { "llghr", 0x85, INSTR_RRE_RR },
+ { "mlgr", 0x86, INSTR_RRE_RR },
+ { "dlgr", 0x87, INSTR_RRE_RR },
+ { "alcgr", 0x88, INSTR_RRE_RR },
+ { "slbgr", 0x89, INSTR_RRE_RR },
+ { "cspg", 0x8a, INSTR_RRE_RR },
+ { "idte", 0x8e, INSTR_RRF_R0RR },
+ { "llcr", 0x94, INSTR_RRE_RR },
+ { "llhr", 0x95, INSTR_RRE_RR },
+ { "esea", 0x9d, INSTR_RRE_R0 },
+ { "lptea", 0xaa, INSTR_RRF_RURR },
+ { "cu14", 0xb0, INSTR_RRF_M0RR },
+ { "cu24", 0xb1, INSTR_RRF_M0RR },
+ { "cu41", 0xb2, INSTR_RRF_M0RR },
+ { "cu42", 0xb3, INSTR_RRF_M0RR },
+#endif
+ { "kmac", 0x1e, INSTR_RRE_RR },
+ { "lrvr", 0x1f, INSTR_RRE_RR },
+ { "km", 0x2e, INSTR_RRE_RR },
+ { "kmc", 0x2f, INSTR_RRE_RR },
+ { "kimd", 0x3e, INSTR_RRE_RR },
+ { "klmd", 0x3f, INSTR_RRE_RR },
+ { "epsw", 0x8d, INSTR_RRE_RR },
+ { "trtt", 0x90, INSTR_RRE_RR },
+ { "trtt", 0x90, INSTR_RRF_M0RR },
+ { "trto", 0x91, INSTR_RRE_RR },
+ { "trto", 0x91, INSTR_RRF_M0RR },
+ { "trot", 0x92, INSTR_RRE_RR },
+ { "trot", 0x92, INSTR_RRF_M0RR },
+ { "troo", 0x93, INSTR_RRE_RR },
+ { "troo", 0x93, INSTR_RRF_M0RR },
+ { "mlr", 0x96, INSTR_RRE_RR },
+ { "dlr", 0x97, INSTR_RRE_RR },
+ { "alcr", 0x98, INSTR_RRE_RR },
+ { "slbr", 0x99, INSTR_RRE_RR },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_c0[] = {
+#ifdef CONFIG_64BIT
+ { "lgfi", 0x01, INSTR_RIL_RI },
+ { "xihf", 0x06, INSTR_RIL_RU },
+ { "xilf", 0x07, INSTR_RIL_RU },
+ { "iihf", 0x08, INSTR_RIL_RU },
+ { "iilf", 0x09, INSTR_RIL_RU },
+ { "nihf", 0x0a, INSTR_RIL_RU },
+ { "nilf", 0x0b, INSTR_RIL_RU },
+ { "oihf", 0x0c, INSTR_RIL_RU },
+ { "oilf", 0x0d, INSTR_RIL_RU },
+ { "llihf", 0x0e, INSTR_RIL_RU },
+ { "llilf", 0x0f, INSTR_RIL_RU },
+#endif
+ { "larl", 0x00, INSTR_RIL_RP },
+ { "brcl", 0x04, INSTR_RIL_UP },
+ { "brasl", 0x05, INSTR_RIL_RP },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_c2[] = {
+#ifdef CONFIG_64BIT
+ { "slgfi", 0x04, INSTR_RIL_RU },
+ { "slfi", 0x05, INSTR_RIL_RU },
+ { "agfi", 0x08, INSTR_RIL_RI },
+ { "afi", 0x09, INSTR_RIL_RI },
+ { "algfi", 0x0a, INSTR_RIL_RU },
+ { "alfi", 0x0b, INSTR_RIL_RU },
+ { "cgfi", 0x0c, INSTR_RIL_RI },
+ { "cfi", 0x0d, INSTR_RIL_RI },
+ { "clgfi", 0x0e, INSTR_RIL_RU },
+ { "clfi", 0x0f, INSTR_RIL_RU },
+#endif
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_c8[] = {
+#ifdef CONFIG_64BIT
+ { "mvcos", 0x00, INSTR_SSF_RRDRD },
+#endif
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_e3[] = {
+#ifdef CONFIG_64BIT
+ { "ltg", 0x02, INSTR_RXY_RRRD },
+ { "lrag", 0x03, INSTR_RXY_RRRD },
+ { "lg", 0x04, INSTR_RXY_RRRD },
+ { "cvby", 0x06, INSTR_RXY_RRRD },
+ { "ag", 0x08, INSTR_RXY_RRRD },
+ { "sg", 0x09, INSTR_RXY_RRRD },
+ { "alg", 0x0a, INSTR_RXY_RRRD },
+ { "slg", 0x0b, INSTR_RXY_RRRD },
+ { "msg", 0x0c, INSTR_RXY_RRRD },
+ { "dsg", 0x0d, INSTR_RXY_RRRD },
+ { "cvbg", 0x0e, INSTR_RXY_RRRD },
+ { "lrvg", 0x0f, INSTR_RXY_RRRD },
+ { "lt", 0x12, INSTR_RXY_RRRD },
+ { "lray", 0x13, INSTR_RXY_RRRD },
+ { "lgf", 0x14, INSTR_RXY_RRRD },
+ { "lgh", 0x15, INSTR_RXY_RRRD },
+ { "llgf", 0x16, INSTR_RXY_RRRD },
+ { "llgt", 0x17, INSTR_RXY_RRRD },
+ { "agf", 0x18, INSTR_RXY_RRRD },
+ { "sgf", 0x19, INSTR_RXY_RRRD },
+ { "algf", 0x1a, INSTR_RXY_RRRD },
+ { "slgf", 0x1b, INSTR_RXY_RRRD },
+ { "msgf", 0x1c, INSTR_RXY_RRRD },
+ { "dsgf", 0x1d, INSTR_RXY_RRRD },
+ { "cg", 0x20, INSTR_RXY_RRRD },
+ { "clg", 0x21, INSTR_RXY_RRRD },
+ { "stg", 0x24, INSTR_RXY_RRRD },
+ { "cvdy", 0x26, INSTR_RXY_RRRD },
+ { "cvdg", 0x2e, INSTR_RXY_RRRD },
+ { "strvg", 0x2f, INSTR_RXY_RRRD },
+ { "cgf", 0x30, INSTR_RXY_RRRD },
+ { "clgf", 0x31, INSTR_RXY_RRRD },
+ { "strvh", 0x3f, INSTR_RXY_RRRD },
+ { "bctg", 0x46, INSTR_RXY_RRRD },
+ { "sty", 0x50, INSTR_RXY_RRRD },
+ { "msy", 0x51, INSTR_RXY_RRRD },
+ { "ny", 0x54, INSTR_RXY_RRRD },
+ { "cly", 0x55, INSTR_RXY_RRRD },
+ { "oy", 0x56, INSTR_RXY_RRRD },
+ { "xy", 0x57, INSTR_RXY_RRRD },
+ { "ly", 0x58, INSTR_RXY_RRRD },
+ { "cy", 0x59, INSTR_RXY_RRRD },
+ { "ay", 0x5a, INSTR_RXY_RRRD },
+ { "sy", 0x5b, INSTR_RXY_RRRD },
+ { "aly", 0x5e, INSTR_RXY_RRRD },
+ { "sly", 0x5f, INSTR_RXY_RRRD },
+ { "sthy", 0x70, INSTR_RXY_RRRD },
+ { "lay", 0x71, INSTR_RXY_RRRD },
+ { "stcy", 0x72, INSTR_RXY_RRRD },
+ { "icy", 0x73, INSTR_RXY_RRRD },
+ { "lb", 0x76, INSTR_RXY_RRRD },
+ { "lgb", 0x77, INSTR_RXY_RRRD },
+ { "lhy", 0x78, INSTR_RXY_RRRD },
+ { "chy", 0x79, INSTR_RXY_RRRD },
+ { "ahy", 0x7a, INSTR_RXY_RRRD },
+ { "shy", 0x7b, INSTR_RXY_RRRD },
+ { "ng", 0x80, INSTR_RXY_RRRD },
+ { "og", 0x81, INSTR_RXY_RRRD },
+ { "xg", 0x82, INSTR_RXY_RRRD },
+ { "mlg", 0x86, INSTR_RXY_RRRD },
+ { "dlg", 0x87, INSTR_RXY_RRRD },
+ { "alcg", 0x88, INSTR_RXY_RRRD },
+ { "slbg", 0x89, INSTR_RXY_RRRD },
+ { "stpq", 0x8e, INSTR_RXY_RRRD },
+ { "lpq", 0x8f, INSTR_RXY_RRRD },
+ { "llgc", 0x90, INSTR_RXY_RRRD },
+ { "llgh", 0x91, INSTR_RXY_RRRD },
+ { "llc", 0x94, INSTR_RXY_RRRD },
+ { "llh", 0x95, INSTR_RXY_RRRD },
+#endif
+ { "lrv", 0x1e, INSTR_RXY_RRRD },
+ { "lrvh", 0x1f, INSTR_RXY_RRRD },
+ { "strv", 0x3e, INSTR_RXY_RRRD },
+ { "ml", 0x96, INSTR_RXY_RRRD },
+ { "dl", 0x97, INSTR_RXY_RRRD },
+ { "alc", 0x98, INSTR_RXY_RRRD },
+ { "slb", 0x99, INSTR_RXY_RRRD },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_e5[] = {
+#ifdef CONFIG_64BIT
+ { "strag", 0x02, INSTR_SSE_RDRD },
+#endif
+ { "lasp", 0x00, INSTR_SSE_RDRD },
+ { "tprot", 0x01, INSTR_SSE_RDRD },
+ { "mvcsk", 0x0e, INSTR_SSE_RDRD },
+ { "mvcdk", 0x0f, INSTR_SSE_RDRD },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_eb[] = {
+#ifdef CONFIG_64BIT
+ { "lmg", 0x04, INSTR_RSY_RRRD },
+ { "srag", 0x0a, INSTR_RSY_RRRD },
+ { "slag", 0x0b, INSTR_RSY_RRRD },
+ { "srlg", 0x0c, INSTR_RSY_RRRD },
+ { "sllg", 0x0d, INSTR_RSY_RRRD },
+ { "tracg", 0x0f, INSTR_RSY_RRRD },
+ { "csy", 0x14, INSTR_RSY_RRRD },
+ { "rllg", 0x1c, INSTR_RSY_RRRD },
+ { "clmh", 0x20, INSTR_RSY_RURD },
+ { "clmy", 0x21, INSTR_RSY_RURD },
+ { "stmg", 0x24, INSTR_RSY_RRRD },
+ { "stctg", 0x25, INSTR_RSY_CCRD },
+ { "stmh", 0x26, INSTR_RSY_RRRD },
+ { "stcmh", 0x2c, INSTR_RSY_RURD },
+ { "stcmy", 0x2d, INSTR_RSY_RURD },
+ { "lctlg", 0x2f, INSTR_RSY_CCRD },
+ { "csg", 0x30, INSTR_RSY_RRRD },
+ { "cdsy", 0x31, INSTR_RSY_RRRD },
+ { "cdsg", 0x3e, INSTR_RSY_RRRD },
+ { "bxhg", 0x44, INSTR_RSY_RRRD },
+ { "bxleg", 0x45, INSTR_RSY_RRRD },
+ { "tmy", 0x51, INSTR_SIY_URD },
+ { "mviy", 0x52, INSTR_SIY_URD },
+ { "niy", 0x54, INSTR_SIY_URD },
+ { "cliy", 0x55, INSTR_SIY_URD },
+ { "oiy", 0x56, INSTR_SIY_URD },
+ { "xiy", 0x57, INSTR_SIY_URD },
+ { "icmh", 0x80, INSTR_RSE_RURD },
+ { "icmh", 0x80, INSTR_RSY_RURD },
+ { "icmy", 0x81, INSTR_RSY_RURD },
+ { "clclu", 0x8f, INSTR_RSY_RRRD },
+ { "stmy", 0x90, INSTR_RSY_RRRD },
+ { "lmh", 0x96, INSTR_RSY_RRRD },
+ { "lmy", 0x98, INSTR_RSY_RRRD },
+ { "lamy", 0x9a, INSTR_RSY_AARD },
+ { "stamy", 0x9b, INSTR_RSY_AARD },
+#endif
+ { "rll", 0x1d, INSTR_RSY_RRRD },
+ { "mvclu", 0x8e, INSTR_RSY_RRRD },
+ { "tp", 0xc0, INSTR_RSL_R0RD },
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_ec[] = {
+#ifdef CONFIG_64BIT
+ { "brxhg", 0x44, INSTR_RIE_RRP },
+ { "brxlg", 0x45, INSTR_RIE_RRP },
+#endif
+ { "", 0, INSTR_INVALID }
+};
+
+static struct insn opcode_ed[] = {
+#ifdef CONFIG_64BIT
+ { "mayl", 0x38, INSTR_RXF_FRRDF },
+ { "myl", 0x39, INSTR_RXF_FRRDF },
+ { "may", 0x3a, INSTR_RXF_FRRDF },
+ { "my", 0x3b, INSTR_RXF_FRRDF },
+ { "mayh", 0x3c, INSTR_RXF_FRRDF },
+ { "myh", 0x3d, INSTR_RXF_FRRDF },
+ { "ley", 0x64, INSTR_RXY_FRRD },
+ { "ldy", 0x65, INSTR_RXY_FRRD },
+ { "stey", 0x66, INSTR_RXY_FRRD },
+ { "stdy", 0x67, INSTR_RXY_FRRD },
+#endif
+ { "ldeb", 0x04, INSTR_RXE_FRRD },
+ { "lxdb", 0x05, INSTR_RXE_FRRD },
+ { "lxeb", 0x06, INSTR_RXE_FRRD },
+ { "mxdb", 0x07, INSTR_RXE_FRRD },
+ { "keb", 0x08, INSTR_RXE_FRRD },
+ { "ceb", 0x09, INSTR_RXE_FRRD },
+ { "aeb", 0x0a, INSTR_RXE_FRRD },
+ { "seb", 0x0b, INSTR_RXE_FRRD },
+ { "mdeb", 0x0c, INSTR_RXE_FRRD },
+ { "deb", 0x0d, INSTR_RXE_FRRD },
+ { "maeb", 0x0e, INSTR_RXF_FRRDF },
+ { "mseb", 0x0f, INSTR_RXF_FRRDF },
+ { "tceb", 0x10, INSTR_RXE_FRRD },
+ { "tcdb", 0x11, INSTR_RXE_FRRD },
+ { "tcxb", 0x12, INSTR_RXE_FRRD },
+ { "sqeb", 0x14, INSTR_RXE_FRRD },
+ { "sqdb", 0x15, INSTR_RXE_FRRD },
+ { "meeb", 0x17, INSTR_RXE_FRRD },
+ { "kdb", 0x18, INSTR_RXE_FRRD },
+ { "cdb", 0x19, INSTR_RXE_FRRD },
+ { "adb", 0x1a, INSTR_RXE_FRRD },
+ { "sdb", 0x1b, INSTR_RXE_FRRD },
+ { "mdb", 0x1c, INSTR_RXE_FRRD },
+ { "ddb", 0x1d, INSTR_RXE_FRRD },
+ { "madb", 0x1e, INSTR_RXF_FRRDF },
+ { "msdb", 0x1f, INSTR_RXF_FRRDF },
+ { "lde", 0x24, INSTR_RXE_FRRD },
+ { "lxd", 0x25, INSTR_RXE_FRRD },
+ { "lxe", 0x26, INSTR_RXE_FRRD },
+ { "mae", 0x2e, INSTR_RXF_FRRDF },
+ { "mse", 0x2f, INSTR_RXF_FRRDF },
+ { "sqe", 0x34, INSTR_RXE_FRRD },
+ { "mee", 0x37, INSTR_RXE_FRRD },
+ { "mad", 0x3e, INSTR_RXF_FRRDF },
+ { "msd", 0x3f, INSTR_RXF_FRRDF },
+ { "", 0, INSTR_INVALID }
+};
+
+/* Extracts an operand value from an instruction. */
+static unsigned int extract_operand(unsigned char *code,
+ const struct operand *operand)
+{
+ unsigned int val;
+ int bits;
+
+ /* Extract fragments of the operand byte for byte. */
+ code += operand->shift / 8;
+ bits = (operand->shift & 7) + operand->bits;
+ val = 0;
+ do {
+ val <<= 8;
+ val |= (unsigned int) *code++;
+ bits -= 8;
+ } while (bits > 0);
+ val >>= -bits;
+ val &= ((1U << (operand->bits - 1)) << 1) - 1;
+
+ /* Check for special long displacement case. */
+ if (operand->bits == 20 && operand->shift == 20)
+ val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
+
+ /* Sign extend value if the operand is signed or pc relative. */
+ if ((operand->flags & (OPERAND_SIGNED | OPERAND_PCREL)) &&
+ (val & (1U << (operand->bits - 1))))
+ val |= (-1U << (operand->bits - 1)) << 1;
+
+ /* Double value if the operand is pc relative. */
+ if (operand->flags & OPERAND_PCREL)
+ val <<= 1;
+
+ /* Length x in an instructions has real length x + 1. */
+ if (operand->flags & OPERAND_LENGTH)
+ val++;
+ return val;
+}
+
+static inline int insn_length(unsigned char code)
+{
+ return ((((int) code + 64) >> 7) + 1) << 1;
+}
+
+static struct insn *find_insn(unsigned char *code)
+{
+ unsigned char opfrag = code[1];
+ unsigned char opmask;
+ struct insn *table;
+
+ switch (code[0]) {
+ case 0x01:
+ table = opcode_01;
+ break;
+ case 0xa5:
+ table = opcode_a5;
+ break;
+ case 0xa7:
+ table = opcode_a7;
+ break;
+ case 0xb2:
+ table = opcode_b2;
+ break;
+ case 0xb3:
+ table = opcode_b3;
+ break;
+ case 0xb9:
+ table = opcode_b9;
+ break;
+ case 0xc0:
+ table = opcode_c0;
+ break;
+ case 0xc2:
+ table = opcode_c2;
+ break;
+ case 0xc8:
+ table = opcode_c8;
+ break;
+ case 0xe3:
+ table = opcode_e3;
+ opfrag = code[5];
+ break;
+ case 0xe5:
+ table = opcode_e5;
+ break;
+ case 0xeb:
+ table = opcode_eb;
+ opfrag = code[5];
+ break;
+ case 0xec:
+ table = opcode_ec;
+ opfrag = code[5];
+ break;
+ case 0xed:
+ table = opcode_ed;
+ opfrag = code[5];
+ break;
+ default:
+ table = opcode;
+ opfrag = code[0];
+ break;
+ }
+ while (table->format != INSTR_INVALID) {
+ opmask = formats[table->format][0];
+ if (table->opfrag == (opfrag & opmask))
+ return table;
+ table++;
+ }
+ return NULL;
+}
+
+static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
+{
+ struct insn *insn;
+ const unsigned char *ops;
+ const struct operand *operand;
+ unsigned int value;
+ char separator;
+ char *ptr;
+ int i;
+
+ ptr = buffer;
+ insn = find_insn(code);
+ if (insn) {
+ ptr += sprintf(ptr, "%.5s\t", insn->name);
+ /* Extract the operands. */
+ separator = 0;
+ for (ops = formats[insn->format] + 1, i = 0;
+ *ops != 0 && i < 6; ops++, i++) {
+ operand = operands + *ops;
+ value = extract_operand(code, operand);
+ if ((operand->flags & OPERAND_INDEX) && value == 0)
+ continue;
+ if ((operand->flags & OPERAND_BASE) &&
+ value == 0 && separator == '(') {
+ separator = ',';
+ continue;
+ }
+ if (separator)
+ ptr += sprintf(ptr, "%c", separator);
+ if (operand->flags & OPERAND_GPR)
+ ptr += sprintf(ptr, "%%r%i", value);
+ else if (operand->flags & OPERAND_FPR)
+ ptr += sprintf(ptr, "%%f%i", value);
+ else if (operand->flags & OPERAND_AR)
+ ptr += sprintf(ptr, "%%a%i", value);
+ else if (operand->flags & OPERAND_CR)
+ ptr += sprintf(ptr, "%%c%i", value);
+ else if (operand->flags & OPERAND_PCREL)
+ ptr += sprintf(ptr, "%lx", (signed int) value
+ + addr);
+ else if (operand->flags & OPERAND_SIGNED)
+ ptr += sprintf(ptr, "%i", value);
+ else
+ ptr += sprintf(ptr, "%u", value);
+ if (operand->flags & OPERAND_DISP)
+ separator = '(';
+ else if (operand->flags & OPERAND_BASE) {
+ ptr += sprintf(ptr, ")");
+ separator = ',';
+ } else
+ separator = ',';
+ }
+ } else
+ ptr += sprintf(ptr, "unknown");
+ return (int) (ptr - buffer);
+}
+
+void show_code(struct pt_regs *regs)
+{
+ char *mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
+ unsigned char code[64];
+ char buffer[64], *ptr;
+ mm_segment_t old_fs;
+ unsigned long addr;
+ int start, end, opsize, hops, i;
+
+ /* Get a snapshot of the 64 bytes surrounding the fault address. */
+ old_fs = get_fs();
+ set_fs((regs->psw.mask & PSW_MASK_PSTATE) ? USER_DS : KERNEL_DS);
+ for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) {
+ addr = regs->psw.addr - 34 + start;
+ if (__copy_from_user(code + start - 2,
+ (char __user *) addr, 2))
+ break;
+ }
+ for (end = 32; end < 64; end += 2) {
+ addr = regs->psw.addr + end - 32;
+ if (__copy_from_user(code + end,
+ (char __user *) addr, 2))
+ break;
+ }
+ set_fs(old_fs);
+ /* Code snapshot useable ? */
+ if ((regs->psw.addr & 1) || start >= end) {
+ printk("%s Code: Bad PSW.\n", mode);
+ return;
+ }
+ /* Find a starting point for the disassembly. */
+ while (start < 32) {
+ for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) {
+ if (!find_insn(code + start + i))
+ break;
+ i += insn_length(code[start + i]);
+ }
+ if (start + i == 32)
+ /* Looks good, sequence ends at PSW. */
+ break;
+ start += 2;
+ }
+ /* Decode the instructions. */
+ ptr = buffer;
+ ptr += sprintf(ptr, "%s Code:", mode);
+ hops = 0;
+ while (start < end && hops < 8) {
+ *ptr++ = (start == 32) ? '>' : ' ';
+ addr = regs->psw.addr + start - 32;
+ ptr += sprintf(ptr, ONELONG, addr);
+ opsize = insn_length(code[start]);
+ if (start + opsize >= end)
+ break;
+ for (i = 0; i < opsize; i++)
+ ptr += sprintf(ptr, "%02x", code[start + i]);
+ *ptr++ = '\t';
+ if (i < 6)
+ *ptr++ = '\t';
+ ptr += print_insn(ptr, code + start, addr);
+ start += opsize;
+ printk(buffer);
+ ptr = buffer;
+ ptr += sprintf(ptr, "\n ");
+ hops++;
+ }
+ printk("\n");
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/early.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/early.c
new file mode 100644
index 0000000000..01832c4406
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/early.c
@@ -0,0 +1,297 @@
+/*
+ * arch/s390/kernel/early.c
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Hongjie Yang <hongjie@us.ibm.com>,
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
+#include <linux/uaccess.h>
+#include <asm/ipl.h>
+#include <asm/lowcore.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/cpcmd.h>
+#include <asm/sclp.h>
+
+/*
+ * Create a Kernel NSS if the SAVESYS= parameter is defined
+ */
+#define DEFSYS_CMD_SIZE 96
+#define SAVESYS_CMD_SIZE 32
+
+char kernel_nss_name[NSS_NAME_SIZE + 1];
+
+#ifdef CONFIG_SHARED_KERNEL
+static noinline __init void create_kernel_nss(void)
+{
+ unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
+#ifdef CONFIG_BLK_DEV_INITRD
+ unsigned int sinitrd_pfn, einitrd_pfn;
+#endif
+ int response;
+ char *savesys_ptr;
+ char upper_command_line[COMMAND_LINE_SIZE];
+ char defsys_cmd[DEFSYS_CMD_SIZE];
+ char savesys_cmd[SAVESYS_CMD_SIZE];
+
+ /* Do nothing if we are not running under VM */
+ if (!MACHINE_IS_VM)
+ return;
+
+ /* Convert COMMAND_LINE to upper case */
+ for (i = 0; i < strlen(COMMAND_LINE); i++)
+ upper_command_line[i] = toupper(COMMAND_LINE[i]);
+
+ savesys_ptr = strstr(upper_command_line, "SAVESYS=");
+
+ if (!savesys_ptr)
+ return;
+
+ savesys_ptr += 8; /* Point to the beginning of the NSS name */
+ for (i = 0; i < NSS_NAME_SIZE; i++) {
+ if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
+ break;
+ kernel_nss_name[i] = savesys_ptr[i];
+ }
+
+ stext_pfn = PFN_DOWN(__pa(&_stext));
+ eshared_pfn = PFN_DOWN(__pa(&_eshared));
+ end_pfn = PFN_UP(__pa(&_end));
+ min_size = end_pfn << 2;
+
+ sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
+ kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
+ eshared_pfn, end_pfn);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (INITRD_START && INITRD_SIZE) {
+ sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
+ einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
+ min_size = einitrd_pfn << 2;
+ sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
+ sinitrd_pfn, einitrd_pfn);
+ }
+#endif
+
+ sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
+ sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
+ kernel_nss_name, kernel_nss_name);
+
+ __cpcmd(defsys_cmd, NULL, 0, &response);
+
+ if (response != 0) {
+ kernel_nss_name[0] = '\0';
+ return;
+ }
+
+ __cpcmd(savesys_cmd, NULL, 0, &response);
+
+ if (response != strlen(savesys_cmd)) {
+ kernel_nss_name[0] = '\0';
+ return;
+ }
+
+ ipl_flags = IPL_NSS_VALID;
+}
+
+#else /* CONFIG_SHARED_KERNEL */
+
+static inline void create_kernel_nss(void) { }
+
+#endif /* CONFIG_SHARED_KERNEL */
+
+/*
+ * Clear bss memory
+ */
+static noinline __init void clear_bss_section(void)
+{
+ memset(__bss_start, 0, __bss_stop - __bss_start);
+}
+
+/*
+ * Initialize storage key for kernel pages
+ */
+static noinline __init void init_kernel_storage_key(void)
+{
+ unsigned long end_pfn, init_pfn;
+
+ end_pfn = PFN_UP(__pa(&_end));
+
+ for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
+ page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+}
+
+static noinline __init void detect_machine_type(void)
+{
+ struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
+
+ get_cpu_id(&S390_lowcore.cpu_data.cpu_id);
+
+ /* Running under z/VM ? */
+ if (cpuinfo->cpu_id.version == 0xff)
+ machine_flags |= 1;
+
+ /* Running on a P/390 ? */
+ if (cpuinfo->cpu_id.machine == 0x7490)
+ machine_flags |= 4;
+}
+
+#ifdef CONFIG_64BIT
+static noinline __init int memory_fast_detect(void)
+{
+ unsigned long val0 = 0;
+ unsigned long val1 = 0xc;
+ int ret = -ENOSYS;
+
+ if (ipl_flags & IPL_NSS_VALID)
+ return -ENOSYS;
+
+ asm volatile(
+ " diag %1,%2,0x260\n"
+ "0: lhi %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
+
+ if (ret || val0 != val1)
+ return -ENOSYS;
+
+ memory_chunk[0].size = val0 + 1;
+ return 0;
+}
+#else
+static inline int memory_fast_detect(void)
+{
+ return -ENOSYS;
+}
+#endif
+
+static inline __init unsigned long __tprot(unsigned long addr)
+{
+ int cc = -1;
+
+ asm volatile(
+ " tprot 0(%1),0\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (cc) : "a" (addr) : "cc");
+ return (unsigned long)cc;
+}
+
+/* Checking memory in 128KB increments. */
+#define CHUNK_INCR (1UL << 17)
+#define ADDR2G (1UL << 31)
+
+static noinline __init void find_memory_chunks(unsigned long memsize)
+{
+ unsigned long addr = 0, old_addr = 0;
+ unsigned long old_cc = CHUNK_READ_WRITE;
+ unsigned long cc;
+ int chunk = 0;
+
+ while (chunk < MEMORY_CHUNKS) {
+ cc = __tprot(addr);
+ while (cc == old_cc) {
+ addr += CHUNK_INCR;
+ if (memsize && addr >= memsize)
+ break;
+#ifndef CONFIG_64BIT
+ if (addr == ADDR2G)
+ break;
+#endif
+ cc = __tprot(addr);
+ }
+
+ if (old_addr != addr &&
+ (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
+ memory_chunk[chunk].addr = old_addr;
+ memory_chunk[chunk].size = addr - old_addr;
+ memory_chunk[chunk].type = old_cc;
+ chunk++;
+ }
+
+ old_addr = addr;
+ old_cc = cc;
+
+#ifndef CONFIG_64BIT
+ if (addr == ADDR2G)
+ break;
+#endif
+ /*
+ * Finish memory detection at the first hole
+ * if storage size is unknown.
+ */
+ if (cc == -1UL && !memsize)
+ break;
+ if (memsize && addr >= memsize)
+ break;
+ }
+}
+
+static __init void early_pgm_check_handler(void)
+{
+ unsigned long addr;
+ const struct exception_table_entry *fixup;
+
+ addr = S390_lowcore.program_old_psw.addr;
+ fixup = search_exception_tables(addr & PSW_ADDR_INSN);
+ if (!fixup)
+ disabled_wait(0);
+ S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+}
+
+static noinline __init void setup_lowcore_early(void)
+{
+ psw_t psw;
+
+ psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+ psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
+ S390_lowcore.external_new_psw = psw;
+ psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
+ S390_lowcore.program_new_psw = psw;
+ s390_base_pgm_handler_fn = early_pgm_check_handler;
+}
+
+/*
+ * Save ipl parameters, clear bss memory, initialize storage keys
+ * and create a kernel NSS at startup if the SAVESYS= parm is defined
+ */
+void __init startup_init(void)
+{
+ unsigned long long memsize;
+
+ ipl_save_parameters();
+ clear_bss_section();
+ init_kernel_storage_key();
+ lockdep_init();
+ lockdep_off();
+ detect_machine_type();
+ create_kernel_nss();
+ sort_main_extable();
+ setup_lowcore_early();
+ sclp_read_info_early();
+ sclp_facilities_detect();
+ memsize = sclp_memory_detect();
+#ifndef CONFIG_64BIT
+ /*
+ * Can't deal with more than 2G in 31 bit addressing mode, so
+ * limit the value in order to avoid strange side effects.
+ */
+ if (memsize > ADDR2G)
+ memsize = ADDR2G;
+#endif
+ if (memory_fast_detect() < 0)
+ find_memory_chunks((unsigned long) memsize);
+ lockdep_on();
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ebcdic.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ebcdic.c
new file mode 100644
index 0000000000..cc0dc609d7
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ebcdic.c
@@ -0,0 +1,401 @@
+/*
+ * arch/s390/kernel/ebcdic.c
+ * ECBDIC -> ASCII, ASCII -> ECBDIC,
+ * upper to lower case (EBCDIC) conversion tables.
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Martin Peschke <peschke@fh-brandenburg.de>
+ */
+
+#include <linux/module.h>
+#include <asm/types.h>
+#include <asm/ebcdic.h>
+
+/*
+ * ASCII (IBM PC 437) -> EBCDIC 037
+ */
+__u8 _ascebc[256] =
+{
+ /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ /* ->NL */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN EM SUB ESC FS GS RS US */
+ /* ->IGS ->IRS ->IUS */
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ /*80*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0 sz */
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+/*
+ * EBCDIC 037 -> ASCII (IBM PC 437)
+ */
+__u8 _ebcasc[256] =
+{
+ /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08 -GE -SPS -RPT VT FF CR SO SI */
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
+ -ENP ->LF */
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
+ -IUS */
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
+ -INP */
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
+ -SW */
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40 SP RSP ä ---- */
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48 . < ( + | */
+ 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+ /* 0x50 & ---- */
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58 ß ! $ * ) ; */
+ 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+ /* 0x60 - / ---- Ä ---- ---- ---- */
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68 ---- , % _ > ? */
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70 ---- ---- ---- ---- ---- ---- ---- */
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78 * ` : # @ ' = " */
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80 * a b c d e f g */
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88 h i ---- ---- ---- */
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90 ° j k l m n o p */
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98 q r ---- ---- */
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0 ~ s t u v w x */
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8 y z ---- ---- ---- ---- */
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0 ^ ---- § ---- */
+ 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8 ---- [ ] ---- ---- ---- ---- */
+ 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0 { A B C D E F G */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8 H I ---- ö ---- */
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0 } J K L M N O P */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8 Q R ---- ü */
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0 \ S T U V W X */
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8 Y Z ---- Ö ---- ---- ---- */
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0 0 1 2 3 4 5 6 7 */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+
+/*
+ * ASCII (IBM PC 437) -> EBCDIC 500
+ */
+__u8 _ascebc_500[256] =
+{
+ /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ /* ->NL */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN EM SUB ESC FS GS RS US */
+ /* ->IGS ->IRS ->IUS */
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x4F, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0x4A, 0xE0, 0x5A, 0x5F, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0xBB, 0xD0, 0xA1, 0x07,
+ /*80*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0 sz */
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+/*
+ * EBCDIC 500 -> ASCII (IBM PC 437)
+ */
+__u8 _ebcasc_500[256] =
+{
+ /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08 -GE -SPS -RPT VT FF CR SO SI */
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
+ -ENP ->LF */
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
+ -IUS */
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
+ -INP */
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
+ -SW */
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40 SP RSP ä ---- */
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48 [ . < ( + ! */
+ 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
+ /* 0x50 & ---- */
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58 ß ] $ * ) ; ^ */
+ 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
+ /* 0x60 - / ---- Ä ---- ---- ---- */
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68 ---- , % _ > ? */
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70 ---- ---- ---- ---- ---- ---- ---- */
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78 * ` : # @ ' = " */
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80 * a b c d e f g */
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88 h i ---- ---- ---- */
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90 ° j k l m n o p */
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98 q r ---- ---- */
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0 ~ s t u v w x */
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8 y z ---- ---- ---- ---- */
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0 ---- § ---- */
+ 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8 ---- | ---- ---- ---- ---- */
+ 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0 { A B C D E F G */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8 H I ---- ö ---- */
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0 } J K L M N O P */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8 Q R ---- ü */
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0 \ S T U V W X */
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8 Y Z ---- Ö ---- ---- ---- */
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0 0 1 2 3 4 5 6 7 */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+
+/*
+ * EBCDIC 037/500 conversion table:
+ * from upper to lower case
+ */
+__u8 _ebc_tolower[256] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x61, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9C, 0x9F,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB, 0x8C, 0x8D, 0x8E, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xEA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF
+};
+
+
+/*
+ * EBCDIC 037/500 conversion table:
+ * from lower to upper case
+ */
+__u8 _ebc_toupper[256] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x80, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0x8A, 0x8B, 0xAC, 0xAD, 0xAE, 0x8F,
+ 0x90, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0x9A, 0x9B, 0x9E, 0x9D, 0x9E, 0x9F,
+ 0xA0, 0xA1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
+
+EXPORT_SYMBOL(_ascebc_500);
+EXPORT_SYMBOL(_ebcasc_500);
+EXPORT_SYMBOL(_ascebc);
+EXPORT_SYMBOL(_ebcasc);
+EXPORT_SYMBOL(_ebc_tolower);
+EXPORT_SYMBOL(_ebc_toupper);
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/entry.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/entry.S
new file mode 100644
index 0000000000..6766e37fe8
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/entry.S
@@ -0,0 +1,1104 @@
+/*
+ * arch/s390/kernel/entry.S
+ * S390 low-level entry points.
+ *
+ * Copyright (C) IBM Corp. 1999,2006
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Hartmut Penner (hp@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/cache.h>
+#include <asm/lowcore.h>
+#include <asm/errno.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+
+/*
+ * Stack layout for the system_call stack entry.
+ * The first few entries are identical to the user_regs_struct.
+ */
+SP_PTREGS = STACK_FRAME_OVERHEAD
+SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
+SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
+SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
+SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4
+SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
+SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 12
+SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
+SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 20
+SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
+SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 28
+SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
+SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 36
+SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
+SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 44
+SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
+SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52
+SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
+SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60
+SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
+SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
+SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
+SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
+
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
+ _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
+ _TIF_MCCK_PENDING)
+
+STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
+STACK_SIZE = 1 << STACK_SHIFT
+
+#define BASED(name) name-system_call(%r13)
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+ .macro TRACE_IRQS_ON
+ l %r1,BASED(.Ltrace_irq_on)
+ basr %r14,%r1
+ .endm
+
+ .macro TRACE_IRQS_OFF
+ l %r1,BASED(.Ltrace_irq_off)
+ basr %r14,%r1
+ .endm
+
+ .macro TRACE_IRQS_CHECK
+ tm SP_PSW(%r15),0x03 # irqs enabled?
+ jz 0f
+ l %r1,BASED(.Ltrace_irq_on)
+ basr %r14,%r1
+ j 1f
+0: l %r1,BASED(.Ltrace_irq_off)
+ basr %r14,%r1
+1:
+ .endm
+#else
+#define TRACE_IRQS_ON
+#define TRACE_IRQS_OFF
+#define TRACE_IRQS_CHECK
+#endif
+
+#ifdef CONFIG_LOCKDEP
+ .macro LOCKDEP_SYS_EXIT
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jz 0f
+ l %r1,BASED(.Llockdep_sys_exit)
+ basr %r14,%r1
+0:
+ .endm
+#else
+#define LOCKDEP_SYS_EXIT
+#endif
+
+/*
+ * Register usage in interrupt handlers:
+ * R9 - pointer to current task structure
+ * R13 - pointer to literal pool
+ * R14 - return register for function calls
+ * R15 - kernel stack pointer
+ */
+
+ .macro STORE_TIMER lc_offset
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ stpt \lc_offset
+#endif
+ .endm
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .macro UPDATE_VTIME lc_from,lc_to,lc_sum
+ lm %r10,%r11,\lc_from
+ sl %r10,\lc_to
+ sl %r11,\lc_to+4
+ bc 3,BASED(0f)
+ sl %r10,BASED(.Lc_1)
+0: al %r10,\lc_sum
+ al %r11,\lc_sum+4
+ bc 12,BASED(1f)
+ al %r10,BASED(.Lc_1)
+1: stm %r10,%r11,\lc_sum
+ .endm
+#endif
+
+ .macro SAVE_ALL_BASE savearea
+ stm %r12,%r15,\savearea
+ l %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13
+ .endm
+
+ .macro SAVE_ALL_SVC psworg,savearea
+ la %r12,\psworg
+ l %r15,__LC_KERNEL_STACK # problem state -> load ksp
+ .endm
+
+ .macro SAVE_ALL_SYNC psworg,savearea
+ la %r12,\psworg
+ tm \psworg+1,0x01 # test problem state bit
+ bz BASED(2f) # skip stack setup save
+ l %r15,__LC_KERNEL_STACK # problem state -> load ksp
+#ifdef CONFIG_CHECK_STACK
+ b BASED(3f)
+2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD
+ bz BASED(stack_overflow)
+3:
+#endif
+2:
+ .endm
+
+ .macro SAVE_ALL_ASYNC psworg,savearea
+ la %r12,\psworg
+ tm \psworg+1,0x01 # test problem state bit
+ bnz BASED(1f) # from user -> load async stack
+ clc \psworg+4(4),BASED(.Lcritical_end)
+ bhe BASED(0f)
+ clc \psworg+4(4),BASED(.Lcritical_start)
+ bl BASED(0f)
+ l %r14,BASED(.Lcleanup_critical)
+ basr %r14,%r14
+ tm 1(%r12),0x01 # retest problem state after cleanup
+ bnz BASED(1f)
+0: l %r14,__LC_ASYNC_STACK # are we already on the async stack ?
+ slr %r14,%r15
+ sra %r14,STACK_SHIFT
+ be BASED(2f)
+1: l %r15,__LC_ASYNC_STACK
+#ifdef CONFIG_CHECK_STACK
+ b BASED(3f)
+2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD
+ bz BASED(stack_overflow)
+3:
+#endif
+2:
+ .endm
+
+ .macro CREATE_STACK_FRAME psworg,savearea
+ s %r15,BASED(.Lc_spsize) # make room for registers & psw
+ mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack
+ la %r12,\psworg
+ st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
+ icm %r12,12,__LC_SVC_ILC
+ stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
+ st %r12,SP_ILC(%r15)
+ mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack
+ la %r12,0
+ st %r12,__SF_BACKCHAIN(%r15) # clear back chain
+ .endm
+
+ .macro RESTORE_ALL psworg,sync
+ mvc \psworg(8),SP_PSW(%r15) # move user PSW to lowcore
+ .if !\sync
+ ni \psworg+1,0xfd # clear wait state bit
+ .endif
+ lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user
+ STORE_TIMER __LC_EXIT_TIMER
+ lpsw \psworg # back to caller
+ .endm
+
+/*
+ * Scheduler resume function, called by switch_to
+ * gpr2 = (task_struct *) prev
+ * gpr3 = (task_struct *) next
+ * Returns:
+ * gpr2 = prev
+ */
+ .globl __switch_to
+__switch_to:
+ basr %r1,0
+__switch_to_base:
+ tm __THREAD_per(%r3),0xe8 # new process is using per ?
+ bz __switch_to_noper-__switch_to_base(%r1) # if not we're fine
+ stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff
+ clc __THREAD_per(12,%r3),__SF_EMPTY(%r15)
+ be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's
+ lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't
+__switch_to_noper:
+ l %r4,__THREAD_info(%r2) # get thread_info of prev
+ tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
+ bz __switch_to_no_mcck-__switch_to_base(%r1)
+ ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
+ l %r4,__THREAD_info(%r3) # get thread_info of next
+ oi __TI_flags+3(%r4),_TIF_MCCK_PENDING # set it in next
+__switch_to_no_mcck:
+ stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
+ st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
+ l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
+ lm %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
+ st %r3,__LC_CURRENT # __LC_CURRENT = current task struct
+ lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
+ l %r3,__THREAD_info(%r3) # load thread_info from task struct
+ st %r3,__LC_THREAD_INFO
+ ahi %r3,STACK_SIZE
+ st %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
+ br %r14
+
+__critical_start:
+/*
+ * SVC interrupt handler routine. System calls are synchronous events and
+ * are executed with interrupts enabled.
+ */
+
+ .globl system_call
+system_call:
+ STORE_TIMER __LC_SYNC_ENTER_TIMER
+sysc_saveall:
+ SAVE_ALL_BASE __LC_SAVE_AREA
+ SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ lh %r7,0x8a # get svc number from lowcore
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+sysc_vtime:
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+sysc_stime:
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+sysc_update:
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+#endif
+sysc_do_svc:
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ sla %r7,2 # *4 and test for svc 0
+ bnz BASED(sysc_nr_ok) # svc number > 0
+ # svc 0: system call number in %r1
+ cl %r1,BASED(.Lnr_syscalls)
+ bnl BASED(sysc_nr_ok)
+ lr %r7,%r1 # copy svc number to %r7
+ sla %r7,2 # *4
+sysc_nr_ok:
+ mvc SP_ARGS(4,%r15),SP_R7(%r15)
+sysc_do_restart:
+ l %r8,BASED(.Lsysc_table)
+ tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+ l %r8,0(%r7,%r8) # get system call addr.
+ bnz BASED(sysc_tracesys)
+ basr %r14,%r8 # call sys_xxxx
+ st %r2,SP_R2(%r15) # store return value (change R2 on stack)
+
+sysc_return:
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ bno BASED(sysc_restore)
+ tm __TI_flags+3(%r9),_TIF_WORK_SVC
+ bnz BASED(sysc_work) # there is work to do (signals etc.)
+sysc_restore:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ la %r1,BASED(sysc_restore_trace_psw)
+ lpsw 0(%r1)
+sysc_restore_trace:
+ TRACE_IRQS_CHECK
+ LOCKDEP_SYS_EXIT
+#endif
+sysc_leave:
+ RESTORE_ALL __LC_RETURN_PSW,1
+sysc_done:
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+ .align 8
+ .globl sysc_restore_trace_psw
+sysc_restore_trace_psw:
+ .long 0, sysc_restore_trace + 0x80000000
+#endif
+
+#
+# recheck if there is more work to do
+#
+sysc_work_loop:
+ tm __TI_flags+3(%r9),_TIF_WORK_SVC
+ bz BASED(sysc_restore) # there is no work to do
+#
+# One of the work bits is on. Find out which one.
+#
+sysc_work:
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+ bo BASED(sysc_mcck_pending)
+ tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
+ bo BASED(sysc_reschedule)
+ tm __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
+ bnz BASED(sysc_sigpending)
+ tm __TI_flags+3(%r9),_TIF_RESTART_SVC
+ bo BASED(sysc_restart)
+ tm __TI_flags+3(%r9),_TIF_SINGLE_STEP
+ bo BASED(sysc_singlestep)
+ b BASED(sysc_restore)
+sysc_work_done:
+
+#
+# _TIF_NEED_RESCHED is set, call schedule
+#
+sysc_reschedule:
+ l %r1,BASED(.Lschedule)
+ la %r14,BASED(sysc_work_loop)
+ br %r1 # call scheduler
+
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+sysc_mcck_pending:
+ l %r1,BASED(.Ls390_handle_mcck)
+ la %r14,BASED(sysc_work_loop)
+ br %r1 # TIF bit will be cleared by handler
+
+#
+# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+#
+sysc_sigpending:
+ ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Ldo_signal)
+ basr %r14,%r1 # call do_signal
+ tm __TI_flags+3(%r9),_TIF_RESTART_SVC
+ bo BASED(sysc_restart)
+ tm __TI_flags+3(%r9),_TIF_SINGLE_STEP
+ bo BASED(sysc_singlestep)
+ b BASED(sysc_work_loop)
+
+#
+# _TIF_RESTART_SVC is set, set up registers and restart svc
+#
+sysc_restart:
+ ni __TI_flags+3(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
+ l %r7,SP_R2(%r15) # load new svc number
+ sla %r7,2
+ mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
+ lm %r2,%r6,SP_R2(%r15) # load svc arguments
+ b BASED(sysc_do_restart) # restart svc
+
+#
+# _TIF_SINGLE_STEP is set, call do_single_step
+#
+sysc_singlestep:
+ ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
+ mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ l %r1,BASED(.Lhandle_per) # load adr. of per handler
+ la %r14,BASED(sysc_return) # load adr. of system return
+ br %r1 # branch to do_single_step
+
+#
+# call trace before and after sys_call
+#
+sysc_tracesys:
+ l %r1,BASED(.Ltrace)
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r3,0
+ srl %r7,2
+ st %r7,SP_R2(%r15)
+ basr %r14,%r1
+ clc SP_R2(4,%r15),BASED(.Lnr_syscalls)
+ bnl BASED(sysc_tracenogo)
+ l %r8,BASED(.Lsysc_table)
+ l %r7,SP_R2(%r15) # strace might have changed the
+ sll %r7,2 # system call
+ l %r8,0(%r7,%r8)
+sysc_tracego:
+ lm %r3,%r6,SP_R3(%r15)
+ l %r2,SP_ORIG_R2(%r15)
+ basr %r14,%r8 # call sys_xxx
+ st %r2,SP_R2(%r15) # store return value
+sysc_tracenogo:
+ tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+ bz BASED(sysc_return)
+ l %r1,BASED(.Ltrace)
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r3,1
+ la %r14,BASED(sysc_return)
+ br %r1
+
+#
+# a new process exits the kernel with ret_from_fork
+#
+ .globl ret_from_fork
+ret_from_fork:
+ l %r13,__LC_SVC_NEW_PSW+4
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ tm SP_PSW+1(%r15),0x01 # forking a kernel thread ?
+ bo BASED(0f)
+ st %r15,SP_R15(%r15) # store stack pointer for new kthread
+0: l %r1,BASED(.Lschedtail)
+ basr %r14,%r1
+ TRACE_IRQS_ON
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ b BASED(sysc_return)
+
+#
+# kernel_execve function needs to deal with pt_regs that is not
+# at the usual place
+#
+ .globl kernel_execve
+kernel_execve:
+ stm %r12,%r15,48(%r15)
+ lr %r14,%r15
+ l %r13,__LC_SVC_NEW_PSW+4
+ s %r15,BASED(.Lc_spsize)
+ st %r14,__SF_BACKCHAIN(%r15)
+ la %r12,SP_PTREGS(%r15)
+ xc 0(__PT_SIZE,%r12),0(%r12)
+ l %r1,BASED(.Ldo_execve)
+ lr %r5,%r12
+ basr %r14,%r1
+ ltr %r2,%r2
+ be BASED(0f)
+ a %r15,BASED(.Lc_spsize)
+ lm %r12,%r15,48(%r15)
+ br %r14
+ # execve succeeded.
+0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts
+ l %r15,__LC_KERNEL_STACK # load ksp
+ s %r15,BASED(.Lc_spsize) # make room for registers & psw
+ l %r9,__LC_THREAD_INFO
+ mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs
+ xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ l %r1,BASED(.Lexecve_tail)
+ basr %r14,%r1
+ b BASED(sysc_return)
+
+/*
+ * Program check handler routine
+ */
+
+ .globl pgm_check_handler
+pgm_check_handler:
+/*
+ * First we need to check for a special case:
+ * Single stepping an instruction that disables the PER event mask will
+ * cause a PER event AFTER the mask has been set. Example: SVC or LPSW.
+ * For a single stepped SVC the program check handler gets control after
+ * the SVC new PSW has been loaded. But we want to execute the SVC first and
+ * then handle the PER event. Therefore we update the SVC old PSW to point
+ * to the pgm_check_handler and branch to the SVC handler after we checked
+ * if we have to load the kernel stack register.
+ * For every other possible cause for PER event without the PER mask set
+ * we just ignore the PER event (FIXME: is there anything we have to do
+ * for LPSW?).
+ */
+ STORE_TIMER __LC_SYNC_ENTER_TIMER
+ SAVE_ALL_BASE __LC_SAVE_AREA
+ tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
+ bnz BASED(pgm_per) # got per exception -> special case
+ SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ bz BASED(pgm_no_vtime)
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+pgm_no_vtime:
+#endif
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+ l %r3,__LC_PGM_ILC # load program interruption code
+ la %r8,0x7f
+ nr %r8,%r3
+pgm_do_call:
+ l %r7,BASED(.Ljump_table)
+ sll %r8,2
+ l %r7,0(%r8,%r7) # load address of handler routine
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ la %r14,BASED(sysc_return)
+ br %r7 # branch to interrupt-handler
+
+#
+# handle per exception
+#
+pgm_per:
+ tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
+ bnz BASED(pgm_per_std) # ok, normal per event from user space
+# ok its one of the special cases, now we need to find out which one
+ clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
+ be BASED(pgm_svcper)
+# no interesting special case, ignore PER event
+ lm %r12,%r15,__LC_SAVE_AREA
+ lpsw 0x28
+
+#
+# Normal per exception
+#
+pgm_per_std:
+ SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ bz BASED(pgm_no_vtime2)
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+pgm_no_vtime2:
+#endif
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+ l %r1,__TI_task(%r9)
+ mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
+ mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
+ mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
+ oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
+ tm SP_PSW+1(%r15),0x01 # kernel per event ?
+ bz BASED(kernel_per)
+ l %r3,__LC_PGM_ILC # load program interruption code
+ la %r8,0x7f
+ nr %r8,%r3 # clear per-event-bit and ilc
+ be BASED(sysc_return) # only per or per+check ?
+ b BASED(pgm_do_call)
+
+#
+# it was a single stepped SVC that is causing all the trouble
+#
+pgm_svcper:
+ SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+#endif
+ lh %r7,0x8a # get svc number from lowcore
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+ l %r1,__TI_task(%r9)
+ mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
+ mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
+ mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
+ oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
+ TRACE_IRQS_ON
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ b BASED(sysc_do_svc)
+
+#
+# per was called from kernel, must be kprobes
+#
+kernel_per:
+ mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ l %r1,BASED(.Lhandle_per) # load adr. of per handler
+ la %r14,BASED(sysc_restore)# load adr. of system return
+ br %r1 # branch to do_single_step
+
+/*
+ * IO interrupt handler routine
+ */
+
+ .globl io_int_handler
+io_int_handler:
+ STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ stck __LC_INT_CLOCK
+ SAVE_ALL_BASE __LC_SAVE_AREA+16
+ SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
+ CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ bz BASED(io_no_vtime)
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+io_no_vtime:
+#endif
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+ l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ basr %r14,%r1 # branch to standard irq handler
+io_return:
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+#ifdef CONFIG_PREEMPT
+ bno BASED(io_preempt) # no -> check for preemptive scheduling
+#else
+ bno BASED(io_restore) # no-> skip resched & signal
+#endif
+ tm __TI_flags+3(%r9),_TIF_WORK_INT
+ bnz BASED(io_work) # there is work to do (signals etc.)
+io_restore:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ la %r1,BASED(io_restore_trace_psw)
+ lpsw 0(%r1)
+io_restore_trace:
+ TRACE_IRQS_CHECK
+ LOCKDEP_SYS_EXIT
+#endif
+io_leave:
+ RESTORE_ALL __LC_RETURN_PSW,0
+io_done:
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+ .align 8
+ .globl io_restore_trace_psw
+io_restore_trace_psw:
+ .long 0, io_restore_trace + 0x80000000
+#endif
+
+#ifdef CONFIG_PREEMPT
+io_preempt:
+ icm %r0,15,__TI_precount(%r9)
+ bnz BASED(io_restore)
+ l %r1,SP_R15(%r15)
+ s %r1,BASED(.Lc_spsize)
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lr %r15,%r1
+io_resume_loop:
+ tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
+ bno BASED(io_restore)
+ l %r1,BASED(.Lpreempt_schedule_irq)
+ la %r14,BASED(io_resume_loop)
+ br %r1 # call schedule
+#endif
+
+#
+# switch to kernel stack, then check the TIF bits
+#
+io_work:
+ l %r1,__LC_KERNEL_STACK
+ s %r1,BASED(.Lc_spsize)
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lr %r15,%r1
+#
+# One of the work bits is on. Find out which one.
+# Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGMASK, _TIF_NEED_RESCHED
+# and _TIF_MCCK_PENDING
+#
+io_work_loop:
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+ bo BASED(io_mcck_pending)
+ tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
+ bo BASED(io_reschedule)
+ tm __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
+ bnz BASED(io_sigpending)
+ b BASED(io_restore)
+io_work_done:
+
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+io_mcck_pending:
+ l %r1,BASED(.Ls390_handle_mcck)
+ basr %r14,%r1 # TIF bit will be cleared by handler
+ b BASED(io_work_loop)
+
+#
+# _TIF_NEED_RESCHED is set, call schedule
+#
+io_reschedule:
+ TRACE_IRQS_ON
+ l %r1,BASED(.Lschedule)
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ basr %r14,%r1 # call scheduler
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ TRACE_IRQS_OFF
+ tm __TI_flags+3(%r9),_TIF_WORK_INT
+ bz BASED(io_restore) # there is no work to do
+ b BASED(io_work_loop)
+
+#
+# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+#
+io_sigpending:
+ TRACE_IRQS_ON
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Ldo_signal)
+ basr %r14,%r1 # call do_signal
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ TRACE_IRQS_OFF
+ b BASED(io_work_loop)
+
+/*
+ * External interrupt handler routine
+ */
+
+ .globl ext_int_handler
+ext_int_handler:
+ STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ stck __LC_INT_CLOCK
+ SAVE_ALL_BASE __LC_SAVE_AREA+16
+ SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
+ CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ bz BASED(ext_no_vtime)
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ext_no_vtime:
+#endif
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ lh %r3,__LC_EXT_INT_CODE # get interruption code
+ l %r1,BASED(.Ldo_extint)
+ basr %r14,%r1
+ b BASED(io_return)
+
+__critical_end:
+
+/*
+ * Machine check handler routines
+ */
+
+ .globl mcck_int_handler
+mcck_int_handler:
+ spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer
+ lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs
+ SAVE_ALL_BASE __LC_SAVE_AREA+32
+ la %r12,__LC_MCK_OLD_PSW
+ tm __LC_MCCK_CODE,0x80 # system damage?
+ bo BASED(mcck_int_main) # yes -> rest of mcck code invalid
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER
+ mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA
+ tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid?
+ bo BASED(1f)
+ la %r14,__LC_SYNC_ENTER_TIMER
+ clc 0(8,%r14),__LC_ASYNC_ENTER_TIMER
+ bl BASED(0f)
+ la %r14,__LC_ASYNC_ENTER_TIMER
+0: clc 0(8,%r14),__LC_EXIT_TIMER
+ bl BASED(0f)
+ la %r14,__LC_EXIT_TIMER
+0: clc 0(8,%r14),__LC_LAST_UPDATE_TIMER
+ bl BASED(0f)
+ la %r14,__LC_LAST_UPDATE_TIMER
+0: spt 0(%r14)
+ mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14)
+1:
+#endif
+ tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
+ bno BASED(mcck_int_main) # no -> skip cleanup critical
+ tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+ bnz BASED(mcck_int_main) # from user -> load async stack
+ clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_end)
+ bhe BASED(mcck_int_main)
+ clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_start)
+ bl BASED(mcck_int_main)
+ l %r14,BASED(.Lcleanup_critical)
+ basr %r14,%r14
+mcck_int_main:
+ l %r14,__LC_PANIC_STACK # are we already on the panic stack?
+ slr %r14,%r15
+ sra %r14,PAGE_SHIFT
+ be BASED(0f)
+ l %r15,__LC_PANIC_STACK # load panic stack
+0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ bno BASED(mcck_no_vtime) # no -> skip cleanup critical
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ bz BASED(mcck_no_vtime)
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+mcck_no_vtime:
+#endif
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Ls390_mcck)
+ basr %r14,%r1 # call machine check handler
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ bno BASED(mcck_return)
+ l %r1,__LC_KERNEL_STACK # switch to kernel stack
+ s %r1,BASED(.Lc_spsize)
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lr %r15,%r1
+ stosm __SF_EMPTY(%r15),0x04 # turn dat on
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+ bno BASED(mcck_return)
+ TRACE_IRQS_OFF
+ l %r1,BASED(.Ls390_handle_mcck)
+ basr %r14,%r1 # call machine check handler
+ TRACE_IRQS_ON
+mcck_return:
+ mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW
+ ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+52
+ tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
+ bno BASED(0f)
+ lm %r0,%r15,SP_R0(%r15) # load gprs 0-15
+ stpt __LC_EXIT_TIMER
+ lpsw __LC_RETURN_MCCK_PSW # back to caller
+0:
+#endif
+ lm %r0,%r15,SP_R0(%r15) # load gprs 0-15
+ lpsw __LC_RETURN_MCCK_PSW # back to caller
+
+ RESTORE_ALL __LC_RETURN_MCCK_PSW,0
+
+/*
+ * Restart interruption handler, kick starter for additional CPUs
+ */
+#ifdef CONFIG_SMP
+ __CPUINIT
+ .globl restart_int_handler
+restart_int_handler:
+ l %r15,__LC_SAVE_AREA+60 # load ksp
+ lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
+ lam %a0,%a15,__LC_AREGS_SAVE_AREA
+ lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone
+ stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
+ basr %r14,0
+ l %r14,restart_addr-.(%r14)
+ br %r14 # branch to start_secondary
+restart_addr:
+ .long start_secondary
+ .previous
+#else
+/*
+ * If we do not run with SMP enabled, let the new CPU crash ...
+ */
+ .globl restart_int_handler
+restart_int_handler:
+ basr %r1,0
+restart_base:
+ lpsw restart_crash-restart_base(%r1)
+ .align 8
+restart_crash:
+ .long 0x000a0000,0x00000000
+restart_go:
+#endif
+
+#ifdef CONFIG_CHECK_STACK
+/*
+ * The synchronous or the asynchronous stack overflowed. We are dead.
+ * No need to properly save the registers, we are going to panic anyway.
+ * Setup a pt_regs so that show_trace can provide a good call trace.
+ */
+stack_overflow:
+ l %r15,__LC_PANIC_STACK # change to panic stack
+ sl %r15,BASED(.Lc_spsize)
+ mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack
+ stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
+ la %r1,__LC_SAVE_AREA
+ ch %r12,BASED(.L0x020) # old psw addr == __LC_SVC_OLD_PSW ?
+ be BASED(0f)
+ ch %r12,BASED(.L0x028) # old psw addr == __LC_PGM_OLD_PSW ?
+ be BASED(0f)
+ la %r1,__LC_SAVE_AREA+16
+0: mvc SP_R12(16,%r15),0(%r1) # move %r12-%r15 to stack
+ xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain
+ l %r1,BASED(1f) # branch to kernel_stack_overflow
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ br %r1
+1: .long kernel_stack_overflow
+#endif
+
+cleanup_table_system_call:
+ .long system_call + 0x80000000, sysc_do_svc + 0x80000000
+cleanup_table_sysc_return:
+ .long sysc_return + 0x80000000, sysc_leave + 0x80000000
+cleanup_table_sysc_leave:
+ .long sysc_leave + 0x80000000, sysc_done + 0x80000000
+cleanup_table_sysc_work_loop:
+ .long sysc_work_loop + 0x80000000, sysc_work_done + 0x80000000
+cleanup_table_io_return:
+ .long io_return + 0x80000000, io_leave + 0x80000000
+cleanup_table_io_leave:
+ .long io_leave + 0x80000000, io_done + 0x80000000
+cleanup_table_io_work_loop:
+ .long io_work_loop + 0x80000000, io_work_done + 0x80000000
+
+cleanup_critical:
+ clc 4(4,%r12),BASED(cleanup_table_system_call)
+ bl BASED(0f)
+ clc 4(4,%r12),BASED(cleanup_table_system_call+4)
+ bl BASED(cleanup_system_call)
+0:
+ clc 4(4,%r12),BASED(cleanup_table_sysc_return)
+ bl BASED(0f)
+ clc 4(4,%r12),BASED(cleanup_table_sysc_return+4)
+ bl BASED(cleanup_sysc_return)
+0:
+ clc 4(4,%r12),BASED(cleanup_table_sysc_leave)
+ bl BASED(0f)
+ clc 4(4,%r12),BASED(cleanup_table_sysc_leave+4)
+ bl BASED(cleanup_sysc_leave)
+0:
+ clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop)
+ bl BASED(0f)
+ clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
+ bl BASED(cleanup_sysc_return)
+0:
+ clc 4(4,%r12),BASED(cleanup_table_io_return)
+ bl BASED(0f)
+ clc 4(4,%r12),BASED(cleanup_table_io_return+4)
+ bl BASED(cleanup_io_return)
+0:
+ clc 4(4,%r12),BASED(cleanup_table_io_leave)
+ bl BASED(0f)
+ clc 4(4,%r12),BASED(cleanup_table_io_leave+4)
+ bl BASED(cleanup_io_leave)
+0:
+ clc 4(4,%r12),BASED(cleanup_table_io_work_loop)
+ bl BASED(0f)
+ clc 4(4,%r12),BASED(cleanup_table_io_work_loop+4)
+ bl BASED(cleanup_io_return)
+0:
+ br %r14
+
+cleanup_system_call:
+ mvc __LC_RETURN_PSW(8),0(%r12)
+ c %r12,BASED(.Lmck_old_psw)
+ be BASED(0f)
+ la %r12,__LC_SAVE_AREA+16
+ b BASED(1f)
+0: la %r12,__LC_SAVE_AREA+32
+1:
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4)
+ bh BASED(0f)
+ mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER
+0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8)
+ bhe BASED(cleanup_vtime)
+#endif
+ clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn)
+ bh BASED(0f)
+ mvc __LC_SAVE_AREA(16),0(%r12)
+0: st %r13,4(%r12)
+ st %r12,__LC_SAVE_AREA+48 # argh
+ SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ l %r12,__LC_SAVE_AREA+48 # argh
+ st %r15,12(%r12)
+ lh %r7,0x8a
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+cleanup_vtime:
+ clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12)
+ bhe BASED(cleanup_stime)
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+cleanup_stime:
+ clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+16)
+ bh BASED(cleanup_update)
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+cleanup_update:
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+#endif
+ mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_system_call+4)
+ la %r12,__LC_RETURN_PSW
+ br %r14
+cleanup_system_call_insn:
+ .long sysc_saveall + 0x80000000
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .long system_call + 0x80000000
+ .long sysc_vtime + 0x80000000
+ .long sysc_stime + 0x80000000
+ .long sysc_update + 0x80000000
+#endif
+
+cleanup_sysc_return:
+ mvc __LC_RETURN_PSW(4),0(%r12)
+ mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_sysc_return)
+ la %r12,__LC_RETURN_PSW
+ br %r14
+
+cleanup_sysc_leave:
+ clc 4(4,%r12),BASED(cleanup_sysc_leave_insn)
+ be BASED(2f)
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ clc 4(4,%r12),BASED(cleanup_sysc_leave_insn+4)
+ be BASED(2f)
+#endif
+ mvc __LC_RETURN_PSW(8),SP_PSW(%r15)
+ c %r12,BASED(.Lmck_old_psw)
+ bne BASED(0f)
+ mvc __LC_SAVE_AREA+32(16),SP_R12(%r15)
+ b BASED(1f)
+0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15)
+1: lm %r0,%r11,SP_R0(%r15)
+ l %r15,SP_R15(%r15)
+2: la %r12,__LC_RETURN_PSW
+ br %r14
+cleanup_sysc_leave_insn:
+ .long sysc_done - 4 + 0x80000000
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .long sysc_done - 8 + 0x80000000
+#endif
+
+cleanup_io_return:
+ mvc __LC_RETURN_PSW(4),0(%r12)
+ mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_io_work_loop)
+ la %r12,__LC_RETURN_PSW
+ br %r14
+
+cleanup_io_leave:
+ clc 4(4,%r12),BASED(cleanup_io_leave_insn)
+ be BASED(2f)
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ clc 4(4,%r12),BASED(cleanup_io_leave_insn+4)
+ be BASED(2f)
+#endif
+ mvc __LC_RETURN_PSW(8),SP_PSW(%r15)
+ c %r12,BASED(.Lmck_old_psw)
+ bne BASED(0f)
+ mvc __LC_SAVE_AREA+32(16),SP_R12(%r15)
+ b BASED(1f)
+0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15)
+1: lm %r0,%r11,SP_R0(%r15)
+ l %r15,SP_R15(%r15)
+2: la %r12,__LC_RETURN_PSW
+ br %r14
+cleanup_io_leave_insn:
+ .long io_done - 4 + 0x80000000
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .long io_done - 8 + 0x80000000
+#endif
+
+/*
+ * Integer constants
+ */
+ .align 4
+.Lc_spsize: .long SP_SIZE
+.Lc_overhead: .long STACK_FRAME_OVERHEAD
+.Lnr_syscalls: .long NR_syscalls
+.L0x018: .short 0x018
+.L0x020: .short 0x020
+.L0x028: .short 0x028
+.L0x030: .short 0x030
+.L0x038: .short 0x038
+.Lc_1: .long 1
+
+/*
+ * Symbol constants
+ */
+.Ls390_mcck: .long s390_do_machine_check
+.Ls390_handle_mcck:
+ .long s390_handle_mcck
+.Lmck_old_psw: .long __LC_MCK_OLD_PSW
+.Ldo_IRQ: .long do_IRQ
+.Ldo_extint: .long do_extint
+.Ldo_signal: .long do_signal
+.Lhandle_per: .long do_single_step
+.Ldo_execve: .long do_execve
+.Lexecve_tail: .long execve_tail
+.Ljump_table: .long pgm_check_table
+.Lschedule: .long schedule
+#ifdef CONFIG_PREEMPT
+.Lpreempt_schedule_irq:
+ .long preempt_schedule_irq
+#endif
+.Ltrace: .long syscall_trace
+.Lschedtail: .long schedule_tail
+.Lsysc_table: .long sys_call_table
+#ifdef CONFIG_TRACE_IRQFLAGS
+.Ltrace_irq_on: .long trace_hardirqs_on
+.Ltrace_irq_off:
+ .long trace_hardirqs_off
+.Llockdep_sys_exit:
+ .long lockdep_sys_exit
+#endif
+.Lcritical_start:
+ .long __critical_start + 0x80000000
+.Lcritical_end:
+ .long __critical_end + 0x80000000
+.Lcleanup_critical:
+ .long cleanup_critical
+
+ .section .rodata, "a"
+#define SYSCALL(esa,esame,emu) .long esa
+sys_call_table:
+#include "syscalls.S"
+#undef SYSCALL
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/entry64.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/entry64.S
new file mode 100644
index 0000000000..efde6e178f
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/entry64.S
@@ -0,0 +1,1045 @@
+/*
+ * arch/s390/kernel/entry64.S
+ * S390 low-level entry points.
+ *
+ * Copyright (C) IBM Corp. 1999,2006
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Hartmut Penner (hp@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/cache.h>
+#include <asm/lowcore.h>
+#include <asm/errno.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+
+/*
+ * Stack layout for the system_call stack entry.
+ * The first few entries are identical to the user_regs_struct.
+ */
+SP_PTREGS = STACK_FRAME_OVERHEAD
+SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
+SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
+SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
+SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
+SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
+SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
+SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
+SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
+SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
+SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
+SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 64
+SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 72
+SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 80
+SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 88
+SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 96
+SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104
+SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112
+SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120
+SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
+SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
+SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
+SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
+
+STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
+STACK_SIZE = 1 << STACK_SHIFT
+
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
+ _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
+ _TIF_MCCK_PENDING)
+
+#define BASED(name) name-system_call(%r13)
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+ .macro TRACE_IRQS_ON
+ brasl %r14,trace_hardirqs_on
+ .endm
+
+ .macro TRACE_IRQS_OFF
+ brasl %r14,trace_hardirqs_off
+ .endm
+
+ .macro TRACE_IRQS_CHECK
+ tm SP_PSW(%r15),0x03 # irqs enabled?
+ jz 0f
+ brasl %r14,trace_hardirqs_on
+ j 1f
+0: brasl %r14,trace_hardirqs_off
+1:
+ .endm
+#else
+#define TRACE_IRQS_ON
+#define TRACE_IRQS_OFF
+#define TRACE_IRQS_CHECK
+#endif
+
+#ifdef CONFIG_LOCKDEP
+ .macro LOCKDEP_SYS_EXIT
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jz 0f
+ brasl %r14,lockdep_sys_exit
+0:
+ .endm
+#else
+#define LOCKDEP_SYS_EXIT
+#endif
+
+ .macro STORE_TIMER lc_offset
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ stpt \lc_offset
+#endif
+ .endm
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .macro UPDATE_VTIME lc_from,lc_to,lc_sum
+ lg %r10,\lc_from
+ slg %r10,\lc_to
+ alg %r10,\lc_sum
+ stg %r10,\lc_sum
+ .endm
+#endif
+
+/*
+ * Register usage in interrupt handlers:
+ * R9 - pointer to current task structure
+ * R13 - pointer to literal pool
+ * R14 - return register for function calls
+ * R15 - kernel stack pointer
+ */
+
+ .macro SAVE_ALL_BASE savearea
+ stmg %r12,%r15,\savearea
+ larl %r13,system_call
+ .endm
+
+ .macro SAVE_ALL_SVC psworg,savearea
+ la %r12,\psworg
+ lg %r15,__LC_KERNEL_STACK # problem state -> load ksp
+ .endm
+
+ .macro SAVE_ALL_SYNC psworg,savearea
+ la %r12,\psworg
+ tm \psworg+1,0x01 # test problem state bit
+ jz 2f # skip stack setup save
+ lg %r15,__LC_KERNEL_STACK # problem state -> load ksp
+#ifdef CONFIG_CHECK_STACK
+ j 3f
+2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD
+ jz stack_overflow
+3:
+#endif
+2:
+ .endm
+
+ .macro SAVE_ALL_ASYNC psworg,savearea
+ la %r12,\psworg
+ tm \psworg+1,0x01 # test problem state bit
+ jnz 1f # from user -> load kernel stack
+ clc \psworg+8(8),BASED(.Lcritical_end)
+ jhe 0f
+ clc \psworg+8(8),BASED(.Lcritical_start)
+ jl 0f
+ brasl %r14,cleanup_critical
+ tm 1(%r12),0x01 # retest problem state after cleanup
+ jnz 1f
+0: lg %r14,__LC_ASYNC_STACK # are we already on the async. stack ?
+ slgr %r14,%r15
+ srag %r14,%r14,STACK_SHIFT
+ jz 2f
+1: lg %r15,__LC_ASYNC_STACK # load async stack
+#ifdef CONFIG_CHECK_STACK
+ j 3f
+2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD
+ jz stack_overflow
+3:
+#endif
+2:
+ .endm
+
+ .macro CREATE_STACK_FRAME psworg,savearea
+ aghi %r15,-SP_SIZE # make room for registers & psw
+ mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
+ la %r12,\psworg
+ stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
+ icm %r12,12,__LC_SVC_ILC
+ stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
+ st %r12,SP_ILC(%r15)
+ mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack
+ la %r12,0
+ stg %r12,__SF_BACKCHAIN(%r15)
+ .endm
+
+ .macro RESTORE_ALL psworg,sync
+ mvc \psworg(16),SP_PSW(%r15) # move user PSW to lowcore
+ .if !\sync
+ ni \psworg+1,0xfd # clear wait state bit
+ .endif
+ lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user
+ STORE_TIMER __LC_EXIT_TIMER
+ lpswe \psworg # back to caller
+ .endm
+
+/*
+ * Scheduler resume function, called by switch_to
+ * gpr2 = (task_struct *) prev
+ * gpr3 = (task_struct *) next
+ * Returns:
+ * gpr2 = prev
+ */
+ .globl __switch_to
+__switch_to:
+ tm __THREAD_per+4(%r3),0xe8 # is the new process using per ?
+ jz __switch_to_noper # if not we're fine
+ stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff
+ clc __THREAD_per(24,%r3),__SF_EMPTY(%r15)
+ je __switch_to_noper # we got away without bashing TLB's
+ lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't
+__switch_to_noper:
+ lg %r4,__THREAD_info(%r2) # get thread_info of prev
+ tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
+ jz __switch_to_no_mcck
+ ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
+ lg %r4,__THREAD_info(%r3) # get thread_info of next
+ oi __TI_flags+7(%r4),_TIF_MCCK_PENDING # set it in next
+__switch_to_no_mcck:
+ stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
+ stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
+ lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
+ lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
+ stg %r3,__LC_CURRENT # __LC_CURRENT = current task struct
+ lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
+ lg %r3,__THREAD_info(%r3) # load thread_info from task struct
+ stg %r3,__LC_THREAD_INFO
+ aghi %r3,STACK_SIZE
+ stg %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
+ br %r14
+
+__critical_start:
+/*
+ * SVC interrupt handler routine. System calls are synchronous events and
+ * are executed with interrupts enabled.
+ */
+
+ .globl system_call
+system_call:
+ STORE_TIMER __LC_SYNC_ENTER_TIMER
+sysc_saveall:
+ SAVE_ALL_BASE __LC_SAVE_AREA
+ SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+sysc_vtime:
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+sysc_stime:
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+sysc_update:
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+#endif
+sysc_do_svc:
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ slag %r7,%r7,2 # *4 and test for svc 0
+ jnz sysc_nr_ok
+ # svc 0: system call number in %r1
+ cl %r1,BASED(.Lnr_syscalls)
+ jnl sysc_nr_ok
+ lgfr %r7,%r1 # clear high word in r1
+ slag %r7,%r7,2 # svc 0: system call number in %r1
+sysc_nr_ok:
+ mvc SP_ARGS(8,%r15),SP_R7(%r15)
+sysc_do_restart:
+ larl %r10,sys_call_table
+#ifdef CONFIG_COMPAT
+ tm __TI_flags+5(%r9),(_TIF_31BIT>>16) # running in 31 bit mode ?
+ jno sysc_noemu
+ larl %r10,sys_call_table_emu # use 31 bit emulation system calls
+sysc_noemu:
+#endif
+ tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+ lgf %r8,0(%r7,%r10) # load address of system call routine
+ jnz sysc_tracesys
+ basr %r14,%r8 # call sys_xxxx
+ stg %r2,SP_R2(%r15) # store return value (change R2 on stack)
+
+sysc_return:
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jno sysc_restore
+ tm __TI_flags+7(%r9),_TIF_WORK_SVC
+ jnz sysc_work # there is work to do (signals etc.)
+sysc_restore:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ larl %r1,sysc_restore_trace_psw
+ lpswe 0(%r1)
+sysc_restore_trace:
+ TRACE_IRQS_CHECK
+ LOCKDEP_SYS_EXIT
+#endif
+sysc_leave:
+ RESTORE_ALL __LC_RETURN_PSW,1
+sysc_done:
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+ .align 8
+ .globl sysc_restore_trace_psw
+sysc_restore_trace_psw:
+ .quad 0, sysc_restore_trace
+#endif
+
+#
+# recheck if there is more work to do
+#
+sysc_work_loop:
+ tm __TI_flags+7(%r9),_TIF_WORK_SVC
+ jz sysc_restore # there is no work to do
+#
+# One of the work bits is on. Find out which one.
+#
+sysc_work:
+ tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
+ jo sysc_mcck_pending
+ tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
+ jo sysc_reschedule
+ tm __TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
+ jnz sysc_sigpending
+ tm __TI_flags+7(%r9),_TIF_RESTART_SVC
+ jo sysc_restart
+ tm __TI_flags+7(%r9),_TIF_SINGLE_STEP
+ jo sysc_singlestep
+ j sysc_restore
+sysc_work_done:
+
+#
+# _TIF_NEED_RESCHED is set, call schedule
+#
+sysc_reschedule:
+ larl %r14,sysc_work_loop
+ jg schedule # return point is sysc_return
+
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+sysc_mcck_pending:
+ larl %r14,sysc_work_loop
+ jg s390_handle_mcck # TIF bit will be cleared by handler
+
+#
+# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+#
+sysc_sigpending:
+ ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ brasl %r14,do_signal # call do_signal
+ tm __TI_flags+7(%r9),_TIF_RESTART_SVC
+ jo sysc_restart
+ tm __TI_flags+7(%r9),_TIF_SINGLE_STEP
+ jo sysc_singlestep
+ j sysc_work_loop
+
+#
+# _TIF_RESTART_SVC is set, set up registers and restart svc
+#
+sysc_restart:
+ ni __TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
+ lg %r7,SP_R2(%r15) # load new svc number
+ slag %r7,%r7,2 # *4
+ mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument
+ lmg %r2,%r6,SP_R2(%r15) # load svc arguments
+ j sysc_do_restart # restart svc
+
+#
+# _TIF_SINGLE_STEP is set, call do_single_step
+#
+sysc_singlestep:
+ ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
+ lhi %r0,__LC_PGM_OLD_PSW
+ sth %r0,SP_TRAP(%r15) # set trap indication to pgm check
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ larl %r14,sysc_return # load adr. of system return
+ jg do_single_step # branch to do_sigtrap
+
+#
+# call syscall_trace before and after system call
+# special linkage: %r12 contains the return address for trace_svc
+#
+sysc_tracesys:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r3,0
+ srl %r7,2
+ stg %r7,SP_R2(%r15)
+ brasl %r14,syscall_trace
+ lghi %r0,NR_syscalls
+ clg %r0,SP_R2(%r15)
+ jnh sysc_tracenogo
+ lg %r7,SP_R2(%r15) # strace might have changed the
+ sll %r7,2 # system call
+ lgf %r8,0(%r7,%r10)
+sysc_tracego:
+ lmg %r3,%r6,SP_R3(%r15)
+ lg %r2,SP_ORIG_R2(%r15)
+ basr %r14,%r8 # call sys_xxx
+ stg %r2,SP_R2(%r15) # store return value
+sysc_tracenogo:
+ tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+ jz sysc_return
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r3,1
+ larl %r14,sysc_return # return point is sysc_return
+ jg syscall_trace
+
+#
+# a new process exits the kernel with ret_from_fork
+#
+ .globl ret_from_fork
+ret_from_fork:
+ lg %r13,__LC_SVC_NEW_PSW+8
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ tm SP_PSW+1(%r15),0x01 # forking a kernel thread ?
+ jo 0f
+ stg %r15,SP_R15(%r15) # store stack pointer for new kthread
+0: brasl %r14,schedule_tail
+ TRACE_IRQS_ON
+ stosm 24(%r15),0x03 # reenable interrupts
+ j sysc_return
+
+#
+# kernel_execve function needs to deal with pt_regs that is not
+# at the usual place
+#
+ .globl kernel_execve
+kernel_execve:
+ stmg %r12,%r15,96(%r15)
+ lgr %r14,%r15
+ aghi %r15,-SP_SIZE
+ stg %r14,__SF_BACKCHAIN(%r15)
+ la %r12,SP_PTREGS(%r15)
+ xc 0(__PT_SIZE,%r12),0(%r12)
+ lgr %r5,%r12
+ brasl %r14,do_execve
+ ltgfr %r2,%r2
+ je 0f
+ aghi %r15,SP_SIZE
+ lmg %r12,%r15,96(%r15)
+ br %r14
+ # execve succeeded.
+0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts
+ lg %r15,__LC_KERNEL_STACK # load ksp
+ aghi %r15,-SP_SIZE # make room for registers & psw
+ lg %r13,__LC_SVC_NEW_PSW+8
+ lg %r9,__LC_THREAD_INFO
+ mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs
+ xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ brasl %r14,execve_tail
+ j sysc_return
+
+/*
+ * Program check handler routine
+ */
+
+ .globl pgm_check_handler
+pgm_check_handler:
+/*
+ * First we need to check for a special case:
+ * Single stepping an instruction that disables the PER event mask will
+ * cause a PER event AFTER the mask has been set. Example: SVC or LPSW.
+ * For a single stepped SVC the program check handler gets control after
+ * the SVC new PSW has been loaded. But we want to execute the SVC first and
+ * then handle the PER event. Therefore we update the SVC old PSW to point
+ * to the pgm_check_handler and branch to the SVC handler after we checked
+ * if we have to load the kernel stack register.
+ * For every other possible cause for PER event without the PER mask set
+ * we just ignore the PER event (FIXME: is there anything we have to do
+ * for LPSW?).
+ */
+ STORE_TIMER __LC_SYNC_ENTER_TIMER
+ SAVE_ALL_BASE __LC_SAVE_AREA
+ tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
+ jnz pgm_per # got per exception -> special case
+ SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ jz pgm_no_vtime
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+pgm_no_vtime:
+#endif
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+ lgf %r3,__LC_PGM_ILC # load program interruption code
+ lghi %r8,0x7f
+ ngr %r8,%r3
+pgm_do_call:
+ sll %r8,3
+ larl %r1,pgm_check_table
+ lg %r1,0(%r8,%r1) # load address of handler routine
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ larl %r14,sysc_return
+ br %r1 # branch to interrupt-handler
+
+#
+# handle per exception
+#
+pgm_per:
+ tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
+ jnz pgm_per_std # ok, normal per event from user space
+# ok its one of the special cases, now we need to find out which one
+ clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
+ je pgm_svcper
+# no interesting special case, ignore PER event
+ lmg %r12,%r15,__LC_SAVE_AREA
+ lpswe __LC_PGM_OLD_PSW
+
+#
+# Normal per exception
+#
+pgm_per_std:
+ SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ jz pgm_no_vtime2
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+pgm_no_vtime2:
+#endif
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+ lg %r1,__TI_task(%r9)
+ tm SP_PSW+1(%r15),0x01 # kernel per event ?
+ jz kernel_per
+ mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
+ mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS
+ mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
+ oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
+ lgf %r3,__LC_PGM_ILC # load program interruption code
+ lghi %r8,0x7f
+ ngr %r8,%r3 # clear per-event-bit and ilc
+ je sysc_return
+ j pgm_do_call
+
+#
+# it was a single stepped SVC that is causing all the trouble
+#
+pgm_svcper:
+ SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+#endif
+ llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ lg %r1,__TI_task(%r9)
+ mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
+ mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS
+ mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
+ oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
+ TRACE_IRQS_ON
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ j sysc_do_svc
+
+#
+# per was called from kernel, must be kprobes
+#
+kernel_per:
+ lhi %r0,__LC_PGM_OLD_PSW
+ sth %r0,SP_TRAP(%r15) # set trap indication to pgm check
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ larl %r14,sysc_restore # load adr. of system ret, no work
+ jg do_single_step # branch to do_single_step
+
+/*
+ * IO interrupt handler routine
+ */
+ .globl io_int_handler
+io_int_handler:
+ STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ stck __LC_INT_CLOCK
+ SAVE_ALL_BASE __LC_SAVE_AREA+32
+ SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
+ CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ jz io_no_vtime
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+io_no_vtime:
+#endif
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ brasl %r14,do_IRQ # call standard irq handler
+io_return:
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+#ifdef CONFIG_PREEMPT
+ jno io_preempt # no -> check for preemptive scheduling
+#else
+ jno io_restore # no-> skip resched & signal
+#endif
+ tm __TI_flags+7(%r9),_TIF_WORK_INT
+ jnz io_work # there is work to do (signals etc.)
+io_restore:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ larl %r1,io_restore_trace_psw
+ lpswe 0(%r1)
+io_restore_trace:
+ TRACE_IRQS_CHECK
+ LOCKDEP_SYS_EXIT
+#endif
+io_leave:
+ RESTORE_ALL __LC_RETURN_PSW,0
+io_done:
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+ .align 8
+ .globl io_restore_trace_psw
+io_restore_trace_psw:
+ .quad 0, io_restore_trace
+#endif
+
+#ifdef CONFIG_PREEMPT
+io_preempt:
+ icm %r0,15,__TI_precount(%r9)
+ jnz io_restore
+ # switch to kernel stack
+ lg %r1,SP_R15(%r15)
+ aghi %r1,-SP_SIZE
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lgr %r15,%r1
+io_resume_loop:
+ tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
+ jno io_restore
+ larl %r14,io_resume_loop
+ jg preempt_schedule_irq
+#endif
+
+#
+# switch to kernel stack, then check TIF bits
+#
+io_work:
+ lg %r1,__LC_KERNEL_STACK
+ aghi %r1,-SP_SIZE
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lgr %r15,%r1
+#
+# One of the work bits is on. Find out which one.
+# Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGPENDING, _TIF_NEED_RESCHED
+# and _TIF_MCCK_PENDING
+#
+io_work_loop:
+ tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
+ jo io_mcck_pending
+ tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
+ jo io_reschedule
+ tm __TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
+ jnz io_sigpending
+ j io_restore
+io_work_done:
+
+#
+# _TIF_MCCK_PENDING is set, call handler
+#
+io_mcck_pending:
+ brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler
+ j io_work_loop
+
+#
+# _TIF_NEED_RESCHED is set, call schedule
+#
+io_reschedule:
+ TRACE_IRQS_ON
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ brasl %r14,schedule # call scheduler
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ TRACE_IRQS_OFF
+ tm __TI_flags+7(%r9),_TIF_WORK_INT
+ jz io_restore # there is no work to do
+ j io_work_loop
+
+#
+# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+#
+io_sigpending:
+ TRACE_IRQS_ON
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ brasl %r14,do_signal # call do_signal
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ TRACE_IRQS_OFF
+ j io_work_loop
+
+/*
+ * External interrupt handler routine
+ */
+ .globl ext_int_handler
+ext_int_handler:
+ STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ stck __LC_INT_CLOCK
+ SAVE_ALL_BASE __LC_SAVE_AREA+32
+ SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
+ CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ jz ext_no_vtime
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ext_no_vtime:
+#endif
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ TRACE_IRQS_OFF
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ llgh %r3,__LC_EXT_INT_CODE # get interruption code
+ brasl %r14,do_extint
+ j io_return
+
+__critical_end:
+
+/*
+ * Machine check handler routines
+ */
+ .globl mcck_int_handler
+mcck_int_handler:
+ la %r1,4095 # revalidate r1
+ spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer
+ lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
+ SAVE_ALL_BASE __LC_SAVE_AREA+64
+ la %r12,__LC_MCK_OLD_PSW
+ tm __LC_MCCK_CODE,0x80 # system damage?
+ jo mcck_int_main # yes -> rest of mcck code invalid
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ la %r14,4095
+ mvc __LC_SAVE_AREA+104(8),__LC_ASYNC_ENTER_TIMER
+ mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14)
+ tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid?
+ jo 1f
+ la %r14,__LC_SYNC_ENTER_TIMER
+ clc 0(8,%r14),__LC_ASYNC_ENTER_TIMER
+ jl 0f
+ la %r14,__LC_ASYNC_ENTER_TIMER
+0: clc 0(8,%r14),__LC_EXIT_TIMER
+ jl 0f
+ la %r14,__LC_EXIT_TIMER
+0: clc 0(8,%r14),__LC_LAST_UPDATE_TIMER
+ jl 0f
+ la %r14,__LC_LAST_UPDATE_TIMER
+0: spt 0(%r14)
+ mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14)
+1:
+#endif
+ tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
+ jno mcck_int_main # no -> skip cleanup critical
+ tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+ jnz mcck_int_main # from user -> load kernel stack
+ clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end)
+ jhe mcck_int_main
+ clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start)
+ jl mcck_int_main
+ brasl %r14,cleanup_critical
+mcck_int_main:
+ lg %r14,__LC_PANIC_STACK # are we already on the panic stack?
+ slgr %r14,%r15
+ srag %r14,%r14,PAGE_SHIFT
+ jz 0f
+ lg %r15,__LC_PANIC_STACK # load panic stack
+0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ jno mcck_no_vtime # no -> no timer update
+ tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ jz mcck_no_vtime
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+mcck_no_vtime:
+#endif
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ brasl %r14,s390_do_machine_check
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jno mcck_return
+ lg %r1,__LC_KERNEL_STACK # switch to kernel stack
+ aghi %r1,-SP_SIZE
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lgr %r15,%r1
+ stosm __SF_EMPTY(%r15),0x04 # turn dat on
+ tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
+ jno mcck_return
+ TRACE_IRQS_OFF
+ brasl %r14,s390_handle_mcck
+ TRACE_IRQS_ON
+mcck_return:
+ mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW
+ ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
+ lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+104
+ tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
+ jno 0f
+ stpt __LC_EXIT_TIMER
+0:
+#endif
+ lpswe __LC_RETURN_MCCK_PSW # back to caller
+
+/*
+ * Restart interruption handler, kick starter for additional CPUs
+ */
+#ifdef CONFIG_SMP
+ __CPUINIT
+ .globl restart_int_handler
+restart_int_handler:
+ lg %r15,__LC_SAVE_AREA+120 # load ksp
+ lghi %r10,__LC_CREGS_SAVE_AREA
+ lctlg %c0,%c15,0(%r10) # get new ctl regs
+ lghi %r10,__LC_AREGS_SAVE_AREA
+ lam %a0,%a15,0(%r10)
+ lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone
+ stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
+ jg start_secondary
+ .previous
+#else
+/*
+ * If we do not run with SMP enabled, let the new CPU crash ...
+ */
+ .globl restart_int_handler
+restart_int_handler:
+ basr %r1,0
+restart_base:
+ lpswe restart_crash-restart_base(%r1)
+ .align 8
+restart_crash:
+ .long 0x000a0000,0x00000000,0x00000000,0x00000000
+restart_go:
+#endif
+
+#ifdef CONFIG_CHECK_STACK
+/*
+ * The synchronous or the asynchronous stack overflowed. We are dead.
+ * No need to properly save the registers, we are going to panic anyway.
+ * Setup a pt_regs so that show_trace can provide a good call trace.
+ */
+stack_overflow:
+ lg %r15,__LC_PANIC_STACK # change to panic stack
+ aghi %r15,-SP_SIZE
+ mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
+ stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
+ la %r1,__LC_SAVE_AREA
+ chi %r12,__LC_SVC_OLD_PSW
+ je 0f
+ chi %r12,__LC_PGM_OLD_PSW
+ je 0f
+ la %r1,__LC_SAVE_AREA+32
+0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack
+ xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ jg kernel_stack_overflow
+#endif
+
+cleanup_table_system_call:
+ .quad system_call, sysc_do_svc
+cleanup_table_sysc_return:
+ .quad sysc_return, sysc_leave
+cleanup_table_sysc_leave:
+ .quad sysc_leave, sysc_done
+cleanup_table_sysc_work_loop:
+ .quad sysc_work_loop, sysc_work_done
+cleanup_table_io_return:
+ .quad io_return, io_leave
+cleanup_table_io_leave:
+ .quad io_leave, io_done
+cleanup_table_io_work_loop:
+ .quad io_work_loop, io_work_done
+
+cleanup_critical:
+ clc 8(8,%r12),BASED(cleanup_table_system_call)
+ jl 0f
+ clc 8(8,%r12),BASED(cleanup_table_system_call+8)
+ jl cleanup_system_call
+0:
+ clc 8(8,%r12),BASED(cleanup_table_sysc_return)
+ jl 0f
+ clc 8(8,%r12),BASED(cleanup_table_sysc_return+8)
+ jl cleanup_sysc_return
+0:
+ clc 8(8,%r12),BASED(cleanup_table_sysc_leave)
+ jl 0f
+ clc 8(8,%r12),BASED(cleanup_table_sysc_leave+8)
+ jl cleanup_sysc_leave
+0:
+ clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop)
+ jl 0f
+ clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
+ jl cleanup_sysc_return
+0:
+ clc 8(8,%r12),BASED(cleanup_table_io_return)
+ jl 0f
+ clc 8(8,%r12),BASED(cleanup_table_io_return+8)
+ jl cleanup_io_return
+0:
+ clc 8(8,%r12),BASED(cleanup_table_io_leave)
+ jl 0f
+ clc 8(8,%r12),BASED(cleanup_table_io_leave+8)
+ jl cleanup_io_leave
+0:
+ clc 8(8,%r12),BASED(cleanup_table_io_work_loop)
+ jl 0f
+ clc 8(8,%r12),BASED(cleanup_table_io_work_loop+8)
+ jl cleanup_io_return
+0:
+ br %r14
+
+cleanup_system_call:
+ mvc __LC_RETURN_PSW(16),0(%r12)
+ cghi %r12,__LC_MCK_OLD_PSW
+ je 0f
+ la %r12,__LC_SAVE_AREA+32
+ j 1f
+0: la %r12,__LC_SAVE_AREA+64
+1:
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8)
+ jh 0f
+ mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER
+0: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16)
+ jhe cleanup_vtime
+#endif
+ clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn)
+ jh 0f
+ mvc __LC_SAVE_AREA(32),0(%r12)
+0: stg %r13,8(%r12)
+ stg %r12,__LC_SAVE_AREA+96 # argh
+ SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ lg %r12,__LC_SAVE_AREA+96 # argh
+ stg %r15,24(%r12)
+ llgh %r7,__LC_SVC_INT_CODE
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+cleanup_vtime:
+ clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24)
+ jhe cleanup_stime
+ UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
+cleanup_stime:
+ clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+32)
+ jh cleanup_update
+ UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
+cleanup_update:
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+#endif
+ mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8)
+ la %r12,__LC_RETURN_PSW
+ br %r14
+cleanup_system_call_insn:
+ .quad sysc_saveall
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .quad system_call
+ .quad sysc_vtime
+ .quad sysc_stime
+ .quad sysc_update
+#endif
+
+cleanup_sysc_return:
+ mvc __LC_RETURN_PSW(8),0(%r12)
+ mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_sysc_return)
+ la %r12,__LC_RETURN_PSW
+ br %r14
+
+cleanup_sysc_leave:
+ clc 8(8,%r12),BASED(cleanup_sysc_leave_insn)
+ je 2f
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8)
+ je 2f
+#endif
+ mvc __LC_RETURN_PSW(16),SP_PSW(%r15)
+ cghi %r12,__LC_MCK_OLD_PSW
+ jne 0f
+ mvc __LC_SAVE_AREA+64(32),SP_R12(%r15)
+ j 1f
+0: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15)
+1: lmg %r0,%r11,SP_R0(%r15)
+ lg %r15,SP_R15(%r15)
+2: la %r12,__LC_RETURN_PSW
+ br %r14
+cleanup_sysc_leave_insn:
+ .quad sysc_done - 4
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .quad sysc_done - 8
+#endif
+
+cleanup_io_return:
+ mvc __LC_RETURN_PSW(8),0(%r12)
+ mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_io_work_loop)
+ la %r12,__LC_RETURN_PSW
+ br %r14
+
+cleanup_io_leave:
+ clc 8(8,%r12),BASED(cleanup_io_leave_insn)
+ je 2f
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ clc 8(8,%r12),BASED(cleanup_io_leave_insn+8)
+ je 2f
+#endif
+ mvc __LC_RETURN_PSW(16),SP_PSW(%r15)
+ cghi %r12,__LC_MCK_OLD_PSW
+ jne 0f
+ mvc __LC_SAVE_AREA+64(32),SP_R12(%r15)
+ j 1f
+0: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15)
+1: lmg %r0,%r11,SP_R0(%r15)
+ lg %r15,SP_R15(%r15)
+2: la %r12,__LC_RETURN_PSW
+ br %r14
+cleanup_io_leave_insn:
+ .quad io_done - 4
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ .quad io_done - 8
+#endif
+
+/*
+ * Integer constants
+ */
+ .align 4
+.Lconst:
+.Lnr_syscalls: .long NR_syscalls
+.L0x0130: .short 0x130
+.L0x0140: .short 0x140
+.L0x0150: .short 0x150
+.L0x0160: .short 0x160
+.L0x0170: .short 0x170
+.Lcritical_start:
+ .quad __critical_start
+.Lcritical_end:
+ .quad __critical_end
+
+ .section .rodata, "a"
+#define SYSCALL(esa,esame,emu) .long esame
+sys_call_table:
+#include "syscalls.S"
+#undef SYSCALL
+
+#ifdef CONFIG_COMPAT
+
+#define SYSCALL(esa,esame,emu) .long emu
+sys_call_table_emu:
+#include "syscalls.S"
+#undef SYSCALL
+#endif
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head.S
new file mode 100644
index 0000000000..83477c7dc7
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head.S
@@ -0,0 +1,468 @@
+/*
+ * arch/s390/kernel/head.S
+ *
+ * Copyright (C) IBM Corp. 1999,2006
+ *
+ * Author(s): Hartmut Penner <hp@de.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Rob van der Heij <rvdhei@iae.nl>
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ * There are 5 different IPL methods
+ * 1) load the image directly into ram at address 0 and do an PSW restart
+ * 2) linload will load the image from address 0x10000 to memory 0x10000
+ * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
+ * 3) generate the tape ipl header, store the generated image on a tape
+ * and ipl from it
+ * In case of SL tape you need to IPL 5 times to get past VOL1 etc
+ * 4) generate the vm reader ipl header, move the generated image to the
+ * VM reader (use option NOH!) and do a ipl from reader (VM only)
+ * 5) direct call of start by the SALIPL loader
+ * We use the cpuid to distinguish between VM and native ipl
+ * params for kernel are pushed to 0x10400 (see setup.h)
+ *
+ */
+
+#include <asm/setup.h>
+#include <asm/lowcore.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/page.h>
+
+#ifdef CONFIG_64BIT
+#define ARCH_OFFSET 4
+#else
+#define ARCH_OFFSET 0
+#endif
+
+.section ".text.head","ax"
+#ifndef CONFIG_IPL
+ .org 0
+ .long 0x00080000,0x80000000+startup # Just a restart PSW
+#else
+#ifdef CONFIG_IPL_TAPE
+#define IPL_BS 1024
+ .org 0
+ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+ .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
+ .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
+ .long 0x00000000,0x00000000 # external old psw
+ .long 0x00000000,0x00000000 # svc old psw
+ .long 0x00000000,0x00000000 # program check old psw
+ .long 0x00000000,0x00000000 # machine check old psw
+ .long 0x00000000,0x00000000 # io old psw
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x000a0000,0x00000058 # external new psw
+ .long 0x000a0000,0x00000060 # svc new psw
+ .long 0x000a0000,0x00000068 # program check new psw
+ .long 0x000a0000,0x00000070 # machine check new psw
+ .long 0x00080000,0x80000000+.Lioint # io new psw
+
+ .org 0x100
+#
+# subroutine for loading from tape
+# Paramters:
+# R1 = device number
+# R2 = load address
+.Lloader:
+ st %r14,.Lldret
+ la %r3,.Lorbread # r3 = address of orb
+ la %r5,.Lirb # r5 = address of irb
+ st %r2,.Lccwread+4 # initialize CCW data addresses
+ lctl %c6,%c6,.Lcr6
+ slr %r2,%r2
+.Lldlp:
+ la %r6,3 # 3 retries
+.Lssch:
+ ssch 0(%r3) # load chunk of IPL_BS bytes
+ bnz .Llderr
+.Lw4end:
+ bas %r14,.Lwait4io
+ tm 8(%r5),0x82 # do we have a problem ?
+ bnz .Lrecov
+ slr %r7,%r7
+ icm %r7,3,10(%r5) # get residual count
+ lcr %r7,%r7
+ la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
+ ar %r2,%r7 # add to total size
+ tm 8(%r5),0x01 # found a tape mark ?
+ bnz .Ldone
+ l %r0,.Lccwread+4 # update CCW data addresses
+ ar %r0,%r7
+ st %r0,.Lccwread+4
+ b .Lldlp
+.Ldone:
+ l %r14,.Lldret
+ br %r14 # r2 contains the total size
+.Lrecov:
+ bas %r14,.Lsense # do the sensing
+ bct %r6,.Lssch # dec. retry count & branch
+ b .Llderr
+#
+# Sense subroutine
+#
+.Lsense:
+ st %r14,.Lsnsret
+ la %r7,.Lorbsense
+ ssch 0(%r7) # start sense command
+ bnz .Llderr
+ bas %r14,.Lwait4io
+ l %r14,.Lsnsret
+ tm 8(%r5),0x82 # do we have a problem ?
+ bnz .Llderr
+ br %r14
+#
+# Wait for interrupt subroutine
+#
+.Lwait4io:
+ lpsw .Lwaitpsw
+.Lioint:
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwait4io
+ tsch 0(%r5)
+ slr %r0,%r0
+ tm 8(%r5),0x82 # do we have a problem ?
+ bnz .Lwtexit
+ tm 8(%r5),0x04 # got device end ?
+ bz .Lwait4io
+.Lwtexit:
+ br %r14
+.Llderr:
+ lpsw .Lcrash
+
+ .align 8
+.Lorbread:
+ .long 0x00000000,0x0080ff00,.Lccwread
+ .align 8
+.Lorbsense:
+ .long 0x00000000,0x0080ff00,.Lccwsense
+ .align 8
+.Lccwread:
+ .long 0x02200000+IPL_BS,0x00000000
+.Lccwsense:
+ .long 0x04200001,0x00000000
+.Lwaitpsw:
+ .long 0x020a0000,0x80000000+.Lioint
+
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6: .long 0xff000000
+ .align 8
+.Lcrash:.long 0x000a0000,0x00000000
+.Lldret:.long 0
+.Lsnsret: .long 0
+#endif /* CONFIG_IPL_TAPE */
+
+#ifdef CONFIG_IPL_VM
+#define IPL_BS 0x730
+ .org 0
+ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+ .long 0x02000018,0x60000050 # by ipl to addresses 0-23.
+ .long 0x02000068,0x60000050 # (a PSW and two CCWs).
+ .fill 80-24,1,0x40 # bytes 24-79 are discarded !!
+ .long 0x020000f0,0x60000050 # The next 160 byte are loaded
+ .long 0x02000140,0x60000050 # to addresses 0x18-0xb7
+ .long 0x02000190,0x60000050 # They form the continuation
+ .long 0x020001e0,0x60000050 # of the CCW program started
+ .long 0x02000230,0x60000050 # by ipl and load the range
+ .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image
+ .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730
+ .long 0x02000320,0x60000050 # in memory. At the end of
+ .long 0x02000370,0x60000050 # the channel program the PSW
+ .long 0x020003c0,0x60000050 # at location 0 is loaded.
+ .long 0x02000410,0x60000050 # Initial processing starts
+ .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
+ .long 0x020004b0,0x60000050
+ .long 0x02000500,0x60000050
+ .long 0x02000550,0x60000050
+ .long 0x020005a0,0x60000050
+ .long 0x020005f0,0x60000050
+ .long 0x02000640,0x60000050
+ .long 0x02000690,0x60000050
+ .long 0x020006e0,0x20000050
+
+ .org 0xf0
+#
+# subroutine for loading cards from the reader
+#
+.Lloader:
+ la %r3,.Lorb # r2 = address of orb into r2
+ la %r5,.Lirb # r4 = address of irb
+ la %r6,.Lccws
+ la %r7,20
+.Linit:
+ st %r2,4(%r6) # initialize CCW data addresses
+ la %r2,0x50(%r2)
+ la %r6,8(%r6)
+ bct 7,.Linit
+
+ lctl %c6,%c6,.Lcr6 # set IO subclass mask
+ slr %r2,%r2
+.Lldlp:
+ ssch 0(%r3) # load chunk of 1600 bytes
+ bnz .Llderr
+.Lwait4irq:
+ mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
+ lpsw .Lwaitpsw
+.Lioint:
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwait4irq
+ tsch 0(%r5)
+
+ slr %r0,%r0
+ ic %r0,8(%r5) # get device status
+ chi %r0,8 # channel end ?
+ be .Lcont
+ chi %r0,12 # channel end + device end ?
+ be .Lcont
+
+ l %r0,4(%r5)
+ s %r0,8(%r3) # r0/8 = number of ccws executed
+ mhi %r0,10 # *10 = number of bytes in ccws
+ lh %r3,10(%r5) # get residual count
+ sr %r0,%r3 # #ccws*80-residual=#bytes read
+ ar %r2,%r0
+
+ br %r14 # r2 contains the total size
+
+.Lcont:
+ ahi %r2,0x640 # add 0x640 to total size
+ la %r6,.Lccws
+ la %r7,20
+.Lincr:
+ l %r0,4(%r6) # update CCW data addresses
+ ahi %r0,0x640
+ st %r0,4(%r6)
+ ahi %r6,8
+ bct 7,.Lincr
+
+ b .Lldlp
+.Llderr:
+ lpsw .Lcrash
+
+ .align 8
+.Lorb: .long 0x00000000,0x0080ff00,.Lccws
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6: .long 0xff000000
+.Lloadp:.long 0,0
+ .align 8
+.Lcrash:.long 0x000a0000,0x00000000
+.Lnewpsw:
+ .long 0x00080000,0x80000000+.Lioint
+.Lwaitpsw:
+ .long 0x020a0000,0x80000000+.Lioint
+
+ .align 8
+.Lccws: .rept 19
+ .long 0x02600050,0x00000000
+ .endr
+ .long 0x02200050,0x00000000
+#endif /* CONFIG_IPL_VM */
+
+iplstart:
+ lh %r1,0xb8 # test if subchannel number
+ bct %r1,.Lnoload # is valid
+ l %r1,0xb8 # load ipl subchannel number
+ la %r2,IPL_BS # load start address
+ bas %r14,.Lloader # load rest of ipl image
+ l %r12,.Lparm # pointer to parameter area
+ st %r1,IPL_DEVICE+ARCH_OFFSET-PARMAREA(%r12) # save ipl device number
+
+#
+# load parameter file from ipl device
+#
+.Lagain1:
+ l %r2,.Linitrd # ramdisk loc. is temp
+ bas %r14,.Lloader # load parameter file
+ ltr %r2,%r2 # got anything ?
+ bz .Lnopf
+ chi %r2,895
+ bnh .Lnotrunc
+ la %r2,895
+.Lnotrunc:
+ l %r4,.Linitrd
+ clc 0(3,%r4),.L_hdr # if it is HDRx
+ bz .Lagain1 # skip dataset header
+ clc 0(3,%r4),.L_eof # if it is EOFx
+ bz .Lagain1 # skip dateset trailer
+ la %r5,0(%r4,%r2)
+ lr %r3,%r2
+.Lidebc:
+ tm 0(%r5),0x80 # high order bit set ?
+ bo .Ldocv # yes -> convert from EBCDIC
+ ahi %r5,-1
+ bct %r3,.Lidebc
+ b .Lnocv
+.Ldocv:
+ l %r3,.Lcvtab
+ tr 0(256,%r4),0(%r3) # convert parameters to ascii
+ tr 256(256,%r4),0(%r3)
+ tr 512(256,%r4),0(%r3)
+ tr 768(122,%r4),0(%r3)
+.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+ mvc 0(256,%r3),0(%r4)
+ mvc 256(256,%r3),256(%r4)
+ mvc 512(256,%r3),512(%r4)
+ mvc 768(122,%r3),768(%r4)
+ slr %r0,%r0
+ b .Lcntlp
+.Ldelspc:
+ ic %r0,0(%r2,%r3)
+ chi %r0,0x20 # is it a space ?
+ be .Lcntlp
+ ahi %r2,1
+ b .Leolp
+.Lcntlp:
+ brct %r2,.Ldelspc
+.Leolp:
+ slr %r0,%r0
+ stc %r0,0(%r2,%r3) # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from ipl device
+#
+.Lagain2:
+ l %r2,.Linitrd # addr of ramdisk
+ st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12)
+ bas %r14,.Lloader # load ramdisk
+ st %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of rd
+ ltr %r2,%r2
+ bnz .Lrdcont
+ st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found
+.Lrdcont:
+ l %r2,.Linitrd
+
+ clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
+ bz .Lagain2
+ clc 0(3,%r2),.L_eof
+ bz .Lagain2
+
+#ifdef CONFIG_IPL_VM
+#
+# reset files in VM reader
+#
+ stidp __LC_CPUID # store cpuid
+ tm __LC_CPUID,0xff # running VM ?
+ bno .Lnoreset
+ la %r2,.Lreset
+ lhi %r3,26
+ diag %r2,%r3,8
+ la %r5,.Lirb
+ stsch 0(%r5) # check if irq is pending
+ tm 30(%r5),0x0f # by verifying if any of the
+ bnz .Lwaitforirq # activity or status control
+ tm 31(%r5),0xff # bits is set in the schib
+ bz .Lnoreset
+.Lwaitforirq:
+ mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw
+.Lwaitrdrirq:
+ lpsw .Lrdrwaitpsw
+.Lrdrint:
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwaitrdrirq
+ la %r5,.Lirb
+ tsch 0(%r5)
+.Lnoreset:
+ b .Lnoload
+
+ .align 8
+.Lrdrnewpsw:
+ .long 0x00080000,0x80000000+.Lrdrint
+.Lrdrwaitpsw:
+ .long 0x020a0000,0x80000000+.Lrdrint
+#endif
+
+#
+# everything loaded, go for it
+#
+.Lnoload:
+ l %r1,.Lstartup
+ br %r1
+
+.Linitrd:.long _end + 0x400000 # default address of initrd
+.Lparm: .long PARMAREA
+.Lstartup: .long startup
+.Lcvtab:.long _ebcasc # ebcdic to ascii table
+.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+ .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+ .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
+.L_eof: .long 0xc5d6c600 /* C'EOF' */
+.L_hdr: .long 0xc8c4d900 /* C'HDR' */
+
+#endif /* CONFIG_IPL */
+
+#
+# SALIPL loader support. Based on a patch by Rob van der Heij.
+# This entry point is called directly from the SALIPL loader and
+# doesn't need a builtin ipl record.
+#
+ .org 0x800
+ .globl start
+start:
+ stm %r0,%r15,0x07b0 # store registers
+ basr %r12,%r0
+.base:
+ l %r11,.parm
+ l %r8,.cmd # pointer to command buffer
+
+ ltr %r9,%r9 # do we have SALIPL parameters?
+ bp .sk8x8
+
+ mvc 0(64,%r8),0x00b0 # copy saved registers
+ xc 64(240-64,%r8),0(%r8) # remainder of buffer
+ tr 0(64,%r8),.lowcase
+ b .gotr
+.sk8x8:
+ mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
+.gotr:
+ l %r10,.tbl # EBCDIC to ASCII table
+ tr 0(240,%r8),0(%r10)
+ slr %r0,%r0
+ st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11)
+ st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11)
+ j startup # continue with startup
+.tbl: .long _ebcasc # translate table
+.cmd: .long COMMAND_LINE # address of command line buffer
+.parm: .long PARMAREA
+.lowcase:
+ .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
+ .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+ .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
+ .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
+ .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
+ .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+ .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
+ .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
+ .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
+ .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
+ .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
+ .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
+ .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
+ .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
+ .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
+ .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
+
+ .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
+ .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
+ .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
+ .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
+ .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
+ .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
+ .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
+ .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
+ .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
+ .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi
+ .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
+ .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr
+ .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx
+ .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz
+ .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
+ .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+
+#ifdef CONFIG_64BIT
+#include "head64.S"
+#else
+#include "head31.S"
+#endif
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head31.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head31.S
new file mode 100644
index 0000000000..dc364c1419
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head31.S
@@ -0,0 +1,188 @@
+/*
+ * arch/s390/kernel/head31.S
+ *
+ * Copyright (C) IBM Corp. 2005,2006
+ *
+ * Author(s): Hartmut Penner <hp@de.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Rob van der Heij <rvdhei@iae.nl>
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+#
+# startup-code at 0x10000, running in absolute addressing mode
+# this is called either by the ipl loader or directly by PSW restart
+# or linload or SALIPL
+#
+ .org 0x10000
+startup:basr %r13,0 # get base
+.LPG0: l %r13,0f-.LPG0(%r13)
+ b 0(%r13)
+0: .long startup_continue
+
+#
+# params at 10400 (setup.h)
+#
+ .org PARMAREA
+ .long 0,0 # IPL_DEVICE
+ .long 0,0 # INITRD_START
+ .long 0,0 # INITRD_SIZE
+
+ .org COMMAND_LINE
+ .byte "root=/dev/ram0 ro"
+ .byte 0
+
+ .org 0x11000
+
+startup_continue:
+ basr %r13,0 # get base
+.LPG1: mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0)
+ lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
+ l %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
+ # move IPL device to lowcore
+ mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
+#
+# Setup stack
+#
+ l %r15,.Linittu-.LPG1(%r13)
+ mvc __LC_CURRENT(4),__TI_task(%r15)
+ ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE
+ st %r15,__LC_KERNEL_STACK # set end of kernel stack
+ ahi %r15,-96
+ xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
+#
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
+#
+ l %r14,.Lstartup_init-.LPG1(%r13)
+ basr %r14,%r14
+
+ l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
+#
+# find out if we have an IEEE fpu
+#
+ mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13)
+ efpc %r0,0 # test IEEE extract fpc instruction
+ oi 3(%r12),2 # set IEEE fpu flag
+.Lchkfpu:
+
+#
+# find out if we have the CSP instruction
+#
+ mvc __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13)
+ la %r0,0
+ lr %r1,%r0
+ la %r2,4
+ csp %r0,%r2 # Test CSP instruction
+ oi 3(%r12),8 # set CSP flag
+.Lchkcsp:
+
+#
+# find out if we have the MVPG instruction
+#
+ mvc __LC_PGM_NEW_PSW(8),.Lpcmvpg-.LPG1(%r13)
+ sr %r0,%r0
+ la %r1,0
+ la %r2,0
+ mvpg %r1,%r2 # Test CSP instruction
+ oi 3(%r12),16 # set MVPG flag
+.Lchkmvpg:
+
+#
+# find out if we have the IDTE instruction
+#
+ mvc __LC_PGM_NEW_PSW(8),.Lpcidte-.LPG1(%r13)
+ .long 0xb2b10000 # store facility list
+ tm 0xc8,0x08 # check bit for clearing-by-ASCE
+ bno .Lchkidte-.LPG1(%r13)
+ lhi %r1,2094
+ lhi %r2,0
+ .long 0xb98e2001
+ oi 3(%r12),0x80 # set IDTE flag
+.Lchkidte:
+
+#
+# find out if the diag 0x9c is available
+#
+ mvc __LC_PGM_NEW_PSW(8),.Lpcdiag9c-.LPG1(%r13)
+ stap __LC_CPUID+4 # store cpu address
+ lh %r1,__LC_CPUID+4
+ diag %r1,0,0x9c # test diag 0x9c
+ oi 2(%r12),1 # set diag9c flag
+.Lchkdiag9c:
+
+ lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
+ # virtual and never return ...
+ .align 8
+.Lentry:.long 0x00080000,0x80000000 + _stext
+.Lctl: .long 0x04b50002 # cr0: various things
+ .long 0 # cr1: primary space segment table
+ .long .Lduct # cr2: dispatchable unit control table
+ .long 0 # cr3: instruction authorization
+ .long 0 # cr4: instruction authorization
+ .long .Lduct # cr5: primary-aste origin
+ .long 0 # cr6: I/O interrupts
+ .long 0 # cr7: secondary space segment table
+ .long 0 # cr8: access registers translation
+ .long 0 # cr9: tracing off
+ .long 0 # cr10: tracing off
+ .long 0 # cr11: tracing off
+ .long 0 # cr12: tracing off
+ .long 0 # cr13: home space segment table
+ .long 0xc0000000 # cr14: machine check handling off
+ .long 0 # cr15: linkage stack operations
+.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
+.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
+.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
+.Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte
+.Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c
+.Lmchunk:.long memory_chunk
+.Lmflags:.long machine_flags
+.Lbss_bgn: .long __bss_start
+.Lbss_end: .long _end
+.Lparmaddr: .long PARMAREA
+.Linittu: .long init_thread_union
+.Lstartup_init:
+ .long startup_init
+ .align 64
+.Lduct: .long 0,0,0,0,.Lduald,0,0,0
+ .long 0,0,0,0,0,0,0,0
+ .align 128
+.Lduald:.rept 8
+ .long 0x80000000,0,0,0 # invalid access-list entries
+ .endr
+
+ .org 0x12000
+ .globl _ehead
+_ehead:
+#ifdef CONFIG_SHARED_KERNEL
+ .org 0x100000
+#endif
+
+#
+# startup-code, running in absolute addressing mode
+#
+ .globl _stext
+_stext: basr %r13,0 # get base
+.LPG3:
+# check control registers
+ stctl %c0,%c15,0(%r15)
+ oi 2(%r15),0x40 # enable sigp emergency signal
+ oi 0(%r15),0x10 # switch on low address protection
+ lctl %c0,%c15,0(%r15)
+
+#
+ lam 0,15,.Laregs-.LPG3(%r13) # load access regs needed by uaccess
+ l %r14,.Lstart-.LPG3(%r13)
+ basr %r14,%r14 # call start_kernel
+#
+# We returned from start_kernel ?!? PANIK
+#
+ basr %r13,0
+ lpsw .Ldw-.(%r13) # load disabled wait psw
+#
+ .align 8
+.Ldw: .long 0x000a0000,0x00000000
+.Lstart:.long start_kernel
+.Laregs:.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head64.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head64.S
new file mode 100644
index 0000000000..79dccd206a
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/head64.S
@@ -0,0 +1,261 @@
+/*
+ * arch/s390/kernel/head64.S
+ *
+ * Copyright (C) IBM Corp. 1999,2006
+ *
+ * Author(s): Hartmut Penner <hp@de.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Rob van der Heij <rvdhei@iae.nl>
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+#
+# startup-code at 0x10000, running in absolute addressing mode
+# this is called either by the ipl loader or directly by PSW restart
+# or linload or SALIPL
+#
+ .org 0x10000
+startup:basr %r13,0 # get base
+.LPG0: l %r13,0f-.LPG0(%r13)
+ b 0(%r13)
+0: .long startup_continue
+
+#
+# params at 10400 (setup.h)
+#
+ .org PARMAREA
+ .quad 0 # IPL_DEVICE
+ .quad 0 # INITRD_START
+ .quad 0 # INITRD_SIZE
+
+ .org COMMAND_LINE
+ .byte "root=/dev/ram0 ro"
+ .byte 0
+
+ .org 0x11000
+
+startup_continue:
+ basr %r13,0 # get base
+.LPG1: sll %r13,1 # remove high order bit
+ srl %r13,1
+
+#ifdef CONFIG_ZFCPDUMP
+
+ # check if we have been ipled using zfcp dump:
+
+ tm 0xb9,0x01 # test if subchannel is enabled
+ jno .nodump # subchannel disabled
+ l %r1,0xb8
+ la %r5,.Lipl_schib-.LPG1(%r13)
+ stsch 0(%r5) # get schib of subchannel
+ jne .nodump # schib not available
+ tm 5(%r5),0x01 # devno valid?
+ jno .nodump
+ tm 4(%r5),0x80 # qdio capable device?
+ jno .nodump
+ l %r2,20(%r0) # address of ipl parameter block
+ lhi %r3,0
+ ic %r3,0x148(%r2) # get opt field
+ chi %r3,0x20 # load with dump?
+ jne .nodump
+
+ # store all prefix registers in case of load with dump:
+
+ la %r7,0 # base register for 0 page
+ la %r8,0 # first cpu
+ l %r11,.Lpref_arr_ptr-.LPG1(%r13) # address of prefix array
+ ahi %r11,4 # skip boot cpu
+ lr %r12,%r11
+ ahi %r12,(CONFIG_NR_CPUS*4) # end of prefix array
+ stap .Lcurrent_cpu+2-.LPG1(%r13) # store current cpu addr
+1:
+ cl %r8,.Lcurrent_cpu-.LPG1(%r13) # is ipl cpu ?
+ je 4f # if yes get next cpu
+2:
+ lr %r9,%r7
+ sigp %r9,%r8,0x9 # stop & store status of cpu
+ brc 8,3f # accepted
+ brc 4,4f # status stored: next cpu
+ brc 2,2b # busy: try again
+ brc 1,4f # not op: next cpu
+3:
+ mvc 0(4,%r11),264(%r7) # copy prefix register to prefix array
+ ahi %r11,4 # next element in prefix array
+ clr %r11,%r12
+ je 5f # no more space in prefix array
+4:
+ ahi %r8,1 # next cpu (r8 += 1)
+ cl %r8,.Llast_cpu-.LPG1(%r13) # is last possible cpu ?
+ jl 1b # jump if not last cpu
+5:
+ lhi %r1,2 # mode 2 = esame (dump)
+ j 6f
+ .align 4
+.Lipl_schib:
+ .rept 13
+ .long 0
+ .endr
+.nodump:
+ lhi %r1,1 # mode 1 = esame (normal ipl)
+6:
+#else
+ lhi %r1,1 # mode 1 = esame (normal ipl)
+#endif /* CONFIG_ZFCPDUMP */
+ mvi __LC_AR_MODE_ID,1 # set esame flag
+ slr %r0,%r0 # set cpuid to zero
+ sigp %r1,%r0,0x12 # switch to esame mode
+ sam64 # switch to 64 bit mode
+ lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
+ lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
+ # move IPL device to lowcore
+ mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
+#
+# Setup stack
+#
+ larl %r15,init_thread_union
+ lg %r14,__TI_task(%r15) # cache current in lowcore
+ stg %r14,__LC_CURRENT
+ aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
+ stg %r15,__LC_KERNEL_STACK # set end of kernel stack
+ aghi %r15,-160
+ xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
+#
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
+#
+ brasl %r14,startup_init
+ # set program check new psw mask
+ mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
+ larl %r12,machine_flags
+#
+# find out if we have the MVPG instruction
+#
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ sgr %r0,%r0
+ lghi %r1,0
+ lghi %r2,0
+ mvpg %r1,%r2 # test MVPG instruction
+ oi 7(%r12),16 # set MVPG flag
+0:
+
+#
+# find out if the diag 0x44 works in 64 bit mode
+#
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ diag 0,0,0x44 # test diag 0x44
+ oi 7(%r12),32 # set diag44 flag
+0:
+
+#
+# find out if we have the IDTE instruction
+#
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ .long 0xb2b10000 # store facility list
+ tm 0xc8,0x08 # check bit for clearing-by-ASCE
+ bno 0f-.LPG1(%r13)
+ lhi %r1,2048
+ lhi %r2,0
+ .long 0xb98e2001
+ oi 7(%r12),0x80 # set IDTE flag
+0:
+
+#
+# find out if the diag 0x9c is available
+#
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ stap __LC_CPUID+4 # store cpu address
+ lh %r1,__LC_CPUID+4
+ diag %r1,0,0x9c # test diag 0x9c
+ oi 6(%r12),1 # set diag9c flag
+0:
+
+#
+# find out if we have the MVCOS instruction
+#
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ .short 0xc800 # mvcos 0(%r0),0(%r0),%r0
+ .short 0x0000
+ .short 0x0000
+0: tm 0x8f,0x13 # special-operation exception?
+ bno 1f-.LPG1(%r13) # if yes, MVCOS is present
+ oi 6(%r12),2 # set MVCOS flag
+1:
+
+ lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
+ # virtual and never return ...
+ .align 16
+.Lentry:.quad 0x0000000180000000,_stext
+.Lctl: .quad 0x04b50002 # cr0: various things
+ .quad 0 # cr1: primary space segment table
+ .quad .Lduct # cr2: dispatchable unit control table
+ .quad 0 # cr3: instruction authorization
+ .quad 0 # cr4: instruction authorization
+ .quad .Lduct # cr5: primary-aste origin
+ .quad 0 # cr6: I/O interrupts
+ .quad 0 # cr7: secondary space segment table
+ .quad 0 # cr8: access registers translation
+ .quad 0 # cr9: tracing off
+ .quad 0 # cr10: tracing off
+ .quad 0 # cr11: tracing off
+ .quad 0 # cr12: tracing off
+ .quad 0 # cr13: home space segment table
+ .quad 0xc0000000 # cr14: machine check handling off
+ .quad 0 # cr15: linkage stack operations
+.Lpcmsk:.quad 0x0000000180000000
+.L4malign:.quad 0xffffffffffc00000
+.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
+.Lnop: .long 0x07000700
+#ifdef CONFIG_ZFCPDUMP
+.Lcurrent_cpu:
+ .long 0x0
+.Llast_cpu:
+ .long 0x0000ffff
+.Lpref_arr_ptr:
+ .long zfcpdump_prefix_array
+#endif /* CONFIG_ZFCPDUMP */
+.Lparmaddr:
+ .quad PARMAREA
+ .align 64
+.Lduct: .long 0,0,0,0,.Lduald,0,0,0
+ .long 0,0,0,0,0,0,0,0
+ .align 128
+.Lduald:.rept 8
+ .long 0x80000000,0,0,0 # invalid access-list entries
+ .endr
+
+ .org 0x12000
+ .globl _ehead
+_ehead:
+#ifdef CONFIG_SHARED_KERNEL
+ .org 0x100000
+#endif
+
+#
+# startup-code, running in absolute addressing mode
+#
+ .globl _stext
+_stext: basr %r13,0 # get base
+.LPG3:
+# check control registers
+ stctg %c0,%c15,0(%r15)
+ oi 6(%r15),0x40 # enable sigp emergency signal
+ oi 4(%r15),0x10 # switch on low address proctection
+ lctlg %c0,%c15,0(%r15)
+
+ lam 0,15,.Laregs-.LPG3(%r13) # load acrs needed by uaccess
+ brasl %r14,start_kernel # go to C code
+#
+# We returned from start_kernel ?!? PANIK
+#
+ basr %r13,0
+ lpswe .Ldw-.(%r13) # load disabled wait psw
+
+ .align 8
+.Ldw: .quad 0x0002000180000000,0x0000000000000000
+.Laregs:.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/init_task.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/init_task.c
new file mode 100644
index 0000000000..d494161b05
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/init_task.c
@@ -0,0 +1,45 @@
+/*
+ * arch/s390/kernel/init_task.c
+ *
+ * S390 version
+ *
+ * Derived from "arch/i386/kernel/init_task.c"
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init_task.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+EXPORT_SYMBOL(init_mm);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union
+ __attribute__((__section__(".data.init_task"))) =
+ { INIT_THREAD_INFO(init_task) };
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ipl.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ipl.c
new file mode 100644
index 0000000000..375232c46c
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ipl.c
@@ -0,0 +1,1488 @@
+/*
+ * arch/s390/kernel/ipl.c
+ * ipl/reipl/dump support for Linux on s390.
+ *
+ * Copyright IBM Corp. 2005,2007
+ * Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ * Volker Sameske <sameske@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/ctype.h>
+#include <asm/ipl.h>
+#include <asm/smp.h>
+#include <asm/setup.h>
+#include <asm/cpcmd.h>
+#include <asm/cio.h>
+#include <asm/ebcdic.h>
+#include <asm/reset.h>
+#include <asm/sclp.h>
+
+#define IPL_PARM_BLOCK_VERSION 0
+
+#define IPL_UNKNOWN_STR "unknown"
+#define IPL_CCW_STR "ccw"
+#define IPL_FCP_STR "fcp"
+#define IPL_FCP_DUMP_STR "fcp_dump"
+#define IPL_NSS_STR "nss"
+
+#define DUMP_CCW_STR "ccw"
+#define DUMP_FCP_STR "fcp"
+#define DUMP_NONE_STR "none"
+
+/*
+ * Four shutdown trigger types are supported:
+ * - panic
+ * - halt
+ * - power off
+ * - reipl
+ */
+#define ON_PANIC_STR "on_panic"
+#define ON_HALT_STR "on_halt"
+#define ON_POFF_STR "on_poff"
+#define ON_REIPL_STR "on_reboot"
+
+struct shutdown_action;
+struct shutdown_trigger {
+ char *name;
+ struct shutdown_action *action;
+};
+
+/*
+ * Five shutdown action types are supported:
+ */
+#define SHUTDOWN_ACTION_IPL_STR "ipl"
+#define SHUTDOWN_ACTION_REIPL_STR "reipl"
+#define SHUTDOWN_ACTION_DUMP_STR "dump"
+#define SHUTDOWN_ACTION_VMCMD_STR "vmcmd"
+#define SHUTDOWN_ACTION_STOP_STR "stop"
+
+struct shutdown_action {
+ char *name;
+ void (*fn) (struct shutdown_trigger *trigger);
+ int (*init) (void);
+};
+
+static char *ipl_type_str(enum ipl_type type)
+{
+ switch (type) {
+ case IPL_TYPE_CCW:
+ return IPL_CCW_STR;
+ case IPL_TYPE_FCP:
+ return IPL_FCP_STR;
+ case IPL_TYPE_FCP_DUMP:
+ return IPL_FCP_DUMP_STR;
+ case IPL_TYPE_NSS:
+ return IPL_NSS_STR;
+ case IPL_TYPE_UNKNOWN:
+ default:
+ return IPL_UNKNOWN_STR;
+ }
+}
+
+enum dump_type {
+ DUMP_TYPE_NONE = 1,
+ DUMP_TYPE_CCW = 2,
+ DUMP_TYPE_FCP = 4,
+};
+
+static char *dump_type_str(enum dump_type type)
+{
+ switch (type) {
+ case DUMP_TYPE_NONE:
+ return DUMP_NONE_STR;
+ case DUMP_TYPE_CCW:
+ return DUMP_CCW_STR;
+ case DUMP_TYPE_FCP:
+ return DUMP_FCP_STR;
+ default:
+ return NULL;
+ }
+}
+
+/*
+ * Must be in data section since the bss section
+ * is not cleared when these are accessed.
+ */
+static u16 ipl_devno __attribute__((__section__(".data"))) = 0;
+u32 ipl_flags __attribute__((__section__(".data"))) = 0;
+
+enum ipl_method {
+ REIPL_METHOD_CCW_CIO,
+ REIPL_METHOD_CCW_DIAG,
+ REIPL_METHOD_CCW_VM,
+ REIPL_METHOD_FCP_RO_DIAG,
+ REIPL_METHOD_FCP_RW_DIAG,
+ REIPL_METHOD_FCP_RO_VM,
+ REIPL_METHOD_FCP_DUMP,
+ REIPL_METHOD_NSS,
+ REIPL_METHOD_DEFAULT,
+};
+
+enum dump_method {
+ DUMP_METHOD_NONE,
+ DUMP_METHOD_CCW_CIO,
+ DUMP_METHOD_CCW_DIAG,
+ DUMP_METHOD_CCW_VM,
+ DUMP_METHOD_FCP_DIAG,
+};
+
+static int diag308_set_works = 0;
+
+static int reipl_capabilities = IPL_TYPE_UNKNOWN;
+
+static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
+static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT;
+static struct ipl_parameter_block *reipl_block_fcp;
+static struct ipl_parameter_block *reipl_block_ccw;
+
+static char reipl_nss_name[NSS_NAME_SIZE + 1];
+
+static int dump_capabilities = DUMP_TYPE_NONE;
+static enum dump_type dump_type = DUMP_TYPE_NONE;
+static enum dump_method dump_method = DUMP_METHOD_NONE;
+static struct ipl_parameter_block *dump_block_fcp;
+static struct ipl_parameter_block *dump_block_ccw;
+
+static struct sclp_ipl_info sclp_ipl_info;
+
+int diag308(unsigned long subcode, void *addr)
+{
+ register unsigned long _addr asm("0") = (unsigned long) addr;
+ register unsigned long _rc asm("1") = 0;
+
+ asm volatile(
+ " diag %0,%2,0x308\n"
+ "0:\n"
+ EX_TABLE(0b,0b)
+ : "+d" (_addr), "+d" (_rc)
+ : "d" (subcode) : "cc", "memory");
+ return _rc;
+}
+EXPORT_SYMBOL_GPL(diag308);
+
+/* SYSFS */
+
+#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
+static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ char *page) \
+{ \
+ return sprintf(page, _format, _value); \
+} \
+static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
+ __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
+
+#define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \
+static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ char *page) \
+{ \
+ return sprintf(page, _fmt_out, \
+ (unsigned long long) _value); \
+} \
+static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ unsigned long long value; \
+ if (sscanf(buf, _fmt_in, &value) != 1) \
+ return -EINVAL; \
+ _value = value; \
+ return len; \
+} \
+static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
+ __ATTR(_name,(S_IRUGO | S_IWUSR), \
+ sys_##_prefix##_##_name##_show, \
+ sys_##_prefix##_##_name##_store);
+
+#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
+static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ char *page) \
+{ \
+ return sprintf(page, _fmt_out, _value); \
+} \
+static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ strncpy(_value, buf, sizeof(_value) - 1); \
+ strstrip(_value); \
+ return len; \
+} \
+static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
+ __ATTR(_name,(S_IRUGO | S_IWUSR), \
+ sys_##_prefix##_##_name##_show, \
+ sys_##_prefix##_##_name##_store);
+
+static void make_attrs_ro(struct attribute **attrs)
+{
+ while (*attrs) {
+ (*attrs)->mode = S_IRUGO;
+ attrs++;
+ }
+}
+
+/*
+ * ipl section
+ */
+
+static __init enum ipl_type get_ipl_type(void)
+{
+ struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
+
+ if (ipl_flags & IPL_NSS_VALID)
+ return IPL_TYPE_NSS;
+ if (!(ipl_flags & IPL_DEVNO_VALID))
+ return IPL_TYPE_UNKNOWN;
+ if (!(ipl_flags & IPL_PARMBLOCK_VALID))
+ return IPL_TYPE_CCW;
+ if (ipl->hdr.version > IPL_MAX_SUPPORTED_VERSION)
+ return IPL_TYPE_UNKNOWN;
+ if (ipl->hdr.pbt != DIAG308_IPL_TYPE_FCP)
+ return IPL_TYPE_UNKNOWN;
+ if (ipl->ipl_info.fcp.opt == DIAG308_IPL_OPT_DUMP)
+ return IPL_TYPE_FCP_DUMP;
+ return IPL_TYPE_FCP;
+}
+
+struct ipl_info ipl_info;
+EXPORT_SYMBOL_GPL(ipl_info);
+
+static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *page)
+{
+ return sprintf(page, "%s\n", ipl_type_str(ipl_info.type));
+}
+
+static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
+
+static ssize_t sys_ipl_device_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
+
+ switch (ipl_info.type) {
+ case IPL_TYPE_CCW:
+ return sprintf(page, "0.0.%04x\n", ipl_devno);
+ case IPL_TYPE_FCP:
+ case IPL_TYPE_FCP_DUMP:
+ return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
+ default:
+ return 0;
+ }
+}
+
+static struct kobj_attribute sys_ipl_device_attr =
+ __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
+
+static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ unsigned int size = IPL_PARMBLOCK_SIZE;
+
+ if (off > size)
+ return 0;
+ if (off + count > size)
+ count = size - off;
+ memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count);
+ return count;
+}
+
+static struct bin_attribute ipl_parameter_attr = {
+ .attr = {
+ .name = "binary_parameter",
+ .mode = S_IRUGO,
+ },
+ .size = PAGE_SIZE,
+ .read = &ipl_parameter_read,
+};
+
+static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
+ void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
+
+ if (off > size)
+ return 0;
+ if (off + count > size)
+ count = size - off;
+ memcpy(buf, scp_data + off, count);
+ return count;
+}
+
+static struct bin_attribute ipl_scp_data_attr = {
+ .attr = {
+ .name = "scp_data",
+ .mode = S_IRUGO,
+ },
+ .size = PAGE_SIZE,
+ .read = ipl_scp_data_read,
+};
+
+/* FCP ipl device attributes */
+
+DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n", (unsigned long long)
+ IPL_PARMBLOCK_START->ipl_info.fcp.wwpn);
+DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n", (unsigned long long)
+ IPL_PARMBLOCK_START->ipl_info.fcp.lun);
+DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n", (unsigned long long)
+ IPL_PARMBLOCK_START->ipl_info.fcp.bootprog);
+DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n", (unsigned long long)
+ IPL_PARMBLOCK_START->ipl_info.fcp.br_lba);
+
+static struct attribute *ipl_fcp_attrs[] = {
+ &sys_ipl_type_attr.attr,
+ &sys_ipl_device_attr.attr,
+ &sys_ipl_fcp_wwpn_attr.attr,
+ &sys_ipl_fcp_lun_attr.attr,
+ &sys_ipl_fcp_bootprog_attr.attr,
+ &sys_ipl_fcp_br_lba_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ipl_fcp_attr_group = {
+ .attrs = ipl_fcp_attrs,
+};
+
+/* CCW ipl device attributes */
+
+static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ char loadparm[LOADPARM_LEN + 1] = {};
+
+ if (!sclp_ipl_info.is_valid)
+ return sprintf(page, "#unknown#\n");
+ memcpy(loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN);
+ EBCASC(loadparm, LOADPARM_LEN);
+ strstrip(loadparm);
+ return sprintf(page, "%s\n", loadparm);
+}
+
+static struct kobj_attribute sys_ipl_ccw_loadparm_attr =
+ __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL);
+
+static struct attribute *ipl_ccw_attrs[] = {
+ &sys_ipl_type_attr.attr,
+ &sys_ipl_device_attr.attr,
+ &sys_ipl_ccw_loadparm_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ipl_ccw_attr_group = {
+ .attrs = ipl_ccw_attrs,
+};
+
+/* NSS ipl device attributes */
+
+DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
+
+static struct attribute *ipl_nss_attrs[] = {
+ &sys_ipl_type_attr.attr,
+ &sys_ipl_nss_name_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ipl_nss_attr_group = {
+ .attrs = ipl_nss_attrs,
+};
+
+/* UNKNOWN ipl device attributes */
+
+static struct attribute *ipl_unknown_attrs[] = {
+ &sys_ipl_type_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ipl_unknown_attr_group = {
+ .attrs = ipl_unknown_attrs,
+};
+
+static struct kset *ipl_kset;
+
+static int __init ipl_register_fcp_files(void)
+{
+ int rc;
+
+ rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
+ if (rc)
+ goto out;
+ rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
+ if (rc)
+ goto out_ipl_parm;
+ rc = sysfs_create_bin_file(&ipl_kset->kobj, &ipl_scp_data_attr);
+ if (!rc)
+ goto out;
+
+ sysfs_remove_bin_file(&ipl_kset->kobj, &ipl_parameter_attr);
+
+out_ipl_parm:
+ sysfs_remove_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
+out:
+ return rc;
+}
+
+static void ipl_run(struct shutdown_trigger *trigger)
+{
+ diag308(DIAG308_IPL, NULL);
+ if (MACHINE_IS_VM)
+ __cpcmd("IPL", NULL, 0, NULL);
+ else if (ipl_info.type == IPL_TYPE_CCW)
+ reipl_ccw_dev(&ipl_info.data.ccw.dev_id);
+}
+
+static int __init ipl_init(void)
+{
+ int rc;
+
+ ipl_kset = kset_create_and_add("ipl", NULL, firmware_kobj);
+ if (!ipl_kset) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ switch (ipl_info.type) {
+ case IPL_TYPE_CCW:
+ rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group);
+ break;
+ case IPL_TYPE_FCP:
+ case IPL_TYPE_FCP_DUMP:
+ rc = ipl_register_fcp_files();
+ break;
+ case IPL_TYPE_NSS:
+ rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nss_attr_group);
+ break;
+ default:
+ rc = sysfs_create_group(&ipl_kset->kobj,
+ &ipl_unknown_attr_group);
+ break;
+ }
+out:
+ if (rc)
+ panic("ipl_init failed: rc = %i\n", rc);
+
+ return 0;
+}
+
+static struct shutdown_action __refdata ipl_action = {
+ .name = SHUTDOWN_ACTION_IPL_STR,
+ .fn = ipl_run,
+ .init = ipl_init,
+};
+
+/*
+ * reipl shutdown action: Reboot Linux on shutdown.
+ */
+
+/* FCP reipl device attributes */
+
+DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n",
+ reipl_block_fcp->ipl_info.fcp.wwpn);
+DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n",
+ reipl_block_fcp->ipl_info.fcp.lun);
+DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n",
+ reipl_block_fcp->ipl_info.fcp.bootprog);
+DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n",
+ reipl_block_fcp->ipl_info.fcp.br_lba);
+DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
+ reipl_block_fcp->ipl_info.fcp.devno);
+
+static struct attribute *reipl_fcp_attrs[] = {
+ &sys_reipl_fcp_device_attr.attr,
+ &sys_reipl_fcp_wwpn_attr.attr,
+ &sys_reipl_fcp_lun_attr.attr,
+ &sys_reipl_fcp_bootprog_attr.attr,
+ &sys_reipl_fcp_br_lba_attr.attr,
+ NULL,
+};
+
+static struct attribute_group reipl_fcp_attr_group = {
+ .name = IPL_FCP_STR,
+ .attrs = reipl_fcp_attrs,
+};
+
+/* CCW reipl device attributes */
+
+DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
+ reipl_block_ccw->ipl_info.ccw.devno);
+
+static void reipl_get_ascii_loadparm(char *loadparm)
+{
+ memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param,
+ LOADPARM_LEN);
+ EBCASC(loadparm, LOADPARM_LEN);
+ loadparm[LOADPARM_LEN] = 0;
+ strstrip(loadparm);
+}
+
+static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ char buf[LOADPARM_LEN + 1];
+
+ reipl_get_ascii_loadparm(buf);
+ return sprintf(page, "%s\n", buf);
+}
+
+static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t len)
+{
+ int i, lp_len;
+
+ /* ignore trailing newline */
+ lp_len = len;
+ if ((len > 0) && (buf[len - 1] == '\n'))
+ lp_len--;
+ /* loadparm can have max 8 characters and must not start with a blank */
+ if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' ')))
+ return -EINVAL;
+ /* loadparm can only contain "a-z,A-Z,0-9,SP,." */
+ for (i = 0; i < lp_len; i++) {
+ if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') ||
+ (buf[i] == '.'))
+ continue;
+ return -EINVAL;
+ }
+ /* initialize loadparm with blanks */
+ memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN);
+ /* copy and convert to ebcdic */
+ memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len);
+ ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN);
+ return len;
+}
+
+static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
+ __ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
+ reipl_ccw_loadparm_store);
+
+static struct attribute *reipl_ccw_attrs[] = {
+ &sys_reipl_ccw_device_attr.attr,
+ &sys_reipl_ccw_loadparm_attr.attr,
+ NULL,
+};
+
+static struct attribute_group reipl_ccw_attr_group = {
+ .name = IPL_CCW_STR,
+ .attrs = reipl_ccw_attrs,
+};
+
+
+/* NSS reipl device attributes */
+
+DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
+
+static struct attribute *reipl_nss_attrs[] = {
+ &sys_reipl_nss_name_attr.attr,
+ NULL,
+};
+
+static struct attribute_group reipl_nss_attr_group = {
+ .name = IPL_NSS_STR,
+ .attrs = reipl_nss_attrs,
+};
+
+/* reipl type */
+
+static int reipl_set_type(enum ipl_type type)
+{
+ if (!(reipl_capabilities & type))
+ return -EINVAL;
+
+ switch(type) {
+ case IPL_TYPE_CCW:
+ if (diag308_set_works)
+ reipl_method = REIPL_METHOD_CCW_DIAG;
+ else if (MACHINE_IS_VM)
+ reipl_method = REIPL_METHOD_CCW_VM;
+ else
+ reipl_method = REIPL_METHOD_CCW_CIO;
+ break;
+ case IPL_TYPE_FCP:
+ if (diag308_set_works)
+ reipl_method = REIPL_METHOD_FCP_RW_DIAG;
+ else if (MACHINE_IS_VM)
+ reipl_method = REIPL_METHOD_FCP_RO_VM;
+ else
+ reipl_method = REIPL_METHOD_FCP_RO_DIAG;
+ break;
+ case IPL_TYPE_FCP_DUMP:
+ reipl_method = REIPL_METHOD_FCP_DUMP;
+ break;
+ case IPL_TYPE_NSS:
+ reipl_method = REIPL_METHOD_NSS;
+ break;
+ case IPL_TYPE_UNKNOWN:
+ reipl_method = REIPL_METHOD_DEFAULT;
+ break;
+ default:
+ BUG();
+ }
+ reipl_type = type;
+ return 0;
+}
+
+static ssize_t reipl_type_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ return sprintf(page, "%s\n", ipl_type_str(reipl_type));
+}
+
+static ssize_t reipl_type_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t len)
+{
+ int rc = -EINVAL;
+
+ if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
+ rc = reipl_set_type(IPL_TYPE_CCW);
+ else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
+ rc = reipl_set_type(IPL_TYPE_FCP);
+ else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
+ rc = reipl_set_type(IPL_TYPE_NSS);
+ return (rc != 0) ? rc : len;
+}
+
+static struct kobj_attribute reipl_type_attr =
+ __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store);
+
+static struct kset *reipl_kset;
+
+void reipl_run(struct shutdown_trigger *trigger)
+{
+ struct ccw_dev_id devid;
+ static char buf[100];
+ char loadparm[LOADPARM_LEN + 1];
+
+ switch (reipl_method) {
+ case REIPL_METHOD_CCW_CIO:
+ devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
+ devid.ssid = 0;
+ reipl_ccw_dev(&devid);
+ break;
+ case REIPL_METHOD_CCW_VM:
+ reipl_get_ascii_loadparm(loadparm);
+ if (strlen(loadparm) == 0)
+ sprintf(buf, "IPL %X CLEAR",
+ reipl_block_ccw->ipl_info.ccw.devno);
+ else
+ sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
+ reipl_block_ccw->ipl_info.ccw.devno, loadparm);
+ __cpcmd(buf, NULL, 0, NULL);
+ break;
+ case REIPL_METHOD_CCW_DIAG:
+ diag308(DIAG308_SET, reipl_block_ccw);
+ diag308(DIAG308_IPL, NULL);
+ break;
+ case REIPL_METHOD_FCP_RW_DIAG:
+ diag308(DIAG308_SET, reipl_block_fcp);
+ diag308(DIAG308_IPL, NULL);
+ break;
+ case REIPL_METHOD_FCP_RO_DIAG:
+ diag308(DIAG308_IPL, NULL);
+ break;
+ case REIPL_METHOD_FCP_RO_VM:
+ __cpcmd("IPL", NULL, 0, NULL);
+ break;
+ case REIPL_METHOD_NSS:
+ sprintf(buf, "IPL %s", reipl_nss_name);
+ __cpcmd(buf, NULL, 0, NULL);
+ break;
+ case REIPL_METHOD_DEFAULT:
+ if (MACHINE_IS_VM)
+ __cpcmd("IPL", NULL, 0, NULL);
+ diag308(DIAG308_IPL, NULL);
+ break;
+ case REIPL_METHOD_FCP_DUMP:
+ default:
+ break;
+ }
+ disabled_wait((unsigned long) __builtin_return_address(0));
+}
+
+static void __init reipl_probe(void)
+{
+ void *buffer;
+
+ buffer = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!buffer)
+ return;
+ if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK)
+ diag308_set_works = 1;
+ free_page((unsigned long)buffer);
+}
+
+static int __init reipl_nss_init(void)
+{
+ int rc;
+
+ if (!MACHINE_IS_VM)
+ return 0;
+ rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group);
+ if (rc)
+ return rc;
+ strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
+ reipl_capabilities |= IPL_TYPE_NSS;
+ return 0;
+}
+
+static int __init reipl_ccw_init(void)
+{
+ int rc;
+
+ reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!reipl_block_ccw)
+ return -ENOMEM;
+ rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group);
+ if (rc) {
+ free_page((unsigned long)reipl_block_ccw);
+ return rc;
+ }
+ reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
+ reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
+ reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
+ reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
+ reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID;
+ /* check if read scp info worked and set loadparm */
+ if (sclp_ipl_info.is_valid)
+ memcpy(reipl_block_ccw->ipl_info.ccw.load_param,
+ &sclp_ipl_info.loadparm, LOADPARM_LEN);
+ else
+ /* read scp info failed: set empty loadparm (EBCDIC blanks) */
+ memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40,
+ LOADPARM_LEN);
+ if (!MACHINE_IS_VM && !diag308_set_works)
+ sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO;
+ if (ipl_info.type == IPL_TYPE_CCW)
+ reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
+ reipl_capabilities |= IPL_TYPE_CCW;
+ return 0;
+}
+
+static int __init reipl_fcp_init(void)
+{
+ int rc;
+
+ if ((!diag308_set_works) && (ipl_info.type != IPL_TYPE_FCP))
+ return 0;
+ if ((!diag308_set_works) && (ipl_info.type == IPL_TYPE_FCP))
+ make_attrs_ro(reipl_fcp_attrs);
+
+ reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!reipl_block_fcp)
+ return -ENOMEM;
+ rc = sysfs_create_group(&reipl_kset->kobj, &reipl_fcp_attr_group);
+ if (rc) {
+ free_page((unsigned long)reipl_block_fcp);
+ return rc;
+ }
+ if (ipl_info.type == IPL_TYPE_FCP) {
+ memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE);
+ } else {
+ reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
+ reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
+ reipl_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;
+ reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
+ reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL;
+ }
+ reipl_capabilities |= IPL_TYPE_FCP;
+ return 0;
+}
+
+static int __init reipl_init(void)
+{
+ int rc;
+
+ reipl_kset = kset_create_and_add("reipl", NULL, firmware_kobj);
+ if (!reipl_kset)
+ return -ENOMEM;
+ rc = sysfs_create_file(&reipl_kset->kobj, &reipl_type_attr.attr);
+ if (rc) {
+ kset_unregister(reipl_kset);
+ return rc;
+ }
+ rc = reipl_ccw_init();
+ if (rc)
+ return rc;
+ rc = reipl_fcp_init();
+ if (rc)
+ return rc;
+ rc = reipl_nss_init();
+ if (rc)
+ return rc;
+ rc = reipl_set_type(ipl_info.type);
+ if (rc)
+ return rc;
+ return 0;
+}
+
+static struct shutdown_action __refdata reipl_action = {
+ .name = SHUTDOWN_ACTION_REIPL_STR,
+ .fn = reipl_run,
+ .init = reipl_init,
+};
+
+/*
+ * dump shutdown action: Dump Linux on shutdown.
+ */
+
+/* FCP dump device attributes */
+
+DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n",
+ dump_block_fcp->ipl_info.fcp.wwpn);
+DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n",
+ dump_block_fcp->ipl_info.fcp.lun);
+DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n",
+ dump_block_fcp->ipl_info.fcp.bootprog);
+DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n",
+ dump_block_fcp->ipl_info.fcp.br_lba);
+DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n",
+ dump_block_fcp->ipl_info.fcp.devno);
+
+static struct attribute *dump_fcp_attrs[] = {
+ &sys_dump_fcp_device_attr.attr,
+ &sys_dump_fcp_wwpn_attr.attr,
+ &sys_dump_fcp_lun_attr.attr,
+ &sys_dump_fcp_bootprog_attr.attr,
+ &sys_dump_fcp_br_lba_attr.attr,
+ NULL,
+};
+
+static struct attribute_group dump_fcp_attr_group = {
+ .name = IPL_FCP_STR,
+ .attrs = dump_fcp_attrs,
+};
+
+/* CCW dump device attributes */
+
+DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
+ dump_block_ccw->ipl_info.ccw.devno);
+
+static struct attribute *dump_ccw_attrs[] = {
+ &sys_dump_ccw_device_attr.attr,
+ NULL,
+};
+
+static struct attribute_group dump_ccw_attr_group = {
+ .name = IPL_CCW_STR,
+ .attrs = dump_ccw_attrs,
+};
+
+/* dump type */
+
+static int dump_set_type(enum dump_type type)
+{
+ if (!(dump_capabilities & type))
+ return -EINVAL;
+ switch (type) {
+ case DUMP_TYPE_CCW:
+ if (diag308_set_works)
+ dump_method = DUMP_METHOD_CCW_DIAG;
+ else if (MACHINE_IS_VM)
+ dump_method = DUMP_METHOD_CCW_VM;
+ else
+ dump_method = DUMP_METHOD_CCW_CIO;
+ break;
+ case DUMP_TYPE_FCP:
+ dump_method = DUMP_METHOD_FCP_DIAG;
+ break;
+ default:
+ dump_method = DUMP_METHOD_NONE;
+ }
+ dump_type = type;
+ return 0;
+}
+
+static ssize_t dump_type_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ return sprintf(page, "%s\n", dump_type_str(dump_type));
+}
+
+static ssize_t dump_type_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t len)
+{
+ int rc = -EINVAL;
+
+ if (strncmp(buf, DUMP_NONE_STR, strlen(DUMP_NONE_STR)) == 0)
+ rc = dump_set_type(DUMP_TYPE_NONE);
+ else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
+ rc = dump_set_type(DUMP_TYPE_CCW);
+ else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
+ rc = dump_set_type(DUMP_TYPE_FCP);
+ return (rc != 0) ? rc : len;
+}
+
+static struct kobj_attribute dump_type_attr =
+ __ATTR(dump_type, 0644, dump_type_show, dump_type_store);
+
+static struct kset *dump_kset;
+
+static void dump_run(struct shutdown_trigger *trigger)
+{
+ struct ccw_dev_id devid;
+ static char buf[100];
+
+ switch (dump_method) {
+ case DUMP_METHOD_CCW_CIO:
+ smp_send_stop();
+ devid.devno = dump_block_ccw->ipl_info.ccw.devno;
+ devid.ssid = 0;
+ reipl_ccw_dev(&devid);
+ break;
+ case DUMP_METHOD_CCW_VM:
+ smp_send_stop();
+ sprintf(buf, "STORE STATUS");
+ __cpcmd(buf, NULL, 0, NULL);
+ sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno);
+ __cpcmd(buf, NULL, 0, NULL);
+ break;
+ case DUMP_METHOD_CCW_DIAG:
+ diag308(DIAG308_SET, dump_block_ccw);
+ diag308(DIAG308_DUMP, NULL);
+ break;
+ case DUMP_METHOD_FCP_DIAG:
+ diag308(DIAG308_SET, dump_block_fcp);
+ diag308(DIAG308_DUMP, NULL);
+ break;
+ case DUMP_METHOD_NONE:
+ default:
+ return;
+ }
+ printk(KERN_EMERG "Dump failed!\n");
+}
+
+static int __init dump_ccw_init(void)
+{
+ int rc;
+
+ dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!dump_block_ccw)
+ return -ENOMEM;
+ rc = sysfs_create_group(&dump_kset->kobj, &dump_ccw_attr_group);
+ if (rc) {
+ free_page((unsigned long)dump_block_ccw);
+ return rc;
+ }
+ dump_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN;
+ dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION;
+ dump_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN;
+ dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW;
+ dump_capabilities |= DUMP_TYPE_CCW;
+ return 0;
+}
+
+static int __init dump_fcp_init(void)
+{
+ int rc;
+
+ if (!sclp_ipl_info.has_dump)
+ return 0; /* LDIPL DUMP is not installed */
+ if (!diag308_set_works)
+ return 0;
+ dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!dump_block_fcp)
+ return -ENOMEM;
+ rc = sysfs_create_group(&dump_kset->kobj, &dump_fcp_attr_group);
+ if (rc) {
+ free_page((unsigned long)dump_block_fcp);
+ return rc;
+ }
+ dump_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN;
+ dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION;
+ dump_block_fcp->hdr.blk0_len = IPL_PARM_BLK0_FCP_LEN;
+ dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP;
+ dump_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_DUMP;
+ dump_capabilities |= DUMP_TYPE_FCP;
+ return 0;
+}
+
+static int __init dump_init(void)
+{
+ int rc;
+
+ dump_kset = kset_create_and_add("dump", NULL, firmware_kobj);
+ if (!dump_kset)
+ return -ENOMEM;
+ rc = sysfs_create_file(&dump_kset->kobj, &dump_type_attr.attr);
+ if (rc) {
+ kset_unregister(dump_kset);
+ return rc;
+ }
+ rc = dump_ccw_init();
+ if (rc)
+ return rc;
+ rc = dump_fcp_init();
+ if (rc)
+ return rc;
+ dump_set_type(DUMP_TYPE_NONE);
+ return 0;
+}
+
+static struct shutdown_action __refdata dump_action = {
+ .name = SHUTDOWN_ACTION_DUMP_STR,
+ .fn = dump_run,
+ .init = dump_init,
+};
+
+/*
+ * vmcmd shutdown action: Trigger vm command on shutdown.
+ */
+
+static char vmcmd_on_reboot[128];
+static char vmcmd_on_panic[128];
+static char vmcmd_on_halt[128];
+static char vmcmd_on_poff[128];
+
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_reboot, "%s\n", "%s\n", vmcmd_on_reboot);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_panic, "%s\n", "%s\n", vmcmd_on_panic);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_halt, "%s\n", "%s\n", vmcmd_on_halt);
+DEFINE_IPL_ATTR_STR_RW(vmcmd, on_poff, "%s\n", "%s\n", vmcmd_on_poff);
+
+static struct attribute *vmcmd_attrs[] = {
+ &sys_vmcmd_on_reboot_attr.attr,
+ &sys_vmcmd_on_panic_attr.attr,
+ &sys_vmcmd_on_halt_attr.attr,
+ &sys_vmcmd_on_poff_attr.attr,
+ NULL,
+};
+
+static struct attribute_group vmcmd_attr_group = {
+ .attrs = vmcmd_attrs,
+};
+
+static struct kset *vmcmd_kset;
+
+static void vmcmd_run(struct shutdown_trigger *trigger)
+{
+ char *cmd, *next_cmd;
+
+ if (strcmp(trigger->name, ON_REIPL_STR) == 0)
+ cmd = vmcmd_on_reboot;
+ else if (strcmp(trigger->name, ON_PANIC_STR) == 0)
+ cmd = vmcmd_on_panic;
+ else if (strcmp(trigger->name, ON_HALT_STR) == 0)
+ cmd = vmcmd_on_halt;
+ else if (strcmp(trigger->name, ON_POFF_STR) == 0)
+ cmd = vmcmd_on_poff;
+ else
+ return;
+
+ if (strlen(cmd) == 0)
+ return;
+ do {
+ next_cmd = strchr(cmd, '\n');
+ if (next_cmd) {
+ next_cmd[0] = 0;
+ next_cmd += 1;
+ }
+ __cpcmd(cmd, NULL, 0, NULL);
+ cmd = next_cmd;
+ } while (cmd != NULL);
+}
+
+static int vmcmd_init(void)
+{
+ if (!MACHINE_IS_VM)
+ return -ENOTSUPP;
+ vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj);
+ if (!vmcmd_kset)
+ return -ENOMEM;
+ return sysfs_create_group(&vmcmd_kset->kobj, &vmcmd_attr_group);
+}
+
+static struct shutdown_action vmcmd_action = {SHUTDOWN_ACTION_VMCMD_STR,
+ vmcmd_run, vmcmd_init};
+
+/*
+ * stop shutdown action: Stop Linux on shutdown.
+ */
+
+static void stop_run(struct shutdown_trigger *trigger)
+{
+ if (strcmp(trigger->name, ON_PANIC_STR) == 0)
+ disabled_wait((unsigned long) __builtin_return_address(0));
+ else {
+ signal_processor(smp_processor_id(), sigp_stop);
+ for (;;);
+ }
+}
+
+static struct shutdown_action stop_action = {SHUTDOWN_ACTION_STOP_STR,
+ stop_run, NULL};
+
+/* action list */
+
+static struct shutdown_action *shutdown_actions_list[] = {
+ &ipl_action, &reipl_action, &dump_action, &vmcmd_action, &stop_action};
+#define SHUTDOWN_ACTIONS_COUNT (sizeof(shutdown_actions_list) / sizeof(void *))
+
+/*
+ * Trigger section
+ */
+
+static struct kset *shutdown_actions_kset;
+
+static int set_trigger(const char *buf, struct shutdown_trigger *trigger,
+ size_t len)
+{
+ int i;
+ for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
+ if (!shutdown_actions_list[i])
+ continue;
+ if (strncmp(buf, shutdown_actions_list[i]->name,
+ strlen(shutdown_actions_list[i]->name)) == 0) {
+ trigger->action = shutdown_actions_list[i];
+ return len;
+ }
+ }
+ return -EINVAL;
+}
+
+/* on reipl */
+
+static struct shutdown_trigger on_reboot_trigger = {ON_REIPL_STR,
+ &reipl_action};
+
+static ssize_t on_reboot_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ return sprintf(page, "%s\n", on_reboot_trigger.action->name);
+}
+
+static ssize_t on_reboot_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t len)
+{
+ return set_trigger(buf, &on_reboot_trigger, len);
+}
+
+static struct kobj_attribute on_reboot_attr =
+ __ATTR(on_reboot, 0644, on_reboot_show, on_reboot_store);
+
+static void do_machine_restart(char *__unused)
+{
+ smp_send_stop();
+ on_reboot_trigger.action->fn(&on_reboot_trigger);
+ reipl_run(NULL);
+}
+void (*_machine_restart)(char *command) = do_machine_restart;
+
+/* on panic */
+
+static struct shutdown_trigger on_panic_trigger = {ON_PANIC_STR, &stop_action};
+
+static ssize_t on_panic_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ return sprintf(page, "%s\n", on_panic_trigger.action->name);
+}
+
+static ssize_t on_panic_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t len)
+{
+ return set_trigger(buf, &on_panic_trigger, len);
+}
+
+static struct kobj_attribute on_panic_attr =
+ __ATTR(on_panic, 0644, on_panic_show, on_panic_store);
+
+static void do_panic(void)
+{
+ on_panic_trigger.action->fn(&on_panic_trigger);
+ stop_run(&on_panic_trigger);
+}
+
+/* on halt */
+
+static struct shutdown_trigger on_halt_trigger = {ON_HALT_STR, &stop_action};
+
+static ssize_t on_halt_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ return sprintf(page, "%s\n", on_halt_trigger.action->name);
+}
+
+static ssize_t on_halt_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t len)
+{
+ return set_trigger(buf, &on_halt_trigger, len);
+}
+
+static struct kobj_attribute on_halt_attr =
+ __ATTR(on_halt, 0644, on_halt_show, on_halt_store);
+
+
+static void do_machine_halt(void)
+{
+ smp_send_stop();
+ on_halt_trigger.action->fn(&on_halt_trigger);
+ stop_run(&on_halt_trigger);
+}
+void (*_machine_halt)(void) = do_machine_halt;
+
+/* on power off */
+
+static struct shutdown_trigger on_poff_trigger = {ON_POFF_STR, &stop_action};
+
+static ssize_t on_poff_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ return sprintf(page, "%s\n", on_poff_trigger.action->name);
+}
+
+static ssize_t on_poff_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t len)
+{
+ return set_trigger(buf, &on_poff_trigger, len);
+}
+
+static struct kobj_attribute on_poff_attr =
+ __ATTR(on_poff, 0644, on_poff_show, on_poff_store);
+
+
+static void do_machine_power_off(void)
+{
+ smp_send_stop();
+ on_poff_trigger.action->fn(&on_poff_trigger);
+ stop_run(&on_poff_trigger);
+}
+void (*_machine_power_off)(void) = do_machine_power_off;
+
+static void __init shutdown_triggers_init(void)
+{
+ shutdown_actions_kset = kset_create_and_add("shutdown_actions", NULL,
+ firmware_kobj);
+ if (!shutdown_actions_kset)
+ goto fail;
+ if (sysfs_create_file(&shutdown_actions_kset->kobj,
+ &on_reboot_attr.attr))
+ goto fail;
+ if (sysfs_create_file(&shutdown_actions_kset->kobj,
+ &on_panic_attr.attr))
+ goto fail;
+ if (sysfs_create_file(&shutdown_actions_kset->kobj,
+ &on_halt_attr.attr))
+ goto fail;
+ if (sysfs_create_file(&shutdown_actions_kset->kobj,
+ &on_poff_attr.attr))
+ goto fail;
+
+ return;
+fail:
+ panic("shutdown_triggers_init failed\n");
+}
+
+static void __init shutdown_actions_init(void)
+{
+ int i;
+
+ for (i = 0; i < SHUTDOWN_ACTIONS_COUNT; i++) {
+ if (!shutdown_actions_list[i]->init)
+ continue;
+ if (shutdown_actions_list[i]->init())
+ shutdown_actions_list[i] = NULL;
+ }
+}
+
+static int __init s390_ipl_init(void)
+{
+ reipl_probe();
+ sclp_get_ipl_info(&sclp_ipl_info);
+ shutdown_actions_init();
+ shutdown_triggers_init();
+ return 0;
+}
+
+__initcall(s390_ipl_init);
+
+static void __init strncpy_skip_quote(char *dst, char *src, int n)
+{
+ int sx, dx;
+
+ dx = 0;
+ for (sx = 0; src[sx] != 0; sx++) {
+ if (src[sx] == '"')
+ continue;
+ dst[dx++] = src[sx];
+ if (dx >= n)
+ break;
+ }
+}
+
+static int __init vmcmd_on_reboot_setup(char *str)
+{
+ if (!MACHINE_IS_VM)
+ return 1;
+ strncpy_skip_quote(vmcmd_on_reboot, str, 127);
+ vmcmd_on_reboot[127] = 0;
+ on_reboot_trigger.action = &vmcmd_action;
+ return 1;
+}
+__setup("vmreboot=", vmcmd_on_reboot_setup);
+
+static int __init vmcmd_on_panic_setup(char *str)
+{
+ if (!MACHINE_IS_VM)
+ return 1;
+ strncpy_skip_quote(vmcmd_on_panic, str, 127);
+ vmcmd_on_panic[127] = 0;
+ on_panic_trigger.action = &vmcmd_action;
+ return 1;
+}
+__setup("vmpanic=", vmcmd_on_panic_setup);
+
+static int __init vmcmd_on_halt_setup(char *str)
+{
+ if (!MACHINE_IS_VM)
+ return 1;
+ strncpy_skip_quote(vmcmd_on_halt, str, 127);
+ vmcmd_on_halt[127] = 0;
+ on_halt_trigger.action = &vmcmd_action;
+ return 1;
+}
+__setup("vmhalt=", vmcmd_on_halt_setup);
+
+static int __init vmcmd_on_poff_setup(char *str)
+{
+ if (!MACHINE_IS_VM)
+ return 1;
+ strncpy_skip_quote(vmcmd_on_poff, str, 127);
+ vmcmd_on_poff[127] = 0;
+ on_poff_trigger.action = &vmcmd_action;
+ return 1;
+}
+__setup("vmpoff=", vmcmd_on_poff_setup);
+
+static int on_panic_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ do_panic();
+ return NOTIFY_OK;
+}
+
+static struct notifier_block on_panic_nb = {
+ .notifier_call = on_panic_notify,
+ .priority = 0,
+};
+
+void __init setup_ipl(void)
+{
+ ipl_info.type = get_ipl_type();
+ switch (ipl_info.type) {
+ case IPL_TYPE_CCW:
+ ipl_info.data.ccw.dev_id.devno = ipl_devno;
+ ipl_info.data.ccw.dev_id.ssid = 0;
+ break;
+ case IPL_TYPE_FCP:
+ case IPL_TYPE_FCP_DUMP:
+ ipl_info.data.fcp.dev_id.devno =
+ IPL_PARMBLOCK_START->ipl_info.fcp.devno;
+ ipl_info.data.fcp.dev_id.ssid = 0;
+ ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
+ ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
+ break;
+ case IPL_TYPE_NSS:
+ strncpy(ipl_info.data.nss.name, kernel_nss_name,
+ sizeof(ipl_info.data.nss.name));
+ break;
+ case IPL_TYPE_UNKNOWN:
+ default:
+ /* We have no info to copy */
+ break;
+ }
+ atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb);
+}
+
+void __init ipl_save_parameters(void)
+{
+ struct cio_iplinfo iplinfo;
+ unsigned int *ipl_ptr;
+ void *src, *dst;
+
+ if (cio_get_iplinfo(&iplinfo))
+ return;
+
+ ipl_devno = iplinfo.devno;
+ ipl_flags |= IPL_DEVNO_VALID;
+ if (!iplinfo.is_qdio)
+ return;
+ ipl_flags |= IPL_PARMBLOCK_VALID;
+ ipl_ptr = (unsigned int *)__LC_IPL_PARMBLOCK_PTR;
+ src = (void *)(unsigned long)*ipl_ptr;
+ dst = (void *)IPL_PARMBLOCK_ORIGIN;
+ memmove(dst, src, PAGE_SIZE);
+ *ipl_ptr = IPL_PARMBLOCK_ORIGIN;
+}
+
+static LIST_HEAD(rcall);
+static DEFINE_MUTEX(rcall_mutex);
+
+void register_reset_call(struct reset_call *reset)
+{
+ mutex_lock(&rcall_mutex);
+ list_add(&reset->list, &rcall);
+ mutex_unlock(&rcall_mutex);
+}
+EXPORT_SYMBOL_GPL(register_reset_call);
+
+void unregister_reset_call(struct reset_call *reset)
+{
+ mutex_lock(&rcall_mutex);
+ list_del(&reset->list);
+ mutex_unlock(&rcall_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_reset_call);
+
+static void do_reset_calls(void)
+{
+ struct reset_call *reset;
+
+ list_for_each_entry(reset, &rcall, list)
+ reset->fn();
+}
+
+u32 dump_prefix_page;
+
+void s390_reset_system(void)
+{
+ struct _lowcore *lc;
+
+ lc = (struct _lowcore *)(unsigned long) store_prefix();
+
+ /* Stack for interrupt/machine check handler */
+ lc->panic_stack = S390_lowcore.panic_stack;
+
+ /* Save prefix page address for dump case */
+ dump_prefix_page = (u32)(unsigned long) lc;
+
+ /* Disable prefixing */
+ set_prefix(0);
+
+ /* Disable lowcore protection */
+ __ctl_clear_bit(0,28);
+
+ /* Set new machine check handler */
+ S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
+ S390_lowcore.mcck_new_psw.addr =
+ PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler;
+
+ /* Set new program check handler */
+ S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
+ S390_lowcore.program_new_psw.addr =
+ PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
+
+ do_reset_calls();
+}
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/irq.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/irq.c
new file mode 100644
index 0000000000..c36d8123ca
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/irq.c
@@ -0,0 +1,105 @@
+/*
+ * arch/s390/kernel/irq.c
+ *
+ * Copyright IBM Corp. 2004,2007
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Thomas Spatzier (tspat@de.ibm.com)
+ *
+ * This file contains interrupt related functions.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/seq_file.h>
+#include <linux/cpu.h>
+#include <linux/proc_fs.h>
+#include <linux/profile.h>
+
+/*
+ * show_interrupts is needed by /proc/interrupts.
+ */
+int show_interrupts(struct seq_file *p, void *v)
+{
+ static const char *intrclass_names[] = { "EXT", "I/O", };
+ int i = *(loff_t *) v, j;
+
+ if (i == 0) {
+ seq_puts(p, " ");
+ for_each_online_cpu(j)
+ seq_printf(p, "CPU%d ",j);
+ seq_putc(p, '\n');
+ }
+
+ if (i < NR_IRQS) {
+ seq_printf(p, "%s: ", intrclass_names[i]);
+#ifndef CONFIG_SMP
+ seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+ seq_putc(p, '\n');
+
+ }
+
+ return 0;
+}
+
+/*
+ * For compatibilty only. S/390 specific setup of interrupts et al. is done
+ * much later in init_channel_subsystem().
+ */
+void __init
+init_IRQ(void)
+{
+ /* nothing... */
+}
+
+/*
+ * Switch to the asynchronous interrupt stack for softirq execution.
+ */
+extern void __do_softirq(void);
+
+asmlinkage void do_softirq(void)
+{
+ unsigned long flags, old, new;
+
+ if (in_interrupt())
+ return;
+
+ local_irq_save(flags);
+
+ if (local_softirq_pending()) {
+ /* Get current stack pointer. */
+ asm volatile("la %0,0(15)" : "=a" (old));
+ /* Check against async. stack address range. */
+ new = S390_lowcore.async_stack;
+ if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) {
+ /* Need to switch to the async. stack. */
+ new -= STACK_FRAME_OVERHEAD;
+ ((struct stack_frame *) new)->back_chain = old;
+
+ asm volatile(" la 15,0(%0)\n"
+ " basr 14,%2\n"
+ " la 15,0(%1)\n"
+ : : "a" (new), "a" (old),
+ "a" (__do_softirq)
+ : "0", "1", "2", "3", "4", "5", "14",
+ "cc", "memory" );
+ } else
+ /* We are already on the async stack. */
+ __do_softirq();
+ }
+
+ local_irq_restore(flags);
+}
+
+void init_irq_proc(void)
+{
+ struct proc_dir_entry *root_irq_dir;
+
+ root_irq_dir = proc_mkdir("irq", NULL);
+ create_prof_cpu_mask(root_irq_dir);
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/kprobes.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/kprobes.c
new file mode 100644
index 0000000000..c5549a2062
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/kprobes.c
@@ -0,0 +1,672 @@
+/*
+ * Kernel Probes (KProbes)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2002, 2006
+ *
+ * s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com>
+ */
+
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+#include <linux/preempt.h>
+#include <linux/stop_machine.h>
+#include <linux/kdebug.h>
+#include <asm/cacheflush.h>
+#include <asm/sections.h>
+#include <asm/uaccess.h>
+#include <linux/module.h>
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+struct kretprobe_blackpoint kretprobe_blacklist[] = {{NULL, NULL}};
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+ /* Make sure the probe isn't going on a difficult instruction */
+ if (is_prohibited_opcode((kprobe_opcode_t *) p->addr))
+ return -EINVAL;
+
+ if ((unsigned long)p->addr & 0x01) {
+ printk("Attempt to register kprobe at an unaligned address\n");
+ return -EINVAL;
+ }
+
+ /* Use the get_insn_slot() facility for correctness */
+ if (!(p->ainsn.insn = get_insn_slot()))
+ return -ENOMEM;
+
+ memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+
+ get_instruction_type(&p->ainsn);
+ p->opcode = *p->addr;
+ return 0;
+}
+
+int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction)
+{
+ switch (*(__u8 *) instruction) {
+ case 0x0c: /* bassm */
+ case 0x0b: /* bsm */
+ case 0x83: /* diag */
+ case 0x44: /* ex */
+ return -EINVAL;
+ }
+ switch (*(__u16 *) instruction) {
+ case 0x0101: /* pr */
+ case 0xb25a: /* bsa */
+ case 0xb240: /* bakr */
+ case 0xb258: /* bsg */
+ case 0xb218: /* pc */
+ case 0xb228: /* pt */
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void __kprobes get_instruction_type(struct arch_specific_insn *ainsn)
+{
+ /* default fixup method */
+ ainsn->fixup = FIXUP_PSW_NORMAL;
+
+ /* save r1 operand */
+ ainsn->reg = (*ainsn->insn & 0xf0) >> 4;
+
+ /* save the instruction length (pop 5-5) in bytes */
+ switch (*(__u8 *) (ainsn->insn) >> 6) {
+ case 0:
+ ainsn->ilen = 2;
+ break;
+ case 1:
+ case 2:
+ ainsn->ilen = 4;
+ break;
+ case 3:
+ ainsn->ilen = 6;
+ break;
+ }
+
+ switch (*(__u8 *) ainsn->insn) {
+ case 0x05: /* balr */
+ case 0x0d: /* basr */
+ ainsn->fixup = FIXUP_RETURN_REGISTER;
+ /* if r2 = 0, no branch will be taken */
+ if ((*ainsn->insn & 0x0f) == 0)
+ ainsn->fixup |= FIXUP_BRANCH_NOT_TAKEN;
+ break;
+ case 0x06: /* bctr */
+ case 0x07: /* bcr */
+ ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN;
+ break;
+ case 0x45: /* bal */
+ case 0x4d: /* bas */
+ ainsn->fixup = FIXUP_RETURN_REGISTER;
+ break;
+ case 0x47: /* bc */
+ case 0x46: /* bct */
+ case 0x86: /* bxh */
+ case 0x87: /* bxle */
+ ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN;
+ break;
+ case 0x82: /* lpsw */
+ ainsn->fixup = FIXUP_NOT_REQUIRED;
+ break;
+ case 0xb2: /* lpswe */
+ if (*(((__u8 *) ainsn->insn) + 1) == 0xb2) {
+ ainsn->fixup = FIXUP_NOT_REQUIRED;
+ }
+ break;
+ case 0xa7: /* bras */
+ if ((*ainsn->insn & 0x0f) == 0x05) {
+ ainsn->fixup |= FIXUP_RETURN_REGISTER;
+ }
+ break;
+ case 0xc0:
+ if ((*ainsn->insn & 0x0f) == 0x00 /* larl */
+ || (*ainsn->insn & 0x0f) == 0x05) /* brasl */
+ ainsn->fixup |= FIXUP_RETURN_REGISTER;
+ break;
+ case 0xeb:
+ if (*(((__u8 *) ainsn->insn) + 5 ) == 0x44 || /* bxhg */
+ *(((__u8 *) ainsn->insn) + 5) == 0x45) {/* bxleg */
+ ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN;
+ }
+ break;
+ case 0xe3: /* bctg */
+ if (*(((__u8 *) ainsn->insn) + 5) == 0x46) {
+ ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN;
+ }
+ break;
+ }
+}
+
+static int __kprobes swap_instruction(void *aref)
+{
+ struct ins_replace_args *args = aref;
+ u32 *addr;
+ u32 instr;
+ int err = -EFAULT;
+
+ /*
+ * Text segment is read-only, hence we use stura to bypass dynamic
+ * address translation to exchange the instruction. Since stura
+ * always operates on four bytes, but we only want to exchange two
+ * bytes do some calculations to get things right. In addition we
+ * shall not cross any page boundaries (vmalloc area!) when writing
+ * the new instruction.
+ */
+ addr = (u32 *)((unsigned long)args->ptr & -4UL);
+ if ((unsigned long)args->ptr & 2)
+ instr = ((*addr) & 0xffff0000) | args->new;
+ else
+ instr = ((*addr) & 0x0000ffff) | args->new << 16;
+
+ asm volatile(
+ " lra %1,0(%1)\n"
+ "0: stura %2,%1\n"
+ "1: la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b)
+ : "+d" (err)
+ : "a" (addr), "d" (instr)
+ : "memory", "cc");
+
+ return err;
+}
+
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ unsigned long status = kcb->kprobe_status;
+ struct ins_replace_args args;
+
+ args.ptr = p->addr;
+ args.old = p->opcode;
+ args.new = BREAKPOINT_INSTRUCTION;
+
+ kcb->kprobe_status = KPROBE_SWAP_INST;
+ stop_machine_run(swap_instruction, &args, NR_CPUS);
+ kcb->kprobe_status = status;
+}
+
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ unsigned long status = kcb->kprobe_status;
+ struct ins_replace_args args;
+
+ args.ptr = p->addr;
+ args.old = BREAKPOINT_INSTRUCTION;
+ args.new = p->opcode;
+
+ kcb->kprobe_status = KPROBE_SWAP_INST;
+ stop_machine_run(swap_instruction, &args, NR_CPUS);
+ kcb->kprobe_status = status;
+}
+
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+ mutex_lock(&kprobe_mutex);
+ free_insn_slot(p->ainsn.insn, 0);
+ mutex_unlock(&kprobe_mutex);
+}
+
+static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
+{
+ per_cr_bits kprobe_per_regs[1];
+
+ memset(kprobe_per_regs, 0, sizeof(per_cr_bits));
+ regs->psw.addr = (unsigned long)p->ainsn.insn | PSW_ADDR_AMODE;
+
+ /* Set up the per control reg info, will pass to lctl */
+ kprobe_per_regs[0].em_instruction_fetch = 1;
+ kprobe_per_regs[0].starting_addr = (unsigned long)p->ainsn.insn;
+ kprobe_per_regs[0].ending_addr = (unsigned long)p->ainsn.insn + 1;
+
+ /* Set the PER control regs, turns on single step for this address */
+ __ctl_load(kprobe_per_regs, 9, 11);
+ regs->psw.mask |= PSW_MASK_PER;
+ regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
+}
+
+static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+ kcb->prev_kprobe.kp = kprobe_running();
+ kcb->prev_kprobe.status = kcb->kprobe_status;
+ kcb->prev_kprobe.kprobe_saved_imask = kcb->kprobe_saved_imask;
+ memcpy(kcb->prev_kprobe.kprobe_saved_ctl, kcb->kprobe_saved_ctl,
+ sizeof(kcb->kprobe_saved_ctl));
+}
+
+static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+ __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
+ kcb->kprobe_status = kcb->prev_kprobe.status;
+ kcb->kprobe_saved_imask = kcb->prev_kprobe.kprobe_saved_imask;
+ memcpy(kcb->kprobe_saved_ctl, kcb->prev_kprobe.kprobe_saved_ctl,
+ sizeof(kcb->kprobe_saved_ctl));
+}
+
+static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
+ struct kprobe_ctlblk *kcb)
+{
+ __get_cpu_var(current_kprobe) = p;
+ /* Save the interrupt and per flags */
+ kcb->kprobe_saved_imask = regs->psw.mask &
+ (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK);
+ /* Save the control regs that govern PER */
+ __ctl_store(kcb->kprobe_saved_ctl, 9, 11);
+}
+
+/* Called with kretprobe_lock held */
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14];
+
+ /* Replace the return addr with trampoline addr */
+ regs->gprs[14] = (unsigned long)&kretprobe_trampoline;
+}
+
+static int __kprobes kprobe_handler(struct pt_regs *regs)
+{
+ struct kprobe *p;
+ int ret = 0;
+ unsigned long *addr = (unsigned long *)
+ ((regs->psw.addr & PSW_ADDR_INSN) - 2);
+ struct kprobe_ctlblk *kcb;
+
+ /*
+ * We don't want to be preempted for the entire
+ * duration of kprobe processing
+ */
+ preempt_disable();
+ kcb = get_kprobe_ctlblk();
+
+ /* Check we're not actually recursing */
+ if (kprobe_running()) {
+ p = get_kprobe(addr);
+ if (p) {
+ if (kcb->kprobe_status == KPROBE_HIT_SS &&
+ *p->ainsn.insn == BREAKPOINT_INSTRUCTION) {
+ regs->psw.mask &= ~PSW_MASK_PER;
+ regs->psw.mask |= kcb->kprobe_saved_imask;
+ goto no_kprobe;
+ }
+ /* We have reentered the kprobe_handler(), since
+ * another probe was hit while within the handler.
+ * We here save the original kprobes variables and
+ * just single step on the instruction of the new probe
+ * without calling any user handlers.
+ */
+ save_previous_kprobe(kcb);
+ set_current_kprobe(p, regs, kcb);
+ kprobes_inc_nmissed_count(p);
+ prepare_singlestep(p, regs);
+ kcb->kprobe_status = KPROBE_REENTER;
+ return 1;
+ } else {
+ p = __get_cpu_var(current_kprobe);
+ if (p->break_handler && p->break_handler(p, regs)) {
+ goto ss_probe;
+ }
+ }
+ goto no_kprobe;
+ }
+
+ p = get_kprobe(addr);
+ if (!p)
+ /*
+ * No kprobe at this address. The fault has not been
+ * caused by a kprobe breakpoint. The race of breakpoint
+ * vs. kprobe remove does not exist because on s390 we
+ * use stop_machine_run to arm/disarm the breakpoints.
+ */
+ goto no_kprobe;
+
+ kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+ set_current_kprobe(p, regs, kcb);
+ if (p->pre_handler && p->pre_handler(p, regs))
+ /* handler has already set things up, so skip ss setup */
+ return 1;
+
+ss_probe:
+ prepare_singlestep(p, regs);
+ kcb->kprobe_status = KPROBE_HIT_SS;
+ return 1;
+
+no_kprobe:
+ preempt_enable_no_resched();
+ return ret;
+}
+
+/*
+ * Function return probe trampoline:
+ * - init_kprobes() establishes a probepoint here
+ * - When the probed function returns, this probe
+ * causes the handlers to fire
+ */
+void kretprobe_trampoline_holder(void)
+{
+ asm volatile(".global kretprobe_trampoline\n"
+ "kretprobe_trampoline: bcr 0,0\n");
+}
+
+/*
+ * Called when the probe at kretprobe trampoline is hit
+ */
+static int __kprobes trampoline_probe_handler(struct kprobe *p,
+ struct pt_regs *regs)
+{
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
+ unsigned long flags, orig_ret_address = 0;
+ unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+
+ INIT_HLIST_HEAD(&empty_rp);
+ spin_lock_irqsave(&kretprobe_lock, flags);
+ head = kretprobe_inst_table_head(current);
+
+ /*
+ * It is possible to have multiple instances associated with a given
+ * task either because an multiple functions in the call path
+ * have a return probe installed on them, and/or more then one return
+ * return probe was registered for a target function.
+ *
+ * We can handle this because:
+ * - instances are always inserted at the head of the list
+ * - when multiple return probes are registered for the same
+ * function, the first instance's ret_addr will point to the
+ * real return address, and all the rest will point to
+ * kretprobe_trampoline
+ */
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+ continue;
+
+ if (ri->rp && ri->rp->handler)
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
+ recycle_rp_inst(ri, &empty_rp);
+
+ if (orig_ret_address != trampoline_address) {
+ /*
+ * This is the real return address. Any other
+ * instances associated with this task are for
+ * other calls deeper on the call stack
+ */
+ break;
+ }
+ }
+ kretprobe_assert(ri, orig_ret_address, trampoline_address);
+ regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE;
+
+ reset_current_kprobe();
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+ preempt_enable_no_resched();
+
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we don't want the post_handler
+ * to run (and have re-enabled preemption)
+ */
+ return 1;
+}
+
+/*
+ * Called after single-stepping. p->addr is the address of the
+ * instruction whose first byte has been replaced by the "breakpoint"
+ * instruction. To avoid the SMP problems that can occur when we
+ * temporarily put back the original opcode to single-step, we
+ * single-stepped a copy of the instruction. The address of this
+ * copy is p->ainsn.insn.
+ */
+static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
+{
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ regs->psw.addr &= PSW_ADDR_INSN;
+
+ if (p->ainsn.fixup & FIXUP_PSW_NORMAL)
+ regs->psw.addr = (unsigned long)p->addr +
+ ((unsigned long)regs->psw.addr -
+ (unsigned long)p->ainsn.insn);
+
+ if (p->ainsn.fixup & FIXUP_BRANCH_NOT_TAKEN)
+ if ((unsigned long)regs->psw.addr -
+ (unsigned long)p->ainsn.insn == p->ainsn.ilen)
+ regs->psw.addr = (unsigned long)p->addr + p->ainsn.ilen;
+
+ if (p->ainsn.fixup & FIXUP_RETURN_REGISTER)
+ regs->gprs[p->ainsn.reg] = ((unsigned long)p->addr +
+ (regs->gprs[p->ainsn.reg] -
+ (unsigned long)p->ainsn.insn))
+ | PSW_ADDR_AMODE;
+
+ regs->psw.addr |= PSW_ADDR_AMODE;
+ /* turn off PER mode */
+ regs->psw.mask &= ~PSW_MASK_PER;
+ /* Restore the original per control regs */
+ __ctl_load(kcb->kprobe_saved_ctl, 9, 11);
+ regs->psw.mask |= kcb->kprobe_saved_imask;
+}
+
+static int __kprobes post_kprobe_handler(struct pt_regs *regs)
+{
+ struct kprobe *cur = kprobe_running();
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ if (!cur)
+ return 0;
+
+ if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
+ kcb->kprobe_status = KPROBE_HIT_SSDONE;
+ cur->post_handler(cur, regs, 0);
+ }
+
+ resume_execution(cur, regs);
+
+ /*Restore back the original saved kprobes variables and continue. */
+ if (kcb->kprobe_status == KPROBE_REENTER) {
+ restore_previous_kprobe(kcb);
+ goto out;
+ }
+ reset_current_kprobe();
+out:
+ preempt_enable_no_resched();
+
+ /*
+ * if somebody else is singlestepping across a probe point, psw mask
+ * will have PER set, in which case, continue the remaining processing
+ * of do_single_step, as if this is not a probe hit.
+ */
+ if (regs->psw.mask & PSW_MASK_PER) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+ struct kprobe *cur = kprobe_running();
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ const struct exception_table_entry *entry;
+
+ switch(kcb->kprobe_status) {
+ case KPROBE_SWAP_INST:
+ /* We are here because the instruction replacement failed */
+ return 0;
+ case KPROBE_HIT_SS:
+ case KPROBE_REENTER:
+ /*
+ * We are here because the instruction being single
+ * stepped caused a page fault. We reset the current
+ * kprobe and the nip points back to the probe address
+ * and allow the page fault handler to continue as a
+ * normal page fault.
+ */
+ regs->psw.addr = (unsigned long)cur->addr | PSW_ADDR_AMODE;
+ regs->psw.mask &= ~PSW_MASK_PER;
+ regs->psw.mask |= kcb->kprobe_saved_imask;
+ if (kcb->kprobe_status == KPROBE_REENTER)
+ restore_previous_kprobe(kcb);
+ else
+ reset_current_kprobe();
+ preempt_enable_no_resched();
+ break;
+ case KPROBE_HIT_ACTIVE:
+ case KPROBE_HIT_SSDONE:
+ /*
+ * We increment the nmissed count for accounting,
+ * we can also use npre/npostfault count for accouting
+ * these specific fault cases.
+ */
+ kprobes_inc_nmissed_count(cur);
+
+ /*
+ * We come here because instructions in the pre/post
+ * handler caused the page_fault, this could happen
+ * if handler tries to access user space by
+ * copy_from_user(), get_user() etc. Let the
+ * user-specified handler try to fix it first.
+ */
+ if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+ return 1;
+
+ /*
+ * In case the user-specified fault handler returned
+ * zero, try to fix up.
+ */
+ entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
+ if (entry) {
+ regs->psw.addr = entry->fixup | PSW_ADDR_AMODE;
+ return 1;
+ }
+
+ /*
+ * fixup_exception() could not handle it,
+ * Let do_page_fault() fix it.
+ */
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Wrapper routine to for handling exceptions.
+ */
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data)
+{
+ struct die_args *args = (struct die_args *)data;
+ int ret = NOTIFY_DONE;
+
+ switch (val) {
+ case DIE_BPT:
+ if (kprobe_handler(args->regs))
+ ret = NOTIFY_STOP;
+ break;
+ case DIE_SSTEP:
+ if (post_kprobe_handler(args->regs))
+ ret = NOTIFY_STOP;
+ break;
+ case DIE_TRAP:
+ /* kprobe_running() needs smp_processor_id() */
+ preempt_disable();
+ if (kprobe_running() &&
+ kprobe_fault_handler(args->regs, args->trapnr))
+ ret = NOTIFY_STOP;
+ preempt_enable();
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct jprobe *jp = container_of(p, struct jprobe, kp);
+ unsigned long addr;
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs));
+
+ /* setup return addr to the jprobe handler routine */
+ regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE;
+
+ /* r14 is the function return address */
+ kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14];
+ /* r15 is the stack pointer */
+ kcb->jprobe_saved_r15 = (unsigned long)regs->gprs[15];
+ addr = (unsigned long)kcb->jprobe_saved_r15;
+
+ memcpy(kcb->jprobes_stack, (kprobe_opcode_t *) addr,
+ MIN_STACK_SIZE(addr));
+ return 1;
+}
+
+void __kprobes jprobe_return(void)
+{
+ asm volatile(".word 0x0002");
+}
+
+void __kprobes jprobe_return_end(void)
+{
+ asm volatile("bcr 0,0");
+}
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_r15);
+
+ /* Put the regs back */
+ memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs));
+ /* put the stack back */
+ memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack,
+ MIN_STACK_SIZE(stack_addr));
+ preempt_enable_no_resched();
+ return 1;
+}
+
+static struct kprobe trampoline_p = {
+ .addr = (kprobe_opcode_t *) & kretprobe_trampoline,
+ .pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init_kprobes(void)
+{
+ return register_kprobe(&trampoline_p);
+}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+ if (p->addr == (kprobe_opcode_t *) & kretprobe_trampoline)
+ return 1;
+ return 0;
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/machine_kexec.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/machine_kexec.c
new file mode 100644
index 0000000000..3c77dd3699
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/machine_kexec.c
@@ -0,0 +1,71 @@
+/*
+ * arch/s390/kernel/machine_kexec.c
+ *
+ * Copyright IBM Corp. 2005,2006
+ *
+ * Author(s): Rolf Adelsberger,
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <asm/cio.h>
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+#include <asm/reset.h>
+#include <asm/ipl.h>
+
+typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long);
+
+extern const unsigned char relocate_kernel[];
+extern const unsigned long long relocate_kernel_len;
+
+int machine_kexec_prepare(struct kimage *image)
+{
+ void *reboot_code_buffer;
+
+ /* Can't replace kernel image since it is read-only. */
+ if (ipl_flags & IPL_NSS_VALID)
+ return -ENOSYS;
+
+ /* We don't support anything but the default image type for now. */
+ if (image->type != KEXEC_TYPE_DEFAULT)
+ return -EINVAL;
+
+ /* Get the destination where the assembler code should be copied to.*/
+ reboot_code_buffer = (void *) page_to_phys(image->control_code_page);
+
+ /* Then copy it */
+ memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len);
+ return 0;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+}
+
+void machine_shutdown(void)
+{
+ printk(KERN_INFO "kexec: machine_shutdown called\n");
+}
+
+void machine_kexec(struct kimage *image)
+{
+ relocate_kernel_t data_mover;
+
+ smp_send_stop();
+ pfault_fini();
+ s390_reset_system();
+
+ data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page);
+
+ /* Call the moving routine */
+ (*data_mover)(&image->head, image->start);
+ for (;;);
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/module.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/module.c
new file mode 100644
index 0000000000..59b4e79668
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/module.c
@@ -0,0 +1,408 @@
+/*
+ * arch/s390/kernel/module.c - Kernel module help for s390.
+ *
+ * S390 version
+ * Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH,
+ * IBM Corporation
+ * Author(s): Arnd Bergmann (arndb@de.ibm.com)
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * based on i386 version
+ * Copyright (C) 2001 Rusty Russell.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/module.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/moduleloader.h>
+#include <linux/bug.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt , ...)
+#endif
+
+#ifndef CONFIG_64BIT
+#define PLT_ENTRY_SIZE 12
+#else /* CONFIG_64BIT */
+#define PLT_ENTRY_SIZE 20
+#endif /* CONFIG_64BIT */
+
+void *module_alloc(unsigned long size)
+{
+ if (size == 0)
+ return NULL;
+ return vmalloc(size);
+}
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+ vfree(module_region);
+ /* FIXME: If module_region == mod->init_region, trim exception
+ table entries. */
+}
+
+static void
+check_rela(Elf_Rela *rela, struct module *me)
+{
+ struct mod_arch_syminfo *info;
+
+ info = me->arch.syminfo + ELF_R_SYM (rela->r_info);
+ switch (ELF_R_TYPE (rela->r_info)) {
+ case R_390_GOT12: /* 12 bit GOT offset. */
+ case R_390_GOT16: /* 16 bit GOT offset. */
+ case R_390_GOT20: /* 20 bit GOT offset. */
+ case R_390_GOT32: /* 32 bit GOT offset. */
+ case R_390_GOT64: /* 64 bit GOT offset. */
+ case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */
+ case R_390_GOTPLT12: /* 12 bit offset to jump slot. */
+ case R_390_GOTPLT16: /* 16 bit offset to jump slot. */
+ case R_390_GOTPLT20: /* 20 bit offset to jump slot. */
+ case R_390_GOTPLT32: /* 32 bit offset to jump slot. */
+ case R_390_GOTPLT64: /* 64 bit offset to jump slot. */
+ case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */
+ if (info->got_offset == -1UL) {
+ info->got_offset = me->arch.got_size;
+ me->arch.got_size += sizeof(void*);
+ }
+ break;
+ case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
+ case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
+ case R_390_PLT32: /* 32 bit PC relative PLT address. */
+ case R_390_PLT64: /* 64 bit PC relative PLT address. */
+ case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */
+ case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
+ case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
+ if (info->plt_offset == -1UL) {
+ info->plt_offset = me->arch.plt_size;
+ me->arch.plt_size += PLT_ENTRY_SIZE;
+ }
+ break;
+ case R_390_COPY:
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ case R_390_RELATIVE:
+ /* Only needed if we want to support loading of
+ modules linked with -shared. */
+ break;
+ }
+}
+
+/*
+ * Account for GOT and PLT relocations. We can't add sections for
+ * got and plt but we can increase the core module size.
+ */
+int
+module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+ char *secstrings, struct module *me)
+{
+ Elf_Shdr *symtab;
+ Elf_Sym *symbols;
+ Elf_Rela *rela;
+ char *strings;
+ int nrela, i, j;
+
+ /* Find symbol table and string table. */
+ symtab = NULL;
+ for (i = 0; i < hdr->e_shnum; i++)
+ switch (sechdrs[i].sh_type) {
+ case SHT_SYMTAB:
+ symtab = sechdrs + i;
+ break;
+ }
+ if (!symtab) {
+ printk(KERN_ERR "module %s: no symbol table\n", me->name);
+ return -ENOEXEC;
+ }
+
+ /* Allocate one syminfo structure per symbol. */
+ me->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym);
+ me->arch.syminfo = vmalloc(me->arch.nsyms *
+ sizeof(struct mod_arch_syminfo));
+ if (!me->arch.syminfo)
+ return -ENOMEM;
+ symbols = (void *) hdr + symtab->sh_offset;
+ strings = (void *) hdr + sechdrs[symtab->sh_link].sh_offset;
+ for (i = 0; i < me->arch.nsyms; i++) {
+ if (symbols[i].st_shndx == SHN_UNDEF &&
+ strcmp(strings + symbols[i].st_name,
+ "_GLOBAL_OFFSET_TABLE_") == 0)
+ /* "Define" it as absolute. */
+ symbols[i].st_shndx = SHN_ABS;
+ me->arch.syminfo[i].got_offset = -1UL;
+ me->arch.syminfo[i].plt_offset = -1UL;
+ me->arch.syminfo[i].got_initialized = 0;
+ me->arch.syminfo[i].plt_initialized = 0;
+ }
+
+ /* Search for got/plt relocations. */
+ me->arch.got_size = me->arch.plt_size = 0;
+ for (i = 0; i < hdr->e_shnum; i++) {
+ if (sechdrs[i].sh_type != SHT_RELA)
+ continue;
+ nrela = sechdrs[i].sh_size / sizeof(Elf_Rela);
+ rela = (void *) hdr + sechdrs[i].sh_offset;
+ for (j = 0; j < nrela; j++)
+ check_rela(rela + j, me);
+ }
+
+ /* Increase core size by size of got & plt and set start
+ offsets for got and plt. */
+ me->core_size = ALIGN(me->core_size, 4);
+ me->arch.got_offset = me->core_size;
+ me->core_size += me->arch.got_size;
+ me->arch.plt_offset = me->core_size;
+ me->core_size += me->arch.plt_size;
+ return 0;
+}
+
+int
+apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
+ unsigned int relsec, struct module *me)
+{
+ printk(KERN_ERR "module %s: RELOCATION unsupported\n",
+ me->name);
+ return -ENOEXEC;
+}
+
+static int
+apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
+ struct module *me)
+{
+ struct mod_arch_syminfo *info;
+ Elf_Addr loc, val;
+ int r_type, r_sym;
+
+ /* This is where to make the change */
+ loc = base + rela->r_offset;
+ /* This is the symbol it is referring to. Note that all
+ undefined symbols have been resolved. */
+ r_sym = ELF_R_SYM(rela->r_info);
+ r_type = ELF_R_TYPE(rela->r_info);
+ info = me->arch.syminfo + r_sym;
+ val = symtab[r_sym].st_value;
+
+ switch (r_type) {
+ case R_390_8: /* Direct 8 bit. */
+ case R_390_12: /* Direct 12 bit. */
+ case R_390_16: /* Direct 16 bit. */
+ case R_390_20: /* Direct 20 bit. */
+ case R_390_32: /* Direct 32 bit. */
+ case R_390_64: /* Direct 64 bit. */
+ val += rela->r_addend;
+ if (r_type == R_390_8)
+ *(unsigned char *) loc = val;
+ else if (r_type == R_390_12)
+ *(unsigned short *) loc = (val & 0xfff) |
+ (*(unsigned short *) loc & 0xf000);
+ else if (r_type == R_390_16)
+ *(unsigned short *) loc = val;
+ else if (r_type == R_390_20)
+ *(unsigned int *) loc =
+ (*(unsigned int *) loc & 0xf00000ff) |
+ (val & 0xfff) << 16 | (val & 0xff000) >> 4;
+ else if (r_type == R_390_32)
+ *(unsigned int *) loc = val;
+ else if (r_type == R_390_64)
+ *(unsigned long *) loc = val;
+ break;
+ case R_390_PC16: /* PC relative 16 bit. */
+ case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */
+ case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */
+ case R_390_PC32: /* PC relative 32 bit. */
+ case R_390_PC64: /* PC relative 64 bit. */
+ val += rela->r_addend - loc;
+ if (r_type == R_390_PC16)
+ *(unsigned short *) loc = val;
+ else if (r_type == R_390_PC16DBL)
+ *(unsigned short *) loc = val >> 1;
+ else if (r_type == R_390_PC32DBL)
+ *(unsigned int *) loc = val >> 1;
+ else if (r_type == R_390_PC32)
+ *(unsigned int *) loc = val;
+ else if (r_type == R_390_PC64)
+ *(unsigned long *) loc = val;
+ break;
+ case R_390_GOT12: /* 12 bit GOT offset. */
+ case R_390_GOT16: /* 16 bit GOT offset. */
+ case R_390_GOT20: /* 20 bit GOT offset. */
+ case R_390_GOT32: /* 32 bit GOT offset. */
+ case R_390_GOT64: /* 64 bit GOT offset. */
+ case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */
+ case R_390_GOTPLT12: /* 12 bit offset to jump slot. */
+ case R_390_GOTPLT20: /* 20 bit offset to jump slot. */
+ case R_390_GOTPLT16: /* 16 bit offset to jump slot. */
+ case R_390_GOTPLT32: /* 32 bit offset to jump slot. */
+ case R_390_GOTPLT64: /* 64 bit offset to jump slot. */
+ case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */
+ if (info->got_initialized == 0) {
+ Elf_Addr *gotent;
+
+ gotent = me->module_core + me->arch.got_offset +
+ info->got_offset;
+ *gotent = val;
+ info->got_initialized = 1;
+ }
+ val = info->got_offset + rela->r_addend;
+ if (r_type == R_390_GOT12 ||
+ r_type == R_390_GOTPLT12)
+ *(unsigned short *) loc = (val & 0xfff) |
+ (*(unsigned short *) loc & 0xf000);
+ else if (r_type == R_390_GOT16 ||
+ r_type == R_390_GOTPLT16)
+ *(unsigned short *) loc = val;
+ else if (r_type == R_390_GOT20 ||
+ r_type == R_390_GOTPLT20)
+ *(unsigned int *) loc =
+ (*(unsigned int *) loc & 0xf00000ff) |
+ (val & 0xfff) << 16 | (val & 0xff000) >> 4;
+ else if (r_type == R_390_GOT32 ||
+ r_type == R_390_GOTPLT32)
+ *(unsigned int *) loc = val;
+ else if (r_type == R_390_GOTENT ||
+ r_type == R_390_GOTPLTENT)
+ *(unsigned int *) loc =
+ (val + (Elf_Addr) me->module_core - loc) >> 1;
+ else if (r_type == R_390_GOT64 ||
+ r_type == R_390_GOTPLT64)
+ *(unsigned long *) loc = val;
+ break;
+ case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
+ case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
+ case R_390_PLT32: /* 32 bit PC relative PLT address. */
+ case R_390_PLT64: /* 64 bit PC relative PLT address. */
+ case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */
+ case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
+ case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
+ if (info->plt_initialized == 0) {
+ unsigned int *ip;
+ ip = me->module_core + me->arch.plt_offset +
+ info->plt_offset;
+#ifndef CONFIG_64BIT
+ ip[0] = 0x0d105810; /* basr 1,0; l 1,6(1); br 1 */
+ ip[1] = 0x100607f1;
+ ip[2] = val;
+#else /* CONFIG_64BIT */
+ ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
+ ip[1] = 0x100a0004;
+ ip[2] = 0x07f10000;
+ ip[3] = (unsigned int) (val >> 32);
+ ip[4] = (unsigned int) val;
+#endif /* CONFIG_64BIT */
+ info->plt_initialized = 1;
+ }
+ if (r_type == R_390_PLTOFF16 ||
+ r_type == R_390_PLTOFF32
+ || r_type == R_390_PLTOFF64
+ )
+ val = me->arch.plt_offset - me->arch.got_offset +
+ info->plt_offset + rela->r_addend;
+ else
+ val = (Elf_Addr) me->module_core +
+ me->arch.plt_offset + info->plt_offset +
+ rela->r_addend - loc;
+ if (r_type == R_390_PLT16DBL)
+ *(unsigned short *) loc = val >> 1;
+ else if (r_type == R_390_PLTOFF16)
+ *(unsigned short *) loc = val;
+ else if (r_type == R_390_PLT32DBL)
+ *(unsigned int *) loc = val >> 1;
+ else if (r_type == R_390_PLT32 ||
+ r_type == R_390_PLTOFF32)
+ *(unsigned int *) loc = val;
+ else if (r_type == R_390_PLT64 ||
+ r_type == R_390_PLTOFF64)
+ *(unsigned long *) loc = val;
+ break;
+ case R_390_GOTOFF16: /* 16 bit offset to GOT. */
+ case R_390_GOTOFF32: /* 32 bit offset to GOT. */
+ case R_390_GOTOFF64: /* 64 bit offset to GOT. */
+ val = val + rela->r_addend -
+ ((Elf_Addr) me->module_core + me->arch.got_offset);
+ if (r_type == R_390_GOTOFF16)
+ *(unsigned short *) loc = val;
+ else if (r_type == R_390_GOTOFF32)
+ *(unsigned int *) loc = val;
+ else if (r_type == R_390_GOTOFF64)
+ *(unsigned long *) loc = val;
+ break;
+ case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
+ case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
+ val = (Elf_Addr) me->module_core + me->arch.got_offset +
+ rela->r_addend - loc;
+ if (r_type == R_390_GOTPC)
+ *(unsigned int *) loc = val;
+ else if (r_type == R_390_GOTPCDBL)
+ *(unsigned int *) loc = val >> 1;
+ break;
+ case R_390_COPY:
+ case R_390_GLOB_DAT: /* Create GOT entry. */
+ case R_390_JMP_SLOT: /* Create PLT entry. */
+ case R_390_RELATIVE: /* Adjust by program base. */
+ /* Only needed if we want to support loading of
+ modules linked with -shared. */
+ break;
+ default:
+ printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+ me->name, r_type);
+ return -ENOEXEC;
+ }
+ return 0;
+}
+
+int
+apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
+ unsigned int symindex, unsigned int relsec,
+ struct module *me)
+{
+ Elf_Addr base;
+ Elf_Sym *symtab;
+ Elf_Rela *rela;
+ unsigned long i, n;
+ int rc;
+
+ DEBUGP("Applying relocate section %u to %u\n",
+ relsec, sechdrs[relsec].sh_info);
+ base = sechdrs[sechdrs[relsec].sh_info].sh_addr;
+ symtab = (Elf_Sym *) sechdrs[symindex].sh_addr;
+ rela = (Elf_Rela *) sechdrs[relsec].sh_addr;
+ n = sechdrs[relsec].sh_size / sizeof(Elf_Rela);
+
+ for (i = 0; i < n; i++, rela++) {
+ rc = apply_rela(rela, base, symtab, me);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ vfree(me->arch.syminfo);
+ return module_bug_finalize(hdr, sechdrs, me);
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+ module_bug_cleanup(mod);
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/process.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/process.c
new file mode 100644
index 0000000000..ce203154d8
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/process.c
@@ -0,0 +1,429 @@
+/*
+ * arch/s390/kernel/process.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Hartmut Penner (hp@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * Derived from "arch/i386/kernel/process.c"
+ * Copyright (C) 1995, Linus Torvalds
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/compiler.h>
+#include <linux/cpu.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/user.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/utsname.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/timer.h>
+#include <asm/cpu.h>
+
+asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
+
+/*
+ * Return saved PC of a blocked thread. used in kernel/sched.
+ * resume in entry.S does not create a new stack frame, it
+ * just stores the registers %r6-%r15 to the frame given by
+ * schedule. We want to return the address of the caller of
+ * schedule, so we have to walk the backchain one time to
+ * find the frame schedule() store its return address.
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+ struct stack_frame *sf, *low, *high;
+
+ if (!tsk || !task_stack_page(tsk))
+ return 0;
+ low = task_stack_page(tsk);
+ high = (struct stack_frame *) task_pt_regs(tsk);
+ sf = (struct stack_frame *) (tsk->thread.ksp & PSW_ADDR_INSN);
+ if (sf <= low || sf > high)
+ return 0;
+ sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN);
+ if (sf <= low || sf > high)
+ return 0;
+ return sf->gprs[8];
+}
+
+/*
+ * Need to know about CPUs going idle?
+ */
+static ATOMIC_NOTIFIER_HEAD(idle_chain);
+
+int register_idle_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&idle_chain, nb);
+}
+EXPORT_SYMBOL(register_idle_notifier);
+
+int unregister_idle_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&idle_chain, nb);
+}
+EXPORT_SYMBOL(unregister_idle_notifier);
+
+void do_monitor_call(struct pt_regs *regs, long interruption_code)
+{
+#ifdef CONFIG_SMP
+ struct s390_idle_data *idle;
+
+ idle = &__get_cpu_var(s390_idle);
+ spin_lock(&idle->lock);
+ idle->idle_time += get_clock() - idle->idle_enter;
+ idle->in_idle = 0;
+ spin_unlock(&idle->lock);
+#endif
+ /* disable monitor call class 0 */
+ __ctl_clear_bit(8, 15);
+
+ atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE,
+ (void *)(long) smp_processor_id());
+}
+
+extern void s390_handle_mcck(void);
+/*
+ * The idle loop on a S390...
+ */
+static void default_idle(void)
+{
+ int cpu, rc;
+ int nr_calls = 0;
+ void *hcpu;
+#ifdef CONFIG_SMP
+ struct s390_idle_data *idle;
+#endif
+
+ /* CPU is going idle. */
+ cpu = smp_processor_id();
+ hcpu = (void *)(long)cpu;
+ local_irq_disable();
+ if (need_resched()) {
+ local_irq_enable();
+ return;
+ }
+
+ rc = __atomic_notifier_call_chain(&idle_chain, S390_CPU_IDLE, hcpu, -1,
+ &nr_calls);
+ if (rc == NOTIFY_BAD) {
+ nr_calls--;
+ __atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE,
+ hcpu, nr_calls, NULL);
+ local_irq_enable();
+ return;
+ }
+
+ /* enable monitor call class 0 */
+ __ctl_set_bit(8, 15);
+
+#ifdef CONFIG_HOTPLUG_CPU
+ if (cpu_is_offline(cpu)) {
+ preempt_enable_no_resched();
+ cpu_die();
+ }
+#endif
+
+ local_mcck_disable();
+ if (test_thread_flag(TIF_MCCK_PENDING)) {
+ local_mcck_enable();
+ /* disable monitor call class 0 */
+ __ctl_clear_bit(8, 15);
+ atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE,
+ hcpu);
+ local_irq_enable();
+ s390_handle_mcck();
+ return;
+ }
+#ifdef CONFIG_SMP
+ idle = &__get_cpu_var(s390_idle);
+ spin_lock(&idle->lock);
+ idle->idle_count++;
+ idle->in_idle = 1;
+ idle->idle_enter = get_clock();
+ spin_unlock(&idle->lock);
+#endif
+ trace_hardirqs_on();
+ /* Wait for external, I/O or machine check interrupt. */
+ __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
+ PSW_MASK_IO | PSW_MASK_EXT);
+}
+
+void cpu_idle(void)
+{
+ for (;;) {
+ while (!need_resched())
+ default_idle();
+
+ preempt_enable_no_resched();
+ schedule();
+ preempt_disable();
+ }
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ print_modules();
+ printk("CPU: %d %s %s %.*s\n",
+ task_thread_info(current)->cpu, print_tainted(),
+ init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+ printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+ current->comm, current->pid, current,
+ (void *) current->thread.ksp);
+ show_registers(regs);
+ /* Show stack backtrace if pt_regs is from kernel mode */
+ if (!(regs->psw.mask & PSW_MASK_PSTATE))
+ show_trace(NULL, (unsigned long *) regs->gprs[15]);
+}
+
+extern void kernel_thread_starter(void);
+
+asm(
+ ".align 4\n"
+ "kernel_thread_starter:\n"
+ " la 2,0(10)\n"
+ " basr 14,9\n"
+ " la 2,0\n"
+ " br 11\n");
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ struct pt_regs regs;
+
+ memset(&regs, 0, sizeof(regs));
+ regs.psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
+ regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
+ regs.gprs[9] = (unsigned long) fn;
+ regs.gprs[10] = (unsigned long) arg;
+ regs.gprs[11] = (unsigned long) do_exit;
+ regs.orig_gpr2 = -1;
+
+ /* Ok, create the new process.. */
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
+ 0, &regs, 0, NULL, NULL);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+ clear_used_math();
+ clear_tsk_thread_flag(current, TIF_USEDFPU);
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
+ unsigned long unused,
+ struct task_struct * p, struct pt_regs * regs)
+{
+ struct fake_frame
+ {
+ struct stack_frame sf;
+ struct pt_regs childregs;
+ } *frame;
+
+ frame = container_of(task_pt_regs(p), struct fake_frame, childregs);
+ p->thread.ksp = (unsigned long) frame;
+ /* Store access registers to kernel stack of new process. */
+ frame->childregs = *regs;
+ frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
+ frame->childregs.gprs[15] = new_stackp;
+ frame->sf.back_chain = 0;
+
+ /* new return point is ret_from_fork */
+ frame->sf.gprs[8] = (unsigned long) ret_from_fork;
+
+ /* fake return stack for resume(), don't go back to schedule */
+ frame->sf.gprs[9] = (unsigned long) frame;
+
+ /* Save access registers to new thread structure. */
+ save_access_regs(&p->thread.acrs[0]);
+
+#ifndef CONFIG_64BIT
+ /*
+ * save fprs to current->thread.fp_regs to merge them with
+ * the emulated registers and then copy the result to the child.
+ */
+ save_fp_regs(&current->thread.fp_regs);
+ memcpy(&p->thread.fp_regs, &current->thread.fp_regs,
+ sizeof(s390_fp_regs));
+ /* Set a new TLS ? */
+ if (clone_flags & CLONE_SETTLS)
+ p->thread.acrs[0] = regs->gprs[6];
+#else /* CONFIG_64BIT */
+ /* Save the fpu registers to new thread structure. */
+ save_fp_regs(&p->thread.fp_regs);
+ /* Set a new TLS ? */
+ if (clone_flags & CLONE_SETTLS) {
+ if (test_thread_flag(TIF_31BIT)) {
+ p->thread.acrs[0] = (unsigned int) regs->gprs[6];
+ } else {
+ p->thread.acrs[0] = (unsigned int)(regs->gprs[6] >> 32);
+ p->thread.acrs[1] = (unsigned int) regs->gprs[6];
+ }
+ }
+#endif /* CONFIG_64BIT */
+ /* start new process with ar4 pointing to the correct address space */
+ p->thread.mm_segment = get_fs();
+ /* Don't copy debug registers */
+ memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
+
+ return 0;
+}
+
+asmlinkage long sys_fork(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL);
+}
+
+asmlinkage long sys_clone(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ unsigned long clone_flags;
+ unsigned long newsp;
+ int __user *parent_tidptr, *child_tidptr;
+
+ clone_flags = regs->gprs[3];
+ newsp = regs->orig_gpr2;
+ parent_tidptr = (int __user *) regs->gprs[4];
+ child_tidptr = (int __user *) regs->gprs[5];
+ if (!newsp)
+ newsp = regs->gprs[15];
+ return do_fork(clone_flags, newsp, regs, 0,
+ parent_tidptr, child_tidptr);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage long sys_vfork(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+ regs->gprs[15], regs, 0, NULL, NULL);
+}
+
+asmlinkage void execve_tail(void)
+{
+ task_lock(current);
+ current->ptrace &= ~PT_DTRACE;
+ task_unlock(current);
+ current->thread.fp_regs.fpc = 0;
+ if (MACHINE_HAS_IEEE)
+ asm volatile("sfpc %0,%0" : : "d" (0));
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage long sys_execve(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ char *filename;
+ unsigned long result;
+ int rc;
+
+ filename = getname((char __user *) regs->orig_gpr2);
+ if (IS_ERR(filename)) {
+ result = PTR_ERR(filename);
+ goto out;
+ }
+ rc = do_execve(filename, (char __user * __user *) regs->gprs[3],
+ (char __user * __user *) regs->gprs[4], regs);
+ if (rc) {
+ result = rc;
+ goto out_putname;
+ }
+ execve_tail();
+ result = regs->gprs[2];
+out_putname:
+ putname(filename);
+out:
+ return result;
+}
+
+/*
+ * fill in the FPU structure for a core dump.
+ */
+int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
+{
+#ifndef CONFIG_64BIT
+ /*
+ * save fprs to current->thread.fp_regs to merge them with
+ * the emulated registers and then copy the result to the dump.
+ */
+ save_fp_regs(&current->thread.fp_regs);
+ memcpy(fpregs, &current->thread.fp_regs, sizeof(s390_fp_regs));
+#else /* CONFIG_64BIT */
+ save_fp_regs(fpregs);
+#endif /* CONFIG_64BIT */
+ return 1;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ struct stack_frame *sf, *low, *high;
+ unsigned long return_address;
+ int count;
+
+ if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p))
+ return 0;
+ low = task_stack_page(p);
+ high = (struct stack_frame *) task_pt_regs(p);
+ sf = (struct stack_frame *) (p->thread.ksp & PSW_ADDR_INSN);
+ if (sf <= low || sf > high)
+ return 0;
+ for (count = 0; count < 16; count++) {
+ sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN);
+ if (sf <= low || sf > high)
+ return 0;
+ return_address = sf->gprs[8] & PSW_ADDR_INSN;
+ if (!in_sched_functions(return_address))
+ return return_address;
+ }
+ return 0;
+}
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ptrace.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ptrace.c
new file mode 100644
index 0000000000..6e036bae98
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/ptrace.c
@@ -0,0 +1,754 @@
+/*
+ * arch/s390/kernel/ptrace.c
+ *
+ * S390 version
+ * 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)
+ *
+ * Based on PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/m68k/kernel/ptrace.c"
+ * Copyright (C) 1994 by Hamish Macdonald
+ * Taken from linux/kernel/ptrace.c and modified for M680x0.
+ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/security.h>
+#include <linux/audit.h>
+#include <linux/signal.h>
+
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+
+#ifdef CONFIG_COMPAT
+#include "compat_ptrace.h"
+#endif
+
+static void
+FixPerRegisters(struct task_struct *task)
+{
+ struct pt_regs *regs;
+ per_struct *per_info;
+
+ regs = task_pt_regs(task);
+ per_info = (per_struct *) &task->thread.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;
+#ifdef CONFIG_COMPAT
+ if (test_thread_flag(TIF_31BIT))
+ per_info->control_regs.bits.ending_addr = 0x7fffffffUL;
+ else
+#endif
+ per_info->control_regs.bits.ending_addr = PSW_ADDR_INSN;
+ } else {
+ per_info->control_regs.bits.starting_addr =
+ per_info->starting_addr;
+ per_info->control_regs.bits.ending_addr =
+ per_info->ending_addr;
+ }
+ /*
+ * if any of the control reg tracing bits are on
+ * we switch on per in the psw
+ */
+ if (per_info->control_regs.words.cr[0] & PER_EM_MASK)
+ regs->psw.mask |= PSW_MASK_PER;
+ else
+ regs->psw.mask &= ~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;
+}
+
+void user_enable_single_step(struct task_struct *task)
+{
+ task->thread.per_info.single_step = 1;
+ FixPerRegisters(task);
+}
+
+void user_disable_single_step(struct task_struct *task)
+{
+ task->thread.per_info.single_step = 0;
+ FixPerRegisters(task);
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void
+ptrace_disable(struct task_struct *child)
+{
+ /* make sure the single step bit is not set. */
+ user_disable_single_step(child);
+}
+
+#ifndef CONFIG_64BIT
+# define __ADDR_MASK 3
+#else
+# define __ADDR_MASK 7
+#endif
+
+/*
+ * Read the word at offset addr from the user area of a process. The
+ * trouble here is that the information is littered over different
+ * locations. The process registers are found on the kernel stack,
+ * the floating point stuff and the trace settings are stored in
+ * the task structure. In addition the different structures in
+ * struct user contain pad bytes that should be read as zeroes.
+ * Lovely...
+ */
+static int
+peek_user(struct task_struct *child, addr_t addr, addr_t data)
+{
+ struct user *dummy = NULL;
+ addr_t offset, tmp, mask;
+
+ /*
+ * Stupid gdb peeks/pokes the access registers in 64 bit with
+ * an alignment of 4. Programmers from hell...
+ */
+ mask = __ADDR_MASK;
+#ifdef CONFIG_64BIT
+ if (addr >= (addr_t) &dummy->regs.acrs &&
+ addr < (addr_t) &dummy->regs.orig_gpr2)
+ mask = 3;
+#endif
+ if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
+ return -EIO;
+
+ if (addr < (addr_t) &dummy->regs.acrs) {
+ /*
+ * psw and gprs are stored on the stack
+ */
+ tmp = *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr);
+ if (addr == (addr_t) &dummy->regs.psw.mask)
+ /* Remove per bit from user psw. */
+ tmp &= ~PSW_MASK_PER;
+
+ } else if (addr < (addr_t) &dummy->regs.orig_gpr2) {
+ /*
+ * access registers are stored in the thread structure
+ */
+ offset = addr - (addr_t) &dummy->regs.acrs;
+#ifdef CONFIG_64BIT
+ /*
+ * Very special case: old & broken 64 bit gdb reading
+ * from acrs[15]. Result is a 64 bit value. Read the
+ * 32 bit acrs[15] value and shift it by 32. Sick...
+ */
+ if (addr == (addr_t) &dummy->regs.acrs[15])
+ tmp = ((unsigned long) child->thread.acrs[15]) << 32;
+ else
+#endif
+ tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
+
+ } else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
+ /*
+ * orig_gpr2 is stored on the kernel stack
+ */
+ tmp = (addr_t) task_pt_regs(child)->orig_gpr2;
+
+ } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
+ /*
+ * floating point regs. are stored in the thread structure
+ */
+ offset = addr - (addr_t) &dummy->regs.fp_regs;
+ tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
+ if (addr == (addr_t) &dummy->regs.fp_regs.fpc)
+ tmp &= (unsigned long) FPC_VALID_MASK
+ << (BITS_PER_LONG - 32);
+
+ } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
+ /*
+ * per_info is found in the thread structure
+ */
+ offset = addr - (addr_t) &dummy->regs.per_info;
+ tmp = *(addr_t *)((addr_t) &child->thread.per_info + offset);
+
+ } else
+ tmp = 0;
+
+ return put_user(tmp, (addr_t __user *) data);
+}
+
+/*
+ * Write a word to the user area of a process at location addr. This
+ * operation does have an additional problem compared to peek_user.
+ * Stores to the program status word and on the floating point
+ * control register needs to get checked for validity.
+ */
+static int
+poke_user(struct task_struct *child, addr_t addr, addr_t data)
+{
+ struct user *dummy = NULL;
+ addr_t offset, mask;
+
+ /*
+ * Stupid gdb peeks/pokes the access registers in 64 bit with
+ * an alignment of 4. Programmers from hell indeed...
+ */
+ mask = __ADDR_MASK;
+#ifdef CONFIG_64BIT
+ if (addr >= (addr_t) &dummy->regs.acrs &&
+ addr < (addr_t) &dummy->regs.orig_gpr2)
+ mask = 3;
+#endif
+ if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
+ return -EIO;
+
+ if (addr < (addr_t) &dummy->regs.acrs) {
+ /*
+ * psw and gprs are stored on the stack
+ */
+ if (addr == (addr_t) &dummy->regs.psw.mask &&
+#ifdef CONFIG_COMPAT
+ data != PSW_MASK_MERGE(psw_user32_bits, data) &&
+#endif
+ data != PSW_MASK_MERGE(psw_user_bits, data))
+ /* Invalid psw mask. */
+ return -EINVAL;
+#ifndef CONFIG_64BIT
+ if (addr == (addr_t) &dummy->regs.psw.addr)
+ /* I'd like to reject addresses without the
+ high order bit but older gdb's rely on it */
+ data |= PSW_ADDR_AMODE;
+#endif
+ *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data;
+
+ } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
+ /*
+ * access registers are stored in the thread structure
+ */
+ offset = addr - (addr_t) &dummy->regs.acrs;
+#ifdef CONFIG_64BIT
+ /*
+ * Very special case: old & broken 64 bit gdb writing
+ * to acrs[15] with a 64 bit value. Ignore the lower
+ * half of the value and write the upper 32 bit to
+ * acrs[15]. Sick...
+ */
+ if (addr == (addr_t) &dummy->regs.acrs[15])
+ child->thread.acrs[15] = (unsigned int) (data >> 32);
+ else
+#endif
+ *(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
+
+ } else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
+ /*
+ * orig_gpr2 is stored on the kernel stack
+ */
+ task_pt_regs(child)->orig_gpr2 = data;
+
+ } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
+ /*
+ * floating point regs. are stored in the thread structure
+ */
+ if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
+ (data & ~((unsigned long) FPC_VALID_MASK
+ << (BITS_PER_LONG - 32))) != 0)
+ return -EINVAL;
+ offset = addr - (addr_t) &dummy->regs.fp_regs;
+ *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
+
+ } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
+ /*
+ * per_info is found in the thread structure
+ */
+ offset = addr - (addr_t) &dummy->regs.per_info;
+ *(addr_t *)((addr_t) &child->thread.per_info + offset) = data;
+
+ }
+
+ FixPerRegisters(child);
+ return 0;
+}
+
+static int
+do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
+{
+ ptrace_area parea;
+ int copied, ret;
+
+ switch (request) {
+ case PTRACE_PEEKTEXT:
+ case PTRACE_PEEKDATA:
+ /* Remove high order bit from address (only for 31 bit). */
+ addr &= PSW_ADDR_INSN;
+ /* read word at location addr. */
+ return generic_ptrace_peekdata(child, addr, data);
+
+ case PTRACE_PEEKUSR:
+ /* read the word at location addr in the USER area. */
+ return peek_user(child, addr, data);
+
+ case PTRACE_POKETEXT:
+ case PTRACE_POKEDATA:
+ /* Remove high order bit from address (only for 31 bit). */
+ addr &= PSW_ADDR_INSN;
+ /* write the word at location addr. */
+ return generic_ptrace_pokedata(child, addr, data);
+
+ case PTRACE_POKEUSR:
+ /* write the word at location addr in the USER area */
+ return poke_user(child, addr, data);
+
+ case PTRACE_PEEKUSR_AREA:
+ case PTRACE_POKEUSR_AREA:
+ if (copy_from_user(&parea, (void __force __user *) addr,
+ sizeof(parea)))
+ return -EFAULT;
+ addr = parea.kernel_addr;
+ data = parea.process_addr;
+ copied = 0;
+ while (copied < parea.len) {
+ if (request == PTRACE_PEEKUSR_AREA)
+ ret = peek_user(child, addr, data);
+ else {
+ addr_t utmp;
+ if (get_user(utmp,
+ (addr_t __force __user *) data))
+ return -EFAULT;
+ ret = poke_user(child, addr, utmp);
+ }
+ if (ret)
+ return ret;
+ addr += sizeof(unsigned long);
+ data += sizeof(unsigned long);
+ copied += sizeof(unsigned long);
+ }
+ return 0;
+ }
+ return ptrace_request(child, request, addr, data);
+}
+
+#ifdef CONFIG_COMPAT
+/*
+ * Now the fun part starts... a 31 bit program running in the
+ * 31 bit emulation tracing another program. PTRACE_PEEKTEXT,
+ * PTRACE_PEEKDATA, PTRACE_POKETEXT and PTRACE_POKEDATA are easy
+ * to handle, the difference to the 64 bit versions of the requests
+ * is that the access is done in multiples of 4 byte instead of
+ * 8 bytes (sizeof(unsigned long) on 31/64 bit).
+ * The ugly part are PTRACE_PEEKUSR, PTRACE_PEEKUSR_AREA,
+ * PTRACE_POKEUSR and PTRACE_POKEUSR_AREA. If the traced program
+ * is a 31 bit program too, the content of struct user can be
+ * emulated. A 31 bit program peeking into the struct user of
+ * a 64 bit program is a no-no.
+ */
+
+/*
+ * Same as peek_user but for a 31 bit program.
+ */
+static int
+peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
+{
+ struct user32 *dummy32 = NULL;
+ per_struct32 *dummy_per32 = NULL;
+ addr_t offset;
+ __u32 tmp;
+
+ if (!test_thread_flag(TIF_31BIT) ||
+ (addr & 3) || addr > sizeof(struct user) - 3)
+ return -EIO;
+
+ if (addr < (addr_t) &dummy32->regs.acrs) {
+ /*
+ * psw and gprs are stored on the stack
+ */
+ if (addr == (addr_t) &dummy32->regs.psw.mask) {
+ /* Fake a 31 bit psw mask. */
+ tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
+ tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp);
+ } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
+ /* Fake a 31 bit psw address. */
+ tmp = (__u32) task_pt_regs(child)->psw.addr |
+ PSW32_ADDR_AMODE31;
+ } else {
+ /* gpr 0-15 */
+ tmp = *(__u32 *)((addr_t) &task_pt_regs(child)->psw +
+ addr*2 + 4);
+ }
+ } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
+ /*
+ * access registers are stored in the thread structure
+ */
+ offset = addr - (addr_t) &dummy32->regs.acrs;
+ tmp = *(__u32*)((addr_t) &child->thread.acrs + offset);
+
+ } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) {
+ /*
+ * orig_gpr2 is stored on the kernel stack
+ */
+ tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4);
+
+ } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
+ /*
+ * floating point regs. are stored in the thread structure
+ */
+ offset = addr - (addr_t) &dummy32->regs.fp_regs;
+ tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset);
+
+ } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
+ /*
+ * per_info is found in the thread structure
+ */
+ offset = addr - (addr_t) &dummy32->regs.per_info;
+ /* This is magic. See per_struct and per_struct32. */
+ if ((offset >= (addr_t) &dummy_per32->control_regs &&
+ offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
+ (offset >= (addr_t) &dummy_per32->starting_addr &&
+ offset <= (addr_t) &dummy_per32->ending_addr) ||
+ offset == (addr_t) &dummy_per32->lowcore.words.address)
+ offset = offset*2 + 4;
+ else
+ offset = offset*2;
+ tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset);
+
+ } else
+ tmp = 0;
+
+ return put_user(tmp, (__u32 __user *) data);
+}
+
+/*
+ * Same as poke_user but for a 31 bit program.
+ */
+static int
+poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
+{
+ struct user32 *dummy32 = NULL;
+ per_struct32 *dummy_per32 = NULL;
+ addr_t offset;
+ __u32 tmp;
+
+ if (!test_thread_flag(TIF_31BIT) ||
+ (addr & 3) || addr > sizeof(struct user32) - 3)
+ return -EIO;
+
+ tmp = (__u32) data;
+
+ if (addr < (addr_t) &dummy32->regs.acrs) {
+ /*
+ * psw, gprs, acrs and orig_gpr2 are stored on the stack
+ */
+ if (addr == (addr_t) &dummy32->regs.psw.mask) {
+ /* Build a 64 bit psw mask from 31 bit mask. */
+ if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp))
+ /* Invalid psw mask. */
+ return -EINVAL;
+ task_pt_regs(child)->psw.mask =
+ PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32);
+ } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
+ /* Build a 64 bit psw address from 31 bit address. */
+ task_pt_regs(child)->psw.addr =
+ (__u64) tmp & PSW32_ADDR_INSN;
+ } else {
+ /* gpr 0-15 */
+ *(__u32*)((addr_t) &task_pt_regs(child)->psw
+ + addr*2 + 4) = tmp;
+ }
+ } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
+ /*
+ * access registers are stored in the thread structure
+ */
+ offset = addr - (addr_t) &dummy32->regs.acrs;
+ *(__u32*)((addr_t) &child->thread.acrs + offset) = tmp;
+
+ } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) {
+ /*
+ * orig_gpr2 is stored on the kernel stack
+ */
+ *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp;
+
+ } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
+ /*
+ * floating point regs. are stored in the thread structure
+ */
+ if (addr == (addr_t) &dummy32->regs.fp_regs.fpc &&
+ (tmp & ~FPC_VALID_MASK) != 0)
+ /* Invalid floating point control. */
+ return -EINVAL;
+ offset = addr - (addr_t) &dummy32->regs.fp_regs;
+ *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp;
+
+ } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
+ /*
+ * per_info is found in the thread structure.
+ */
+ offset = addr - (addr_t) &dummy32->regs.per_info;
+ /*
+ * This is magic. See per_struct and per_struct32.
+ * By incident the offsets in per_struct are exactly
+ * twice the offsets in per_struct32 for all fields.
+ * The 8 byte fields need special handling though,
+ * because the second half (bytes 4-7) is needed and
+ * not the first half.
+ */
+ if ((offset >= (addr_t) &dummy_per32->control_regs &&
+ offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
+ (offset >= (addr_t) &dummy_per32->starting_addr &&
+ offset <= (addr_t) &dummy_per32->ending_addr) ||
+ offset == (addr_t) &dummy_per32->lowcore.words.address)
+ offset = offset*2 + 4;
+ else
+ offset = offset*2;
+ *(__u32 *)((addr_t) &child->thread.per_info + offset) = tmp;
+
+ }
+
+ FixPerRegisters(child);
+ return 0;
+}
+
+static int
+do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
+{
+ unsigned int tmp; /* 4 bytes !! */
+ ptrace_area_emu31 parea;
+ int copied, ret;
+
+ switch (request) {
+ case PTRACE_PEEKTEXT:
+ case PTRACE_PEEKDATA:
+ /* read word at location addr. */
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ if (copied != sizeof(tmp))
+ return -EIO;
+ return put_user(tmp, (unsigned int __force __user *) data);
+
+ case PTRACE_PEEKUSR:
+ /* read the word at location addr in the USER area. */
+ return peek_user_emu31(child, addr, data);
+
+ case PTRACE_POKETEXT:
+ case PTRACE_POKEDATA:
+ /* write the word at location addr. */
+ tmp = data;
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
+ if (copied != sizeof(tmp))
+ return -EIO;
+ return 0;
+
+ case PTRACE_POKEUSR:
+ /* write the word at location addr in the USER area */
+ return poke_user_emu31(child, addr, data);
+
+ case PTRACE_PEEKUSR_AREA:
+ case PTRACE_POKEUSR_AREA:
+ if (copy_from_user(&parea, (void __force __user *) addr,
+ sizeof(parea)))
+ return -EFAULT;
+ addr = parea.kernel_addr;
+ data = parea.process_addr;
+ copied = 0;
+ while (copied < parea.len) {
+ if (request == PTRACE_PEEKUSR_AREA)
+ ret = peek_user_emu31(child, addr, data);
+ else {
+ __u32 utmp;
+ if (get_user(utmp,
+ (__u32 __force __user *) data))
+ return -EFAULT;
+ ret = poke_user_emu31(child, addr, utmp);
+ }
+ if (ret)
+ return ret;
+ addr += sizeof(unsigned int);
+ data += sizeof(unsigned int);
+ copied += sizeof(unsigned int);
+ }
+ return 0;
+ case PTRACE_GETEVENTMSG:
+ return put_user((__u32) child->ptrace_message,
+ (unsigned int __force __user *) data);
+ case PTRACE_GETSIGINFO:
+ if (child->last_siginfo == NULL)
+ return -EINVAL;
+ return copy_siginfo_to_user32((compat_siginfo_t
+ __force __user *) data,
+ child->last_siginfo);
+ case PTRACE_SETSIGINFO:
+ if (child->last_siginfo == NULL)
+ return -EINVAL;
+ return copy_siginfo_from_user32(child->last_siginfo,
+ (compat_siginfo_t
+ __force __user *) data);
+ }
+ return ptrace_request(child, request, addr, data);
+}
+#endif
+
+#define PT32_IEEE_IP 0x13c
+
+static int
+do_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+ int ret;
+
+ if (request == PTRACE_ATTACH)
+ return ptrace_attach(child);
+
+ /*
+ * Special cases to get/store the ieee instructions pointer.
+ */
+ if (child == current) {
+ if (request == PTRACE_PEEKUSR && addr == PT_IEEE_IP)
+ return peek_user(child, addr, data);
+ if (request == PTRACE_POKEUSR && addr == PT_IEEE_IP)
+ return poke_user(child, addr, data);
+#ifdef CONFIG_COMPAT
+ if (request == PTRACE_PEEKUSR &&
+ addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT))
+ return peek_user_emu31(child, addr, data);
+ if (request == PTRACE_POKEUSR &&
+ addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT))
+ return poke_user_emu31(child, addr, data);
+#endif
+ }
+
+ ret = ptrace_check_attach(child, request == PTRACE_KILL);
+ if (ret < 0)
+ return ret;
+
+ switch (request) {
+ case PTRACE_SYSCALL:
+ /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT:
+ /* restart after signal. */
+ if (!valid_signal(data))
+ return -EIO;
+ if (request == PTRACE_SYSCALL)
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ else
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ child->exit_code = data;
+ /* make sure the single step bit is not set. */
+ user_disable_single_step(child);
+ wake_up_process(child);
+ return 0;
+
+ case PTRACE_KILL:
+ /*
+ * make the child exit. Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
+ * exit.
+ */
+ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
+ return 0;
+ child->exit_code = SIGKILL;
+ /* make sure the single step bit is not set. */
+ user_disable_single_step(child);
+ wake_up_process(child);
+ return 0;
+
+ case PTRACE_SINGLESTEP:
+ /* set the trap flag. */
+ if (!valid_signal(data))
+ return -EIO;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ child->exit_code = data;
+ user_enable_single_step(child);
+ /* give it a chance to run. */
+ wake_up_process(child);
+ return 0;
+
+ /* Do requests that differ for 31/64 bit */
+ default:
+#ifdef CONFIG_COMPAT
+ if (test_thread_flag(TIF_31BIT))
+ return do_ptrace_emu31(child, request, addr, data);
+#endif
+ return do_ptrace_normal(child, request, addr, data);
+ }
+ /* Not reached. */
+ return -EIO;
+}
+
+asmlinkage long
+sys_ptrace(long request, long pid, long addr, long data)
+{
+ struct task_struct *child;
+ int ret;
+
+ lock_kernel();
+ if (request == PTRACE_TRACEME) {
+ ret = ptrace_traceme();
+ goto out;
+ }
+
+ child = ptrace_get_task_struct(pid);
+ if (IS_ERR(child)) {
+ ret = PTR_ERR(child);
+ goto out;
+ }
+
+ ret = do_ptrace(child, request, addr, data);
+ put_task_struct(child);
+out:
+ unlock_kernel();
+ return ret;
+}
+
+asmlinkage void
+syscall_trace(struct pt_regs *regs, int entryexit)
+{
+ if (unlikely(current->audit_context) && entryexit)
+ audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
+
+ if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ goto out;
+ if (!(current->ptrace & PT_PTRACED))
+ goto out;
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0));
+
+ /*
+ * If the debuffer 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
+ */
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
+ out:
+ if (unlikely(current->audit_context) && !entryexit)
+ audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
+ regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
+ regs->gprs[4], regs->gprs[5]);
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/reipl.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/reipl.S
new file mode 100644
index 0000000000..2f481cc3d1
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/reipl.S
@@ -0,0 +1,86 @@
+/*
+ * arch/s390/kernel/reipl.S
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ */
+
+#include <asm/lowcore.h>
+
+#
+# do_reipl_asm
+# Parameter: r2 = schid of reipl device
+#
+ .globl do_reipl_asm
+do_reipl_asm: basr %r13,0
+.Lpg0: lpsw .Lnewpsw-.Lpg0(%r13)
+.Lpg1: # do store status of all registers
+
+ stm %r0,%r15,__LC_GPREGS_SAVE_AREA
+ stctl %c0,%c15,__LC_CREGS_SAVE_AREA
+ stam %a0,%a15,__LC_AREGS_SAVE_AREA
+ l %r10,.Ldump_pfx-.Lpg0(%r13)
+ mvc __LC_PREFIX_SAVE_AREA(4),0(%r10)
+ stckc .Lclkcmp-.Lpg0(%r13)
+ mvc __LC_CLOCK_COMP_SAVE_AREA(8),.Lclkcmp-.Lpg0(%r13)
+ stpt __LC_CPU_TIMER_SAVE_AREA
+ st %r13, __LC_PSW_SAVE_AREA+4
+ lctl %c6,%c6,.Lall-.Lpg0(%r13)
+ lr %r1,%r2
+ mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
+ stsch .Lschib-.Lpg0(%r13)
+ oi .Lschib+5-.Lpg0(%r13),0x84
+.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
+ msch .Lschib-.Lpg0(%r13)
+ lhi %r0,5
+.Lssch: ssch .Liplorb-.Lpg0(%r13)
+ jz .L001
+ brct %r0,.Lssch
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)
+.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13)
+.Lcont: c %r1,__LC_SUBCHANNEL_ID
+ jnz .Ltpi
+ clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
+ jnz .Ltpi
+ tsch .Liplirb-.Lpg0(%r13)
+ tm .Liplirb+9-.Lpg0(%r13),0xbf
+ jz .L002
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
+ jz .L003
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L003: st %r1,__LC_SUBCHANNEL_ID
+ lpsw 0
+ sigp 0,0,0(6)
+.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
+ lpsw .Ldispsw-.Lpg0(%r13)
+ .align 8
+.Lclkcmp: .quad 0x0000000000000000
+.Lall: .long 0xff000000
+.Ldump_pfx: .long dump_prefix_page
+ .align 8
+.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1
+.Lpcnew: .long 0x00080000,0x80000000+.Lecs
+.Lionew: .long 0x00080000,0x80000000+.Lcont
+.Lwaitpsw: .long 0x020a0000,0x00000000+.Ltpi
+.Ldispsw: .long 0x000a0000,0x00000000
+.Liplccws: .long 0x02000000,0x60000018
+ .long 0x08000008,0x20000001
+.Liplorb: .long 0x0049504c,0x0040ff80
+ .long 0x00000000+.Liplccws
+.Lschib: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+.Liplirb: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/reipl64.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/reipl64.S
new file mode 100644
index 0000000000..c41930499a
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/reipl64.S
@@ -0,0 +1,113 @@
+/*
+ * arch/s390/kernel/reipl.S
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ */
+
+#include <asm/lowcore.h>
+
+#
+# do_reipl_asm
+# Parameter: r2 = schid of reipl device
+#
+
+ .globl do_reipl_asm
+do_reipl_asm: basr %r13,0
+.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
+.Lpg1: # do store status of all registers
+
+ stg %r1,.Lregsave-.Lpg0(%r13)
+ lghi %r1,0x1000
+ stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1)
+ lg %r0,.Lregsave-.Lpg0(%r13)
+ stg %r0,__LC_GPREGS_SAVE_AREA-0x1000+8(%r1)
+ stctg %c0,%c15,__LC_CREGS_SAVE_AREA-0x1000(%r1)
+ stam %a0,%a15,__LC_AREGS_SAVE_AREA-0x1000(%r1)
+ lg %r10,.Ldump_pfx-.Lpg0(%r13)
+ mvc __LC_PREFIX_SAVE_AREA-0x1000(4,%r1),0(%r10)
+ stfpc __LC_FP_CREG_SAVE_AREA-0x1000(%r1)
+ stckc .Lclkcmp-.Lpg0(%r13)
+ mvc __LC_CLOCK_COMP_SAVE_AREA-0x1000(8,%r1),.Lclkcmp-.Lpg0(%r13)
+ stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1)
+ stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1)
+
+ lctlg %c6,%c6,.Lall-.Lpg0(%r13)
+ lgr %r1,%r2
+ mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
+ stsch .Lschib-.Lpg0(%r13)
+ oi .Lschib+5-.Lpg0(%r13),0x84
+.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
+ msch .Lschib-.Lpg0(%r13)
+ lghi %r0,5
+.Lssch: ssch .Liplorb-.Lpg0(%r13)
+ jz .L001
+ brct %r0,.Lssch
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)
+.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13)
+.Lcont: c %r1,__LC_SUBCHANNEL_ID
+ jnz .Ltpi
+ clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
+ jnz .Ltpi
+ tsch .Liplirb-.Lpg0(%r13)
+ tm .Liplirb+9-.Lpg0(%r13),0xbf
+ jz .L002
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
+ jz .L003
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L003: st %r1,__LC_SUBCHANNEL_ID
+ lhi %r1,0 # mode 0 = esa
+ slr %r0,%r0 # set cpuid to zero
+ sigp %r1,%r0,0x12 # switch to esa mode
+ lpsw 0
+.Ldisab: sll %r14,1
+ srl %r14,1 # need to kill hi bit to avoid specification exceptions.
+ st %r14,.Ldispsw+12-.Lpg0(%r13)
+ lpswe .Ldispsw-.Lpg0(%r13)
+ .align 8
+.Lclkcmp: .quad 0x0000000000000000
+.Lall: .quad 0x00000000ff000000
+.Ldump_pfx: .quad dump_prefix_page
+.Lregsave: .quad 0x0000000000000000
+ .align 16
+/*
+ * These addresses have to be 31 bit otherwise
+ * the sigp will throw a specifcation exception
+ * when switching to ESA mode as bit 31 be set
+ * in the ESA psw.
+ * Bit 31 of the addresses has to be 0 for the
+ * 31bit lpswe instruction a fact they appear to have
+ * ommited from the pop.
+ */
+.Lnewpsw: .quad 0x0000000080000000
+ .quad .Lpg1
+.Lpcnew: .quad 0x0000000080000000
+ .quad .Lecs
+.Lionew: .quad 0x0000000080000000
+ .quad .Lcont
+.Lwaitpsw: .quad 0x0202000080000000
+ .quad .Ltpi
+.Ldispsw: .quad 0x0002000080000000
+ .quad 0x0000000000000000
+.Liplccws: .long 0x02000000,0x60000018
+ .long 0x08000008,0x20000001
+.Liplorb: .long 0x0049504c,0x0040ff80
+ .long 0x00000000+.Liplccws
+.Lschib: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+.Liplirb: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/relocate_kernel.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/relocate_kernel.S
new file mode 100644
index 0000000000..3b456b80bc
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/relocate_kernel.S
@@ -0,0 +1,117 @@
+/*
+ * arch/s390/kernel/relocate_kernel.S
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger,
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+/*
+ * moves the new kernel to its destination...
+ * %r2 = pointer to first kimage_entry_t
+ * %r3 = start address - where to jump to after the job is done...
+ *
+ * %r5 will be used as temp. storage
+ * %r6 holds the destination address
+ * %r7 = PAGE_SIZE
+ * %r8 holds the source address
+ * %r9 = PAGE_SIZE
+ * %r10 is a page mask
+ */
+
+ .text
+ .globl relocate_kernel
+ relocate_kernel:
+ basr %r13,0 # base address
+ .base:
+ stnsm sys_msk-.base(%r13),0xfb # disable DAT
+ stctl %c0,%c15,ctlregs-.base(%r13)
+ stm %r0,%r15,gprregs-.base(%r13)
+ la %r1,load_psw-.base(%r13)
+ mvc 0(8,%r0),0(%r1)
+ la %r0,.back-.base(%r13)
+ st %r0,4(%r0)
+ oi 4(%r0),0x80
+ mvc 0x68(8,%r0),0(%r1)
+ la %r0,.back_pgm-.base(%r13)
+ st %r0,0x6c(%r0)
+ oi 0x6c(%r0),0x80
+ lhi %r0,0
+ diag %r0,%r0,0x308
+ .back:
+ basr %r13,0
+ .back_base:
+ oi have_diag308-.back_base(%r13),0x01
+ lctl %c0,%c15,ctlregs-.back_base(%r13)
+ lm %r0,%r15,gprregs-.back_base(%r13)
+ j .start_reloc
+ .back_pgm:
+ lm %r0,%r15,gprregs-.base(%r13)
+ .start_reloc:
+ lhi %r10,-1 # preparing the mask
+ sll %r10,12 # shift it such that it becomes 0xf000
+ .top:
+ lhi %r7,4096 # load PAGE_SIZE in r7
+ lhi %r9,4096 # load PAGE_SIZE in r9
+ l %r5,0(%r2) # read another word for indirection page
+ ahi %r2,4 # increment pointer
+ tml %r5,0x1 # is it a destination page?
+ je .indir_check # NO, goto "indir_check"
+ lr %r6,%r5 # r6 = r5
+ nr %r6,%r10 # mask it out and...
+ j .top # ...next iteration
+ .indir_check:
+ tml %r5,0x2 # is it a indirection page?
+ je .done_test # NO, goto "done_test"
+ nr %r5,%r10 # YES, mask out,
+ lr %r2,%r5 # move it into the right register,
+ j .top # and read next...
+ .done_test:
+ tml %r5,0x4 # is it the done indicator?
+ je .source_test # NO! Well, then it should be the source indicator...
+ j .done # ok, lets finish it here...
+ .source_test:
+ tml %r5,0x8 # it should be a source indicator...
+ je .top # NO, ignore it...
+ lr %r8,%r5 # r8 = r5
+ nr %r8,%r10 # masking
+ 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+ jo 0b
+ j .top
+ .done:
+ sr %r0,%r0 # clear register r0
+ la %r4,load_psw-.base(%r13) # load psw-address into the register
+ o %r3,4(%r4) # or load address into psw
+ st %r3,4(%r4)
+ mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0
+ tm have_diag308-.base(%r13),0x01
+ jno .no_diag308
+ diag %r0,%r0,0x308
+ .no_diag308:
+ sr %r1,%r1 # clear %r1
+ sr %r2,%r2 # clear %r2
+ sigp %r1,%r2,0x12 # set cpuid to zero
+ lpsw 0 # hopefully start new kernel...
+
+ .align 8
+ load_psw:
+ .long 0x00080000,0x80000000
+ sys_msk:
+ .quad 0
+ ctlregs:
+ .rept 16
+ .long 0
+ .endr
+ gprregs:
+ .rept 16
+ .long 0
+ .endr
+ have_diag308:
+ .byte 0
+ .align 8
+ relocate_kernel_end:
+ .globl relocate_kernel_len
+ relocate_kernel_len:
+ .quad relocate_kernel_end - relocate_kernel
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/relocate_kernel64.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/relocate_kernel64.S
new file mode 100644
index 0000000000..1f9ea2067b
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/relocate_kernel64.S
@@ -0,0 +1,120 @@
+/*
+ * arch/s390/kernel/relocate_kernel64.S
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger,
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+/*
+ * moves the new kernel to its destination...
+ * %r2 = pointer to first kimage_entry_t
+ * %r3 = start address - where to jump to after the job is done...
+ *
+ * %r5 will be used as temp. storage
+ * %r6 holds the destination address
+ * %r7 = PAGE_SIZE
+ * %r8 holds the source address
+ * %r9 = PAGE_SIZE
+ *
+ * 0xf000 is a page_mask
+ */
+
+ .text
+ .globl relocate_kernel
+ relocate_kernel:
+ basr %r13,0 # base address
+ .base:
+ stnsm sys_msk-.base(%r13),0xfb # disable DAT
+ stctg %c0,%c15,ctlregs-.base(%r13)
+ stmg %r0,%r15,gprregs-.base(%r13)
+ lghi %r0,3
+ sllg %r0,%r0,31
+ stg %r0,0x1d0(%r0)
+ la %r0,.back_pgm-.base(%r13)
+ stg %r0,0x1d8(%r0)
+ la %r1,load_psw-.base(%r13)
+ mvc 0(8,%r0),0(%r1)
+ la %r0,.back-.base(%r13)
+ st %r0,4(%r0)
+ oi 4(%r0),0x80
+ lghi %r0,0
+ diag %r0,%r0,0x308
+ .back:
+ lhi %r1,1 # mode 1 = esame
+ sigp %r1,%r0,0x12 # switch to esame mode
+ sam64 # switch to 64 bit addressing mode
+ basr %r13,0
+ .back_base:
+ oi have_diag308-.back_base(%r13),0x01
+ lctlg %c0,%c15,ctlregs-.back_base(%r13)
+ lmg %r0,%r15,gprregs-.back_base(%r13)
+ j .top
+ .back_pgm:
+ lmg %r0,%r15,gprregs-.base(%r13)
+ .top:
+ lghi %r7,4096 # load PAGE_SIZE in r7
+ lghi %r9,4096 # load PAGE_SIZE in r9
+ lg %r5,0(%r2) # read another word for indirection page
+ aghi %r2,8 # increment pointer
+ tml %r5,0x1 # is it a destination page?
+ je .indir_check # NO, goto "indir_check"
+ lgr %r6,%r5 # r6 = r5
+ nill %r6,0xf000 # mask it out and...
+ j .top # ...next iteration
+ .indir_check:
+ tml %r5,0x2 # is it a indirection page?
+ je .done_test # NO, goto "done_test"
+ nill %r5,0xf000 # YES, mask out,
+ lgr %r2,%r5 # move it into the right register,
+ j .top # and read next...
+ .done_test:
+ tml %r5,0x4 # is it the done indicator?
+ je .source_test # NO! Well, then it should be the source indicator...
+ j .done # ok, lets finish it here...
+ .source_test:
+ tml %r5,0x8 # it should be a source indicator...
+ je .top # NO, ignore it...
+ lgr %r8,%r5 # r8 = r5
+ nill %r8,0xf000 # masking
+ 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+ jo 0b
+ j .top
+ .done:
+ sgr %r0,%r0 # clear register r0
+ la %r4,load_psw-.base(%r13) # load psw-address into the register
+ o %r3,4(%r4) # or load address into psw
+ st %r3,4(%r4)
+ mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0
+ tm have_diag308-.base(%r13),0x01
+ jno .no_diag308
+ diag %r0,%r0,0x308
+ .no_diag308:
+ sam31 # 31 bit mode
+ sr %r1,%r1 # erase register r1
+ sr %r2,%r2 # erase register r2
+ sigp %r1,%r2,0x12 # set cpuid to zero
+ lpsw 0 # hopefully start new kernel...
+
+ .align 8
+ load_psw:
+ .long 0x00080000,0x80000000
+ sys_msk:
+ .quad 0
+ ctlregs:
+ .rept 16
+ .quad 0
+ .endr
+ gprregs:
+ .rept 16
+ .quad 0
+ .endr
+ have_diag308:
+ .byte 0
+ .align 8
+ relocate_kernel_end:
+ .globl relocate_kernel_len
+ relocate_kernel_len:
+ .quad relocate_kernel_end - relocate_kernel
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/s390_ext.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/s390_ext.c
new file mode 100644
index 0000000000..acf93dba77
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/s390_ext.c
@@ -0,0 +1,140 @@
+/*
+ * arch/s390/kernel/s390_ext.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+
+#include <asm/lowcore.h>
+#include <asm/s390_ext.h>
+#include <asm/irq_regs.h>
+#include <asm/irq.h>
+
+/*
+ * ext_int_hash[index] is the start of the list for all external interrupts
+ * that hash to this index. With the current set of external interrupts
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
+ * iucv and 0x2603 pfault) this is always the first element.
+ */
+ext_int_info_t *ext_int_hash[256] = { NULL, };
+
+static inline int ext_hash(__u16 code)
+{
+ return (code + (code >> 9)) & 0xff;
+}
+
+int register_external_interrupt(__u16 code, ext_int_handler_t handler)
+{
+ ext_int_info_t *p;
+ int index;
+
+ p = kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
+ if (p == NULL)
+ return -ENOMEM;
+ p->code = code;
+ p->handler = handler;
+ index = ext_hash(code);
+ p->next = ext_int_hash[index];
+ ext_int_hash[index] = p;
+ return 0;
+}
+
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+ ext_int_info_t *p)
+{
+ int index;
+
+ if (p == NULL)
+ return -EINVAL;
+ p->code = code;
+ p->handler = handler;
+ index = ext_hash(code);
+ p->next = ext_int_hash[index];
+ ext_int_hash[index] = p;
+ return 0;
+}
+
+int unregister_external_interrupt(__u16 code, ext_int_handler_t handler)
+{
+ ext_int_info_t *p, *q;
+ int index;
+
+ index = ext_hash(code);
+ q = NULL;
+ p = ext_int_hash[index];
+ while (p != NULL) {
+ if (p->code == code && p->handler == handler)
+ break;
+ q = p;
+ p = p->next;
+ }
+ if (p == NULL)
+ return -ENOENT;
+ if (q != NULL)
+ q->next = p->next;
+ else
+ ext_int_hash[index] = p->next;
+ kfree(p);
+ return 0;
+}
+
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+ ext_int_info_t *p)
+{
+ ext_int_info_t *q;
+ int index;
+
+ if (p == NULL || p->code != code || p->handler != handler)
+ return -EINVAL;
+ index = ext_hash(code);
+ q = ext_int_hash[index];
+ if (p != q) {
+ while (q != NULL) {
+ if (q->next == p)
+ break;
+ q = q->next;
+ }
+ if (q == NULL)
+ return -ENOENT;
+ q->next = p->next;
+ } else
+ ext_int_hash[index] = p->next;
+ return 0;
+}
+
+void do_extint(struct pt_regs *regs, unsigned short code)
+{
+ ext_int_info_t *p;
+ int index;
+ struct pt_regs *old_regs;
+
+ old_regs = set_irq_regs(regs);
+ irq_enter();
+ asm volatile ("mc 0,0");
+ if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
+ /**
+ * Make sure that the i/o interrupt did not "overtake"
+ * the last HZ timer interrupt.
+ */
+ account_ticks(S390_lowcore.int_clock);
+ kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
+ index = ext_hash(code);
+ for (p = ext_int_hash[index]; p; p = p->next) {
+ if (likely(p->code == code))
+ p->handler(code);
+ }
+ irq_exit();
+ set_irq_regs(old_regs);
+}
+
+EXPORT_SYMBOL(register_external_interrupt);
+EXPORT_SYMBOL(unregister_external_interrupt);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/s390_ksyms.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/s390_ksyms.c
new file mode 100644
index 0000000000..7234c737f8
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/s390_ksyms.c
@@ -0,0 +1,52 @@
+/*
+ * arch/s390/kernel/s390_ksyms.c
+ *
+ * S390 version
+ */
+#include <linux/highuid.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/syscalls.h>
+#include <linux/interrupt.h>
+#include <asm/checksum.h>
+#include <asm/cpcmd.h>
+#include <asm/delay.h>
+#include <asm/pgalloc.h>
+#include <asm/setup.h>
+#ifdef CONFIG_IP_MULTICAST
+#include <net/arp.h>
+#endif
+
+/*
+ * memory management
+ */
+EXPORT_SYMBOL(_oi_bitmap);
+EXPORT_SYMBOL(_ni_bitmap);
+EXPORT_SYMBOL(_zb_findmap);
+EXPORT_SYMBOL(_sb_findmap);
+
+/*
+ * semaphore ops
+ */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+
+/*
+ * binfmt_elf loader
+ */
+extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs);
+EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(empty_zero_page);
+
+/*
+ * misc.
+ */
+EXPORT_SYMBOL(machine_flags);
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(csum_fold);
+EXPORT_SYMBOL(console_mode);
+EXPORT_SYMBOL(console_devno);
+EXPORT_SYMBOL(console_irq);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/semaphore.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/semaphore.c
new file mode 100644
index 0000000000..191303f6c1
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/semaphore.c
@@ -0,0 +1,108 @@
+/*
+ * linux/arch/s390/kernel/semaphore.c
+ *
+ * S390 version
+ * Copyright (C) 1998-2000 IBM Corporation
+ * Author(s): Martin Schwidefsky
+ *
+ * Derived from "linux/arch/i386/kernel/semaphore.c
+ * Copyright (C) 1999, Linus Torvalds
+ *
+ */
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <asm/semaphore.h>
+
+/*
+ * Atomically update sem->count. Equivalent to:
+ * old_val = sem->count.counter;
+ * new_val = ((old_val >= 0) ? old_val : 0) + incr;
+ * sem->count.counter = new_val;
+ * return old_val;
+ */
+static inline int __sem_update_count(struct semaphore *sem, int incr)
+{
+ int old_val, new_val;
+
+ asm volatile(
+ " l %0,0(%3)\n"
+ "0: ltr %1,%0\n"
+ " jhe 1f\n"
+ " lhi %1,0\n"
+ "1: ar %1,%4\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b\n"
+ : "=&d" (old_val), "=&d" (new_val), "=m" (sem->count)
+ : "a" (&sem->count), "d" (incr), "m" (sem->count)
+ : "cc");
+ return old_val;
+}
+
+/*
+ * The inline function up() incremented count but the result
+ * was <= 0. This indicates that some process is waiting on
+ * the semaphore. The semaphore is free and we'll wake the
+ * first sleeping process, so we set count to 1 unless some
+ * other cpu has called up in the meantime in which case
+ * we just increment count by 1.
+ */
+void __up(struct semaphore *sem)
+{
+ __sem_update_count(sem, 1);
+ wake_up(&sem->wait);
+}
+
+/*
+ * The inline function down() decremented count and the result
+ * was < 0. The wait loop will atomically test and update the
+ * semaphore counter following the rules:
+ * count > 0: decrement count, wake up queue and exit.
+ * count <= 0: set count to -1, go to sleep.
+ */
+void __sched __down(struct semaphore * sem)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ __set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ add_wait_queue_exclusive(&sem->wait, &wait);
+ while (__sem_update_count(sem, -1) <= 0) {
+ schedule();
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ }
+ remove_wait_queue(&sem->wait, &wait);
+ __set_task_state(tsk, TASK_RUNNING);
+ wake_up(&sem->wait);
+}
+
+/*
+ * Same as __down() with an additional test for signals.
+ * If a signal is pending the count is updated as follows:
+ * count > 0: wake up queue and exit.
+ * count <= 0: set count to 0, wake up queue and exit.
+ */
+int __sched __down_interruptible(struct semaphore * sem)
+{
+ int retval = 0;
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ __set_task_state(tsk, TASK_INTERRUPTIBLE);
+ add_wait_queue_exclusive(&sem->wait, &wait);
+ while (__sem_update_count(sem, -1) <= 0) {
+ if (signal_pending(current)) {
+ __sem_update_count(sem, 0);
+ retval = -EINTR;
+ break;
+ }
+ schedule();
+ set_task_state(tsk, TASK_INTERRUPTIBLE);
+ }
+ remove_wait_queue(&sem->wait, &wait);
+ __set_task_state(tsk, TASK_RUNNING);
+ wake_up(&sem->wait);
+ return retval;
+}
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/setup.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/setup.c
new file mode 100644
index 0000000000..290e504061
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/setup.c
@@ -0,0 +1,928 @@
+/*
+ * arch/s390/kernel/setup.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * Derived from "arch/i386/kernel/setup.c"
+ * Copyright (C) 1995, Linus Torvalds
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/bootmem.h>
+#include <linux/root_dev.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+#include <linux/kernel_stat.h>
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/pfn.h>
+#include <linux/ctype.h>
+#include <linux/reboot.h>
+
+#include <asm/ipl.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+#include <asm/mmu_context.h>
+#include <asm/cpcmd.h>
+#include <asm/lowcore.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/sections.h>
+#include <asm/ebcdic.h>
+#include <asm/compat.h>
+
+long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
+ PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
+long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+ PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
+
+/*
+ * User copy operations.
+ */
+struct uaccess_ops uaccess;
+EXPORT_SYMBOL(uaccess);
+
+/*
+ * Machine setup..
+ */
+unsigned int console_mode = 0;
+unsigned int console_devno = -1;
+unsigned int console_irq = -1;
+unsigned long machine_flags = 0;
+unsigned long elf_hwcap = 0;
+char elf_platform[ELF_PLATFORM_SIZE];
+
+struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS];
+volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
+static unsigned long __initdata memory_end;
+
+/*
+ * This is set up by the setup-routine at boot-time
+ * for S390 need to find out, what we have to setup
+ * using address 0x10400 ...
+ */
+
+#include <asm/setup.h>
+
+static struct resource code_resource = {
+ .name = "Kernel code",
+ .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource data_resource = {
+ .name = "Kernel data",
+ .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+/*
+ * cpu_init() initializes state that is per-CPU.
+ */
+void __cpuinit cpu_init(void)
+{
+ int addr = hard_smp_processor_id();
+
+ /*
+ * Store processor id in lowcore (used e.g. in timer_interrupt)
+ */
+ get_cpu_id(&S390_lowcore.cpu_data.cpu_id);
+ S390_lowcore.cpu_data.cpu_addr = addr;
+
+ /*
+ * Force FPU initialization:
+ */
+ clear_thread_flag(TIF_USEDFPU);
+ clear_used_math();
+
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
+ if (current->mm)
+ BUG();
+ enter_lazy_tlb(&init_mm, current);
+}
+
+/*
+ * condev= and conmode= setup parameter.
+ */
+
+static int __init condev_setup(char *str)
+{
+ int vdev;
+
+ vdev = simple_strtoul(str, &str, 0);
+ if (vdev >= 0 && vdev < 65536) {
+ console_devno = vdev;
+ console_irq = -1;
+ }
+ return 1;
+}
+
+__setup("condev=", condev_setup);
+
+static int __init conmode_setup(char *str)
+{
+#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
+ if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
+ SET_CONSOLE_SCLP;
+#endif
+#if defined(CONFIG_TN3215_CONSOLE)
+ if (strncmp(str, "3215", 5) == 0)
+ SET_CONSOLE_3215;
+#endif
+#if defined(CONFIG_TN3270_CONSOLE)
+ if (strncmp(str, "3270", 5) == 0)
+ SET_CONSOLE_3270;
+#endif
+ return 1;
+}
+
+__setup("conmode=", conmode_setup);
+
+static void __init conmode_default(void)
+{
+ char query_buffer[1024];
+ char *ptr;
+
+ if (MACHINE_IS_VM) {
+ cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL);
+ console_devno = simple_strtoul(query_buffer + 5, NULL, 16);
+ ptr = strstr(query_buffer, "SUBCHANNEL =");
+ console_irq = simple_strtoul(ptr + 13, NULL, 16);
+ cpcmd("QUERY TERM", query_buffer, 1024, NULL);
+ ptr = strstr(query_buffer, "CONMODE");
+ /*
+ * Set the conmode to 3215 so that the device recognition
+ * will set the cu_type of the console to 3215. If the
+ * conmode is 3270 and we don't set it back then both
+ * 3215 and the 3270 driver will try to access the console
+ * device (3215 as console and 3270 as normal tty).
+ */
+ cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
+ if (ptr == NULL) {
+#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
+ SET_CONSOLE_SCLP;
+#endif
+ return;
+ }
+ if (strncmp(ptr + 8, "3270", 4) == 0) {
+#if defined(CONFIG_TN3270_CONSOLE)
+ SET_CONSOLE_3270;
+#elif defined(CONFIG_TN3215_CONSOLE)
+ SET_CONSOLE_3215;
+#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
+ SET_CONSOLE_SCLP;
+#endif
+ } else if (strncmp(ptr + 8, "3215", 4) == 0) {
+#if defined(CONFIG_TN3215_CONSOLE)
+ SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+ SET_CONSOLE_3270;
+#elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
+ SET_CONSOLE_SCLP;
+#endif
+ }
+ } else if (MACHINE_IS_P390) {
+#if defined(CONFIG_TN3215_CONSOLE)
+ SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+ SET_CONSOLE_3270;
+#endif
+ } else {
+#if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE)
+ SET_CONSOLE_SCLP;
+#endif
+ }
+}
+
+#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
+static void __init setup_zfcpdump(unsigned int console_devno)
+{
+ static char str[64];
+
+ if (ipl_info.type != IPL_TYPE_FCP_DUMP)
+ return;
+ if (console_devno != -1)
+ sprintf(str, "cio_ignore=all,!0.0.%04x,!0.0.%04x",
+ ipl_info.data.fcp.dev_id.devno, console_devno);
+ else
+ sprintf(str, "cio_ignore=all,!0.0.%04x",
+ ipl_info.data.fcp.dev_id.devno);
+ strcat(COMMAND_LINE, " ");
+ strcat(COMMAND_LINE, str);
+ console_loglevel = 2;
+}
+#else
+static inline void setup_zfcpdump(unsigned int console_devno) {}
+#endif /* CONFIG_ZFCPDUMP */
+
+ /*
+ * Reboot, halt and power_off stubs. They just call _machine_restart,
+ * _machine_halt or _machine_power_off.
+ */
+
+void machine_restart(char *command)
+{
+ if ((!in_interrupt() && !in_atomic()) || oops_in_progress)
+ /*
+ * Only unblank the console if we are called in enabled
+ * context or a bust_spinlocks cleared the way for us.
+ */
+ console_unblank();
+ _machine_restart(command);
+}
+
+void machine_halt(void)
+{
+ if (!in_interrupt() || oops_in_progress)
+ /*
+ * Only unblank the console if we are called in enabled
+ * context or a bust_spinlocks cleared the way for us.
+ */
+ console_unblank();
+ _machine_halt();
+}
+
+void machine_power_off(void)
+{
+ if (!in_interrupt() || oops_in_progress)
+ /*
+ * Only unblank the console if we are called in enabled
+ * context or a bust_spinlocks cleared the way for us.
+ */
+ console_unblank();
+ _machine_power_off();
+}
+
+/*
+ * Dummy power off function.
+ */
+void (*pm_power_off)(void) = machine_power_off;
+
+static int __init early_parse_mem(char *p)
+{
+ memory_end = memparse(p, &p);
+ return 0;
+}
+early_param("mem", early_parse_mem);
+
+/*
+ * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
+ */
+static int __init early_parse_ipldelay(char *p)
+{
+ unsigned long delay = 0;
+
+ delay = simple_strtoul(p, &p, 0);
+
+ switch (*p) {
+ case 's':
+ case 'S':
+ delay *= 1000000;
+ break;
+ case 'm':
+ case 'M':
+ delay *= 60 * 1000000;
+ }
+
+ /* now wait for the requested amount of time */
+ udelay(delay);
+
+ return 0;
+}
+early_param("ipldelay", early_parse_ipldelay);
+
+#ifdef CONFIG_S390_SWITCH_AMODE
+unsigned int switch_amode = 0;
+EXPORT_SYMBOL_GPL(switch_amode);
+
+static void set_amode_and_uaccess(unsigned long user_amode,
+ unsigned long user32_amode)
+{
+ psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode |
+ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+ PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+#ifdef CONFIG_COMPAT
+ psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode |
+ PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+ PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+ psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode |
+ PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+ PSW32_MASK_PSTATE;
+#endif
+ psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+ PSW_MASK_MCHECK | PSW_DEFAULT_KEY;
+
+ if (MACHINE_HAS_MVCOS) {
+ printk("mvcos available.\n");
+ memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
+ } else {
+ printk("mvcos not available.\n");
+ memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
+ }
+}
+
+/*
+ * Switch kernel/user addressing modes?
+ */
+static int __init early_parse_switch_amode(char *p)
+{
+ switch_amode = 1;
+ return 0;
+}
+early_param("switch_amode", early_parse_switch_amode);
+
+#else /* CONFIG_S390_SWITCH_AMODE */
+static inline void set_amode_and_uaccess(unsigned long user_amode,
+ unsigned long user32_amode)
+{
+}
+#endif /* CONFIG_S390_SWITCH_AMODE */
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+unsigned int s390_noexec = 0;
+EXPORT_SYMBOL_GPL(s390_noexec);
+
+/*
+ * Enable execute protection?
+ */
+static int __init early_parse_noexec(char *p)
+{
+ if (!strncmp(p, "off", 3))
+ return 0;
+ switch_amode = 1;
+ s390_noexec = 1;
+ return 0;
+}
+early_param("noexec", early_parse_noexec);
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
+static void setup_addressing_mode(void)
+{
+ if (s390_noexec) {
+ printk("S390 execute protection active, ");
+ set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY);
+ } else if (switch_amode) {
+ printk("S390 address spaces switched, ");
+ set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
+ }
+#ifdef CONFIG_TRACE_IRQFLAGS
+ sysc_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
+ io_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
+#endif
+}
+
+static void __init
+setup_lowcore(void)
+{
+ struct _lowcore *lc;
+ int lc_pages;
+
+ /*
+ * Setup lowcore for boot cpu
+ */
+ lc_pages = sizeof(void *) == 8 ? 2 : 1;
+ lc = (struct _lowcore *)
+ __alloc_bootmem(lc_pages * PAGE_SIZE, lc_pages * PAGE_SIZE, 0);
+ memset(lc, 0, lc_pages * PAGE_SIZE);
+ lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+ lc->restart_psw.addr =
+ PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
+ if (switch_amode)
+ lc->restart_psw.mask |= PSW_ASC_HOME;
+ lc->external_new_psw.mask = psw_kernel_bits;
+ lc->external_new_psw.addr =
+ PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
+ lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
+ lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
+ lc->program_new_psw.mask = psw_kernel_bits;
+ lc->program_new_psw.addr =
+ PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
+ lc->mcck_new_psw.mask =
+ psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
+ lc->mcck_new_psw.addr =
+ PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
+ lc->io_new_psw.mask = psw_kernel_bits;
+ lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
+ lc->ipl_device = S390_lowcore.ipl_device;
+ lc->jiffy_timer = -1LL;
+ lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
+ lc->async_stack = (unsigned long)
+ __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
+ lc->panic_stack = (unsigned long)
+ __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
+ lc->current_task = (unsigned long) init_thread_union.thread_info.task;
+ lc->thread_info = (unsigned long) &init_thread_union;
+#ifndef CONFIG_64BIT
+ if (MACHINE_HAS_IEEE) {
+ lc->extended_save_area_addr = (__u32)
+ __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
+ /* enable extended save area */
+ __ctl_set_bit(14, 29);
+ }
+#endif
+ set_prefix((u32)(unsigned long) lc);
+}
+
+static void __init
+setup_resources(void)
+{
+ struct resource *res, *sub_res;
+ int i;
+
+ code_resource.start = (unsigned long) &_text;
+ code_resource.end = (unsigned long) &_etext - 1;
+ data_resource.start = (unsigned long) &_etext;
+ data_resource.end = (unsigned long) &_edata - 1;
+
+ for (i = 0; i < MEMORY_CHUNKS; i++) {
+ if (!memory_chunk[i].size)
+ continue;
+ res = alloc_bootmem_low(sizeof(struct resource));
+ res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+ switch (memory_chunk[i].type) {
+ case CHUNK_READ_WRITE:
+ res->name = "System RAM";
+ break;
+ case CHUNK_READ_ONLY:
+ res->name = "System ROM";
+ res->flags |= IORESOURCE_READONLY;
+ break;
+ default:
+ res->name = "reserved";
+ }
+ res->start = memory_chunk[i].addr;
+ res->end = memory_chunk[i].addr + memory_chunk[i].size - 1;
+ request_resource(&iomem_resource, res);
+
+ if (code_resource.start >= res->start &&
+ code_resource.start <= res->end &&
+ code_resource.end > res->end) {
+ sub_res = alloc_bootmem_low(sizeof(struct resource));
+ memcpy(sub_res, &code_resource,
+ sizeof(struct resource));
+ sub_res->end = res->end;
+ code_resource.start = res->end + 1;
+ request_resource(res, sub_res);
+ }
+
+ if (code_resource.start >= res->start &&
+ code_resource.start <= res->end &&
+ code_resource.end <= res->end)
+ request_resource(res, &code_resource);
+
+ if (data_resource.start >= res->start &&
+ data_resource.start <= res->end &&
+ data_resource.end > res->end) {
+ sub_res = alloc_bootmem_low(sizeof(struct resource));
+ memcpy(sub_res, &data_resource,
+ sizeof(struct resource));
+ sub_res->end = res->end;
+ data_resource.start = res->end + 1;
+ request_resource(res, sub_res);
+ }
+
+ if (data_resource.start >= res->start &&
+ data_resource.start <= res->end &&
+ data_resource.end <= res->end)
+ request_resource(res, &data_resource);
+ }
+}
+
+unsigned long real_memory_size;
+EXPORT_SYMBOL_GPL(real_memory_size);
+
+static void __init setup_memory_end(void)
+{
+ unsigned long memory_size;
+ unsigned long max_mem;
+ int i;
+
+#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
+ if (ipl_info.type == IPL_TYPE_FCP_DUMP)
+ memory_end = ZFCPDUMP_HSA_SIZE;
+#endif
+ memory_size = 0;
+ memory_end &= PAGE_MASK;
+
+ max_mem = memory_end ? min(VMEM_MAX_PHYS, memory_end) : VMEM_MAX_PHYS;
+ memory_end = min(max_mem, memory_end);
+
+ /*
+ * Make sure all chunks are MAX_ORDER aligned so we don't need the
+ * extra checks that HOLES_IN_ZONE would require.
+ */
+ for (i = 0; i < MEMORY_CHUNKS; i++) {
+ unsigned long start, end;
+ struct mem_chunk *chunk;
+ unsigned long align;
+
+ chunk = &memory_chunk[i];
+ align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1);
+ start = (chunk->addr + align - 1) & ~(align - 1);
+ end = (chunk->addr + chunk->size) & ~(align - 1);
+ if (start >= end)
+ memset(chunk, 0, sizeof(*chunk));
+ else {
+ chunk->addr = start;
+ chunk->size = end - start;
+ }
+ }
+
+ for (i = 0; i < MEMORY_CHUNKS; i++) {
+ struct mem_chunk *chunk = &memory_chunk[i];
+
+ real_memory_size = max(real_memory_size,
+ chunk->addr + chunk->size);
+ if (chunk->addr >= max_mem) {
+ memset(chunk, 0, sizeof(*chunk));
+ continue;
+ }
+ if (chunk->addr + chunk->size > max_mem)
+ chunk->size = max_mem - chunk->addr;
+ memory_size = max(memory_size, chunk->addr + chunk->size);
+ }
+ if (!memory_end)
+ memory_end = memory_size;
+}
+
+static void __init
+setup_memory(void)
+{
+ unsigned long bootmap_size;
+ unsigned long start_pfn, end_pfn;
+ int i;
+
+ /*
+ * partially used pages are not usable - thus
+ * we are rounding upwards:
+ */
+ start_pfn = PFN_UP(__pa(&_end));
+ end_pfn = max_pfn = PFN_DOWN(memory_end);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /*
+ * Move the initrd in case the bitmap of the bootmem allocater
+ * would overwrite it.
+ */
+
+ if (INITRD_START && INITRD_SIZE) {
+ unsigned long bmap_size;
+ unsigned long start;
+
+ bmap_size = bootmem_bootmap_pages(end_pfn - start_pfn + 1);
+ bmap_size = PFN_PHYS(bmap_size);
+
+ if (PFN_PHYS(start_pfn) + bmap_size > INITRD_START) {
+ start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE;
+
+ if (start + INITRD_SIZE > memory_end) {
+ printk("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\n"
+ "disabling initrd\n",
+ start + INITRD_SIZE, memory_end);
+ INITRD_START = INITRD_SIZE = 0;
+ } else {
+ printk("Moving initrd (0x%08lx -> 0x%08lx, "
+ "size: %ld)\n",
+ INITRD_START, start, INITRD_SIZE);
+ memmove((void *) start, (void *) INITRD_START,
+ INITRD_SIZE);
+ INITRD_START = start;
+ }
+ }
+ }
+#endif
+
+ /*
+ * Initialize the boot-time allocator
+ */
+ bootmap_size = init_bootmem(start_pfn, end_pfn);
+
+ /*
+ * Register RAM areas with the bootmem allocator.
+ */
+
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+ unsigned long start_chunk, end_chunk, pfn;
+
+ if (memory_chunk[i].type != CHUNK_READ_WRITE)
+ continue;
+ start_chunk = PFN_DOWN(memory_chunk[i].addr);
+ end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size) - 1;
+ end_chunk = min(end_chunk, end_pfn);
+ if (start_chunk >= end_chunk)
+ continue;
+ add_active_range(0, start_chunk, end_chunk);
+ pfn = max(start_chunk, start_pfn);
+ for (; pfn <= end_chunk; pfn++)
+ page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY);
+ }
+
+ psw_set_key(PAGE_DEFAULT_KEY);
+
+ free_bootmem_with_active_regions(0, max_pfn);
+
+ /*
+ * Reserve memory used for lowcore/command line/kernel image.
+ */
+ reserve_bootmem(0, (unsigned long)_ehead, BOOTMEM_DEFAULT);
+ reserve_bootmem((unsigned long)_stext,
+ PFN_PHYS(start_pfn) - (unsigned long)_stext,
+ BOOTMEM_DEFAULT);
+ /*
+ * Reserve the bootmem bitmap itself as well. We do this in two
+ * steps (first step was init_bootmem()) because this catches
+ * the (very unlikely) case of us accidentally initializing the
+ * bootmem allocator with an invalid RAM area.
+ */
+ reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size,
+ BOOTMEM_DEFAULT);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (INITRD_START && INITRD_SIZE) {
+ if (INITRD_START + INITRD_SIZE <= memory_end) {
+ reserve_bootmem(INITRD_START, INITRD_SIZE,
+ BOOTMEM_DEFAULT);
+ initrd_start = INITRD_START;
+ initrd_end = initrd_start + INITRD_SIZE;
+ } else {
+ printk("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ initrd_start + INITRD_SIZE, memory_end);
+ initrd_start = initrd_end = 0;
+ }
+ }
+#endif
+}
+
+static __init unsigned int stfl(void)
+{
+ asm volatile(
+ " .insn s,0xb2b10000,0(0)\n" /* stfl */
+ "0:\n"
+ EX_TABLE(0b,0b));
+ return S390_lowcore.stfl_fac_list;
+}
+
+static __init int stfle(unsigned long long *list, int doublewords)
+{
+ typedef struct { unsigned long long _[doublewords]; } addrtype;
+ register unsigned long __nr asm("0") = doublewords - 1;
+
+ asm volatile(".insn s,0xb2b00000,%0" /* stfle */
+ : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
+ return __nr + 1;
+}
+
+/*
+ * Setup hardware capabilities.
+ */
+static void __init setup_hwcaps(void)
+{
+ static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
+ struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
+ unsigned long long facility_list_extended;
+ unsigned int facility_list;
+ int i;
+
+ facility_list = stfl();
+ /*
+ * The store facility list bits numbers as found in the principles
+ * of operation are numbered with bit 1UL<<31 as number 0 to
+ * bit 1UL<<0 as number 31.
+ * Bit 0: instructions named N3, "backported" to esa-mode
+ * Bit 2: z/Architecture mode is active
+ * Bit 7: the store-facility-list-extended facility is installed
+ * Bit 17: the message-security assist is installed
+ * Bit 19: the long-displacement facility is installed
+ * Bit 21: the extended-immediate facility is installed
+ * These get translated to:
+ * HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1,
+ * HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3,
+ * HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5.
+ */
+ for (i = 0; i < 6; i++)
+ if (facility_list & (1UL << (31 - stfl_bits[i])))
+ elf_hwcap |= 1UL << i;
+
+ /*
+ * Check for additional facilities with store-facility-list-extended.
+ * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0
+ * and 1ULL<<0 as bit 63. Bits 0-31 contain the same information
+ * as stored by stfl, bits 32-xxx contain additional facilities.
+ * How many facility words are stored depends on the number of
+ * doublewords passed to the instruction. The additional facilites
+ * are:
+ * Bit 43: decimal floating point facility is installed
+ * translated to:
+ * HWCAP_S390_DFP bit 6.
+ */
+ if ((elf_hwcap & (1UL << 2)) &&
+ stfle(&facility_list_extended, 1) > 0) {
+ if (facility_list_extended & (1ULL << (64 - 43)))
+ elf_hwcap |= 1UL << 6;
+ }
+
+ switch (cpuinfo->cpu_id.machine) {
+ case 0x9672:
+#if !defined(CONFIG_64BIT)
+ default: /* Use "g5" as default for 31 bit kernels. */
+#endif
+ strcpy(elf_platform, "g5");
+ break;
+ case 0x2064:
+ case 0x2066:
+#if defined(CONFIG_64BIT)
+ default: /* Use "z900" as default for 64 bit kernels. */
+#endif
+ strcpy(elf_platform, "z900");
+ break;
+ case 0x2084:
+ case 0x2086:
+ strcpy(elf_platform, "z990");
+ break;
+ case 0x2094:
+ strcpy(elf_platform, "z9-109");
+ break;
+ }
+}
+
+/*
+ * Setup function called from init/main.c just after the banner
+ * was printed.
+ */
+
+void __init
+setup_arch(char **cmdline_p)
+{
+ /*
+ * print what head.S has found out about the machine
+ */
+#ifndef CONFIG_64BIT
+ printk((MACHINE_IS_VM) ?
+ "We are running under VM (31 bit mode)\n" :
+ "We are running native (31 bit mode)\n");
+ printk((MACHINE_HAS_IEEE) ?
+ "This machine has an IEEE fpu\n" :
+ "This machine has no IEEE fpu\n");
+#else /* CONFIG_64BIT */
+ printk((MACHINE_IS_VM) ?
+ "We are running under VM (64 bit mode)\n" :
+ "We are running native (64 bit mode)\n");
+#endif /* CONFIG_64BIT */
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+
+ *cmdline_p = COMMAND_LINE;
+ *(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0';
+
+ ROOT_DEV = Root_RAM0;
+
+ init_mm.start_code = PAGE_OFFSET;
+ init_mm.end_code = (unsigned long) &_etext;
+ init_mm.end_data = (unsigned long) &_edata;
+ init_mm.brk = (unsigned long) &_end;
+
+ if (MACHINE_HAS_MVCOS)
+ memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess));
+ else
+ memcpy(&uaccess, &uaccess_std, sizeof(uaccess));
+
+ parse_early_param();
+
+ setup_ipl();
+ setup_memory_end();
+ setup_addressing_mode();
+ setup_memory();
+ setup_resources();
+ setup_lowcore();
+
+ cpu_init();
+ __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
+
+ /*
+ * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
+ */
+ setup_hwcaps();
+
+ /*
+ * Create kernel page tables and switch to virtual addressing.
+ */
+ paging_init();
+
+ /* Setup default console */
+ conmode_default();
+
+ /* Setup zfcpdump support */
+ setup_zfcpdump(console_devno);
+}
+
+void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)
+{
+ printk(KERN_INFO "cpu %d "
+#ifdef CONFIG_SMP
+ "phys_idx=%d "
+#endif
+ "vers=%02X ident=%06X machine=%04X unused=%04X\n",
+ cpuinfo->cpu_nr,
+#ifdef CONFIG_SMP
+ cpuinfo->cpu_addr,
+#endif
+ cpuinfo->cpu_id.version,
+ cpuinfo->cpu_id.ident,
+ cpuinfo->cpu_id.machine,
+ cpuinfo->cpu_id.unused);
+}
+
+/*
+ * show_cpuinfo - Get information on one CPU for use by procfs.
+ */
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+ static const char *hwcap_str[7] = {
+ "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp"
+ };
+ struct cpuinfo_S390 *cpuinfo;
+ unsigned long n = (unsigned long) v - 1;
+ int i;
+
+ s390_adjust_jiffies();
+ preempt_disable();
+ if (!n) {
+ seq_printf(m, "vendor_id : IBM/S390\n"
+ "# processors : %i\n"
+ "bogomips per cpu: %lu.%02lu\n",
+ num_online_cpus(), loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ))%100);
+ seq_puts(m, "features\t: ");
+ for (i = 0; i < 7; i++)
+ if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
+ seq_printf(m, "%s ", hwcap_str[i]);
+ seq_puts(m, "\n");
+ }
+
+ if (cpu_online(n)) {
+#ifdef CONFIG_SMP
+ if (smp_processor_id() == n)
+ cpuinfo = &S390_lowcore.cpu_data;
+ else
+ cpuinfo = &lowcore_ptr[n]->cpu_data;
+#else
+ cpuinfo = &S390_lowcore.cpu_data;
+#endif
+ seq_printf(m, "processor %li: "
+ "version = %02X, "
+ "identification = %06X, "
+ "machine = %04X\n",
+ n, cpuinfo->cpu_id.version,
+ cpuinfo->cpu_id.ident,
+ cpuinfo->cpu_id.machine);
+ }
+ preempt_enable();
+ return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+ return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL;
+}
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return c_start(m, pos);
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+const struct seq_operations cpuinfo_op = {
+ .start = c_start,
+ .next = c_next,
+ .stop = c_stop,
+ .show = show_cpuinfo,
+};
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/signal.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/signal.c
new file mode 100644
index 0000000000..4449bf32cb
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/signal.c
@@ -0,0 +1,522 @@
+/*
+ * arch/s390/kernel/signal.c
+ *
+ * Copyright (C) IBM Corp. 1999,2006
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ * Based on Intel version
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/tty.h>
+#include <linux/personality.h>
+#include <linux/binfmts.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/lowcore.h>
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+
+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;
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys_sigsuspend(int history0, int history1, old_sigset_t mask)
+{
+ mask &= _BLOCKABLE;
+ spin_lock_irq(&current->sighand->siglock);
+ current->saved_sigmask = current->blocked;
+ siginitset(&current->blocked, mask);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+
+ return -ERESTARTNOHAND;
+}
+
+asmlinkage 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) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
+ return -EFAULT;
+ 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) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+asmlinkage long
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ return do_sigaltstack(uss, uoss, regs->gprs[15]);
+}
+
+
+
+/* Returns non-zero on fault. */
+static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
+{
+ _sigregs user_sregs;
+
+ save_access_regs(current->thread.acrs);
+
+ /* Copy a 'clean' PSW mask to the user to avoid leaking
+ information about whether PER is currently on. */
+ user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask);
+ user_sregs.regs.psw.addr = regs->psw.addr;
+ memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
+ memcpy(&user_sregs.regs.acrs, current->thread.acrs,
+ sizeof(sregs->regs.acrs));
+ /*
+ * We have to store the fp registers to current->thread.fp_regs
+ * to merge them with the emulated registers.
+ */
+ save_fp_regs(&current->thread.fp_regs);
+ memcpy(&user_sregs.fpregs, &current->thread.fp_regs,
+ sizeof(s390_fp_regs));
+ return __copy_to_user(sregs, &user_sregs, sizeof(_sigregs));
+}
+
+/* Returns positive number on error */
+static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
+{
+ int err;
+ _sigregs user_sregs;
+
+ /* Alwys make any pending restarted system call return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+ err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs));
+ if (err)
+ return err;
+ regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask,
+ user_sregs.regs.psw.mask);
+ regs->psw.addr = PSW_ADDR_AMODE | user_sregs.regs.psw.addr;
+ memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
+ memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
+ sizeof(sregs->regs.acrs));
+ restore_access_regs(current->thread.acrs);
+
+ memcpy(&current->thread.fp_regs, &user_sregs.fpregs,
+ sizeof(s390_fp_regs));
+ current->thread.fp_regs.fpc &= FPC_VALID_MASK;
+
+ restore_fp_regs(&current->thread.fp_regs);
+ regs->trap = -1; /* disable syscall checks */
+ return 0;
+}
+
+asmlinkage long sys_sigreturn(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ sigframe __user *frame = (sigframe __user *)regs->gprs[15];
+ sigset_t set;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
+ goto badframe;
+
+ 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 badframe;
+
+ return regs->gprs[2];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+asmlinkage long sys_rt_sigreturn(void)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15];
+ sigset_t set;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (restore_sigregs(regs, &frame->uc.uc_mcontext))
+ goto badframe;
+
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL,
+ regs->gprs[15]) == -EFAULT)
+ goto badframe;
+ return regs->gprs[2];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+
+/*
+ * Determine which stack to use..
+ */
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+ unsigned long sp;
+
+ /* Default to using normal stack */
+ sp = regs->gprs[15];
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (! sas_ss_flags(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+ }
+
+ /* This is the legacy signal stack switching. */
+ else if (!user_mode(regs) &&
+ !(ka->sa.sa_flags & SA_RESTORER) &&
+ ka->sa.sa_restorer) {
+ sp = (unsigned long) ka->sa.sa_restorer;
+ }
+
+ return (void __user *)((sp - frame_size) & -8ul);
+}
+
+static inline int map_signal(int sig)
+{
+ if (current_thread_info()->exec_domain
+ && current_thread_info()->exec_domain->signal_invmap
+ && sig < 32)
+ return current_thread_info()->exec_domain->signal_invmap[sig];
+ else
+ return sig;
+}
+
+static int setup_frame(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs * regs)
+{
+ sigframe __user *frame;
+
+ frame = get_sigframe(ka, regs, sizeof(sigframe));
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe)))
+ goto give_sigsegv;
+
+ if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE))
+ goto give_sigsegv;
+
+ if (save_sigregs(regs, &frame->sregs))
+ goto give_sigsegv;
+ if (__put_user(&frame->sregs, &frame->sc.sregs))
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ regs->gprs[14] = (unsigned long)
+ ka->sa.sa_restorer | PSW_ADDR_AMODE;
+ } else {
+ regs->gprs[14] = (unsigned long)
+ frame->retcode | PSW_ADDR_AMODE;
+ if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
+ (u16 __user *)(frame->retcode)))
+ goto give_sigsegv;
+ }
+
+ /* Set up backchain. */
+ if (__put_user(regs->gprs[15], (addr_t __user *) frame))
+ goto give_sigsegv;
+
+ /* Set up registers for signal handler */
+ regs->gprs[15] = (unsigned long) frame;
+ regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
+
+ regs->gprs[2] = map_signal(sig);
+ regs->gprs[3] = (unsigned long) &frame->sc;
+
+ /* We forgot to include these in the sigcontext.
+ To avoid breaking binary compatibility, they are passed as args. */
+ regs->gprs[4] = current->thread.trap_no;
+ regs->gprs[5] = current->thread.prot_addr;
+
+ /* Place signal number on stack to allow backtrace from handler. */
+ if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
+ goto give_sigsegv;
+ return 0;
+
+give_sigsegv:
+ force_sigsegv(sig, current);
+ return -EFAULT;
+}
+
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs * regs)
+{
+ int err = 0;
+ rt_sigframe __user *frame;
+
+ frame = get_sigframe(ka, regs, sizeof(rt_sigframe));
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe)))
+ goto give_sigsegv;
+
+ if (copy_siginfo_to_user(&frame->info, info))
+ goto give_sigsegv;
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(NULL, &frame->uc.uc_link);
+ err |= __put_user((void __user *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->gprs[15]),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= save_sigregs(regs, &frame->uc.uc_mcontext);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ regs->gprs[14] = (unsigned long)
+ ka->sa.sa_restorer | PSW_ADDR_AMODE;
+ } else {
+ regs->gprs[14] = (unsigned long)
+ frame->retcode | PSW_ADDR_AMODE;
+ if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
+ (u16 __user *)(frame->retcode)))
+ goto give_sigsegv;
+ }
+
+ /* Set up backchain. */
+ if (__put_user(regs->gprs[15], (addr_t __user *) frame))
+ goto give_sigsegv;
+
+ /* Set up registers for signal handler */
+ regs->gprs[15] = (unsigned long) frame;
+ regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
+
+ regs->gprs[2] = map_signal(sig);
+ regs->gprs[3] = (unsigned long) &frame->info;
+ regs->gprs[4] = (unsigned long) &frame->uc;
+ return 0;
+
+give_sigsegv:
+ force_sigsegv(sig, current);
+ return -EFAULT;
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+static int
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+{
+ int ret;
+
+ /* Set up the stack frame */
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
+ else
+ ret = setup_frame(sig, ka, oldset, regs);
+
+ if (ret == 0) {
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ }
+
+ return ret;
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+void do_signal(struct pt_regs *regs)
+{
+ unsigned long retval = 0, continue_addr = 0, restart_addr = 0;
+ siginfo_t info;
+ int signr;
+ struct k_sigaction ka;
+ sigset_t *oldset;
+
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (!user_mode(regs))
+ return;
+
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
+ oldset = &current->blocked;
+
+ /* Are we from a system call? */
+ if (regs->trap == __LC_SVC_OLD_PSW) {
+ continue_addr = regs->psw.addr;
+ restart_addr = continue_addr - regs->ilc;
+ retval = regs->gprs[2];
+
+ /* Prepare for system call restart. We do this here so that a
+ debugger will see the already changed PSW. */
+ switch (retval) {
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ regs->gprs[2] = regs->orig_gpr2;
+ regs->psw.addr = restart_addr;
+ break;
+ case -ERESTART_RESTARTBLOCK:
+ regs->gprs[2] = -EINTR;
+ }
+ regs->trap = -1; /* Don't deal with this again. */
+ }
+
+ /* Get signal to deliver. When running under ptrace, at this point
+ the debugger may change all our registers ... */
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+ /* Depending on the signal settings we may need to revert the
+ decision to restart the system call. */
+ if (signr > 0 && regs->psw.addr == restart_addr) {
+ if (retval == -ERESTARTNOHAND
+ || (retval == -ERESTARTSYS
+ && !(current->sighand->action[signr-1].sa.sa_flags
+ & SA_RESTART))) {
+ regs->gprs[2] = -EINTR;
+ regs->psw.addr = continue_addr;
+ }
+ }
+
+ if (signr > 0) {
+ /* Whee! Actually deliver the signal. */
+ int ret;
+#ifdef CONFIG_COMPAT
+ if (test_thread_flag(TIF_31BIT)) {
+ extern int handle_signal32(unsigned long sig,
+ struct k_sigaction *ka,
+ siginfo_t *info,
+ sigset_t *oldset,
+ struct pt_regs *regs);
+ ret = handle_signal32(signr, &ka, &info, oldset, regs);
+ }
+ else
+#endif
+ ret = handle_signal(signr, &ka, &info, oldset, regs);
+ if (!ret) {
+ /*
+ * A signal was successfully delivered; the saved
+ * sigmask will have been stored in the signal frame,
+ * and will be restored by sigreturn, so we can simply
+ * clear the TIF_RESTORE_SIGMASK flag.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+
+ /*
+ * If we would have taken a single-step trap
+ * for a normal instruction, act like we took
+ * one for the handler setup.
+ */
+ if (current->thread.per_info.single_step)
+ set_thread_flag(TIF_SINGLE_STEP);
+ }
+ return;
+ }
+
+ /*
+ * If there's no signal to deliver, we just put the saved sigmask back.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ }
+
+ /* Restart a different system call. */
+ if (retval == -ERESTART_RESTARTBLOCK
+ && regs->psw.addr == continue_addr) {
+ regs->gprs[2] = __NR_restart_syscall;
+ set_thread_flag(TIF_RESTART_SVC);
+ }
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/smp.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/smp.c
new file mode 100644
index 0000000000..8f894d380a
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/smp.c
@@ -0,0 +1,1103 @@
+/*
+ * arch/s390/kernel/smp.c
+ *
+ * Copyright IBM Corp. 1999,2007
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ * Heiko Carstens (heiko.carstens@de.ibm.com)
+ *
+ * based on other smp stuff by
+ * (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net>
+ * (c) 1998 Ingo Molnar
+ *
+ * We work with logical cpu numbering everywhere we can. The only
+ * functions using the real cpu address (got from STAP) are the sigp
+ * functions. For all other functions we use the identity mapping.
+ * That means that cpu_number_map[i] == i for every cpu. cpu_number_map is
+ * used e.g. to find the idle task belonging to a logical cpu. Every array
+ * in the kernel is sorted by the logical cpu number and not by the physical
+ * one which is causing all the confusion with __cpu_logical_map and
+ * cpu_number_map in other architectures.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#include <linux/cache.h>
+#include <linux/interrupt.h>
+#include <linux/cpu.h>
+#include <linux/timex.h>
+#include <linux/bootmem.h>
+#include <asm/ipl.h>
+#include <asm/setup.h>
+#include <asm/sigp.h>
+#include <asm/pgalloc.h>
+#include <asm/irq.h>
+#include <asm/s390_ext.h>
+#include <asm/cpcmd.h>
+#include <asm/tlbflush.h>
+#include <asm/timer.h>
+#include <asm/lowcore.h>
+#include <asm/sclp.h>
+#include <asm/cpu.h>
+
+/*
+ * An array with a pointer the lowcore of every CPU.
+ */
+struct _lowcore *lowcore_ptr[NR_CPUS];
+EXPORT_SYMBOL(lowcore_ptr);
+
+cpumask_t cpu_online_map = CPU_MASK_NONE;
+EXPORT_SYMBOL(cpu_online_map);
+
+cpumask_t cpu_possible_map = CPU_MASK_ALL;
+EXPORT_SYMBOL(cpu_possible_map);
+
+static struct task_struct *current_set[NR_CPUS];
+
+static u8 smp_cpu_type;
+static int smp_use_sigp_detection;
+
+enum s390_cpu_state {
+ CPU_STATE_STANDBY,
+ CPU_STATE_CONFIGURED,
+};
+
+#ifdef CONFIG_HOTPLUG_CPU
+static DEFINE_MUTEX(smp_cpu_state_mutex);
+#endif
+static int smp_cpu_state[NR_CPUS];
+
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
+DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
+
+static void smp_ext_bitcall(int, ec_bit_sig);
+
+/*
+ * Structure and data for __smp_call_function_map(). This is designed to
+ * minimise static memory requirements. It also looks cleaner.
+ */
+static DEFINE_SPINLOCK(call_lock);
+
+struct call_data_struct {
+ void (*func) (void *info);
+ void *info;
+ cpumask_t started;
+ cpumask_t finished;
+ int wait;
+};
+
+static struct call_data_struct *call_data;
+
+/*
+ * 'Call function' interrupt callback
+ */
+static void do_call_function(void)
+{
+ void (*func) (void *info) = call_data->func;
+ void *info = call_data->info;
+ int wait = call_data->wait;
+
+ cpu_set(smp_processor_id(), call_data->started);
+ (*func)(info);
+ if (wait)
+ cpu_set(smp_processor_id(), call_data->finished);;
+}
+
+static void __smp_call_function_map(void (*func) (void *info), void *info,
+ int nonatomic, int wait, cpumask_t map)
+{
+ struct call_data_struct data;
+ int cpu, local = 0;
+
+ /*
+ * Can deadlock when interrupts are disabled or if in wrong context.
+ */
+ WARN_ON(irqs_disabled() || in_irq());
+
+ /*
+ * Check for local function call. We have to have the same call order
+ * as in on_each_cpu() because of machine_restart_smp().
+ */
+ if (cpu_isset(smp_processor_id(), map)) {
+ local = 1;
+ cpu_clear(smp_processor_id(), map);
+ }
+
+ cpus_and(map, map, cpu_online_map);
+ if (cpus_empty(map))
+ goto out;
+
+ data.func = func;
+ data.info = info;
+ data.started = CPU_MASK_NONE;
+ data.wait = wait;
+ if (wait)
+ data.finished = CPU_MASK_NONE;
+
+ spin_lock(&call_lock);
+ call_data = &data;
+
+ for_each_cpu_mask(cpu, map)
+ smp_ext_bitcall(cpu, ec_call_function);
+
+ /* Wait for response */
+ while (!cpus_equal(map, data.started))
+ cpu_relax();
+ if (wait)
+ while (!cpus_equal(map, data.finished))
+ cpu_relax();
+ spin_unlock(&call_lock);
+out:
+ if (local) {
+ local_irq_disable();
+ func(info);
+ local_irq_enable();
+ }
+}
+
+/*
+ * smp_call_function:
+ * @func: the function to run; this must be fast and non-blocking
+ * @info: an arbitrary pointer to pass to the function
+ * @nonatomic: unused
+ * @wait: if true, wait (atomically) until function has completed on other CPUs
+ *
+ * Run a function on all other CPUs.
+ *
+ * You must not call this function with disabled interrupts, from a
+ * hardware interrupt handler or from a bottom half.
+ */
+int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
+ int wait)
+{
+ cpumask_t map;
+
+ preempt_disable();
+ map = cpu_online_map;
+ cpu_clear(smp_processor_id(), map);
+ __smp_call_function_map(func, info, nonatomic, wait, map);
+ preempt_enable();
+ return 0;
+}
+EXPORT_SYMBOL(smp_call_function);
+
+/*
+ * smp_call_function_single:
+ * @cpu: the CPU where func should run
+ * @func: the function to run; this must be fast and non-blocking
+ * @info: an arbitrary pointer to pass to the function
+ * @nonatomic: unused
+ * @wait: if true, wait (atomically) until function has completed on other CPUs
+ *
+ * Run a function on one processor.
+ *
+ * You must not call this function with disabled interrupts, from a
+ * hardware interrupt handler or from a bottom half.
+ */
+int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+ int nonatomic, int wait)
+{
+ preempt_disable();
+ __smp_call_function_map(func, info, nonatomic, wait,
+ cpumask_of_cpu(cpu));
+ preempt_enable();
+ return 0;
+}
+EXPORT_SYMBOL(smp_call_function_single);
+
+/**
+ * smp_call_function_mask(): Run a function on a set of other CPUs.
+ * @mask: The set of cpus to run on. Must not include the current cpu.
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @wait: If true, wait (atomically) until function has completed on other CPUs.
+ *
+ * Returns 0 on success, else a negative status code.
+ *
+ * If @wait is true, then returns once @func has returned; otherwise
+ * it returns just before the target cpu calls @func.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.
+ */
+int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info,
+ int wait)
+{
+ preempt_disable();
+ cpu_clear(smp_processor_id(), mask);
+ __smp_call_function_map(func, info, 0, wait, mask);
+ preempt_enable();
+ return 0;
+}
+EXPORT_SYMBOL(smp_call_function_mask);
+
+void smp_send_stop(void)
+{
+ int cpu, rc;
+
+ /* Disable all interrupts/machine checks */
+ __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
+
+ /* write magic number to zero page (absolute 0) */
+ lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
+
+ /* stop all processors */
+ for_each_online_cpu(cpu) {
+ if (cpu == smp_processor_id())
+ continue;
+ do {
+ rc = signal_processor(cpu, sigp_stop);
+ } while (rc == sigp_busy);
+
+ while (!smp_cpu_not_running(cpu))
+ cpu_relax();
+ }
+}
+
+/*
+ * This is the main routine where commands issued by other
+ * cpus are handled.
+ */
+
+static void do_ext_call_interrupt(__u16 code)
+{
+ unsigned long bits;
+
+ /*
+ * handle bit signal external calls
+ *
+ * For the ec_schedule signal we have to do nothing. All the work
+ * is done automatically when we return from the interrupt.
+ */
+ bits = xchg(&S390_lowcore.ext_call_fast, 0);
+
+ if (test_bit(ec_call_function, &bits))
+ do_call_function();
+}
+
+/*
+ * Send an external call sigp to another cpu and return without waiting
+ * for its completion.
+ */
+static void smp_ext_bitcall(int cpu, ec_bit_sig sig)
+{
+ /*
+ * Set signaling bit in lowcore of target cpu and kick it
+ */
+ set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast);
+ while (signal_processor(cpu, sigp_emergency_signal) == sigp_busy)
+ udelay(10);
+}
+
+#ifndef CONFIG_64BIT
+/*
+ * this function sends a 'purge tlb' signal to another CPU.
+ */
+void smp_ptlb_callback(void *info)
+{
+ __tlb_flush_local();
+}
+
+void smp_ptlb_all(void)
+{
+ on_each_cpu(smp_ptlb_callback, NULL, 0, 1);
+}
+EXPORT_SYMBOL(smp_ptlb_all);
+#endif /* ! CONFIG_64BIT */
+
+/*
+ * this function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+ * anything. Worst case is that we lose a reschedule ...
+ */
+void smp_send_reschedule(int cpu)
+{
+ smp_ext_bitcall(cpu, ec_schedule);
+}
+
+/*
+ * parameter area for the set/clear control bit callbacks
+ */
+struct ec_creg_mask_parms {
+ unsigned long orvals[16];
+ unsigned long andvals[16];
+};
+
+/*
+ * callback for setting/clearing control bits
+ */
+static void smp_ctl_bit_callback(void *info)
+{
+ struct ec_creg_mask_parms *pp = info;
+ unsigned long cregs[16];
+ int i;
+
+ __ctl_store(cregs, 0, 15);
+ for (i = 0; i <= 15; i++)
+ cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
+ __ctl_load(cregs, 0, 15);
+}
+
+/*
+ * Set a bit in a control register of all cpus
+ */
+void smp_ctl_set_bit(int cr, int bit)
+{
+ struct ec_creg_mask_parms parms;
+
+ memset(&parms.orvals, 0, sizeof(parms.orvals));
+ memset(&parms.andvals, 0xff, sizeof(parms.andvals));
+ parms.orvals[cr] = 1 << bit;
+ on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
+}
+EXPORT_SYMBOL(smp_ctl_set_bit);
+
+/*
+ * Clear a bit in a control register of all cpus
+ */
+void smp_ctl_clear_bit(int cr, int bit)
+{
+ struct ec_creg_mask_parms parms;
+
+ memset(&parms.orvals, 0, sizeof(parms.orvals));
+ memset(&parms.andvals, 0xff, sizeof(parms.andvals));
+ parms.andvals[cr] = ~(1L << bit);
+ on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
+}
+EXPORT_SYMBOL(smp_ctl_clear_bit);
+
+/*
+ * In early ipl state a temp. logically cpu number is needed, so the sigp
+ * functions can be used to sense other cpus. Since NR_CPUS is >= 2 on
+ * CONFIG_SMP and the ipl cpu is logical cpu 0, it must be 1.
+ */
+#define CPU_INIT_NO 1
+
+#if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
+
+/*
+ * zfcpdump_prefix_array holds prefix registers for the following scenario:
+ * 64 bit zfcpdump kernel and 31 bit kernel which is to be dumped. We have to
+ * save its prefix registers, since they get lost, when switching from 31 bit
+ * to 64 bit.
+ */
+unsigned int zfcpdump_prefix_array[NR_CPUS + 1] \
+ __attribute__((__section__(".data")));
+
+static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu)
+{
+ if (ipl_info.type != IPL_TYPE_FCP_DUMP)
+ return;
+ if (cpu >= NR_CPUS) {
+ printk(KERN_WARNING "Registers for cpu %i not saved since dump "
+ "kernel was compiled with NR_CPUS=%i\n", cpu, NR_CPUS);
+ return;
+ }
+ zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL);
+ __cpu_logical_map[CPU_INIT_NO] = (__u16) phy_cpu;
+ while (signal_processor(CPU_INIT_NO, sigp_stop_and_store_status) ==
+ sigp_busy)
+ cpu_relax();
+ memcpy(zfcpdump_save_areas[cpu],
+ (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE,
+ SAVE_AREA_SIZE);
+#ifdef CONFIG_64BIT
+ /* copy original prefix register */
+ zfcpdump_save_areas[cpu]->s390x.pref_reg = zfcpdump_prefix_array[cpu];
+#endif
+}
+
+union save_area *zfcpdump_save_areas[NR_CPUS + 1];
+EXPORT_SYMBOL_GPL(zfcpdump_save_areas);
+
+#else
+
+static inline void smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { }
+
+#endif /* CONFIG_ZFCPDUMP || CONFIG_ZFCPDUMP_MODULE */
+
+static int cpu_stopped(int cpu)
+{
+ __u32 status;
+
+ /* Check for stopped state */
+ if (signal_processor_ps(&status, 0, cpu, sigp_sense) ==
+ sigp_status_stored) {
+ if (status & 0x40)
+ return 1;
+ }
+ return 0;
+}
+
+static int cpu_known(int cpu_id)
+{
+ int cpu;
+
+ for_each_present_cpu(cpu) {
+ if (__cpu_logical_map[cpu] == cpu_id)
+ return 1;
+ }
+ return 0;
+}
+
+static int smp_rescan_cpus_sigp(cpumask_t avail)
+{
+ int cpu_id, logical_cpu;
+
+ logical_cpu = first_cpu(avail);
+ if (logical_cpu == NR_CPUS)
+ return 0;
+ for (cpu_id = 0; cpu_id <= 65535; cpu_id++) {
+ if (cpu_known(cpu_id))
+ continue;
+ __cpu_logical_map[logical_cpu] = cpu_id;
+ if (!cpu_stopped(logical_cpu))
+ continue;
+ cpu_set(logical_cpu, cpu_present_map);
+ smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
+ logical_cpu = next_cpu(logical_cpu, avail);
+ if (logical_cpu == NR_CPUS)
+ break;
+ }
+ return 0;
+}
+
+static int smp_rescan_cpus_sclp(cpumask_t avail)
+{
+ struct sclp_cpu_info *info;
+ int cpu_id, logical_cpu, cpu;
+ int rc;
+
+ logical_cpu = first_cpu(avail);
+ if (logical_cpu == NR_CPUS)
+ return 0;
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ rc = sclp_get_cpu_info(info);
+ if (rc)
+ goto out;
+ for (cpu = 0; cpu < info->combined; cpu++) {
+ if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
+ continue;
+ cpu_id = info->cpu[cpu].address;
+ if (cpu_known(cpu_id))
+ continue;
+ __cpu_logical_map[logical_cpu] = cpu_id;
+ cpu_set(logical_cpu, cpu_present_map);
+ if (cpu >= info->configured)
+ smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
+ else
+ smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
+ logical_cpu = next_cpu(logical_cpu, avail);
+ if (logical_cpu == NR_CPUS)
+ break;
+ }
+out:
+ kfree(info);
+ return rc;
+}
+
+static int smp_rescan_cpus(void)
+{
+ cpumask_t avail;
+
+ cpus_xor(avail, cpu_possible_map, cpu_present_map);
+ if (smp_use_sigp_detection)
+ return smp_rescan_cpus_sigp(avail);
+ else
+ return smp_rescan_cpus_sclp(avail);
+}
+
+static void __init smp_detect_cpus(void)
+{
+ unsigned int cpu, c_cpus, s_cpus;
+ struct sclp_cpu_info *info;
+ u16 boot_cpu_addr, cpu_addr;
+
+ c_cpus = 1;
+ s_cpus = 0;
+ boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ panic("smp_detect_cpus failed to allocate memory\n");
+ /* Use sigp detection algorithm if sclp doesn't work. */
+ if (sclp_get_cpu_info(info)) {
+ smp_use_sigp_detection = 1;
+ for (cpu = 0; cpu <= 65535; cpu++) {
+ if (cpu == boot_cpu_addr)
+ continue;
+ __cpu_logical_map[CPU_INIT_NO] = cpu;
+ if (!cpu_stopped(CPU_INIT_NO))
+ continue;
+ smp_get_save_area(c_cpus, cpu);
+ c_cpus++;
+ }
+ goto out;
+ }
+
+ if (info->has_cpu_type) {
+ for (cpu = 0; cpu < info->combined; cpu++) {
+ if (info->cpu[cpu].address == boot_cpu_addr) {
+ smp_cpu_type = info->cpu[cpu].type;
+ break;
+ }
+ }
+ }
+
+ for (cpu = 0; cpu < info->combined; cpu++) {
+ if (info->has_cpu_type && info->cpu[cpu].type != smp_cpu_type)
+ continue;
+ cpu_addr = info->cpu[cpu].address;
+ if (cpu_addr == boot_cpu_addr)
+ continue;
+ __cpu_logical_map[CPU_INIT_NO] = cpu_addr;
+ if (!cpu_stopped(CPU_INIT_NO)) {
+ s_cpus++;
+ continue;
+ }
+ smp_get_save_area(c_cpus, cpu_addr);
+ c_cpus++;
+ }
+out:
+ kfree(info);
+ printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus);
+ get_online_cpus();
+ smp_rescan_cpus();
+ put_online_cpus();
+}
+
+/*
+ * Activate a secondary processor.
+ */
+int __cpuinit start_secondary(void *cpuvoid)
+{
+ /* Setup the cpu */
+ cpu_init();
+ preempt_disable();
+ /* Enable TOD clock interrupts on the secondary cpu. */
+ init_cpu_timer();
+#ifdef CONFIG_VIRT_TIMER
+ /* Enable cpu timer interrupts on the secondary cpu. */
+ init_cpu_vtimer();
+#endif
+ /* Enable pfault pseudo page faults on this cpu. */
+ pfault_init();
+
+ /* Mark this cpu as online */
+ cpu_set(smp_processor_id(), cpu_online_map);
+ /* Switch on interrupts */
+ local_irq_enable();
+ /* Print info about this processor */
+ print_cpu_info(&S390_lowcore.cpu_data);
+ /* cpu_idle will call schedule for us */
+ cpu_idle();
+ return 0;
+}
+
+static void __init smp_create_idle(unsigned int cpu)
+{
+ struct task_struct *p;
+
+ /*
+ * don't care about the psw and regs settings since we'll never
+ * reschedule the forked task.
+ */
+ p = fork_idle(cpu);
+ if (IS_ERR(p))
+ panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
+ current_set[cpu] = p;
+ spin_lock_init(&(&per_cpu(s390_idle, cpu))->lock);
+}
+
+static int __cpuinit smp_alloc_lowcore(int cpu)
+{
+ unsigned long async_stack, panic_stack;
+ struct _lowcore *lowcore;
+ int lc_order;
+
+ lc_order = sizeof(long) == 8 ? 1 : 0;
+ lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order);
+ if (!lowcore)
+ return -ENOMEM;
+ async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
+ panic_stack = __get_free_page(GFP_KERNEL);
+ if (!panic_stack || !async_stack)
+ goto out;
+ memcpy(lowcore, &S390_lowcore, 512);
+ memset((char *)lowcore + 512, 0, sizeof(*lowcore) - 512);
+ lowcore->async_stack = async_stack + ASYNC_SIZE;
+ lowcore->panic_stack = panic_stack + PAGE_SIZE;
+
+#ifndef CONFIG_64BIT
+ if (MACHINE_HAS_IEEE) {
+ unsigned long save_area;
+
+ save_area = get_zeroed_page(GFP_KERNEL);
+ if (!save_area)
+ goto out_save_area;
+ lowcore->extended_save_area_addr = (u32) save_area;
+ }
+#endif
+ lowcore_ptr[cpu] = lowcore;
+ return 0;
+
+#ifndef CONFIG_64BIT
+out_save_area:
+ free_page(panic_stack);
+#endif
+out:
+ free_pages(async_stack, ASYNC_ORDER);
+ free_pages((unsigned long) lowcore, lc_order);
+ return -ENOMEM;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void smp_free_lowcore(int cpu)
+{
+ struct _lowcore *lowcore;
+ int lc_order;
+
+ lc_order = sizeof(long) == 8 ? 1 : 0;
+ lowcore = lowcore_ptr[cpu];
+#ifndef CONFIG_64BIT
+ if (MACHINE_HAS_IEEE)
+ free_page((unsigned long) lowcore->extended_save_area_addr);
+#endif
+ free_page(lowcore->panic_stack - PAGE_SIZE);
+ free_pages(lowcore->async_stack - ASYNC_SIZE, ASYNC_ORDER);
+ free_pages((unsigned long) lowcore, lc_order);
+ lowcore_ptr[cpu] = NULL;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/* Upping and downing of CPUs */
+int __cpuinit __cpu_up(unsigned int cpu)
+{
+ struct task_struct *idle;
+ struct _lowcore *cpu_lowcore;
+ struct stack_frame *sf;
+ sigp_ccode ccode;
+
+ if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED)
+ return -EIO;
+ if (smp_alloc_lowcore(cpu))
+ return -ENOMEM;
+
+ ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]),
+ cpu, sigp_set_prefix);
+ if (ccode) {
+ printk("sigp_set_prefix failed for cpu %d "
+ "with condition code %d\n",
+ (int) cpu, (int) ccode);
+ return -EIO;
+ }
+
+ idle = current_set[cpu];
+ cpu_lowcore = lowcore_ptr[cpu];
+ cpu_lowcore->kernel_stack = (unsigned long)
+ task_stack_page(idle) + THREAD_SIZE;
+ cpu_lowcore->thread_info = (unsigned long) task_thread_info(idle);
+ sf = (struct stack_frame *) (cpu_lowcore->kernel_stack
+ - sizeof(struct pt_regs)
+ - sizeof(struct stack_frame));
+ memset(sf, 0, sizeof(struct stack_frame));
+ sf->gprs[9] = (unsigned long) sf;
+ cpu_lowcore->save_area[15] = (unsigned long) sf;
+ __ctl_store(cpu_lowcore->cregs_save_area[0], 0, 15);
+ asm volatile(
+ " stam 0,15,0(%0)"
+ : : "a" (&cpu_lowcore->access_regs_save_area) : "memory");
+ cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];
+ cpu_lowcore->current_task = (unsigned long) idle;
+ cpu_lowcore->cpu_data.cpu_nr = cpu;
+ cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
+ cpu_lowcore->ipl_device = S390_lowcore.ipl_device;
+ eieio();
+
+ while (signal_processor(cpu, sigp_restart) == sigp_busy)
+ udelay(10);
+
+ while (!cpu_online(cpu))
+ cpu_relax();
+ return 0;
+}
+
+static int __init setup_possible_cpus(char *s)
+{
+ int pcpus, cpu;
+
+ pcpus = simple_strtoul(s, NULL, 0);
+ cpu_possible_map = cpumask_of_cpu(0);
+ for (cpu = 1; cpu < pcpus && cpu < NR_CPUS; cpu++)
+ cpu_set(cpu, cpu_possible_map);
+ return 0;
+}
+early_param("possible_cpus", setup_possible_cpus);
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+int __cpu_disable(void)
+{
+ struct ec_creg_mask_parms cr_parms;
+ int cpu = smp_processor_id();
+
+ cpu_clear(cpu, cpu_online_map);
+
+ /* Disable pfault pseudo page faults on this cpu. */
+ pfault_fini();
+
+ memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals));
+ memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals));
+
+ /* disable all external interrupts */
+ cr_parms.orvals[0] = 0;
+ cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 |
+ 1 << 11 | 1 << 10 | 1 << 6 | 1 << 4);
+ /* disable all I/O interrupts */
+ cr_parms.orvals[6] = 0;
+ cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 |
+ 1 << 27 | 1 << 26 | 1 << 25 | 1 << 24);
+ /* disable most machine checks */
+ cr_parms.orvals[14] = 0;
+ cr_parms.andvals[14] = ~(1 << 28 | 1 << 27 | 1 << 26 |
+ 1 << 25 | 1 << 24);
+
+ smp_ctl_bit_callback(&cr_parms);
+
+ return 0;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+ /* Wait until target cpu is down */
+ while (!smp_cpu_not_running(cpu))
+ cpu_relax();
+ smp_free_lowcore(cpu);
+ printk(KERN_INFO "Processor %d spun down\n", cpu);
+}
+
+void cpu_die(void)
+{
+ idle_task_exit();
+ signal_processor(smp_processor_id(), sigp_stop);
+ BUG();
+ for (;;);
+}
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+#ifndef CONFIG_64BIT
+ unsigned long save_area = 0;
+#endif
+ unsigned long async_stack, panic_stack;
+ struct _lowcore *lowcore;
+ unsigned int cpu;
+ int lc_order;
+
+ smp_detect_cpus();
+
+ /* request the 0x1201 emergency signal external interrupt */
+ if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
+ panic("Couldn't request external interrupt 0x1201");
+ print_cpu_info(&S390_lowcore.cpu_data);
+
+ /* Reallocate current lowcore, but keep its contents. */
+ lc_order = sizeof(long) == 8 ? 1 : 0;
+ lowcore = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, lc_order);
+ panic_stack = __get_free_page(GFP_KERNEL);
+ async_stack = __get_free_pages(GFP_KERNEL, ASYNC_ORDER);
+#ifndef CONFIG_64BIT
+ if (MACHINE_HAS_IEEE)
+ save_area = get_zeroed_page(GFP_KERNEL);
+#endif
+ local_irq_disable();
+ local_mcck_disable();
+ lowcore_ptr[smp_processor_id()] = lowcore;
+ *lowcore = S390_lowcore;
+ lowcore->panic_stack = panic_stack + PAGE_SIZE;
+ lowcore->async_stack = async_stack + ASYNC_SIZE;
+#ifndef CONFIG_64BIT
+ if (MACHINE_HAS_IEEE)
+ lowcore->extended_save_area_addr = (u32) save_area;
+#endif
+ set_prefix((u32)(unsigned long) lowcore);
+ local_mcck_enable();
+ local_irq_enable();
+ for_each_possible_cpu(cpu)
+ if (cpu != smp_processor_id())
+ smp_create_idle(cpu);
+}
+
+void __init smp_prepare_boot_cpu(void)
+{
+ BUG_ON(smp_processor_id() != 0);
+
+ current_thread_info()->cpu = 0;
+ cpu_set(0, cpu_present_map);
+ cpu_set(0, cpu_online_map);
+ S390_lowcore.percpu_offset = __per_cpu_offset[0];
+ current_set[0] = current;
+ smp_cpu_state[0] = CPU_STATE_CONFIGURED;
+ spin_lock_init(&(&__get_cpu_var(s390_idle))->lock);
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+/*
+ * the frequency of the profiling timer can be changed
+ * by writing a multiplier value into /proc/profile.
+ *
+ * usually you want to run this on all CPUs ;)
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+ return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t cpu_configure_show(struct sys_device *dev, char *buf)
+{
+ ssize_t count;
+
+ mutex_lock(&smp_cpu_state_mutex);
+ count = sprintf(buf, "%d\n", smp_cpu_state[dev->id]);
+ mutex_unlock(&smp_cpu_state_mutex);
+ return count;
+}
+
+static ssize_t cpu_configure_store(struct sys_device *dev, const char *buf,
+ size_t count)
+{
+ int cpu = dev->id;
+ int val, rc;
+ char delim;
+
+ if (sscanf(buf, "%d %c", &val, &delim) != 1)
+ return -EINVAL;
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ mutex_lock(&smp_cpu_state_mutex);
+ get_online_cpus();
+ rc = -EBUSY;
+ if (cpu_online(cpu))
+ goto out;
+ rc = 0;
+ switch (val) {
+ case 0:
+ if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) {
+ rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]);
+ if (!rc)
+ smp_cpu_state[cpu] = CPU_STATE_STANDBY;
+ }
+ break;
+ case 1:
+ if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) {
+ rc = sclp_cpu_configure(__cpu_logical_map[cpu]);
+ if (!rc)
+ smp_cpu_state[cpu] = CPU_STATE_CONFIGURED;
+ }
+ break;
+ default:
+ break;
+ }
+out:
+ put_online_cpus();
+ mutex_unlock(&smp_cpu_state_mutex);
+ return rc ? rc : count;
+}
+static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+static ssize_t show_cpu_address(struct sys_device *dev, char *buf)
+{
+ return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]);
+}
+static SYSDEV_ATTR(address, 0444, show_cpu_address, NULL);
+
+
+static struct attribute *cpu_common_attrs[] = {
+#ifdef CONFIG_HOTPLUG_CPU
+ &attr_configure.attr,
+#endif
+ &attr_address.attr,
+ NULL,
+};
+
+static struct attribute_group cpu_common_attr_group = {
+ .attrs = cpu_common_attrs,
+};
+
+static ssize_t show_capability(struct sys_device *dev, char *buf)
+{
+ unsigned int capability;
+ int rc;
+
+ rc = get_cpu_capability(&capability);
+ if (rc)
+ return rc;
+ return sprintf(buf, "%u\n", capability);
+}
+static SYSDEV_ATTR(capability, 0444, show_capability, NULL);
+
+static ssize_t show_idle_count(struct sys_device *dev, char *buf)
+{
+ struct s390_idle_data *idle;
+ unsigned long long idle_count;
+
+ idle = &per_cpu(s390_idle, dev->id);
+ spin_lock_irq(&idle->lock);
+ idle_count = idle->idle_count;
+ spin_unlock_irq(&idle->lock);
+ return sprintf(buf, "%llu\n", idle_count);
+}
+static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL);
+
+static ssize_t show_idle_time(struct sys_device *dev, char *buf)
+{
+ struct s390_idle_data *idle;
+ unsigned long long new_time;
+
+ idle = &per_cpu(s390_idle, dev->id);
+ spin_lock_irq(&idle->lock);
+ if (idle->in_idle) {
+ new_time = get_clock();
+ idle->idle_time += new_time - idle->idle_enter;
+ idle->idle_enter = new_time;
+ }
+ new_time = idle->idle_time;
+ spin_unlock_irq(&idle->lock);
+ return sprintf(buf, "%llu\n", new_time >> 12);
+}
+static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL);
+
+static struct attribute *cpu_online_attrs[] = {
+ &attr_capability.attr,
+ &attr_idle_count.attr,
+ &attr_idle_time_us.attr,
+ NULL,
+};
+
+static struct attribute_group cpu_online_attr_group = {
+ .attrs = cpu_online_attrs,
+};
+
+static int __cpuinit smp_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned int)(long)hcpu;
+ struct cpu *c = &per_cpu(cpu_devices, cpu);
+ struct sys_device *s = &c->sysdev;
+ struct s390_idle_data *idle;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ idle = &per_cpu(s390_idle, cpu);
+ spin_lock_irq(&idle->lock);
+ idle->idle_enter = 0;
+ idle->idle_time = 0;
+ idle->idle_count = 0;
+ spin_unlock_irq(&idle->lock);
+ if (sysfs_create_group(&s->kobj, &cpu_online_attr_group))
+ return NOTIFY_BAD;
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ sysfs_remove_group(&s->kobj, &cpu_online_attr_group);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata smp_cpu_nb = {
+ .notifier_call = smp_cpu_notify,
+};
+
+static int __devinit smp_add_present_cpu(int cpu)
+{
+ struct cpu *c = &per_cpu(cpu_devices, cpu);
+ struct sys_device *s = &c->sysdev;
+ int rc;
+
+ c->hotpluggable = 1;
+ rc = register_cpu(c, cpu);
+ if (rc)
+ goto out;
+ rc = sysfs_create_group(&s->kobj, &cpu_common_attr_group);
+ if (rc)
+ goto out_cpu;
+ if (!cpu_online(cpu))
+ goto out;
+ rc = sysfs_create_group(&s->kobj, &cpu_online_attr_group);
+ if (!rc)
+ return 0;
+ sysfs_remove_group(&s->kobj, &cpu_common_attr_group);
+out_cpu:
+#ifdef CONFIG_HOTPLUG_CPU
+ unregister_cpu(c);
+#endif
+out:
+ return rc;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t __ref rescan_store(struct sys_device *dev,
+ const char *buf, size_t count)
+{
+ cpumask_t newcpus;
+ int cpu;
+ int rc;
+
+ mutex_lock(&smp_cpu_state_mutex);
+ get_online_cpus();
+ newcpus = cpu_present_map;
+ rc = smp_rescan_cpus();
+ if (rc)
+ goto out;
+ cpus_andnot(newcpus, cpu_present_map, newcpus);
+ for_each_cpu_mask(cpu, newcpus) {
+ rc = smp_add_present_cpu(cpu);
+ if (rc)
+ cpu_clear(cpu, cpu_present_map);
+ }
+ rc = 0;
+out:
+ put_online_cpus();
+ mutex_unlock(&smp_cpu_state_mutex);
+ return rc ? rc : count;
+}
+static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store);
+#endif /* CONFIG_HOTPLUG_CPU */
+
+static int __init topology_init(void)
+{
+ int cpu;
+ int rc;
+
+ register_cpu_notifier(&smp_cpu_nb);
+
+#ifdef CONFIG_HOTPLUG_CPU
+ rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
+ &attr_rescan.attr);
+ if (rc)
+ return rc;
+#endif
+ for_each_present_cpu(cpu) {
+ rc = smp_add_present_cpu(cpu);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+subsys_initcall(topology_init);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/stacktrace.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/stacktrace.c
new file mode 100644
index 0000000000..85e46a5d0e
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/stacktrace.c
@@ -0,0 +1,95 @@
+/*
+ * arch/s390/kernel/stacktrace.c
+ *
+ * Stack trace management functions
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/kallsyms.h>
+
+static unsigned long save_context_stack(struct stack_trace *trace,
+ unsigned long sp,
+ unsigned long low,
+ unsigned long high,
+ int savesched)
+{
+ struct stack_frame *sf;
+ struct pt_regs *regs;
+ unsigned long addr;
+
+ while(1) {
+ sp &= PSW_ADDR_INSN;
+ if (sp < low || sp > high)
+ return sp;
+ sf = (struct stack_frame *)sp;
+ while(1) {
+ addr = sf->gprs[8] & PSW_ADDR_INSN;
+ if (!trace->skip)
+ trace->entries[trace->nr_entries++] = addr;
+ else
+ trace->skip--;
+ if (trace->nr_entries >= trace->max_entries)
+ return sp;
+ low = sp;
+ sp = sf->back_chain & PSW_ADDR_INSN;
+ if (!sp)
+ break;
+ if (sp <= low || sp > high - sizeof(*sf))
+ return sp;
+ sf = (struct stack_frame *)sp;
+ }
+ /* Zero backchain detected, check for interrupt frame. */
+ sp = (unsigned long)(sf + 1);
+ if (sp <= low || sp > high - sizeof(*regs))
+ return sp;
+ regs = (struct pt_regs *)sp;
+ addr = regs->psw.addr & PSW_ADDR_INSN;
+ if (savesched || !in_sched_functions(addr)) {
+ if (!trace->skip)
+ trace->entries[trace->nr_entries++] = addr;
+ else
+ trace->skip--;
+ }
+ if (trace->nr_entries >= trace->max_entries)
+ return sp;
+ low = sp;
+ sp = regs->gprs[15];
+ }
+}
+
+void save_stack_trace(struct stack_trace *trace)
+{
+ register unsigned long sp asm ("15");
+ unsigned long orig_sp, new_sp;
+
+ orig_sp = sp & PSW_ADDR_INSN;
+ new_sp = save_context_stack(trace, orig_sp,
+ S390_lowcore.panic_stack - PAGE_SIZE,
+ S390_lowcore.panic_stack, 1);
+ if (new_sp != orig_sp)
+ return;
+ new_sp = save_context_stack(trace, new_sp,
+ S390_lowcore.async_stack - ASYNC_SIZE,
+ S390_lowcore.async_stack, 1);
+ if (new_sp != orig_sp)
+ return;
+ save_context_stack(trace, new_sp,
+ S390_lowcore.thread_info,
+ S390_lowcore.thread_info + THREAD_SIZE, 1);
+}
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+ unsigned long sp, low, high;
+
+ sp = tsk->thread.ksp & PSW_ADDR_INSN;
+ low = (unsigned long) task_stack_page(tsk);
+ high = (unsigned long) task_pt_regs(tsk);
+ save_context_stack(trace, sp, low, high, 0);
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/sys_s390.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/sys_s390.c
new file mode 100644
index 0000000000..fefee99f28
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/sys_s390.c
@@ -0,0 +1,288 @@
+/*
+ * arch/s390/kernel/sys_s390.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Thomas Spatzier (tspat@de.ibm.com)
+ *
+ * Derived from "arch/i386/kernel/sys_i386.c"
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/s390
+ * platform.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+#include <linux/personality.h>
+#include <linux/unistd.h>
+#include <linux/ipc.h>
+
+#include <asm/uaccess.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way Unix traditionally does this, though.
+ */
+asmlinkage long sys_pipe(unsigned long __user *fildes)
+{
+ int fd[2];
+ int error;
+
+ error = do_pipe(fd);
+ if (!error) {
+ if (copy_to_user(fildes, fd, 2*sizeof(int)))
+ error = -EFAULT;
+ }
+ return error;
+}
+
+/* common code for old and new mmaps */
+static inline long do_mmap2(
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+{
+ long error = -EBADF;
+ struct file * file = NULL;
+
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ if (!(flags & MAP_ANONYMOUS)) {
+ file = fget(fd);
+ if (!file)
+ goto out;
+ }
+
+ down_write(&current->mm->mmap_sem);
+ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ up_write(&current->mm->mmap_sem);
+
+ if (file)
+ fput(file);
+out:
+ return error;
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux for S/390 isn't able to handle more than 5
+ * system call parameters, so these system calls used 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;
+};
+
+asmlinkage long sys_mmap2(struct mmap_arg_struct __user *arg)
+{
+ struct mmap_arg_struct a;
+ int error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+out:
+ return error;
+}
+
+asmlinkage long old_mmap(struct mmap_arg_struct __user *arg)
+{
+ struct mmap_arg_struct a;
+ long error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+
+ error = -EINVAL;
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+out:
+ return error;
+}
+
+#ifndef CONFIG_64BIT
+struct sel_arg_struct {
+ unsigned long n;
+ fd_set __user *inp, *outp, *exp;
+ struct timeval __user *tvp;
+};
+
+asmlinkage long old_select(struct sel_arg_struct __user *arg)
+{
+ struct sel_arg_struct a;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ return -EFAULT;
+ /* sys_select() does the appropriate kernel locking */
+ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+
+}
+#endif /* CONFIG_64BIT */
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage long sys_ipc(uint call, int first, unsigned long second,
+ unsigned long 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);
+ break;
+ 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);
+ break;
+ }
+ 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;
+
+ }
+
+ return -EINVAL;
+}
+
+#ifdef CONFIG_64BIT
+asmlinkage long s390x_newuname(struct new_utsname __user *name)
+{
+ int ret = sys_newuname(name);
+
+ if (current->personality == PER_LINUX32 && !ret) {
+ ret = copy_to_user(name->machine, "s390\0\0\0\0", 8);
+ if (ret) ret = -EFAULT;
+ }
+ return ret;
+}
+
+asmlinkage long s390x_personality(unsigned long personality)
+{
+ int ret;
+
+ if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+ personality = PER_LINUX32;
+ ret = sys_personality(personality);
+ if (ret == PER_LINUX32)
+ ret = PER_LINUX;
+
+ return ret;
+}
+#endif /* CONFIG_64BIT */
+
+/*
+ * Wrapper function for sys_fadvise64/fadvise64_64
+ */
+#ifndef CONFIG_64BIT
+
+asmlinkage 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);
+}
+
+#endif
+
+struct fadvise64_64_args {
+ int fd;
+ long long offset;
+ long long len;
+ int advice;
+};
+
+asmlinkage 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);
+}
+
+#ifndef CONFIG_64BIT
+/*
+ * This is a wrapper to call sys_fallocate(). For 31 bit s390 the last
+ * 64 bit argument "len" is split into the upper and lower 32 bits. The
+ * system call wrapper in the user space loads the value to %r6/%r7.
+ * The code in entry.S keeps the values in %r2 - %r6 where they are and
+ * stores %r7 to 96(%r15). But the standard C linkage requires that
+ * the whole 64 bit value for len is stored on the stack and doesn't
+ * use %r6 at all. So s390_fallocate has to convert the arguments from
+ * %r2: fd, %r3: mode, %r4/%r5: offset, %r6/96(%r15)-99(%r15): len
+ * to
+ * %r2: fd, %r3: mode, %r4/%r5: offset, 96(%r15)-103(%r15): len
+ */
+asmlinkage long s390_fallocate(int fd, int mode, loff_t offset,
+ u32 len_high, u32 len_low)
+{
+ return sys_fallocate(fd, mode, offset, ((u64)len_high << 32) | len_low);
+}
+#endif
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/syscalls.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/syscalls.S
new file mode 100644
index 0000000000..c87ec687d4
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/syscalls.S
@@ -0,0 +1,332 @@
+/*
+ * definitions for sys_call_table, each line represents an
+ * entry in the table in the form
+ * SYSCALL(31 bit syscall, 64 bit syscall, 31 bit emulated syscall)
+ *
+ * this file is meant to be included from entry.S and entry64.S
+ */
+
+#define NI_SYSCALL SYSCALL(sys_ni_syscall,sys_ni_syscall,sys_ni_syscall)
+
+NI_SYSCALL /* 0 */
+SYSCALL(sys_exit,sys_exit,sys32_exit_wrapper)
+SYSCALL(sys_fork,sys_fork,sys_fork)
+SYSCALL(sys_read,sys_read,sys32_read_wrapper)
+SYSCALL(sys_write,sys_write,sys32_write_wrapper)
+SYSCALL(sys_open,sys_open,sys32_open_wrapper) /* 5 */
+SYSCALL(sys_close,sys_close,sys32_close_wrapper)
+SYSCALL(sys_restart_syscall,sys_restart_syscall,sys_restart_syscall)
+SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper)
+SYSCALL(sys_link,sys_link,sys32_link_wrapper)
+SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper) /* 10 */
+SYSCALL(sys_execve,sys_execve,sys32_execve)
+SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper)
+SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper) /* old time syscall */
+SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper)
+SYSCALL(sys_chmod,sys_chmod,sys32_chmod_wrapper) /* 15 */
+SYSCALL(sys_lchown16,sys_ni_syscall,sys32_lchown16_wrapper) /* old lchown16 syscall*/
+NI_SYSCALL /* old break syscall holder */
+NI_SYSCALL /* old stat syscall holder */
+SYSCALL(sys_lseek,sys_lseek,sys32_lseek_wrapper)
+SYSCALL(sys_getpid,sys_getpid,sys_getpid) /* 20 */
+SYSCALL(sys_mount,sys_mount,sys32_mount_wrapper)
+SYSCALL(sys_oldumount,sys_oldumount,sys32_oldumount_wrapper)
+SYSCALL(sys_setuid16,sys_ni_syscall,sys32_setuid16_wrapper) /* old setuid16 syscall*/
+SYSCALL(sys_getuid16,sys_ni_syscall,sys32_getuid16) /* old getuid16 syscall*/
+SYSCALL(sys_stime,sys_ni_syscall,sys32_stime_wrapper) /* 25 old stime syscall */
+SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper)
+SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper)
+NI_SYSCALL /* old fstat syscall */
+SYSCALL(sys_pause,sys_pause,sys32_pause)
+SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper) /* 30 */
+NI_SYSCALL /* old stty syscall */
+NI_SYSCALL /* old gtty syscall */
+SYSCALL(sys_access,sys_access,sys32_access_wrapper)
+SYSCALL(sys_nice,sys_nice,sys32_nice_wrapper)
+NI_SYSCALL /* 35 old ftime syscall */
+SYSCALL(sys_sync,sys_sync,sys_sync)
+SYSCALL(sys_kill,sys_kill,sys32_kill_wrapper)
+SYSCALL(sys_rename,sys_rename,sys32_rename_wrapper)
+SYSCALL(sys_mkdir,sys_mkdir,sys32_mkdir_wrapper)
+SYSCALL(sys_rmdir,sys_rmdir,sys32_rmdir_wrapper) /* 40 */
+SYSCALL(sys_dup,sys_dup,sys32_dup_wrapper)
+SYSCALL(sys_pipe,sys_pipe,sys32_pipe_wrapper)
+SYSCALL(sys_times,sys_times,compat_sys_times_wrapper)
+NI_SYSCALL /* old prof syscall */
+SYSCALL(sys_brk,sys_brk,sys32_brk_wrapper) /* 45 */
+SYSCALL(sys_setgid16,sys_ni_syscall,sys32_setgid16_wrapper) /* old setgid16 syscall*/
+SYSCALL(sys_getgid16,sys_ni_syscall,sys32_getgid16) /* old getgid16 syscall*/
+SYSCALL(sys_signal,sys_signal,sys32_signal_wrapper)
+SYSCALL(sys_geteuid16,sys_ni_syscall,sys32_geteuid16) /* old geteuid16 syscall */
+SYSCALL(sys_getegid16,sys_ni_syscall,sys32_getegid16) /* 50 old getegid16 syscall */
+SYSCALL(sys_acct,sys_acct,sys32_acct_wrapper)
+SYSCALL(sys_umount,sys_umount,sys32_umount_wrapper)
+NI_SYSCALL /* old lock syscall */
+SYSCALL(sys_ioctl,sys_ioctl,compat_sys_ioctl_wrapper)
+SYSCALL(sys_fcntl,sys_fcntl,compat_sys_fcntl_wrapper) /* 55 */
+NI_SYSCALL /* intel mpx syscall */
+SYSCALL(sys_setpgid,sys_setpgid,sys32_setpgid_wrapper)
+NI_SYSCALL /* old ulimit syscall */
+NI_SYSCALL /* old uname syscall */
+SYSCALL(sys_umask,sys_umask,sys32_umask_wrapper) /* 60 */
+SYSCALL(sys_chroot,sys_chroot,sys32_chroot_wrapper)
+SYSCALL(sys_ustat,sys_ustat,sys32_ustat_wrapper)
+SYSCALL(sys_dup2,sys_dup2,sys32_dup2_wrapper)
+SYSCALL(sys_getppid,sys_getppid,sys_getppid)
+SYSCALL(sys_getpgrp,sys_getpgrp,sys_getpgrp) /* 65 */
+SYSCALL(sys_setsid,sys_setsid,sys_setsid)
+SYSCALL(sys_sigaction,sys_sigaction,sys32_sigaction_wrapper)
+NI_SYSCALL /* old sgetmask syscall*/
+NI_SYSCALL /* old ssetmask syscall*/
+SYSCALL(sys_setreuid16,sys_ni_syscall,sys32_setreuid16_wrapper) /* old setreuid16 syscall */
+SYSCALL(sys_setregid16,sys_ni_syscall,sys32_setregid16_wrapper) /* old setregid16 syscall */
+SYSCALL(sys_sigsuspend,sys_sigsuspend,sys_sigsuspend_wrapper)
+SYSCALL(sys_sigpending,sys_sigpending,compat_sys_sigpending_wrapper)
+SYSCALL(sys_sethostname,sys_sethostname,sys32_sethostname_wrapper)
+SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit_wrapper) /* 75 */
+SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit_wrapper)
+SYSCALL(sys_getrusage,sys_getrusage,compat_sys_getrusage_wrapper)
+SYSCALL(sys_gettimeofday,sys_gettimeofday,sys32_gettimeofday_wrapper)
+SYSCALL(sys_settimeofday,sys_settimeofday,sys32_settimeofday_wrapper)
+SYSCALL(sys_getgroups16,sys_ni_syscall,sys32_getgroups16_wrapper) /* 80 old getgroups16 syscall */
+SYSCALL(sys_setgroups16,sys_ni_syscall,sys32_setgroups16_wrapper) /* old setgroups16 syscall */
+NI_SYSCALL /* old select syscall */
+SYSCALL(sys_symlink,sys_symlink,sys32_symlink_wrapper)
+NI_SYSCALL /* old lstat syscall */
+SYSCALL(sys_readlink,sys_readlink,sys32_readlink_wrapper) /* 85 */
+SYSCALL(sys_uselib,sys_uselib,sys32_uselib_wrapper)
+SYSCALL(sys_swapon,sys_swapon,sys32_swapon_wrapper)
+SYSCALL(sys_reboot,sys_reboot,sys32_reboot_wrapper)
+SYSCALL(sys_ni_syscall,sys_ni_syscall,old32_readdir_wrapper) /* old readdir syscall */
+SYSCALL(old_mmap,old_mmap,old32_mmap_wrapper) /* 90 */
+SYSCALL(sys_munmap,sys_munmap,sys32_munmap_wrapper)
+SYSCALL(sys_truncate,sys_truncate,sys32_truncate_wrapper)
+SYSCALL(sys_ftruncate,sys_ftruncate,sys32_ftruncate_wrapper)
+SYSCALL(sys_fchmod,sys_fchmod,sys32_fchmod_wrapper)
+SYSCALL(sys_fchown16,sys_ni_syscall,sys32_fchown16_wrapper) /* 95 old fchown16 syscall*/
+SYSCALL(sys_getpriority,sys_getpriority,sys32_getpriority_wrapper)
+SYSCALL(sys_setpriority,sys_setpriority,sys32_setpriority_wrapper)
+NI_SYSCALL /* old profil syscall */
+SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs_wrapper)
+SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs_wrapper) /* 100 */
+NI_SYSCALL /* ioperm for i386 */
+SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall_wrapper)
+SYSCALL(sys_syslog,sys_syslog,sys32_syslog_wrapper)
+SYSCALL(sys_setitimer,sys_setitimer,compat_sys_setitimer_wrapper)
+SYSCALL(sys_getitimer,sys_getitimer,compat_sys_getitimer_wrapper) /* 105 */
+SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat_wrapper)
+SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat_wrapper)
+SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat_wrapper)
+NI_SYSCALL /* old uname syscall */
+SYSCALL(sys_lookup_dcookie,sys_lookup_dcookie,sys32_lookup_dcookie_wrapper) /* 110 */
+SYSCALL(sys_vhangup,sys_vhangup,sys_vhangup)
+NI_SYSCALL /* old "idle" system call */
+NI_SYSCALL /* vm86old for i386 */
+SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4_wrapper)
+SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */
+SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper)
+SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper)
+SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper)
+SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn)
+SYSCALL(sys_clone,sys_clone,sys32_clone) /* 120 */
+SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper)
+SYSCALL(sys_newuname,s390x_newuname,sys32_newuname_wrapper)
+NI_SYSCALL /* modify_ldt for i386 */
+SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper)
+SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */
+SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask_wrapper)
+NI_SYSCALL /* old "create module" */
+SYSCALL(sys_init_module,sys_init_module,sys32_init_module_wrapper)
+SYSCALL(sys_delete_module,sys_delete_module,sys32_delete_module_wrapper)
+NI_SYSCALL /* 130: old get_kernel_syms */
+SYSCALL(sys_quotactl,sys_quotactl,sys32_quotactl_wrapper)
+SYSCALL(sys_getpgid,sys_getpgid,sys32_getpgid_wrapper)
+SYSCALL(sys_fchdir,sys_fchdir,sys32_fchdir_wrapper)
+SYSCALL(sys_bdflush,sys_bdflush,sys32_bdflush_wrapper)
+SYSCALL(sys_sysfs,sys_sysfs,sys32_sysfs_wrapper) /* 135 */
+SYSCALL(sys_personality,s390x_personality,sys32_personality_wrapper)
+NI_SYSCALL /* for afs_syscall */
+SYSCALL(sys_setfsuid16,sys_ni_syscall,sys32_setfsuid16_wrapper) /* old setfsuid16 syscall */
+SYSCALL(sys_setfsgid16,sys_ni_syscall,sys32_setfsgid16_wrapper) /* old setfsgid16 syscall */
+SYSCALL(sys_llseek,sys_llseek,sys32_llseek_wrapper) /* 140 */
+SYSCALL(sys_getdents,sys_getdents,sys32_getdents_wrapper)
+SYSCALL(sys_select,sys_select,compat_sys_select_wrapper)
+SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper)
+SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper)
+SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper) /* 145 */
+SYSCALL(sys_writev,sys_writev,compat_sys_writev_wrapper)
+SYSCALL(sys_getsid,sys_getsid,sys32_getsid_wrapper)
+SYSCALL(sys_fdatasync,sys_fdatasync,sys32_fdatasync_wrapper)
+SYSCALL(sys_sysctl,sys_sysctl,sys32_sysctl_wrapper)
+SYSCALL(sys_mlock,sys_mlock,sys32_mlock_wrapper) /* 150 */
+SYSCALL(sys_munlock,sys_munlock,sys32_munlock_wrapper)
+SYSCALL(sys_mlockall,sys_mlockall,sys32_mlockall_wrapper)
+SYSCALL(sys_munlockall,sys_munlockall,sys_munlockall)
+SYSCALL(sys_sched_setparam,sys_sched_setparam,sys32_sched_setparam_wrapper)
+SYSCALL(sys_sched_getparam,sys_sched_getparam,sys32_sched_getparam_wrapper) /* 155 */
+SYSCALL(sys_sched_setscheduler,sys_sched_setscheduler,sys32_sched_setscheduler_wrapper)
+SYSCALL(sys_sched_getscheduler,sys_sched_getscheduler,sys32_sched_getscheduler_wrapper)
+SYSCALL(sys_sched_yield,sys_sched_yield,sys_sched_yield)
+SYSCALL(sys_sched_get_priority_max,sys_sched_get_priority_max,sys32_sched_get_priority_max_wrapper)
+SYSCALL(sys_sched_get_priority_min,sys_sched_get_priority_min,sys32_sched_get_priority_min_wrapper) /* 160 */
+SYSCALL(sys_sched_rr_get_interval,sys_sched_rr_get_interval,sys32_sched_rr_get_interval_wrapper)
+SYSCALL(sys_nanosleep,sys_nanosleep,compat_sys_nanosleep_wrapper)
+SYSCALL(sys_mremap,sys_mremap,sys32_mremap_wrapper)
+SYSCALL(sys_setresuid16,sys_ni_syscall,sys32_setresuid16_wrapper) /* old setresuid16 syscall */
+SYSCALL(sys_getresuid16,sys_ni_syscall,sys32_getresuid16_wrapper) /* 165 old getresuid16 syscall */
+NI_SYSCALL /* for vm86 */
+NI_SYSCALL /* old sys_query_module */
+SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper)
+SYSCALL(sys_nfsservctl,sys_nfsservctl,compat_sys_nfsservctl_wrapper)
+SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old setresgid16 syscall */
+SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */
+SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
+SYSCALL(sys_rt_sigreturn,sys_rt_sigreturn,sys32_rt_sigreturn)
+SYSCALL(sys_rt_sigaction,sys_rt_sigaction,sys32_rt_sigaction_wrapper)
+SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,sys32_rt_sigprocmask_wrapper) /* 175 */
+SYSCALL(sys_rt_sigpending,sys_rt_sigpending,sys32_rt_sigpending_wrapper)
+SYSCALL(sys_rt_sigtimedwait,sys_rt_sigtimedwait,compat_sys_rt_sigtimedwait_wrapper)
+SYSCALL(sys_rt_sigqueueinfo,sys_rt_sigqueueinfo,sys32_rt_sigqueueinfo_wrapper)
+SYSCALL(sys_rt_sigsuspend,sys_rt_sigsuspend,compat_sys_rt_sigsuspend_wrapper)
+SYSCALL(sys_pread64,sys_pread64,sys32_pread64_wrapper) /* 180 */
+SYSCALL(sys_pwrite64,sys_pwrite64,sys32_pwrite64_wrapper)
+SYSCALL(sys_chown16,sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall */
+SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper)
+SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper)
+SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper) /* 185 */
+SYSCALL(sys_sigaltstack,sys_sigaltstack,sys32_sigaltstack)
+SYSCALL(sys_sendfile,sys_sendfile64,sys32_sendfile_wrapper)
+NI_SYSCALL /* streams1 */
+NI_SYSCALL /* streams2 */
+SYSCALL(sys_vfork,sys_vfork,sys_vfork) /* 190 */
+SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit_wrapper)
+SYSCALL(sys_mmap2,sys_mmap2,sys32_mmap2_wrapper)
+SYSCALL(sys_truncate64,sys_ni_syscall,sys32_truncate64_wrapper)
+SYSCALL(sys_ftruncate64,sys_ni_syscall,sys32_ftruncate64_wrapper)
+SYSCALL(sys_stat64,sys_ni_syscall,sys32_stat64_wrapper) /* 195 */
+SYSCALL(sys_lstat64,sys_ni_syscall,sys32_lstat64_wrapper)
+SYSCALL(sys_fstat64,sys_ni_syscall,sys32_fstat64_wrapper)
+SYSCALL(sys_lchown,sys_lchown,sys32_lchown_wrapper)
+SYSCALL(sys_getuid,sys_getuid,sys_getuid)
+SYSCALL(sys_getgid,sys_getgid,sys_getgid) /* 200 */
+SYSCALL(sys_geteuid,sys_geteuid,sys_geteuid)
+SYSCALL(sys_getegid,sys_getegid,sys_getegid)
+SYSCALL(sys_setreuid,sys_setreuid,sys32_setreuid_wrapper)
+SYSCALL(sys_setregid,sys_setregid,sys32_setregid_wrapper)
+SYSCALL(sys_getgroups,sys_getgroups,sys32_getgroups_wrapper) /* 205 */
+SYSCALL(sys_setgroups,sys_setgroups,sys32_setgroups_wrapper)
+SYSCALL(sys_fchown,sys_fchown,sys32_fchown_wrapper)
+SYSCALL(sys_setresuid,sys_setresuid,sys32_setresuid_wrapper)
+SYSCALL(sys_getresuid,sys_getresuid,sys32_getresuid_wrapper)
+SYSCALL(sys_setresgid,sys_setresgid,sys32_setresgid_wrapper) /* 210 */
+SYSCALL(sys_getresgid,sys_getresgid,sys32_getresgid_wrapper)
+SYSCALL(sys_chown,sys_chown,sys32_chown_wrapper)
+SYSCALL(sys_setuid,sys_setuid,sys32_setuid_wrapper)
+SYSCALL(sys_setgid,sys_setgid,sys32_setgid_wrapper)
+SYSCALL(sys_setfsuid,sys_setfsuid,sys32_setfsuid_wrapper) /* 215 */
+SYSCALL(sys_setfsgid,sys_setfsgid,sys32_setfsgid_wrapper)
+SYSCALL(sys_pivot_root,sys_pivot_root,sys32_pivot_root_wrapper)
+SYSCALL(sys_mincore,sys_mincore,sys32_mincore_wrapper)
+SYSCALL(sys_madvise,sys_madvise,sys32_madvise_wrapper)
+SYSCALL(sys_getdents64,sys_getdents64,sys32_getdents64_wrapper) /* 220 */
+SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64_wrapper)
+SYSCALL(sys_readahead,sys_readahead,sys32_readahead)
+SYSCALL(sys_sendfile64,sys_ni_syscall,sys32_sendfile64)
+SYSCALL(sys_setxattr,sys_setxattr,sys32_setxattr_wrapper)
+SYSCALL(sys_lsetxattr,sys_lsetxattr,sys32_lsetxattr_wrapper) /* 225 */
+SYSCALL(sys_fsetxattr,sys_fsetxattr,sys32_fsetxattr_wrapper)
+SYSCALL(sys_getxattr,sys_getxattr,sys32_getxattr_wrapper)
+SYSCALL(sys_lgetxattr,sys_lgetxattr,sys32_lgetxattr_wrapper)
+SYSCALL(sys_fgetxattr,sys_fgetxattr,sys32_fgetxattr_wrapper)
+SYSCALL(sys_listxattr,sys_listxattr,sys32_listxattr_wrapper) /* 230 */
+SYSCALL(sys_llistxattr,sys_llistxattr,sys32_llistxattr_wrapper)
+SYSCALL(sys_flistxattr,sys_flistxattr,sys32_flistxattr_wrapper)
+SYSCALL(sys_removexattr,sys_removexattr,sys32_removexattr_wrapper)
+SYSCALL(sys_lremovexattr,sys_lremovexattr,sys32_lremovexattr_wrapper)
+SYSCALL(sys_fremovexattr,sys_fremovexattr,sys32_fremovexattr_wrapper) /* 235 */
+SYSCALL(sys_gettid,sys_gettid,sys_gettid)
+SYSCALL(sys_tkill,sys_tkill,sys_tkill)
+SYSCALL(sys_futex,sys_futex,compat_sys_futex_wrapper)
+SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,sys32_sched_setaffinity_wrapper)
+SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,sys32_sched_getaffinity_wrapper) /* 240 */
+SYSCALL(sys_tgkill,sys_tgkill,sys_tgkill)
+NI_SYSCALL /* reserved for TUX */
+SYSCALL(sys_io_setup,sys_io_setup,sys32_io_setup_wrapper)
+SYSCALL(sys_io_destroy,sys_io_destroy,sys32_io_destroy_wrapper)
+SYSCALL(sys_io_getevents,sys_io_getevents,sys32_io_getevents_wrapper) /* 245 */
+SYSCALL(sys_io_submit,sys_io_submit,sys32_io_submit_wrapper)
+SYSCALL(sys_io_cancel,sys_io_cancel,sys32_io_cancel_wrapper)
+SYSCALL(sys_exit_group,sys_exit_group,sys32_exit_group_wrapper)
+SYSCALL(sys_epoll_create,sys_epoll_create,sys_epoll_create_wrapper)
+SYSCALL(sys_epoll_ctl,sys_epoll_ctl,sys_epoll_ctl_wrapper) /* 250 */
+SYSCALL(sys_epoll_wait,sys_epoll_wait,sys_epoll_wait_wrapper)
+SYSCALL(sys_set_tid_address,sys_set_tid_address,sys32_set_tid_address_wrapper)
+SYSCALL(s390_fadvise64,sys_fadvise64_64,sys32_fadvise64_wrapper)
+SYSCALL(sys_timer_create,sys_timer_create,sys32_timer_create_wrapper)
+SYSCALL(sys_timer_settime,sys_timer_settime,sys32_timer_settime_wrapper) /* 255 */
+SYSCALL(sys_timer_gettime,sys_timer_gettime,sys32_timer_gettime_wrapper)
+SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,sys32_timer_getoverrun_wrapper)
+SYSCALL(sys_timer_delete,sys_timer_delete,sys32_timer_delete_wrapper)
+SYSCALL(sys_clock_settime,sys_clock_settime,sys32_clock_settime_wrapper)
+SYSCALL(sys_clock_gettime,sys_clock_gettime,sys32_clock_gettime_wrapper) /* 260 */
+SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper)
+SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper)
+NI_SYSCALL /* reserved for vserver */
+SYSCALL(s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper)
+SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper)
+SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper)
+SYSCALL(sys_remap_file_pages,sys_remap_file_pages,sys32_remap_file_pages_wrapper)
+NI_SYSCALL /* 268 sys_mbind */
+NI_SYSCALL /* 269 sys_get_mempolicy */
+NI_SYSCALL /* 270 sys_set_mempolicy */
+SYSCALL(sys_mq_open,sys_mq_open,compat_sys_mq_open_wrapper)
+SYSCALL(sys_mq_unlink,sys_mq_unlink,sys32_mq_unlink_wrapper)
+SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper)
+SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
+SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
+SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
+SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper)
+SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
+SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
+SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl) /* 280 */
+SYSCALL(sys_waitid,sys_waitid,compat_sys_waitid_wrapper)
+SYSCALL(sys_ioprio_set,sys_ioprio_set,sys_ioprio_set_wrapper)
+SYSCALL(sys_ioprio_get,sys_ioprio_get,sys_ioprio_get_wrapper)
+SYSCALL(sys_inotify_init,sys_inotify_init,sys_inotify_init)
+SYSCALL(sys_inotify_add_watch,sys_inotify_add_watch,sys_inotify_add_watch_wrapper) /* 285 */
+SYSCALL(sys_inotify_rm_watch,sys_inotify_rm_watch,sys_inotify_rm_watch_wrapper)
+NI_SYSCALL /* 287 sys_migrate_pages */
+SYSCALL(sys_openat,sys_openat,compat_sys_openat_wrapper)
+SYSCALL(sys_mkdirat,sys_mkdirat,sys_mkdirat_wrapper)
+SYSCALL(sys_mknodat,sys_mknodat,sys_mknodat_wrapper) /* 290 */
+SYSCALL(sys_fchownat,sys_fchownat,sys_fchownat_wrapper)
+SYSCALL(sys_futimesat,sys_futimesat,compat_sys_futimesat_wrapper)
+SYSCALL(sys_fstatat64,sys_newfstatat,sys32_fstatat64_wrapper)
+SYSCALL(sys_unlinkat,sys_unlinkat,sys_unlinkat_wrapper)
+SYSCALL(sys_renameat,sys_renameat,sys_renameat_wrapper) /* 295 */
+SYSCALL(sys_linkat,sys_linkat,sys_linkat_wrapper)
+SYSCALL(sys_symlinkat,sys_symlinkat,sys_symlinkat_wrapper)
+SYSCALL(sys_readlinkat,sys_readlinkat,sys_readlinkat_wrapper)
+SYSCALL(sys_fchmodat,sys_fchmodat,sys_fchmodat_wrapper)
+SYSCALL(sys_faccessat,sys_faccessat,sys_faccessat_wrapper) /* 300 */
+SYSCALL(sys_pselect6,sys_pselect6,compat_sys_pselect6_wrapper)
+SYSCALL(sys_ppoll,sys_ppoll,compat_sys_ppoll_wrapper)
+SYSCALL(sys_unshare,sys_unshare,sys_unshare_wrapper)
+SYSCALL(sys_set_robust_list,sys_set_robust_list,compat_sys_set_robust_list_wrapper)
+SYSCALL(sys_get_robust_list,sys_get_robust_list,compat_sys_get_robust_list_wrapper)
+SYSCALL(sys_splice,sys_splice,sys_splice_wrapper)
+SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper)
+SYSCALL(sys_tee,sys_tee,sys_tee_wrapper)
+SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice_wrapper)
+NI_SYSCALL /* 310 sys_move_pages */
+SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper)
+SYSCALL(sys_epoll_pwait,sys_epoll_pwait,compat_sys_epoll_pwait_wrapper)
+SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper)
+SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper)
+SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */
+SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper)
+NI_SYSCALL /* 317 old sys_timer_fd */
+SYSCALL(sys_eventfd,sys_eventfd,sys_eventfd_wrapper)
+SYSCALL(sys_timerfd_create,sys_timerfd_create,sys_timerfd_create_wrapper)
+SYSCALL(sys_timerfd_settime,sys_timerfd_settime,compat_sys_timerfd_settime_wrapper) /* 320 */
+SYSCALL(sys_timerfd_gettime,sys_timerfd_gettime,compat_sys_timerfd_gettime_wrapper)
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/time.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/time.c
new file mode 100644
index 0000000000..cb232c1553
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/time.c
@@ -0,0 +1,1403 @@
+/*
+ * arch/s390/kernel/time.c
+ * Time of day based timer functions.
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ * Derived from "arch/i386/kernel/time.c"
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/sysdev.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+#include <linux/profile.h>
+#include <linux/timex.h>
+#include <linux/notifier.h>
+#include <linux/clocksource.h>
+
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+#include <asm/s390_ext.h>
+#include <asm/div64.h>
+#include <asm/irq.h>
+#include <asm/irq_regs.h>
+#include <asm/timer.h>
+#include <asm/etr.h>
+
+/* change this if you have some constant time drift */
+#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ)
+#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
+
+/* The value of the TOD clock for 1.1.1970. */
+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
+
+/*
+ * Create a small time difference between the timer interrupts
+ * on the different cpus to avoid lock contention.
+ */
+#define CPU_DEVIATION (smp_processor_id() << 12)
+
+#define TICK_SIZE tick
+
+static ext_int_info_t ext_int_info_cc;
+static ext_int_info_t ext_int_etr_cc;
+static u64 init_timer_cc;
+static u64 jiffies_timer_cc;
+static u64 xtime_cc;
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+ return ((get_clock() - jiffies_timer_cc) * 125) >> 9;
+}
+
+/*
+ * Monotonic_clock - returns # of nanoseconds passed since time_init()
+ */
+unsigned long long monotonic_clock(void)
+{
+ return sched_clock();
+}
+EXPORT_SYMBOL(monotonic_clock);
+
+void tod_to_timeval(__u64 todval, struct timespec *xtime)
+{
+ unsigned long long sec;
+
+ sec = todval >> 12;
+ do_div(sec, 1000000);
+ xtime->tv_sec = sec;
+ todval -= (sec * 1000000) << 12;
+ xtime->tv_nsec = ((todval * 1000) >> 12);
+}
+
+#ifdef CONFIG_PROFILING
+#define s390_do_profile() profile_tick(CPU_PROFILING)
+#else
+#define s390_do_profile() do { ; } while(0)
+#endif /* CONFIG_PROFILING */
+
+/*
+ * Advance the per cpu tick counter up to the time given with the
+ * "time" argument. The per cpu update consists of accounting
+ * the virtual cpu time, calling update_process_times and calling
+ * the profiling hook. If xtime is before time it is advanced as well.
+ */
+void account_ticks(u64 time)
+{
+ __u32 ticks;
+ __u64 tmp;
+
+ /* Calculate how many ticks have passed. */
+ if (time < S390_lowcore.jiffy_timer)
+ return;
+ tmp = time - S390_lowcore.jiffy_timer;
+ if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */
+ ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
+ S390_lowcore.jiffy_timer +=
+ CLK_TICKS_PER_JIFFY * (__u64) ticks;
+ } else if (tmp >= CLK_TICKS_PER_JIFFY) {
+ ticks = 2;
+ S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY;
+ } else {
+ ticks = 1;
+ S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
+ }
+
+#ifdef CONFIG_SMP
+ /*
+ * Do not rely on the boot cpu to do the calls to do_timer.
+ * Spread it over all cpus instead.
+ */
+ write_seqlock(&xtime_lock);
+ if (S390_lowcore.jiffy_timer > xtime_cc) {
+ __u32 xticks;
+ tmp = S390_lowcore.jiffy_timer - xtime_cc;
+ if (tmp >= 2*CLK_TICKS_PER_JIFFY) {
+ xticks = __div(tmp, CLK_TICKS_PER_JIFFY);
+ xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY;
+ } else {
+ xticks = 1;
+ xtime_cc += CLK_TICKS_PER_JIFFY;
+ }
+ do_timer(xticks);
+ }
+ write_sequnlock(&xtime_lock);
+#else
+ do_timer(ticks);
+#endif
+
+ while (ticks--)
+ update_process_times(user_mode(get_irq_regs()));
+
+ s390_do_profile();
+}
+
+#ifdef CONFIG_NO_IDLE_HZ
+
+#ifdef CONFIG_NO_IDLE_HZ_INIT
+int sysctl_hz_timer = 0;
+#else
+int sysctl_hz_timer = 1;
+#endif
+
+/*
+ * Stop the HZ tick on the current CPU.
+ * Only cpu_idle may call this function.
+ */
+static void stop_hz_timer(void)
+{
+ unsigned long flags;
+ unsigned long seq, next;
+ __u64 timer, todval;
+ int cpu = smp_processor_id();
+
+ if (sysctl_hz_timer != 0)
+ return;
+
+ cpu_set(cpu, nohz_cpu_mask);
+
+ /*
+ * Leave the clock comparator set up for the next timer
+ * tick if either rcu or a softirq is pending.
+ */
+ if (rcu_needs_cpu(cpu) || local_softirq_pending()) {
+ cpu_clear(cpu, nohz_cpu_mask);
+ return;
+ }
+
+ /*
+ * This cpu is going really idle. Set up the clock comparator
+ * for the next event.
+ */
+ next = next_timer_interrupt();
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ timer = ((__u64) next) - ((__u64) jiffies) + jiffies_64;
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+ todval = -1ULL;
+ /* Be careful about overflows. */
+ if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) {
+ timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY;
+ if (timer >= jiffies_timer_cc)
+ todval = timer;
+ }
+ set_clock_comparator(todval);
+}
+
+/*
+ * Start the HZ tick on the current CPU.
+ * Only cpu_idle may call this function.
+ */
+static void start_hz_timer(void)
+{
+ if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
+ return;
+ account_ticks(get_clock());
+ set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+ cpu_clear(smp_processor_id(), nohz_cpu_mask);
+}
+
+static int nohz_idle_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ switch (action) {
+ case S390_CPU_IDLE:
+ stop_hz_timer();
+ break;
+ case S390_CPU_NOT_IDLE:
+ start_hz_timer();
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block nohz_idle_nb = {
+ .notifier_call = nohz_idle_notify,
+};
+
+static void __init nohz_init(void)
+{
+ if (register_idle_notifier(&nohz_idle_nb))
+ panic("Couldn't register idle notifier");
+}
+
+#endif
+
+/*
+ * Set up per cpu jiffy timer and set the clock comparator.
+ */
+static void setup_jiffy_timer(void)
+{
+ /* Set up clock comparator to next jiffy. */
+ S390_lowcore.jiffy_timer =
+ jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY;
+ set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+/*
+ * Set up lowcore and control register of the current cpu to
+ * enable TOD clock and clock comparator interrupts.
+ */
+void init_cpu_timer(void)
+{
+ setup_jiffy_timer();
+
+ /* Enable clock comparator timer interrupt. */
+ __ctl_set_bit(0,11);
+
+ /* Always allow ETR external interrupts, even without an ETR. */
+ __ctl_set_bit(0, 4);
+}
+
+static void clock_comparator_interrupt(__u16 code)
+{
+ /* set clock comparator for next tick */
+ set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+static void etr_reset(void);
+static void etr_ext_handler(__u16);
+
+/*
+ * Get the TOD clock running.
+ */
+static u64 __init reset_tod_clock(void)
+{
+ u64 time;
+
+ etr_reset();
+ if (store_clock(&time) == 0)
+ return time;
+ /* TOD clock not running. Set the clock to Unix Epoch. */
+ if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0)
+ panic("TOD clock not operational.");
+
+ return TOD_UNIX_EPOCH;
+}
+
+static cycle_t read_tod_clock(void)
+{
+ return get_clock();
+}
+
+static struct clocksource clocksource_tod = {
+ .name = "tod",
+ .rating = 400,
+ .read = read_tod_clock,
+ .mask = -1ULL,
+ .mult = 1000,
+ .shift = 12,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+
+/*
+ * Initialize the TOD clock and the CPU timer of
+ * the boot cpu.
+ */
+void __init time_init(void)
+{
+ init_timer_cc = reset_tod_clock();
+ xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
+ jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY;
+
+ /* set xtime */
+ tod_to_timeval(init_timer_cc - TOD_UNIX_EPOCH, &xtime);
+ set_normalized_timespec(&wall_to_monotonic,
+ -xtime.tv_sec, -xtime.tv_nsec);
+
+ /* request the clock comparator external interrupt */
+ if (register_early_external_interrupt(0x1004,
+ clock_comparator_interrupt,
+ &ext_int_info_cc) != 0)
+ panic("Couldn't request external interrupt 0x1004");
+
+ if (clocksource_register(&clocksource_tod) != 0)
+ panic("Could not register TOD clock source");
+
+ /* request the etr external interrupt */
+ if (register_early_external_interrupt(0x1406, etr_ext_handler,
+ &ext_int_etr_cc) != 0)
+ panic("Couldn't request external interrupt 0x1406");
+
+ /* Enable TOD clock interrupts on the boot cpu. */
+ init_cpu_timer();
+
+#ifdef CONFIG_NO_IDLE_HZ
+ nohz_init();
+#endif
+
+#ifdef CONFIG_VIRT_TIMER
+ vtime_init();
+#endif
+}
+
+/*
+ * External Time Reference (ETR) code.
+ */
+static int etr_port0_online;
+static int etr_port1_online;
+
+static int __init early_parse_etr(char *p)
+{
+ if (strncmp(p, "off", 3) == 0)
+ etr_port0_online = etr_port1_online = 0;
+ else if (strncmp(p, "port0", 5) == 0)
+ etr_port0_online = 1;
+ else if (strncmp(p, "port1", 5) == 0)
+ etr_port1_online = 1;
+ else if (strncmp(p, "on", 2) == 0)
+ etr_port0_online = etr_port1_online = 1;
+ return 0;
+}
+early_param("etr", early_parse_etr);
+
+enum etr_event {
+ ETR_EVENT_PORT0_CHANGE,
+ ETR_EVENT_PORT1_CHANGE,
+ ETR_EVENT_PORT_ALERT,
+ ETR_EVENT_SYNC_CHECK,
+ ETR_EVENT_SWITCH_LOCAL,
+ ETR_EVENT_UPDATE,
+};
+
+enum etr_flags {
+ ETR_FLAG_ENOSYS,
+ ETR_FLAG_EACCES,
+ ETR_FLAG_STEAI,
+};
+
+/*
+ * Valid bit combinations of the eacr register are (x = don't care):
+ * e0 e1 dp p0 p1 ea es sl
+ * 0 0 x 0 0 0 0 0 initial, disabled state
+ * 0 0 x 0 1 1 0 0 port 1 online
+ * 0 0 x 1 0 1 0 0 port 0 online
+ * 0 0 x 1 1 1 0 0 both ports online
+ * 0 1 x 0 1 1 0 0 port 1 online and usable, ETR or PPS mode
+ * 0 1 x 0 1 1 0 1 port 1 online, usable and ETR mode
+ * 0 1 x 0 1 1 1 0 port 1 online, usable, PPS mode, in-sync
+ * 0 1 x 0 1 1 1 1 port 1 online, usable, ETR mode, in-sync
+ * 0 1 x 1 1 1 0 0 both ports online, port 1 usable
+ * 0 1 x 1 1 1 1 0 both ports online, port 1 usable, PPS mode, in-sync
+ * 0 1 x 1 1 1 1 1 both ports online, port 1 usable, ETR mode, in-sync
+ * 1 0 x 1 0 1 0 0 port 0 online and usable, ETR or PPS mode
+ * 1 0 x 1 0 1 0 1 port 0 online, usable and ETR mode
+ * 1 0 x 1 0 1 1 0 port 0 online, usable, PPS mode, in-sync
+ * 1 0 x 1 0 1 1 1 port 0 online, usable, ETR mode, in-sync
+ * 1 0 x 1 1 1 0 0 both ports online, port 0 usable
+ * 1 0 x 1 1 1 1 0 both ports online, port 0 usable, PPS mode, in-sync
+ * 1 0 x 1 1 1 1 1 both ports online, port 0 usable, ETR mode, in-sync
+ * 1 1 x 1 1 1 1 0 both ports online & usable, ETR, in-sync
+ * 1 1 x 1 1 1 1 1 both ports online & usable, ETR, in-sync
+ */
+static struct etr_eacr etr_eacr;
+static u64 etr_tolec; /* time of last eacr update */
+static unsigned long etr_flags;
+static struct etr_aib etr_port0;
+static int etr_port0_uptodate;
+static struct etr_aib etr_port1;
+static int etr_port1_uptodate;
+static unsigned long etr_events;
+static struct timer_list etr_timer;
+static DEFINE_PER_CPU(atomic_t, etr_sync_word);
+
+static void etr_timeout(unsigned long dummy);
+static void etr_work_fn(struct work_struct *work);
+static DECLARE_WORK(etr_work, etr_work_fn);
+
+/*
+ * The etr get_clock function. It will write the current clock value
+ * to the clock pointer and return 0 if the clock is in sync with the
+ * external time source. If the clock mode is local it will return
+ * -ENOSYS and -EAGAIN if the clock is not in sync with the external
+ * reference. This function is what ETR is all about..
+ */
+int get_sync_clock(unsigned long long *clock)
+{
+ atomic_t *sw_ptr;
+ unsigned int sw0, sw1;
+
+ sw_ptr = &get_cpu_var(etr_sync_word);
+ sw0 = atomic_read(sw_ptr);
+ *clock = get_clock();
+ sw1 = atomic_read(sw_ptr);
+ put_cpu_var(etr_sync_sync);
+ if (sw0 == sw1 && (sw0 & 0x80000000U))
+ /* Success: time is in sync. */
+ return 0;
+ if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+ return -ENOSYS;
+ if (test_bit(ETR_FLAG_EACCES, &etr_flags))
+ return -EACCES;
+ return -EAGAIN;
+}
+EXPORT_SYMBOL(get_sync_clock);
+
+/*
+ * Make get_sync_clock return -EAGAIN.
+ */
+static void etr_disable_sync_clock(void *dummy)
+{
+ atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+ /*
+ * Clear the in-sync bit 2^31. All get_sync_clock calls will
+ * fail until the sync bit is turned back on. In addition
+ * increase the "sequence" counter to avoid the race of an
+ * etr event and the complete recovery against get_sync_clock.
+ */
+ atomic_clear_mask(0x80000000, sw_ptr);
+ atomic_inc(sw_ptr);
+}
+
+/*
+ * Make get_sync_clock return 0 again.
+ * Needs to be called from a context disabled for preemption.
+ */
+static void etr_enable_sync_clock(void)
+{
+ atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+ atomic_set_mask(0x80000000, sw_ptr);
+}
+
+/*
+ * Reset ETR attachment.
+ */
+static void etr_reset(void)
+{
+ etr_eacr = (struct etr_eacr) {
+ .e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0,
+ .p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0,
+ .es = 0, .sl = 0 };
+ if (etr_setr(&etr_eacr) == 0)
+ etr_tolec = get_clock();
+ else {
+ set_bit(ETR_FLAG_ENOSYS, &etr_flags);
+ if (etr_port0_online || etr_port1_online) {
+ printk(KERN_WARNING "Running on non ETR capable "
+ "machine, only local mode available.\n");
+ etr_port0_online = etr_port1_online = 0;
+ }
+ }
+}
+
+static int __init etr_init(void)
+{
+ struct etr_aib aib;
+
+ if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+ return 0;
+ /* Check if this machine has the steai instruction. */
+ if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0)
+ set_bit(ETR_FLAG_STEAI, &etr_flags);
+ setup_timer(&etr_timer, etr_timeout, 0UL);
+ if (!etr_port0_online && !etr_port1_online)
+ set_bit(ETR_FLAG_EACCES, &etr_flags);
+ if (etr_port0_online) {
+ set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+ schedule_work(&etr_work);
+ }
+ if (etr_port1_online) {
+ set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+ schedule_work(&etr_work);
+ }
+ return 0;
+}
+
+arch_initcall(etr_init);
+
+/*
+ * Two sorts of ETR machine checks. The architecture reads:
+ * "When a machine-check niterruption occurs and if a switch-to-local or
+ * ETR-sync-check interrupt request is pending but disabled, this pending
+ * disabled interruption request is indicated and is cleared".
+ * Which means that we can get etr_switch_to_local events from the machine
+ * check handler although the interruption condition is disabled. Lovely..
+ */
+
+/*
+ * Switch to local machine check. This is called when the last usable
+ * ETR port goes inactive. After switch to local the clock is not in sync.
+ */
+void etr_switch_to_local(void)
+{
+ if (!etr_eacr.sl)
+ return;
+ etr_disable_sync_clock(NULL);
+ set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);
+ schedule_work(&etr_work);
+}
+
+/*
+ * ETR sync check machine check. This is called when the ETR OTE and the
+ * local clock OTE are farther apart than the ETR sync check tolerance.
+ * After a ETR sync check the clock is not in sync. The machine check
+ * is broadcasted to all cpus at the same time.
+ */
+void etr_sync_check(void)
+{
+ if (!etr_eacr.es)
+ return;
+ etr_disable_sync_clock(NULL);
+ set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);
+ schedule_work(&etr_work);
+}
+
+/*
+ * ETR external interrupt. There are two causes:
+ * 1) port state change, check the usability of the port
+ * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the
+ * sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3)
+ * or ETR-data word 4 (edf4) has changed.
+ */
+static void etr_ext_handler(__u16 code)
+{
+ struct etr_interruption_parameter *intparm =
+ (struct etr_interruption_parameter *) &S390_lowcore.ext_params;
+
+ if (intparm->pc0)
+ /* ETR port 0 state change. */
+ set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+ if (intparm->pc1)
+ /* ETR port 1 state change. */
+ set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+ if (intparm->eai)
+ /*
+ * ETR port alert on either port 0, 1 or both.
+ * Both ports are not up-to-date now.
+ */
+ set_bit(ETR_EVENT_PORT_ALERT, &etr_events);
+ schedule_work(&etr_work);
+}
+
+static void etr_timeout(unsigned long dummy)
+{
+ set_bit(ETR_EVENT_UPDATE, &etr_events);
+ schedule_work(&etr_work);
+}
+
+/*
+ * Check if the etr mode is pss.
+ */
+static inline int etr_mode_is_pps(struct etr_eacr eacr)
+{
+ return eacr.es && !eacr.sl;
+}
+
+/*
+ * Check if the etr mode is etr.
+ */
+static inline int etr_mode_is_etr(struct etr_eacr eacr)
+{
+ return eacr.es && eacr.sl;
+}
+
+/*
+ * Check if the port can be used for TOD synchronization.
+ * For PPS mode the port has to receive OTEs. For ETR mode
+ * the port has to receive OTEs, the ETR stepping bit has to
+ * be zero and the validity bits for data frame 1, 2, and 3
+ * have to be 1.
+ */
+static int etr_port_valid(struct etr_aib *aib, int port)
+{
+ unsigned int psc;
+
+ /* Check that this port is receiving OTEs. */
+ if (aib->tsp == 0)
+ return 0;
+
+ psc = port ? aib->esw.psc1 : aib->esw.psc0;
+ if (psc == etr_lpsc_pps_mode)
+ return 1;
+ if (psc == etr_lpsc_operational_step)
+ return !aib->esw.y && aib->slsw.v1 &&
+ aib->slsw.v2 && aib->slsw.v3;
+ return 0;
+}
+
+/*
+ * Check if two ports are on the same network.
+ */
+static int etr_compare_network(struct etr_aib *aib1, struct etr_aib *aib2)
+{
+ // FIXME: any other fields we have to compare?
+ return aib1->edf1.net_id == aib2->edf1.net_id;
+}
+
+/*
+ * Wrapper for etr_stei that converts physical port states
+ * to logical port states to be consistent with the output
+ * of stetr (see etr_psc vs. etr_lpsc).
+ */
+static void etr_steai_cv(struct etr_aib *aib, unsigned int func)
+{
+ BUG_ON(etr_steai(aib, func) != 0);
+ /* Convert port state to logical port state. */
+ if (aib->esw.psc0 == 1)
+ aib->esw.psc0 = 2;
+ else if (aib->esw.psc0 == 0 && aib->esw.p == 0)
+ aib->esw.psc0 = 1;
+ if (aib->esw.psc1 == 1)
+ aib->esw.psc1 = 2;
+ else if (aib->esw.psc1 == 0 && aib->esw.p == 1)
+ aib->esw.psc1 = 1;
+}
+
+/*
+ * Check if the aib a2 is still connected to the same attachment as
+ * aib a1, the etv values differ by one and a2 is valid.
+ */
+static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p)
+{
+ int state_a1, state_a2;
+
+ /* Paranoia check: e0/e1 should better be the same. */
+ if (a1->esw.eacr.e0 != a2->esw.eacr.e0 ||
+ a1->esw.eacr.e1 != a2->esw.eacr.e1)
+ return 0;
+
+ /* Still connected to the same etr ? */
+ state_a1 = p ? a1->esw.psc1 : a1->esw.psc0;
+ state_a2 = p ? a2->esw.psc1 : a2->esw.psc0;
+ if (state_a1 == etr_lpsc_operational_step) {
+ if (state_a2 != etr_lpsc_operational_step ||
+ a1->edf1.net_id != a2->edf1.net_id ||
+ a1->edf1.etr_id != a2->edf1.etr_id ||
+ a1->edf1.etr_pn != a2->edf1.etr_pn)
+ return 0;
+ } else if (state_a2 != etr_lpsc_pps_mode)
+ return 0;
+
+ /* The ETV value of a2 needs to be ETV of a1 + 1. */
+ if (a1->edf2.etv + 1 != a2->edf2.etv)
+ return 0;
+
+ if (!etr_port_valid(a2, p))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * The time is "clock". xtime is what we think the time is.
+ * Adjust the value by a multiple of jiffies and add the delta to ntp.
+ * "delay" is an approximation how long the synchronization took. If
+ * the time correction is positive, then "delay" is subtracted from
+ * the time difference and only the remaining part is passed to ntp.
+ */
+static void etr_adjust_time(unsigned long long clock, unsigned long long delay)
+{
+ unsigned long long delta, ticks;
+ struct timex adjust;
+
+ /*
+ * We don't have to take the xtime lock because the cpu
+ * executing etr_adjust_time is running disabled in
+ * tasklet context and all other cpus are looping in
+ * etr_sync_cpu_start.
+ */
+ if (clock > xtime_cc) {
+ /* It is later than we thought. */
+ delta = ticks = clock - xtime_cc;
+ delta = ticks = (delta < delay) ? 0 : delta - delay;
+ delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+ init_timer_cc = init_timer_cc + delta;
+ jiffies_timer_cc = jiffies_timer_cc + delta;
+ xtime_cc = xtime_cc + delta;
+ adjust.offset = ticks * (1000000 / HZ);
+ } else {
+ /* It is earlier than we thought. */
+ delta = ticks = xtime_cc - clock;
+ delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+ init_timer_cc = init_timer_cc - delta;
+ jiffies_timer_cc = jiffies_timer_cc - delta;
+ xtime_cc = xtime_cc - delta;
+ adjust.offset = -ticks * (1000000 / HZ);
+ }
+ if (adjust.offset != 0) {
+ printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n",
+ adjust.offset);
+ adjust.modes = ADJ_OFFSET_SINGLESHOT;
+ do_adjtimex(&adjust);
+ }
+}
+
+static void etr_sync_cpu_start(void *dummy)
+{
+ int *in_sync = dummy;
+
+ etr_enable_sync_clock();
+ /*
+ * This looks like a busy wait loop but it isn't. etr_sync_cpus
+ * is called on all other cpus while the TOD clocks is stopped.
+ * __udelay will stop the cpu on an enabled wait psw until the
+ * TOD is running again.
+ */
+ while (*in_sync == 0) {
+ __udelay(1);
+ /*
+ * A different cpu changes *in_sync. Therefore use
+ * barrier() to force memory access.
+ */
+ barrier();
+ }
+ if (*in_sync != 1)
+ /* Didn't work. Clear per-cpu in sync bit again. */
+ etr_disable_sync_clock(NULL);
+ /*
+ * This round of TOD syncing is done. Set the clock comparator
+ * to the next tick and let the processor continue.
+ */
+ setup_jiffy_timer();
+}
+
+static void etr_sync_cpu_end(void *dummy)
+{
+}
+
+/*
+ * Sync the TOD clock using the port refered to by aibp. This port
+ * has to be enabled and the other port has to be disabled. The
+ * last eacr update has to be more than 1.6 seconds in the past.
+ */
+static int etr_sync_clock(struct etr_aib *aib, int port)
+{
+ struct etr_aib *sync_port;
+ unsigned long long clock, delay;
+ int in_sync, follows;
+ int rc;
+
+ /* Check if the current aib is adjacent to the sync port aib. */
+ sync_port = (port == 0) ? &etr_port0 : &etr_port1;
+ follows = etr_aib_follows(sync_port, aib, port);
+ memcpy(sync_port, aib, sizeof(*aib));
+ if (!follows)
+ return -EAGAIN;
+
+ /*
+ * Catch all other cpus and make them wait until we have
+ * successfully synced the clock. smp_call_function will
+ * return after all other cpus are in etr_sync_cpu_start.
+ */
+ in_sync = 0;
+ preempt_disable();
+ smp_call_function(etr_sync_cpu_start,&in_sync,0,0);
+ local_irq_disable();
+ etr_enable_sync_clock();
+
+ /* Set clock to next OTE. */
+ __ctl_set_bit(14, 21);
+ __ctl_set_bit(0, 29);
+ clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32;
+ if (set_clock(clock) == 0) {
+ __udelay(1); /* Wait for the clock to start. */
+ __ctl_clear_bit(0, 29);
+ __ctl_clear_bit(14, 21);
+ etr_stetr(aib);
+ /* Adjust Linux timing variables. */
+ delay = (unsigned long long)
+ (aib->edf2.etv - sync_port->edf2.etv) << 32;
+ etr_adjust_time(clock, delay);
+ setup_jiffy_timer();
+ /* Verify that the clock is properly set. */
+ if (!etr_aib_follows(sync_port, aib, port)) {
+ /* Didn't work. */
+ etr_disable_sync_clock(NULL);
+ in_sync = -EAGAIN;
+ rc = -EAGAIN;
+ } else {
+ in_sync = 1;
+ rc = 0;
+ }
+ } else {
+ /* Could not set the clock ?!? */
+ __ctl_clear_bit(0, 29);
+ __ctl_clear_bit(14, 21);
+ etr_disable_sync_clock(NULL);
+ in_sync = -EAGAIN;
+ rc = -EAGAIN;
+ }
+ local_irq_enable();
+ smp_call_function(etr_sync_cpu_end,NULL,0,0);
+ preempt_enable();
+ return rc;
+}
+
+/*
+ * Handle the immediate effects of the different events.
+ * The port change event is used for online/offline changes.
+ */
+static struct etr_eacr etr_handle_events(struct etr_eacr eacr)
+{
+ if (test_and_clear_bit(ETR_EVENT_SYNC_CHECK, &etr_events))
+ eacr.es = 0;
+ if (test_and_clear_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events))
+ eacr.es = eacr.sl = 0;
+ if (test_and_clear_bit(ETR_EVENT_PORT_ALERT, &etr_events))
+ etr_port0_uptodate = etr_port1_uptodate = 0;
+
+ if (test_and_clear_bit(ETR_EVENT_PORT0_CHANGE, &etr_events)) {
+ if (eacr.e0)
+ /*
+ * Port change of an enabled port. We have to
+ * assume that this can have caused an stepping
+ * port switch.
+ */
+ etr_tolec = get_clock();
+ eacr.p0 = etr_port0_online;
+ if (!eacr.p0)
+ eacr.e0 = 0;
+ etr_port0_uptodate = 0;
+ }
+ if (test_and_clear_bit(ETR_EVENT_PORT1_CHANGE, &etr_events)) {
+ if (eacr.e1)
+ /*
+ * Port change of an enabled port. We have to
+ * assume that this can have caused an stepping
+ * port switch.
+ */
+ etr_tolec = get_clock();
+ eacr.p1 = etr_port1_online;
+ if (!eacr.p1)
+ eacr.e1 = 0;
+ etr_port1_uptodate = 0;
+ }
+ clear_bit(ETR_EVENT_UPDATE, &etr_events);
+ return eacr;
+}
+
+/*
+ * Set up a timer that expires after the etr_tolec + 1.6 seconds if
+ * one of the ports needs an update.
+ */
+static void etr_set_tolec_timeout(unsigned long long now)
+{
+ unsigned long micros;
+
+ if ((!etr_eacr.p0 || etr_port0_uptodate) &&
+ (!etr_eacr.p1 || etr_port1_uptodate))
+ return;
+ micros = (now > etr_tolec) ? ((now - etr_tolec) >> 12) : 0;
+ micros = (micros > 1600000) ? 0 : 1600000 - micros;
+ mod_timer(&etr_timer, jiffies + (micros * HZ) / 1000000 + 1);
+}
+
+/*
+ * Set up a time that expires after 1/2 second.
+ */
+static void etr_set_sync_timeout(void)
+{
+ mod_timer(&etr_timer, jiffies + HZ/2);
+}
+
+/*
+ * Update the aib information for one or both ports.
+ */
+static struct etr_eacr etr_handle_update(struct etr_aib *aib,
+ struct etr_eacr eacr)
+{
+ /* With both ports disabled the aib information is useless. */
+ if (!eacr.e0 && !eacr.e1)
+ return eacr;
+
+ /* Update port0 or port1 with aib stored in etr_work_fn. */
+ if (aib->esw.q == 0) {
+ /* Information for port 0 stored. */
+ if (eacr.p0 && !etr_port0_uptodate) {
+ etr_port0 = *aib;
+ if (etr_port0_online)
+ etr_port0_uptodate = 1;
+ }
+ } else {
+ /* Information for port 1 stored. */
+ if (eacr.p1 && !etr_port1_uptodate) {
+ etr_port1 = *aib;
+ if (etr_port0_online)
+ etr_port1_uptodate = 1;
+ }
+ }
+
+ /*
+ * Do not try to get the alternate port aib if the clock
+ * is not in sync yet.
+ */
+ if (!eacr.es)
+ return eacr;
+
+ /*
+ * If steai is available we can get the information about
+ * the other port immediately. If only stetr is available the
+ * data-port bit toggle has to be used.
+ */
+ if (test_bit(ETR_FLAG_STEAI, &etr_flags)) {
+ if (eacr.p0 && !etr_port0_uptodate) {
+ etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0);
+ etr_port0_uptodate = 1;
+ }
+ if (eacr.p1 && !etr_port1_uptodate) {
+ etr_steai_cv(&etr_port1, ETR_STEAI_PORT_1);
+ etr_port1_uptodate = 1;
+ }
+ } else {
+ /*
+ * One port was updated above, if the other
+ * port is not uptodate toggle dp bit.
+ */
+ if ((eacr.p0 && !etr_port0_uptodate) ||
+ (eacr.p1 && !etr_port1_uptodate))
+ eacr.dp ^= 1;
+ else
+ eacr.dp = 0;
+ }
+ return eacr;
+}
+
+/*
+ * Write new etr control register if it differs from the current one.
+ * Return 1 if etr_tolec has been updated as well.
+ */
+static void etr_update_eacr(struct etr_eacr eacr)
+{
+ int dp_changed;
+
+ if (memcmp(&etr_eacr, &eacr, sizeof(eacr)) == 0)
+ /* No change, return. */
+ return;
+ /*
+ * The disable of an active port of the change of the data port
+ * bit can/will cause a change in the data port.
+ */
+ dp_changed = etr_eacr.e0 > eacr.e0 || etr_eacr.e1 > eacr.e1 ||
+ (etr_eacr.dp ^ eacr.dp) != 0;
+ etr_eacr = eacr;
+ etr_setr(&etr_eacr);
+ if (dp_changed)
+ etr_tolec = get_clock();
+}
+
+/*
+ * ETR tasklet. In this function you'll find the main logic. In
+ * particular this is the only function that calls etr_update_eacr(),
+ * it "controls" the etr control register.
+ */
+static void etr_work_fn(struct work_struct *work)
+{
+ unsigned long long now;
+ struct etr_eacr eacr;
+ struct etr_aib aib;
+ int sync_port;
+
+ /* Create working copy of etr_eacr. */
+ eacr = etr_eacr;
+
+ /* Check for the different events and their immediate effects. */
+ eacr = etr_handle_events(eacr);
+
+ /* Check if ETR is supposed to be active. */
+ eacr.ea = eacr.p0 || eacr.p1;
+ if (!eacr.ea) {
+ /* Both ports offline. Reset everything. */
+ eacr.dp = eacr.es = eacr.sl = 0;
+ on_each_cpu(etr_disable_sync_clock, NULL, 0, 1);
+ del_timer_sync(&etr_timer);
+ etr_update_eacr(eacr);
+ set_bit(ETR_FLAG_EACCES, &etr_flags);
+ return;
+ }
+
+ /* Store aib to get the current ETR status word. */
+ BUG_ON(etr_stetr(&aib) != 0);
+ etr_port0.esw = etr_port1.esw = aib.esw; /* Copy status word. */
+ now = get_clock();
+
+ /*
+ * Update the port information if the last stepping port change
+ * or data port change is older than 1.6 seconds.
+ */
+ if (now >= etr_tolec + (1600000 << 12))
+ eacr = etr_handle_update(&aib, eacr);
+
+ /*
+ * Select ports to enable. The prefered synchronization mode is PPS.
+ * If a port can be enabled depends on a number of things:
+ * 1) The port needs to be online and uptodate. A port is not
+ * disabled just because it is not uptodate, but it is only
+ * enabled if it is uptodate.
+ * 2) The port needs to have the same mode (pps / etr).
+ * 3) The port needs to be usable -> etr_port_valid() == 1
+ * 4) To enable the second port the clock needs to be in sync.
+ * 5) If both ports are useable and are ETR ports, the network id
+ * has to be the same.
+ * The eacr.sl bit is used to indicate etr mode vs. pps mode.
+ */
+ if (eacr.p0 && aib.esw.psc0 == etr_lpsc_pps_mode) {
+ eacr.sl = 0;
+ eacr.e0 = 1;
+ if (!etr_mode_is_pps(etr_eacr))
+ eacr.es = 0;
+ if (!eacr.es || !eacr.p1 || aib.esw.psc1 != etr_lpsc_pps_mode)
+ eacr.e1 = 0;
+ // FIXME: uptodate checks ?
+ else if (etr_port0_uptodate && etr_port1_uptodate)
+ eacr.e1 = 1;
+ sync_port = (etr_port0_uptodate &&
+ etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+ clear_bit(ETR_FLAG_EACCES, &etr_flags);
+ } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) {
+ eacr.sl = 0;
+ eacr.e0 = 0;
+ eacr.e1 = 1;
+ if (!etr_mode_is_pps(etr_eacr))
+ eacr.es = 0;
+ sync_port = (etr_port1_uptodate &&
+ etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+ clear_bit(ETR_FLAG_EACCES, &etr_flags);
+ } else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) {
+ eacr.sl = 1;
+ eacr.e0 = 1;
+ if (!etr_mode_is_etr(etr_eacr))
+ eacr.es = 0;
+ if (!eacr.es || !eacr.p1 ||
+ aib.esw.psc1 != etr_lpsc_operational_alt)
+ eacr.e1 = 0;
+ else if (etr_port0_uptodate && etr_port1_uptodate &&
+ etr_compare_network(&etr_port0, &etr_port1))
+ eacr.e1 = 1;
+ sync_port = (etr_port0_uptodate &&
+ etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+ clear_bit(ETR_FLAG_EACCES, &etr_flags);
+ } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) {
+ eacr.sl = 1;
+ eacr.e0 = 0;
+ eacr.e1 = 1;
+ if (!etr_mode_is_etr(etr_eacr))
+ eacr.es = 0;
+ sync_port = (etr_port1_uptodate &&
+ etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+ clear_bit(ETR_FLAG_EACCES, &etr_flags);
+ } else {
+ /* Both ports not usable. */
+ eacr.es = eacr.sl = 0;
+ sync_port = -1;
+ set_bit(ETR_FLAG_EACCES, &etr_flags);
+ }
+
+ /*
+ * If the clock is in sync just update the eacr and return.
+ * If there is no valid sync port wait for a port update.
+ */
+ if (eacr.es || sync_port < 0) {
+ etr_update_eacr(eacr);
+ etr_set_tolec_timeout(now);
+ return;
+ }
+
+ /*
+ * Prepare control register for clock syncing
+ * (reset data port bit, set sync check control.
+ */
+ eacr.dp = 0;
+ eacr.es = 1;
+
+ /*
+ * Update eacr and try to synchronize the clock. If the update
+ * of eacr caused a stepping port switch (or if we have to
+ * assume that a stepping port switch has occured) or the
+ * clock syncing failed, reset the sync check control bit
+ * and set up a timer to try again after 0.5 seconds
+ */
+ etr_update_eacr(eacr);
+ if (now < etr_tolec + (1600000 << 12) ||
+ etr_sync_clock(&aib, sync_port) != 0) {
+ /* Sync failed. Try again in 1/2 second. */
+ eacr.es = 0;
+ etr_update_eacr(eacr);
+ etr_set_sync_timeout();
+ } else
+ etr_set_tolec_timeout(now);
+}
+
+/*
+ * Sysfs interface functions
+ */
+static struct sysdev_class etr_sysclass = {
+ .name = "etr",
+};
+
+static struct sys_device etr_port0_dev = {
+ .id = 0,
+ .cls = &etr_sysclass,
+};
+
+static struct sys_device etr_port1_dev = {
+ .id = 1,
+ .cls = &etr_sysclass,
+};
+
+/*
+ * ETR class attributes
+ */
+static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf)
+{
+ return sprintf(buf, "%i\n", etr_port0.esw.p);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL);
+
+static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf)
+{
+ char *mode_str;
+
+ if (etr_mode_is_pps(etr_eacr))
+ mode_str = "pps";
+ else if (etr_mode_is_etr(etr_eacr))
+ mode_str = "etr";
+ else
+ mode_str = "local";
+ return sprintf(buf, "%s\n", mode_str);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_mode, 0400, etr_stepping_mode_show, NULL);
+
+/*
+ * ETR port attributes
+ */
+static inline struct etr_aib *etr_aib_from_dev(struct sys_device *dev)
+{
+ if (dev == &etr_port0_dev)
+ return etr_port0_online ? &etr_port0 : NULL;
+ else
+ return etr_port1_online ? &etr_port1 : NULL;
+}
+
+static ssize_t etr_online_show(struct sys_device *dev, char *buf)
+{
+ unsigned int online;
+
+ online = (dev == &etr_port0_dev) ? etr_port0_online : etr_port1_online;
+ return sprintf(buf, "%i\n", online);
+}
+
+static ssize_t etr_online_store(struct sys_device *dev,
+ const char *buf, size_t count)
+{
+ unsigned int value;
+
+ value = simple_strtoul(buf, NULL, 0);
+ if (value != 0 && value != 1)
+ return -EINVAL;
+ if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+ return -ENOSYS;
+ if (dev == &etr_port0_dev) {
+ if (etr_port0_online == value)
+ return count; /* Nothing to do. */
+ etr_port0_online = value;
+ set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+ schedule_work(&etr_work);
+ } else {
+ if (etr_port1_online == value)
+ return count; /* Nothing to do. */
+ etr_port1_online = value;
+ set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+ schedule_work(&etr_work);
+ }
+ return count;
+}
+
+static SYSDEV_ATTR(online, 0600, etr_online_show, etr_online_store);
+
+static ssize_t etr_stepping_control_show(struct sys_device *dev, char *buf)
+{
+ return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+ etr_eacr.e0 : etr_eacr.e1);
+}
+
+static SYSDEV_ATTR(stepping_control, 0400, etr_stepping_control_show, NULL);
+
+static ssize_t etr_mode_code_show(struct sys_device *dev, char *buf)
+{
+ if (!etr_port0_online && !etr_port1_online)
+ /* Status word is not uptodate if both ports are offline. */
+ return -ENODATA;
+ return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+ etr_port0.esw.psc0 : etr_port0.esw.psc1);
+}
+
+static SYSDEV_ATTR(state_code, 0400, etr_mode_code_show, NULL);
+
+static ssize_t etr_untuned_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v1)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf1.u);
+}
+
+static SYSDEV_ATTR(untuned, 0400, etr_untuned_show, NULL);
+
+static ssize_t etr_network_id_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v1)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf1.net_id);
+}
+
+static SYSDEV_ATTR(network, 0400, etr_network_id_show, NULL);
+
+static ssize_t etr_id_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v1)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf1.etr_id);
+}
+
+static SYSDEV_ATTR(id, 0400, etr_id_show, NULL);
+
+static ssize_t etr_port_number_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v1)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf1.etr_pn);
+}
+
+static SYSDEV_ATTR(port, 0400, etr_port_number_show, NULL);
+
+static ssize_t etr_coupled_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v3)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf3.c);
+}
+
+static SYSDEV_ATTR(coupled, 0400, etr_coupled_show, NULL);
+
+static ssize_t etr_local_time_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v3)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf3.blto);
+}
+
+static SYSDEV_ATTR(local_time, 0400, etr_local_time_show, NULL);
+
+static ssize_t etr_utc_offset_show(struct sys_device *dev, char *buf)
+{
+ struct etr_aib *aib = etr_aib_from_dev(dev);
+
+ if (!aib || !aib->slsw.v3)
+ return -ENODATA;
+ return sprintf(buf, "%i\n", aib->edf3.buo);
+}
+
+static SYSDEV_ATTR(utc_offset, 0400, etr_utc_offset_show, NULL);
+
+static struct sysdev_attribute *etr_port_attributes[] = {
+ &attr_online,
+ &attr_stepping_control,
+ &attr_state_code,
+ &attr_untuned,
+ &attr_network,
+ &attr_id,
+ &attr_port,
+ &attr_coupled,
+ &attr_local_time,
+ &attr_utc_offset,
+ NULL
+};
+
+static int __init etr_register_port(struct sys_device *dev)
+{
+ struct sysdev_attribute **attr;
+ int rc;
+
+ rc = sysdev_register(dev);
+ if (rc)
+ goto out;
+ for (attr = etr_port_attributes; *attr; attr++) {
+ rc = sysdev_create_file(dev, *attr);
+ if (rc)
+ goto out_unreg;
+ }
+ return 0;
+out_unreg:
+ for (; attr >= etr_port_attributes; attr--)
+ sysdev_remove_file(dev, *attr);
+ sysdev_unregister(dev);
+out:
+ return rc;
+}
+
+static void __init etr_unregister_port(struct sys_device *dev)
+{
+ struct sysdev_attribute **attr;
+
+ for (attr = etr_port_attributes; *attr; attr++)
+ sysdev_remove_file(dev, *attr);
+ sysdev_unregister(dev);
+}
+
+static int __init etr_init_sysfs(void)
+{
+ int rc;
+
+ rc = sysdev_class_register(&etr_sysclass);
+ if (rc)
+ goto out;
+ rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_port);
+ if (rc)
+ goto out_unreg_class;
+ rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_mode);
+ if (rc)
+ goto out_remove_stepping_port;
+ rc = etr_register_port(&etr_port0_dev);
+ if (rc)
+ goto out_remove_stepping_mode;
+ rc = etr_register_port(&etr_port1_dev);
+ if (rc)
+ goto out_remove_port0;
+ return 0;
+
+out_remove_port0:
+ etr_unregister_port(&etr_port0_dev);
+out_remove_stepping_mode:
+ sysdev_class_remove_file(&etr_sysclass, &attr_stepping_mode);
+out_remove_stepping_port:
+ sysdev_class_remove_file(&etr_sysclass, &attr_stepping_port);
+out_unreg_class:
+ sysdev_class_unregister(&etr_sysclass);
+out:
+ return rc;
+}
+
+device_initcall(etr_init_sysfs);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/traps.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/traps.c
new file mode 100644
index 0000000000..60f728aeaf
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/traps.c
@@ -0,0 +1,744 @@
+/*
+ * arch/s390/kernel/traps.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * Derived from "arch/i386/kernel/traps.c"
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'asm.s'.
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/kdebug.h>
+#include <linux/kallsyms.h>
+#include <linux/reboot.h>
+#include <linux/kprobes.h>
+#include <linux/bug.h>
+#include <linux/utsname.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/mathemu.h>
+#include <asm/cpcmd.h>
+#include <asm/s390_ext.h>
+#include <asm/lowcore.h>
+#include <asm/debug.h>
+
+/* Called from entry.S only */
+extern void handle_per_exception(struct pt_regs *regs);
+
+typedef void pgm_check_handler_t(struct pt_regs *, long);
+pgm_check_handler_t *pgm_check_table[128];
+
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
+int sysctl_userprocess_debug = 1;
+#else
+int sysctl_userprocess_debug = 0;
+#endif
+#endif
+
+extern pgm_check_handler_t do_protection_exception;
+extern pgm_check_handler_t do_dat_exception;
+extern pgm_check_handler_t do_monitor_call;
+extern pgm_check_handler_t do_asce_exception;
+
+#define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; })
+
+#ifndef CONFIG_64BIT
+#define FOURLONG "%08lx %08lx %08lx %08lx\n"
+static int kstack_depth_to_print = 12;
+#else /* CONFIG_64BIT */
+#define FOURLONG "%016lx %016lx %016lx %016lx\n"
+static int kstack_depth_to_print = 20;
+#endif /* CONFIG_64BIT */
+
+/*
+ * For show_trace we have tree different stack to consider:
+ * - the panic stack which is used if the kernel stack has overflown
+ * - the asynchronous interrupt stack (cpu related)
+ * - the synchronous kernel stack (process related)
+ * The stack trace can start at any of the three stack and can potentially
+ * touch all of them. The order is: panic stack, async stack, sync stack.
+ */
+static unsigned long
+__show_trace(unsigned long sp, unsigned long low, unsigned long high)
+{
+ struct stack_frame *sf;
+ struct pt_regs *regs;
+
+ while (1) {
+ sp = sp & PSW_ADDR_INSN;
+ if (sp < low || sp > high - sizeof(*sf))
+ return sp;
+ sf = (struct stack_frame *) sp;
+ printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
+ print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN);
+ /* Follow the backchain. */
+ while (1) {
+ low = sp;
+ sp = sf->back_chain & PSW_ADDR_INSN;
+ if (!sp)
+ break;
+ if (sp <= low || sp > high - sizeof(*sf))
+ return sp;
+ sf = (struct stack_frame *) sp;
+ printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
+ print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN);
+ }
+ /* Zero backchain detected, check for interrupt frame. */
+ sp = (unsigned long) (sf + 1);
+ if (sp <= low || sp > high - sizeof(*regs))
+ return sp;
+ regs = (struct pt_regs *) sp;
+ printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN);
+ print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN);
+ low = sp;
+ sp = regs->gprs[15];
+ }
+}
+
+void show_trace(struct task_struct *task, unsigned long *stack)
+{
+ register unsigned long __r15 asm ("15");
+ unsigned long sp;
+
+ sp = (unsigned long) stack;
+ if (!sp)
+ sp = task ? task->thread.ksp : __r15;
+ printk("Call Trace:\n");
+#ifdef CONFIG_CHECK_STACK
+ sp = __show_trace(sp, S390_lowcore.panic_stack - 4096,
+ S390_lowcore.panic_stack);
+#endif
+ sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE,
+ S390_lowcore.async_stack);
+ if (task)
+ __show_trace(sp, (unsigned long) task_stack_page(task),
+ (unsigned long) task_stack_page(task) + THREAD_SIZE);
+ else
+ __show_trace(sp, S390_lowcore.thread_info,
+ S390_lowcore.thread_info + THREAD_SIZE);
+ printk("\n");
+ if (!task)
+ task = current;
+ debug_show_held_locks(task);
+}
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+ register unsigned long * __r15 asm ("15");
+ unsigned long *stack;
+ int i;
+
+ if (!sp)
+ stack = task ? (unsigned long *) task->thread.ksp : __r15;
+ else
+ stack = sp;
+
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
+ break;
+ if (i && ((i * sizeof (long) % 32) == 0))
+ printk("\n ");
+ printk("%p ", (void *)*stack++);
+ }
+ printk("\n");
+ show_trace(task, sp);
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+ printk("CPU: %d %s %s %.*s\n",
+ task_thread_info(current)->cpu, print_tainted(),
+ init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+ printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+ current->comm, current->pid, current,
+ (void *) current->thread.ksp);
+ show_stack(NULL, NULL);
+}
+EXPORT_SYMBOL(dump_stack);
+
+static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
+{
+ return (regs->psw.mask & bits) / ((~bits + 1) & bits);
+}
+
+void show_registers(struct pt_regs *regs)
+{
+ char *mode;
+
+ mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
+ printk("%s PSW : %p %p",
+ mode, (void *) regs->psw.mask,
+ (void *) regs->psw.addr);
+ print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN);
+ printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
+ "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
+ mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
+ mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY),
+ mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT),
+ mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC),
+ mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM));
+#ifdef CONFIG_64BIT
+ printk(" EA:%x", mask_bits(regs, PSW_BASE_BITS));
+#endif
+ printk("\n%s GPRS: " FOURLONG, mode,
+ regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
+ printk(" " FOURLONG,
+ regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
+ printk(" " FOURLONG,
+ regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
+ printk(" " FOURLONG,
+ regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
+
+ show_code(regs);
+}
+
+/* This is called from fs/proc/array.c */
+void task_show_regs(struct seq_file *m, struct task_struct *task)
+{
+ struct pt_regs *regs;
+
+ regs = task_pt_regs(task);
+ seq_printf(m, "task: %p, ksp: %p\n",
+ task, (void *)task->thread.ksp);
+ seq_printf(m, "User PSW : %p %p\n",
+ (void *) regs->psw.mask, (void *)regs->psw.addr);
+
+ seq_printf(m, "User GPRS: " FOURLONG,
+ regs->gprs[0], regs->gprs[1],
+ regs->gprs[2], regs->gprs[3]);
+ seq_printf(m, " " FOURLONG,
+ regs->gprs[4], regs->gprs[5],
+ regs->gprs[6], regs->gprs[7]);
+ seq_printf(m, " " FOURLONG,
+ regs->gprs[8], regs->gprs[9],
+ regs->gprs[10], regs->gprs[11]);
+ seq_printf(m, " " FOURLONG,
+ regs->gprs[12], regs->gprs[13],
+ regs->gprs[14], regs->gprs[15]);
+ seq_printf(m, "User ACRS: %08x %08x %08x %08x\n",
+ task->thread.acrs[0], task->thread.acrs[1],
+ task->thread.acrs[2], task->thread.acrs[3]);
+ seq_printf(m, " %08x %08x %08x %08x\n",
+ task->thread.acrs[4], task->thread.acrs[5],
+ task->thread.acrs[6], task->thread.acrs[7]);
+ seq_printf(m, " %08x %08x %08x %08x\n",
+ task->thread.acrs[8], task->thread.acrs[9],
+ task->thread.acrs[10], task->thread.acrs[11]);
+ seq_printf(m, " %08x %08x %08x %08x\n",
+ task->thread.acrs[12], task->thread.acrs[13],
+ task->thread.acrs[14], task->thread.acrs[15]);
+}
+
+static DEFINE_SPINLOCK(die_lock);
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+ static int die_counter;
+
+ oops_enter();
+ debug_stop_all();
+ console_verbose();
+ spin_lock_irq(&die_lock);
+ bust_spinlocks(1);
+ printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+ printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+ printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ printk("DEBUG_PAGEALLOC");
+#endif
+ printk("\n");
+ notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
+ show_regs(regs);
+ bust_spinlocks(0);
+ add_taint(TAINT_DIE);
+ spin_unlock_irq(&die_lock);
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+ if (panic_on_oops)
+ panic("Fatal exception: panic_on_oops");
+ oops_exit();
+ do_exit(SIGSEGV);
+}
+
+static void inline
+report_user_fault(long interruption_code, struct pt_regs *regs)
+{
+#if defined(CONFIG_SYSCTL)
+ if (!sysctl_userprocess_debug)
+ return;
+#endif
+#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
+ printk("User process fault: interruption code 0x%lX\n",
+ interruption_code);
+ show_regs(regs);
+#endif
+}
+
+int is_valid_bugaddr(unsigned long addr)
+{
+ return 1;
+}
+
+static void __kprobes inline do_trap(long interruption_code, int signr,
+ char *str, struct pt_regs *regs,
+ siginfo_t *info)
+{
+ /*
+ * We got all needed information from the lowcore and can
+ * now safely switch on interrupts.
+ */
+ if (regs->psw.mask & PSW_MASK_PSTATE)
+ local_irq_enable();
+
+ if (notify_die(DIE_TRAP, str, regs, interruption_code,
+ interruption_code, signr) == NOTIFY_STOP)
+ return;
+
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ struct task_struct *tsk = current;
+
+ tsk->thread.trap_no = interruption_code & 0xffff;
+ force_sig_info(signr, info, tsk);
+ report_user_fault(interruption_code, regs);
+ } else {
+ const struct exception_table_entry *fixup;
+ fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
+ if (fixup)
+ regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+ else {
+ enum bug_trap_type btt;
+
+ btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
+ if (btt == BUG_TRAP_TYPE_WARN)
+ return;
+ die(str, regs, interruption_code);
+ }
+ }
+}
+
+static inline void __user *get_check_address(struct pt_regs *regs)
+{
+ return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
+}
+
+void __kprobes do_single_step(struct pt_regs *regs)
+{
+ if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0,
+ SIGTRAP) == NOTIFY_STOP){
+ return;
+ }
+ if ((current->ptrace & PT_PTRACED) != 0)
+ force_sig(SIGTRAP, current);
+}
+
+static void default_trap_handler(struct pt_regs * regs, long interruption_code)
+{
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ local_irq_enable();
+ do_exit(SIGSEGV);
+ report_user_fault(interruption_code, regs);
+ } else
+ die("Unknown program exception", regs, interruption_code);
+}
+
+#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
+static void name(struct pt_regs * regs, long interruption_code) \
+{ \
+ siginfo_t info; \
+ info.si_signo = signr; \
+ info.si_errno = 0; \
+ info.si_code = sicode; \
+ info.si_addr = siaddr; \
+ do_trap(interruption_code, signr, str, regs, &info); \
+}
+
+DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
+ ILL_ILLADR, get_check_address(regs))
+DO_ERROR_INFO(SIGILL, "execute exception", execute_exception,
+ ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception,
+ FPE_INTDIV, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE, "fixpoint overflow exception", overflow_exception,
+ FPE_INTOVF, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE, "HFP overflow exception", hfp_overflow_exception,
+ FPE_FLTOVF, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE, "HFP underflow exception", hfp_underflow_exception,
+ FPE_FLTUND, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE, "HFP significance exception", hfp_significance_exception,
+ FPE_FLTRES, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE, "HFP divide exception", hfp_divide_exception,
+ FPE_FLTDIV, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE, "HFP square root exception", hfp_sqrt_exception,
+ FPE_FLTINV, get_check_address(regs))
+DO_ERROR_INFO(SIGILL, "operand exception", operand_exception,
+ ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op,
+ ILL_PRVOPC, get_check_address(regs))
+DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception,
+ ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL, "translation exception", translation_exception,
+ ILL_ILLOPN, get_check_address(regs))
+
+static inline void
+do_fp_trap(struct pt_regs *regs, void __user *location,
+ int fpc, long interruption_code)
+{
+ siginfo_t si;
+
+ si.si_signo = SIGFPE;
+ si.si_errno = 0;
+ si.si_addr = location;
+ si.si_code = 0;
+ /* FPC[2] is Data Exception Code */
+ if ((fpc & 0x00000300) == 0) {
+ /* bits 6 and 7 of DXC are 0 iff IEEE exception */
+ if (fpc & 0x8000) /* invalid fp operation */
+ si.si_code = FPE_FLTINV;
+ else if (fpc & 0x4000) /* div by 0 */
+ si.si_code = FPE_FLTDIV;
+ else if (fpc & 0x2000) /* overflow */
+ si.si_code = FPE_FLTOVF;
+ else if (fpc & 0x1000) /* underflow */
+ si.si_code = FPE_FLTUND;
+ else if (fpc & 0x0800) /* inexact */
+ si.si_code = FPE_FLTRES;
+ }
+ current->thread.ieee_instruction_pointer = (addr_t) location;
+ do_trap(interruption_code, SIGFPE,
+ "floating point exception", regs, &si);
+}
+
+static void illegal_op(struct pt_regs * regs, long interruption_code)
+{
+ siginfo_t info;
+ __u8 opcode[6];
+ __u16 __user *location;
+ int signal = 0;
+
+ location = get_check_address(regs);
+
+ /*
+ * We got all needed information from the lowcore and can
+ * now safely switch on interrupts.
+ */
+ if (regs->psw.mask & PSW_MASK_PSTATE)
+ local_irq_enable();
+
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
+ return;
+ if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
+ if (current->ptrace & PT_PTRACED)
+ force_sig(SIGTRAP, current);
+ else
+ signal = SIGILL;
+#ifdef CONFIG_MATHEMU
+ } else if (opcode[0] == 0xb3) {
+ if (get_user(*((__u16 *) (opcode+2)), location+1))
+ return;
+ signal = math_emu_b3(opcode, regs);
+ } else if (opcode[0] == 0xed) {
+ if (get_user(*((__u32 *) (opcode+2)),
+ (__u32 __user *)(location+1)))
+ return;
+ signal = math_emu_ed(opcode, regs);
+ } else if (*((__u16 *) opcode) == 0xb299) {
+ if (get_user(*((__u16 *) (opcode+2)), location+1))
+ return;
+ signal = math_emu_srnm(opcode, regs);
+ } else if (*((__u16 *) opcode) == 0xb29c) {
+ if (get_user(*((__u16 *) (opcode+2)), location+1))
+ return;
+ signal = math_emu_stfpc(opcode, regs);
+ } else if (*((__u16 *) opcode) == 0xb29d) {
+ if (get_user(*((__u16 *) (opcode+2)), location+1))
+ return;
+ signal = math_emu_lfpc(opcode, regs);
+#endif
+ } else
+ signal = SIGILL;
+ } else {
+ /*
+ * If we get an illegal op in kernel mode, send it through the
+ * kprobes notifier. If kprobes doesn't pick it up, SIGILL
+ */
+ if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
+ 3, SIGTRAP) != NOTIFY_STOP)
+ signal = SIGILL;
+ }
+
+#ifdef CONFIG_MATHEMU
+ if (signal == SIGFPE)
+ do_fp_trap(regs, location,
+ current->thread.fp_regs.fpc, interruption_code);
+ else if (signal == SIGSEGV) {
+ info.si_signo = signal;
+ info.si_errno = 0;
+ info.si_code = SEGV_MAPERR;
+ info.si_addr = (void __user *) location;
+ do_trap(interruption_code, signal,
+ "user address fault", regs, &info);
+ } else
+#endif
+ if (signal) {
+ info.si_signo = signal;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLOPC;
+ info.si_addr = (void __user *) location;
+ do_trap(interruption_code, signal,
+ "illegal operation", regs, &info);
+ }
+}
+
+
+#ifdef CONFIG_MATHEMU
+asmlinkage void
+specification_exception(struct pt_regs * regs, long interruption_code)
+{
+ __u8 opcode[6];
+ __u16 __user *location = NULL;
+ int signal = 0;
+
+ location = (__u16 __user *) get_check_address(regs);
+
+ /*
+ * We got all needed information from the lowcore and can
+ * now safely switch on interrupts.
+ */
+ if (regs->psw.mask & PSW_MASK_PSTATE)
+ local_irq_enable();
+
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ get_user(*((__u16 *) opcode), location);
+ switch (opcode[0]) {
+ case 0x28: /* LDR Rx,Ry */
+ signal = math_emu_ldr(opcode);
+ break;
+ case 0x38: /* LER Rx,Ry */
+ signal = math_emu_ler(opcode);
+ break;
+ case 0x60: /* STD R,D(X,B) */
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_std(opcode, regs);
+ break;
+ case 0x68: /* LD R,D(X,B) */
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_ld(opcode, regs);
+ break;
+ case 0x70: /* STE R,D(X,B) */
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_ste(opcode, regs);
+ break;
+ case 0x78: /* LE R,D(X,B) */
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_le(opcode, regs);
+ break;
+ default:
+ signal = SIGILL;
+ break;
+ }
+ } else
+ signal = SIGILL;
+
+ if (signal == SIGFPE)
+ do_fp_trap(regs, location,
+ current->thread.fp_regs.fpc, interruption_code);
+ else if (signal) {
+ siginfo_t info;
+ info.si_signo = signal;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLOPN;
+ info.si_addr = location;
+ do_trap(interruption_code, signal,
+ "specification exception", regs, &info);
+ }
+}
+#else
+DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
+ ILL_ILLOPN, get_check_address(regs));
+#endif
+
+static void data_exception(struct pt_regs * regs, long interruption_code)
+{
+ __u16 __user *location;
+ int signal = 0;
+
+ location = get_check_address(regs);
+
+ /*
+ * We got all needed information from the lowcore and can
+ * now safely switch on interrupts.
+ */
+ if (regs->psw.mask & PSW_MASK_PSTATE)
+ local_irq_enable();
+
+ if (MACHINE_HAS_IEEE)
+ asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
+
+#ifdef CONFIG_MATHEMU
+ else if (regs->psw.mask & PSW_MASK_PSTATE) {
+ __u8 opcode[6];
+ get_user(*((__u16 *) opcode), location);
+ switch (opcode[0]) {
+ case 0x28: /* LDR Rx,Ry */
+ signal = math_emu_ldr(opcode);
+ break;
+ case 0x38: /* LER Rx,Ry */
+ signal = math_emu_ler(opcode);
+ break;
+ case 0x60: /* STD R,D(X,B) */
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_std(opcode, regs);
+ break;
+ case 0x68: /* LD R,D(X,B) */
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_ld(opcode, regs);
+ break;
+ case 0x70: /* STE R,D(X,B) */
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_ste(opcode, regs);
+ break;
+ case 0x78: /* LE R,D(X,B) */
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_le(opcode, regs);
+ break;
+ case 0xb3:
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_b3(opcode, regs);
+ break;
+ case 0xed:
+ get_user(*((__u32 *) (opcode+2)),
+ (__u32 __user *)(location+1));
+ signal = math_emu_ed(opcode, regs);
+ break;
+ case 0xb2:
+ if (opcode[1] == 0x99) {
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_srnm(opcode, regs);
+ } else if (opcode[1] == 0x9c) {
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_stfpc(opcode, regs);
+ } else if (opcode[1] == 0x9d) {
+ get_user(*((__u16 *) (opcode+2)), location+1);
+ signal = math_emu_lfpc(opcode, regs);
+ } else
+ signal = SIGILL;
+ break;
+ default:
+ signal = SIGILL;
+ break;
+ }
+ }
+#endif
+ if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
+ signal = SIGFPE;
+ else
+ signal = SIGILL;
+ if (signal == SIGFPE)
+ do_fp_trap(regs, location,
+ current->thread.fp_regs.fpc, interruption_code);
+ else if (signal) {
+ siginfo_t info;
+ info.si_signo = signal;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLOPN;
+ info.si_addr = location;
+ do_trap(interruption_code, signal,
+ "data exception", regs, &info);
+ }
+}
+
+static void space_switch_exception(struct pt_regs * regs, long int_code)
+{
+ siginfo_t info;
+
+ /* Set user psw back to home space mode. */
+ if (regs->psw.mask & PSW_MASK_PSTATE)
+ regs->psw.mask |= PSW_ASC_HOME;
+ /* Send SIGILL. */
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_PRVOPC;
+ info.si_addr = get_check_address(regs);
+ do_trap(int_code, SIGILL, "space switch event", regs, &info);
+}
+
+asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
+{
+ bust_spinlocks(1);
+ printk("Kernel stack overflow.\n");
+ show_regs(regs);
+ bust_spinlocks(0);
+ panic("Corrupt kernel stack, can't continue.");
+}
+
+/* init is done in lowcore.S and head.S */
+
+void __init trap_init(void)
+{
+ int i;
+
+ for (i = 0; i < 128; i++)
+ pgm_check_table[i] = &default_trap_handler;
+ pgm_check_table[1] = &illegal_op;
+ pgm_check_table[2] = &privileged_op;
+ pgm_check_table[3] = &execute_exception;
+ pgm_check_table[4] = &do_protection_exception;
+ pgm_check_table[5] = &addressing_exception;
+ pgm_check_table[6] = &specification_exception;
+ pgm_check_table[7] = &data_exception;
+ pgm_check_table[8] = &overflow_exception;
+ pgm_check_table[9] = &divide_exception;
+ pgm_check_table[0x0A] = &overflow_exception;
+ pgm_check_table[0x0B] = &divide_exception;
+ pgm_check_table[0x0C] = &hfp_overflow_exception;
+ pgm_check_table[0x0D] = &hfp_underflow_exception;
+ pgm_check_table[0x0E] = &hfp_significance_exception;
+ pgm_check_table[0x0F] = &hfp_divide_exception;
+ pgm_check_table[0x10] = &do_dat_exception;
+ pgm_check_table[0x11] = &do_dat_exception;
+ pgm_check_table[0x12] = &translation_exception;
+ pgm_check_table[0x13] = &special_op_exception;
+#ifdef CONFIG_64BIT
+ pgm_check_table[0x38] = &do_asce_exception;
+ pgm_check_table[0x39] = &do_dat_exception;
+ pgm_check_table[0x3A] = &do_dat_exception;
+ pgm_check_table[0x3B] = &do_dat_exception;
+#endif /* CONFIG_64BIT */
+ pgm_check_table[0x15] = &operand_exception;
+ pgm_check_table[0x1C] = &space_switch_exception;
+ pgm_check_table[0x1D] = &hfp_sqrt_exception;
+ pgm_check_table[0x40] = &do_monitor_call;
+ pfault_irq_init();
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/vmlinux.lds.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/vmlinux.lds.S
new file mode 100644
index 0000000000..b4607155e8
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/vmlinux.lds.S
@@ -0,0 +1,166 @@
+/* ld script to make s390 Linux kernel
+ * Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#include <asm/page.h>
+#include <asm-generic/vmlinux.lds.h>
+
+#ifndef CONFIG_64BIT
+OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
+OUTPUT_ARCH(s390)
+ENTRY(_start)
+jiffies = jiffies_64 + 4;
+#else
+OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
+OUTPUT_ARCH(s390:64-bit)
+ENTRY(_start)
+jiffies = jiffies_64;
+#endif
+
+PHDRS {
+ text PT_LOAD FLAGS(5); /* R_E */
+ data PT_LOAD FLAGS(7); /* RWE */
+ note PT_NOTE FLAGS(0); /* ___ */
+}
+
+SECTIONS
+{
+ . = 0x00000000;
+ .text : {
+ _text = .; /* Text and read-only data */
+ *(.text.head)
+ TEXT_TEXT
+ SCHED_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ *(.fixup)
+ *(.gnu.warning)
+ } :text = 0x0700
+
+ _etext = .; /* End of text section */
+
+ NOTES :text :note
+ BUG_TABLE :text
+
+ RODATA
+
+#ifdef CONFIG_SHARED_KERNEL
+ . = ALIGN(0x100000); /* VM shared segments are 1MB aligned */
+#endif
+
+ . = ALIGN(PAGE_SIZE);
+ _eshared = .; /* End of shareable data */
+
+ . = ALIGN(16); /* Exception table */
+ __ex_table : {
+ __start___ex_table = .;
+ *(__ex_table)
+ __stop___ex_table = .;
+ }
+
+ .data : { /* Data */
+ DATA_DATA
+ CONSTRUCTORS
+ }
+
+ . = ALIGN(PAGE_SIZE);
+ .data_nosave : {
+ __nosave_begin = .;
+ *(.data.nosave)
+ }
+ . = ALIGN(PAGE_SIZE);
+ __nosave_end = .;
+
+ . = ALIGN(PAGE_SIZE);
+ .data.page_aligned : {
+ *(.data.idt)
+ }
+
+ . = ALIGN(0x100);
+ .data.cacheline_aligned : {
+ *(.data.cacheline_aligned)
+ }
+
+ . = ALIGN(0x100);
+ .data.read_mostly : {
+ *(.data.read_mostly)
+ }
+ _edata = .; /* End of data section */
+
+ . = ALIGN(2 * PAGE_SIZE); /* init_task */
+ .data.init_task : {
+ *(.data.init_task)
+ }
+
+ /* will be freed after init */
+ . = ALIGN(PAGE_SIZE); /* Init code and data */
+ __init_begin = .;
+ .init.text : {
+ _sinittext = .;
+ INIT_TEXT
+ _einittext = .;
+ }
+ /*
+ * .exit.text is discarded at runtime, not link time,
+ * to deal with references from __bug_table
+ */
+ .exit.text : {
+ EXIT_TEXT
+ }
+
+ .init.data : {
+ INIT_DATA
+ }
+ . = ALIGN(0x100);
+ .init.setup : {
+ __setup_start = .;
+ *(.init.setup)
+ __setup_end = .;
+ }
+ .initcall.init : {
+ __initcall_start = .;
+ INITCALLS
+ __initcall_end = .;
+ }
+
+ .con_initcall.init : {
+ __con_initcall_start = .;
+ *(.con_initcall.init)
+ __con_initcall_end = .;
+ }
+ SECURITY_INIT
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ . = ALIGN(0x100);
+ .init.ramfs : {
+ __initramfs_start = .;
+ *(.init.ramfs)
+ . = ALIGN(2);
+ __initramfs_end = .;
+ }
+#endif
+
+ PERCPU(PAGE_SIZE)
+ . = ALIGN(PAGE_SIZE);
+ __init_end = .; /* freed after init ends here */
+
+ /* BSS */
+ .bss : {
+ __bss_start = .;
+ *(.bss)
+ . = ALIGN(2);
+ __bss_stop = .;
+ }
+
+ _end = . ;
+
+ /* Sections to be discarded */
+ /DISCARD/ : {
+ EXIT_DATA
+ *(.exitcall.exit)
+ }
+
+ /* Debugging sections. */
+ STABS_DEBUG
+ DWARF_DEBUG
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/vtime.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/vtime.c
new file mode 100644
index 0000000000..c5f05b3fb2
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/kernel/vtime.c
@@ -0,0 +1,569 @@
+/*
+ * arch/s390/kernel/vtime.c
+ * Virtual cpu timer based timer functions.
+ *
+ * S390 version
+ * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+#include <linux/timex.h>
+#include <linux/notifier.h>
+#include <linux/kernel_stat.h>
+#include <linux/rcupdate.h>
+#include <linux/posix-timers.h>
+
+#include <asm/s390_ext.h>
+#include <asm/timer.h>
+#include <asm/irq_regs.h>
+
+static ext_int_info_t ext_int_info_timer;
+static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+/*
+ * Update process times based on virtual cpu times stored by entry.S
+ * to the lowcore fields user_timer, system_timer & steal_clock.
+ */
+void account_process_tick(struct task_struct *tsk, int user_tick)
+{
+ cputime_t cputime;
+ __u64 timer, clock;
+ int rcu_user_flag;
+
+ timer = S390_lowcore.last_update_timer;
+ clock = S390_lowcore.last_update_clock;
+ asm volatile (" STPT %0\n" /* Store current cpu timer value */
+ " STCK %1" /* Store current tod clock value */
+ : "=m" (S390_lowcore.last_update_timer),
+ "=m" (S390_lowcore.last_update_clock) );
+ S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
+ S390_lowcore.steal_clock += S390_lowcore.last_update_clock - clock;
+
+ cputime = S390_lowcore.user_timer >> 12;
+ rcu_user_flag = cputime != 0;
+ S390_lowcore.user_timer -= cputime << 12;
+ S390_lowcore.steal_clock -= cputime << 12;
+ account_user_time(tsk, cputime);
+
+ cputime = S390_lowcore.system_timer >> 12;
+ S390_lowcore.system_timer -= cputime << 12;
+ S390_lowcore.steal_clock -= cputime << 12;
+ account_system_time(tsk, HARDIRQ_OFFSET, cputime);
+
+ cputime = S390_lowcore.steal_clock;
+ if ((__s64) cputime > 0) {
+ cputime >>= 12;
+ S390_lowcore.steal_clock -= cputime << 12;
+ account_steal_time(tsk, cputime);
+ }
+}
+
+/*
+ * Update process times based on virtual cpu times stored by entry.S
+ * to the lowcore fields user_timer, system_timer & steal_clock.
+ */
+void account_vtime(struct task_struct *tsk)
+{
+ cputime_t cputime;
+ __u64 timer;
+
+ timer = S390_lowcore.last_update_timer;
+ asm volatile (" STPT %0" /* Store current cpu timer value */
+ : "=m" (S390_lowcore.last_update_timer) );
+ S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
+
+ cputime = S390_lowcore.user_timer >> 12;
+ S390_lowcore.user_timer -= cputime << 12;
+ S390_lowcore.steal_clock -= cputime << 12;
+ account_user_time(tsk, cputime);
+
+ cputime = S390_lowcore.system_timer >> 12;
+ S390_lowcore.system_timer -= cputime << 12;
+ S390_lowcore.steal_clock -= cputime << 12;
+ account_system_time(tsk, 0, cputime);
+}
+
+/*
+ * Update process times based on virtual cpu times stored by entry.S
+ * to the lowcore fields user_timer, system_timer & steal_clock.
+ */
+void account_system_vtime(struct task_struct *tsk)
+{
+ cputime_t cputime;
+ __u64 timer;
+
+ timer = S390_lowcore.last_update_timer;
+ asm volatile (" STPT %0" /* Store current cpu timer value */
+ : "=m" (S390_lowcore.last_update_timer) );
+ S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
+
+ cputime = S390_lowcore.system_timer >> 12;
+ S390_lowcore.system_timer -= cputime << 12;
+ S390_lowcore.steal_clock -= cputime << 12;
+ account_system_time(tsk, 0, cputime);
+}
+
+static inline void set_vtimer(__u64 expires)
+{
+ __u64 timer;
+
+ asm volatile (" STPT %0\n" /* Store current cpu timer value */
+ " SPT %1" /* Set new value immediatly afterwards */
+ : "=m" (timer) : "m" (expires) );
+ S390_lowcore.system_timer += S390_lowcore.last_update_timer - timer;
+ S390_lowcore.last_update_timer = expires;
+
+ /* store expire time for this CPU timer */
+ __get_cpu_var(virt_cpu_timer).to_expire = expires;
+}
+#else
+static inline void set_vtimer(__u64 expires)
+{
+ S390_lowcore.last_update_timer = expires;
+ asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
+
+ /* store expire time for this CPU timer */
+ __get_cpu_var(virt_cpu_timer).to_expire = expires;
+}
+#endif
+
+static void start_cpu_timer(void)
+{
+ struct vtimer_queue *vt_list;
+
+ vt_list = &__get_cpu_var(virt_cpu_timer);
+
+ /* CPU timer interrupt is pending, don't reprogramm it */
+ if (vt_list->idle & 1LL<<63)
+ return;
+
+ if (!list_empty(&vt_list->list))
+ set_vtimer(vt_list->idle);
+}
+
+static void stop_cpu_timer(void)
+{
+ struct vtimer_queue *vt_list;
+
+ vt_list = &__get_cpu_var(virt_cpu_timer);
+
+ /* nothing to do */
+ if (list_empty(&vt_list->list)) {
+ vt_list->idle = VTIMER_MAX_SLICE;
+ goto fire;
+ }
+
+ /* store the actual expire value */
+ asm volatile ("STPT %0" : "=m" (vt_list->idle));
+
+ /*
+ * If the CPU timer is negative we don't reprogramm
+ * it because we will get instantly an interrupt.
+ */
+ if (vt_list->idle & 1LL<<63)
+ return;
+
+ vt_list->offset += vt_list->to_expire - vt_list->idle;
+
+ /*
+ * We cannot halt the CPU timer, we just write a value that
+ * nearly never expires (only after 71 years) and re-write
+ * the stored expire value if we continue the timer
+ */
+ fire:
+ set_vtimer(VTIMER_MAX_SLICE);
+}
+
+/*
+ * Sorted add to a list. List is linear searched until first bigger
+ * element is found.
+ */
+static void list_add_sorted(struct vtimer_list *timer, struct list_head *head)
+{
+ struct vtimer_list *event;
+
+ list_for_each_entry(event, head, entry) {
+ if (event->expires > timer->expires) {
+ list_add_tail(&timer->entry, &event->entry);
+ return;
+ }
+ }
+ list_add_tail(&timer->entry, head);
+}
+
+/*
+ * Do the callback functions of expired vtimer events.
+ * Called from within the interrupt handler.
+ */
+static void do_callbacks(struct list_head *cb_list)
+{
+ struct vtimer_queue *vt_list;
+ struct vtimer_list *event, *tmp;
+ void (*fn)(unsigned long);
+ unsigned long data;
+
+ if (list_empty(cb_list))
+ return;
+
+ vt_list = &__get_cpu_var(virt_cpu_timer);
+
+ list_for_each_entry_safe(event, tmp, cb_list, entry) {
+ fn = event->function;
+ data = event->data;
+ fn(data);
+
+ if (!event->interval)
+ /* delete one shot timer */
+ list_del_init(&event->entry);
+ else {
+ /* move interval timer back to list */
+ spin_lock(&vt_list->lock);
+ list_del_init(&event->entry);
+ list_add_sorted(event, &vt_list->list);
+ spin_unlock(&vt_list->lock);
+ }
+ }
+}
+
+/*
+ * Handler for the virtual CPU timer.
+ */
+static void do_cpu_timer_interrupt(__u16 error_code)
+{
+ __u64 next, delta;
+ struct vtimer_queue *vt_list;
+ struct vtimer_list *event, *tmp;
+ struct list_head *ptr;
+ /* the callback queue */
+ struct list_head cb_list;
+
+ INIT_LIST_HEAD(&cb_list);
+ vt_list = &__get_cpu_var(virt_cpu_timer);
+
+ /* walk timer list, fire all expired events */
+ spin_lock(&vt_list->lock);
+
+ if (vt_list->to_expire < VTIMER_MAX_SLICE)
+ vt_list->offset += vt_list->to_expire;
+
+ list_for_each_entry_safe(event, tmp, &vt_list->list, entry) {
+ if (event->expires > vt_list->offset)
+ /* found first unexpired event, leave */
+ break;
+
+ /* re-charge interval timer, we have to add the offset */
+ if (event->interval)
+ event->expires = event->interval + vt_list->offset;
+
+ /* move expired timer to the callback queue */
+ list_move_tail(&event->entry, &cb_list);
+ }
+ spin_unlock(&vt_list->lock);
+ do_callbacks(&cb_list);
+
+ /* next event is first in list */
+ spin_lock(&vt_list->lock);
+ if (!list_empty(&vt_list->list)) {
+ ptr = vt_list->list.next;
+ event = list_entry(ptr, struct vtimer_list, entry);
+ next = event->expires - vt_list->offset;
+
+ /* add the expired time from this interrupt handler
+ * and the callback functions
+ */
+ asm volatile ("STPT %0" : "=m" (delta));
+ delta = 0xffffffffffffffffLL - delta + 1;
+ vt_list->offset += delta;
+ next -= delta;
+ } else {
+ vt_list->offset = 0;
+ next = VTIMER_MAX_SLICE;
+ }
+ spin_unlock(&vt_list->lock);
+ set_vtimer(next);
+}
+
+void init_virt_timer(struct vtimer_list *timer)
+{
+ timer->function = NULL;
+ INIT_LIST_HEAD(&timer->entry);
+ spin_lock_init(&timer->lock);
+}
+EXPORT_SYMBOL(init_virt_timer);
+
+static inline int vtimer_pending(struct vtimer_list *timer)
+{
+ return (!list_empty(&timer->entry));
+}
+
+/*
+ * this function should only run on the specified CPU
+ */
+static void internal_add_vtimer(struct vtimer_list *timer)
+{
+ unsigned long flags;
+ __u64 done;
+ struct vtimer_list *event;
+ struct vtimer_queue *vt_list;
+
+ vt_list = &per_cpu(virt_cpu_timer, timer->cpu);
+ spin_lock_irqsave(&vt_list->lock, flags);
+
+ if (timer->cpu != smp_processor_id())
+ printk("internal_add_vtimer: BUG, running on wrong CPU");
+
+ /* if list is empty we only have to set the timer */
+ if (list_empty(&vt_list->list)) {
+ /* reset the offset, this may happen if the last timer was
+ * just deleted by mod_virt_timer and the interrupt
+ * didn't happen until here
+ */
+ vt_list->offset = 0;
+ goto fire;
+ }
+
+ /* save progress */
+ asm volatile ("STPT %0" : "=m" (done));
+
+ /* calculate completed work */
+ done = vt_list->to_expire - done + vt_list->offset;
+ vt_list->offset = 0;
+
+ list_for_each_entry(event, &vt_list->list, entry)
+ event->expires -= done;
+
+ fire:
+ list_add_sorted(timer, &vt_list->list);
+
+ /* get first element, which is the next vtimer slice */
+ event = list_entry(vt_list->list.next, struct vtimer_list, entry);
+
+ set_vtimer(event->expires);
+ spin_unlock_irqrestore(&vt_list->lock, flags);
+ /* release CPU acquired in prepare_vtimer or mod_virt_timer() */
+ put_cpu();
+}
+
+static inline int prepare_vtimer(struct vtimer_list *timer)
+{
+ if (!timer->function) {
+ printk("add_virt_timer: uninitialized timer\n");
+ return -EINVAL;
+ }
+
+ if (!timer->expires || timer->expires > VTIMER_MAX_SLICE) {
+ printk("add_virt_timer: invalid timer expire value!\n");
+ return -EINVAL;
+ }
+
+ if (vtimer_pending(timer)) {
+ printk("add_virt_timer: timer pending\n");
+ return -EBUSY;
+ }
+
+ timer->cpu = get_cpu();
+ return 0;
+}
+
+/*
+ * add_virt_timer - add an oneshot virtual CPU timer
+ */
+void add_virt_timer(void *new)
+{
+ struct vtimer_list *timer;
+
+ timer = (struct vtimer_list *)new;
+
+ if (prepare_vtimer(timer) < 0)
+ return;
+
+ timer->interval = 0;
+ internal_add_vtimer(timer);
+}
+EXPORT_SYMBOL(add_virt_timer);
+
+/*
+ * add_virt_timer_int - add an interval virtual CPU timer
+ */
+void add_virt_timer_periodic(void *new)
+{
+ struct vtimer_list *timer;
+
+ timer = (struct vtimer_list *)new;
+
+ if (prepare_vtimer(timer) < 0)
+ return;
+
+ timer->interval = timer->expires;
+ internal_add_vtimer(timer);
+}
+EXPORT_SYMBOL(add_virt_timer_periodic);
+
+/*
+ * If we change a pending timer the function must be called on the CPU
+ * where the timer is running on, e.g. by smp_call_function_single()
+ *
+ * The original mod_timer adds the timer if it is not pending. For compatibility
+ * we do the same. The timer will be added on the current CPU as a oneshot timer.
+ *
+ * returns whether it has modified a pending timer (1) or not (0)
+ */
+int mod_virt_timer(struct vtimer_list *timer, __u64 expires)
+{
+ struct vtimer_queue *vt_list;
+ unsigned long flags;
+ int cpu;
+
+ if (!timer->function) {
+ printk("mod_virt_timer: uninitialized timer\n");
+ return -EINVAL;
+ }
+
+ if (!expires || expires > VTIMER_MAX_SLICE) {
+ printk("mod_virt_timer: invalid expire range\n");
+ return -EINVAL;
+ }
+
+ /*
+ * This is a common optimization triggered by the
+ * networking code - if the timer is re-modified
+ * to be the same thing then just return:
+ */
+ if (timer->expires == expires && vtimer_pending(timer))
+ return 1;
+
+ cpu = get_cpu();
+ vt_list = &per_cpu(virt_cpu_timer, cpu);
+
+ /* disable interrupts before test if timer is pending */
+ spin_lock_irqsave(&vt_list->lock, flags);
+
+ /* if timer isn't pending add it on the current CPU */
+ if (!vtimer_pending(timer)) {
+ spin_unlock_irqrestore(&vt_list->lock, flags);
+ /* we do not activate an interval timer with mod_virt_timer */
+ timer->interval = 0;
+ timer->expires = expires;
+ timer->cpu = cpu;
+ internal_add_vtimer(timer);
+ return 0;
+ }
+
+ /* check if we run on the right CPU */
+ if (timer->cpu != cpu) {
+ printk("mod_virt_timer: running on wrong CPU, check your code\n");
+ spin_unlock_irqrestore(&vt_list->lock, flags);
+ put_cpu();
+ return -EINVAL;
+ }
+
+ list_del_init(&timer->entry);
+ timer->expires = expires;
+
+ /* also change the interval if we have an interval timer */
+ if (timer->interval)
+ timer->interval = expires;
+
+ /* the timer can't expire anymore so we can release the lock */
+ spin_unlock_irqrestore(&vt_list->lock, flags);
+ internal_add_vtimer(timer);
+ return 1;
+}
+EXPORT_SYMBOL(mod_virt_timer);
+
+/*
+ * delete a virtual timer
+ *
+ * returns whether the deleted timer was pending (1) or not (0)
+ */
+int del_virt_timer(struct vtimer_list *timer)
+{
+ unsigned long flags;
+ struct vtimer_queue *vt_list;
+
+ /* check if timer is pending */
+ if (!vtimer_pending(timer))
+ return 0;
+
+ vt_list = &per_cpu(virt_cpu_timer, timer->cpu);
+ spin_lock_irqsave(&vt_list->lock, flags);
+
+ /* we don't interrupt a running timer, just let it expire! */
+ list_del_init(&timer->entry);
+
+ /* last timer removed */
+ if (list_empty(&vt_list->list)) {
+ vt_list->to_expire = 0;
+ vt_list->offset = 0;
+ }
+
+ spin_unlock_irqrestore(&vt_list->lock, flags);
+ return 1;
+}
+EXPORT_SYMBOL(del_virt_timer);
+
+/*
+ * Start the virtual CPU timer on the current CPU.
+ */
+void init_cpu_vtimer(void)
+{
+ struct vtimer_queue *vt_list;
+
+ /* kick the virtual timer */
+ S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
+ S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
+ asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
+ asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
+
+ /* enable cpu timer interrupts */
+ __ctl_set_bit(0,10);
+
+ vt_list = &__get_cpu_var(virt_cpu_timer);
+ INIT_LIST_HEAD(&vt_list->list);
+ spin_lock_init(&vt_list->lock);
+ vt_list->to_expire = 0;
+ vt_list->offset = 0;
+ vt_list->idle = 0;
+
+}
+
+static int vtimer_idle_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ switch (action) {
+ case S390_CPU_IDLE:
+ stop_cpu_timer();
+ break;
+ case S390_CPU_NOT_IDLE:
+ start_cpu_timer();
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vtimer_idle_nb = {
+ .notifier_call = vtimer_idle_notify,
+};
+
+void __init vtime_init(void)
+{
+ /* request the cpu timer external interrupt */
+ if (register_early_external_interrupt(0x1005, do_cpu_timer_interrupt,
+ &ext_int_info_timer) != 0)
+ panic("Couldn't request external interrupt 0x1005");
+
+ if (register_idle_notifier(&vtimer_idle_nb))
+ panic("Couldn't register idle notifier");
+
+ /* Enable cpu timer interrupts on the boot cpu. */
+ init_cpu_vtimer();
+}
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/Makefile
new file mode 100644
index 0000000000..52084436ab
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for s390-specific library files..
+#
+
+EXTRA_AFLAGS := -traditional
+
+lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
+obj-$(CONFIG_32BIT) += div64.o qrnnd.o
+lib-$(CONFIG_64BIT) += uaccess_mvcos.o
+lib-$(CONFIG_SMP) += spinlock.o
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/delay.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/delay.c
new file mode 100644
index 0000000000..70f2a862b6
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/delay.c
@@ -0,0 +1,74 @@
+/*
+ * arch/s390/lib/delay.c
+ * Precise Delay Loops for S390
+ *
+ * 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/sched.h>
+#include <linux/delay.h>
+#include <linux/timex.h>
+#include <linux/irqflags.h>
+#include <linux/interrupt.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" : : "d" ((loops/2) + 1));
+}
+
+/*
+ * Waits for 'usecs' microseconds using the TOD clock comparator.
+ */
+void __udelay(unsigned long usecs)
+{
+ u64 end, time, jiffy_timer = 0;
+ unsigned long flags, cr0, mask, dummy;
+ int irq_context;
+
+ irq_context = in_interrupt();
+ if (!irq_context)
+ local_bh_disable();
+ local_irq_save(flags);
+ if (raw_irqs_disabled_flags(flags)) {
+ jiffy_timer = S390_lowcore.jiffy_timer;
+ S390_lowcore.jiffy_timer = -1ULL - (4096 << 12);
+ __ctl_store(cr0, 0, 0);
+ dummy = (cr0 & 0xffff00e0) | 0x00000800;
+ __ctl_load(dummy , 0, 0);
+ mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+ } else
+ mask = psw_kernel_bits | PSW_MASK_WAIT |
+ PSW_MASK_EXT | PSW_MASK_IO;
+
+ end = get_clock() + ((u64) usecs << 12);
+ do {
+ time = end < S390_lowcore.jiffy_timer ?
+ end : S390_lowcore.jiffy_timer;
+ set_clock_comparator(time);
+ trace_hardirqs_on();
+ __load_psw_mask(mask);
+ local_irq_disable();
+ } while (get_clock() < end);
+
+ if (raw_irqs_disabled_flags(flags)) {
+ __ctl_load(cr0, 0, 0);
+ S390_lowcore.jiffy_timer = jiffy_timer;
+ }
+ if (!irq_context)
+ _local_bh_enable();
+ set_clock_comparator(S390_lowcore.jiffy_timer);
+ local_irq_restore(flags);
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/div64.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/div64.c
new file mode 100644
index 0000000000..a5f8300bf3
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/div64.c
@@ -0,0 +1,149 @@
+/*
+ * arch/s390/lib/div64.c
+ *
+ * __div64_32 implementation for 31 bit.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+
+#ifdef CONFIG_MARCH_G5
+
+/*
+ * Function to divide an unsigned 64 bit integer by an unsigned
+ * 31 bit integer using signed 64/32 bit division.
+ */
+static uint32_t __div64_31(uint64_t *n, uint32_t base)
+{
+ register uint32_t reg2 asm("2");
+ register uint32_t reg3 asm("3");
+ uint32_t *words = (uint32_t *) n;
+ uint32_t tmp;
+
+ /* Special case base==1, remainder = 0, quotient = n */
+ if (base == 1)
+ return 0;
+ /*
+ * Special case base==0 will cause a fixed point divide exception
+ * on the dr instruction and may not happen anyway. For the
+ * following calculation we can assume base > 1. The first
+ * signed 64 / 32 bit division with an upper half of 0 will
+ * give the correct upper half of the 64 bit quotient.
+ */
+ reg2 = 0UL;
+ reg3 = words[0];
+ asm volatile(
+ " dr %0,%2\n"
+ : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" );
+ words[0] = reg3;
+ reg3 = words[1];
+ /*
+ * To get the lower half of the 64 bit quotient and the 32 bit
+ * remainder we have to use a little trick. Since we only have
+ * a signed division the quotient can get too big. To avoid this
+ * the 64 bit dividend is halved, then the signed division will
+ * work. Afterwards the quotient and the remainder are doubled.
+ * If the last bit of the dividend has been one the remainder
+ * is increased by one then checked against the base. If the
+ * remainder has overflown subtract base and increase the
+ * quotient. Simple, no ?
+ */
+ asm volatile(
+ " nr %2,%1\n"
+ " srdl %0,1\n"
+ " dr %0,%3\n"
+ " alr %0,%0\n"
+ " alr %1,%1\n"
+ " alr %0,%2\n"
+ " clr %0,%3\n"
+ " jl 0f\n"
+ " slr %0,%3\n"
+ " alr %1,%2\n"
+ "0:\n"
+ : "+d" (reg2), "+d" (reg3), "=d" (tmp)
+ : "d" (base), "2" (1UL) : "cc" );
+ words[1] = reg3;
+ return reg2;
+}
+
+/*
+ * Function to divide an unsigned 64 bit integer by an unsigned
+ * 32 bit integer using the unsigned 64/31 bit division.
+ */
+uint32_t __div64_32(uint64_t *n, uint32_t base)
+{
+ uint32_t r;
+
+ /*
+ * If the most significant bit of base is set, divide n by
+ * (base/2). That allows to use 64/31 bit division and gives a
+ * good approximation of the result: n = (base/2)*q + r. The
+ * result needs to be corrected with two simple transformations.
+ * If base is already < 2^31-1 __div64_31 can be used directly.
+ */
+ r = __div64_31(n, ((signed) base < 0) ? (base/2) : base);
+ if ((signed) base < 0) {
+ uint64_t q = *n;
+ /*
+ * First transformation:
+ * n = (base/2)*q + r
+ * = ((base/2)*2)*(q/2) + ((q&1) ? (base/2) : 0) + r
+ * Since r < (base/2), r + (base/2) < base.
+ * With q1 = (q/2) and r1 = r + ((q&1) ? (base/2) : 0)
+ * n = ((base/2)*2)*q1 + r1 with r1 < base.
+ */
+ if (q & 1)
+ r += base/2;
+ q >>= 1;
+ /*
+ * Second transformation. ((base/2)*2) could have lost the
+ * last bit.
+ * n = ((base/2)*2)*q1 + r1
+ * = base*q1 - ((base&1) ? q1 : 0) + r1
+ */
+ if (base & 1) {
+ int64_t rx = r - q;
+ /*
+ * base is >= 2^31. The worst case for the while
+ * loop is n=2^64-1 base=2^31+1. That gives a
+ * maximum for q=(2^64-1)/2^31 = 0x1ffffffff. Since
+ * base >= 2^31 the loop is finished after a maximum
+ * of three iterations.
+ */
+ while (rx < 0) {
+ rx += base;
+ q--;
+ }
+ r = rx;
+ }
+ *n = q;
+ }
+ return r;
+}
+
+#else /* MARCH_G5 */
+
+uint32_t __div64_32(uint64_t *n, uint32_t base)
+{
+ register uint32_t reg2 asm("2");
+ register uint32_t reg3 asm("3");
+ uint32_t *words = (uint32_t *) n;
+
+ reg2 = 0UL;
+ reg3 = words[0];
+ asm volatile(
+ " dlr %0,%2\n"
+ : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" );
+ words[0] = reg3;
+ reg3 = words[1];
+ asm volatile(
+ " dlr %0,%2\n"
+ : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" );
+ words[1] = reg3;
+ return reg2;
+}
+
+#endif /* MARCH_G5 */
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/qrnnd.S b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/qrnnd.S
new file mode 100644
index 0000000000..eb1df632e7
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/qrnnd.S
@@ -0,0 +1,77 @@
+# S/390 __udiv_qrnnd
+
+# r2 : &__r
+# r3 : upper half of 64 bit word n
+# r4 : lower half of 64 bit word n
+# r5 : divisor d
+# the reminder r of the division is to be stored to &__r and
+# the quotient q is to be returned
+
+ .text
+ .globl __udiv_qrnnd
+__udiv_qrnnd:
+ st %r2,24(%r15) # store pointer to reminder for later
+ lr %r0,%r3 # reload n
+ lr %r1,%r4
+ ltr %r2,%r5 # reload and test divisor
+ jp 5f
+ # divisor >= 0x80000000
+ srdl %r0,2 # n/4
+ srl %r2,1 # d/2
+ slr %r1,%r2 # special case if last bit of d is set
+ brc 3,0f # (n/4) div (n/2) can overflow by 1
+ ahi %r0,-1 # trick: subtract n/2, then divide
+0: dr %r0,%r2 # signed division
+ ahi %r1,1 # trick part 2: add 1 to the quotient
+ # now (n >> 2) = (d >> 1) * %r1 + %r0
+ lhi %r3,1
+ nr %r3,%r1 # test last bit of q
+ jz 1f
+ alr %r0,%r2 # add (d>>1) to r
+1: srl %r1,1 # q >>= 1
+ # now (n >> 2) = (d&-2) * %r1 + %r0
+ lhi %r3,1
+ nr %r3,%r5 # test last bit of d
+ jz 2f
+ slr %r0,%r1 # r -= q
+ brc 3,2f # borrow ?
+ alr %r0,%r5 # r += d
+ ahi %r1,-1
+2: # now (n >> 2) = d * %r1 + %r0
+ alr %r1,%r1 # q <<= 1
+ alr %r0,%r0 # r <<= 1
+ brc 12,3f # overflow on r ?
+ slr %r0,%r5 # r -= d
+ ahi %r1,1 # q += 1
+3: lhi %r3,2
+ nr %r3,%r4 # test next to last bit of n
+ jz 4f
+ ahi %r0,1 # r += 1
+4: clr %r0,%r5 # r >= d ?
+ jl 6f
+ slr %r0,%r5 # r -= d
+ ahi %r1,1 # q += 1
+ # now (n >> 1) = d * %r1 + %r0
+ j 6f
+5: # divisor < 0x80000000
+ srdl %r0,1
+ dr %r0,%r2 # signed division
+ # now (n >> 1) = d * %r1 + %r0
+6: alr %r1,%r1 # q <<= 1
+ alr %r0,%r0 # r <<= 1
+ brc 12,7f # overflow on r ?
+ slr %r0,%r5 # r -= d
+ ahi %r1,1 # q += 1
+7: lhi %r3,1
+ nr %r3,%r4 # isolate last bit of n
+ alr %r0,%r3 # r += (n & 1)
+ clr %r0,%r5 # r >= d ?
+ jl 8f
+ slr %r0,%r5 # r -= d
+ ahi %r1,1 # q += 1
+8: # now n = d * %r1 + %r0
+ l %r2,24(%r15)
+ st %r0,0(%r2)
+ lr %r2,%r1
+ br %r14
+ .end __udiv_qrnnd
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/spinlock.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/spinlock.c
new file mode 100644
index 0000000000..e41f4008af
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/spinlock.c
@@ -0,0 +1,172 @@
+/*
+ * arch/s390/lib/spinlock.c
+ * Out of line spinlock code.
+ *
+ * Copyright (C) IBM Corp. 2004, 2006
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+int spin_retry = 1000;
+
+/**
+ * spin_retry= parameter
+ */
+static int __init spin_retry_setup(char *str)
+{
+ spin_retry = simple_strtoul(str, &str, 0);
+ return 1;
+}
+__setup("spin_retry=", spin_retry_setup);
+
+static inline void _raw_yield(void)
+{
+ if (MACHINE_HAS_DIAG44)
+ asm volatile("diag 0,0,0x44");
+}
+
+static inline void _raw_yield_cpu(int cpu)
+{
+ if (MACHINE_HAS_DIAG9C)
+ asm volatile("diag %0,0,0x9c"
+ : : "d" (__cpu_logical_map[cpu]));
+ else
+ _raw_yield();
+}
+
+void _raw_spin_lock_wait(raw_spinlock_t *lp)
+{
+ int count = spin_retry;
+ unsigned int cpu = ~smp_processor_id();
+
+ while (1) {
+ if (count-- <= 0) {
+ unsigned int owner = lp->owner_cpu;
+ if (owner != 0)
+ _raw_yield_cpu(~owner);
+ count = spin_retry;
+ }
+ if (__raw_spin_is_locked(lp))
+ continue;
+ if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+ return;
+ }
+}
+EXPORT_SYMBOL(_raw_spin_lock_wait);
+
+void _raw_spin_lock_wait_flags(raw_spinlock_t *lp, unsigned long flags)
+{
+ int count = spin_retry;
+ unsigned int cpu = ~smp_processor_id();
+
+ local_irq_restore(flags);
+ while (1) {
+ if (count-- <= 0) {
+ unsigned int owner = lp->owner_cpu;
+ if (owner != 0)
+ _raw_yield_cpu(~owner);
+ count = spin_retry;
+ }
+ if (__raw_spin_is_locked(lp))
+ continue;
+ local_irq_disable();
+ if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+ return;
+ local_irq_restore(flags);
+ }
+}
+EXPORT_SYMBOL(_raw_spin_lock_wait_flags);
+
+int _raw_spin_trylock_retry(raw_spinlock_t *lp)
+{
+ unsigned int cpu = ~smp_processor_id();
+ int count;
+
+ for (count = spin_retry; count > 0; count--) {
+ if (__raw_spin_is_locked(lp))
+ continue;
+ if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0)
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(_raw_spin_trylock_retry);
+
+void _raw_spin_relax(raw_spinlock_t *lock)
+{
+ unsigned int cpu = lock->owner_cpu;
+ if (cpu != 0)
+ _raw_yield_cpu(~cpu);
+}
+EXPORT_SYMBOL(_raw_spin_relax);
+
+void _raw_read_lock_wait(raw_rwlock_t *rw)
+{
+ unsigned int old;
+ int count = spin_retry;
+
+ while (1) {
+ if (count-- <= 0) {
+ _raw_yield();
+ count = spin_retry;
+ }
+ if (!__raw_read_can_lock(rw))
+ continue;
+ old = rw->lock & 0x7fffffffU;
+ if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
+ return;
+ }
+}
+EXPORT_SYMBOL(_raw_read_lock_wait);
+
+int _raw_read_trylock_retry(raw_rwlock_t *rw)
+{
+ unsigned int old;
+ int count = spin_retry;
+
+ while (count-- > 0) {
+ if (!__raw_read_can_lock(rw))
+ continue;
+ old = rw->lock & 0x7fffffffU;
+ if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(_raw_read_trylock_retry);
+
+void _raw_write_lock_wait(raw_rwlock_t *rw)
+{
+ int count = spin_retry;
+
+ while (1) {
+ if (count-- <= 0) {
+ _raw_yield();
+ count = spin_retry;
+ }
+ if (!__raw_write_can_lock(rw))
+ continue;
+ if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
+ return;
+ }
+}
+EXPORT_SYMBOL(_raw_write_lock_wait);
+
+int _raw_write_trylock_retry(raw_rwlock_t *rw)
+{
+ int count = spin_retry;
+
+ while (count-- > 0) {
+ if (!__raw_write_can_lock(rw))
+ continue;
+ if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(_raw_write_trylock_retry);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/string.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/string.c
new file mode 100644
index 0000000000..ae5cf5d03d
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/string.c
@@ -0,0 +1,381 @@
+/*
+ * arch/s390/lib/string.c
+ * Optimized string functions
+ *
+ * S390 version
+ * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#define IN_ARCH_STRING_C 1
+
+#include <linux/types.h>
+#include <linux/module.h>
+
+/*
+ * Helper functions to find the end of a string
+ */
+static inline char *__strend(const char *s)
+{
+ register unsigned long r0 asm("0") = 0;
+
+ asm volatile ("0: srst %0,%1\n"
+ " jo 0b"
+ : "+d" (r0), "+a" (s) : : "cc" );
+ return (char *) r0;
+}
+
+static inline char *__strnend(const char *s, size_t n)
+{
+ register unsigned long r0 asm("0") = 0;
+ const char *p = s + n;
+
+ asm volatile ("0: srst %0,%1\n"
+ " jo 0b"
+ : "+d" (p), "+a" (s) : "d" (r0) : "cc" );
+ return (char *) p;
+}
+
+/**
+ * strlen - Find the length of a string
+ * @s: The string to be sized
+ *
+ * returns the length of @s
+ */
+size_t strlen(const char *s)
+{
+ return __strend(s) - s;
+}
+EXPORT_SYMBOL(strlen);
+
+/**
+ * strnlen - Find the length of a length-limited string
+ * @s: The string to be sized
+ * @n: The maximum number of bytes to search
+ *
+ * returns the minimum of the length of @s and @n
+ */
+size_t strnlen(const char * s, size_t n)
+{
+ return __strnend(s, n) - s;
+}
+EXPORT_SYMBOL(strnlen);
+
+/**
+ * strcpy - Copy a %NUL terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ *
+ * returns a pointer to @dest
+ */
+char *strcpy(char *dest, const char *src)
+{
+ register int r0 asm("0") = 0;
+ char *ret = dest;
+
+ asm volatile ("0: mvst %0,%1\n"
+ " jo 0b"
+ : "+&a" (dest), "+&a" (src) : "d" (r0)
+ : "cc", "memory" );
+ return ret;
+}
+EXPORT_SYMBOL(strcpy);
+
+/**
+ * strlcpy - Copy a %NUL terminated string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ */
+size_t strlcpy(char *dest, const char *src, size_t size)
+{
+ size_t ret = __strend(src) - src;
+
+ if (size) {
+ size_t len = (ret >= size) ? size-1 : ret;
+ dest[len] = '\0';
+ __builtin_memcpy(dest, src, len);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(strlcpy);
+
+/**
+ * strncpy - Copy a length-limited, %NUL-terminated string
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @n: The maximum number of bytes to copy
+ *
+ * The result is not %NUL-terminated if the source exceeds
+ * @n bytes.
+ */
+char *strncpy(char *dest, const char *src, size_t n)
+{
+ size_t len = __strnend(src, n) - src;
+ __builtin_memset(dest + len, 0, n - len);
+ __builtin_memcpy(dest, src, len);
+ return dest;
+}
+EXPORT_SYMBOL(strncpy);
+
+/**
+ * strcat - Append one %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ *
+ * returns a pointer to @dest
+ */
+char *strcat(char *dest, const char *src)
+{
+ register int r0 asm("0") = 0;
+ unsigned long dummy;
+ char *ret = dest;
+
+ asm volatile ("0: srst %0,%1\n"
+ " jo 0b\n"
+ "1: mvst %0,%2\n"
+ " jo 1b"
+ : "=&a" (dummy), "+a" (dest), "+a" (src)
+ : "d" (r0), "0" (0UL) : "cc", "memory" );
+ return ret;
+}
+EXPORT_SYMBOL(strcat);
+
+/**
+ * strlcat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @n: The size of the destination buffer.
+ */
+size_t strlcat(char *dest, const char *src, size_t n)
+{
+ size_t dsize = __strend(dest) - dest;
+ size_t len = __strend(src) - src;
+ size_t res = dsize + len;
+
+ if (dsize < n) {
+ dest += dsize;
+ n -= dsize;
+ if (len >= n)
+ len = n - 1;
+ dest[len] = '\0';
+ __builtin_memcpy(dest, src, len);
+ }
+ return res;
+}
+EXPORT_SYMBOL(strlcat);
+
+/**
+ * strncat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @n: The maximum numbers of bytes to copy
+ *
+ * returns a pointer to @dest
+ *
+ * Note that in contrast to strncpy, strncat ensures the result is
+ * terminated.
+ */
+char *strncat(char *dest, const char *src, size_t n)
+{
+ size_t len = __strnend(src, n) - src;
+ char *p = __strend(dest);
+
+ p[len] = '\0';
+ __builtin_memcpy(p, src, len);
+ return dest;
+}
+EXPORT_SYMBOL(strncat);
+
+/**
+ * strcmp - Compare two strings
+ * @cs: One string
+ * @ct: Another string
+ *
+ * returns 0 if @cs and @ct are equal,
+ * < 0 if @cs is less than @ct
+ * > 0 if @cs is greater than @ct
+ */
+int strcmp(const char *cs, const char *ct)
+{
+ register int r0 asm("0") = 0;
+ int ret = 0;
+
+ asm volatile ("0: clst %2,%3\n"
+ " jo 0b\n"
+ " je 1f\n"
+ " ic %0,0(%2)\n"
+ " ic %1,0(%3)\n"
+ " sr %0,%1\n"
+ "1:"
+ : "+d" (ret), "+d" (r0), "+a" (cs), "+a" (ct)
+ : : "cc" );
+ return ret;
+}
+EXPORT_SYMBOL(strcmp);
+
+/**
+ * strrchr - Find the last occurrence of a character in a string
+ * @s: The string to be searched
+ * @c: The character to search for
+ */
+char * strrchr(const char * s, int c)
+{
+ size_t len = __strend(s) - s;
+
+ if (len)
+ do {
+ if (s[len] == (char) c)
+ return (char *) s + len;
+ } while (--len > 0);
+ return NULL;
+}
+EXPORT_SYMBOL(strrchr);
+
+/**
+ * strstr - Find the first substring in a %NUL terminated string
+ * @s1: The string to be searched
+ * @s2: The string to search for
+ */
+char * strstr(const char * s1,const char * s2)
+{
+ int l1, l2;
+
+ l2 = __strend(s2) - s2;
+ if (!l2)
+ return (char *) s1;
+ l1 = __strend(s1) - s1;
+ while (l1-- >= l2) {
+ register unsigned long r2 asm("2") = (unsigned long) s1;
+ register unsigned long r3 asm("3") = (unsigned long) l2;
+ register unsigned long r4 asm("4") = (unsigned long) s2;
+ register unsigned long r5 asm("5") = (unsigned long) l2;
+ int cc;
+
+ asm volatile ("0: clcle %1,%3,0\n"
+ " jo 0b\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=&d" (cc), "+a" (r2), "+a" (r3),
+ "+a" (r4), "+a" (r5) : : "cc" );
+ if (!cc)
+ return (char *) s1;
+ s1++;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(strstr);
+
+/**
+ * memchr - Find a character in an area of memory.
+ * @s: The memory area
+ * @c: The byte to search for
+ * @n: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or %NULL
+ * if @c is not found
+ */
+void *memchr(const void *s, int c, size_t n)
+{
+ register int r0 asm("0") = (char) c;
+ const void *ret = s + n;
+
+ asm volatile ("0: srst %0,%1\n"
+ " jo 0b\n"
+ " jl 1f\n"
+ " la %0,0\n"
+ "1:"
+ : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
+ return (void *) ret;
+}
+EXPORT_SYMBOL(memchr);
+
+/**
+ * memcmp - Compare two areas of memory
+ * @cs: One area of memory
+ * @ct: Another area of memory
+ * @count: The size of the area.
+ */
+int memcmp(const void *cs, const void *ct, size_t n)
+{
+ register unsigned long r2 asm("2") = (unsigned long) cs;
+ register unsigned long r3 asm("3") = (unsigned long) n;
+ register unsigned long r4 asm("4") = (unsigned long) ct;
+ register unsigned long r5 asm("5") = (unsigned long) n;
+ int ret;
+
+ asm volatile ("0: clcle %1,%3,0\n"
+ " jo 0b\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=&d" (ret), "+a" (r2), "+a" (r3), "+a" (r4), "+a" (r5)
+ : : "cc" );
+ if (ret)
+ ret = *(char *) r2 - *(char *) r4;
+ return ret;
+}
+EXPORT_SYMBOL(memcmp);
+
+/**
+ * memscan - Find a character in an area of memory.
+ * @s: The memory area
+ * @c: The byte to search for
+ * @n: The size of the area.
+ *
+ * returns the address of the first occurrence of @c, or 1 byte past
+ * the area if @c is not found
+ */
+void *memscan(void *s, int c, size_t n)
+{
+ register int r0 asm("0") = (char) c;
+ const void *ret = s + n;
+
+ asm volatile ("0: srst %0,%1\n"
+ " jo 0b\n"
+ : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
+ return (void *) ret;
+}
+EXPORT_SYMBOL(memscan);
+
+/**
+ * memcpy - Copy one area of memory to another
+ * @dest: Where to copy to
+ * @src: Where to copy from
+ * @n: The size of the area.
+ *
+ * returns a pointer to @dest
+ */
+void *memcpy(void *dest, const void *src, size_t n)
+{
+ return __builtin_memcpy(dest, src, n);
+}
+EXPORT_SYMBOL(memcpy);
+
+/**
+ * memset - Fill a region of memory with the given value
+ * @s: Pointer to the start of the area.
+ * @c: The byte to fill the area with
+ * @n: The size of the area.
+ *
+ * returns a pointer to @s
+ */
+void *memset(void *s, int c, size_t n)
+{
+ char *xs;
+
+ if (c == 0)
+ return __builtin_memset(s, 0, n);
+
+ xs = (char *) s;
+ if (n > 0)
+ do {
+ *xs++ = c;
+ } while (--n > 0);
+ return s;
+}
+EXPORT_SYMBOL(memset);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess.h b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess.h
new file mode 100644
index 0000000000..126011df14
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess.h
@@ -0,0 +1,23 @@
+/*
+ * arch/s390/uaccess.h
+ *
+ * Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __ARCH_S390_LIB_UACCESS_H
+#define __ARCH_S390_LIB_UACCESS_H
+
+extern size_t copy_from_user_std(size_t, const void __user *, void *);
+extern size_t copy_to_user_std(size_t, void __user *, const void *);
+extern size_t strnlen_user_std(size_t, const char __user *);
+extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
+extern int futex_atomic_cmpxchg_std(int __user *, int, int);
+extern int futex_atomic_op_std(int, int __user *, int, int *);
+
+extern size_t copy_from_user_pt(size_t, const void __user *, void *);
+extern size_t copy_to_user_pt(size_t, void __user *, const void *);
+extern int futex_atomic_op_pt(int, int __user *, int, int *);
+extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+
+#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_mvcos.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_mvcos.c
new file mode 100644
index 0000000000..6d8772339d
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_mvcos.c
@@ -0,0 +1,229 @@
+/*
+ * arch/s390/lib/uaccess_mvcos.c
+ *
+ * Optimized user space space access functions based on mvcos.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Gerald Schaefer (gerald.schaefer@de.ibm.com)
+ */
+
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+#include <asm/futex.h>
+#include "uaccess.h"
+
+#ifndef __s390x__
+#define AHI "ahi"
+#define ALR "alr"
+#define CLR "clr"
+#define LHI "lhi"
+#define SLR "slr"
+#else
+#define AHI "aghi"
+#define ALR "algr"
+#define CLR "clgr"
+#define LHI "lghi"
+#define SLR "slgr"
+#endif
+
+static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
+{
+ register unsigned long reg0 asm("0") = 0x81UL;
+ unsigned long tmp1, tmp2;
+
+ tmp1 = -4096UL;
+ asm volatile(
+ "0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n"
+ " jz 7f\n"
+ "1:"ALR" %0,%3\n"
+ " "SLR" %1,%3\n"
+ " "SLR" %2,%3\n"
+ " j 0b\n"
+ "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */
+ " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */
+ " "SLR" %4,%1\n"
+ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
+ " jnh 4f\n"
+ "3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n"
+ " "SLR" %0,%4\n"
+ " "ALR" %2,%4\n"
+ "4:"LHI" %4,-1\n"
+ " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
+ " bras %3,6f\n" /* memset loop */
+ " xc 0(1,%2),0(%2)\n"
+ "5: xc 0(256,%2),0(%2)\n"
+ " la %2,256(%2)\n"
+ "6:"AHI" %4,-256\n"
+ " jnm 5b\n"
+ " ex %4,0(%3)\n"
+ " j 8f\n"
+ "7:"SLR" %0,%0\n"
+ "8: \n"
+ EX_TABLE(0b,2b) EX_TABLE(3b,4b)
+ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
+ : "d" (reg0) : "cc", "memory");
+ return size;
+}
+
+static size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
+{
+ if (size <= 256)
+ return copy_from_user_std(size, ptr, x);
+ return copy_from_user_mvcos(size, ptr, x);
+}
+
+static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
+{
+ register unsigned long reg0 asm("0") = 0x810000UL;
+ unsigned long tmp1, tmp2;
+
+ tmp1 = -4096UL;
+ asm volatile(
+ "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
+ " jz 4f\n"
+ "1:"ALR" %0,%3\n"
+ " "SLR" %1,%3\n"
+ " "SLR" %2,%3\n"
+ " j 0b\n"
+ "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */
+ " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */
+ " "SLR" %4,%1\n"
+ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
+ " jnh 5f\n"
+ "3: .insn ss,0xc80000000000,0(%4,%1),0(%2),0\n"
+ " "SLR" %0,%4\n"
+ " j 5f\n"
+ "4:"SLR" %0,%0\n"
+ "5: \n"
+ EX_TABLE(0b,2b) EX_TABLE(3b,5b)
+ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
+ : "d" (reg0) : "cc", "memory");
+ return size;
+}
+
+static size_t copy_to_user_mvcos_check(size_t size, void __user *ptr,
+ const void *x)
+{
+ if (size <= 256)
+ return copy_to_user_std(size, ptr, x);
+ return copy_to_user_mvcos(size, ptr, x);
+}
+
+static size_t copy_in_user_mvcos(size_t size, void __user *to,
+ const void __user *from)
+{
+ register unsigned long reg0 asm("0") = 0x810081UL;
+ unsigned long tmp1, tmp2;
+
+ tmp1 = -4096UL;
+ /* FIXME: copy with reduced length. */
+ asm volatile(
+ "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
+ " jz 2f\n"
+ "1:"ALR" %0,%3\n"
+ " "SLR" %1,%3\n"
+ " "SLR" %2,%3\n"
+ " j 0b\n"
+ "2:"SLR" %0,%0\n"
+ "3: \n"
+ EX_TABLE(0b,3b)
+ : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2)
+ : "d" (reg0) : "cc", "memory");
+ return size;
+}
+
+static size_t clear_user_mvcos(size_t size, void __user *to)
+{
+ register unsigned long reg0 asm("0") = 0x810000UL;
+ unsigned long tmp1, tmp2;
+
+ tmp1 = -4096UL;
+ asm volatile(
+ "0: .insn ss,0xc80000000000,0(%0,%1),0(%4),0\n"
+ " jz 4f\n"
+ "1:"ALR" %0,%2\n"
+ " "SLR" %1,%2\n"
+ " j 0b\n"
+ "2: la %3,4095(%1)\n"/* %4 = to + 4095 */
+ " nr %3,%2\n" /* %4 = (to + 4095) & -4096 */
+ " "SLR" %3,%1\n"
+ " "CLR" %0,%3\n" /* copy crosses next page boundary? */
+ " jnh 5f\n"
+ "3: .insn ss,0xc80000000000,0(%3,%1),0(%4),0\n"
+ " "SLR" %0,%3\n"
+ " j 5f\n"
+ "4:"SLR" %0,%0\n"
+ "5: \n"
+ EX_TABLE(0b,2b) EX_TABLE(3b,5b)
+ : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
+ : "a" (empty_zero_page), "d" (reg0) : "cc", "memory");
+ return size;
+}
+
+static size_t strnlen_user_mvcos(size_t count, const char __user *src)
+{
+ char buf[256];
+ int rc;
+ size_t done, len, len_str;
+
+ done = 0;
+ do {
+ len = min(count - done, (size_t) 256);
+ rc = uaccess.copy_from_user(len, src + done, buf);
+ if (unlikely(rc == len))
+ return 0;
+ len -= rc;
+ len_str = strnlen(buf, len);
+ done += len_str;
+ } while ((len_str == len) && (done < count));
+ return done + 1;
+}
+
+static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
+ char *dst)
+{
+ int rc;
+ size_t done, len, len_str;
+
+ done = 0;
+ do {
+ len = min(count - done, (size_t) 4096);
+ rc = uaccess.copy_from_user(len, src + done, dst);
+ if (unlikely(rc == len))
+ return -EFAULT;
+ len -= rc;
+ len_str = strnlen(dst, len);
+ done += len_str;
+ } while ((len_str == len) && (done < count));
+ return done;
+}
+
+struct uaccess_ops uaccess_mvcos = {
+ .copy_from_user = copy_from_user_mvcos_check,
+ .copy_from_user_small = copy_from_user_std,
+ .copy_to_user = copy_to_user_mvcos_check,
+ .copy_to_user_small = copy_to_user_std,
+ .copy_in_user = copy_in_user_mvcos,
+ .clear_user = clear_user_mvcos,
+ .strnlen_user = strnlen_user_std,
+ .strncpy_from_user = strncpy_from_user_std,
+ .futex_atomic_op = futex_atomic_op_std,
+ .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
+};
+
+#ifdef CONFIG_S390_SWITCH_AMODE
+struct uaccess_ops uaccess_mvcos_switch = {
+ .copy_from_user = copy_from_user_mvcos,
+ .copy_from_user_small = copy_from_user_mvcos,
+ .copy_to_user = copy_to_user_mvcos,
+ .copy_to_user_small = copy_to_user_mvcos,
+ .copy_in_user = copy_in_user_mvcos,
+ .clear_user = clear_user_mvcos,
+ .strnlen_user = strnlen_user_mvcos,
+ .strncpy_from_user = strncpy_from_user_mvcos,
+ .futex_atomic_op = futex_atomic_op_pt,
+ .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
+};
+#endif
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_pt.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_pt.c
new file mode 100644
index 0000000000..5efdfe9f5e
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_pt.c
@@ -0,0 +1,441 @@
+/*
+ * arch/s390/lib/uaccess_pt.c
+ *
+ * User access functions based on page table walks for enhanced
+ * system layout without hardware support.
+ *
+ * Copyright IBM Corp. 2006
+ * Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
+ */
+
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+#include <asm/futex.h>
+#include "uaccess.h"
+
+static inline pte_t *follow_table(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+
+ pgd = pgd_offset(mm, addr);
+ if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+ return NULL;
+
+ pud = pud_offset(pgd, addr);
+ if (pud_none(*pud) || unlikely(pud_bad(*pud)))
+ return NULL;
+
+ pmd = pmd_offset(pud, addr);
+ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+ return NULL;
+
+ return pte_offset_map(pmd, addr);
+}
+
+static int __handle_fault(struct mm_struct *mm, unsigned long address,
+ int write_access)
+{
+ struct vm_area_struct *vma;
+ int ret = -EFAULT;
+ int fault;
+
+ if (in_atomic())
+ return ret;
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, address);
+ if (unlikely(!vma))
+ goto out;
+ if (unlikely(vma->vm_start > address)) {
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto out;
+ if (expand_stack(vma, address))
+ goto out;
+ }
+
+ if (!write_access) {
+ /* page not present, check vm flags */
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ goto out;
+ } else {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto out;
+ }
+
+survive:
+ fault = handle_mm_fault(mm, vma, address, write_access);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto out_sigbus;
+ BUG();
+ }
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
+ ret = 0;
+out:
+ up_read(&mm->mmap_sem);
+ return ret;
+
+out_of_memory:
+ up_read(&mm->mmap_sem);
+ if (is_global_init(current)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+ }
+ printk("VM: killing process %s\n", current->comm);
+ return ret;
+
+out_sigbus:
+ up_read(&mm->mmap_sem);
+ current->thread.prot_addr = address;
+ current->thread.trap_no = 0x11;
+ force_sig(SIGBUS, current);
+ return ret;
+}
+
+static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
+ size_t n, int write_user)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long offset, pfn, done, size;
+ pte_t *pte;
+ void *from, *to;
+
+ done = 0;
+retry:
+ spin_lock(&mm->page_table_lock);
+ do {
+ pte = follow_table(mm, uaddr);
+ if (!pte || !pte_present(*pte) ||
+ (write_user && !pte_write(*pte)))
+ goto fault;
+
+ pfn = pte_pfn(*pte);
+ if (!pfn_valid(pfn))
+ goto out;
+
+ offset = uaddr & (PAGE_SIZE - 1);
+ size = min(n - done, PAGE_SIZE - offset);
+ if (write_user) {
+ to = (void *)((pfn << PAGE_SHIFT) + offset);
+ from = kptr + done;
+ } else {
+ from = (void *)((pfn << PAGE_SHIFT) + offset);
+ to = kptr + done;
+ }
+ memcpy(to, from, size);
+ done += size;
+ uaddr += size;
+ } while (done < n);
+out:
+ spin_unlock(&mm->page_table_lock);
+ return n - done;
+fault:
+ spin_unlock(&mm->page_table_lock);
+ if (__handle_fault(mm, uaddr, write_user))
+ return n - done;
+ goto retry;
+}
+
+/*
+ * Do DAT for user address by page table walk, return kernel address.
+ * This function needs to be called with current->mm->page_table_lock held.
+ */
+static unsigned long __dat_user_addr(unsigned long uaddr)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long pfn, ret;
+ pte_t *pte;
+ int rc;
+
+ ret = 0;
+retry:
+ pte = follow_table(mm, uaddr);
+ if (!pte || !pte_present(*pte))
+ goto fault;
+
+ pfn = pte_pfn(*pte);
+ if (!pfn_valid(pfn))
+ goto out;
+
+ ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
+out:
+ return ret;
+fault:
+ spin_unlock(&mm->page_table_lock);
+ rc = __handle_fault(mm, uaddr, 0);
+ spin_lock(&mm->page_table_lock);
+ if (rc)
+ goto out;
+ goto retry;
+}
+
+size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
+{
+ size_t rc;
+
+ if (segment_eq(get_fs(), KERNEL_DS)) {
+ memcpy(to, (void __kernel __force *) from, n);
+ return 0;
+ }
+ rc = __user_copy_pt((unsigned long) from, to, n, 0);
+ if (unlikely(rc))
+ memset(to + n - rc, 0, rc);
+ return rc;
+}
+
+size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
+{
+ if (segment_eq(get_fs(), KERNEL_DS)) {
+ memcpy((void __kernel __force *) to, from, n);
+ return 0;
+ }
+ return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
+}
+
+static size_t clear_user_pt(size_t n, void __user *to)
+{
+ long done, size, ret;
+
+ if (segment_eq(get_fs(), KERNEL_DS)) {
+ memset((void __kernel __force *) to, 0, n);
+ return 0;
+ }
+ done = 0;
+ do {
+ if (n - done > PAGE_SIZE)
+ size = PAGE_SIZE;
+ else
+ size = n - done;
+ ret = __user_copy_pt((unsigned long) to + done,
+ &empty_zero_page, size, 1);
+ done += size;
+ if (ret)
+ return ret + n - done;
+ } while (done < n);
+ return 0;
+}
+
+static size_t strnlen_user_pt(size_t count, const char __user *src)
+{
+ char *addr;
+ unsigned long uaddr = (unsigned long) src;
+ struct mm_struct *mm = current->mm;
+ unsigned long offset, pfn, done, len;
+ pte_t *pte;
+ size_t len_str;
+
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return strnlen((const char __kernel __force *) src, count) + 1;
+ done = 0;
+retry:
+ spin_lock(&mm->page_table_lock);
+ do {
+ pte = follow_table(mm, uaddr);
+ if (!pte || !pte_present(*pte))
+ goto fault;
+
+ pfn = pte_pfn(*pte);
+ if (!pfn_valid(pfn)) {
+ done = -1;
+ goto out;
+ }
+
+ offset = uaddr & (PAGE_SIZE-1);
+ addr = (char *)(pfn << PAGE_SHIFT) + offset;
+ len = min(count - done, PAGE_SIZE - offset);
+ len_str = strnlen(addr, len);
+ done += len_str;
+ uaddr += len_str;
+ } while ((len_str == len) && (done < count));
+out:
+ spin_unlock(&mm->page_table_lock);
+ return done + 1;
+fault:
+ spin_unlock(&mm->page_table_lock);
+ if (__handle_fault(mm, uaddr, 0)) {
+ return 0;
+ }
+ goto retry;
+}
+
+static size_t strncpy_from_user_pt(size_t count, const char __user *src,
+ char *dst)
+{
+ size_t n = strnlen_user_pt(count, src);
+
+ if (!n)
+ return -EFAULT;
+ if (n > count)
+ n = count;
+ if (segment_eq(get_fs(), KERNEL_DS)) {
+ memcpy(dst, (const char __kernel __force *) src, n);
+ if (dst[n-1] == '\0')
+ return n-1;
+ else
+ return n;
+ }
+ if (__user_copy_pt((unsigned long) src, dst, n, 0))
+ return -EFAULT;
+ if (dst[n-1] == '\0')
+ return n-1;
+ else
+ return n;
+}
+
+static size_t copy_in_user_pt(size_t n, void __user *to,
+ const void __user *from)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
+ uaddr, done, size;
+ unsigned long uaddr_from = (unsigned long) from;
+ unsigned long uaddr_to = (unsigned long) to;
+ pte_t *pte_from, *pte_to;
+ int write_user;
+
+ done = 0;
+retry:
+ spin_lock(&mm->page_table_lock);
+ do {
+ pte_from = follow_table(mm, uaddr_from);
+ if (!pte_from || !pte_present(*pte_from)) {
+ uaddr = uaddr_from;
+ write_user = 0;
+ goto fault;
+ }
+
+ pte_to = follow_table(mm, uaddr_to);
+ if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
+ uaddr = uaddr_to;
+ write_user = 1;
+ goto fault;
+ }
+
+ pfn_from = pte_pfn(*pte_from);
+ if (!pfn_valid(pfn_from))
+ goto out;
+ pfn_to = pte_pfn(*pte_to);
+ if (!pfn_valid(pfn_to))
+ goto out;
+
+ offset_from = uaddr_from & (PAGE_SIZE-1);
+ offset_to = uaddr_from & (PAGE_SIZE-1);
+ offset_max = max(offset_from, offset_to);
+ size = min(n - done, PAGE_SIZE - offset_max);
+
+ memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to,
+ (void *)(pfn_from << PAGE_SHIFT) + offset_from, size);
+ done += size;
+ uaddr_from += size;
+ uaddr_to += size;
+ } while (done < n);
+out:
+ spin_unlock(&mm->page_table_lock);
+ return n - done;
+fault:
+ spin_unlock(&mm->page_table_lock);
+ if (__handle_fault(mm, uaddr, write_user))
+ return n - done;
+ goto retry;
+}
+
+#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
+ asm volatile("0: l %1,0(%6)\n" \
+ "1: " insn \
+ "2: cs %1,%2,0(%6)\n" \
+ "3: jl 1b\n" \
+ " lhi %0,0\n" \
+ "4:\n" \
+ EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \
+ : "=d" (ret), "=&d" (oldval), "=&d" (newval), \
+ "=m" (*uaddr) \
+ : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
+ "m" (*uaddr) : "cc" );
+
+int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+{
+ int oldval = 0, newval, ret;
+
+ spin_lock(&current->mm->page_table_lock);
+ uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+ if (!uaddr) {
+ spin_unlock(&current->mm->page_table_lock);
+ return -EFAULT;
+ }
+ get_page(virt_to_page(uaddr));
+ spin_unlock(&current->mm->page_table_lock);
+ switch (op) {
+ case FUTEX_OP_SET:
+ __futex_atomic_op("lr %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ADD:
+ __futex_atomic_op("lr %2,%1\nar %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+ __futex_atomic_op("lr %2,%1\nor %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_XOR:
+ __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+ put_page(virt_to_page(uaddr));
+ *old = oldval;
+ return ret;
+}
+
+int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+{
+ int ret;
+
+ if (!current->mm)
+ return -EFAULT;
+ spin_lock(&current->mm->page_table_lock);
+ uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+ if (!uaddr) {
+ spin_unlock(&current->mm->page_table_lock);
+ return -EFAULT;
+ }
+ get_page(virt_to_page(uaddr));
+ spin_unlock(&current->mm->page_table_lock);
+ asm volatile(" cs %1,%4,0(%5)\n"
+ "0: lr %0,%1\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
+ : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
+ : "cc", "memory" );
+ put_page(virt_to_page(uaddr));
+ return ret;
+}
+
+struct uaccess_ops uaccess_pt = {
+ .copy_from_user = copy_from_user_pt,
+ .copy_from_user_small = copy_from_user_pt,
+ .copy_to_user = copy_to_user_pt,
+ .copy_to_user_small = copy_to_user_pt,
+ .copy_in_user = copy_in_user_pt,
+ .clear_user = clear_user_pt,
+ .strnlen_user = strnlen_user_pt,
+ .strncpy_from_user = strncpy_from_user_pt,
+ .futex_atomic_op = futex_atomic_op_pt,
+ .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
+};
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_std.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_std.c
new file mode 100644
index 0000000000..d2ffbadb51
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/lib/uaccess_std.c
@@ -0,0 +1,317 @@
+/*
+ * arch/s390/lib/uaccess_std.c
+ *
+ * Standard user space access functions based on mvcp/mvcs and doing
+ * interesting things in the secondary space mode.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Gerald Schaefer (gerald.schaefer@de.ibm.com)
+ */
+
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <asm/futex.h>
+#include "uaccess.h"
+
+#ifndef __s390x__
+#define AHI "ahi"
+#define ALR "alr"
+#define CLR "clr"
+#define LHI "lhi"
+#define SLR "slr"
+#else
+#define AHI "aghi"
+#define ALR "algr"
+#define CLR "clgr"
+#define LHI "lghi"
+#define SLR "slgr"
+#endif
+
+size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
+{
+ unsigned long tmp1, tmp2;
+
+ tmp1 = -256UL;
+ asm volatile(
+ "0: mvcp 0(%0,%2),0(%1),%3\n"
+ " jz 8f\n"
+ "1:"ALR" %0,%3\n"
+ " la %1,256(%1)\n"
+ " la %2,256(%2)\n"
+ "2: mvcp 0(%0,%2),0(%1),%3\n"
+ " jnz 1b\n"
+ " j 8f\n"
+ "3: la %4,255(%1)\n" /* %4 = ptr + 255 */
+ " "LHI" %3,-4096\n"
+ " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
+ " "SLR" %4,%1\n"
+ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
+ " jnh 5f\n"
+ "4: mvcp 0(%4,%2),0(%1),%3\n"
+ " "SLR" %0,%4\n"
+ " "ALR" %2,%4\n"
+ "5:"LHI" %4,-1\n"
+ " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
+ " bras %3,7f\n" /* memset loop */
+ " xc 0(1,%2),0(%2)\n"
+ "6: xc 0(256,%2),0(%2)\n"
+ " la %2,256(%2)\n"
+ "7:"AHI" %4,-256\n"
+ " jnm 6b\n"
+ " ex %4,0(%3)\n"
+ " j 9f\n"
+ "8:"SLR" %0,%0\n"
+ "9: \n"
+ EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,5b)
+ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
+ : : "cc", "memory");
+ return size;
+}
+
+static size_t copy_from_user_std_check(size_t size, const void __user *ptr,
+ void *x)
+{
+ if (size <= 1024)
+ return copy_from_user_std(size, ptr, x);
+ return copy_from_user_pt(size, ptr, x);
+}
+
+size_t copy_to_user_std(size_t size, void __user *ptr, const void *x)
+{
+ unsigned long tmp1, tmp2;
+
+ tmp1 = -256UL;
+ asm volatile(
+ "0: mvcs 0(%0,%1),0(%2),%3\n"
+ " jz 5f\n"
+ "1:"ALR" %0,%3\n"
+ " la %1,256(%1)\n"
+ " la %2,256(%2)\n"
+ "2: mvcs 0(%0,%1),0(%2),%3\n"
+ " jnz 1b\n"
+ " j 5f\n"
+ "3: la %4,255(%1)\n" /* %4 = ptr + 255 */
+ " "LHI" %3,-4096\n"
+ " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
+ " "SLR" %4,%1\n"
+ " "CLR" %0,%4\n" /* copy crosses next page boundary? */
+ " jnh 6f\n"
+ "4: mvcs 0(%4,%1),0(%2),%3\n"
+ " "SLR" %0,%4\n"
+ " j 6f\n"
+ "5:"SLR" %0,%0\n"
+ "6: \n"
+ EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
+ : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
+ : : "cc", "memory");
+ return size;
+}
+
+static size_t copy_to_user_std_check(size_t size, void __user *ptr,
+ const void *x)
+{
+ if (size <= 1024)
+ return copy_to_user_std(size, ptr, x);
+ return copy_to_user_pt(size, ptr, x);
+}
+
+static size_t copy_in_user_std(size_t size, void __user *to,
+ const void __user *from)
+{
+ unsigned long tmp1;
+
+ asm volatile(
+ " "AHI" %0,-1\n"
+ " jo 5f\n"
+ " sacf 256\n"
+ " bras %3,3f\n"
+ "0:"AHI" %0,257\n"
+ "1: mvc 0(1,%1),0(%2)\n"
+ " la %1,1(%1)\n"
+ " la %2,1(%2)\n"
+ " "AHI" %0,-1\n"
+ " jnz 1b\n"
+ " j 5f\n"
+ "2: mvc 0(256,%1),0(%2)\n"
+ " la %1,256(%1)\n"
+ " la %2,256(%2)\n"
+ "3:"AHI" %0,-256\n"
+ " jnm 2b\n"
+ "4: ex %0,1b-0b(%3)\n"
+ " sacf 0\n"
+ "5: "SLR" %0,%0\n"
+ "6:\n"
+ EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
+ : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1)
+ : : "cc", "memory");
+ return size;
+}
+
+static size_t clear_user_std(size_t size, void __user *to)
+{
+ unsigned long tmp1, tmp2;
+
+ asm volatile(
+ " "AHI" %0,-1\n"
+ " jo 5f\n"
+ " sacf 256\n"
+ " bras %3,3f\n"
+ " xc 0(1,%1),0(%1)\n"
+ "0:"AHI" %0,257\n"
+ " la %2,255(%1)\n" /* %2 = ptr + 255 */
+ " srl %2,12\n"
+ " sll %2,12\n" /* %2 = (ptr + 255) & -4096 */
+ " "SLR" %2,%1\n"
+ " "CLR" %0,%2\n" /* clear crosses next page boundary? */
+ " jnh 5f\n"
+ " "AHI" %2,-1\n"
+ "1: ex %2,0(%3)\n"
+ " "AHI" %2,1\n"
+ " "SLR" %0,%2\n"
+ " j 5f\n"
+ "2: xc 0(256,%1),0(%1)\n"
+ " la %1,256(%1)\n"
+ "3:"AHI" %0,-256\n"
+ " jnm 2b\n"
+ "4: ex %0,0(%3)\n"
+ " sacf 0\n"
+ "5: "SLR" %0,%0\n"
+ "6:\n"
+ EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
+ : "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2)
+ : : "cc", "memory");
+ return size;
+}
+
+size_t strnlen_user_std(size_t size, const char __user *src)
+{
+ register unsigned long reg0 asm("0") = 0UL;
+ unsigned long tmp1, tmp2;
+
+ asm volatile(
+ " la %2,0(%1)\n"
+ " la %3,0(%0,%1)\n"
+ " "SLR" %0,%0\n"
+ " sacf 256\n"
+ "0: srst %3,%2\n"
+ " jo 0b\n"
+ " la %0,1(%3)\n" /* strnlen_user results includes \0 */
+ " "SLR" %0,%1\n"
+ "1: sacf 0\n"
+ EX_TABLE(0b,1b)
+ : "+a" (size), "+a" (src), "=a" (tmp1), "=a" (tmp2)
+ : "d" (reg0) : "cc", "memory");
+ return size;
+}
+
+size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
+{
+ register unsigned long reg0 asm("0") = 0UL;
+ unsigned long tmp1, tmp2;
+
+ asm volatile(
+ " la %3,0(%1)\n"
+ " la %4,0(%0,%1)\n"
+ " sacf 256\n"
+ "0: srst %4,%3\n"
+ " jo 0b\n"
+ " sacf 0\n"
+ " la %0,0(%4)\n"
+ " jh 1f\n" /* found \0 in string ? */
+ " "AHI" %4,1\n" /* include \0 in copy */
+ "1:"SLR" %0,%1\n" /* %0 = return length (without \0) */
+ " "SLR" %4,%1\n" /* %4 = copy length (including \0) */
+ "2: mvcp 0(%4,%2),0(%1),%5\n"
+ " jz 9f\n"
+ "3:"AHI" %4,-256\n"
+ " la %1,256(%1)\n"
+ " la %2,256(%2)\n"
+ "4: mvcp 0(%4,%2),0(%1),%5\n"
+ " jnz 3b\n"
+ " j 9f\n"
+ "7: sacf 0\n"
+ "8:"LHI" %0,%6\n"
+ "9:\n"
+ EX_TABLE(0b,7b) EX_TABLE(2b,8b) EX_TABLE(4b,8b)
+ : "+a" (size), "+a" (src), "+d" (dst), "=a" (tmp1), "=a" (tmp2)
+ : "d" (reg0), "K" (-EFAULT) : "cc", "memory");
+ return size;
+}
+
+#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
+ asm volatile( \
+ " sacf 256\n" \
+ "0: l %1,0(%6)\n" \
+ "1:"insn \
+ "2: cs %1,%2,0(%6)\n" \
+ "3: jl 1b\n" \
+ " lhi %0,0\n" \
+ "4: sacf 0\n" \
+ EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \
+ : "=d" (ret), "=&d" (oldval), "=&d" (newval), \
+ "=m" (*uaddr) \
+ : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
+ "m" (*uaddr) : "cc");
+
+int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
+{
+ int oldval = 0, newval, ret;
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ __futex_atomic_op("lr %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ADD:
+ __futex_atomic_op("lr %2,%1\nar %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+ __futex_atomic_op("lr %2,%1\nor %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ case FUTEX_OP_XOR:
+ __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
+ ret, oldval, newval, uaddr, oparg);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+ *old = oldval;
+ return ret;
+}
+
+int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
+{
+ int ret;
+
+ asm volatile(
+ " sacf 256\n"
+ "0: cs %1,%4,0(%5)\n"
+ "1: lr %0,%1\n"
+ "2: sacf 0\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
+ : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
+ : "cc", "memory" );
+ return ret;
+}
+
+struct uaccess_ops uaccess_std = {
+ .copy_from_user = copy_from_user_std_check,
+ .copy_from_user_small = copy_from_user_std,
+ .copy_to_user = copy_to_user_std_check,
+ .copy_to_user_small = copy_to_user_std,
+ .copy_in_user = copy_in_user_std,
+ .clear_user = clear_user_std,
+ .strnlen_user = strnlen_user_std,
+ .strncpy_from_user = strncpy_from_user_std,
+ .futex_atomic_op = futex_atomic_op_std,
+ .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
+};
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/math-emu/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/math-emu/Makefile
new file mode 100644
index 0000000000..73b3e72efc
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/math-emu/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the FPU instruction emulation.
+#
+
+obj-$(CONFIG_MATHEMU) := math.o
+
+EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
+EXTRA_AFLAGS := -traditional
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/math-emu/math.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/math-emu/math.c
new file mode 100644
index 0000000000..3ee78ccb61
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/math-emu/math.c
@@ -0,0 +1,2255 @@
+/*
+ * arch/s390/math-emu/math.c
+ *
+ * S390 version
+ * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * 'math.c' emulates IEEE instructions on a S390 processor
+ * that does not have the IEEE fpu (all processors before G5).
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+#include <asm/lowcore.h>
+
+#include <asm/sfp-util.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+#include <math-emu/double.h>
+#include <math-emu/quad.h>
+
+/*
+ * I miss a macro to round a floating point number to the
+ * nearest integer in the same floating point format.
+ */
+#define _FP_TO_FPINT_ROUND(fs, wc, X) \
+ do { \
+ switch (X##_c) \
+ { \
+ case FP_CLS_NORMAL: \
+ if (X##_e > _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs) \
+ { /* floating point number has no bits after the dot. */ \
+ } \
+ else if (X##_e <= _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs && \
+ X##_e > _FP_EXPBIAS_##fs) \
+ { /* some bits before the dot, some after it. */ \
+ _FP_FRAC_SRS_##wc(X, _FP_WFRACBITS_##fs, \
+ X##_e - _FP_EXPBIAS_##fs \
+ + _FP_FRACBITS_##fs); \
+ _FP_ROUND(wc, X); \
+ _FP_FRAC_SLL_##wc(X, X##_e - _FP_EXPBIAS_##fs \
+ + _FP_FRACBITS_##fs); \
+ } \
+ else \
+ { /* all bits after the dot. */ \
+ FP_SET_EXCEPTION(FP_EX_INEXACT); \
+ X##_c = FP_CLS_ZERO; \
+ } \
+ break; \
+ case FP_CLS_NAN: \
+ case FP_CLS_INF: \
+ case FP_CLS_ZERO: \
+ break; \
+ } \
+ } while (0)
+
+#define FP_TO_FPINT_ROUND_S(X) _FP_TO_FPINT_ROUND(S,1,X)
+#define FP_TO_FPINT_ROUND_D(X) _FP_TO_FPINT_ROUND(D,2,X)
+#define FP_TO_FPINT_ROUND_Q(X) _FP_TO_FPINT_ROUND(Q,4,X)
+
+typedef union {
+ long double ld;
+ struct {
+ __u64 high;
+ __u64 low;
+ } w;
+} mathemu_ldcv;
+
+#ifdef CONFIG_SYSCTL
+int sysctl_ieee_emulation_warnings=1;
+#endif
+
+#define mathemu_put_user(x, p) \
+ do { \
+ if (put_user((x),(p))) \
+ return SIGSEGV; \
+ } while (0)
+
+#define mathemu_get_user(x, p) \
+ do { \
+ if (get_user((x),(p))) \
+ return SIGSEGV; \
+ } while (0)
+
+#define mathemu_copy_from_user(d, s, n)\
+ do { \
+ if (copy_from_user((d),(s),(n)) != 0) \
+ return SIGSEGV; \
+ } while (0)
+
+#define mathemu_copy_to_user(d, s, n) \
+ do { \
+ if (copy_to_user((d),(s),(n)) != 0) \
+ return SIGSEGV; \
+ } while (0)
+
+static void display_emulation_not_implemented(struct pt_regs *regs, char *instr)
+{
+ __u16 *location;
+
+#ifdef CONFIG_SYSCTL
+ if(sysctl_ieee_emulation_warnings)
+#endif
+ {
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ printk("%s ieee fpu instruction not emulated "
+ "process name: %s pid: %d \n",
+ instr, current->comm, current->pid);
+ printk("%s's PSW: %08lx %08lx\n", instr,
+ (unsigned long) regs->psw.mask,
+ (unsigned long) location);
+ }
+}
+
+static inline void emu_set_CC (struct pt_regs *regs, int cc)
+{
+ regs->psw.mask = (regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12);
+}
+
+/*
+ * Set the condition code in the user psw.
+ * 0 : Result is zero
+ * 1 : Result is less than zero
+ * 2 : Result is greater than zero
+ * 3 : Result is NaN or INF
+ */
+static inline void emu_set_CC_cs(struct pt_regs *regs, int class, int sign)
+{
+ switch (class) {
+ case FP_CLS_NORMAL:
+ case FP_CLS_INF:
+ emu_set_CC(regs, sign ? 1 : 2);
+ break;
+ case FP_CLS_ZERO:
+ emu_set_CC(regs, 0);
+ break;
+ case FP_CLS_NAN:
+ emu_set_CC(regs, 3);
+ break;
+ }
+}
+
+/* Add long double */
+static int emu_axbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QB, &cvt.ld);
+ FP_ADD_Q(QR, QA, QB);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ emu_set_CC_cs(regs, QR_c, QR_s);
+ return _fex;
+}
+
+/* Add double */
+static int emu_adbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+ FP_ADD_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ emu_set_CC_cs(regs, DR_c, DR_s);
+ return _fex;
+}
+
+/* Add double */
+static int emu_adb (struct pt_regs *regs, int rx, double *val) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, val);
+ FP_ADD_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ emu_set_CC_cs(regs, DR_c, DR_s);
+ return _fex;
+}
+
+/* Add float */
+static int emu_aebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+ FP_ADD_S(SR, SA, SB);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ emu_set_CC_cs(regs, SR_c, SR_s);
+ return _fex;
+}
+
+/* Add float */
+static int emu_aeb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, val);
+ FP_ADD_S(SR, SA, SB);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ emu_set_CC_cs(regs, SR_c, SR_s);
+ return _fex;
+}
+
+/* Compare long double */
+static int emu_cxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QB);
+ mathemu_ldcv cvt;
+ int IR;
+
+ cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+ FP_UNPACK_RAW_QP(QA, &cvt.ld);
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_RAW_QP(QB, &cvt.ld);
+ FP_CMP_Q(IR, QA, QB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ return 0;
+}
+
+/* Compare double */
+static int emu_cdbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DB);
+ int IR;
+
+ FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_RAW_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+ FP_CMP_D(IR, DA, DB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ return 0;
+}
+
+/* Compare double */
+static int emu_cdb (struct pt_regs *regs, int rx, double *val) {
+ FP_DECL_D(DA); FP_DECL_D(DB);
+ int IR;
+
+ FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_RAW_DP(DB, val);
+ FP_CMP_D(IR, DA, DB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ return 0;
+}
+
+/* Compare float */
+static int emu_cebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SB);
+ int IR;
+
+ FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_RAW_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+ FP_CMP_S(IR, SA, SB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ return 0;
+}
+
+/* Compare float */
+static int emu_ceb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_S(SB);
+ int IR;
+
+ FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_RAW_SP(SB, val);
+ FP_CMP_S(IR, SA, SB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ return 0;
+}
+
+/* Compare and signal long double */
+static int emu_kxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QB);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int IR;
+
+ cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+ FP_UNPACK_RAW_QP(QA, &cvt.ld);
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QB, &cvt.ld);
+ FP_CMP_Q(IR, QA, QB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ if (IR == 3)
+ FP_SET_EXCEPTION (FP_EX_INVALID);
+ return _fex;
+}
+
+/* Compare and signal double */
+static int emu_kdbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DB);
+ FP_DECL_EX;
+ int IR;
+
+ FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_RAW_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+ FP_CMP_D(IR, DA, DB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ if (IR == 3)
+ FP_SET_EXCEPTION (FP_EX_INVALID);
+ return _fex;
+}
+
+/* Compare and signal double */
+static int emu_kdb (struct pt_regs *regs, int rx, double *val) {
+ FP_DECL_D(DA); FP_DECL_D(DB);
+ FP_DECL_EX;
+ int IR;
+
+ FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_RAW_DP(DB, val);
+ FP_CMP_D(IR, DA, DB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ if (IR == 3)
+ FP_SET_EXCEPTION (FP_EX_INVALID);
+ return _fex;
+}
+
+/* Compare and signal float */
+static int emu_kebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SB);
+ FP_DECL_EX;
+ int IR;
+
+ FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_RAW_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+ FP_CMP_S(IR, SA, SB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ if (IR == 3)
+ FP_SET_EXCEPTION (FP_EX_INVALID);
+ return _fex;
+}
+
+/* Compare and signal float */
+static int emu_keb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_S(SB);
+ FP_DECL_EX;
+ int IR;
+
+ FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_RAW_SP(SB, val);
+ FP_CMP_S(IR, SA, SB, 3);
+ /*
+ * IR == -1 if DA < DB, IR == 0 if DA == DB,
+ * IR == 1 if DA > DB and IR == 3 if unorderded
+ */
+ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+ if (IR == 3)
+ FP_SET_EXCEPTION (FP_EX_INVALID);
+ return _fex;
+}
+
+/* Convert from fixed long double */
+static int emu_cxfbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ __s32 si;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ si = regs->gprs[ry];
+ FP_FROM_INT_Q(QR, si, 32, int);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Convert from fixed double */
+static int emu_cdfbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DR);
+ FP_DECL_EX;
+ __s32 si;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ si = regs->gprs[ry];
+ FP_FROM_INT_D(DR, si, 32, int);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ return _fex;
+}
+
+/* Convert from fixed float */
+static int emu_cefbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SR);
+ FP_DECL_EX;
+ __s32 si;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ si = regs->gprs[ry];
+ FP_FROM_INT_S(SR, si, 32, int);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ return _fex;
+}
+
+/* Convert to fixed long double */
+static int emu_cfxbr (struct pt_regs *regs, int rx, int ry, int mask) {
+ FP_DECL_Q(QA);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ __s32 si;
+ int mode;
+
+ if (mask == 0)
+ mode = current->thread.fp_regs.fpc & 3;
+ else if (mask == 1)
+ mode = FP_RND_NEAREST;
+ else
+ mode = mask - 4;
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ FP_TO_INT_ROUND_Q(si, QA, 32, 1);
+ regs->gprs[rx] = si;
+ emu_set_CC_cs(regs, QA_c, QA_s);
+ return _fex;
+}
+
+/* Convert to fixed double */
+static int emu_cfdbr (struct pt_regs *regs, int rx, int ry, int mask) {
+ FP_DECL_D(DA);
+ FP_DECL_EX;
+ __s32 si;
+ int mode;
+
+ if (mask == 0)
+ mode = current->thread.fp_regs.fpc & 3;
+ else if (mask == 1)
+ mode = FP_RND_NEAREST;
+ else
+ mode = mask - 4;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+ FP_TO_INT_ROUND_D(si, DA, 32, 1);
+ regs->gprs[rx] = si;
+ emu_set_CC_cs(regs, DA_c, DA_s);
+ return _fex;
+}
+
+/* Convert to fixed float */
+static int emu_cfebr (struct pt_regs *regs, int rx, int ry, int mask) {
+ FP_DECL_S(SA);
+ FP_DECL_EX;
+ __s32 si;
+ int mode;
+
+ if (mask == 0)
+ mode = current->thread.fp_regs.fpc & 3;
+ else if (mask == 1)
+ mode = FP_RND_NEAREST;
+ else
+ mode = mask - 4;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+ FP_TO_INT_ROUND_S(si, SA, 32, 1);
+ regs->gprs[rx] = si;
+ emu_set_CC_cs(regs, SA_c, SA_s);
+ return _fex;
+}
+
+/* Divide long double */
+static int emu_dxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QB, &cvt.ld);
+ FP_DIV_Q(QR, QA, QB);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Divide double */
+static int emu_ddbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+ FP_DIV_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ return _fex;
+}
+
+/* Divide double */
+static int emu_ddb (struct pt_regs *regs, int rx, double *val) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, val);
+ FP_DIV_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ return _fex;
+}
+
+/* Divide float */
+static int emu_debr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+ FP_DIV_S(SR, SA, SB);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ return _fex;
+}
+
+/* Divide float */
+static int emu_deb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, val);
+ FP_DIV_S(SR, SA, SB);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ return _fex;
+}
+
+/* Divide to integer double */
+static int emu_didbr (struct pt_regs *regs, int rx, int ry, int mask) {
+ display_emulation_not_implemented(regs, "didbr");
+ return 0;
+}
+
+/* Divide to integer float */
+static int emu_diebr (struct pt_regs *regs, int rx, int ry, int mask) {
+ display_emulation_not_implemented(regs, "diebr");
+ return 0;
+}
+
+/* Extract fpc */
+static int emu_efpc (struct pt_regs *regs, int rx, int ry) {
+ regs->gprs[rx] = current->thread.fp_regs.fpc;
+ return 0;
+}
+
+/* Load and test long double */
+static int emu_ltxbr (struct pt_regs *regs, int rx, int ry) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ mathemu_ldcv cvt;
+ FP_DECL_Q(QA);
+ FP_DECL_EX;
+
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
+ fp_regs->fprs[rx+2].ui = fp_regs->fprs[ry+2].ui;
+ emu_set_CC_cs(regs, QA_c, QA_s);
+ return _fex;
+}
+
+/* Load and test double */
+static int emu_ltdbr (struct pt_regs *regs, int rx, int ry) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ FP_DECL_D(DA);
+ FP_DECL_EX;
+
+ FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d);
+ fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
+ emu_set_CC_cs(regs, DA_c, DA_s);
+ return _fex;
+}
+
+/* Load and test double */
+static int emu_ltebr (struct pt_regs *regs, int rx, int ry) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ FP_DECL_S(SA);
+ FP_DECL_EX;
+
+ FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f);
+ fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
+ emu_set_CC_cs(regs, SA_c, SA_s);
+ return _fex;
+}
+
+/* Load complement long double */
+static int emu_lcxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ FP_NEG_Q(QR, QA);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ emu_set_CC_cs(regs, QR_c, QR_s);
+ return _fex;
+}
+
+/* Load complement double */
+static int emu_lcdbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+ FP_NEG_D(DR, DA);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ emu_set_CC_cs(regs, DR_c, DR_s);
+ return _fex;
+}
+
+/* Load complement float */
+static int emu_lcebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+ FP_NEG_S(SR, SA);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ emu_set_CC_cs(regs, SR_c, SR_s);
+ return _fex;
+}
+
+/* Load floating point integer long double */
+static int emu_fixbr (struct pt_regs *regs, int rx, int ry, int mask) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ FP_DECL_Q(QA);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ __s32 si;
+ int mode;
+
+ if (mask == 0)
+ mode = fp_regs->fpc & 3;
+ else if (mask == 1)
+ mode = FP_RND_NEAREST;
+ else
+ mode = mask - 4;
+ cvt.w.high = fp_regs->fprs[ry].ui;
+ cvt.w.low = fp_regs->fprs[ry+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ FP_TO_FPINT_ROUND_Q(QA);
+ FP_PACK_QP(&cvt.ld, QA);
+ fp_regs->fprs[rx].ui = cvt.w.high;
+ fp_regs->fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Load floating point integer double */
+static int emu_fidbr (struct pt_regs *regs, int rx, int ry, int mask) {
+ /* FIXME: rounding mode !! */
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ FP_DECL_D(DA);
+ FP_DECL_EX;
+ __s32 si;
+ int mode;
+
+ if (mask == 0)
+ mode = fp_regs->fpc & 3;
+ else if (mask == 1)
+ mode = FP_RND_NEAREST;
+ else
+ mode = mask - 4;
+ FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d);
+ FP_TO_FPINT_ROUND_D(DA);
+ FP_PACK_DP(&fp_regs->fprs[rx].d, DA);
+ return _fex;
+}
+
+/* Load floating point integer float */
+static int emu_fiebr (struct pt_regs *regs, int rx, int ry, int mask) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ FP_DECL_S(SA);
+ FP_DECL_EX;
+ __s32 si;
+ int mode;
+
+ if (mask == 0)
+ mode = fp_regs->fpc & 3;
+ else if (mask == 1)
+ mode = FP_RND_NEAREST;
+ else
+ mode = mask - 4;
+ FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f);
+ FP_TO_FPINT_ROUND_S(SA);
+ FP_PACK_SP(&fp_regs->fprs[rx].f, SA);
+ return _fex;
+}
+
+/* Load lengthened double to long double */
+static int emu_lxdbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+ FP_CONV (Q, D, 4, 2, QR, DA);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Load lengthened double to long double */
+static int emu_lxdb (struct pt_regs *regs, int rx, double *val) {
+ FP_DECL_D(DA); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, val);
+ FP_CONV (Q, D, 4, 2, QR, DA);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Load lengthened float to long double */
+static int emu_lxebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+ FP_CONV (Q, S, 4, 1, QR, SA);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Load lengthened float to long double */
+static int emu_lxeb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, val);
+ FP_CONV (Q, S, 4, 1, QR, SA);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Load lengthened float to double */
+static int emu_ldebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+ FP_CONV (D, S, 2, 1, DR, SA);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ return _fex;
+}
+
+/* Load lengthened float to double */
+static int emu_ldeb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, val);
+ FP_CONV (D, S, 2, 1, DR, SA);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ return _fex;
+}
+
+/* Load negative long double */
+static int emu_lnxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ if (QA_s == 0) {
+ FP_NEG_Q(QR, QA);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ } else {
+ current->thread.fp_regs.fprs[rx].ui =
+ current->thread.fp_regs.fprs[ry].ui;
+ current->thread.fp_regs.fprs[rx+2].ui =
+ current->thread.fp_regs.fprs[ry+2].ui;
+ }
+ emu_set_CC_cs(regs, QR_c, QR_s);
+ return _fex;
+}
+
+/* Load negative double */
+static int emu_lndbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+ if (DA_s == 0) {
+ FP_NEG_D(DR, DA);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ } else
+ current->thread.fp_regs.fprs[rx].ui =
+ current->thread.fp_regs.fprs[ry].ui;
+ emu_set_CC_cs(regs, DR_c, DR_s);
+ return _fex;
+}
+
+/* Load negative float */
+static int emu_lnebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+ if (SA_s == 0) {
+ FP_NEG_S(SR, SA);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ } else
+ current->thread.fp_regs.fprs[rx].ui =
+ current->thread.fp_regs.fprs[ry].ui;
+ emu_set_CC_cs(regs, SR_c, SR_s);
+ return _fex;
+}
+
+/* Load positive long double */
+static int emu_lpxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ if (QA_s != 0) {
+ FP_NEG_Q(QR, QA);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ } else{
+ current->thread.fp_regs.fprs[rx].ui =
+ current->thread.fp_regs.fprs[ry].ui;
+ current->thread.fp_regs.fprs[rx+2].ui =
+ current->thread.fp_regs.fprs[ry+2].ui;
+ }
+ emu_set_CC_cs(regs, QR_c, QR_s);
+ return _fex;
+}
+
+/* Load positive double */
+static int emu_lpdbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+ if (DA_s != 0) {
+ FP_NEG_D(DR, DA);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ } else
+ current->thread.fp_regs.fprs[rx].ui =
+ current->thread.fp_regs.fprs[ry].ui;
+ emu_set_CC_cs(regs, DR_c, DR_s);
+ return _fex;
+}
+
+/* Load positive float */
+static int emu_lpebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+ if (SA_s != 0) {
+ FP_NEG_S(SR, SA);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ } else
+ current->thread.fp_regs.fprs[rx].ui =
+ current->thread.fp_regs.fprs[ry].ui;
+ emu_set_CC_cs(regs, SR_c, SR_s);
+ return _fex;
+}
+
+/* Load rounded long double to double */
+static int emu_ldxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_D(DR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ FP_CONV (D, Q, 2, 4, DR, QA);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].f, DR);
+ return _fex;
+}
+
+/* Load rounded long double to float */
+static int emu_lexbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_S(SR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ FP_CONV (S, Q, 1, 4, SR, QA);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ return _fex;
+}
+
+/* Load rounded double to float */
+static int emu_ledbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+ FP_CONV (S, D, 1, 2, SR, DA);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ return _fex;
+}
+
+/* Multiply long double */
+static int emu_mxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QB, &cvt.ld);
+ FP_MUL_Q(QR, QA, QB);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Multiply double */
+static int emu_mdbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+ FP_MUL_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ return _fex;
+}
+
+/* Multiply double */
+static int emu_mdb (struct pt_regs *regs, int rx, double *val) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, val);
+ FP_MUL_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ return _fex;
+}
+
+/* Multiply double to long double */
+static int emu_mxdbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_CONV (Q, D, 4, 2, QA, DA);
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+ FP_CONV (Q, D, 4, 2, QB, DA);
+ FP_MUL_Q(QR, QA, QB);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Multiply double to long double */
+static int emu_mxdb (struct pt_regs *regs, int rx, long double *val) {
+ FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ FP_UNPACK_QP(QB, val);
+ FP_MUL_Q(QR, QA, QB);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ return _fex;
+}
+
+/* Multiply float */
+static int emu_meebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+ FP_MUL_S(SR, SA, SB);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ return _fex;
+}
+
+/* Multiply float */
+static int emu_meeb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, val);
+ FP_MUL_S(SR, SA, SB);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ return _fex;
+}
+
+/* Multiply float to double */
+static int emu_mdebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_CONV (D, S, 2, 1, DA, SA);
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+ FP_CONV (D, S, 2, 1, DB, SA);
+ FP_MUL_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ return _fex;
+}
+
+/* Multiply float to double */
+static int emu_mdeb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_CONV (D, S, 2, 1, DA, SA);
+ FP_UNPACK_SP(SA, val);
+ FP_CONV (D, S, 2, 1, DB, SA);
+ FP_MUL_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ return _fex;
+}
+
+/* Multiply and add double */
+static int emu_madbr (struct pt_regs *regs, int rx, int ry, int rz) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+ FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
+ FP_MUL_D(DR, DA, DB);
+ FP_ADD_D(DR, DR, DC);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
+ return _fex;
+}
+
+/* Multiply and add double */
+static int emu_madb (struct pt_regs *regs, int rx, double *val, int rz) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, val);
+ FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
+ FP_MUL_D(DR, DA, DB);
+ FP_ADD_D(DR, DR, DC);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
+ return _fex;
+}
+
+/* Multiply and add float */
+static int emu_maebr (struct pt_regs *regs, int rx, int ry, int rz) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+ FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
+ FP_MUL_S(SR, SA, SB);
+ FP_ADD_S(SR, SR, SC);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
+ return _fex;
+}
+
+/* Multiply and add float */
+static int emu_maeb (struct pt_regs *regs, int rx, float *val, int rz) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, val);
+ FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
+ FP_MUL_S(SR, SA, SB);
+ FP_ADD_S(SR, SR, SC);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
+ return _fex;
+}
+
+/* Multiply and subtract double */
+static int emu_msdbr (struct pt_regs *regs, int rx, int ry, int rz) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+ FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
+ FP_MUL_D(DR, DA, DB);
+ FP_SUB_D(DR, DR, DC);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
+ return _fex;
+}
+
+/* Multiply and subtract double */
+static int emu_msdb (struct pt_regs *regs, int rx, double *val, int rz) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, val);
+ FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
+ FP_MUL_D(DR, DA, DB);
+ FP_SUB_D(DR, DR, DC);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
+ return _fex;
+}
+
+/* Multiply and subtract float */
+static int emu_msebr (struct pt_regs *regs, int rx, int ry, int rz) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+ FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
+ FP_MUL_S(SR, SA, SB);
+ FP_SUB_S(SR, SR, SC);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
+ return _fex;
+}
+
+/* Multiply and subtract float */
+static int emu_mseb (struct pt_regs *regs, int rx, float *val, int rz) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, val);
+ FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
+ FP_MUL_S(SR, SA, SB);
+ FP_SUB_S(SR, SR, SC);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
+ return _fex;
+}
+
+/* Set floating point control word */
+static int emu_sfpc (struct pt_regs *regs, int rx, int ry) {
+ __u32 temp;
+
+ temp = regs->gprs[rx];
+ if ((temp & ~FPC_VALID_MASK) != 0)
+ return SIGILL;
+ current->thread.fp_regs.fpc = temp;
+ return 0;
+}
+
+/* Square root long double */
+static int emu_sqxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ FP_SQRT_Q(QR, QA);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ emu_set_CC_cs(regs, QR_c, QR_s);
+ return _fex;
+}
+
+/* Square root double */
+static int emu_sqdbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
+ FP_SQRT_D(DR, DA);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ emu_set_CC_cs(regs, DR_c, DR_s);
+ return _fex;
+}
+
+/* Square root double */
+static int emu_sqdb (struct pt_regs *regs, int rx, double *val) {
+ FP_DECL_D(DA); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, val);
+ FP_SQRT_D(DR, DA);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ emu_set_CC_cs(regs, DR_c, DR_s);
+ return _fex;
+}
+
+/* Square root float */
+static int emu_sqebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
+ FP_SQRT_S(SR, SA);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ emu_set_CC_cs(regs, SR_c, SR_s);
+ return _fex;
+}
+
+/* Square root float */
+static int emu_sqeb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, val);
+ FP_SQRT_S(SR, SA);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ emu_set_CC_cs(regs, SR_c, SR_s);
+ return _fex;
+}
+
+/* Subtract long double */
+static int emu_sxbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
+ FP_DECL_EX;
+ mathemu_ldcv cvt;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+ FP_UNPACK_QP(QA, &cvt.ld);
+ cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
+ FP_UNPACK_QP(QB, &cvt.ld);
+ FP_SUB_Q(QR, QA, QB);
+ FP_PACK_QP(&cvt.ld, QR);
+ current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
+ current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
+ emu_set_CC_cs(regs, QR_c, QR_s);
+ return _fex;
+}
+
+/* Subtract double */
+static int emu_sdbr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
+ FP_SUB_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ emu_set_CC_cs(regs, DR_c, DR_s);
+ return _fex;
+}
+
+/* Subtract double */
+static int emu_sdb (struct pt_regs *regs, int rx, double *val) {
+ FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ FP_UNPACK_DP(DB, val);
+ FP_SUB_D(DR, DA, DB);
+ FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
+ emu_set_CC_cs(regs, DR_c, DR_s);
+ return _fex;
+}
+
+/* Subtract float */
+static int emu_sebr (struct pt_regs *regs, int rx, int ry) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
+ FP_SUB_S(SR, SA, SB);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ emu_set_CC_cs(regs, SR_c, SR_s);
+ return _fex;
+}
+
+/* Subtract float */
+static int emu_seb (struct pt_regs *regs, int rx, float *val) {
+ FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+ FP_DECL_EX;
+ int mode;
+
+ mode = current->thread.fp_regs.fpc & 3;
+ FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ FP_UNPACK_SP(SB, val);
+ FP_SUB_S(SR, SA, SB);
+ FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
+ emu_set_CC_cs(regs, SR_c, SR_s);
+ return _fex;
+}
+
+/* Test data class long double */
+static int emu_tcxb (struct pt_regs *regs, int rx, long val) {
+ FP_DECL_Q(QA);
+ mathemu_ldcv cvt;
+ int bit;
+
+ cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
+ cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
+ FP_UNPACK_RAW_QP(QA, &cvt.ld);
+ switch (QA_e) {
+ default:
+ bit = 8; /* normalized number */
+ break;
+ case 0:
+ if (_FP_FRAC_ZEROP_4(QA))
+ bit = 10; /* zero */
+ else
+ bit = 6; /* denormalized number */
+ break;
+ case _FP_EXPMAX_Q:
+ if (_FP_FRAC_ZEROP_4(QA))
+ bit = 4; /* infinity */
+ else if (_FP_FRAC_HIGH_RAW_Q(QA) & _FP_QNANBIT_Q)
+ bit = 2; /* quiet NAN */
+ else
+ bit = 0; /* signaling NAN */
+ break;
+ }
+ if (!QA_s)
+ bit++;
+ emu_set_CC(regs, ((__u32) val >> bit) & 1);
+ return 0;
+}
+
+/* Test data class double */
+static int emu_tcdb (struct pt_regs *regs, int rx, long val) {
+ FP_DECL_D(DA);
+ int bit;
+
+ FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
+ switch (DA_e) {
+ default:
+ bit = 8; /* normalized number */
+ break;
+ case 0:
+ if (_FP_FRAC_ZEROP_2(DA))
+ bit = 10; /* zero */
+ else
+ bit = 6; /* denormalized number */
+ break;
+ case _FP_EXPMAX_D:
+ if (_FP_FRAC_ZEROP_2(DA))
+ bit = 4; /* infinity */
+ else if (_FP_FRAC_HIGH_RAW_D(DA) & _FP_QNANBIT_D)
+ bit = 2; /* quiet NAN */
+ else
+ bit = 0; /* signaling NAN */
+ break;
+ }
+ if (!DA_s)
+ bit++;
+ emu_set_CC(regs, ((__u32) val >> bit) & 1);
+ return 0;
+}
+
+/* Test data class float */
+static int emu_tceb (struct pt_regs *regs, int rx, long val) {
+ FP_DECL_S(SA);
+ int bit;
+
+ FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
+ switch (SA_e) {
+ default:
+ bit = 8; /* normalized number */
+ break;
+ case 0:
+ if (_FP_FRAC_ZEROP_1(SA))
+ bit = 10; /* zero */
+ else
+ bit = 6; /* denormalized number */
+ break;
+ case _FP_EXPMAX_S:
+ if (_FP_FRAC_ZEROP_1(SA))
+ bit = 4; /* infinity */
+ else if (_FP_FRAC_HIGH_RAW_S(SA) & _FP_QNANBIT_S)
+ bit = 2; /* quiet NAN */
+ else
+ bit = 0; /* signaling NAN */
+ break;
+ }
+ if (!SA_s)
+ bit++;
+ emu_set_CC(regs, ((__u32) val >> bit) & 1);
+ return 0;
+}
+
+static inline void emu_load_regd(int reg) {
+ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ return;
+ asm volatile( /* load reg from fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " ld 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4),"a" (&current->thread.fp_regs.fprs[reg].d)
+ : "1");
+}
+
+static inline void emu_load_rege(int reg) {
+ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ return;
+ asm volatile( /* load reg from fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " le 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
+ : "1");
+}
+
+static inline void emu_store_regd(int reg) {
+ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ return;
+ asm volatile( /* store reg to fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " std 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
+ : "1");
+}
+
+
+static inline void emu_store_rege(int reg) {
+ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ return;
+ asm volatile( /* store reg to fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " ste 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
+ : "1");
+}
+
+int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
+ int _fex = 0;
+ static const __u8 format_table[256] = {
+ [0x00] = 0x03,[0x01] = 0x03,[0x02] = 0x03,[0x03] = 0x03,
+ [0x04] = 0x0f,[0x05] = 0x0d,[0x06] = 0x0e,[0x07] = 0x0d,
+ [0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03,
+ [0x0c] = 0x0f,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06,
+ [0x10] = 0x02,[0x11] = 0x02,[0x12] = 0x02,[0x13] = 0x02,
+ [0x14] = 0x03,[0x15] = 0x02,[0x16] = 0x01,[0x17] = 0x03,
+ [0x18] = 0x02,[0x19] = 0x02,[0x1a] = 0x02,[0x1b] = 0x02,
+ [0x1c] = 0x02,[0x1d] = 0x02,[0x1e] = 0x05,[0x1f] = 0x05,
+ [0x40] = 0x01,[0x41] = 0x01,[0x42] = 0x01,[0x43] = 0x01,
+ [0x44] = 0x12,[0x45] = 0x0d,[0x46] = 0x11,[0x47] = 0x04,
+ [0x48] = 0x01,[0x49] = 0x01,[0x4a] = 0x01,[0x4b] = 0x01,
+ [0x4c] = 0x01,[0x4d] = 0x01,[0x53] = 0x06,[0x57] = 0x06,
+ [0x5b] = 0x05,[0x5f] = 0x05,[0x84] = 0x13,[0x8c] = 0x13,
+ [0x94] = 0x09,[0x95] = 0x08,[0x96] = 0x07,[0x98] = 0x0c,
+ [0x99] = 0x0b,[0x9a] = 0x0a
+ };
+ static const void *jump_table[256]= {
+ [0x00] = emu_lpebr,[0x01] = emu_lnebr,[0x02] = emu_ltebr,
+ [0x03] = emu_lcebr,[0x04] = emu_ldebr,[0x05] = emu_lxdbr,
+ [0x06] = emu_lxebr,[0x07] = emu_mxdbr,[0x08] = emu_kebr,
+ [0x09] = emu_cebr, [0x0a] = emu_aebr, [0x0b] = emu_sebr,
+ [0x0c] = emu_mdebr,[0x0d] = emu_debr, [0x0e] = emu_maebr,
+ [0x0f] = emu_msebr,[0x10] = emu_lpdbr,[0x11] = emu_lndbr,
+ [0x12] = emu_ltdbr,[0x13] = emu_lcdbr,[0x14] = emu_sqebr,
+ [0x15] = emu_sqdbr,[0x16] = emu_sqxbr,[0x17] = emu_meebr,
+ [0x18] = emu_kdbr, [0x19] = emu_cdbr, [0x1a] = emu_adbr,
+ [0x1b] = emu_sdbr, [0x1c] = emu_mdbr, [0x1d] = emu_ddbr,
+ [0x1e] = emu_madbr,[0x1f] = emu_msdbr,[0x40] = emu_lpxbr,
+ [0x41] = emu_lnxbr,[0x42] = emu_ltxbr,[0x43] = emu_lcxbr,
+ [0x44] = emu_ledbr,[0x45] = emu_ldxbr,[0x46] = emu_lexbr,
+ [0x47] = emu_fixbr,[0x48] = emu_kxbr, [0x49] = emu_cxbr,
+ [0x4a] = emu_axbr, [0x4b] = emu_sxbr, [0x4c] = emu_mxbr,
+ [0x4d] = emu_dxbr, [0x53] = emu_diebr,[0x57] = emu_fiebr,
+ [0x5b] = emu_didbr,[0x5f] = emu_fidbr,[0x84] = emu_sfpc,
+ [0x8c] = emu_efpc, [0x94] = emu_cefbr,[0x95] = emu_cdfbr,
+ [0x96] = emu_cxfbr,[0x98] = emu_cfebr,[0x99] = emu_cfdbr,
+ [0x9a] = emu_cfxbr
+ };
+
+ switch (format_table[opcode[1]]) {
+ case 1: /* RRE format, long double operation */
+ if (opcode[3] & 0x22)
+ return SIGILL;
+ emu_store_regd((opcode[3] >> 4) & 15);
+ emu_store_regd(((opcode[3] >> 4) & 15) + 2);
+ emu_store_regd(opcode[3] & 15);
+ emu_store_regd((opcode[3] & 15) + 2);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *,int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+ emu_load_regd(opcode[3] & 15);
+ emu_load_regd((opcode[3] & 15) + 2);
+ break;
+ case 2: /* RRE format, double operation */
+ emu_store_regd((opcode[3] >> 4) & 15);
+ emu_store_regd(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ emu_load_regd(opcode[3] & 15);
+ break;
+ case 3: /* RRE format, float operation */
+ emu_store_rege((opcode[3] >> 4) & 15);
+ emu_store_rege(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_rege((opcode[3] >> 4) & 15);
+ emu_load_rege(opcode[3] & 15);
+ break;
+ case 4: /* RRF format, long double operation */
+ if (opcode[3] & 0x22)
+ return SIGILL;
+ emu_store_regd((opcode[3] >> 4) & 15);
+ emu_store_regd(((opcode[3] >> 4) & 15) + 2);
+ emu_store_regd(opcode[3] & 15);
+ emu_store_regd((opcode[3] & 15) + 2);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+ emu_load_regd(opcode[3] & 15);
+ emu_load_regd((opcode[3] & 15) + 2);
+ break;
+ case 5: /* RRF format, double operation */
+ emu_store_regd((opcode[2] >> 4) & 15);
+ emu_store_regd((opcode[3] >> 4) & 15);
+ emu_store_regd(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+ emu_load_regd((opcode[2] >> 4) & 15);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ emu_load_regd(opcode[3] & 15);
+ break;
+ case 6: /* RRF format, float operation */
+ emu_store_rege((opcode[2] >> 4) & 15);
+ emu_store_rege((opcode[3] >> 4) & 15);
+ emu_store_rege(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+ emu_load_rege((opcode[2] >> 4) & 15);
+ emu_load_rege((opcode[3] >> 4) & 15);
+ emu_load_rege(opcode[3] & 15);
+ break;
+ case 7: /* RRE format, cxfbr instruction */
+ /* call the emulation function */
+ if (opcode[3] & 0x20)
+ return SIGILL;
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+ break;
+ case 8: /* RRE format, cdfbr instruction */
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ break;
+ case 9: /* RRE format, cefbr instruction */
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_rege((opcode[3] >> 4) & 15);
+ break;
+ case 10: /* RRF format, cfxbr instruction */
+ if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
+ /* mask of { 2,3,8-15 } is invalid */
+ return SIGILL;
+ if (opcode[3] & 2)
+ return SIGILL;
+ emu_store_regd(opcode[3] & 15);
+ emu_store_regd((opcode[3] & 15) + 2);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+ break;
+ case 11: /* RRF format, cfdbr instruction */
+ if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
+ /* mask of { 2,3,8-15 } is invalid */
+ return SIGILL;
+ emu_store_regd(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+ break;
+ case 12: /* RRF format, cfebr instruction */
+ if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
+ /* mask of { 2,3,8-15 } is invalid */
+ return SIGILL;
+ emu_store_rege(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+ break;
+ case 13: /* RRE format, ldxbr & mdxbr instruction */
+ /* double store but long double load */
+ if (opcode[3] & 0x20)
+ return SIGILL;
+ emu_store_regd((opcode[3] >> 4) & 15);
+ emu_store_regd(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+ break;
+ case 14: /* RRE format, ldxbr & mdxbr instruction */
+ /* float store but long double load */
+ if (opcode[3] & 0x20)
+ return SIGILL;
+ emu_store_rege((opcode[3] >> 4) & 15);
+ emu_store_rege(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ emu_load_regd(((opcode[3] >> 4) & 15) + 2);
+ break;
+ case 15: /* RRE format, ldebr & mdebr instruction */
+ /* float store but double load */
+ emu_store_rege((opcode[3] >> 4) & 15);
+ emu_store_rege(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ break;
+ case 16: /* RRE format, ldxbr instruction */
+ /* long double store but double load */
+ if (opcode[3] & 2)
+ return SIGILL;
+ emu_store_regd(opcode[3] & 15);
+ emu_store_regd((opcode[3] & 15) + 2);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_regd((opcode[3] >> 4) & 15);
+ break;
+ case 17: /* RRE format, ldxbr instruction */
+ /* long double store but float load */
+ if (opcode[3] & 2)
+ return SIGILL;
+ emu_store_regd(opcode[3] & 15);
+ emu_store_regd((opcode[3] & 15) + 2);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_rege((opcode[3] >> 4) & 15);
+ break;
+ case 18: /* RRE format, ledbr instruction */
+ /* double store but float load */
+ emu_store_regd(opcode[3] & 15);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ emu_load_rege((opcode[3] >> 4) & 15);
+ break;
+ case 19: /* RRE format, efpc & sfpc instruction */
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, int))
+ jump_table[opcode[1]])
+ (regs, opcode[3] >> 4, opcode[3] & 15);
+ break;
+ default: /* invalid operation */
+ return SIGILL;
+ }
+ if (_fex != 0) {
+ current->thread.fp_regs.fpc |= _fex;
+ if (current->thread.fp_regs.fpc & (_fex << 8))
+ return SIGFPE;
+ }
+ return 0;
+}
+
+static void* calc_addr(struct pt_regs *regs, int rx, int rb, int disp)
+{
+ addr_t addr;
+
+ rx &= 15;
+ rb &= 15;
+ addr = disp & 0xfff;
+ addr += (rx != 0) ? regs->gprs[rx] : 0; /* + index */
+ addr += (rb != 0) ? regs->gprs[rb] : 0; /* + base */
+ return (void*) addr;
+}
+
+int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
+ int _fex = 0;
+
+ static const __u8 format_table[256] = {
+ [0x04] = 0x06,[0x05] = 0x05,[0x06] = 0x07,[0x07] = 0x05,
+ [0x08] = 0x02,[0x09] = 0x02,[0x0a] = 0x02,[0x0b] = 0x02,
+ [0x0c] = 0x06,[0x0d] = 0x02,[0x0e] = 0x04,[0x0f] = 0x04,
+ [0x10] = 0x08,[0x11] = 0x09,[0x12] = 0x0a,[0x14] = 0x02,
+ [0x15] = 0x01,[0x17] = 0x02,[0x18] = 0x01,[0x19] = 0x01,
+ [0x1a] = 0x01,[0x1b] = 0x01,[0x1c] = 0x01,[0x1d] = 0x01,
+ [0x1e] = 0x03,[0x1f] = 0x03,
+ };
+ static const void *jump_table[]= {
+ [0x04] = emu_ldeb,[0x05] = emu_lxdb,[0x06] = emu_lxeb,
+ [0x07] = emu_mxdb,[0x08] = emu_keb, [0x09] = emu_ceb,
+ [0x0a] = emu_aeb, [0x0b] = emu_seb, [0x0c] = emu_mdeb,
+ [0x0d] = emu_deb, [0x0e] = emu_maeb,[0x0f] = emu_mseb,
+ [0x10] = emu_tceb,[0x11] = emu_tcdb,[0x12] = emu_tcxb,
+ [0x14] = emu_sqeb,[0x15] = emu_sqdb,[0x17] = emu_meeb,
+ [0x18] = emu_kdb, [0x19] = emu_cdb, [0x1a] = emu_adb,
+ [0x1b] = emu_sdb, [0x1c] = emu_mdb, [0x1d] = emu_ddb,
+ [0x1e] = emu_madb,[0x1f] = emu_msdb
+ };
+
+ switch (format_table[opcode[5]]) {
+ case 1: /* RXE format, double constant */ {
+ __u64 *dxb, temp;
+ __u32 opc;
+
+ emu_store_regd((opcode[1] >> 4) & 15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mathemu_copy_from_user(&temp, dxb, 8);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, double *))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, (double *) &temp);
+ emu_load_regd((opcode[1] >> 4) & 15);
+ break;
+ }
+ case 2: /* RXE format, float constant */ {
+ __u32 *dxb, temp;
+ __u32 opc;
+
+ emu_store_rege((opcode[1] >> 4) & 15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mathemu_get_user(temp, dxb);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, float *))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, (float *) &temp);
+ emu_load_rege((opcode[1] >> 4) & 15);
+ break;
+ }
+ case 3: /* RXF format, double constant */ {
+ __u64 *dxb, temp;
+ __u32 opc;
+
+ emu_store_regd((opcode[1] >> 4) & 15);
+ emu_store_regd((opcode[4] >> 4) & 15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mathemu_copy_from_user(&temp, dxb, 8);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, double *, int))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, (double *) &temp, opcode[4] >> 4);
+ emu_load_regd((opcode[1] >> 4) & 15);
+ break;
+ }
+ case 4: /* RXF format, float constant */ {
+ __u32 *dxb, temp;
+ __u32 opc;
+
+ emu_store_rege((opcode[1] >> 4) & 15);
+ emu_store_rege((opcode[4] >> 4) & 15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mathemu_get_user(temp, dxb);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, float *, int))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, (float *) &temp, opcode[4] >> 4);
+ emu_load_rege((opcode[4] >> 4) & 15);
+ break;
+ }
+ case 5: /* RXE format, double constant */
+ /* store double and load long double */
+ {
+ __u64 *dxb, temp;
+ __u32 opc;
+ if ((opcode[1] >> 4) & 0x20)
+ return SIGILL;
+ emu_store_regd((opcode[1] >> 4) & 15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mathemu_copy_from_user(&temp, dxb, 8);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, double *))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, (double *) &temp);
+ emu_load_regd((opcode[1] >> 4) & 15);
+ emu_load_regd(((opcode[1] >> 4) & 15) + 2);
+ break;
+ }
+ case 6: /* RXE format, float constant */
+ /* store float and load double */
+ {
+ __u32 *dxb, temp;
+ __u32 opc;
+ emu_store_rege((opcode[1] >> 4) & 15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mathemu_get_user(temp, dxb);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, float *))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, (float *) &temp);
+ emu_load_regd((opcode[1] >> 4) & 15);
+ break;
+ }
+ case 7: /* RXE format, float constant */
+ /* store float and load long double */
+ {
+ __u32 *dxb, temp;
+ __u32 opc;
+ if ((opcode[1] >> 4) & 0x20)
+ return SIGILL;
+ emu_store_rege((opcode[1] >> 4) & 15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mathemu_get_user(temp, dxb);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, float *))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, (float *) &temp);
+ emu_load_regd((opcode[1] >> 4) & 15);
+ emu_load_regd(((opcode[1] >> 4) & 15) + 2);
+ break;
+ }
+ case 8: /* RXE format, RX address used as int value */ {
+ __u64 dxb;
+ __u32 opc;
+
+ emu_store_rege((opcode[1] >> 4) & 15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, long))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, dxb);
+ break;
+ }
+ case 9: /* RXE format, RX address used as int value */ {
+ __u64 dxb;
+ __u32 opc;
+
+ emu_store_regd((opcode[1] >> 4) & 15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, long))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, dxb);
+ break;
+ }
+ case 10: /* RXE format, RX address used as int value */ {
+ __u64 dxb;
+ __u32 opc;
+
+ if ((opcode[1] >> 4) & 2)
+ return SIGILL;
+ emu_store_regd((opcode[1] >> 4) & 15);
+ emu_store_regd(((opcode[1] >> 4) & 15) + 2);
+ opc = *((__u32 *) opcode);
+ dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ /* call the emulation function */
+ _fex = ((int (*)(struct pt_regs *, int, long))
+ jump_table[opcode[5]])
+ (regs, opcode[1] >> 4, dxb);
+ break;
+ }
+ default: /* invalid operation */
+ return SIGILL;
+ }
+ if (_fex != 0) {
+ current->thread.fp_regs.fpc |= _fex;
+ if (current->thread.fp_regs.fpc & (_fex << 8))
+ return SIGFPE;
+ }
+ return 0;
+}
+
+/*
+ * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
+ */
+int math_emu_ldr(__u8 *opcode) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ __u16 opc = *((__u16 *) opcode);
+
+ if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
+ /* we got an exception therfore ry can't be in {0,2,4,6} */
+ asm volatile( /* load rx from fp_regs.fprs[ry] */
+ " bras 1,0f\n"
+ " ld 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (opc & 0xf0), "a" (&fp_regs->fprs[opc & 0xf].d)
+ : "1");
+ } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
+ asm volatile ( /* store ry to fp_regs.fprs[rx] */
+ " bras 1,0f\n"
+ " std 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" ((opc & 0xf) << 4),
+ "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d)
+ : "1");
+ } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+ fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
+ return 0;
+}
+
+/*
+ * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
+ */
+int math_emu_ler(__u8 *opcode) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ __u16 opc = *((__u16 *) opcode);
+
+ if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
+ /* we got an exception therfore ry can't be in {0,2,4,6} */
+ asm volatile( /* load rx from fp_regs.fprs[ry] */
+ " bras 1,0f\n"
+ " le 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (opc & 0xf0), "a" (&fp_regs->fprs[opc & 0xf].f)
+ : "1");
+ } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
+ asm volatile( /* store ry to fp_regs.fprs[rx] */
+ " bras 1,0f\n"
+ " ste 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" ((opc & 0xf) << 4),
+ "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f)
+ : "1");
+ } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+ fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
+ return 0;
+}
+
+/*
+ * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+int math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ __u32 opc = *((__u32 *) opcode);
+ __u64 *dxb;
+
+ dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mathemu_copy_from_user(&fp_regs->fprs[(opc >> 20) & 0xf].d, dxb, 8);
+ return 0;
+}
+
+/*
+ * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+int math_emu_le(__u8 *opcode, struct pt_regs * regs) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ __u32 opc = *((__u32 *) opcode);
+ __u32 *mem, *dxb;
+
+ dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f);
+ mathemu_get_user(mem[0], dxb);
+ return 0;
+}
+
+/*
+ * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+int math_emu_std(__u8 *opcode, struct pt_regs * regs) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ __u32 opc = *((__u32 *) opcode);
+ __u64 *dxb;
+
+ dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mathemu_copy_to_user(dxb, &fp_regs->fprs[(opc >> 20) & 0xf].d, 8);
+ return 0;
+}
+
+/*
+ * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+int math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
+ s390_fp_regs *fp_regs = &current->thread.fp_regs;
+ __u32 opc = *((__u32 *) opcode);
+ __u32 *mem, *dxb;
+
+ dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
+ mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f);
+ mathemu_put_user(mem[0], dxb);
+ return 0;
+}
+
+/*
+ * Emulate LFPC D(B)
+ */
+int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
+ __u32 opc = *((__u32 *) opcode);
+ __u32 *dxb, temp;
+
+ dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc);
+ mathemu_get_user(temp, dxb);
+ if ((temp & ~FPC_VALID_MASK) != 0)
+ return SIGILL;
+ current->thread.fp_regs.fpc = temp;
+ return 0;
+}
+
+/*
+ * Emulate STFPC D(B)
+ */
+int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
+ __u32 opc = *((__u32 *) opcode);
+ __u32 *dxb;
+
+ dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc);
+ mathemu_put_user(current->thread.fp_regs.fpc, dxb);
+ return 0;
+}
+
+/*
+ * Emulate SRNM D(B)
+ */
+int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
+ __u32 opc = *((__u32 *) opcode);
+ __u32 temp;
+
+ temp = calc_addr(regs, 0, opc>>12, opc);
+ current->thread.fp_regs.fpc &= ~3;
+ current->thread.fp_regs.fpc |= (temp & 3);
+ return 0;
+}
+
+/* broken compiler ... */
+long long
+__negdi2 (long long u)
+{
+
+ union lll {
+ long long ll;
+ long s[2];
+ };
+
+ union lll w,uu;
+
+ uu.ll = u;
+
+ w.s[1] = -uu.s[1];
+ w.s[0] = -uu.s[0] - ((int) w.s[1] != 0);
+
+ return w.ll;
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/Makefile
new file mode 100644
index 0000000000..66401930f8
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the linux s390-specific parts of the memory manager.
+#
+
+obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o
+obj-$(CONFIG_CMM) += cmm.o
+
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/cmm.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/cmm.c
new file mode 100644
index 0000000000..413c240cbc
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/cmm.c
@@ -0,0 +1,479 @@
+/*
+ * arch/s390/mm/cmm.c
+ *
+ * S390 version
+ * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * Collaborative memory management interface.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/sysctl.h>
+#include <linux/ctype.h>
+#include <linux/swap.h>
+#include <linux/kthread.h>
+#include <linux/oom.h>
+
+#include <asm/pgalloc.h>
+#include <asm/uaccess.h>
+#include <asm/diag.h>
+
+static char *sender = "VMRMSVM";
+module_param(sender, charp, 0400);
+MODULE_PARM_DESC(sender,
+ "Guest name that may send SMSG messages (default VMRMSVM)");
+
+#include "../../../drivers/s390/net/smsgiucv.h"
+
+#define CMM_NR_PAGES ((PAGE_SIZE / sizeof(unsigned long)) - 2)
+
+struct cmm_page_array {
+ struct cmm_page_array *next;
+ unsigned long index;
+ unsigned long pages[CMM_NR_PAGES];
+};
+
+static long cmm_pages;
+static long cmm_timed_pages;
+static volatile long cmm_pages_target;
+static volatile long cmm_timed_pages_target;
+static long cmm_timeout_pages;
+static long cmm_timeout_seconds;
+
+static struct cmm_page_array *cmm_page_list;
+static struct cmm_page_array *cmm_timed_page_list;
+static DEFINE_SPINLOCK(cmm_lock);
+
+static struct task_struct *cmm_thread_ptr;
+static wait_queue_head_t cmm_thread_wait;
+static struct timer_list cmm_timer;
+
+static void cmm_timer_fn(unsigned long);
+static void cmm_set_timer(void);
+
+static long
+cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list)
+{
+ struct cmm_page_array *pa, *npa;
+ unsigned long addr;
+
+ while (nr) {
+ addr = __get_free_page(GFP_NOIO);
+ if (!addr)
+ break;
+ spin_lock(&cmm_lock);
+ pa = *list;
+ if (!pa || pa->index >= CMM_NR_PAGES) {
+ /* Need a new page for the page list. */
+ spin_unlock(&cmm_lock);
+ npa = (struct cmm_page_array *)
+ __get_free_page(GFP_NOIO);
+ if (!npa) {
+ free_page(addr);
+ break;
+ }
+ spin_lock(&cmm_lock);
+ pa = *list;
+ if (!pa || pa->index >= CMM_NR_PAGES) {
+ npa->next = pa;
+ npa->index = 0;
+ pa = npa;
+ *list = pa;
+ } else
+ free_page((unsigned long) npa);
+ }
+ diag10(addr);
+ pa->pages[pa->index++] = addr;
+ (*counter)++;
+ spin_unlock(&cmm_lock);
+ nr--;
+ }
+ return nr;
+}
+
+static long
+cmm_free_pages(long nr, long *counter, struct cmm_page_array **list)
+{
+ struct cmm_page_array *pa;
+ unsigned long addr;
+
+ spin_lock(&cmm_lock);
+ pa = *list;
+ while (nr) {
+ if (!pa || pa->index <= 0)
+ break;
+ addr = pa->pages[--pa->index];
+ if (pa->index == 0) {
+ pa = pa->next;
+ free_page((unsigned long) *list);
+ *list = pa;
+ }
+ free_page(addr);
+ (*counter)--;
+ nr--;
+ }
+ spin_unlock(&cmm_lock);
+ return nr;
+}
+
+static int cmm_oom_notify(struct notifier_block *self,
+ unsigned long dummy, void *parm)
+{
+ unsigned long *freed = parm;
+ long nr = 256;
+
+ nr = cmm_free_pages(nr, &cmm_timed_pages, &cmm_timed_page_list);
+ if (nr > 0)
+ nr = cmm_free_pages(nr, &cmm_pages, &cmm_page_list);
+ cmm_pages_target = cmm_pages;
+ cmm_timed_pages_target = cmm_timed_pages;
+ *freed += 256 - nr;
+ return NOTIFY_OK;
+}
+
+static struct notifier_block cmm_oom_nb = {
+ .notifier_call = cmm_oom_notify
+};
+
+static int
+cmm_thread(void *dummy)
+{
+ int rc;
+
+ while (1) {
+ rc = wait_event_interruptible(cmm_thread_wait,
+ (cmm_pages != cmm_pages_target ||
+ cmm_timed_pages != cmm_timed_pages_target ||
+ kthread_should_stop()));
+ if (kthread_should_stop() || rc == -ERESTARTSYS) {
+ cmm_pages_target = cmm_pages;
+ cmm_timed_pages_target = cmm_timed_pages;
+ break;
+ }
+ if (cmm_pages_target > cmm_pages) {
+ if (cmm_alloc_pages(1, &cmm_pages, &cmm_page_list))
+ cmm_pages_target = cmm_pages;
+ } else if (cmm_pages_target < cmm_pages) {
+ cmm_free_pages(1, &cmm_pages, &cmm_page_list);
+ }
+ if (cmm_timed_pages_target > cmm_timed_pages) {
+ if (cmm_alloc_pages(1, &cmm_timed_pages,
+ &cmm_timed_page_list))
+ cmm_timed_pages_target = cmm_timed_pages;
+ } else if (cmm_timed_pages_target < cmm_timed_pages) {
+ cmm_free_pages(1, &cmm_timed_pages,
+ &cmm_timed_page_list);
+ }
+ if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer))
+ cmm_set_timer();
+ }
+ return 0;
+}
+
+static void
+cmm_kick_thread(void)
+{
+ wake_up(&cmm_thread_wait);
+}
+
+static void
+cmm_set_timer(void)
+{
+ if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) {
+ if (timer_pending(&cmm_timer))
+ del_timer(&cmm_timer);
+ return;
+ }
+ if (timer_pending(&cmm_timer)) {
+ if (mod_timer(&cmm_timer, jiffies + cmm_timeout_seconds*HZ))
+ return;
+ }
+ cmm_timer.function = cmm_timer_fn;
+ cmm_timer.data = 0;
+ cmm_timer.expires = jiffies + cmm_timeout_seconds*HZ;
+ add_timer(&cmm_timer);
+}
+
+static void
+cmm_timer_fn(unsigned long ignored)
+{
+ long nr;
+
+ nr = cmm_timed_pages_target - cmm_timeout_pages;
+ if (nr < 0)
+ cmm_timed_pages_target = 0;
+ else
+ cmm_timed_pages_target = nr;
+ cmm_kick_thread();
+ cmm_set_timer();
+}
+
+void
+cmm_set_pages(long nr)
+{
+ cmm_pages_target = nr;
+ cmm_kick_thread();
+}
+
+long
+cmm_get_pages(void)
+{
+ return cmm_pages;
+}
+
+void
+cmm_add_timed_pages(long nr)
+{
+ cmm_timed_pages_target += nr;
+ cmm_kick_thread();
+}
+
+long
+cmm_get_timed_pages(void)
+{
+ return cmm_timed_pages;
+}
+
+void
+cmm_set_timeout(long nr, long seconds)
+{
+ cmm_timeout_pages = nr;
+ cmm_timeout_seconds = seconds;
+ cmm_set_timer();
+}
+
+static int
+cmm_skip_blanks(char *cp, char **endp)
+{
+ char *str;
+
+ for (str = cp; *str == ' ' || *str == '\t'; str++);
+ *endp = str;
+ return str != cp;
+}
+
+#ifdef CONFIG_CMM_PROC
+
+static struct ctl_table cmm_table[];
+
+static int
+cmm_pages_handler(ctl_table *ctl, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ char buf[16], *p;
+ long nr;
+ int len;
+
+ if (!*lenp || (*ppos && !write)) {
+ *lenp = 0;
+ return 0;
+ }
+
+ if (write) {
+ len = *lenp;
+ if (copy_from_user(buf, buffer,
+ len > sizeof(buf) ? sizeof(buf) : len))
+ return -EFAULT;
+ buf[sizeof(buf) - 1] = '\0';
+ cmm_skip_blanks(buf, &p);
+ nr = simple_strtoul(p, &p, 0);
+ if (ctl == &cmm_table[0])
+ cmm_set_pages(nr);
+ else
+ cmm_add_timed_pages(nr);
+ } else {
+ if (ctl == &cmm_table[0])
+ nr = cmm_get_pages();
+ else
+ nr = cmm_get_timed_pages();
+ len = sprintf(buf, "%ld\n", nr);
+ if (len > *lenp)
+ len = *lenp;
+ if (copy_to_user(buffer, buf, len))
+ return -EFAULT;
+ }
+ *lenp = len;
+ *ppos += len;
+ return 0;
+}
+
+static int
+cmm_timeout_handler(ctl_table *ctl, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ char buf[64], *p;
+ long nr, seconds;
+ int len;
+
+ if (!*lenp || (*ppos && !write)) {
+ *lenp = 0;
+ return 0;
+ }
+
+ if (write) {
+ len = *lenp;
+ if (copy_from_user(buf, buffer,
+ len > sizeof(buf) ? sizeof(buf) : len))
+ return -EFAULT;
+ buf[sizeof(buf) - 1] = '\0';
+ cmm_skip_blanks(buf, &p);
+ nr = simple_strtoul(p, &p, 0);
+ cmm_skip_blanks(p, &p);
+ seconds = simple_strtoul(p, &p, 0);
+ cmm_set_timeout(nr, seconds);
+ } else {
+ len = sprintf(buf, "%ld %ld\n",
+ cmm_timeout_pages, cmm_timeout_seconds);
+ if (len > *lenp)
+ len = *lenp;
+ if (copy_to_user(buffer, buf, len))
+ return -EFAULT;
+ }
+ *lenp = len;
+ *ppos += len;
+ return 0;
+}
+
+static struct ctl_table cmm_table[] = {
+ {
+ .procname = "cmm_pages",
+ .mode = 0644,
+ .proc_handler = &cmm_pages_handler,
+ },
+ {
+ .procname = "cmm_timed_pages",
+ .mode = 0644,
+ .proc_handler = &cmm_pages_handler,
+ },
+ {
+ .procname = "cmm_timeout",
+ .mode = 0644,
+ .proc_handler = &cmm_timeout_handler,
+ },
+ { .ctl_name = 0 }
+};
+
+static struct ctl_table cmm_dir_table[] = {
+ {
+ .ctl_name = CTL_VM,
+ .procname = "vm",
+ .maxlen = 0,
+ .mode = 0555,
+ .child = cmm_table,
+ },
+ { .ctl_name = 0 }
+};
+#endif
+
+#ifdef CONFIG_CMM_IUCV
+#define SMSG_PREFIX "CMM"
+static void
+cmm_smsg_target(char *from, char *msg)
+{
+ long nr, seconds;
+
+ if (strlen(sender) > 0 && strcmp(from, sender) != 0)
+ return;
+ if (!cmm_skip_blanks(msg + strlen(SMSG_PREFIX), &msg))
+ return;
+ if (strncmp(msg, "SHRINK", 6) == 0) {
+ if (!cmm_skip_blanks(msg + 6, &msg))
+ return;
+ nr = simple_strtoul(msg, &msg, 0);
+ cmm_skip_blanks(msg, &msg);
+ if (*msg == '\0')
+ cmm_set_pages(nr);
+ } else if (strncmp(msg, "RELEASE", 7) == 0) {
+ if (!cmm_skip_blanks(msg + 7, &msg))
+ return;
+ nr = simple_strtoul(msg, &msg, 0);
+ cmm_skip_blanks(msg, &msg);
+ if (*msg == '\0')
+ cmm_add_timed_pages(nr);
+ } else if (strncmp(msg, "REUSE", 5) == 0) {
+ if (!cmm_skip_blanks(msg + 5, &msg))
+ return;
+ nr = simple_strtoul(msg, &msg, 0);
+ if (!cmm_skip_blanks(msg, &msg))
+ return;
+ seconds = simple_strtoul(msg, &msg, 0);
+ cmm_skip_blanks(msg, &msg);
+ if (*msg == '\0')
+ cmm_set_timeout(nr, seconds);
+ }
+}
+#endif
+
+static struct ctl_table_header *cmm_sysctl_header;
+
+static int
+cmm_init (void)
+{
+ int rc = -ENOMEM;
+
+#ifdef CONFIG_CMM_PROC
+ cmm_sysctl_header = register_sysctl_table(cmm_dir_table);
+ if (!cmm_sysctl_header)
+ goto out;
+#endif
+#ifdef CONFIG_CMM_IUCV
+ rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
+ if (rc < 0)
+ goto out_smsg;
+#endif
+ rc = register_oom_notifier(&cmm_oom_nb);
+ if (rc < 0)
+ goto out_oom_notify;
+ init_waitqueue_head(&cmm_thread_wait);
+ init_timer(&cmm_timer);
+ cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread");
+ rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
+ if (!rc)
+ goto out;
+ /*
+ * kthread_create failed. undo all the stuff from above again.
+ */
+ unregister_oom_notifier(&cmm_oom_nb);
+
+out_oom_notify:
+#ifdef CONFIG_CMM_IUCV
+ smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
+out_smsg:
+#endif
+#ifdef CONFIG_CMM_PROC
+ unregister_sysctl_table(cmm_sysctl_header);
+#endif
+out:
+ return rc;
+}
+
+static void
+cmm_exit(void)
+{
+ kthread_stop(cmm_thread_ptr);
+ unregister_oom_notifier(&cmm_oom_nb);
+ cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
+ cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
+#ifdef CONFIG_CMM_PROC
+ unregister_sysctl_table(cmm_sysctl_header);
+#endif
+#ifdef CONFIG_CMM_IUCV
+ smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
+#endif
+}
+
+module_init(cmm_init);
+module_exit(cmm_exit);
+
+EXPORT_SYMBOL(cmm_set_pages);
+EXPORT_SYMBOL(cmm_get_pages);
+EXPORT_SYMBOL(cmm_add_timed_pages);
+EXPORT_SYMBOL(cmm_get_timed_pages);
+EXPORT_SYMBOL(cmm_set_timeout);
+
+MODULE_LICENSE("GPL");
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/extmem.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/extmem.c
new file mode 100644
index 0000000000..880b0ebf89
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/extmem.c
@@ -0,0 +1,589 @@
+/*
+ * File...........: arch/s390/mm/extmem.c
+ * Author(s)......: Carsten Otte <cotte@de.ibm.com>
+ * Rob M van der Heij <rvdheij@nl.ibm.com>
+ * Steven Shultz <shultzss@us.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation 2002-2004
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/bootmem.h>
+#include <linux/ctype.h>
+#include <linux/ioport.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/ebcdic.h>
+#include <asm/errno.h>
+#include <asm/extmem.h>
+#include <asm/cpcmd.h>
+#include <asm/setup.h>
+
+#define DCSS_DEBUG /* Debug messages on/off */
+
+#define DCSS_NAME "extmem"
+#ifdef DCSS_DEBUG
+#define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSS_NAME " debug:" x)
+#else
+#define PRINT_DEBUG(x...) do {} while (0)
+#endif
+#define PRINT_INFO(x...) printk(KERN_INFO DCSS_NAME " info:" x)
+#define PRINT_WARN(x...) printk(KERN_WARNING DCSS_NAME " warning:" x)
+#define PRINT_ERR(x...) printk(KERN_ERR DCSS_NAME " error:" x)
+
+
+#define DCSS_LOADSHR 0x00
+#define DCSS_LOADNSR 0x04
+#define DCSS_PURGESEG 0x08
+#define DCSS_FINDSEG 0x0c
+#define DCSS_LOADNOLY 0x10
+#define DCSS_SEGEXT 0x18
+#define DCSS_FINDSEGA 0x0c
+
+struct qrange {
+ unsigned int start; // 3byte start address, 1 byte type
+ unsigned int end; // 3byte end address, 1 byte reserved
+};
+
+struct qout64 {
+ int segstart;
+ int segend;
+ int segcnt;
+ int segrcnt;
+ struct qrange range[6];
+};
+
+struct qin64 {
+ char qopcode;
+ char rsrv1[3];
+ char qrcode;
+ char rsrv2[3];
+ char qname[8];
+ unsigned int qoutptr;
+ short int qoutlen;
+};
+
+struct dcss_segment {
+ struct list_head list;
+ char dcss_name[8];
+ char res_name[15];
+ unsigned long start_addr;
+ unsigned long end;
+ atomic_t ref_count;
+ int do_nonshared;
+ unsigned int vm_segtype;
+ struct qrange range[6];
+ int segcnt;
+ struct resource *res;
+};
+
+static DEFINE_MUTEX(dcss_lock);
+static LIST_HEAD(dcss_list);
+static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
+ "EW/EN-MIXED" };
+
+/*
+ * Create the 8 bytes, ebcdic VM segment name from
+ * an ascii name.
+ */
+static void
+dcss_mkname(char *name, char *dcss_name)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ if (name[i] == '\0')
+ break;
+ dcss_name[i] = toupper(name[i]);
+ };
+ for (; i < 8; i++)
+ dcss_name[i] = ' ';
+ ASCEBC(dcss_name, 8);
+}
+
+
+/*
+ * search all segments in dcss_list, and return the one
+ * namend *name. If not found, return NULL.
+ */
+static struct dcss_segment *
+segment_by_name (char *name)
+{
+ char dcss_name[9];
+ struct list_head *l;
+ struct dcss_segment *tmp, *retval = NULL;
+
+ BUG_ON(!mutex_is_locked(&dcss_lock));
+ dcss_mkname (name, dcss_name);
+ list_for_each (l, &dcss_list) {
+ tmp = list_entry (l, struct dcss_segment, list);
+ if (memcmp(tmp->dcss_name, dcss_name, 8) == 0) {
+ retval = tmp;
+ break;
+ }
+ }
+ return retval;
+}
+
+
+/*
+ * Perform a function on a dcss segment.
+ */
+static inline int
+dcss_diag (__u8 func, void *parameter,
+ unsigned long *ret1, unsigned long *ret2)
+{
+ unsigned long rx, ry;
+ int rc;
+
+ rx = (unsigned long) parameter;
+ ry = (unsigned long) func;
+ asm volatile(
+#ifdef CONFIG_64BIT
+ " sam31\n"
+ " diag %0,%1,0x64\n"
+ " sam64\n"
+#else
+ " diag %0,%1,0x64\n"
+#endif
+ " ipm %2\n"
+ " srl %2,28\n"
+ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
+ *ret1 = rx;
+ *ret2 = ry;
+ return rc;
+}
+
+static inline int
+dcss_diag_translate_rc (int vm_rc) {
+ if (vm_rc == 44)
+ return -ENOENT;
+ return -EIO;
+}
+
+
+/* do a diag to get info about a segment.
+ * fills start_address, end and vm_segtype fields
+ */
+static int
+query_segment_type (struct dcss_segment *seg)
+{
+ struct qin64 *qin = kmalloc (sizeof(struct qin64), GFP_DMA);
+ struct qout64 *qout = kmalloc (sizeof(struct qout64), GFP_DMA);
+
+ int diag_cc, rc, i;
+ unsigned long dummy, vmrc;
+
+ if ((qin == NULL) || (qout == NULL)) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
+
+ /* initialize diag input parameters */
+ qin->qopcode = DCSS_FINDSEGA;
+ qin->qoutptr = (unsigned long) qout;
+ qin->qoutlen = sizeof(struct qout64);
+ memcpy (qin->qname, seg->dcss_name, 8);
+
+ diag_cc = dcss_diag (DCSS_SEGEXT, qin, &dummy, &vmrc);
+
+ if (diag_cc > 1) {
+ PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc);
+ rc = dcss_diag_translate_rc (vmrc);
+ goto out_free;
+ }
+
+ if (qout->segcnt > 6) {
+ rc = -ENOTSUPP;
+ goto out_free;
+ }
+
+ if (qout->segcnt == 1) {
+ seg->vm_segtype = qout->range[0].start & 0xff;
+ } else {
+ /* multi-part segment. only one type supported here:
+ - all parts are contiguous
+ - all parts are either EW or EN type
+ - maximum 6 parts allowed */
+ unsigned long start = qout->segstart >> PAGE_SHIFT;
+ for (i=0; i<qout->segcnt; i++) {
+ if (((qout->range[i].start & 0xff) != SEG_TYPE_EW) &&
+ ((qout->range[i].start & 0xff) != SEG_TYPE_EN)) {
+ rc = -ENOTSUPP;
+ goto out_free;
+ }
+ if (start != qout->range[i].start >> PAGE_SHIFT) {
+ rc = -ENOTSUPP;
+ goto out_free;
+ }
+ start = (qout->range[i].end >> PAGE_SHIFT) + 1;
+ }
+ seg->vm_segtype = SEG_TYPE_EWEN;
+ }
+
+ /* analyze diag output and update seg */
+ seg->start_addr = qout->segstart;
+ seg->end = qout->segend;
+
+ memcpy (seg->range, qout->range, 6*sizeof(struct qrange));
+ seg->segcnt = qout->segcnt;
+
+ rc = 0;
+
+ out_free:
+ kfree(qin);
+ kfree(qout);
+ return rc;
+}
+
+/*
+ * get info about a segment
+ * possible return values:
+ * -ENOSYS : we are not running on VM
+ * -EIO : could not perform query diagnose
+ * -ENOENT : no such segment
+ * -ENOTSUPP: multi-part segment cannot be used with linux
+ * -ENOSPC : segment cannot be used (overlaps with storage)
+ * -ENOMEM : out of memory
+ * 0 .. 6 : type of segment as defined in include/asm-s390/extmem.h
+ */
+int
+segment_type (char* name)
+{
+ int rc;
+ struct dcss_segment seg;
+
+ if (!MACHINE_IS_VM)
+ return -ENOSYS;
+
+ dcss_mkname(name, seg.dcss_name);
+ rc = query_segment_type (&seg);
+ if (rc < 0)
+ return rc;
+ return seg.vm_segtype;
+}
+
+/*
+ * real segment loading function, called from segment_load
+ */
+static int
+__segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end)
+{
+ struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment),
+ GFP_DMA);
+ int dcss_command, rc, diag_cc;
+
+ if (seg == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ dcss_mkname (name, seg->dcss_name);
+ rc = query_segment_type (seg);
+ if (rc < 0)
+ goto out_free;
+
+ rc = add_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+
+ switch (rc) {
+ case 0:
+ break;
+ case -ENOSPC:
+ PRINT_WARN("segment_load: not loading segment %s - overlaps "
+ "storage/segment\n", name);
+ goto out_free;
+ case -ERANGE:
+ PRINT_WARN("segment_load: not loading segment %s - exceeds "
+ "kernel mapping range\n", name);
+ goto out_free;
+ default:
+ PRINT_WARN("segment_load: not loading segment %s (rc: %d)\n",
+ name, rc);
+ goto out_free;
+ }
+
+ seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+ if (seg->res == NULL) {
+ rc = -ENOMEM;
+ goto out_shared;
+ }
+ seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+ seg->res->start = seg->start_addr;
+ seg->res->end = seg->end;
+ memcpy(&seg->res_name, seg->dcss_name, 8);
+ EBCASC(seg->res_name, 8);
+ seg->res_name[8] = '\0';
+ strncat(seg->res_name, " (DCSS)", 7);
+ seg->res->name = seg->res_name;
+ rc = seg->vm_segtype;
+ if (rc == SEG_TYPE_SC ||
+ ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
+ seg->res->flags |= IORESOURCE_READONLY;
+ if (request_resource(&iomem_resource, seg->res)) {
+ rc = -EBUSY;
+ kfree(seg->res);
+ goto out_shared;
+ }
+
+ if (do_nonshared)
+ dcss_command = DCSS_LOADNSR;
+ else
+ dcss_command = DCSS_LOADNOLY;
+
+ diag_cc = dcss_diag(dcss_command, seg->dcss_name,
+ &seg->start_addr, &seg->end);
+ if (diag_cc > 1) {
+ PRINT_WARN ("segment_load: could not load segment %s - "
+ "diag returned error (%ld)\n",name,seg->end);
+ rc = dcss_diag_translate_rc (seg->end);
+ dcss_diag(DCSS_PURGESEG, seg->dcss_name,
+ &seg->start_addr, &seg->end);
+ goto out_resource;
+ }
+ seg->do_nonshared = do_nonshared;
+ atomic_set(&seg->ref_count, 1);
+ list_add(&seg->list, &dcss_list);
+ *addr = seg->start_addr;
+ *end = seg->end;
+ if (do_nonshared)
+ PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
+ "type %s in non-shared mode\n", name,
+ (void*)seg->start_addr, (void*)seg->end,
+ segtype_string[seg->vm_segtype]);
+ else {
+ PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
+ "type %s in shared mode\n", name,
+ (void*)seg->start_addr, (void*)seg->end,
+ segtype_string[seg->vm_segtype]);
+ }
+ goto out;
+ out_resource:
+ release_resource(seg->res);
+ kfree(seg->res);
+ out_shared:
+ remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+ out_free:
+ kfree(seg);
+ out:
+ return rc;
+}
+
+/*
+ * this function loads a DCSS segment
+ * name : name of the DCSS
+ * do_nonshared : 0 indicates that the dcss should be shared with other linux images
+ * 1 indicates that the dcss should be exclusive for this linux image
+ * addr : will be filled with start address of the segment
+ * end : will be filled with end address of the segment
+ * return values:
+ * -ENOSYS : we are not running on VM
+ * -EIO : could not perform query or load diagnose
+ * -ENOENT : no such segment
+ * -ENOTSUPP: multi-part segment cannot be used with linux
+ * -ENOSPC : segment cannot be used (overlaps with storage)
+ * -EBUSY : segment can temporarily not be used (overlaps with dcss)
+ * -ERANGE : segment cannot be used (exceeds kernel mapping range)
+ * -EPERM : segment is currently loaded with incompatible permissions
+ * -ENOMEM : out of memory
+ * 0 .. 6 : type of segment as defined in include/asm-s390/extmem.h
+ */
+int
+segment_load (char *name, int do_nonshared, unsigned long *addr,
+ unsigned long *end)
+{
+ struct dcss_segment *seg;
+ int rc;
+
+ if (!MACHINE_IS_VM)
+ return -ENOSYS;
+
+ mutex_lock(&dcss_lock);
+ seg = segment_by_name (name);
+ if (seg == NULL)
+ rc = __segment_load (name, do_nonshared, addr, end);
+ else {
+ if (do_nonshared == seg->do_nonshared) {
+ atomic_inc(&seg->ref_count);
+ *addr = seg->start_addr;
+ *end = seg->end;
+ rc = seg->vm_segtype;
+ } else {
+ *addr = *end = 0;
+ rc = -EPERM;
+ }
+ }
+ mutex_unlock(&dcss_lock);
+ return rc;
+}
+
+/*
+ * this function modifies the shared state of a DCSS segment. note that
+ * name : name of the DCSS
+ * do_nonshared : 0 indicates that the dcss should be shared with other linux images
+ * 1 indicates that the dcss should be exclusive for this linux image
+ * return values:
+ * -EIO : could not perform load diagnose (segment gone!)
+ * -ENOENT : no such segment (segment gone!)
+ * -EAGAIN : segment is in use by other exploiters, try later
+ * -EINVAL : no segment with the given name is currently loaded - name invalid
+ * -EBUSY : segment can temporarily not be used (overlaps with dcss)
+ * 0 : operation succeeded
+ */
+int
+segment_modify_shared (char *name, int do_nonshared)
+{
+ struct dcss_segment *seg;
+ unsigned long dummy;
+ int dcss_command, rc, diag_cc;
+
+ mutex_lock(&dcss_lock);
+ seg = segment_by_name (name);
+ if (seg == NULL) {
+ rc = -EINVAL;
+ goto out_unlock;
+ }
+ if (do_nonshared == seg->do_nonshared) {
+ PRINT_INFO ("segment_modify_shared: not reloading segment %s"
+ " - already in requested mode\n",name);
+ rc = 0;
+ goto out_unlock;
+ }
+ if (atomic_read (&seg->ref_count) != 1) {
+ PRINT_WARN ("segment_modify_shared: not reloading segment %s - "
+ "segment is in use by other driver(s)\n",name);
+ rc = -EAGAIN;
+ goto out_unlock;
+ }
+ release_resource(seg->res);
+ if (do_nonshared) {
+ dcss_command = DCSS_LOADNSR;
+ seg->res->flags &= ~IORESOURCE_READONLY;
+ } else {
+ dcss_command = DCSS_LOADNOLY;
+ if (seg->vm_segtype == SEG_TYPE_SR ||
+ seg->vm_segtype == SEG_TYPE_ER)
+ seg->res->flags |= IORESOURCE_READONLY;
+ }
+ if (request_resource(&iomem_resource, seg->res)) {
+ PRINT_WARN("segment_modify_shared: could not reload segment %s"
+ " - overlapping resources\n", name);
+ rc = -EBUSY;
+ kfree(seg->res);
+ goto out_del;
+ }
+ dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+ diag_cc = dcss_diag(dcss_command, seg->dcss_name,
+ &seg->start_addr, &seg->end);
+ if (diag_cc > 1) {
+ PRINT_WARN ("segment_modify_shared: could not reload segment %s"
+ " - diag returned error (%ld)\n",name,seg->end);
+ rc = dcss_diag_translate_rc (seg->end);
+ goto out_del;
+ }
+ seg->do_nonshared = do_nonshared;
+ rc = 0;
+ goto out_unlock;
+ out_del:
+ remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+ list_del(&seg->list);
+ dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+ kfree(seg);
+ out_unlock:
+ mutex_unlock(&dcss_lock);
+ return rc;
+}
+
+/*
+ * Decrease the use count of a DCSS segment and remove
+ * it from the address space if nobody is using it
+ * any longer.
+ */
+void
+segment_unload(char *name)
+{
+ unsigned long dummy;
+ struct dcss_segment *seg;
+
+ if (!MACHINE_IS_VM)
+ return;
+
+ mutex_lock(&dcss_lock);
+ seg = segment_by_name (name);
+ if (seg == NULL) {
+ PRINT_ERR ("could not find segment %s in segment_unload, "
+ "please report to linux390@de.ibm.com\n",name);
+ goto out_unlock;
+ }
+ if (atomic_dec_return(&seg->ref_count) != 0)
+ goto out_unlock;
+ release_resource(seg->res);
+ kfree(seg->res);
+ remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+ list_del(&seg->list);
+ dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
+ kfree(seg);
+out_unlock:
+ mutex_unlock(&dcss_lock);
+}
+
+/*
+ * save segment content permanently
+ */
+void
+segment_save(char *name)
+{
+ struct dcss_segment *seg;
+ int startpfn = 0;
+ int endpfn = 0;
+ char cmd1[160];
+ char cmd2[80];
+ int i, response;
+
+ if (!MACHINE_IS_VM)
+ return;
+
+ mutex_lock(&dcss_lock);
+ seg = segment_by_name (name);
+
+ if (seg == NULL) {
+ PRINT_ERR("could not find segment %s in segment_save, please "
+ "report to linux390@de.ibm.com\n", name);
+ goto out;
+ }
+
+ startpfn = seg->start_addr >> PAGE_SHIFT;
+ endpfn = (seg->end) >> PAGE_SHIFT;
+ sprintf(cmd1, "DEFSEG %s", name);
+ for (i=0; i<seg->segcnt; i++) {
+ sprintf(cmd1+strlen(cmd1), " %X-%X %s",
+ seg->range[i].start >> PAGE_SHIFT,
+ seg->range[i].end >> PAGE_SHIFT,
+ segtype_string[seg->range[i].start & 0xff]);
+ }
+ sprintf(cmd2, "SAVESEG %s", name);
+ response = 0;
+ cpcmd(cmd1, NULL, 0, &response);
+ if (response) {
+ PRINT_ERR("segment_save: DEFSEG failed with response code %i\n",
+ response);
+ goto out;
+ }
+ cpcmd(cmd2, NULL, 0, &response);
+ if (response) {
+ PRINT_ERR("segment_save: SAVESEG failed with response code %i\n",
+ response);
+ goto out;
+ }
+out:
+ mutex_unlock(&dcss_lock);
+}
+
+EXPORT_SYMBOL(segment_load);
+EXPORT_SYMBOL(segment_unload);
+EXPORT_SYMBOL(segment_save);
+EXPORT_SYMBOL(segment_type);
+EXPORT_SYMBOL(segment_modify_shared);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/fault.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/fault.c
new file mode 100644
index 0000000000..ed13d429a4
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/fault.c
@@ -0,0 +1,618 @@
+/*
+ * arch/s390/mm/fault.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com)
+ * Ulrich Weigand (uweigand@de.ibm.com)
+ *
+ * Derived from "arch/i386/mm/fault.c"
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/kdebug.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/kprobes.h>
+#include <linux/uaccess.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/s390_ext.h>
+#include <asm/mmu_context.h>
+
+#ifndef CONFIG_64BIT
+#define __FAIL_ADDR_MASK 0x7ffff000
+#define __FIXUP_MASK 0x7fffffff
+#define __SUBCODE_MASK 0x0200
+#define __PF_RES_FIELD 0ULL
+#else /* CONFIG_64BIT */
+#define __FAIL_ADDR_MASK -4096L
+#define __FIXUP_MASK ~0L
+#define __SUBCODE_MASK 0x0600
+#define __PF_RES_FIELD 0x8000000000000000ULL
+#endif /* CONFIG_64BIT */
+
+#ifdef CONFIG_SYSCTL
+extern int sysctl_userprocess_debug;
+#endif
+
+extern void die(const char *,struct pt_regs *,long);
+
+#ifdef CONFIG_KPROBES
+static inline int notify_page_fault(struct pt_regs *regs, long err)
+{
+ int ret = 0;
+
+ /* kprobe_running() needs smp_processor_id() */
+ if (!user_mode(regs)) {
+ preempt_disable();
+ if (kprobe_running() && kprobe_fault_handler(regs, 14))
+ ret = 1;
+ preempt_enable();
+ }
+
+ return ret;
+}
+#else
+static inline int notify_page_fault(struct pt_regs *regs, long err)
+{
+ return 0;
+}
+#endif
+
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out.
+ */
+void bust_spinlocks(int yes)
+{
+ if (yes) {
+ oops_in_progress = 1;
+ } else {
+ int loglevel_save = console_loglevel;
+ console_unblank();
+ oops_in_progress = 0;
+ /*
+ * OK, the message is on the console. Now we call printk()
+ * without oops_in_progress set so that printk will give klogd
+ * a poke. Hold onto your hats...
+ */
+ console_loglevel = 15;
+ printk(" ");
+ console_loglevel = loglevel_save;
+ }
+}
+
+/*
+ * Returns the address space associated with the fault.
+ * Returns 0 for kernel space, 1 for user space and
+ * 2 for code execution in user space with noexec=on.
+ */
+static inline int check_space(struct task_struct *tsk)
+{
+ /*
+ * The lowest two bits of S390_lowcore.trans_exc_code
+ * indicate which paging table was used.
+ */
+ int desc = S390_lowcore.trans_exc_code & 3;
+
+ if (desc == 3) /* Home Segment Table Descriptor */
+ return switch_amode == 0;
+ if (desc == 2) /* Secondary Segment Table Descriptor */
+ return tsk->thread.mm_segment.ar4;
+#ifdef CONFIG_S390_SWITCH_AMODE
+ if (unlikely(desc == 1)) { /* STD determined via access register */
+ /* %a0 always indicates primary space. */
+ if (S390_lowcore.exc_access_id != 0) {
+ save_access_regs(tsk->thread.acrs);
+ /*
+ * An alet of 0 indicates primary space.
+ * An alet of 1 indicates secondary space.
+ * Any other alet values generate an
+ * alen-translation exception.
+ */
+ if (tsk->thread.acrs[S390_lowcore.exc_access_id])
+ return tsk->thread.mm_segment.ar4;
+ }
+ }
+#endif
+ /* Primary Segment Table Descriptor */
+ return switch_amode << s390_noexec;
+}
+
+/*
+ * Send SIGSEGV to task. This is an external routine
+ * to keep the stack usage of do_page_fault small.
+ */
+static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
+ int si_code, unsigned long address)
+{
+ struct siginfo si;
+
+#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
+#if defined(CONFIG_SYSCTL)
+ if (sysctl_userprocess_debug)
+#endif
+ {
+ printk("User process fault: interruption code 0x%lX\n",
+ error_code);
+ printk("failing address: %lX\n", address);
+ show_regs(regs);
+ }
+#endif
+ si.si_signo = SIGSEGV;
+ si.si_code = si_code;
+ si.si_addr = (void __user *) address;
+ force_sig_info(SIGSEGV, &si, current);
+}
+
+static void do_no_context(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ const struct exception_table_entry *fixup;
+
+ /* Are we prepared to handle this kernel fault? */
+ fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
+ if (fixup) {
+ regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+ return;
+ }
+
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ if (check_space(current) == 0)
+ printk(KERN_ALERT "Unable to handle kernel pointer dereference"
+ " at virtual kernel address %p\n", (void *)address);
+ else
+ printk(KERN_ALERT "Unable to handle kernel paging request"
+ " at virtual user address %p\n", (void *)address);
+
+ die("Oops", regs, error_code);
+ do_exit(SIGKILL);
+}
+
+static void do_low_address(struct pt_regs *regs, unsigned long error_code)
+{
+ /* Low-address protection hit in kernel mode means
+ NULL pointer write access in kernel mode. */
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ /* Low-address protection hit in user mode 'cannot happen'. */
+ die ("Low-address protection", regs, error_code);
+ do_exit(SIGKILL);
+ }
+
+ do_no_context(regs, error_code, 0);
+}
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+static int do_out_of_memory(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
+
+ up_read(&mm->mmap_sem);
+ if (is_global_init(tsk)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ return 1;
+ }
+ printk("VM: killing process %s\n", tsk->comm);
+ if (regs->psw.mask & PSW_MASK_PSTATE)
+ do_group_exit(SIGKILL);
+ do_no_context(regs, error_code, address);
+ return 0;
+}
+
+static void do_sigbus(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
+
+ up_read(&mm->mmap_sem);
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->thread.prot_addr = address;
+ tsk->thread.trap_no = error_code;
+ force_sig(SIGBUS, tsk);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!(regs->psw.mask & PSW_MASK_PSTATE))
+ do_no_context(regs, error_code, address);
+}
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+extern long sys_sigreturn(struct pt_regs *regs);
+extern long sys_rt_sigreturn(struct pt_regs *regs);
+extern long sys32_sigreturn(struct pt_regs *regs);
+extern long sys32_rt_sigreturn(struct pt_regs *regs);
+
+static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
+ unsigned long address, unsigned long error_code)
+{
+ u16 instruction;
+ int rc;
+#ifdef CONFIG_COMPAT
+ int compat;
+#endif
+
+ pagefault_disable();
+ rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
+ pagefault_enable();
+ if (rc)
+ return -EFAULT;
+
+ up_read(&mm->mmap_sem);
+ clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+#ifdef CONFIG_COMPAT
+ compat = test_tsk_thread_flag(current, TIF_31BIT);
+ if (compat && instruction == 0x0a77)
+ sys32_sigreturn(regs);
+ else if (compat && instruction == 0x0aad)
+ sys32_rt_sigreturn(regs);
+ else
+#endif
+ if (instruction == 0x0a77)
+ sys_sigreturn(regs);
+ else if (instruction == 0x0aad)
+ sys_rt_sigreturn(regs);
+ else {
+ current->thread.prot_addr = address;
+ current->thread.trap_no = error_code;
+ do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+ }
+ return 0;
+}
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * error_code:
+ * 04 Protection -> Write-Protection (suprression)
+ * 10 Segment translation -> Not present (nullification)
+ * 11 Page translation -> Not present (nullification)
+ * 3b Region third trans. -> Not present (nullification)
+ */
+static inline void
+do_exception(struct pt_regs *regs, unsigned long error_code, int write)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ unsigned long address;
+ int space;
+ int si_code;
+ int fault;
+
+ if (notify_page_fault(regs, error_code))
+ return;
+
+ tsk = current;
+ mm = tsk->mm;
+
+ /* get the failing address and the affected space */
+ address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
+ space = check_space(tsk);
+
+ /*
+ * Verify that the fault happened in user space, that
+ * we are not in an interrupt and that there is a
+ * user context.
+ */
+ if (unlikely(space == 0 || in_atomic() || !mm))
+ goto no_context;
+
+ /*
+ * When we get here, the fault happened in the current
+ * task's user address space, so we can switch on the
+ * interrupts again and then search the VMAs
+ */
+ local_irq_enable();
+
+ down_read(&mm->mmap_sem);
+
+ si_code = SEGV_MAPERR;
+ vma = find_vma(mm, address);
+ if (!vma)
+ goto bad_area;
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+ if (unlikely((space == 2) && !(vma->vm_flags & VM_EXEC)))
+ if (!signal_return(mm, regs, address, error_code))
+ /*
+ * signal_return() has done an up_read(&mm->mmap_sem)
+ * if it returns 0.
+ */
+ return;
+#endif
+
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, address))
+ goto bad_area;
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ si_code = SEGV_ACCERR;
+ if (!write) {
+ /* page not present, check vm flags */
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ goto bad_area;
+ } else {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ }
+
+survive:
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ fault = handle_mm_fault(mm, vma, address, write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM) {
+ if (do_out_of_memory(regs, error_code, address))
+ goto survive;
+ return;
+ } else if (fault & VM_FAULT_SIGBUS) {
+ do_sigbus(regs, error_code, address);
+ return;
+ }
+ BUG();
+ }
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
+
+ up_read(&mm->mmap_sem);
+ /*
+ * The instruction that caused the program check will
+ * be repeated. Don't signal single step via SIGTRAP.
+ */
+ clear_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
+ return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+ up_read(&mm->mmap_sem);
+
+ /* User mode accesses just cause a SIGSEGV */
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ tsk->thread.prot_addr = address;
+ tsk->thread.trap_no = error_code;
+ do_sigsegv(regs, error_code, si_code, address);
+ return;
+ }
+
+no_context:
+ do_no_context(regs, error_code, address);
+}
+
+void __kprobes do_protection_exception(struct pt_regs *regs,
+ unsigned long error_code)
+{
+ /* Protection exception is supressing, decrement psw address. */
+ regs->psw.addr -= (error_code >> 16);
+ /*
+ * Check for low-address protection. This needs to be treated
+ * as a special case because the translation exception code
+ * field is not guaranteed to contain valid data in this case.
+ */
+ if (unlikely(!(S390_lowcore.trans_exc_code & 4))) {
+ do_low_address(regs, error_code);
+ return;
+ }
+ do_exception(regs, 4, 1);
+}
+
+void __kprobes do_dat_exception(struct pt_regs *regs, unsigned long error_code)
+{
+ do_exception(regs, error_code & 0xff, 0);
+}
+
+#ifdef CONFIG_64BIT
+void __kprobes do_asce_exception(struct pt_regs *regs, unsigned long error_code)
+{
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ unsigned long address;
+ int space;
+
+ mm = current->mm;
+ address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
+ space = check_space(current);
+
+ if (unlikely(space == 0 || in_atomic() || !mm))
+ goto no_context;
+
+ local_irq_enable();
+
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, address);
+ up_read(&mm->mmap_sem);
+
+ if (vma) {
+ update_mm(mm, current);
+ return;
+ }
+
+ /* User mode accesses just cause a SIGSEGV */
+ if (regs->psw.mask & PSW_MASK_PSTATE) {
+ current->thread.prot_addr = address;
+ current->thread.trap_no = error_code;
+ do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+ return;
+ }
+
+no_context:
+ do_no_context(regs, error_code, address);
+}
+#endif
+
+#ifdef CONFIG_PFAULT
+/*
+ * 'pfault' pseudo page faults routines.
+ */
+static ext_int_info_t ext_int_pfault;
+static int pfault_disable = 0;
+
+static int __init nopfault(char *str)
+{
+ pfault_disable = 1;
+ return 1;
+}
+
+__setup("nopfault", nopfault);
+
+typedef struct {
+ __u16 refdiagc;
+ __u16 reffcode;
+ __u16 refdwlen;
+ __u16 refversn;
+ __u64 refgaddr;
+ __u64 refselmk;
+ __u64 refcmpmk;
+ __u64 reserved;
+} __attribute__ ((packed, aligned(8))) pfault_refbk_t;
+
+int pfault_init(void)
+{
+ pfault_refbk_t refbk =
+ { 0x258, 0, 5, 2, __LC_CURRENT, 1ULL << 48, 1ULL << 48,
+ __PF_RES_FIELD };
+ int rc;
+
+ if (!MACHINE_IS_VM || pfault_disable)
+ return -1;
+ asm volatile(
+ " diag %1,%0,0x258\n"
+ "0: j 2f\n"
+ "1: la %0,8\n"
+ "2:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc");
+ __ctl_set_bit(0, 9);
+ return rc;
+}
+
+void pfault_fini(void)
+{
+ pfault_refbk_t refbk =
+ { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+
+ if (!MACHINE_IS_VM || pfault_disable)
+ return;
+ __ctl_clear_bit(0,9);
+ asm volatile(
+ " diag %0,0,0x258\n"
+ "0:\n"
+ EX_TABLE(0b,0b)
+ : : "a" (&refbk), "m" (refbk) : "cc");
+}
+
+static void pfault_interrupt(__u16 error_code)
+{
+ struct task_struct *tsk;
+ __u16 subcode;
+
+ /*
+ * Get the external interruption subcode & pfault
+ * initial/completion signal bit. VM stores this
+ * in the 'cpu address' field associated with the
+ * external interrupt.
+ */
+ subcode = S390_lowcore.cpu_addr;
+ if ((subcode & 0xff00) != __SUBCODE_MASK)
+ return;
+
+ /*
+ * Get the token (= address of the task structure of the affected task).
+ */
+ tsk = *(struct task_struct **) __LC_PFAULT_INTPARM;
+
+ if (subcode & 0x0080) {
+ /* signal bit is set -> a page has been swapped in by VM */
+ if (xchg(&tsk->thread.pfault_wait, -1) != 0) {
+ /* Initial interrupt was faster than the completion
+ * interrupt. pfault_wait is valid. Set pfault_wait
+ * back to zero and wake up the process. This can
+ * safely be done because the task is still sleeping
+ * and can't produce new pfaults. */
+ tsk->thread.pfault_wait = 0;
+ wake_up_process(tsk);
+ put_task_struct(tsk);
+ }
+ } else {
+ /* signal bit not set -> a real page is missing. */
+ get_task_struct(tsk);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (xchg(&tsk->thread.pfault_wait, 1) != 0) {
+ /* Completion interrupt was faster than the initial
+ * interrupt (swapped in a -1 for pfault_wait). Set
+ * pfault_wait back to zero and exit. This can be
+ * done safely because tsk is running in kernel
+ * mode and can't produce new pfaults. */
+ tsk->thread.pfault_wait = 0;
+ set_task_state(tsk, TASK_RUNNING);
+ put_task_struct(tsk);
+ } else
+ set_tsk_need_resched(tsk);
+ }
+}
+
+void __init pfault_irq_init(void)
+{
+ if (!MACHINE_IS_VM)
+ return;
+
+ /*
+ * Try to get pfault pseudo page faults going.
+ */
+ if (register_early_external_interrupt(0x2603, pfault_interrupt,
+ &ext_int_pfault) != 0)
+ panic("Couldn't request external interrupt 0x2603");
+
+ if (pfault_init() == 0)
+ return;
+
+ /* Tough luck, no pfault. */
+ pfault_disable = 1;
+ unregister_early_external_interrupt(0x2603, pfault_interrupt,
+ &ext_int_pfault);
+}
+#endif
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/init.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/init.c
new file mode 100644
index 0000000000..8053245fe2
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/init.c
@@ -0,0 +1,226 @@
+/*
+ * arch/s390/mm/init.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com)
+ *
+ * Derived from "arch/i386/mm/init.c"
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+#include <linux/pfn.h>
+#include <linux/poison.h>
+#include <linux/initrd.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/dma.h>
+#include <asm/lowcore.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/sections.h>
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
+char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+
+void show_mem(void)
+{
+ int i, total = 0, reserved = 0;
+ int shared = 0, cached = 0;
+ struct page *page;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6ldkB\n", nr_swap_pages << (PAGE_SHIFT - 10));
+ i = max_mapnr;
+ while (i-- > 0) {
+ if (!pfn_valid(i))
+ continue;
+ page = pfn_to_page(i);
+ total++;
+ if (PageReserved(page))
+ reserved++;
+ else if (PageSwapCache(page))
+ cached++;
+ else if (page_count(page))
+ shared += page_count(page) - 1;
+ }
+ printk("%d pages of RAM\n", total);
+ printk("%d reserved pages\n", reserved);
+ printk("%d pages shared\n", shared);
+ printk("%d pages swap cached\n", cached);
+
+ printk("%lu pages dirty\n", global_page_state(NR_FILE_DIRTY));
+ printk("%lu pages writeback\n", global_page_state(NR_WRITEBACK));
+ printk("%lu pages mapped\n", global_page_state(NR_FILE_MAPPED));
+ printk("%lu pages slab\n",
+ global_page_state(NR_SLAB_RECLAIMABLE) +
+ global_page_state(NR_SLAB_UNRECLAIMABLE));
+ printk("%lu pages pagetables\n", global_page_state(NR_PAGETABLE));
+}
+
+static void __init setup_ro_region(void)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t new_pte;
+ unsigned long address, end;
+
+ address = ((unsigned long)&_stext) & PAGE_MASK;
+ end = PFN_ALIGN((unsigned long)&_eshared);
+
+ for (; address < end; address += PAGE_SIZE) {
+ pgd = pgd_offset_k(address);
+ pud = pud_offset(pgd, address);
+ pmd = pmd_offset(pud, address);
+ pte = pte_offset_kernel(pmd, address);
+ new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
+ *pte = new_pte;
+ }
+}
+
+/*
+ * paging_init() sets up the page tables
+ */
+void __init paging_init(void)
+{
+ static const int ssm_mask = 0x04000000L;
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
+ unsigned long pgd_type;
+
+ init_mm.pgd = swapper_pg_dir;
+ S390_lowcore.kernel_asce = __pa(init_mm.pgd) & PAGE_MASK;
+#ifdef CONFIG_64BIT
+ /* A three level page table (4TB) is enough for the kernel space. */
+ S390_lowcore.kernel_asce |= _ASCE_TYPE_REGION3 | _ASCE_TABLE_LENGTH;
+ pgd_type = _REGION3_ENTRY_EMPTY;
+#else
+ S390_lowcore.kernel_asce |= _ASCE_TABLE_LENGTH;
+ pgd_type = _SEGMENT_ENTRY_EMPTY;
+#endif
+ clear_table((unsigned long *) init_mm.pgd, pgd_type,
+ sizeof(unsigned long)*2048);
+ vmem_map_init();
+ setup_ro_region();
+
+ /* enable virtual mapping in kernel mode */
+ __ctl_load(S390_lowcore.kernel_asce, 1, 1);
+ __ctl_load(S390_lowcore.kernel_asce, 7, 7);
+ __ctl_load(S390_lowcore.kernel_asce, 13, 13);
+ __raw_local_irq_ssm(ssm_mask);
+
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+#ifdef CONFIG_ZONE_DMA
+ max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
+#endif
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+ free_area_init_nodes(max_zone_pfns);
+}
+
+void __init mem_init(void)
+{
+ unsigned long codesize, reservedpages, datasize, initsize;
+
+ max_mapnr = num_physpages = max_low_pfn;
+ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+
+ /* clear the zero-page */
+ memset(empty_zero_page, 0, PAGE_SIZE);
+
+ /* this will put all low memory onto the freelists */
+ totalram_pages += free_all_bootmem();
+
+ reservedpages = 0;
+
+ codesize = (unsigned long) &_etext - (unsigned long) &_text;
+ datasize = (unsigned long) &_edata - (unsigned long) &_etext;
+ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
+ printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
+ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+ max_mapnr << (PAGE_SHIFT-10),
+ codesize >> 10,
+ reservedpages << (PAGE_SHIFT-10),
+ datasize >>10,
+ initsize >> 10);
+ printk("Write protected kernel read-only data: %#lx - %#lx\n",
+ (unsigned long)&_stext,
+ PFN_ALIGN((unsigned long)&_eshared) - 1);
+}
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long address;
+ int i;
+
+ for (i = 0; i < numpages; i++) {
+ address = page_to_phys(page + i);
+ pgd = pgd_offset_k(address);
+ pud = pud_offset(pgd, address);
+ pmd = pmd_offset(pud, address);
+ pte = pte_offset_kernel(pmd, address);
+ if (!enable) {
+ ptep_invalidate(&init_mm, address, pte);
+ continue;
+ }
+ *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW));
+ /* Flush cpu write queue. */
+ mb();
+ }
+}
+#endif
+
+void free_initmem(void)
+{
+ unsigned long addr;
+
+ addr = (unsigned long)(&__init_begin);
+ for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(addr));
+ init_page_count(virt_to_page(addr));
+ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
+ free_page(addr);
+ totalram_pages++;
+ }
+ printk ("Freeing unused kernel memory: %ldk freed\n",
+ ((unsigned long)&__init_end - (unsigned long)&__init_begin) >> 10);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ if (start < end)
+ printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(start));
+ init_page_count(virt_to_page(start));
+ free_page(start);
+ totalram_pages++;
+ }
+}
+#endif
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/mmap.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/mmap.c
new file mode 100644
index 0000000000..5932a82454
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/mmap.c
@@ -0,0 +1,151 @@
+/*
+ * linux/arch/s390/mm/mmap.c
+ *
+ * flexible mmap layout support
+ *
+ * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * Started by Ingo Molnar <mingo@elte.hu>
+ */
+
+#include <linux/personality.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <asm/pgalloc.h>
+
+/*
+ * Top of mmap area (just below the process stack).
+ *
+ * Leave an at least ~128 MB hole.
+ */
+#define MIN_GAP (128*1024*1024)
+#define MAX_GAP (TASK_SIZE/6*5)
+
+static inline unsigned long mmap_base(void)
+{
+ unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
+
+ if (gap < MIN_GAP)
+ gap = MIN_GAP;
+ else if (gap > MAX_GAP)
+ gap = MAX_GAP;
+
+ return TASK_SIZE - (gap & PAGE_MASK);
+}
+
+static inline int mmap_is_legacy(void)
+{
+#ifdef CONFIG_64BIT
+ /*
+ * Force standard allocation for 64 bit programs.
+ */
+ if (!test_thread_flag(TIF_31BIT))
+ return 1;
+#endif
+ return sysctl_legacy_va_layout ||
+ (current->personality & ADDR_COMPAT_LAYOUT) ||
+ current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY;
+}
+
+#ifndef CONFIG_64BIT
+
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+ /*
+ * Fall back to the standard layout if the personality
+ * bit is set, or if the expected stack growth is unlimited:
+ */
+ if (mmap_is_legacy()) {
+ mm->mmap_base = TASK_UNMAPPED_BASE;
+ mm->get_unmapped_area = arch_get_unmapped_area;
+ mm->unmap_area = arch_unmap_area;
+ } else {
+ mm->mmap_base = mmap_base();
+ mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+ mm->unmap_area = arch_unmap_area_topdown;
+ }
+}
+EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
+
+#else
+
+static unsigned long
+s390_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct mm_struct *mm = current->mm;
+ int rc;
+
+ addr = arch_get_unmapped_area(filp, addr, len, pgoff, flags);
+ if (addr & ~PAGE_MASK)
+ return addr;
+ if (unlikely(mm->context.asce_limit < addr + len)) {
+ rc = crst_table_upgrade(mm, addr + len);
+ if (rc)
+ return (unsigned long) rc;
+ }
+ return addr;
+}
+
+static unsigned long
+s390_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
+ const unsigned long len, const unsigned long pgoff,
+ const unsigned long flags)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long addr = addr0;
+ int rc;
+
+ addr = arch_get_unmapped_area_topdown(filp, addr, len, pgoff, flags);
+ if (addr & ~PAGE_MASK)
+ return addr;
+ if (unlikely(mm->context.asce_limit < addr + len)) {
+ rc = crst_table_upgrade(mm, addr + len);
+ if (rc)
+ return (unsigned long) rc;
+ }
+ return addr;
+}
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+ /*
+ * Fall back to the standard layout if the personality
+ * bit is set, or if the expected stack growth is unlimited:
+ */
+ if (mmap_is_legacy()) {
+ mm->mmap_base = TASK_UNMAPPED_BASE;
+ mm->get_unmapped_area = s390_get_unmapped_area;
+ mm->unmap_area = arch_unmap_area;
+ } else {
+ mm->mmap_base = mmap_base();
+ mm->get_unmapped_area = s390_get_unmapped_area_topdown;
+ mm->unmap_area = arch_unmap_area_topdown;
+ }
+}
+EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
+
+#endif
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/pgtable.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/pgtable.c
new file mode 100644
index 0000000000..fd072013f8
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/pgtable.c
@@ -0,0 +1,230 @@
+/*
+ * arch/s390/mm/pgtable.c
+ *
+ * Copyright IBM Corp. 2007
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/quicklist.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+
+#ifndef CONFIG_64BIT
+#define ALLOC_ORDER 1
+#define TABLES_PER_PAGE 4
+#define FRAG_MASK 15UL
+#define SECOND_HALVES 10UL
+#else
+#define ALLOC_ORDER 2
+#define TABLES_PER_PAGE 2
+#define FRAG_MASK 3UL
+#define SECOND_HALVES 2UL
+#endif
+
+unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
+{
+ struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
+
+ if (!page)
+ return NULL;
+ page->index = 0;
+ if (noexec) {
+ struct page *shadow = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
+ if (!shadow) {
+ __free_pages(page, ALLOC_ORDER);
+ return NULL;
+ }
+ page->index = page_to_phys(shadow);
+ }
+ spin_lock(&mm->page_table_lock);
+ list_add(&page->lru, &mm->context.crst_list);
+ spin_unlock(&mm->page_table_lock);
+ return (unsigned long *) page_to_phys(page);
+}
+
+void crst_table_free(struct mm_struct *mm, unsigned long *table)
+{
+ unsigned long *shadow = get_shadow_table(table);
+ struct page *page = virt_to_page(table);
+
+ spin_lock(&mm->page_table_lock);
+ list_del(&page->lru);
+ spin_unlock(&mm->page_table_lock);
+ if (shadow)
+ free_pages((unsigned long) shadow, ALLOC_ORDER);
+ free_pages((unsigned long) table, ALLOC_ORDER);
+}
+
+#ifdef CONFIG_64BIT
+int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
+{
+ unsigned long *table, *pgd;
+ unsigned long entry;
+
+ BUG_ON(limit > (1UL << 53));
+repeat:
+ table = crst_table_alloc(mm, mm->context.noexec);
+ if (!table)
+ return -ENOMEM;
+ spin_lock(&mm->page_table_lock);
+ if (mm->context.asce_limit < limit) {
+ pgd = (unsigned long *) mm->pgd;
+ if (mm->context.asce_limit <= (1UL << 31)) {
+ entry = _REGION3_ENTRY_EMPTY;
+ mm->context.asce_limit = 1UL << 42;
+ mm->context.asce_bits = _ASCE_TABLE_LENGTH |
+ _ASCE_USER_BITS |
+ _ASCE_TYPE_REGION3;
+ } else {
+ entry = _REGION2_ENTRY_EMPTY;
+ mm->context.asce_limit = 1UL << 53;
+ mm->context.asce_bits = _ASCE_TABLE_LENGTH |
+ _ASCE_USER_BITS |
+ _ASCE_TYPE_REGION2;
+ }
+ crst_table_init(table, entry);
+ pgd_populate(mm, (pgd_t *) table, (pud_t *) pgd);
+ mm->pgd = (pgd_t *) table;
+ table = NULL;
+ }
+ spin_unlock(&mm->page_table_lock);
+ if (table)
+ crst_table_free(mm, table);
+ if (mm->context.asce_limit < limit)
+ goto repeat;
+ update_mm(mm, current);
+ return 0;
+}
+
+void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
+{
+ pgd_t *pgd;
+
+ if (mm->context.asce_limit <= limit)
+ return;
+ __tlb_flush_mm(mm);
+ while (mm->context.asce_limit > limit) {
+ pgd = mm->pgd;
+ switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) {
+ case _REGION_ENTRY_TYPE_R2:
+ mm->context.asce_limit = 1UL << 42;
+ mm->context.asce_bits = _ASCE_TABLE_LENGTH |
+ _ASCE_USER_BITS |
+ _ASCE_TYPE_REGION3;
+ break;
+ case _REGION_ENTRY_TYPE_R3:
+ mm->context.asce_limit = 1UL << 31;
+ mm->context.asce_bits = _ASCE_TABLE_LENGTH |
+ _ASCE_USER_BITS |
+ _ASCE_TYPE_SEGMENT;
+ break;
+ default:
+ BUG();
+ }
+ mm->pgd = (pgd_t *) (pgd_val(*pgd) & _REGION_ENTRY_ORIGIN);
+ crst_table_free(mm, (unsigned long *) pgd);
+ }
+ update_mm(mm, current);
+}
+#endif
+
+/*
+ * page table entry allocation/free routines.
+ */
+unsigned long *page_table_alloc(struct mm_struct *mm)
+{
+ struct page *page;
+ unsigned long *table;
+ unsigned long bits;
+
+ bits = mm->context.noexec ? 3UL : 1UL;
+ spin_lock(&mm->page_table_lock);
+ page = NULL;
+ if (!list_empty(&mm->context.pgtable_list)) {
+ page = list_first_entry(&mm->context.pgtable_list,
+ struct page, lru);
+ if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1))
+ page = NULL;
+ }
+ if (!page) {
+ spin_unlock(&mm->page_table_lock);
+ page = alloc_page(GFP_KERNEL|__GFP_REPEAT);
+ if (!page)
+ return NULL;
+ pgtable_page_ctor(page);
+ page->flags &= ~FRAG_MASK;
+ table = (unsigned long *) page_to_phys(page);
+ clear_table(table, _PAGE_TYPE_EMPTY, PAGE_SIZE);
+ spin_lock(&mm->page_table_lock);
+ list_add(&page->lru, &mm->context.pgtable_list);
+ }
+ table = (unsigned long *) page_to_phys(page);
+ while (page->flags & bits) {
+ table += 256;
+ bits <<= 1;
+ }
+ page->flags |= bits;
+ if ((page->flags & FRAG_MASK) == ((1UL << TABLES_PER_PAGE) - 1))
+ list_move_tail(&page->lru, &mm->context.pgtable_list);
+ spin_unlock(&mm->page_table_lock);
+ return table;
+}
+
+void page_table_free(struct mm_struct *mm, unsigned long *table)
+{
+ struct page *page;
+ unsigned long bits;
+
+ bits = mm->context.noexec ? 3UL : 1UL;
+ bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
+ page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
+ spin_lock(&mm->page_table_lock);
+ page->flags ^= bits;
+ if (page->flags & FRAG_MASK) {
+ /* Page now has some free pgtable fragments. */
+ list_move(&page->lru, &mm->context.pgtable_list);
+ page = NULL;
+ } else
+ /* All fragments of the 4K page have been freed. */
+ list_del(&page->lru);
+ spin_unlock(&mm->page_table_lock);
+ if (page) {
+ pgtable_page_dtor(page);
+ __free_page(page);
+ }
+}
+
+void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
+{
+ struct page *page;
+
+ spin_lock(&mm->page_table_lock);
+ /* Free shadow region and segment tables. */
+ list_for_each_entry(page, &mm->context.crst_list, lru)
+ if (page->index) {
+ free_pages((unsigned long) page->index, ALLOC_ORDER);
+ page->index = 0;
+ }
+ /* "Free" second halves of page tables. */
+ list_for_each_entry(page, &mm->context.pgtable_list, lru)
+ page->flags &= ~SECOND_HALVES;
+ spin_unlock(&mm->page_table_lock);
+ mm->context.noexec = 0;
+ update_mm(mm, tsk);
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/vmem.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/vmem.c
new file mode 100644
index 0000000000..35d90a4720
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/mm/vmem.c
@@ -0,0 +1,412 @@
+/*
+ * arch/s390/mm/vmem.c
+ *
+ * Copyright IBM Corp. 2006
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/bootmem.h>
+#include <linux/pfn.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/setup.h>
+#include <asm/tlbflush.h>
+
+static DEFINE_MUTEX(vmem_mutex);
+
+struct memory_segment {
+ struct list_head list;
+ unsigned long start;
+ unsigned long size;
+};
+
+static LIST_HEAD(mem_segs);
+
+void __meminit memmap_init(unsigned long size, int nid, unsigned long zone,
+ unsigned long start_pfn)
+{
+ struct page *start, *end;
+ struct page *map_start, *map_end;
+ int i;
+
+ start = pfn_to_page(start_pfn);
+ end = start + size;
+
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+ unsigned long cstart, cend;
+
+ cstart = PFN_DOWN(memory_chunk[i].addr);
+ cend = cstart + PFN_DOWN(memory_chunk[i].size);
+
+ map_start = mem_map + cstart;
+ map_end = mem_map + cend;
+
+ if (map_start < start)
+ map_start = start;
+ if (map_end > end)
+ map_end = end;
+
+ map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1))
+ / sizeof(struct page);
+ map_end += ((PFN_ALIGN((unsigned long) map_end)
+ - (unsigned long) map_end)
+ / sizeof(struct page));
+
+ if (map_start < map_end)
+ memmap_init_zone((unsigned long)(map_end - map_start),
+ nid, zone, page_to_pfn(map_start),
+ MEMMAP_EARLY);
+ }
+}
+
+static void __ref *vmem_alloc_pages(unsigned int order)
+{
+ if (slab_is_available())
+ return (void *)__get_free_pages(GFP_KERNEL, order);
+ return alloc_bootmem_pages((1 << order) * PAGE_SIZE);
+}
+
+static inline pud_t *vmem_pud_alloc(void)
+{
+ pud_t *pud = NULL;
+
+#ifdef CONFIG_64BIT
+ pud = vmem_alloc_pages(2);
+ if (!pud)
+ return NULL;
+ pud_val(*pud) = _REGION3_ENTRY_EMPTY;
+ memcpy(pud + 1, pud, (PTRS_PER_PUD - 1)*sizeof(pud_t));
+#endif
+ return pud;
+}
+
+static inline pmd_t *vmem_pmd_alloc(void)
+{
+ pmd_t *pmd = NULL;
+
+#ifdef CONFIG_64BIT
+ pmd = vmem_alloc_pages(2);
+ if (!pmd)
+ return NULL;
+ clear_table((unsigned long *) pmd, _SEGMENT_ENTRY_EMPTY, PAGE_SIZE*4);
+#endif
+ return pmd;
+}
+
+static pte_t __init_refok *vmem_pte_alloc(void)
+{
+ pte_t *pte;
+
+ if (slab_is_available())
+ pte = (pte_t *) page_table_alloc(&init_mm);
+ else
+ pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t));
+ if (!pte)
+ return NULL;
+ clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY,
+ PTRS_PER_PTE * sizeof(pte_t));
+ return pte;
+}
+
+/*
+ * Add a physical memory range to the 1:1 mapping.
+ */
+static int vmem_add_range(unsigned long start, unsigned long size)
+{
+ unsigned long address;
+ pgd_t *pg_dir;
+ pud_t *pu_dir;
+ pmd_t *pm_dir;
+ pte_t *pt_dir;
+ pte_t pte;
+ int ret = -ENOMEM;
+
+ for (address = start; address < start + size; address += PAGE_SIZE) {
+ pg_dir = pgd_offset_k(address);
+ if (pgd_none(*pg_dir)) {
+ pu_dir = vmem_pud_alloc();
+ if (!pu_dir)
+ goto out;
+ pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+ }
+
+ pu_dir = pud_offset(pg_dir, address);
+ if (pud_none(*pu_dir)) {
+ pm_dir = vmem_pmd_alloc();
+ if (!pm_dir)
+ goto out;
+ pud_populate_kernel(&init_mm, pu_dir, pm_dir);
+ }
+
+ pm_dir = pmd_offset(pu_dir, address);
+ if (pmd_none(*pm_dir)) {
+ pt_dir = vmem_pte_alloc();
+ if (!pt_dir)
+ goto out;
+ pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+ }
+
+ pt_dir = pte_offset_kernel(pm_dir, address);
+ pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
+ *pt_dir = pte;
+ }
+ ret = 0;
+out:
+ flush_tlb_kernel_range(start, start + size);
+ return ret;
+}
+
+/*
+ * Remove a physical memory range from the 1:1 mapping.
+ * Currently only invalidates page table entries.
+ */
+static void vmem_remove_range(unsigned long start, unsigned long size)
+{
+ unsigned long address;
+ pgd_t *pg_dir;
+ pud_t *pu_dir;
+ pmd_t *pm_dir;
+ pte_t *pt_dir;
+ pte_t pte;
+
+ pte_val(pte) = _PAGE_TYPE_EMPTY;
+ for (address = start; address < start + size; address += PAGE_SIZE) {
+ pg_dir = pgd_offset_k(address);
+ pu_dir = pud_offset(pg_dir, address);
+ if (pud_none(*pu_dir))
+ continue;
+ pm_dir = pmd_offset(pu_dir, address);
+ if (pmd_none(*pm_dir))
+ continue;
+ pt_dir = pte_offset_kernel(pm_dir, address);
+ *pt_dir = pte;
+ }
+ flush_tlb_kernel_range(start, start + size);
+}
+
+/*
+ * Add a backed mem_map array to the virtual mem_map array.
+ */
+static int vmem_add_mem_map(unsigned long start, unsigned long size)
+{
+ unsigned long address, start_addr, end_addr;
+ struct page *map_start, *map_end;
+ pgd_t *pg_dir;
+ pud_t *pu_dir;
+ pmd_t *pm_dir;
+ pte_t *pt_dir;
+ pte_t pte;
+ int ret = -ENOMEM;
+
+ map_start = VMEM_MAP + PFN_DOWN(start);
+ map_end = VMEM_MAP + PFN_DOWN(start + size);
+
+ start_addr = (unsigned long) map_start & PAGE_MASK;
+ end_addr = PFN_ALIGN((unsigned long) map_end);
+
+ for (address = start_addr; address < end_addr; address += PAGE_SIZE) {
+ pg_dir = pgd_offset_k(address);
+ if (pgd_none(*pg_dir)) {
+ pu_dir = vmem_pud_alloc();
+ if (!pu_dir)
+ goto out;
+ pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+ }
+
+ pu_dir = pud_offset(pg_dir, address);
+ if (pud_none(*pu_dir)) {
+ pm_dir = vmem_pmd_alloc();
+ if (!pm_dir)
+ goto out;
+ pud_populate_kernel(&init_mm, pu_dir, pm_dir);
+ }
+
+ pm_dir = pmd_offset(pu_dir, address);
+ if (pmd_none(*pm_dir)) {
+ pt_dir = vmem_pte_alloc();
+ if (!pt_dir)
+ goto out;
+ pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+ }
+
+ pt_dir = pte_offset_kernel(pm_dir, address);
+ if (pte_none(*pt_dir)) {
+ unsigned long new_page;
+
+ new_page =__pa(vmem_alloc_pages(0));
+ if (!new_page)
+ goto out;
+ pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
+ *pt_dir = pte;
+ }
+ }
+ ret = 0;
+out:
+ flush_tlb_kernel_range(start_addr, end_addr);
+ return ret;
+}
+
+static int vmem_add_mem(unsigned long start, unsigned long size)
+{
+ int ret;
+
+ ret = vmem_add_mem_map(start, size);
+ if (ret)
+ return ret;
+ return vmem_add_range(start, size);
+}
+
+/*
+ * Add memory segment to the segment list if it doesn't overlap with
+ * an already present segment.
+ */
+static int insert_memory_segment(struct memory_segment *seg)
+{
+ struct memory_segment *tmp;
+
+ if (seg->start + seg->size >= VMEM_MAX_PHYS ||
+ seg->start + seg->size < seg->start)
+ return -ERANGE;
+
+ list_for_each_entry(tmp, &mem_segs, list) {
+ if (seg->start >= tmp->start + tmp->size)
+ continue;
+ if (seg->start + seg->size <= tmp->start)
+ continue;
+ return -ENOSPC;
+ }
+ list_add(&seg->list, &mem_segs);
+ return 0;
+}
+
+/*
+ * Remove memory segment from the segment list.
+ */
+static void remove_memory_segment(struct memory_segment *seg)
+{
+ list_del(&seg->list);
+}
+
+static void __remove_shared_memory(struct memory_segment *seg)
+{
+ remove_memory_segment(seg);
+ vmem_remove_range(seg->start, seg->size);
+}
+
+int remove_shared_memory(unsigned long start, unsigned long size)
+{
+ struct memory_segment *seg;
+ int ret;
+
+ mutex_lock(&vmem_mutex);
+
+ ret = -ENOENT;
+ list_for_each_entry(seg, &mem_segs, list) {
+ if (seg->start == start && seg->size == size)
+ break;
+ }
+
+ if (seg->start != start || seg->size != size)
+ goto out;
+
+ ret = 0;
+ __remove_shared_memory(seg);
+ kfree(seg);
+out:
+ mutex_unlock(&vmem_mutex);
+ return ret;
+}
+
+int add_shared_memory(unsigned long start, unsigned long size)
+{
+ struct memory_segment *seg;
+ struct page *page;
+ unsigned long pfn, num_pfn, end_pfn;
+ int ret;
+
+ mutex_lock(&vmem_mutex);
+ ret = -ENOMEM;
+ seg = kzalloc(sizeof(*seg), GFP_KERNEL);
+ if (!seg)
+ goto out;
+ seg->start = start;
+ seg->size = size;
+
+ ret = insert_memory_segment(seg);
+ if (ret)
+ goto out_free;
+
+ ret = vmem_add_mem(start, size);
+ if (ret)
+ goto out_remove;
+
+ pfn = PFN_DOWN(start);
+ num_pfn = PFN_DOWN(size);
+ end_pfn = pfn + num_pfn;
+
+ page = pfn_to_page(pfn);
+ memset(page, 0, num_pfn * sizeof(struct page));
+
+ for (; pfn < end_pfn; pfn++) {
+ page = pfn_to_page(pfn);
+ init_page_count(page);
+ reset_page_mapcount(page);
+ SetPageReserved(page);
+ INIT_LIST_HEAD(&page->lru);
+ }
+ goto out;
+
+out_remove:
+ __remove_shared_memory(seg);
+out_free:
+ kfree(seg);
+out:
+ mutex_unlock(&vmem_mutex);
+ return ret;
+}
+
+/*
+ * map whole physical memory to virtual memory (identity mapping)
+ * we reserve enough space in the vmalloc area for vmemmap to hotplug
+ * additional memory segments.
+ */
+void __init vmem_map_init(void)
+{
+ int i;
+
+ INIT_LIST_HEAD(&init_mm.context.crst_list);
+ INIT_LIST_HEAD(&init_mm.context.pgtable_list);
+ init_mm.context.noexec = 0;
+ NODE_DATA(0)->node_mem_map = VMEM_MAP;
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
+ vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
+}
+
+/*
+ * Convert memory chunk array to a memory segment list so there is a single
+ * list that contains both r/w memory and shared memory segments.
+ */
+static int __init vmem_convert_memory_chunk(void)
+{
+ struct memory_segment *seg;
+ int i;
+
+ mutex_lock(&vmem_mutex);
+ for (i = 0; i < MEMORY_CHUNKS; i++) {
+ if (!memory_chunk[i].size)
+ continue;
+ seg = kzalloc(sizeof(*seg), GFP_KERNEL);
+ if (!seg)
+ panic("Out of memory...\n");
+ seg->start = memory_chunk[i].addr;
+ seg->size = memory_chunk[i].size;
+ insert_memory_segment(seg);
+ }
+ mutex_unlock(&vmem_mutex);
+ return 0;
+}
+
+core_initcall(vmem_convert_memory_chunk);
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/Makefile b/cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/Makefile
new file mode 100644
index 0000000000..537b2d840e
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/Makefile
@@ -0,0 +1,9 @@
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
+ oprof.o cpu_buffer.o buffer_sync.o \
+ event_buffer.o oprofile_files.o \
+ oprofilefs.o oprofile_stats.o \
+ timer_int.o )
+
+oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/backtrace.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/backtrace.c
new file mode 100644
index 0000000000..bc4b84a35c
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/backtrace.c
@@ -0,0 +1,79 @@
+/**
+ * arch/s390/oprofile/backtrace.c
+ *
+ * S390 Version
+ * Copyright (C) 2005 IBM Corporation, IBM Deutschland Entwicklung GmbH.
+ * Author(s): Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
+ */
+
+#include <linux/oprofile.h>
+
+#include <asm/processor.h> /* for struct stack_frame */
+
+static unsigned long
+__show_trace(unsigned int *depth, unsigned long sp,
+ unsigned long low, unsigned long high)
+{
+ struct stack_frame *sf;
+ struct pt_regs *regs;
+
+ while (*depth) {
+ sp = sp & PSW_ADDR_INSN;
+ if (sp < low || sp > high - sizeof(*sf))
+ return sp;
+ sf = (struct stack_frame *) sp;
+ (*depth)--;
+ oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN);
+
+ /* Follow the backchain. */
+ while (*depth) {
+ low = sp;
+ sp = sf->back_chain & PSW_ADDR_INSN;
+ if (!sp)
+ break;
+ if (sp <= low || sp > high - sizeof(*sf))
+ return sp;
+ sf = (struct stack_frame *) sp;
+ (*depth)--;
+ oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN);
+
+ }
+
+ if (*depth == 0)
+ break;
+
+ /* Zero backchain detected, check for interrupt frame. */
+ sp = (unsigned long) (sf + 1);
+ if (sp <= low || sp > high - sizeof(*regs))
+ return sp;
+ regs = (struct pt_regs *) sp;
+ (*depth)--;
+ oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN);
+ low = sp;
+ sp = regs->gprs[15];
+ }
+ return sp;
+}
+
+void s390_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+ unsigned long head;
+ struct stack_frame* head_sf;
+
+ if (user_mode (regs))
+ return;
+
+ head = regs->gprs[15];
+ head_sf = (struct stack_frame*)head;
+
+ if (!head_sf->back_chain)
+ return;
+
+ head = head_sf->back_chain;
+
+ head = __show_trace(&depth, head, S390_lowcore.async_stack - ASYNC_SIZE,
+ S390_lowcore.async_stack);
+
+ __show_trace(&depth, head, S390_lowcore.thread_info,
+ S390_lowcore.thread_info + THREAD_SIZE);
+}
diff --git a/cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/init.c b/cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/init.c
new file mode 100644
index 0000000000..7a995113b9
--- /dev/null
+++ b/cleopatre/linux-2.6.25.10-spc300/arch/s390/oprofile/init.c
@@ -0,0 +1,26 @@
+/**
+ * arch/s390/oprofile/init.c
+ *
+ * S390 Version
+ * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *
+ * @remark Copyright 2002 OProfile authors
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+
+
+extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth);
+
+int __init oprofile_arch_init(struct oprofile_operations* ops)
+{
+ ops->backtrace = s390_backtrace;
+ return -ENODEV;
+}
+
+void oprofile_arch_exit(void)
+{
+}