aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/s390
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/Kconfig480
-rw-r--r--arch/s390/Kconfig.debug5
-rw-r--r--arch/s390/Makefile116
-rw-r--r--arch/s390/appldata/Makefile8
-rw-r--r--arch/s390/appldata/appldata.h59
-rw-r--r--arch/s390/appldata/appldata_base.c770
-rw-r--r--arch/s390/appldata/appldata_mem.c195
-rw-r--r--arch/s390/appldata/appldata_net_sum.c195
-rw-r--r--arch/s390/appldata/appldata_os.c241
-rw-r--r--arch/s390/boot/Makefile18
-rw-r--r--arch/s390/boot/install.sh38
-rw-r--r--arch/s390/crypto/Makefile8
-rw-r--r--arch/s390/crypto/crypt_z990.h374
-rw-r--r--arch/s390/crypto/crypt_z990_query.c111
-rw-r--r--arch/s390/crypto/crypto_des.h18
-rw-r--r--arch/s390/crypto/des_check_key.c130
-rw-r--r--arch/s390/crypto/des_z990.c284
-rw-r--r--arch/s390/crypto/sha1_z990.c167
-rw-r--r--arch/s390/defconfig589
-rw-r--r--arch/s390/kernel/Makefile31
-rw-r--r--arch/s390/kernel/asm-offsets.c49
-rw-r--r--arch/s390/kernel/binfmt_elf32.c210
-rw-r--r--arch/s390/kernel/bitmap.S56
-rw-r--r--arch/s390/kernel/compat_exec_domain.c30
-rw-r--r--arch/s390/kernel/compat_ioctl.c73
-rw-r--r--arch/s390/kernel/compat_linux.c1045
-rw-r--r--arch/s390/kernel/compat_linux.h197
-rw-r--r--arch/s390/kernel/compat_ptrace.h83
-rw-r--r--arch/s390/kernel/compat_signal.c648
-rw-r--r--arch/s390/kernel/compat_wrapper.S1443
-rw-r--r--arch/s390/kernel/cpcmd.c111
-rw-r--r--arch/s390/kernel/debug.c1286
-rw-r--r--arch/s390/kernel/ebcdic.c400
-rw-r--r--arch/s390/kernel/entry.S868
-rw-r--r--arch/s390/kernel/entry64.S881
-rw-r--r--arch/s390/kernel/head.S772
-rw-r--r--arch/s390/kernel/head64.S769
-rw-r--r--arch/s390/kernel/init_task.c44
-rw-r--r--arch/s390/kernel/irq.c105
-rw-r--r--arch/s390/kernel/module.c405
-rw-r--r--arch/s390/kernel/process.c416
-rw-r--r--arch/s390/kernel/profile.c20
-rw-r--r--arch/s390/kernel/ptrace.c738
-rw-r--r--arch/s390/kernel/reipl.S78
-rw-r--r--arch/s390/kernel/reipl64.S96
-rw-r--r--arch/s390/kernel/s390_ext.c135
-rw-r--r--arch/s390/kernel/s390_ksyms.c65
-rw-r--r--arch/s390/kernel/semaphore.c108
-rw-r--r--arch/s390/kernel/setup.c632
-rw-r--r--arch/s390/kernel/signal.c527
-rw-r--r--arch/s390/kernel/smp.c840
-rw-r--r--arch/s390/kernel/sys_s390.c270
-rw-r--r--arch/s390/kernel/syscalls.S292
-rw-r--r--arch/s390/kernel/time.c382
-rw-r--r--arch/s390/kernel/traps.c738
-rw-r--r--arch/s390/kernel/vmlinux.lds.S130
-rw-r--r--arch/s390/kernel/vtime.c565
-rw-r--r--arch/s390/lib/Makefile9
-rw-r--r--arch/s390/lib/delay.c51
-rw-r--r--arch/s390/lib/string.c381
-rw-r--r--arch/s390/lib/uaccess.S210
-rw-r--r--arch/s390/lib/uaccess64.S206
-rw-r--r--arch/s390/math-emu/Makefile8
-rw-r--r--arch/s390/math-emu/math.c2258
-rw-r--r--arch/s390/math-emu/qrnnd.S77
-rw-r--r--arch/s390/math-emu/sfp-util.h63
-rw-r--r--arch/s390/mm/Makefile7
-rw-r--r--arch/s390/mm/cmm.c443
-rw-r--r--arch/s390/mm/extmem.c588
-rw-r--r--arch/s390/mm/fault.c586
-rw-r--r--arch/s390/mm/init.c310
-rw-r--r--arch/s390/mm/ioremap.c138
-rw-r--r--arch/s390/mm/mmap.c86
-rw-r--r--arch/s390/oprofile/Kconfig22
-rw-r--r--arch/s390/oprofile/Makefile9
-rw-r--r--arch/s390/oprofile/init.c22
76 files changed, 24818 insertions, 0 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
new file mode 100644
index 000000000000..ab79af84699a
--- /dev/null
+++ b/arch/s390/Kconfig
@@ -0,0 +1,480 @@
1#
2# For a description of the syntax of this configuration file,
3# see Documentation/kbuild/kconfig-language.txt.
4#
5
6config MMU
7 bool
8 default y
9
10config RWSEM_GENERIC_SPINLOCK
11 bool
12
13config RWSEM_XCHGADD_ALGORITHM
14 bool
15 default y
16
17config GENERIC_CALIBRATE_DELAY
18 bool
19 default y
20
21config GENERIC_BUST_SPINLOCK
22 bool
23
24mainmenu "Linux Kernel Configuration"
25
26config ARCH_S390
27 bool
28 default y
29
30config UID16
31 bool
32 default y
33 depends on ARCH_S390X = 'n'
34
35source "init/Kconfig"
36
37menu "Base setup"
38
39comment "Processor type and features"
40
41config ARCH_S390X
42 bool "64 bit kernel"
43 help
44 Select this option if you have a 64 bit IBM zSeries machine
45 and want to use the 64 bit addressing mode.
46
47config 64BIT
48 def_bool ARCH_S390X
49
50config ARCH_S390_31
51 bool
52 depends on ARCH_S390X = 'n'
53 default y
54
55config SMP
56 bool "Symmetric multi-processing support"
57 ---help---
58 This enables support for systems with more than one CPU. If you have
59 a system with only one CPU, like most personal computers, say N. If
60 you have a system with more than one CPU, say Y.
61
62 If you say N here, the kernel will run on single and multiprocessor
63 machines, but will use only one CPU of a multiprocessor machine. If
64 you say Y here, the kernel will run on many, but not all,
65 singleprocessor machines. On a singleprocessor machine, the kernel
66 will run faster if you say N here.
67
68 See also the <file:Documentation/smp.txt> and the SMP-HOWTO
69 available at <http://www.tldp.org/docs.html#howto>.
70
71 Even if you don't know what to do here, say Y.
72
73config NR_CPUS
74 int "Maximum number of CPUs (2-64)"
75 range 2 64
76 depends on SMP
77 default "32"
78 help
79 This allows you to specify the maximum number of CPUs which this
80 kernel will support. The maximum supported value is 64 and the
81 minimum value which makes sense is 2.
82
83 This is purely to save memory - each supported CPU adds
84 approximately sixteen kilobytes to the kernel image.
85
86config HOTPLUG_CPU
87 bool "Support for hot-pluggable CPUs"
88 depends on SMP
89 select HOTPLUG
90 default n
91 help
92 Say Y here to be able to turn CPUs off and on. CPUs
93 can be controlled through /sys/devices/system/cpu/cpu#.
94 Say N if you want to disable CPU hotplug.
95
96config MATHEMU
97 bool "IEEE FPU emulation"
98 depends on MARCH_G5
99 help
100 This option is required for IEEE compliant floating point arithmetic
101 on older S/390 machines. Say Y unless you know your machine doesn't
102 need this.
103
104config S390_SUPPORT
105 bool "Kernel support for 31 bit emulation"
106 depends on ARCH_S390X
107 help
108 Select this option if you want to enable your system kernel to
109 handle system-calls from ELF binaries for 31 bit ESA. This option
110 (and some other stuff like libraries and such) is needed for
111 executing 31 bit applications. It is safe to say "Y".
112
113config COMPAT
114 bool
115 depends on S390_SUPPORT
116 default y
117
118config SYSVIPC_COMPAT
119 bool
120 depends on COMPAT && SYSVIPC
121 default y
122
123config BINFMT_ELF32
124 tristate "Kernel support for 31 bit ELF binaries"
125 depends on S390_SUPPORT
126 help
127 This allows you to run 32-bit Linux/ELF binaries on your zSeries
128 in 64 bit mode. Everybody wants this; say Y.
129
130comment "Code generation options"
131
132choice
133 prompt "Processor type"
134 default MARCH_G5
135
136config MARCH_G5
137 bool "S/390 model G5 and G6"
138 depends on ARCH_S390_31
139 help
140 Select this to build a 31 bit kernel that works
141 on all S/390 and zSeries machines.
142
143config MARCH_Z900
144 bool "IBM eServer zSeries model z800 and z900"
145 help
146 Select this to optimize for zSeries machines. This
147 will enable some optimizations that are not available
148 on older 31 bit only CPUs.
149
150config MARCH_Z990
151 bool "IBM eServer zSeries model z890 and z990"
152 help
153 Select this enable optimizations for model z890/z990.
154 This will be slightly faster but does not work on
155 older machines such as the z900.
156
157endchoice
158
159config PACK_STACK
160 bool "Pack kernel stack"
161 help
162 This option enables the compiler option -mkernel-backchain if it
163 is available. If the option is available the compiler supports
164 the new stack layout which dramatically reduces the minimum stack
165 frame size. With an old compiler a non-leaf function needs a
166 minimum of 96 bytes on 31 bit and 160 bytes on 64 bit. With
167 -mkernel-backchain the minimum size drops to 16 byte on 31 bit
168 and 24 byte on 64 bit.
169
170 Say Y if you are unsure.
171
172config SMALL_STACK
173 bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb"
174 depends on PACK_STACK
175 help
176 If you say Y here and the compiler supports the -mkernel-backchain
177 option the kernel will use a smaller kernel stack size. For 31 bit
178 the reduced size is 4kb instead of 8kb and for 64 bit it is 8kb
179 instead of 16kb. This allows to run more thread on a system and
180 reduces the pressure on the memory management for higher order
181 page allocations.
182
183 Say N if you are unsure.
184
185
186config CHECK_STACK
187 bool "Detect kernel stack overflow"
188 help
189 This option enables the compiler option -mstack-guard and
190 -mstack-size if they are available. If the compiler supports them
191 it will emit additional code to each function prolog to trigger
192 an illegal operation if the kernel stack is about to overflow.
193
194 Say N if you are unsure.
195
196config STACK_GUARD
197 int "Size of the guard area (128-1024)"
198 range 128 1024
199 depends on CHECK_STACK
200 default "256"
201 help
202 This allows you to specify the size of the guard area at the lower
203 end of the kernel stack. If the kernel stack points into the guard
204 area on function entry an illegal operation is triggered. The size
205 needs to be a power of 2. Please keep in mind that the size of an
206 interrupt frame is 184 bytes for 31 bit and 328 bytes on 64 bit.
207 The minimum size for the stack guard should be 256 for 31 bit and
208 512 for 64 bit.
209
210config WARN_STACK
211 bool "Emit compiler warnings for function with broken stack usage"
212 help
213 This option enables the compiler options -mwarn-framesize and
214 -mwarn-dynamicstack. If the compiler supports these options it
215 will generate warnings for function which either use alloca or
216 create a stack frame bigger then CONFIG_WARN_STACK_SIZE.
217
218 Say N if you are unsure.
219
220config WARN_STACK_SIZE
221 int "Maximum frame size considered safe (128-2048)"
222 range 128 2048
223 depends on WARN_STACK
224 default "256"
225 help
226 This allows you to specify the maximum frame size a function may
227 have without the compiler complaining about it.
228
229comment "I/O subsystem configuration"
230
231config MACHCHK_WARNING
232 bool "Process warning machine checks"
233 help
234 Select this option if you want the machine check handler on IBM S/390 or
235 zSeries to process warning machine checks (e.g. on power failures).
236 If unsure, say "Y".
237
238config QDIO
239 tristate "QDIO support"
240 ---help---
241 This driver provides the Queued Direct I/O base support for the
242 IBM S/390 (G5 and G6) and eServer zSeries (z800, z890, z900 and z990).
243
244 For details please refer to the documentation provided by IBM at
245 <http://www10.software.ibm.com/developerworks/opensource/linux390>
246
247 To compile this driver as a module, choose M here: the
248 module will be called qdio.
249
250 If unsure, say Y.
251
252config QDIO_PERF_STATS
253 bool "Performance statistics in /proc"
254 depends on QDIO
255 help
256 Say Y here to get performance statistics in /proc/qdio_perf
257
258 If unsure, say N.
259
260config QDIO_DEBUG
261 bool "Extended debugging information"
262 depends on QDIO
263 help
264 Say Y here to get extended debugging output in /proc/s390dbf/qdio...
265 Warning: this option reduces the performance of the QDIO module.
266
267 If unsure, say N.
268
269comment "Misc"
270
271config PREEMPT
272 bool "Preemptible Kernel"
273 help
274 This option reduces the latency of the kernel when reacting to
275 real-time or interactive events by allowing a low priority process to
276 be preempted even if it is in kernel mode executing a system call.
277 This allows applications to run more reliably even when the system is
278 under load.
279
280 Say N if you are unsure.
281
282config IPL
283 bool "Builtin IPL record support"
284 help
285 If you want to use the produced kernel to IPL directly from a
286 device, you have to merge a bootsector specific to the device
287 into the first bytes of the kernel. You will have to select the
288 IPL device.
289
290choice
291 prompt "IPL method generated into head.S"
292 depends on IPL
293 default IPL_TAPE
294 help
295 Select "tape" if you want to IPL the image from a Tape.
296
297 Select "vm_reader" if you are running under VM/ESA and want
298 to IPL the image from the emulated card reader.
299
300config IPL_TAPE
301 bool "tape"
302
303config IPL_VM
304 bool "vm_reader"
305
306endchoice
307
308source "fs/Kconfig.binfmt"
309
310config PROCESS_DEBUG
311 bool "Show crashed user process info"
312 help
313 Say Y to print all process fault locations to the console. This is
314 a debugging option; you probably do not want to set it unless you
315 are an S390 port maintainer.
316
317config PFAULT
318 bool "Pseudo page fault support"
319 help
320 Select this option, if you want to use PFAULT pseudo page fault
321 handling under VM. If running native or in LPAR, this option
322 has no effect. If your VM does not support PFAULT, PAGEEX
323 pseudo page fault handling will be used.
324 Note that VM 4.2 supports PFAULT but has a bug in its
325 implementation that causes some problems.
326 Everybody who wants to run Linux under VM != VM4.2 should select
327 this option.
328
329config SHARED_KERNEL
330 bool "VM shared kernel support"
331 help
332 Select this option, if you want to share the text segment of the
333 Linux kernel between different VM guests. This reduces memory
334 usage with lots of guests but greatly increases kernel size.
335 You should only select this option if you know what you are
336 doing and want to exploit this feature.
337
338config CMM
339 tristate "Cooperative memory management"
340 help
341 Select this option, if you want to enable the kernel interface
342 to reduce the memory size of the system. This is accomplished
343 by allocating pages of memory and put them "on hold". This only
344 makes sense for a system running under VM where the unused pages
345 will be reused by VM for other guest systems. The interface
346 allows an external monitor to balance memory of many systems.
347 Everybody who wants to run Linux under VM should select this
348 option.
349
350config CMM_PROC
351 bool "/proc interface to cooperative memory management"
352 depends on CMM
353 help
354 Select this option to enable the /proc interface to the
355 cooperative memory management.
356
357config CMM_IUCV
358 bool "IUCV special message interface to cooperative memory management"
359 depends on CMM && (SMSGIUCV=y || CMM=SMSGIUCV)
360 help
361 Select this option to enable the special message interface to
362 the cooperative memory management.
363
364config VIRT_TIMER
365 bool "Virtual CPU timer support"
366 help
367 This provides a kernel interface for virtual CPU timers.
368 Default is disabled.
369
370config VIRT_CPU_ACCOUNTING
371 bool "Base user process accounting on virtual cpu timer"
372 depends on VIRT_TIMER
373 help
374 Select this option to use CPU timer deltas to do user
375 process accounting.
376
377config APPLDATA_BASE
378 bool "Linux - VM Monitor Stream, base infrastructure"
379 depends on PROC_FS && VIRT_TIMER=y
380 help
381 This provides a kernel interface for creating and updating z/VM APPLDATA
382 monitor records. The monitor records are updated at certain time
383 intervals, once the timer is started.
384 Writing 1 or 0 to /proc/appldata/timer starts(1) or stops(0) the timer,
385 i.e. enables or disables monitoring on the Linux side.
386 A custom interval value (in seconds) can be written to
387 /proc/appldata/interval.
388
389 Defaults are 60 seconds interval and timer off.
390 The /proc entries can also be read from, showing the current settings.
391
392config APPLDATA_MEM
393 tristate "Monitor memory management statistics"
394 depends on APPLDATA_BASE
395 help
396 This provides memory management related data to the Linux - VM Monitor
397 Stream, like paging/swapping rate, memory utilisation, etc.
398 Writing 1 or 0 to /proc/appldata/memory creates(1) or removes(0) a z/VM
399 APPLDATA monitor record, i.e. enables or disables monitoring this record
400 on the z/VM side.
401
402 Default is disabled.
403 The /proc entry can also be read from, showing the current settings.
404
405 This can also be compiled as a module, which will be called
406 appldata_mem.o.
407
408config APPLDATA_OS
409 tristate "Monitor OS statistics"
410 depends on APPLDATA_BASE
411 help
412 This provides OS related data to the Linux - VM Monitor Stream, like
413 CPU utilisation, etc.
414 Writing 1 or 0 to /proc/appldata/os creates(1) or removes(0) a z/VM
415 APPLDATA monitor record, i.e. enables or disables monitoring this record
416 on the z/VM side.
417
418 Default is disabled.
419 This can also be compiled as a module, which will be called
420 appldata_os.o.
421
422config APPLDATA_NET_SUM
423 tristate "Monitor overall network statistics"
424 depends on APPLDATA_BASE
425 help
426 This provides network related data to the Linux - VM Monitor Stream,
427 currently there is only a total sum of network I/O statistics, no
428 per-interface data.
429 Writing 1 or 0 to /proc/appldata/net_sum creates(1) or removes(0) a z/VM
430 APPLDATA monitor record, i.e. enables or disables monitoring this record
431 on the z/VM side.
432
433 Default is disabled.
434 This can also be compiled as a module, which will be called
435 appldata_net_sum.o.
436
437config NO_IDLE_HZ
438 bool "No HZ timer ticks in idle"
439 help
440 Switches the regular HZ timer off when the system is going idle.
441 This helps z/VM to detect that the Linux system is idle. VM can
442 then "swap-out" this guest which reduces memory usage. It also
443 reduces the overhead of idle systems.
444
445 The HZ timer can be switched on/off via /proc/sys/kernel/hz_timer.
446 hz_timer=0 means HZ timer is disabled. hz_timer=1 means HZ
447 timer is active.
448
449config NO_IDLE_HZ_INIT
450 bool "HZ timer in idle off by default"
451 depends on NO_IDLE_HZ
452 help
453 The HZ timer is switched off in idle by default. That means the
454 HZ timer is already disabled at boot time.
455
456endmenu
457
458config PCMCIA
459 bool
460 default n
461
462source "drivers/base/Kconfig"
463
464source "drivers/scsi/Kconfig"
465
466source "drivers/s390/Kconfig"
467
468source "net/Kconfig"
469
470source "fs/Kconfig"
471
472source "arch/s390/oprofile/Kconfig"
473
474source "arch/s390/Kconfig.debug"
475
476source "security/Kconfig"
477
478source "crypto/Kconfig"
479
480source "lib/Kconfig"
diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug
new file mode 100644
index 000000000000..f53b6d5300e5
--- /dev/null
+++ b/arch/s390/Kconfig.debug
@@ -0,0 +1,5 @@
1menu "Kernel hacking"
2
3source "lib/Kconfig.debug"
4
5endmenu
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
new file mode 100644
index 000000000000..3cd8dd25c9d7
--- /dev/null
+++ b/arch/s390/Makefile
@@ -0,0 +1,116 @@
1#
2# s390/Makefile
3#
4# This file is included by the global makefile so that you can add your own
5# architecture-specific flags and dependencies. Remember to do have actions
6# for "archclean" and "archdep" for cleaning up and making dependencies for
7# this architecture
8#
9# This file is subject to the terms and conditions of the GNU General Public
10# License. See the file "COPYING" in the main directory of this archive
11# for more details.
12#
13# Copyright (C) 1994 by Linus Torvalds
14#
15
16ifdef CONFIG_ARCH_S390_31
17LDFLAGS := -m elf_s390
18CFLAGS += -m31
19AFLAGS += -m31
20UTS_MACHINE := s390
21STACK_SIZE := 8192
22endif
23
24ifdef CONFIG_ARCH_S390X
25LDFLAGS := -m elf64_s390
26MODFLAGS += -fpic -D__PIC__
27CFLAGS += -m64
28AFLAGS += -m64
29UTS_MACHINE := s390x
30STACK_SIZE := 16384
31endif
32
33cflags-$(CONFIG_MARCH_G5) += $(call cc-option,-march=g5)
34cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900)
35cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
36
37# old style option for packed stacks
38ifeq ($(call cc-option-yn,-mkernel-backchain),y)
39cflags-$(CONFIG_PACK_STACK) += -mkernel-backchain -D__PACK_STACK
40aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK
41cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
42aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
43ifdef CONFIG_SMALL_STACK
44STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) )
45endif
46endif
47
48# new style option for packed stacks
49ifeq ($(call cc-option-yn,-mpacked-stack),y)
50cflags-$(CONFIG_PACK_STACK) += -mpacked-stack -D__PACK_STACK
51aflags-$(CONFIG_PACK_STACK) += -D__PACK_STACK
52cflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
53aflags-$(CONFIG_SMALL_STACK) += -D__SMALL_STACK
54ifdef CONFIG_SMALL_STACK
55STACK_SIZE := $(shell echo $$(($(STACK_SIZE)/2)) )
56endif
57endif
58
59ifeq ($(call cc-option-yn,-mstack-size=8192 -mstack-guard=128),y)
60cflags-$(CONFIG_CHECK_STACK) += -mstack-size=$(STACK_SIZE)
61cflags-$(CONFIG_CHECK_STACK) += -mstack-guard=$(CONFIG_STACK_GUARD)
62endif
63
64ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
65cflags-$(CONFIG_WARN_STACK) += -mwarn-dynamicstack
66cflags-$(CONFIG_WARN_STACK) += -mwarn-framesize=$(CONFIG_WARN_STACK_SIZE)
67endif
68
69CFLAGS += -mbackchain -msoft-float $(cflags-y)
70CFLAGS += $(call cc-option,-finline-limit=10000)
71CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare
72AFLAGS += $(aflags-y)
73
74OBJCOPYFLAGS := -O binary
75LDFLAGS_vmlinux := -e start
76
77head-$(CONFIG_ARCH_S390_31) += arch/$(ARCH)/kernel/head.o
78head-$(CONFIG_ARCH_S390X) += arch/$(ARCH)/kernel/head64.o
79head-y += arch/$(ARCH)/kernel/init_task.o
80
81core-y += arch/$(ARCH)/mm/ arch/$(ARCH)/kernel/ arch/$(ARCH)/crypto/ \
82 arch/$(ARCH)/appldata/
83libs-y += arch/$(ARCH)/lib/
84drivers-y += drivers/s390/
85drivers-$(CONFIG_MATHEMU) += arch/$(ARCH)/math-emu/
86
87# must be linked after kernel
88drivers-$(CONFIG_OPROFILE) += arch/s390/oprofile/
89
90boot := arch/$(ARCH)/boot
91
92all: image
93
94install: vmlinux
95 $(Q)$(MAKE) $(build)=$(boot) $@
96
97image: vmlinux
98 $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
99
100archclean:
101 $(Q)$(MAKE) $(clean)=$(boot)
102
103prepare: include/asm-$(ARCH)/offsets.h
104
105arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
106 include/config/MARKER
107
108include/asm-$(ARCH)/offsets.h: arch/$(ARCH)/kernel/asm-offsets.s
109 $(call filechk,gen-asm-offsets)
110
111CLEAN_FILES += include/asm-$(ARCH)/offsets.h
112
113# Don't use tabs in echo arguments
114define archhelp
115 echo '* image - Kernel image for IPL ($(boot)/image)'
116endef
diff --git a/arch/s390/appldata/Makefile b/arch/s390/appldata/Makefile
new file mode 100644
index 000000000000..99f1cf071304
--- /dev/null
+++ b/arch/s390/appldata/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for the Linux - z/VM Monitor Stream.
3#
4
5obj-$(CONFIG_APPLDATA_BASE) += appldata_base.o
6obj-$(CONFIG_APPLDATA_MEM) += appldata_mem.o
7obj-$(CONFIG_APPLDATA_OS) += appldata_os.o
8obj-$(CONFIG_APPLDATA_NET_SUM) += appldata_net_sum.o
diff --git a/arch/s390/appldata/appldata.h b/arch/s390/appldata/appldata.h
new file mode 100644
index 000000000000..e806a8922bbb
--- /dev/null
+++ b/arch/s390/appldata/appldata.h
@@ -0,0 +1,59 @@
1/*
2 * arch/s390/appldata/appldata.h
3 *
4 * Definitions and interface for Linux - z/VM Monitor Stream.
5 *
6 * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
7 *
8 * Author: Gerald Schaefer <geraldsc@de.ibm.com>
9 */
10
11//#define APPLDATA_DEBUG /* Debug messages on/off */
12
13#define APPLDATA_MAX_REC_SIZE 4024 /* Maximum size of the */
14 /* data buffer */
15#define APPLDATA_MAX_PROCS 100
16
17#define APPLDATA_PROC_NAME_LENGTH 16 /* Max. length of /proc name */
18
19#define APPLDATA_RECORD_MEM_ID 0x01 /* IDs to identify the */
20#define APPLDATA_RECORD_OS_ID 0x02 /* individual records, */
21#define APPLDATA_RECORD_NET_SUM_ID 0x03 /* must be < 256 ! */
22#define APPLDATA_RECORD_PROC_ID 0x04
23
24#define CTL_APPLDATA 2120 /* sysctl IDs, must be unique */
25#define CTL_APPLDATA_TIMER 2121
26#define CTL_APPLDATA_INTERVAL 2122
27#define CTL_APPLDATA_MEM 2123
28#define CTL_APPLDATA_OS 2124
29#define CTL_APPLDATA_NET_SUM 2125
30#define CTL_APPLDATA_PROC 2126
31
32#define P_INFO(x...) printk(KERN_INFO MY_PRINT_NAME " info: " x)
33#define P_ERROR(x...) printk(KERN_ERR MY_PRINT_NAME " error: " x)
34#define P_WARNING(x...) printk(KERN_WARNING MY_PRINT_NAME " status: " x)
35
36#ifdef APPLDATA_DEBUG
37#define P_DEBUG(x...) printk(KERN_DEBUG MY_PRINT_NAME " debug: " x)
38#else
39#define P_DEBUG(x...) do {} while (0)
40#endif
41
42struct appldata_ops {
43 struct list_head list;
44 struct ctl_table_header *sysctl_header;
45 struct ctl_table *ctl_table;
46 int active; /* monitoring status */
47
48 /* fill in from here */
49 unsigned int ctl_nr; /* sysctl ID */
50 char name[APPLDATA_PROC_NAME_LENGTH]; /* name of /proc fs node */
51 unsigned char record_nr; /* Record Nr. for Product ID */
52 void (*callback)(void *data); /* callback function */
53 void *data; /* record data */
54 unsigned int size; /* size of record */
55 struct module *owner; /* THIS_MODULE */
56};
57
58extern int appldata_register_ops(struct appldata_ops *ops);
59extern void appldata_unregister_ops(struct appldata_ops *ops);
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
new file mode 100644
index 000000000000..01ae1964c938
--- /dev/null
+++ b/arch/s390/appldata/appldata_base.c
@@ -0,0 +1,770 @@
1/*
2 * arch/s390/appldata/appldata_base.c
3 *
4 * Base infrastructure for Linux-z/VM Monitor Stream, Stage 1.
5 * Exports appldata_register_ops() and appldata_unregister_ops() for the
6 * data gathering modules.
7 *
8 * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
9 *
10 * Author: Gerald Schaefer <geraldsc@de.ibm.com>
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/errno.h>
18#include <asm/uaccess.h>
19#include <asm/io.h>
20#include <asm/smp.h>
21#include <linux/interrupt.h>
22#include <linux/proc_fs.h>
23#include <linux/page-flags.h>
24#include <linux/swap.h>
25#include <linux/pagemap.h>
26#include <linux/sysctl.h>
27#include <asm/timer.h>
28//#include <linux/kernel_stat.h>
29#include <linux/notifier.h>
30#include <linux/cpu.h>
31
32#include "appldata.h"
33
34
35#define MY_PRINT_NAME "appldata" /* for debug messages, etc. */
36#define APPLDATA_CPU_INTERVAL 10000 /* default (CPU) time for
37 sampling interval in
38 milliseconds */
39
40#define TOD_MICRO 0x01000 /* nr. of TOD clock units
41 for 1 microsecond */
42#ifndef CONFIG_ARCH_S390X
43
44#define APPLDATA_START_INTERVAL_REC 0x00 /* Function codes for */
45#define APPLDATA_STOP_REC 0x01 /* DIAG 0xDC */
46#define APPLDATA_GEN_EVENT_RECORD 0x02
47#define APPLDATA_START_CONFIG_REC 0x03
48
49#else
50
51#define APPLDATA_START_INTERVAL_REC 0x80
52#define APPLDATA_STOP_REC 0x81
53#define APPLDATA_GEN_EVENT_RECORD 0x82
54#define APPLDATA_START_CONFIG_REC 0x83
55
56#endif /* CONFIG_ARCH_S390X */
57
58
59/*
60 * Parameter list for DIAGNOSE X'DC'
61 */
62#ifndef CONFIG_ARCH_S390X
63struct appldata_parameter_list {
64 u16 diag; /* The DIAGNOSE code X'00DC' */
65 u8 function; /* The function code for the DIAGNOSE */
66 u8 parlist_length; /* Length of the parameter list */
67 u32 product_id_addr; /* Address of the 16-byte product ID */
68 u16 reserved;
69 u16 buffer_length; /* Length of the application data buffer */
70 u32 buffer_addr; /* Address of the application data buffer */
71};
72#else
73struct appldata_parameter_list {
74 u16 diag;
75 u8 function;
76 u8 parlist_length;
77 u32 unused01;
78 u16 reserved;
79 u16 buffer_length;
80 u32 unused02;
81 u64 product_id_addr;
82 u64 buffer_addr;
83};
84#endif /* CONFIG_ARCH_S390X */
85
86/*
87 * /proc entries (sysctl)
88 */
89static const char appldata_proc_name[APPLDATA_PROC_NAME_LENGTH] = "appldata";
90static int appldata_timer_handler(ctl_table *ctl, int write, struct file *filp,
91 void __user *buffer, size_t *lenp, loff_t *ppos);
92static int appldata_interval_handler(ctl_table *ctl, int write,
93 struct file *filp,
94 void __user *buffer,
95 size_t *lenp, loff_t *ppos);
96
97static struct ctl_table_header *appldata_sysctl_header;
98static struct ctl_table appldata_table[] = {
99 {
100 .ctl_name = CTL_APPLDATA_TIMER,
101 .procname = "timer",
102 .mode = S_IRUGO | S_IWUSR,
103 .proc_handler = &appldata_timer_handler,
104 },
105 {
106 .ctl_name = CTL_APPLDATA_INTERVAL,
107 .procname = "interval",
108 .mode = S_IRUGO | S_IWUSR,
109 .proc_handler = &appldata_interval_handler,
110 },
111 { .ctl_name = 0 }
112};
113
114static struct ctl_table appldata_dir_table[] = {
115 {
116 .ctl_name = CTL_APPLDATA,
117 .procname = appldata_proc_name,
118 .maxlen = 0,
119 .mode = S_IRUGO | S_IXUGO,
120 .child = appldata_table,
121 },
122 { .ctl_name = 0 }
123};
124
125/*
126 * Timer
127 */
128DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
129static atomic_t appldata_expire_count = ATOMIC_INIT(0);
130
131static DEFINE_SPINLOCK(appldata_timer_lock);
132static int appldata_interval = APPLDATA_CPU_INTERVAL;
133static int appldata_timer_active;
134
135/*
136 * Tasklet
137 */
138static struct tasklet_struct appldata_tasklet_struct;
139
140/*
141 * Ops list
142 */
143static DEFINE_SPINLOCK(appldata_ops_lock);
144static LIST_HEAD(appldata_ops_list);
145
146
147/************************* timer, tasklet, DIAG ******************************/
148/*
149 * appldata_timer_function()
150 *
151 * schedule tasklet and reschedule timer
152 */
153static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
154{
155 P_DEBUG(" -= Timer =-\n");
156 P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(),
157 atomic_read(&appldata_expire_count));
158 if (atomic_dec_and_test(&appldata_expire_count)) {
159 atomic_set(&appldata_expire_count, num_online_cpus());
160 tasklet_schedule((struct tasklet_struct *) data);
161 }
162}
163
164/*
165 * appldata_tasklet_function()
166 *
167 * call data gathering function for each (active) module
168 */
169static void appldata_tasklet_function(unsigned long data)
170{
171 struct list_head *lh;
172 struct appldata_ops *ops;
173 int i;
174
175 P_DEBUG(" -= Tasklet =-\n");
176 i = 0;
177 spin_lock(&appldata_ops_lock);
178 list_for_each(lh, &appldata_ops_list) {
179 ops = list_entry(lh, struct appldata_ops, list);
180 P_DEBUG("list_for_each loop: %i) active = %u, name = %s\n",
181 ++i, ops->active, ops->name);
182 if (ops->active == 1) {
183 ops->callback(ops->data);
184 }
185 }
186 spin_unlock(&appldata_ops_lock);
187}
188
189/*
190 * appldata_diag()
191 *
192 * prepare parameter list, issue DIAG 0xDC
193 */
194static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
195 u16 length)
196{
197 unsigned long ry;
198 struct appldata_product_id {
199 char prod_nr[7]; /* product nr. */
200 char prod_fn[2]; /* product function */
201 char record_nr; /* record nr. */
202 char version_nr[2]; /* version */
203 char release_nr[2]; /* release */
204 char mod_lvl[2]; /* modification lvl. */
205 } appldata_product_id = {
206 /* all strings are EBCDIC, record_nr is byte */
207 .prod_nr = {0xD3, 0xC9, 0xD5, 0xE4,
208 0xE7, 0xD2, 0xD9}, /* "LINUXKR" */
209 .prod_fn = {0xD5, 0xD3}, /* "NL" */
210 .record_nr = record_nr,
211 .version_nr = {0xF2, 0xF6}, /* "26" */
212 .release_nr = {0xF0, 0xF1}, /* "01" */
213 .mod_lvl = {0xF0, 0xF0}, /* "00" */
214 };
215 struct appldata_parameter_list appldata_parameter_list = {
216 .diag = 0xDC,
217 .function = function,
218 .parlist_length =
219 sizeof(appldata_parameter_list),
220 .buffer_length = length,
221 .product_id_addr =
222 (unsigned long) &appldata_product_id,
223 .buffer_addr = virt_to_phys((void *) buffer)
224 };
225
226 if (!MACHINE_IS_VM)
227 return -ENOSYS;
228 ry = -1;
229 asm volatile(
230 "diag %1,%0,0xDC\n\t"
231 : "=d" (ry) : "d" (&(appldata_parameter_list)) : "cc");
232 return (int) ry;
233}
234/********************** timer, tasklet, DIAG <END> ***************************/
235
236
237/****************************** /proc stuff **********************************/
238
239/*
240 * appldata_mod_vtimer_wrap()
241 *
242 * wrapper function for mod_virt_timer(), because smp_call_function_on()
243 * accepts only one parameter.
244 */
245static void __appldata_mod_vtimer_wrap(void *p) {
246 struct {
247 struct vtimer_list *timer;
248 u64 expires;
249 } *args = p;
250 mod_virt_timer(args->timer, args->expires);
251}
252
253#define APPLDATA_ADD_TIMER 0
254#define APPLDATA_DEL_TIMER 1
255#define APPLDATA_MOD_TIMER 2
256
257/*
258 * __appldata_vtimer_setup()
259 *
260 * Add, delete or modify virtual timers on all online cpus.
261 * The caller needs to get the appldata_timer_lock spinlock.
262 */
263static void
264__appldata_vtimer_setup(int cmd)
265{
266 u64 per_cpu_interval;
267 int i;
268
269 switch (cmd) {
270 case APPLDATA_ADD_TIMER:
271 if (appldata_timer_active)
272 break;
273 per_cpu_interval = (u64) (appldata_interval*1000 /
274 num_online_cpus()) * TOD_MICRO;
275 for_each_online_cpu(i) {
276 per_cpu(appldata_timer, i).expires = per_cpu_interval;
277 smp_call_function_on(add_virt_timer_periodic,
278 &per_cpu(appldata_timer, i),
279 0, 1, i);
280 }
281 appldata_timer_active = 1;
282 P_INFO("Monitoring timer started.\n");
283 break;
284 case APPLDATA_DEL_TIMER:
285 for_each_online_cpu(i)
286 del_virt_timer(&per_cpu(appldata_timer, i));
287 if (!appldata_timer_active)
288 break;
289 appldata_timer_active = 0;
290 atomic_set(&appldata_expire_count, num_online_cpus());
291 P_INFO("Monitoring timer stopped.\n");
292 break;
293 case APPLDATA_MOD_TIMER:
294 per_cpu_interval = (u64) (appldata_interval*1000 /
295 num_online_cpus()) * TOD_MICRO;
296 if (!appldata_timer_active)
297 break;
298 for_each_online_cpu(i) {
299 struct {
300 struct vtimer_list *timer;
301 u64 expires;
302 } args;
303 args.timer = &per_cpu(appldata_timer, i);
304 args.expires = per_cpu_interval;
305 smp_call_function_on(__appldata_mod_vtimer_wrap,
306 &args, 0, 1, i);
307 }
308 }
309}
310
311/*
312 * appldata_timer_handler()
313 *
314 * Start/Stop timer, show status of timer (0 = not active, 1 = active)
315 */
316static int
317appldata_timer_handler(ctl_table *ctl, int write, struct file *filp,
318 void __user *buffer, size_t *lenp, loff_t *ppos)
319{
320 int len;
321 char buf[2];
322
323 if (!*lenp || *ppos) {
324 *lenp = 0;
325 return 0;
326 }
327 if (!write) {
328 len = sprintf(buf, appldata_timer_active ? "1\n" : "0\n");
329 if (len > *lenp)
330 len = *lenp;
331 if (copy_to_user(buffer, buf, len))
332 return -EFAULT;
333 goto out;
334 }
335 len = *lenp;
336 if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len))
337 return -EFAULT;
338 spin_lock(&appldata_timer_lock);
339 if (buf[0] == '1')
340 __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
341 else if (buf[0] == '0')
342 __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
343 spin_unlock(&appldata_timer_lock);
344out:
345 *lenp = len;
346 *ppos += len;
347 return 0;
348}
349
350/*
351 * appldata_interval_handler()
352 *
353 * Set (CPU) timer interval for collection of data (in milliseconds), show
354 * current timer interval.
355 */
356static int
357appldata_interval_handler(ctl_table *ctl, int write, struct file *filp,
358 void __user *buffer, size_t *lenp, loff_t *ppos)
359{
360 int len, interval;
361 char buf[16];
362
363 if (!*lenp || *ppos) {
364 *lenp = 0;
365 return 0;
366 }
367 if (!write) {
368 len = sprintf(buf, "%i\n", appldata_interval);
369 if (len > *lenp)
370 len = *lenp;
371 if (copy_to_user(buffer, buf, len))
372 return -EFAULT;
373 goto out;
374 }
375 len = *lenp;
376 if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) {
377 return -EFAULT;
378 }
379 sscanf(buf, "%i", &interval);
380 if (interval <= 0) {
381 P_ERROR("Timer CPU interval has to be > 0!\n");
382 return -EINVAL;
383 }
384
385 spin_lock(&appldata_timer_lock);
386 appldata_interval = interval;
387 __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
388 spin_unlock(&appldata_timer_lock);
389
390 P_INFO("Monitoring CPU interval set to %u milliseconds.\n",
391 interval);
392out:
393 *lenp = len;
394 *ppos += len;
395 return 0;
396}
397
398/*
399 * appldata_generic_handler()
400 *
401 * Generic start/stop monitoring and DIAG, show status of
402 * monitoring (0 = not in process, 1 = in process)
403 */
404static int
405appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
406 void __user *buffer, size_t *lenp, loff_t *ppos)
407{
408 struct appldata_ops *ops = NULL, *tmp_ops;
409 int rc, len, found;
410 char buf[2];
411 struct list_head *lh;
412
413 found = 0;
414 spin_lock_bh(&appldata_ops_lock);
415 list_for_each(lh, &appldata_ops_list) {
416 tmp_ops = list_entry(lh, struct appldata_ops, list);
417 if (&tmp_ops->ctl_table[2] == ctl) {
418 found = 1;
419 }
420 }
421 if (!found) {
422 spin_unlock_bh(&appldata_ops_lock);
423 return -ENODEV;
424 }
425 ops = ctl->data;
426 if (!try_module_get(ops->owner)) { // protect this function
427 spin_unlock_bh(&appldata_ops_lock);
428 return -ENODEV;
429 }
430 spin_unlock_bh(&appldata_ops_lock);
431
432 if (!*lenp || *ppos) {
433 *lenp = 0;
434 module_put(ops->owner);
435 return 0;
436 }
437 if (!write) {
438 len = sprintf(buf, ops->active ? "1\n" : "0\n");
439 if (len > *lenp)
440 len = *lenp;
441 if (copy_to_user(buffer, buf, len)) {
442 module_put(ops->owner);
443 return -EFAULT;
444 }
445 goto out;
446 }
447 len = *lenp;
448 if (copy_from_user(buf, buffer,
449 len > sizeof(buf) ? sizeof(buf) : len)) {
450 module_put(ops->owner);
451 return -EFAULT;
452 }
453
454 spin_lock_bh(&appldata_ops_lock);
455 if ((buf[0] == '1') && (ops->active == 0)) {
456 if (!try_module_get(ops->owner)) { // protect tasklet
457 spin_unlock_bh(&appldata_ops_lock);
458 module_put(ops->owner);
459 return -ENODEV;
460 }
461 ops->active = 1;
462 ops->callback(ops->data); // init record
463 rc = appldata_diag(ops->record_nr,
464 APPLDATA_START_INTERVAL_REC,
465 (unsigned long) ops->data, ops->size);
466 if (rc != 0) {
467 P_ERROR("START DIAG 0xDC for %s failed, "
468 "return code: %d\n", ops->name, rc);
469 module_put(ops->owner);
470 ops->active = 0;
471 } else {
472 P_INFO("Monitoring %s data enabled, "
473 "DIAG 0xDC started.\n", ops->name);
474 }
475 } else if ((buf[0] == '0') && (ops->active == 1)) {
476 ops->active = 0;
477 rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
478 (unsigned long) ops->data, ops->size);
479 if (rc != 0) {
480 P_ERROR("STOP DIAG 0xDC for %s failed, "
481 "return code: %d\n", ops->name, rc);
482 } else {
483 P_INFO("Monitoring %s data disabled, "
484 "DIAG 0xDC stopped.\n", ops->name);
485 }
486 module_put(ops->owner);
487 }
488 spin_unlock_bh(&appldata_ops_lock);
489out:
490 *lenp = len;
491 *ppos += len;
492 module_put(ops->owner);
493 return 0;
494}
495
496/*************************** /proc stuff <END> *******************************/
497
498
499/************************* module-ops management *****************************/
500/*
501 * appldata_register_ops()
502 *
503 * update ops list, register /proc/sys entries
504 */
505int appldata_register_ops(struct appldata_ops *ops)
506{
507 struct list_head *lh;
508 struct appldata_ops *tmp_ops;
509 int i;
510
511 i = 0;
512
513 if ((ops->size > APPLDATA_MAX_REC_SIZE) ||
514 (ops->size < 0)){
515 P_ERROR("Invalid size of %s record = %i, maximum = %i!\n",
516 ops->name, ops->size, APPLDATA_MAX_REC_SIZE);
517 return -ENOMEM;
518 }
519 if ((ops->ctl_nr == CTL_APPLDATA) ||
520 (ops->ctl_nr == CTL_APPLDATA_TIMER) ||
521 (ops->ctl_nr == CTL_APPLDATA_INTERVAL)) {
522 P_ERROR("ctl_nr %i already in use!\n", ops->ctl_nr);
523 return -EBUSY;
524 }
525 ops->ctl_table = kmalloc(4*sizeof(struct ctl_table), GFP_KERNEL);
526 if (ops->ctl_table == NULL) {
527 P_ERROR("Not enough memory for %s ctl_table!\n", ops->name);
528 return -ENOMEM;
529 }
530 memset(ops->ctl_table, 0, 4*sizeof(struct ctl_table));
531
532 spin_lock_bh(&appldata_ops_lock);
533 list_for_each(lh, &appldata_ops_list) {
534 tmp_ops = list_entry(lh, struct appldata_ops, list);
535 P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n",
536 ++i, tmp_ops->name, tmp_ops->ctl_nr);
537 P_DEBUG("Comparing %s (ctl %i) with %s (ctl %i)\n",
538 tmp_ops->name, tmp_ops->ctl_nr, ops->name,
539 ops->ctl_nr);
540 if (strncmp(tmp_ops->name, ops->name,
541 APPLDATA_PROC_NAME_LENGTH) == 0) {
542 P_ERROR("Name \"%s\" already registered!\n", ops->name);
543 kfree(ops->ctl_table);
544 spin_unlock_bh(&appldata_ops_lock);
545 return -EBUSY;
546 }
547 if (tmp_ops->ctl_nr == ops->ctl_nr) {
548 P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr);
549 kfree(ops->ctl_table);
550 spin_unlock_bh(&appldata_ops_lock);
551 return -EBUSY;
552 }
553 }
554 list_add(&ops->list, &appldata_ops_list);
555 spin_unlock_bh(&appldata_ops_lock);
556
557 ops->ctl_table[0].ctl_name = CTL_APPLDATA;
558 ops->ctl_table[0].procname = appldata_proc_name;
559 ops->ctl_table[0].maxlen = 0;
560 ops->ctl_table[0].mode = S_IRUGO | S_IXUGO;
561 ops->ctl_table[0].child = &ops->ctl_table[2];
562
563 ops->ctl_table[1].ctl_name = 0;
564
565 ops->ctl_table[2].ctl_name = ops->ctl_nr;
566 ops->ctl_table[2].procname = ops->name;
567 ops->ctl_table[2].mode = S_IRUGO | S_IWUSR;
568 ops->ctl_table[2].proc_handler = appldata_generic_handler;
569 ops->ctl_table[2].data = ops;
570
571 ops->ctl_table[3].ctl_name = 0;
572
573 ops->sysctl_header = register_sysctl_table(ops->ctl_table,1);
574
575 P_INFO("%s-ops registered!\n", ops->name);
576 return 0;
577}
578
579/*
580 * appldata_unregister_ops()
581 *
582 * update ops list, unregister /proc entries, stop DIAG if necessary
583 */
584void appldata_unregister_ops(struct appldata_ops *ops)
585{
586 spin_lock_bh(&appldata_ops_lock);
587 unregister_sysctl_table(ops->sysctl_header);
588 list_del(&ops->list);
589 kfree(ops->ctl_table);
590 ops->ctl_table = NULL;
591 spin_unlock_bh(&appldata_ops_lock);
592 P_INFO("%s-ops unregistered!\n", ops->name);
593}
594/********************** module-ops management <END> **************************/
595
596
597/******************************* init / exit *********************************/
598
599static void
600appldata_online_cpu(int cpu)
601{
602 init_virt_timer(&per_cpu(appldata_timer, cpu));
603 per_cpu(appldata_timer, cpu).function = appldata_timer_function;
604 per_cpu(appldata_timer, cpu).data = (unsigned long)
605 &appldata_tasklet_struct;
606 atomic_inc(&appldata_expire_count);
607 spin_lock(&appldata_timer_lock);
608 __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
609 spin_unlock(&appldata_timer_lock);
610}
611
612static void
613appldata_offline_cpu(int cpu)
614{
615 del_virt_timer(&per_cpu(appldata_timer, cpu));
616 if (atomic_dec_and_test(&appldata_expire_count)) {
617 atomic_set(&appldata_expire_count, num_online_cpus());
618 tasklet_schedule(&appldata_tasklet_struct);
619 }
620 spin_lock(&appldata_timer_lock);
621 __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
622 spin_unlock(&appldata_timer_lock);
623}
624
625static int
626appldata_cpu_notify(struct notifier_block *self,
627 unsigned long action, void *hcpu)
628{
629 switch (action) {
630 case CPU_ONLINE:
631 appldata_online_cpu((long) hcpu);
632 break;
633#ifdef CONFIG_HOTPLUG_CPU
634 case CPU_DEAD:
635 appldata_offline_cpu((long) hcpu);
636 break;
637#endif
638 default:
639 break;
640 }
641 return NOTIFY_OK;
642}
643
644static struct notifier_block __devinitdata appldata_nb = {
645 .notifier_call = appldata_cpu_notify,
646};
647
648/*
649 * appldata_init()
650 *
651 * init timer and tasklet, register /proc entries
652 */
653static int __init appldata_init(void)
654{
655 int i;
656
657 P_DEBUG("sizeof(parameter_list) = %lu\n",
658 sizeof(struct appldata_parameter_list));
659
660 for_each_online_cpu(i)
661 appldata_online_cpu(i);
662
663 /* Register cpu hotplug notifier */
664 register_cpu_notifier(&appldata_nb);
665
666 appldata_sysctl_header = register_sysctl_table(appldata_dir_table, 1);
667#ifdef MODULE
668 appldata_dir_table[0].de->owner = THIS_MODULE;
669 appldata_table[0].de->owner = THIS_MODULE;
670 appldata_table[1].de->owner = THIS_MODULE;
671#endif
672
673 tasklet_init(&appldata_tasklet_struct, appldata_tasklet_function, 0);
674 P_DEBUG("Base interface initialized.\n");
675 return 0;
676}
677
678/*
679 * appldata_exit()
680 *
681 * stop timer and tasklet, unregister /proc entries
682 */
683static void __exit appldata_exit(void)
684{
685 struct list_head *lh;
686 struct appldata_ops *ops;
687 int rc, i;
688
689 P_DEBUG("Unloading module ...\n");
690 /*
691 * ops list should be empty, but just in case something went wrong...
692 */
693 spin_lock_bh(&appldata_ops_lock);
694 list_for_each(lh, &appldata_ops_list) {
695 ops = list_entry(lh, struct appldata_ops, list);
696 rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
697 (unsigned long) ops->data, ops->size);
698 if (rc != 0) {
699 P_ERROR("STOP DIAG 0xDC for %s failed, "
700 "return code: %d\n", ops->name, rc);
701 }
702 }
703 spin_unlock_bh(&appldata_ops_lock);
704
705 for_each_online_cpu(i)
706 appldata_offline_cpu(i);
707
708 appldata_timer_active = 0;
709
710 unregister_sysctl_table(appldata_sysctl_header);
711
712 tasklet_kill(&appldata_tasklet_struct);
713 P_DEBUG("... module unloaded!\n");
714}
715/**************************** init / exit <END> ******************************/
716
717
718module_init(appldata_init);
719module_exit(appldata_exit);
720MODULE_LICENSE("GPL");
721MODULE_AUTHOR("Gerald Schaefer");
722MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
723
724EXPORT_SYMBOL_GPL(appldata_register_ops);
725EXPORT_SYMBOL_GPL(appldata_unregister_ops);
726
727#ifdef MODULE
728/*
729 * Kernel symbols needed by appldata_mem and appldata_os modules.
730 * However, if this file is compiled as a module (for testing only), these
731 * symbols are not exported. In this case, we define them locally and export
732 * those.
733 */
734void si_swapinfo(struct sysinfo *val)
735{
736 val->freeswap = -1ul;
737 val->totalswap = -1ul;
738}
739
740unsigned long avenrun[3] = {-1 - FIXED_1/200, -1 - FIXED_1/200,
741 -1 - FIXED_1/200};
742int nr_threads = -1;
743
744void get_full_page_state(struct page_state *ps)
745{
746 memset(ps, -1, sizeof(struct page_state));
747}
748
749unsigned long nr_running(void)
750{
751 return -1;
752}
753
754unsigned long nr_iowait(void)
755{
756 return -1;
757}
758
759/*unsigned long nr_context_switches(void)
760{
761 return -1;
762}*/
763#endif /* MODULE */
764EXPORT_SYMBOL_GPL(si_swapinfo);
765EXPORT_SYMBOL_GPL(nr_threads);
766EXPORT_SYMBOL_GPL(avenrun);
767EXPORT_SYMBOL_GPL(get_full_page_state);
768EXPORT_SYMBOL_GPL(nr_running);
769EXPORT_SYMBOL_GPL(nr_iowait);
770//EXPORT_SYMBOL_GPL(nr_context_switches);
diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c
new file mode 100644
index 000000000000..462ee9a84e76
--- /dev/null
+++ b/arch/s390/appldata/appldata_mem.c
@@ -0,0 +1,195 @@
1/*
2 * arch/s390/appldata/appldata_mem.c
3 *
4 * Data gathering module for Linux-VM Monitor Stream, Stage 1.
5 * Collects data related to memory management.
6 *
7 * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
8 *
9 * Author: Gerald Schaefer <geraldsc@de.ibm.com>
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/errno.h>
17#include <linux/kernel_stat.h>
18#include <asm/io.h>
19#include <linux/pagemap.h>
20#include <linux/swap.h>
21
22#include "appldata.h"
23
24
25#define MY_PRINT_NAME "appldata_mem" /* for debug messages, etc. */
26#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* Converts #Pages to KB */
27
28/*
29 * Memory data
30 *
31 * This is accessed as binary data by z/VM. If changes to it can't be avoided,
32 * the structure version (product ID, see appldata_base.c) needs to be changed
33 * as well and all documentation and z/VM applications using it must be
34 * updated.
35 *
36 * The record layout is documented in the Linux for zSeries Device Drivers
37 * book:
38 * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
39 */
40struct appldata_mem_data {
41 u64 timestamp;
42 u32 sync_count_1; /* after VM collected the record data, */
43 u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
44 same. If not, the record has been updated on
45 the Linux side while VM was collecting the
46 (possibly corrupt) data */
47
48 u64 pgpgin; /* data read from disk */
49 u64 pgpgout; /* data written to disk */
50 u64 pswpin; /* pages swapped in */
51 u64 pswpout; /* pages swapped out */
52
53 u64 sharedram; /* sharedram is currently set to 0 */
54
55 u64 totalram; /* total main memory size */
56 u64 freeram; /* free main memory size */
57 u64 totalhigh; /* total high memory size */
58 u64 freehigh; /* free high memory size */
59
60 u64 bufferram; /* memory reserved for buffers, free cache */
61 u64 cached; /* size of (used) cache, w/o buffers */
62 u64 totalswap; /* total swap space size */
63 u64 freeswap; /* free swap space */
64
65// New in 2.6 -->
66 u64 pgalloc; /* page allocations */
67 u64 pgfault; /* page faults (major+minor) */
68 u64 pgmajfault; /* page faults (major only) */
69// <-- New in 2.6
70
71} appldata_mem_data;
72
73
74static inline void appldata_debug_print(struct appldata_mem_data *mem_data)
75{
76 P_DEBUG("--- MEM - RECORD ---\n");
77 P_DEBUG("pgpgin = %8lu KB\n", mem_data->pgpgin);
78 P_DEBUG("pgpgout = %8lu KB\n", mem_data->pgpgout);
79 P_DEBUG("pswpin = %8lu Pages\n", mem_data->pswpin);
80 P_DEBUG("pswpout = %8lu Pages\n", mem_data->pswpout);
81 P_DEBUG("pgalloc = %8lu \n", mem_data->pgalloc);
82 P_DEBUG("pgfault = %8lu \n", mem_data->pgfault);
83 P_DEBUG("pgmajfault = %8lu \n", mem_data->pgmajfault);
84 P_DEBUG("sharedram = %8lu KB\n", mem_data->sharedram);
85 P_DEBUG("totalram = %8lu KB\n", mem_data->totalram);
86 P_DEBUG("freeram = %8lu KB\n", mem_data->freeram);
87 P_DEBUG("totalhigh = %8lu KB\n", mem_data->totalhigh);
88 P_DEBUG("freehigh = %8lu KB\n", mem_data->freehigh);
89 P_DEBUG("bufferram = %8lu KB\n", mem_data->bufferram);
90 P_DEBUG("cached = %8lu KB\n", mem_data->cached);
91 P_DEBUG("totalswap = %8lu KB\n", mem_data->totalswap);
92 P_DEBUG("freeswap = %8lu KB\n", mem_data->freeswap);
93 P_DEBUG("sync_count_1 = %u\n", mem_data->sync_count_1);
94 P_DEBUG("sync_count_2 = %u\n", mem_data->sync_count_2);
95 P_DEBUG("timestamp = %lX\n", mem_data->timestamp);
96}
97
98/*
99 * appldata_get_mem_data()
100 *
101 * gather memory data
102 */
103static void appldata_get_mem_data(void *data)
104{
105 /*
106 * don't put large structures on the stack, we are
107 * serialized through the appldata_ops_lock and can use static
108 */
109 static struct sysinfo val;
110 static struct page_state ps;
111 struct appldata_mem_data *mem_data;
112
113 mem_data = data;
114 mem_data->sync_count_1++;
115
116 get_full_page_state(&ps);
117 mem_data->pgpgin = ps.pgpgin >> 1;
118 mem_data->pgpgout = ps.pgpgout >> 1;
119 mem_data->pswpin = ps.pswpin;
120 mem_data->pswpout = ps.pswpout;
121 mem_data->pgalloc = ps.pgalloc_high + ps.pgalloc_normal +
122 ps.pgalloc_dma;
123 mem_data->pgfault = ps.pgfault;
124 mem_data->pgmajfault = ps.pgmajfault;
125
126 si_meminfo(&val);
127 mem_data->sharedram = val.sharedram;
128 mem_data->totalram = P2K(val.totalram);
129 mem_data->freeram = P2K(val.freeram);
130 mem_data->totalhigh = P2K(val.totalhigh);
131 mem_data->freehigh = P2K(val.freehigh);
132 mem_data->bufferram = P2K(val.bufferram);
133 mem_data->cached = P2K(atomic_read(&nr_pagecache) - val.bufferram);
134
135 si_swapinfo(&val);
136 mem_data->totalswap = P2K(val.totalswap);
137 mem_data->freeswap = P2K(val.freeswap);
138
139 mem_data->timestamp = get_clock();
140 mem_data->sync_count_2++;
141#ifdef APPLDATA_DEBUG
142 appldata_debug_print(mem_data);
143#endif
144}
145
146
147static struct appldata_ops ops = {
148 .ctl_nr = CTL_APPLDATA_MEM,
149 .name = "mem",
150 .record_nr = APPLDATA_RECORD_MEM_ID,
151 .size = sizeof(struct appldata_mem_data),
152 .callback = &appldata_get_mem_data,
153 .data = &appldata_mem_data,
154 .owner = THIS_MODULE,
155};
156
157
158/*
159 * appldata_mem_init()
160 *
161 * init_data, register ops
162 */
163static int __init appldata_mem_init(void)
164{
165 int rc;
166
167 P_DEBUG("sizeof(mem) = %lu\n", sizeof(struct appldata_mem_data));
168
169 rc = appldata_register_ops(&ops);
170 if (rc != 0) {
171 P_ERROR("Error registering ops, rc = %i\n", rc);
172 } else {
173 P_DEBUG("%s-ops registered!\n", ops.name);
174 }
175 return rc;
176}
177
178/*
179 * appldata_mem_exit()
180 *
181 * unregister ops
182 */
183static void __exit appldata_mem_exit(void)
184{
185 appldata_unregister_ops(&ops);
186 P_DEBUG("%s-ops unregistered!\n", ops.name);
187}
188
189
190module_init(appldata_mem_init);
191module_exit(appldata_mem_exit);
192
193MODULE_LICENSE("GPL");
194MODULE_AUTHOR("Gerald Schaefer");
195MODULE_DESCRIPTION("Linux-VM Monitor Stream, MEMORY statistics");
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
new file mode 100644
index 000000000000..dd61638d3027
--- /dev/null
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -0,0 +1,195 @@
1/*
2 * arch/s390/appldata/appldata_net_sum.c
3 *
4 * Data gathering module for Linux-VM Monitor Stream, Stage 1.
5 * Collects accumulated network statistics (Packets received/transmitted,
6 * dropped, errors, ...).
7 *
8 * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
9 *
10 * Author: Gerald Schaefer <geraldsc@de.ibm.com>
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/errno.h>
18#include <linux/kernel_stat.h>
19#include <linux/netdevice.h>
20
21#include "appldata.h"
22
23
24#define MY_PRINT_NAME "appldata_net_sum" /* for debug messages, etc. */
25
26
27/*
28 * Network data
29 *
30 * This is accessed as binary data by z/VM. If changes to it can't be avoided,
31 * the structure version (product ID, see appldata_base.c) needs to be changed
32 * as well and all documentation and z/VM applications using it must be updated.
33 *
34 * The record layout is documented in the Linux for zSeries Device Drivers
35 * book:
36 * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
37 */
38struct appldata_net_sum_data {
39 u64 timestamp;
40 u32 sync_count_1; /* after VM collected the record data, */
41 u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
42 same. If not, the record has been updated on
43 the Linux side while VM was collecting the
44 (possibly corrupt) data */
45
46 u32 nr_interfaces; /* nr. of network interfaces being monitored */
47
48 u32 padding; /* next value is 64-bit aligned, so these */
49 /* 4 byte would be padded out by compiler */
50
51 u64 rx_packets; /* total packets received */
52 u64 tx_packets; /* total packets transmitted */
53 u64 rx_bytes; /* total bytes received */
54 u64 tx_bytes; /* total bytes transmitted */
55 u64 rx_errors; /* bad packets received */
56 u64 tx_errors; /* packet transmit problems */
57 u64 rx_dropped; /* no space in linux buffers */
58 u64 tx_dropped; /* no space available in linux */
59 u64 collisions; /* collisions while transmitting */
60} appldata_net_sum_data;
61
62
63static inline void appldata_print_debug(struct appldata_net_sum_data *net_data)
64{
65 P_DEBUG("--- NET - RECORD ---\n");
66
67 P_DEBUG("nr_interfaces = %u\n", net_data->nr_interfaces);
68 P_DEBUG("rx_packets = %8lu\n", net_data->rx_packets);
69 P_DEBUG("tx_packets = %8lu\n", net_data->tx_packets);
70 P_DEBUG("rx_bytes = %8lu\n", net_data->rx_bytes);
71 P_DEBUG("tx_bytes = %8lu\n", net_data->tx_bytes);
72 P_DEBUG("rx_errors = %8lu\n", net_data->rx_errors);
73 P_DEBUG("tx_errors = %8lu\n", net_data->tx_errors);
74 P_DEBUG("rx_dropped = %8lu\n", net_data->rx_dropped);
75 P_DEBUG("tx_dropped = %8lu\n", net_data->tx_dropped);
76 P_DEBUG("collisions = %8lu\n", net_data->collisions);
77
78 P_DEBUG("sync_count_1 = %u\n", net_data->sync_count_1);
79 P_DEBUG("sync_count_2 = %u\n", net_data->sync_count_2);
80 P_DEBUG("timestamp = %lX\n", net_data->timestamp);
81}
82
83/*
84 * appldata_get_net_sum_data()
85 *
86 * gather accumulated network statistics
87 */
88static void appldata_get_net_sum_data(void *data)
89{
90 int i;
91 struct appldata_net_sum_data *net_data;
92 struct net_device *dev;
93 struct net_device_stats *stats;
94 unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes, rx_errors,
95 tx_errors, rx_dropped, tx_dropped, collisions;
96
97 net_data = data;
98 net_data->sync_count_1++;
99
100 i = 0;
101 rx_packets = 0;
102 tx_packets = 0;
103 rx_bytes = 0;
104 tx_bytes = 0;
105 rx_errors = 0;
106 tx_errors = 0;
107 rx_dropped = 0;
108 tx_dropped = 0;
109 collisions = 0;
110 read_lock(&dev_base_lock);
111 for (dev = dev_base; dev != NULL; dev = dev->next) {
112 if (dev->get_stats == NULL) {
113 continue;
114 }
115 stats = dev->get_stats(dev);
116 rx_packets += stats->rx_packets;
117 tx_packets += stats->tx_packets;
118 rx_bytes += stats->rx_bytes;
119 tx_bytes += stats->tx_bytes;
120 rx_errors += stats->rx_errors;
121 tx_errors += stats->tx_errors;
122 rx_dropped += stats->rx_dropped;
123 tx_dropped += stats->tx_dropped;
124 collisions += stats->collisions;
125 i++;
126 }
127 read_unlock(&dev_base_lock);
128 net_data->nr_interfaces = i;
129 net_data->rx_packets = rx_packets;
130 net_data->tx_packets = tx_packets;
131 net_data->rx_bytes = rx_bytes;
132 net_data->tx_bytes = tx_bytes;
133 net_data->rx_errors = rx_errors;
134 net_data->tx_errors = tx_errors;
135 net_data->rx_dropped = rx_dropped;
136 net_data->tx_dropped = tx_dropped;
137 net_data->collisions = collisions;
138
139 net_data->timestamp = get_clock();
140 net_data->sync_count_2++;
141#ifdef APPLDATA_DEBUG
142 appldata_print_debug(net_data);
143#endif
144}
145
146
147static struct appldata_ops ops = {
148 .ctl_nr = CTL_APPLDATA_NET_SUM,
149 .name = "net_sum",
150 .record_nr = APPLDATA_RECORD_NET_SUM_ID,
151 .size = sizeof(struct appldata_net_sum_data),
152 .callback = &appldata_get_net_sum_data,
153 .data = &appldata_net_sum_data,
154 .owner = THIS_MODULE,
155};
156
157
158/*
159 * appldata_net_init()
160 *
161 * init data, register ops
162 */
163static int __init appldata_net_init(void)
164{
165 int rc;
166
167 P_DEBUG("sizeof(net) = %lu\n", sizeof(struct appldata_net_sum_data));
168
169 rc = appldata_register_ops(&ops);
170 if (rc != 0) {
171 P_ERROR("Error registering ops, rc = %i\n", rc);
172 } else {
173 P_DEBUG("%s-ops registered!\n", ops.name);
174 }
175 return rc;
176}
177
178/*
179 * appldata_net_exit()
180 *
181 * unregister ops
182 */
183static void __exit appldata_net_exit(void)
184{
185 appldata_unregister_ops(&ops);
186 P_DEBUG("%s-ops unregistered!\n", ops.name);
187}
188
189
190module_init(appldata_net_init);
191module_exit(appldata_net_exit);
192
193MODULE_LICENSE("GPL");
194MODULE_AUTHOR("Gerald Schaefer");
195MODULE_DESCRIPTION("Linux-VM Monitor Stream, accumulated network statistics");
diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c
new file mode 100644
index 000000000000..b83f07484551
--- /dev/null
+++ b/arch/s390/appldata/appldata_os.c
@@ -0,0 +1,241 @@
1/*
2 * arch/s390/appldata/appldata_os.c
3 *
4 * Data gathering module for Linux-VM Monitor Stream, Stage 1.
5 * Collects misc. OS related data (CPU utilization, running processes).
6 *
7 * Copyright (C) 2003 IBM Corporation, IBM Deutschland Entwicklung GmbH.
8 *
9 * Author: Gerald Schaefer <geraldsc@de.ibm.com>
10 */
11
12#include <linux/config.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/errno.h>
17#include <linux/kernel_stat.h>
18#include <linux/netdevice.h>
19#include <linux/sched.h>
20#include <asm/smp.h>
21
22#include "appldata.h"
23
24
25#define MY_PRINT_NAME "appldata_os" /* for debug messages, etc. */
26#define LOAD_INT(x) ((x) >> FSHIFT)
27#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
28
29/*
30 * OS data
31 *
32 * This is accessed as binary data by z/VM. If changes to it can't be avoided,
33 * the structure version (product ID, see appldata_base.c) needs to be changed
34 * as well and all documentation and z/VM applications using it must be
35 * updated.
36 *
37 * The record layout is documented in the Linux for zSeries Device Drivers
38 * book:
39 * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
40 */
41struct appldata_os_per_cpu {
42 u32 per_cpu_user; /* timer ticks spent in user mode */
43 u32 per_cpu_nice; /* ... spent with modified priority */
44 u32 per_cpu_system; /* ... spent in kernel mode */
45 u32 per_cpu_idle; /* ... spent in idle mode */
46
47// New in 2.6 -->
48 u32 per_cpu_irq; /* ... spent in interrupts */
49 u32 per_cpu_softirq; /* ... spent in softirqs */
50 u32 per_cpu_iowait; /* ... spent while waiting for I/O */
51// <-- New in 2.6
52};
53
54struct appldata_os_data {
55 u64 timestamp;
56 u32 sync_count_1; /* after VM collected the record data, */
57 u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
58 same. If not, the record has been updated on
59 the Linux side while VM was collecting the
60 (possibly corrupt) data */
61
62 u32 nr_cpus; /* number of (virtual) CPUs */
63 u32 per_cpu_size; /* size of the per-cpu data struct */
64 u32 cpu_offset; /* offset of the first per-cpu data struct */
65
66 u32 nr_running; /* number of runnable threads */
67 u32 nr_threads; /* number of threads */
68 u32 avenrun[3]; /* average nr. of running processes during */
69 /* the last 1, 5 and 15 minutes */
70
71// New in 2.6 -->
72 u32 nr_iowait; /* number of blocked threads
73 (waiting for I/O) */
74// <-- New in 2.6
75
76 /* per cpu data */
77 struct appldata_os_per_cpu os_cpu[0];
78};
79
80static struct appldata_os_data *appldata_os_data;
81
82
83static inline void appldata_print_debug(struct appldata_os_data *os_data)
84{
85 int a0, a1, a2, i;
86
87 P_DEBUG("--- OS - RECORD ---\n");
88 P_DEBUG("nr_threads = %u\n", os_data->nr_threads);
89 P_DEBUG("nr_running = %u\n", os_data->nr_running);
90 P_DEBUG("nr_iowait = %u\n", os_data->nr_iowait);
91 P_DEBUG("avenrun(int) = %8x / %8x / %8x\n", os_data->avenrun[0],
92 os_data->avenrun[1], os_data->avenrun[2]);
93 a0 = os_data->avenrun[0];
94 a1 = os_data->avenrun[1];
95 a2 = os_data->avenrun[2];
96 P_DEBUG("avenrun(float) = %d.%02d / %d.%02d / %d.%02d\n",
97 LOAD_INT(a0), LOAD_FRAC(a0), LOAD_INT(a1), LOAD_FRAC(a1),
98 LOAD_INT(a2), LOAD_FRAC(a2));
99
100 P_DEBUG("nr_cpus = %u\n", os_data->nr_cpus);
101 for (i = 0; i < os_data->nr_cpus; i++) {
102 P_DEBUG("cpu%u : user = %u, nice = %u, system = %u, "
103 "idle = %u, irq = %u, softirq = %u, iowait = %u\n",
104 i,
105 os_data->os_cpu[i].per_cpu_user,
106 os_data->os_cpu[i].per_cpu_nice,
107 os_data->os_cpu[i].per_cpu_system,
108 os_data->os_cpu[i].per_cpu_idle,
109 os_data->os_cpu[i].per_cpu_irq,
110 os_data->os_cpu[i].per_cpu_softirq,
111 os_data->os_cpu[i].per_cpu_iowait);
112 }
113
114 P_DEBUG("sync_count_1 = %u\n", os_data->sync_count_1);
115 P_DEBUG("sync_count_2 = %u\n", os_data->sync_count_2);
116 P_DEBUG("timestamp = %lX\n", os_data->timestamp);
117}
118
119/*
120 * appldata_get_os_data()
121 *
122 * gather OS data
123 */
124static void appldata_get_os_data(void *data)
125{
126 int i, j;
127 struct appldata_os_data *os_data;
128
129 os_data = data;
130 os_data->sync_count_1++;
131
132 os_data->nr_cpus = num_online_cpus();
133
134 os_data->nr_threads = nr_threads;
135 os_data->nr_running = nr_running();
136 os_data->nr_iowait = nr_iowait();
137 os_data->avenrun[0] = avenrun[0] + (FIXED_1/200);
138 os_data->avenrun[1] = avenrun[1] + (FIXED_1/200);
139 os_data->avenrun[2] = avenrun[2] + (FIXED_1/200);
140
141 j = 0;
142 for_each_online_cpu(i) {
143 os_data->os_cpu[j].per_cpu_user =
144 kstat_cpu(i).cpustat.user;
145 os_data->os_cpu[j].per_cpu_nice =
146 kstat_cpu(i).cpustat.nice;
147 os_data->os_cpu[j].per_cpu_system =
148 kstat_cpu(i).cpustat.system;
149 os_data->os_cpu[j].per_cpu_idle =
150 kstat_cpu(i).cpustat.idle;
151 os_data->os_cpu[j].per_cpu_irq =
152 kstat_cpu(i).cpustat.irq;
153 os_data->os_cpu[j].per_cpu_softirq =
154 kstat_cpu(i).cpustat.softirq;
155 os_data->os_cpu[j].per_cpu_iowait =
156 kstat_cpu(i).cpustat.iowait;
157 j++;
158 }
159
160 os_data->timestamp = get_clock();
161 os_data->sync_count_2++;
162#ifdef APPLDATA_DEBUG
163 appldata_print_debug(os_data);
164#endif
165}
166
167
168static struct appldata_ops ops = {
169 .ctl_nr = CTL_APPLDATA_OS,
170 .name = "os",
171 .record_nr = APPLDATA_RECORD_OS_ID,
172 .callback = &appldata_get_os_data,
173 .owner = THIS_MODULE,
174};
175
176
177/*
178 * appldata_os_init()
179 *
180 * init data, register ops
181 */
182static int __init appldata_os_init(void)
183{
184 int rc, size;
185
186 size = sizeof(struct appldata_os_data) +
187 (NR_CPUS * sizeof(struct appldata_os_per_cpu));
188 if (size > APPLDATA_MAX_REC_SIZE) {
189 P_ERROR("Size of record = %i, bigger than maximum (%i)!\n",
190 size, APPLDATA_MAX_REC_SIZE);
191 rc = -ENOMEM;
192 goto out;
193 }
194 P_DEBUG("sizeof(os) = %i, sizeof(os_cpu) = %lu\n", size,
195 sizeof(struct appldata_os_per_cpu));
196
197 appldata_os_data = kmalloc(size, GFP_DMA);
198 if (appldata_os_data == NULL) {
199 P_ERROR("No memory for %s!\n", ops.name);
200 rc = -ENOMEM;
201 goto out;
202 }
203 memset(appldata_os_data, 0, size);
204
205 appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu);
206 appldata_os_data->cpu_offset = offsetof(struct appldata_os_data,
207 os_cpu);
208 P_DEBUG("cpu offset = %u\n", appldata_os_data->cpu_offset);
209
210 ops.data = appldata_os_data;
211 ops.size = size;
212 rc = appldata_register_ops(&ops);
213 if (rc != 0) {
214 P_ERROR("Error registering ops, rc = %i\n", rc);
215 kfree(appldata_os_data);
216 } else {
217 P_DEBUG("%s-ops registered!\n", ops.name);
218 }
219out:
220 return rc;
221}
222
223/*
224 * appldata_os_exit()
225 *
226 * unregister ops
227 */
228static void __exit appldata_os_exit(void)
229{
230 appldata_unregister_ops(&ops);
231 kfree(appldata_os_data);
232 P_DEBUG("%s-ops unregistered!\n", ops.name);
233}
234
235
236module_init(appldata_os_init);
237module_exit(appldata_os_exit);
238
239MODULE_LICENSE("GPL");
240MODULE_AUTHOR("Gerald Schaefer");
241MODULE_DESCRIPTION("Linux-VM Monitor Stream, OS statistics");
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
new file mode 100644
index 000000000000..4d97eef36b8d
--- /dev/null
+++ b/arch/s390/boot/Makefile
@@ -0,0 +1,18 @@
1#
2# Makefile for the linux s390-specific parts of the memory manager.
3#
4
5COMPILE_VERSION := __linux_compile_version_id__`hostname | \
6 tr -c '[0-9A-Za-z]' '_'`__`date | \
7 tr -c '[0-9A-Za-z]' '_'`_t
8
9EXTRA_CFLAGS := -DCOMPILE_VERSION=$(COMPILE_VERSION) -gstabs -I.
10
11targets := image
12
13$(obj)/image: vmlinux FORCE
14 $(call if_changed,objcopy)
15
16install: $(CONFIGURE) $(obj)/image
17 sh -x $(srctree)/$(obj)/install.sh $(KERNELRELEASE) $(obj)/image \
18 System.map Kerntypes "$(INSTALL_PATH)"
diff --git a/arch/s390/boot/install.sh b/arch/s390/boot/install.sh
new file mode 100644
index 000000000000..278a8139cb18
--- /dev/null
+++ b/arch/s390/boot/install.sh
@@ -0,0 +1,38 @@
1#!/bin/sh
2#
3# arch/s390x/boot/install.sh
4#
5# This file is subject to the terms and conditions of the GNU General Public
6# License. See the file "COPYING" in the main directory of this archive
7# for more details.
8#
9# Copyright (C) 1995 by Linus Torvalds
10#
11# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
12#
13# "make install" script for s390 architecture
14#
15# Arguments:
16# $1 - kernel version
17# $2 - kernel image file
18# $3 - kernel map file
19# $4 - default install path (blank if root directory)
20#
21
22# User may have a custom install script
23
24if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi
25if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
26
27# Default install - same as make zlilo
28
29if [ -f $4/vmlinuz ]; then
30 mv $4/vmlinuz $4/vmlinuz.old
31fi
32
33if [ -f $4/System.map ]; then
34 mv $4/System.map $4/System.old
35fi
36
37cat $2 > $4/vmlinuz
38cp $3 $4/System.map
diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile
new file mode 100644
index 000000000000..96a05e6b51e0
--- /dev/null
+++ b/arch/s390/crypto/Makefile
@@ -0,0 +1,8 @@
1#
2# Cryptographic API
3#
4
5obj-$(CONFIG_CRYPTO_SHA1_Z990) += sha1_z990.o
6obj-$(CONFIG_CRYPTO_DES_Z990) += des_z990.o des_check_key.o
7
8obj-$(CONFIG_CRYPTO_TEST) += crypt_z990_query.o
diff --git a/arch/s390/crypto/crypt_z990.h b/arch/s390/crypto/crypt_z990.h
new file mode 100644
index 000000000000..4df660b99e5a
--- /dev/null
+++ b/arch/s390/crypto/crypt_z990.h
@@ -0,0 +1,374 @@
1/*
2 * Cryptographic API.
3 *
4 * Support for z990 cryptographic instructions.
5 *
6 * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
7 * Author(s): Thomas Spatzier (tspat@de.ibm.com)
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
12 * any later version.
13 *
14 */
15#ifndef _CRYPTO_ARCH_S390_CRYPT_Z990_H
16#define _CRYPTO_ARCH_S390_CRYPT_Z990_H
17
18#include <asm/errno.h>
19
20#define CRYPT_Z990_OP_MASK 0xFF00
21#define CRYPT_Z990_FUNC_MASK 0x00FF
22
23
24/*z990 cryptographic operations*/
25enum crypt_z990_operations {
26 CRYPT_Z990_KM = 0x0100,
27 CRYPT_Z990_KMC = 0x0200,
28 CRYPT_Z990_KIMD = 0x0300,
29 CRYPT_Z990_KLMD = 0x0400,
30 CRYPT_Z990_KMAC = 0x0500
31};
32
33/*function codes for KM (CIPHER MESSAGE) instruction*/
34enum crypt_z990_km_func {
35 KM_QUERY = CRYPT_Z990_KM | 0,
36 KM_DEA_ENCRYPT = CRYPT_Z990_KM | 1,
37 KM_DEA_DECRYPT = CRYPT_Z990_KM | 1 | 0x80, //modifier bit->decipher
38 KM_TDEA_128_ENCRYPT = CRYPT_Z990_KM | 2,
39 KM_TDEA_128_DECRYPT = CRYPT_Z990_KM | 2 | 0x80,
40 KM_TDEA_192_ENCRYPT = CRYPT_Z990_KM | 3,
41 KM_TDEA_192_DECRYPT = CRYPT_Z990_KM | 3 | 0x80,
42};
43
44/*function codes for KMC (CIPHER MESSAGE WITH CHAINING) instruction*/
45enum crypt_z990_kmc_func {
46 KMC_QUERY = CRYPT_Z990_KMC | 0,
47 KMC_DEA_ENCRYPT = CRYPT_Z990_KMC | 1,
48 KMC_DEA_DECRYPT = CRYPT_Z990_KMC | 1 | 0x80, //modifier bit->decipher
49 KMC_TDEA_128_ENCRYPT = CRYPT_Z990_KMC | 2,
50 KMC_TDEA_128_DECRYPT = CRYPT_Z990_KMC | 2 | 0x80,
51 KMC_TDEA_192_ENCRYPT = CRYPT_Z990_KMC | 3,
52 KMC_TDEA_192_DECRYPT = CRYPT_Z990_KMC | 3 | 0x80,
53};
54
55/*function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) instruction*/
56enum crypt_z990_kimd_func {
57 KIMD_QUERY = CRYPT_Z990_KIMD | 0,
58 KIMD_SHA_1 = CRYPT_Z990_KIMD | 1,
59};
60
61/*function codes for KLMD (COMPUTE LAST MESSAGE DIGEST) instruction*/
62enum crypt_z990_klmd_func {
63 KLMD_QUERY = CRYPT_Z990_KLMD | 0,
64 KLMD_SHA_1 = CRYPT_Z990_KLMD | 1,
65};
66
67/*function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) instruction*/
68enum crypt_z990_kmac_func {
69 KMAC_QUERY = CRYPT_Z990_KMAC | 0,
70 KMAC_DEA = CRYPT_Z990_KMAC | 1,
71 KMAC_TDEA_128 = CRYPT_Z990_KMAC | 2,
72 KMAC_TDEA_192 = CRYPT_Z990_KMAC | 3
73};
74
75/*status word for z990 crypto instructions' QUERY functions*/
76struct crypt_z990_query_status {
77 u64 high;
78 u64 low;
79};
80
81/*
82 * Standard fixup and ex_table sections for crypt_z990 inline functions.
83 * label 0: the z990 crypto operation
84 * label 1: just after 1 to catch illegal operation exception on non-z990
85 * label 6: the return point after fixup
86 * label 7: set error value if exception _in_ crypto operation
87 * label 8: set error value if illegal operation exception
88 * [ret] is the variable to receive the error code
89 * [ERR] is the error code value
90 */
91#ifndef __s390x__
92#define __crypt_z990_fixup \
93 ".section .fixup,\"ax\" \n" \
94 "7: lhi %0,%h[e1] \n" \
95 " bras 1,9f \n" \
96 " .long 6b \n" \
97 "8: lhi %0,%h[e2] \n" \
98 " bras 1,9f \n" \
99 " .long 6b \n" \
100 "9: l 1,0(1) \n" \
101 " br 1 \n" \
102 ".previous \n" \
103 ".section __ex_table,\"a\" \n" \
104 " .align 4 \n" \
105 " .long 0b,7b \n" \
106 " .long 1b,8b \n" \
107 ".previous"
108#else /* __s390x__ */
109#define __crypt_z990_fixup \
110 ".section .fixup,\"ax\" \n" \
111 "7: lhi %0,%h[e1] \n" \
112 " jg 6b \n" \
113 "8: lhi %0,%h[e2] \n" \
114 " jg 6b \n" \
115 ".previous\n" \
116 ".section __ex_table,\"a\" \n" \
117 " .align 8 \n" \
118 " .quad 0b,7b \n" \
119 " .quad 1b,8b \n" \
120 ".previous"
121#endif /* __s390x__ */
122
123/*
124 * Standard code for setting the result of z990 crypto instructions.
125 * %0: the register which will receive the result
126 * [result]: the register containing the result (e.g. second operand length
127 * to compute number of processed bytes].
128 */
129#ifndef __s390x__
130#define __crypt_z990_set_result \
131 " lr %0,%[result] \n"
132#else /* __s390x__ */
133#define __crypt_z990_set_result \
134 " lgr %0,%[result] \n"
135#endif
136
137/*
138 * Executes the KM (CIPHER MESSAGE) operation of the z990 CPU.
139 * @param func: the function code passed to KM; see crypt_z990_km_func
140 * @param param: address of parameter block; see POP for details on each func
141 * @param dest: address of destination memory area
142 * @param src: address of source memory area
143 * @param src_len: length of src operand in bytes
144 * @returns < zero for failure, 0 for the query func, number of processed bytes
145 * for encryption/decryption funcs
146 */
147static inline int
148crypt_z990_km(long func, void* param, u8* dest, const u8* src, long src_len)
149{
150 register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK;
151 register void* __param asm("1") = param;
152 register u8* __dest asm("4") = dest;
153 register const u8* __src asm("2") = src;
154 register long __src_len asm("3") = src_len;
155 int ret;
156
157 ret = 0;
158 __asm__ __volatile__ (
159 "0: .insn rre,0xB92E0000,%1,%2 \n" //KM opcode
160 "1: brc 1,0b \n" //handle partial completion
161 __crypt_z990_set_result
162 "6: \n"
163 __crypt_z990_fixup
164 : "+d" (ret), "+a" (__dest), "+a" (__src),
165 [result] "+d" (__src_len)
166 : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
167 "a" (__param)
168 : "cc", "memory"
169 );
170 if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){
171 ret = src_len - ret;
172 }
173 return ret;
174}
175
176/*
177 * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the z990 CPU.
178 * @param func: the function code passed to KM; see crypt_z990_kmc_func
179 * @param param: address of parameter block; see POP for details on each func
180 * @param dest: address of destination memory area
181 * @param src: address of source memory area
182 * @param src_len: length of src operand in bytes
183 * @returns < zero for failure, 0 for the query func, number of processed bytes
184 * for encryption/decryption funcs
185 */
186static inline int
187crypt_z990_kmc(long func, void* param, u8* dest, const u8* src, long src_len)
188{
189 register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK;
190 register void* __param asm("1") = param;
191 register u8* __dest asm("4") = dest;
192 register const u8* __src asm("2") = src;
193 register long __src_len asm("3") = src_len;
194 int ret;
195
196 ret = 0;
197 __asm__ __volatile__ (
198 "0: .insn rre,0xB92F0000,%1,%2 \n" //KMC opcode
199 "1: brc 1,0b \n" //handle partial completion
200 __crypt_z990_set_result
201 "6: \n"
202 __crypt_z990_fixup
203 : "+d" (ret), "+a" (__dest), "+a" (__src),
204 [result] "+d" (__src_len)
205 : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
206 "a" (__param)
207 : "cc", "memory"
208 );
209 if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){
210 ret = src_len - ret;
211 }
212 return ret;
213}
214
215/*
216 * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
217 * of the z990 CPU.
218 * @param func: the function code passed to KM; see crypt_z990_kimd_func
219 * @param param: address of parameter block; see POP for details on each func
220 * @param src: address of source memory area
221 * @param src_len: length of src operand in bytes
222 * @returns < zero for failure, 0 for the query func, number of processed bytes
223 * for digest funcs
224 */
225static inline int
226crypt_z990_kimd(long func, void* param, const u8* src, long src_len)
227{
228 register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK;
229 register void* __param asm("1") = param;
230 register const u8* __src asm("2") = src;
231 register long __src_len asm("3") = src_len;
232 int ret;
233
234 ret = 0;
235 __asm__ __volatile__ (
236 "0: .insn rre,0xB93E0000,%1,%1 \n" //KIMD opcode
237 "1: brc 1,0b \n" /*handle partical completion of kimd*/
238 __crypt_z990_set_result
239 "6: \n"
240 __crypt_z990_fixup
241 : "+d" (ret), "+a" (__src), [result] "+d" (__src_len)
242 : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
243 "a" (__param)
244 : "cc", "memory"
245 );
246 if (ret >= 0 && (func & CRYPT_Z990_FUNC_MASK)){
247 ret = src_len - ret;
248 }
249 return ret;
250}
251
252/*
253 * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the z990 CPU.
254 * @param func: the function code passed to KM; see crypt_z990_klmd_func
255 * @param param: address of parameter block; see POP for details on each func
256 * @param src: address of source memory area
257 * @param src_len: length of src operand in bytes
258 * @returns < zero for failure, 0 for the query func, number of processed bytes
259 * for digest funcs
260 */
261static inline int
262crypt_z990_klmd(long func, void* param, const u8* src, long src_len)
263{
264 register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK;
265 register void* __param asm("1") = param;
266 register const u8* __src asm("2") = src;
267 register long __src_len asm("3") = src_len;
268 int ret;
269
270 ret = 0;
271 __asm__ __volatile__ (
272 "0: .insn rre,0xB93F0000,%1,%1 \n" //KLMD opcode
273 "1: brc 1,0b \n" /*handle partical completion of klmd*/
274 __crypt_z990_set_result
275 "6: \n"
276 __crypt_z990_fixup
277 : "+d" (ret), "+a" (__src), [result] "+d" (__src_len)
278 : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
279 "a" (__param)
280 : "cc", "memory"
281 );
282 if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){
283 ret = src_len - ret;
284 }
285 return ret;
286}
287
288/*
289 * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
290 * of the z990 CPU.
291 * @param func: the function code passed to KM; see crypt_z990_klmd_func
292 * @param param: address of parameter block; see POP for details on each func
293 * @param src: address of source memory area
294 * @param src_len: length of src operand in bytes
295 * @returns < zero for failure, 0 for the query func, number of processed bytes
296 * for digest funcs
297 */
298static inline int
299crypt_z990_kmac(long func, void* param, const u8* src, long src_len)
300{
301 register long __func asm("0") = func & CRYPT_Z990_FUNC_MASK;
302 register void* __param asm("1") = param;
303 register const u8* __src asm("2") = src;
304 register long __src_len asm("3") = src_len;
305 int ret;
306
307 ret = 0;
308 __asm__ __volatile__ (
309 "0: .insn rre,0xB91E0000,%5,%5 \n" //KMAC opcode
310 "1: brc 1,0b \n" /*handle partical completion of klmd*/
311 __crypt_z990_set_result
312 "6: \n"
313 __crypt_z990_fixup
314 : "+d" (ret), "+a" (__src), [result] "+d" (__src_len)
315 : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
316 "a" (__param)
317 : "cc", "memory"
318 );
319 if (ret >= 0 && func & CRYPT_Z990_FUNC_MASK){
320 ret = src_len - ret;
321 }
322 return ret;
323}
324
325/**
326 * Tests if a specific z990 crypto function is implemented on the machine.
327 * @param func: the function code of the specific function; 0 if op in general
328 * @return 1 if func available; 0 if func or op in general not available
329 */
330static inline int
331crypt_z990_func_available(int func)
332{
333 int ret;
334
335 struct crypt_z990_query_status status = {
336 .high = 0,
337 .low = 0
338 };
339 switch (func & CRYPT_Z990_OP_MASK){
340 case CRYPT_Z990_KM:
341 ret = crypt_z990_km(KM_QUERY, &status, NULL, NULL, 0);
342 break;
343 case CRYPT_Z990_KMC:
344 ret = crypt_z990_kmc(KMC_QUERY, &status, NULL, NULL, 0);
345 break;
346 case CRYPT_Z990_KIMD:
347 ret = crypt_z990_kimd(KIMD_QUERY, &status, NULL, 0);
348 break;
349 case CRYPT_Z990_KLMD:
350 ret = crypt_z990_klmd(KLMD_QUERY, &status, NULL, 0);
351 break;
352 case CRYPT_Z990_KMAC:
353 ret = crypt_z990_kmac(KMAC_QUERY, &status, NULL, 0);
354 break;
355 default:
356 ret = 0;
357 return ret;
358 }
359 if (ret >= 0){
360 func &= CRYPT_Z990_FUNC_MASK;
361 func &= 0x7f; //mask modifier bit
362 if (func < 64){
363 ret = (status.high >> (64 - func - 1)) & 0x1;
364 } else {
365 ret = (status.low >> (128 - func - 1)) & 0x1;
366 }
367 } else {
368 ret = 0;
369 }
370 return ret;
371}
372
373
374#endif // _CRYPTO_ARCH_S390_CRYPT_Z990_H
diff --git a/arch/s390/crypto/crypt_z990_query.c b/arch/s390/crypto/crypt_z990_query.c
new file mode 100644
index 000000000000..7133983d1384
--- /dev/null
+++ b/arch/s390/crypto/crypt_z990_query.c
@@ -0,0 +1,111 @@
1/*
2 * Cryptographic API.
3 *
4 * Support for z990 cryptographic instructions.
5 * Testing module for querying processor crypto capabilities.
6 *
7 * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
8 * Author(s): Thomas Spatzier (tspat@de.ibm.com)
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 */
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/kernel.h>
19#include <asm/errno.h>
20#include "crypt_z990.h"
21
22static void
23query_available_functions(void)
24{
25 printk(KERN_INFO "#####################\n");
26 //query available KM functions
27 printk(KERN_INFO "KM_QUERY: %d\n",
28 crypt_z990_func_available(KM_QUERY));
29 printk(KERN_INFO "KM_DEA: %d\n",
30 crypt_z990_func_available(KM_DEA_ENCRYPT));
31 printk(KERN_INFO "KM_TDEA_128: %d\n",
32 crypt_z990_func_available(KM_TDEA_128_ENCRYPT));
33 printk(KERN_INFO "KM_TDEA_192: %d\n",
34 crypt_z990_func_available(KM_TDEA_192_ENCRYPT));
35 //query available KMC functions
36 printk(KERN_INFO "KMC_QUERY: %d\n",
37 crypt_z990_func_available(KMC_QUERY));
38 printk(KERN_INFO "KMC_DEA: %d\n",
39 crypt_z990_func_available(KMC_DEA_ENCRYPT));
40 printk(KERN_INFO "KMC_TDEA_128: %d\n",
41 crypt_z990_func_available(KMC_TDEA_128_ENCRYPT));
42 printk(KERN_INFO "KMC_TDEA_192: %d\n",
43 crypt_z990_func_available(KMC_TDEA_192_ENCRYPT));
44 //query available KIMD fucntions
45 printk(KERN_INFO "KIMD_QUERY: %d\n",
46 crypt_z990_func_available(KIMD_QUERY));
47 printk(KERN_INFO "KIMD_SHA_1: %d\n",
48 crypt_z990_func_available(KIMD_SHA_1));
49 //query available KLMD functions
50 printk(KERN_INFO "KLMD_QUERY: %d\n",
51 crypt_z990_func_available(KLMD_QUERY));
52 printk(KERN_INFO "KLMD_SHA_1: %d\n",
53 crypt_z990_func_available(KLMD_SHA_1));
54 //query available KMAC functions
55 printk(KERN_INFO "KMAC_QUERY: %d\n",
56 crypt_z990_func_available(KMAC_QUERY));
57 printk(KERN_INFO "KMAC_DEA: %d\n",
58 crypt_z990_func_available(KMAC_DEA));
59 printk(KERN_INFO "KMAC_TDEA_128: %d\n",
60 crypt_z990_func_available(KMAC_TDEA_128));
61 printk(KERN_INFO "KMAC_TDEA_192: %d\n",
62 crypt_z990_func_available(KMAC_TDEA_192));
63}
64
65static int
66init(void)
67{
68 struct crypt_z990_query_status status = {
69 .high = 0,
70 .low = 0
71 };
72
73 printk(KERN_INFO "crypt_z990: querying available crypto functions\n");
74 crypt_z990_km(KM_QUERY, &status, NULL, NULL, 0);
75 printk(KERN_INFO "KM: %016llx %016llx\n",
76 (unsigned long long) status.high,
77 (unsigned long long) status.low);
78 status.high = status.low = 0;
79 crypt_z990_kmc(KMC_QUERY, &status, NULL, NULL, 0);
80 printk(KERN_INFO "KMC: %016llx %016llx\n",
81 (unsigned long long) status.high,
82 (unsigned long long) status.low);
83 status.high = status.low = 0;
84 crypt_z990_kimd(KIMD_QUERY, &status, NULL, 0);
85 printk(KERN_INFO "KIMD: %016llx %016llx\n",
86 (unsigned long long) status.high,
87 (unsigned long long) status.low);
88 status.high = status.low = 0;
89 crypt_z990_klmd(KLMD_QUERY, &status, NULL, 0);
90 printk(KERN_INFO "KLMD: %016llx %016llx\n",
91 (unsigned long long) status.high,
92 (unsigned long long) status.low);
93 status.high = status.low = 0;
94 crypt_z990_kmac(KMAC_QUERY, &status, NULL, 0);
95 printk(KERN_INFO "KMAC: %016llx %016llx\n",
96 (unsigned long long) status.high,
97 (unsigned long long) status.low);
98
99 query_available_functions();
100 return -1;
101}
102
103static void __exit
104cleanup(void)
105{
106}
107
108module_init(init);
109module_exit(cleanup);
110
111MODULE_LICENSE("GPL");
diff --git a/arch/s390/crypto/crypto_des.h b/arch/s390/crypto/crypto_des.h
new file mode 100644
index 000000000000..c964b64111dd
--- /dev/null
+++ b/arch/s390/crypto/crypto_des.h
@@ -0,0 +1,18 @@
1/*
2 * Cryptographic API.
3 *
4 * Function for checking keys for the DES and Tripple DES Encryption
5 * algorithms.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 */
13#ifndef __CRYPTO_DES_H__
14#define __CRYPTO_DES_H__
15
16extern int crypto_des_check_key(const u8*, unsigned int, u32*);
17
18#endif //__CRYPTO_DES_H__
diff --git a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c
new file mode 100644
index 000000000000..e3f5c5f238fe
--- /dev/null
+++ b/arch/s390/crypto/des_check_key.c
@@ -0,0 +1,130 @@
1/*
2 * Cryptographic API.
3 *
4 * Function for checking keys for the DES and Tripple DES Encryption
5 * algorithms.
6 *
7 * Originally released as descore by Dana L. How <how@isl.stanford.edu>.
8 * Modified by Raimar Falke <rf13@inf.tu-dresden.de> for the Linux-Kernel.
9 * Derived from Cryptoapi and Nettle implementations, adapted for in-place
10 * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL.
11 *
12 * s390 Version:
13 * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
14 * Author(s): Thomas Spatzier (tspat@de.ibm.com)
15 *
16 * Derived from "crypto/des.c"
17 * Copyright (c) 1992 Dana L. How.
18 * Copyright (c) Raimar Falke <rf13@inf.tu-dresden.de>
19 * Copyright (c) Gisle Sflensminde <gisle@ii.uib.no>
20 * Copyright (C) 2001 Niels Mvller.
21 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
22 *
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 2 of the License, or
26 * (at your option) any later version.
27 *
28 */
29#include <linux/init.h>
30#include <linux/module.h>
31#include <linux/errno.h>
32#include <linux/crypto.h>
33
34#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o))
35
36static const u8 parity[] = {
37 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,
38 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,
39 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,
40 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,
41 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,
42 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,
43 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,
44 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,
45};
46
47/*
48 * RFC2451: Weak key checks SHOULD be performed.
49 */
50int
51crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags)
52{
53 u32 n, w;
54
55 n = parity[key[0]]; n <<= 4;
56 n |= parity[key[1]]; n <<= 4;
57 n |= parity[key[2]]; n <<= 4;
58 n |= parity[key[3]]; n <<= 4;
59 n |= parity[key[4]]; n <<= 4;
60 n |= parity[key[5]]; n <<= 4;
61 n |= parity[key[6]]; n <<= 4;
62 n |= parity[key[7]];
63 w = 0x88888888L;
64
65 if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY)
66 && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */
67 if (n < 0x41415151) {
68 if (n < 0x31312121) {
69 if (n < 0x14141515) {
70 /* 01 01 01 01 01 01 01 01 */
71 if (n == 0x11111111) goto weak;
72 /* 01 1F 01 1F 01 0E 01 0E */
73 if (n == 0x13131212) goto weak;
74 } else {
75 /* 01 E0 01 E0 01 F1 01 F1 */
76 if (n == 0x14141515) goto weak;
77 /* 01 FE 01 FE 01 FE 01 FE */
78 if (n == 0x16161616) goto weak;
79 }
80 } else {
81 if (n < 0x34342525) {
82 /* 1F 01 1F 01 0E 01 0E 01 */
83 if (n == 0x31312121) goto weak;
84 /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */
85 if (n == 0x33332222) goto weak;
86 } else {
87 /* 1F E0 1F E0 0E F1 0E F1 */
88 if (n == 0x34342525) goto weak;
89 /* 1F FE 1F FE 0E FE 0E FE */
90 if (n == 0x36362626) goto weak;
91 }
92 }
93 } else {
94 if (n < 0x61616161) {
95 if (n < 0x44445555) {
96 /* E0 01 E0 01 F1 01 F1 01 */
97 if (n == 0x41415151) goto weak;
98 /* E0 1F E0 1F F1 0E F1 0E */
99 if (n == 0x43435252) goto weak;
100 } else {
101 /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */
102 if (n == 0x44445555) goto weak;
103 /* E0 FE E0 FE F1 FE F1 FE */
104 if (n == 0x46465656) goto weak;
105 }
106 } else {
107 if (n < 0x64646565) {
108 /* FE 01 FE 01 FE 01 FE 01 */
109 if (n == 0x61616161) goto weak;
110 /* FE 1F FE 1F FE 0E FE 0E */
111 if (n == 0x63636262) goto weak;
112 } else {
113 /* FE E0 FE E0 FE F1 FE F1 */
114 if (n == 0x64646565) goto weak;
115 /* FE FE FE FE FE FE FE FE */
116 if (n == 0x66666666) goto weak;
117 }
118 }
119 }
120 }
121 return 0;
122weak:
123 *flags |= CRYPTO_TFM_RES_WEAK_KEY;
124 return -EINVAL;
125}
126
127EXPORT_SYMBOL(crypto_des_check_key);
128
129MODULE_LICENSE("GPL");
130MODULE_DESCRIPTION("Key Check function for DES & DES3 Cipher Algorithms");
diff --git a/arch/s390/crypto/des_z990.c b/arch/s390/crypto/des_z990.c
new file mode 100644
index 000000000000..813cf37b1177
--- /dev/null
+++ b/arch/s390/crypto/des_z990.c
@@ -0,0 +1,284 @@
1/*
2 * Cryptographic API.
3 *
4 * z990 implementation of the DES Cipher Algorithm.
5 *
6 * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Thomas Spatzier (tspat@de.ibm.com)
8 *
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 */
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/mm.h>
19#include <linux/errno.h>
20#include <asm/scatterlist.h>
21#include <linux/crypto.h>
22#include "crypt_z990.h"
23#include "crypto_des.h"
24
25#define DES_BLOCK_SIZE 8
26#define DES_KEY_SIZE 8
27
28#define DES3_128_KEY_SIZE (2 * DES_KEY_SIZE)
29#define DES3_128_BLOCK_SIZE DES_BLOCK_SIZE
30
31#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE)
32#define DES3_192_BLOCK_SIZE DES_BLOCK_SIZE
33
34struct crypt_z990_des_ctx {
35 u8 iv[DES_BLOCK_SIZE];
36 u8 key[DES_KEY_SIZE];
37};
38
39struct crypt_z990_des3_128_ctx {
40 u8 iv[DES_BLOCK_SIZE];
41 u8 key[DES3_128_KEY_SIZE];
42};
43
44struct crypt_z990_des3_192_ctx {
45 u8 iv[DES_BLOCK_SIZE];
46 u8 key[DES3_192_KEY_SIZE];
47};
48
49static int
50des_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
51{
52 struct crypt_z990_des_ctx *dctx;
53 int ret;
54
55 dctx = ctx;
56 //test if key is valid (not a weak key)
57 ret = crypto_des_check_key(key, keylen, flags);
58 if (ret == 0){
59 memcpy(dctx->key, key, keylen);
60 }
61 return ret;
62}
63
64
65static void
66des_encrypt(void *ctx, u8 *dst, const u8 *src)
67{
68 struct crypt_z990_des_ctx *dctx;
69
70 dctx = ctx;
71 crypt_z990_km(KM_DEA_ENCRYPT, dctx->key, dst, src, DES_BLOCK_SIZE);
72}
73
74static void
75des_decrypt(void *ctx, u8 *dst, const u8 *src)
76{
77 struct crypt_z990_des_ctx *dctx;
78
79 dctx = ctx;
80 crypt_z990_km(KM_DEA_DECRYPT, dctx->key, dst, src, DES_BLOCK_SIZE);
81}
82
83static struct crypto_alg des_alg = {
84 .cra_name = "des",
85 .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
86 .cra_blocksize = DES_BLOCK_SIZE,
87 .cra_ctxsize = sizeof(struct crypt_z990_des_ctx),
88 .cra_module = THIS_MODULE,
89 .cra_list = LIST_HEAD_INIT(des_alg.cra_list),
90 .cra_u = { .cipher = {
91 .cia_min_keysize = DES_KEY_SIZE,
92 .cia_max_keysize = DES_KEY_SIZE,
93 .cia_setkey = des_setkey,
94 .cia_encrypt = des_encrypt,
95 .cia_decrypt = des_decrypt } }
96};
97
98/*
99 * RFC2451:
100 *
101 * For DES-EDE3, there is no known need to reject weak or
102 * complementation keys. Any weakness is obviated by the use of
103 * multiple keys.
104 *
105 * However, if the two independent 64-bit keys are equal,
106 * then the DES3 operation is simply the same as DES.
107 * Implementers MUST reject keys that exhibit this property.
108 *
109 */
110static int
111des3_128_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
112{
113 int i, ret;
114 struct crypt_z990_des3_128_ctx *dctx;
115 const u8* temp_key = key;
116
117 dctx = ctx;
118 if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) {
119
120 *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
121 return -EINVAL;
122 }
123 for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) {
124 ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
125 if (ret < 0)
126 return ret;
127 }
128 memcpy(dctx->key, key, keylen);
129 return 0;
130}
131
132static void
133des3_128_encrypt(void *ctx, u8 *dst, const u8 *src)
134{
135 struct crypt_z990_des3_128_ctx *dctx;
136
137 dctx = ctx;
138 crypt_z990_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src,
139 DES3_128_BLOCK_SIZE);
140}
141
142static void
143des3_128_decrypt(void *ctx, u8 *dst, const u8 *src)
144{
145 struct crypt_z990_des3_128_ctx *dctx;
146
147 dctx = ctx;
148 crypt_z990_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src,
149 DES3_128_BLOCK_SIZE);
150}
151
152static struct crypto_alg des3_128_alg = {
153 .cra_name = "des3_ede128",
154 .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
155 .cra_blocksize = DES3_128_BLOCK_SIZE,
156 .cra_ctxsize = sizeof(struct crypt_z990_des3_128_ctx),
157 .cra_module = THIS_MODULE,
158 .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list),
159 .cra_u = { .cipher = {
160 .cia_min_keysize = DES3_128_KEY_SIZE,
161 .cia_max_keysize = DES3_128_KEY_SIZE,
162 .cia_setkey = des3_128_setkey,
163 .cia_encrypt = des3_128_encrypt,
164 .cia_decrypt = des3_128_decrypt } }
165};
166
167/*
168 * RFC2451:
169 *
170 * For DES-EDE3, there is no known need to reject weak or
171 * complementation keys. Any weakness is obviated by the use of
172 * multiple keys.
173 *
174 * However, if the first two or last two independent 64-bit keys are
175 * equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
176 * same as DES. Implementers MUST reject keys that exhibit this
177 * property.
178 *
179 */
180static int
181des3_192_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
182{
183 int i, ret;
184 struct crypt_z990_des3_192_ctx *dctx;
185 const u8* temp_key;
186
187 dctx = ctx;
188 temp_key = key;
189 if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
190 memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
191 DES_KEY_SIZE))) {
192
193 *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
194 return -EINVAL;
195 }
196 for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
197 ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
198 if (ret < 0){
199 return ret;
200 }
201 }
202 memcpy(dctx->key, key, keylen);
203 return 0;
204}
205
206static void
207des3_192_encrypt(void *ctx, u8 *dst, const u8 *src)
208{
209 struct crypt_z990_des3_192_ctx *dctx;
210
211 dctx = ctx;
212 crypt_z990_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src,
213 DES3_192_BLOCK_SIZE);
214}
215
216static void
217des3_192_decrypt(void *ctx, u8 *dst, const u8 *src)
218{
219 struct crypt_z990_des3_192_ctx *dctx;
220
221 dctx = ctx;
222 crypt_z990_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src,
223 DES3_192_BLOCK_SIZE);
224}
225
226static struct crypto_alg des3_192_alg = {
227 .cra_name = "des3_ede",
228 .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
229 .cra_blocksize = DES3_192_BLOCK_SIZE,
230 .cra_ctxsize = sizeof(struct crypt_z990_des3_192_ctx),
231 .cra_module = THIS_MODULE,
232 .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list),
233 .cra_u = { .cipher = {
234 .cia_min_keysize = DES3_192_KEY_SIZE,
235 .cia_max_keysize = DES3_192_KEY_SIZE,
236 .cia_setkey = des3_192_setkey,
237 .cia_encrypt = des3_192_encrypt,
238 .cia_decrypt = des3_192_decrypt } }
239};
240
241
242
243static int
244init(void)
245{
246 int ret;
247
248 if (!crypt_z990_func_available(KM_DEA_ENCRYPT) ||
249 !crypt_z990_func_available(KM_TDEA_128_ENCRYPT) ||
250 !crypt_z990_func_available(KM_TDEA_192_ENCRYPT)){
251 return -ENOSYS;
252 }
253
254 ret = 0;
255 ret |= (crypto_register_alg(&des_alg) == 0)? 0:1;
256 ret |= (crypto_register_alg(&des3_128_alg) == 0)? 0:2;
257 ret |= (crypto_register_alg(&des3_192_alg) == 0)? 0:4;
258 if (ret){
259 crypto_unregister_alg(&des3_192_alg);
260 crypto_unregister_alg(&des3_128_alg);
261 crypto_unregister_alg(&des_alg);
262 return -EEXIST;
263 }
264
265 printk(KERN_INFO "crypt_z990: des_z990 loaded.\n");
266 return 0;
267}
268
269static void __exit
270fini(void)
271{
272 crypto_unregister_alg(&des3_192_alg);
273 crypto_unregister_alg(&des3_128_alg);
274 crypto_unregister_alg(&des_alg);
275}
276
277module_init(init);
278module_exit(fini);
279
280MODULE_ALIAS("des");
281MODULE_ALIAS("des3_ede");
282
283MODULE_LICENSE("GPL");
284MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
diff --git a/arch/s390/crypto/sha1_z990.c b/arch/s390/crypto/sha1_z990.c
new file mode 100644
index 000000000000..298174ddf5b1
--- /dev/null
+++ b/arch/s390/crypto/sha1_z990.c
@@ -0,0 +1,167 @@
1/*
2 * Cryptographic API.
3 *
4 * z990 implementation of the SHA1 Secure Hash Algorithm.
5 *
6 * Derived from cryptoapi implementation, adapted for in-place
7 * scatterlist interface. Originally based on the public domain
8 * implementation written by Steve Reid.
9 *
10 * s390 Version:
11 * Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
12 * Author(s): Thomas Spatzier (tspat@de.ibm.com)
13 *
14 * Derived from "crypto/sha1.c"
15 * Copyright (c) Alan Smithee.
16 * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
17 * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
18 *
19 * This program is free software; you can redistribute it and/or modify it
20 * under the terms of the GNU General Public License as published by the Free
21 * Software Foundation; either version 2 of the License, or (at your option)
22 * any later version.
23 *
24 */
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/mm.h>
28#include <linux/crypto.h>
29#include <asm/scatterlist.h>
30#include <asm/byteorder.h>
31#include "crypt_z990.h"
32
33#define SHA1_DIGEST_SIZE 20
34#define SHA1_BLOCK_SIZE 64
35
36struct crypt_z990_sha1_ctx {
37 u64 count;
38 u32 state[5];
39 u32 buf_len;
40 u8 buffer[2 * SHA1_BLOCK_SIZE];
41};
42
43static void
44sha1_init(void *ctx)
45{
46 static const struct crypt_z990_sha1_ctx initstate = {
47 .state = {
48 0x67452301,
49 0xEFCDAB89,
50 0x98BADCFE,
51 0x10325476,
52 0xC3D2E1F0
53 },
54 };
55 memcpy(ctx, &initstate, sizeof(initstate));
56}
57
58static void
59sha1_update(void *ctx, const u8 *data, unsigned int len)
60{
61 struct crypt_z990_sha1_ctx *sctx;
62 long imd_len;
63
64 sctx = ctx;
65 sctx->count += len * 8; //message bit length
66
67 //anything in buffer yet? -> must be completed
68 if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) {
69 //complete full block and hash
70 memcpy(sctx->buffer + sctx->buf_len, data,
71 SHA1_BLOCK_SIZE - sctx->buf_len);
72 crypt_z990_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
73 SHA1_BLOCK_SIZE);
74 data += SHA1_BLOCK_SIZE - sctx->buf_len;
75 len -= SHA1_BLOCK_SIZE - sctx->buf_len;
76 sctx->buf_len = 0;
77 }
78
79 //rest of data contains full blocks?
80 imd_len = len & ~0x3ful;
81 if (imd_len){
82 crypt_z990_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
83 data += imd_len;
84 len -= imd_len;
85 }
86 //anything left? store in buffer
87 if (len){
88 memcpy(sctx->buffer + sctx->buf_len , data, len);
89 sctx->buf_len += len;
90 }
91}
92
93
94static void
95pad_message(struct crypt_z990_sha1_ctx* sctx)
96{
97 int index;
98
99 index = sctx->buf_len;
100 sctx->buf_len = (sctx->buf_len < 56)?
101 SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
102 //start pad with 1
103 sctx->buffer[index] = 0x80;
104 //pad with zeros
105 index++;
106 memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
107 //append length
108 memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
109 sizeof sctx->count);
110}
111
112/* Add padding and return the message digest. */
113static void
114sha1_final(void* ctx, u8 *out)
115{
116 struct crypt_z990_sha1_ctx *sctx = ctx;
117
118 //must perform manual padding
119 pad_message(sctx);
120 crypt_z990_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len);
121 //copy digest to out
122 memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
123 /* Wipe context */
124 memset(sctx, 0, sizeof *sctx);
125}
126
127static struct crypto_alg alg = {
128 .cra_name = "sha1",
129 .cra_flags = CRYPTO_ALG_TYPE_DIGEST,
130 .cra_blocksize = SHA1_BLOCK_SIZE,
131 .cra_ctxsize = sizeof(struct crypt_z990_sha1_ctx),
132 .cra_module = THIS_MODULE,
133 .cra_list = LIST_HEAD_INIT(alg.cra_list),
134 .cra_u = { .digest = {
135 .dia_digestsize = SHA1_DIGEST_SIZE,
136 .dia_init = sha1_init,
137 .dia_update = sha1_update,
138 .dia_final = sha1_final } }
139};
140
141static int
142init(void)
143{
144 int ret = -ENOSYS;
145
146 if (crypt_z990_func_available(KIMD_SHA_1)){
147 ret = crypto_register_alg(&alg);
148 if (ret == 0){
149 printk(KERN_INFO "crypt_z990: sha1_z990 loaded.\n");
150 }
151 }
152 return ret;
153}
154
155static void __exit
156fini(void)
157{
158 crypto_unregister_alg(&alg);
159}
160
161module_init(init);
162module_exit(fini);
163
164MODULE_ALIAS("sha1");
165
166MODULE_LICENSE("GPL");
167MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
new file mode 100644
index 000000000000..1358b4201701
--- /dev/null
+++ b/arch/s390/defconfig
@@ -0,0 +1,589 @@
1#
2# Automatically generated make config: don't edit
3# Linux kernel version: 2.6.11
4# Wed Mar 2 16:57:55 2005
5#
6CONFIG_MMU=y
7CONFIG_RWSEM_XCHGADD_ALGORITHM=y
8CONFIG_GENERIC_CALIBRATE_DELAY=y
9CONFIG_ARCH_S390=y
10CONFIG_UID16=y
11
12#
13# Code maturity level options
14#
15CONFIG_EXPERIMENTAL=y
16CONFIG_CLEAN_COMPILE=y
17CONFIG_LOCK_KERNEL=y
18
19#
20# General setup
21#
22CONFIG_LOCALVERSION=""
23CONFIG_SWAP=y
24CONFIG_SYSVIPC=y
25# CONFIG_POSIX_MQUEUE is not set
26# CONFIG_BSD_PROCESS_ACCT is not set
27CONFIG_SYSCTL=y
28# CONFIG_AUDIT is not set
29CONFIG_LOG_BUF_SHIFT=17
30CONFIG_HOTPLUG=y
31CONFIG_KOBJECT_UEVENT=y
32CONFIG_IKCONFIG=y
33CONFIG_IKCONFIG_PROC=y
34# CONFIG_EMBEDDED is not set
35CONFIG_KALLSYMS=y
36# CONFIG_KALLSYMS_ALL is not set
37# CONFIG_KALLSYMS_EXTRA_PASS is not set
38CONFIG_FUTEX=y
39CONFIG_EPOLL=y
40# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
41CONFIG_SHMEM=y
42CONFIG_CC_ALIGN_FUNCTIONS=0
43CONFIG_CC_ALIGN_LABELS=0
44CONFIG_CC_ALIGN_LOOPS=0
45CONFIG_CC_ALIGN_JUMPS=0
46# CONFIG_TINY_SHMEM is not set
47
48#
49# Loadable module support
50#
51CONFIG_MODULES=y
52# CONFIG_MODULE_UNLOAD is not set
53CONFIG_OBSOLETE_MODPARM=y
54# CONFIG_MODVERSIONS is not set
55# CONFIG_MODULE_SRCVERSION_ALL is not set
56CONFIG_KMOD=y
57CONFIG_STOP_MACHINE=y
58
59#
60# Base setup
61#
62
63#
64# Processor type and features
65#
66# CONFIG_ARCH_S390X is not set
67# CONFIG_64BIT is not set
68CONFIG_ARCH_S390_31=y
69CONFIG_SMP=y
70CONFIG_NR_CPUS=32
71CONFIG_HOTPLUG_CPU=y
72CONFIG_MATHEMU=y
73
74#
75# Code generation options
76#
77CONFIG_MARCH_G5=y
78# CONFIG_MARCH_Z900 is not set
79# CONFIG_MARCH_Z990 is not set
80CONFIG_PACK_STACK=y
81# CONFIG_SMALL_STACK is not set
82# CONFIG_CHECK_STACK is not set
83# CONFIG_WARN_STACK is not set
84
85#
86# I/O subsystem configuration
87#
88CONFIG_MACHCHK_WARNING=y
89CONFIG_QDIO=y
90# CONFIG_QDIO_PERF_STATS is not set
91# CONFIG_QDIO_DEBUG is not set
92
93#
94# Misc
95#
96# CONFIG_PREEMPT is not set
97CONFIG_IPL=y
98# CONFIG_IPL_TAPE is not set
99CONFIG_IPL_VM=y
100CONFIG_BINFMT_ELF=y
101CONFIG_BINFMT_MISC=m
102# CONFIG_PROCESS_DEBUG is not set
103CONFIG_PFAULT=y
104# CONFIG_SHARED_KERNEL is not set
105# CONFIG_CMM is not set
106# CONFIG_VIRT_TIMER is not set
107CONFIG_NO_IDLE_HZ=y
108CONFIG_NO_IDLE_HZ_INIT=y
109# CONFIG_PCMCIA is not set
110
111#
112# Generic Driver Options
113#
114CONFIG_STANDALONE=y
115CONFIG_PREVENT_FIRMWARE_BUILD=y
116# CONFIG_FW_LOADER is not set
117# CONFIG_DEBUG_DRIVER is not set
118
119#
120# SCSI device support
121#
122CONFIG_SCSI=y
123CONFIG_SCSI_PROC_FS=y
124
125#
126# SCSI support type (disk, tape, CD-ROM)
127#
128CONFIG_BLK_DEV_SD=y
129CONFIG_CHR_DEV_ST=y
130# CONFIG_CHR_DEV_OSST is not set
131CONFIG_BLK_DEV_SR=y
132CONFIG_BLK_DEV_SR_VENDOR=y
133CONFIG_CHR_DEV_SG=y
134
135#
136# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
137#
138CONFIG_SCSI_MULTI_LUN=y
139CONFIG_SCSI_CONSTANTS=y
140CONFIG_SCSI_LOGGING=y
141
142#
143# SCSI Transport Attributes
144#
145# CONFIG_SCSI_SPI_ATTRS is not set
146CONFIG_SCSI_FC_ATTRS=y
147# CONFIG_SCSI_ISCSI_ATTRS is not set
148
149#
150# SCSI low-level drivers
151#
152# CONFIG_SCSI_SATA is not set
153# CONFIG_SCSI_DEBUG is not set
154CONFIG_ZFCP=y
155CONFIG_CCW=y
156
157#
158# Block devices
159#
160# CONFIG_BLK_DEV_COW_COMMON is not set
161CONFIG_BLK_DEV_LOOP=m
162# CONFIG_BLK_DEV_CRYPTOLOOP is not set
163CONFIG_BLK_DEV_NBD=m
164CONFIG_BLK_DEV_RAM=y
165CONFIG_BLK_DEV_RAM_COUNT=16
166CONFIG_BLK_DEV_RAM_SIZE=4096
167CONFIG_BLK_DEV_INITRD=y
168CONFIG_INITRAMFS_SOURCE=""
169# CONFIG_LBD is not set
170# CONFIG_CDROM_PKTCDVD is not set
171
172#
173# S/390 block device drivers
174#
175CONFIG_BLK_DEV_XPRAM=m
176# CONFIG_DCSSBLK is not set
177CONFIG_DASD=y
178CONFIG_DASD_PROFILE=y
179CONFIG_DASD_ECKD=y
180CONFIG_DASD_FBA=y
181CONFIG_DASD_DIAG=y
182# CONFIG_DASD_CMB is not set
183
184#
185# IO Schedulers
186#
187CONFIG_IOSCHED_NOOP=y
188CONFIG_IOSCHED_AS=y
189CONFIG_IOSCHED_DEADLINE=y
190CONFIG_IOSCHED_CFQ=y
191# CONFIG_ATA_OVER_ETH is not set
192
193#
194# Multi-device support (RAID and LVM)
195#
196CONFIG_MD=y
197CONFIG_BLK_DEV_MD=y
198CONFIG_MD_LINEAR=m
199CONFIG_MD_RAID0=m
200CONFIG_MD_RAID1=m
201# CONFIG_MD_RAID10 is not set
202CONFIG_MD_RAID5=m
203# CONFIG_MD_RAID6 is not set
204CONFIG_MD_MULTIPATH=m
205# CONFIG_MD_FAULTY is not set
206# CONFIG_BLK_DEV_DM is not set
207
208#
209# Character device drivers
210#
211CONFIG_UNIX98_PTYS=y
212CONFIG_UNIX98_PTY_COUNT=2048
213
214#
215# Watchdog Cards
216#
217# CONFIG_WATCHDOG is not set
218
219#
220# S/390 character device drivers
221#
222CONFIG_TN3270=y
223CONFIG_TN3270_TTY=y
224CONFIG_TN3270_FS=m
225CONFIG_TN3270_CONSOLE=y
226CONFIG_TN3215=y
227CONFIG_TN3215_CONSOLE=y
228CONFIG_CCW_CONSOLE=y
229CONFIG_SCLP=y
230CONFIG_SCLP_TTY=y
231CONFIG_SCLP_CONSOLE=y
232# CONFIG_SCLP_VT220_TTY is not set
233CONFIG_SCLP_CPI=m
234CONFIG_S390_TAPE=m
235
236#
237# S/390 tape interface support
238#
239CONFIG_S390_TAPE_BLOCK=y
240
241#
242# S/390 tape hardware support
243#
244CONFIG_S390_TAPE_34XX=m
245# CONFIG_VMLOGRDR is not set
246# CONFIG_MONREADER is not set
247# CONFIG_DCSS_SHM is not set
248
249#
250# Cryptographic devices
251#
252CONFIG_Z90CRYPT=m
253
254#
255# Networking support
256#
257CONFIG_NET=y
258
259#
260# Networking options
261#
262CONFIG_PACKET=y
263# CONFIG_PACKET_MMAP is not set
264# CONFIG_NETLINK_DEV is not set
265CONFIG_UNIX=y
266CONFIG_NET_KEY=y
267CONFIG_INET=y
268CONFIG_IP_MULTICAST=y
269# CONFIG_IP_ADVANCED_ROUTER is not set
270# CONFIG_IP_PNP is not set
271# CONFIG_NET_IPIP is not set
272# CONFIG_NET_IPGRE is not set
273# CONFIG_IP_MROUTE is not set
274# CONFIG_ARPD is not set
275# CONFIG_SYN_COOKIES is not set
276# CONFIG_INET_AH is not set
277# CONFIG_INET_ESP is not set
278# CONFIG_INET_IPCOMP is not set
279# CONFIG_INET_TUNNEL is not set
280CONFIG_IP_TCPDIAG=y
281CONFIG_IP_TCPDIAG_IPV6=y
282CONFIG_IPV6=y
283# CONFIG_IPV6_PRIVACY is not set
284# CONFIG_INET6_AH is not set
285# CONFIG_INET6_ESP is not set
286# CONFIG_INET6_IPCOMP is not set
287# CONFIG_INET6_TUNNEL is not set
288# CONFIG_IPV6_TUNNEL is not set
289# CONFIG_NETFILTER is not set
290CONFIG_XFRM=y
291# CONFIG_XFRM_USER is not set
292
293#
294# SCTP Configuration (EXPERIMENTAL)
295#
296# CONFIG_IP_SCTP is not set
297# CONFIG_ATM is not set
298# CONFIG_BRIDGE is not set
299# CONFIG_VLAN_8021Q is not set
300# CONFIG_DECNET is not set
301# CONFIG_LLC2 is not set
302# CONFIG_IPX is not set
303# CONFIG_ATALK is not set
304# CONFIG_X25 is not set
305# CONFIG_LAPB is not set
306# CONFIG_NET_DIVERT is not set
307# CONFIG_ECONET is not set
308# CONFIG_WAN_ROUTER is not set
309
310#
311# QoS and/or fair queueing
312#
313CONFIG_NET_SCHED=y
314CONFIG_NET_SCH_CLK_JIFFIES=y
315# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
316# CONFIG_NET_SCH_CLK_CPU is not set
317CONFIG_NET_SCH_CBQ=m
318# CONFIG_NET_SCH_HTB is not set
319# CONFIG_NET_SCH_HFSC is not set
320CONFIG_NET_SCH_PRIO=m
321CONFIG_NET_SCH_RED=m
322CONFIG_NET_SCH_SFQ=m
323CONFIG_NET_SCH_TEQL=m
324CONFIG_NET_SCH_TBF=m
325CONFIG_NET_SCH_GRED=m
326CONFIG_NET_SCH_DSMARK=m
327# CONFIG_NET_SCH_NETEM is not set
328# CONFIG_NET_SCH_INGRESS is not set
329CONFIG_NET_QOS=y
330CONFIG_NET_ESTIMATOR=y
331CONFIG_NET_CLS=y
332CONFIG_NET_CLS_TCINDEX=m
333CONFIG_NET_CLS_ROUTE4=m
334CONFIG_NET_CLS_ROUTE=y
335CONFIG_NET_CLS_FW=m
336CONFIG_NET_CLS_U32=m
337# CONFIG_CLS_U32_PERF is not set
338# CONFIG_NET_CLS_IND is not set
339CONFIG_NET_CLS_RSVP=m
340CONFIG_NET_CLS_RSVP6=m
341# CONFIG_NET_CLS_ACT is not set
342CONFIG_NET_CLS_POLICE=y
343
344#
345# Network testing
346#
347# CONFIG_NET_PKTGEN is not set
348# CONFIG_NETPOLL is not set
349# CONFIG_NET_POLL_CONTROLLER is not set
350# CONFIG_HAMRADIO is not set
351# CONFIG_IRDA is not set
352# CONFIG_BT is not set
353CONFIG_NETDEVICES=y
354CONFIG_DUMMY=m
355CONFIG_BONDING=m
356CONFIG_EQUALIZER=m
357CONFIG_TUN=m
358
359#
360# Ethernet (10 or 100Mbit)
361#
362CONFIG_NET_ETHERNET=y
363# CONFIG_MII is not set
364
365#
366# Ethernet (1000 Mbit)
367#
368
369#
370# Ethernet (10000 Mbit)
371#
372
373#
374# Token Ring devices
375#
376# CONFIG_TR is not set
377
378#
379# Wireless LAN (non-hamradio)
380#
381# CONFIG_NET_RADIO is not set
382
383#
384# Wan interfaces
385#
386# CONFIG_WAN is not set
387
388#
389# S/390 network device drivers
390#
391CONFIG_LCS=m
392CONFIG_CTC=m
393CONFIG_IUCV=m
394# CONFIG_NETIUCV is not set
395# CONFIG_SMSGIUCV is not set
396CONFIG_QETH=y
397
398#
399# Gigabit Ethernet default settings
400#
401# CONFIG_QETH_IPV6 is not set
402# CONFIG_QETH_PERF_STATS is not set
403CONFIG_CCWGROUP=y
404# CONFIG_PPP is not set
405# CONFIG_SLIP is not set
406# CONFIG_SHAPER is not set
407# CONFIG_NETCONSOLE is not set
408
409#
410# File systems
411#
412CONFIG_EXT2_FS=y
413# CONFIG_EXT2_FS_XATTR is not set
414CONFIG_EXT3_FS=y
415CONFIG_EXT3_FS_XATTR=y
416# CONFIG_EXT3_FS_POSIX_ACL is not set
417# CONFIG_EXT3_FS_SECURITY is not set
418CONFIG_JBD=y
419# CONFIG_JBD_DEBUG is not set
420CONFIG_FS_MBCACHE=y
421# CONFIG_REISERFS_FS is not set
422# CONFIG_JFS_FS is not set
423
424#
425# XFS support
426#
427# CONFIG_XFS_FS is not set
428# CONFIG_MINIX_FS is not set
429# CONFIG_ROMFS_FS is not set
430# CONFIG_QUOTA is not set
431CONFIG_DNOTIFY=y
432# CONFIG_AUTOFS_FS is not set
433# CONFIG_AUTOFS4_FS is not set
434
435#
436# CD-ROM/DVD Filesystems
437#
438# CONFIG_ISO9660_FS is not set
439# CONFIG_UDF_FS is not set
440
441#
442# DOS/FAT/NT Filesystems
443#
444# CONFIG_MSDOS_FS is not set
445# CONFIG_VFAT_FS is not set
446# CONFIG_NTFS_FS is not set
447
448#
449# Pseudo filesystems
450#
451CONFIG_PROC_FS=y
452CONFIG_PROC_KCORE=y
453CONFIG_SYSFS=y
454# CONFIG_DEVFS_FS is not set
455# CONFIG_DEVPTS_FS_XATTR is not set
456CONFIG_TMPFS=y
457# CONFIG_TMPFS_XATTR is not set
458# CONFIG_HUGETLB_PAGE is not set
459CONFIG_RAMFS=y
460
461#
462# Miscellaneous filesystems
463#
464# CONFIG_ADFS_FS is not set
465# CONFIG_AFFS_FS is not set
466# CONFIG_HFS_FS is not set
467# CONFIG_HFSPLUS_FS is not set
468# CONFIG_BEFS_FS is not set
469# CONFIG_BFS_FS is not set
470# CONFIG_EFS_FS is not set
471# CONFIG_CRAMFS is not set
472# CONFIG_VXFS_FS is not set
473# CONFIG_HPFS_FS is not set
474# CONFIG_QNX4FS_FS is not set
475# CONFIG_SYSV_FS is not set
476# CONFIG_UFS_FS is not set
477
478#
479# Network File Systems
480#
481CONFIG_NFS_FS=y
482CONFIG_NFS_V3=y
483# CONFIG_NFS_V4 is not set
484# CONFIG_NFS_DIRECTIO is not set
485CONFIG_NFSD=y
486CONFIG_NFSD_V3=y
487# CONFIG_NFSD_V4 is not set
488CONFIG_NFSD_TCP=y
489CONFIG_LOCKD=y
490CONFIG_LOCKD_V4=y
491CONFIG_EXPORTFS=y
492CONFIG_SUNRPC=y
493# CONFIG_RPCSEC_GSS_KRB5 is not set
494# CONFIG_RPCSEC_GSS_SPKM3 is not set
495# CONFIG_SMB_FS is not set
496# CONFIG_CIFS is not set
497# CONFIG_NCP_FS is not set
498# CONFIG_CODA_FS is not set
499# CONFIG_AFS_FS is not set
500
501#
502# Partition Types
503#
504CONFIG_PARTITION_ADVANCED=y
505# CONFIG_ACORN_PARTITION is not set
506# CONFIG_OSF_PARTITION is not set
507# CONFIG_AMIGA_PARTITION is not set
508# CONFIG_ATARI_PARTITION is not set
509CONFIG_IBM_PARTITION=y
510# CONFIG_MAC_PARTITION is not set
511CONFIG_MSDOS_PARTITION=y
512# CONFIG_BSD_DISKLABEL is not set
513# CONFIG_MINIX_SUBPARTITION is not set
514# CONFIG_SOLARIS_X86_PARTITION is not set
515# CONFIG_UNIXWARE_DISKLABEL is not set
516# CONFIG_LDM_PARTITION is not set
517# CONFIG_SGI_PARTITION is not set
518# CONFIG_ULTRIX_PARTITION is not set
519# CONFIG_SUN_PARTITION is not set
520# CONFIG_EFI_PARTITION is not set
521
522#
523# Native Language Support
524#
525# CONFIG_NLS is not set
526
527#
528# Profiling support
529#
530# CONFIG_PROFILING is not set
531
532#
533# Kernel hacking
534#
535CONFIG_DEBUG_KERNEL=y
536CONFIG_MAGIC_SYSRQ=y
537# CONFIG_SCHEDSTATS is not set
538# CONFIG_DEBUG_SLAB is not set
539# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
540# CONFIG_DEBUG_KOBJECT is not set
541# CONFIG_DEBUG_INFO is not set
542# CONFIG_DEBUG_FS is not set
543
544#
545# Security options
546#
547# CONFIG_KEYS is not set
548# CONFIG_SECURITY is not set
549
550#
551# Cryptographic options
552#
553CONFIG_CRYPTO=y
554# CONFIG_CRYPTO_HMAC is not set
555# CONFIG_CRYPTO_NULL is not set
556# CONFIG_CRYPTO_MD4 is not set
557# CONFIG_CRYPTO_MD5 is not set
558# CONFIG_CRYPTO_SHA1 is not set
559# CONFIG_CRYPTO_SHA1_Z990 is not set
560# CONFIG_CRYPTO_SHA256 is not set
561# CONFIG_CRYPTO_SHA512 is not set
562# CONFIG_CRYPTO_WP512 is not set
563# CONFIG_CRYPTO_DES is not set
564# CONFIG_CRYPTO_DES_Z990 is not set
565# CONFIG_CRYPTO_BLOWFISH is not set
566# CONFIG_CRYPTO_TWOFISH is not set
567# CONFIG_CRYPTO_SERPENT is not set
568# CONFIG_CRYPTO_AES is not set
569# CONFIG_CRYPTO_CAST5 is not set
570# CONFIG_CRYPTO_CAST6 is not set
571# CONFIG_CRYPTO_TEA is not set
572# CONFIG_CRYPTO_ARC4 is not set
573# CONFIG_CRYPTO_KHAZAD is not set
574# CONFIG_CRYPTO_ANUBIS is not set
575# CONFIG_CRYPTO_DEFLATE is not set
576# CONFIG_CRYPTO_MICHAEL_MIC is not set
577# CONFIG_CRYPTO_CRC32C is not set
578# CONFIG_CRYPTO_TEST is not set
579
580#
581# Hardware crypto devices
582#
583
584#
585# Library routines
586#
587# CONFIG_CRC_CCITT is not set
588CONFIG_CRC32=m
589# CONFIG_LIBCRC32C is not set
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
new file mode 100644
index 000000000000..b41e0e199a7c
--- /dev/null
+++ b/arch/s390/kernel/Makefile
@@ -0,0 +1,31 @@
1#
2# Makefile for the linux kernel.
3#
4
5EXTRA_AFLAGS := -traditional
6
7obj-y := bitmap.o traps.o time.o process.o \
8 setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
9 semaphore.o s390_ext.o debug.o profile.o irq.o
10
11extra-$(CONFIG_ARCH_S390_31) += head.o
12extra-$(CONFIG_ARCH_S390X) += head64.o
13extra-y += init_task.o vmlinux.lds
14
15obj-$(CONFIG_MODULES) += s390_ksyms.o module.o
16obj-$(CONFIG_SMP) += smp.o
17
18obj-$(CONFIG_S390_SUPPORT) += compat_linux.o compat_signal.o \
19 compat_ioctl.o compat_wrapper.o \
20 compat_exec_domain.o
21obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
22
23obj-$(CONFIG_ARCH_S390_31) += entry.o reipl.o
24obj-$(CONFIG_ARCH_S390X) += entry64.o reipl64.o
25
26obj-$(CONFIG_VIRT_TIMER) += vtime.o
27
28#
29# This is just to get the dependencies...
30#
31binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
new file mode 100644
index 000000000000..3f7018e9dbe4
--- /dev/null
+++ b/arch/s390/kernel/asm-offsets.c
@@ -0,0 +1,49 @@
1/*
2 * Generate definitions needed by assembly language modules.
3 * This code generates raw asm output which is post-processed to extract
4 * and format the required data.
5 */
6
7#include <linux/config.h>
8#include <linux/sched.h>
9
10/* Use marker if you need to separate the values later */
11
12#define DEFINE(sym, val, marker) \
13 asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val))
14
15#define BLANK() asm volatile("\n->" : : )
16
17int main(void)
18{
19 DEFINE(__THREAD_info, offsetof(struct task_struct, thread_info),);
20 DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
21 DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
22 DEFINE(__THREAD_mm_segment,
23 offsetof(struct task_struct, thread.mm_segment),);
24 BLANK();
25 DEFINE(__TASK_pid, offsetof(struct task_struct, pid),);
26 BLANK();
27 DEFINE(__PER_atmid, offsetof(per_struct, lowcore.words.perc_atmid),);
28 DEFINE(__PER_address, offsetof(per_struct, lowcore.words.address),);
29 DEFINE(__PER_access_id, offsetof(per_struct, lowcore.words.access_id),);
30 BLANK();
31 DEFINE(__TI_task, offsetof(struct thread_info, task),);
32 DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain),);
33 DEFINE(__TI_flags, offsetof(struct thread_info, flags),);
34 DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),);
35 DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),);
36 BLANK();
37 DEFINE(__PT_ARGS, offsetof(struct pt_regs, args),);
38 DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),);
39 DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),);
40 DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),);
41 DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc),);
42 DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap),);
43 DEFINE(__PT_SIZE, sizeof(struct pt_regs),);
44 BLANK();
45 DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain),);
46 DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs),);
47 DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1),);
48 return 0;
49}
diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c
new file mode 100644
index 000000000000..03ba5893f17b
--- /dev/null
+++ b/arch/s390/kernel/binfmt_elf32.c
@@ -0,0 +1,210 @@
1/*
2 * Support for 32-bit Linux for S390 ELF binaries.
3 *
4 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
5 * Author(s): Gerhard Tonn (ton@de.ibm.com)
6 *
7 * Heavily inspired by the 32-bit Sparc compat code which is
8 * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
9 * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
10 */
11
12#define __ASMS390_ELF_H
13
14#include <linux/time.h>
15
16/*
17 * These are used to set parameters in the core dumps.
18 */
19#define ELF_CLASS ELFCLASS32
20#define ELF_DATA ELFDATA2MSB
21#define ELF_ARCH EM_S390
22
23/*
24 * This is used to ensure we don't load something for the wrong architecture.
25 */
26#define elf_check_arch(x) \
27 (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
28 && (x)->e_ident[EI_CLASS] == ELF_CLASS)
29
30/* ELF register definitions */
31#define NUM_GPRS 16
32#define NUM_FPRS 16
33#define NUM_ACRS 16
34
35/* For SVR4/S390 the function pointer to be registered with `atexit` is
36 passed in R14. */
37#define ELF_PLAT_INIT(_r, load_addr) \
38 do { \
39 _r->gprs[14] = 0; \
40 } while(0)
41
42#define USE_ELF_CORE_DUMP
43#define ELF_EXEC_PAGESIZE 4096
44
45/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
46 use of this is to invoke "./ld.so someprog" to test out a new version of
47 the loader. We need to make sure that it is out of the way of the program
48 that it will "exec", and that there is sufficient room for the brk. */
49
50#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
51
52/* Wow, the "main" arch needs arch dependent functions too.. :) */
53
54/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
55 now struct_user_regs, they are different) */
56
57#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs32(regs, &pr_reg);
58
59#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs32(tsk, regs)
60
61#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs)
62
63/* This yields a mask that user programs can use to figure out what
64 instruction set this CPU supports. */
65
66#define ELF_HWCAP (0)
67
68/* This yields a string that ld.so will use to load implementation
69 specific libraries for optimization. This is more specific in
70 intent than poking at uname or /proc/cpuinfo.
71
72 For the moment, we have only optimizations for the Intel generations,
73 but that could change... */
74
75#define ELF_PLATFORM (NULL)
76
77#define SET_PERSONALITY(ex, ibcs2) \
78do { \
79 if (ibcs2) \
80 set_personality(PER_SVR4); \
81 else if (current->personality != PER_LINUX32) \
82 set_personality(PER_LINUX); \
83 set_thread_flag(TIF_31BIT); \
84} while (0)
85
86#include "compat_linux.h"
87
88typedef _s390_fp_regs32 elf_fpregset_t;
89
90typedef struct
91{
92
93 _psw_t32 psw;
94 __u32 gprs[__NUM_GPRS];
95 __u32 acrs[__NUM_ACRS];
96 __u32 orig_gpr2;
97} s390_regs32;
98typedef s390_regs32 elf_gregset_t;
99
100static inline int dump_regs32(struct pt_regs *ptregs, elf_gregset_t *regs)
101{
102 int i;
103
104 memcpy(&regs->psw.mask, &ptregs->psw.mask, 4);
105 memcpy(&regs->psw.addr, (char *)&ptregs->psw.addr + 4, 4);
106 for (i = 0; i < NUM_GPRS; i++)
107 regs->gprs[i] = ptregs->gprs[i];
108 save_access_regs(regs->acrs);
109 regs->orig_gpr2 = ptregs->orig_gpr2;
110 return 1;
111}
112
113static inline int dump_task_regs32(struct task_struct *tsk, elf_gregset_t *regs)
114{
115 struct pt_regs *ptregs = __KSTK_PTREGS(tsk);
116 int i;
117
118 memcpy(&regs->psw.mask, &ptregs->psw.mask, 4);
119 memcpy(&regs->psw.addr, (char *)&ptregs->psw.addr + 4, 4);
120 for (i = 0; i < NUM_GPRS; i++)
121 regs->gprs[i] = ptregs->gprs[i];
122 memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs));
123 regs->orig_gpr2 = ptregs->orig_gpr2;
124 return 1;
125}
126
127static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
128{
129 if (tsk == current)
130 save_fp_regs((s390_fp_regs *) fpregs);
131 else
132 memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t));
133 return 1;
134}
135
136#include <asm/processor.h>
137#include <linux/module.h>
138#include <linux/config.h>
139#include <linux/elfcore.h>
140#include <linux/binfmts.h>
141#include <linux/compat.h>
142
143#define elf_prstatus elf_prstatus32
144struct elf_prstatus32
145{
146 struct elf_siginfo pr_info; /* Info associated with signal */
147 short pr_cursig; /* Current signal */
148 u32 pr_sigpend; /* Set of pending signals */
149 u32 pr_sighold; /* Set of held signals */
150 pid_t pr_pid;
151 pid_t pr_ppid;
152 pid_t pr_pgrp;
153 pid_t pr_sid;
154 struct compat_timeval pr_utime; /* User time */
155 struct compat_timeval pr_stime; /* System time */
156 struct compat_timeval pr_cutime; /* Cumulative user time */
157 struct compat_timeval pr_cstime; /* Cumulative system time */
158 elf_gregset_t pr_reg; /* GP registers */
159 int pr_fpvalid; /* True if math co-processor being used. */
160};
161
162#define elf_prpsinfo elf_prpsinfo32
163struct elf_prpsinfo32
164{
165 char pr_state; /* numeric process state */
166 char pr_sname; /* char for pr_state */
167 char pr_zomb; /* zombie */
168 char pr_nice; /* nice val */
169 u32 pr_flag; /* flags */
170 u16 pr_uid;
171 u16 pr_gid;
172 pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
173 /* Lots missing */
174 char pr_fname[16]; /* filename of executable */
175 char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
176};
177
178#include <linux/highuid.h>
179
180#undef NEW_TO_OLD_UID
181#undef NEW_TO_OLD_GID
182#define NEW_TO_OLD_UID(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
183#define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
184
185#define elf_addr_t u32
186/*
187#define init_elf_binfmt init_elf32_binfmt
188*/
189
190#undef start_thread
191#define start_thread start_thread31
192
193MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries,"
194 " Copyright 2000 IBM Corporation");
195MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
196
197#undef MODULE_DESCRIPTION
198#undef MODULE_AUTHOR
199
200#undef cputime_to_timeval
201#define cputime_to_timeval cputime_to_compat_timeval
202static __inline__ void
203cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
204{
205 value->tv_usec = cputime % 1000000;
206 value->tv_sec = cputime / 1000000;
207}
208
209#include "../../../fs/binfmt_elf.c"
210
diff --git a/arch/s390/kernel/bitmap.S b/arch/s390/kernel/bitmap.S
new file mode 100644
index 000000000000..dfb41f946e23
--- /dev/null
+++ b/arch/s390/kernel/bitmap.S
@@ -0,0 +1,56 @@
1/*
2 * arch/s390/kernel/bitmap.S
3 * Bitmaps for set_bit, clear_bit, test_and_set_bit, ...
4 * See include/asm-s390/{bitops.h|posix_types.h} for details
5 *
6 * S390 version
7 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
8 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
9 */
10
11 .globl _oi_bitmap
12_oi_bitmap:
13 .byte 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
14
15 .globl _ni_bitmap
16_ni_bitmap:
17 .byte 0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F
18
19 .globl _zb_findmap
20_zb_findmap:
21 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
22 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
23 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
24 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6
25 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
26 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
27 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
28 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7
29 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
30 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
31 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
32 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6
33 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
34 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
35 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
36 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8
37
38 .globl _sb_findmap
39_sb_findmap:
40 .byte 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
41 .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
42 .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
43 .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
44 .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
45 .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
46 .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
47 .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
48 .byte 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
49 .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
50 .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
51 .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
52 .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
53 .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
54 .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
55 .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
56
diff --git a/arch/s390/kernel/compat_exec_domain.c b/arch/s390/kernel/compat_exec_domain.c
new file mode 100644
index 000000000000..71d27c493568
--- /dev/null
+++ b/arch/s390/kernel/compat_exec_domain.c
@@ -0,0 +1,30 @@
1/*
2 * Support for 32-bit Linux for S390 personality.
3 *
4 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
5 * Author(s): Gerhard Tonn (ton@de.ibm.com)
6 *
7 *
8 */
9
10#include <linux/kernel.h>
11#include <linux/init.h>
12#include <linux/personality.h>
13#include <linux/sched.h>
14
15struct exec_domain s390_exec_domain;
16
17static int __init
18s390_init (void)
19{
20 s390_exec_domain.name = "Linux/s390";
21 s390_exec_domain.handler = NULL;
22 s390_exec_domain.pers_low = PER_LINUX32;
23 s390_exec_domain.pers_high = PER_LINUX32;
24 s390_exec_domain.signal_map = default_exec_domain.signal_map;
25 s390_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
26 register_exec_domain(&s390_exec_domain);
27 return 0;
28}
29
30__initcall(s390_init);
diff --git a/arch/s390/kernel/compat_ioctl.c b/arch/s390/kernel/compat_ioctl.c
new file mode 100644
index 000000000000..96571ff7115d
--- /dev/null
+++ b/arch/s390/kernel/compat_ioctl.c
@@ -0,0 +1,73 @@
1/*
2 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
3 *
4 * S390 version
5 * Copyright (C) 2000-2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Gerhard Tonn (ton@de.ibm.com)
7 * Arnd Bergmann (arndb@de.ibm.com)
8 *
9 * Original implementation from 32-bit Sparc compat code which is
10 * Copyright (C) 2000 Silicon Graphics, Inc.
11 * Written by Ulf Carlsson (ulfc@engr.sgi.com)
12 */
13
14#include "compat_linux.h"
15#define INCLUDES
16#define CODE
17#include "../../../fs/compat_ioctl.c"
18#include <asm/dasd.h>
19#include <asm/tape390.h>
20
21static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd,
22 unsigned long arg, struct file *f)
23{
24 return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
25}
26
27static int do_ioctl32_ulong(unsigned int fd, unsigned int cmd,
28 unsigned long arg, struct file *f)
29{
30 return sys_ioctl(fd, cmd, arg);
31}
32
33#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL((cmd),(ioctl_trans_handler_t)do_ioctl32_pointer)
34#define ULONG_IOCTL(cmd) HANDLE_IOCTL((cmd),(ioctl_trans_handler_t)do_ioctl32_ulong)
35#define HANDLE_IOCTL(cmd,handler) { (cmd), (ioctl_trans_handler_t)(handler), NULL },
36
37struct ioctl_trans ioctl_start[] = {
38/* architecture independent ioctls */
39#include <linux/compat_ioctl.h>
40#define DECLARES
41#include "../../../fs/compat_ioctl.c"
42
43/* s390 only ioctls */
44#if defined(CONFIG_DASD) || defined(CONFIG_DASD_MODULE)
45COMPATIBLE_IOCTL(DASDAPIVER)
46COMPATIBLE_IOCTL(BIODASDDISABLE)
47COMPATIBLE_IOCTL(BIODASDENABLE)
48COMPATIBLE_IOCTL(BIODASDRSRV)
49COMPATIBLE_IOCTL(BIODASDRLSE)
50COMPATIBLE_IOCTL(BIODASDSLCK)
51COMPATIBLE_IOCTL(BIODASDINFO)
52COMPATIBLE_IOCTL(BIODASDINFO2)
53COMPATIBLE_IOCTL(BIODASDFMT)
54COMPATIBLE_IOCTL(BIODASDPRRST)
55COMPATIBLE_IOCTL(BIODASDQUIESCE)
56COMPATIBLE_IOCTL(BIODASDRESUME)
57COMPATIBLE_IOCTL(BIODASDPRRD)
58COMPATIBLE_IOCTL(BIODASDPSRD)
59COMPATIBLE_IOCTL(BIODASDGATTR)
60COMPATIBLE_IOCTL(BIODASDSATTR)
61
62#endif
63
64#if defined(CONFIG_S390_TAPE) || defined(CONFIG_S390_TAPE_MODULE)
65COMPATIBLE_IOCTL(TAPE390_DISPLAY)
66#endif
67
68/* s390 doesn't need handlers here */
69COMPATIBLE_IOCTL(TIOCGSERIAL)
70COMPATIBLE_IOCTL(TIOCSSERIAL)
71};
72
73int ioctl_table_size = ARRAY_SIZE(ioctl_start);
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
new file mode 100644
index 000000000000..614056222875
--- /dev/null
+++ b/arch/s390/kernel/compat_linux.c
@@ -0,0 +1,1045 @@
1/*
2 * arch/s390x/kernel/linux32.c
3 *
4 * S390 version
5 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 * Gerhard Tonn (ton@de.ibm.com)
8 * Thomas Spatzier (tspat@de.ibm.com)
9 *
10 * Conversion between 31bit and 64bit native syscalls.
11 *
12 * Heavily inspired by the 32-bit Sparc compat code which is
13 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
14 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
15 *
16 */
17
18
19#include <linux/config.h>
20#include <linux/kernel.h>
21#include <linux/sched.h>
22#include <linux/fs.h>
23#include <linux/mm.h>
24#include <linux/file.h>
25#include <linux/signal.h>
26#include <linux/resource.h>
27#include <linux/times.h>
28#include <linux/utsname.h>
29#include <linux/timex.h>
30#include <linux/smp.h>
31#include <linux/smp_lock.h>
32#include <linux/sem.h>
33#include <linux/msg.h>
34#include <linux/shm.h>
35#include <linux/slab.h>
36#include <linux/uio.h>
37#include <linux/nfs_fs.h>
38#include <linux/quota.h>
39#include <linux/module.h>
40#include <linux/sunrpc/svc.h>
41#include <linux/nfsd/nfsd.h>
42#include <linux/nfsd/cache.h>
43#include <linux/nfsd/xdr.h>
44#include <linux/nfsd/syscall.h>
45#include <linux/poll.h>
46#include <linux/personality.h>
47#include <linux/stat.h>
48#include <linux/filter.h>
49#include <linux/highmem.h>
50#include <linux/highuid.h>
51#include <linux/mman.h>
52#include <linux/ipv6.h>
53#include <linux/in.h>
54#include <linux/icmpv6.h>
55#include <linux/syscalls.h>
56#include <linux/sysctl.h>
57#include <linux/binfmts.h>
58#include <linux/compat.h>
59#include <linux/vfs.h>
60#include <linux/ptrace.h>
61
62#include <asm/types.h>
63#include <asm/ipc.h>
64#include <asm/uaccess.h>
65#include <asm/semaphore.h>
66
67#include <net/scm.h>
68#include <net/sock.h>
69
70#include "compat_linux.h"
71
72
73/* For this source file, we want overflow handling. */
74
75#undef high2lowuid
76#undef high2lowgid
77#undef low2highuid
78#undef low2highgid
79#undef SET_UID16
80#undef SET_GID16
81#undef NEW_TO_OLD_UID
82#undef NEW_TO_OLD_GID
83#undef SET_OLDSTAT_UID
84#undef SET_OLDSTAT_GID
85#undef SET_STAT_UID
86#undef SET_STAT_GID
87
88#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
89#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
90#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
91#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
92#define SET_UID16(var, uid) var = high2lowuid(uid)
93#define SET_GID16(var, gid) var = high2lowgid(gid)
94#define NEW_TO_OLD_UID(uid) high2lowuid(uid)
95#define NEW_TO_OLD_GID(gid) high2lowgid(gid)
96#define SET_OLDSTAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
97#define SET_OLDSTAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
98#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
99#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
100
101asmlinkage long sys32_chown16(const char * filename, u16 user, u16 group)
102{
103 return sys_chown(filename, low2highuid(user), low2highgid(group));
104}
105
106asmlinkage long sys32_lchown16(const char * filename, u16 user, u16 group)
107{
108 return sys_lchown(filename, low2highuid(user), low2highgid(group));
109}
110
111asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
112{
113 return sys_fchown(fd, low2highuid(user), low2highgid(group));
114}
115
116asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
117{
118 return sys_setregid(low2highgid(rgid), low2highgid(egid));
119}
120
121asmlinkage long sys32_setgid16(u16 gid)
122{
123 return sys_setgid((gid_t)gid);
124}
125
126asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
127{
128 return sys_setreuid(low2highuid(ruid), low2highuid(euid));
129}
130
131asmlinkage long sys32_setuid16(u16 uid)
132{
133 return sys_setuid((uid_t)uid);
134}
135
136asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
137{
138 return sys_setresuid(low2highuid(ruid), low2highuid(euid),
139 low2highuid(suid));
140}
141
142asmlinkage long sys32_getresuid16(u16 *ruid, u16 *euid, u16 *suid)
143{
144 int retval;
145
146 if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
147 !(retval = put_user(high2lowuid(current->euid), euid)))
148 retval = put_user(high2lowuid(current->suid), suid);
149
150 return retval;
151}
152
153asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
154{
155 return sys_setresgid(low2highgid(rgid), low2highgid(egid),
156 low2highgid(sgid));
157}
158
159asmlinkage long sys32_getresgid16(u16 *rgid, u16 *egid, u16 *sgid)
160{
161 int retval;
162
163 if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
164 !(retval = put_user(high2lowgid(current->egid), egid)))
165 retval = put_user(high2lowgid(current->sgid), sgid);
166
167 return retval;
168}
169
170asmlinkage long sys32_setfsuid16(u16 uid)
171{
172 return sys_setfsuid((uid_t)uid);
173}
174
175asmlinkage long sys32_setfsgid16(u16 gid)
176{
177 return sys_setfsgid((gid_t)gid);
178}
179
180static int groups16_to_user(u16 *grouplist, struct group_info *group_info)
181{
182 int i;
183 u16 group;
184
185 for (i = 0; i < group_info->ngroups; i++) {
186 group = (u16)GROUP_AT(group_info, i);
187 if (put_user(group, grouplist+i))
188 return -EFAULT;
189 }
190
191 return 0;
192}
193
194static int groups16_from_user(struct group_info *group_info, u16 *grouplist)
195{
196 int i;
197 u16 group;
198
199 for (i = 0; i < group_info->ngroups; i++) {
200 if (get_user(group, grouplist+i))
201 return -EFAULT;
202 GROUP_AT(group_info, i) = (gid_t)group;
203 }
204
205 return 0;
206}
207
208asmlinkage long sys32_getgroups16(int gidsetsize, u16 *grouplist)
209{
210 int i;
211
212 if (gidsetsize < 0)
213 return -EINVAL;
214
215 get_group_info(current->group_info);
216 i = current->group_info->ngroups;
217 if (gidsetsize) {
218 if (i > gidsetsize) {
219 i = -EINVAL;
220 goto out;
221 }
222 if (groups16_to_user(grouplist, current->group_info)) {
223 i = -EFAULT;
224 goto out;
225 }
226 }
227out:
228 put_group_info(current->group_info);
229 return i;
230}
231
232asmlinkage long sys32_setgroups16(int gidsetsize, u16 *grouplist)
233{
234 struct group_info *group_info;
235 int retval;
236
237 if (!capable(CAP_SETGID))
238 return -EPERM;
239 if ((unsigned)gidsetsize > NGROUPS_MAX)
240 return -EINVAL;
241
242 group_info = groups_alloc(gidsetsize);
243 if (!group_info)
244 return -ENOMEM;
245 retval = groups16_from_user(group_info, grouplist);
246 if (retval) {
247 put_group_info(group_info);
248 return retval;
249 }
250
251 retval = set_current_groups(group_info);
252 put_group_info(group_info);
253
254 return retval;
255}
256
257asmlinkage long sys32_getuid16(void)
258{
259 return high2lowuid(current->uid);
260}
261
262asmlinkage long sys32_geteuid16(void)
263{
264 return high2lowuid(current->euid);
265}
266
267asmlinkage long sys32_getgid16(void)
268{
269 return high2lowgid(current->gid);
270}
271
272asmlinkage long sys32_getegid16(void)
273{
274 return high2lowgid(current->egid);
275}
276
277/* 32-bit timeval and related flotsam. */
278
279static inline long get_tv32(struct timeval *o, struct compat_timeval *i)
280{
281 return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) ||
282 (__get_user(o->tv_sec, &i->tv_sec) ||
283 __get_user(o->tv_usec, &i->tv_usec)));
284}
285
286static inline long put_tv32(struct compat_timeval *o, struct timeval *i)
287{
288 return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
289 (__put_user(i->tv_sec, &o->tv_sec) ||
290 __put_user(i->tv_usec, &o->tv_usec)));
291}
292
293/*
294 * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.
295 *
296 * This is really horribly ugly.
297 */
298asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr)
299{
300 if (call >> 16) /* hack for backward compatibility */
301 return -EINVAL;
302
303 call &= 0xffff;
304
305 switch (call) {
306 case SEMTIMEDOP:
307 return compat_sys_semtimedop(first, compat_ptr(ptr),
308 second, compat_ptr(third));
309 case SEMOP:
310 /* struct sembuf is the same on 32 and 64bit :)) */
311 return sys_semtimedop(first, compat_ptr(ptr),
312 second, NULL);
313 case SEMGET:
314 return sys_semget(first, second, third);
315 case SEMCTL:
316 return compat_sys_semctl(first, second, third,
317 compat_ptr(ptr));
318 case MSGSND:
319 return compat_sys_msgsnd(first, second, third,
320 compat_ptr(ptr));
321 case MSGRCV:
322 return compat_sys_msgrcv(first, second, 0, third,
323 0, compat_ptr(ptr));
324 case MSGGET:
325 return sys_msgget((key_t) first, second);
326 case MSGCTL:
327 return compat_sys_msgctl(first, second, compat_ptr(ptr));
328 case SHMAT:
329 return compat_sys_shmat(first, second, third,
330 0, compat_ptr(ptr));
331 case SHMDT:
332 return sys_shmdt(compat_ptr(ptr));
333 case SHMGET:
334 return sys_shmget(first, (unsigned)second, third);
335 case SHMCTL:
336 return compat_sys_shmctl(first, second, compat_ptr(ptr));
337 }
338
339 return -ENOSYS;
340}
341
342asmlinkage long sys32_truncate64(const char * path, unsigned long high, unsigned long low)
343{
344 if ((int)high < 0)
345 return -EINVAL;
346 else
347 return sys_truncate(path, (high << 32) | low);
348}
349
350asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
351{
352 if ((int)high < 0)
353 return -EINVAL;
354 else
355 return sys_ftruncate(fd, (high << 32) | low);
356}
357
358int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
359{
360 int err;
361
362 if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
363 return -EOVERFLOW;
364
365 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
366 err |= put_user(stat->ino, &statbuf->st_ino);
367 err |= put_user(stat->mode, &statbuf->st_mode);
368 err |= put_user(stat->nlink, &statbuf->st_nlink);
369 err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
370 err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
371 err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
372 err |= put_user(stat->size, &statbuf->st_size);
373 err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
374 err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
375 err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
376 err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
377 err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
378 err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
379 err |= put_user(stat->blksize, &statbuf->st_blksize);
380 err |= put_user(stat->blocks, &statbuf->st_blocks);
381/* fixme
382 err |= put_user(0, &statbuf->__unused4[0]);
383 err |= put_user(0, &statbuf->__unused4[1]);
384*/
385 return err;
386}
387
388struct sysinfo32 {
389 s32 uptime;
390 u32 loads[3];
391 u32 totalram;
392 u32 freeram;
393 u32 sharedram;
394 u32 bufferram;
395 u32 totalswap;
396 u32 freeswap;
397 unsigned short procs;
398 unsigned short pads;
399 u32 totalhigh;
400 u32 freehigh;
401 unsigned int mem_unit;
402 char _f[8];
403};
404
405asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
406{
407 struct sysinfo s;
408 int ret, err;
409 mm_segment_t old_fs = get_fs ();
410
411 set_fs (KERNEL_DS);
412 ret = sys_sysinfo(&s);
413 set_fs (old_fs);
414 err = put_user (s.uptime, &info->uptime);
415 err |= __put_user (s.loads[0], &info->loads[0]);
416 err |= __put_user (s.loads[1], &info->loads[1]);
417 err |= __put_user (s.loads[2], &info->loads[2]);
418 err |= __put_user (s.totalram, &info->totalram);
419 err |= __put_user (s.freeram, &info->freeram);
420 err |= __put_user (s.sharedram, &info->sharedram);
421 err |= __put_user (s.bufferram, &info->bufferram);
422 err |= __put_user (s.totalswap, &info->totalswap);
423 err |= __put_user (s.freeswap, &info->freeswap);
424 err |= __put_user (s.procs, &info->procs);
425 err |= __put_user (s.totalhigh, &info->totalhigh);
426 err |= __put_user (s.freehigh, &info->freehigh);
427 err |= __put_user (s.mem_unit, &info->mem_unit);
428 if (err)
429 return -EFAULT;
430 return ret;
431}
432
433asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
434 struct compat_timespec __user *interval)
435{
436 struct timespec t;
437 int ret;
438 mm_segment_t old_fs = get_fs ();
439
440 set_fs (KERNEL_DS);
441 ret = sys_sched_rr_get_interval(pid, &t);
442 set_fs (old_fs);
443 if (put_compat_timespec(&t, interval))
444 return -EFAULT;
445 return ret;
446}
447
448asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
449 compat_sigset_t __user *oset, size_t sigsetsize)
450{
451 sigset_t s;
452 compat_sigset_t s32;
453 int ret;
454 mm_segment_t old_fs = get_fs();
455
456 if (set) {
457 if (copy_from_user (&s32, set, sizeof(compat_sigset_t)))
458 return -EFAULT;
459 switch (_NSIG_WORDS) {
460 case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
461 case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
462 case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
463 case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
464 }
465 }
466 set_fs (KERNEL_DS);
467 ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sigsetsize);
468 set_fs (old_fs);
469 if (ret) return ret;
470 if (oset) {
471 switch (_NSIG_WORDS) {
472 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
473 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
474 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
475 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
476 }
477 if (copy_to_user (oset, &s32, sizeof(compat_sigset_t)))
478 return -EFAULT;
479 }
480 return 0;
481}
482
483asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
484 size_t sigsetsize)
485{
486 sigset_t s;
487 compat_sigset_t s32;
488 int ret;
489 mm_segment_t old_fs = get_fs();
490
491 set_fs (KERNEL_DS);
492 ret = sys_rt_sigpending(&s, sigsetsize);
493 set_fs (old_fs);
494 if (!ret) {
495 switch (_NSIG_WORDS) {
496 case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
497 case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
498 case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
499 case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
500 }
501 if (copy_to_user (set, &s32, sizeof(compat_sigset_t)))
502 return -EFAULT;
503 }
504 return ret;
505}
506
507asmlinkage long
508sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
509{
510 siginfo_t info;
511 int ret;
512 mm_segment_t old_fs = get_fs();
513
514 if (copy_siginfo_from_user32(&info, uinfo))
515 return -EFAULT;
516 set_fs (KERNEL_DS);
517 ret = sys_rt_sigqueueinfo(pid, sig, &info);
518 set_fs (old_fs);
519 return ret;
520}
521
522/*
523 * sys32_execve() executes a new program after the asm stub has set
524 * things up for us. This should basically do what I want it to.
525 */
526asmlinkage long
527sys32_execve(struct pt_regs regs)
528{
529 int error;
530 char * filename;
531
532 filename = getname(compat_ptr(regs.orig_gpr2));
533 error = PTR_ERR(filename);
534 if (IS_ERR(filename))
535 goto out;
536 error = compat_do_execve(filename, compat_ptr(regs.gprs[3]),
537 compat_ptr(regs.gprs[4]), &regs);
538 if (error == 0)
539 {
540 task_lock(current);
541 current->ptrace &= ~PT_DTRACE;
542 task_unlock(current);
543 current->thread.fp_regs.fpc=0;
544 __asm__ __volatile__
545 ("sr 0,0\n\t"
546 "sfpc 0,0\n\t"
547 : : :"0");
548 }
549 putname(filename);
550out:
551 return error;
552}
553
554
555#ifdef CONFIG_MODULES
556
557asmlinkage long
558sys32_init_module(void __user *umod, unsigned long len,
559 const char __user *uargs)
560{
561 return sys_init_module(umod, len, uargs);
562}
563
564asmlinkage long
565sys32_delete_module(const char __user *name_user, unsigned int flags)
566{
567 return sys_delete_module(name_user, flags);
568}
569
570#else /* CONFIG_MODULES */
571
572asmlinkage long
573sys32_init_module(void __user *umod, unsigned long len,
574 const char __user *uargs)
575{
576 return -ENOSYS;
577}
578
579asmlinkage long
580sys32_delete_module(const char __user *name_user, unsigned int flags)
581{
582 return -ENOSYS;
583}
584
585#endif /* CONFIG_MODULES */
586
587/* Translations due to time_t size differences. Which affects all
588 sorts of things, like timeval and itimerval. */
589
590extern struct timezone sys_tz;
591
592asmlinkage long sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
593{
594 if (tv) {
595 struct timeval ktv;
596 do_gettimeofday(&ktv);
597 if (put_tv32(tv, &ktv))
598 return -EFAULT;
599 }
600 if (tz) {
601 if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
602 return -EFAULT;
603 }
604 return 0;
605}
606
607static inline long get_ts32(struct timespec *o, struct compat_timeval *i)
608{
609 long usec;
610
611 if (!access_ok(VERIFY_READ, i, sizeof(*i)))
612 return -EFAULT;
613 if (__get_user(o->tv_sec, &i->tv_sec))
614 return -EFAULT;
615 if (__get_user(usec, &i->tv_usec))
616 return -EFAULT;
617 o->tv_nsec = usec * 1000;
618 return 0;
619}
620
621asmlinkage long sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
622{
623 struct timespec kts;
624 struct timezone ktz;
625
626 if (tv) {
627 if (get_ts32(&kts, tv))
628 return -EFAULT;
629 }
630 if (tz) {
631 if (copy_from_user(&ktz, tz, sizeof(ktz)))
632 return -EFAULT;
633 }
634
635 return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
636}
637
638/* These are here just in case some old sparc32 binary calls it. */
639asmlinkage long sys32_pause(void)
640{
641 current->state = TASK_INTERRUPTIBLE;
642 schedule();
643 return -ERESTARTNOHAND;
644}
645
646asmlinkage long sys32_pread64(unsigned int fd, char *ubuf,
647 size_t count, u32 poshi, u32 poslo)
648{
649 if ((compat_ssize_t) count < 0)
650 return -EINVAL;
651 return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
652}
653
654asmlinkage long sys32_pwrite64(unsigned int fd, const char *ubuf,
655 size_t count, u32 poshi, u32 poslo)
656{
657 if ((compat_ssize_t) count < 0)
658 return -EINVAL;
659 return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
660}
661
662asmlinkage compat_ssize_t sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
663{
664 return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
665}
666
667asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, size_t count)
668{
669 mm_segment_t old_fs = get_fs();
670 int ret;
671 off_t of;
672
673 if (offset && get_user(of, offset))
674 return -EFAULT;
675
676 set_fs(KERNEL_DS);
677 ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
678 set_fs(old_fs);
679
680 if (!ret && offset && put_user(of, offset))
681 return -EFAULT;
682
683 return ret;
684}
685
686asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
687 compat_loff_t *offset, s32 count)
688{
689 mm_segment_t old_fs = get_fs();
690 int ret;
691 loff_t lof;
692
693 if (offset && get_user(lof, offset))
694 return -EFAULT;
695
696 set_fs(KERNEL_DS);
697 ret = sys_sendfile64(out_fd, in_fd, offset ? &lof : NULL, count);
698 set_fs(old_fs);
699
700 if (offset && put_user(lof, offset))
701 return -EFAULT;
702
703 return ret;
704}
705
706/* Handle adjtimex compatibility. */
707
708struct timex32 {
709 u32 modes;
710 s32 offset, freq, maxerror, esterror;
711 s32 status, constant, precision, tolerance;
712 struct compat_timeval time;
713 s32 tick;
714 s32 ppsfreq, jitter, shift, stabil;
715 s32 jitcnt, calcnt, errcnt, stbcnt;
716 s32 :32; s32 :32; s32 :32; s32 :32;
717 s32 :32; s32 :32; s32 :32; s32 :32;
718 s32 :32; s32 :32; s32 :32; s32 :32;
719};
720
721extern int do_adjtimex(struct timex *);
722
723asmlinkage long sys32_adjtimex(struct timex32 *utp)
724{
725 struct timex txc;
726 int ret;
727
728 memset(&txc, 0, sizeof(struct timex));
729
730 if(get_user(txc.modes, &utp->modes) ||
731 __get_user(txc.offset, &utp->offset) ||
732 __get_user(txc.freq, &utp->freq) ||
733 __get_user(txc.maxerror, &utp->maxerror) ||
734 __get_user(txc.esterror, &utp->esterror) ||
735 __get_user(txc.status, &utp->status) ||
736 __get_user(txc.constant, &utp->constant) ||
737 __get_user(txc.precision, &utp->precision) ||
738 __get_user(txc.tolerance, &utp->tolerance) ||
739 __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
740 __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
741 __get_user(txc.tick, &utp->tick) ||
742 __get_user(txc.ppsfreq, &utp->ppsfreq) ||
743 __get_user(txc.jitter, &utp->jitter) ||
744 __get_user(txc.shift, &utp->shift) ||
745 __get_user(txc.stabil, &utp->stabil) ||
746 __get_user(txc.jitcnt, &utp->jitcnt) ||
747 __get_user(txc.calcnt, &utp->calcnt) ||
748 __get_user(txc.errcnt, &utp->errcnt) ||
749 __get_user(txc.stbcnt, &utp->stbcnt))
750 return -EFAULT;
751
752 ret = do_adjtimex(&txc);
753
754 if(put_user(txc.modes, &utp->modes) ||
755 __put_user(txc.offset, &utp->offset) ||
756 __put_user(txc.freq, &utp->freq) ||
757 __put_user(txc.maxerror, &utp->maxerror) ||
758 __put_user(txc.esterror, &utp->esterror) ||
759 __put_user(txc.status, &utp->status) ||
760 __put_user(txc.constant, &utp->constant) ||
761 __put_user(txc.precision, &utp->precision) ||
762 __put_user(txc.tolerance, &utp->tolerance) ||
763 __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
764 __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
765 __put_user(txc.tick, &utp->tick) ||
766 __put_user(txc.ppsfreq, &utp->ppsfreq) ||
767 __put_user(txc.jitter, &utp->jitter) ||
768 __put_user(txc.shift, &utp->shift) ||
769 __put_user(txc.stabil, &utp->stabil) ||
770 __put_user(txc.jitcnt, &utp->jitcnt) ||
771 __put_user(txc.calcnt, &utp->calcnt) ||
772 __put_user(txc.errcnt, &utp->errcnt) ||
773 __put_user(txc.stbcnt, &utp->stbcnt))
774 ret = -EFAULT;
775
776 return ret;
777}
778
779#ifdef CONFIG_SYSCTL
780struct __sysctl_args32 {
781 u32 name;
782 int nlen;
783 u32 oldval;
784 u32 oldlenp;
785 u32 newval;
786 u32 newlen;
787 u32 __unused[4];
788};
789
790asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
791{
792 struct __sysctl_args32 tmp;
793 int error;
794 size_t oldlen, *oldlenp = NULL;
795 unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
796
797 if (copy_from_user(&tmp, args, sizeof(tmp)))
798 return -EFAULT;
799
800 if (tmp.oldval && tmp.oldlenp) {
801 /* Duh, this is ugly and might not work if sysctl_args
802 is in read-only memory, but do_sysctl does indirectly
803 a lot of uaccess in both directions and we'd have to
804 basically copy the whole sysctl.c here, and
805 glibc's __sysctl uses rw memory for the structure
806 anyway. */
807 if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||
808 put_user(oldlen, (size_t *)addr))
809 return -EFAULT;
810 oldlenp = (size_t *)addr;
811 }
812
813 lock_kernel();
814 error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),
815 oldlenp, (void *)A(tmp.newval), tmp.newlen);
816 unlock_kernel();
817 if (oldlenp) {
818 if (!error) {
819 if (get_user(oldlen, (size_t *)addr) ||
820 put_user(oldlen, (u32 *)A(tmp.oldlenp)))
821 error = -EFAULT;
822 }
823 copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
824 }
825 return error;
826}
827#endif
828
829struct stat64_emu31 {
830 unsigned long long st_dev;
831 unsigned int __pad1;
832#define STAT64_HAS_BROKEN_ST_INO 1
833 u32 __st_ino;
834 unsigned int st_mode;
835 unsigned int st_nlink;
836 u32 st_uid;
837 u32 st_gid;
838 unsigned long long st_rdev;
839 unsigned int __pad3;
840 long st_size;
841 u32 st_blksize;
842 unsigned char __pad4[4];
843 u32 __pad5; /* future possible st_blocks high bits */
844 u32 st_blocks; /* Number 512-byte blocks allocated. */
845 u32 st_atime;
846 u32 __pad6;
847 u32 st_mtime;
848 u32 __pad7;
849 u32 st_ctime;
850 u32 __pad8; /* will be high 32 bits of ctime someday */
851 unsigned long st_ino;
852};
853
854static int cp_stat64(struct stat64_emu31 *ubuf, struct kstat *stat)
855{
856 struct stat64_emu31 tmp;
857
858 memset(&tmp, 0, sizeof(tmp));
859
860 tmp.st_dev = huge_encode_dev(stat->dev);
861 tmp.st_ino = stat->ino;
862 tmp.__st_ino = (u32)stat->ino;
863 tmp.st_mode = stat->mode;
864 tmp.st_nlink = (unsigned int)stat->nlink;
865 tmp.st_uid = stat->uid;
866 tmp.st_gid = stat->gid;
867 tmp.st_rdev = huge_encode_dev(stat->rdev);
868 tmp.st_size = stat->size;
869 tmp.st_blksize = (u32)stat->blksize;
870 tmp.st_blocks = (u32)stat->blocks;
871 tmp.st_atime = (u32)stat->atime.tv_sec;
872 tmp.st_mtime = (u32)stat->mtime.tv_sec;
873 tmp.st_ctime = (u32)stat->ctime.tv_sec;
874
875 return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
876}
877
878asmlinkage long sys32_stat64(char * filename, struct stat64_emu31 * statbuf)
879{
880 struct kstat stat;
881 int ret = vfs_stat(filename, &stat);
882 if (!ret)
883 ret = cp_stat64(statbuf, &stat);
884 return ret;
885}
886
887asmlinkage long sys32_lstat64(char * filename, struct stat64_emu31 * statbuf)
888{
889 struct kstat stat;
890 int ret = vfs_lstat(filename, &stat);
891 if (!ret)
892 ret = cp_stat64(statbuf, &stat);
893 return ret;
894}
895
896asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 * statbuf)
897{
898 struct kstat stat;
899 int ret = vfs_fstat(fd, &stat);
900 if (!ret)
901 ret = cp_stat64(statbuf, &stat);
902 return ret;
903}
904
905/*
906 * Linux/i386 didn't use to be able to handle more than
907 * 4 system call parameters, so these system calls used a memory
908 * block for parameter passing..
909 */
910
911struct mmap_arg_struct_emu31 {
912 u32 addr;
913 u32 len;
914 u32 prot;
915 u32 flags;
916 u32 fd;
917 u32 offset;
918};
919
920/* common code for old and new mmaps */
921static inline long do_mmap2(
922 unsigned long addr, unsigned long len,
923 unsigned long prot, unsigned long flags,
924 unsigned long fd, unsigned long pgoff)
925{
926 struct file * file = NULL;
927 unsigned long error = -EBADF;
928
929 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
930 if (!(flags & MAP_ANONYMOUS)) {
931 file = fget(fd);
932 if (!file)
933 goto out;
934 }
935
936 down_write(&current->mm->mmap_sem);
937 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
938 if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) {
939 /* Result is out of bounds. */
940 do_munmap(current->mm, addr, len);
941 error = -ENOMEM;
942 }
943 up_write(&current->mm->mmap_sem);
944
945 if (file)
946 fput(file);
947out:
948 return error;
949}
950
951
952asmlinkage unsigned long
953old32_mmap(struct mmap_arg_struct_emu31 *arg)
954{
955 struct mmap_arg_struct_emu31 a;
956 int error = -EFAULT;
957
958 if (copy_from_user(&a, arg, sizeof(a)))
959 goto out;
960
961 error = -EINVAL;
962 if (a.offset & ~PAGE_MASK)
963 goto out;
964
965 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
966out:
967 return error;
968}
969
970asmlinkage long
971sys32_mmap2(struct mmap_arg_struct_emu31 *arg)
972{
973 struct mmap_arg_struct_emu31 a;
974 int error = -EFAULT;
975
976 if (copy_from_user(&a, arg, sizeof(a)))
977 goto out;
978 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
979out:
980 return error;
981}
982
983asmlinkage long sys32_read(unsigned int fd, char * buf, size_t count)
984{
985 if ((compat_ssize_t) count < 0)
986 return -EINVAL;
987
988 return sys_read(fd, buf, count);
989}
990
991asmlinkage long sys32_write(unsigned int fd, char * buf, size_t count)
992{
993 if ((compat_ssize_t) count < 0)
994 return -EINVAL;
995
996 return sys_write(fd, buf, count);
997}
998
999asmlinkage long sys32_clone(struct pt_regs regs)
1000{
1001 unsigned long clone_flags;
1002 unsigned long newsp;
1003 int *parent_tidptr, *child_tidptr;
1004
1005 clone_flags = regs.gprs[3] & 0xffffffffUL;
1006 newsp = regs.orig_gpr2 & 0x7fffffffUL;
1007 parent_tidptr = (int *) (regs.gprs[4] & 0x7fffffffUL);
1008 child_tidptr = (int *) (regs.gprs[5] & 0x7fffffffUL);
1009 if (!newsp)
1010 newsp = regs.gprs[15];
1011 return do_fork(clone_flags, newsp, &regs, 0,
1012 parent_tidptr, child_tidptr);
1013}
1014
1015/*
1016 * Wrapper function for sys_timer_create.
1017 */
1018extern asmlinkage long
1019sys_timer_create(clockid_t, struct sigevent *, timer_t *);
1020
1021asmlinkage long
1022sys32_timer_create(clockid_t which_clock, struct compat_sigevent *se32,
1023 timer_t *timer_id)
1024{
1025 struct sigevent se;
1026 timer_t ktimer_id;
1027 mm_segment_t old_fs;
1028 long ret;
1029
1030 if (se32 == NULL)
1031 return sys_timer_create(which_clock, NULL, timer_id);
1032
1033 if (get_compat_sigevent(&se, se32))
1034 return -EFAULT;
1035
1036 old_fs = get_fs();
1037 set_fs(KERNEL_DS);
1038 ret = sys_timer_create(which_clock, &se, &ktimer_id);
1039 set_fs(old_fs);
1040
1041 if (!ret)
1042 ret = put_user (ktimer_id, timer_id);
1043
1044 return ret;
1045}
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
new file mode 100644
index 000000000000..bf33dcfec7db
--- /dev/null
+++ b/arch/s390/kernel/compat_linux.h
@@ -0,0 +1,197 @@
1#ifndef _ASM_S390X_S390_H
2#define _ASM_S390X_S390_H
3
4#include <linux/config.h>
5#include <linux/compat.h>
6#include <linux/socket.h>
7#include <linux/syscalls.h>
8#include <linux/nfs_fs.h>
9#include <linux/sunrpc/svc.h>
10#include <linux/nfsd/nfsd.h>
11#include <linux/nfsd/export.h>
12
13/* Macro that masks the high order bit of an 32 bit pointer and converts it*/
14/* to a 64 bit pointer */
15#define A(__x) ((unsigned long)((__x) & 0x7FFFFFFFUL))
16#define AA(__x) \
17 ((unsigned long)(__x))
18
19/* Now 32bit compatibility types */
20struct ipc_kludge_32 {
21 __u32 msgp; /* pointer */
22 __s32 msgtyp;
23};
24
25struct old_sigaction32 {
26 __u32 sa_handler; /* Really a pointer, but need to deal with 32 bits */
27 compat_old_sigset_t sa_mask; /* A 32 bit mask */
28 __u32 sa_flags;
29 __u32 sa_restorer; /* Another 32 bit pointer */
30};
31
32typedef struct compat_siginfo {
33 int si_signo;
34 int si_errno;
35 int si_code;
36
37 union {
38 int _pad[((128/sizeof(int)) - 3)];
39
40 /* kill() */
41 struct {
42 pid_t _pid; /* sender's pid */
43 uid_t _uid; /* sender's uid */
44 } _kill;
45
46 /* POSIX.1b timers */
47 struct {
48 timer_t _tid; /* timer id */
49 int _overrun; /* overrun count */
50 compat_sigval_t _sigval; /* same as below */
51 int _sys_private; /* not to be passed to user */
52 } _timer;
53
54 /* POSIX.1b signals */
55 struct {
56 pid_t _pid; /* sender's pid */
57 uid_t _uid; /* sender's uid */
58 compat_sigval_t _sigval;
59 } _rt;
60
61 /* SIGCHLD */
62 struct {
63 pid_t _pid; /* which child */
64 uid_t _uid; /* sender's uid */
65 int _status;/* exit code */
66 compat_clock_t _utime;
67 compat_clock_t _stime;
68 } _sigchld;
69
70 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
71 struct {
72 __u32 _addr; /* faulting insn/memory ref. - pointer */
73 } _sigfault;
74
75 /* SIGPOLL */
76 struct {
77 int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
78 int _fd;
79 } _sigpoll;
80 } _sifields;
81} compat_siginfo_t;
82
83/*
84 * How these fields are to be accessed.
85 */
86#define si_pid _sifields._kill._pid
87#define si_uid _sifields._kill._uid
88#define si_status _sifields._sigchld._status
89#define si_utime _sifields._sigchld._utime
90#define si_stime _sifields._sigchld._stime
91#define si_value _sifields._rt._sigval
92#define si_int _sifields._rt._sigval.sival_int
93#define si_ptr _sifields._rt._sigval.sival_ptr
94#define si_addr _sifields._sigfault._addr
95#define si_band _sifields._sigpoll._band
96#define si_fd _sifields._sigpoll._fd
97#define si_tid _sifields._timer._tid
98#define si_overrun _sifields._timer._overrun
99
100/* asm/sigcontext.h */
101typedef union
102{
103 __u64 d;
104 __u32 f;
105} freg_t32;
106
107typedef struct
108{
109 unsigned int fpc;
110 freg_t32 fprs[__NUM_FPRS];
111} _s390_fp_regs32;
112
113typedef struct
114{
115 __u32 mask;
116 __u32 addr;
117} _psw_t32 __attribute__ ((aligned(8)));
118
119#define PSW32_MASK_PER 0x40000000UL
120#define PSW32_MASK_DAT 0x04000000UL
121#define PSW32_MASK_IO 0x02000000UL
122#define PSW32_MASK_EXT 0x01000000UL
123#define PSW32_MASK_KEY 0x00F00000UL
124#define PSW32_MASK_MCHECK 0x00040000UL
125#define PSW32_MASK_WAIT 0x00020000UL
126#define PSW32_MASK_PSTATE 0x00010000UL
127#define PSW32_MASK_ASC 0x0000C000UL
128#define PSW32_MASK_CC 0x00003000UL
129#define PSW32_MASK_PM 0x00000f00UL
130
131#define PSW32_ADDR_AMODE31 0x80000000UL
132#define PSW32_ADDR_INSN 0x7FFFFFFFUL
133
134#define PSW32_BASE_BITS 0x00080000UL
135
136#define PSW32_ASC_PRIMARY 0x00000000UL
137#define PSW32_ASC_ACCREG 0x00004000UL
138#define PSW32_ASC_SECONDARY 0x00008000UL
139#define PSW32_ASC_HOME 0x0000C000UL
140
141#define PSW32_USER_BITS (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
142 PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
143 PSW32_MASK_PSTATE)
144
145#define PSW32_MASK_MERGE(CURRENT,NEW) \
146 (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
147 ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
148
149
150typedef struct
151{
152 _psw_t32 psw;
153 __u32 gprs[__NUM_GPRS];
154 __u32 acrs[__NUM_ACRS];
155} _s390_regs_common32;
156
157typedef struct
158{
159 _s390_regs_common32 regs;
160 _s390_fp_regs32 fpregs;
161} _sigregs32;
162
163#define _SIGCONTEXT_NSIG32 64
164#define _SIGCONTEXT_NSIG_BPW32 32
165#define __SIGNAL_FRAMESIZE32 96
166#define _SIGMASK_COPY_SIZE32 (sizeof(u32)*2)
167
168struct sigcontext32
169{
170 __u32 oldmask[_COMPAT_NSIG_WORDS];
171 __u32 sregs; /* pointer */
172};
173
174/* asm/signal.h */
175struct sigaction32 {
176 __u32 sa_handler; /* pointer */
177 __u32 sa_flags;
178 __u32 sa_restorer; /* pointer */
179 compat_sigset_t sa_mask; /* mask last for extensibility */
180};
181
182typedef struct {
183 __u32 ss_sp; /* pointer */
184 int ss_flags;
185 compat_size_t ss_size;
186} stack_t32;
187
188/* asm/ucontext.h */
189struct ucontext32 {
190 __u32 uc_flags;
191 __u32 uc_link; /* pointer */
192 stack_t32 uc_stack;
193 _sigregs32 uc_mcontext;
194 compat_sigset_t uc_sigmask; /* mask last for extensibility */
195};
196
197#endif /* _ASM_S390X_S390_H */
diff --git a/arch/s390/kernel/compat_ptrace.h b/arch/s390/kernel/compat_ptrace.h
new file mode 100644
index 000000000000..419aef913ee1
--- /dev/null
+++ b/arch/s390/kernel/compat_ptrace.h
@@ -0,0 +1,83 @@
1#ifndef _PTRACE32_H
2#define _PTRACE32_H
3
4#include "compat_linux.h" /* needed for _psw_t32 */
5
6typedef struct {
7 __u32 cr[3];
8} per_cr_words32;
9
10typedef struct {
11 __u16 perc_atmid; /* 0x096 */
12 __u32 address; /* 0x098 */
13 __u8 access_id; /* 0x0a1 */
14} per_lowcore_words32;
15
16typedef struct {
17 union {
18 per_cr_words32 words;
19 } control_regs;
20 /*
21 * Use these flags instead of setting em_instruction_fetch
22 * directly they are used so that single stepping can be
23 * switched on & off while not affecting other tracing
24 */
25 unsigned single_step : 1;
26 unsigned instruction_fetch : 1;
27 unsigned : 30;
28 /*
29 * These addresses are copied into cr10 & cr11 if single
30 * stepping is switched off
31 */
32 __u32 starting_addr;
33 __u32 ending_addr;
34 union {
35 per_lowcore_words32 words;
36 } lowcore;
37} per_struct32;
38
39struct user_regs_struct32
40{
41 _psw_t32 psw;
42 u32 gprs[NUM_GPRS];
43 u32 acrs[NUM_ACRS];
44 u32 orig_gpr2;
45 s390_fp_regs fp_regs;
46 /*
47 * These per registers are in here so that gdb can modify them
48 * itself as there is no "official" ptrace interface for hardware
49 * watchpoints. This is the way intel does it.
50 */
51 per_struct32 per_info;
52 u32 ieee_instruction_pointer;
53 /* Used to give failing instruction back to user for ieee exceptions */
54};
55
56struct user32 {
57 /* We start with the registers, to mimic the way that "memory"
58 is returned from the ptrace(3,...) function. */
59 struct user_regs_struct32 regs; /* Where the registers are actually stored */
60 /* The rest of this junk is to help gdb figure out what goes where */
61 u32 u_tsize; /* Text segment size (pages). */
62 u32 u_dsize; /* Data segment size (pages). */
63 u32 u_ssize; /* Stack segment size (pages). */
64 u32 start_code; /* Starting virtual address of text. */
65 u32 start_stack; /* Starting virtual address of stack area.
66 This is actually the bottom of the stack,
67 the top of the stack is always found in the
68 esp register. */
69 s32 signal; /* Signal that caused the core dump. */
70 u32 u_ar0; /* Used by gdb to help find the values for */
71 /* the registers. */
72 u32 magic; /* To uniquely identify a core file */
73 char u_comm[32]; /* User command that was responsible */
74};
75
76typedef struct
77{
78 __u32 len;
79 __u32 kernel_addr;
80 __u32 process_addr;
81} ptrace_area_emu31;
82
83#endif /* _PTRACE32_H */
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
new file mode 100644
index 000000000000..d05d65ac9694
--- /dev/null
+++ b/arch/s390/kernel/compat_signal.c
@@ -0,0 +1,648 @@
1/*
2 * arch/s390/kernel/signal32.c
3 *
4 * S390 version
5 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
7 * Gerhard Tonn (ton@de.ibm.com)
8 *
9 * Copyright (C) 1991, 1992 Linus Torvalds
10 *
11 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
12 */
13
14#include <linux/config.h>
15#include <linux/compat.h>
16#include <linux/sched.h>
17#include <linux/mm.h>
18#include <linux/smp.h>
19#include <linux/smp_lock.h>
20#include <linux/kernel.h>
21#include <linux/signal.h>
22#include <linux/errno.h>
23#include <linux/wait.h>
24#include <linux/ptrace.h>
25#include <linux/unistd.h>
26#include <linux/stddef.h>
27#include <linux/tty.h>
28#include <linux/personality.h>
29#include <linux/binfmts.h>
30#include <asm/ucontext.h>
31#include <asm/uaccess.h>
32#include <asm/lowcore.h>
33#include "compat_linux.h"
34#include "compat_ptrace.h"
35
36#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
37
38typedef struct
39{
40 __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
41 struct sigcontext32 sc;
42 _sigregs32 sregs;
43 int signo;
44 __u8 retcode[S390_SYSCALL_SIZE];
45} sigframe32;
46
47typedef struct
48{
49 __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
50 __u8 retcode[S390_SYSCALL_SIZE];
51 compat_siginfo_t info;
52 struct ucontext32 uc;
53} rt_sigframe32;
54
55asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
56
57int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
58{
59 int err;
60
61 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
62 return -EFAULT;
63
64 /* If you change siginfo_t structure, please be sure
65 this code is fixed accordingly.
66 It should never copy any pad contained in the structure
67 to avoid security leaks, but must copy the generic
68 3 ints plus the relevant union member.
69 This routine must convert siginfo from 64bit to 32bit as well
70 at the same time. */
71 err = __put_user(from->si_signo, &to->si_signo);
72 err |= __put_user(from->si_errno, &to->si_errno);
73 err |= __put_user((short)from->si_code, &to->si_code);
74 if (from->si_code < 0)
75 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
76 else {
77 switch (from->si_code >> 16) {
78 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
79 case __SI_MESGQ >> 16:
80 err |= __put_user(from->si_int, &to->si_int);
81 /* fallthrough */
82 case __SI_KILL >> 16:
83 err |= __put_user(from->si_pid, &to->si_pid);
84 err |= __put_user(from->si_uid, &to->si_uid);
85 break;
86 case __SI_CHLD >> 16:
87 err |= __put_user(from->si_pid, &to->si_pid);
88 err |= __put_user(from->si_uid, &to->si_uid);
89 err |= __put_user(from->si_utime, &to->si_utime);
90 err |= __put_user(from->si_stime, &to->si_stime);
91 err |= __put_user(from->si_status, &to->si_status);
92 break;
93 case __SI_FAULT >> 16:
94 err |= __put_user((unsigned long) from->si_addr,
95 &to->si_addr);
96 break;
97 case __SI_POLL >> 16:
98 err |= __put_user(from->si_band, &to->si_band);
99 err |= __put_user(from->si_fd, &to->si_fd);
100 break;
101 case __SI_TIMER >> 16:
102 err |= __put_user(from->si_tid, &to->si_tid);
103 err |= __put_user(from->si_overrun, &to->si_overrun);
104 err |= __put_user(from->si_int, &to->si_int);
105 break;
106 default:
107 break;
108 }
109 }
110 return err;
111}
112
113int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
114{
115 int err;
116 u32 tmp;
117
118 if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
119 return -EFAULT;
120
121 err = __get_user(to->si_signo, &from->si_signo);
122 err |= __get_user(to->si_errno, &from->si_errno);
123 err |= __get_user(to->si_code, &from->si_code);
124
125 if (to->si_code < 0)
126 err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
127 else {
128 switch (to->si_code >> 16) {
129 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
130 case __SI_MESGQ >> 16:
131 err |= __get_user(to->si_int, &from->si_int);
132 /* fallthrough */
133 case __SI_KILL >> 16:
134 err |= __get_user(to->si_pid, &from->si_pid);
135 err |= __get_user(to->si_uid, &from->si_uid);
136 break;
137 case __SI_CHLD >> 16:
138 err |= __get_user(to->si_pid, &from->si_pid);
139 err |= __get_user(to->si_uid, &from->si_uid);
140 err |= __get_user(to->si_utime, &from->si_utime);
141 err |= __get_user(to->si_stime, &from->si_stime);
142 err |= __get_user(to->si_status, &from->si_status);
143 break;
144 case __SI_FAULT >> 16:
145 err |= __get_user(tmp, &from->si_addr);
146 to->si_addr = (void *)(u64) (tmp & PSW32_ADDR_INSN);
147 break;
148 case __SI_POLL >> 16:
149 err |= __get_user(to->si_band, &from->si_band);
150 err |= __get_user(to->si_fd, &from->si_fd);
151 break;
152 case __SI_TIMER >> 16:
153 err |= __get_user(to->si_tid, &from->si_tid);
154 err |= __get_user(to->si_overrun, &from->si_overrun);
155 err |= __get_user(to->si_int, &from->si_int);
156 break;
157 default:
158 break;
159 }
160 }
161 return err;
162}
163
164/*
165 * Atomically swap in the new signal mask, and wait for a signal.
166 */
167asmlinkage int
168sys32_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t mask)
169{
170 sigset_t saveset;
171
172 mask &= _BLOCKABLE;
173 spin_lock_irq(&current->sighand->siglock);
174 saveset = current->blocked;
175 siginitset(&current->blocked, mask);
176 recalc_sigpending();
177 spin_unlock_irq(&current->sighand->siglock);
178 regs->gprs[2] = -EINTR;
179
180 while (1) {
181 set_current_state(TASK_INTERRUPTIBLE);
182 schedule();
183 if (do_signal(regs, &saveset))
184 return -EINTR;
185 }
186}
187
188asmlinkage int
189sys32_rt_sigsuspend(struct pt_regs * regs, compat_sigset_t __user *unewset,
190 size_t sigsetsize)
191{
192 sigset_t saveset, newset;
193 compat_sigset_t set32;
194
195 /* XXX: Don't preclude handling different sized sigset_t's. */
196 if (sigsetsize != sizeof(sigset_t))
197 return -EINVAL;
198
199 if (copy_from_user(&set32, unewset, sizeof(set32)))
200 return -EFAULT;
201 switch (_NSIG_WORDS) {
202 case 4: newset.sig[3] = set32.sig[6] + (((long)set32.sig[7]) << 32);
203 case 3: newset.sig[2] = set32.sig[4] + (((long)set32.sig[5]) << 32);
204 case 2: newset.sig[1] = set32.sig[2] + (((long)set32.sig[3]) << 32);
205 case 1: newset.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32);
206 }
207 sigdelsetmask(&newset, ~_BLOCKABLE);
208
209 spin_lock_irq(&current->sighand->siglock);
210 saveset = current->blocked;
211 current->blocked = newset;
212 recalc_sigpending();
213 spin_unlock_irq(&current->sighand->siglock);
214 regs->gprs[2] = -EINTR;
215
216 while (1) {
217 set_current_state(TASK_INTERRUPTIBLE);
218 schedule();
219 if (do_signal(regs, &saveset))
220 return -EINTR;
221 }
222}
223
224asmlinkage long
225sys32_sigaction(int sig, const struct old_sigaction32 __user *act,
226 struct old_sigaction32 __user *oact)
227{
228 struct k_sigaction new_ka, old_ka;
229 unsigned long sa_handler, sa_restorer;
230 int ret;
231
232 if (act) {
233 compat_old_sigset_t mask;
234 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
235 __get_user(sa_handler, &act->sa_handler) ||
236 __get_user(sa_restorer, &act->sa_restorer))
237 return -EFAULT;
238 new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
239 new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer;
240 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
241 __get_user(mask, &act->sa_mask);
242 siginitset(&new_ka.sa.sa_mask, mask);
243 }
244
245 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
246
247 if (!ret && oact) {
248 sa_handler = (unsigned long) old_ka.sa.sa_handler;
249 sa_restorer = (unsigned long) old_ka.sa.sa_restorer;
250 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
251 __put_user(sa_handler, &oact->sa_handler) ||
252 __put_user(sa_restorer, &oact->sa_restorer))
253 return -EFAULT;
254 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
255 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
256 }
257
258 return ret;
259}
260
261int
262do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact);
263
264asmlinkage long
265sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
266 struct sigaction32 __user *oact, size_t sigsetsize)
267{
268 struct k_sigaction new_ka, old_ka;
269 unsigned long sa_handler;
270 int ret;
271 compat_sigset_t set32;
272
273 /* XXX: Don't preclude handling different sized sigset_t's. */
274 if (sigsetsize != sizeof(compat_sigset_t))
275 return -EINVAL;
276
277 if (act) {
278 ret = get_user(sa_handler, &act->sa_handler);
279 ret |= __copy_from_user(&set32, &act->sa_mask,
280 sizeof(compat_sigset_t));
281 switch (_NSIG_WORDS) {
282 case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
283 | (((long)set32.sig[7]) << 32);
284 case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
285 | (((long)set32.sig[5]) << 32);
286 case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
287 | (((long)set32.sig[3]) << 32);
288 case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
289 | (((long)set32.sig[1]) << 32);
290 }
291 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
292
293 if (ret)
294 return -EFAULT;
295 new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
296 }
297
298 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
299
300 if (!ret && oact) {
301 switch (_NSIG_WORDS) {
302 case 4:
303 set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
304 set32.sig[6] = old_ka.sa.sa_mask.sig[3];
305 case 3:
306 set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
307 set32.sig[4] = old_ka.sa.sa_mask.sig[2];
308 case 2:
309 set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
310 set32.sig[2] = old_ka.sa.sa_mask.sig[1];
311 case 1:
312 set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
313 set32.sig[0] = old_ka.sa.sa_mask.sig[0];
314 }
315 ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler);
316 ret |= __copy_to_user(&oact->sa_mask, &set32,
317 sizeof(compat_sigset_t));
318 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
319 }
320
321 return ret;
322}
323
324asmlinkage long
325sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss,
326 struct pt_regs *regs)
327{
328 stack_t kss, koss;
329 unsigned long ss_sp;
330 int ret, err = 0;
331 mm_segment_t old_fs = get_fs();
332
333 if (uss) {
334 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
335 return -EFAULT;
336 err |= __get_user(ss_sp, &uss->ss_sp);
337 err |= __get_user(kss.ss_size, &uss->ss_size);
338 err |= __get_user(kss.ss_flags, &uss->ss_flags);
339 if (err)
340 return -EFAULT;
341 kss.ss_sp = (void *) ss_sp;
342 }
343
344 set_fs (KERNEL_DS);
345 ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL),
346 (stack_t __user *) (uoss ? &koss : NULL),
347 regs->gprs[15]);
348 set_fs (old_fs);
349
350 if (!ret && uoss) {
351 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
352 return -EFAULT;
353 ss_sp = (unsigned long) koss.ss_sp;
354 err |= __put_user(ss_sp, &uoss->ss_sp);
355 err |= __put_user(koss.ss_size, &uoss->ss_size);
356 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
357 if (err)
358 return -EFAULT;
359 }
360 return ret;
361}
362
363static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
364{
365 _s390_regs_common32 regs32;
366 int err, i;
367
368 regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS,
369 (__u32)(regs->psw.mask >> 32));
370 regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
371 for (i = 0; i < NUM_GPRS; i++)
372 regs32.gprs[i] = (__u32) regs->gprs[i];
373 save_access_regs(current->thread.acrs);
374 memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs));
375 err = __copy_to_user(&sregs->regs, &regs32, sizeof(regs32));
376 if (err)
377 return err;
378 save_fp_regs(&current->thread.fp_regs);
379 /* s390_fp_regs and _s390_fp_regs32 are the same ! */
380 return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
381 sizeof(_s390_fp_regs32));
382}
383
384static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
385{
386 _s390_regs_common32 regs32;
387 int err, i;
388
389 /* Alwys make any pending restarted system call return -EINTR */
390 current_thread_info()->restart_block.fn = do_no_restart_syscall;
391
392 err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
393 if (err)
394 return err;
395 regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask,
396 (__u64)regs32.psw.mask << 32);
397 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
398 for (i = 0; i < NUM_GPRS; i++)
399 regs->gprs[i] = (__u64) regs32.gprs[i];
400 memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs));
401 restore_access_regs(current->thread.acrs);
402
403 err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
404 sizeof(_s390_fp_regs32));
405 current->thread.fp_regs.fpc &= FPC_VALID_MASK;
406 if (err)
407 return err;
408
409 restore_fp_regs(&current->thread.fp_regs);
410 regs->trap = -1; /* disable syscall checks */
411 return 0;
412}
413
414asmlinkage long sys32_sigreturn(struct pt_regs *regs)
415{
416 sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
417 sigset_t set;
418
419 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
420 goto badframe;
421 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
422 goto badframe;
423
424 sigdelsetmask(&set, ~_BLOCKABLE);
425 spin_lock_irq(&current->sighand->siglock);
426 current->blocked = set;
427 recalc_sigpending();
428 spin_unlock_irq(&current->sighand->siglock);
429
430 if (restore_sigregs32(regs, &frame->sregs))
431 goto badframe;
432
433 return regs->gprs[2];
434
435badframe:
436 force_sig(SIGSEGV, current);
437 return 0;
438}
439
440asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
441{
442 rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
443 sigset_t set;
444 stack_t st;
445 __u32 ss_sp;
446 int err;
447 mm_segment_t old_fs = get_fs();
448
449 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
450 goto badframe;
451 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
452 goto badframe;
453
454 sigdelsetmask(&set, ~_BLOCKABLE);
455 spin_lock_irq(&current->sighand->siglock);
456 current->blocked = set;
457 recalc_sigpending();
458 spin_unlock_irq(&current->sighand->siglock);
459
460 if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
461 goto badframe;
462
463 err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
464 st.ss_sp = (void *) A((unsigned long)ss_sp);
465 err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);
466 err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
467 if (err)
468 goto badframe;
469
470 /* It is more difficult to avoid calling this function than to
471 call it and ignore errors. */
472 set_fs (KERNEL_DS);
473 do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]);
474 set_fs (old_fs);
475
476 return regs->gprs[2];
477
478badframe:
479 force_sig(SIGSEGV, current);
480 return 0;
481}
482
483/*
484 * Set up a signal frame.
485 */
486
487
488/*
489 * Determine which stack to use..
490 */
491static inline void __user *
492get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
493{
494 unsigned long sp;
495
496 /* Default to using normal stack */
497 sp = (unsigned long) A(regs->gprs[15]);
498
499 /* This is the X/Open sanctioned signal stack switching. */
500 if (ka->sa.sa_flags & SA_ONSTACK) {
501 if (! on_sig_stack(sp))
502 sp = current->sas_ss_sp + current->sas_ss_size;
503 }
504
505 /* This is the legacy signal stack switching. */
506 else if (!user_mode(regs) &&
507 !(ka->sa.sa_flags & SA_RESTORER) &&
508 ka->sa.sa_restorer) {
509 sp = (unsigned long) ka->sa.sa_restorer;
510 }
511
512 return (void __user *)((sp - frame_size) & -8ul);
513}
514
515static inline int map_signal(int sig)
516{
517 if (current_thread_info()->exec_domain
518 && current_thread_info()->exec_domain->signal_invmap
519 && sig < 32)
520 return current_thread_info()->exec_domain->signal_invmap[sig];
521 else
522 return sig;
523}
524
525static void setup_frame32(int sig, struct k_sigaction *ka,
526 sigset_t *set, struct pt_regs * regs)
527{
528 sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
529 if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
530 goto give_sigsegv;
531
532 if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
533 goto give_sigsegv;
534
535 if (save_sigregs32(regs, &frame->sregs))
536 goto give_sigsegv;
537 if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
538 goto give_sigsegv;
539
540 /* Set up to return from userspace. If provided, use a stub
541 already in userspace. */
542 if (ka->sa.sa_flags & SA_RESTORER) {
543 regs->gprs[14] = (__u64) ka->sa.sa_restorer;
544 } else {
545 regs->gprs[14] = (__u64) frame->retcode;
546 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
547 (u16 __user *)(frame->retcode)))
548 goto give_sigsegv;
549 }
550
551 /* Set up backchain. */
552 if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
553 goto give_sigsegv;
554
555 /* Set up registers for signal handler */
556 regs->gprs[15] = (__u64) frame;
557 regs->psw.addr = (__u64) ka->sa.sa_handler;
558
559 regs->gprs[2] = map_signal(sig);
560 regs->gprs[3] = (__u64) &frame->sc;
561
562 /* We forgot to include these in the sigcontext.
563 To avoid breaking binary compatibility, they are passed as args. */
564 regs->gprs[4] = current->thread.trap_no;
565 regs->gprs[5] = current->thread.prot_addr;
566
567 /* Place signal number on stack to allow backtrace from handler. */
568 if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
569 goto give_sigsegv;
570 return;
571
572give_sigsegv:
573 force_sigsegv(sig, current);
574}
575
576static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
577 sigset_t *set, struct pt_regs * regs)
578{
579 int err = 0;
580 rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
581 if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
582 goto give_sigsegv;
583
584 if (copy_siginfo_to_user32(&frame->info, info))
585 goto give_sigsegv;
586
587 /* Create the ucontext. */
588 err |= __put_user(0, &frame->uc.uc_flags);
589 err |= __put_user(0, &frame->uc.uc_link);
590 err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
591 err |= __put_user(sas_ss_flags(regs->gprs[15]),
592 &frame->uc.uc_stack.ss_flags);
593 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
594 err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
595 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
596 if (err)
597 goto give_sigsegv;
598
599 /* Set up to return from userspace. If provided, use a stub
600 already in userspace. */
601 if (ka->sa.sa_flags & SA_RESTORER) {
602 regs->gprs[14] = (__u64) ka->sa.sa_restorer;
603 } else {
604 regs->gprs[14] = (__u64) frame->retcode;
605 err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
606 (u16 __user *)(frame->retcode));
607 }
608
609 /* Set up backchain. */
610 if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
611 goto give_sigsegv;
612
613 /* Set up registers for signal handler */
614 regs->gprs[15] = (__u64) frame;
615 regs->psw.addr = (__u64) ka->sa.sa_handler;
616
617 regs->gprs[2] = map_signal(sig);
618 regs->gprs[3] = (__u64) &frame->info;
619 regs->gprs[4] = (__u64) &frame->uc;
620 return;
621
622give_sigsegv:
623 force_sigsegv(sig, current);
624}
625
626/*
627 * OK, we're invoking a handler
628 */
629
630void
631handle_signal32(unsigned long sig, struct k_sigaction *ka,
632 siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
633{
634 /* Set up the stack frame */
635 if (ka->sa.sa_flags & SA_SIGINFO)
636 setup_rt_frame32(sig, ka, info, oldset, regs);
637 else
638 setup_frame32(sig, ka, oldset, regs);
639
640 if (!(ka->sa.sa_flags & SA_NODEFER)) {
641 spin_lock_irq(&current->sighand->siglock);
642 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
643 sigaddset(&current->blocked,sig);
644 recalc_sigpending();
645 spin_unlock_irq(&current->sighand->siglock);
646 }
647}
648
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
new file mode 100644
index 000000000000..7a607b1d0380
--- /dev/null
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -0,0 +1,1443 @@
1/*
2* arch/s390/kernel/sys_wrapper31.S
3* wrapper for 31 bit compatible system calls.
4*
5* S390 version
6* Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
7* Author(s): Gerhard Tonn (ton@de.ibm.com),
8* Thomas Spatzier (tspat@de.ibm.com)
9*/
10
11 .globl sys32_exit_wrapper
12sys32_exit_wrapper:
13 lgfr %r2,%r2 # int
14 jg sys_exit # branch to sys_exit
15
16 .globl sys32_read_wrapper
17sys32_read_wrapper:
18 llgfr %r2,%r2 # unsigned int
19 llgtr %r3,%r3 # char *
20 llgfr %r4,%r4 # size_t
21 jg sys32_read # branch to sys_read
22
23 .globl sys32_write_wrapper
24sys32_write_wrapper:
25 llgfr %r2,%r2 # unsigned int
26 llgtr %r3,%r3 # const char *
27 llgfr %r4,%r4 # size_t
28 jg sys32_write # branch to system call
29
30 .globl sys32_open_wrapper
31sys32_open_wrapper:
32 llgtr %r2,%r2 # const char *
33 lgfr %r3,%r3 # int
34 lgfr %r4,%r4 # int
35 jg sys_open # branch to system call
36
37 .globl sys32_close_wrapper
38sys32_close_wrapper:
39 llgfr %r2,%r2 # unsigned int
40 jg sys_close # branch to system call
41
42 .globl sys32_creat_wrapper
43sys32_creat_wrapper:
44 llgtr %r2,%r2 # const char *
45 lgfr %r3,%r3 # int
46 jg sys_creat # branch to system call
47
48 .globl sys32_link_wrapper
49sys32_link_wrapper:
50 llgtr %r2,%r2 # const char *
51 llgtr %r3,%r3 # const char *
52 jg sys_link # branch to system call
53
54 .globl sys32_unlink_wrapper
55sys32_unlink_wrapper:
56 llgtr %r2,%r2 # const char *
57 jg sys_unlink # branch to system call
58
59 .globl sys32_chdir_wrapper
60sys32_chdir_wrapper:
61 llgtr %r2,%r2 # const char *
62 jg sys_chdir # branch to system call
63
64 .globl sys32_time_wrapper
65sys32_time_wrapper:
66 llgtr %r2,%r2 # int *
67 jg compat_sys_time # branch to system call
68
69 .globl sys32_mknod_wrapper
70sys32_mknod_wrapper:
71 llgtr %r2,%r2 # const char *
72 lgfr %r3,%r3 # int
73 llgfr %r4,%r4 # dev
74 jg sys_mknod # branch to system call
75
76 .globl sys32_chmod_wrapper
77sys32_chmod_wrapper:
78 llgtr %r2,%r2 # const char *
79 llgfr %r3,%r3 # mode_t
80 jg sys_chmod # branch to system call
81
82 .globl sys32_lchown16_wrapper
83sys32_lchown16_wrapper:
84 llgtr %r2,%r2 # const char *
85 llgfr %r3,%r3 # __kernel_old_uid_emu31_t
86 llgfr %r4,%r4 # __kernel_old_uid_emu31_t
87 jg sys32_lchown16 # branch to system call
88
89 .globl sys32_lseek_wrapper
90sys32_lseek_wrapper:
91 llgfr %r2,%r2 # unsigned int
92 lgfr %r3,%r3 # off_t
93 llgfr %r4,%r4 # unsigned int
94 jg sys_lseek # branch to system call
95
96#sys32_getpid_wrapper # void
97
98 .globl sys32_mount_wrapper
99sys32_mount_wrapper:
100 llgtr %r2,%r2 # char *
101 llgtr %r3,%r3 # char *
102 llgtr %r4,%r4 # char *
103 llgfr %r5,%r5 # unsigned long
104 llgtr %r6,%r6 # void *
105 jg compat_sys_mount # branch to system call
106
107 .globl sys32_oldumount_wrapper
108sys32_oldumount_wrapper:
109 llgtr %r2,%r2 # char *
110 jg sys_oldumount # branch to system call
111
112 .globl sys32_setuid16_wrapper
113sys32_setuid16_wrapper:
114 llgfr %r2,%r2 # __kernel_old_uid_emu31_t
115 jg sys32_setuid16 # branch to system call
116
117#sys32_getuid16_wrapper # void
118
119 .globl sys32_ptrace_wrapper
120sys32_ptrace_wrapper:
121 lgfr %r2,%r2 # long
122 lgfr %r3,%r3 # long
123 llgtr %r4,%r4 # long
124 llgfr %r5,%r5 # long
125 jg sys_ptrace # branch to system call
126
127 .globl sys32_alarm_wrapper
128sys32_alarm_wrapper:
129 llgfr %r2,%r2 # unsigned int
130 jg sys_alarm # branch to system call
131
132#sys32_pause_wrapper # void
133
134 .globl compat_sys_utime_wrapper
135compat_sys_utime_wrapper:
136 llgtr %r2,%r2 # char *
137 llgtr %r3,%r3 # struct compat_utimbuf *
138 jg compat_sys_utime # branch to system call
139
140 .globl sys32_access_wrapper
141sys32_access_wrapper:
142 llgtr %r2,%r2 # const char *
143 lgfr %r3,%r3 # int
144 jg sys_access # branch to system call
145
146 .globl sys32_nice_wrapper
147sys32_nice_wrapper:
148 lgfr %r2,%r2 # int
149 jg sys_nice # branch to system call
150
151#sys32_sync_wrapper # void
152
153 .globl sys32_kill_wrapper
154sys32_kill_wrapper:
155 lgfr %r2,%r2 # int
156 lgfr %r3,%r3 # int
157 jg sys_kill # branch to system call
158
159 .globl sys32_rename_wrapper
160sys32_rename_wrapper:
161 llgtr %r2,%r2 # const char *
162 llgtr %r3,%r3 # const char *
163 jg sys_rename # branch to system call
164
165 .globl sys32_mkdir_wrapper
166sys32_mkdir_wrapper:
167 llgtr %r2,%r2 # const char *
168 lgfr %r3,%r3 # int
169 jg sys_mkdir # branch to system call
170
171 .globl sys32_rmdir_wrapper
172sys32_rmdir_wrapper:
173 llgtr %r2,%r2 # const char *
174 jg sys_rmdir # branch to system call
175
176 .globl sys32_dup_wrapper
177sys32_dup_wrapper:
178 llgfr %r2,%r2 # unsigned int
179 jg sys_dup # branch to system call
180
181 .globl sys32_pipe_wrapper
182sys32_pipe_wrapper:
183 llgtr %r2,%r2 # u32 *
184 jg sys_pipe # branch to system call
185
186 .globl compat_sys_times_wrapper
187compat_sys_times_wrapper:
188 llgtr %r2,%r2 # struct compat_tms *
189 jg compat_sys_times # branch to system call
190
191 .globl sys32_brk_wrapper
192sys32_brk_wrapper:
193 llgtr %r2,%r2 # unsigned long
194 jg sys_brk # branch to system call
195
196 .globl sys32_setgid16_wrapper
197sys32_setgid16_wrapper:
198 llgfr %r2,%r2 # __kernel_old_gid_emu31_t
199 jg sys32_setgid16 # branch to system call
200
201#sys32_getgid16_wrapper # void
202
203 .globl sys32_signal_wrapper
204sys32_signal_wrapper:
205 lgfr %r2,%r2 # int
206 llgtr %r3,%r3 # __sighandler_t
207 jg sys_signal
208
209#sys32_geteuid16_wrapper # void
210
211#sys32_getegid16_wrapper # void
212
213 .globl sys32_acct_wrapper
214sys32_acct_wrapper:
215 llgtr %r2,%r2 # char *
216 jg sys_acct # branch to system call
217
218 .globl sys32_umount_wrapper
219sys32_umount_wrapper:
220 llgtr %r2,%r2 # char *
221 lgfr %r3,%r3 # int
222 jg sys_umount # branch to system call
223
224 .globl compat_sys_ioctl_wrapper
225compat_sys_ioctl_wrapper:
226 llgfr %r2,%r2 # unsigned int
227 llgfr %r3,%r3 # unsigned int
228 llgfr %r4,%r4 # unsigned int
229 jg compat_sys_ioctl # branch to system call
230
231 .globl compat_sys_fcntl_wrapper
232compat_sys_fcntl_wrapper:
233 llgfr %r2,%r2 # unsigned int
234 llgfr %r3,%r3 # unsigned int
235 llgfr %r4,%r4 # unsigned long
236 jg compat_sys_fcntl # branch to system call
237
238 .globl sys32_setpgid_wrapper
239sys32_setpgid_wrapper:
240 lgfr %r2,%r2 # pid_t
241 lgfr %r3,%r3 # pid_t
242 jg sys_setpgid # branch to system call
243
244 .globl sys32_umask_wrapper
245sys32_umask_wrapper:
246 lgfr %r2,%r2 # int
247 jg sys_umask # branch to system call
248
249 .globl sys32_chroot_wrapper
250sys32_chroot_wrapper:
251 llgtr %r2,%r2 # char *
252 jg sys_chroot # branch to system call
253
254 .globl sys32_ustat_wrapper
255sys32_ustat_wrapper:
256 llgfr %r2,%r2 # dev_t
257 llgtr %r3,%r3 # struct ustat *
258 jg sys_ustat
259
260 .globl sys32_dup2_wrapper
261sys32_dup2_wrapper:
262 llgfr %r2,%r2 # unsigned int
263 llgfr %r3,%r3 # unsigned int
264 jg sys_dup2 # branch to system call
265
266#sys32_getppid_wrapper # void
267
268#sys32_getpgrp_wrapper # void
269
270#sys32_setsid_wrapper # void
271
272 .globl sys32_sigaction_wrapper
273sys32_sigaction_wrapper:
274 lgfr %r2,%r2 # int
275 llgtr %r3,%r3 # const struct old_sigaction *
276 llgtr %r4,%r4 # struct old_sigaction32 *
277 jg sys32_sigaction # branch to system call
278
279 .globl sys32_setreuid16_wrapper
280sys32_setreuid16_wrapper:
281 llgfr %r2,%r2 # __kernel_old_uid_emu31_t
282 llgfr %r3,%r3 # __kernel_old_uid_emu31_t
283 jg sys32_setreuid16 # branch to system call
284
285 .globl sys32_setregid16_wrapper
286sys32_setregid16_wrapper:
287 llgfr %r2,%r2 # __kernel_old_gid_emu31_t
288 llgfr %r3,%r3 # __kernel_old_gid_emu31_t
289 jg sys32_setregid16 # branch to system call
290
291#sys32_sigsuspend_wrapper # done in sigsuspend_glue
292
293 .globl compat_sys_sigpending_wrapper
294compat_sys_sigpending_wrapper:
295 llgtr %r2,%r2 # compat_old_sigset_t *
296 jg compat_sys_sigpending # branch to system call
297
298 .globl sys32_sethostname_wrapper
299sys32_sethostname_wrapper:
300 llgtr %r2,%r2 # char *
301 lgfr %r3,%r3 # int
302 jg sys_sethostname # branch to system call
303
304 .globl compat_sys_setrlimit_wrapper
305compat_sys_setrlimit_wrapper:
306 llgfr %r2,%r2 # unsigned int
307 llgtr %r3,%r3 # struct rlimit_emu31 *
308 jg compat_sys_setrlimit # branch to system call
309
310 .globl compat_sys_old_getrlimit_wrapper
311compat_sys_old_getrlimit_wrapper:
312 llgfr %r2,%r2 # unsigned int
313 llgtr %r3,%r3 # struct rlimit_emu31 *
314 jg compat_sys_old_getrlimit # branch to system call
315
316 .globl compat_sys_getrlimit_wrapper
317compat_sys_getrlimit_wrapper:
318 llgfr %r2,%r2 # unsigned int
319 llgtr %r3,%r3 # struct rlimit_emu31 *
320 jg compat_sys_getrlimit # branch to system call
321
322 .globl sys32_mmap2_wrapper
323sys32_mmap2_wrapper:
324 llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
325 jg sys32_mmap2 # branch to system call
326
327 .globl compat_sys_getrusage_wrapper
328compat_sys_getrusage_wrapper:
329 lgfr %r2,%r2 # int
330 llgtr %r3,%r3 # struct rusage_emu31 *
331 jg compat_sys_getrusage # branch to system call
332
333 .globl sys32_gettimeofday_wrapper
334sys32_gettimeofday_wrapper:
335 llgtr %r2,%r2 # struct timeval_emu31 *
336 llgtr %r3,%r3 # struct timezone *
337 jg sys32_gettimeofday # branch to system call
338
339 .globl sys32_settimeofday_wrapper
340sys32_settimeofday_wrapper:
341 llgtr %r2,%r2 # struct timeval_emu31 *
342 llgtr %r3,%r3 # struct timezone *
343 jg sys32_settimeofday # branch to system call
344
345 .globl sys32_getgroups16_wrapper
346sys32_getgroups16_wrapper:
347 lgfr %r2,%r2 # int
348 llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
349 jg sys32_getgroups16 # branch to system call
350
351 .globl sys32_setgroups16_wrapper
352sys32_setgroups16_wrapper:
353 lgfr %r2,%r2 # int
354 llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
355 jg sys32_setgroups16 # branch to system call
356
357 .globl sys32_symlink_wrapper
358sys32_symlink_wrapper:
359 llgtr %r2,%r2 # const char *
360 llgtr %r3,%r3 # const char *
361 jg sys_symlink # branch to system call
362
363 .globl sys32_readlink_wrapper
364sys32_readlink_wrapper:
365 llgtr %r2,%r2 # const char *
366 llgtr %r3,%r3 # char *
367 lgfr %r4,%r4 # int
368 jg sys_readlink # branch to system call
369
370 .globl sys32_uselib_wrapper
371sys32_uselib_wrapper:
372 llgtr %r2,%r2 # const char *
373 jg sys_uselib # branch to system call
374
375 .globl sys32_swapon_wrapper
376sys32_swapon_wrapper:
377 llgtr %r2,%r2 # const char *
378 lgfr %r3,%r3 # int
379 jg sys_swapon # branch to system call
380
381 .globl sys32_reboot_wrapper
382sys32_reboot_wrapper:
383 lgfr %r2,%r2 # int
384 lgfr %r3,%r3 # int
385 llgfr %r4,%r4 # unsigned int
386 llgtr %r5,%r5 # void *
387 jg sys_reboot # branch to system call
388
389 .globl old32_readdir_wrapper
390old32_readdir_wrapper:
391 llgfr %r2,%r2 # unsigned int
392 llgtr %r3,%r3 # void *
393 llgfr %r4,%r4 # unsigned int
394 jg compat_sys_old_readdir # branch to system call
395
396 .globl old32_mmap_wrapper
397old32_mmap_wrapper:
398 llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
399 jg old32_mmap # branch to system call
400
401 .globl sys32_munmap_wrapper
402sys32_munmap_wrapper:
403 llgfr %r2,%r2 # unsigned long
404 llgfr %r3,%r3 # size_t
405 jg sys_munmap # branch to system call
406
407 .globl sys32_truncate_wrapper
408sys32_truncate_wrapper:
409 llgtr %r2,%r2 # const char *
410 llgfr %r3,%r3 # unsigned long
411 jg sys_truncate # branch to system call
412
413 .globl sys32_ftruncate_wrapper
414sys32_ftruncate_wrapper:
415 llgfr %r2,%r2 # unsigned int
416 llgfr %r3,%r3 # unsigned long
417 jg sys_ftruncate # branch to system call
418
419 .globl sys32_fchmod_wrapper
420sys32_fchmod_wrapper:
421 llgfr %r2,%r2 # unsigned int
422 llgfr %r3,%r3 # mode_t
423 jg sys_fchmod # branch to system call
424
425 .globl sys32_fchown16_wrapper
426sys32_fchown16_wrapper:
427 llgfr %r2,%r2 # unsigned int
428 llgfr %r3,%r3 # compat_uid_t
429 llgfr %r4,%r4 # compat_uid_t
430 jg sys32_fchown16 # branch to system call
431
432 .globl sys32_getpriority_wrapper
433sys32_getpriority_wrapper:
434 lgfr %r2,%r2 # int
435 lgfr %r3,%r3 # int
436 jg sys_getpriority # branch to system call
437
438 .globl sys32_setpriority_wrapper
439sys32_setpriority_wrapper:
440 lgfr %r2,%r2 # int
441 lgfr %r3,%r3 # int
442 lgfr %r4,%r4 # int
443 jg sys_setpriority # branch to system call
444
445 .globl compat_sys_statfs_wrapper
446compat_sys_statfs_wrapper:
447 llgtr %r2,%r2 # char *
448 llgtr %r3,%r3 # struct compat_statfs *
449 jg compat_sys_statfs # branch to system call
450
451 .globl compat_sys_fstatfs_wrapper
452compat_sys_fstatfs_wrapper:
453 llgfr %r2,%r2 # unsigned int
454 llgtr %r3,%r3 # struct compat_statfs *
455 jg compat_sys_fstatfs # branch to system call
456
457 .globl compat_sys_socketcall_wrapper
458compat_sys_socketcall_wrapper:
459 lgfr %r2,%r2 # int
460 llgtr %r3,%r3 # u32 *
461 jg compat_sys_socketcall # branch to system call
462
463 .globl sys32_syslog_wrapper
464sys32_syslog_wrapper:
465 lgfr %r2,%r2 # int
466 llgtr %r3,%r3 # char *
467 lgfr %r4,%r4 # int
468 jg sys_syslog # branch to system call
469
470 .globl compat_sys_setitimer_wrapper
471compat_sys_setitimer_wrapper:
472 lgfr %r2,%r2 # int
473 llgtr %r3,%r3 # struct itimerval_emu31 *
474 llgtr %r4,%r4 # struct itimerval_emu31 *
475 jg compat_sys_setitimer # branch to system call
476
477 .globl compat_sys_getitimer_wrapper
478compat_sys_getitimer_wrapper:
479 lgfr %r2,%r2 # int
480 llgtr %r3,%r3 # struct itimerval_emu31 *
481 jg compat_sys_getitimer # branch to system call
482
483 .globl compat_sys_newstat_wrapper
484compat_sys_newstat_wrapper:
485 llgtr %r2,%r2 # char *
486 llgtr %r3,%r3 # struct stat_emu31 *
487 jg compat_sys_newstat # branch to system call
488
489 .globl compat_sys_newlstat_wrapper
490compat_sys_newlstat_wrapper:
491 llgtr %r2,%r2 # char *
492 llgtr %r3,%r3 # struct stat_emu31 *
493 jg compat_sys_newlstat # branch to system call
494
495 .globl compat_sys_newfstat_wrapper
496compat_sys_newfstat_wrapper:
497 llgfr %r2,%r2 # unsigned int
498 llgtr %r3,%r3 # struct stat_emu31 *
499 jg compat_sys_newfstat # branch to system call
500
501#sys32_vhangup_wrapper # void
502
503 .globl compat_sys_wait4_wrapper
504compat_sys_wait4_wrapper:
505 lgfr %r2,%r2 # pid_t
506 llgtr %r3,%r3 # unsigned int *
507 lgfr %r4,%r4 # int
508 llgtr %r5,%r5 # struct rusage *
509 jg compat_sys_wait4 # branch to system call
510
511 .globl sys32_swapoff_wrapper
512sys32_swapoff_wrapper:
513 llgtr %r2,%r2 # const char *
514 jg sys_swapoff # branch to system call
515
516 .globl sys32_sysinfo_wrapper
517sys32_sysinfo_wrapper:
518 llgtr %r2,%r2 # struct sysinfo_emu31 *
519 jg sys32_sysinfo # branch to system call
520
521 .globl sys32_ipc_wrapper
522sys32_ipc_wrapper:
523 llgfr %r2,%r2 # uint
524 lgfr %r3,%r3 # int
525 lgfr %r4,%r4 # int
526 lgfr %r5,%r5 # int
527 llgfr %r6,%r6 # u32
528 jg sys32_ipc # branch to system call
529
530 .globl sys32_fsync_wrapper
531sys32_fsync_wrapper:
532 llgfr %r2,%r2 # unsigned int
533 jg sys_fsync # branch to system call
534
535#sys32_sigreturn_wrapper # done in sigreturn_glue
536
537#sys32_clone_wrapper # done in clone_glue
538
539 .globl sys32_setdomainname_wrapper
540sys32_setdomainname_wrapper:
541 llgtr %r2,%r2 # char *
542 lgfr %r3,%r3 # int
543 jg sys_setdomainname # branch to system call
544
545 .globl sys32_newuname_wrapper
546sys32_newuname_wrapper:
547 llgtr %r2,%r2 # struct new_utsname *
548 jg s390x_newuname # branch to system call
549
550 .globl sys32_adjtimex_wrapper
551sys32_adjtimex_wrapper:
552 llgtr %r2,%r2 # struct timex_emu31 *
553 jg sys32_adjtimex # branch to system call
554
555 .globl sys32_mprotect_wrapper
556sys32_mprotect_wrapper:
557 llgtr %r2,%r2 # unsigned long (actually pointer
558 llgfr %r3,%r3 # size_t
559 llgfr %r4,%r4 # unsigned long
560 jg sys_mprotect # branch to system call
561
562 .globl compat_sys_sigprocmask_wrapper
563compat_sys_sigprocmask_wrapper:
564 lgfr %r2,%r2 # int
565 llgtr %r3,%r3 # compat_old_sigset_t *
566 llgtr %r4,%r4 # compat_old_sigset_t *
567 jg compat_sys_sigprocmask # branch to system call
568
569 .globl sys32_init_module_wrapper
570sys32_init_module_wrapper:
571 llgtr %r2,%r2 # void *
572 llgfr %r3,%r3 # unsigned long
573 llgtr %r4,%r4 # char *
574 jg sys32_init_module # branch to system call
575
576 .globl sys32_delete_module_wrapper
577sys32_delete_module_wrapper:
578 llgtr %r2,%r2 # const char *
579 llgfr %r3,%r3 # unsigned int
580 jg sys32_delete_module # branch to system call
581
582 .globl sys32_quotactl_wrapper
583sys32_quotactl_wrapper:
584 llgfr %r2,%r2 # unsigned int
585 llgtr %r3,%r3 # const char *
586 llgfr %r4,%r4 # qid_t
587 llgtr %r5,%r5 # caddr_t
588 jg sys_quotactl # branch to system call
589
590 .globl sys32_getpgid_wrapper
591sys32_getpgid_wrapper:
592 lgfr %r2,%r2 # pid_t
593 jg sys_getpgid # branch to system call
594
595 .globl sys32_fchdir_wrapper
596sys32_fchdir_wrapper:
597 llgfr %r2,%r2 # unsigned int
598 jg sys_fchdir # branch to system call
599
600 .globl sys32_bdflush_wrapper
601sys32_bdflush_wrapper:
602 lgfr %r2,%r2 # int
603 lgfr %r3,%r3 # long
604 jg sys_bdflush # branch to system call
605
606 .globl sys32_sysfs_wrapper
607sys32_sysfs_wrapper:
608 lgfr %r2,%r2 # int
609 llgfr %r3,%r3 # unsigned long
610 llgfr %r4,%r4 # unsigned long
611 jg sys_sysfs # branch to system call
612
613 .globl sys32_personality_wrapper
614sys32_personality_wrapper:
615 llgfr %r2,%r2 # unsigned long
616 jg s390x_personality # branch to system call
617
618 .globl sys32_setfsuid16_wrapper
619sys32_setfsuid16_wrapper:
620 llgfr %r2,%r2 # __kernel_old_uid_emu31_t
621 jg sys32_setfsuid16 # branch to system call
622
623 .globl sys32_setfsgid16_wrapper
624sys32_setfsgid16_wrapper:
625 llgfr %r2,%r2 # __kernel_old_gid_emu31_t
626 jg sys32_setfsgid16 # branch to system call
627
628 .globl sys32_llseek_wrapper
629sys32_llseek_wrapper:
630 llgfr %r2,%r2 # unsigned int
631 llgfr %r3,%r3 # unsigned long
632 llgfr %r4,%r4 # unsigned long
633 llgtr %r5,%r5 # loff_t *
634 llgfr %r6,%r6 # unsigned int
635 jg sys_llseek # branch to system call
636
637 .globl sys32_getdents_wrapper
638sys32_getdents_wrapper:
639 llgfr %r2,%r2 # unsigned int
640 llgtr %r3,%r3 # void *
641 llgfr %r4,%r4 # unsigned int
642 jg compat_sys_getdents # branch to system call
643
644 .globl compat_sys_select_wrapper
645compat_sys_select_wrapper:
646 lgfr %r2,%r2 # int
647 llgtr %r3,%r3 # compat_fd_set *
648 llgtr %r4,%r4 # compat_fd_set *
649 llgtr %r5,%r5 # compat_fd_set *
650 llgtr %r6,%r6 # struct compat_timeval *
651 jg compat_sys_select # branch to system call
652
653 .globl sys32_flock_wrapper
654sys32_flock_wrapper:
655 llgfr %r2,%r2 # unsigned int
656 llgfr %r3,%r3 # unsigned int
657 jg sys_flock # branch to system call
658
659 .globl sys32_msync_wrapper
660sys32_msync_wrapper:
661 llgfr %r2,%r2 # unsigned long
662 llgfr %r3,%r3 # size_t
663 lgfr %r4,%r4 # int
664 jg sys_msync # branch to system call
665
666 .globl compat_sys_readv_wrapper
667compat_sys_readv_wrapper:
668 lgfr %r2,%r2 # int
669 llgtr %r3,%r3 # const struct compat_iovec *
670 llgfr %r4,%r4 # unsigned long
671 jg compat_sys_readv # branch to system call
672
673 .globl compat_sys_writev_wrapper
674compat_sys_writev_wrapper:
675 lgfr %r2,%r2 # int
676 llgtr %r3,%r3 # const struct compat_iovec *
677 llgfr %r4,%r4 # unsigned long
678 jg compat_sys_writev # branch to system call
679
680 .globl sys32_getsid_wrapper
681sys32_getsid_wrapper:
682 lgfr %r2,%r2 # pid_t
683 jg sys_getsid # branch to system call
684
685 .globl sys32_fdatasync_wrapper
686sys32_fdatasync_wrapper:
687 llgfr %r2,%r2 # unsigned int
688 jg sys_fdatasync # branch to system call
689
690#sys32_sysctl_wrapper # tbd
691
692 .globl sys32_mlock_wrapper
693sys32_mlock_wrapper:
694 llgfr %r2,%r2 # unsigned long
695 llgfr %r3,%r3 # size_t
696 jg sys_mlock # branch to system call
697
698 .globl sys32_munlock_wrapper
699sys32_munlock_wrapper:
700 llgfr %r2,%r2 # unsigned long
701 llgfr %r3,%r3 # size_t
702 jg sys_munlock # branch to system call
703
704 .globl sys32_mlockall_wrapper
705sys32_mlockall_wrapper:
706 lgfr %r2,%r2 # int
707 jg sys_mlockall # branch to system call
708
709#sys32_munlockall_wrapper # void
710
711 .globl sys32_sched_setparam_wrapper
712sys32_sched_setparam_wrapper:
713 lgfr %r2,%r2 # pid_t
714 llgtr %r3,%r3 # struct sched_param *
715 jg sys_sched_setparam # branch to system call
716
717 .globl sys32_sched_getparam_wrapper
718sys32_sched_getparam_wrapper:
719 lgfr %r2,%r2 # pid_t
720 llgtr %r3,%r3 # struct sched_param *
721 jg sys_sched_getparam # branch to system call
722
723 .globl sys32_sched_setscheduler_wrapper
724sys32_sched_setscheduler_wrapper:
725 lgfr %r2,%r2 # pid_t
726 lgfr %r3,%r3 # int
727 llgtr %r4,%r4 # struct sched_param *
728 jg sys_sched_setscheduler # branch to system call
729
730 .globl sys32_sched_getscheduler_wrapper
731sys32_sched_getscheduler_wrapper:
732 lgfr %r2,%r2 # pid_t
733 jg sys_sched_getscheduler # branch to system call
734
735#sys32_sched_yield_wrapper # void
736
737 .globl sys32_sched_get_priority_max_wrapper
738sys32_sched_get_priority_max_wrapper:
739 lgfr %r2,%r2 # int
740 jg sys_sched_get_priority_max # branch to system call
741
742 .globl sys32_sched_get_priority_min_wrapper
743sys32_sched_get_priority_min_wrapper:
744 lgfr %r2,%r2 # int
745 jg sys_sched_get_priority_min # branch to system call
746
747 .globl sys32_sched_rr_get_interval_wrapper
748sys32_sched_rr_get_interval_wrapper:
749 lgfr %r2,%r2 # pid_t
750 llgtr %r3,%r3 # struct compat_timespec *
751 jg sys32_sched_rr_get_interval # branch to system call
752
753 .globl compat_sys_nanosleep_wrapper
754compat_sys_nanosleep_wrapper:
755 llgtr %r2,%r2 # struct compat_timespec *
756 llgtr %r3,%r3 # struct compat_timespec *
757 jg compat_sys_nanosleep # branch to system call
758
759 .globl sys32_mremap_wrapper
760sys32_mremap_wrapper:
761 llgfr %r2,%r2 # unsigned long
762 llgfr %r3,%r3 # unsigned long
763 llgfr %r4,%r4 # unsigned long
764 llgfr %r5,%r5 # unsigned long
765 llgfr %r6,%r6 # unsigned long
766 jg sys_mremap # branch to system call
767
768 .globl sys32_setresuid16_wrapper
769sys32_setresuid16_wrapper:
770 llgfr %r2,%r2 # __kernel_old_uid_emu31_t
771 llgfr %r3,%r3 # __kernel_old_uid_emu31_t
772 llgfr %r4,%r4 # __kernel_old_uid_emu31_t
773 jg sys32_setresuid16 # branch to system call
774
775 .globl sys32_getresuid16_wrapper
776sys32_getresuid16_wrapper:
777 llgtr %r2,%r2 # __kernel_old_uid_emu31_t *
778 llgtr %r3,%r3 # __kernel_old_uid_emu31_t *
779 llgtr %r4,%r4 # __kernel_old_uid_emu31_t *
780 jg sys32_getresuid16 # branch to system call
781
782 .globl sys32_poll_wrapper
783sys32_poll_wrapper:
784 llgtr %r2,%r2 # struct pollfd *
785 llgfr %r3,%r3 # unsigned int
786 lgfr %r4,%r4 # long
787 jg sys_poll # branch to system call
788
789 .globl compat_sys_nfsservctl_wrapper
790compat_sys_nfsservctl_wrapper:
791 lgfr %r2,%r2 # int
792 llgtr %r3,%r3 # struct compat_nfsctl_arg*
793 llgtr %r4,%r4 # union compat_nfsctl_res*
794 jg compat_sys_nfsservctl # branch to system call
795
796 .globl sys32_setresgid16_wrapper
797sys32_setresgid16_wrapper:
798 llgfr %r2,%r2 # __kernel_old_gid_emu31_t
799 llgfr %r3,%r3 # __kernel_old_gid_emu31_t
800 llgfr %r4,%r4 # __kernel_old_gid_emu31_t
801 jg sys32_setresgid16 # branch to system call
802
803 .globl sys32_getresgid16_wrapper
804sys32_getresgid16_wrapper:
805 llgtr %r2,%r2 # __kernel_old_gid_emu31_t *
806 llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
807 llgtr %r4,%r4 # __kernel_old_gid_emu31_t *
808 jg sys32_getresgid16 # branch to system call
809
810 .globl sys32_prctl_wrapper
811sys32_prctl_wrapper:
812 lgfr %r2,%r2 # int
813 llgfr %r3,%r3 # unsigned long
814 llgfr %r4,%r4 # unsigned long
815 llgfr %r5,%r5 # unsigned long
816 llgfr %r6,%r6 # unsigned long
817 jg sys_prctl # branch to system call
818
819#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
820
821 .globl sys32_rt_sigaction_wrapper
822sys32_rt_sigaction_wrapper:
823 lgfr %r2,%r2 # int
824 llgtr %r3,%r3 # const struct sigaction_emu31 *
825 llgtr %r4,%r4 # const struct sigaction_emu31 *
826 llgfr %r5,%r5 # size_t
827 jg sys32_rt_sigaction # branch to system call
828
829 .globl sys32_rt_sigprocmask_wrapper
830sys32_rt_sigprocmask_wrapper:
831 lgfr %r2,%r2 # int
832 llgtr %r3,%r3 # old_sigset_emu31 *
833 llgtr %r4,%r4 # old_sigset_emu31 *
834 llgfr %r5,%r5 # size_t
835 jg sys32_rt_sigprocmask # branch to system call
836
837 .globl sys32_rt_sigpending_wrapper
838sys32_rt_sigpending_wrapper:
839 llgtr %r2,%r2 # sigset_emu31 *
840 llgfr %r3,%r3 # size_t
841 jg sys32_rt_sigpending # branch to system call
842
843 .globl compat_sys_rt_sigtimedwait_wrapper
844compat_sys_rt_sigtimedwait_wrapper:
845 llgtr %r2,%r2 # const sigset_emu31_t *
846 llgtr %r3,%r3 # siginfo_emu31_t *
847 llgtr %r4,%r4 # const struct compat_timespec *
848 llgfr %r5,%r5 # size_t
849 jg compat_sys_rt_sigtimedwait # branch to system call
850
851 .globl sys32_rt_sigqueueinfo_wrapper
852sys32_rt_sigqueueinfo_wrapper:
853 lgfr %r2,%r2 # int
854 lgfr %r3,%r3 # int
855 llgtr %r4,%r4 # siginfo_emu31_t *
856 jg sys32_rt_sigqueueinfo # branch to system call
857
858#sys32_rt_sigsuspend_wrapper # done in rt_sigsuspend_glue
859
860 .globl sys32_pread64_wrapper
861sys32_pread64_wrapper:
862 llgfr %r2,%r2 # unsigned int
863 llgtr %r3,%r3 # char *
864 llgfr %r4,%r4 # size_t
865 llgfr %r5,%r5 # u32
866 llgfr %r6,%r6 # u32
867 jg sys32_pread64 # branch to system call
868
869 .globl sys32_pwrite64_wrapper
870sys32_pwrite64_wrapper:
871 llgfr %r2,%r2 # unsigned int
872 llgtr %r3,%r3 # const char *
873 llgfr %r4,%r4 # size_t
874 llgfr %r5,%r5 # u32
875 llgfr %r6,%r6 # u32
876 jg sys32_pwrite64 # branch to system call
877
878 .globl sys32_chown16_wrapper
879sys32_chown16_wrapper:
880 llgtr %r2,%r2 # const char *
881 llgfr %r3,%r3 # __kernel_old_uid_emu31_t
882 llgfr %r4,%r4 # __kernel_old_gid_emu31_t
883 jg sys32_chown16 # branch to system call
884
885 .globl sys32_getcwd_wrapper
886sys32_getcwd_wrapper:
887 llgtr %r2,%r2 # char *
888 llgfr %r3,%r3 # unsigned long
889 jg sys_getcwd # branch to system call
890
891 .globl sys32_capget_wrapper
892sys32_capget_wrapper:
893 llgtr %r2,%r2 # cap_user_header_t
894 llgtr %r3,%r3 # cap_user_data_t
895 jg sys_capget # branch to system call
896
897 .globl sys32_capset_wrapper
898sys32_capset_wrapper:
899 llgtr %r2,%r2 # cap_user_header_t
900 llgtr %r3,%r3 # const cap_user_data_t
901 jg sys_capset # branch to system call
902
903 .globl sys32_sigaltstack_wrapper
904sys32_sigaltstack_wrapper:
905 llgtr %r2,%r2 # const stack_emu31_t *
906 llgtr %r3,%r3 # stack_emu31_t *
907 jg sys32_sigaltstack
908
909 .globl sys32_sendfile_wrapper
910sys32_sendfile_wrapper:
911 lgfr %r2,%r2 # int
912 lgfr %r3,%r3 # int
913 llgtr %r4,%r4 # __kernel_off_emu31_t *
914 llgfr %r5,%r5 # size_t
915 jg sys32_sendfile # branch to system call
916
917#sys32_vfork_wrapper # done in vfork_glue
918
919 .globl sys32_truncate64_wrapper
920sys32_truncate64_wrapper:
921 llgtr %r2,%r2 # const char *
922 llgfr %r3,%r3 # unsigned long
923 llgfr %r4,%r4 # unsigned long
924 jg sys32_truncate64 # branch to system call
925
926 .globl sys32_ftruncate64_wrapper
927sys32_ftruncate64_wrapper:
928 llgfr %r2,%r2 # unsigned int
929 llgfr %r3,%r3 # unsigned long
930 llgfr %r4,%r4 # unsigned long
931 jg sys32_ftruncate64 # branch to system call
932
933 .globl sys32_lchown_wrapper
934sys32_lchown_wrapper:
935 llgtr %r2,%r2 # const char *
936 llgfr %r3,%r3 # uid_t
937 llgfr %r4,%r4 # gid_t
938 jg sys_lchown # branch to system call
939
940#sys32_getuid_wrapper # void
941#sys32_getgid_wrapper # void
942#sys32_geteuid_wrapper # void
943#sys32_getegid_wrapper # void
944
945 .globl sys32_setreuid_wrapper
946sys32_setreuid_wrapper:
947 llgfr %r2,%r2 # uid_t
948 llgfr %r3,%r3 # uid_t
949 jg sys_setreuid # branch to system call
950
951 .globl sys32_setregid_wrapper
952sys32_setregid_wrapper:
953 llgfr %r2,%r2 # gid_t
954 llgfr %r3,%r3 # gid_t
955 jg sys_setregid # branch to system call
956
957 .globl sys32_getgroups_wrapper
958sys32_getgroups_wrapper:
959 lgfr %r2,%r2 # int
960 llgtr %r3,%r3 # gid_t *
961 jg sys_getgroups # branch to system call
962
963 .globl sys32_setgroups_wrapper
964sys32_setgroups_wrapper:
965 lgfr %r2,%r2 # int
966 llgtr %r3,%r3 # gid_t *
967 jg sys_setgroups # branch to system call
968
969 .globl sys32_fchown_wrapper
970sys32_fchown_wrapper:
971 llgfr %r2,%r2 # unsigned int
972 llgfr %r3,%r3 # uid_t
973 llgfr %r4,%r4 # gid_t
974 jg sys_fchown # branch to system call
975
976 .globl sys32_setresuid_wrapper
977sys32_setresuid_wrapper:
978 llgfr %r2,%r2 # uid_t
979 llgfr %r3,%r3 # uid_t
980 llgfr %r4,%r4 # uid_t
981 jg sys_setresuid # branch to system call
982
983 .globl sys32_getresuid_wrapper
984sys32_getresuid_wrapper:
985 llgtr %r2,%r2 # uid_t *
986 llgtr %r3,%r3 # uid_t *
987 llgtr %r4,%r4 # uid_t *
988 jg sys_getresuid # branch to system call
989
990 .globl sys32_setresgid_wrapper
991sys32_setresgid_wrapper:
992 llgfr %r2,%r2 # gid_t
993 llgfr %r3,%r3 # gid_t
994 llgfr %r4,%r4 # gid_t
995 jg sys_setresgid # branch to system call
996
997 .globl sys32_getresgid_wrapper
998sys32_getresgid_wrapper:
999 llgtr %r2,%r2 # gid_t *
1000 llgtr %r3,%r3 # gid_t *
1001 llgtr %r4,%r4 # gid_t *
1002 jg sys_getresgid # branch to system call
1003
1004 .globl sys32_chown_wrapper
1005sys32_chown_wrapper:
1006 llgtr %r2,%r2 # const char *
1007 llgfr %r3,%r3 # uid_t
1008 llgfr %r4,%r4 # gid_t
1009 jg sys_chown # branch to system call
1010
1011 .globl sys32_setuid_wrapper
1012sys32_setuid_wrapper:
1013 llgfr %r2,%r2 # uid_t
1014 jg sys_setuid # branch to system call
1015
1016 .globl sys32_setgid_wrapper
1017sys32_setgid_wrapper:
1018 llgfr %r2,%r2 # gid_t
1019 jg sys_setgid # branch to system call
1020
1021 .globl sys32_setfsuid_wrapper
1022sys32_setfsuid_wrapper:
1023 llgfr %r2,%r2 # uid_t
1024 jg sys_setfsuid # branch to system call
1025
1026 .globl sys32_setfsgid_wrapper
1027sys32_setfsgid_wrapper:
1028 llgfr %r2,%r2 # gid_t
1029 jg sys_setfsgid # branch to system call
1030
1031 .globl sys32_pivot_root_wrapper
1032sys32_pivot_root_wrapper:
1033 llgtr %r2,%r2 # const char *
1034 llgtr %r3,%r3 # const char *
1035 jg sys_pivot_root # branch to system call
1036
1037 .globl sys32_mincore_wrapper
1038sys32_mincore_wrapper:
1039 llgfr %r2,%r2 # unsigned long
1040 llgfr %r3,%r3 # size_t
1041 llgtr %r4,%r4 # unsigned char *
1042 jg sys_mincore # branch to system call
1043
1044 .globl sys32_madvise_wrapper
1045sys32_madvise_wrapper:
1046 llgfr %r2,%r2 # unsigned long
1047 llgfr %r3,%r3 # size_t
1048 lgfr %r4,%r4 # int
1049 jg sys_madvise # branch to system call
1050
1051 .globl sys32_getdents64_wrapper
1052sys32_getdents64_wrapper:
1053 llgfr %r2,%r2 # unsigned int
1054 llgtr %r3,%r3 # void *
1055 llgfr %r4,%r4 # unsigned int
1056 jg sys_getdents64 # branch to system call
1057
1058 .globl compat_sys_fcntl64_wrapper
1059compat_sys_fcntl64_wrapper:
1060 llgfr %r2,%r2 # unsigned int
1061 llgfr %r3,%r3 # unsigned int
1062 llgfr %r4,%r4 # unsigned long
1063 jg compat_sys_fcntl64 # branch to system call
1064
1065 .globl sys32_stat64_wrapper
1066sys32_stat64_wrapper:
1067 llgtr %r2,%r2 # char *
1068 llgtr %r3,%r3 # struct stat64 *
1069 jg sys32_stat64 # branch to system call
1070
1071 .globl sys32_lstat64_wrapper
1072sys32_lstat64_wrapper:
1073 llgtr %r2,%r2 # char *
1074 llgtr %r3,%r3 # struct stat64 *
1075 jg sys32_lstat64 # branch to system call
1076
1077 .globl sys32_stime_wrapper
1078sys32_stime_wrapper:
1079 llgtr %r2,%r2 # long *
1080 jg compat_sys_stime # branch to system call
1081
1082 .globl sys32_sysctl_wrapper
1083sys32_sysctl_wrapper:
1084 llgtr %r2,%r2 # struct __sysctl_args32 *
1085 jg sys32_sysctl
1086
1087 .globl sys32_fstat64_wrapper
1088sys32_fstat64_wrapper:
1089 llgfr %r2,%r2 # unsigned long
1090 llgtr %r3,%r3 # struct stat64 *
1091 jg sys32_fstat64 # branch to system call
1092
1093 .globl compat_sys_futex_wrapper
1094compat_sys_futex_wrapper:
1095 llgtr %r2,%r2 # u32 *
1096 lgfr %r3,%r3 # int
1097 lgfr %r4,%r4 # int
1098 llgtr %r5,%r5 # struct compat_timespec *
1099 llgtr %r6,%r6 # u32 *
1100 lgf %r0,164(%r15) # int
1101 stg %r0,160(%r15)
1102 jg compat_sys_futex # branch to system call
1103
1104 .globl sys32_setxattr_wrapper
1105sys32_setxattr_wrapper:
1106 llgtr %r2,%r2 # char *
1107 llgtr %r3,%r3 # char *
1108 llgtr %r4,%r4 # void *
1109 llgfr %r5,%r5 # size_t
1110 lgfr %r6,%r6 # int
1111 jg sys_setxattr
1112
1113 .globl sys32_lsetxattr_wrapper
1114sys32_lsetxattr_wrapper:
1115 llgtr %r2,%r2 # char *
1116 llgtr %r3,%r3 # char *
1117 llgtr %r4,%r4 # void *
1118 llgfr %r5,%r5 # size_t
1119 lgfr %r6,%r6 # int
1120 jg sys_lsetxattr
1121
1122 .globl sys32_fsetxattr_wrapper
1123sys32_fsetxattr_wrapper:
1124 lgfr %r2,%r2 # int
1125 llgtr %r3,%r3 # char *
1126 llgtr %r4,%r4 # void *
1127 llgfr %r5,%r5 # size_t
1128 lgfr %r6,%r6 # int
1129 jg sys_fsetxattr
1130
1131 .globl sys32_getxattr_wrapper
1132sys32_getxattr_wrapper:
1133 llgtr %r2,%r2 # char *
1134 llgtr %r3,%r3 # char *
1135 llgtr %r4,%r4 # void *
1136 llgfr %r5,%r5 # size_t
1137 jg sys_getxattr
1138
1139 .globl sys32_lgetxattr_wrapper
1140sys32_lgetxattr_wrapper:
1141 llgtr %r2,%r2 # char *
1142 llgtr %r3,%r3 # char *
1143 llgtr %r4,%r4 # void *
1144 llgfr %r5,%r5 # size_t
1145 jg sys_lgetxattr
1146
1147 .globl sys32_fgetxattr_wrapper
1148sys32_fgetxattr_wrapper:
1149 lgfr %r2,%r2 # int
1150 llgtr %r3,%r3 # char *
1151 llgtr %r4,%r4 # void *
1152 llgfr %r5,%r5 # size_t
1153 jg sys_fgetxattr
1154
1155 .globl sys32_listxattr_wrapper
1156sys32_listxattr_wrapper:
1157 llgtr %r2,%r2 # char *
1158 llgtr %r3,%r3 # char *
1159 llgfr %r4,%r4 # size_t
1160 jg sys_listxattr
1161
1162 .globl sys32_llistxattr_wrapper
1163sys32_llistxattr_wrapper:
1164 llgtr %r2,%r2 # char *
1165 llgtr %r3,%r3 # char *
1166 llgfr %r4,%r4 # size_t
1167 jg sys_llistxattr
1168
1169 .globl sys32_flistxattr_wrapper
1170sys32_flistxattr_wrapper:
1171 lgfr %r2,%r2 # int
1172 llgtr %r3,%r3 # char *
1173 llgfr %r4,%r4 # size_t
1174 jg sys_flistxattr
1175
1176 .globl sys32_removexattr_wrapper
1177sys32_removexattr_wrapper:
1178 llgtr %r2,%r2 # char *
1179 llgtr %r3,%r3 # char *
1180 jg sys_removexattr
1181
1182 .globl sys32_lremovexattr_wrapper
1183sys32_lremovexattr_wrapper:
1184 llgtr %r2,%r2 # char *
1185 llgtr %r3,%r3 # char *
1186 jg sys_lremovexattr
1187
1188 .globl sys32_fremovexattr_wrapper
1189sys32_fremovexattr_wrapper:
1190 lgfr %r2,%r2 # int
1191 llgtr %r3,%r3 # char *
1192 jg sys_fremovexattr
1193
1194 .globl sys32_sched_setaffinity_wrapper
1195sys32_sched_setaffinity_wrapper:
1196 lgfr %r2,%r2 # int
1197 llgfr %r3,%r3 # unsigned int
1198 llgtr %r4,%r4 # unsigned long *
1199 jg compat_sys_sched_setaffinity
1200
1201 .globl sys32_sched_getaffinity_wrapper
1202sys32_sched_getaffinity_wrapper:
1203 lgfr %r2,%r2 # int
1204 llgfr %r3,%r3 # unsigned int
1205 llgtr %r4,%r4 # unsigned long *
1206 jg compat_sys_sched_getaffinity
1207
1208 .globl sys32_exit_group_wrapper
1209sys32_exit_group_wrapper:
1210 lgfr %r2,%r2 # int
1211 jg sys_exit_group # branch to system call
1212
1213 .globl sys32_set_tid_address_wrapper
1214sys32_set_tid_address_wrapper:
1215 llgtr %r2,%r2 # int *
1216 jg sys_set_tid_address # branch to system call
1217
1218 .globl sys_epoll_create_wrapper
1219sys_epoll_create_wrapper:
1220 lgfr %r2,%r2 # int
1221 jg sys_epoll_create # branch to system call
1222
1223 .globl sys_epoll_ctl_wrapper
1224sys_epoll_ctl_wrapper:
1225 lgfr %r2,%r2 # int
1226 lgfr %r3,%r3 # int
1227 lgfr %r4,%r4 # int
1228 llgtr %r5,%r5 # struct epoll_event *
1229 jg sys_epoll_ctl # branch to system call
1230
1231 .globl sys_epoll_wait_wrapper
1232sys_epoll_wait_wrapper:
1233 lgfr %r2,%r2 # int
1234 llgtr %r3,%r3 # struct epoll_event *
1235 lgfr %r4,%r4 # int
1236 lgfr %r5,%r5 # int
1237 jg sys_epoll_wait # branch to system call
1238
1239 .globl sys32_lookup_dcookie_wrapper
1240sys32_lookup_dcookie_wrapper:
1241 sllg %r2,%r2,32 # get high word of 64bit dcookie
1242 or %r2,%r3 # get low word of 64bit dcookie
1243 llgtr %r3,%r4 # char *
1244 llgfr %r4,%r5 # size_t
1245 jg sys_lookup_dcookie
1246
1247 .globl sys32_fadvise64_wrapper
1248sys32_fadvise64_wrapper:
1249 lgfr %r2,%r2 # int
1250 sllg %r3,%r3,32 # get high word of 64bit loff_t
1251 or %r3,%r4 # get low word of 64bit loff_t
1252 llgfr %r4,%r5 # size_t (unsigned long)
1253 lgfr %r5,%r6 # int
1254 jg sys_fadvise64
1255
1256 .globl sys32_fadvise64_64_wrapper
1257sys32_fadvise64_64_wrapper:
1258 llgtr %r2,%r2 # struct fadvise64_64_args *
1259 jg s390_fadvise64_64
1260
1261 .globl sys32_clock_settime_wrapper
1262sys32_clock_settime_wrapper:
1263 lgfr %r2,%r2 # clockid_t (int)
1264 llgtr %r3,%r3 # struct compat_timespec *
1265 jg compat_sys_clock_settime
1266
1267 .globl sys32_clock_gettime_wrapper
1268sys32_clock_gettime_wrapper:
1269 lgfr %r2,%r2 # clockid_t (int)
1270 llgtr %r3,%r3 # struct compat_timespec *
1271 jg compat_sys_clock_gettime
1272
1273 .globl sys32_clock_getres_wrapper
1274sys32_clock_getres_wrapper:
1275 lgfr %r2,%r2 # clockid_t (int)
1276 llgtr %r3,%r3 # struct compat_timespec *
1277 jg compat_sys_clock_getres
1278
1279 .globl sys32_clock_nanosleep_wrapper
1280sys32_clock_nanosleep_wrapper:
1281 lgfr %r2,%r2 # clockid_t (int)
1282 lgfr %r3,%r3 # int
1283 llgtr %r4,%r4 # struct compat_timespec *
1284 llgtr %r5,%r5 # struct compat_timespec *
1285 jg compat_sys_clock_nanosleep
1286
1287 .globl sys32_timer_create_wrapper
1288sys32_timer_create_wrapper:
1289 lgfr %r2,%r2 # timer_t (int)
1290 llgtr %r3,%r3 # struct compat_sigevent *
1291 llgtr %r4,%r4 # timer_t *
1292 jg sys32_timer_create
1293
1294 .globl sys32_timer_settime_wrapper
1295sys32_timer_settime_wrapper:
1296 lgfr %r2,%r2 # timer_t (int)
1297 lgfr %r3,%r3 # int
1298 llgtr %r4,%r4 # struct compat_itimerspec *
1299 llgtr %r5,%r5 # struct compat_itimerspec *
1300 jg compat_sys_timer_settime
1301
1302 .globl sys32_timer_gettime_wrapper
1303sys32_timer_gettime_wrapper:
1304 lgfr %r2,%r2 # timer_t (int)
1305 llgtr %r3,%r3 # struct compat_itimerspec *
1306 jg compat_sys_timer_gettime
1307
1308 .globl sys32_timer_getoverrun_wrapper
1309sys32_timer_getoverrun_wrapper:
1310 lgfr %r2,%r2 # timer_t (int)
1311 jg sys_timer_getoverrun
1312
1313 .globl sys32_timer_delete_wrapper
1314sys32_timer_delete_wrapper:
1315 lgfr %r2,%r2 # timer_t (int)
1316 jg sys_timer_delete
1317
1318 .globl sys32_io_setup_wrapper
1319sys32_io_setup_wrapper:
1320 llgfr %r2,%r2 # unsigned int
1321 llgtr %r3,%r3 # u32 *
1322 jg compat_sys_io_setup
1323
1324 .globl sys32_io_destroy_wrapper
1325sys32_io_destroy_wrapper:
1326 llgfr %r2,%r2 # (aio_context_t) u32
1327 jg sys_io_destroy
1328
1329 .globl sys32_io_getevents_wrapper
1330sys32_io_getevents_wrapper:
1331 llgfr %r2,%r2 # (aio_context_t) u32
1332 lgfr %r3,%r3 # long
1333 lgfr %r4,%r4 # long
1334 llgtr %r5,%r5 # struct io_event *
1335 llgtr %r6,%r6 # struct compat_timespec *
1336 jg compat_sys_io_getevents
1337
1338 .globl sys32_io_submit_wrapper
1339sys32_io_submit_wrapper:
1340 llgfr %r2,%r2 # (aio_context_t) u32
1341 lgfr %r3,%r3 # long
1342 llgtr %r4,%r4 # struct iocb **
1343 jg compat_sys_io_submit
1344
1345 .globl sys32_io_cancel_wrapper
1346sys32_io_cancel_wrapper:
1347 llgfr %r2,%r2 # (aio_context_t) u32
1348 llgtr %r3,%r3 # struct iocb *
1349 llgtr %r4,%r4 # struct io_event *
1350 jg sys_io_cancel
1351
1352 .globl compat_sys_statfs64_wrapper
1353compat_sys_statfs64_wrapper:
1354 llgtr %r2,%r2 # const char *
1355 llgfr %r3,%r3 # compat_size_t
1356 llgtr %r4,%r4 # struct compat_statfs64 *
1357 jg compat_sys_statfs64
1358
1359 .globl compat_sys_fstatfs64_wrapper
1360compat_sys_fstatfs64_wrapper:
1361 llgfr %r2,%r2 # unsigned int fd
1362 llgfr %r3,%r3 # compat_size_t
1363 llgtr %r4,%r4 # struct compat_statfs64 *
1364 jg compat_sys_fstatfs64
1365
1366 .globl compat_sys_mq_open_wrapper
1367compat_sys_mq_open_wrapper:
1368 llgtr %r2,%r2 # const char *
1369 lgfr %r3,%r3 # int
1370 llgfr %r4,%r4 # mode_t
1371 llgtr %r5,%r5 # struct compat_mq_attr *
1372 jg compat_sys_mq_open
1373
1374 .globl sys32_mq_unlink_wrapper
1375sys32_mq_unlink_wrapper:
1376 llgtr %r2,%r2 # const char *
1377 jg sys_mq_unlink
1378
1379 .globl compat_sys_mq_timedsend_wrapper
1380compat_sys_mq_timedsend_wrapper:
1381 lgfr %r2,%r2 # mqd_t
1382 llgtr %r3,%r3 # const char *
1383 llgfr %r4,%r4 # size_t
1384 llgfr %r5,%r5 # unsigned int
1385 llgtr %r6,%r6 # const struct compat_timespec *
1386 jg compat_sys_mq_timedsend
1387
1388 .globl compat_sys_mq_timedreceive_wrapper
1389compat_sys_mq_timedreceive_wrapper:
1390 lgfr %r2,%r2 # mqd_t
1391 llgtr %r3,%r3 # char *
1392 llgfr %r4,%r4 # size_t
1393 llgtr %r5,%r5 # unsigned int *
1394 llgtr %r6,%r6 # const struct compat_timespec *
1395 jg compat_sys_mq_timedreceive
1396
1397 .globl compat_sys_mq_notify_wrapper
1398compat_sys_mq_notify_wrapper:
1399 lgfr %r2,%r2 # mqd_t
1400 llgtr %r3,%r3 # struct compat_sigevent *
1401 jg compat_sys_mq_notify
1402
1403 .globl compat_sys_mq_getsetattr_wrapper
1404compat_sys_mq_getsetattr_wrapper:
1405 lgfr %r2,%r2 # mqd_t
1406 llgtr %r3,%r3 # struct compat_mq_attr *
1407 llgtr %r4,%r4 # struct compat_mq_attr *
1408 jg compat_sys_mq_getsetattr
1409
1410 .globl compat_sys_add_key_wrapper
1411compat_sys_add_key_wrapper:
1412 llgtr %r2,%r2 # const char *
1413 llgtr %r3,%r3 # const char *
1414 llgtr %r4,%r4 # const void *
1415 llgfr %r5,%r5 # size_t
1416 llgfr %r6,%r6 # (key_serial_t) u32
1417 jg sys_add_key
1418
1419 .globl compat_sys_request_key_wrapper
1420compat_sys_request_key_wrapper:
1421 llgtr %r2,%r2 # const char *
1422 llgtr %r3,%r3 # const char *
1423 llgtr %r4,%r4 # const void *
1424 llgfr %r5,%r5 # (key_serial_t) u32
1425 jg sys_request_key
1426
1427 .globl sys32_remap_file_pages_wrapper
1428sys32_remap_file_pages_wrapper:
1429 llgfr %r2,%r2 # unsigned long
1430 llgfr %r3,%r3 # unsigned long
1431 llgfr %r4,%r4 # unsigned long
1432 llgfr %r5,%r5 # unsigned long
1433 llgfr %r6,%r6 # unsigned long
1434 jg sys_remap_file_pages
1435
1436 .globl compat_sys_waitid_wrapper
1437compat_sys_waitid_wrapper:
1438 lgfr %r2,%r2 # int
1439 lgfr %r3,%r3 # pid_t
1440 llgtr %r4,%r4 # siginfo_emu31_t *
1441 lgfr %r5,%r5 # int
1442 llgtr %r6,%r6 # struct rusage_emu31 *
1443 jg compat_sys_waitid
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
new file mode 100644
index 000000000000..44df8dc07c59
--- /dev/null
+++ b/arch/s390/kernel/cpcmd.c
@@ -0,0 +1,111 @@
1/*
2 * arch/s390/kernel/cpcmd.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 * Christian Borntraeger (cborntra@de.ibm.com),
8 */
9
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/slab.h>
13#include <linux/spinlock.h>
14#include <linux/stddef.h>
15#include <linux/string.h>
16#include <asm/ebcdic.h>
17#include <asm/cpcmd.h>
18#include <asm/system.h>
19
20static DEFINE_SPINLOCK(cpcmd_lock);
21static char cpcmd_buf[240];
22
23/*
24 * the caller of __cpcmd has to ensure that the response buffer is below 2 GB
25 */
26void __cpcmd(char *cmd, char *response, int rlen)
27{
28 const int mask = 0x40000000L;
29 unsigned long flags;
30 int cmdlen;
31
32 spin_lock_irqsave(&cpcmd_lock, flags);
33 cmdlen = strlen(cmd);
34 BUG_ON(cmdlen > 240);
35 strcpy(cpcmd_buf, cmd);
36 ASCEBC(cpcmd_buf, cmdlen);
37
38 if (response != NULL && rlen > 0) {
39 memset(response, 0, rlen);
40#ifndef CONFIG_ARCH_S390X
41 asm volatile ("LRA 2,0(%0)\n\t"
42 "LR 4,%1\n\t"
43 "O 4,%4\n\t"
44 "LRA 3,0(%2)\n\t"
45 "LR 5,%3\n\t"
46 ".long 0x83240008 # Diagnose X'08'\n\t"
47 : /* no output */
48 : "a" (cpcmd_buf), "d" (cmdlen),
49 "a" (response), "d" (rlen), "m" (mask)
50 : "cc", "2", "3", "4", "5" );
51#else /* CONFIG_ARCH_S390X */
52 asm volatile (" lrag 2,0(%0)\n"
53 " lgr 4,%1\n"
54 " o 4,%4\n"
55 " lrag 3,0(%2)\n"
56 " lgr 5,%3\n"
57 " sam31\n"
58 " .long 0x83240008 # Diagnose X'08'\n"
59 " sam64"
60 : /* no output */
61 : "a" (cpcmd_buf), "d" (cmdlen),
62 "a" (response), "d" (rlen), "m" (mask)
63 : "cc", "2", "3", "4", "5" );
64#endif /* CONFIG_ARCH_S390X */
65 EBCASC(response, rlen);
66 } else {
67#ifndef CONFIG_ARCH_S390X
68 asm volatile ("LRA 2,0(%0)\n\t"
69 "LR 3,%1\n\t"
70 ".long 0x83230008 # Diagnose X'08'\n\t"
71 : /* no output */
72 : "a" (cpcmd_buf), "d" (cmdlen)
73 : "2", "3" );
74#else /* CONFIG_ARCH_S390X */
75 asm volatile (" lrag 2,0(%0)\n"
76 " lgr 3,%1\n"
77 " sam31\n"
78 " .long 0x83230008 # Diagnose X'08'\n"
79 " sam64"
80 : /* no output */
81 : "a" (cpcmd_buf), "d" (cmdlen)
82 : "2", "3" );
83#endif /* CONFIG_ARCH_S390X */
84 }
85 spin_unlock_irqrestore(&cpcmd_lock, flags);
86}
87
88EXPORT_SYMBOL(__cpcmd);
89
90#ifdef CONFIG_ARCH_S390X
91void cpcmd(char *cmd, char *response, int rlen)
92{
93 char *lowbuf;
94 if ((rlen == 0) || (response == NULL)
95 || !((unsigned long)response >> 31))
96 __cpcmd(cmd, response, rlen);
97 else {
98 lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
99 if (!lowbuf) {
100 printk(KERN_WARNING
101 "cpcmd: could not allocate response buffer\n");
102 return;
103 }
104 __cpcmd(cmd, lowbuf, rlen);
105 memcpy(response, lowbuf, rlen);
106 kfree(lowbuf);
107 }
108}
109
110EXPORT_SYMBOL(cpcmd);
111#endif /* CONFIG_ARCH_S390X */
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
new file mode 100644
index 000000000000..91f8ce5543d3
--- /dev/null
+++ b/arch/s390/kernel/debug.c
@@ -0,0 +1,1286 @@
1/*
2 * arch/s390/kernel/debug.c
3 * S/390 debug facility
4 *
5 * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
6 * IBM Corporation
7 * Author(s): Michael Holzheu (holzheu@de.ibm.com),
8 * Holger Smolinski (Holger.Smolinski@de.ibm.com)
9 *
10 * Bugreports to: <Linux390@de.ibm.com>
11 */
12
13#include <linux/config.h>
14#include <linux/stddef.h>
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/slab.h>
18#include <linux/ctype.h>
19#include <linux/sysctl.h>
20#include <asm/uaccess.h>
21#include <asm/semaphore.h>
22
23#include <linux/module.h>
24#include <linux/init.h>
25
26#include <asm/debug.h>
27
28#define DEBUG_PROLOG_ENTRY -1
29
30/* typedefs */
31
32typedef struct file_private_info {
33 loff_t offset; /* offset of last read in file */
34 int act_area; /* number of last formated area */
35 int act_entry; /* last formated entry (offset */
36 /* relative to beginning of last */
37 /* formated area) */
38 size_t act_entry_offset; /* up to this offset we copied */
39 /* in last read the last formated */
40 /* entry to userland */
41 char temp_buf[2048]; /* buffer for output */
42 debug_info_t *debug_info_org; /* original debug information */
43 debug_info_t *debug_info_snap; /* snapshot of debug information */
44 struct debug_view *view; /* used view of debug info */
45} file_private_info_t;
46
47typedef struct
48{
49 char *string;
50 /*
51 * This assumes that all args are converted into longs
52 * on L/390 this is the case for all types of parameter
53 * except of floats, and long long (32 bit)
54 *
55 */
56 long args[0];
57} debug_sprintf_entry_t;
58
59
60extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
61
62/* internal function prototyes */
63
64static int debug_init(void);
65static ssize_t debug_output(struct file *file, char __user *user_buf,
66 size_t user_len, loff_t * offset);
67static ssize_t debug_input(struct file *file, const char __user *user_buf,
68 size_t user_len, loff_t * offset);
69static int debug_open(struct inode *inode, struct file *file);
70static int debug_close(struct inode *inode, struct file *file);
71static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
72static void debug_info_get(debug_info_t *);
73static void debug_info_put(debug_info_t *);
74static int debug_prolog_level_fn(debug_info_t * id,
75 struct debug_view *view, char *out_buf);
76static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
77 struct file *file, const char __user *user_buf,
78 size_t user_buf_size, loff_t * offset);
79static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
80 struct file *file, const char __user *user_buf,
81 size_t user_buf_size, loff_t * offset);
82static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
83 char *out_buf, const char *in_buf);
84static int debug_raw_format_fn(debug_info_t * id,
85 struct debug_view *view, char *out_buf,
86 const char *in_buf);
87static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
88 int area, debug_entry_t * entry, char *out_buf);
89
90static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
91 char *out_buf, debug_sprintf_entry_t *curr_event);
92
93/* globals */
94
95struct debug_view debug_raw_view = {
96 "raw",
97 NULL,
98 &debug_raw_header_fn,
99 &debug_raw_format_fn,
100 NULL,
101 NULL
102};
103
104struct debug_view debug_hex_ascii_view = {
105 "hex_ascii",
106 NULL,
107 &debug_dflt_header_fn,
108 &debug_hex_ascii_format_fn,
109 NULL,
110 NULL
111};
112
113struct debug_view debug_level_view = {
114 "level",
115 &debug_prolog_level_fn,
116 NULL,
117 NULL,
118 &debug_input_level_fn,
119 NULL
120};
121
122struct debug_view debug_flush_view = {
123 "flush",
124 NULL,
125 NULL,
126 NULL,
127 &debug_input_flush_fn,
128 NULL
129};
130
131struct debug_view debug_sprintf_view = {
132 "sprintf",
133 NULL,
134 &debug_dflt_header_fn,
135 (debug_format_proc_t*)&debug_sprintf_format_fn,
136 NULL,
137 NULL
138};
139
140
141unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
142
143/* static globals */
144
145static debug_info_t *debug_area_first = NULL;
146static debug_info_t *debug_area_last = NULL;
147DECLARE_MUTEX(debug_lock);
148
149static int initialized;
150
151static struct file_operations debug_file_ops = {
152 .owner = THIS_MODULE,
153 .read = debug_output,
154 .write = debug_input,
155 .open = debug_open,
156 .release = debug_close,
157};
158
159static struct proc_dir_entry *debug_proc_root_entry;
160
161/* functions */
162
163/*
164 * debug_info_alloc
165 * - alloc new debug-info
166 */
167
168static debug_info_t* debug_info_alloc(char *name, int page_order,
169 int nr_areas, int buf_size)
170{
171 debug_info_t* rc;
172 int i;
173
174 /* alloc everything */
175
176 rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
177 if(!rc)
178 goto fail_malloc_rc;
179 rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC);
180 if(!rc->active_entry)
181 goto fail_malloc_active_entry;
182 memset(rc->active_entry, 0, nr_areas * sizeof(int));
183 rc->areas = (debug_entry_t **) kmalloc(nr_areas *
184 sizeof(debug_entry_t *),
185 GFP_ATOMIC);
186 if (!rc->areas)
187 goto fail_malloc_areas;
188 for (i = 0; i < nr_areas; i++) {
189 rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
190 page_order);
191 if (!rc->areas[i]) {
192 for (i--; i >= 0; i--) {
193 free_pages((unsigned long) rc->areas[i],
194 page_order);
195 }
196 goto fail_malloc_areas2;
197 } else {
198 memset(rc->areas[i], 0, PAGE_SIZE << page_order);
199 }
200 }
201
202 /* initialize members */
203
204 spin_lock_init(&rc->lock);
205 rc->page_order = page_order;
206 rc->nr_areas = nr_areas;
207 rc->active_area = 0;
208 rc->level = DEBUG_DEFAULT_LEVEL;
209 rc->buf_size = buf_size;
210 rc->entry_size = sizeof(debug_entry_t) + buf_size;
211 strlcpy(rc->name, name, sizeof(rc->name));
212 memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
213#ifdef CONFIG_PROC_FS
214 memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
215 sizeof(struct proc_dir_entry*));
216#endif /* CONFIG_PROC_FS */
217 atomic_set(&(rc->ref_count), 0);
218
219 return rc;
220
221fail_malloc_areas2:
222 kfree(rc->areas);
223fail_malloc_areas:
224 kfree(rc->active_entry);
225fail_malloc_active_entry:
226 kfree(rc);
227fail_malloc_rc:
228 return NULL;
229}
230
231/*
232 * debug_info_free
233 * - free memory debug-info
234 */
235
236static void debug_info_free(debug_info_t* db_info){
237 int i;
238 for (i = 0; i < db_info->nr_areas; i++) {
239 free_pages((unsigned long) db_info->areas[i],
240 db_info->page_order);
241 }
242 kfree(db_info->areas);
243 kfree(db_info->active_entry);
244 kfree(db_info);
245}
246
247/*
248 * debug_info_create
249 * - create new debug-info
250 */
251
252static debug_info_t* debug_info_create(char *name, int page_order,
253 int nr_areas, int buf_size)
254{
255 debug_info_t* rc;
256
257 rc = debug_info_alloc(name, page_order, nr_areas, buf_size);
258 if(!rc)
259 goto out;
260
261
262 /* create proc rood directory */
263 rc->proc_root_entry = proc_mkdir(rc->name, debug_proc_root_entry);
264
265 /* append new element to linked list */
266 if (debug_area_first == NULL) {
267 /* first element in list */
268 debug_area_first = rc;
269 rc->prev = NULL;
270 } else {
271 /* append element to end of list */
272 debug_area_last->next = rc;
273 rc->prev = debug_area_last;
274 }
275 debug_area_last = rc;
276 rc->next = NULL;
277
278 debug_info_get(rc);
279out:
280 return rc;
281}
282
283/*
284 * debug_info_copy
285 * - copy debug-info
286 */
287
288static debug_info_t* debug_info_copy(debug_info_t* in)
289{
290 int i;
291 debug_info_t* rc;
292 rc = debug_info_alloc(in->name, in->page_order,
293 in->nr_areas, in->buf_size);
294 if(!rc)
295 goto out;
296
297 for(i = 0; i < in->nr_areas; i++){
298 memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order);
299 }
300out:
301 return rc;
302}
303
304/*
305 * debug_info_get
306 * - increments reference count for debug-info
307 */
308
309static void debug_info_get(debug_info_t * db_info)
310{
311 if (db_info)
312 atomic_inc(&db_info->ref_count);
313}
314
315/*
316 * debug_info_put:
317 * - decreases reference count for debug-info and frees it if necessary
318 */
319
320static void debug_info_put(debug_info_t *db_info)
321{
322 int i;
323
324 if (!db_info)
325 return;
326 if (atomic_dec_and_test(&db_info->ref_count)) {
327#ifdef DEBUG
328 printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
329 db_info, db_info->name);
330#endif
331 for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
332 if (db_info->views[i] == NULL)
333 continue;
334#ifdef CONFIG_PROC_FS
335 remove_proc_entry(db_info->proc_entries[i]->name,
336 db_info->proc_root_entry);
337#endif
338 }
339#ifdef CONFIG_PROC_FS
340 remove_proc_entry(db_info->proc_root_entry->name,
341 debug_proc_root_entry);
342#endif
343 if(db_info == debug_area_first)
344 debug_area_first = db_info->next;
345 if(db_info == debug_area_last)
346 debug_area_last = db_info->prev;
347 if(db_info->prev) db_info->prev->next = db_info->next;
348 if(db_info->next) db_info->next->prev = db_info->prev;
349 debug_info_free(db_info);
350 }
351}
352
353/*
354 * debug_format_entry:
355 * - format one debug entry and return size of formated data
356 */
357
358static int debug_format_entry(file_private_info_t *p_info)
359{
360 debug_info_t *id_org = p_info->debug_info_org;
361 debug_info_t *id_snap = p_info->debug_info_snap;
362 struct debug_view *view = p_info->view;
363 debug_entry_t *act_entry;
364 size_t len = 0;
365 if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
366 /* print prolog */
367 if (view->prolog_proc)
368 len += view->prolog_proc(id_org, view,p_info->temp_buf);
369 goto out;
370 }
371
372 act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] +
373 p_info->act_entry);
374
375 if (act_entry->id.stck == 0LL)
376 goto out; /* empty entry */
377 if (view->header_proc)
378 len += view->header_proc(id_org, view, p_info->act_area,
379 act_entry, p_info->temp_buf + len);
380 if (view->format_proc)
381 len += view->format_proc(id_org, view, p_info->temp_buf + len,
382 DEBUG_DATA(act_entry));
383 out:
384 return len;
385}
386
387/*
388 * debug_next_entry:
389 * - goto next entry in p_info
390 */
391
392extern inline int debug_next_entry(file_private_info_t *p_info)
393{
394 debug_info_t *id = p_info->debug_info_snap;
395 if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
396 p_info->act_entry = 0;
397 goto out;
398 }
399 if ((p_info->act_entry += id->entry_size)
400 > ((PAGE_SIZE << (id->page_order))
401 - id->entry_size)){
402
403 /* next area */
404 p_info->act_entry = 0;
405 p_info->act_area++;
406 if(p_info->act_area >= id->nr_areas)
407 return 1;
408 }
409out:
410 return 0;
411}
412
413/*
414 * debug_output:
415 * - called for user read()
416 * - copies formated debug entries to the user buffer
417 */
418
419static ssize_t debug_output(struct file *file, /* file descriptor */
420 char __user *user_buf, /* user buffer */
421 size_t len, /* length of buffer */
422 loff_t *offset) /* offset in the file */
423{
424 size_t count = 0;
425 size_t entry_offset, size = 0;
426 file_private_info_t *p_info;
427
428 p_info = ((file_private_info_t *) file->private_data);
429 if (*offset != p_info->offset)
430 return -EPIPE;
431 if(p_info->act_area >= p_info->debug_info_snap->nr_areas)
432 return 0;
433
434 entry_offset = p_info->act_entry_offset;
435
436 while(count < len){
437 size = debug_format_entry(p_info);
438 size = min((len - count), (size - entry_offset));
439
440 if(size){
441 if (copy_to_user(user_buf + count,
442 p_info->temp_buf + entry_offset, size))
443 return -EFAULT;
444 }
445 count += size;
446 entry_offset = 0;
447 if(count != len)
448 if(debug_next_entry(p_info))
449 goto out;
450 }
451out:
452 p_info->offset = *offset + count;
453 p_info->act_entry_offset = size;
454 *offset = p_info->offset;
455 return count;
456}
457
458/*
459 * debug_input:
460 * - called for user write()
461 * - calls input function of view
462 */
463
464static ssize_t debug_input(struct file *file,
465 const char __user *user_buf, size_t length,
466 loff_t *offset)
467{
468 int rc = 0;
469 file_private_info_t *p_info;
470
471 down(&debug_lock);
472 p_info = ((file_private_info_t *) file->private_data);
473 if (p_info->view->input_proc)
474 rc = p_info->view->input_proc(p_info->debug_info_org,
475 p_info->view, file, user_buf,
476 length, offset);
477 else
478 rc = -EPERM;
479 up(&debug_lock);
480 return rc; /* number of input characters */
481}
482
483/*
484 * debug_open:
485 * - called for user open()
486 * - copies formated output to private_data area of the file
487 * handle
488 */
489
490static int debug_open(struct inode *inode, struct file *file)
491{
492 int i = 0, rc = 0;
493 file_private_info_t *p_info;
494 debug_info_t *debug_info, *debug_info_snapshot;
495
496#ifdef DEBUG
497 printk("debug_open\n");
498#endif
499 down(&debug_lock);
500
501 /* find debug log and view */
502
503 debug_info = debug_area_first;
504 while(debug_info != NULL){
505 for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
506 if (debug_info->views[i] == NULL)
507 continue;
508 else if (debug_info->proc_entries[i] ==
509 PDE(file->f_dentry->d_inode)) {
510 goto found; /* found view ! */
511 }
512 }
513 debug_info = debug_info->next;
514 }
515 /* no entry found */
516 rc = -EINVAL;
517 goto out;
518
519 found:
520
521 /* make snapshot of current debug areas to get it consistent */
522
523 debug_info_snapshot = debug_info_copy(debug_info);
524
525 if(!debug_info_snapshot){
526#ifdef DEBUG
527 printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n");
528#endif
529 rc = -ENOMEM;
530 goto out;
531 }
532
533 if ((file->private_data =
534 kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
535#ifdef DEBUG
536 printk(KERN_ERR "debug_open: kmalloc failed\n");
537#endif
538 debug_info_free(debug_info_snapshot);
539 rc = -ENOMEM;
540 goto out;
541 }
542 p_info = (file_private_info_t *) file->private_data;
543 p_info->offset = 0;
544 p_info->debug_info_snap = debug_info_snapshot;
545 p_info->debug_info_org = debug_info;
546 p_info->view = debug_info->views[i];
547 p_info->act_area = 0;
548 p_info->act_entry = DEBUG_PROLOG_ENTRY;
549 p_info->act_entry_offset = 0;
550
551 debug_info_get(debug_info);
552
553 out:
554 up(&debug_lock);
555 return rc;
556}
557
558/*
559 * debug_close:
560 * - called for user close()
561 * - deletes private_data area of the file handle
562 */
563
564static int debug_close(struct inode *inode, struct file *file)
565{
566 file_private_info_t *p_info;
567#ifdef DEBUG
568 printk("debug_close\n");
569#endif
570 p_info = (file_private_info_t *) file->private_data;
571 debug_info_free(p_info->debug_info_snap);
572 debug_info_put(p_info->debug_info_org);
573 kfree(file->private_data);
574 return 0; /* success */
575}
576
577/*
578 * debug_register:
579 * - creates and initializes debug area for the caller
580 * - returns handle for debug area
581 */
582
583debug_info_t *debug_register
584 (char *name, int page_order, int nr_areas, int buf_size)
585{
586 debug_info_t *rc = NULL;
587
588 if (!initialized)
589 BUG();
590 down(&debug_lock);
591
592 /* create new debug_info */
593
594 rc = debug_info_create(name, page_order, nr_areas, buf_size);
595 if(!rc)
596 goto out;
597 debug_register_view(rc, &debug_level_view);
598 debug_register_view(rc, &debug_flush_view);
599#ifdef DEBUG
600 printk(KERN_INFO
601 "debug: reserved %d areas of %d pages for debugging %s\n",
602 nr_areas, 1 << page_order, rc->name);
603#endif
604 out:
605 if (rc == NULL){
606 printk(KERN_ERR "debug: debug_register failed for %s\n",name);
607 }
608 up(&debug_lock);
609 return rc;
610}
611
612/*
613 * debug_unregister:
614 * - give back debug area
615 */
616
617void debug_unregister(debug_info_t * id)
618{
619 if (!id)
620 goto out;
621 down(&debug_lock);
622#ifdef DEBUG
623 printk(KERN_INFO "debug: unregistering %s\n", id->name);
624#endif
625 debug_info_put(id);
626 up(&debug_lock);
627
628 out:
629 return;
630}
631
632/*
633 * debug_set_level:
634 * - set actual debug level
635 */
636
637void debug_set_level(debug_info_t* id, int new_level)
638{
639 unsigned long flags;
640 if(!id)
641 return;
642 spin_lock_irqsave(&id->lock,flags);
643 if(new_level == DEBUG_OFF_LEVEL){
644 id->level = DEBUG_OFF_LEVEL;
645 printk(KERN_INFO "debug: %s: switched off\n",id->name);
646 } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
647 printk(KERN_INFO
648 "debug: %s: level %i is out of range (%i - %i)\n",
649 id->name, new_level, 0, DEBUG_MAX_LEVEL);
650 } else {
651 id->level = new_level;
652#ifdef DEBUG
653 printk(KERN_INFO
654 "debug: %s: new level %i\n",id->name,id->level);
655#endif
656 }
657 spin_unlock_irqrestore(&id->lock,flags);
658}
659
660
661/*
662 * proceed_active_entry:
663 * - set active entry to next in the ring buffer
664 */
665
666extern inline void proceed_active_entry(debug_info_t * id)
667{
668 if ((id->active_entry[id->active_area] += id->entry_size)
669 > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
670 id->active_entry[id->active_area] = 0;
671}
672
673/*
674 * proceed_active_area:
675 * - set active area to next in the ring buffer
676 */
677
678extern inline void proceed_active_area(debug_info_t * id)
679{
680 id->active_area++;
681 id->active_area = id->active_area % id->nr_areas;
682}
683
684/*
685 * get_active_entry:
686 */
687
688extern inline debug_entry_t *get_active_entry(debug_info_t * id)
689{
690 return (debug_entry_t *) ((char *) id->areas[id->active_area] +
691 id->active_entry[id->active_area]);
692}
693
694/*
695 * debug_finish_entry:
696 * - set timestamp, caller address, cpu number etc.
697 */
698
699extern inline void debug_finish_entry(debug_info_t * id, debug_entry_t* active,
700 int level, int exception)
701{
702 STCK(active->id.stck);
703 active->id.fields.cpuid = smp_processor_id();
704 active->caller = __builtin_return_address(0);
705 active->id.fields.exception = exception;
706 active->id.fields.level = level;
707 proceed_active_entry(id);
708 if(exception)
709 proceed_active_area(id);
710}
711
712static int debug_stoppable=1;
713static int debug_active=1;
714
715#define CTL_S390DBF 5677
716#define CTL_S390DBF_STOPPABLE 5678
717#define CTL_S390DBF_ACTIVE 5679
718
719/*
720 * proc handler for the running debug_active sysctl
721 * always allow read, allow write only if debug_stoppable is set or
722 * if debug_active is already off
723 */
724static int s390dbf_procactive(ctl_table *table, int write, struct file *filp,
725 void __user *buffer, size_t *lenp, loff_t *ppos)
726{
727 if (!write || debug_stoppable || !debug_active)
728 return proc_dointvec(table, write, filp, buffer, lenp, ppos);
729 else
730 return 0;
731}
732
733
734static struct ctl_table s390dbf_table[] = {
735 {
736 .ctl_name = CTL_S390DBF_STOPPABLE,
737 .procname = "debug_stoppable",
738 .data = &debug_stoppable,
739 .maxlen = sizeof(int),
740 .mode = S_IRUGO | S_IWUSR,
741 .proc_handler = &proc_dointvec,
742 .strategy = &sysctl_intvec,
743 },
744 {
745 .ctl_name = CTL_S390DBF_ACTIVE,
746 .procname = "debug_active",
747 .data = &debug_active,
748 .maxlen = sizeof(int),
749 .mode = S_IRUGO | S_IWUSR,
750 .proc_handler = &s390dbf_procactive,
751 .strategy = &sysctl_intvec,
752 },
753 { .ctl_name = 0 }
754};
755
756static struct ctl_table s390dbf_dir_table[] = {
757 {
758 .ctl_name = CTL_S390DBF,
759 .procname = "s390dbf",
760 .maxlen = 0,
761 .mode = S_IRUGO | S_IXUGO,
762 .child = s390dbf_table,
763 },
764 { .ctl_name = 0 }
765};
766
767struct ctl_table_header *s390dbf_sysctl_header;
768
769void debug_stop_all(void)
770{
771 if (debug_stoppable)
772 debug_active = 0;
773}
774
775
776/*
777 * debug_event_common:
778 * - write debug entry with given size
779 */
780
781debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf,
782 int len)
783{
784 unsigned long flags;
785 debug_entry_t *active;
786
787 if (!debug_active)
788 return NULL;
789 spin_lock_irqsave(&id->lock, flags);
790 active = get_active_entry(id);
791 memset(DEBUG_DATA(active), 0, id->buf_size);
792 memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
793 debug_finish_entry(id, active, level, 0);
794 spin_unlock_irqrestore(&id->lock, flags);
795
796 return active;
797}
798
799/*
800 * debug_exception_common:
801 * - write debug entry with given size and switch to next debug area
802 */
803
804debug_entry_t *debug_exception_common(debug_info_t * id, int level,
805 const void *buf, int len)
806{
807 unsigned long flags;
808 debug_entry_t *active;
809
810 if (!debug_active)
811 return NULL;
812 spin_lock_irqsave(&id->lock, flags);
813 active = get_active_entry(id);
814 memset(DEBUG_DATA(active), 0, id->buf_size);
815 memcpy(DEBUG_DATA(active), buf, min(len, id->buf_size));
816 debug_finish_entry(id, active, level, 1);
817 spin_unlock_irqrestore(&id->lock, flags);
818
819 return active;
820}
821
822/*
823 * counts arguments in format string for sprintf view
824 */
825
826extern inline int debug_count_numargs(char *string)
827{
828 int numargs=0;
829
830 while(*string) {
831 if(*string++=='%')
832 numargs++;
833 }
834 return(numargs);
835}
836
837/*
838 * debug_sprintf_event:
839 */
840
841debug_entry_t *debug_sprintf_event(debug_info_t* id,
842 int level,char *string,...)
843{
844 va_list ap;
845 int numargs,idx;
846 unsigned long flags;
847 debug_sprintf_entry_t *curr_event;
848 debug_entry_t *active;
849
850 if((!id) || (level > id->level))
851 return NULL;
852 if (!debug_active)
853 return NULL;
854 numargs=debug_count_numargs(string);
855
856 spin_lock_irqsave(&id->lock, flags);
857 active = get_active_entry(id);
858 curr_event=(debug_sprintf_entry_t *) DEBUG_DATA(active);
859 va_start(ap,string);
860 curr_event->string=string;
861 for(idx=0;idx<min(numargs,(int)(id->buf_size / sizeof(long))-1);idx++)
862 curr_event->args[idx]=va_arg(ap,long);
863 va_end(ap);
864 debug_finish_entry(id, active, level, 0);
865 spin_unlock_irqrestore(&id->lock, flags);
866
867 return active;
868}
869
870/*
871 * debug_sprintf_exception:
872 */
873
874debug_entry_t *debug_sprintf_exception(debug_info_t* id,
875 int level,char *string,...)
876{
877 va_list ap;
878 int numargs,idx;
879 unsigned long flags;
880 debug_sprintf_entry_t *curr_event;
881 debug_entry_t *active;
882
883 if((!id) || (level > id->level))
884 return NULL;
885 if (!debug_active)
886 return NULL;
887
888 numargs=debug_count_numargs(string);
889
890 spin_lock_irqsave(&id->lock, flags);
891 active = get_active_entry(id);
892 curr_event=(debug_sprintf_entry_t *)DEBUG_DATA(active);
893 va_start(ap,string);
894 curr_event->string=string;
895 for(idx=0;idx<min(numargs,(int)(id->buf_size / sizeof(long))-1);idx++)
896 curr_event->args[idx]=va_arg(ap,long);
897 va_end(ap);
898 debug_finish_entry(id, active, level, 1);
899 spin_unlock_irqrestore(&id->lock, flags);
900
901 return active;
902}
903
904/*
905 * debug_init:
906 * - is called exactly once to initialize the debug feature
907 */
908
909static int __init debug_init(void)
910{
911 int rc = 0;
912
913 s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table, 1);
914 down(&debug_lock);
915#ifdef CONFIG_PROC_FS
916 debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
917#endif /* CONFIG_PROC_FS */
918 printk(KERN_INFO "debug: Initialization complete\n");
919 initialized = 1;
920 up(&debug_lock);
921
922 return rc;
923}
924
925/*
926 * debug_register_view:
927 */
928
929int debug_register_view(debug_info_t * id, struct debug_view *view)
930{
931 int rc = 0;
932 int i;
933 unsigned long flags;
934 mode_t mode = S_IFREG;
935 struct proc_dir_entry *pde;
936
937 if (!id)
938 goto out;
939 if (view->prolog_proc || view->format_proc || view->header_proc)
940 mode |= S_IRUSR;
941 if (view->input_proc)
942 mode |= S_IWUSR;
943 pde = create_proc_entry(view->name, mode, id->proc_root_entry);
944 if (!pde){
945 printk(KERN_WARNING "debug: create_proc_entry() failed! Cannot register view %s/%s\n", id->name,view->name);
946 rc = -1;
947 goto out;
948 }
949
950 spin_lock_irqsave(&id->lock, flags);
951 for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
952 if (id->views[i] == NULL)
953 break;
954 }
955 if (i == DEBUG_MAX_VIEWS) {
956 printk(KERN_WARNING "debug: cannot register view %s/%s\n",
957 id->name,view->name);
958 printk(KERN_WARNING
959 "debug: maximum number of views reached (%i)!\n", i);
960 remove_proc_entry(pde->name, id->proc_root_entry);
961 rc = -1;
962 }
963 else {
964 id->views[i] = view;
965 pde->proc_fops = &debug_file_ops;
966 id->proc_entries[i] = pde;
967 }
968 spin_unlock_irqrestore(&id->lock, flags);
969 out:
970 return rc;
971}
972
973/*
974 * debug_unregister_view:
975 */
976
977int debug_unregister_view(debug_info_t * id, struct debug_view *view)
978{
979 int rc = 0;
980 int i;
981 unsigned long flags;
982
983 if (!id)
984 goto out;
985 spin_lock_irqsave(&id->lock, flags);
986 for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
987 if (id->views[i] == view)
988 break;
989 }
990 if (i == DEBUG_MAX_VIEWS)
991 rc = -1;
992 else {
993#ifdef CONFIG_PROC_FS
994 remove_proc_entry(id->proc_entries[i]->name,
995 id->proc_root_entry);
996#endif
997 id->views[i] = NULL;
998 rc = 0;
999 }
1000 spin_unlock_irqrestore(&id->lock, flags);
1001 out:
1002 return rc;
1003}
1004
1005/*
1006 * functions for debug-views
1007 ***********************************
1008*/
1009
1010/*
1011 * prints out actual debug level
1012 */
1013
1014static int debug_prolog_level_fn(debug_info_t * id,
1015 struct debug_view *view, char *out_buf)
1016{
1017 int rc = 0;
1018
1019 if(id->level == -1) rc = sprintf(out_buf,"-\n");
1020 else rc = sprintf(out_buf, "%i\n", id->level);
1021 return rc;
1022}
1023
1024/*
1025 * reads new debug level
1026 */
1027
1028static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
1029 struct file *file, const char __user *user_buf,
1030 size_t in_buf_size, loff_t * offset)
1031{
1032 char input_buf[1];
1033 int rc = in_buf_size;
1034
1035 if (*offset != 0)
1036 goto out;
1037 if (copy_from_user(input_buf, user_buf, 1)){
1038 rc = -EFAULT;
1039 goto out;
1040 }
1041 if (isdigit(input_buf[0])) {
1042 int new_level = ((int) input_buf[0] - (int) '0');
1043 debug_set_level(id, new_level);
1044 } else if(input_buf[0] == '-') {
1045 debug_set_level(id, DEBUG_OFF_LEVEL);
1046 } else {
1047 printk(KERN_INFO "debug: level `%c` is not valid\n",
1048 input_buf[0]);
1049 }
1050 out:
1051 *offset += in_buf_size;
1052 return rc; /* number of input characters */
1053}
1054
1055
1056/*
1057 * flushes debug areas
1058 */
1059
1060void debug_flush(debug_info_t* id, int area)
1061{
1062 unsigned long flags;
1063 int i;
1064
1065 if(!id)
1066 return;
1067 spin_lock_irqsave(&id->lock,flags);
1068 if(area == DEBUG_FLUSH_ALL){
1069 id->active_area = 0;
1070 memset(id->active_entry, 0, id->nr_areas * sizeof(int));
1071 for (i = 0; i < id->nr_areas; i++)
1072 memset(id->areas[i], 0, PAGE_SIZE << id->page_order);
1073 printk(KERN_INFO "debug: %s: all areas flushed\n",id->name);
1074 } else if(area >= 0 && area < id->nr_areas) {
1075 id->active_entry[area] = 0;
1076 memset(id->areas[area], 0, PAGE_SIZE << id->page_order);
1077 printk(KERN_INFO
1078 "debug: %s: area %i has been flushed\n",
1079 id->name, area);
1080 } else {
1081 printk(KERN_INFO
1082 "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
1083 id->name, area, 0, id->nr_areas-1);
1084 }
1085 spin_unlock_irqrestore(&id->lock,flags);
1086}
1087
1088/*
1089 * view function: flushes debug areas
1090 */
1091
1092static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
1093 struct file *file, const char __user *user_buf,
1094 size_t in_buf_size, loff_t * offset)
1095{
1096 char input_buf[1];
1097 int rc = in_buf_size;
1098
1099 if (*offset != 0)
1100 goto out;
1101 if (copy_from_user(input_buf, user_buf, 1)){
1102 rc = -EFAULT;
1103 goto out;
1104 }
1105 if(input_buf[0] == '-') {
1106 debug_flush(id, DEBUG_FLUSH_ALL);
1107 goto out;
1108 }
1109 if (isdigit(input_buf[0])) {
1110 int area = ((int) input_buf[0] - (int) '0');
1111 debug_flush(id, area);
1112 goto out;
1113 }
1114
1115 printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]);
1116
1117 out:
1118 *offset += in_buf_size;
1119 return rc; /* number of input characters */
1120}
1121
1122/*
1123 * prints debug header in raw format
1124 */
1125
1126int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
1127 int area, debug_entry_t * entry, char *out_buf)
1128{
1129 int rc;
1130
1131 rc = sizeof(debug_entry_t);
1132 memcpy(out_buf,entry,sizeof(debug_entry_t));
1133 return rc;
1134}
1135
1136/*
1137 * prints debug data in raw format
1138 */
1139
1140static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
1141 char *out_buf, const char *in_buf)
1142{
1143 int rc;
1144
1145 rc = id->buf_size;
1146 memcpy(out_buf, in_buf, id->buf_size);
1147 return rc;
1148}
1149
1150/*
1151 * prints debug data in hex/ascii format
1152 */
1153
1154static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
1155 char *out_buf, const char *in_buf)
1156{
1157 int i, rc = 0;
1158
1159 for (i = 0; i < id->buf_size; i++) {
1160 rc += sprintf(out_buf + rc, "%02x ",
1161 ((unsigned char *) in_buf)[i]);
1162 }
1163 rc += sprintf(out_buf + rc, "| ");
1164 for (i = 0; i < id->buf_size; i++) {
1165 unsigned char c = in_buf[i];
1166 if (!isprint(c))
1167 rc += sprintf(out_buf + rc, ".");
1168 else
1169 rc += sprintf(out_buf + rc, "%c", c);
1170 }
1171 rc += sprintf(out_buf + rc, "\n");
1172 return rc;
1173}
1174
1175/*
1176 * prints header for debug entry
1177 */
1178
1179int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
1180 int area, debug_entry_t * entry, char *out_buf)
1181{
1182 struct timeval time_val;
1183 unsigned long long time;
1184 char *except_str;
1185 unsigned long caller;
1186 int rc = 0;
1187 unsigned int level;
1188
1189 level = entry->id.fields.level;
1190 time = entry->id.stck;
1191 /* adjust todclock to 1970 */
1192 time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
1193 tod_to_timeval(time, &time_val);
1194
1195 if (entry->id.fields.exception)
1196 except_str = "*";
1197 else
1198 except_str = "-";
1199 caller = ((unsigned long) entry->caller) & PSW_ADDR_INSN;
1200 rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %p ",
1201 area, time_val.tv_sec, time_val.tv_usec, level,
1202 except_str, entry->id.fields.cpuid, (void *) caller);
1203 return rc;
1204}
1205
1206/*
1207 * prints debug data sprintf-formated:
1208 * debug_sprinf_event/exception calls must be used together with this view
1209 */
1210
1211#define DEBUG_SPRINTF_MAX_ARGS 10
1212
1213int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
1214 char *out_buf, debug_sprintf_entry_t *curr_event)
1215{
1216 int num_longs, num_used_args = 0,i, rc = 0;
1217 int index[DEBUG_SPRINTF_MAX_ARGS];
1218
1219 /* count of longs fit into one entry */
1220 num_longs = id->buf_size / sizeof(long);
1221
1222 if(num_longs < 1)
1223 goto out; /* bufsize of entry too small */
1224 if(num_longs == 1) {
1225 /* no args, we use only the string */
1226 strcpy(out_buf, curr_event->string);
1227 rc = strlen(curr_event->string);
1228 goto out;
1229 }
1230
1231 /* number of arguments used for sprintf (without the format string) */
1232 num_used_args = min(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1));
1233
1234 memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int));
1235
1236 for(i = 0; i < num_used_args; i++)
1237 index[i] = i;
1238
1239 rc = sprintf(out_buf, curr_event->string, curr_event->args[index[0]],
1240 curr_event->args[index[1]], curr_event->args[index[2]],
1241 curr_event->args[index[3]], curr_event->args[index[4]],
1242 curr_event->args[index[5]], curr_event->args[index[6]],
1243 curr_event->args[index[7]], curr_event->args[index[8]],
1244 curr_event->args[index[9]]);
1245
1246out:
1247
1248 return rc;
1249}
1250
1251/*
1252 * clean up module
1253 */
1254void __exit debug_exit(void)
1255{
1256#ifdef DEBUG
1257 printk("debug_cleanup_module: \n");
1258#endif
1259#ifdef CONFIG_PROC_FS
1260 remove_proc_entry(debug_proc_root_entry->name, NULL);
1261#endif /* CONFIG_PROC_FS */
1262 unregister_sysctl_table(s390dbf_sysctl_header);
1263 return;
1264}
1265
1266/*
1267 * module definitions
1268 */
1269core_initcall(debug_init);
1270module_exit(debug_exit);
1271MODULE_LICENSE("GPL");
1272
1273EXPORT_SYMBOL(debug_register);
1274EXPORT_SYMBOL(debug_unregister);
1275EXPORT_SYMBOL(debug_set_level);
1276EXPORT_SYMBOL(debug_stop_all);
1277EXPORT_SYMBOL(debug_register_view);
1278EXPORT_SYMBOL(debug_unregister_view);
1279EXPORT_SYMBOL(debug_event_common);
1280EXPORT_SYMBOL(debug_exception_common);
1281EXPORT_SYMBOL(debug_hex_ascii_view);
1282EXPORT_SYMBOL(debug_raw_view);
1283EXPORT_SYMBOL(debug_dflt_header_fn);
1284EXPORT_SYMBOL(debug_sprintf_view);
1285EXPORT_SYMBOL(debug_sprintf_exception);
1286EXPORT_SYMBOL(debug_sprintf_event);
diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c
new file mode 100644
index 000000000000..bb0f973137f0
--- /dev/null
+++ b/arch/s390/kernel/ebcdic.c
@@ -0,0 +1,400 @@
1/*
2 * arch/s390/kernel/ebcdic.c
3 * ECBDIC -> ASCII, ASCII -> ECBDIC,
4 * upper to lower case (EBCDIC) conversion tables.
5 *
6 * S390 version
7 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
8 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
9 * Martin Peschke <peschke@fh-brandenburg.de>
10 */
11
12#include <linux/module.h>
13#include <asm/types.h>
14
15/*
16 * ASCII (IBM PC 437) -> EBCDIC 037
17 */
18__u8 _ascebc[256] =
19{
20 /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
21 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
22 /*08 BS HT LF VT FF CR SO SI */
23 /* ->NL */
24 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
25 /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
26 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
27 /*18 CAN EM SUB ESC FS GS RS US */
28 /* ->IGS ->IRS ->IUS */
29 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
30 /*20 SP ! " # $ % & ' */
31 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
32 /*28 ( ) * + , - . / */
33 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
34 /*30 0 1 2 3 4 5 6 7 */
35 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
36 /*38 8 9 : ; < = > ? */
37 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
38 /*40 @ A B C D E F G */
39 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
40 /*48 H I J K L M N O */
41 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
42 /*50 P Q R S T U V W */
43 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
44 /*58 X Y Z [ \ ] ^ _ */
45 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
46 /*60 ` a b c d e f g */
47 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
48 /*68 h i j k l m n o */
49 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
50 /*70 p q r s t u v w */
51 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
52 /*78 x y z { | } ~ DL */
53 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
54 /*80*/
55 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
56 /*88*/
57 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
58 /*90*/
59 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
60 /*98*/
61 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
62 /*A0*/
63 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
64 /*A8*/
65 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
66 /*B0*/
67 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
68 /*B8*/
69 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
70 /*C0*/
71 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
72 /*C8*/
73 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
74 /*D0*/
75 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
76 /*D8*/
77 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
78 /*E0 sz */
79 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
80 /*E8*/
81 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
82 /*F0*/
83 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
84 /*F8*/
85 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
86};
87
88/*
89 * EBCDIC 037 -> ASCII (IBM PC 437)
90 */
91__u8 _ebcasc[256] =
92{
93 /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
94 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
95 /* 0x08 -GE -SPS -RPT VT FF CR SO SI */
96 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
97 /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
98 -ENP ->LF */
99 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
100 /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
101 -IUS */
102 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
103 /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
104 -INP */
105 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
106 /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
107 -SW */
108 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
109 /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
110 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
111 /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
112 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
113 /* 0x40 SP RSP ä ---- */
114 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
115 /* 0x48 . < ( + | */
116 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
117 /* 0x50 & ---- */
118 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
119 /* 0x58 ß ! $ * ) ; */
120 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
121 /* 0x60 - / ---- Ä ---- ---- ---- */
122 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
123 /* 0x68 ---- , % _ > ? */
124 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
125 /* 0x70 ---- ---- ---- ---- ---- ---- ---- */
126 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
127 /* 0x78 * ` : # @ ' = " */
128 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
129 /* 0x80 * a b c d e f g */
130 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
131 /* 0x88 h i ---- ---- ---- */
132 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
133 /* 0x90 ° j k l m n o p */
134 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
135 /* 0x98 q r ---- ---- */
136 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
137 /* 0xA0 ~ s t u v w x */
138 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
139 /* 0xA8 y z ---- ---- ---- ---- */
140 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
141 /* 0xB0 ^ ---- § ---- */
142 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
143 /* 0xB8 ---- [ ] ---- ---- ---- ---- */
144 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
145 /* 0xC0 { A B C D E F G */
146 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
147 /* 0xC8 H I ---- ö ---- */
148 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
149 /* 0xD0 } J K L M N O P */
150 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
151 /* 0xD8 Q R ---- ü */
152 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
153 /* 0xE0 \ S T U V W X */
154 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
155 /* 0xE8 Y Z ---- Ö ---- ---- ---- */
156 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
157 /* 0xF0 0 1 2 3 4 5 6 7 */
158 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
159 /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
160 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
161};
162
163
164/*
165 * ASCII (IBM PC 437) -> EBCDIC 500
166 */
167__u8 _ascebc_500[256] =
168{
169 /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
170 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
171 /*08 BS HT LF VT FF CR SO SI */
172 /* ->NL */
173 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
174 /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
175 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
176 /*18 CAN EM SUB ESC FS GS RS US */
177 /* ->IGS ->IRS ->IUS */
178 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
179 /*20 SP ! " # $ % & ' */
180 0x40, 0x4F, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
181 /*28 ( ) * + , - . / */
182 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
183 /*30 0 1 2 3 4 5 6 7 */
184 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
185 /*38 8 9 : ; < = > ? */
186 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
187 /*40 @ A B C D E F G */
188 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
189 /*48 H I J K L M N O */
190 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
191 /*50 P Q R S T U V W */
192 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
193 /*58 X Y Z [ \ ] ^ _ */
194 0xE7, 0xE8, 0xE9, 0x4A, 0xE0, 0x5A, 0x5F, 0x6D,
195 /*60 ` a b c d e f g */
196 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
197 /*68 h i j k l m n o */
198 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
199 /*70 p q r s t u v w */
200 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
201 /*78 x y z { | } ~ DL */
202 0xA7, 0xA8, 0xA9, 0xC0, 0xBB, 0xD0, 0xA1, 0x07,
203 /*80*/
204 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
205 /*88*/
206 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
207 /*90*/
208 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
209 /*98*/
210 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
211 /*A0*/
212 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
213 /*A8*/
214 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
215 /*B0*/
216 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
217 /*B8*/
218 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
219 /*C0*/
220 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
221 /*C8*/
222 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
223 /*D0*/
224 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
225 /*D8*/
226 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
227 /*E0 sz */
228 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
229 /*E8*/
230 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
231 /*F0*/
232 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
233 /*F8*/
234 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
235};
236
237/*
238 * EBCDIC 500 -> ASCII (IBM PC 437)
239 */
240__u8 _ebcasc_500[256] =
241{
242 /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
243 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
244 /* 0x08 -GE -SPS -RPT VT FF CR SO SI */
245 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
246 /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
247 -ENP ->LF */
248 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
249 /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
250 -IUS */
251 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
252 /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
253 -INP */
254 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
255 /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
256 -SW */
257 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
258 /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
259 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
260 /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
261 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
262 /* 0x40 SP RSP ä ---- */
263 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
264 /* 0x48 [ . < ( + ! */
265 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
266 /* 0x50 & ---- */
267 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
268 /* 0x58 ß ] $ * ) ; ^ */
269 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
270 /* 0x60 - / ---- Ä ---- ---- ---- */
271 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
272 /* 0x68 ---- , % _ > ? */
273 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
274 /* 0x70 ---- ---- ---- ---- ---- ---- ---- */
275 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
276 /* 0x78 * ` : # @ ' = " */
277 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
278 /* 0x80 * a b c d e f g */
279 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
280 /* 0x88 h i ---- ---- ---- */
281 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
282 /* 0x90 ° j k l m n o p */
283 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
284 /* 0x98 q r ---- ---- */
285 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
286 /* 0xA0 ~ s t u v w x */
287 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
288 /* 0xA8 y z ---- ---- ---- ---- */
289 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
290 /* 0xB0 ---- § ---- */
291 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
292 /* 0xB8 ---- | ---- ---- ---- ---- */
293 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
294 /* 0xC0 { A B C D E F G */
295 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
296 /* 0xC8 H I ---- ö ---- */
297 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
298 /* 0xD0 } J K L M N O P */
299 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
300 /* 0xD8 Q R ---- ü */
301 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
302 /* 0xE0 \ S T U V W X */
303 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
304 /* 0xE8 Y Z ---- Ö ---- ---- ---- */
305 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
306 /* 0xF0 0 1 2 3 4 5 6 7 */
307 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
308 /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
309 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
310};
311
312
313/*
314 * EBCDIC 037/500 conversion table:
315 * from upper to lower case
316 */
317__u8 _ebc_tolower[256] =
318{
319 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
320 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
321 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
322 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
323 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
324 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
325 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
326 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
327 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
328 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
329 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
330 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
331 0x60, 0x61, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
332 0x48, 0x49, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
333 0x70, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
334 0x58, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
335 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
336 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
337 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
338 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9C, 0x9F,
339 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
340 0xA8, 0xA9, 0xAA, 0xAB, 0x8C, 0x8D, 0x8E, 0xAF,
341 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
342 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
343 0xC0, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
344 0x88, 0x89, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
345 0xD0, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
346 0x98, 0x99, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
347 0xE0, 0xE1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
348 0xA8, 0xA9, 0xEA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
349 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
350 0xF8, 0xF9, 0xFA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF
351};
352
353
354/*
355 * EBCDIC 037/500 conversion table:
356 * from lower to upper case
357 */
358__u8 _ebc_toupper[256] =
359{
360 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
361 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
362 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
363 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
364 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
365 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
366 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
367 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
368 0x40, 0x41, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
369 0x68, 0x69, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
370 0x50, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
371 0x78, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
372 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
373 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
374 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
375 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
376 0x80, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
377 0xC8, 0xC9, 0x8A, 0x8B, 0xAC, 0xAD, 0xAE, 0x8F,
378 0x90, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
379 0xD8, 0xD9, 0x9A, 0x9B, 0x9E, 0x9D, 0x9E, 0x9F,
380 0xA0, 0xA1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
381 0xE8, 0xE9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
382 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
383 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
384 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
385 0xC8, 0xC9, 0xCA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
386 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
387 0xD8, 0xD9, 0xDA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF,
388 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
389 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
390 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
391 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
392};
393
394EXPORT_SYMBOL(_ascebc_500);
395EXPORT_SYMBOL(_ebcasc_500);
396EXPORT_SYMBOL(_ascebc);
397EXPORT_SYMBOL(_ebcasc);
398EXPORT_SYMBOL(_ebc_tolower);
399EXPORT_SYMBOL(_ebc_toupper);
400
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
new file mode 100644
index 000000000000..c0e09b33febe
--- /dev/null
+++ b/arch/s390/kernel/entry.S
@@ -0,0 +1,868 @@
1/*
2 * arch/s390/kernel/entry.S
3 * S390 low-level entry points.
4 *
5 * S390 version
6 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
8 * Hartmut Penner (hp@de.ibm.com),
9 * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
10 */
11
12#include <linux/sys.h>
13#include <linux/linkage.h>
14#include <linux/config.h>
15#include <asm/cache.h>
16#include <asm/lowcore.h>
17#include <asm/errno.h>
18#include <asm/ptrace.h>
19#include <asm/thread_info.h>
20#include <asm/offsets.h>
21#include <asm/unistd.h>
22#include <asm/page.h>
23
24/*
25 * Stack layout for the system_call stack entry.
26 * The first few entries are identical to the user_regs_struct.
27 */
28SP_PTREGS = STACK_FRAME_OVERHEAD
29SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
30SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
31SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
32SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4
33SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
34SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 12
35SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
36SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 20
37SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
38SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 28
39SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
40SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 36
41SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
42SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 44
43SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
44SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52
45SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
46SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60
47SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
48SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
49SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
50SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
51
52_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
53 _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
54_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
55
56STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
57STACK_SIZE = 1 << STACK_SHIFT
58
59#define BASED(name) name-system_call(%r13)
60
61/*
62 * Register usage in interrupt handlers:
63 * R9 - pointer to current task structure
64 * R13 - pointer to literal pool
65 * R14 - return register for function calls
66 * R15 - kernel stack pointer
67 */
68
69 .macro STORE_TIMER lc_offset
70#ifdef CONFIG_VIRT_CPU_ACCOUNTING
71 stpt \lc_offset
72#endif
73 .endm
74
75#ifdef CONFIG_VIRT_CPU_ACCOUNTING
76 .macro UPDATE_VTIME lc_from,lc_to,lc_sum
77 lm %r10,%r11,\lc_from
78 sl %r10,\lc_to
79 sl %r11,\lc_to+4
80 bc 3,BASED(0f)
81 sl %r10,BASED(.Lc_1)
820: al %r10,\lc_sum
83 al %r11,\lc_sum+4
84 bc 12,BASED(1f)
85 al %r10,BASED(.Lc_1)
861: stm %r10,%r11,\lc_sum
87 .endm
88#endif
89
90 .macro SAVE_ALL_BASE savearea
91 stm %r12,%r15,\savearea
92 l %r13,__LC_SVC_NEW_PSW+4 # load &system_call to %r13
93 .endm
94
95 .macro SAVE_ALL psworg,savearea,sync
96 la %r12,\psworg
97 .if \sync
98 tm \psworg+1,0x01 # test problem state bit
99 bz BASED(2f) # skip stack setup save
100 l %r15,__LC_KERNEL_STACK # problem state -> load ksp
101 .else
102 tm \psworg+1,0x01 # test problem state bit
103 bnz BASED(1f) # from user -> load async stack
104 clc \psworg+4(4),BASED(.Lcritical_end)
105 bhe BASED(0f)
106 clc \psworg+4(4),BASED(.Lcritical_start)
107 bl BASED(0f)
108 l %r14,BASED(.Lcleanup_critical)
109 basr %r14,%r14
110 tm 0(%r12),0x01 # retest problem state after cleanup
111 bnz BASED(1f)
1120: l %r14,__LC_ASYNC_STACK # are we already on the async stack ?
113 slr %r14,%r15
114 sra %r14,STACK_SHIFT
115 be BASED(2f)
1161: l %r15,__LC_ASYNC_STACK
117 .endif
118#ifdef CONFIG_CHECK_STACK
119 b BASED(3f)
1202: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD
121 bz BASED(stack_overflow)
1223:
123#endif
1242: s %r15,BASED(.Lc_spsize) # make room for registers & psw
125 mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack
126 la %r12,\psworg
127 st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
128 icm %r12,12,__LC_SVC_ILC
129 stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
130 st %r12,SP_ILC(%r15)
131 mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack
132 la %r12,0
133 st %r12,__SF_BACKCHAIN(%r15) # clear back chain
134 .endm
135
136 .macro RESTORE_ALL sync
137 mvc __LC_RETURN_PSW(8),SP_PSW(%r15) # move user PSW to lowcore
138 .if !\sync
139 ni __LC_RETURN_PSW+1,0xfd # clear wait state bit
140 .endif
141 lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user
142 STORE_TIMER __LC_EXIT_TIMER
143 lpsw __LC_RETURN_PSW # back to caller
144 .endm
145
146/*
147 * Scheduler resume function, called by switch_to
148 * gpr2 = (task_struct *) prev
149 * gpr3 = (task_struct *) next
150 * Returns:
151 * gpr2 = prev
152 */
153 .globl __switch_to
154__switch_to:
155 basr %r1,0
156__switch_to_base:
157 tm __THREAD_per(%r3),0xe8 # new process is using per ?
158 bz __switch_to_noper-__switch_to_base(%r1) # if not we're fine
159 stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff
160 clc __THREAD_per(12,%r3),__SF_EMPTY(%r15)
161 be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's
162 lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't
163__switch_to_noper:
164 stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
165 st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
166 l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
167 lm %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
168 st %r3,__LC_CURRENT # __LC_CURRENT = current task struct
169 lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
170 l %r3,__THREAD_info(%r3) # load thread_info from task struct
171 st %r3,__LC_THREAD_INFO
172 ahi %r3,STACK_SIZE
173 st %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
174 br %r14
175
176__critical_start:
177/*
178 * SVC interrupt handler routine. System calls are synchronous events and
179 * are executed with interrupts enabled.
180 */
181
182 .globl system_call
183system_call:
184 STORE_TIMER __LC_SYNC_ENTER_TIMER
185sysc_saveall:
186 SAVE_ALL_BASE __LC_SAVE_AREA
187 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
188 lh %r7,0x8a # get svc number from lowcore
189#ifdef CONFIG_VIRT_CPU_ACCOUNTING
190sysc_vtime:
191 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
192 bz BASED(sysc_do_svc)
193 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
194sysc_stime:
195 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
196sysc_update:
197 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
198#endif
199sysc_do_svc:
200 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
201 sla %r7,2 # *4 and test for svc 0
202 bnz BASED(sysc_nr_ok) # svc number > 0
203 # svc 0: system call number in %r1
204 cl %r1,BASED(.Lnr_syscalls)
205 bnl BASED(sysc_nr_ok)
206 lr %r7,%r1 # copy svc number to %r7
207 sla %r7,2 # *4
208sysc_nr_ok:
209 mvc SP_ARGS(4,%r15),SP_R7(%r15)
210sysc_do_restart:
211 tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
212 l %r8,sys_call_table-system_call(%r7,%r13) # get system call addr.
213 bnz BASED(sysc_tracesys)
214 basr %r14,%r8 # call sys_xxxx
215 st %r2,SP_R2(%r15) # store return value (change R2 on stack)
216 # ATTENTION: check sys_execve_glue before
217 # changing anything here !!
218
219sysc_return:
220 tm SP_PSW+1(%r15),0x01 # returning to user ?
221 bno BASED(sysc_leave)
222 tm __TI_flags+3(%r9),_TIF_WORK_SVC
223 bnz BASED(sysc_work) # there is work to do (signals etc.)
224sysc_leave:
225 RESTORE_ALL 1
226
227#
228# recheck if there is more work to do
229#
230sysc_work_loop:
231 tm __TI_flags+3(%r9),_TIF_WORK_SVC
232 bz BASED(sysc_leave) # there is no work to do
233#
234# One of the work bits is on. Find out which one.
235#
236sysc_work:
237 tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
238 bo BASED(sysc_reschedule)
239 tm __TI_flags+3(%r9),_TIF_SIGPENDING
240 bo BASED(sysc_sigpending)
241 tm __TI_flags+3(%r9),_TIF_RESTART_SVC
242 bo BASED(sysc_restart)
243 tm __TI_flags+3(%r9),_TIF_SINGLE_STEP
244 bo BASED(sysc_singlestep)
245 b BASED(sysc_leave)
246
247#
248# _TIF_NEED_RESCHED is set, call schedule
249#
250sysc_reschedule:
251 l %r1,BASED(.Lschedule)
252 la %r14,BASED(sysc_work_loop)
253 br %r1 # call scheduler
254
255#
256# _TIF_SIGPENDING is set, call do_signal
257#
258sysc_sigpending:
259 ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
260 la %r2,SP_PTREGS(%r15) # load pt_regs
261 sr %r3,%r3 # clear *oldset
262 l %r1,BASED(.Ldo_signal)
263 basr %r14,%r1 # call do_signal
264 tm __TI_flags+3(%r9),_TIF_RESTART_SVC
265 bo BASED(sysc_restart)
266 tm __TI_flags+3(%r9),_TIF_SINGLE_STEP
267 bo BASED(sysc_singlestep)
268 b BASED(sysc_leave) # out of here, do NOT recheck
269
270#
271# _TIF_RESTART_SVC is set, set up registers and restart svc
272#
273sysc_restart:
274 ni __TI_flags+3(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
275 l %r7,SP_R2(%r15) # load new svc number
276 sla %r7,2
277 mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
278 lm %r2,%r6,SP_R2(%r15) # load svc arguments
279 b BASED(sysc_do_restart) # restart svc
280
281#
282# _TIF_SINGLE_STEP is set, call do_single_step
283#
284sysc_singlestep:
285 ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
286 mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check
287 la %r2,SP_PTREGS(%r15) # address of register-save area
288 l %r1,BASED(.Lhandle_per) # load adr. of per handler
289 la %r14,BASED(sysc_return) # load adr. of system return
290 br %r1 # branch to do_single_step
291
292__critical_end:
293
294#
295# call trace before and after sys_call
296#
297sysc_tracesys:
298 l %r1,BASED(.Ltrace)
299 la %r2,SP_PTREGS(%r15) # load pt_regs
300 la %r3,0
301 srl %r7,2
302 st %r7,SP_R2(%r15)
303 basr %r14,%r1
304 clc SP_R2(4,%r15),BASED(.Lnr_syscalls)
305 bnl BASED(sysc_tracenogo)
306 l %r7,SP_R2(%r15) # strace might have changed the
307 sll %r7,2 # system call
308 l %r8,sys_call_table-system_call(%r7,%r13)
309sysc_tracego:
310 lm %r3,%r6,SP_R3(%r15)
311 l %r2,SP_ORIG_R2(%r15)
312 basr %r14,%r8 # call sys_xxx
313 st %r2,SP_R2(%r15) # store return value
314sysc_tracenogo:
315 tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
316 bz BASED(sysc_return)
317 l %r1,BASED(.Ltrace)
318 la %r2,SP_PTREGS(%r15) # load pt_regs
319 la %r3,1
320 la %r14,BASED(sysc_return)
321 br %r1
322
323#
324# a new process exits the kernel with ret_from_fork
325#
326 .globl ret_from_fork
327ret_from_fork:
328 l %r13,__LC_SVC_NEW_PSW+4
329 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
330 tm SP_PSW+1(%r15),0x01 # forking a kernel thread ?
331 bo BASED(0f)
332 st %r15,SP_R15(%r15) # store stack pointer for new kthread
3330: l %r1,BASED(.Lschedtail)
334 basr %r14,%r1
335 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
336 b BASED(sysc_return)
337
338#
339# clone, fork, vfork, exec and sigreturn need glue,
340# because they all expect pt_regs as parameter,
341# but are called with different parameter.
342# return-address is set up above
343#
344sys_clone_glue:
345 la %r2,SP_PTREGS(%r15) # load pt_regs
346 l %r1,BASED(.Lclone)
347 br %r1 # branch to sys_clone
348
349sys_fork_glue:
350 la %r2,SP_PTREGS(%r15) # load pt_regs
351 l %r1,BASED(.Lfork)
352 br %r1 # branch to sys_fork
353
354sys_vfork_glue:
355 la %r2,SP_PTREGS(%r15) # load pt_regs
356 l %r1,BASED(.Lvfork)
357 br %r1 # branch to sys_vfork
358
359sys_execve_glue:
360 la %r2,SP_PTREGS(%r15) # load pt_regs
361 l %r1,BASED(.Lexecve)
362 lr %r12,%r14 # save return address
363 basr %r14,%r1 # call sys_execve
364 ltr %r2,%r2 # check if execve failed
365 bnz 0(%r12) # it did fail -> store result in gpr2
366 b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8
367 # in system_call/sysc_tracesys
368
369sys_sigreturn_glue:
370 la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
371 l %r1,BASED(.Lsigreturn)
372 br %r1 # branch to sys_sigreturn
373
374sys_rt_sigreturn_glue:
375 la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
376 l %r1,BASED(.Lrt_sigreturn)
377 br %r1 # branch to sys_sigreturn
378
379#
380# sigsuspend and rt_sigsuspend need pt_regs as an additional
381# parameter and they have to skip the store of %r2 into the
382# user register %r2 because the return value was set in
383# sigsuspend and rt_sigsuspend already and must not be overwritten!
384#
385
386sys_sigsuspend_glue:
387 lr %r5,%r4 # move mask back
388 lr %r4,%r3 # move history1 parameter
389 lr %r3,%r2 # move history0 parameter
390 la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
391 l %r1,BASED(.Lsigsuspend)
392 la %r14,4(%r14) # skip store of return value
393 br %r1 # branch to sys_sigsuspend
394
395sys_rt_sigsuspend_glue:
396 lr %r4,%r3 # move sigsetsize parameter
397 lr %r3,%r2 # move unewset parameter
398 la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
399 l %r1,BASED(.Lrt_sigsuspend)
400 la %r14,4(%r14) # skip store of return value
401 br %r1 # branch to sys_rt_sigsuspend
402
403sys_sigaltstack_glue:
404 la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
405 l %r1,BASED(.Lsigaltstack)
406 br %r1 # branch to sys_sigreturn
407
408
409/*
410 * Program check handler routine
411 */
412
413 .globl pgm_check_handler
414pgm_check_handler:
415/*
416 * First we need to check for a special case:
417 * Single stepping an instruction that disables the PER event mask will
418 * cause a PER event AFTER the mask has been set. Example: SVC or LPSW.
419 * For a single stepped SVC the program check handler gets control after
420 * the SVC new PSW has been loaded. But we want to execute the SVC first and
421 * then handle the PER event. Therefore we update the SVC old PSW to point
422 * to the pgm_check_handler and branch to the SVC handler after we checked
423 * if we have to load the kernel stack register.
424 * For every other possible cause for PER event without the PER mask set
425 * we just ignore the PER event (FIXME: is there anything we have to do
426 * for LPSW?).
427 */
428 STORE_TIMER __LC_SYNC_ENTER_TIMER
429 SAVE_ALL_BASE __LC_SAVE_AREA
430 tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
431 bnz BASED(pgm_per) # got per exception -> special case
432 SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
433#ifdef CONFIG_VIRT_CPU_ACCOUNTING
434 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
435 bz BASED(pgm_no_vtime)
436 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
437 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
438 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
439pgm_no_vtime:
440#endif
441 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
442 l %r3,__LC_PGM_ILC # load program interruption code
443 la %r8,0x7f
444 nr %r8,%r3
445pgm_do_call:
446 l %r7,BASED(.Ljump_table)
447 sll %r8,2
448 l %r7,0(%r8,%r7) # load address of handler routine
449 la %r2,SP_PTREGS(%r15) # address of register-save area
450 la %r14,BASED(sysc_return)
451 br %r7 # branch to interrupt-handler
452
453#
454# handle per exception
455#
456pgm_per:
457 tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
458 bnz BASED(pgm_per_std) # ok, normal per event from user space
459# ok its one of the special cases, now we need to find out which one
460 clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
461 be BASED(pgm_svcper)
462# no interesting special case, ignore PER event
463 lm %r12,%r15,__LC_SAVE_AREA
464 lpsw 0x28
465
466#
467# Normal per exception
468#
469pgm_per_std:
470 SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
471#ifdef CONFIG_VIRT_CPU_ACCOUNTING
472 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
473 bz BASED(pgm_no_vtime2)
474 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
475 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
476 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
477pgm_no_vtime2:
478#endif
479 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
480 l %r1,__TI_task(%r9)
481 mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
482 mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
483 mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
484 oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
485 l %r3,__LC_PGM_ILC # load program interruption code
486 la %r8,0x7f
487 nr %r8,%r3 # clear per-event-bit and ilc
488 be BASED(sysc_return) # only per or per+check ?
489 b BASED(pgm_do_call)
490
491#
492# it was a single stepped SVC that is causing all the trouble
493#
494pgm_svcper:
495 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
496#ifdef CONFIG_VIRT_CPU_ACCOUNTING
497 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
498 bz BASED(pgm_no_vtime3)
499 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
500 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
501 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
502pgm_no_vtime3:
503#endif
504 lh %r7,0x8a # get svc number from lowcore
505 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
506 l %r1,__TI_task(%r9)
507 mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
508 mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
509 mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
510 oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
511 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
512 b BASED(sysc_do_svc)
513
514/*
515 * IO interrupt handler routine
516 */
517
518 .globl io_int_handler
519io_int_handler:
520 STORE_TIMER __LC_ASYNC_ENTER_TIMER
521 stck __LC_INT_CLOCK
522 SAVE_ALL_BASE __LC_SAVE_AREA+16
523 SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
524#ifdef CONFIG_VIRT_CPU_ACCOUNTING
525 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
526 bz BASED(io_no_vtime)
527 UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
528 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
529 mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
530io_no_vtime:
531#endif
532 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
533 l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ
534 la %r2,SP_PTREGS(%r15) # address of register-save area
535 basr %r14,%r1 # branch to standard irq handler
536
537io_return:
538 tm SP_PSW+1(%r15),0x01 # returning to user ?
539#ifdef CONFIG_PREEMPT
540 bno BASED(io_preempt) # no -> check for preemptive scheduling
541#else
542 bno BASED(io_leave) # no-> skip resched & signal
543#endif
544 tm __TI_flags+3(%r9),_TIF_WORK_INT
545 bnz BASED(io_work) # there is work to do (signals etc.)
546io_leave:
547 RESTORE_ALL 0
548
549#ifdef CONFIG_PREEMPT
550io_preempt:
551 icm %r0,15,__TI_precount(%r9)
552 bnz BASED(io_leave)
553 l %r1,SP_R15(%r15)
554 s %r1,BASED(.Lc_spsize)
555 mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
556 xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
557 lr %r15,%r1
558io_resume_loop:
559 tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
560 bno BASED(io_leave)
561 mvc __TI_precount(4,%r9),BASED(.Lc_pactive)
562 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
563 l %r1,BASED(.Lschedule)
564 basr %r14,%r1 # call schedule
565 stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
566 xc __TI_precount(4,%r9),__TI_precount(%r9)
567 b BASED(io_resume_loop)
568#endif
569
570#
571# switch to kernel stack, then check the TIF bits
572#
573io_work:
574 l %r1,__LC_KERNEL_STACK
575 s %r1,BASED(.Lc_spsize)
576 mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
577 xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
578 lr %r15,%r1
579#
580# One of the work bits is on. Find out which one.
581# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
582#
583io_work_loop:
584 tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
585 bo BASED(io_reschedule)
586 tm __TI_flags+3(%r9),_TIF_SIGPENDING
587 bo BASED(io_sigpending)
588 b BASED(io_leave)
589
590#
591# _TIF_NEED_RESCHED is set, call schedule
592#
593io_reschedule:
594 l %r1,BASED(.Lschedule)
595 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
596 basr %r14,%r1 # call scheduler
597 stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
598 tm __TI_flags+3(%r9),_TIF_WORK_INT
599 bz BASED(io_leave) # there is no work to do
600 b BASED(io_work_loop)
601
602#
603# _TIF_SIGPENDING is set, call do_signal
604#
605io_sigpending:
606 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
607 la %r2,SP_PTREGS(%r15) # load pt_regs
608 sr %r3,%r3 # clear *oldset
609 l %r1,BASED(.Ldo_signal)
610 basr %r14,%r1 # call do_signal
611 stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
612 b BASED(io_leave) # out of here, do NOT recheck
613
614/*
615 * External interrupt handler routine
616 */
617
618 .globl ext_int_handler
619ext_int_handler:
620 STORE_TIMER __LC_ASYNC_ENTER_TIMER
621 stck __LC_INT_CLOCK
622 SAVE_ALL_BASE __LC_SAVE_AREA+16
623 SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
624#ifdef CONFIG_VIRT_CPU_ACCOUNTING
625 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
626 bz BASED(ext_no_vtime)
627 UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
628 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
629 mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
630ext_no_vtime:
631#endif
632 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
633 la %r2,SP_PTREGS(%r15) # address of register-save area
634 lh %r3,__LC_EXT_INT_CODE # get interruption code
635 l %r1,BASED(.Ldo_extint)
636 basr %r14,%r1
637 b BASED(io_return)
638
639/*
640 * Machine check handler routines
641 */
642
643 .globl mcck_int_handler
644mcck_int_handler:
645 STORE_TIMER __LC_ASYNC_ENTER_TIMER
646 SAVE_ALL_BASE __LC_SAVE_AREA+32
647 SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0
648#ifdef CONFIG_VIRT_CPU_ACCOUNTING
649 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
650 bz BASED(mcck_no_vtime)
651 UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
652 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
653 mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
654mcck_no_vtime:
655#endif
656 l %r1,BASED(.Ls390_mcck)
657 basr %r14,%r1 # call machine check handler
658mcck_return:
659 RESTORE_ALL 0
660
661#ifdef CONFIG_SMP
662/*
663 * Restart interruption handler, kick starter for additional CPUs
664 */
665 .globl restart_int_handler
666restart_int_handler:
667 l %r15,__LC_SAVE_AREA+60 # load ksp
668 lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
669 lam %a0,%a15,__LC_AREGS_SAVE_AREA
670 lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone
671 stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
672 basr %r14,0
673 l %r14,restart_addr-.(%r14)
674 br %r14 # branch to start_secondary
675restart_addr:
676 .long start_secondary
677#else
678/*
679 * If we do not run with SMP enabled, let the new CPU crash ...
680 */
681 .globl restart_int_handler
682restart_int_handler:
683 basr %r1,0
684restart_base:
685 lpsw restart_crash-restart_base(%r1)
686 .align 8
687restart_crash:
688 .long 0x000a0000,0x00000000
689restart_go:
690#endif
691
692#ifdef CONFIG_CHECK_STACK
693/*
694 * The synchronous or the asynchronous stack overflowed. We are dead.
695 * No need to properly save the registers, we are going to panic anyway.
696 * Setup a pt_regs so that show_trace can provide a good call trace.
697 */
698stack_overflow:
699 l %r15,__LC_PANIC_STACK # change to panic stack
700 sl %r15,BASED(.Lc_spsize)
701 mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack
702 stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
703 la %r1,__LC_SAVE_AREA
704 ch %r12,BASED(.L0x020) # old psw addr == __LC_SVC_OLD_PSW ?
705 be BASED(0f)
706 ch %r12,BASED(.L0x028) # old psw addr == __LC_PGM_OLD_PSW ?
707 be BASED(0f)
708 la %r1,__LC_SAVE_AREA+16
7090: mvc SP_R12(16,%r15),0(%r1) # move %r12-%r15 to stack
710 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain
711 l %r1,BASED(1f) # branch to kernel_stack_overflow
712 la %r2,SP_PTREGS(%r15) # load pt_regs
713 br %r1
7141: .long kernel_stack_overflow
715#endif
716
717cleanup_table_system_call:
718 .long system_call + 0x80000000, sysc_do_svc + 0x80000000
719cleanup_table_sysc_return:
720 .long sysc_return + 0x80000000, sysc_leave + 0x80000000
721cleanup_table_sysc_leave:
722 .long sysc_leave + 0x80000000, sysc_work_loop + 0x80000000
723cleanup_table_sysc_work_loop:
724 .long sysc_work_loop + 0x80000000, sysc_reschedule + 0x80000000
725
726cleanup_critical:
727 clc 4(4,%r12),BASED(cleanup_table_system_call)
728 bl BASED(0f)
729 clc 4(4,%r12),BASED(cleanup_table_system_call+4)
730 bl BASED(cleanup_system_call)
7310:
732 clc 4(4,%r12),BASED(cleanup_table_sysc_return)
733 bl BASED(0f)
734 clc 4(4,%r12),BASED(cleanup_table_sysc_return+4)
735 bl BASED(cleanup_sysc_return)
7360:
737 clc 4(4,%r12),BASED(cleanup_table_sysc_leave)
738 bl BASED(0f)
739 clc 4(4,%r12),BASED(cleanup_table_sysc_leave+4)
740 bl BASED(cleanup_sysc_leave)
7410:
742 clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop)
743 bl BASED(0f)
744 clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
745 bl BASED(cleanup_sysc_leave)
7460:
747 br %r14
748
749cleanup_system_call:
750 mvc __LC_RETURN_PSW(8),0(%r12)
751#ifdef CONFIG_VIRT_CPU_ACCOUNTING
752 clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4)
753 bh BASED(0f)
754 mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER
7550: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8)
756 bhe BASED(cleanup_vtime)
757#endif
758 clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn)
759 bh BASED(0f)
760 mvc __LC_SAVE_AREA(16),__LC_SAVE_AREA+16
7610: st %r13,__LC_SAVE_AREA+20
762 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
763 st %r15,__LC_SAVE_AREA+28
764 lh %r7,0x8a
765#ifdef CONFIG_VIRT_CPU_ACCOUNTING
766cleanup_vtime:
767 clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12)
768 bhe BASED(cleanup_stime)
769 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
770 bz BASED(cleanup_novtime)
771 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
772cleanup_stime:
773 clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+16)
774 bh BASED(cleanup_update)
775 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
776cleanup_update:
777 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
778cleanup_novtime:
779#endif
780 mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_system_call+4)
781 la %r12,__LC_RETURN_PSW
782 br %r14
783cleanup_system_call_insn:
784 .long sysc_saveall + 0x80000000
785#ifdef CONFIG_VIRT_CPU_ACCOUNTING
786 .long system_call + 0x80000000
787 .long sysc_vtime + 0x80000000
788 .long sysc_stime + 0x80000000
789 .long sysc_update + 0x80000000
790#endif
791
792cleanup_sysc_return:
793 mvc __LC_RETURN_PSW(4),0(%r12)
794 mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_sysc_return)
795 la %r12,__LC_RETURN_PSW
796 br %r14
797
798cleanup_sysc_leave:
799 clc 4(4,%r12),BASED(cleanup_sysc_leave_insn)
800 be BASED(0f)
801#ifdef CONFIG_VIRT_CPU_ACCOUNTING
802 mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
803 clc 4(4,%r12),BASED(cleanup_sysc_leave_insn+4)
804 be BASED(0f)
805#endif
806 mvc __LC_RETURN_PSW(8),SP_PSW(%r15)
807 mvc __LC_SAVE_AREA+16(16),SP_R12(%r15)
808 lm %r0,%r11,SP_R0(%r15)
809 l %r15,SP_R15(%r15)
8100: la %r12,__LC_RETURN_PSW
811 br %r14
812cleanup_sysc_leave_insn:
813#ifdef CONFIG_VIRT_CPU_ACCOUNTING
814 .long sysc_leave + 14 + 0x80000000
815#endif
816 .long sysc_leave + 10 + 0x80000000
817
818/*
819 * Integer constants
820 */
821 .align 4
822.Lc_spsize: .long SP_SIZE
823.Lc_overhead: .long STACK_FRAME_OVERHEAD
824.Lc_pactive: .long PREEMPT_ACTIVE
825.Lnr_syscalls: .long NR_syscalls
826.L0x018: .short 0x018
827.L0x020: .short 0x020
828.L0x028: .short 0x028
829.L0x030: .short 0x030
830.L0x038: .short 0x038
831.Lc_1: .long 1
832
833/*
834 * Symbol constants
835 */
836.Ls390_mcck: .long s390_do_machine_check
837.Ldo_IRQ: .long do_IRQ
838.Ldo_extint: .long do_extint
839.Ldo_signal: .long do_signal
840.Lhandle_per: .long do_single_step
841.Ljump_table: .long pgm_check_table
842.Lschedule: .long schedule
843.Lclone: .long sys_clone
844.Lexecve: .long sys_execve
845.Lfork: .long sys_fork
846.Lrt_sigreturn:.long sys_rt_sigreturn
847.Lrt_sigsuspend:
848 .long sys_rt_sigsuspend
849.Lsigreturn: .long sys_sigreturn
850.Lsigsuspend: .long sys_sigsuspend
851.Lsigaltstack: .long sys_sigaltstack
852.Ltrace: .long syscall_trace
853.Lvfork: .long sys_vfork
854.Lschedtail: .long schedule_tail
855
856.Lcritical_start:
857 .long __critical_start + 0x80000000
858.Lcritical_end:
859 .long __critical_end + 0x80000000
860.Lcleanup_critical:
861 .long cleanup_critical
862
863#define SYSCALL(esa,esame,emu) .long esa
864 .globl sys_call_table
865sys_call_table:
866#include "syscalls.S"
867#undef SYSCALL
868
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
new file mode 100644
index 000000000000..51527ab8c8f9
--- /dev/null
+++ b/arch/s390/kernel/entry64.S
@@ -0,0 +1,881 @@
1/*
2 * arch/s390/kernel/entry.S
3 * S390 low-level entry points.
4 *
5 * S390 version
6 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
8 * Hartmut Penner (hp@de.ibm.com),
9 * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
10 */
11
12#include <linux/sys.h>
13#include <linux/linkage.h>
14#include <linux/config.h>
15#include <asm/cache.h>
16#include <asm/lowcore.h>
17#include <asm/errno.h>
18#include <asm/ptrace.h>
19#include <asm/thread_info.h>
20#include <asm/offsets.h>
21#include <asm/unistd.h>
22#include <asm/page.h>
23
24/*
25 * Stack layout for the system_call stack entry.
26 * The first few entries are identical to the user_regs_struct.
27 */
28SP_PTREGS = STACK_FRAME_OVERHEAD
29SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
30SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
31SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
32SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
33SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
34SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
35SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
36SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
37SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
38SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
39SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 64
40SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 72
41SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 80
42SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 88
43SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 96
44SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104
45SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112
46SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120
47SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
48SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
49SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
50SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
51
52STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
53STACK_SIZE = 1 << STACK_SHIFT
54
55_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
56 _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
57_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
58
59#define BASED(name) name-system_call(%r13)
60
61 .macro STORE_TIMER lc_offset
62#ifdef CONFIG_VIRT_CPU_ACCOUNTING
63 stpt \lc_offset
64#endif
65 .endm
66
67#ifdef CONFIG_VIRT_CPU_ACCOUNTING
68 .macro UPDATE_VTIME lc_from,lc_to,lc_sum
69 lg %r10,\lc_from
70 slg %r10,\lc_to
71 alg %r10,\lc_sum
72 stg %r10,\lc_sum
73 .endm
74#endif
75
76/*
77 * Register usage in interrupt handlers:
78 * R9 - pointer to current task structure
79 * R13 - pointer to literal pool
80 * R14 - return register for function calls
81 * R15 - kernel stack pointer
82 */
83
84 .macro SAVE_ALL_BASE savearea
85 stmg %r12,%r15,\savearea
86 larl %r13,system_call
87 .endm
88
89 .macro SAVE_ALL psworg,savearea,sync
90 la %r12,\psworg
91 .if \sync
92 tm \psworg+1,0x01 # test problem state bit
93 jz 2f # skip stack setup save
94 lg %r15,__LC_KERNEL_STACK # problem state -> load ksp
95 .else
96 tm \psworg+1,0x01 # test problem state bit
97 jnz 1f # from user -> load kernel stack
98 clc \psworg+8(8),BASED(.Lcritical_end)
99 jhe 0f
100 clc \psworg+8(8),BASED(.Lcritical_start)
101 jl 0f
102 brasl %r14,cleanup_critical
103 tm 0(%r12),0x01 # retest problem state after cleanup
104 jnz 1f
1050: lg %r14,__LC_ASYNC_STACK # are we already on the async. stack ?
106 slgr %r14,%r15
107 srag %r14,%r14,STACK_SHIFT
108 jz 2f
1091: lg %r15,__LC_ASYNC_STACK # load async stack
110 .endif
111#ifdef CONFIG_CHECK_STACK
112 j 3f
1132: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD
114 jz stack_overflow
1153:
116#endif
1172: aghi %r15,-SP_SIZE # make room for registers & psw
118 mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
119 la %r12,\psworg
120 stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
121 icm %r12,12,__LC_SVC_ILC
122 stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
123 st %r12,SP_ILC(%r15)
124 mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack
125 la %r12,0
126 stg %r12,__SF_BACKCHAIN(%r15)
127 .endm
128
129 .macro RESTORE_ALL sync
130 mvc __LC_RETURN_PSW(16),SP_PSW(%r15) # move user PSW to lowcore
131 .if !\sync
132 ni __LC_RETURN_PSW+1,0xfd # clear wait state bit
133 .endif
134 lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 of user
135 STORE_TIMER __LC_EXIT_TIMER
136 lpswe __LC_RETURN_PSW # back to caller
137 .endm
138
139/*
140 * Scheduler resume function, called by switch_to
141 * gpr2 = (task_struct *) prev
142 * gpr3 = (task_struct *) next
143 * Returns:
144 * gpr2 = prev
145 */
146 .globl __switch_to
147__switch_to:
148 tm __THREAD_per+4(%r3),0xe8 # is the new process using per ?
149 jz __switch_to_noper # if not we're fine
150 stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff
151 clc __THREAD_per(24,%r3),__SF_EMPTY(%r15)
152 je __switch_to_noper # we got away without bashing TLB's
153 lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't
154__switch_to_noper:
155 stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
156 stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
157 lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
158 lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
159 stg %r3,__LC_CURRENT # __LC_CURRENT = current task struct
160 lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
161 lg %r3,__THREAD_info(%r3) # load thread_info from task struct
162 stg %r3,__LC_THREAD_INFO
163 aghi %r3,STACK_SIZE
164 stg %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
165 br %r14
166
167__critical_start:
168/*
169 * SVC interrupt handler routine. System calls are synchronous events and
170 * are executed with interrupts enabled.
171 */
172
173 .globl system_call
174system_call:
175 STORE_TIMER __LC_SYNC_ENTER_TIMER
176sysc_saveall:
177 SAVE_ALL_BASE __LC_SAVE_AREA
178 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
179 llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
180#ifdef CONFIG_VIRT_CPU_ACCOUNTING
181sysc_vtime:
182 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
183 jz sysc_do_svc
184 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
185sysc_stime:
186 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
187sysc_update:
188 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
189#endif
190sysc_do_svc:
191 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
192 slag %r7,%r7,2 # *4 and test for svc 0
193 jnz sysc_nr_ok
194 # svc 0: system call number in %r1
195 cl %r1,BASED(.Lnr_syscalls)
196 jnl sysc_nr_ok
197 lgfr %r7,%r1 # clear high word in r1
198 slag %r7,%r7,2 # svc 0: system call number in %r1
199sysc_nr_ok:
200 mvc SP_ARGS(8,%r15),SP_R7(%r15)
201sysc_do_restart:
202 larl %r10,sys_call_table
203#ifdef CONFIG_S390_SUPPORT
204 tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ?
205 jo sysc_noemu
206 larl %r10,sys_call_table_emu # use 31 bit emulation system calls
207sysc_noemu:
208#endif
209 tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
210 lgf %r8,0(%r7,%r10) # load address of system call routine
211 jnz sysc_tracesys
212 basr %r14,%r8 # call sys_xxxx
213 stg %r2,SP_R2(%r15) # store return value (change R2 on stack)
214 # ATTENTION: check sys_execve_glue before
215 # changing anything here !!
216
217sysc_return:
218 tm SP_PSW+1(%r15),0x01 # returning to user ?
219 jno sysc_leave
220 tm __TI_flags+7(%r9),_TIF_WORK_SVC
221 jnz sysc_work # there is work to do (signals etc.)
222sysc_leave:
223 RESTORE_ALL 1
224
225#
226# recheck if there is more work to do
227#
228sysc_work_loop:
229 tm __TI_flags+7(%r9),_TIF_WORK_SVC
230 jz sysc_leave # there is no work to do
231#
232# One of the work bits is on. Find out which one.
233#
234sysc_work:
235 tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
236 jo sysc_reschedule
237 tm __TI_flags+7(%r9),_TIF_SIGPENDING
238 jo sysc_sigpending
239 tm __TI_flags+7(%r9),_TIF_RESTART_SVC
240 jo sysc_restart
241 tm __TI_flags+7(%r9),_TIF_SINGLE_STEP
242 jo sysc_singlestep
243 j sysc_leave
244
245#
246# _TIF_NEED_RESCHED is set, call schedule
247#
248sysc_reschedule:
249 larl %r14,sysc_work_loop
250 jg schedule # return point is sysc_return
251
252#
253# _TIF_SIGPENDING is set, call do_signal
254#
255sysc_sigpending:
256 ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
257 la %r2,SP_PTREGS(%r15) # load pt_regs
258 sgr %r3,%r3 # clear *oldset
259 brasl %r14,do_signal # call do_signal
260 tm __TI_flags+7(%r9),_TIF_RESTART_SVC
261 jo sysc_restart
262 tm __TI_flags+7(%r9),_TIF_SINGLE_STEP
263 jo sysc_singlestep
264 j sysc_leave # out of here, do NOT recheck
265
266#
267# _TIF_RESTART_SVC is set, set up registers and restart svc
268#
269sysc_restart:
270 ni __TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
271 lg %r7,SP_R2(%r15) # load new svc number
272 slag %r7,%r7,2 # *4
273 mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument
274 lmg %r2,%r6,SP_R2(%r15) # load svc arguments
275 j sysc_do_restart # restart svc
276
277#
278# _TIF_SINGLE_STEP is set, call do_single_step
279#
280sysc_singlestep:
281 ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
282 lhi %r0,__LC_PGM_OLD_PSW
283 sth %r0,SP_TRAP(%r15) # set trap indication to pgm check
284 la %r2,SP_PTREGS(%r15) # address of register-save area
285 larl %r14,sysc_return # load adr. of system return
286 jg do_single_step # branch to do_sigtrap
287
288
289__critical_end:
290
291#
292# call syscall_trace before and after system call
293# special linkage: %r12 contains the return address for trace_svc
294#
295sysc_tracesys:
296 la %r2,SP_PTREGS(%r15) # load pt_regs
297 la %r3,0
298 srl %r7,2
299 stg %r7,SP_R2(%r15)
300 brasl %r14,syscall_trace
301 lghi %r0,NR_syscalls
302 clg %r0,SP_R2(%r15)
303 jnh sysc_tracenogo
304 lg %r7,SP_R2(%r15) # strace might have changed the
305 sll %r7,2 # system call
306 lgf %r8,0(%r7,%r10)
307sysc_tracego:
308 lmg %r3,%r6,SP_R3(%r15)
309 lg %r2,SP_ORIG_R2(%r15)
310 basr %r14,%r8 # call sys_xxx
311 stg %r2,SP_R2(%r15) # store return value
312sysc_tracenogo:
313 tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
314 jz sysc_return
315 la %r2,SP_PTREGS(%r15) # load pt_regs
316 la %r3,1
317 larl %r14,sysc_return # return point is sysc_return
318 jg syscall_trace
319
320#
321# a new process exits the kernel with ret_from_fork
322#
323 .globl ret_from_fork
324ret_from_fork:
325 lg %r13,__LC_SVC_NEW_PSW+8
326 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
327 tm SP_PSW+1(%r15),0x01 # forking a kernel thread ?
328 jo 0f
329 stg %r15,SP_R15(%r15) # store stack pointer for new kthread
3300: brasl %r14,schedule_tail
331 stosm 24(%r15),0x03 # reenable interrupts
332 j sysc_return
333
334#
335# clone, fork, vfork, exec and sigreturn need glue,
336# because they all expect pt_regs as parameter,
337# but are called with different parameter.
338# return-address is set up above
339#
340sys_clone_glue:
341 la %r2,SP_PTREGS(%r15) # load pt_regs
342 jg sys_clone # branch to sys_clone
343
344#ifdef CONFIG_S390_SUPPORT
345sys32_clone_glue:
346 la %r2,SP_PTREGS(%r15) # load pt_regs
347 jg sys32_clone # branch to sys32_clone
348#endif
349
350sys_fork_glue:
351 la %r2,SP_PTREGS(%r15) # load pt_regs
352 jg sys_fork # branch to sys_fork
353
354sys_vfork_glue:
355 la %r2,SP_PTREGS(%r15) # load pt_regs
356 jg sys_vfork # branch to sys_vfork
357
358sys_execve_glue:
359 la %r2,SP_PTREGS(%r15) # load pt_regs
360 lgr %r12,%r14 # save return address
361 brasl %r14,sys_execve # call sys_execve
362 ltgr %r2,%r2 # check if execve failed
363 bnz 0(%r12) # it did fail -> store result in gpr2
364 b 6(%r12) # SKIP STG 2,SP_R2(15) in
365 # system_call/sysc_tracesys
366#ifdef CONFIG_S390_SUPPORT
367sys32_execve_glue:
368 la %r2,SP_PTREGS(%r15) # load pt_regs
369 lgr %r12,%r14 # save return address
370 brasl %r14,sys32_execve # call sys32_execve
371 ltgr %r2,%r2 # check if execve failed
372 bnz 0(%r12) # it did fail -> store result in gpr2
373 b 6(%r12) # SKIP STG 2,SP_R2(15) in
374 # system_call/sysc_tracesys
375#endif
376
377sys_sigreturn_glue:
378 la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
379 jg sys_sigreturn # branch to sys_sigreturn
380
381#ifdef CONFIG_S390_SUPPORT
382sys32_sigreturn_glue:
383 la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
384 jg sys32_sigreturn # branch to sys32_sigreturn
385#endif
386
387sys_rt_sigreturn_glue:
388 la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
389 jg sys_rt_sigreturn # branch to sys_sigreturn
390
391#ifdef CONFIG_S390_SUPPORT
392sys32_rt_sigreturn_glue:
393 la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
394 jg sys32_rt_sigreturn # branch to sys32_sigreturn
395#endif
396
397#
398# sigsuspend and rt_sigsuspend need pt_regs as an additional
399# parameter and they have to skip the store of %r2 into the
400# user register %r2 because the return value was set in
401# sigsuspend and rt_sigsuspend already and must not be overwritten!
402#
403
404sys_sigsuspend_glue:
405 lgr %r5,%r4 # move mask back
406 lgr %r4,%r3 # move history1 parameter
407 lgr %r3,%r2 # move history0 parameter
408 la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
409 la %r14,6(%r14) # skip store of return value
410 jg sys_sigsuspend # branch to sys_sigsuspend
411
412#ifdef CONFIG_S390_SUPPORT
413sys32_sigsuspend_glue:
414 llgfr %r4,%r4 # unsigned long
415 lgr %r5,%r4 # move mask back
416 lgfr %r3,%r3 # int
417 lgr %r4,%r3 # move history1 parameter
418 lgfr %r2,%r2 # int
419 lgr %r3,%r2 # move history0 parameter
420 la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
421 la %r14,6(%r14) # skip store of return value
422 jg sys32_sigsuspend # branch to sys32_sigsuspend
423#endif
424
425sys_rt_sigsuspend_glue:
426 lgr %r4,%r3 # move sigsetsize parameter
427 lgr %r3,%r2 # move unewset parameter
428 la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
429 la %r14,6(%r14) # skip store of return value
430 jg sys_rt_sigsuspend # branch to sys_rt_sigsuspend
431
432#ifdef CONFIG_S390_SUPPORT
433sys32_rt_sigsuspend_glue:
434 llgfr %r3,%r3 # size_t
435 lgr %r4,%r3 # move sigsetsize parameter
436 llgtr %r2,%r2 # sigset_emu31_t *
437 lgr %r3,%r2 # move unewset parameter
438 la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
439 la %r14,6(%r14) # skip store of return value
440 jg sys32_rt_sigsuspend # branch to sys32_rt_sigsuspend
441#endif
442
443sys_sigaltstack_glue:
444 la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
445 jg sys_sigaltstack # branch to sys_sigreturn
446
447#ifdef CONFIG_S390_SUPPORT
448sys32_sigaltstack_glue:
449 la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
450 jg sys32_sigaltstack_wrapper # branch to sys_sigreturn
451#endif
452
453/*
454 * Program check handler routine
455 */
456
457 .globl pgm_check_handler
458pgm_check_handler:
459/*
460 * First we need to check for a special case:
461 * Single stepping an instruction that disables the PER event mask will
462 * cause a PER event AFTER the mask has been set. Example: SVC or LPSW.
463 * For a single stepped SVC the program check handler gets control after
464 * the SVC new PSW has been loaded. But we want to execute the SVC first and
465 * then handle the PER event. Therefore we update the SVC old PSW to point
466 * to the pgm_check_handler and branch to the SVC handler after we checked
467 * if we have to load the kernel stack register.
468 * For every other possible cause for PER event without the PER mask set
469 * we just ignore the PER event (FIXME: is there anything we have to do
470 * for LPSW?).
471 */
472 STORE_TIMER __LC_SYNC_ENTER_TIMER
473 SAVE_ALL_BASE __LC_SAVE_AREA
474 tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
475 jnz pgm_per # got per exception -> special case
476 SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
477#ifdef CONFIG_VIRT_CPU_ACCOUNTING
478 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
479 jz pgm_no_vtime
480 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
481 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
482 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
483pgm_no_vtime:
484#endif
485 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
486 lgf %r3,__LC_PGM_ILC # load program interruption code
487 lghi %r8,0x7f
488 ngr %r8,%r3
489pgm_do_call:
490 sll %r8,3
491 larl %r1,pgm_check_table
492 lg %r1,0(%r8,%r1) # load address of handler routine
493 la %r2,SP_PTREGS(%r15) # address of register-save area
494 larl %r14,sysc_return
495 br %r1 # branch to interrupt-handler
496
497#
498# handle per exception
499#
500pgm_per:
501 tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
502 jnz pgm_per_std # ok, normal per event from user space
503# ok its one of the special cases, now we need to find out which one
504 clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
505 je pgm_svcper
506# no interesting special case, ignore PER event
507 lmg %r12,%r15,__LC_SAVE_AREA
508 lpswe __LC_PGM_OLD_PSW
509
510#
511# Normal per exception
512#
513pgm_per_std:
514 SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
515#ifdef CONFIG_VIRT_CPU_ACCOUNTING
516 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
517 jz pgm_no_vtime2
518 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
519 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
520 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
521pgm_no_vtime2:
522#endif
523 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
524 lg %r1,__TI_task(%r9)
525 mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
526 mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS
527 mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
528 oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
529 lgf %r3,__LC_PGM_ILC # load program interruption code
530 lghi %r8,0x7f
531 ngr %r8,%r3 # clear per-event-bit and ilc
532 je sysc_return
533 j pgm_do_call
534
535#
536# it was a single stepped SVC that is causing all the trouble
537#
538pgm_svcper:
539 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
540#ifdef CONFIG_VIRT_CPU_ACCOUNTING
541 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
542 jz pgm_no_vtime3
543 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
544 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
545 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
546pgm_no_vtime3:
547#endif
548 llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
549 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
550 lg %r1,__TI_task(%r9)
551 mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
552 mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS
553 mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
554 oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
555 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
556 j sysc_do_svc
557
558/*
559 * IO interrupt handler routine
560 */
561 .globl io_int_handler
562io_int_handler:
563 STORE_TIMER __LC_ASYNC_ENTER_TIMER
564 stck __LC_INT_CLOCK
565 SAVE_ALL_BASE __LC_SAVE_AREA+32
566 SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
567#ifdef CONFIG_VIRT_CPU_ACCOUNTING
568 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
569 jz io_no_vtime
570 UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
571 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
572 mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
573io_no_vtime:
574#endif
575 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
576 la %r2,SP_PTREGS(%r15) # address of register-save area
577 brasl %r14,do_IRQ # call standard irq handler
578
579io_return:
580 tm SP_PSW+1(%r15),0x01 # returning to user ?
581#ifdef CONFIG_PREEMPT
582 jno io_preempt # no -> check for preemptive scheduling
583#else
584 jno io_leave # no-> skip resched & signal
585#endif
586 tm __TI_flags+7(%r9),_TIF_WORK_INT
587 jnz io_work # there is work to do (signals etc.)
588io_leave:
589 RESTORE_ALL 0
590
591#ifdef CONFIG_PREEMPT
592io_preempt:
593 icm %r0,15,__TI_precount(%r9)
594 jnz io_leave
595 # switch to kernel stack
596 lg %r1,SP_R15(%r15)
597 aghi %r1,-SP_SIZE
598 mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
599 xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
600 lgr %r15,%r1
601io_resume_loop:
602 tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
603 jno io_leave
604 larl %r1,.Lc_pactive
605 mvc __TI_precount(4,%r9),0(%r1)
606 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
607 brasl %r14,schedule # call schedule
608 stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
609 xc __TI_precount(4,%r9),__TI_precount(%r9)
610 j io_resume_loop
611#endif
612
613#
614# switch to kernel stack, then check TIF bits
615#
616io_work:
617 lg %r1,__LC_KERNEL_STACK
618 aghi %r1,-SP_SIZE
619 mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
620 xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
621 lgr %r15,%r1
622#
623# One of the work bits is on. Find out which one.
624# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
625#
626io_work_loop:
627 tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
628 jo io_reschedule
629 tm __TI_flags+7(%r9),_TIF_SIGPENDING
630 jo io_sigpending
631 j io_leave
632
633#
634# _TIF_NEED_RESCHED is set, call schedule
635#
636io_reschedule:
637 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
638 brasl %r14,schedule # call scheduler
639 stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
640 tm __TI_flags+7(%r9),_TIF_WORK_INT
641 jz io_leave # there is no work to do
642 j io_work_loop
643
644#
645# _TIF_SIGPENDING is set, call do_signal
646#
647io_sigpending:
648 stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
649 la %r2,SP_PTREGS(%r15) # load pt_regs
650 slgr %r3,%r3 # clear *oldset
651 brasl %r14,do_signal # call do_signal
652 stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
653 j sysc_leave # out of here, do NOT recheck
654
655/*
656 * External interrupt handler routine
657 */
658 .globl ext_int_handler
659ext_int_handler:
660 STORE_TIMER __LC_ASYNC_ENTER_TIMER
661 stck __LC_INT_CLOCK
662 SAVE_ALL_BASE __LC_SAVE_AREA+32
663 SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
664#ifdef CONFIG_VIRT_CPU_ACCOUNTING
665 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
666 jz ext_no_vtime
667 UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
668 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
669 mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
670ext_no_vtime:
671#endif
672 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
673 la %r2,SP_PTREGS(%r15) # address of register-save area
674 llgh %r3,__LC_EXT_INT_CODE # get interruption code
675 brasl %r14,do_extint
676 j io_return
677
678/*
679 * Machine check handler routines
680 */
681 .globl mcck_int_handler
682mcck_int_handler:
683 STORE_TIMER __LC_ASYNC_ENTER_TIMER
684 SAVE_ALL_BASE __LC_SAVE_AREA+64
685 SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0
686#ifdef CONFIG_VIRT_CPU_ACCOUNTING
687 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
688 jz mcck_no_vtime
689 UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
690 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
691 mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
692mcck_no_vtime:
693#endif
694 brasl %r14,s390_do_machine_check
695mcck_return:
696 RESTORE_ALL 0
697
698#ifdef CONFIG_SMP
699/*
700 * Restart interruption handler, kick starter for additional CPUs
701 */
702 .globl restart_int_handler
703restart_int_handler:
704 lg %r15,__LC_SAVE_AREA+120 # load ksp
705 lghi %r10,__LC_CREGS_SAVE_AREA
706 lctlg %c0,%c15,0(%r10) # get new ctl regs
707 lghi %r10,__LC_AREGS_SAVE_AREA
708 lam %a0,%a15,0(%r10)
709 lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone
710 stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
711 jg start_secondary
712#else
713/*
714 * If we do not run with SMP enabled, let the new CPU crash ...
715 */
716 .globl restart_int_handler
717restart_int_handler:
718 basr %r1,0
719restart_base:
720 lpswe restart_crash-restart_base(%r1)
721 .align 8
722restart_crash:
723 .long 0x000a0000,0x00000000,0x00000000,0x00000000
724restart_go:
725#endif
726
727#ifdef CONFIG_CHECK_STACK
728/*
729 * The synchronous or the asynchronous stack overflowed. We are dead.
730 * No need to properly save the registers, we are going to panic anyway.
731 * Setup a pt_regs so that show_trace can provide a good call trace.
732 */
733stack_overflow:
734 lg %r15,__LC_PANIC_STACK # change to panic stack
735 aghi %r1,-SP_SIZE
736 mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
737 stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
738 la %r1,__LC_SAVE_AREA
739 chi %r12,__LC_SVC_OLD_PSW
740 je 0f
741 chi %r12,__LC_PGM_OLD_PSW
742 je 0f
743 la %r1,__LC_SAVE_AREA+16
7440: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack
745 xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain
746 la %r2,SP_PTREGS(%r15) # load pt_regs
747 jg kernel_stack_overflow
748#endif
749
750cleanup_table_system_call:
751 .quad system_call, sysc_do_svc
752cleanup_table_sysc_return:
753 .quad sysc_return, sysc_leave
754cleanup_table_sysc_leave:
755 .quad sysc_leave, sysc_work_loop
756cleanup_table_sysc_work_loop:
757 .quad sysc_work_loop, sysc_reschedule
758
759cleanup_critical:
760 clc 8(8,%r12),BASED(cleanup_table_system_call)
761 jl 0f
762 clc 8(8,%r12),BASED(cleanup_table_system_call+8)
763 jl cleanup_system_call
7640:
765 clc 8(8,%r12),BASED(cleanup_table_sysc_return)
766 jl 0f
767 clc 8(8,%r12),BASED(cleanup_table_sysc_return+8)
768 jl cleanup_sysc_return
7690:
770 clc 8(8,%r12),BASED(cleanup_table_sysc_leave)
771 jl 0f
772 clc 8(8,%r12),BASED(cleanup_table_sysc_leave+8)
773 jl cleanup_sysc_leave
7740:
775 clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop)
776 jl 0f
777 clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
778 jl cleanup_sysc_leave
7790:
780 br %r14
781
782cleanup_system_call:
783 mvc __LC_RETURN_PSW(16),0(%r12)
784#ifdef CONFIG_VIRT_CPU_ACCOUNTING
785 clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8)
786 jh 0f
787 mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER
7880: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16)
789 jhe cleanup_vtime
790#endif
791 clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn)
792 jh 0f
793 mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32
7940: stg %r13,__LC_SAVE_AREA+40
795 SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
796 stg %r15,__LC_SAVE_AREA+56
797 llgh %r7,__LC_SVC_INT_CODE
798#ifdef CONFIG_VIRT_CPU_ACCOUNTING
799cleanup_vtime:
800 clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24)
801 jhe cleanup_stime
802 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
803 jz cleanup_novtime
804 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
805cleanup_stime:
806 clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+32)
807 jh cleanup_update
808 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
809cleanup_update:
810 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
811cleanup_novtime:
812#endif
813 mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8)
814 la %r12,__LC_RETURN_PSW
815 br %r14
816cleanup_system_call_insn:
817 .quad sysc_saveall
818#ifdef CONFIG_VIRT_CPU_ACCOUNTING
819 .quad system_call
820 .quad sysc_vtime
821 .quad sysc_stime
822 .quad sysc_update
823#endif
824
825cleanup_sysc_return:
826 mvc __LC_RETURN_PSW(8),0(%r12)
827 mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_sysc_return)
828 la %r12,__LC_RETURN_PSW
829 br %r14
830
831cleanup_sysc_leave:
832 clc 8(8,%r12),BASED(cleanup_sysc_leave_insn)
833 je 0f
834#ifdef CONFIG_VIRT_CPU_ACCOUNTING
835 mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
836 clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8)
837 je 0f
838#endif
839 mvc __LC_RETURN_PSW(16),SP_PSW(%r15)
840 mvc __LC_SAVE_AREA+32(32),SP_R12(%r15)
841 lmg %r0,%r11,SP_R0(%r15)
842 lg %r15,SP_R15(%r15)
8430: la %r12,__LC_RETURN_PSW
844 br %r14
845cleanup_sysc_leave_insn:
846#ifdef CONFIG_VIRT_CPU_ACCOUNTING
847 .quad sysc_leave + 16
848#endif
849 .quad sysc_leave + 12
850
851/*
852 * Integer constants
853 */
854 .align 4
855.Lconst:
856.Lc_pactive: .long PREEMPT_ACTIVE
857.Lnr_syscalls: .long NR_syscalls
858.L0x0130: .short 0x130
859.L0x0140: .short 0x140
860.L0x0150: .short 0x150
861.L0x0160: .short 0x160
862.L0x0170: .short 0x170
863.Lcritical_start:
864 .quad __critical_start
865.Lcritical_end:
866 .quad __critical_end
867
868#define SYSCALL(esa,esame,emu) .long esame
869 .globl sys_call_table
870sys_call_table:
871#include "syscalls.S"
872#undef SYSCALL
873
874#ifdef CONFIG_S390_SUPPORT
875
876#define SYSCALL(esa,esame,emu) .long emu
877 .globl sys_call_table_emu
878sys_call_table_emu:
879#include "syscalls.S"
880#undef SYSCALL
881#endif
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
new file mode 100644
index 000000000000..b804c55bd919
--- /dev/null
+++ b/arch/s390/kernel/head.S
@@ -0,0 +1,772 @@
1/*
2 * arch/s390/kernel/head.S
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Hartmut Penner (hp@de.ibm.com),
7 * Martin Schwidefsky (schwidefsky@de.ibm.com),
8 * Rob van der Heij (rvdhei@iae.nl)
9 *
10 * There are 5 different IPL methods
11 * 1) load the image directly into ram at address 0 and do an PSW restart
12 * 2) linload will load the image from address 0x10000 to memory 0x10000
13 * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
14 * 3) generate the tape ipl header, store the generated image on a tape
15 * and ipl from it
16 * In case of SL tape you need to IPL 5 times to get past VOL1 etc
17 * 4) generate the vm reader ipl header, move the generated image to the
18 * VM reader (use option NOH!) and do a ipl from reader (VM only)
19 * 5) direct call of start by the SALIPL loader
20 * We use the cpuid to distinguish between VM and native ipl
21 * params for kernel are pushed to 0x10400 (see setup.h)
22
23 Changes:
24 Okt 25 2000 <rvdheij@iae.nl>
25 added code to skip HDR and EOF to allow SL tape IPL (5 retries)
26 changed first CCW from rewind to backspace block
27
28 */
29
30#include <linux/config.h>
31#include <asm/setup.h>
32#include <asm/lowcore.h>
33#include <asm/offsets.h>
34#include <asm/thread_info.h>
35#include <asm/page.h>
36
37#ifndef CONFIG_IPL
38 .org 0
39 .long 0x00080000,0x80000000+startup # Just a restart PSW
40#else
41#ifdef CONFIG_IPL_TAPE
42#define IPL_BS 1024
43 .org 0
44 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
45 .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
46 .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
47 .long 0x00000000,0x00000000 # external old psw
48 .long 0x00000000,0x00000000 # svc old psw
49 .long 0x00000000,0x00000000 # program check old psw
50 .long 0x00000000,0x00000000 # machine check old psw
51 .long 0x00000000,0x00000000 # io old psw
52 .long 0x00000000,0x00000000
53 .long 0x00000000,0x00000000
54 .long 0x00000000,0x00000000
55 .long 0x000a0000,0x00000058 # external new psw
56 .long 0x000a0000,0x00000060 # svc new psw
57 .long 0x000a0000,0x00000068 # program check new psw
58 .long 0x000a0000,0x00000070 # machine check new psw
59 .long 0x00080000,0x80000000+.Lioint # io new psw
60
61 .org 0x100
62#
63# subroutine for loading from tape
64# Paramters:
65# R1 = device number
66# R2 = load address
67.Lloader:
68 st %r14,.Lldret
69 la %r3,.Lorbread # r3 = address of orb
70 la %r5,.Lirb # r5 = address of irb
71 st %r2,.Lccwread+4 # initialize CCW data addresses
72 lctl %c6,%c6,.Lcr6
73 slr %r2,%r2
74.Lldlp:
75 la %r6,3 # 3 retries
76.Lssch:
77 ssch 0(%r3) # load chunk of IPL_BS bytes
78 bnz .Llderr
79.Lw4end:
80 bas %r14,.Lwait4io
81 tm 8(%r5),0x82 # do we have a problem ?
82 bnz .Lrecov
83 slr %r7,%r7
84 icm %r7,3,10(%r5) # get residual count
85 lcr %r7,%r7
86 la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
87 ar %r2,%r7 # add to total size
88 tm 8(%r5),0x01 # found a tape mark ?
89 bnz .Ldone
90 l %r0,.Lccwread+4 # update CCW data addresses
91 ar %r0,%r7
92 st %r0,.Lccwread+4
93 b .Lldlp
94.Ldone:
95 l %r14,.Lldret
96 br %r14 # r2 contains the total size
97.Lrecov:
98 bas %r14,.Lsense # do the sensing
99 bct %r6,.Lssch # dec. retry count & branch
100 b .Llderr
101#
102# Sense subroutine
103#
104.Lsense:
105 st %r14,.Lsnsret
106 la %r7,.Lorbsense
107 ssch 0(%r7) # start sense command
108 bnz .Llderr
109 bas %r14,.Lwait4io
110 l %r14,.Lsnsret
111 tm 8(%r5),0x82 # do we have a problem ?
112 bnz .Llderr
113 br %r14
114#
115# Wait for interrupt subroutine
116#
117.Lwait4io:
118 lpsw .Lwaitpsw
119.Lioint:
120 c %r1,0xb8 # compare subchannel number
121 bne .Lwait4io
122 tsch 0(%r5)
123 slr %r0,%r0
124 tm 8(%r5),0x82 # do we have a problem ?
125 bnz .Lwtexit
126 tm 8(%r5),0x04 # got device end ?
127 bz .Lwait4io
128.Lwtexit:
129 br %r14
130.Llderr:
131 lpsw .Lcrash
132
133 .align 8
134.Lorbread:
135 .long 0x00000000,0x0080ff00,.Lccwread
136 .align 8
137.Lorbsense:
138 .long 0x00000000,0x0080ff00,.Lccwsense
139 .align 8
140.Lccwread:
141 .long 0x02200000+IPL_BS,0x00000000
142.Lccwsense:
143 .long 0x04200001,0x00000000
144.Lwaitpsw:
145 .long 0x020a0000,0x80000000+.Lioint
146
147.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
148.Lcr6: .long 0xff000000
149 .align 8
150.Lcrash:.long 0x000a0000,0x00000000
151.Lldret:.long 0
152.Lsnsret: .long 0
153#endif /* CONFIG_IPL_TAPE */
154
155#ifdef CONFIG_IPL_VM
156#define IPL_BS 0x730
157 .org 0
158 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
159 .long 0x02000018,0x60000050 # by ipl to addresses 0-23.
160 .long 0x02000068,0x60000050 # (a PSW and two CCWs).
161 .fill 80-24,1,0x40 # bytes 24-79 are discarded !!
162 .long 0x020000f0,0x60000050 # The next 160 byte are loaded
163 .long 0x02000140,0x60000050 # to addresses 0x18-0xb7
164 .long 0x02000190,0x60000050 # They form the continuation
165 .long 0x020001e0,0x60000050 # of the CCW program started
166 .long 0x02000230,0x60000050 # by ipl and load the range
167 .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image
168 .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730
169 .long 0x02000320,0x60000050 # in memory. At the end of
170 .long 0x02000370,0x60000050 # the channel program the PSW
171 .long 0x020003c0,0x60000050 # at location 0 is loaded.
172 .long 0x02000410,0x60000050 # Initial processing starts
173 .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
174 .long 0x020004b0,0x60000050
175 .long 0x02000500,0x60000050
176 .long 0x02000550,0x60000050
177 .long 0x020005a0,0x60000050
178 .long 0x020005f0,0x60000050
179 .long 0x02000640,0x60000050
180 .long 0x02000690,0x60000050
181 .long 0x020006e0,0x20000050
182
183 .org 0xf0
184#
185# subroutine for loading cards from the reader
186#
187.Lloader:
188 la %r3,.Lorb # r2 = address of orb into r2
189 la %r5,.Lirb # r4 = address of irb
190 la %r6,.Lccws
191 la %r7,20
192.Linit:
193 st %r2,4(%r6) # initialize CCW data addresses
194 la %r2,0x50(%r2)
195 la %r6,8(%r6)
196 bct 7,.Linit
197
198 lctl %c6,%c6,.Lcr6 # set IO subclass mask
199 slr %r2,%r2
200.Lldlp:
201 ssch 0(%r3) # load chunk of 1600 bytes
202 bnz .Llderr
203.Lwait4irq:
204 mvc __LC_IO_NEW_PSW(8),.Lnewpsw # set up IO interrupt psw
205 lpsw .Lwaitpsw
206.Lioint:
207 c %r1,0xb8 # compare subchannel number
208 bne .Lwait4irq
209 tsch 0(%r5)
210
211 slr %r0,%r0
212 ic %r0,8(%r5) # get device status
213 chi %r0,8 # channel end ?
214 be .Lcont
215 chi %r0,12 # channel end + device end ?
216 be .Lcont
217
218 l %r0,4(%r5)
219 s %r0,8(%r3) # r0/8 = number of ccws executed
220 mhi %r0,10 # *10 = number of bytes in ccws
221 lh %r3,10(%r5) # get residual count
222 sr %r0,%r3 # #ccws*80-residual=#bytes read
223 ar %r2,%r0
224
225 br %r14 # r2 contains the total size
226
227.Lcont:
228 ahi %r2,0x640 # add 0x640 to total size
229 la %r6,.Lccws
230 la %r7,20
231.Lincr:
232 l %r0,4(%r6) # update CCW data addresses
233 ahi %r0,0x640
234 st %r0,4(%r6)
235 ahi %r6,8
236 bct 7,.Lincr
237
238 b .Lldlp
239.Llderr:
240 lpsw .Lcrash
241
242 .align 8
243.Lorb: .long 0x00000000,0x0080ff00,.Lccws
244.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
245.Lcr6: .long 0xff000000
246.Lloadp:.long 0,0
247 .align 8
248.Lcrash:.long 0x000a0000,0x00000000
249.Lnewpsw:
250 .long 0x00080000,0x80000000+.Lioint
251.Lwaitpsw:
252 .long 0x020a0000,0x80000000+.Lioint
253
254 .align 8
255.Lccws: .rept 19
256 .long 0x02600050,0x00000000
257 .endr
258 .long 0x02200050,0x00000000
259#endif /* CONFIG_IPL_VM */
260
261iplstart:
262 lh %r1,0xb8 # test if subchannel number
263 bct %r1,.Lnoload # is valid
264 l %r1,0xb8 # load ipl subchannel number
265 la %r2,IPL_BS # load start address
266 bas %r14,.Lloader # load rest of ipl image
267 l %r12,.Lparm # pointer to parameter area
268 st %r1,IPL_DEVICE-PARMAREA(%r12) # store ipl device number
269
270#
271# load parameter file from ipl device
272#
273.Lagain1:
274 l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp
275 bas %r14,.Lloader # load parameter file
276 ltr %r2,%r2 # got anything ?
277 bz .Lnopf
278 chi %r2,895
279 bnh .Lnotrunc
280 la %r2,895
281.Lnotrunc:
282 l %r4,INITRD_START-PARMAREA(%r12)
283 clc 0(3,%r4),.L_hdr # if it is HDRx
284 bz .Lagain1 # skip dataset header
285 clc 0(3,%r4),.L_eof # if it is EOFx
286 bz .Lagain1 # skip dateset trailer
287 la %r5,0(%r4,%r2)
288 lr %r3,%r2
289.Lidebc:
290 tm 0(%r5),0x80 # high order bit set ?
291 bo .Ldocv # yes -> convert from EBCDIC
292 ahi %r5,-1
293 bct %r3,.Lidebc
294 b .Lnocv
295.Ldocv:
296 l %r3,.Lcvtab
297 tr 0(256,%r4),0(%r3) # convert parameters to ascii
298 tr 256(256,%r4),0(%r3)
299 tr 512(256,%r4),0(%r3)
300 tr 768(122,%r4),0(%r3)
301.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
302 mvc 0(256,%r3),0(%r4)
303 mvc 256(256,%r3),256(%r4)
304 mvc 512(256,%r3),512(%r4)
305 mvc 768(122,%r3),768(%r4)
306 slr %r0,%r0
307 b .Lcntlp
308.Ldelspc:
309 ic %r0,0(%r2,%r3)
310 chi %r0,0x20 # is it a space ?
311 be .Lcntlp
312 ahi %r2,1
313 b .Leolp
314.Lcntlp:
315 brct %r2,.Ldelspc
316.Leolp:
317 slr %r0,%r0
318 stc %r0,0(%r2,%r3) # terminate buffer
319.Lnopf:
320
321#
322# load ramdisk from ipl device
323#
324.Lagain2:
325 l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
326 bas %r14,.Lloader # load ramdisk
327 st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
328 ltr %r2,%r2
329 bnz .Lrdcont
330 st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it
331.Lrdcont:
332 l %r2,INITRD_START-PARMAREA(%r12)
333
334 clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
335 bz .Lagain2
336 clc 0(3,%r2),.L_eof
337 bz .Lagain2
338
339#ifdef CONFIG_IPL_VM
340#
341# reset files in VM reader
342#
343 stidp __LC_CPUID # store cpuid
344 tm __LC_CPUID,0xff # running VM ?
345 bno .Lnoreset
346 la %r2,.Lreset
347 lhi %r3,26
348 .long 0x83230008
349.Lnoreset:
350#endif
351
352#
353# everything loaded, go for it
354#
355.Lnoload:
356 l %r1,.Lstartup
357 br %r1
358
359.Lparm: .long PARMAREA
360.Lstartup: .long startup
361.Lcvtab:.long _ebcasc # ebcdic to ascii table
362.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
363 .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
364 .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
365.L_eof: .long 0xc5d6c600 /* C'EOF' */
366.L_hdr: .long 0xc8c4d900 /* C'HDR' */
367
368#endif /* CONFIG_IPL */
369
370#
371# SALIPL loader support. Based on a patch by Rob van der Heij.
372# This entry point is called directly from the SALIPL loader and
373# doesn't need a builtin ipl record.
374#
375 .org 0x800
376 .globl start
377start:
378 stm %r0,%r15,0x07b0 # store registers
379 basr %r12,%r0
380.base:
381 l %r11,.parm
382 l %r8,.cmd # pointer to command buffer
383
384 ltr %r9,%r9 # do we have SALIPL parameters?
385 bp .sk8x8
386
387 mvc 0(64,%r8),0x00b0 # copy saved registers
388 xc 64(240-64,%r8),0(%r8) # remainder of buffer
389 tr 0(64,%r8),.lowcase
390 b .gotr
391.sk8x8:
392 mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
393.gotr:
394 l %r10,.tbl # EBCDIC to ASCII table
395 tr 0(240,%r8),0(%r10)
396 stidp __LC_CPUID # Are we running on VM maybe
397 cli __LC_CPUID,0xff
398 bnz .test
399 .long 0x83300060 # diag 3,0,x'0060' - storage size
400 b .done
401.test:
402 mvc 0x68(8),.pgmnw # set up pgm check handler
403 l %r2,.fourmeg
404 lr %r3,%r2
405 bctr %r3,%r0 # 4M-1
406.loop: iske %r0,%r3
407 ar %r3,%r2
408.pgmx:
409 sr %r3,%r2
410 la %r3,1(%r3)
411.done:
412 l %r1,.memsize
413 st %r3,0(%r1)
414 slr %r0,%r0
415 st %r0,INITRD_SIZE-PARMAREA(%r11)
416 st %r0,INITRD_START-PARMAREA(%r11)
417 j startup # continue with startup
418.tbl: .long _ebcasc # translate table
419.cmd: .long COMMAND_LINE # address of command line buffer
420.parm: .long PARMAREA
421.memsize: .long memory_size
422.fourmeg: .long 0x00400000 # 4M
423.pgmnw: .long 0x00080000,.pgmx
424.lowcase:
425 .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
426 .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
427 .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
428 .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
429 .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
430 .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
431 .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
432 .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
433 .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
434 .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
435 .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
436 .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
437 .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
438 .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
439 .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
440 .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
441
442 .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
443 .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
444 .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
445 .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
446 .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
447 .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
448 .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
449 .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
450 .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
451 .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi
452 .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
453 .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr
454 .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx
455 .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz
456 .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
457 .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
458
459#
460# startup-code at 0x10000, running in real mode
461# this is called either by the ipl loader or directly by PSW restart
462# or linload or SALIPL
463#
464 .org 0x10000
465startup:basr %r13,0 # get base
466.LPG1: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
467 la %r12,_pstart-.LPG1(%r13) # pointer to parameter area
468 # move IPL device to lowcore
469 mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
470
471#
472# clear bss memory
473#
474 l %r2,.Lbss_bgn-.LPG1(%r13) # start of bss
475 l %r3,.Lbss_end-.LPG1(%r13) # end of bss
476 sr %r3,%r2 # length of bss
477 sr %r4,%r4 #
478 sr %r5,%r5 # set src,length and pad to zero
479 sr %r0,%r0 #
480 mvcle %r2,%r4,0 # clear mem
481 jo .-4 # branch back, if not finish
482
483 l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
484.Lservicecall:
485 stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts
486
487 stctl %r0, %r0,.Lcr-.LPG1(%r13) # get cr0
488 la %r1,0x200 # set bit 22
489 o %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1
490 st %r1,.Lcr-.LPG1(%r13)
491 lctl %r0, %r0,.Lcr-.LPG1(%r13) # load modified cr0
492
493 mvc __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw
494 la %r1, .Lsclph-.LPG1(%r13)
495 a %r1,__LC_EXT_NEW_PSW+4 # set handler
496 st %r1,__LC_EXT_NEW_PSW+4
497
498 la %r4,_pstart-.LPG1(%r13) # %r4 is our index for sccb stuff
499 la %r1, .Lsccb-PARMAREA(%r4) # our sccb
500 .insn rre,0xb2200000,%r2,%r1 # service call
501 ipm %r1
502 srl %r1,28 # get cc code
503 xr %r3, %r3
504 chi %r1,3
505 be .Lfchunk-.LPG1(%r13) # leave
506 chi %r1,2
507 be .Lservicecall-.LPG1(%r13)
508 lpsw .Lwaitsclp-.LPG1(%r13)
509.Lsclph:
510 lh %r1,.Lsccbr-PARMAREA(%r4)
511 chi %r1,0x10 # 0x0010 is the sucess code
512 je .Lprocsccb # let's process the sccb
513 chi %r1,0x1f0
514 bne .Lfchunk-.LPG1(%r13) # unhandled error code
515 c %r2, .Lrcp-.LPG1(%r13) # Did we try Read SCP forced
516 bne .Lfchunk-.LPG1(%r13) # if no, give up
517 l %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP
518 b .Lservicecall-.LPG1(%r13)
519.Lprocsccb:
520 lh %r1,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
521 chi %r1,0x00
522 jne .Lscnd
523 l %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one
524.Lscnd:
525 xr %r3,%r3 # same logic
526 ic %r3,.Lscpa1-PARMAREA(%r4)
527 chi %r3,0x00
528 jne .Lcompmem
529 l %r3,.Lscpa2-PARMAREA(%r13)
530.Lcompmem:
531 mr %r2,%r1 # mem in MB on 128-bit
532 l %r1,.Lonemb-.LPG1(%r13)
533 mr %r2,%r1 # mem size in bytes in %r3
534 b .Lfchunk-.LPG1(%r13)
535
536.Lpmask:
537 .byte 0
538.align 8
539.Lpcext:.long 0x00080000,0x80000000
540.Lcr:
541 .long 0x00 # place holder for cr0
542.Lwaitsclp:
543 .long 0x020A0000
544 .long .Lsclph
545.Lrcp:
546 .int 0x00120001 # Read SCP forced code
547.Lrcp2:
548 .int 0x00020001 # Read SCP code
549.Lonemb:
550 .int 0x100000
551.Lfchunk:
552
553#
554# find memory chunks.
555#
556 lr %r9,%r3 # end of mem
557 mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
558 la %r1,1 # test in increments of 128KB
559 sll %r1,17
560 l %r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array
561 slr %r4,%r4 # set start of chunk to zero
562 slr %r5,%r5 # set end of chunk to zero
563 slr %r6,%r6 # set access code to zero
564 la %r10, MEMORY_CHUNKS # number of chunks
565.Lloop:
566 tprot 0(%r5),0 # test protection of first byte
567 ipm %r7
568 srl %r7,28
569 clr %r6,%r7 # compare cc with last access code
570 be .Lsame-.LPG1(%r13)
571 b .Lchkmem-.LPG1(%r13)
572.Lsame:
573 ar %r5,%r1 # add 128KB to end of chunk
574 bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop
575.Lchkmem: # > 2GB or tprot got a program check
576 clr %r4,%r5 # chunk size > 0?
577 be .Lchkloop-.LPG1(%r13)
578 st %r4,0(%r3) # store start address of chunk
579 lr %r0,%r5
580 slr %r0,%r4
581 st %r0,4(%r3) # store size of chunk
582 st %r6,8(%r3) # store type of chunk
583 la %r3,12(%r3)
584 l %r4,.Lmemsize-.LPG1(%r13) # address of variable memory_size
585 st %r5,0(%r4) # store last end to memory size
586 ahi %r10,-1 # update chunk number
587.Lchkloop:
588 lr %r6,%r7 # set access code to last cc
589 # we got an exception or we're starting a new
590 # chunk , we must check if we should
591 # still try to find valid memory (if we detected
592 # the amount of available storage), and if we
593 # have chunks left
594 xr %r0,%r0
595 clr %r0,%r9 # did we detect memory?
596 je .Ldonemem # if not, leave
597 chi %r10,0 # do we have chunks left?
598 je .Ldonemem
599 alr %r5,%r1 # add 128KB to end of chunk
600 lr %r4,%r5 # potential new chunk
601 clr %r5,%r9 # should we go on?
602 jl .Lloop
603.Ldonemem:
604 l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
605#
606# find out if we are running under VM
607#
608 stidp __LC_CPUID # store cpuid
609 tm __LC_CPUID,0xff # running under VM ?
610 bno .Lnovm-.LPG1(%r13)
611 oi 3(%r12),1 # set VM flag
612.Lnovm:
613 lh %r0,__LC_CPUID+4 # get cpu version
614 chi %r0,0x7490 # running on a P/390 ?
615 bne .Lnop390-.LPG1(%r13)
616 oi 3(%r12),4 # set P/390 flag
617.Lnop390:
618
619#
620# find out if we have an IEEE fpu
621#
622 mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13)
623 efpc %r0,0 # test IEEE extract fpc instruction
624 oi 3(%r12),2 # set IEEE fpu flag
625.Lchkfpu:
626
627#
628# find out if we have the CSP instruction
629#
630 mvc __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13)
631 la %r0,0
632 lr %r1,%r0
633 la %r2,4
634 csp %r0,%r2 # Test CSP instruction
635 oi 3(%r12),8 # set CSP flag
636.Lchkcsp:
637
638#
639# find out if we have the MVPG instruction
640#
641 mvc __LC_PGM_NEW_PSW(8),.Lpcmvpg-.LPG1(%r13)
642 sr %r0,%r0
643 la %r1,0
644 la %r2,0
645 mvpg %r1,%r2 # Test CSP instruction
646 oi 3(%r12),16 # set MVPG flag
647.Lchkmvpg:
648
649#
650# find out if we have the IDTE instruction
651#
652 mvc __LC_PGM_NEW_PSW(8),.Lpcidte-.LPG1(%r13)
653 .long 0xb2b10000 # store facility list
654 tm 0xc8,0x08 # check bit for clearing-by-ASCE
655 bno .Lchkidte-.LPG1(%r13)
656 lhi %r1,2094
657 lhi %r2,0
658 .long 0xb98e2001
659 oi 3(%r12),0x80 # set IDTE flag
660.Lchkidte:
661
662 lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
663 # virtual and never return ...
664 .align 8
665.Lentry:.long 0x00080000,0x80000000 + _stext
666.Lctl: .long 0x04b50002 # cr0: various things
667 .long 0 # cr1: primary space segment table
668 .long .Lduct # cr2: dispatchable unit control table
669 .long 0 # cr3: instruction authorization
670 .long 0 # cr4: instruction authorization
671 .long 0xffffffff # cr5: primary-aste origin
672 .long 0 # cr6: I/O interrupts
673 .long 0 # cr7: secondary space segment table
674 .long 0 # cr8: access registers translation
675 .long 0 # cr9: tracing off
676 .long 0 # cr10: tracing off
677 .long 0 # cr11: tracing off
678 .long 0 # cr12: tracing off
679 .long 0 # cr13: home space segment table
680 .long 0xc0000000 # cr14: machine check handling off
681 .long 0 # cr15: linkage stack operations
682.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem
683.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
684.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
685.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
686.Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte
687.Lmemsize:.long memory_size
688.Lmchunk:.long memory_chunk
689.Lmflags:.long machine_flags
690.Lbss_bgn: .long __bss_start
691.Lbss_end: .long _end
692
693 .org PARMAREA-64
694.Lduct: .long 0,0,0,0,0,0,0,0
695 .long 0,0,0,0,0,0,0,0
696
697#
698# params at 10400 (setup.h)
699#
700 .org PARMAREA
701 .global _pstart
702_pstart:
703 .long 0,0 # IPL_DEVICE
704 .long 0,RAMDISK_ORIGIN # INITRD_START
705 .long 0,RAMDISK_SIZE # INITRD_SIZE
706
707 .org COMMAND_LINE
708 .byte "root=/dev/ram0 ro"
709 .byte 0
710 .org 0x11000
711.Lsccb:
712 .hword 0x1000 # length, one page
713 .byte 0x00,0x00,0x00
714 .byte 0x80 # variable response bit set
715.Lsccbr:
716 .hword 0x00 # response code
717.Lscpincr1:
718 .hword 0x00
719.Lscpa1:
720 .byte 0x00
721 .fill 89,1,0
722.Lscpa2:
723 .int 0x00
724.Lscpincr2:
725 .quad 0x00
726 .fill 3984,1,0
727 .org 0x12000
728 .global _pend
729_pend:
730
731#ifdef CONFIG_SHARED_KERNEL
732 .org 0x100000
733#endif
734
735#
736# startup-code, running in virtual mode
737#
738 .globl _stext
739_stext: basr %r13,0 # get base
740.LPG2:
741#
742# Setup stack
743#
744 l %r15,.Linittu-.LPG2(%r13)
745 mvc __LC_CURRENT(4),__TI_task(%r15)
746 ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
747 st %r15,__LC_KERNEL_STACK # set end of kernel stack
748 ahi %r15,-96
749 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
750
751# check control registers
752 stctl %c0,%c15,0(%r15)
753 oi 2(%r15),0x20 # enable sigp external interrupts
754 oi 0(%r15),0x10 # switch on low address protection
755 lctl %c0,%c15,0(%r15)
756
757#
758 lam 0,15,.Laregs-.LPG2(%r13) # load access regs needed by uaccess
759 l %r14,.Lstart-.LPG2(%r13)
760 basr %r14,%r14 # call start_kernel
761#
762# We returned from start_kernel ?!? PANIK
763#
764 basr %r13,0
765 lpsw .Ldw-.(%r13) # load disabled wait psw
766#
767 .align 8
768.Ldw: .long 0x000a0000,0x00000000
769.Linittu: .long init_thread_union
770.Lstart: .long start_kernel
771.Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
772
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
new file mode 100644
index 000000000000..8366793bc371
--- /dev/null
+++ b/arch/s390/kernel/head64.S
@@ -0,0 +1,769 @@
1/*
2 * arch/s390/kernel/head.S
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Hartmut Penner (hp@de.ibm.com),
7 * Martin Schwidefsky (schwidefsky@de.ibm.com),
8 * Rob van der Heij (rvdhei@iae.nl)
9 *
10 * There are 5 different IPL methods
11 * 1) load the image directly into ram at address 0 and do an PSW restart
12 * 2) linload will load the image from address 0x10000 to memory 0x10000
13 * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
14 * 3) generate the tape ipl header, store the generated image on a tape
15 * and ipl from it
16 * In case of SL tape you need to IPL 5 times to get past VOL1 etc
17 * 4) generate the vm reader ipl header, move the generated image to the
18 * VM reader (use option NOH!) and do a ipl from reader (VM only)
19 * 5) direct call of start by the SALIPL loader
20 * We use the cpuid to distinguish between VM and native ipl
21 * params for kernel are pushed to 0x10400 (see setup.h)
22
23 Changes:
24 Okt 25 2000 <rvdheij@iae.nl>
25 added code to skip HDR and EOF to allow SL tape IPL (5 retries)
26 changed first CCW from rewind to backspace block
27
28 */
29
30#include <linux/config.h>
31#include <asm/setup.h>
32#include <asm/lowcore.h>
33#include <asm/offsets.h>
34#include <asm/thread_info.h>
35#include <asm/page.h>
36
37#ifndef CONFIG_IPL
38 .org 0
39 .long 0x00080000,0x80000000+startup # Just a restart PSW
40#else
41#ifdef CONFIG_IPL_TAPE
42#define IPL_BS 1024
43 .org 0
44 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
45 .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
46 .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
47 .long 0x00000000,0x00000000 # external old psw
48 .long 0x00000000,0x00000000 # svc old psw
49 .long 0x00000000,0x00000000 # program check old psw
50 .long 0x00000000,0x00000000 # machine check old psw
51 .long 0x00000000,0x00000000 # io old psw
52 .long 0x00000000,0x00000000
53 .long 0x00000000,0x00000000
54 .long 0x00000000,0x00000000
55 .long 0x000a0000,0x00000058 # external new psw
56 .long 0x000a0000,0x00000060 # svc new psw
57 .long 0x000a0000,0x00000068 # program check new psw
58 .long 0x000a0000,0x00000070 # machine check new psw
59 .long 0x00080000,0x80000000+.Lioint # io new psw
60
61 .org 0x100
62#
63# subroutine for loading from tape
64# Paramters:
65# R1 = device number
66# R2 = load address
67.Lloader:
68 st %r14,.Lldret
69 la %r3,.Lorbread # r3 = address of orb
70 la %r5,.Lirb # r5 = address of irb
71 st %r2,.Lccwread+4 # initialize CCW data addresses
72 lctl %c6,%c6,.Lcr6
73 slr %r2,%r2
74.Lldlp:
75 la %r6,3 # 3 retries
76.Lssch:
77 ssch 0(%r3) # load chunk of IPL_BS bytes
78 bnz .Llderr
79.Lw4end:
80 bas %r14,.Lwait4io
81 tm 8(%r5),0x82 # do we have a problem ?
82 bnz .Lrecov
83 slr %r7,%r7
84 icm %r7,3,10(%r5) # get residual count
85 lcr %r7,%r7
86 la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
87 ar %r2,%r7 # add to total size
88 tm 8(%r5),0x01 # found a tape mark ?
89 bnz .Ldone
90 l %r0,.Lccwread+4 # update CCW data addresses
91 ar %r0,%r7
92 st %r0,.Lccwread+4
93 b .Lldlp
94.Ldone:
95 l %r14,.Lldret
96 br %r14 # r2 contains the total size
97.Lrecov:
98 bas %r14,.Lsense # do the sensing
99 bct %r6,.Lssch # dec. retry count & branch
100 b .Llderr
101#
102# Sense subroutine
103#
104.Lsense:
105 st %r14,.Lsnsret
106 la %r7,.Lorbsense
107 ssch 0(%r7) # start sense command
108 bnz .Llderr
109 bas %r14,.Lwait4io
110 l %r14,.Lsnsret
111 tm 8(%r5),0x82 # do we have a problem ?
112 bnz .Llderr
113 br %r14
114#
115# Wait for interrupt subroutine
116#
117.Lwait4io:
118 lpsw .Lwaitpsw
119.Lioint:
120 c %r1,0xb8 # compare subchannel number
121 bne .Lwait4io
122 tsch 0(%r5)
123 slr %r0,%r0
124 tm 8(%r5),0x82 # do we have a problem ?
125 bnz .Lwtexit
126 tm 8(%r5),0x04 # got device end ?
127 bz .Lwait4io
128.Lwtexit:
129 br %r14
130.Llderr:
131 lpsw .Lcrash
132
133 .align 8
134.Lorbread:
135 .long 0x00000000,0x0080ff00,.Lccwread
136 .align 8
137.Lorbsense:
138 .long 0x00000000,0x0080ff00,.Lccwsense
139 .align 8
140.Lccwread:
141 .long 0x02200000+IPL_BS,0x00000000
142.Lccwsense:
143 .long 0x04200001,0x00000000
144.Lwaitpsw:
145 .long 0x020a0000,0x80000000+.Lioint
146
147.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
148.Lcr6: .long 0xff000000
149 .align 8
150.Lcrash:.long 0x000a0000,0x00000000
151.Lldret:.long 0
152.Lsnsret: .long 0
153#endif /* CONFIG_IPL_TAPE */
154
155#ifdef CONFIG_IPL_VM
156#define IPL_BS 0x730
157 .org 0
158 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
159 .long 0x02000018,0x60000050 # by ipl to addresses 0-23.
160 .long 0x02000068,0x60000050 # (a PSW and two CCWs).
161 .fill 80-24,1,0x40 # bytes 24-79 are discarded !!
162 .long 0x020000f0,0x60000050 # The next 160 byte are loaded
163 .long 0x02000140,0x60000050 # to addresses 0x18-0xb7
164 .long 0x02000190,0x60000050 # They form the continuation
165 .long 0x020001e0,0x60000050 # of the CCW program started
166 .long 0x02000230,0x60000050 # by ipl and load the range
167 .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image
168 .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730
169 .long 0x02000320,0x60000050 # in memory. At the end of
170 .long 0x02000370,0x60000050 # the channel program the PSW
171 .long 0x020003c0,0x60000050 # at location 0 is loaded.
172 .long 0x02000410,0x60000050 # Initial processing starts
173 .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
174 .long 0x020004b0,0x60000050
175 .long 0x02000500,0x60000050
176 .long 0x02000550,0x60000050
177 .long 0x020005a0,0x60000050
178 .long 0x020005f0,0x60000050
179 .long 0x02000640,0x60000050
180 .long 0x02000690,0x60000050
181 .long 0x020006e0,0x20000050
182
183 .org 0xf0
184#
185# subroutine for loading cards from the reader
186#
187.Lloader:
188 la %r3,.Lorb # r2 = address of orb into r2
189 la %r5,.Lirb # r4 = address of irb
190 la %r6,.Lccws
191 la %r7,20
192.Linit:
193 st %r2,4(%r6) # initialize CCW data addresses
194 la %r2,0x50(%r2)
195 la %r6,8(%r6)
196 bct 7,.Linit
197
198 lctl %c6,%c6,.Lcr6 # set IO subclass mask
199 slr %r2,%r2
200.Lldlp:
201 ssch 0(%r3) # load chunk of 1600 bytes
202 bnz .Llderr
203.Lwait4irq:
204 mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
205 lpsw .Lwaitpsw
206.Lioint:
207 c %r1,0xb8 # compare subchannel number
208 bne .Lwait4irq
209 tsch 0(%r5)
210
211 slr %r0,%r0
212 ic %r0,8(%r5) # get device status
213 chi %r0,8 # channel end ?
214 be .Lcont
215 chi %r0,12 # channel end + device end ?
216 be .Lcont
217
218 l %r0,4(%r5)
219 s %r0,8(%r3) # r0/8 = number of ccws executed
220 mhi %r0,10 # *10 = number of bytes in ccws
221 lh %r3,10(%r5) # get residual count
222 sr %r0,%r3 # #ccws*80-residual=#bytes read
223 ar %r2,%r0
224
225 br %r14 # r2 contains the total size
226
227.Lcont:
228 ahi %r2,0x640 # add 0x640 to total size
229 la %r6,.Lccws
230 la %r7,20
231.Lincr:
232 l %r0,4(%r6) # update CCW data addresses
233 ahi %r0,0x640
234 st %r0,4(%r6)
235 ahi %r6,8
236 bct 7,.Lincr
237
238 b .Lldlp
239.Llderr:
240 lpsw .Lcrash
241
242 .align 8
243.Lorb: .long 0x00000000,0x0080ff00,.Lccws
244.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
245.Lcr6: .long 0xff000000
246.Lloadp:.long 0,0
247 .align 8
248.Lcrash:.long 0x000a0000,0x00000000
249.Lnewpsw:
250 .long 0x00080000,0x80000000+.Lioint
251.Lwaitpsw:
252 .long 0x020a0000,0x80000000+.Lioint
253
254 .align 8
255.Lccws: .rept 19
256 .long 0x02600050,0x00000000
257 .endr
258 .long 0x02200050,0x00000000
259#endif /* CONFIG_IPL_VM */
260
261iplstart:
262 lh %r1,0xb8 # test if subchannel number
263 bct %r1,.Lnoload # is valid
264 l %r1,0xb8 # load ipl subchannel number
265 la %r2,IPL_BS # load start address
266 bas %r14,.Lloader # load rest of ipl image
267 larl %r12,_pstart # pointer to parameter area
268 st %r1,IPL_DEVICE+4-PARMAREA(%r12) # store ipl device number
269
270#
271# load parameter file from ipl device
272#
273.Lagain1:
274 l %r2,INITRD_START+4-PARMAREA(%r12)# use ramdisk location as temp
275 bas %r14,.Lloader # load parameter file
276 ltr %r2,%r2 # got anything ?
277 bz .Lnopf
278 chi %r2,895
279 bnh .Lnotrunc
280 la %r2,895
281.Lnotrunc:
282 l %r4,INITRD_START+4-PARMAREA(%r12)
283 clc 0(3,%r4),.L_hdr # if it is HDRx
284 bz .Lagain1 # skip dataset header
285 clc 0(3,%r4),.L_eof # if it is EOFx
286 bz .Lagain1 # skip dateset trailer
287 la %r5,0(%r4,%r2)
288 lr %r3,%r2
289.Lidebc:
290 tm 0(%r5),0x80 # high order bit set ?
291 bo .Ldocv # yes -> convert from EBCDIC
292 ahi %r5,-1
293 bct %r3,.Lidebc
294 b .Lnocv
295.Ldocv:
296 l %r3,.Lcvtab
297 tr 0(256,%r4),0(%r3) # convert parameters to ascii
298 tr 256(256,%r4),0(%r3)
299 tr 512(256,%r4),0(%r3)
300 tr 768(122,%r4),0(%r3)
301.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
302 mvc 0(256,%r3),0(%r4)
303 mvc 256(256,%r3),256(%r4)
304 mvc 512(256,%r3),512(%r4)
305 mvc 768(122,%r3),768(%r4)
306 slr %r0,%r0
307 b .Lcntlp
308.Ldelspc:
309 ic %r0,0(%r2,%r3)
310 chi %r0,0x20 # is it a space ?
311 be .Lcntlp
312 ahi %r2,1
313 b .Leolp
314.Lcntlp:
315 brct %r2,.Ldelspc
316.Leolp:
317 slr %r0,%r0
318 stc %r0,0(%r2,%r3) # terminate buffer
319.Lnopf:
320
321#
322# load ramdisk from ipl device
323#
324.Lagain2:
325 l %r2,INITRD_START+4-PARMAREA(%r12)# load adr. of ramdisk
326 bas %r14,.Lloader # load ramdisk
327 st %r2,INITRD_SIZE+4-PARMAREA(%r12) # store size of ramdisk
328 ltr %r2,%r2
329 bnz .Lrdcont
330 st %r2,INITRD_START+4-PARMAREA(%r12)# no ramdisk found, null it
331.Lrdcont:
332 l %r2,INITRD_START+4-PARMAREA(%r12)
333 clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
334 bz .Lagain2
335 clc 0(3,%r2),.L_eof
336 bz .Lagain2
337
338#ifdef CONFIG_IPL_VM
339#
340# reset files in VM reader
341#
342 stidp __LC_CPUID # store cpuid
343 tm __LC_CPUID,0xff # running VM ?
344 bno .Lnoreset
345 la %r2,.Lreset
346 lhi %r3,26
347 .long 0x83230008
348.Lnoreset:
349#endif
350
351#
352# everything loaded, go for it
353#
354.Lnoload:
355 l %r1,.Lstartup
356 br %r1
357
358.Lstartup: .long startup
359.Lcvtab:.long _ebcasc # ebcdic to ascii table
360.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
361 .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
362 .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
363.L_eof: .long 0xc5d6c600 /* C'EOF' */
364.L_hdr: .long 0xc8c4d900 /* C'HDR' */
365#endif /* CONFIG_IPL */
366
367#
368# SALIPL loader support. Based on a patch by Rob van der Heij.
369# This entry point is called directly from the SALIPL loader and
370# doesn't need a builtin ipl record.
371#
372 .org 0x800
373 .globl start
374start:
375 stm %r0,%r15,0x07b0 # store registers
376 basr %r12,%r0
377.base:
378 l %r11,.parm
379 l %r8,.cmd # pointer to command buffer
380
381 ltr %r9,%r9 # do we have SALIPL parameters?
382 bp .sk8x8
383
384 mvc 0(64,%r8),0x00b0 # copy saved registers
385 xc 64(240-64,%r8),0(%r8) # remainder of buffer
386 tr 0(64,%r8),.lowcase
387 b .gotr
388.sk8x8:
389 mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
390.gotr:
391 l %r10,.tbl # EBCDIC to ASCII table
392 tr 0(240,%r8),0(%r10)
393 stidp __LC_CPUID # Are we running on VM maybe
394 cli __LC_CPUID,0xff
395 bnz .test
396 .long 0x83300060 # diag 3,0,x'0060' - storage size
397 b .done
398.test:
399 mvc 0x68(8),.pgmnw # set up pgm check handler
400 l %r2,.fourmeg
401 lr %r3,%r2
402 bctr %r3,%r0 # 4M-1
403.loop: iske %r0,%r3
404 ar %r3,%r2
405.pgmx:
406 sr %r3,%r2
407 la %r3,1(%r3)
408.done:
409 l %r1,.memsize
410 st %r3,4(%r1)
411 slr %r0,%r0
412 st %r0,INITRD_SIZE+4-PARMAREA(%r11)
413 st %r0,INITRD_START+4-PARMAREA(%r11)
414 j startup # continue with startup
415.tbl: .long _ebcasc # translate table
416.cmd: .long COMMAND_LINE # address of command line buffer
417.parm: .long PARMAREA
418.fourmeg: .long 0x00400000 # 4M
419.pgmnw: .long 0x00080000,.pgmx
420.memsize: .long memory_size
421.lowcase:
422 .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
423 .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
424 .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
425 .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
426 .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
427 .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
428 .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
429 .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
430 .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
431 .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
432 .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
433 .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
434 .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
435 .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
436 .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
437 .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
438
439 .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
440 .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
441 .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
442 .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
443 .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
444 .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
445 .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
446 .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
447 .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
448 .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi
449 .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
450 .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr
451 .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx
452 .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz
453 .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
454 .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
455
456#
457# startup-code at 0x10000, running in real mode
458# this is called either by the ipl loader or directly by PSW restart
459# or linload or SALIPL
460#
461 .org 0x10000
462startup:basr %r13,0 # get base
463.LPG1: sll %r13,1 # remove high order bit
464 srl %r13,1
465 lhi %r1,1 # mode 1 = esame
466 slr %r0,%r0 # set cpuid to zero
467 sigp %r1,%r0,0x12 # switch to esame mode
468 sam64 # switch to 64 bit mode
469 lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
470 larl %r12,_pstart # pointer to parameter area
471 # move IPL device to lowcore
472 mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
473
474#
475# clear bss memory
476#
477 larl %r2,__bss_start # start of bss segment
478 larl %r3,_end # end of bss segment
479 sgr %r3,%r2 # length of bss
480 sgr %r4,%r4 #
481 sgr %r5,%r5 # set src,length and pad to zero
482 mvcle %r2,%r4,0 # clear mem
483 jo .-4 # branch back, if not finish
484
485 l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
486.Lservicecall:
487 stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts
488
489 stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0
490 la %r1,0x200 # set bit 22
491 og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1
492 stg %r1,.Lcr-.LPG1(%r13)
493 lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0
494
495 mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw
496 larl %r1,.Lsclph
497 stg %r1,__LC_EXT_NEW_PSW+8 # set handler
498
499 larl %r4,_pstart # %r4 is our index for sccb stuff
500 la %r1,.Lsccb-PARMAREA(%r4) # our sccb
501 .insn rre,0xb2200000,%r2,%r1 # service call
502 ipm %r1
503 srl %r1,28 # get cc code
504 xr %r3,%r3
505 chi %r1,3
506 be .Lfchunk-.LPG1(%r13) # leave
507 chi %r1,2
508 be .Lservicecall-.LPG1(%r13)
509 lpsw .Lwaitsclp-.LPG1(%r13)
510.Lsclph:
511 lh %r1,.Lsccbr-PARMAREA(%r4)
512 chi %r1,0x10 # 0x0010 is the sucess code
513 je .Lprocsccb # let's process the sccb
514 chi %r1,0x1f0
515 bne .Lfchunk-.LPG1(%r13) # unhandled error code
516 c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced
517 bne .Lfchunk-.LPG1(%r13) # if no, give up
518 l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP
519 b .Lservicecall-.LPG1(%r13)
520.Lprocsccb:
521 lh %r1,.Lscpincr1-PARMAREA(%r4) # use this one if != 0
522 chi %r1,0x00
523 jne .Lscnd
524 lg %r1,.Lscpincr2-PARMAREA(%r4) # otherwise use this one
525.Lscnd:
526 xr %r3,%r3 # same logic
527 ic %r3,.Lscpa1-PARMAREA(%r4)
528 chi %r3,0x00
529 jne .Lcompmem
530 l %r3,.Lscpa2-PARMAREA(%r13)
531.Lcompmem:
532 mlgr %r2,%r1 # mem in MB on 128-bit
533 l %r1,.Lonemb-.LPG1(%r13)
534 mlgr %r2,%r1 # mem size in bytes in %r3
535 b .Lfchunk-.LPG1(%r13)
536
537.Lpmask:
538 .byte 0
539 .align 8
540.Lcr:
541 .quad 0x00 # place holder for cr0
542.Lwaitsclp:
543 .long 0x020A0000
544 .quad .Lsclph
545.Lrcp:
546 .int 0x00120001 # Read SCP forced code
547.Lrcp2:
548 .int 0x00020001 # Read SCP code
549.Lonemb:
550 .int 0x100000
551
552.Lfchunk:
553 # set program check new psw mask
554 mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
555
556#
557# find memory chunks.
558#
559 lgr %r9,%r3 # end of mem
560 larl %r1,.Lchkmem # set program check address
561 stg %r1,__LC_PGM_NEW_PSW+8
562 la %r1,1 # test in increments of 128KB
563 sllg %r1,%r1,17
564 larl %r3,memory_chunk
565 slgr %r4,%r4 # set start of chunk to zero
566 slgr %r5,%r5 # set end of chunk to zero
567 slr %r6,%r6 # set access code to zero
568 la %r10,MEMORY_CHUNKS # number of chunks
569.Lloop:
570 tprot 0(%r5),0 # test protection of first byte
571 ipm %r7
572 srl %r7,28
573 clr %r6,%r7 # compare cc with last access code
574 je .Lsame
575 j .Lchkmem
576.Lsame:
577 algr %r5,%r1 # add 128KB to end of chunk
578 # no need to check here,
579 brc 12,.Lloop # this is the same chunk
580.Lchkmem: # > 16EB or tprot got a program check
581 clgr %r4,%r5 # chunk size > 0?
582 je .Lchkloop
583 stg %r4,0(%r3) # store start address of chunk
584 lgr %r0,%r5
585 slgr %r0,%r4
586 stg %r0,8(%r3) # store size of chunk
587 st %r6,20(%r3) # store type of chunk
588 la %r3,24(%r3)
589 larl %r8,memory_size
590 stg %r5,0(%r8) # store memory size
591 ahi %r10,-1 # update chunk number
592.Lchkloop:
593 lr %r6,%r7 # set access code to last cc
594 # we got an exception or we're starting a new
595 # chunk , we must check if we should
596 # still try to find valid memory (if we detected
597 # the amount of available storage), and if we
598 # have chunks left
599 lghi %r4,1
600 sllg %r4,%r4,31
601 clgr %r5,%r4
602 je .Lhsaskip
603 xr %r0, %r0
604 clgr %r0, %r9 # did we detect memory?
605 je .Ldonemem # if not, leave
606 chi %r10, 0 # do we have chunks left?
607 je .Ldonemem
608.Lhsaskip:
609 algr %r5,%r1 # add 128KB to end of chunk
610 lgr %r4,%r5 # potential new chunk
611 clgr %r5,%r9 # should we go on?
612 jl .Lloop
613.Ldonemem:
614
615 larl %r12,machine_flags
616#
617# find out if we are running under VM
618#
619 stidp __LC_CPUID # store cpuid
620 tm __LC_CPUID,0xff # running under VM ?
621 bno 0f-.LPG1(%r13)
622 oi 7(%r12),1 # set VM flag
6230: lh %r0,__LC_CPUID+4 # get cpu version
624 chi %r0,0x7490 # running on a P/390 ?
625 bne 1f-.LPG1(%r13)
626 oi 7(%r12),4 # set P/390 flag
6271:
628
629#
630# find out if we have the MVPG instruction
631#
632 la %r1,0f-.LPG1(%r13) # set program check address
633 stg %r1,__LC_PGM_NEW_PSW+8
634 sgr %r0,%r0
635 lghi %r1,0
636 lghi %r2,0
637 mvpg %r1,%r2 # test MVPG instruction
638 oi 7(%r12),16 # set MVPG flag
6390:
640
641#
642# find out if the diag 0x44 works in 64 bit mode
643#
644 la %r1,0f-.LPG1(%r13) # set program check address
645 stg %r1,__LC_PGM_NEW_PSW+8
646 mvc __LC_DIAG44_OPCODE(8),.Lnop-.LPG1(%r13)
647 diag 0,0,0x44 # test diag 0x44
648 oi 7(%r12),32 # set diag44 flag
649 mvc __LC_DIAG44_OPCODE(8),.Ldiag44-.LPG1(%r13)
6500:
651
652#
653# find out if we have the IDTE instruction
654#
655 la %r1,0f-.LPG1(%r13) # set program check address
656 stg %r1,__LC_PGM_NEW_PSW+8
657 .long 0xb2b10000 # store facility list
658 tm 0xc8,0x08 # check bit for clearing-by-ASCE
659 bno 0f-.LPG1(%r13)
660 lhi %r1,2094
661 lhi %r2,0
662 .long 0xb98e2001
663 oi 7(%r12),0x80 # set IDTE flag
6640:
665
666 lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
667 # virtual and never return ...
668 .align 16
669.Lentry:.quad 0x0000000180000000,_stext
670.Lctl: .quad 0x04b50002 # cr0: various things
671 .quad 0 # cr1: primary space segment table
672 .quad .Lduct # cr2: dispatchable unit control table
673 .quad 0 # cr3: instruction authorization
674 .quad 0 # cr4: instruction authorization
675 .quad 0xffffffffffffffff # cr5: primary-aste origin
676 .quad 0 # cr6: I/O interrupts
677 .quad 0 # cr7: secondary space segment table
678 .quad 0 # cr8: access registers translation
679 .quad 0 # cr9: tracing off
680 .quad 0 # cr10: tracing off
681 .quad 0 # cr11: tracing off
682 .quad 0 # cr12: tracing off
683 .quad 0 # cr13: home space segment table
684 .quad 0xc0000000 # cr14: machine check handling off
685 .quad 0 # cr15: linkage stack operations
686.Lpcmsk:.quad 0x0000000180000000
687.L4malign:.quad 0xffffffffffc00000
688.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
689.Lnop: .long 0x07000700
690.Ldiag44:.long 0x83000044
691
692 .org PARMAREA-64
693.Lduct: .long 0,0,0,0,0,0,0,0
694 .long 0,0,0,0,0,0,0,0
695
696#
697# params at 10400 (setup.h)
698#
699 .org PARMAREA
700 .global _pstart
701_pstart:
702 .quad 0 # IPL_DEVICE
703 .quad RAMDISK_ORIGIN # INITRD_START
704 .quad RAMDISK_SIZE # INITRD_SIZE
705
706 .org COMMAND_LINE
707 .byte "root=/dev/ram0 ro"
708 .byte 0
709 .org 0x11000
710.Lsccb:
711 .hword 0x1000 # length, one page
712 .byte 0x00,0x00,0x00
713 .byte 0x80 # variable response bit set
714.Lsccbr:
715 .hword 0x00 # response code
716.Lscpincr1:
717 .hword 0x00
718.Lscpa1:
719 .byte 0x00
720 .fill 89,1,0
721.Lscpa2:
722 .int 0x00
723.Lscpincr2:
724 .quad 0x00
725 .fill 3984,1,0
726 .org 0x12000
727 .global _pend
728_pend:
729
730#ifdef CONFIG_SHARED_KERNEL
731 .org 0x100000
732#endif
733
734#
735# startup-code, running in virtual mode
736#
737 .globl _stext
738_stext: basr %r13,0 # get base
739.LPG2:
740#
741# Setup stack
742#
743 larl %r15,init_thread_union
744 lg %r14,__TI_task(%r15) # cache current in lowcore
745 stg %r14,__LC_CURRENT
746 aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
747 stg %r15,__LC_KERNEL_STACK # set end of kernel stack
748 aghi %r15,-160
749 xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
750
751# check control registers
752 stctg %c0,%c15,0(%r15)
753 oi 6(%r15),0x20 # enable sigp external interrupts
754 oi 4(%r15),0x10 # switch on low address proctection
755 lctlg %c0,%c15,0(%r15)
756
757#
758 lam 0,15,.Laregs-.LPG2(%r13) # load access regs needed by uaccess
759 brasl %r14,start_kernel # go to C code
760#
761# We returned from start_kernel ?!? PANIK
762#
763 basr %r13,0
764 lpswe .Ldw-.(%r13) # load disabled wait psw
765#
766 .align 8
767.Ldw: .quad 0x0002000180000000,0x0000000000000000
768.Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
769
diff --git a/arch/s390/kernel/init_task.c b/arch/s390/kernel/init_task.c
new file mode 100644
index 000000000000..d73a74013e73
--- /dev/null
+++ b/arch/s390/kernel/init_task.c
@@ -0,0 +1,44 @@
1/*
2 * arch/s390/kernel/init_task.c
3 *
4 * S390 version
5 *
6 * Derived from "arch/i386/kernel/init_task.c"
7 */
8
9#include <linux/mm.h>
10#include <linux/module.h>
11#include <linux/sched.h>
12#include <linux/init_task.h>
13#include <linux/mqueue.h>
14
15#include <asm/uaccess.h>
16#include <asm/pgtable.h>
17
18static struct fs_struct init_fs = INIT_FS;
19static struct files_struct init_files = INIT_FILES;
20static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
21static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
22struct mm_struct init_mm = INIT_MM(init_mm);
23
24EXPORT_SYMBOL(init_mm);
25
26/*
27 * Initial thread structure.
28 *
29 * We need to make sure that this is 8192-byte aligned due to the
30 * way process stacks are handled. This is done by having a special
31 * "init_task" linker map entry..
32 */
33union thread_union init_thread_union
34 __attribute__((__section__(".data.init_task"))) =
35 { INIT_THREAD_INFO(init_task) };
36
37/*
38 * Initial task structure.
39 *
40 * All other task structs will be allocated on slabs in fork.c
41 */
42struct task_struct init_task = INIT_TASK(init_task);
43
44EXPORT_SYMBOL(init_task);
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
new file mode 100644
index 000000000000..480b6a5fef3a
--- /dev/null
+++ b/arch/s390/kernel/irq.c
@@ -0,0 +1,105 @@
1/*
2 * arch/s390/kernel/irq.c
3 *
4 * S390 version
5 * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 *
8 * This file contains interrupt related functions.
9 */
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/kernel_stat.h>
14#include <linux/interrupt.h>
15#include <linux/seq_file.h>
16#include <linux/cpu.h>
17
18/*
19 * show_interrupts is needed by /proc/interrupts.
20 */
21int show_interrupts(struct seq_file *p, void *v)
22{
23 static const char *intrclass_names[] = { "EXT", "I/O", };
24 int i = *(loff_t *) v, j;
25
26 if (i == 0) {
27 seq_puts(p, " ");
28 for_each_online_cpu(j)
29 seq_printf(p, "CPU%d ",j);
30 seq_putc(p, '\n');
31 }
32
33 if (i < NR_IRQS) {
34 seq_printf(p, "%s: ", intrclass_names[i]);
35#ifndef CONFIG_SMP
36 seq_printf(p, "%10u ", kstat_irqs(i));
37#else
38 for_each_online_cpu(j)
39 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
40#endif
41 seq_putc(p, '\n');
42
43 }
44
45 return 0;
46}
47
48/*
49 * For compatibilty only. S/390 specific setup of interrupts et al. is done
50 * much later in init_channel_subsystem().
51 */
52void __init
53init_IRQ(void)
54{
55 /* nothing... */
56}
57
58/*
59 * Switch to the asynchronous interrupt stack for softirq execution.
60 */
61extern void __do_softirq(void);
62
63asmlinkage void do_softirq(void)
64{
65 unsigned long flags, old, new;
66
67 if (in_interrupt())
68 return;
69
70 local_irq_save(flags);
71
72 account_system_vtime(current);
73
74 local_bh_disable();
75
76 if (local_softirq_pending()) {
77 /* Get current stack pointer. */
78 asm volatile("la %0,0(15)" : "=a" (old));
79 /* Check against async. stack address range. */
80 new = S390_lowcore.async_stack;
81 if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) {
82 /* Need to switch to the async. stack. */
83 new -= STACK_FRAME_OVERHEAD;
84 ((struct stack_frame *) new)->back_chain = old;
85
86 asm volatile(" la 15,0(%0)\n"
87 " basr 14,%2\n"
88 " la 15,0(%1)\n"
89 : : "a" (new), "a" (old),
90 "a" (__do_softirq)
91 : "0", "1", "2", "3", "4", "5", "14",
92 "cc", "memory" );
93 } else
94 /* We are already on the async stack. */
95 __do_softirq();
96 }
97
98 account_system_vtime(current);
99
100 __local_bh_enable();
101
102 local_irq_restore(flags);
103}
104
105EXPORT_SYMBOL(do_softirq);
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
new file mode 100644
index 000000000000..607d506689c8
--- /dev/null
+++ b/arch/s390/kernel/module.c
@@ -0,0 +1,405 @@
1/*
2 * arch/s390/kernel/module.c - Kernel module help for s390.
3 *
4 * S390 version
5 * Copyright (C) 2002, 2003 IBM Deutschland Entwicklung GmbH,
6 * IBM Corporation
7 * Author(s): Arnd Bergmann (arndb@de.ibm.com)
8 * Martin Schwidefsky (schwidefsky@de.ibm.com)
9 *
10 * based on i386 version
11 * Copyright (C) 2001 Rusty Russell.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27#include <linux/module.h>
28#include <linux/elf.h>
29#include <linux/vmalloc.h>
30#include <linux/fs.h>
31#include <linux/string.h>
32#include <linux/kernel.h>
33
34#if 0
35#define DEBUGP printk
36#else
37#define DEBUGP(fmt , ...)
38#endif
39
40#ifndef CONFIG_ARCH_S390X
41#define PLT_ENTRY_SIZE 12
42#else /* CONFIG_ARCH_S390X */
43#define PLT_ENTRY_SIZE 20
44#endif /* CONFIG_ARCH_S390X */
45
46void *module_alloc(unsigned long size)
47{
48 if (size == 0)
49 return NULL;
50 return vmalloc(size);
51}
52
53/* Free memory returned from module_alloc */
54void module_free(struct module *mod, void *module_region)
55{
56 vfree(module_region);
57 /* FIXME: If module_region == mod->init_region, trim exception
58 table entries. */
59}
60
61static inline void
62check_rela(Elf_Rela *rela, struct module *me)
63{
64 struct mod_arch_syminfo *info;
65
66 info = me->arch.syminfo + ELF_R_SYM (rela->r_info);
67 switch (ELF_R_TYPE (rela->r_info)) {
68 case R_390_GOT12: /* 12 bit GOT offset. */
69 case R_390_GOT16: /* 16 bit GOT offset. */
70 case R_390_GOT20: /* 20 bit GOT offset. */
71 case R_390_GOT32: /* 32 bit GOT offset. */
72 case R_390_GOT64: /* 64 bit GOT offset. */
73 case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */
74 case R_390_GOTPLT12: /* 12 bit offset to jump slot. */
75 case R_390_GOTPLT16: /* 16 bit offset to jump slot. */
76 case R_390_GOTPLT20: /* 20 bit offset to jump slot. */
77 case R_390_GOTPLT32: /* 32 bit offset to jump slot. */
78 case R_390_GOTPLT64: /* 64 bit offset to jump slot. */
79 case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */
80 if (info->got_offset == -1UL) {
81 info->got_offset = me->arch.got_size;
82 me->arch.got_size += sizeof(void*);
83 }
84 break;
85 case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
86 case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
87 case R_390_PLT32: /* 32 bit PC relative PLT address. */
88 case R_390_PLT64: /* 64 bit PC relative PLT address. */
89 case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */
90 case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
91 case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
92 if (info->plt_offset == -1UL) {
93 info->plt_offset = me->arch.plt_size;
94 me->arch.plt_size += PLT_ENTRY_SIZE;
95 }
96 break;
97 case R_390_COPY:
98 case R_390_GLOB_DAT:
99 case R_390_JMP_SLOT:
100 case R_390_RELATIVE:
101 /* Only needed if we want to support loading of
102 modules linked with -shared. */
103 break;
104 }
105}
106
107/*
108 * Account for GOT and PLT relocations. We can't add sections for
109 * got and plt but we can increase the core module size.
110 */
111int
112module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
113 char *secstrings, struct module *me)
114{
115 Elf_Shdr *symtab;
116 Elf_Sym *symbols;
117 Elf_Rela *rela;
118 char *strings;
119 int nrela, i, j;
120
121 /* Find symbol table and string table. */
122 symtab = 0;
123 for (i = 0; i < hdr->e_shnum; i++)
124 switch (sechdrs[i].sh_type) {
125 case SHT_SYMTAB:
126 symtab = sechdrs + i;
127 break;
128 }
129 if (!symtab) {
130 printk(KERN_ERR "module %s: no symbol table\n", me->name);
131 return -ENOEXEC;
132 }
133
134 /* Allocate one syminfo structure per symbol. */
135 me->arch.nsyms = symtab->sh_size / sizeof(Elf_Sym);
136 me->arch.syminfo = vmalloc(me->arch.nsyms *
137 sizeof(struct mod_arch_syminfo));
138 if (!me->arch.syminfo)
139 return -ENOMEM;
140 symbols = (void *) hdr + symtab->sh_offset;
141 strings = (void *) hdr + sechdrs[symtab->sh_link].sh_offset;
142 for (i = 0; i < me->arch.nsyms; i++) {
143 if (symbols[i].st_shndx == SHN_UNDEF &&
144 strcmp(strings + symbols[i].st_name,
145 "_GLOBAL_OFFSET_TABLE_") == 0)
146 /* "Define" it as absolute. */
147 symbols[i].st_shndx = SHN_ABS;
148 me->arch.syminfo[i].got_offset = -1UL;
149 me->arch.syminfo[i].plt_offset = -1UL;
150 me->arch.syminfo[i].got_initialized = 0;
151 me->arch.syminfo[i].plt_initialized = 0;
152 }
153
154 /* Search for got/plt relocations. */
155 me->arch.got_size = me->arch.plt_size = 0;
156 for (i = 0; i < hdr->e_shnum; i++) {
157 if (sechdrs[i].sh_type != SHT_RELA)
158 continue;
159 nrela = sechdrs[i].sh_size / sizeof(Elf_Rela);
160 rela = (void *) hdr + sechdrs[i].sh_offset;
161 for (j = 0; j < nrela; j++)
162 check_rela(rela + j, me);
163 }
164
165 /* Increase core size by size of got & plt and set start
166 offsets for got and plt. */
167 me->core_size = ALIGN(me->core_size, 4);
168 me->arch.got_offset = me->core_size;
169 me->core_size += me->arch.got_size;
170 me->arch.plt_offset = me->core_size;
171 me->core_size += me->arch.plt_size;
172 return 0;
173}
174
175int
176apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
177 unsigned int relsec, struct module *me)
178{
179 printk(KERN_ERR "module %s: RELOCATION unsupported\n",
180 me->name);
181 return -ENOEXEC;
182}
183
184static inline int
185apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
186 struct module *me)
187{
188 struct mod_arch_syminfo *info;
189 Elf_Addr loc, val;
190 int r_type, r_sym;
191
192 /* This is where to make the change */
193 loc = base + rela->r_offset;
194 /* This is the symbol it is referring to. Note that all
195 undefined symbols have been resolved. */
196 r_sym = ELF_R_SYM(rela->r_info);
197 r_type = ELF_R_TYPE(rela->r_info);
198 info = me->arch.syminfo + r_sym;
199 val = symtab[r_sym].st_value;
200
201 switch (r_type) {
202 case R_390_8: /* Direct 8 bit. */
203 case R_390_12: /* Direct 12 bit. */
204 case R_390_16: /* Direct 16 bit. */
205 case R_390_20: /* Direct 20 bit. */
206 case R_390_32: /* Direct 32 bit. */
207 case R_390_64: /* Direct 64 bit. */
208 val += rela->r_addend;
209 if (r_type == R_390_8)
210 *(unsigned char *) loc = val;
211 else if (r_type == R_390_12)
212 *(unsigned short *) loc = (val & 0xfff) |
213 (*(unsigned short *) loc & 0xf000);
214 else if (r_type == R_390_16)
215 *(unsigned short *) loc = val;
216 else if (r_type == R_390_20)
217 *(unsigned int *) loc =
218 (*(unsigned int *) loc & 0xf00000ff) |
219 (val & 0xfff) << 16 | (val & 0xff000) >> 4;
220 else if (r_type == R_390_32)
221 *(unsigned int *) loc = val;
222 else if (r_type == R_390_64)
223 *(unsigned long *) loc = val;
224 break;
225 case R_390_PC16: /* PC relative 16 bit. */
226 case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */
227 case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */
228 case R_390_PC32: /* PC relative 32 bit. */
229 case R_390_PC64: /* PC relative 64 bit. */
230 val += rela->r_addend - loc;
231 if (r_type == R_390_PC16)
232 *(unsigned short *) loc = val;
233 else if (r_type == R_390_PC16DBL)
234 *(unsigned short *) loc = val >> 1;
235 else if (r_type == R_390_PC32DBL)
236 *(unsigned int *) loc = val >> 1;
237 else if (r_type == R_390_PC32)
238 *(unsigned int *) loc = val;
239 else if (r_type == R_390_PC64)
240 *(unsigned long *) loc = val;
241 break;
242 case R_390_GOT12: /* 12 bit GOT offset. */
243 case R_390_GOT16: /* 16 bit GOT offset. */
244 case R_390_GOT20: /* 20 bit GOT offset. */
245 case R_390_GOT32: /* 32 bit GOT offset. */
246 case R_390_GOT64: /* 64 bit GOT offset. */
247 case R_390_GOTENT: /* 32 bit PC rel. to GOT entry shifted by 1. */
248 case R_390_GOTPLT12: /* 12 bit offset to jump slot. */
249 case R_390_GOTPLT20: /* 20 bit offset to jump slot. */
250 case R_390_GOTPLT16: /* 16 bit offset to jump slot. */
251 case R_390_GOTPLT32: /* 32 bit offset to jump slot. */
252 case R_390_GOTPLT64: /* 64 bit offset to jump slot. */
253 case R_390_GOTPLTENT: /* 32 bit rel. offset to jump slot >> 1. */
254 if (info->got_initialized == 0) {
255 Elf_Addr *gotent;
256
257 gotent = me->module_core + me->arch.got_offset +
258 info->got_offset;
259 *gotent = val;
260 info->got_initialized = 1;
261 }
262 val = info->got_offset + rela->r_addend;
263 if (r_type == R_390_GOT12 ||
264 r_type == R_390_GOTPLT12)
265 *(unsigned short *) loc = (val & 0xfff) |
266 (*(unsigned short *) loc & 0xf000);
267 else if (r_type == R_390_GOT16 ||
268 r_type == R_390_GOTPLT16)
269 *(unsigned short *) loc = val;
270 else if (r_type == R_390_GOT20 ||
271 r_type == R_390_GOTPLT20)
272 *(unsigned int *) loc =
273 (*(unsigned int *) loc & 0xf00000ff) |
274 (val & 0xfff) << 16 | (val & 0xff000) >> 4;
275 else if (r_type == R_390_GOT32 ||
276 r_type == R_390_GOTPLT32)
277 *(unsigned int *) loc = val;
278 else if (r_type == R_390_GOTENT ||
279 r_type == R_390_GOTPLTENT)
280 *(unsigned int *) loc =
281 (val + (Elf_Addr) me->module_core - loc) >> 1;
282 else if (r_type == R_390_GOT64 ||
283 r_type == R_390_GOTPLT64)
284 *(unsigned long *) loc = val;
285 break;
286 case R_390_PLT16DBL: /* 16 bit PC rel. PLT shifted by 1. */
287 case R_390_PLT32DBL: /* 32 bit PC rel. PLT shifted by 1. */
288 case R_390_PLT32: /* 32 bit PC relative PLT address. */
289 case R_390_PLT64: /* 64 bit PC relative PLT address. */
290 case R_390_PLTOFF16: /* 16 bit offset from GOT to PLT. */
291 case R_390_PLTOFF32: /* 32 bit offset from GOT to PLT. */
292 case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */
293 if (info->plt_initialized == 0) {
294 unsigned int *ip;
295 ip = me->module_core + me->arch.plt_offset +
296 info->plt_offset;
297#ifndef CONFIG_ARCH_S390X
298 ip[0] = 0x0d105810; /* basr 1,0; l 1,6(1); br 1 */
299 ip[1] = 0x100607f1;
300 ip[2] = val;
301#else /* CONFIG_ARCH_S390X */
302 ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
303 ip[1] = 0x100a0004;
304 ip[2] = 0x07f10000;
305 ip[3] = (unsigned int) (val >> 32);
306 ip[4] = (unsigned int) val;
307#endif /* CONFIG_ARCH_S390X */
308 info->plt_initialized = 1;
309 }
310 if (r_type == R_390_PLTOFF16 ||
311 r_type == R_390_PLTOFF32
312 || r_type == R_390_PLTOFF64
313 )
314 val = me->arch.plt_offset - me->arch.got_offset +
315 info->plt_offset + rela->r_addend;
316 else
317 val = (Elf_Addr) me->module_core +
318 me->arch.plt_offset + info->plt_offset +
319 rela->r_addend - loc;
320 if (r_type == R_390_PLT16DBL)
321 *(unsigned short *) loc = val >> 1;
322 else if (r_type == R_390_PLTOFF16)
323 *(unsigned short *) loc = val;
324 else if (r_type == R_390_PLT32DBL)
325 *(unsigned int *) loc = val >> 1;
326 else if (r_type == R_390_PLT32 ||
327 r_type == R_390_PLTOFF32)
328 *(unsigned int *) loc = val;
329 else if (r_type == R_390_PLT64 ||
330 r_type == R_390_PLTOFF64)
331 *(unsigned long *) loc = val;
332 break;
333 case R_390_GOTOFF16: /* 16 bit offset to GOT. */
334 case R_390_GOTOFF32: /* 32 bit offset to GOT. */
335 case R_390_GOTOFF64: /* 64 bit offset to GOT. */
336 val = val + rela->r_addend -
337 ((Elf_Addr) me->module_core + me->arch.got_offset);
338 if (r_type == R_390_GOTOFF16)
339 *(unsigned short *) loc = val;
340 else if (r_type == R_390_GOTOFF32)
341 *(unsigned int *) loc = val;
342 else if (r_type == R_390_GOTOFF64)
343 *(unsigned long *) loc = val;
344 break;
345 case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */
346 case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */
347 val = (Elf_Addr) me->module_core + me->arch.got_offset +
348 rela->r_addend - loc;
349 if (r_type == R_390_GOTPC)
350 *(unsigned int *) loc = val;
351 else if (r_type == R_390_GOTPCDBL)
352 *(unsigned int *) loc = val >> 1;
353 break;
354 case R_390_COPY:
355 case R_390_GLOB_DAT: /* Create GOT entry. */
356 case R_390_JMP_SLOT: /* Create PLT entry. */
357 case R_390_RELATIVE: /* Adjust by program base. */
358 /* Only needed if we want to support loading of
359 modules linked with -shared. */
360 break;
361 default:
362 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
363 me->name, r_type);
364 return -ENOEXEC;
365 }
366 return 0;
367}
368
369int
370apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
371 unsigned int symindex, unsigned int relsec,
372 struct module *me)
373{
374 Elf_Addr base;
375 Elf_Sym *symtab;
376 Elf_Rela *rela;
377 unsigned long i, n;
378 int rc;
379
380 DEBUGP("Applying relocate section %u to %u\n",
381 relsec, sechdrs[relsec].sh_info);
382 base = sechdrs[sechdrs[relsec].sh_info].sh_addr;
383 symtab = (Elf_Sym *) sechdrs[symindex].sh_addr;
384 rela = (Elf_Rela *) sechdrs[relsec].sh_addr;
385 n = sechdrs[relsec].sh_size / sizeof(Elf_Rela);
386
387 for (i = 0; i < n; i++, rela++) {
388 rc = apply_rela(rela, base, symtab, me);
389 if (rc)
390 return rc;
391 }
392 return 0;
393}
394
395int module_finalize(const Elf_Ehdr *hdr,
396 const Elf_Shdr *sechdrs,
397 struct module *me)
398{
399 vfree(me->arch.syminfo);
400 return 0;
401}
402
403void module_arch_cleanup(struct module *mod)
404{
405}
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
new file mode 100644
index 000000000000..7aea25d6e300
--- /dev/null
+++ b/arch/s390/kernel/process.c
@@ -0,0 +1,416 @@
1/*
2 * arch/s390/kernel/process.c
3 *
4 * S390 version
5 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 * Hartmut Penner (hp@de.ibm.com),
8 * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
9 *
10 * Derived from "arch/i386/kernel/process.c"
11 * Copyright (C) 1995, Linus Torvalds
12 */
13
14/*
15 * This file handles the architecture-dependent parts of process handling..
16 */
17
18#include <linux/config.h>
19#include <linux/compiler.h>
20#include <linux/cpu.h>
21#include <linux/errno.h>
22#include <linux/sched.h>
23#include <linux/kernel.h>
24#include <linux/mm.h>
25#include <linux/smp.h>
26#include <linux/smp_lock.h>
27#include <linux/stddef.h>
28#include <linux/unistd.h>
29#include <linux/ptrace.h>
30#include <linux/slab.h>
31#include <linux/vmalloc.h>
32#include <linux/user.h>
33#include <linux/a.out.h>
34#include <linux/interrupt.h>
35#include <linux/delay.h>
36#include <linux/reboot.h>
37#include <linux/init.h>
38#include <linux/module.h>
39#include <linux/notifier.h>
40
41#include <asm/uaccess.h>
42#include <asm/pgtable.h>
43#include <asm/system.h>
44#include <asm/io.h>
45#include <asm/processor.h>
46#include <asm/irq.h>
47#include <asm/timer.h>
48
49asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
50
51/*
52 * Return saved PC of a blocked thread. used in kernel/sched.
53 * resume in entry.S does not create a new stack frame, it
54 * just stores the registers %r6-%r15 to the frame given by
55 * schedule. We want to return the address of the caller of
56 * schedule, so we have to walk the backchain one time to
57 * find the frame schedule() store its return address.
58 */
59unsigned long thread_saved_pc(struct task_struct *tsk)
60{
61 struct stack_frame *sf;
62
63 sf = (struct stack_frame *) tsk->thread.ksp;
64 sf = (struct stack_frame *) sf->back_chain;
65 return sf->gprs[8];
66}
67
68/*
69 * Need to know about CPUs going idle?
70 */
71static struct notifier_block *idle_chain;
72
73int register_idle_notifier(struct notifier_block *nb)
74{
75 return notifier_chain_register(&idle_chain, nb);
76}
77EXPORT_SYMBOL(register_idle_notifier);
78
79int unregister_idle_notifier(struct notifier_block *nb)
80{
81 return notifier_chain_unregister(&idle_chain, nb);
82}
83EXPORT_SYMBOL(unregister_idle_notifier);
84
85void do_monitor_call(struct pt_regs *regs, long interruption_code)
86{
87 /* disable monitor call class 0 */
88 __ctl_clear_bit(8, 15);
89
90 notifier_call_chain(&idle_chain, CPU_NOT_IDLE,
91 (void *)(long) smp_processor_id());
92}
93
94/*
95 * The idle loop on a S390...
96 */
97void default_idle(void)
98{
99 psw_t wait_psw;
100 unsigned long reg;
101 int cpu, rc;
102
103 local_irq_disable();
104 if (need_resched()) {
105 local_irq_enable();
106 schedule();
107 return;
108 }
109
110 /* CPU is going idle. */
111 cpu = smp_processor_id();
112 rc = notifier_call_chain(&idle_chain, CPU_IDLE, (void *)(long) cpu);
113 if (rc != NOTIFY_OK && rc != NOTIFY_DONE)
114 BUG();
115 if (rc != NOTIFY_OK) {
116 local_irq_enable();
117 return;
118 }
119
120 /* enable monitor call class 0 */
121 __ctl_set_bit(8, 15);
122
123#ifdef CONFIG_HOTPLUG_CPU
124 if (cpu_is_offline(smp_processor_id()))
125 cpu_die();
126#endif
127
128 /*
129 * Wait for external, I/O or machine check interrupt and
130 * switch off machine check bit after the wait has ended.
131 */
132 wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
133 PSW_MASK_IO | PSW_MASK_EXT;
134#ifndef CONFIG_ARCH_S390X
135 asm volatile (
136 " basr %0,0\n"
137 "0: la %0,1f-0b(%0)\n"
138 " st %0,4(%1)\n"
139 " oi 4(%1),0x80\n"
140 " lpsw 0(%1)\n"
141 "1: la %0,2f-1b(%0)\n"
142 " st %0,4(%1)\n"
143 " oi 4(%1),0x80\n"
144 " ni 1(%1),0xf9\n"
145 " lpsw 0(%1)\n"
146 "2:"
147 : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
148#else /* CONFIG_ARCH_S390X */
149 asm volatile (
150 " larl %0,0f\n"
151 " stg %0,8(%1)\n"
152 " lpswe 0(%1)\n"
153 "0: larl %0,1f\n"
154 " stg %0,8(%1)\n"
155 " ni 1(%1),0xf9\n"
156 " lpswe 0(%1)\n"
157 "1:"
158 : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
159#endif /* CONFIG_ARCH_S390X */
160}
161
162void cpu_idle(void)
163{
164 for (;;)
165 default_idle();
166}
167
168void show_regs(struct pt_regs *regs)
169{
170 struct task_struct *tsk = current;
171
172 printk("CPU: %d %s\n", tsk->thread_info->cpu, print_tainted());
173 printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
174 current->comm, current->pid, (void *) tsk,
175 (void *) tsk->thread.ksp);
176
177 show_registers(regs);
178 /* Show stack backtrace if pt_regs is from kernel mode */
179 if (!(regs->psw.mask & PSW_MASK_PSTATE))
180 show_trace(0,(unsigned long *) regs->gprs[15]);
181}
182
183extern void kernel_thread_starter(void);
184
185__asm__(".align 4\n"
186 "kernel_thread_starter:\n"
187 " la 2,0(10)\n"
188 " basr 14,9\n"
189 " la 2,0\n"
190 " br 11\n");
191
192int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
193{
194 struct pt_regs regs;
195
196 memset(&regs, 0, sizeof(regs));
197 regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
198 regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
199 regs.gprs[9] = (unsigned long) fn;
200 regs.gprs[10] = (unsigned long) arg;
201 regs.gprs[11] = (unsigned long) do_exit;
202 regs.orig_gpr2 = -1;
203
204 /* Ok, create the new process.. */
205 return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
206 0, &regs, 0, NULL, NULL);
207}
208
209/*
210 * Free current thread data structures etc..
211 */
212void exit_thread(void)
213{
214}
215
216void flush_thread(void)
217{
218 clear_used_math();
219 clear_tsk_thread_flag(current, TIF_USEDFPU);
220}
221
222void release_thread(struct task_struct *dead_task)
223{
224}
225
226int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
227 unsigned long unused,
228 struct task_struct * p, struct pt_regs * regs)
229{
230 struct fake_frame
231 {
232 struct stack_frame sf;
233 struct pt_regs childregs;
234 } *frame;
235
236 frame = ((struct fake_frame *)
237 (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
238 p->thread.ksp = (unsigned long) frame;
239 /* Store access registers to kernel stack of new process. */
240 frame->childregs = *regs;
241 frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
242 frame->childregs.gprs[15] = new_stackp;
243 frame->sf.back_chain = 0;
244
245 /* new return point is ret_from_fork */
246 frame->sf.gprs[8] = (unsigned long) ret_from_fork;
247
248 /* fake return stack for resume(), don't go back to schedule */
249 frame->sf.gprs[9] = (unsigned long) frame;
250
251 /* Save access registers to new thread structure. */
252 save_access_regs(&p->thread.acrs[0]);
253
254#ifndef CONFIG_ARCH_S390X
255 /*
256 * save fprs to current->thread.fp_regs to merge them with
257 * the emulated registers and then copy the result to the child.
258 */
259 save_fp_regs(&current->thread.fp_regs);
260 memcpy(&p->thread.fp_regs, &current->thread.fp_regs,
261 sizeof(s390_fp_regs));
262 p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
263 /* Set a new TLS ? */
264 if (clone_flags & CLONE_SETTLS)
265 p->thread.acrs[0] = regs->gprs[6];
266#else /* CONFIG_ARCH_S390X */
267 /* Save the fpu registers to new thread structure. */
268 save_fp_regs(&p->thread.fp_regs);
269 p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
270 /* Set a new TLS ? */
271 if (clone_flags & CLONE_SETTLS) {
272 if (test_thread_flag(TIF_31BIT)) {
273 p->thread.acrs[0] = (unsigned int) regs->gprs[6];
274 } else {
275 p->thread.acrs[0] = (unsigned int)(regs->gprs[6] >> 32);
276 p->thread.acrs[1] = (unsigned int) regs->gprs[6];
277 }
278 }
279#endif /* CONFIG_ARCH_S390X */
280 /* start new process with ar4 pointing to the correct address space */
281 p->thread.mm_segment = get_fs();
282 /* Don't copy debug registers */
283 memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
284
285 return 0;
286}
287
288asmlinkage long sys_fork(struct pt_regs regs)
289{
290 return do_fork(SIGCHLD, regs.gprs[15], &regs, 0, NULL, NULL);
291}
292
293asmlinkage long sys_clone(struct pt_regs regs)
294{
295 unsigned long clone_flags;
296 unsigned long newsp;
297 int __user *parent_tidptr, *child_tidptr;
298
299 clone_flags = regs.gprs[3];
300 newsp = regs.orig_gpr2;
301 parent_tidptr = (int __user *) regs.gprs[4];
302 child_tidptr = (int __user *) regs.gprs[5];
303 if (!newsp)
304 newsp = regs.gprs[15];
305 return do_fork(clone_flags, newsp, &regs, 0,
306 parent_tidptr, child_tidptr);
307}
308
309/*
310 * This is trivial, and on the face of it looks like it
311 * could equally well be done in user mode.
312 *
313 * Not so, for quite unobvious reasons - register pressure.
314 * In user mode vfork() cannot have a stack frame, and if
315 * done by calling the "clone()" system call directly, you
316 * do not have enough call-clobbered registers to hold all
317 * the information you need.
318 */
319asmlinkage long sys_vfork(struct pt_regs regs)
320{
321 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
322 regs.gprs[15], &regs, 0, NULL, NULL);
323}
324
325/*
326 * sys_execve() executes a new program.
327 */
328asmlinkage long sys_execve(struct pt_regs regs)
329{
330 int error;
331 char * filename;
332
333 filename = getname((char __user *) regs.orig_gpr2);
334 error = PTR_ERR(filename);
335 if (IS_ERR(filename))
336 goto out;
337 error = do_execve(filename, (char __user * __user *) regs.gprs[3],
338 (char __user * __user *) regs.gprs[4], &regs);
339 if (error == 0) {
340 task_lock(current);
341 current->ptrace &= ~PT_DTRACE;
342 task_unlock(current);
343 current->thread.fp_regs.fpc = 0;
344 if (MACHINE_HAS_IEEE)
345 asm volatile("sfpc %0,%0" : : "d" (0));
346 }
347 putname(filename);
348out:
349 return error;
350}
351
352
353/*
354 * fill in the FPU structure for a core dump.
355 */
356int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
357{
358#ifndef CONFIG_ARCH_S390X
359 /*
360 * save fprs to current->thread.fp_regs to merge them with
361 * the emulated registers and then copy the result to the dump.
362 */
363 save_fp_regs(&current->thread.fp_regs);
364 memcpy(fpregs, &current->thread.fp_regs, sizeof(s390_fp_regs));
365#else /* CONFIG_ARCH_S390X */
366 save_fp_regs(fpregs);
367#endif /* CONFIG_ARCH_S390X */
368 return 1;
369}
370
371/*
372 * fill in the user structure for a core dump..
373 */
374void dump_thread(struct pt_regs * regs, struct user * dump)
375{
376
377/* changed the size calculations - should hopefully work better. lbt */
378 dump->magic = CMAGIC;
379 dump->start_code = 0;
380 dump->start_stack = regs->gprs[15] & ~(PAGE_SIZE - 1);
381 dump->u_tsize = current->mm->end_code >> PAGE_SHIFT;
382 dump->u_dsize = (current->mm->brk + PAGE_SIZE - 1) >> PAGE_SHIFT;
383 dump->u_dsize -= dump->u_tsize;
384 dump->u_ssize = 0;
385 if (dump->start_stack < TASK_SIZE)
386 dump->u_ssize = (TASK_SIZE - dump->start_stack) >> PAGE_SHIFT;
387 memcpy(&dump->regs, regs, sizeof(s390_regs));
388 dump_fpu (regs, &dump->regs.fp_regs);
389 dump->regs.per_info = current->thread.per_info;
390}
391
392unsigned long get_wchan(struct task_struct *p)
393{
394 struct stack_frame *sf, *low, *high;
395 unsigned long return_address;
396 int count;
397
398 if (!p || p == current || p->state == TASK_RUNNING || !p->thread_info)
399 return 0;
400 low = (struct stack_frame *) p->thread_info;
401 high = (struct stack_frame *)
402 ((unsigned long) p->thread_info + THREAD_SIZE) - 1;
403 sf = (struct stack_frame *) (p->thread.ksp & PSW_ADDR_INSN);
404 if (sf <= low || sf > high)
405 return 0;
406 for (count = 0; count < 16; count++) {
407 sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN);
408 if (sf <= low || sf > high)
409 return 0;
410 return_address = sf->gprs[8] & PSW_ADDR_INSN;
411 if (!in_sched_functions(return_address))
412 return return_address;
413 }
414 return 0;
415}
416
diff --git a/arch/s390/kernel/profile.c b/arch/s390/kernel/profile.c
new file mode 100644
index 000000000000..7ba777eec1a8
--- /dev/null
+++ b/arch/s390/kernel/profile.c
@@ -0,0 +1,20 @@
1/*
2 * arch/s390/kernel/profile.c
3 *
4 * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
5 * Author(s): Thomas Spatzier (tspat@de.ibm.com)
6 *
7 */
8#include <linux/proc_fs.h>
9#include <linux/profile.h>
10
11static struct proc_dir_entry * root_irq_dir;
12
13void init_irq_proc(void)
14{
15 /* create /proc/irq */
16 root_irq_dir = proc_mkdir("irq", 0);
17
18 /* create /proc/irq/prof_cpu_mask */
19 create_prof_cpu_mask(root_irq_dir);
20}
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
new file mode 100644
index 000000000000..647233c02fc8
--- /dev/null
+++ b/arch/s390/kernel/ptrace.c
@@ -0,0 +1,738 @@
1/*
2 * arch/s390/kernel/ptrace.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
7 * Martin Schwidefsky (schwidefsky@de.ibm.com)
8 *
9 * Based on PowerPC version
10 * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
11 *
12 * Derived from "arch/m68k/kernel/ptrace.c"
13 * Copyright (C) 1994 by Hamish Macdonald
14 * Taken from linux/kernel/ptrace.c and modified for M680x0.
15 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
16 *
17 * Modified by Cort Dougan (cort@cs.nmt.edu)
18 *
19 *
20 * This file is subject to the terms and conditions of the GNU General
21 * Public License. See the file README.legal in the main directory of
22 * this archive for more details.
23 */
24
25#include <linux/kernel.h>
26#include <linux/sched.h>
27#include <linux/mm.h>
28#include <linux/smp.h>
29#include <linux/smp_lock.h>
30#include <linux/errno.h>
31#include <linux/ptrace.h>
32#include <linux/user.h>
33#include <linux/security.h>
34#include <linux/audit.h>
35
36#include <asm/segment.h>
37#include <asm/page.h>
38#include <asm/pgtable.h>
39#include <asm/pgalloc.h>
40#include <asm/system.h>
41#include <asm/uaccess.h>
42
43#ifdef CONFIG_S390_SUPPORT
44#include "compat_ptrace.h"
45#endif
46
47static void
48FixPerRegisters(struct task_struct *task)
49{
50 struct pt_regs *regs;
51 per_struct *per_info;
52
53 regs = __KSTK_PTREGS(task);
54 per_info = (per_struct *) &task->thread.per_info;
55 per_info->control_regs.bits.em_instruction_fetch =
56 per_info->single_step | per_info->instruction_fetch;
57
58 if (per_info->single_step) {
59 per_info->control_regs.bits.starting_addr = 0;
60#ifdef CONFIG_S390_SUPPORT
61 if (test_thread_flag(TIF_31BIT))
62 per_info->control_regs.bits.ending_addr = 0x7fffffffUL;
63 else
64#endif
65 per_info->control_regs.bits.ending_addr = PSW_ADDR_INSN;
66 } else {
67 per_info->control_regs.bits.starting_addr =
68 per_info->starting_addr;
69 per_info->control_regs.bits.ending_addr =
70 per_info->ending_addr;
71 }
72 /*
73 * if any of the control reg tracing bits are on
74 * we switch on per in the psw
75 */
76 if (per_info->control_regs.words.cr[0] & PER_EM_MASK)
77 regs->psw.mask |= PSW_MASK_PER;
78 else
79 regs->psw.mask &= ~PSW_MASK_PER;
80
81 if (per_info->control_regs.bits.em_storage_alteration)
82 per_info->control_regs.bits.storage_alt_space_ctl = 1;
83 else
84 per_info->control_regs.bits.storage_alt_space_ctl = 0;
85}
86
87void
88set_single_step(struct task_struct *task)
89{
90 task->thread.per_info.single_step = 1;
91 FixPerRegisters(task);
92}
93
94void
95clear_single_step(struct task_struct *task)
96{
97 task->thread.per_info.single_step = 0;
98 FixPerRegisters(task);
99}
100
101/*
102 * Called by kernel/ptrace.c when detaching..
103 *
104 * Make sure single step bits etc are not set.
105 */
106void
107ptrace_disable(struct task_struct *child)
108{
109 /* make sure the single step bit is not set. */
110 clear_single_step(child);
111}
112
113#ifndef CONFIG_ARCH_S390X
114# define __ADDR_MASK 3
115#else
116# define __ADDR_MASK 7
117#endif
118
119/*
120 * Read the word at offset addr from the user area of a process. The
121 * trouble here is that the information is littered over different
122 * locations. The process registers are found on the kernel stack,
123 * the floating point stuff and the trace settings are stored in
124 * the task structure. In addition the different structures in
125 * struct user contain pad bytes that should be read as zeroes.
126 * Lovely...
127 */
128static int
129peek_user(struct task_struct *child, addr_t addr, addr_t data)
130{
131 struct user *dummy = NULL;
132 addr_t offset, tmp;
133
134 /*
135 * Stupid gdb peeks/pokes the access registers in 64 bit with
136 * an alignment of 4. Programmers from hell...
137 */
138 if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
139 return -EIO;
140
141 if (addr < (addr_t) &dummy->regs.acrs) {
142 /*
143 * psw and gprs are stored on the stack
144 */
145 tmp = *(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr);
146 if (addr == (addr_t) &dummy->regs.psw.mask)
147 /* Remove per bit from user psw. */
148 tmp &= ~PSW_MASK_PER;
149
150 } else if (addr < (addr_t) &dummy->regs.orig_gpr2) {
151 /*
152 * access registers are stored in the thread structure
153 */
154 offset = addr - (addr_t) &dummy->regs.acrs;
155 tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
156
157 } else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
158 /*
159 * orig_gpr2 is stored on the kernel stack
160 */
161 tmp = (addr_t) __KSTK_PTREGS(child)->orig_gpr2;
162
163 } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
164 /*
165 * floating point regs. are stored in the thread structure
166 */
167 offset = addr - (addr_t) &dummy->regs.fp_regs;
168 tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
169
170 } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
171 /*
172 * per_info is found in the thread structure
173 */
174 offset = addr - (addr_t) &dummy->regs.per_info;
175 tmp = *(addr_t *)((addr_t) &child->thread.per_info + offset);
176
177 } else
178 tmp = 0;
179
180 return put_user(tmp, (addr_t __user *) data);
181}
182
183/*
184 * Write a word to the user area of a process at location addr. This
185 * operation does have an additional problem compared to peek_user.
186 * Stores to the program status word and on the floating point
187 * control register needs to get checked for validity.
188 */
189static int
190poke_user(struct task_struct *child, addr_t addr, addr_t data)
191{
192 struct user *dummy = NULL;
193 addr_t offset;
194
195 /*
196 * Stupid gdb peeks/pokes the access registers in 64 bit with
197 * an alignment of 4. Programmers from hell indeed...
198 */
199 if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
200 return -EIO;
201
202 if (addr < (addr_t) &dummy->regs.acrs) {
203 /*
204 * psw and gprs are stored on the stack
205 */
206 if (addr == (addr_t) &dummy->regs.psw.mask &&
207#ifdef CONFIG_S390_SUPPORT
208 data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&
209#endif
210 data != PSW_MASK_MERGE(PSW_USER_BITS, data))
211 /* Invalid psw mask. */
212 return -EINVAL;
213#ifndef CONFIG_ARCH_S390X
214 if (addr == (addr_t) &dummy->regs.psw.addr)
215 /* I'd like to reject addresses without the
216 high order bit but older gdb's rely on it */
217 data |= PSW_ADDR_AMODE;
218#endif
219 *(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr) = data;
220
221 } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
222 /*
223 * access registers are stored in the thread structure
224 */
225 offset = addr - (addr_t) &dummy->regs.acrs;
226 *(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
227
228 } else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
229 /*
230 * orig_gpr2 is stored on the kernel stack
231 */
232 __KSTK_PTREGS(child)->orig_gpr2 = data;
233
234 } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
235 /*
236 * floating point regs. are stored in the thread structure
237 */
238 if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
239 (data & ~FPC_VALID_MASK) != 0)
240 return -EINVAL;
241 offset = addr - (addr_t) &dummy->regs.fp_regs;
242 *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
243
244 } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
245 /*
246 * per_info is found in the thread structure
247 */
248 offset = addr - (addr_t) &dummy->regs.per_info;
249 *(addr_t *)((addr_t) &child->thread.per_info + offset) = data;
250
251 }
252
253 FixPerRegisters(child);
254 return 0;
255}
256
257static int
258do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
259{
260 unsigned long tmp;
261 ptrace_area parea;
262 int copied, ret;
263
264 switch (request) {
265 case PTRACE_PEEKTEXT:
266 case PTRACE_PEEKDATA:
267 /* Remove high order bit from address (only for 31 bit). */
268 addr &= PSW_ADDR_INSN;
269 /* read word at location addr. */
270 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
271 if (copied != sizeof(tmp))
272 return -EIO;
273 return put_user(tmp, (unsigned long __user *) data);
274
275 case PTRACE_PEEKUSR:
276 /* read the word at location addr in the USER area. */
277 return peek_user(child, addr, data);
278
279 case PTRACE_POKETEXT:
280 case PTRACE_POKEDATA:
281 /* Remove high order bit from address (only for 31 bit). */
282 addr &= PSW_ADDR_INSN;
283 /* write the word at location addr. */
284 copied = access_process_vm(child, addr, &data, sizeof(data),1);
285 if (copied != sizeof(data))
286 return -EIO;
287 return 0;
288
289 case PTRACE_POKEUSR:
290 /* write the word at location addr in the USER area */
291 return poke_user(child, addr, data);
292
293 case PTRACE_PEEKUSR_AREA:
294 case PTRACE_POKEUSR_AREA:
295 if (copy_from_user(&parea, (void __user *) addr,
296 sizeof(parea)))
297 return -EFAULT;
298 addr = parea.kernel_addr;
299 data = parea.process_addr;
300 copied = 0;
301 while (copied < parea.len) {
302 if (request == PTRACE_PEEKUSR_AREA)
303 ret = peek_user(child, addr, data);
304 else {
305 addr_t tmp;
306 if (get_user (tmp, (addr_t __user *) data))
307 return -EFAULT;
308 ret = poke_user(child, addr, tmp);
309 }
310 if (ret)
311 return ret;
312 addr += sizeof(unsigned long);
313 data += sizeof(unsigned long);
314 copied += sizeof(unsigned long);
315 }
316 return 0;
317 }
318 return ptrace_request(child, request, addr, data);
319}
320
321#ifdef CONFIG_S390_SUPPORT
322/*
323 * Now the fun part starts... a 31 bit program running in the
324 * 31 bit emulation tracing another program. PTRACE_PEEKTEXT,
325 * PTRACE_PEEKDATA, PTRACE_POKETEXT and PTRACE_POKEDATA are easy
326 * to handle, the difference to the 64 bit versions of the requests
327 * is that the access is done in multiples of 4 byte instead of
328 * 8 bytes (sizeof(unsigned long) on 31/64 bit).
329 * The ugly part are PTRACE_PEEKUSR, PTRACE_PEEKUSR_AREA,
330 * PTRACE_POKEUSR and PTRACE_POKEUSR_AREA. If the traced program
331 * is a 31 bit program too, the content of struct user can be
332 * emulated. A 31 bit program peeking into the struct user of
333 * a 64 bit program is a no-no.
334 */
335
336/*
337 * Same as peek_user but for a 31 bit program.
338 */
339static int
340peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
341{
342 struct user32 *dummy32 = NULL;
343 per_struct32 *dummy_per32 = NULL;
344 addr_t offset;
345 __u32 tmp;
346
347 if (!test_thread_flag(TIF_31BIT) ||
348 (addr & 3) || addr > sizeof(struct user) - 3)
349 return -EIO;
350
351 if (addr < (addr_t) &dummy32->regs.acrs) {
352 /*
353 * psw and gprs are stored on the stack
354 */
355 if (addr == (addr_t) &dummy32->regs.psw.mask) {
356 /* Fake a 31 bit psw mask. */
357 tmp = (__u32)(__KSTK_PTREGS(child)->psw.mask >> 32);
358 tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp);
359 } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
360 /* Fake a 31 bit psw address. */
361 tmp = (__u32) __KSTK_PTREGS(child)->psw.addr |
362 PSW32_ADDR_AMODE31;
363 } else {
364 /* gpr 0-15 */
365 tmp = *(__u32 *)((addr_t) &__KSTK_PTREGS(child)->psw +
366 addr*2 + 4);
367 }
368 } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
369 /*
370 * access registers are stored in the thread structure
371 */
372 offset = addr - (addr_t) &dummy32->regs.acrs;
373 tmp = *(__u32*)((addr_t) &child->thread.acrs + offset);
374
375 } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) {
376 /*
377 * orig_gpr2 is stored on the kernel stack
378 */
379 tmp = *(__u32*)((addr_t) &__KSTK_PTREGS(child)->orig_gpr2 + 4);
380
381 } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
382 /*
383 * floating point regs. are stored in the thread structure
384 */
385 offset = addr - (addr_t) &dummy32->regs.fp_regs;
386 tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset);
387
388 } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
389 /*
390 * per_info is found in the thread structure
391 */
392 offset = addr - (addr_t) &dummy32->regs.per_info;
393 /* This is magic. See per_struct and per_struct32. */
394 if ((offset >= (addr_t) &dummy_per32->control_regs &&
395 offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
396 (offset >= (addr_t) &dummy_per32->starting_addr &&
397 offset <= (addr_t) &dummy_per32->ending_addr) ||
398 offset == (addr_t) &dummy_per32->lowcore.words.address)
399 offset = offset*2 + 4;
400 else
401 offset = offset*2;
402 tmp = *(__u32 *)((addr_t) &child->thread.per_info + offset);
403
404 } else
405 tmp = 0;
406
407 return put_user(tmp, (__u32 __user *) data);
408}
409
410/*
411 * Same as poke_user but for a 31 bit program.
412 */
413static int
414poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
415{
416 struct user32 *dummy32 = NULL;
417 per_struct32 *dummy_per32 = NULL;
418 addr_t offset;
419 __u32 tmp;
420
421 if (!test_thread_flag(TIF_31BIT) ||
422 (addr & 3) || addr > sizeof(struct user32) - 3)
423 return -EIO;
424
425 tmp = (__u32) data;
426
427 if (addr < (addr_t) &dummy32->regs.acrs) {
428 /*
429 * psw, gprs, acrs and orig_gpr2 are stored on the stack
430 */
431 if (addr == (addr_t) &dummy32->regs.psw.mask) {
432 /* Build a 64 bit psw mask from 31 bit mask. */
433 if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp))
434 /* Invalid psw mask. */
435 return -EINVAL;
436 __KSTK_PTREGS(child)->psw.mask =
437 PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32);
438 } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
439 /* Build a 64 bit psw address from 31 bit address. */
440 __KSTK_PTREGS(child)->psw.addr =
441 (__u64) tmp & PSW32_ADDR_INSN;
442 } else {
443 /* gpr 0-15 */
444 *(__u32*)((addr_t) &__KSTK_PTREGS(child)->psw
445 + addr*2 + 4) = tmp;
446 }
447 } else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
448 /*
449 * access registers are stored in the thread structure
450 */
451 offset = addr - (addr_t) &dummy32->regs.acrs;
452 *(__u32*)((addr_t) &child->thread.acrs + offset) = tmp;
453
454 } else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) {
455 /*
456 * orig_gpr2 is stored on the kernel stack
457 */
458 *(__u32*)((addr_t) &__KSTK_PTREGS(child)->orig_gpr2 + 4) = tmp;
459
460 } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
461 /*
462 * floating point regs. are stored in the thread structure
463 */
464 if (addr == (addr_t) &dummy32->regs.fp_regs.fpc &&
465 (tmp & ~FPC_VALID_MASK) != 0)
466 /* Invalid floating point control. */
467 return -EINVAL;
468 offset = addr - (addr_t) &dummy32->regs.fp_regs;
469 *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp;
470
471 } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
472 /*
473 * per_info is found in the thread structure.
474 */
475 offset = addr - (addr_t) &dummy32->regs.per_info;
476 /*
477 * This is magic. See per_struct and per_struct32.
478 * By incident the offsets in per_struct are exactly
479 * twice the offsets in per_struct32 for all fields.
480 * The 8 byte fields need special handling though,
481 * because the second half (bytes 4-7) is needed and
482 * not the first half.
483 */
484 if ((offset >= (addr_t) &dummy_per32->control_regs &&
485 offset < (addr_t) (&dummy_per32->control_regs + 1)) ||
486 (offset >= (addr_t) &dummy_per32->starting_addr &&
487 offset <= (addr_t) &dummy_per32->ending_addr) ||
488 offset == (addr_t) &dummy_per32->lowcore.words.address)
489 offset = offset*2 + 4;
490 else
491 offset = offset*2;
492 *(__u32 *)((addr_t) &child->thread.per_info + offset) = tmp;
493
494 }
495
496 FixPerRegisters(child);
497 return 0;
498}
499
500static int
501do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
502{
503 unsigned int tmp; /* 4 bytes !! */
504 ptrace_area_emu31 parea;
505 int copied, ret;
506
507 switch (request) {
508 case PTRACE_PEEKTEXT:
509 case PTRACE_PEEKDATA:
510 /* read word at location addr. */
511 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
512 if (copied != sizeof(tmp))
513 return -EIO;
514 return put_user(tmp, (unsigned int __user *) data);
515
516 case PTRACE_PEEKUSR:
517 /* read the word at location addr in the USER area. */
518 return peek_user_emu31(child, addr, data);
519
520 case PTRACE_POKETEXT:
521 case PTRACE_POKEDATA:
522 /* write the word at location addr. */
523 tmp = data;
524 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
525 if (copied != sizeof(tmp))
526 return -EIO;
527 return 0;
528
529 case PTRACE_POKEUSR:
530 /* write the word at location addr in the USER area */
531 return poke_user_emu31(child, addr, data);
532
533 case PTRACE_PEEKUSR_AREA:
534 case PTRACE_POKEUSR_AREA:
535 if (copy_from_user(&parea, (void __user *) addr,
536 sizeof(parea)))
537 return -EFAULT;
538 addr = parea.kernel_addr;
539 data = parea.process_addr;
540 copied = 0;
541 while (copied < parea.len) {
542 if (request == PTRACE_PEEKUSR_AREA)
543 ret = peek_user_emu31(child, addr, data);
544 else {
545 __u32 tmp;
546 if (get_user (tmp, (__u32 __user *) data))
547 return -EFAULT;
548 ret = poke_user_emu31(child, addr, tmp);
549 }
550 if (ret)
551 return ret;
552 addr += sizeof(unsigned int);
553 data += sizeof(unsigned int);
554 copied += sizeof(unsigned int);
555 }
556 return 0;
557 case PTRACE_GETEVENTMSG:
558 return put_user((__u32) child->ptrace_message,
559 (unsigned int __user *) data);
560 case PTRACE_GETSIGINFO:
561 if (child->last_siginfo == NULL)
562 return -EINVAL;
563 return copy_siginfo_to_user32((compat_siginfo_t __user *) data,
564 child->last_siginfo);
565 case PTRACE_SETSIGINFO:
566 if (child->last_siginfo == NULL)
567 return -EINVAL;
568 return copy_siginfo_from_user32(child->last_siginfo,
569 (compat_siginfo_t __user *) data);
570 }
571 return ptrace_request(child, request, addr, data);
572}
573#endif
574
575#define PT32_IEEE_IP 0x13c
576
577static int
578do_ptrace(struct task_struct *child, long request, long addr, long data)
579{
580 int ret;
581
582 if (request == PTRACE_ATTACH)
583 return ptrace_attach(child);
584
585 /*
586 * Special cases to get/store the ieee instructions pointer.
587 */
588 if (child == current) {
589 if (request == PTRACE_PEEKUSR && addr == PT_IEEE_IP)
590 return peek_user(child, addr, data);
591 if (request == PTRACE_POKEUSR && addr == PT_IEEE_IP)
592 return poke_user(child, addr, data);
593#ifdef CONFIG_S390_SUPPORT
594 if (request == PTRACE_PEEKUSR &&
595 addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT))
596 return peek_user_emu31(child, addr, data);
597 if (request == PTRACE_POKEUSR &&
598 addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT))
599 return poke_user_emu31(child, addr, data);
600#endif
601 }
602
603 ret = ptrace_check_attach(child, request == PTRACE_KILL);
604 if (ret < 0)
605 return ret;
606
607 switch (request) {
608 case PTRACE_SYSCALL:
609 /* continue and stop at next (return from) syscall */
610 case PTRACE_CONT:
611 /* restart after signal. */
612 if ((unsigned long) data >= _NSIG)
613 return -EIO;
614 if (request == PTRACE_SYSCALL)
615 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
616 else
617 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
618 child->exit_code = data;
619 /* make sure the single step bit is not set. */
620 clear_single_step(child);
621 wake_up_process(child);
622 return 0;
623
624 case PTRACE_KILL:
625 /*
626 * make the child exit. Best I can do is send it a sigkill.
627 * perhaps it should be put in the status that it wants to
628 * exit.
629 */
630 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
631 return 0;
632 child->exit_code = SIGKILL;
633 /* make sure the single step bit is not set. */
634 clear_single_step(child);
635 wake_up_process(child);
636 return 0;
637
638 case PTRACE_SINGLESTEP:
639 /* set the trap flag. */
640 if ((unsigned long) data >= _NSIG)
641 return -EIO;
642 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
643 child->exit_code = data;
644 if (data)
645 set_tsk_thread_flag(child, TIF_SINGLE_STEP);
646 else
647 set_single_step(child);
648 /* give it a chance to run. */
649 wake_up_process(child);
650 return 0;
651
652 case PTRACE_DETACH:
653 /* detach a process that was attached. */
654 return ptrace_detach(child, data);
655
656
657 /* Do requests that differ for 31/64 bit */
658 default:
659#ifdef CONFIG_S390_SUPPORT
660 if (test_thread_flag(TIF_31BIT))
661 return do_ptrace_emu31(child, request, addr, data);
662#endif
663 return do_ptrace_normal(child, request, addr, data);
664 }
665 /* Not reached. */
666 return -EIO;
667}
668
669asmlinkage long
670sys_ptrace(long request, long pid, long addr, long data)
671{
672 struct task_struct *child;
673 int ret;
674
675 lock_kernel();
676
677 if (request == PTRACE_TRACEME) {
678 /* are we already being traced? */
679 ret = -EPERM;
680 if (current->ptrace & PT_PTRACED)
681 goto out;
682 ret = security_ptrace(current->parent, current);
683 if (ret)
684 goto out;
685 /* set the ptrace bit in the process flags. */
686 current->ptrace |= PT_PTRACED;
687 goto out;
688 }
689
690 ret = -EPERM;
691 if (pid == 1) /* you may not mess with init */
692 goto out;
693
694 ret = -ESRCH;
695 read_lock(&tasklist_lock);
696 child = find_task_by_pid(pid);
697 if (child)
698 get_task_struct(child);
699 read_unlock(&tasklist_lock);
700 if (!child)
701 goto out;
702
703 ret = do_ptrace(child, request, addr, data);
704
705 put_task_struct(child);
706out:
707 unlock_kernel();
708 return ret;
709}
710
711asmlinkage void
712syscall_trace(struct pt_regs *regs, int entryexit)
713{
714 if (unlikely(current->audit_context)) {
715 if (!entryexit)
716 audit_syscall_entry(current, regs->gprs[2],
717 regs->orig_gpr2, regs->gprs[3],
718 regs->gprs[4], regs->gprs[5]);
719 else
720 audit_syscall_exit(current, regs->gprs[2]);
721 }
722 if (!test_thread_flag(TIF_SYSCALL_TRACE))
723 return;
724 if (!(current->ptrace & PT_PTRACED))
725 return;
726 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
727 ? 0x80 : 0));
728
729 /*
730 * this isn't the same as continuing with a signal, but it will do
731 * for normal use. strace only continues with a signal if the
732 * stopping signal is not SIGTRAP. -brl
733 */
734 if (current->exit_code) {
735 send_sig(current->exit_code, current, 1);
736 current->exit_code = 0;
737 }
738}
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
new file mode 100644
index 000000000000..658e5ac484f9
--- /dev/null
+++ b/arch/s390/kernel/reipl.S
@@ -0,0 +1,78 @@
1/*
2 * arch/s390/kernel/reipl.S
3 *
4 * S390 version
5 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com)
7 */
8
9#include <asm/lowcore.h>
10
11 .globl do_reipl
12do_reipl: basr %r13,0
13.Lpg0: lpsw .Lnewpsw-.Lpg0(%r13)
14.Lpg1: lctl %c6,%c6,.Lall-.Lpg0(%r13)
15 stctl %c0,%c0,.Lctlsave-.Lpg0(%r13)
16 ni .Lctlsave-.Lpg0(%r13),0xef
17 lctl %c0,%c0,.Lctlsave-.Lpg0(%r13)
18 lr %r1,%r2
19 mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
20 stsch .Lschib-.Lpg0(%r13)
21 oi .Lschib+5-.Lpg0(%r13),0x84
22.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
23 msch .Lschib-.Lpg0(%r13)
24 lhi %r0,5
25.Lssch: ssch .Liplorb-.Lpg0(%r13)
26 jz .L001
27 brct %r0,.Lssch
28 bas %r14,.Ldisab-.Lpg0(%r13)
29.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)
30.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13)
31.Lcont: c %r1,__LC_SUBCHANNEL_ID
32 jnz .Ltpi
33 clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
34 jnz .Ltpi
35 tsch .Liplirb-.Lpg0(%r13)
36 tm .Liplirb+9-.Lpg0(%r13),0xbf
37 jz .L002
38 bas %r14,.Ldisab-.Lpg0(%r13)
39.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
40 jz .L003
41 bas %r14,.Ldisab-.Lpg0(%r13)
42.L003: spx .Lnull-.Lpg0(%r13)
43 st %r1,__LC_SUBCHANNEL_ID
44 lpsw 0
45 sigp 0,0,0(6)
46.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
47 lpsw .Ldispsw-.Lpg0(%r13)
48 .align 8
49.Lall: .long 0xff000000
50.Lnull: .long 0x00000000
51.Lctlsave: .long 0x00000000
52 .align 8
53.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1
54.Lpcnew: .long 0x00080000,0x80000000+.Lecs
55.Lionew: .long 0x00080000,0x80000000+.Lcont
56.Lwaitpsw: .long 0x020a0000,0x00000000+.Ltpi
57.Ldispsw: .long 0x000a0000,0x00000000
58.Liplccws: .long 0x02000000,0x60000018
59 .long 0x08000008,0x20000001
60.Liplorb: .long 0x0049504c,0x0040ff80
61 .long 0x00000000+.Liplccws
62.Lschib: .long 0x00000000,0x00000000
63 .long 0x00000000,0x00000000
64 .long 0x00000000,0x00000000
65 .long 0x00000000,0x00000000
66 .long 0x00000000,0x00000000
67 .long 0x00000000,0x00000000
68.Liplirb: .long 0x00000000,0x00000000
69 .long 0x00000000,0x00000000
70 .long 0x00000000,0x00000000
71 .long 0x00000000,0x00000000
72 .long 0x00000000,0x00000000
73 .long 0x00000000,0x00000000
74 .long 0x00000000,0x00000000
75 .long 0x00000000,0x00000000
76
77
78
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S
new file mode 100644
index 000000000000..4d090d60f3ef
--- /dev/null
+++ b/arch/s390/kernel/reipl64.S
@@ -0,0 +1,96 @@
1/*
2 * arch/s390/kernel/reipl.S
3 *
4 * S390 version
5 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com)
7 Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
8 */
9
10#include <asm/lowcore.h>
11 .globl do_reipl
12do_reipl: basr %r13,0
13.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
14.Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13)
15 stctg %c0,%c0,.Lctlsave-.Lpg0(%r13)
16 ni .Lctlsave+4-.Lpg0(%r13),0xef
17 lctlg %c0,%c0,.Lctlsave-.Lpg0(%r13)
18 lgr %r1,%r2
19 mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
20 stsch .Lschib-.Lpg0(%r13)
21 oi .Lschib+5-.Lpg0(%r13),0x84
22.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
23 msch .Lschib-.Lpg0(%r13)
24 lghi %r0,5
25.Lssch: ssch .Liplorb-.Lpg0(%r13)
26 jz .L001
27 brct %r0,.Lssch
28 bas %r14,.Ldisab-.Lpg0(%r13)
29.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)
30.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13)
31.Lcont: c %r1,__LC_SUBCHANNEL_ID
32 jnz .Ltpi
33 clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
34 jnz .Ltpi
35 tsch .Liplirb-.Lpg0(%r13)
36 tm .Liplirb+9-.Lpg0(%r13),0xbf
37 jz .L002
38 bas %r14,.Ldisab-.Lpg0(%r13)
39.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
40 jz .L003
41 bas %r14,.Ldisab-.Lpg0(%r13)
42.L003: spx .Lnull-.Lpg0(%r13)
43 st %r1,__LC_SUBCHANNEL_ID
44 lhi %r1,0 # mode 0 = esa
45 slr %r0,%r0 # set cpuid to zero
46 sigp %r1,%r0,0x12 # switch to esa mode
47 lpsw 0
48.Ldisab: sll %r14,1
49 srl %r14,1 # need to kill hi bit to avoid specification exceptions.
50 st %r14,.Ldispsw+12-.Lpg0(%r13)
51 lpswe .Ldispsw-.Lpg0(%r13)
52 .align 8
53.Lall: .quad 0x00000000ff000000
54.Lctlsave: .quad 0x0000000000000000
55.Lnull: .long 0x0000000000000000
56 .align 16
57/*
58 * These addresses have to be 31 bit otherwise
59 * the sigp will throw a specifcation exception
60 * when switching to ESA mode as bit 31 be set
61 * in the ESA psw.
62 * Bit 31 of the addresses has to be 0 for the
63 * 31bit lpswe instruction a fact they appear to have
64 * ommited from the pop.
65 */
66.Lnewpsw: .quad 0x0000000080000000
67 .quad .Lpg1
68.Lpcnew: .quad 0x0000000080000000
69 .quad .Lecs
70.Lionew: .quad 0x0000000080000000
71 .quad .Lcont
72.Lwaitpsw: .quad 0x0202000080000000
73 .quad .Ltpi
74.Ldispsw: .quad 0x0002000080000000
75 .quad 0x0000000000000000
76.Liplccws: .long 0x02000000,0x60000018
77 .long 0x08000008,0x20000001
78.Liplorb: .long 0x0049504c,0x0040ff80
79 .long 0x00000000+.Liplccws
80.Lschib: .long 0x00000000,0x00000000
81 .long 0x00000000,0x00000000
82 .long 0x00000000,0x00000000
83 .long 0x00000000,0x00000000
84 .long 0x00000000,0x00000000
85 .long 0x00000000,0x00000000
86.Liplirb: .long 0x00000000,0x00000000
87 .long 0x00000000,0x00000000
88 .long 0x00000000,0x00000000
89 .long 0x00000000,0x00000000
90 .long 0x00000000,0x00000000
91 .long 0x00000000,0x00000000
92 .long 0x00000000,0x00000000
93 .long 0x00000000,0x00000000
94
95
96
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
new file mode 100644
index 000000000000..3bdd38ec71da
--- /dev/null
+++ b/arch/s390/kernel/s390_ext.c
@@ -0,0 +1,135 @@
1/*
2 * arch/s390/kernel/s390_ext.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com),
7 * Martin Schwidefsky (schwidefsky@de.ibm.com)
8 */
9
10#include <linux/module.h>
11#include <linux/kernel.h>
12#include <linux/slab.h>
13#include <linux/errno.h>
14#include <linux/kernel_stat.h>
15#include <linux/interrupt.h>
16
17#include <asm/lowcore.h>
18#include <asm/s390_ext.h>
19#include <asm/irq.h>
20
21/*
22 * Simple hash strategy: index = code & 0xff;
23 * ext_int_hash[index] is the start of the list for all external interrupts
24 * that hash to this index. With the current set of external interrupts
25 * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
26 * iucv and 0x2603 pfault) this is always the first element.
27 */
28ext_int_info_t *ext_int_hash[256] = { 0, };
29
30int register_external_interrupt(__u16 code, ext_int_handler_t handler)
31{
32 ext_int_info_t *p;
33 int index;
34
35 p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
36 if (p == NULL)
37 return -ENOMEM;
38 p->code = code;
39 p->handler = handler;
40 index = code & 0xff;
41 p->next = ext_int_hash[index];
42 ext_int_hash[index] = p;
43 return 0;
44}
45
46int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
47 ext_int_info_t *p)
48{
49 int index;
50
51 if (p == NULL)
52 return -EINVAL;
53 p->code = code;
54 p->handler = handler;
55 index = code & 0xff;
56 p->next = ext_int_hash[index];
57 ext_int_hash[index] = p;
58 return 0;
59}
60
61int unregister_external_interrupt(__u16 code, ext_int_handler_t handler)
62{
63 ext_int_info_t *p, *q;
64 int index;
65
66 index = code & 0xff;
67 q = NULL;
68 p = ext_int_hash[index];
69 while (p != NULL) {
70 if (p->code == code && p->handler == handler)
71 break;
72 q = p;
73 p = p->next;
74 }
75 if (p == NULL)
76 return -ENOENT;
77 if (q != NULL)
78 q->next = p->next;
79 else
80 ext_int_hash[index] = p->next;
81 kfree(p);
82 return 0;
83}
84
85int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
86 ext_int_info_t *p)
87{
88 ext_int_info_t *q;
89 int index;
90
91 if (p == NULL || p->code != code || p->handler != handler)
92 return -EINVAL;
93 index = code & 0xff;
94 q = ext_int_hash[index];
95 if (p != q) {
96 while (q != NULL) {
97 if (q->next == p)
98 break;
99 q = q->next;
100 }
101 if (q == NULL)
102 return -ENOENT;
103 q->next = p->next;
104 } else
105 ext_int_hash[index] = p->next;
106 return 0;
107}
108
109void do_extint(struct pt_regs *regs, unsigned short code)
110{
111 ext_int_info_t *p;
112 int index;
113
114 irq_enter();
115 asm volatile ("mc 0,0");
116 if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
117 /**
118 * Make sure that the i/o interrupt did not "overtake"
119 * the last HZ timer interrupt.
120 */
121 account_ticks(regs);
122 kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
123 index = code & 0xff;
124 for (p = ext_int_hash[index]; p; p = p->next) {
125 if (likely(p->code == code)) {
126 if (likely(p->handler))
127 p->handler(regs, code);
128 }
129 }
130 irq_exit();
131}
132
133EXPORT_SYMBOL(register_external_interrupt);
134EXPORT_SYMBOL(unregister_external_interrupt);
135
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
new file mode 100644
index 000000000000..11fd6d556d8f
--- /dev/null
+++ b/arch/s390/kernel/s390_ksyms.c
@@ -0,0 +1,65 @@
1/*
2 * arch/s390/kernel/s390_ksyms.c
3 *
4 * S390 version
5 */
6#include <linux/config.h>
7#include <linux/highuid.h>
8#include <linux/module.h>
9#include <linux/mm.h>
10#include <linux/smp.h>
11#include <linux/syscalls.h>
12#include <linux/interrupt.h>
13#include <linux/ioctl32.h>
14#include <asm/checksum.h>
15#include <asm/cpcmd.h>
16#include <asm/delay.h>
17#include <asm/pgalloc.h>
18#include <asm/setup.h>
19#ifdef CONFIG_IP_MULTICAST
20#include <net/arp.h>
21#endif
22
23/*
24 * memory management
25 */
26EXPORT_SYMBOL(_oi_bitmap);
27EXPORT_SYMBOL(_ni_bitmap);
28EXPORT_SYMBOL(_zb_findmap);
29EXPORT_SYMBOL(_sb_findmap);
30EXPORT_SYMBOL(__copy_from_user_asm);
31EXPORT_SYMBOL(__copy_to_user_asm);
32EXPORT_SYMBOL(__copy_in_user_asm);
33EXPORT_SYMBOL(__clear_user_asm);
34EXPORT_SYMBOL(__strncpy_from_user_asm);
35EXPORT_SYMBOL(__strnlen_user_asm);
36EXPORT_SYMBOL(diag10);
37EXPORT_SYMBOL(default_storage_key);
38
39/*
40 * semaphore ops
41 */
42EXPORT_SYMBOL(__up);
43EXPORT_SYMBOL(__down);
44EXPORT_SYMBOL(__down_interruptible);
45
46/*
47 * binfmt_elf loader
48 */
49extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs);
50EXPORT_SYMBOL(dump_fpu);
51EXPORT_SYMBOL(overflowuid);
52EXPORT_SYMBOL(overflowgid);
53EXPORT_SYMBOL(empty_zero_page);
54
55/*
56 * misc.
57 */
58EXPORT_SYMBOL(machine_flags);
59EXPORT_SYMBOL(__udelay);
60EXPORT_SYMBOL(kernel_thread);
61EXPORT_SYMBOL(csum_fold);
62EXPORT_SYMBOL(console_mode);
63EXPORT_SYMBOL(console_devno);
64EXPORT_SYMBOL(console_irq);
65EXPORT_SYMBOL(sys_wait4);
diff --git a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c
new file mode 100644
index 000000000000..8dfb690c159f
--- /dev/null
+++ b/arch/s390/kernel/semaphore.c
@@ -0,0 +1,108 @@
1/*
2 * linux/arch/s390/kernel/semaphore.c
3 *
4 * S390 version
5 * Copyright (C) 1998-2000 IBM Corporation
6 * Author(s): Martin Schwidefsky
7 *
8 * Derived from "linux/arch/i386/kernel/semaphore.c
9 * Copyright (C) 1999, Linus Torvalds
10 *
11 */
12#include <linux/sched.h>
13#include <linux/errno.h>
14#include <linux/init.h>
15
16#include <asm/semaphore.h>
17
18/*
19 * Atomically update sem->count. Equivalent to:
20 * old_val = sem->count.counter;
21 * new_val = ((old_val >= 0) ? old_val : 0) + incr;
22 * sem->count.counter = new_val;
23 * return old_val;
24 */
25static inline int __sem_update_count(struct semaphore *sem, int incr)
26{
27 int old_val, new_val;
28
29 __asm__ __volatile__(" l %0,0(%3)\n"
30 "0: ltr %1,%0\n"
31 " jhe 1f\n"
32 " lhi %1,0\n"
33 "1: ar %1,%4\n"
34 " cs %0,%1,0(%3)\n"
35 " jl 0b\n"
36 : "=&d" (old_val), "=&d" (new_val),
37 "=m" (sem->count)
38 : "a" (&sem->count), "d" (incr), "m" (sem->count)
39 : "cc" );
40 return old_val;
41}
42
43/*
44 * The inline function up() incremented count but the result
45 * was <= 0. This indicates that some process is waiting on
46 * the semaphore. The semaphore is free and we'll wake the
47 * first sleeping process, so we set count to 1 unless some
48 * other cpu has called up in the meantime in which case
49 * we just increment count by 1.
50 */
51void __up(struct semaphore *sem)
52{
53 __sem_update_count(sem, 1);
54 wake_up(&sem->wait);
55}
56
57/*
58 * The inline function down() decremented count and the result
59 * was < 0. The wait loop will atomically test and update the
60 * semaphore counter following the rules:
61 * count > 0: decrement count, wake up queue and exit.
62 * count <= 0: set count to -1, go to sleep.
63 */
64void __sched __down(struct semaphore * sem)
65{
66 struct task_struct *tsk = current;
67 DECLARE_WAITQUEUE(wait, tsk);
68
69 __set_task_state(tsk, TASK_UNINTERRUPTIBLE);
70 add_wait_queue_exclusive(&sem->wait, &wait);
71 while (__sem_update_count(sem, -1) <= 0) {
72 schedule();
73 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
74 }
75 remove_wait_queue(&sem->wait, &wait);
76 __set_task_state(tsk, TASK_RUNNING);
77 wake_up(&sem->wait);
78}
79
80/*
81 * Same as __down() with an additional test for signals.
82 * If a signal is pending the count is updated as follows:
83 * count > 0: wake up queue and exit.
84 * count <= 0: set count to 0, wake up queue and exit.
85 */
86int __sched __down_interruptible(struct semaphore * sem)
87{
88 int retval = 0;
89 struct task_struct *tsk = current;
90 DECLARE_WAITQUEUE(wait, tsk);
91
92 __set_task_state(tsk, TASK_INTERRUPTIBLE);
93 add_wait_queue_exclusive(&sem->wait, &wait);
94 while (__sem_update_count(sem, -1) <= 0) {
95 if (signal_pending(current)) {
96 __sem_update_count(sem, 0);
97 retval = -EINTR;
98 break;
99 }
100 schedule();
101 set_task_state(tsk, TASK_INTERRUPTIBLE);
102 }
103 remove_wait_queue(&sem->wait, &wait);
104 __set_task_state(tsk, TASK_RUNNING);
105 wake_up(&sem->wait);
106 return retval;
107}
108
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
new file mode 100644
index 000000000000..c879c40aa7a5
--- /dev/null
+++ b/arch/s390/kernel/setup.c
@@ -0,0 +1,632 @@
1/*
2 * arch/s390/kernel/setup.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Hartmut Penner (hp@de.ibm.com),
7 * Martin Schwidefsky (schwidefsky@de.ibm.com)
8 *
9 * Derived from "arch/i386/kernel/setup.c"
10 * Copyright (C) 1995, Linus Torvalds
11 */
12
13/*
14 * This file handles the architecture-dependent parts of initialization
15 */
16
17#include <linux/errno.h>
18#include <linux/module.h>
19#include <linux/sched.h>
20#include <linux/kernel.h>
21#include <linux/mm.h>
22#include <linux/stddef.h>
23#include <linux/unistd.h>
24#include <linux/ptrace.h>
25#include <linux/slab.h>
26#include <linux/user.h>
27#include <linux/a.out.h>
28#include <linux/tty.h>
29#include <linux/ioport.h>
30#include <linux/delay.h>
31#include <linux/config.h>
32#include <linux/init.h>
33#include <linux/initrd.h>
34#include <linux/bootmem.h>
35#include <linux/root_dev.h>
36#include <linux/console.h>
37#include <linux/seq_file.h>
38#include <linux/kernel_stat.h>
39
40#include <asm/uaccess.h>
41#include <asm/system.h>
42#include <asm/smp.h>
43#include <asm/mmu_context.h>
44#include <asm/cpcmd.h>
45#include <asm/lowcore.h>
46#include <asm/irq.h>
47
48/*
49 * Machine setup..
50 */
51unsigned int console_mode = 0;
52unsigned int console_devno = -1;
53unsigned int console_irq = -1;
54unsigned long memory_size = 0;
55unsigned long machine_flags = 0;
56unsigned int default_storage_key = 0;
57struct {
58 unsigned long addr, size, type;
59} memory_chunk[MEMORY_CHUNKS] = { { 0 } };
60#define CHUNK_READ_WRITE 0
61#define CHUNK_READ_ONLY 1
62volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
63
64/*
65 * Setup options
66 */
67extern int _text,_etext, _edata, _end;
68
69/*
70 * This is set up by the setup-routine at boot-time
71 * for S390 need to find out, what we have to setup
72 * using address 0x10400 ...
73 */
74
75#include <asm/setup.h>
76
77static char command_line[COMMAND_LINE_SIZE] = { 0, };
78
79static struct resource code_resource = {
80 .name = "Kernel code",
81 .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
82};
83
84static struct resource data_resource = {
85 .name = "Kernel data",
86 .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
87};
88
89/*
90 * cpu_init() initializes state that is per-CPU.
91 */
92void __devinit cpu_init (void)
93{
94 int addr = hard_smp_processor_id();
95
96 /*
97 * Store processor id in lowcore (used e.g. in timer_interrupt)
98 */
99 asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
100 S390_lowcore.cpu_data.cpu_addr = addr;
101
102 /*
103 * Force FPU initialization:
104 */
105 clear_thread_flag(TIF_USEDFPU);
106 clear_used_math();
107
108 atomic_inc(&init_mm.mm_count);
109 current->active_mm = &init_mm;
110 if (current->mm)
111 BUG();
112 enter_lazy_tlb(&init_mm, current);
113}
114
115/*
116 * VM halt and poweroff setup routines
117 */
118char vmhalt_cmd[128] = "";
119char vmpoff_cmd[128] = "";
120
121static inline void strncpy_skip_quote(char *dst, char *src, int n)
122{
123 int sx, dx;
124
125 dx = 0;
126 for (sx = 0; src[sx] != 0; sx++) {
127 if (src[sx] == '"') continue;
128 dst[dx++] = src[sx];
129 if (dx >= n) break;
130 }
131}
132
133static int __init vmhalt_setup(char *str)
134{
135 strncpy_skip_quote(vmhalt_cmd, str, 127);
136 vmhalt_cmd[127] = 0;
137 return 1;
138}
139
140__setup("vmhalt=", vmhalt_setup);
141
142static int __init vmpoff_setup(char *str)
143{
144 strncpy_skip_quote(vmpoff_cmd, str, 127);
145 vmpoff_cmd[127] = 0;
146 return 1;
147}
148
149__setup("vmpoff=", vmpoff_setup);
150
151/*
152 * condev= and conmode= setup parameter.
153 */
154
155static int __init condev_setup(char *str)
156{
157 int vdev;
158
159 vdev = simple_strtoul(str, &str, 0);
160 if (vdev >= 0 && vdev < 65536) {
161 console_devno = vdev;
162 console_irq = -1;
163 }
164 return 1;
165}
166
167__setup("condev=", condev_setup);
168
169static int __init conmode_setup(char *str)
170{
171#if defined(CONFIG_SCLP_CONSOLE)
172 if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0)
173 SET_CONSOLE_SCLP;
174#endif
175#if defined(CONFIG_TN3215_CONSOLE)
176 if (strncmp(str, "3215", 5) == 0)
177 SET_CONSOLE_3215;
178#endif
179#if defined(CONFIG_TN3270_CONSOLE)
180 if (strncmp(str, "3270", 5) == 0)
181 SET_CONSOLE_3270;
182#endif
183 return 1;
184}
185
186__setup("conmode=", conmode_setup);
187
188static void __init conmode_default(void)
189{
190 char query_buffer[1024];
191 char *ptr;
192
193 if (MACHINE_IS_VM) {
194 __cpcmd("QUERY CONSOLE", query_buffer, 1024);
195 console_devno = simple_strtoul(query_buffer + 5, NULL, 16);
196 ptr = strstr(query_buffer, "SUBCHANNEL =");
197 console_irq = simple_strtoul(ptr + 13, NULL, 16);
198 __cpcmd("QUERY TERM", query_buffer, 1024);
199 ptr = strstr(query_buffer, "CONMODE");
200 /*
201 * Set the conmode to 3215 so that the device recognition
202 * will set the cu_type of the console to 3215. If the
203 * conmode is 3270 and we don't set it back then both
204 * 3215 and the 3270 driver will try to access the console
205 * device (3215 as console and 3270 as normal tty).
206 */
207 __cpcmd("TERM CONMODE 3215", NULL, 0);
208 if (ptr == NULL) {
209#if defined(CONFIG_SCLP_CONSOLE)
210 SET_CONSOLE_SCLP;
211#endif
212 return;
213 }
214 if (strncmp(ptr + 8, "3270", 4) == 0) {
215#if defined(CONFIG_TN3270_CONSOLE)
216 SET_CONSOLE_3270;
217#elif defined(CONFIG_TN3215_CONSOLE)
218 SET_CONSOLE_3215;
219#elif defined(CONFIG_SCLP_CONSOLE)
220 SET_CONSOLE_SCLP;
221#endif
222 } else if (strncmp(ptr + 8, "3215", 4) == 0) {
223#if defined(CONFIG_TN3215_CONSOLE)
224 SET_CONSOLE_3215;
225#elif defined(CONFIG_TN3270_CONSOLE)
226 SET_CONSOLE_3270;
227#elif defined(CONFIG_SCLP_CONSOLE)
228 SET_CONSOLE_SCLP;
229#endif
230 }
231 } else if (MACHINE_IS_P390) {
232#if defined(CONFIG_TN3215_CONSOLE)
233 SET_CONSOLE_3215;
234#elif defined(CONFIG_TN3270_CONSOLE)
235 SET_CONSOLE_3270;
236#endif
237 } else {
238#if defined(CONFIG_SCLP_CONSOLE)
239 SET_CONSOLE_SCLP;
240#endif
241 }
242}
243
244#ifdef CONFIG_SMP
245extern void machine_restart_smp(char *);
246extern void machine_halt_smp(void);
247extern void machine_power_off_smp(void);
248
249void (*_machine_restart)(char *command) = machine_restart_smp;
250void (*_machine_halt)(void) = machine_halt_smp;
251void (*_machine_power_off)(void) = machine_power_off_smp;
252#else
253/*
254 * Reboot, halt and power_off routines for non SMP.
255 */
256extern void reipl(unsigned long devno);
257static void do_machine_restart_nonsmp(char * __unused)
258{
259 if (MACHINE_IS_VM)
260 cpcmd ("IPL", NULL, 0);
261 else
262 reipl (0x10000 | S390_lowcore.ipl_device);
263}
264
265static void do_machine_halt_nonsmp(void)
266{
267 if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
268 cpcmd(vmhalt_cmd, NULL, 0);
269 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
270}
271
272static void do_machine_power_off_nonsmp(void)
273{
274 if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
275 cpcmd(vmpoff_cmd, NULL, 0);
276 signal_processor(smp_processor_id(), sigp_stop_and_store_status);
277}
278
279void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
280void (*_machine_halt)(void) = do_machine_halt_nonsmp;
281void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
282#endif
283
284 /*
285 * Reboot, halt and power_off stubs. They just call _machine_restart,
286 * _machine_halt or _machine_power_off.
287 */
288
289void machine_restart(char *command)
290{
291 console_unblank();
292 _machine_restart(command);
293}
294
295EXPORT_SYMBOL(machine_restart);
296
297void machine_halt(void)
298{
299 console_unblank();
300 _machine_halt();
301}
302
303EXPORT_SYMBOL(machine_halt);
304
305void machine_power_off(void)
306{
307 console_unblank();
308 _machine_power_off();
309}
310
311EXPORT_SYMBOL(machine_power_off);
312
313/*
314 * Setup function called from init/main.c just after the banner
315 * was printed.
316 */
317extern char _pstart, _pend, _stext;
318
319void __init setup_arch(char **cmdline_p)
320{
321 unsigned long bootmap_size;
322 unsigned long memory_start, memory_end;
323 char c = ' ', cn, *to = command_line, *from = COMMAND_LINE;
324 unsigned long start_pfn, end_pfn;
325 static unsigned int smptrap=0;
326 unsigned long delay = 0;
327 struct _lowcore *lc;
328 int i;
329
330 if (smptrap)
331 return;
332 smptrap=1;
333
334 /*
335 * print what head.S has found out about the machine
336 */
337#ifndef CONFIG_ARCH_S390X
338 printk((MACHINE_IS_VM) ?
339 "We are running under VM (31 bit mode)\n" :
340 "We are running native (31 bit mode)\n");
341 printk((MACHINE_HAS_IEEE) ?
342 "This machine has an IEEE fpu\n" :
343 "This machine has no IEEE fpu\n");
344#else /* CONFIG_ARCH_S390X */
345 printk((MACHINE_IS_VM) ?
346 "We are running under VM (64 bit mode)\n" :
347 "We are running native (64 bit mode)\n");
348#endif /* CONFIG_ARCH_S390X */
349
350 ROOT_DEV = Root_RAM0;
351 memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/
352#ifndef CONFIG_ARCH_S390X
353 memory_end = memory_size & ~0x400000UL; /* align memory end to 4MB */
354 /*
355 * We need some free virtual space to be able to do vmalloc.
356 * On a machine with 2GB memory we make sure that we have at
357 * least 128 MB free space for vmalloc.
358 */
359 if (memory_end > 1920*1024*1024)
360 memory_end = 1920*1024*1024;
361#else /* CONFIG_ARCH_S390X */
362 memory_end = memory_size & ~0x200000UL; /* detected in head.s */
363#endif /* CONFIG_ARCH_S390X */
364 init_mm.start_code = PAGE_OFFSET;
365 init_mm.end_code = (unsigned long) &_etext;
366 init_mm.end_data = (unsigned long) &_edata;
367 init_mm.brk = (unsigned long) &_end;
368
369 code_resource.start = (unsigned long) &_text;
370 code_resource.end = (unsigned long) &_etext - 1;
371 data_resource.start = (unsigned long) &_etext;
372 data_resource.end = (unsigned long) &_edata - 1;
373
374 /* Save unparsed command line copy for /proc/cmdline */
375 memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
376 saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
377
378 for (;;) {
379 /*
380 * "mem=XXX[kKmM]" sets memsize
381 */
382 if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
383 memory_end = simple_strtoul(from+4, &from, 0);
384 if ( *from == 'K' || *from == 'k' ) {
385 memory_end = memory_end << 10;
386 from++;
387 } else if ( *from == 'M' || *from == 'm' ) {
388 memory_end = memory_end << 20;
389 from++;
390 }
391 }
392 /*
393 * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
394 */
395 if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
396 delay = simple_strtoul(from+9, &from, 0);
397 if (*from == 's' || *from == 'S') {
398 delay = delay*1000000;
399 from++;
400 } else if (*from == 'm' || *from == 'M') {
401 delay = delay*60*1000000;
402 from++;
403 }
404 /* now wait for the requested amount of time */
405 udelay(delay);
406 }
407 cn = *(from++);
408 if (!cn)
409 break;
410 if (cn == '\n')
411 cn = ' '; /* replace newlines with space */
412 if (cn == 0x0d)
413 cn = ' '; /* replace 0x0d with space */
414 if (cn == ' ' && c == ' ')
415 continue; /* remove additional spaces */
416 c = cn;
417 if (to - command_line >= COMMAND_LINE_SIZE)
418 break;
419 *(to++) = c;
420 }
421 if (c == ' ' && to > command_line) to--;
422 *to = '\0';
423 *cmdline_p = command_line;
424
425 /*
426 * partially used pages are not usable - thus
427 * we are rounding upwards:
428 */
429 start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT;
430 end_pfn = max_pfn = memory_end >> PAGE_SHIFT;
431
432 /*
433 * Initialize the boot-time allocator (with low memory only):
434 */
435 bootmap_size = init_bootmem(start_pfn, end_pfn);
436
437 /*
438 * Register RAM areas with the bootmem allocator.
439 */
440 for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) {
441 unsigned long start_chunk, end_chunk;
442
443 if (memory_chunk[i].type != CHUNK_READ_WRITE)
444 continue;
445 start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1);
446 start_chunk >>= PAGE_SHIFT;
447 end_chunk = (memory_chunk[i].addr + memory_chunk[i].size);
448 end_chunk >>= PAGE_SHIFT;
449 if (start_chunk < start_pfn)
450 start_chunk = start_pfn;
451 if (end_chunk > end_pfn)
452 end_chunk = end_pfn;
453 if (start_chunk < end_chunk)
454 free_bootmem(start_chunk << PAGE_SHIFT,
455 (end_chunk - start_chunk) << PAGE_SHIFT);
456 }
457
458 /*
459 * Reserve the bootmem bitmap itself as well. We do this in two
460 * steps (first step was init_bootmem()) because this catches
461 * the (very unlikely) case of us accidentally initializing the
462 * bootmem allocator with an invalid RAM area.
463 */
464 reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
465
466#ifdef CONFIG_BLK_DEV_INITRD
467 if (INITRD_START) {
468 if (INITRD_START + INITRD_SIZE <= memory_end) {
469 reserve_bootmem(INITRD_START, INITRD_SIZE);
470 initrd_start = INITRD_START;
471 initrd_end = initrd_start + INITRD_SIZE;
472 } else {
473 printk("initrd extends beyond end of memory "
474 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
475 initrd_start + INITRD_SIZE, memory_end);
476 initrd_start = initrd_end = 0;
477 }
478 }
479#endif
480
481 for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) {
482 struct resource *res;
483
484 res = alloc_bootmem_low(sizeof(struct resource));
485 res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
486
487 switch (memory_chunk[i].type) {
488 case CHUNK_READ_WRITE:
489 res->name = "System RAM";
490 break;
491 case CHUNK_READ_ONLY:
492 res->name = "System ROM";
493 res->flags |= IORESOURCE_READONLY;
494 break;
495 default:
496 res->name = "reserved";
497 }
498 res->start = memory_chunk[i].addr;
499 res->end = memory_chunk[i].addr + memory_chunk[i].size - 1;
500 request_resource(&iomem_resource, res);
501 request_resource(res, &code_resource);
502 request_resource(res, &data_resource);
503 }
504
505 /*
506 * Setup lowcore for boot cpu
507 */
508#ifndef CONFIG_ARCH_S390X
509 lc = (struct _lowcore *) __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
510 memset(lc, 0, PAGE_SIZE);
511#else /* CONFIG_ARCH_S390X */
512 lc = (struct _lowcore *) __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0);
513 memset(lc, 0, 2*PAGE_SIZE);
514#endif /* CONFIG_ARCH_S390X */
515 lc->restart_psw.mask = PSW_BASE_BITS;
516 lc->restart_psw.addr =
517 PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
518 lc->external_new_psw.mask = PSW_KERNEL_BITS;
519 lc->external_new_psw.addr =
520 PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
521 lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
522 lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
523 lc->program_new_psw.mask = PSW_KERNEL_BITS;
524 lc->program_new_psw.addr =
525 PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
526 lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
527 lc->mcck_new_psw.addr =
528 PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
529 lc->io_new_psw.mask = PSW_KERNEL_BITS;
530 lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
531 lc->ipl_device = S390_lowcore.ipl_device;
532 lc->jiffy_timer = -1LL;
533 lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
534 lc->async_stack = (unsigned long)
535 __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
536#ifdef CONFIG_CHECK_STACK
537 lc->panic_stack = (unsigned long)
538 __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
539#endif
540 lc->current_task = (unsigned long) init_thread_union.thread_info.task;
541 lc->thread_info = (unsigned long) &init_thread_union;
542#ifdef CONFIG_ARCH_S390X
543 if (MACHINE_HAS_DIAG44)
544 lc->diag44_opcode = 0x83000044;
545 else
546 lc->diag44_opcode = 0x07000700;
547#endif /* CONFIG_ARCH_S390X */
548 set_prefix((u32)(unsigned long) lc);
549 cpu_init();
550 __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
551
552 /*
553 * Create kernel page tables and switch to virtual addressing.
554 */
555 paging_init();
556
557 /* Setup default console */
558 conmode_default();
559}
560
561void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
562{
563 printk("cpu %d "
564#ifdef CONFIG_SMP
565 "phys_idx=%d "
566#endif
567 "vers=%02X ident=%06X machine=%04X unused=%04X\n",
568 cpuinfo->cpu_nr,
569#ifdef CONFIG_SMP
570 cpuinfo->cpu_addr,
571#endif
572 cpuinfo->cpu_id.version,
573 cpuinfo->cpu_id.ident,
574 cpuinfo->cpu_id.machine,
575 cpuinfo->cpu_id.unused);
576}
577
578/*
579 * show_cpuinfo - Get information on one CPU for use by procfs.
580 */
581
582static int show_cpuinfo(struct seq_file *m, void *v)
583{
584 struct cpuinfo_S390 *cpuinfo;
585 unsigned long n = (unsigned long) v - 1;
586
587 if (!n) {
588 seq_printf(m, "vendor_id : IBM/S390\n"
589 "# processors : %i\n"
590 "bogomips per cpu: %lu.%02lu\n",
591 num_online_cpus(), loops_per_jiffy/(500000/HZ),
592 (loops_per_jiffy/(5000/HZ))%100);
593 }
594 if (cpu_online(n)) {
595#ifdef CONFIG_SMP
596 if (smp_processor_id() == n)
597 cpuinfo = &S390_lowcore.cpu_data;
598 else
599 cpuinfo = &lowcore_ptr[n]->cpu_data;
600#else
601 cpuinfo = &S390_lowcore.cpu_data;
602#endif
603 seq_printf(m, "processor %li: "
604 "version = %02X, "
605 "identification = %06X, "
606 "machine = %04X\n",
607 n, cpuinfo->cpu_id.version,
608 cpuinfo->cpu_id.ident,
609 cpuinfo->cpu_id.machine);
610 }
611 return 0;
612}
613
614static void *c_start(struct seq_file *m, loff_t *pos)
615{
616 return *pos < NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL;
617}
618static void *c_next(struct seq_file *m, void *v, loff_t *pos)
619{
620 ++*pos;
621 return c_start(m, pos);
622}
623static void c_stop(struct seq_file *m, void *v)
624{
625}
626struct seq_operations cpuinfo_op = {
627 .start = c_start,
628 .next = c_next,
629 .stop = c_stop,
630 .show = show_cpuinfo,
631};
632
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
new file mode 100644
index 000000000000..610c1d03e975
--- /dev/null
+++ b/arch/s390/kernel/signal.c
@@ -0,0 +1,527 @@
1/*
2 * arch/s390/kernel/signal.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
7 *
8 * Based on Intel version
9 *
10 * Copyright (C) 1991, 1992 Linus Torvalds
11 *
12 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
13 */
14
15#include <linux/config.h>
16#include <linux/sched.h>
17#include <linux/mm.h>
18#include <linux/smp.h>
19#include <linux/smp_lock.h>
20#include <linux/kernel.h>
21#include <linux/signal.h>
22#include <linux/errno.h>
23#include <linux/wait.h>
24#include <linux/ptrace.h>
25#include <linux/unistd.h>
26#include <linux/stddef.h>
27#include <linux/tty.h>
28#include <linux/personality.h>
29#include <linux/binfmts.h>
30#include <asm/ucontext.h>
31#include <asm/uaccess.h>
32#include <asm/lowcore.h>
33
34#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
35
36
37typedef struct
38{
39 __u8 callee_used_stack[__SIGNAL_FRAMESIZE];
40 struct sigcontext sc;
41 _sigregs sregs;
42 int signo;
43 __u8 retcode[S390_SYSCALL_SIZE];
44} sigframe;
45
46typedef struct
47{
48 __u8 callee_used_stack[__SIGNAL_FRAMESIZE];
49 __u8 retcode[S390_SYSCALL_SIZE];
50 struct siginfo info;
51 struct ucontext uc;
52} rt_sigframe;
53
54int do_signal(struct pt_regs *regs, sigset_t *oldset);
55
56/*
57 * Atomically swap in the new signal mask, and wait for a signal.
58 */
59asmlinkage int
60sys_sigsuspend(struct pt_regs * regs, int history0, int history1,
61 old_sigset_t mask)
62{
63 sigset_t saveset;
64
65 mask &= _BLOCKABLE;
66 spin_lock_irq(&current->sighand->siglock);
67 saveset = current->blocked;
68 siginitset(&current->blocked, mask);
69 recalc_sigpending();
70 spin_unlock_irq(&current->sighand->siglock);
71 regs->gprs[2] = -EINTR;
72
73 while (1) {
74 set_current_state(TASK_INTERRUPTIBLE);
75 schedule();
76 if (do_signal(regs, &saveset))
77 return -EINTR;
78 }
79}
80
81asmlinkage long
82sys_rt_sigsuspend(struct pt_regs *regs, sigset_t __user *unewset,
83 size_t sigsetsize)
84{
85 sigset_t saveset, newset;
86
87 /* XXX: Don't preclude handling different sized sigset_t's. */
88 if (sigsetsize != sizeof(sigset_t))
89 return -EINVAL;
90
91 if (copy_from_user(&newset, unewset, sizeof(newset)))
92 return -EFAULT;
93 sigdelsetmask(&newset, ~_BLOCKABLE);
94
95 spin_lock_irq(&current->sighand->siglock);
96 saveset = current->blocked;
97 current->blocked = newset;
98 recalc_sigpending();
99 spin_unlock_irq(&current->sighand->siglock);
100 regs->gprs[2] = -EINTR;
101
102 while (1) {
103 set_current_state(TASK_INTERRUPTIBLE);
104 schedule();
105 if (do_signal(regs, &saveset))
106 return -EINTR;
107 }
108}
109
110asmlinkage long
111sys_sigaction(int sig, const struct old_sigaction __user *act,
112 struct old_sigaction __user *oact)
113{
114 struct k_sigaction new_ka, old_ka;
115 int ret;
116
117 if (act) {
118 old_sigset_t mask;
119 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
120 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
121 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
122 return -EFAULT;
123 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
124 __get_user(mask, &act->sa_mask);
125 siginitset(&new_ka.sa.sa_mask, mask);
126 }
127
128 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
129
130 if (!ret && oact) {
131 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
132 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
133 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
134 return -EFAULT;
135 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
136 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
137 }
138
139 return ret;
140}
141
142asmlinkage long
143sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
144 struct pt_regs *regs)
145{
146 return do_sigaltstack(uss, uoss, regs->gprs[15]);
147}
148
149
150
151/* Returns non-zero on fault. */
152static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
153{
154 unsigned long old_mask = regs->psw.mask;
155 int err;
156
157 save_access_regs(current->thread.acrs);
158
159 /* Copy a 'clean' PSW mask to the user to avoid leaking
160 information about whether PER is currently on. */
161 regs->psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
162 err = __copy_to_user(&sregs->regs.psw, &regs->psw,
163 sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs));
164 regs->psw.mask = old_mask;
165 if (err != 0)
166 return err;
167 err = __copy_to_user(&sregs->regs.acrs, current->thread.acrs,
168 sizeof(sregs->regs.acrs));
169 if (err != 0)
170 return err;
171 /*
172 * We have to store the fp registers to current->thread.fp_regs
173 * to merge them with the emulated registers.
174 */
175 save_fp_regs(&current->thread.fp_regs);
176 return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
177 sizeof(s390_fp_regs));
178}
179
180/* Returns positive number on error */
181static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
182{
183 unsigned long old_mask = regs->psw.mask;
184 int err;
185
186 /* Alwys make any pending restarted system call return -EINTR */
187 current_thread_info()->restart_block.fn = do_no_restart_syscall;
188
189 err = __copy_from_user(&regs->psw, &sregs->regs.psw,
190 sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs));
191 regs->psw.mask = PSW_MASK_MERGE(old_mask, regs->psw.mask);
192 regs->psw.addr |= PSW_ADDR_AMODE;
193 if (err)
194 return err;
195 err = __copy_from_user(&current->thread.acrs, &sregs->regs.acrs,
196 sizeof(sregs->regs.acrs));
197 if (err)
198 return err;
199 restore_access_regs(current->thread.acrs);
200
201 err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
202 sizeof(s390_fp_regs));
203 current->thread.fp_regs.fpc &= FPC_VALID_MASK;
204 if (err)
205 return err;
206
207 restore_fp_regs(&current->thread.fp_regs);
208 regs->trap = -1; /* disable syscall checks */
209 return 0;
210}
211
212asmlinkage long sys_sigreturn(struct pt_regs *regs)
213{
214 sigframe __user *frame = (sigframe __user *)regs->gprs[15];
215 sigset_t set;
216
217 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
218 goto badframe;
219 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
220 goto badframe;
221
222 sigdelsetmask(&set, ~_BLOCKABLE);
223 spin_lock_irq(&current->sighand->siglock);
224 current->blocked = set;
225 recalc_sigpending();
226 spin_unlock_irq(&current->sighand->siglock);
227
228 if (restore_sigregs(regs, &frame->sregs))
229 goto badframe;
230
231 return regs->gprs[2];
232
233badframe:
234 force_sig(SIGSEGV, current);
235 return 0;
236}
237
238asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
239{
240 rt_sigframe __user *frame = (rt_sigframe __user *)regs->gprs[15];
241 sigset_t set;
242
243 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
244 goto badframe;
245 if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
246 goto badframe;
247
248 sigdelsetmask(&set, ~_BLOCKABLE);
249 spin_lock_irq(&current->sighand->siglock);
250 current->blocked = set;
251 recalc_sigpending();
252 spin_unlock_irq(&current->sighand->siglock);
253
254 if (restore_sigregs(regs, &frame->uc.uc_mcontext))
255 goto badframe;
256
257 /* It is more difficult to avoid calling this function than to
258 call it and ignore errors. */
259 do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
260 return regs->gprs[2];
261
262badframe:
263 force_sig(SIGSEGV, current);
264 return 0;
265}
266
267/*
268 * Set up a signal frame.
269 */
270
271
272/*
273 * Determine which stack to use..
274 */
275static inline void __user *
276get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
277{
278 unsigned long sp;
279
280 /* Default to using normal stack */
281 sp = regs->gprs[15];
282
283 /* This is the X/Open sanctioned signal stack switching. */
284 if (ka->sa.sa_flags & SA_ONSTACK) {
285 if (! sas_ss_flags(sp))
286 sp = current->sas_ss_sp + current->sas_ss_size;
287 }
288
289 /* This is the legacy signal stack switching. */
290 else if (!user_mode(regs) &&
291 !(ka->sa.sa_flags & SA_RESTORER) &&
292 ka->sa.sa_restorer) {
293 sp = (unsigned long) ka->sa.sa_restorer;
294 }
295
296 return (void __user *)((sp - frame_size) & -8ul);
297}
298
299static inline int map_signal(int sig)
300{
301 if (current_thread_info()->exec_domain
302 && current_thread_info()->exec_domain->signal_invmap
303 && sig < 32)
304 return current_thread_info()->exec_domain->signal_invmap[sig];
305 else
306 return sig;
307}
308
309static void setup_frame(int sig, struct k_sigaction *ka,
310 sigset_t *set, struct pt_regs * regs)
311{
312 sigframe __user *frame;
313
314 frame = get_sigframe(ka, regs, sizeof(sigframe));
315 if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe)))
316 goto give_sigsegv;
317
318 if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE))
319 goto give_sigsegv;
320
321 if (save_sigregs(regs, &frame->sregs))
322 goto give_sigsegv;
323 if (__put_user(&frame->sregs, &frame->sc.sregs))
324 goto give_sigsegv;
325
326 /* Set up to return from userspace. If provided, use a stub
327 already in userspace. */
328 if (ka->sa.sa_flags & SA_RESTORER) {
329 regs->gprs[14] = (unsigned long)
330 ka->sa.sa_restorer | PSW_ADDR_AMODE;
331 } else {
332 regs->gprs[14] = (unsigned long)
333 frame->retcode | PSW_ADDR_AMODE;
334 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
335 (u16 __user *)(frame->retcode)))
336 goto give_sigsegv;
337 }
338
339 /* Set up backchain. */
340 if (__put_user(regs->gprs[15], (addr_t __user *) frame))
341 goto give_sigsegv;
342
343 /* Set up registers for signal handler */
344 regs->gprs[15] = (unsigned long) frame;
345 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
346
347 regs->gprs[2] = map_signal(sig);
348 regs->gprs[3] = (unsigned long) &frame->sc;
349
350 /* We forgot to include these in the sigcontext.
351 To avoid breaking binary compatibility, they are passed as args. */
352 regs->gprs[4] = current->thread.trap_no;
353 regs->gprs[5] = current->thread.prot_addr;
354
355 /* Place signal number on stack to allow backtrace from handler. */
356 if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
357 goto give_sigsegv;
358 return;
359
360give_sigsegv:
361 force_sigsegv(sig, current);
362}
363
364static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
365 sigset_t *set, struct pt_regs * regs)
366{
367 int err = 0;
368 rt_sigframe __user *frame;
369
370 frame = get_sigframe(ka, regs, sizeof(rt_sigframe));
371 if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe)))
372 goto give_sigsegv;
373
374 if (copy_siginfo_to_user(&frame->info, info))
375 goto give_sigsegv;
376
377 /* Create the ucontext. */
378 err |= __put_user(0, &frame->uc.uc_flags);
379 err |= __put_user(0, &frame->uc.uc_link);
380 err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
381 err |= __put_user(sas_ss_flags(regs->gprs[15]),
382 &frame->uc.uc_stack.ss_flags);
383 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
384 err |= save_sigregs(regs, &frame->uc.uc_mcontext);
385 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
386 if (err)
387 goto give_sigsegv;
388
389 /* Set up to return from userspace. If provided, use a stub
390 already in userspace. */
391 if (ka->sa.sa_flags & SA_RESTORER) {
392 regs->gprs[14] = (unsigned long)
393 ka->sa.sa_restorer | PSW_ADDR_AMODE;
394 } else {
395 regs->gprs[14] = (unsigned long)
396 frame->retcode | PSW_ADDR_AMODE;
397 err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
398 (u16 __user *)(frame->retcode));
399 }
400
401 /* Set up backchain. */
402 if (__put_user(regs->gprs[15], (addr_t __user *) frame))
403 goto give_sigsegv;
404
405 /* Set up registers for signal handler */
406 regs->gprs[15] = (unsigned long) frame;
407 regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
408
409 regs->gprs[2] = map_signal(sig);
410 regs->gprs[3] = (unsigned long) &frame->info;
411 regs->gprs[4] = (unsigned long) &frame->uc;
412 return;
413
414give_sigsegv:
415 force_sigsegv(sig, current);
416}
417
418/*
419 * OK, we're invoking a handler
420 */
421
422static void
423handle_signal(unsigned long sig, struct k_sigaction *ka,
424 siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
425{
426 /* Set up the stack frame */
427 if (ka->sa.sa_flags & SA_SIGINFO)
428 setup_rt_frame(sig, ka, info, oldset, regs);
429 else
430 setup_frame(sig, ka, oldset, regs);
431
432 if (!(ka->sa.sa_flags & SA_NODEFER)) {
433 spin_lock_irq(&current->sighand->siglock);
434 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
435 sigaddset(&current->blocked,sig);
436 recalc_sigpending();
437 spin_unlock_irq(&current->sighand->siglock);
438 }
439}
440
441/*
442 * Note that 'init' is a special process: it doesn't get signals it doesn't
443 * want to handle. Thus you cannot kill init even with a SIGKILL even by
444 * mistake.
445 *
446 * Note that we go through the signals twice: once to check the signals that
447 * the kernel can handle, and then we build all the user-level signal handling
448 * stack-frames in one go after that.
449 */
450int do_signal(struct pt_regs *regs, sigset_t *oldset)
451{
452 unsigned long retval = 0, continue_addr = 0, restart_addr = 0;
453 siginfo_t info;
454 int signr;
455 struct k_sigaction ka;
456
457 /*
458 * We want the common case to go fast, which
459 * is why we may in certain cases get here from
460 * kernel mode. Just return without doing anything
461 * if so.
462 */
463 if (!user_mode(regs))
464 return 1;
465
466 if (!oldset)
467 oldset = &current->blocked;
468
469 /* Are we from a system call? */
470 if (regs->trap == __LC_SVC_OLD_PSW) {
471 continue_addr = regs->psw.addr;
472 restart_addr = continue_addr - regs->ilc;
473 retval = regs->gprs[2];
474
475 /* Prepare for system call restart. We do this here so that a
476 debugger will see the already changed PSW. */
477 if (retval == -ERESTARTNOHAND ||
478 retval == -ERESTARTSYS ||
479 retval == -ERESTARTNOINTR) {
480 regs->gprs[2] = regs->orig_gpr2;
481 regs->psw.addr = restart_addr;
482 } else if (retval == -ERESTART_RESTARTBLOCK) {
483 regs->gprs[2] = -EINTR;
484 }
485 }
486
487 /* Get signal to deliver. When running under ptrace, at this point
488 the debugger may change all our registers ... */
489 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
490
491 /* Depending on the signal settings we may need to revert the
492 decision to restart the system call. */
493 if (signr > 0 && regs->psw.addr == restart_addr) {
494 if (retval == -ERESTARTNOHAND
495 || (retval == -ERESTARTSYS
496 && !(current->sighand->action[signr-1].sa.sa_flags
497 & SA_RESTART))) {
498 regs->gprs[2] = -EINTR;
499 regs->psw.addr = continue_addr;
500 }
501 }
502
503 if (signr > 0) {
504 /* Whee! Actually deliver the signal. */
505#ifdef CONFIG_S390_SUPPORT
506 if (test_thread_flag(TIF_31BIT)) {
507 extern void handle_signal32(unsigned long sig,
508 struct k_sigaction *ka,
509 siginfo_t *info,
510 sigset_t *oldset,
511 struct pt_regs *regs);
512 handle_signal32(signr, &ka, &info, oldset, regs);
513 return 1;
514 }
515#endif
516 handle_signal(signr, &ka, &info, oldset, regs);
517 return 1;
518 }
519
520 /* Restart a different system call. */
521 if (retval == -ERESTART_RESTARTBLOCK
522 && regs->psw.addr == continue_addr) {
523 regs->gprs[2] = __NR_restart_syscall;
524 set_thread_flag(TIF_RESTART_SVC);
525 }
526 return 0;
527}
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
new file mode 100644
index 000000000000..fdfcf0488b49
--- /dev/null
+++ b/arch/s390/kernel/smp.c
@@ -0,0 +1,840 @@
1/*
2 * arch/s390/kernel/smp.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
7 * Martin Schwidefsky (schwidefsky@de.ibm.com)
8 * Heiko Carstens (heiko.carstens@de.ibm.com)
9 *
10 * based on other smp stuff by
11 * (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net>
12 * (c) 1998 Ingo Molnar
13 *
14 * We work with logical cpu numbering everywhere we can. The only
15 * functions using the real cpu address (got from STAP) are the sigp
16 * functions. For all other functions we use the identity mapping.
17 * That means that cpu_number_map[i] == i for every cpu. cpu_number_map is
18 * used e.g. to find the idle task belonging to a logical cpu. Every array
19 * in the kernel is sorted by the logical cpu number and not by the physical
20 * one which is causing all the confusion with __cpu_logical_map and
21 * cpu_number_map in other architectures.
22 */
23
24#include <linux/module.h>
25#include <linux/init.h>
26
27#include <linux/mm.h>
28#include <linux/spinlock.h>
29#include <linux/kernel_stat.h>
30#include <linux/smp_lock.h>
31
32#include <linux/delay.h>
33#include <linux/cache.h>
34#include <linux/interrupt.h>
35#include <linux/cpu.h>
36
37#include <asm/sigp.h>
38#include <asm/pgalloc.h>
39#include <asm/irq.h>
40#include <asm/s390_ext.h>
41#include <asm/cpcmd.h>
42#include <asm/tlbflush.h>
43
44/* prototypes */
45
46extern volatile int __cpu_logical_map[];
47
48/*
49 * An array with a pointer the lowcore of every CPU.
50 */
51
52struct _lowcore *lowcore_ptr[NR_CPUS];
53
54cpumask_t cpu_online_map;
55cpumask_t cpu_possible_map;
56
57static struct task_struct *current_set[NR_CPUS];
58
59EXPORT_SYMBOL(cpu_online_map);
60
61/*
62 * Reboot, halt and power_off routines for SMP.
63 */
64extern char vmhalt_cmd[];
65extern char vmpoff_cmd[];
66
67extern void reipl(unsigned long devno);
68
69static void smp_ext_bitcall(int, ec_bit_sig);
70static void smp_ext_bitcall_others(ec_bit_sig);
71
72/*
73 * Structure and data for smp_call_function(). This is designed to minimise
74 * static memory requirements. It also looks cleaner.
75 */
76static DEFINE_SPINLOCK(call_lock);
77
78struct call_data_struct {
79 void (*func) (void *info);
80 void *info;
81 atomic_t started;
82 atomic_t finished;
83 int wait;
84};
85
86static struct call_data_struct * call_data;
87
88/*
89 * 'Call function' interrupt callback
90 */
91static void do_call_function(void)
92{
93 void (*func) (void *info) = call_data->func;
94 void *info = call_data->info;
95 int wait = call_data->wait;
96
97 atomic_inc(&call_data->started);
98 (*func)(info);
99 if (wait)
100 atomic_inc(&call_data->finished);
101}
102
103/*
104 * this function sends a 'generic call function' IPI to all other CPUs
105 * in the system.
106 */
107
108int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
109 int wait)
110/*
111 * [SUMMARY] Run a function on all other CPUs.
112 * <func> The function to run. This must be fast and non-blocking.
113 * <info> An arbitrary pointer to pass to the function.
114 * <nonatomic> currently unused.
115 * <wait> If true, wait (atomically) until function has completed on other CPUs.
116 * [RETURNS] 0 on success, else a negative status code. Does not return until
117 * remote CPUs are nearly ready to execute <<func>> or are or have executed.
118 *
119 * You must not call this function with disabled interrupts or from a
120 * hardware interrupt handler or from a bottom half handler.
121 */
122{
123 struct call_data_struct data;
124 int cpus = num_online_cpus()-1;
125
126 if (cpus <= 0)
127 return 0;
128
129 /* Can deadlock when called with interrupts disabled */
130 WARN_ON(irqs_disabled());
131
132 data.func = func;
133 data.info = info;
134 atomic_set(&data.started, 0);
135 data.wait = wait;
136 if (wait)
137 atomic_set(&data.finished, 0);
138
139 spin_lock(&call_lock);
140 call_data = &data;
141 /* Send a message to all other CPUs and wait for them to respond */
142 smp_ext_bitcall_others(ec_call_function);
143
144 /* Wait for response */
145 while (atomic_read(&data.started) != cpus)
146 cpu_relax();
147
148 if (wait)
149 while (atomic_read(&data.finished) != cpus)
150 cpu_relax();
151 spin_unlock(&call_lock);
152
153 return 0;
154}
155
156/*
157 * Call a function on one CPU
158 * cpu : the CPU the function should be executed on
159 *
160 * You must not call this function with disabled interrupts or from a
161 * hardware interrupt handler. You may call it from a bottom half.
162 *
163 * It is guaranteed that the called function runs on the specified CPU,
164 * preemption is disabled.
165 */
166int smp_call_function_on(void (*func) (void *info), void *info,
167 int nonatomic, int wait, int cpu)
168{
169 struct call_data_struct data;
170 int curr_cpu;
171
172 if (!cpu_online(cpu))
173 return -EINVAL;
174
175 /* disable preemption for local function call */
176 curr_cpu = get_cpu();
177
178 if (curr_cpu == cpu) {
179 /* direct call to function */
180 func(info);
181 put_cpu();
182 return 0;
183 }
184
185 data.func = func;
186 data.info = info;
187 atomic_set(&data.started, 0);
188 data.wait = wait;
189 if (wait)
190 atomic_set(&data.finished, 0);
191
192 spin_lock_bh(&call_lock);
193 call_data = &data;
194 smp_ext_bitcall(cpu, ec_call_function);
195
196 /* Wait for response */
197 while (atomic_read(&data.started) != 1)
198 cpu_relax();
199
200 if (wait)
201 while (atomic_read(&data.finished) != 1)
202 cpu_relax();
203
204 spin_unlock_bh(&call_lock);
205 put_cpu();
206 return 0;
207}
208EXPORT_SYMBOL(smp_call_function_on);
209
210static inline void do_send_stop(void)
211{
212 int cpu, rc;
213
214 /* stop all processors */
215 for_each_online_cpu(cpu) {
216 if (cpu == smp_processor_id())
217 continue;
218 do {
219 rc = signal_processor(cpu, sigp_stop);
220 } while (rc == sigp_busy);
221 }
222}
223
224static inline void do_store_status(void)
225{
226 int cpu, rc;
227
228 /* store status of all processors in their lowcores (real 0) */
229 for_each_online_cpu(cpu) {
230 if (cpu == smp_processor_id())
231 continue;
232 do {
233 rc = signal_processor_p(
234 (__u32)(unsigned long) lowcore_ptr[cpu], cpu,
235 sigp_store_status_at_address);
236 } while(rc == sigp_busy);
237 }
238}
239
240/*
241 * this function sends a 'stop' sigp to all other CPUs in the system.
242 * it goes straight through.
243 */
244void smp_send_stop(void)
245{
246 /* write magic number to zero page (absolute 0) */
247 lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
248
249 /* stop other processors. */
250 do_send_stop();
251
252 /* store status of other processors. */
253 do_store_status();
254}
255
256/*
257 * Reboot, halt and power_off routines for SMP.
258 */
259
260static void do_machine_restart(void * __unused)
261{
262 int cpu;
263 static atomic_t cpuid = ATOMIC_INIT(-1);
264
265 if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid))
266 signal_processor(smp_processor_id(), sigp_stop);
267
268 /* Wait for all other cpus to enter stopped state */
269 for_each_online_cpu(cpu) {
270 if (cpu == smp_processor_id())
271 continue;
272 while(!smp_cpu_not_running(cpu))
273 cpu_relax();
274 }
275
276 /* Store status of other cpus. */
277 do_store_status();
278
279 /*
280 * Finally call reipl. Because we waited for all other
281 * cpus to enter this function we know that they do
282 * not hold any s390irq-locks (the cpus have been
283 * interrupted by an external interrupt and s390irq
284 * locks are always held disabled).
285 */
286 if (MACHINE_IS_VM)
287 cpcmd ("IPL", NULL, 0);
288 else
289 reipl (0x10000 | S390_lowcore.ipl_device);
290}
291
292void machine_restart_smp(char * __unused)
293{
294 on_each_cpu(do_machine_restart, NULL, 0, 0);
295}
296
297static void do_wait_for_stop(void)
298{
299 unsigned long cr[16];
300
301 __ctl_store(cr, 0, 15);
302 cr[0] &= ~0xffff;
303 cr[6] = 0;
304 __ctl_load(cr, 0, 15);
305 for (;;)
306 enabled_wait();
307}
308
309static void do_machine_halt(void * __unused)
310{
311 static atomic_t cpuid = ATOMIC_INIT(-1);
312
313 if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid) == 0) {
314 smp_send_stop();
315 if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
316 cpcmd(vmhalt_cmd, NULL, 0);
317 signal_processor(smp_processor_id(),
318 sigp_stop_and_store_status);
319 }
320 do_wait_for_stop();
321}
322
323void machine_halt_smp(void)
324{
325 on_each_cpu(do_machine_halt, NULL, 0, 0);
326}
327
328static void do_machine_power_off(void * __unused)
329{
330 static atomic_t cpuid = ATOMIC_INIT(-1);
331
332 if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid) == 0) {
333 smp_send_stop();
334 if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
335 cpcmd(vmpoff_cmd, NULL, 0);
336 signal_processor(smp_processor_id(),
337 sigp_stop_and_store_status);
338 }
339 do_wait_for_stop();
340}
341
342void machine_power_off_smp(void)
343{
344 on_each_cpu(do_machine_power_off, NULL, 0, 0);
345}
346
347/*
348 * This is the main routine where commands issued by other
349 * cpus are handled.
350 */
351
352void do_ext_call_interrupt(struct pt_regs *regs, __u16 code)
353{
354 unsigned long bits;
355
356 /*
357 * handle bit signal external calls
358 *
359 * For the ec_schedule signal we have to do nothing. All the work
360 * is done automatically when we return from the interrupt.
361 */
362 bits = xchg(&S390_lowcore.ext_call_fast, 0);
363
364 if (test_bit(ec_call_function, &bits))
365 do_call_function();
366}
367
368/*
369 * Send an external call sigp to another cpu and return without waiting
370 * for its completion.
371 */
372static void smp_ext_bitcall(int cpu, ec_bit_sig sig)
373{
374 /*
375 * Set signaling bit in lowcore of target cpu and kick it
376 */
377 set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast);
378 while(signal_processor(cpu, sigp_external_call) == sigp_busy)
379 udelay(10);
380}
381
382/*
383 * Send an external call sigp to every other cpu in the system and
384 * return without waiting for its completion.
385 */
386static void smp_ext_bitcall_others(ec_bit_sig sig)
387{
388 int cpu;
389
390 for_each_online_cpu(cpu) {
391 if (cpu == smp_processor_id())
392 continue;
393 /*
394 * Set signaling bit in lowcore of target cpu and kick it
395 */
396 set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast);
397 while (signal_processor(cpu, sigp_external_call) == sigp_busy)
398 udelay(10);
399 }
400}
401
402#ifndef CONFIG_ARCH_S390X
403/*
404 * this function sends a 'purge tlb' signal to another CPU.
405 */
406void smp_ptlb_callback(void *info)
407{
408 local_flush_tlb();
409}
410
411void smp_ptlb_all(void)
412{
413 on_each_cpu(smp_ptlb_callback, NULL, 0, 1);
414}
415EXPORT_SYMBOL(smp_ptlb_all);
416#endif /* ! CONFIG_ARCH_S390X */
417
418/*
419 * this function sends a 'reschedule' IPI to another CPU.
420 * it goes straight through and wastes no time serializing
421 * anything. Worst case is that we lose a reschedule ...
422 */
423void smp_send_reschedule(int cpu)
424{
425 smp_ext_bitcall(cpu, ec_schedule);
426}
427
428/*
429 * parameter area for the set/clear control bit callbacks
430 */
431typedef struct
432{
433 __u16 start_ctl;
434 __u16 end_ctl;
435 unsigned long orvals[16];
436 unsigned long andvals[16];
437} ec_creg_mask_parms;
438
439/*
440 * callback for setting/clearing control bits
441 */
442void smp_ctl_bit_callback(void *info) {
443 ec_creg_mask_parms *pp;
444 unsigned long cregs[16];
445 int i;
446
447 pp = (ec_creg_mask_parms *) info;
448 __ctl_store(cregs[pp->start_ctl], pp->start_ctl, pp->end_ctl);
449 for (i = pp->start_ctl; i <= pp->end_ctl; i++)
450 cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
451 __ctl_load(cregs[pp->start_ctl], pp->start_ctl, pp->end_ctl);
452}
453
454/*
455 * Set a bit in a control register of all cpus
456 */
457void smp_ctl_set_bit(int cr, int bit) {
458 ec_creg_mask_parms parms;
459
460 parms.start_ctl = cr;
461 parms.end_ctl = cr;
462 parms.orvals[cr] = 1 << bit;
463 parms.andvals[cr] = -1L;
464 preempt_disable();
465 smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
466 __ctl_set_bit(cr, bit);
467 preempt_enable();
468}
469
470/*
471 * Clear a bit in a control register of all cpus
472 */
473void smp_ctl_clear_bit(int cr, int bit) {
474 ec_creg_mask_parms parms;
475
476 parms.start_ctl = cr;
477 parms.end_ctl = cr;
478 parms.orvals[cr] = 0;
479 parms.andvals[cr] = ~(1L << bit);
480 preempt_disable();
481 smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
482 __ctl_clear_bit(cr, bit);
483 preempt_enable();
484}
485
486/*
487 * Lets check how many CPUs we have.
488 */
489
490void
491__init smp_check_cpus(unsigned int max_cpus)
492{
493 int cpu, num_cpus;
494 __u16 boot_cpu_addr;
495
496 /*
497 * cpu 0 is the boot cpu. See smp_prepare_boot_cpu.
498 */
499
500 boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
501 current_thread_info()->cpu = 0;
502 num_cpus = 1;
503 for (cpu = 0; cpu <= 65535 && num_cpus < max_cpus; cpu++) {
504 if ((__u16) cpu == boot_cpu_addr)
505 continue;
506 __cpu_logical_map[num_cpus] = (__u16) cpu;
507 if (signal_processor(num_cpus, sigp_sense) ==
508 sigp_not_operational)
509 continue;
510 cpu_set(num_cpus, cpu_present_map);
511 num_cpus++;
512 }
513
514 for (cpu = 1; cpu < max_cpus; cpu++)
515 cpu_set(cpu, cpu_possible_map);
516
517 printk("Detected %d CPU's\n",(int) num_cpus);
518 printk("Boot cpu address %2X\n", boot_cpu_addr);
519}
520
521/*
522 * Activate a secondary processor.
523 */
524extern void init_cpu_timer(void);
525extern void init_cpu_vtimer(void);
526extern int pfault_init(void);
527extern void pfault_fini(void);
528
529int __devinit start_secondary(void *cpuvoid)
530{
531 /* Setup the cpu */
532 cpu_init();
533 /* init per CPU timer */
534 init_cpu_timer();
535#ifdef CONFIG_VIRT_TIMER
536 init_cpu_vtimer();
537#endif
538#ifdef CONFIG_PFAULT
539 /* Enable pfault pseudo page faults on this cpu. */
540 pfault_init();
541#endif
542 /* Mark this cpu as online */
543 cpu_set(smp_processor_id(), cpu_online_map);
544 /* Switch on interrupts */
545 local_irq_enable();
546 /* Print info about this processor */
547 print_cpu_info(&S390_lowcore.cpu_data);
548 /* cpu_idle will call schedule for us */
549 cpu_idle();
550 return 0;
551}
552
553static void __init smp_create_idle(unsigned int cpu)
554{
555 struct task_struct *p;
556
557 /*
558 * don't care about the psw and regs settings since we'll never
559 * reschedule the forked task.
560 */
561 p = fork_idle(cpu);
562 if (IS_ERR(p))
563 panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
564 current_set[cpu] = p;
565}
566
567/* Reserving and releasing of CPUs */
568
569static DEFINE_SPINLOCK(smp_reserve_lock);
570static int smp_cpu_reserved[NR_CPUS];
571
572int
573smp_get_cpu(cpumask_t cpu_mask)
574{
575 unsigned long flags;
576 int cpu;
577
578 spin_lock_irqsave(&smp_reserve_lock, flags);
579 /* Try to find an already reserved cpu. */
580 for_each_cpu_mask(cpu, cpu_mask) {
581 if (smp_cpu_reserved[cpu] != 0) {
582 smp_cpu_reserved[cpu]++;
583 /* Found one. */
584 goto out;
585 }
586 }
587 /* Reserve a new cpu from cpu_mask. */
588 for_each_cpu_mask(cpu, cpu_mask) {
589 if (cpu_online(cpu)) {
590 smp_cpu_reserved[cpu]++;
591 goto out;
592 }
593 }
594 cpu = -ENODEV;
595out:
596 spin_unlock_irqrestore(&smp_reserve_lock, flags);
597 return cpu;
598}
599
600void
601smp_put_cpu(int cpu)
602{
603 unsigned long flags;
604
605 spin_lock_irqsave(&smp_reserve_lock, flags);
606 smp_cpu_reserved[cpu]--;
607 spin_unlock_irqrestore(&smp_reserve_lock, flags);
608}
609
610static inline int
611cpu_stopped(int cpu)
612{
613 __u32 status;
614
615 /* Check for stopped state */
616 if (signal_processor_ps(&status, 0, cpu, sigp_sense) == sigp_status_stored) {
617 if (status & 0x40)
618 return 1;
619 }
620 return 0;
621}
622
623/* Upping and downing of CPUs */
624
625int
626__cpu_up(unsigned int cpu)
627{
628 struct task_struct *idle;
629 struct _lowcore *cpu_lowcore;
630 struct stack_frame *sf;
631 sigp_ccode ccode;
632 int curr_cpu;
633
634 for (curr_cpu = 0; curr_cpu <= 65535; curr_cpu++) {
635 __cpu_logical_map[cpu] = (__u16) curr_cpu;
636 if (cpu_stopped(cpu))
637 break;
638 }
639
640 if (!cpu_stopped(cpu))
641 return -ENODEV;
642
643 ccode = signal_processor_p((__u32)(unsigned long)(lowcore_ptr[cpu]),
644 cpu, sigp_set_prefix);
645 if (ccode){
646 printk("sigp_set_prefix failed for cpu %d "
647 "with condition code %d\n",
648 (int) cpu, (int) ccode);
649 return -EIO;
650 }
651
652 idle = current_set[cpu];
653 cpu_lowcore = lowcore_ptr[cpu];
654 cpu_lowcore->kernel_stack = (unsigned long)
655 idle->thread_info + (THREAD_SIZE);
656 sf = (struct stack_frame *) (cpu_lowcore->kernel_stack
657 - sizeof(struct pt_regs)
658 - sizeof(struct stack_frame));
659 memset(sf, 0, sizeof(struct stack_frame));
660 sf->gprs[9] = (unsigned long) sf;
661 cpu_lowcore->save_area[15] = (unsigned long) sf;
662 __ctl_store(cpu_lowcore->cregs_save_area[0], 0, 15);
663 __asm__ __volatile__("stam 0,15,0(%0)"
664 : : "a" (&cpu_lowcore->access_regs_save_area)
665 : "memory");
666 cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];
667 cpu_lowcore->current_task = (unsigned long) idle;
668 cpu_lowcore->cpu_data.cpu_nr = cpu;
669 eieio();
670 signal_processor(cpu,sigp_restart);
671
672 while (!cpu_online(cpu))
673 cpu_relax();
674 return 0;
675}
676
677int
678__cpu_disable(void)
679{
680 unsigned long flags;
681 ec_creg_mask_parms cr_parms;
682
683 spin_lock_irqsave(&smp_reserve_lock, flags);
684 if (smp_cpu_reserved[smp_processor_id()] != 0) {
685 spin_unlock_irqrestore(&smp_reserve_lock, flags);
686 return -EBUSY;
687 }
688
689#ifdef CONFIG_PFAULT
690 /* Disable pfault pseudo page faults on this cpu. */
691 pfault_fini();
692#endif
693
694 /* disable all external interrupts */
695
696 cr_parms.start_ctl = 0;
697 cr_parms.end_ctl = 0;
698 cr_parms.orvals[0] = 0;
699 cr_parms.andvals[0] = ~(1<<15 | 1<<14 | 1<<13 | 1<<12 |
700 1<<11 | 1<<10 | 1<< 6 | 1<< 4);
701 smp_ctl_bit_callback(&cr_parms);
702
703 /* disable all I/O interrupts */
704
705 cr_parms.start_ctl = 6;
706 cr_parms.end_ctl = 6;
707 cr_parms.orvals[6] = 0;
708 cr_parms.andvals[6] = ~(1<<31 | 1<<30 | 1<<29 | 1<<28 |
709 1<<27 | 1<<26 | 1<<25 | 1<<24);
710 smp_ctl_bit_callback(&cr_parms);
711
712 /* disable most machine checks */
713
714 cr_parms.start_ctl = 14;
715 cr_parms.end_ctl = 14;
716 cr_parms.orvals[14] = 0;
717 cr_parms.andvals[14] = ~(1<<28 | 1<<27 | 1<<26 | 1<<25 | 1<<24);
718 smp_ctl_bit_callback(&cr_parms);
719
720 spin_unlock_irqrestore(&smp_reserve_lock, flags);
721 return 0;
722}
723
724void
725__cpu_die(unsigned int cpu)
726{
727 /* Wait until target cpu is down */
728 while (!smp_cpu_not_running(cpu))
729 cpu_relax();
730 printk("Processor %d spun down\n", cpu);
731}
732
733void
734cpu_die(void)
735{
736 idle_task_exit();
737 signal_processor(smp_processor_id(), sigp_stop);
738 BUG();
739 for(;;);
740}
741
742/*
743 * Cycle through the processors and setup structures.
744 */
745
746void __init smp_prepare_cpus(unsigned int max_cpus)
747{
748 unsigned long stack;
749 unsigned int cpu;
750 int i;
751
752 /* request the 0x1202 external interrupt */
753 if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
754 panic("Couldn't request external interrupt 0x1202");
755 smp_check_cpus(max_cpus);
756 memset(lowcore_ptr,0,sizeof(lowcore_ptr));
757 /*
758 * Initialize prefix pages and stacks for all possible cpus
759 */
760 print_cpu_info(&S390_lowcore.cpu_data);
761
762 for(i = 0; i < NR_CPUS; i++) {
763 if (!cpu_possible(i))
764 continue;
765 lowcore_ptr[i] = (struct _lowcore *)
766 __get_free_pages(GFP_KERNEL|GFP_DMA,
767 sizeof(void*) == 8 ? 1 : 0);
768 stack = __get_free_pages(GFP_KERNEL,ASYNC_ORDER);
769 if (lowcore_ptr[i] == NULL || stack == 0ULL)
770 panic("smp_boot_cpus failed to allocate memory\n");
771
772 *(lowcore_ptr[i]) = S390_lowcore;
773 lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE);
774#ifdef CONFIG_CHECK_STACK
775 stack = __get_free_pages(GFP_KERNEL,0);
776 if (stack == 0ULL)
777 panic("smp_boot_cpus failed to allocate memory\n");
778 lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE);
779#endif
780 }
781 set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]);
782
783 for_each_cpu(cpu)
784 if (cpu != smp_processor_id())
785 smp_create_idle(cpu);
786}
787
788void __devinit smp_prepare_boot_cpu(void)
789{
790 BUG_ON(smp_processor_id() != 0);
791
792 cpu_set(0, cpu_online_map);
793 cpu_set(0, cpu_present_map);
794 cpu_set(0, cpu_possible_map);
795 S390_lowcore.percpu_offset = __per_cpu_offset[0];
796 current_set[0] = current;
797}
798
799void smp_cpus_done(unsigned int max_cpus)
800{
801 cpu_present_map = cpu_possible_map;
802}
803
804/*
805 * the frequency of the profiling timer can be changed
806 * by writing a multiplier value into /proc/profile.
807 *
808 * usually you want to run this on all CPUs ;)
809 */
810int setup_profiling_timer(unsigned int multiplier)
811{
812 return 0;
813}
814
815static DEFINE_PER_CPU(struct cpu, cpu_devices);
816
817static int __init topology_init(void)
818{
819 int cpu;
820 int ret;
821
822 for_each_cpu(cpu) {
823 ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL);
824 if (ret)
825 printk(KERN_WARNING "topology_init: register_cpu %d "
826 "failed (%d)\n", cpu, ret);
827 }
828 return 0;
829}
830
831subsys_initcall(topology_init);
832
833EXPORT_SYMBOL(cpu_possible_map);
834EXPORT_SYMBOL(lowcore_ptr);
835EXPORT_SYMBOL(smp_ctl_set_bit);
836EXPORT_SYMBOL(smp_ctl_clear_bit);
837EXPORT_SYMBOL(smp_call_function);
838EXPORT_SYMBOL(smp_get_cpu);
839EXPORT_SYMBOL(smp_put_cpu);
840
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
new file mode 100644
index 000000000000..efe6b83b53f7
--- /dev/null
+++ b/arch/s390/kernel/sys_s390.c
@@ -0,0 +1,270 @@
1/*
2 * arch/s390/kernel/sys_s390.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 * Thomas Spatzier (tspat@de.ibm.com)
8 *
9 * Derived from "arch/i386/kernel/sys_i386.c"
10 *
11 * This file contains various random system calls that
12 * have a non-standard calling sequence on the Linux/s390
13 * platform.
14 */
15
16#include <linux/errno.h>
17#include <linux/sched.h>
18#include <linux/mm.h>
19#include <linux/smp.h>
20#include <linux/smp_lock.h>
21#include <linux/sem.h>
22#include <linux/msg.h>
23#include <linux/shm.h>
24#include <linux/stat.h>
25#include <linux/syscalls.h>
26#include <linux/mman.h>
27#include <linux/file.h>
28#include <linux/utsname.h>
29#ifdef CONFIG_ARCH_S390X
30#include <linux/personality.h>
31#endif /* CONFIG_ARCH_S390X */
32
33#include <asm/uaccess.h>
34#include <asm/ipc.h>
35
36/*
37 * sys_pipe() is the normal C calling standard for creating
38 * a pipe. It's not the way Unix traditionally does this, though.
39 */
40asmlinkage long sys_pipe(unsigned long __user *fildes)
41{
42 int fd[2];
43 int error;
44
45 error = do_pipe(fd);
46 if (!error) {
47 if (copy_to_user(fildes, fd, 2*sizeof(int)))
48 error = -EFAULT;
49 }
50 return error;
51}
52
53/* common code for old and new mmaps */
54static inline long do_mmap2(
55 unsigned long addr, unsigned long len,
56 unsigned long prot, unsigned long flags,
57 unsigned long fd, unsigned long pgoff)
58{
59 long error = -EBADF;
60 struct file * file = NULL;
61
62 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
63 if (!(flags & MAP_ANONYMOUS)) {
64 file = fget(fd);
65 if (!file)
66 goto out;
67 }
68
69 down_write(&current->mm->mmap_sem);
70 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
71 up_write(&current->mm->mmap_sem);
72
73 if (file)
74 fput(file);
75out:
76 return error;
77}
78
79/*
80 * Perform the select(nd, in, out, ex, tv) and mmap() system
81 * calls. Linux for S/390 isn't able to handle more than 5
82 * system call parameters, so these system calls used a memory
83 * block for parameter passing..
84 */
85
86struct mmap_arg_struct {
87 unsigned long addr;
88 unsigned long len;
89 unsigned long prot;
90 unsigned long flags;
91 unsigned long fd;
92 unsigned long offset;
93};
94
95asmlinkage long sys_mmap2(struct mmap_arg_struct __user *arg)
96{
97 struct mmap_arg_struct a;
98 int error = -EFAULT;
99
100 if (copy_from_user(&a, arg, sizeof(a)))
101 goto out;
102 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
103out:
104 return error;
105}
106
107asmlinkage long old_mmap(struct mmap_arg_struct __user *arg)
108{
109 struct mmap_arg_struct a;
110 long error = -EFAULT;
111
112 if (copy_from_user(&a, arg, sizeof(a)))
113 goto out;
114
115 error = -EINVAL;
116 if (a.offset & ~PAGE_MASK)
117 goto out;
118
119 error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
120out:
121 return error;
122}
123
124#ifndef CONFIG_ARCH_S390X
125struct sel_arg_struct {
126 unsigned long n;
127 fd_set *inp, *outp, *exp;
128 struct timeval *tvp;
129};
130
131asmlinkage long old_select(struct sel_arg_struct __user *arg)
132{
133 struct sel_arg_struct a;
134
135 if (copy_from_user(&a, arg, sizeof(a)))
136 return -EFAULT;
137 /* sys_select() does the appropriate kernel locking */
138 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
139
140}
141#endif /* CONFIG_ARCH_S390X */
142
143/*
144 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
145 *
146 * This is really horribly ugly.
147 */
148asmlinkage long sys_ipc(uint call, int first, unsigned long second,
149 unsigned long third, void __user *ptr)
150{
151 struct ipc_kludge tmp;
152 int ret;
153
154 switch (call) {
155 case SEMOP:
156 return sys_semtimedop(first, (struct sembuf __user *)ptr,
157 (unsigned)second, NULL);
158 case SEMTIMEDOP:
159 return sys_semtimedop(first, (struct sembuf __user *)ptr,
160 (unsigned)second,
161 (const struct timespec __user *) third);
162 case SEMGET:
163 return sys_semget(first, (int)second, third);
164 case SEMCTL: {
165 union semun fourth;
166 if (!ptr)
167 return -EINVAL;
168 if (get_user(fourth.__pad, (void __user * __user *) ptr))
169 return -EFAULT;
170 return sys_semctl(first, (int)second, third, fourth);
171 }
172 case MSGSND:
173 return sys_msgsnd (first, (struct msgbuf __user *) ptr,
174 (size_t)second, third);
175 break;
176 case MSGRCV:
177 if (!ptr)
178 return -EINVAL;
179 if (copy_from_user (&tmp, (struct ipc_kludge __user *) ptr,
180 sizeof (struct ipc_kludge)))
181 return -EFAULT;
182 return sys_msgrcv (first, tmp.msgp,
183 (size_t)second, tmp.msgtyp, third);
184 case MSGGET:
185 return sys_msgget((key_t)first, (int)second);
186 case MSGCTL:
187 return sys_msgctl(first, (int)second,
188 (struct msqid_ds __user *)ptr);
189
190 case SHMAT: {
191 ulong raddr;
192 ret = do_shmat(first, (char __user *)ptr,
193 (int)second, &raddr);
194 if (ret)
195 return ret;
196 return put_user (raddr, (ulong __user *) third);
197 break;
198 }
199 case SHMDT:
200 return sys_shmdt ((char __user *)ptr);
201 case SHMGET:
202 return sys_shmget(first, (size_t)second, third);
203 case SHMCTL:
204 return sys_shmctl(first, (int)second,
205 (struct shmid_ds __user *) ptr);
206 default:
207 return -ENOSYS;
208
209 }
210
211 return -EINVAL;
212}
213
214#ifdef CONFIG_ARCH_S390X
215asmlinkage long s390x_newuname(struct new_utsname __user *name)
216{
217 int ret = sys_newuname(name);
218
219 if (current->personality == PER_LINUX32 && !ret) {
220 ret = copy_to_user(name->machine, "s390\0\0\0\0", 8);
221 if (ret) ret = -EFAULT;
222 }
223 return ret;
224}
225
226asmlinkage long s390x_personality(unsigned long personality)
227{
228 int ret;
229
230 if (current->personality == PER_LINUX32 && personality == PER_LINUX)
231 personality = PER_LINUX32;
232 ret = sys_personality(personality);
233 if (ret == PER_LINUX32)
234 ret = PER_LINUX;
235
236 return ret;
237}
238#endif /* CONFIG_ARCH_S390X */
239
240/*
241 * Wrapper function for sys_fadvise64/fadvise64_64
242 */
243#ifndef CONFIG_ARCH_S390X
244
245asmlinkage long
246s390_fadvise64(int fd, u32 offset_high, u32 offset_low, size_t len, int advice)
247{
248 return sys_fadvise64(fd, (u64) offset_high << 32 | offset_low,
249 len, advice);
250}
251
252#endif
253
254struct fadvise64_64_args {
255 int fd;
256 long long offset;
257 long long len;
258 int advice;
259};
260
261asmlinkage long
262s390_fadvise64_64(struct fadvise64_64_args __user *args)
263{
264 struct fadvise64_64_args a;
265
266 if ( copy_from_user(&a, args, sizeof(a)) )
267 return -EFAULT;
268 return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
269}
270
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
new file mode 100644
index 000000000000..515938628f82
--- /dev/null
+++ b/arch/s390/kernel/syscalls.S
@@ -0,0 +1,292 @@
1/*
2 * definitions for sys_call_table, each line represents an
3 * entry in the table in the form
4 * SYSCALL(31 bit syscall, 64 bit syscall, 31 bit emulated syscall)
5 *
6 * this file is meant to be included from entry.S and entry64.S
7 */
8
9#define NI_SYSCALL SYSCALL(sys_ni_syscall,sys_ni_syscall,sys_ni_syscall)
10
11NI_SYSCALL /* 0 */
12SYSCALL(sys_exit,sys_exit,sys32_exit_wrapper)
13SYSCALL(sys_fork_glue,sys_fork_glue,sys_fork_glue)
14SYSCALL(sys_read,sys_read,sys32_read_wrapper)
15SYSCALL(sys_write,sys_write,sys32_write_wrapper)
16SYSCALL(sys_open,sys_open,sys32_open_wrapper) /* 5 */
17SYSCALL(sys_close,sys_close,sys32_close_wrapper)
18SYSCALL(sys_restart_syscall,sys_restart_syscall,sys_restart_syscall)
19SYSCALL(sys_creat,sys_creat,sys32_creat_wrapper)
20SYSCALL(sys_link,sys_link,sys32_link_wrapper)
21SYSCALL(sys_unlink,sys_unlink,sys32_unlink_wrapper) /* 10 */
22SYSCALL(sys_execve_glue,sys_execve_glue,sys32_execve_glue)
23SYSCALL(sys_chdir,sys_chdir,sys32_chdir_wrapper)
24SYSCALL(sys_time,sys_ni_syscall,sys32_time_wrapper) /* old time syscall */
25SYSCALL(sys_mknod,sys_mknod,sys32_mknod_wrapper)
26SYSCALL(sys_chmod,sys_chmod,sys32_chmod_wrapper) /* 15 */
27SYSCALL(sys_lchown16,sys_ni_syscall,sys32_lchown16_wrapper) /* old lchown16 syscall*/
28NI_SYSCALL /* old break syscall holder */
29NI_SYSCALL /* old stat syscall holder */
30SYSCALL(sys_lseek,sys_lseek,sys32_lseek_wrapper)
31SYSCALL(sys_getpid,sys_getpid,sys_getpid) /* 20 */
32SYSCALL(sys_mount,sys_mount,sys32_mount_wrapper)
33SYSCALL(sys_oldumount,sys_oldumount,sys32_oldumount_wrapper)
34SYSCALL(sys_setuid16,sys_ni_syscall,sys32_setuid16_wrapper) /* old setuid16 syscall*/
35SYSCALL(sys_getuid16,sys_ni_syscall,sys32_getuid16) /* old getuid16 syscall*/
36SYSCALL(sys_stime,sys_ni_syscall,sys32_stime_wrapper) /* 25 old stime syscall */
37SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper)
38SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper)
39NI_SYSCALL /* old fstat syscall */
40SYSCALL(sys_pause,sys_pause,sys32_pause)
41SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper) /* 30 */
42NI_SYSCALL /* old stty syscall */
43NI_SYSCALL /* old gtty syscall */
44SYSCALL(sys_access,sys_access,sys32_access_wrapper)
45SYSCALL(sys_nice,sys_nice,sys32_nice_wrapper)
46NI_SYSCALL /* 35 old ftime syscall */
47SYSCALL(sys_sync,sys_sync,sys_sync)
48SYSCALL(sys_kill,sys_kill,sys32_kill_wrapper)
49SYSCALL(sys_rename,sys_rename,sys32_rename_wrapper)
50SYSCALL(sys_mkdir,sys_mkdir,sys32_mkdir_wrapper)
51SYSCALL(sys_rmdir,sys_rmdir,sys32_rmdir_wrapper) /* 40 */
52SYSCALL(sys_dup,sys_dup,sys32_dup_wrapper)
53SYSCALL(sys_pipe,sys_pipe,sys32_pipe_wrapper)
54SYSCALL(sys_times,sys_times,compat_sys_times_wrapper)
55NI_SYSCALL /* old prof syscall */
56SYSCALL(sys_brk,sys_brk,sys32_brk_wrapper) /* 45 */
57SYSCALL(sys_setgid16,sys_ni_syscall,sys32_setgid16_wrapper) /* old setgid16 syscall*/
58SYSCALL(sys_getgid16,sys_ni_syscall,sys32_getgid16) /* old getgid16 syscall*/
59SYSCALL(sys_signal,sys_signal,sys32_signal_wrapper)
60SYSCALL(sys_geteuid16,sys_ni_syscall,sys32_geteuid16) /* old geteuid16 syscall */
61SYSCALL(sys_getegid16,sys_ni_syscall,sys32_getegid16) /* 50 old getegid16 syscall */
62SYSCALL(sys_acct,sys_acct,sys32_acct_wrapper)
63SYSCALL(sys_umount,sys_umount,sys32_umount_wrapper)
64NI_SYSCALL /* old lock syscall */
65SYSCALL(sys_ioctl,sys_ioctl,compat_sys_ioctl_wrapper)
66SYSCALL(sys_fcntl,sys_fcntl,compat_sys_fcntl_wrapper) /* 55 */
67NI_SYSCALL /* intel mpx syscall */
68SYSCALL(sys_setpgid,sys_setpgid,sys32_setpgid_wrapper)
69NI_SYSCALL /* old ulimit syscall */
70NI_SYSCALL /* old uname syscall */
71SYSCALL(sys_umask,sys_umask,sys32_umask_wrapper) /* 60 */
72SYSCALL(sys_chroot,sys_chroot,sys32_chroot_wrapper)
73SYSCALL(sys_ustat,sys_ustat,sys32_ustat_wrapper)
74SYSCALL(sys_dup2,sys_dup2,sys32_dup2_wrapper)
75SYSCALL(sys_getppid,sys_getppid,sys_getppid)
76SYSCALL(sys_getpgrp,sys_getpgrp,sys_getpgrp) /* 65 */
77SYSCALL(sys_setsid,sys_setsid,sys_setsid)
78SYSCALL(sys_sigaction,sys_sigaction,sys32_sigaction_wrapper)
79NI_SYSCALL /* old sgetmask syscall*/
80NI_SYSCALL /* old ssetmask syscall*/
81SYSCALL(sys_setreuid16,sys_ni_syscall,sys32_setreuid16_wrapper) /* old setreuid16 syscall */
82SYSCALL(sys_setregid16,sys_ni_syscall,sys32_setregid16_wrapper) /* old setregid16 syscall */
83SYSCALL(sys_sigsuspend_glue,sys_sigsuspend_glue,sys32_sigsuspend_glue)
84SYSCALL(sys_sigpending,sys_sigpending,compat_sys_sigpending_wrapper)
85SYSCALL(sys_sethostname,sys_sethostname,sys32_sethostname_wrapper)
86SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit_wrapper) /* 75 */
87SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit_wrapper)
88SYSCALL(sys_getrusage,sys_getrusage,compat_sys_getrusage_wrapper)
89SYSCALL(sys_gettimeofday,sys_gettimeofday,sys32_gettimeofday_wrapper)
90SYSCALL(sys_settimeofday,sys_settimeofday,sys32_settimeofday_wrapper)
91SYSCALL(sys_getgroups16,sys_ni_syscall,sys32_getgroups16_wrapper) /* 80 old getgroups16 syscall */
92SYSCALL(sys_setgroups16,sys_ni_syscall,sys32_setgroups16_wrapper) /* old setgroups16 syscall */
93NI_SYSCALL /* old select syscall */
94SYSCALL(sys_symlink,sys_symlink,sys32_symlink_wrapper)
95NI_SYSCALL /* old lstat syscall */
96SYSCALL(sys_readlink,sys_readlink,sys32_readlink_wrapper) /* 85 */
97SYSCALL(sys_uselib,sys_uselib,sys32_uselib_wrapper)
98SYSCALL(sys_swapon,sys_swapon,sys32_swapon_wrapper)
99SYSCALL(sys_reboot,sys_reboot,sys32_reboot_wrapper)
100SYSCALL(sys_ni_syscall,sys_ni_syscall,old32_readdir_wrapper) /* old readdir syscall */
101SYSCALL(old_mmap,old_mmap,old32_mmap_wrapper) /* 90 */
102SYSCALL(sys_munmap,sys_munmap,sys32_munmap_wrapper)
103SYSCALL(sys_truncate,sys_truncate,sys32_truncate_wrapper)
104SYSCALL(sys_ftruncate,sys_ftruncate,sys32_ftruncate_wrapper)
105SYSCALL(sys_fchmod,sys_fchmod,sys32_fchmod_wrapper)
106SYSCALL(sys_fchown16,sys_ni_syscall,sys32_fchown16_wrapper) /* 95 old fchown16 syscall*/
107SYSCALL(sys_getpriority,sys_getpriority,sys32_getpriority_wrapper)
108SYSCALL(sys_setpriority,sys_setpriority,sys32_setpriority_wrapper)
109NI_SYSCALL /* old profil syscall */
110SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs_wrapper)
111SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs_wrapper) /* 100 */
112NI_SYSCALL /* ioperm for i386 */
113SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall_wrapper)
114SYSCALL(sys_syslog,sys_syslog,sys32_syslog_wrapper)
115SYSCALL(sys_setitimer,sys_setitimer,compat_sys_setitimer_wrapper)
116SYSCALL(sys_getitimer,sys_getitimer,compat_sys_getitimer_wrapper) /* 105 */
117SYSCALL(sys_newstat,sys_newstat,compat_sys_newstat_wrapper)
118SYSCALL(sys_newlstat,sys_newlstat,compat_sys_newlstat_wrapper)
119SYSCALL(sys_newfstat,sys_newfstat,compat_sys_newfstat_wrapper)
120NI_SYSCALL /* old uname syscall */
121SYSCALL(sys_lookup_dcookie,sys_lookup_dcookie,sys32_lookup_dcookie_wrapper) /* 110 */
122SYSCALL(sys_vhangup,sys_vhangup,sys_vhangup)
123NI_SYSCALL /* old "idle" system call */
124NI_SYSCALL /* vm86old for i386 */
125SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4_wrapper)
126SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */
127SYSCALL(sys_sysinfo,sys_sysinfo,sys32_sysinfo_wrapper)
128SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper)
129SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper)
130SYSCALL(sys_sigreturn_glue,sys_sigreturn_glue,sys32_sigreturn_glue)
131SYSCALL(sys_clone_glue,sys_clone_glue,sys32_clone_glue) /* 120 */
132SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper)
133SYSCALL(sys_newuname,s390x_newuname,sys32_newuname_wrapper)
134NI_SYSCALL /* modify_ldt for i386 */
135SYSCALL(sys_adjtimex,sys_adjtimex,sys32_adjtimex_wrapper)
136SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */
137SYSCALL(sys_sigprocmask,sys_sigprocmask,compat_sys_sigprocmask_wrapper)
138NI_SYSCALL /* old "create module" */
139SYSCALL(sys_init_module,sys_init_module,sys32_init_module_wrapper)
140SYSCALL(sys_delete_module,sys_delete_module,sys32_delete_module_wrapper)
141NI_SYSCALL /* 130: old get_kernel_syms */
142SYSCALL(sys_quotactl,sys_quotactl,sys32_quotactl_wrapper)
143SYSCALL(sys_getpgid,sys_getpgid,sys32_getpgid_wrapper)
144SYSCALL(sys_fchdir,sys_fchdir,sys32_fchdir_wrapper)
145SYSCALL(sys_bdflush,sys_bdflush,sys32_bdflush_wrapper)
146SYSCALL(sys_sysfs,sys_sysfs,sys32_sysfs_wrapper) /* 135 */
147SYSCALL(sys_personality,s390x_personality,sys32_personality_wrapper)
148NI_SYSCALL /* for afs_syscall */
149SYSCALL(sys_setfsuid16,sys_ni_syscall,sys32_setfsuid16_wrapper) /* old setfsuid16 syscall */
150SYSCALL(sys_setfsgid16,sys_ni_syscall,sys32_setfsgid16_wrapper) /* old setfsgid16 syscall */
151SYSCALL(sys_llseek,sys_llseek,sys32_llseek_wrapper) /* 140 */
152SYSCALL(sys_getdents,sys_getdents,sys32_getdents_wrapper)
153SYSCALL(sys_select,sys_select,compat_sys_select_wrapper)
154SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper)
155SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper)
156SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper) /* 145 */
157SYSCALL(sys_writev,sys_writev,compat_sys_writev_wrapper)
158SYSCALL(sys_getsid,sys_getsid,sys32_getsid_wrapper)
159SYSCALL(sys_fdatasync,sys_fdatasync,sys32_fdatasync_wrapper)
160SYSCALL(sys_sysctl,sys_sysctl,sys32_sysctl_wrapper)
161SYSCALL(sys_mlock,sys_mlock,sys32_mlock_wrapper) /* 150 */
162SYSCALL(sys_munlock,sys_munlock,sys32_munlock_wrapper)
163SYSCALL(sys_mlockall,sys_mlockall,sys32_mlockall_wrapper)
164SYSCALL(sys_munlockall,sys_munlockall,sys_munlockall)
165SYSCALL(sys_sched_setparam,sys_sched_setparam,sys32_sched_setparam_wrapper)
166SYSCALL(sys_sched_getparam,sys_sched_getparam,sys32_sched_getparam_wrapper) /* 155 */
167SYSCALL(sys_sched_setscheduler,sys_sched_setscheduler,sys32_sched_setscheduler_wrapper)
168SYSCALL(sys_sched_getscheduler,sys_sched_getscheduler,sys32_sched_getscheduler_wrapper)
169SYSCALL(sys_sched_yield,sys_sched_yield,sys_sched_yield)
170SYSCALL(sys_sched_get_priority_max,sys_sched_get_priority_max,sys32_sched_get_priority_max_wrapper)
171SYSCALL(sys_sched_get_priority_min,sys_sched_get_priority_min,sys32_sched_get_priority_min_wrapper) /* 160 */
172SYSCALL(sys_sched_rr_get_interval,sys_sched_rr_get_interval,sys32_sched_rr_get_interval_wrapper)
173SYSCALL(sys_nanosleep,sys_nanosleep,compat_sys_nanosleep_wrapper)
174SYSCALL(sys_mremap,sys_mremap,sys32_mremap_wrapper)
175SYSCALL(sys_setresuid16,sys_ni_syscall,sys32_setresuid16_wrapper) /* old setresuid16 syscall */
176SYSCALL(sys_getresuid16,sys_ni_syscall,sys32_getresuid16_wrapper) /* 165 old getresuid16 syscall */
177NI_SYSCALL /* for vm86 */
178NI_SYSCALL /* old sys_query_module */
179SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper)
180SYSCALL(sys_nfsservctl,sys_nfsservctl,compat_sys_nfsservctl_wrapper)
181SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old setresgid16 syscall */
182SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */
183SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
184SYSCALL(sys_rt_sigreturn_glue,sys_rt_sigreturn_glue,sys32_rt_sigreturn_glue)
185SYSCALL(sys_rt_sigaction,sys_rt_sigaction,sys32_rt_sigaction_wrapper)
186SYSCALL(sys_rt_sigprocmask,sys_rt_sigprocmask,sys32_rt_sigprocmask_wrapper) /* 175 */
187SYSCALL(sys_rt_sigpending,sys_rt_sigpending,sys32_rt_sigpending_wrapper)
188SYSCALL(sys_rt_sigtimedwait,sys_rt_sigtimedwait,compat_sys_rt_sigtimedwait_wrapper)
189SYSCALL(sys_rt_sigqueueinfo,sys_rt_sigqueueinfo,sys32_rt_sigqueueinfo_wrapper)
190SYSCALL(sys_rt_sigsuspend_glue,sys_rt_sigsuspend_glue,sys32_rt_sigsuspend_glue)
191SYSCALL(sys_pread64,sys_pread64,sys32_pread64_wrapper) /* 180 */
192SYSCALL(sys_pwrite64,sys_pwrite64,sys32_pwrite64_wrapper)
193SYSCALL(sys_chown16,sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall */
194SYSCALL(sys_getcwd,sys_getcwd,sys32_getcwd_wrapper)
195SYSCALL(sys_capget,sys_capget,sys32_capget_wrapper)
196SYSCALL(sys_capset,sys_capset,sys32_capset_wrapper) /* 185 */
197SYSCALL(sys_sigaltstack_glue,sys_sigaltstack_glue,sys32_sigaltstack_glue)
198SYSCALL(sys_sendfile,sys_sendfile64,sys32_sendfile_wrapper)
199NI_SYSCALL /* streams1 */
200NI_SYSCALL /* streams2 */
201SYSCALL(sys_vfork_glue,sys_vfork_glue,sys_vfork_glue) /* 190 */
202SYSCALL(sys_getrlimit,sys_getrlimit,compat_sys_getrlimit_wrapper)
203SYSCALL(sys_mmap2,sys_mmap2,sys32_mmap2_wrapper)
204SYSCALL(sys_truncate64,sys_ni_syscall,sys32_truncate64_wrapper)
205SYSCALL(sys_ftruncate64,sys_ni_syscall,sys32_ftruncate64_wrapper)
206SYSCALL(sys_stat64,sys_ni_syscall,sys32_stat64_wrapper) /* 195 */
207SYSCALL(sys_lstat64,sys_ni_syscall,sys32_lstat64_wrapper)
208SYSCALL(sys_fstat64,sys_ni_syscall,sys32_fstat64_wrapper)
209SYSCALL(sys_lchown,sys_lchown,sys32_lchown_wrapper)
210SYSCALL(sys_getuid,sys_getuid,sys_getuid)
211SYSCALL(sys_getgid,sys_getgid,sys_getgid) /* 200 */
212SYSCALL(sys_geteuid,sys_geteuid,sys_geteuid)
213SYSCALL(sys_getegid,sys_getegid,sys_getegid)
214SYSCALL(sys_setreuid,sys_setreuid,sys32_setreuid_wrapper)
215SYSCALL(sys_setregid,sys_setregid,sys32_setregid_wrapper)
216SYSCALL(sys_getgroups,sys_getgroups,sys32_getgroups_wrapper) /* 205 */
217SYSCALL(sys_setgroups,sys_setgroups,sys32_setgroups_wrapper)
218SYSCALL(sys_fchown,sys_fchown,sys32_fchown_wrapper)
219SYSCALL(sys_setresuid,sys_setresuid,sys32_setresuid_wrapper)
220SYSCALL(sys_getresuid,sys_getresuid,sys32_getresuid_wrapper)
221SYSCALL(sys_setresgid,sys_setresgid,sys32_setresgid_wrapper) /* 210 */
222SYSCALL(sys_getresgid,sys_getresgid,sys32_getresgid_wrapper)
223SYSCALL(sys_chown,sys_chown,sys32_chown_wrapper)
224SYSCALL(sys_setuid,sys_setuid,sys32_setuid_wrapper)
225SYSCALL(sys_setgid,sys_setgid,sys32_setgid_wrapper)
226SYSCALL(sys_setfsuid,sys_setfsuid,sys32_setfsuid_wrapper) /* 215 */
227SYSCALL(sys_setfsgid,sys_setfsgid,sys32_setfsgid_wrapper)
228SYSCALL(sys_pivot_root,sys_pivot_root,sys32_pivot_root_wrapper)
229SYSCALL(sys_mincore,sys_mincore,sys32_mincore_wrapper)
230SYSCALL(sys_madvise,sys_madvise,sys32_madvise_wrapper)
231SYSCALL(sys_getdents64,sys_getdents64,sys32_getdents64_wrapper) /* 220 */
232SYSCALL(sys_fcntl64,sys_ni_syscall,compat_sys_fcntl64_wrapper)
233SYSCALL(sys_readahead,sys_readahead,sys32_readahead)
234SYSCALL(sys_sendfile64,sys_ni_syscall,sys32_sendfile64)
235SYSCALL(sys_setxattr,sys_setxattr,sys32_setxattr_wrapper)
236SYSCALL(sys_lsetxattr,sys_lsetxattr,sys32_lsetxattr_wrapper) /* 225 */
237SYSCALL(sys_fsetxattr,sys_fsetxattr,sys32_fsetxattr_wrapper)
238SYSCALL(sys_getxattr,sys_getxattr,sys32_getxattr_wrapper)
239SYSCALL(sys_lgetxattr,sys_lgetxattr,sys32_lgetxattr_wrapper)
240SYSCALL(sys_fgetxattr,sys_fgetxattr,sys32_fgetxattr_wrapper)
241SYSCALL(sys_listxattr,sys_listxattr,sys32_listxattr_wrapper) /* 230 */
242SYSCALL(sys_llistxattr,sys_llistxattr,sys32_llistxattr_wrapper)
243SYSCALL(sys_flistxattr,sys_flistxattr,sys32_flistxattr_wrapper)
244SYSCALL(sys_removexattr,sys_removexattr,sys32_removexattr_wrapper)
245SYSCALL(sys_lremovexattr,sys_lremovexattr,sys32_lremovexattr_wrapper)
246SYSCALL(sys_fremovexattr,sys_fremovexattr,sys32_fremovexattr_wrapper) /* 235 */
247SYSCALL(sys_gettid,sys_gettid,sys_gettid)
248SYSCALL(sys_tkill,sys_tkill,sys_tkill)
249SYSCALL(sys_futex,sys_futex,compat_sys_futex_wrapper)
250SYSCALL(sys_sched_setaffinity,sys_sched_setaffinity,sys32_sched_setaffinity_wrapper)
251SYSCALL(sys_sched_getaffinity,sys_sched_getaffinity,sys32_sched_getaffinity_wrapper) /* 240 */
252SYSCALL(sys_tgkill,sys_tgkill,sys_tgkill)
253NI_SYSCALL /* reserved for TUX */
254SYSCALL(sys_io_setup,sys_io_setup,sys32_io_setup_wrapper)
255SYSCALL(sys_io_destroy,sys_io_destroy,sys32_io_destroy_wrapper)
256SYSCALL(sys_io_getevents,sys_io_getevents,sys32_io_getevents_wrapper) /* 245 */
257SYSCALL(sys_io_submit,sys_io_submit,sys32_io_submit_wrapper)
258SYSCALL(sys_io_cancel,sys_io_cancel,sys32_io_cancel_wrapper)
259SYSCALL(sys_exit_group,sys_exit_group,sys32_exit_group_wrapper)
260SYSCALL(sys_epoll_create,sys_epoll_create,sys_epoll_create_wrapper)
261SYSCALL(sys_epoll_ctl,sys_epoll_ctl,sys_epoll_ctl_wrapper) /* 250 */
262SYSCALL(sys_epoll_wait,sys_epoll_wait,sys_epoll_wait_wrapper)
263SYSCALL(sys_set_tid_address,sys_set_tid_address,sys32_set_tid_address_wrapper)
264SYSCALL(s390_fadvise64,sys_fadvise64_64,sys32_fadvise64_wrapper)
265SYSCALL(sys_timer_create,sys_timer_create,sys32_timer_create_wrapper)
266SYSCALL(sys_timer_settime,sys_timer_settime,sys32_timer_settime_wrapper) /* 255 */
267SYSCALL(sys_timer_gettime,sys_timer_gettime,sys32_timer_gettime_wrapper)
268SYSCALL(sys_timer_getoverrun,sys_timer_getoverrun,sys32_timer_getoverrun_wrapper)
269SYSCALL(sys_timer_delete,sys_timer_delete,sys32_timer_delete_wrapper)
270SYSCALL(sys_clock_settime,sys_clock_settime,sys32_clock_settime_wrapper)
271SYSCALL(sys_clock_gettime,sys_clock_gettime,sys32_clock_gettime_wrapper) /* 260 */
272SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper)
273SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper)
274NI_SYSCALL /* reserved for vserver */
275SYSCALL(s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper)
276SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper)
277SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper)
278SYSCALL(sys_remap_file_pages,sys_remap_file_pages,sys32_remap_file_pages_wrapper)
279NI_SYSCALL /* 268 sys_mbind */
280NI_SYSCALL /* 269 sys_get_mempolicy */
281NI_SYSCALL /* 270 sys_set_mempolicy */
282SYSCALL(sys_mq_open,sys_mq_open,compat_sys_mq_open_wrapper)
283SYSCALL(sys_mq_unlink,sys_mq_unlink,sys32_mq_unlink_wrapper)
284SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper)
285SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
286SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
287SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
288NI_SYSCALL /* reserved for kexec */
289SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
290SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
291SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl) /* 280 */
292SYSCALL(sys_waitid,sys_waitid,compat_sys_waitid_wrapper)
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
new file mode 100644
index 000000000000..061e81138dc2
--- /dev/null
+++ b/arch/s390/kernel/time.c
@@ -0,0 +1,382 @@
1/*
2 * arch/s390/kernel/time.c
3 * Time of day based timer functions.
4 *
5 * S390 version
6 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Hartmut Penner (hp@de.ibm.com),
8 * Martin Schwidefsky (schwidefsky@de.ibm.com),
9 * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
10 *
11 * Derived from "arch/i386/kernel/time.c"
12 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
13 */
14
15#include <linux/config.h>
16#include <linux/errno.h>
17#include <linux/module.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/param.h>
21#include <linux/string.h>
22#include <linux/mm.h>
23#include <linux/interrupt.h>
24#include <linux/time.h>
25#include <linux/delay.h>
26#include <linux/init.h>
27#include <linux/smp.h>
28#include <linux/types.h>
29#include <linux/profile.h>
30#include <linux/timex.h>
31#include <linux/notifier.h>
32
33#include <asm/uaccess.h>
34#include <asm/delay.h>
35#include <asm/s390_ext.h>
36#include <asm/div64.h>
37#include <asm/irq.h>
38#include <asm/timer.h>
39
40/* change this if you have some constant time drift */
41#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ)
42#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
43
44/*
45 * Create a small time difference between the timer interrupts
46 * on the different cpus to avoid lock contention.
47 */
48#define CPU_DEVIATION (smp_processor_id() << 12)
49
50#define TICK_SIZE tick
51
52u64 jiffies_64 = INITIAL_JIFFIES;
53
54EXPORT_SYMBOL(jiffies_64);
55
56static ext_int_info_t ext_int_info_cc;
57static u64 init_timer_cc;
58static u64 jiffies_timer_cc;
59static u64 xtime_cc;
60
61extern unsigned long wall_jiffies;
62
63/*
64 * Scheduler clock - returns current time in nanosec units.
65 */
66unsigned long long sched_clock(void)
67{
68 return ((get_clock() - jiffies_timer_cc) * 1000) >> 12;
69}
70
71void tod_to_timeval(__u64 todval, struct timespec *xtime)
72{
73 unsigned long long sec;
74
75 sec = todval >> 12;
76 do_div(sec, 1000000);
77 xtime->tv_sec = sec;
78 todval -= (sec * 1000000) << 12;
79 xtime->tv_nsec = ((todval * 1000) >> 12);
80}
81
82static inline unsigned long do_gettimeoffset(void)
83{
84 __u64 now;
85
86 now = (get_clock() - jiffies_timer_cc) >> 12;
87 /* We require the offset from the latest update of xtime */
88 now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
89 return (unsigned long) now;
90}
91
92/*
93 * This version of gettimeofday has microsecond resolution.
94 */
95void do_gettimeofday(struct timeval *tv)
96{
97 unsigned long flags;
98 unsigned long seq;
99 unsigned long usec, sec;
100
101 do {
102 seq = read_seqbegin_irqsave(&xtime_lock, flags);
103
104 sec = xtime.tv_sec;
105 usec = xtime.tv_nsec / 1000 + do_gettimeoffset();
106 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
107
108 while (usec >= 1000000) {
109 usec -= 1000000;
110 sec++;
111 }
112
113 tv->tv_sec = sec;
114 tv->tv_usec = usec;
115}
116
117EXPORT_SYMBOL(do_gettimeofday);
118
119int do_settimeofday(struct timespec *tv)
120{
121 time_t wtm_sec, sec = tv->tv_sec;
122 long wtm_nsec, nsec = tv->tv_nsec;
123
124 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
125 return -EINVAL;
126
127 write_seqlock_irq(&xtime_lock);
128 /* This is revolting. We need to set the xtime.tv_nsec
129 * correctly. However, the value in this location is
130 * is value at the last tick.
131 * Discover what correction gettimeofday
132 * would have done, and then undo it!
133 */
134 nsec -= do_gettimeoffset() * 1000;
135
136 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
137 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
138
139 set_normalized_timespec(&xtime, sec, nsec);
140 set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
141
142 time_adjust = 0; /* stop active adjtime() */
143 time_status |= STA_UNSYNC;
144 time_maxerror = NTP_PHASE_LIMIT;
145 time_esterror = NTP_PHASE_LIMIT;
146 write_sequnlock_irq(&xtime_lock);
147 clock_was_set();
148 return 0;
149}
150
151EXPORT_SYMBOL(do_settimeofday);
152
153
154#ifdef CONFIG_PROFILING
155#define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs)
156#else
157#define s390_do_profile(regs) do { ; } while(0)
158#endif /* CONFIG_PROFILING */
159
160
161/*
162 * timer_interrupt() needs to keep up the real-time clock,
163 * as well as call the "do_timer()" routine every clocktick
164 */
165void account_ticks(struct pt_regs *regs)
166{
167 __u64 tmp;
168 __u32 ticks, xticks;
169
170 /* Calculate how many ticks have passed. */
171 if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
172 /*
173 * We have to program the clock comparator even if
174 * no tick has passed. That happens if e.g. an i/o
175 * interrupt wakes up an idle processor that has
176 * switched off its hz timer.
177 */
178 tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
179 asm volatile ("SCKC %0" : : "m" (tmp));
180 return;
181 }
182 tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
183 if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */
184 ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
185 S390_lowcore.jiffy_timer +=
186 CLK_TICKS_PER_JIFFY * (__u64) ticks;
187 } else if (tmp >= CLK_TICKS_PER_JIFFY) {
188 ticks = 2;
189 S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY;
190 } else {
191 ticks = 1;
192 S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
193 }
194
195 /* set clock comparator for next tick */
196 tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
197 asm volatile ("SCKC %0" : : "m" (tmp));
198
199#ifdef CONFIG_SMP
200 /*
201 * Do not rely on the boot cpu to do the calls to do_timer.
202 * Spread it over all cpus instead.
203 */
204 write_seqlock(&xtime_lock);
205 if (S390_lowcore.jiffy_timer > xtime_cc) {
206 tmp = S390_lowcore.jiffy_timer - xtime_cc;
207 if (tmp >= 2*CLK_TICKS_PER_JIFFY) {
208 xticks = __div(tmp, CLK_TICKS_PER_JIFFY);
209 xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY;
210 } else {
211 xticks = 1;
212 xtime_cc += CLK_TICKS_PER_JIFFY;
213 }
214 while (xticks--)
215 do_timer(regs);
216 }
217 write_sequnlock(&xtime_lock);
218#else
219 for (xticks = ticks; xticks > 0; xticks--)
220 do_timer(regs);
221#endif
222
223#ifdef CONFIG_VIRT_CPU_ACCOUNTING
224 account_user_vtime(current);
225#else
226 while (ticks--)
227 update_process_times(user_mode(regs));
228#endif
229
230 s390_do_profile(regs);
231}
232
233#ifdef CONFIG_NO_IDLE_HZ
234
235#ifdef CONFIG_NO_IDLE_HZ_INIT
236int sysctl_hz_timer = 0;
237#else
238int sysctl_hz_timer = 1;
239#endif
240
241/*
242 * Stop the HZ tick on the current CPU.
243 * Only cpu_idle may call this function.
244 */
245static inline void stop_hz_timer(void)
246{
247 __u64 timer;
248
249 if (sysctl_hz_timer != 0)
250 return;
251
252 cpu_set(smp_processor_id(), nohz_cpu_mask);
253
254 /*
255 * Leave the clock comparator set up for the next timer
256 * tick if either rcu or a softirq is pending.
257 */
258 if (rcu_pending(smp_processor_id()) || local_softirq_pending()) {
259 cpu_clear(smp_processor_id(), nohz_cpu_mask);
260 return;
261 }
262
263 /*
264 * This cpu is going really idle. Set up the clock comparator
265 * for the next event.
266 */
267 timer = (__u64) (next_timer_interrupt() - jiffies) + jiffies_64;
268 timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY;
269 asm volatile ("SCKC %0" : : "m" (timer));
270}
271
272/*
273 * Start the HZ tick on the current CPU.
274 * Only cpu_idle may call this function.
275 */
276static inline void start_hz_timer(void)
277{
278 if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
279 return;
280 account_ticks(__KSTK_PTREGS(current));
281 cpu_clear(smp_processor_id(), nohz_cpu_mask);
282}
283
284static int nohz_idle_notify(struct notifier_block *self,
285 unsigned long action, void *hcpu)
286{
287 switch (action) {
288 case CPU_IDLE:
289 stop_hz_timer();
290 break;
291 case CPU_NOT_IDLE:
292 start_hz_timer();
293 break;
294 }
295 return NOTIFY_OK;
296}
297
298static struct notifier_block nohz_idle_nb = {
299 .notifier_call = nohz_idle_notify,
300};
301
302void __init nohz_init(void)
303{
304 if (register_idle_notifier(&nohz_idle_nb))
305 panic("Couldn't register idle notifier");
306}
307
308#endif
309
310/*
311 * Start the clock comparator on the current CPU.
312 */
313void init_cpu_timer(void)
314{
315 unsigned long cr0;
316 __u64 timer;
317
318 timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY;
319 S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY;
320 timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
321 asm volatile ("SCKC %0" : : "m" (timer));
322 /* allow clock comparator timer interrupt */
323 __ctl_store(cr0, 0, 0);
324 cr0 |= 0x800;
325 __ctl_load(cr0, 0, 0);
326}
327
328extern void vtime_init(void);
329
330/*
331 * Initialize the TOD clock and the CPU timer of
332 * the boot cpu.
333 */
334void __init time_init(void)
335{
336 __u64 set_time_cc;
337 int cc;
338
339 /* kick the TOD clock */
340 asm volatile ("STCK 0(%1)\n\t"
341 "IPM %0\n\t"
342 "SRL %0,28" : "=r" (cc) : "a" (&init_timer_cc)
343 : "memory", "cc");
344 switch (cc) {
345 case 0: /* clock in set state: all is fine */
346 break;
347 case 1: /* clock in non-set state: FIXME */
348 printk("time_init: TOD clock in non-set state\n");
349 break;
350 case 2: /* clock in error state: FIXME */
351 printk("time_init: TOD clock in error state\n");
352 break;
353 case 3: /* clock in stopped or not-operational state: FIXME */
354 printk("time_init: TOD clock stopped/non-operational\n");
355 break;
356 }
357 jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY;
358
359 /* set xtime */
360 xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
361 set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
362 (0x3c26700LL*1000000*4096);
363 tod_to_timeval(set_time_cc, &xtime);
364 set_normalized_timespec(&wall_to_monotonic,
365 -xtime.tv_sec, -xtime.tv_nsec);
366
367 /* request the clock comparator external interrupt */
368 if (register_early_external_interrupt(0x1004, 0,
369 &ext_int_info_cc) != 0)
370 panic("Couldn't request external interrupt 0x1004");
371
372 init_cpu_timer();
373
374#ifdef CONFIG_NO_IDLE_HZ
375 nohz_init();
376#endif
377
378#ifdef CONFIG_VIRT_TIMER
379 vtime_init();
380#endif
381}
382
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
new file mode 100644
index 000000000000..8b90e9528b91
--- /dev/null
+++ b/arch/s390/kernel/traps.c
@@ -0,0 +1,738 @@
1/*
2 * arch/s390/kernel/traps.c
3 *
4 * S390 version
5 * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
8 *
9 * Derived from "arch/i386/kernel/traps.c"
10 * Copyright (C) 1991, 1992 Linus Torvalds
11 */
12
13/*
14 * 'Traps.c' handles hardware traps and faults after we have saved some
15 * state in 'asm.s'.
16 */
17#include <linux/config.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/string.h>
21#include <linux/errno.h>
22#include <linux/ptrace.h>
23#include <linux/timer.h>
24#include <linux/mm.h>
25#include <linux/smp.h>
26#include <linux/smp_lock.h>
27#include <linux/init.h>
28#include <linux/interrupt.h>
29#include <linux/delay.h>
30#include <linux/module.h>
31#include <linux/kallsyms.h>
32
33#include <asm/system.h>
34#include <asm/uaccess.h>
35#include <asm/io.h>
36#include <asm/atomic.h>
37#include <asm/mathemu.h>
38#include <asm/cpcmd.h>
39#include <asm/s390_ext.h>
40#include <asm/lowcore.h>
41#include <asm/debug.h>
42
43/* Called from entry.S only */
44extern void handle_per_exception(struct pt_regs *regs);
45
46typedef void pgm_check_handler_t(struct pt_regs *, long);
47pgm_check_handler_t *pgm_check_table[128];
48
49#ifdef CONFIG_SYSCTL
50#ifdef CONFIG_PROCESS_DEBUG
51int sysctl_userprocess_debug = 1;
52#else
53int sysctl_userprocess_debug = 0;
54#endif
55#endif
56
57extern pgm_check_handler_t do_protection_exception;
58extern pgm_check_handler_t do_dat_exception;
59extern pgm_check_handler_t do_pseudo_page_fault;
60#ifdef CONFIG_PFAULT
61extern int pfault_init(void);
62extern void pfault_fini(void);
63extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
64static ext_int_info_t ext_int_pfault;
65#endif
66extern pgm_check_handler_t do_monitor_call;
67
68#define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; })
69
70#ifndef CONFIG_ARCH_S390X
71#define FOURLONG "%08lx %08lx %08lx %08lx\n"
72static int kstack_depth_to_print = 12;
73#else /* CONFIG_ARCH_S390X */
74#define FOURLONG "%016lx %016lx %016lx %016lx\n"
75static int kstack_depth_to_print = 20;
76#endif /* CONFIG_ARCH_S390X */
77
78/*
79 * For show_trace we have tree different stack to consider:
80 * - the panic stack which is used if the kernel stack has overflown
81 * - the asynchronous interrupt stack (cpu related)
82 * - the synchronous kernel stack (process related)
83 * The stack trace can start at any of the three stack and can potentially
84 * touch all of them. The order is: panic stack, async stack, sync stack.
85 */
86static unsigned long
87__show_trace(unsigned long sp, unsigned long low, unsigned long high)
88{
89 struct stack_frame *sf;
90 struct pt_regs *regs;
91
92 while (1) {
93 sp = sp & PSW_ADDR_INSN;
94 if (sp < low || sp > high - sizeof(*sf))
95 return sp;
96 sf = (struct stack_frame *) sp;
97 printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
98 print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN);
99 /* Follow the backchain. */
100 while (1) {
101 low = sp;
102 sp = sf->back_chain & PSW_ADDR_INSN;
103 if (!sp)
104 break;
105 if (sp <= low || sp > high - sizeof(*sf))
106 return sp;
107 sf = (struct stack_frame *) sp;
108 printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
109 print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN);
110 }
111 /* Zero backchain detected, check for interrupt frame. */
112 sp = (unsigned long) (sf + 1);
113 if (sp <= low || sp > high - sizeof(*regs))
114 return sp;
115 regs = (struct pt_regs *) sp;
116 printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN);
117 print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN);
118 low = sp;
119 sp = regs->gprs[15];
120 }
121}
122
123void show_trace(struct task_struct *task, unsigned long * stack)
124{
125 register unsigned long __r15 asm ("15");
126 unsigned long sp;
127
128 sp = (unsigned long) stack;
129 if (!sp)
130 sp = task ? task->thread.ksp : __r15;
131 printk("Call Trace:\n");
132#ifdef CONFIG_CHECK_STACK
133 sp = __show_trace(sp, S390_lowcore.panic_stack - 4096,
134 S390_lowcore.panic_stack);
135#endif
136 sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE,
137 S390_lowcore.async_stack);
138 if (task)
139 __show_trace(sp, (unsigned long) task->thread_info,
140 (unsigned long) task->thread_info + THREAD_SIZE);
141 else
142 __show_trace(sp, S390_lowcore.thread_info,
143 S390_lowcore.thread_info + THREAD_SIZE);
144 printk("\n");
145}
146
147void show_stack(struct task_struct *task, unsigned long *sp)
148{
149 register unsigned long * __r15 asm ("15");
150 unsigned long *stack;
151 int i;
152
153 // debugging aid: "show_stack(NULL);" prints the
154 // back trace for this cpu.
155
156 if (!sp)
157 sp = task ? (unsigned long *) task->thread.ksp : __r15;
158
159 stack = sp;
160 for (i = 0; i < kstack_depth_to_print; i++) {
161 if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
162 break;
163 if (i && ((i * sizeof (long) % 32) == 0))
164 printk("\n ");
165 printk("%p ", (void *)*stack++);
166 }
167 printk("\n");
168 show_trace(task, sp);
169}
170
171/*
172 * The architecture-independent dump_stack generator
173 */
174void dump_stack(void)
175{
176 show_stack(0, 0);
177}
178
179EXPORT_SYMBOL(dump_stack);
180
181void show_registers(struct pt_regs *regs)
182{
183 mm_segment_t old_fs;
184 char *mode;
185 int i;
186
187 mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
188 printk("%s PSW : %p %p",
189 mode, (void *) regs->psw.mask,
190 (void *) regs->psw.addr);
191 print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN);
192 printk("%s GPRS: " FOURLONG, mode,
193 regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
194 printk(" " FOURLONG,
195 regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
196 printk(" " FOURLONG,
197 regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
198 printk(" " FOURLONG,
199 regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
200
201#if 0
202 /* FIXME: this isn't needed any more but it changes the ksymoops
203 * input. To remove or not to remove ... */
204 save_access_regs(regs->acrs);
205 printk("%s ACRS: %08x %08x %08x %08x\n", mode,
206 regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]);
207 printk(" %08x %08x %08x %08x\n",
208 regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]);
209 printk(" %08x %08x %08x %08x\n",
210 regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]);
211 printk(" %08x %08x %08x %08x\n",
212 regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]);
213#endif
214
215 /*
216 * Print the first 20 byte of the instruction stream at the
217 * time of the fault.
218 */
219 old_fs = get_fs();
220 if (regs->psw.mask & PSW_MASK_PSTATE)
221 set_fs(USER_DS);
222 else
223 set_fs(KERNEL_DS);
224 printk("%s Code: ", mode);
225 for (i = 0; i < 20; i++) {
226 unsigned char c;
227 if (__get_user(c, (char __user *)(regs->psw.addr + i))) {
228 printk(" Bad PSW.");
229 break;
230 }
231 printk("%02x ", c);
232 }
233 set_fs(old_fs);
234
235 printk("\n");
236}
237
238/* This is called from fs/proc/array.c */
239char *task_show_regs(struct task_struct *task, char *buffer)
240{
241 struct pt_regs *regs;
242
243 regs = __KSTK_PTREGS(task);
244 buffer += sprintf(buffer, "task: %p, ksp: %p\n",
245 task, (void *)task->thread.ksp);
246 buffer += sprintf(buffer, "User PSW : %p %p\n",
247 (void *) regs->psw.mask, (void *)regs->psw.addr);
248
249 buffer += sprintf(buffer, "User GPRS: " FOURLONG,
250 regs->gprs[0], regs->gprs[1],
251 regs->gprs[2], regs->gprs[3]);
252 buffer += sprintf(buffer, " " FOURLONG,
253 regs->gprs[4], regs->gprs[5],
254 regs->gprs[6], regs->gprs[7]);
255 buffer += sprintf(buffer, " " FOURLONG,
256 regs->gprs[8], regs->gprs[9],
257 regs->gprs[10], regs->gprs[11]);
258 buffer += sprintf(buffer, " " FOURLONG,
259 regs->gprs[12], regs->gprs[13],
260 regs->gprs[14], regs->gprs[15]);
261 buffer += sprintf(buffer, "User ACRS: %08x %08x %08x %08x\n",
262 task->thread.acrs[0], task->thread.acrs[1],
263 task->thread.acrs[2], task->thread.acrs[3]);
264 buffer += sprintf(buffer, " %08x %08x %08x %08x\n",
265 task->thread.acrs[4], task->thread.acrs[5],
266 task->thread.acrs[6], task->thread.acrs[7]);
267 buffer += sprintf(buffer, " %08x %08x %08x %08x\n",
268 task->thread.acrs[8], task->thread.acrs[9],
269 task->thread.acrs[10], task->thread.acrs[11]);
270 buffer += sprintf(buffer, " %08x %08x %08x %08x\n",
271 task->thread.acrs[12], task->thread.acrs[13],
272 task->thread.acrs[14], task->thread.acrs[15]);
273 return buffer;
274}
275
276DEFINE_SPINLOCK(die_lock);
277
278void die(const char * str, struct pt_regs * regs, long err)
279{
280 static int die_counter;
281
282 debug_stop_all();
283 console_verbose();
284 spin_lock_irq(&die_lock);
285 bust_spinlocks(1);
286 printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
287 show_regs(regs);
288 bust_spinlocks(0);
289 spin_unlock_irq(&die_lock);
290 if (in_interrupt())
291 panic("Fatal exception in interrupt");
292 if (panic_on_oops)
293 panic("Fatal exception: panic_on_oops");
294 do_exit(SIGSEGV);
295}
296
297static void inline
298report_user_fault(long interruption_code, struct pt_regs *regs)
299{
300#if defined(CONFIG_SYSCTL)
301 if (!sysctl_userprocess_debug)
302 return;
303#endif
304#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
305 printk("User process fault: interruption code 0x%lX\n",
306 interruption_code);
307 show_regs(regs);
308#endif
309}
310
311static void inline do_trap(long interruption_code, int signr, char *str,
312 struct pt_regs *regs, siginfo_t *info)
313{
314 /*
315 * We got all needed information from the lowcore and can
316 * now safely switch on interrupts.
317 */
318 if (regs->psw.mask & PSW_MASK_PSTATE)
319 local_irq_enable();
320
321 if (regs->psw.mask & PSW_MASK_PSTATE) {
322 struct task_struct *tsk = current;
323
324 tsk->thread.trap_no = interruption_code & 0xffff;
325 force_sig_info(signr, info, tsk);
326 report_user_fault(interruption_code, regs);
327 } else {
328 const struct exception_table_entry *fixup;
329 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
330 if (fixup)
331 regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
332 else
333 die(str, regs, interruption_code);
334 }
335}
336
337static inline void *get_check_address(struct pt_regs *regs)
338{
339 return (void *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
340}
341
342void do_single_step(struct pt_regs *regs)
343{
344 if ((current->ptrace & PT_PTRACED) != 0)
345 force_sig(SIGTRAP, current);
346}
347
348asmlinkage void
349default_trap_handler(struct pt_regs * regs, long interruption_code)
350{
351 if (regs->psw.mask & PSW_MASK_PSTATE) {
352 local_irq_enable();
353 do_exit(SIGSEGV);
354 report_user_fault(interruption_code, regs);
355 } else
356 die("Unknown program exception", regs, interruption_code);
357}
358
359#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
360asmlinkage void name(struct pt_regs * regs, long interruption_code) \
361{ \
362 siginfo_t info; \
363 info.si_signo = signr; \
364 info.si_errno = 0; \
365 info.si_code = sicode; \
366 info.si_addr = (void *)siaddr; \
367 do_trap(interruption_code, signr, str, regs, &info); \
368}
369
370DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
371 ILL_ILLADR, get_check_address(regs))
372DO_ERROR_INFO(SIGILL, "execute exception", execute_exception,
373 ILL_ILLOPN, get_check_address(regs))
374DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception,
375 FPE_INTDIV, get_check_address(regs))
376DO_ERROR_INFO(SIGFPE, "fixpoint overflow exception", overflow_exception,
377 FPE_INTOVF, get_check_address(regs))
378DO_ERROR_INFO(SIGFPE, "HFP overflow exception", hfp_overflow_exception,
379 FPE_FLTOVF, get_check_address(regs))
380DO_ERROR_INFO(SIGFPE, "HFP underflow exception", hfp_underflow_exception,
381 FPE_FLTUND, get_check_address(regs))
382DO_ERROR_INFO(SIGFPE, "HFP significance exception", hfp_significance_exception,
383 FPE_FLTRES, get_check_address(regs))
384DO_ERROR_INFO(SIGFPE, "HFP divide exception", hfp_divide_exception,
385 FPE_FLTDIV, get_check_address(regs))
386DO_ERROR_INFO(SIGFPE, "HFP square root exception", hfp_sqrt_exception,
387 FPE_FLTINV, get_check_address(regs))
388DO_ERROR_INFO(SIGILL, "operand exception", operand_exception,
389 ILL_ILLOPN, get_check_address(regs))
390DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op,
391 ILL_PRVOPC, get_check_address(regs))
392DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception,
393 ILL_ILLOPN, get_check_address(regs))
394DO_ERROR_INFO(SIGILL, "translation exception", translation_exception,
395 ILL_ILLOPN, get_check_address(regs))
396
397static inline void
398do_fp_trap(struct pt_regs *regs, void *location,
399 int fpc, long interruption_code)
400{
401 siginfo_t si;
402
403 si.si_signo = SIGFPE;
404 si.si_errno = 0;
405 si.si_addr = location;
406 si.si_code = 0;
407 /* FPC[2] is Data Exception Code */
408 if ((fpc & 0x00000300) == 0) {
409 /* bits 6 and 7 of DXC are 0 iff IEEE exception */
410 if (fpc & 0x8000) /* invalid fp operation */
411 si.si_code = FPE_FLTINV;
412 else if (fpc & 0x4000) /* div by 0 */
413 si.si_code = FPE_FLTDIV;
414 else if (fpc & 0x2000) /* overflow */
415 si.si_code = FPE_FLTOVF;
416 else if (fpc & 0x1000) /* underflow */
417 si.si_code = FPE_FLTUND;
418 else if (fpc & 0x0800) /* inexact */
419 si.si_code = FPE_FLTRES;
420 }
421 current->thread.ieee_instruction_pointer = (addr_t) location;
422 do_trap(interruption_code, SIGFPE,
423 "floating point exception", regs, &si);
424}
425
426asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
427{
428 siginfo_t info;
429 __u8 opcode[6];
430 __u16 *location;
431 int signal = 0;
432
433 location = (__u16 *) get_check_address(regs);
434
435 /*
436 * We got all needed information from the lowcore and can
437 * now safely switch on interrupts.
438 */
439 if (regs->psw.mask & PSW_MASK_PSTATE)
440 local_irq_enable();
441
442 if (regs->psw.mask & PSW_MASK_PSTATE) {
443 get_user(*((__u16 *) opcode), (__u16 __user *) location);
444 if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
445 if (current->ptrace & PT_PTRACED)
446 force_sig(SIGTRAP, current);
447 else
448 signal = SIGILL;
449#ifdef CONFIG_MATHEMU
450 } else if (opcode[0] == 0xb3) {
451 get_user(*((__u16 *) (opcode+2)), location+1);
452 signal = math_emu_b3(opcode, regs);
453 } else if (opcode[0] == 0xed) {
454 get_user(*((__u32 *) (opcode+2)),
455 (__u32 *)(location+1));
456 signal = math_emu_ed(opcode, regs);
457 } else if (*((__u16 *) opcode) == 0xb299) {
458 get_user(*((__u16 *) (opcode+2)), location+1);
459 signal = math_emu_srnm(opcode, regs);
460 } else if (*((__u16 *) opcode) == 0xb29c) {
461 get_user(*((__u16 *) (opcode+2)), location+1);
462 signal = math_emu_stfpc(opcode, regs);
463 } else if (*((__u16 *) opcode) == 0xb29d) {
464 get_user(*((__u16 *) (opcode+2)), location+1);
465 signal = math_emu_lfpc(opcode, regs);
466#endif
467 } else
468 signal = SIGILL;
469 } else
470 signal = SIGILL;
471
472#ifdef CONFIG_MATHEMU
473 if (signal == SIGFPE)
474 do_fp_trap(regs, location,
475 current->thread.fp_regs.fpc, interruption_code);
476 else if (signal == SIGSEGV) {
477 info.si_signo = signal;
478 info.si_errno = 0;
479 info.si_code = SEGV_MAPERR;
480 info.si_addr = (void *) location;
481 do_trap(interruption_code, signal,
482 "user address fault", regs, &info);
483 } else
484#endif
485 if (signal) {
486 info.si_signo = signal;
487 info.si_errno = 0;
488 info.si_code = ILL_ILLOPC;
489 info.si_addr = (void *) location;
490 do_trap(interruption_code, signal,
491 "illegal operation", regs, &info);
492 }
493}
494
495
496#ifdef CONFIG_MATHEMU
497asmlinkage void
498specification_exception(struct pt_regs * regs, long interruption_code)
499{
500 __u8 opcode[6];
501 __u16 *location = NULL;
502 int signal = 0;
503
504 location = (__u16 *) get_check_address(regs);
505
506 /*
507 * We got all needed information from the lowcore and can
508 * now safely switch on interrupts.
509 */
510 if (regs->psw.mask & PSW_MASK_PSTATE)
511 local_irq_enable();
512
513 if (regs->psw.mask & PSW_MASK_PSTATE) {
514 get_user(*((__u16 *) opcode), location);
515 switch (opcode[0]) {
516 case 0x28: /* LDR Rx,Ry */
517 signal = math_emu_ldr(opcode);
518 break;
519 case 0x38: /* LER Rx,Ry */
520 signal = math_emu_ler(opcode);
521 break;
522 case 0x60: /* STD R,D(X,B) */
523 get_user(*((__u16 *) (opcode+2)), location+1);
524 signal = math_emu_std(opcode, regs);
525 break;
526 case 0x68: /* LD R,D(X,B) */
527 get_user(*((__u16 *) (opcode+2)), location+1);
528 signal = math_emu_ld(opcode, regs);
529 break;
530 case 0x70: /* STE R,D(X,B) */
531 get_user(*((__u16 *) (opcode+2)), location+1);
532 signal = math_emu_ste(opcode, regs);
533 break;
534 case 0x78: /* LE R,D(X,B) */
535 get_user(*((__u16 *) (opcode+2)), location+1);
536 signal = math_emu_le(opcode, regs);
537 break;
538 default:
539 signal = SIGILL;
540 break;
541 }
542 } else
543 signal = SIGILL;
544
545 if (signal == SIGFPE)
546 do_fp_trap(regs, location,
547 current->thread.fp_regs.fpc, interruption_code);
548 else if (signal) {
549 siginfo_t info;
550 info.si_signo = signal;
551 info.si_errno = 0;
552 info.si_code = ILL_ILLOPN;
553 info.si_addr = location;
554 do_trap(interruption_code, signal,
555 "specification exception", regs, &info);
556 }
557}
558#else
559DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
560 ILL_ILLOPN, get_check_address(regs));
561#endif
562
563asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
564{
565 __u16 *location;
566 int signal = 0;
567
568 location = (__u16 *) get_check_address(regs);
569
570 /*
571 * We got all needed information from the lowcore and can
572 * now safely switch on interrupts.
573 */
574 if (regs->psw.mask & PSW_MASK_PSTATE)
575 local_irq_enable();
576
577 if (MACHINE_HAS_IEEE)
578 __asm__ volatile ("stfpc %0\n\t"
579 : "=m" (current->thread.fp_regs.fpc));
580
581#ifdef CONFIG_MATHEMU
582 else if (regs->psw.mask & PSW_MASK_PSTATE) {
583 __u8 opcode[6];
584 get_user(*((__u16 *) opcode), location);
585 switch (opcode[0]) {
586 case 0x28: /* LDR Rx,Ry */
587 signal = math_emu_ldr(opcode);
588 break;
589 case 0x38: /* LER Rx,Ry */
590 signal = math_emu_ler(opcode);
591 break;
592 case 0x60: /* STD R,D(X,B) */
593 get_user(*((__u16 *) (opcode+2)), location+1);
594 signal = math_emu_std(opcode, regs);
595 break;
596 case 0x68: /* LD R,D(X,B) */
597 get_user(*((__u16 *) (opcode+2)), location+1);
598 signal = math_emu_ld(opcode, regs);
599 break;
600 case 0x70: /* STE R,D(X,B) */
601 get_user(*((__u16 *) (opcode+2)), location+1);
602 signal = math_emu_ste(opcode, regs);
603 break;
604 case 0x78: /* LE R,D(X,B) */
605 get_user(*((__u16 *) (opcode+2)), location+1);
606 signal = math_emu_le(opcode, regs);
607 break;
608 case 0xb3:
609 get_user(*((__u16 *) (opcode+2)), location+1);
610 signal = math_emu_b3(opcode, regs);
611 break;
612 case 0xed:
613 get_user(*((__u32 *) (opcode+2)),
614 (__u32 *)(location+1));
615 signal = math_emu_ed(opcode, regs);
616 break;
617 case 0xb2:
618 if (opcode[1] == 0x99) {
619 get_user(*((__u16 *) (opcode+2)), location+1);
620 signal = math_emu_srnm(opcode, regs);
621 } else if (opcode[1] == 0x9c) {
622 get_user(*((__u16 *) (opcode+2)), location+1);
623 signal = math_emu_stfpc(opcode, regs);
624 } else if (opcode[1] == 0x9d) {
625 get_user(*((__u16 *) (opcode+2)), location+1);
626 signal = math_emu_lfpc(opcode, regs);
627 } else
628 signal = SIGILL;
629 break;
630 default:
631 signal = SIGILL;
632 break;
633 }
634 }
635#endif
636 if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
637 signal = SIGFPE;
638 else
639 signal = SIGILL;
640 if (signal == SIGFPE)
641 do_fp_trap(regs, location,
642 current->thread.fp_regs.fpc, interruption_code);
643 else if (signal) {
644 siginfo_t info;
645 info.si_signo = signal;
646 info.si_errno = 0;
647 info.si_code = ILL_ILLOPN;
648 info.si_addr = location;
649 do_trap(interruption_code, signal,
650 "data exception", regs, &info);
651 }
652}
653
654asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code)
655{
656 siginfo_t info;
657
658 /* Set user psw back to home space mode. */
659 if (regs->psw.mask & PSW_MASK_PSTATE)
660 regs->psw.mask |= PSW_ASC_HOME;
661 /* Send SIGILL. */
662 info.si_signo = SIGILL;
663 info.si_errno = 0;
664 info.si_code = ILL_PRVOPC;
665 info.si_addr = get_check_address(regs);
666 do_trap(int_code, SIGILL, "space switch event", regs, &info);
667}
668
669asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
670{
671 die("Kernel stack overflow", regs, 0);
672 panic("Corrupt kernel stack, can't continue.");
673}
674
675
676/* init is done in lowcore.S and head.S */
677
678void __init trap_init(void)
679{
680 int i;
681
682 for (i = 0; i < 128; i++)
683 pgm_check_table[i] = &default_trap_handler;
684 pgm_check_table[1] = &illegal_op;
685 pgm_check_table[2] = &privileged_op;
686 pgm_check_table[3] = &execute_exception;
687 pgm_check_table[4] = &do_protection_exception;
688 pgm_check_table[5] = &addressing_exception;
689 pgm_check_table[6] = &specification_exception;
690 pgm_check_table[7] = &data_exception;
691 pgm_check_table[8] = &overflow_exception;
692 pgm_check_table[9] = &divide_exception;
693 pgm_check_table[0x0A] = &overflow_exception;
694 pgm_check_table[0x0B] = &divide_exception;
695 pgm_check_table[0x0C] = &hfp_overflow_exception;
696 pgm_check_table[0x0D] = &hfp_underflow_exception;
697 pgm_check_table[0x0E] = &hfp_significance_exception;
698 pgm_check_table[0x0F] = &hfp_divide_exception;
699 pgm_check_table[0x10] = &do_dat_exception;
700 pgm_check_table[0x11] = &do_dat_exception;
701 pgm_check_table[0x12] = &translation_exception;
702 pgm_check_table[0x13] = &special_op_exception;
703#ifndef CONFIG_ARCH_S390X
704 pgm_check_table[0x14] = &do_pseudo_page_fault;
705#else /* CONFIG_ARCH_S390X */
706 pgm_check_table[0x38] = &do_dat_exception;
707 pgm_check_table[0x39] = &do_dat_exception;
708 pgm_check_table[0x3A] = &do_dat_exception;
709 pgm_check_table[0x3B] = &do_dat_exception;
710#endif /* CONFIG_ARCH_S390X */
711 pgm_check_table[0x15] = &operand_exception;
712 pgm_check_table[0x1C] = &space_switch_exception;
713 pgm_check_table[0x1D] = &hfp_sqrt_exception;
714 pgm_check_table[0x40] = &do_monitor_call;
715
716 if (MACHINE_IS_VM) {
717 /*
718 * First try to get pfault pseudo page faults going.
719 * If this isn't available turn on pagex page faults.
720 */
721#ifdef CONFIG_PFAULT
722 /* request the 0x2603 external interrupt */
723 if (register_early_external_interrupt(0x2603, pfault_interrupt,
724 &ext_int_pfault) != 0)
725 panic("Couldn't request external interrupt 0x2603");
726
727 if (pfault_init() == 0)
728 return;
729
730 /* Tough luck, no pfault. */
731 unregister_early_external_interrupt(0x2603, pfault_interrupt,
732 &ext_int_pfault);
733#endif
734#ifndef CONFIG_ARCH_S390X
735 cpcmd("SET PAGEX ON", NULL, 0);
736#endif
737 }
738}
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..89fdb3808bc0
--- /dev/null
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -0,0 +1,130 @@
1/* ld script to make s390 Linux kernel
2 * Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
3 */
4
5#include <asm-generic/vmlinux.lds.h>
6#include <linux/config.h>
7
8#ifndef CONFIG_ARCH_S390X
9OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
10OUTPUT_ARCH(s390)
11ENTRY(_start)
12jiffies = jiffies_64 + 4;
13#else
14OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
15OUTPUT_ARCH(s390:64-bit)
16ENTRY(_start)
17jiffies = jiffies_64;
18#endif
19
20SECTIONS
21{
22 . = 0x00000000;
23 _text = .; /* Text and read-only data */
24 .text : {
25 *(.text)
26 SCHED_TEXT
27 LOCK_TEXT
28 *(.fixup)
29 *(.gnu.warning)
30 } = 0x0700
31
32 _etext = .; /* End of text section */
33
34 . = ALIGN(16); /* Exception table */
35 __start___ex_table = .;
36 __ex_table : { *(__ex_table) }
37 __stop___ex_table = .;
38
39 RODATA
40
41#ifdef CONFIG_SHARED_KERNEL
42 . = ALIGN(1048576); /* VM shared segments are 1MB aligned */
43
44 _eshared = .; /* End of shareable data */
45#endif
46
47 .data : { /* Data */
48 *(.data)
49 CONSTRUCTORS
50 }
51
52 . = ALIGN(4096);
53 __nosave_begin = .;
54 .data_nosave : { *(.data.nosave) }
55 . = ALIGN(4096);
56 __nosave_end = .;
57
58 . = ALIGN(4096);
59 .data.page_aligned : { *(.data.idt) }
60
61 . = ALIGN(32);
62 .data.cacheline_aligned : { *(.data.cacheline_aligned) }
63
64 _edata = .; /* End of data section */
65
66 . = ALIGN(8192); /* init_task */
67 .data.init_task : { *(.data.init_task) }
68
69 /* will be freed after init */
70 . = ALIGN(4096); /* Init code and data */
71 __init_begin = .;
72 .init.text : {
73 _sinittext = .;
74 *(.init.text)
75 _einittext = .;
76 }
77 .init.data : { *(.init.data) }
78 . = ALIGN(256);
79 __setup_start = .;
80 .init.setup : { *(.init.setup) }
81 __setup_end = .;
82 __initcall_start = .;
83 .initcall.init : {
84 *(.initcall1.init)
85 *(.initcall2.init)
86 *(.initcall3.init)
87 *(.initcall4.init)
88 *(.initcall5.init)
89 *(.initcall6.init)
90 *(.initcall7.init)
91 }
92 __initcall_end = .;
93 __con_initcall_start = .;
94 .con_initcall.init : { *(.con_initcall.init) }
95 __con_initcall_end = .;
96 SECURITY_INIT
97 . = ALIGN(256);
98 __initramfs_start = .;
99 .init.ramfs : { *(.init.initramfs) }
100 . = ALIGN(2);
101 __initramfs_end = .;
102 . = ALIGN(256);
103 __per_cpu_start = .;
104 .data.percpu : { *(.data.percpu) }
105 __per_cpu_end = .;
106 . = ALIGN(4096);
107 __init_end = .;
108 /* freed after init ends here */
109
110 __bss_start = .; /* BSS */
111 .bss : { *(.bss) }
112 . = ALIGN(2);
113 __bss_stop = .;
114
115 _end = . ;
116
117 /* Sections to be discarded */
118 /DISCARD/ : {
119 *(.exitcall.exit)
120 }
121
122 /* Stabs debugging sections. */
123 .stab 0 : { *(.stab) }
124 .stabstr 0 : { *(.stabstr) }
125 .stab.excl 0 : { *(.stab.excl) }
126 .stab.exclstr 0 : { *(.stab.exclstr) }
127 .stab.index 0 : { *(.stab.index) }
128 .stab.indexstr 0 : { *(.stab.indexstr) }
129 .comment 0 : { *(.comment) }
130}
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
new file mode 100644
index 000000000000..bb6cf02418a2
--- /dev/null
+++ b/arch/s390/kernel/vtime.c
@@ -0,0 +1,565 @@
1/*
2 * arch/s390/kernel/vtime.c
3 * Virtual cpu timer based timer functions.
4 *
5 * S390 version
6 * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
8 */
9
10#include <linux/config.h>
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/time.h>
14#include <linux/delay.h>
15#include <linux/init.h>
16#include <linux/smp.h>
17#include <linux/types.h>
18#include <linux/timex.h>
19#include <linux/notifier.h>
20#include <linux/kernel_stat.h>
21#include <linux/rcupdate.h>
22#include <linux/posix-timers.h>
23
24#include <asm/s390_ext.h>
25#include <asm/timer.h>
26
27#define VTIMER_MAGIC (TIMER_MAGIC + 1)
28static ext_int_info_t ext_int_info_timer;
29DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
30
31#ifdef CONFIG_VIRT_CPU_ACCOUNTING
32/*
33 * Update process times based on virtual cpu times stored by entry.S
34 * to the lowcore fields user_timer, system_timer & steal_clock.
35 */
36void account_user_vtime(struct task_struct *tsk)
37{
38 cputime_t cputime;
39 __u64 timer, clock;
40 int rcu_user_flag;
41
42 timer = S390_lowcore.last_update_timer;
43 clock = S390_lowcore.last_update_clock;
44 asm volatile (" STPT %0\n" /* Store current cpu timer value */
45 " STCK %1" /* Store current tod clock value */
46 : "=m" (S390_lowcore.last_update_timer),
47 "=m" (S390_lowcore.last_update_clock) );
48 S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
49 S390_lowcore.steal_clock += S390_lowcore.last_update_clock - clock;
50
51 cputime = S390_lowcore.user_timer >> 12;
52 rcu_user_flag = cputime != 0;
53 S390_lowcore.user_timer -= cputime << 12;
54 S390_lowcore.steal_clock -= cputime << 12;
55 account_user_time(tsk, cputime);
56
57 cputime = S390_lowcore.system_timer >> 12;
58 S390_lowcore.system_timer -= cputime << 12;
59 S390_lowcore.steal_clock -= cputime << 12;
60 account_system_time(tsk, HARDIRQ_OFFSET, cputime);
61
62 cputime = S390_lowcore.steal_clock;
63 if ((__s64) cputime > 0) {
64 cputime >>= 12;
65 S390_lowcore.steal_clock -= cputime << 12;
66 account_steal_time(tsk, cputime);
67 }
68
69 run_local_timers();
70 if (rcu_pending(smp_processor_id()))
71 rcu_check_callbacks(smp_processor_id(), rcu_user_flag);
72 scheduler_tick();
73 run_posix_cpu_timers(tsk);
74}
75
76/*
77 * Update process times based on virtual cpu times stored by entry.S
78 * to the lowcore fields user_timer, system_timer & steal_clock.
79 */
80void account_system_vtime(struct task_struct *tsk)
81{
82 cputime_t cputime;
83 __u64 timer;
84
85 timer = S390_lowcore.last_update_timer;
86 asm volatile (" STPT %0" /* Store current cpu timer value */
87 : "=m" (S390_lowcore.last_update_timer) );
88 S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
89
90 cputime = S390_lowcore.system_timer >> 12;
91 S390_lowcore.system_timer -= cputime << 12;
92 S390_lowcore.steal_clock -= cputime << 12;
93 account_system_time(tsk, 0, cputime);
94}
95
96static inline void set_vtimer(__u64 expires)
97{
98 __u64 timer;
99
100 asm volatile (" STPT %0\n" /* Store current cpu timer value */
101 " SPT %1" /* Set new value immediatly afterwards */
102 : "=m" (timer) : "m" (expires) );
103 S390_lowcore.system_timer += S390_lowcore.last_update_timer - timer;
104 S390_lowcore.last_update_timer = expires;
105
106 /* store expire time for this CPU timer */
107 per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires;
108}
109#else
110static inline void set_vtimer(__u64 expires)
111{
112 S390_lowcore.last_update_timer = expires;
113 asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
114
115 /* store expire time for this CPU timer */
116 per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires;
117}
118#endif
119
120static void start_cpu_timer(void)
121{
122 struct vtimer_queue *vt_list;
123
124 vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
125 set_vtimer(vt_list->idle);
126}
127
128static void stop_cpu_timer(void)
129{
130 __u64 done;
131 struct vtimer_queue *vt_list;
132
133 vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
134
135 /* nothing to do */
136 if (list_empty(&vt_list->list)) {
137 vt_list->idle = VTIMER_MAX_SLICE;
138 goto fire;
139 }
140
141 /* store progress */
142 asm volatile ("STPT %0" : "=m" (done));
143
144 /*
145 * If done is negative we do not stop the CPU timer
146 * because we will get instantly an interrupt that
147 * will start the CPU timer again.
148 */
149 if (done & 1LL<<63)
150 return;
151 else
152 vt_list->offset += vt_list->to_expire - done;
153
154 /* save the actual expire value */
155 vt_list->idle = done;
156
157 /*
158 * We cannot halt the CPU timer, we just write a value that
159 * nearly never expires (only after 71 years) and re-write
160 * the stored expire value if we continue the timer
161 */
162 fire:
163 set_vtimer(VTIMER_MAX_SLICE);
164}
165
166/*
167 * Sorted add to a list. List is linear searched until first bigger
168 * element is found.
169 */
170static void list_add_sorted(struct vtimer_list *timer, struct list_head *head)
171{
172 struct vtimer_list *event;
173
174 list_for_each_entry(event, head, entry) {
175 if (event->expires > timer->expires) {
176 list_add_tail(&timer->entry, &event->entry);
177 return;
178 }
179 }
180 list_add_tail(&timer->entry, head);
181}
182
183/*
184 * Do the callback functions of expired vtimer events.
185 * Called from within the interrupt handler.
186 */
187static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs)
188{
189 struct vtimer_queue *vt_list;
190 struct vtimer_list *event, *tmp;
191 void (*fn)(unsigned long, struct pt_regs*);
192 unsigned long data;
193
194 if (list_empty(cb_list))
195 return;
196
197 vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
198
199 list_for_each_entry_safe(event, tmp, cb_list, entry) {
200 fn = event->function;
201 data = event->data;
202 fn(data, regs);
203
204 if (!event->interval)
205 /* delete one shot timer */
206 list_del_init(&event->entry);
207 else {
208 /* move interval timer back to list */
209 spin_lock(&vt_list->lock);
210 list_del_init(&event->entry);
211 list_add_sorted(event, &vt_list->list);
212 spin_unlock(&vt_list->lock);
213 }
214 }
215}
216
217/*
218 * Handler for the virtual CPU timer.
219 */
220static void do_cpu_timer_interrupt(struct pt_regs *regs, __u16 error_code)
221{
222 int cpu;
223 __u64 next, delta;
224 struct vtimer_queue *vt_list;
225 struct vtimer_list *event, *tmp;
226 struct list_head *ptr;
227 /* the callback queue */
228 struct list_head cb_list;
229
230 INIT_LIST_HEAD(&cb_list);
231 cpu = smp_processor_id();
232 vt_list = &per_cpu(virt_cpu_timer, cpu);
233
234 /* walk timer list, fire all expired events */
235 spin_lock(&vt_list->lock);
236
237 if (vt_list->to_expire < VTIMER_MAX_SLICE)
238 vt_list->offset += vt_list->to_expire;
239
240 list_for_each_entry_safe(event, tmp, &vt_list->list, entry) {
241 if (event->expires > vt_list->offset)
242 /* found first unexpired event, leave */
243 break;
244
245 /* re-charge interval timer, we have to add the offset */
246 if (event->interval)
247 event->expires = event->interval + vt_list->offset;
248
249 /* move expired timer to the callback queue */
250 list_move_tail(&event->entry, &cb_list);
251 }
252 spin_unlock(&vt_list->lock);
253 do_callbacks(&cb_list, regs);
254
255 /* next event is first in list */
256 spin_lock(&vt_list->lock);
257 if (!list_empty(&vt_list->list)) {
258 ptr = vt_list->list.next;
259 event = list_entry(ptr, struct vtimer_list, entry);
260 next = event->expires - vt_list->offset;
261
262 /* add the expired time from this interrupt handler
263 * and the callback functions
264 */
265 asm volatile ("STPT %0" : "=m" (delta));
266 delta = 0xffffffffffffffffLL - delta + 1;
267 vt_list->offset += delta;
268 next -= delta;
269 } else {
270 vt_list->offset = 0;
271 next = VTIMER_MAX_SLICE;
272 }
273 spin_unlock(&vt_list->lock);
274 set_vtimer(next);
275}
276
277void init_virt_timer(struct vtimer_list *timer)
278{
279 timer->magic = VTIMER_MAGIC;
280 timer->function = NULL;
281 INIT_LIST_HEAD(&timer->entry);
282 spin_lock_init(&timer->lock);
283}
284EXPORT_SYMBOL(init_virt_timer);
285
286static inline int check_vtimer(struct vtimer_list *timer)
287{
288 if (timer->magic != VTIMER_MAGIC)
289 return -EINVAL;
290 return 0;
291}
292
293static inline int vtimer_pending(struct vtimer_list *timer)
294{
295 return (!list_empty(&timer->entry));
296}
297
298/*
299 * this function should only run on the specified CPU
300 */
301static void internal_add_vtimer(struct vtimer_list *timer)
302{
303 unsigned long flags;
304 __u64 done;
305 struct vtimer_list *event;
306 struct vtimer_queue *vt_list;
307
308 vt_list = &per_cpu(virt_cpu_timer, timer->cpu);
309 spin_lock_irqsave(&vt_list->lock, flags);
310
311 if (timer->cpu != smp_processor_id())
312 printk("internal_add_vtimer: BUG, running on wrong CPU");
313
314 /* if list is empty we only have to set the timer */
315 if (list_empty(&vt_list->list)) {
316 /* reset the offset, this may happen if the last timer was
317 * just deleted by mod_virt_timer and the interrupt
318 * didn't happen until here
319 */
320 vt_list->offset = 0;
321 goto fire;
322 }
323
324 /* save progress */
325 asm volatile ("STPT %0" : "=m" (done));
326
327 /* calculate completed work */
328 done = vt_list->to_expire - done + vt_list->offset;
329 vt_list->offset = 0;
330
331 list_for_each_entry(event, &vt_list->list, entry)
332 event->expires -= done;
333
334 fire:
335 list_add_sorted(timer, &vt_list->list);
336
337 /* get first element, which is the next vtimer slice */
338 event = list_entry(vt_list->list.next, struct vtimer_list, entry);
339
340 set_vtimer(event->expires);
341 spin_unlock_irqrestore(&vt_list->lock, flags);
342 /* release CPU aquired in prepare_vtimer or mod_virt_timer() */
343 put_cpu();
344}
345
346static inline int prepare_vtimer(struct vtimer_list *timer)
347{
348 if (check_vtimer(timer) || !timer->function) {
349 printk("add_virt_timer: uninitialized timer\n");
350 return -EINVAL;
351 }
352
353 if (!timer->expires || timer->expires > VTIMER_MAX_SLICE) {
354 printk("add_virt_timer: invalid timer expire value!\n");
355 return -EINVAL;
356 }
357
358 if (vtimer_pending(timer)) {
359 printk("add_virt_timer: timer pending\n");
360 return -EBUSY;
361 }
362
363 timer->cpu = get_cpu();
364 return 0;
365}
366
367/*
368 * add_virt_timer - add an oneshot virtual CPU timer
369 */
370void add_virt_timer(void *new)
371{
372 struct vtimer_list *timer;
373
374 timer = (struct vtimer_list *)new;
375
376 if (prepare_vtimer(timer) < 0)
377 return;
378
379 timer->interval = 0;
380 internal_add_vtimer(timer);
381}
382EXPORT_SYMBOL(add_virt_timer);
383
384/*
385 * add_virt_timer_int - add an interval virtual CPU timer
386 */
387void add_virt_timer_periodic(void *new)
388{
389 struct vtimer_list *timer;
390
391 timer = (struct vtimer_list *)new;
392
393 if (prepare_vtimer(timer) < 0)
394 return;
395
396 timer->interval = timer->expires;
397 internal_add_vtimer(timer);
398}
399EXPORT_SYMBOL(add_virt_timer_periodic);
400
401/*
402 * If we change a pending timer the function must be called on the CPU
403 * where the timer is running on, e.g. by smp_call_function_on()
404 *
405 * The original mod_timer adds the timer if it is not pending. For compatibility
406 * we do the same. The timer will be added on the current CPU as a oneshot timer.
407 *
408 * returns whether it has modified a pending timer (1) or not (0)
409 */
410int mod_virt_timer(struct vtimer_list *timer, __u64 expires)
411{
412 struct vtimer_queue *vt_list;
413 unsigned long flags;
414 int cpu;
415
416 if (check_vtimer(timer) || !timer->function) {
417 printk("mod_virt_timer: uninitialized timer\n");
418 return -EINVAL;
419 }
420
421 if (!expires || expires > VTIMER_MAX_SLICE) {
422 printk("mod_virt_timer: invalid expire range\n");
423 return -EINVAL;
424 }
425
426 /*
427 * This is a common optimization triggered by the
428 * networking code - if the timer is re-modified
429 * to be the same thing then just return:
430 */
431 if (timer->expires == expires && vtimer_pending(timer))
432 return 1;
433
434 cpu = get_cpu();
435 vt_list = &per_cpu(virt_cpu_timer, cpu);
436
437 /* disable interrupts before test if timer is pending */
438 spin_lock_irqsave(&vt_list->lock, flags);
439
440 /* if timer isn't pending add it on the current CPU */
441 if (!vtimer_pending(timer)) {
442 spin_unlock_irqrestore(&vt_list->lock, flags);
443 /* we do not activate an interval timer with mod_virt_timer */
444 timer->interval = 0;
445 timer->expires = expires;
446 timer->cpu = cpu;
447 internal_add_vtimer(timer);
448 return 0;
449 }
450
451 /* check if we run on the right CPU */
452 if (timer->cpu != cpu) {
453 printk("mod_virt_timer: running on wrong CPU, check your code\n");
454 spin_unlock_irqrestore(&vt_list->lock, flags);
455 put_cpu();
456 return -EINVAL;
457 }
458
459 list_del_init(&timer->entry);
460 timer->expires = expires;
461
462 /* also change the interval if we have an interval timer */
463 if (timer->interval)
464 timer->interval = expires;
465
466 /* the timer can't expire anymore so we can release the lock */
467 spin_unlock_irqrestore(&vt_list->lock, flags);
468 internal_add_vtimer(timer);
469 return 1;
470}
471EXPORT_SYMBOL(mod_virt_timer);
472
473/*
474 * delete a virtual timer
475 *
476 * returns whether the deleted timer was pending (1) or not (0)
477 */
478int del_virt_timer(struct vtimer_list *timer)
479{
480 unsigned long flags;
481 struct vtimer_queue *vt_list;
482
483 if (check_vtimer(timer)) {
484 printk("del_virt_timer: timer not initialized\n");
485 return -EINVAL;
486 }
487
488 /* check if timer is pending */
489 if (!vtimer_pending(timer))
490 return 0;
491
492 vt_list = &per_cpu(virt_cpu_timer, timer->cpu);
493 spin_lock_irqsave(&vt_list->lock, flags);
494
495 /* we don't interrupt a running timer, just let it expire! */
496 list_del_init(&timer->entry);
497
498 /* last timer removed */
499 if (list_empty(&vt_list->list)) {
500 vt_list->to_expire = 0;
501 vt_list->offset = 0;
502 }
503
504 spin_unlock_irqrestore(&vt_list->lock, flags);
505 return 1;
506}
507EXPORT_SYMBOL(del_virt_timer);
508
509/*
510 * Start the virtual CPU timer on the current CPU.
511 */
512void init_cpu_vtimer(void)
513{
514 struct vtimer_queue *vt_list;
515 unsigned long cr0;
516
517 /* kick the virtual timer */
518 S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
519 S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
520 asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
521 asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
522 __ctl_store(cr0, 0, 0);
523 cr0 |= 0x400;
524 __ctl_load(cr0, 0, 0);
525
526 vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
527 INIT_LIST_HEAD(&vt_list->list);
528 spin_lock_init(&vt_list->lock);
529 vt_list->to_expire = 0;
530 vt_list->offset = 0;
531 vt_list->idle = 0;
532
533}
534
535static int vtimer_idle_notify(struct notifier_block *self,
536 unsigned long action, void *hcpu)
537{
538 switch (action) {
539 case CPU_IDLE:
540 stop_cpu_timer();
541 break;
542 case CPU_NOT_IDLE:
543 start_cpu_timer();
544 break;
545 }
546 return NOTIFY_OK;
547}
548
549static struct notifier_block vtimer_idle_nb = {
550 .notifier_call = vtimer_idle_notify,
551};
552
553void __init vtime_init(void)
554{
555 /* request the cpu timer external interrupt */
556 if (register_early_external_interrupt(0x1005, do_cpu_timer_interrupt,
557 &ext_int_info_timer) != 0)
558 panic("Couldn't request external interrupt 0x1005");
559
560 if (register_idle_notifier(&vtimer_idle_nb))
561 panic("Couldn't register idle notifier");
562
563 init_cpu_vtimer();
564}
565
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
new file mode 100644
index 000000000000..a8758b1d20a9
--- /dev/null
+++ b/arch/s390/lib/Makefile
@@ -0,0 +1,9 @@
1#
2# Makefile for s390-specific library files..
3#
4
5EXTRA_AFLAGS := -traditional
6
7lib-y += delay.o string.o
8lib-$(CONFIG_ARCH_S390_31) += uaccess.o
9lib-$(CONFIG_ARCH_S390X) += uaccess64.o
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
new file mode 100644
index 000000000000..e96c35bddac7
--- /dev/null
+++ b/arch/s390/lib/delay.c
@@ -0,0 +1,51 @@
1/*
2 * arch/s390/kernel/delay.c
3 * Precise Delay Loops for S390
4 *
5 * S390 version
6 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
8 *
9 * Derived from "arch/i386/lib/delay.c"
10 * Copyright (C) 1993 Linus Torvalds
11 * Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
12 */
13
14#include <linux/config.h>
15#include <linux/sched.h>
16#include <linux/delay.h>
17
18#ifdef CONFIG_SMP
19#include <asm/smp.h>
20#endif
21
22void __delay(unsigned long loops)
23{
24 /*
25 * To end the bloody studid and useless discussion about the
26 * BogoMips number I took the liberty to define the __delay
27 * function in a way that that resulting BogoMips number will
28 * yield the megahertz number of the cpu. The important function
29 * is udelay and that is done using the tod clock. -- martin.
30 */
31 __asm__ __volatile__(
32 "0: brct %0,0b"
33 : /* no outputs */ : "r" (loops/2) );
34}
35
36/*
37 * Waits for 'usecs' microseconds using the tod clock, giving up the time slice
38 * of the virtual PU inbetween to avoid congestion.
39 */
40void __udelay(unsigned long usecs)
41{
42 uint64_t start_cc, end_cc;
43
44 if (usecs == 0)
45 return;
46 asm volatile ("STCK %0" : "=m" (start_cc));
47 do {
48 cpu_relax();
49 asm volatile ("STCK %0" : "=m" (end_cc));
50 } while (((end_cc - start_cc)/4096) < usecs);
51}
diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c
new file mode 100644
index 000000000000..8240cc77e06e
--- /dev/null
+++ b/arch/s390/lib/string.c
@@ -0,0 +1,381 @@
1/*
2 * arch/s390/lib/string.c
3 * Optimized string functions
4 *
5 * S390 version
6 * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
8 */
9
10#define IN_ARCH_STRING_C 1
11
12#include <linux/types.h>
13#include <linux/module.h>
14
15/*
16 * Helper functions to find the end of a string
17 */
18static inline char *__strend(const char *s)
19{
20 register unsigned long r0 asm("0") = 0;
21
22 asm volatile ("0: srst %0,%1\n"
23 " jo 0b"
24 : "+d" (r0), "+a" (s) : : "cc" );
25 return (char *) r0;
26}
27
28static inline char *__strnend(const char *s, size_t n)
29{
30 register unsigned long r0 asm("0") = 0;
31 const char *p = s + n;
32
33 asm volatile ("0: srst %0,%1\n"
34 " jo 0b"
35 : "+d" (p), "+a" (s) : "d" (r0) : "cc" );
36 return (char *) p;
37}
38
39/**
40 * strlen - Find the length of a string
41 * @s: The string to be sized
42 *
43 * returns the length of @s
44 */
45size_t strlen(const char *s)
46{
47 return __strend(s) - s;
48}
49EXPORT_SYMBOL(strlen);
50
51/**
52 * strnlen - Find the length of a length-limited string
53 * @s: The string to be sized
54 * @n: The maximum number of bytes to search
55 *
56 * returns the minimum of the length of @s and @n
57 */
58size_t strnlen(const char * s, size_t n)
59{
60 return __strnend(s, n) - s;
61}
62EXPORT_SYMBOL(strnlen);
63
64/**
65 * strcpy - Copy a %NUL terminated string
66 * @dest: Where to copy the string to
67 * @src: Where to copy the string from
68 *
69 * returns a pointer to @dest
70 */
71char *strcpy(char *dest, const char *src)
72{
73 register int r0 asm("0") = 0;
74 char *ret = dest;
75
76 asm volatile ("0: mvst %0,%1\n"
77 " jo 0b"
78 : "+&a" (dest), "+&a" (src) : "d" (r0)
79 : "cc", "memory" );
80 return ret;
81}
82EXPORT_SYMBOL(strcpy);
83
84/**
85 * strlcpy - Copy a %NUL terminated string into a sized buffer
86 * @dest: Where to copy the string to
87 * @src: Where to copy the string from
88 * @size: size of destination buffer
89 *
90 * Compatible with *BSD: the result is always a valid
91 * NUL-terminated string that fits in the buffer (unless,
92 * of course, the buffer size is zero). It does not pad
93 * out the result like strncpy() does.
94 */
95size_t strlcpy(char *dest, const char *src, size_t size)
96{
97 size_t ret = __strend(src) - src;
98
99 if (size) {
100 size_t len = (ret >= size) ? size-1 : ret;
101 dest[len] = '\0';
102 __builtin_memcpy(dest, src, len);
103 }
104 return ret;
105}
106EXPORT_SYMBOL(strlcpy);
107
108/**
109 * strncpy - Copy a length-limited, %NUL-terminated string
110 * @dest: Where to copy the string to
111 * @src: Where to copy the string from
112 * @n: The maximum number of bytes to copy
113 *
114 * The result is not %NUL-terminated if the source exceeds
115 * @n bytes.
116 */
117char *strncpy(char *dest, const char *src, size_t n)
118{
119 size_t len = __strnend(src, n) - src;
120 __builtin_memset(dest + len, 0, n - len);
121 __builtin_memcpy(dest, src, len);
122 return dest;
123}
124EXPORT_SYMBOL(strncpy);
125
126/**
127 * strcat - Append one %NUL-terminated string to another
128 * @dest: The string to be appended to
129 * @src: The string to append to it
130 *
131 * returns a pointer to @dest
132 */
133char *strcat(char *dest, const char *src)
134{
135 register int r0 asm("0") = 0;
136 unsigned long dummy;
137 char *ret = dest;
138
139 asm volatile ("0: srst %0,%1\n"
140 " jo 0b\n"
141 "1: mvst %0,%2\n"
142 " jo 1b"
143 : "=&a" (dummy), "+a" (dest), "+a" (src)
144 : "d" (r0), "0" (0UL) : "cc", "memory" );
145 return ret;
146}
147EXPORT_SYMBOL(strcat);
148
149/**
150 * strlcat - Append a length-limited, %NUL-terminated string to another
151 * @dest: The string to be appended to
152 * @src: The string to append to it
153 * @n: The size of the destination buffer.
154 */
155size_t strlcat(char *dest, const char *src, size_t n)
156{
157 size_t dsize = __strend(dest) - dest;
158 size_t len = __strend(src) - src;
159 size_t res = dsize + len;
160
161 if (dsize < n) {
162 dest += dsize;
163 n -= dsize;
164 if (len >= n)
165 len = n - 1;
166 dest[len] = '\0';
167 __builtin_memcpy(dest, src, len);
168 }
169 return res;
170}
171EXPORT_SYMBOL(strlcat);
172
173/**
174 * strncat - Append a length-limited, %NUL-terminated string to another
175 * @dest: The string to be appended to
176 * @src: The string to append to it
177 * @n: The maximum numbers of bytes to copy
178 *
179 * returns a pointer to @dest
180 *
181 * Note that in contrast to strncpy, strncat ensures the result is
182 * terminated.
183 */
184char *strncat(char *dest, const char *src, size_t n)
185{
186 size_t len = __strnend(src, n) - src;
187 char *p = __strend(dest);
188
189 p[len] = '\0';
190 __builtin_memcpy(p, src, len);
191 return dest;
192}
193EXPORT_SYMBOL(strncat);
194
195/**
196 * strcmp - Compare two strings
197 * @cs: One string
198 * @ct: Another string
199 *
200 * returns 0 if @cs and @ct are equal,
201 * < 0 if @cs is less than @ct
202 * > 0 if @cs is greater than @ct
203 */
204int strcmp(const char *cs, const char *ct)
205{
206 register int r0 asm("0") = 0;
207 int ret = 0;
208
209 asm volatile ("0: clst %2,%3\n"
210 " jo 0b\n"
211 " je 1f\n"
212 " ic %0,0(%2)\n"
213 " ic %1,0(%3)\n"
214 " sr %0,%1\n"
215 "1:"
216 : "+d" (ret), "+d" (r0), "+a" (cs), "+a" (ct)
217 : : "cc" );
218 return ret;
219}
220EXPORT_SYMBOL(strcmp);
221
222/**
223 * strrchr - Find the last occurrence of a character in a string
224 * @s: The string to be searched
225 * @c: The character to search for
226 */
227char * strrchr(const char * s, int c)
228{
229 size_t len = __strend(s) - s;
230
231 if (len)
232 do {
233 if (s[len] == (char) c)
234 return (char *) s + len;
235 } while (--len > 0);
236 return 0;
237}
238EXPORT_SYMBOL(strrchr);
239
240/**
241 * strstr - Find the first substring in a %NUL terminated string
242 * @s1: The string to be searched
243 * @s2: The string to search for
244 */
245char * strstr(const char * s1,const char * s2)
246{
247 int l1, l2;
248
249 l2 = __strend(s2) - s2;
250 if (!l2)
251 return (char *) s1;
252 l1 = __strend(s1) - s1;
253 while (l1-- >= l2) {
254 register unsigned long r2 asm("2") = (unsigned long) s1;
255 register unsigned long r3 asm("3") = (unsigned long) l2;
256 register unsigned long r4 asm("4") = (unsigned long) s2;
257 register unsigned long r5 asm("5") = (unsigned long) l2;
258 int cc;
259
260 asm volatile ("0: clcle %1,%3,0\n"
261 " jo 0b\n"
262 " ipm %0\n"
263 " srl %0,28"
264 : "=&d" (cc), "+a" (r2), "+a" (r3),
265 "+a" (r4), "+a" (r5) : : "cc" );
266 if (!cc)
267 return (char *) s1;
268 s1++;
269 }
270 return 0;
271}
272EXPORT_SYMBOL(strstr);
273
274/**
275 * memchr - Find a character in an area of memory.
276 * @s: The memory area
277 * @c: The byte to search for
278 * @n: The size of the area.
279 *
280 * returns the address of the first occurrence of @c, or %NULL
281 * if @c is not found
282 */
283void *memchr(const void *s, int c, size_t n)
284{
285 register int r0 asm("0") = (char) c;
286 const void *ret = s + n;
287
288 asm volatile ("0: srst %0,%1\n"
289 " jo 0b\n"
290 " jl 1f\n"
291 " la %0,0\n"
292 "1:"
293 : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
294 return (void *) ret;
295}
296EXPORT_SYMBOL(memchr);
297
298/**
299 * memcmp - Compare two areas of memory
300 * @cs: One area of memory
301 * @ct: Another area of memory
302 * @count: The size of the area.
303 */
304int memcmp(const void *cs, const void *ct, size_t n)
305{
306 register unsigned long r2 asm("2") = (unsigned long) cs;
307 register unsigned long r3 asm("3") = (unsigned long) n;
308 register unsigned long r4 asm("4") = (unsigned long) ct;
309 register unsigned long r5 asm("5") = (unsigned long) n;
310 int ret;
311
312 asm volatile ("0: clcle %1,%3,0\n"
313 " jo 0b\n"
314 " ipm %0\n"
315 " srl %0,28"
316 : "=&d" (ret), "+a" (r2), "+a" (r3), "+a" (r4), "+a" (r5)
317 : : "cc" );
318 if (ret)
319 ret = *(char *) r2 - *(char *) r4;
320 return ret;
321}
322EXPORT_SYMBOL(memcmp);
323
324/**
325 * memscan - Find a character in an area of memory.
326 * @s: The memory area
327 * @c: The byte to search for
328 * @n: The size of the area.
329 *
330 * returns the address of the first occurrence of @c, or 1 byte past
331 * the area if @c is not found
332 */
333void *memscan(void *s, int c, size_t n)
334{
335 register int r0 asm("0") = (char) c;
336 const void *ret = s + n;
337
338 asm volatile ("0: srst %0,%1\n"
339 " jo 0b\n"
340 : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
341 return (void *) ret;
342}
343EXPORT_SYMBOL(memscan);
344
345/**
346 * memcpy - Copy one area of memory to another
347 * @dest: Where to copy to
348 * @src: Where to copy from
349 * @n: The size of the area.
350 *
351 * returns a pointer to @dest
352 */
353void *memcpy(void *dest, const void *src, size_t n)
354{
355 return __builtin_memcpy(dest, src, n);
356}
357EXPORT_SYMBOL(memcpy);
358
359/**
360 * memset - Fill a region of memory with the given value
361 * @s: Pointer to the start of the area.
362 * @c: The byte to fill the area with
363 * @n: The size of the area.
364 *
365 * returns a pointer to @s
366 */
367void *memset(void *s, int c, size_t n)
368{
369 char *xs;
370
371 if (c == 0)
372 return __builtin_memset(s, 0, n);
373
374 xs = (char *) s;
375 if (n > 0)
376 do {
377 *xs++ = c;
378 } while (--n > 0);
379 return s;
380}
381EXPORT_SYMBOL(memset);
diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S
new file mode 100644
index 000000000000..e8029ef42ef2
--- /dev/null
+++ b/arch/s390/lib/uaccess.S
@@ -0,0 +1,210 @@
1/*
2 * arch/s390/lib/uaccess.S
3 * __copy_{from|to}_user functions.
4 *
5 * s390
6 * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
8 *
9 * These functions have standard call interface
10 */
11
12#include <linux/errno.h>
13#include <asm/lowcore.h>
14#include <asm/offsets.h>
15
16 .text
17 .align 4
18 .globl __copy_from_user_asm
19 # %r2 = to, %r3 = n, %r4 = from
20__copy_from_user_asm:
21 slr %r0,%r0
220: mvcp 0(%r3,%r2),0(%r4),%r0
23 jnz 1f
24 slr %r2,%r2
25 br %r14
261: la %r2,256(%r2)
27 la %r4,256(%r4)
28 ahi %r3,-256
292: mvcp 0(%r3,%r2),0(%r4),%r0
30 jnz 1b
313: slr %r2,%r2
32 br %r14
334: lhi %r0,-4096
34 lr %r5,%r4
35 slr %r5,%r0
36 nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
37 slr %r5,%r4 # %r5 = #bytes to next user page boundary
38 clr %r3,%r5 # copy crosses next page boundary ?
39 jnh 6f # no, the current page faulted
40 # move with the reduced length which is < 256
415: mvcp 0(%r5,%r2),0(%r4),%r0
42 slr %r3,%r5
436: lr %r2,%r3
44 br %r14
45 .section __ex_table,"a"
46 .long 0b,4b
47 .long 2b,4b
48 .long 5b,6b
49 .previous
50
51 .align 4
52 .text
53 .globl __copy_to_user_asm
54 # %r2 = from, %r3 = n, %r4 = to
55__copy_to_user_asm:
56 slr %r0,%r0
570: mvcs 0(%r3,%r4),0(%r2),%r0
58 jnz 1f
59 slr %r2,%r2
60 br %r14
611: la %r2,256(%r2)
62 la %r4,256(%r4)
63 ahi %r3,-256
642: mvcs 0(%r3,%r4),0(%r2),%r0
65 jnz 1b
663: slr %r2,%r2
67 br %r14
684: lhi %r0,-4096
69 lr %r5,%r4
70 slr %r5,%r0
71 nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
72 slr %r5,%r4 # %r5 = #bytes to next user page boundary
73 clr %r3,%r5 # copy crosses next page boundary ?
74 jnh 6f # no, the current page faulted
75 # move with the reduced length which is < 256
765: mvcs 0(%r5,%r4),0(%r2),%r0
77 slr %r3,%r5
786: lr %r2,%r3
79 br %r14
80 .section __ex_table,"a"
81 .long 0b,4b
82 .long 2b,4b
83 .long 5b,6b
84 .previous
85
86 .align 4
87 .text
88 .globl __copy_in_user_asm
89 # %r2 = from, %r3 = n, %r4 = to
90__copy_in_user_asm:
91 sacf 256
92 bras 1,1f
93 mvc 0(1,%r4),0(%r2)
940: mvc 0(256,%r4),0(%r2)
95 la %r2,256(%r2)
96 la %r4,256(%r4)
971: ahi %r3,-256
98 jnm 0b
992: ex %r3,0(%r1)
100 sacf 0
101 slr %r2,%r2
102 br 14
1033: mvc 0(1,%r4),0(%r2)
104 la %r2,1(%r2)
105 la %r4,1(%r4)
106 ahi %r3,-1
107 jnm 3b
1084: lr %r2,%r3
109 sacf 0
110 br %r14
111 .section __ex_table,"a"
112 .long 0b,3b
113 .long 2b,3b
114 .long 3b,4b
115 .previous
116
117 .align 4
118 .text
119 .globl __clear_user_asm
120 # %r2 = to, %r3 = n
121__clear_user_asm:
122 bras %r5,0f
123 .long empty_zero_page
1240: l %r5,0(%r5)
125 slr %r0,%r0
1261: mvcs 0(%r3,%r2),0(%r5),%r0
127 jnz 2f
128 slr %r2,%r2
129 br %r14
1302: la %r2,256(%r2)
131 ahi %r3,-256
1323: mvcs 0(%r3,%r2),0(%r5),%r0
133 jnz 2b
1344: slr %r2,%r2
135 br %r14
1365: lhi %r0,-4096
137 lr %r4,%r2
138 slr %r4,%r0
139 nr %r4,%r0 # %r4 = (%r2 + 4096) & -4096
140 slr %r4,%r2 # %r4 = #bytes to next user page boundary
141 clr %r3,%r4 # clear crosses next page boundary ?
142 jnh 7f # no, the current page faulted
143 # clear with the reduced length which is < 256
1446: mvcs 0(%r4,%r2),0(%r5),%r0
145 slr %r3,%r4
1467: lr %r2,%r3
147 br %r14
148 .section __ex_table,"a"
149 .long 1b,5b
150 .long 3b,5b
151 .long 6b,7b
152 .previous
153
154 .align 4
155 .text
156 .globl __strncpy_from_user_asm
157 # %r2 = count, %r3 = dst, %r4 = src
158__strncpy_from_user_asm:
159 lhi %r0,0
160 lr %r1,%r4
161 la %r4,0(%r4) # clear high order bit from %r4
162 la %r2,0(%r2,%r4) # %r2 points to first byte after string
163 sacf 256
1640: srst %r2,%r1
165 jo 0b
166 sacf 0
167 lr %r1,%r2
168 jh 1f # \0 found in string ?
169 ahi %r1,1 # include \0 in copy
1701: slr %r1,%r4 # %r1 = copy length (without \0)
171 slr %r2,%r4 # %r2 = return length (including \0)
1722: mvcp 0(%r1,%r3),0(%r4),%r0
173 jnz 3f
174 br %r14
1753: la %r3,256(%r3)
176 la %r4,256(%r4)
177 ahi %r1,-256
178 mvcp 0(%r1,%r3),0(%r4),%r0
179 jnz 3b
180 br %r14
1814: sacf 0
182 lhi %r2,-EFAULT
183 br %r14
184 .section __ex_table,"a"
185 .long 0b,4b
186 .previous
187
188 .align 4
189 .text
190 .globl __strnlen_user_asm
191 # %r2 = count, %r3 = src
192__strnlen_user_asm:
193 lhi %r0,0
194 lr %r1,%r3
195 la %r3,0(%r3) # clear high order bit from %r4
196 la %r2,0(%r2,%r3) # %r2 points to first byte after string
197 sacf 256
1980: srst %r2,%r1
199 jo 0b
200 sacf 0
201 jh 1f # \0 found in string ?
202 ahi %r2,1 # strnlen_user result includes the \0
2031: slr %r2,%r3
204 br %r14
2052: sacf 0
206 lhi %r2,-EFAULT
207 br %r14
208 .section __ex_table,"a"
209 .long 0b,2b
210 .previous
diff --git a/arch/s390/lib/uaccess64.S b/arch/s390/lib/uaccess64.S
new file mode 100644
index 000000000000..0ca56972f4f0
--- /dev/null
+++ b/arch/s390/lib/uaccess64.S
@@ -0,0 +1,206 @@
1/*
2 * arch/s390x/lib/uaccess.S
3 * __copy_{from|to}_user functions.
4 *
5 * s390
6 * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
8 *
9 * These functions have standard call interface
10 */
11
12#include <linux/errno.h>
13#include <asm/lowcore.h>
14#include <asm/offsets.h>
15
16 .text
17 .align 4
18 .globl __copy_from_user_asm
19 # %r2 = to, %r3 = n, %r4 = from
20__copy_from_user_asm:
21 slgr %r0,%r0
220: mvcp 0(%r3,%r2),0(%r4),%r0
23 jnz 1f
24 slgr %r2,%r2
25 br %r14
261: la %r2,256(%r2)
27 la %r4,256(%r4)
28 aghi %r3,-256
292: mvcp 0(%r3,%r2),0(%r4),%r0
30 jnz 1b
313: slgr %r2,%r2
32 br %r14
334: lghi %r0,-4096
34 lgr %r5,%r4
35 slgr %r5,%r0
36 ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
37 slgr %r5,%r4 # %r5 = #bytes to next user page boundary
38 clgr %r3,%r5 # copy crosses next page boundary ?
39 jnh 6f # no, the current page faulted
40 # move with the reduced length which is < 256
415: mvcp 0(%r5,%r2),0(%r4),%r0
42 slgr %r3,%r5
436: lgr %r2,%r3
44 br %r14
45 .section __ex_table,"a"
46 .quad 0b,4b
47 .quad 2b,4b
48 .quad 5b,6b
49 .previous
50
51 .align 4
52 .text
53 .globl __copy_to_user_asm
54 # %r2 = from, %r3 = n, %r4 = to
55__copy_to_user_asm:
56 slgr %r0,%r0
570: mvcs 0(%r3,%r4),0(%r2),%r0
58 jnz 1f
59 slgr %r2,%r2
60 br %r14
611: la %r2,256(%r2)
62 la %r4,256(%r4)
63 aghi %r3,-256
642: mvcs 0(%r3,%r4),0(%r2),%r0
65 jnz 1b
663: slgr %r2,%r2
67 br %r14
684: lghi %r0,-4096
69 lgr %r5,%r4
70 slgr %r5,%r0
71 ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096
72 slgr %r5,%r4 # %r5 = #bytes to next user page boundary
73 clgr %r3,%r5 # copy crosses next page boundary ?
74 jnh 6f # no, the current page faulted
75 # move with the reduced length which is < 256
765: mvcs 0(%r5,%r4),0(%r2),%r0
77 slgr %r3,%r5
786: lgr %r2,%r3
79 br %r14
80 .section __ex_table,"a"
81 .quad 0b,4b
82 .quad 2b,4b
83 .quad 5b,6b
84 .previous
85
86 .align 4
87 .text
88 .globl __copy_in_user_asm
89 # %r2 = from, %r3 = n, %r4 = to
90__copy_in_user_asm:
91 sacf 256
92 bras 1,1f
93 mvc 0(1,%r4),0(%r2)
940: mvc 0(256,%r4),0(%r2)
95 la %r2,256(%r2)
96 la %r4,256(%r4)
971: aghi %r3,-256
98 jnm 0b
992: ex %r3,0(%r1)
100 sacf 0
101 slgr %r2,%r2
102 br 14
1033: mvc 0(1,%r4),0(%r2)
104 la %r2,1(%r2)
105 la %r4,1(%r4)
106 aghi %r3,-1
107 jnm 3b
1084: lgr %r2,%r3
109 sacf 0
110 br %r14
111 .section __ex_table,"a"
112 .quad 0b,3b
113 .quad 2b,3b
114 .quad 3b,4b
115 .previous
116
117 .align 4
118 .text
119 .globl __clear_user_asm
120 # %r2 = to, %r3 = n
121__clear_user_asm:
122 slgr %r0,%r0
123 larl %r5,empty_zero_page
1241: mvcs 0(%r3,%r2),0(%r5),%r0
125 jnz 2f
126 slgr %r2,%r2
127 br %r14
1282: la %r2,256(%r2)
129 aghi %r3,-256
1303: mvcs 0(%r3,%r2),0(%r5),%r0
131 jnz 2b
1324: slgr %r2,%r2
133 br %r14
1345: lghi %r0,-4096
135 lgr %r4,%r2
136 slgr %r4,%r0
137 ngr %r4,%r0 # %r4 = (%r2 + 4096) & -4096
138 slgr %r4,%r2 # %r4 = #bytes to next user page boundary
139 clgr %r3,%r4 # clear crosses next page boundary ?
140 jnh 7f # no, the current page faulted
141 # clear with the reduced length which is < 256
1426: mvcs 0(%r4,%r2),0(%r5),%r0
143 slgr %r3,%r4
1447: lgr %r2,%r3
145 br %r14
146 .section __ex_table,"a"
147 .quad 1b,5b
148 .quad 3b,5b
149 .quad 6b,7b
150 .previous
151
152 .align 4
153 .text
154 .globl __strncpy_from_user_asm
155 # %r2 = count, %r3 = dst, %r4 = src
156__strncpy_from_user_asm:
157 lghi %r0,0
158 lgr %r1,%r4
159 la %r2,0(%r2,%r4) # %r2 points to first byte after string
160 sacf 256
1610: srst %r2,%r1
162 jo 0b
163 sacf 0
164 lgr %r1,%r2
165 jh 1f # \0 found in string ?
166 aghi %r1,1 # include \0 in copy
1671: slgr %r1,%r4 # %r1 = copy length (without \0)
168 slgr %r2,%r4 # %r2 = return length (including \0)
1692: mvcp 0(%r1,%r3),0(%r4),%r0
170 jnz 3f
171 br %r14
1723: la %r3,256(%r3)
173 la %r4,256(%r4)
174 aghi %r1,-256
175 mvcp 0(%r1,%r3),0(%r4),%r0
176 jnz 3b
177 br %r14
1784: sacf 0
179 lghi %r2,-EFAULT
180 br %r14
181 .section __ex_table,"a"
182 .quad 0b,4b
183 .previous
184
185 .align 4
186 .text
187 .globl __strnlen_user_asm
188 # %r2 = count, %r3 = src
189__strnlen_user_asm:
190 lghi %r0,0
191 lgr %r1,%r3
192 la %r2,0(%r2,%r3) # %r2 points to first byte after string
193 sacf 256
1940: srst %r2,%r1
195 jo 0b
196 sacf 0
197 jh 1f # \0 found in string ?
198 aghi %r2,1 # strnlen_user result includes the \0
1991: slgr %r2,%r3
200 br %r14
2012: sacf 0
202 lghi %r2,-EFAULT
203 br %r14
204 .section __ex_table,"a"
205 .quad 0b,2b
206 .previous
diff --git a/arch/s390/math-emu/Makefile b/arch/s390/math-emu/Makefile
new file mode 100644
index 000000000000..c10df144f2ab
--- /dev/null
+++ b/arch/s390/math-emu/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for the FPU instruction emulation.
3#
4
5obj-$(CONFIG_MATHEMU) := math.o qrnnd.o
6
7EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
8EXTRA_AFLAGS := -traditional
diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c
new file mode 100644
index 000000000000..648df7140335
--- /dev/null
+++ b/arch/s390/math-emu/math.c
@@ -0,0 +1,2258 @@
1/*
2 * arch/s390/math-emu/math.c
3 *
4 * S390 version
5 * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 *
8 * 'math.c' emulates IEEE instructions on a S390 processor
9 * that does not have the IEEE fpu (all processors before G5).
10 */
11
12#include <linux/config.h>
13#include <linux/types.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <asm/uaccess.h>
17#include <asm/lowcore.h>
18
19#include "sfp-util.h"
20#include <math-emu/soft-fp.h>
21#include <math-emu/single.h>
22#include <math-emu/double.h>
23#include <math-emu/quad.h>
24
25/*
26 * I miss a macro to round a floating point number to the
27 * nearest integer in the same floating point format.
28 */
29#define _FP_TO_FPINT_ROUND(fs, wc, X) \
30 do { \
31 switch (X##_c) \
32 { \
33 case FP_CLS_NORMAL: \
34 if (X##_e > _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs) \
35 { /* floating point number has no bits after the dot. */ \
36 } \
37 else if (X##_e <= _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs && \
38 X##_e > _FP_EXPBIAS_##fs) \
39 { /* some bits before the dot, some after it. */ \
40 _FP_FRAC_SRS_##wc(X, _FP_WFRACBITS_##fs, \
41 X##_e - _FP_EXPBIAS_##fs \
42 + _FP_FRACBITS_##fs); \
43 _FP_ROUND(wc, X); \
44 _FP_FRAC_SLL_##wc(X, X##_e - _FP_EXPBIAS_##fs \
45 + _FP_FRACBITS_##fs); \
46 } \
47 else \
48 { /* all bits after the dot. */ \
49 FP_SET_EXCEPTION(FP_EX_INEXACT); \
50 X##_c = FP_CLS_ZERO; \
51 } \
52 break; \
53 case FP_CLS_NAN: \
54 case FP_CLS_INF: \
55 case FP_CLS_ZERO: \
56 break; \
57 } \
58 } while (0)
59
60#define FP_TO_FPINT_ROUND_S(X) _FP_TO_FPINT_ROUND(S,1,X)
61#define FP_TO_FPINT_ROUND_D(X) _FP_TO_FPINT_ROUND(D,2,X)
62#define FP_TO_FPINT_ROUND_Q(X) _FP_TO_FPINT_ROUND(Q,4,X)
63
64typedef union {
65 long double ld;
66 struct {
67 __u64 high;
68 __u64 low;
69 } w;
70} mathemu_ldcv;
71
72#ifdef CONFIG_SYSCTL
73int sysctl_ieee_emulation_warnings=1;
74#endif
75
76#define mathemu_put_user(x, p) \
77 do { \
78 if (put_user((x),(p))) \
79 return SIGSEGV; \
80 } while (0)
81
82#define mathemu_get_user(x, p) \
83 do { \
84 if (get_user((x),(p))) \
85 return SIGSEGV; \
86 } while (0)
87
88#define mathemu_copy_from_user(d, s, n)\
89 do { \
90 if (copy_from_user((d),(s),(n)) != 0) \
91 return SIGSEGV; \
92 } while (0)
93
94#define mathemu_copy_to_user(d, s, n) \
95 do { \
96 if (copy_to_user((d),(s),(n)) != 0) \
97 return SIGSEGV; \
98 } while (0)
99
100static void display_emulation_not_implemented(struct pt_regs *regs, char *instr)
101{
102 __u16 *location;
103
104#ifdef CONFIG_SYSCTL
105 if(sysctl_ieee_emulation_warnings)
106#endif
107 {
108 location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
109 printk("%s ieee fpu instruction not emulated "
110 "process name: %s pid: %d \n",
111 instr, current->comm, current->pid);
112 printk("%s's PSW: %08lx %08lx\n", instr,
113 (unsigned long) regs->psw.mask,
114 (unsigned long) location);
115 }
116}
117
118static inline void emu_set_CC (struct pt_regs *regs, int cc)
119{
120 regs->psw.mask = (regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12);
121}
122
123/*
124 * Set the condition code in the user psw.
125 * 0 : Result is zero
126 * 1 : Result is less than zero
127 * 2 : Result is greater than zero
128 * 3 : Result is NaN or INF
129 */
130static inline void emu_set_CC_cs(struct pt_regs *regs, int class, int sign)
131{
132 switch (class) {
133 case FP_CLS_NORMAL:
134 case FP_CLS_INF:
135 emu_set_CC(regs, sign ? 1 : 2);
136 break;
137 case FP_CLS_ZERO:
138 emu_set_CC(regs, 0);
139 break;
140 case FP_CLS_NAN:
141 emu_set_CC(regs, 3);
142 break;
143 }
144}
145
146/* Add long double */
147static int emu_axbr (struct pt_regs *regs, int rx, int ry) {
148 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
149 FP_DECL_EX;
150 mathemu_ldcv cvt;
151 int mode;
152
153 mode = current->thread.fp_regs.fpc & 3;
154 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
155 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
156 FP_UNPACK_QP(QA, &cvt.ld);
157 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
158 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
159 FP_UNPACK_QP(QB, &cvt.ld);
160 FP_ADD_Q(QR, QA, QB);
161 FP_PACK_QP(&cvt.ld, QR);
162 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
163 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
164 emu_set_CC_cs(regs, QR_c, QR_s);
165 return _fex;
166}
167
168/* Add double */
169static int emu_adbr (struct pt_regs *regs, int rx, int ry) {
170 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
171 FP_DECL_EX;
172 int mode;
173
174 mode = current->thread.fp_regs.fpc & 3;
175 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
176 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
177 FP_ADD_D(DR, DA, DB);
178 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
179 emu_set_CC_cs(regs, DR_c, DR_s);
180 return _fex;
181}
182
183/* Add double */
184static int emu_adb (struct pt_regs *regs, int rx, double *val) {
185 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
186 FP_DECL_EX;
187 int mode;
188
189 mode = current->thread.fp_regs.fpc & 3;
190 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
191 FP_UNPACK_DP(DB, val);
192 FP_ADD_D(DR, DA, DB);
193 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
194 emu_set_CC_cs(regs, DR_c, DR_s);
195 return _fex;
196}
197
198/* Add float */
199static int emu_aebr (struct pt_regs *regs, int rx, int ry) {
200 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
201 FP_DECL_EX;
202 int mode;
203
204 mode = current->thread.fp_regs.fpc & 3;
205 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
206 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
207 FP_ADD_S(SR, SA, SB);
208 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
209 emu_set_CC_cs(regs, SR_c, SR_s);
210 return _fex;
211}
212
213/* Add float */
214static int emu_aeb (struct pt_regs *regs, int rx, float *val) {
215 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
216 FP_DECL_EX;
217 int mode;
218
219 mode = current->thread.fp_regs.fpc & 3;
220 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
221 FP_UNPACK_SP(SB, val);
222 FP_ADD_S(SR, SA, SB);
223 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
224 emu_set_CC_cs(regs, SR_c, SR_s);
225 return _fex;
226}
227
228/* Compare long double */
229static int emu_cxbr (struct pt_regs *regs, int rx, int ry) {
230 FP_DECL_Q(QA); FP_DECL_Q(QB);
231 mathemu_ldcv cvt;
232 int IR;
233
234 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
235 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
236 FP_UNPACK_RAW_QP(QA, &cvt.ld);
237 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
238 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
239 FP_UNPACK_RAW_QP(QB, &cvt.ld);
240 FP_CMP_Q(IR, QA, QB, 3);
241 /*
242 * IR == -1 if DA < DB, IR == 0 if DA == DB,
243 * IR == 1 if DA > DB and IR == 3 if unorderded
244 */
245 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
246 return 0;
247}
248
249/* Compare double */
250static int emu_cdbr (struct pt_regs *regs, int rx, int ry) {
251 FP_DECL_D(DA); FP_DECL_D(DB);
252 int IR;
253
254 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
255 FP_UNPACK_RAW_DP(DB, &current->thread.fp_regs.fprs[ry].d);
256 FP_CMP_D(IR, DA, DB, 3);
257 /*
258 * IR == -1 if DA < DB, IR == 0 if DA == DB,
259 * IR == 1 if DA > DB and IR == 3 if unorderded
260 */
261 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
262 return 0;
263}
264
265/* Compare double */
266static int emu_cdb (struct pt_regs *regs, int rx, double *val) {
267 FP_DECL_D(DA); FP_DECL_D(DB);
268 int IR;
269
270 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
271 FP_UNPACK_RAW_DP(DB, val);
272 FP_CMP_D(IR, DA, DB, 3);
273 /*
274 * IR == -1 if DA < DB, IR == 0 if DA == DB,
275 * IR == 1 if DA > DB and IR == 3 if unorderded
276 */
277 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
278 return 0;
279}
280
281/* Compare float */
282static int emu_cebr (struct pt_regs *regs, int rx, int ry) {
283 FP_DECL_S(SA); FP_DECL_S(SB);
284 int IR;
285
286 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
287 FP_UNPACK_RAW_SP(SB, &current->thread.fp_regs.fprs[ry].f);
288 FP_CMP_S(IR, SA, SB, 3);
289 /*
290 * IR == -1 if DA < DB, IR == 0 if DA == DB,
291 * IR == 1 if DA > DB and IR == 3 if unorderded
292 */
293 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
294 return 0;
295}
296
297/* Compare float */
298static int emu_ceb (struct pt_regs *regs, int rx, float *val) {
299 FP_DECL_S(SA); FP_DECL_S(SB);
300 int IR;
301
302 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
303 FP_UNPACK_RAW_SP(SB, val);
304 FP_CMP_S(IR, SA, SB, 3);
305 /*
306 * IR == -1 if DA < DB, IR == 0 if DA == DB,
307 * IR == 1 if DA > DB and IR == 3 if unorderded
308 */
309 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
310 return 0;
311}
312
313/* Compare and signal long double */
314static int emu_kxbr (struct pt_regs *regs, int rx, int ry) {
315 FP_DECL_Q(QA); FP_DECL_Q(QB);
316 FP_DECL_EX;
317 mathemu_ldcv cvt;
318 int IR;
319
320 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
321 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
322 FP_UNPACK_RAW_QP(QA, &cvt.ld);
323 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
324 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
325 FP_UNPACK_QP(QB, &cvt.ld);
326 FP_CMP_Q(IR, QA, QB, 3);
327 /*
328 * IR == -1 if DA < DB, IR == 0 if DA == DB,
329 * IR == 1 if DA > DB and IR == 3 if unorderded
330 */
331 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
332 if (IR == 3)
333 FP_SET_EXCEPTION (FP_EX_INVALID);
334 return _fex;
335}
336
337/* Compare and signal double */
338static int emu_kdbr (struct pt_regs *regs, int rx, int ry) {
339 FP_DECL_D(DA); FP_DECL_D(DB);
340 FP_DECL_EX;
341 int IR;
342
343 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
344 FP_UNPACK_RAW_DP(DB, &current->thread.fp_regs.fprs[ry].d);
345 FP_CMP_D(IR, DA, DB, 3);
346 /*
347 * IR == -1 if DA < DB, IR == 0 if DA == DB,
348 * IR == 1 if DA > DB and IR == 3 if unorderded
349 */
350 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
351 if (IR == 3)
352 FP_SET_EXCEPTION (FP_EX_INVALID);
353 return _fex;
354}
355
356/* Compare and signal double */
357static int emu_kdb (struct pt_regs *regs, int rx, double *val) {
358 FP_DECL_D(DA); FP_DECL_D(DB);
359 FP_DECL_EX;
360 int IR;
361
362 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
363 FP_UNPACK_RAW_DP(DB, val);
364 FP_CMP_D(IR, DA, DB, 3);
365 /*
366 * IR == -1 if DA < DB, IR == 0 if DA == DB,
367 * IR == 1 if DA > DB and IR == 3 if unorderded
368 */
369 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
370 if (IR == 3)
371 FP_SET_EXCEPTION (FP_EX_INVALID);
372 return _fex;
373}
374
375/* Compare and signal float */
376static int emu_kebr (struct pt_regs *regs, int rx, int ry) {
377 FP_DECL_S(SA); FP_DECL_S(SB);
378 FP_DECL_EX;
379 int IR;
380
381 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
382 FP_UNPACK_RAW_SP(SB, &current->thread.fp_regs.fprs[ry].f);
383 FP_CMP_S(IR, SA, SB, 3);
384 /*
385 * IR == -1 if DA < DB, IR == 0 if DA == DB,
386 * IR == 1 if DA > DB and IR == 3 if unorderded
387 */
388 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
389 if (IR == 3)
390 FP_SET_EXCEPTION (FP_EX_INVALID);
391 return _fex;
392}
393
394/* Compare and signal float */
395static int emu_keb (struct pt_regs *regs, int rx, float *val) {
396 FP_DECL_S(SA); FP_DECL_S(SB);
397 FP_DECL_EX;
398 int IR;
399
400 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
401 FP_UNPACK_RAW_SP(SB, val);
402 FP_CMP_S(IR, SA, SB, 3);
403 /*
404 * IR == -1 if DA < DB, IR == 0 if DA == DB,
405 * IR == 1 if DA > DB and IR == 3 if unorderded
406 */
407 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
408 if (IR == 3)
409 FP_SET_EXCEPTION (FP_EX_INVALID);
410 return _fex;
411}
412
413/* Convert from fixed long double */
414static int emu_cxfbr (struct pt_regs *regs, int rx, int ry) {
415 FP_DECL_Q(QR);
416 FP_DECL_EX;
417 mathemu_ldcv cvt;
418 __s32 si;
419 int mode;
420
421 mode = current->thread.fp_regs.fpc & 3;
422 si = regs->gprs[ry];
423 FP_FROM_INT_Q(QR, si, 32, int);
424 FP_PACK_QP(&cvt.ld, QR);
425 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
426 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
427 return _fex;
428}
429
430/* Convert from fixed double */
431static int emu_cdfbr (struct pt_regs *regs, int rx, int ry) {
432 FP_DECL_D(DR);
433 FP_DECL_EX;
434 __s32 si;
435 int mode;
436
437 mode = current->thread.fp_regs.fpc & 3;
438 si = regs->gprs[ry];
439 FP_FROM_INT_D(DR, si, 32, int);
440 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
441 return _fex;
442}
443
444/* Convert from fixed float */
445static int emu_cefbr (struct pt_regs *regs, int rx, int ry) {
446 FP_DECL_S(SR);
447 FP_DECL_EX;
448 __s32 si;
449 int mode;
450
451 mode = current->thread.fp_regs.fpc & 3;
452 si = regs->gprs[ry];
453 FP_FROM_INT_S(SR, si, 32, int);
454 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
455 return _fex;
456}
457
458/* Convert to fixed long double */
459static int emu_cfxbr (struct pt_regs *regs, int rx, int ry, int mask) {
460 FP_DECL_Q(QA);
461 FP_DECL_EX;
462 mathemu_ldcv cvt;
463 __s32 si;
464 int mode;
465
466 if (mask == 0)
467 mode = current->thread.fp_regs.fpc & 3;
468 else if (mask == 1)
469 mode = FP_RND_NEAREST;
470 else
471 mode = mask - 4;
472 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
473 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
474 FP_UNPACK_QP(QA, &cvt.ld);
475 FP_TO_INT_ROUND_Q(si, QA, 32, 1);
476 regs->gprs[rx] = si;
477 emu_set_CC_cs(regs, QA_c, QA_s);
478 return _fex;
479}
480
481/* Convert to fixed double */
482static int emu_cfdbr (struct pt_regs *regs, int rx, int ry, int mask) {
483 FP_DECL_D(DA);
484 FP_DECL_EX;
485 __s32 si;
486 int mode;
487
488 if (mask == 0)
489 mode = current->thread.fp_regs.fpc & 3;
490 else if (mask == 1)
491 mode = FP_RND_NEAREST;
492 else
493 mode = mask - 4;
494 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
495 FP_TO_INT_ROUND_D(si, DA, 32, 1);
496 regs->gprs[rx] = si;
497 emu_set_CC_cs(regs, DA_c, DA_s);
498 return _fex;
499}
500
501/* Convert to fixed float */
502static int emu_cfebr (struct pt_regs *regs, int rx, int ry, int mask) {
503 FP_DECL_S(SA);
504 FP_DECL_EX;
505 __s32 si;
506 int mode;
507
508 if (mask == 0)
509 mode = current->thread.fp_regs.fpc & 3;
510 else if (mask == 1)
511 mode = FP_RND_NEAREST;
512 else
513 mode = mask - 4;
514 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
515 FP_TO_INT_ROUND_S(si, SA, 32, 1);
516 regs->gprs[rx] = si;
517 emu_set_CC_cs(regs, SA_c, SA_s);
518 return _fex;
519}
520
521/* Divide long double */
522static int emu_dxbr (struct pt_regs *regs, int rx, int ry) {
523 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
524 FP_DECL_EX;
525 mathemu_ldcv cvt;
526 int mode;
527
528 mode = current->thread.fp_regs.fpc & 3;
529 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
530 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
531 FP_UNPACK_QP(QA, &cvt.ld);
532 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
533 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
534 FP_UNPACK_QP(QB, &cvt.ld);
535 FP_DIV_Q(QR, QA, QB);
536 FP_PACK_QP(&cvt.ld, QR);
537 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
538 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
539 return _fex;
540}
541
542/* Divide double */
543static int emu_ddbr (struct pt_regs *regs, int rx, int ry) {
544 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
545 FP_DECL_EX;
546 int mode;
547
548 mode = current->thread.fp_regs.fpc & 3;
549 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
550 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
551 FP_DIV_D(DR, DA, DB);
552 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
553 return _fex;
554}
555
556/* Divide double */
557static int emu_ddb (struct pt_regs *regs, int rx, double *val) {
558 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
559 FP_DECL_EX;
560 int mode;
561
562 mode = current->thread.fp_regs.fpc & 3;
563 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
564 FP_UNPACK_DP(DB, val);
565 FP_DIV_D(DR, DA, DB);
566 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
567 return _fex;
568}
569
570/* Divide float */
571static int emu_debr (struct pt_regs *regs, int rx, int ry) {
572 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
573 FP_DECL_EX;
574 int mode;
575
576 mode = current->thread.fp_regs.fpc & 3;
577 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
578 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
579 FP_DIV_S(SR, SA, SB);
580 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
581 return _fex;
582}
583
584/* Divide float */
585static int emu_deb (struct pt_regs *regs, int rx, float *val) {
586 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
587 FP_DECL_EX;
588 int mode;
589
590 mode = current->thread.fp_regs.fpc & 3;
591 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
592 FP_UNPACK_SP(SB, val);
593 FP_DIV_S(SR, SA, SB);
594 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
595 return _fex;
596}
597
598/* Divide to integer double */
599static int emu_didbr (struct pt_regs *regs, int rx, int ry, int mask) {
600 display_emulation_not_implemented(regs, "didbr");
601 return 0;
602}
603
604/* Divide to integer float */
605static int emu_diebr (struct pt_regs *regs, int rx, int ry, int mask) {
606 display_emulation_not_implemented(regs, "diebr");
607 return 0;
608}
609
610/* Extract fpc */
611static int emu_efpc (struct pt_regs *regs, int rx, int ry) {
612 regs->gprs[rx] = current->thread.fp_regs.fpc;
613 return 0;
614}
615
616/* Load and test long double */
617static int emu_ltxbr (struct pt_regs *regs, int rx, int ry) {
618 s390_fp_regs *fp_regs = &current->thread.fp_regs;
619 mathemu_ldcv cvt;
620 FP_DECL_Q(QA);
621 FP_DECL_EX;
622
623 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
624 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
625 FP_UNPACK_QP(QA, &cvt.ld);
626 fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
627 fp_regs->fprs[rx+2].ui = fp_regs->fprs[ry+2].ui;
628 emu_set_CC_cs(regs, QA_c, QA_s);
629 return _fex;
630}
631
632/* Load and test double */
633static int emu_ltdbr (struct pt_regs *regs, int rx, int ry) {
634 s390_fp_regs *fp_regs = &current->thread.fp_regs;
635 FP_DECL_D(DA);
636 FP_DECL_EX;
637
638 FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d);
639 fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
640 emu_set_CC_cs(regs, DA_c, DA_s);
641 return _fex;
642}
643
644/* Load and test double */
645static int emu_ltebr (struct pt_regs *regs, int rx, int ry) {
646 s390_fp_regs *fp_regs = &current->thread.fp_regs;
647 FP_DECL_S(SA);
648 FP_DECL_EX;
649
650 FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f);
651 fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
652 emu_set_CC_cs(regs, SA_c, SA_s);
653 return _fex;
654}
655
656/* Load complement long double */
657static int emu_lcxbr (struct pt_regs *regs, int rx, int ry) {
658 FP_DECL_Q(QA); FP_DECL_Q(QR);
659 FP_DECL_EX;
660 mathemu_ldcv cvt;
661 int mode;
662
663 mode = current->thread.fp_regs.fpc & 3;
664 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
665 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
666 FP_UNPACK_QP(QA, &cvt.ld);
667 FP_NEG_Q(QR, QA);
668 FP_PACK_QP(&cvt.ld, QR);
669 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
670 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
671 emu_set_CC_cs(regs, QR_c, QR_s);
672 return _fex;
673}
674
675/* Load complement double */
676static int emu_lcdbr (struct pt_regs *regs, int rx, int ry) {
677 FP_DECL_D(DA); FP_DECL_D(DR);
678 FP_DECL_EX;
679 int mode;
680
681 mode = current->thread.fp_regs.fpc & 3;
682 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
683 FP_NEG_D(DR, DA);
684 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
685 emu_set_CC_cs(regs, DR_c, DR_s);
686 return _fex;
687}
688
689/* Load complement float */
690static int emu_lcebr (struct pt_regs *regs, int rx, int ry) {
691 FP_DECL_S(SA); FP_DECL_S(SR);
692 FP_DECL_EX;
693 int mode;
694
695 mode = current->thread.fp_regs.fpc & 3;
696 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
697 FP_NEG_S(SR, SA);
698 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
699 emu_set_CC_cs(regs, SR_c, SR_s);
700 return _fex;
701}
702
703/* Load floating point integer long double */
704static int emu_fixbr (struct pt_regs *regs, int rx, int ry, int mask) {
705 s390_fp_regs *fp_regs = &current->thread.fp_regs;
706 FP_DECL_Q(QA);
707 FP_DECL_EX;
708 mathemu_ldcv cvt;
709 __s32 si;
710 int mode;
711
712 if (mask == 0)
713 mode = fp_regs->fpc & 3;
714 else if (mask == 1)
715 mode = FP_RND_NEAREST;
716 else
717 mode = mask - 4;
718 cvt.w.high = fp_regs->fprs[ry].ui;
719 cvt.w.low = fp_regs->fprs[ry+2].ui;
720 FP_UNPACK_QP(QA, &cvt.ld);
721 FP_TO_FPINT_ROUND_Q(QA);
722 FP_PACK_QP(&cvt.ld, QA);
723 fp_regs->fprs[rx].ui = cvt.w.high;
724 fp_regs->fprs[rx+2].ui = cvt.w.low;
725 return _fex;
726}
727
728/* Load floating point integer double */
729static int emu_fidbr (struct pt_regs *regs, int rx, int ry, int mask) {
730 /* FIXME: rounding mode !! */
731 s390_fp_regs *fp_regs = &current->thread.fp_regs;
732 FP_DECL_D(DA);
733 FP_DECL_EX;
734 __s32 si;
735 int mode;
736
737 if (mask == 0)
738 mode = fp_regs->fpc & 3;
739 else if (mask == 1)
740 mode = FP_RND_NEAREST;
741 else
742 mode = mask - 4;
743 FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d);
744 FP_TO_FPINT_ROUND_D(DA);
745 FP_PACK_DP(&fp_regs->fprs[rx].d, DA);
746 return _fex;
747}
748
749/* Load floating point integer float */
750static int emu_fiebr (struct pt_regs *regs, int rx, int ry, int mask) {
751 s390_fp_regs *fp_regs = &current->thread.fp_regs;
752 FP_DECL_S(SA);
753 FP_DECL_EX;
754 __s32 si;
755 int mode;
756
757 if (mask == 0)
758 mode = fp_regs->fpc & 3;
759 else if (mask == 1)
760 mode = FP_RND_NEAREST;
761 else
762 mode = mask - 4;
763 FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f);
764 FP_TO_FPINT_ROUND_S(SA);
765 FP_PACK_SP(&fp_regs->fprs[rx].f, SA);
766 return _fex;
767}
768
769/* Load lengthened double to long double */
770static int emu_lxdbr (struct pt_regs *regs, int rx, int ry) {
771 FP_DECL_D(DA); FP_DECL_Q(QR);
772 FP_DECL_EX;
773 mathemu_ldcv cvt;
774 int mode;
775
776 mode = current->thread.fp_regs.fpc & 3;
777 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
778 FP_CONV (Q, D, 4, 2, QR, DA);
779 FP_PACK_QP(&cvt.ld, QR);
780 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
781 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
782 return _fex;
783}
784
785/* Load lengthened double to long double */
786static int emu_lxdb (struct pt_regs *regs, int rx, double *val) {
787 FP_DECL_D(DA); FP_DECL_Q(QR);
788 FP_DECL_EX;
789 mathemu_ldcv cvt;
790 int mode;
791
792 mode = current->thread.fp_regs.fpc & 3;
793 FP_UNPACK_DP(DA, val);
794 FP_CONV (Q, D, 4, 2, QR, DA);
795 FP_PACK_QP(&cvt.ld, QR);
796 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
797 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
798 return _fex;
799}
800
801/* Load lengthened float to long double */
802static int emu_lxebr (struct pt_regs *regs, int rx, int ry) {
803 FP_DECL_S(SA); FP_DECL_Q(QR);
804 FP_DECL_EX;
805 mathemu_ldcv cvt;
806 int mode;
807
808 mode = current->thread.fp_regs.fpc & 3;
809 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
810 FP_CONV (Q, S, 4, 1, QR, SA);
811 FP_PACK_QP(&cvt.ld, QR);
812 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
813 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
814 return _fex;
815}
816
817/* Load lengthened float to long double */
818static int emu_lxeb (struct pt_regs *regs, int rx, float *val) {
819 FP_DECL_S(SA); FP_DECL_Q(QR);
820 FP_DECL_EX;
821 mathemu_ldcv cvt;
822 int mode;
823
824 mode = current->thread.fp_regs.fpc & 3;
825 FP_UNPACK_SP(SA, val);
826 FP_CONV (Q, S, 4, 1, QR, SA);
827 FP_PACK_QP(&cvt.ld, QR);
828 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
829 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
830 return _fex;
831}
832
833/* Load lengthened float to double */
834static int emu_ldebr (struct pt_regs *regs, int rx, int ry) {
835 FP_DECL_S(SA); FP_DECL_D(DR);
836 FP_DECL_EX;
837 int mode;
838
839 mode = current->thread.fp_regs.fpc & 3;
840 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
841 FP_CONV (D, S, 2, 1, DR, SA);
842 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
843 return _fex;
844}
845
846/* Load lengthened float to double */
847static int emu_ldeb (struct pt_regs *regs, int rx, float *val) {
848 FP_DECL_S(SA); FP_DECL_D(DR);
849 FP_DECL_EX;
850 int mode;
851
852 mode = current->thread.fp_regs.fpc & 3;
853 FP_UNPACK_SP(SA, val);
854 FP_CONV (D, S, 2, 1, DR, SA);
855 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
856 return _fex;
857}
858
859/* Load negative long double */
860static int emu_lnxbr (struct pt_regs *regs, int rx, int ry) {
861 FP_DECL_Q(QA); FP_DECL_Q(QR);
862 FP_DECL_EX;
863 mathemu_ldcv cvt;
864 int mode;
865
866 mode = current->thread.fp_regs.fpc & 3;
867 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
868 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
869 FP_UNPACK_QP(QA, &cvt.ld);
870 if (QA_s == 0) {
871 FP_NEG_Q(QR, QA);
872 FP_PACK_QP(&cvt.ld, QR);
873 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
874 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
875 } else {
876 current->thread.fp_regs.fprs[rx].ui =
877 current->thread.fp_regs.fprs[ry].ui;
878 current->thread.fp_regs.fprs[rx+2].ui =
879 current->thread.fp_regs.fprs[ry+2].ui;
880 }
881 emu_set_CC_cs(regs, QR_c, QR_s);
882 return _fex;
883}
884
885/* Load negative double */
886static int emu_lndbr (struct pt_regs *regs, int rx, int ry) {
887 FP_DECL_D(DA); FP_DECL_D(DR);
888 FP_DECL_EX;
889 int mode;
890
891 mode = current->thread.fp_regs.fpc & 3;
892 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
893 if (DA_s == 0) {
894 FP_NEG_D(DR, DA);
895 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
896 } else
897 current->thread.fp_regs.fprs[rx].ui =
898 current->thread.fp_regs.fprs[ry].ui;
899 emu_set_CC_cs(regs, DR_c, DR_s);
900 return _fex;
901}
902
903/* Load negative float */
904static int emu_lnebr (struct pt_regs *regs, int rx, int ry) {
905 FP_DECL_S(SA); FP_DECL_S(SR);
906 FP_DECL_EX;
907 int mode;
908
909 mode = current->thread.fp_regs.fpc & 3;
910 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
911 if (SA_s == 0) {
912 FP_NEG_S(SR, SA);
913 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
914 } else
915 current->thread.fp_regs.fprs[rx].ui =
916 current->thread.fp_regs.fprs[ry].ui;
917 emu_set_CC_cs(regs, SR_c, SR_s);
918 return _fex;
919}
920
921/* Load positive long double */
922static int emu_lpxbr (struct pt_regs *regs, int rx, int ry) {
923 FP_DECL_Q(QA); FP_DECL_Q(QR);
924 FP_DECL_EX;
925 mathemu_ldcv cvt;
926 int mode;
927
928 mode = current->thread.fp_regs.fpc & 3;
929 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
930 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
931 FP_UNPACK_QP(QA, &cvt.ld);
932 if (QA_s != 0) {
933 FP_NEG_Q(QR, QA);
934 FP_PACK_QP(&cvt.ld, QR);
935 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
936 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
937 } else{
938 current->thread.fp_regs.fprs[rx].ui =
939 current->thread.fp_regs.fprs[ry].ui;
940 current->thread.fp_regs.fprs[rx+2].ui =
941 current->thread.fp_regs.fprs[ry+2].ui;
942 }
943 emu_set_CC_cs(regs, QR_c, QR_s);
944 return _fex;
945}
946
947/* Load positive double */
948static int emu_lpdbr (struct pt_regs *regs, int rx, int ry) {
949 FP_DECL_D(DA); FP_DECL_D(DR);
950 FP_DECL_EX;
951 int mode;
952
953 mode = current->thread.fp_regs.fpc & 3;
954 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
955 if (DA_s != 0) {
956 FP_NEG_D(DR, DA);
957 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
958 } else
959 current->thread.fp_regs.fprs[rx].ui =
960 current->thread.fp_regs.fprs[ry].ui;
961 emu_set_CC_cs(regs, DR_c, DR_s);
962 return _fex;
963}
964
965/* Load positive float */
966static int emu_lpebr (struct pt_regs *regs, int rx, int ry) {
967 FP_DECL_S(SA); FP_DECL_S(SR);
968 FP_DECL_EX;
969 int mode;
970
971 mode = current->thread.fp_regs.fpc & 3;
972 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
973 if (SA_s != 0) {
974 FP_NEG_S(SR, SA);
975 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
976 } else
977 current->thread.fp_regs.fprs[rx].ui =
978 current->thread.fp_regs.fprs[ry].ui;
979 emu_set_CC_cs(regs, SR_c, SR_s);
980 return _fex;
981}
982
983/* Load rounded long double to double */
984static int emu_ldxbr (struct pt_regs *regs, int rx, int ry) {
985 FP_DECL_Q(QA); FP_DECL_D(DR);
986 FP_DECL_EX;
987 mathemu_ldcv cvt;
988 int mode;
989
990 mode = current->thread.fp_regs.fpc & 3;
991 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
992 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
993 FP_UNPACK_QP(QA, &cvt.ld);
994 FP_CONV (D, Q, 2, 4, DR, QA);
995 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].f, DR);
996 return _fex;
997}
998
999/* Load rounded long double to float */
1000static int emu_lexbr (struct pt_regs *regs, int rx, int ry) {
1001 FP_DECL_Q(QA); FP_DECL_S(SR);
1002 FP_DECL_EX;
1003 mathemu_ldcv cvt;
1004 int mode;
1005
1006 mode = current->thread.fp_regs.fpc & 3;
1007 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
1008 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
1009 FP_UNPACK_QP(QA, &cvt.ld);
1010 FP_CONV (S, Q, 1, 4, SR, QA);
1011 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1012 return _fex;
1013}
1014
1015/* Load rounded double to float */
1016static int emu_ledbr (struct pt_regs *regs, int rx, int ry) {
1017 FP_DECL_D(DA); FP_DECL_S(SR);
1018 FP_DECL_EX;
1019 int mode;
1020
1021 mode = current->thread.fp_regs.fpc & 3;
1022 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
1023 FP_CONV (S, D, 1, 2, SR, DA);
1024 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1025 return _fex;
1026}
1027
1028/* Multiply long double */
1029static int emu_mxbr (struct pt_regs *regs, int rx, int ry) {
1030 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
1031 FP_DECL_EX;
1032 mathemu_ldcv cvt;
1033 int mode;
1034
1035 mode = current->thread.fp_regs.fpc & 3;
1036 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
1037 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
1038 FP_UNPACK_QP(QA, &cvt.ld);
1039 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
1040 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
1041 FP_UNPACK_QP(QB, &cvt.ld);
1042 FP_MUL_Q(QR, QA, QB);
1043 FP_PACK_QP(&cvt.ld, QR);
1044 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1045 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1046 return _fex;
1047}
1048
1049/* Multiply double */
1050static int emu_mdbr (struct pt_regs *regs, int rx, int ry) {
1051 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1052 FP_DECL_EX;
1053 int mode;
1054
1055 mode = current->thread.fp_regs.fpc & 3;
1056 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1057 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
1058 FP_MUL_D(DR, DA, DB);
1059 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1060 return _fex;
1061}
1062
1063/* Multiply double */
1064static int emu_mdb (struct pt_regs *regs, int rx, double *val) {
1065 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1066 FP_DECL_EX;
1067 int mode;
1068
1069 mode = current->thread.fp_regs.fpc & 3;
1070 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1071 FP_UNPACK_DP(DB, val);
1072 FP_MUL_D(DR, DA, DB);
1073 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1074 return _fex;
1075}
1076
1077/* Multiply double to long double */
1078static int emu_mxdbr (struct pt_regs *regs, int rx, int ry) {
1079 FP_DECL_D(DA); FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
1080 FP_DECL_EX;
1081 mathemu_ldcv cvt;
1082 int mode;
1083
1084 mode = current->thread.fp_regs.fpc & 3;
1085 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1086 FP_CONV (Q, D, 4, 2, QA, DA);
1087 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
1088 FP_CONV (Q, D, 4, 2, QB, DA);
1089 FP_MUL_Q(QR, QA, QB);
1090 FP_PACK_QP(&cvt.ld, QR);
1091 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1092 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1093 return _fex;
1094}
1095
1096/* Multiply double to long double */
1097static int emu_mxdb (struct pt_regs *regs, int rx, long double *val) {
1098 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
1099 FP_DECL_EX;
1100 mathemu_ldcv cvt;
1101 int mode;
1102
1103 mode = current->thread.fp_regs.fpc & 3;
1104 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
1105 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
1106 FP_UNPACK_QP(QA, &cvt.ld);
1107 FP_UNPACK_QP(QB, val);
1108 FP_MUL_Q(QR, QA, QB);
1109 FP_PACK_QP(&cvt.ld, QR);
1110 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1111 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1112 return _fex;
1113}
1114
1115/* Multiply float */
1116static int emu_meebr (struct pt_regs *regs, int rx, int ry) {
1117 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
1118 FP_DECL_EX;
1119 int mode;
1120
1121 mode = current->thread.fp_regs.fpc & 3;
1122 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1123 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
1124 FP_MUL_S(SR, SA, SB);
1125 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1126 return _fex;
1127}
1128
1129/* Multiply float */
1130static int emu_meeb (struct pt_regs *regs, int rx, float *val) {
1131 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
1132 FP_DECL_EX;
1133 int mode;
1134
1135 mode = current->thread.fp_regs.fpc & 3;
1136 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1137 FP_UNPACK_SP(SB, val);
1138 FP_MUL_S(SR, SA, SB);
1139 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1140 return _fex;
1141}
1142
1143/* Multiply float to double */
1144static int emu_mdebr (struct pt_regs *regs, int rx, int ry) {
1145 FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1146 FP_DECL_EX;
1147 int mode;
1148
1149 mode = current->thread.fp_regs.fpc & 3;
1150 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1151 FP_CONV (D, S, 2, 1, DA, SA);
1152 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
1153 FP_CONV (D, S, 2, 1, DB, SA);
1154 FP_MUL_D(DR, DA, DB);
1155 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1156 return _fex;
1157}
1158
1159/* Multiply float to double */
1160static int emu_mdeb (struct pt_regs *regs, int rx, float *val) {
1161 FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1162 FP_DECL_EX;
1163 int mode;
1164
1165 mode = current->thread.fp_regs.fpc & 3;
1166 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1167 FP_CONV (D, S, 2, 1, DA, SA);
1168 FP_UNPACK_SP(SA, val);
1169 FP_CONV (D, S, 2, 1, DB, SA);
1170 FP_MUL_D(DR, DA, DB);
1171 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1172 return _fex;
1173}
1174
1175/* Multiply and add double */
1176static int emu_madbr (struct pt_regs *regs, int rx, int ry, int rz) {
1177 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
1178 FP_DECL_EX;
1179 int mode;
1180
1181 mode = current->thread.fp_regs.fpc & 3;
1182 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1183 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
1184 FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
1185 FP_MUL_D(DR, DA, DB);
1186 FP_ADD_D(DR, DR, DC);
1187 FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
1188 return _fex;
1189}
1190
1191/* Multiply and add double */
1192static int emu_madb (struct pt_regs *regs, int rx, double *val, int rz) {
1193 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
1194 FP_DECL_EX;
1195 int mode;
1196
1197 mode = current->thread.fp_regs.fpc & 3;
1198 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1199 FP_UNPACK_DP(DB, val);
1200 FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
1201 FP_MUL_D(DR, DA, DB);
1202 FP_ADD_D(DR, DR, DC);
1203 FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
1204 return _fex;
1205}
1206
1207/* Multiply and add float */
1208static int emu_maebr (struct pt_regs *regs, int rx, int ry, int rz) {
1209 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
1210 FP_DECL_EX;
1211 int mode;
1212
1213 mode = current->thread.fp_regs.fpc & 3;
1214 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1215 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
1216 FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
1217 FP_MUL_S(SR, SA, SB);
1218 FP_ADD_S(SR, SR, SC);
1219 FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
1220 return _fex;
1221}
1222
1223/* Multiply and add float */
1224static int emu_maeb (struct pt_regs *regs, int rx, float *val, int rz) {
1225 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
1226 FP_DECL_EX;
1227 int mode;
1228
1229 mode = current->thread.fp_regs.fpc & 3;
1230 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1231 FP_UNPACK_SP(SB, val);
1232 FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
1233 FP_MUL_S(SR, SA, SB);
1234 FP_ADD_S(SR, SR, SC);
1235 FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
1236 return _fex;
1237}
1238
1239/* Multiply and subtract double */
1240static int emu_msdbr (struct pt_regs *regs, int rx, int ry, int rz) {
1241 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
1242 FP_DECL_EX;
1243 int mode;
1244
1245 mode = current->thread.fp_regs.fpc & 3;
1246 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1247 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
1248 FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
1249 FP_MUL_D(DR, DA, DB);
1250 FP_SUB_D(DR, DR, DC);
1251 FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
1252 return _fex;
1253}
1254
1255/* Multiply and subtract double */
1256static int emu_msdb (struct pt_regs *regs, int rx, double *val, int rz) {
1257 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
1258 FP_DECL_EX;
1259 int mode;
1260
1261 mode = current->thread.fp_regs.fpc & 3;
1262 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1263 FP_UNPACK_DP(DB, val);
1264 FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
1265 FP_MUL_D(DR, DA, DB);
1266 FP_SUB_D(DR, DR, DC);
1267 FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
1268 return _fex;
1269}
1270
1271/* Multiply and subtract float */
1272static int emu_msebr (struct pt_regs *regs, int rx, int ry, int rz) {
1273 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
1274 FP_DECL_EX;
1275 int mode;
1276
1277 mode = current->thread.fp_regs.fpc & 3;
1278 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1279 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
1280 FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
1281 FP_MUL_S(SR, SA, SB);
1282 FP_SUB_S(SR, SR, SC);
1283 FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
1284 return _fex;
1285}
1286
1287/* Multiply and subtract float */
1288static int emu_mseb (struct pt_regs *regs, int rx, float *val, int rz) {
1289 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
1290 FP_DECL_EX;
1291 int mode;
1292
1293 mode = current->thread.fp_regs.fpc & 3;
1294 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1295 FP_UNPACK_SP(SB, val);
1296 FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
1297 FP_MUL_S(SR, SA, SB);
1298 FP_SUB_S(SR, SR, SC);
1299 FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
1300 return _fex;
1301}
1302
1303/* Set floating point control word */
1304static int emu_sfpc (struct pt_regs *regs, int rx, int ry) {
1305 __u32 temp;
1306
1307 temp = regs->gprs[rx];
1308 if ((temp & ~FPC_VALID_MASK) != 0)
1309 return SIGILL;
1310 current->thread.fp_regs.fpc = temp;
1311 return 0;
1312}
1313
1314/* Square root long double */
1315static int emu_sqxbr (struct pt_regs *regs, int rx, int ry) {
1316 FP_DECL_Q(QA); FP_DECL_Q(QR);
1317 FP_DECL_EX;
1318 mathemu_ldcv cvt;
1319 int mode;
1320
1321 mode = current->thread.fp_regs.fpc & 3;
1322 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
1323 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
1324 FP_UNPACK_QP(QA, &cvt.ld);
1325 FP_SQRT_Q(QR, QA);
1326 FP_PACK_QP(&cvt.ld, QR);
1327 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1328 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1329 emu_set_CC_cs(regs, QR_c, QR_s);
1330 return _fex;
1331}
1332
1333/* Square root double */
1334static int emu_sqdbr (struct pt_regs *regs, int rx, int ry) {
1335 FP_DECL_D(DA); FP_DECL_D(DR);
1336 FP_DECL_EX;
1337 int mode;
1338
1339 mode = current->thread.fp_regs.fpc & 3;
1340 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
1341 FP_SQRT_D(DR, DA);
1342 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1343 emu_set_CC_cs(regs, DR_c, DR_s);
1344 return _fex;
1345}
1346
1347/* Square root double */
1348static int emu_sqdb (struct pt_regs *regs, int rx, double *val) {
1349 FP_DECL_D(DA); FP_DECL_D(DR);
1350 FP_DECL_EX;
1351 int mode;
1352
1353 mode = current->thread.fp_regs.fpc & 3;
1354 FP_UNPACK_DP(DA, val);
1355 FP_SQRT_D(DR, DA);
1356 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1357 emu_set_CC_cs(regs, DR_c, DR_s);
1358 return _fex;
1359}
1360
1361/* Square root float */
1362static int emu_sqebr (struct pt_regs *regs, int rx, int ry) {
1363 FP_DECL_S(SA); FP_DECL_S(SR);
1364 FP_DECL_EX;
1365 int mode;
1366
1367 mode = current->thread.fp_regs.fpc & 3;
1368 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
1369 FP_SQRT_S(SR, SA);
1370 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1371 emu_set_CC_cs(regs, SR_c, SR_s);
1372 return _fex;
1373}
1374
1375/* Square root float */
1376static int emu_sqeb (struct pt_regs *regs, int rx, float *val) {
1377 FP_DECL_S(SA); FP_DECL_S(SR);
1378 FP_DECL_EX;
1379 int mode;
1380
1381 mode = current->thread.fp_regs.fpc & 3;
1382 FP_UNPACK_SP(SA, val);
1383 FP_SQRT_S(SR, SA);
1384 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1385 emu_set_CC_cs(regs, SR_c, SR_s);
1386 return _fex;
1387}
1388
1389/* Subtract long double */
1390static int emu_sxbr (struct pt_regs *regs, int rx, int ry) {
1391 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
1392 FP_DECL_EX;
1393 mathemu_ldcv cvt;
1394 int mode;
1395
1396 mode = current->thread.fp_regs.fpc & 3;
1397 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
1398 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
1399 FP_UNPACK_QP(QA, &cvt.ld);
1400 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
1401 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
1402 FP_UNPACK_QP(QB, &cvt.ld);
1403 FP_SUB_Q(QR, QA, QB);
1404 FP_PACK_QP(&cvt.ld, QR);
1405 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1406 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1407 emu_set_CC_cs(regs, QR_c, QR_s);
1408 return _fex;
1409}
1410
1411/* Subtract double */
1412static int emu_sdbr (struct pt_regs *regs, int rx, int ry) {
1413 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1414 FP_DECL_EX;
1415 int mode;
1416
1417 mode = current->thread.fp_regs.fpc & 3;
1418 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1419 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
1420 FP_SUB_D(DR, DA, DB);
1421 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1422 emu_set_CC_cs(regs, DR_c, DR_s);
1423 return _fex;
1424}
1425
1426/* Subtract double */
1427static int emu_sdb (struct pt_regs *regs, int rx, double *val) {
1428 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1429 FP_DECL_EX;
1430 int mode;
1431
1432 mode = current->thread.fp_regs.fpc & 3;
1433 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1434 FP_UNPACK_DP(DB, val);
1435 FP_SUB_D(DR, DA, DB);
1436 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1437 emu_set_CC_cs(regs, DR_c, DR_s);
1438 return _fex;
1439}
1440
1441/* Subtract float */
1442static int emu_sebr (struct pt_regs *regs, int rx, int ry) {
1443 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
1444 FP_DECL_EX;
1445 int mode;
1446
1447 mode = current->thread.fp_regs.fpc & 3;
1448 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1449 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
1450 FP_SUB_S(SR, SA, SB);
1451 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1452 emu_set_CC_cs(regs, SR_c, SR_s);
1453 return _fex;
1454}
1455
1456/* Subtract float */
1457static int emu_seb (struct pt_regs *regs, int rx, float *val) {
1458 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
1459 FP_DECL_EX;
1460 int mode;
1461
1462 mode = current->thread.fp_regs.fpc & 3;
1463 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1464 FP_UNPACK_SP(SB, val);
1465 FP_SUB_S(SR, SA, SB);
1466 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1467 emu_set_CC_cs(regs, SR_c, SR_s);
1468 return _fex;
1469}
1470
1471/* Test data class long double */
1472static int emu_tcxb (struct pt_regs *regs, int rx, long val) {
1473 FP_DECL_Q(QA);
1474 mathemu_ldcv cvt;
1475 int bit;
1476
1477 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
1478 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
1479 FP_UNPACK_RAW_QP(QA, &cvt.ld);
1480 switch (QA_e) {
1481 default:
1482 bit = 8; /* normalized number */
1483 break;
1484 case 0:
1485 if (_FP_FRAC_ZEROP_4(QA))
1486 bit = 10; /* zero */
1487 else
1488 bit = 6; /* denormalized number */
1489 break;
1490 case _FP_EXPMAX_Q:
1491 if (_FP_FRAC_ZEROP_4(QA))
1492 bit = 4; /* infinity */
1493 else if (_FP_FRAC_HIGH_RAW_Q(QA) & _FP_QNANBIT_Q)
1494 bit = 2; /* quiet NAN */
1495 else
1496 bit = 0; /* signaling NAN */
1497 break;
1498 }
1499 if (!QA_s)
1500 bit++;
1501 emu_set_CC(regs, ((__u32) val >> bit) & 1);
1502 return 0;
1503}
1504
1505/* Test data class double */
1506static int emu_tcdb (struct pt_regs *regs, int rx, long val) {
1507 FP_DECL_D(DA);
1508 int bit;
1509
1510 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1511 switch (DA_e) {
1512 default:
1513 bit = 8; /* normalized number */
1514 break;
1515 case 0:
1516 if (_FP_FRAC_ZEROP_2(DA))
1517 bit = 10; /* zero */
1518 else
1519 bit = 6; /* denormalized number */
1520 break;
1521 case _FP_EXPMAX_D:
1522 if (_FP_FRAC_ZEROP_2(DA))
1523 bit = 4; /* infinity */
1524 else if (_FP_FRAC_HIGH_RAW_D(DA) & _FP_QNANBIT_D)
1525 bit = 2; /* quiet NAN */
1526 else
1527 bit = 0; /* signaling NAN */
1528 break;
1529 }
1530 if (!DA_s)
1531 bit++;
1532 emu_set_CC(regs, ((__u32) val >> bit) & 1);
1533 return 0;
1534}
1535
1536/* Test data class float */
1537static int emu_tceb (struct pt_regs *regs, int rx, long val) {
1538 FP_DECL_S(SA);
1539 int bit;
1540
1541 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1542 switch (SA_e) {
1543 default:
1544 bit = 8; /* normalized number */
1545 break;
1546 case 0:
1547 if (_FP_FRAC_ZEROP_1(SA))
1548 bit = 10; /* zero */
1549 else
1550 bit = 6; /* denormalized number */
1551 break;
1552 case _FP_EXPMAX_S:
1553 if (_FP_FRAC_ZEROP_1(SA))
1554 bit = 4; /* infinity */
1555 else if (_FP_FRAC_HIGH_RAW_S(SA) & _FP_QNANBIT_S)
1556 bit = 2; /* quiet NAN */
1557 else
1558 bit = 0; /* signaling NAN */
1559 break;
1560 }
1561 if (!SA_s)
1562 bit++;
1563 emu_set_CC(regs, ((__u32) val >> bit) & 1);
1564 return 0;
1565}
1566
1567static inline void emu_load_regd(int reg) {
1568 if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
1569 return;
1570 asm volatile ( /* load reg from fp_regs.fprs[reg] */
1571 " bras 1,0f\n"
1572 " ld 0,0(%1)\n"
1573 "0: ex %0,0(1)"
1574 : /* no output */
1575 : "a" (reg<<4),"a" (&current->thread.fp_regs.fprs[reg].d)
1576 : "1" );
1577}
1578
1579static inline void emu_load_rege(int reg) {
1580 if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
1581 return;
1582 asm volatile ( /* load reg from fp_regs.fprs[reg] */
1583 " bras 1,0f\n"
1584 " le 0,0(%1)\n"
1585 "0: ex %0,0(1)"
1586 : /* no output */
1587 : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
1588 : "1" );
1589}
1590
1591static inline void emu_store_regd(int reg) {
1592 if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
1593 return;
1594 asm volatile ( /* store reg to fp_regs.fprs[reg] */
1595 " bras 1,0f\n"
1596 " std 0,0(%1)\n"
1597 "0: ex %0,0(1)"
1598 : /* no output */
1599 : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
1600 : "1" );
1601}
1602
1603
1604static inline void emu_store_rege(int reg) {
1605 if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
1606 return;
1607 asm volatile ( /* store reg to fp_regs.fprs[reg] */
1608 " bras 1,0f\n"
1609 " ste 0,0(%1)\n"
1610 "0: ex %0,0(1)"
1611 : /* no output */
1612 : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
1613 : "1" );
1614}
1615
1616int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
1617 int _fex = 0;
1618 static const __u8 format_table[256] = {
1619 [0x00] = 0x03,[0x01] = 0x03,[0x02] = 0x03,[0x03] = 0x03,
1620 [0x04] = 0x0f,[0x05] = 0x0d,[0x06] = 0x0e,[0x07] = 0x0d,
1621 [0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03,
1622 [0x0c] = 0x0f,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06,
1623 [0x10] = 0x02,[0x11] = 0x02,[0x12] = 0x02,[0x13] = 0x02,
1624 [0x14] = 0x03,[0x15] = 0x02,[0x16] = 0x01,[0x17] = 0x03,
1625 [0x18] = 0x02,[0x19] = 0x02,[0x1a] = 0x02,[0x1b] = 0x02,
1626 [0x1c] = 0x02,[0x1d] = 0x02,[0x1e] = 0x05,[0x1f] = 0x05,
1627 [0x40] = 0x01,[0x41] = 0x01,[0x42] = 0x01,[0x43] = 0x01,
1628 [0x44] = 0x12,[0x45] = 0x0d,[0x46] = 0x11,[0x47] = 0x04,
1629 [0x48] = 0x01,[0x49] = 0x01,[0x4a] = 0x01,[0x4b] = 0x01,
1630 [0x4c] = 0x01,[0x4d] = 0x01,[0x53] = 0x06,[0x57] = 0x06,
1631 [0x5b] = 0x05,[0x5f] = 0x05,[0x84] = 0x13,[0x8c] = 0x13,
1632 [0x94] = 0x09,[0x95] = 0x08,[0x96] = 0x07,[0x98] = 0x0c,
1633 [0x99] = 0x0b,[0x9a] = 0x0a
1634 };
1635 static const void *jump_table[256]= {
1636 [0x00] = emu_lpebr,[0x01] = emu_lnebr,[0x02] = emu_ltebr,
1637 [0x03] = emu_lcebr,[0x04] = emu_ldebr,[0x05] = emu_lxdbr,
1638 [0x06] = emu_lxebr,[0x07] = emu_mxdbr,[0x08] = emu_kebr,
1639 [0x09] = emu_cebr, [0x0a] = emu_aebr, [0x0b] = emu_sebr,
1640 [0x0c] = emu_mdebr,[0x0d] = emu_debr, [0x0e] = emu_maebr,
1641 [0x0f] = emu_msebr,[0x10] = emu_lpdbr,[0x11] = emu_lndbr,
1642 [0x12] = emu_ltdbr,[0x13] = emu_lcdbr,[0x14] = emu_sqebr,
1643 [0x15] = emu_sqdbr,[0x16] = emu_sqxbr,[0x17] = emu_meebr,
1644 [0x18] = emu_kdbr, [0x19] = emu_cdbr, [0x1a] = emu_adbr,
1645 [0x1b] = emu_sdbr, [0x1c] = emu_mdbr, [0x1d] = emu_ddbr,
1646 [0x1e] = emu_madbr,[0x1f] = emu_msdbr,[0x40] = emu_lpxbr,
1647 [0x41] = emu_lnxbr,[0x42] = emu_ltxbr,[0x43] = emu_lcxbr,
1648 [0x44] = emu_ledbr,[0x45] = emu_ldxbr,[0x46] = emu_lexbr,
1649 [0x47] = emu_fixbr,[0x48] = emu_kxbr, [0x49] = emu_cxbr,
1650 [0x4a] = emu_axbr, [0x4b] = emu_sxbr, [0x4c] = emu_mxbr,
1651 [0x4d] = emu_dxbr, [0x53] = emu_diebr,[0x57] = emu_fiebr,
1652 [0x5b] = emu_didbr,[0x5f] = emu_fidbr,[0x84] = emu_sfpc,
1653 [0x8c] = emu_efpc, [0x94] = emu_cefbr,[0x95] = emu_cdfbr,
1654 [0x96] = emu_cxfbr,[0x98] = emu_cfebr,[0x99] = emu_cfdbr,
1655 [0x9a] = emu_cfxbr
1656 };
1657
1658 switch (format_table[opcode[1]]) {
1659 case 1: /* RRE format, long double operation */
1660 if (opcode[3] & 0x22)
1661 return SIGILL;
1662 emu_store_regd((opcode[3] >> 4) & 15);
1663 emu_store_regd(((opcode[3] >> 4) & 15) + 2);
1664 emu_store_regd(opcode[3] & 15);
1665 emu_store_regd((opcode[3] & 15) + 2);
1666 /* call the emulation function */
1667 _fex = ((int (*)(struct pt_regs *,int, int))
1668 jump_table[opcode[1]])
1669 (regs, opcode[3] >> 4, opcode[3] & 15);
1670 emu_load_regd((opcode[3] >> 4) & 15);
1671 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1672 emu_load_regd(opcode[3] & 15);
1673 emu_load_regd((opcode[3] & 15) + 2);
1674 break;
1675 case 2: /* RRE format, double operation */
1676 emu_store_regd((opcode[3] >> 4) & 15);
1677 emu_store_regd(opcode[3] & 15);
1678 /* call the emulation function */
1679 _fex = ((int (*)(struct pt_regs *, int, int))
1680 jump_table[opcode[1]])
1681 (regs, opcode[3] >> 4, opcode[3] & 15);
1682 emu_load_regd((opcode[3] >> 4) & 15);
1683 emu_load_regd(opcode[3] & 15);
1684 break;
1685 case 3: /* RRE format, float operation */
1686 emu_store_rege((opcode[3] >> 4) & 15);
1687 emu_store_rege(opcode[3] & 15);
1688 /* call the emulation function */
1689 _fex = ((int (*)(struct pt_regs *, int, int))
1690 jump_table[opcode[1]])
1691 (regs, opcode[3] >> 4, opcode[3] & 15);
1692 emu_load_rege((opcode[3] >> 4) & 15);
1693 emu_load_rege(opcode[3] & 15);
1694 break;
1695 case 4: /* RRF format, long double operation */
1696 if (opcode[3] & 0x22)
1697 return SIGILL;
1698 emu_store_regd((opcode[3] >> 4) & 15);
1699 emu_store_regd(((opcode[3] >> 4) & 15) + 2);
1700 emu_store_regd(opcode[3] & 15);
1701 emu_store_regd((opcode[3] & 15) + 2);
1702 /* call the emulation function */
1703 _fex = ((int (*)(struct pt_regs *, int, int, int))
1704 jump_table[opcode[1]])
1705 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1706 emu_load_regd((opcode[3] >> 4) & 15);
1707 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1708 emu_load_regd(opcode[3] & 15);
1709 emu_load_regd((opcode[3] & 15) + 2);
1710 break;
1711 case 5: /* RRF format, double operation */
1712 emu_store_regd((opcode[2] >> 4) & 15);
1713 emu_store_regd((opcode[3] >> 4) & 15);
1714 emu_store_regd(opcode[3] & 15);
1715 /* call the emulation function */
1716 _fex = ((int (*)(struct pt_regs *, int, int, int))
1717 jump_table[opcode[1]])
1718 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1719 emu_load_regd((opcode[2] >> 4) & 15);
1720 emu_load_regd((opcode[3] >> 4) & 15);
1721 emu_load_regd(opcode[3] & 15);
1722 break;
1723 case 6: /* RRF format, float operation */
1724 emu_store_rege((opcode[2] >> 4) & 15);
1725 emu_store_rege((opcode[3] >> 4) & 15);
1726 emu_store_rege(opcode[3] & 15);
1727 /* call the emulation function */
1728 _fex = ((int (*)(struct pt_regs *, int, int, int))
1729 jump_table[opcode[1]])
1730 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1731 emu_load_rege((opcode[2] >> 4) & 15);
1732 emu_load_rege((opcode[3] >> 4) & 15);
1733 emu_load_rege(opcode[3] & 15);
1734 break;
1735 case 7: /* RRE format, cxfbr instruction */
1736 /* call the emulation function */
1737 if (opcode[3] & 0x20)
1738 return SIGILL;
1739 _fex = ((int (*)(struct pt_regs *, int, int))
1740 jump_table[opcode[1]])
1741 (regs, opcode[3] >> 4, opcode[3] & 15);
1742 emu_load_regd((opcode[3] >> 4) & 15);
1743 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1744 break;
1745 case 8: /* RRE format, cdfbr instruction */
1746 /* call the emulation function */
1747 _fex = ((int (*)(struct pt_regs *, int, int))
1748 jump_table[opcode[1]])
1749 (regs, opcode[3] >> 4, opcode[3] & 15);
1750 emu_load_regd((opcode[3] >> 4) & 15);
1751 break;
1752 case 9: /* RRE format, cefbr instruction */
1753 /* call the emulation function */
1754 _fex = ((int (*)(struct pt_regs *, int, int))
1755 jump_table[opcode[1]])
1756 (regs, opcode[3] >> 4, opcode[3] & 15);
1757 emu_load_rege((opcode[3] >> 4) & 15);
1758 break;
1759 case 10: /* RRF format, cfxbr instruction */
1760 if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
1761 /* mask of { 2,3,8-15 } is invalid */
1762 return SIGILL;
1763 if (opcode[3] & 2)
1764 return SIGILL;
1765 emu_store_regd(opcode[3] & 15);
1766 emu_store_regd((opcode[3] & 15) + 2);
1767 /* call the emulation function */
1768 _fex = ((int (*)(struct pt_regs *, int, int, int))
1769 jump_table[opcode[1]])
1770 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1771 break;
1772 case 11: /* RRF format, cfdbr instruction */
1773 if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
1774 /* mask of { 2,3,8-15 } is invalid */
1775 return SIGILL;
1776 emu_store_regd(opcode[3] & 15);
1777 /* call the emulation function */
1778 _fex = ((int (*)(struct pt_regs *, int, int, int))
1779 jump_table[opcode[1]])
1780 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1781 break;
1782 case 12: /* RRF format, cfebr instruction */
1783 if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
1784 /* mask of { 2,3,8-15 } is invalid */
1785 return SIGILL;
1786 emu_store_rege(opcode[3] & 15);
1787 /* call the emulation function */
1788 _fex = ((int (*)(struct pt_regs *, int, int, int))
1789 jump_table[opcode[1]])
1790 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1791 break;
1792 case 13: /* RRE format, ldxbr & mdxbr instruction */
1793 /* double store but long double load */
1794 if (opcode[3] & 0x20)
1795 return SIGILL;
1796 emu_store_regd((opcode[3] >> 4) & 15);
1797 emu_store_regd(opcode[3] & 15);
1798 /* call the emulation function */
1799 _fex = ((int (*)(struct pt_regs *, int, int))
1800 jump_table[opcode[1]])
1801 (regs, opcode[3] >> 4, opcode[3] & 15);
1802 emu_load_regd((opcode[3] >> 4) & 15);
1803 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1804 break;
1805 case 14: /* RRE format, ldxbr & mdxbr instruction */
1806 /* float store but long double load */
1807 if (opcode[3] & 0x20)
1808 return SIGILL;
1809 emu_store_rege((opcode[3] >> 4) & 15);
1810 emu_store_rege(opcode[3] & 15);
1811 /* call the emulation function */
1812 _fex = ((int (*)(struct pt_regs *, int, int))
1813 jump_table[opcode[1]])
1814 (regs, opcode[3] >> 4, opcode[3] & 15);
1815 emu_load_regd((opcode[3] >> 4) & 15);
1816 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1817 break;
1818 case 15: /* RRE format, ldebr & mdebr instruction */
1819 /* float store but double load */
1820 emu_store_rege((opcode[3] >> 4) & 15);
1821 emu_store_rege(opcode[3] & 15);
1822 /* call the emulation function */
1823 _fex = ((int (*)(struct pt_regs *, int, int))
1824 jump_table[opcode[1]])
1825 (regs, opcode[3] >> 4, opcode[3] & 15);
1826 emu_load_regd((opcode[3] >> 4) & 15);
1827 break;
1828 case 16: /* RRE format, ldxbr instruction */
1829 /* long double store but double load */
1830 if (opcode[3] & 2)
1831 return SIGILL;
1832 emu_store_regd(opcode[3] & 15);
1833 emu_store_regd((opcode[3] & 15) + 2);
1834 /* call the emulation function */
1835 _fex = ((int (*)(struct pt_regs *, int, int))
1836 jump_table[opcode[1]])
1837 (regs, opcode[3] >> 4, opcode[3] & 15);
1838 emu_load_regd((opcode[3] >> 4) & 15);
1839 break;
1840 case 17: /* RRE format, ldxbr instruction */
1841 /* long double store but float load */
1842 if (opcode[3] & 2)
1843 return SIGILL;
1844 emu_store_regd(opcode[3] & 15);
1845 emu_store_regd((opcode[3] & 15) + 2);
1846 /* call the emulation function */
1847 _fex = ((int (*)(struct pt_regs *, int, int))
1848 jump_table[opcode[1]])
1849 (regs, opcode[3] >> 4, opcode[3] & 15);
1850 emu_load_rege((opcode[3] >> 4) & 15);
1851 break;
1852 case 18: /* RRE format, ledbr instruction */
1853 /* double store but float load */
1854 emu_store_regd(opcode[3] & 15);
1855 /* call the emulation function */
1856 _fex = ((int (*)(struct pt_regs *, int, int))
1857 jump_table[opcode[1]])
1858 (regs, opcode[3] >> 4, opcode[3] & 15);
1859 emu_load_rege((opcode[3] >> 4) & 15);
1860 break;
1861 case 19: /* RRE format, efpc & sfpc instruction */
1862 /* call the emulation function */
1863 _fex = ((int (*)(struct pt_regs *, int, int))
1864 jump_table[opcode[1]])
1865 (regs, opcode[3] >> 4, opcode[3] & 15);
1866 break;
1867 default: /* invalid operation */
1868 return SIGILL;
1869 }
1870 if (_fex != 0) {
1871 current->thread.fp_regs.fpc |= _fex;
1872 if (current->thread.fp_regs.fpc & (_fex << 8))
1873 return SIGFPE;
1874 }
1875 return 0;
1876}
1877
1878static void* calc_addr(struct pt_regs *regs, int rx, int rb, int disp)
1879{
1880 addr_t addr;
1881
1882 rx &= 15;
1883 rb &= 15;
1884 addr = disp & 0xfff;
1885 addr += (rx != 0) ? regs->gprs[rx] : 0; /* + index */
1886 addr += (rb != 0) ? regs->gprs[rb] : 0; /* + base */
1887 return (void*) addr;
1888}
1889
1890int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
1891 int _fex = 0;
1892
1893 static const __u8 format_table[256] = {
1894 [0x04] = 0x06,[0x05] = 0x05,[0x06] = 0x07,[0x07] = 0x05,
1895 [0x08] = 0x02,[0x09] = 0x02,[0x0a] = 0x02,[0x0b] = 0x02,
1896 [0x0c] = 0x06,[0x0d] = 0x02,[0x0e] = 0x04,[0x0f] = 0x04,
1897 [0x10] = 0x08,[0x11] = 0x09,[0x12] = 0x0a,[0x14] = 0x02,
1898 [0x15] = 0x01,[0x17] = 0x02,[0x18] = 0x01,[0x19] = 0x01,
1899 [0x1a] = 0x01,[0x1b] = 0x01,[0x1c] = 0x01,[0x1d] = 0x01,
1900 [0x1e] = 0x03,[0x1f] = 0x03,
1901 };
1902 static const void *jump_table[]= {
1903 [0x04] = emu_ldeb,[0x05] = emu_lxdb,[0x06] = emu_lxeb,
1904 [0x07] = emu_mxdb,[0x08] = emu_keb, [0x09] = emu_ceb,
1905 [0x0a] = emu_aeb, [0x0b] = emu_seb, [0x0c] = emu_mdeb,
1906 [0x0d] = emu_deb, [0x0e] = emu_maeb,[0x0f] = emu_mseb,
1907 [0x10] = emu_tceb,[0x11] = emu_tcdb,[0x12] = emu_tcxb,
1908 [0x14] = emu_sqeb,[0x15] = emu_sqdb,[0x17] = emu_meeb,
1909 [0x18] = emu_kdb, [0x19] = emu_cdb, [0x1a] = emu_adb,
1910 [0x1b] = emu_sdb, [0x1c] = emu_mdb, [0x1d] = emu_ddb,
1911 [0x1e] = emu_madb,[0x1f] = emu_msdb
1912 };
1913
1914 switch (format_table[opcode[5]]) {
1915 case 1: /* RXE format, double constant */ {
1916 __u64 *dxb, temp;
1917 __u32 opc;
1918
1919 emu_store_regd((opcode[1] >> 4) & 15);
1920 opc = *((__u32 *) opcode);
1921 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1922 mathemu_copy_from_user(&temp, dxb, 8);
1923 /* call the emulation function */
1924 _fex = ((int (*)(struct pt_regs *, int, double *))
1925 jump_table[opcode[5]])
1926 (regs, opcode[1] >> 4, (double *) &temp);
1927 emu_load_regd((opcode[1] >> 4) & 15);
1928 break;
1929 }
1930 case 2: /* RXE format, float constant */ {
1931 __u32 *dxb, temp;
1932 __u32 opc;
1933
1934 emu_store_rege((opcode[1] >> 4) & 15);
1935 opc = *((__u32 *) opcode);
1936 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1937 mathemu_get_user(temp, dxb);
1938 /* call the emulation function */
1939 _fex = ((int (*)(struct pt_regs *, int, float *))
1940 jump_table[opcode[5]])
1941 (regs, opcode[1] >> 4, (float *) &temp);
1942 emu_load_rege((opcode[1] >> 4) & 15);
1943 break;
1944 }
1945 case 3: /* RXF format, double constant */ {
1946 __u64 *dxb, temp;
1947 __u32 opc;
1948
1949 emu_store_regd((opcode[1] >> 4) & 15);
1950 emu_store_regd((opcode[4] >> 4) & 15);
1951 opc = *((__u32 *) opcode);
1952 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1953 mathemu_copy_from_user(&temp, dxb, 8);
1954 /* call the emulation function */
1955 _fex = ((int (*)(struct pt_regs *, int, double *, int))
1956 jump_table[opcode[5]])
1957 (regs, opcode[1] >> 4, (double *) &temp, opcode[4] >> 4);
1958 emu_load_regd((opcode[1] >> 4) & 15);
1959 break;
1960 }
1961 case 4: /* RXF format, float constant */ {
1962 __u32 *dxb, temp;
1963 __u32 opc;
1964
1965 emu_store_rege((opcode[1] >> 4) & 15);
1966 emu_store_rege((opcode[4] >> 4) & 15);
1967 opc = *((__u32 *) opcode);
1968 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1969 mathemu_get_user(temp, dxb);
1970 /* call the emulation function */
1971 _fex = ((int (*)(struct pt_regs *, int, float *, int))
1972 jump_table[opcode[5]])
1973 (regs, opcode[1] >> 4, (float *) &temp, opcode[4] >> 4);
1974 emu_load_rege((opcode[4] >> 4) & 15);
1975 break;
1976 }
1977 case 5: /* RXE format, double constant */
1978 /* store double and load long double */
1979 {
1980 __u64 *dxb, temp;
1981 __u32 opc;
1982 if ((opcode[1] >> 4) & 0x20)
1983 return SIGILL;
1984 emu_store_regd((opcode[1] >> 4) & 15);
1985 opc = *((__u32 *) opcode);
1986 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1987 mathemu_copy_from_user(&temp, dxb, 8);
1988 /* call the emulation function */
1989 _fex = ((int (*)(struct pt_regs *, int, double *))
1990 jump_table[opcode[5]])
1991 (regs, opcode[1] >> 4, (double *) &temp);
1992 emu_load_regd((opcode[1] >> 4) & 15);
1993 emu_load_regd(((opcode[1] >> 4) & 15) + 2);
1994 break;
1995 }
1996 case 6: /* RXE format, float constant */
1997 /* store float and load double */
1998 {
1999 __u32 *dxb, temp;
2000 __u32 opc;
2001 emu_store_rege((opcode[1] >> 4) & 15);
2002 opc = *((__u32 *) opcode);
2003 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2004 mathemu_get_user(temp, dxb);
2005 /* call the emulation function */
2006 _fex = ((int (*)(struct pt_regs *, int, float *))
2007 jump_table[opcode[5]])
2008 (regs, opcode[1] >> 4, (float *) &temp);
2009 emu_load_regd((opcode[1] >> 4) & 15);
2010 break;
2011 }
2012 case 7: /* RXE format, float constant */
2013 /* store float and load long double */
2014 {
2015 __u32 *dxb, temp;
2016 __u32 opc;
2017 if ((opcode[1] >> 4) & 0x20)
2018 return SIGILL;
2019 emu_store_rege((opcode[1] >> 4) & 15);
2020 opc = *((__u32 *) opcode);
2021 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2022 mathemu_get_user(temp, dxb);
2023 /* call the emulation function */
2024 _fex = ((int (*)(struct pt_regs *, int, float *))
2025 jump_table[opcode[5]])
2026 (regs, opcode[1] >> 4, (float *) &temp);
2027 emu_load_regd((opcode[1] >> 4) & 15);
2028 emu_load_regd(((opcode[1] >> 4) & 15) + 2);
2029 break;
2030 }
2031 case 8: /* RXE format, RX address used as int value */ {
2032 __u64 dxb;
2033 __u32 opc;
2034
2035 emu_store_rege((opcode[1] >> 4) & 15);
2036 opc = *((__u32 *) opcode);
2037 dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
2038 /* call the emulation function */
2039 _fex = ((int (*)(struct pt_regs *, int, long))
2040 jump_table[opcode[5]])
2041 (regs, opcode[1] >> 4, dxb);
2042 break;
2043 }
2044 case 9: /* RXE format, RX address used as int value */ {
2045 __u64 dxb;
2046 __u32 opc;
2047
2048 emu_store_regd((opcode[1] >> 4) & 15);
2049 opc = *((__u32 *) opcode);
2050 dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
2051 /* call the emulation function */
2052 _fex = ((int (*)(struct pt_regs *, int, long))
2053 jump_table[opcode[5]])
2054 (regs, opcode[1] >> 4, dxb);
2055 break;
2056 }
2057 case 10: /* RXE format, RX address used as int value */ {
2058 __u64 dxb;
2059 __u32 opc;
2060
2061 if ((opcode[1] >> 4) & 2)
2062 return SIGILL;
2063 emu_store_regd((opcode[1] >> 4) & 15);
2064 emu_store_regd(((opcode[1] >> 4) & 15) + 2);
2065 opc = *((__u32 *) opcode);
2066 dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
2067 /* call the emulation function */
2068 _fex = ((int (*)(struct pt_regs *, int, long))
2069 jump_table[opcode[5]])
2070 (regs, opcode[1] >> 4, dxb);
2071 break;
2072 }
2073 default: /* invalid operation */
2074 return SIGILL;
2075 }
2076 if (_fex != 0) {
2077 current->thread.fp_regs.fpc |= _fex;
2078 if (current->thread.fp_regs.fpc & (_fex << 8))
2079 return SIGFPE;
2080 }
2081 return 0;
2082}
2083
2084/*
2085 * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
2086 */
2087int math_emu_ldr(__u8 *opcode) {
2088 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2089 __u16 opc = *((__u16 *) opcode);
2090
2091 if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
2092 /* we got an exception therfore ry can't be in {0,2,4,6} */
2093 __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
2094 " bras 1,0f\n"
2095 " ld 0,0(%1)\n"
2096 "0: ex %0,0(1)"
2097 : /* no output */
2098 : "a" (opc & 0xf0),
2099 "a" (&fp_regs->fprs[opc & 0xf].d)
2100 : "1" );
2101 } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
2102 __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
2103 " bras 1,0f\n"
2104 " std 0,0(%1)\n"
2105 "0: ex %0,0(1)"
2106 : /* no output */
2107 : "a" ((opc & 0xf) << 4),
2108 "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d)
2109 : "1" );
2110 } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
2111 fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
2112 return 0;
2113}
2114
2115/*
2116 * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
2117 */
2118int math_emu_ler(__u8 *opcode) {
2119 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2120 __u16 opc = *((__u16 *) opcode);
2121
2122 if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
2123 /* we got an exception therfore ry can't be in {0,2,4,6} */
2124 __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
2125 " bras 1,0f\n"
2126 " le 0,0(%1)\n"
2127 "0: ex %0,0(1)"
2128 : /* no output */
2129 : "a" (opc & 0xf0),
2130 "a" (&fp_regs->fprs[opc & 0xf].f)
2131 : "1" );
2132 } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
2133 __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
2134 " bras 1,0f\n"
2135 " ste 0,0(%1)\n"
2136 "0: ex %0,0(1)"
2137 : /* no output */
2138 : "a" ((opc & 0xf) << 4),
2139 "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f)
2140 : "1" );
2141 } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
2142 fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
2143 return 0;
2144}
2145
2146/*
2147 * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
2148 */
2149int math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
2150 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2151 __u32 opc = *((__u32 *) opcode);
2152 __u64 *dxb;
2153
2154 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2155 mathemu_copy_from_user(&fp_regs->fprs[(opc >> 20) & 0xf].d, dxb, 8);
2156 return 0;
2157}
2158
2159/*
2160 * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
2161 */
2162int math_emu_le(__u8 *opcode, struct pt_regs * regs) {
2163 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2164 __u32 opc = *((__u32 *) opcode);
2165 __u32 *mem, *dxb;
2166
2167 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2168 mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f);
2169 mathemu_get_user(mem[0], dxb);
2170 return 0;
2171}
2172
2173/*
2174 * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
2175 */
2176int math_emu_std(__u8 *opcode, struct pt_regs * regs) {
2177 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2178 __u32 opc = *((__u32 *) opcode);
2179 __u64 *dxb;
2180
2181 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2182 mathemu_copy_to_user(dxb, &fp_regs->fprs[(opc >> 20) & 0xf].d, 8);
2183 return 0;
2184}
2185
2186/*
2187 * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
2188 */
2189int math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
2190 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2191 __u32 opc = *((__u32 *) opcode);
2192 __u32 *mem, *dxb;
2193
2194 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2195 mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f);
2196 mathemu_put_user(mem[0], dxb);
2197 return 0;
2198}
2199
2200/*
2201 * Emulate LFPC D(B)
2202 */
2203int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
2204 __u32 opc = *((__u32 *) opcode);
2205 __u32 *dxb, temp;
2206
2207 dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc);
2208 mathemu_get_user(temp, dxb);
2209 if ((temp & ~FPC_VALID_MASK) != 0)
2210 return SIGILL;
2211 current->thread.fp_regs.fpc = temp;
2212 return 0;
2213}
2214
2215/*
2216 * Emulate STFPC D(B)
2217 */
2218int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
2219 __u32 opc = *((__u32 *) opcode);
2220 __u32 *dxb;
2221
2222 dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc);
2223 mathemu_put_user(current->thread.fp_regs.fpc, dxb);
2224 return 0;
2225}
2226
2227/*
2228 * Emulate SRNM D(B)
2229 */
2230int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
2231 __u32 opc = *((__u32 *) opcode);
2232 __u32 temp;
2233
2234 temp = calc_addr(regs, 0, opc>>12, opc);
2235 current->thread.fp_regs.fpc &= ~3;
2236 current->thread.fp_regs.fpc |= (temp & 3);
2237 return 0;
2238}
2239
2240/* broken compiler ... */
2241long long
2242__negdi2 (long long u)
2243{
2244
2245 union lll {
2246 long long ll;
2247 long s[2];
2248 };
2249
2250 union lll w,uu;
2251
2252 uu.ll = u;
2253
2254 w.s[1] = -uu.s[1];
2255 w.s[0] = -uu.s[0] - ((int) w.s[1] != 0);
2256
2257 return w.ll;
2258}
diff --git a/arch/s390/math-emu/qrnnd.S b/arch/s390/math-emu/qrnnd.S
new file mode 100644
index 000000000000..b01c2b648e22
--- /dev/null
+++ b/arch/s390/math-emu/qrnnd.S
@@ -0,0 +1,77 @@
1# S/390 __udiv_qrnnd
2
3# r2 : &__r
4# r3 : upper half of 64 bit word n
5# r4 : lower half of 64 bit word n
6# r5 : divisor d
7# the reminder r of the division is to be stored to &__r and
8# the quotient q is to be returned
9
10 .text
11 .globl __udiv_qrnnd
12__udiv_qrnnd:
13 st %r2,24(%r15) # store pointer to reminder for later
14 lr %r0,%r3 # reload n
15 lr %r1,%r4
16 ltr %r2,%r5 # reload and test divisor
17 jp 5f
18 # divisor >= 0x80000000
19 srdl %r0,2 # n/4
20 srl %r2,1 # d/2
21 slr %r1,%r2 # special case if last bit of d is set
22 brc 3,0f # (n/4) div (n/2) can overflow by 1
23 ahi %r0,-1 # trick: subtract n/2, then divide
240: dr %r0,%r2 # signed division
25 ahi %r1,1 # trick part 2: add 1 to the quotient
26 # now (n >> 2) = (d >> 1) * %r1 + %r0
27 lhi %r3,1
28 nr %r3,%r1 # test last bit of q
29 jz 1f
30 alr %r0,%r2 # add (d>>1) to r
311: srl %r1,1 # q >>= 1
32 # now (n >> 2) = (d&-2) * %r1 + %r0
33 lhi %r3,1
34 nr %r3,%r5 # test last bit of d
35 jz 2f
36 slr %r0,%r1 # r -= q
37 brc 3,2f # borrow ?
38 alr %r0,%r5 # r += d
39 ahi %r1,-1
402: # now (n >> 2) = d * %r1 + %r0
41 alr %r1,%r1 # q <<= 1
42 alr %r0,%r0 # r <<= 1
43 brc 12,3f # overflow on r ?
44 slr %r0,%r5 # r -= d
45 ahi %r1,1 # q += 1
463: lhi %r3,2
47 nr %r3,%r4 # test next to last bit of n
48 jz 4f
49 ahi %r0,1 # r += 1
504: clr %r0,%r5 # r >= d ?
51 jl 6f
52 slr %r0,%r5 # r -= d
53 ahi %r1,1 # q += 1
54 # now (n >> 1) = d * %r1 + %r0
55 j 6f
565: # divisor < 0x80000000
57 srdl %r0,1
58 dr %r0,%r2 # signed division
59 # now (n >> 1) = d * %r1 + %r0
606: alr %r1,%r1 # q <<= 1
61 alr %r0,%r0 # r <<= 1
62 brc 12,7f # overflow on r ?
63 slr %r0,%r5 # r -= d
64 ahi %r1,1 # q += 1
657: lhi %r3,1
66 nr %r3,%r4 # isolate last bit of n
67 alr %r0,%r3 # r += (n & 1)
68 clr %r0,%r5 # r >= d ?
69 jl 8f
70 slr %r0,%r5 # r -= d
71 ahi %r1,1 # q += 1
728: # now n = d * %r1 + %r0
73 l %r2,24(%r15)
74 st %r0,0(%r2)
75 lr %r2,%r1
76 br %r14
77 .end __udiv_qrnnd
diff --git a/arch/s390/math-emu/sfp-util.h b/arch/s390/math-emu/sfp-util.h
new file mode 100644
index 000000000000..ab556b600f73
--- /dev/null
+++ b/arch/s390/math-emu/sfp-util.h
@@ -0,0 +1,63 @@
1#include <linux/kernel.h>
2#include <linux/sched.h>
3#include <linux/types.h>
4#include <asm/byteorder.h>
5
6#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \
7 unsigned int __sh = (ah); \
8 unsigned int __sl = (al); \
9 __asm__ (" alr %1,%3\n" \
10 " brc 12,0f\n" \
11 " ahi %0,1\n" \
12 "0: alr %0,%2" \
13 : "+&d" (__sh), "+d" (__sl) \
14 : "d" (bh), "d" (bl) : "cc" ); \
15 (sh) = __sh; \
16 (sl) = __sl; \
17})
18
19#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \
20 unsigned int __sh = (ah); \
21 unsigned int __sl = (al); \
22 __asm__ (" slr %1,%3\n" \
23 " brc 3,0f\n" \
24 " ahi %0,-1\n" \
25 "0: slr %0,%2" \
26 : "+&d" (__sh), "+d" (__sl) \
27 : "d" (bh), "d" (bl) : "cc" ); \
28 (sh) = __sh; \
29 (sl) = __sl; \
30})
31
32/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */
33#define umul_ppmm(wh, wl, u, v) ({ \
34 unsigned int __wh = u; \
35 unsigned int __wl = v; \
36 __asm__ (" ltr 1,%0\n" \
37 " mr 0,%1\n" \
38 " jnm 0f\n" \
39 " alr 0,%1\n" \
40 "0: ltr %1,%1\n" \
41 " jnm 1f\n" \
42 " alr 0,%0\n" \
43 "1: lr %0,0\n" \
44 " lr %1,1\n" \
45 : "+d" (__wh), "+d" (__wl) \
46 : : "0", "1", "cc" ); \
47 wh = __wh; \
48 wl = __wl; \
49})
50
51#define udiv_qrnnd(q, r, n1, n0, d) \
52 do { unsigned long __r; \
53 (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \
54 (r) = __r; \
55 } while (0)
56extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
57 unsigned long , unsigned long);
58
59#define UDIV_NEEDS_NORMALIZATION 0
60
61#define abort() return 0
62
63#define __BYTE_ORDER __BIG_ENDIAN
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
new file mode 100644
index 000000000000..aa9a42b6e62d
--- /dev/null
+++ b/arch/s390/mm/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the linux s390-specific parts of the memory manager.
3#
4
5obj-y := init.o fault.o ioremap.o extmem.o mmap.o
6obj-$(CONFIG_CMM) += cmm.o
7
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
new file mode 100644
index 000000000000..d30cdb4248a9
--- /dev/null
+++ b/arch/s390/mm/cmm.c
@@ -0,0 +1,443 @@
1/*
2 * arch/s390/mm/cmm.c
3 *
4 * S390 version
5 * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
7 *
8 * Collaborative memory management interface.
9 */
10
11#include <linux/config.h>
12#include <linux/errno.h>
13#include <linux/fs.h>
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/sched.h>
17#include <linux/sysctl.h>
18#include <linux/ctype.h>
19
20#include <asm/pgalloc.h>
21#include <asm/uaccess.h>
22
23#include "../../../drivers/s390/net/smsgiucv.h"
24
25#define CMM_NR_PAGES ((PAGE_SIZE / sizeof(unsigned long)) - 2)
26
27struct cmm_page_array {
28 struct cmm_page_array *next;
29 unsigned long index;
30 unsigned long pages[CMM_NR_PAGES];
31};
32
33static long cmm_pages = 0;
34static long cmm_timed_pages = 0;
35static volatile long cmm_pages_target = 0;
36static volatile long cmm_timed_pages_target = 0;
37static long cmm_timeout_pages = 0;
38static long cmm_timeout_seconds = 0;
39
40static struct cmm_page_array *cmm_page_list = 0;
41static struct cmm_page_array *cmm_timed_page_list = 0;
42
43static unsigned long cmm_thread_active = 0;
44static struct work_struct cmm_thread_starter;
45static wait_queue_head_t cmm_thread_wait;
46static struct timer_list cmm_timer;
47
48static void cmm_timer_fn(unsigned long);
49static void cmm_set_timer(void);
50
51static long
52cmm_strtoul(const char *cp, char **endp)
53{
54 unsigned int base = 10;
55
56 if (*cp == '0') {
57 base = 8;
58 cp++;
59 if ((*cp == 'x' || *cp == 'X') && isxdigit(cp[1])) {
60 base = 16;
61 cp++;
62 }
63 }
64 return simple_strtoul(cp, endp, base);
65}
66
67static long
68cmm_alloc_pages(long pages, long *counter, struct cmm_page_array **list)
69{
70 struct cmm_page_array *pa;
71 unsigned long page;
72
73 pa = *list;
74 while (pages) {
75 page = __get_free_page(GFP_NOIO);
76 if (!page)
77 break;
78 if (!pa || pa->index >= CMM_NR_PAGES) {
79 /* Need a new page for the page list. */
80 pa = (struct cmm_page_array *)
81 __get_free_page(GFP_NOIO);
82 if (!pa) {
83 free_page(page);
84 break;
85 }
86 pa->next = *list;
87 pa->index = 0;
88 *list = pa;
89 }
90 diag10(page);
91 pa->pages[pa->index++] = page;
92 (*counter)++;
93 pages--;
94 }
95 return pages;
96}
97
98static void
99cmm_free_pages(long pages, long *counter, struct cmm_page_array **list)
100{
101 struct cmm_page_array *pa;
102 unsigned long page;
103
104 pa = *list;
105 while (pages) {
106 if (!pa || pa->index <= 0)
107 break;
108 page = pa->pages[--pa->index];
109 if (pa->index == 0) {
110 pa = pa->next;
111 free_page((unsigned long) *list);
112 *list = pa;
113 }
114 free_page(page);
115 (*counter)--;
116 pages--;
117 }
118}
119
120static int
121cmm_thread(void *dummy)
122{
123 int rc;
124
125 daemonize("cmmthread");
126 while (1) {
127 rc = wait_event_interruptible(cmm_thread_wait,
128 (cmm_pages != cmm_pages_target ||
129 cmm_timed_pages != cmm_timed_pages_target));
130 if (rc == -ERESTARTSYS) {
131 /* Got kill signal. End thread. */
132 clear_bit(0, &cmm_thread_active);
133 cmm_pages_target = cmm_pages;
134 cmm_timed_pages_target = cmm_timed_pages;
135 break;
136 }
137 if (cmm_pages_target > cmm_pages) {
138 if (cmm_alloc_pages(1, &cmm_pages, &cmm_page_list))
139 cmm_pages_target = cmm_pages;
140 } else if (cmm_pages_target < cmm_pages) {
141 cmm_free_pages(1, &cmm_pages, &cmm_page_list);
142 }
143 if (cmm_timed_pages_target > cmm_timed_pages) {
144 if (cmm_alloc_pages(1, &cmm_timed_pages,
145 &cmm_timed_page_list))
146 cmm_timed_pages_target = cmm_timed_pages;
147 } else if (cmm_timed_pages_target < cmm_timed_pages) {
148 cmm_free_pages(1, &cmm_timed_pages,
149 &cmm_timed_page_list);
150 }
151 if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer))
152 cmm_set_timer();
153 }
154 return 0;
155}
156
157static void
158cmm_start_thread(void)
159{
160 kernel_thread(cmm_thread, 0, 0);
161}
162
163static void
164cmm_kick_thread(void)
165{
166 if (!test_and_set_bit(0, &cmm_thread_active))
167 schedule_work(&cmm_thread_starter);
168 wake_up(&cmm_thread_wait);
169}
170
171static void
172cmm_set_timer(void)
173{
174 if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) {
175 if (timer_pending(&cmm_timer))
176 del_timer(&cmm_timer);
177 return;
178 }
179 if (timer_pending(&cmm_timer)) {
180 if (mod_timer(&cmm_timer, jiffies + cmm_timeout_seconds*HZ))
181 return;
182 }
183 cmm_timer.function = cmm_timer_fn;
184 cmm_timer.data = 0;
185 cmm_timer.expires = jiffies + cmm_timeout_seconds*HZ;
186 add_timer(&cmm_timer);
187}
188
189static void
190cmm_timer_fn(unsigned long ignored)
191{
192 long pages;
193
194 pages = cmm_timed_pages_target - cmm_timeout_pages;
195 if (pages < 0)
196 cmm_timed_pages_target = 0;
197 else
198 cmm_timed_pages_target = pages;
199 cmm_kick_thread();
200 cmm_set_timer();
201}
202
203void
204cmm_set_pages(long pages)
205{
206 cmm_pages_target = pages;
207 cmm_kick_thread();
208}
209
210long
211cmm_get_pages(void)
212{
213 return cmm_pages;
214}
215
216void
217cmm_add_timed_pages(long pages)
218{
219 cmm_timed_pages_target += pages;
220 cmm_kick_thread();
221}
222
223long
224cmm_get_timed_pages(void)
225{
226 return cmm_timed_pages;
227}
228
229void
230cmm_set_timeout(long pages, long seconds)
231{
232 cmm_timeout_pages = pages;
233 cmm_timeout_seconds = seconds;
234 cmm_set_timer();
235}
236
237static inline int
238cmm_skip_blanks(char *cp, char **endp)
239{
240 char *str;
241
242 for (str = cp; *str == ' ' || *str == '\t'; str++);
243 *endp = str;
244 return str != cp;
245}
246
247#ifdef CONFIG_CMM_PROC
248/* These will someday get removed. */
249#define VM_CMM_PAGES 1111
250#define VM_CMM_TIMED_PAGES 1112
251#define VM_CMM_TIMEOUT 1113
252
253static struct ctl_table cmm_table[];
254
255static int
256cmm_pages_handler(ctl_table *ctl, int write, struct file *filp,
257 void *buffer, size_t *lenp, loff_t *ppos)
258{
259 char buf[16], *p;
260 long pages;
261 int len;
262
263 if (!*lenp || (*ppos && !write)) {
264 *lenp = 0;
265 return 0;
266 }
267
268 if (write) {
269 len = *lenp;
270 if (copy_from_user(buf, buffer,
271 len > sizeof(buf) ? sizeof(buf) : len))
272 return -EFAULT;
273 buf[sizeof(buf) - 1] = '\0';
274 cmm_skip_blanks(buf, &p);
275 pages = cmm_strtoul(p, &p);
276 if (ctl == &cmm_table[0])
277 cmm_set_pages(pages);
278 else
279 cmm_add_timed_pages(pages);
280 } else {
281 if (ctl == &cmm_table[0])
282 pages = cmm_get_pages();
283 else
284 pages = cmm_get_timed_pages();
285 len = sprintf(buf, "%ld\n", pages);
286 if (len > *lenp)
287 len = *lenp;
288 if (copy_to_user(buffer, buf, len))
289 return -EFAULT;
290 }
291 *lenp = len;
292 *ppos += len;
293 return 0;
294}
295
296static int
297cmm_timeout_handler(ctl_table *ctl, int write, struct file *filp,
298 void *buffer, size_t *lenp, loff_t *ppos)
299{
300 char buf[64], *p;
301 long pages, seconds;
302 int len;
303
304 if (!*lenp || (*ppos && !write)) {
305 *lenp = 0;
306 return 0;
307 }
308
309 if (write) {
310 len = *lenp;
311 if (copy_from_user(buf, buffer,
312 len > sizeof(buf) ? sizeof(buf) : len))
313 return -EFAULT;
314 buf[sizeof(buf) - 1] = '\0';
315 cmm_skip_blanks(buf, &p);
316 pages = cmm_strtoul(p, &p);
317 cmm_skip_blanks(p, &p);
318 seconds = cmm_strtoul(p, &p);
319 cmm_set_timeout(pages, seconds);
320 } else {
321 len = sprintf(buf, "%ld %ld\n",
322 cmm_timeout_pages, cmm_timeout_seconds);
323 if (len > *lenp)
324 len = *lenp;
325 if (copy_to_user(buffer, buf, len))
326 return -EFAULT;
327 }
328 *lenp = len;
329 *ppos += len;
330 return 0;
331}
332
333static struct ctl_table cmm_table[] = {
334 {
335 .ctl_name = VM_CMM_PAGES,
336 .procname = "cmm_pages",
337 .mode = 0600,
338 .proc_handler = &cmm_pages_handler,
339 },
340 {
341 .ctl_name = VM_CMM_TIMED_PAGES,
342 .procname = "cmm_timed_pages",
343 .mode = 0600,
344 .proc_handler = &cmm_pages_handler,
345 },
346 {
347 .ctl_name = VM_CMM_TIMEOUT,
348 .procname = "cmm_timeout",
349 .mode = 0600,
350 .proc_handler = &cmm_timeout_handler,
351 },
352 { .ctl_name = 0 }
353};
354
355static struct ctl_table cmm_dir_table[] = {
356 {
357 .ctl_name = CTL_VM,
358 .procname = "vm",
359 .maxlen = 0,
360 .mode = 0555,
361 .child = cmm_table,
362 },
363 { .ctl_name = 0 }
364};
365#endif
366
367#ifdef CONFIG_CMM_IUCV
368#define SMSG_PREFIX "CMM"
369static void
370cmm_smsg_target(char *msg)
371{
372 long pages, seconds;
373
374 if (!cmm_skip_blanks(msg + strlen(SMSG_PREFIX), &msg))
375 return;
376 if (strncmp(msg, "SHRINK", 6) == 0) {
377 if (!cmm_skip_blanks(msg + 6, &msg))
378 return;
379 pages = cmm_strtoul(msg, &msg);
380 cmm_skip_blanks(msg, &msg);
381 if (*msg == '\0')
382 cmm_set_pages(pages);
383 } else if (strncmp(msg, "RELEASE", 7) == 0) {
384 if (!cmm_skip_blanks(msg + 7, &msg))
385 return;
386 pages = cmm_strtoul(msg, &msg);
387 cmm_skip_blanks(msg, &msg);
388 if (*msg == '\0')
389 cmm_add_timed_pages(pages);
390 } else if (strncmp(msg, "REUSE", 5) == 0) {
391 if (!cmm_skip_blanks(msg + 5, &msg))
392 return;
393 pages = cmm_strtoul(msg, &msg);
394 if (!cmm_skip_blanks(msg, &msg))
395 return;
396 seconds = cmm_strtoul(msg, &msg);
397 cmm_skip_blanks(msg, &msg);
398 if (*msg == '\0')
399 cmm_set_timeout(pages, seconds);
400 }
401}
402#endif
403
404struct ctl_table_header *cmm_sysctl_header;
405
406static int
407cmm_init (void)
408{
409#ifdef CONFIG_CMM_PROC
410 cmm_sysctl_header = register_sysctl_table(cmm_dir_table, 1);
411#endif
412#ifdef CONFIG_CMM_IUCV
413 smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
414#endif
415 INIT_WORK(&cmm_thread_starter, (void *) cmm_start_thread, 0);
416 init_waitqueue_head(&cmm_thread_wait);
417 init_timer(&cmm_timer);
418 return 0;
419}
420
421static void
422cmm_exit(void)
423{
424 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
425 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
426#ifdef CONFIG_CMM_PROC
427 unregister_sysctl_table(cmm_sysctl_header);
428#endif
429#ifdef CONFIG_CMM_IUCV
430 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
431#endif
432}
433
434module_init(cmm_init);
435module_exit(cmm_exit);
436
437EXPORT_SYMBOL(cmm_set_pages);
438EXPORT_SYMBOL(cmm_get_pages);
439EXPORT_SYMBOL(cmm_add_timed_pages);
440EXPORT_SYMBOL(cmm_get_timed_pages);
441EXPORT_SYMBOL(cmm_set_timeout);
442
443MODULE_LICENSE("GPL");
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
new file mode 100644
index 000000000000..648deed17e25
--- /dev/null
+++ b/arch/s390/mm/extmem.c
@@ -0,0 +1,588 @@
1/*
2 * File...........: arch/s390/mm/extmem.c
3 * Author(s)......: Carsten Otte <cotte@de.ibm.com>
4 * Rob M van der Heij <rvdheij@nl.ibm.com>
5 * Steven Shultz <shultzss@us.ibm.com>
6 * Bugreports.to..: <Linux390@de.ibm.com>
7 * (C) IBM Corporation 2002-2004
8 */
9
10#include <linux/kernel.h>
11#include <linux/string.h>
12#include <linux/spinlock.h>
13#include <linux/list.h>
14#include <linux/slab.h>
15#include <linux/module.h>
16#include <linux/bootmem.h>
17#include <asm/page.h>
18#include <asm/ebcdic.h>
19#include <asm/errno.h>
20#include <asm/extmem.h>
21#include <asm/cpcmd.h>
22#include <linux/ctype.h>
23
24#define DCSS_DEBUG /* Debug messages on/off */
25
26#define DCSS_NAME "extmem"
27#ifdef DCSS_DEBUG
28#define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSS_NAME " debug:" x)
29#else
30#define PRINT_DEBUG(x...) do {} while (0)
31#endif
32#define PRINT_INFO(x...) printk(KERN_INFO DCSS_NAME " info:" x)
33#define PRINT_WARN(x...) printk(KERN_WARNING DCSS_NAME " warning:" x)
34#define PRINT_ERR(x...) printk(KERN_ERR DCSS_NAME " error:" x)
35
36
37#define DCSS_LOADSHR 0x00
38#define DCSS_LOADNSR 0x04
39#define DCSS_PURGESEG 0x08
40#define DCSS_FINDSEG 0x0c
41#define DCSS_LOADNOLY 0x10
42#define DCSS_SEGEXT 0x18
43#define DCSS_FINDSEGA 0x0c
44
45struct qrange {
46 unsigned int start; // 3byte start address, 1 byte type
47 unsigned int end; // 3byte end address, 1 byte reserved
48};
49
50struct qout64 {
51 int segstart;
52 int segend;
53 int segcnt;
54 int segrcnt;
55 struct qrange range[6];
56};
57
58struct qin64 {
59 char qopcode;
60 char rsrv1[3];
61 char qrcode;
62 char rsrv2[3];
63 char qname[8];
64 unsigned int qoutptr;
65 short int qoutlen;
66};
67
68struct dcss_segment {
69 struct list_head list;
70 char dcss_name[8];
71 unsigned long start_addr;
72 unsigned long end;
73 atomic_t ref_count;
74 int do_nonshared;
75 unsigned int vm_segtype;
76 struct qrange range[6];
77 int segcnt;
78};
79
80static DEFINE_SPINLOCK(dcss_lock);
81static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list);
82static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
83 "EW/EN-MIXED" };
84
85extern struct {
86 unsigned long addr, size, type;
87} memory_chunk[MEMORY_CHUNKS];
88
89/*
90 * Create the 8 bytes, ebcdic VM segment name from
91 * an ascii name.
92 */
93static void inline
94dcss_mkname(char *name, char *dcss_name)
95{
96 int i;
97
98 for (i = 0; i < 8; i++) {
99 if (name[i] == '\0')
100 break;
101 dcss_name[i] = toupper(name[i]);
102 };
103 for (; i < 8; i++)
104 dcss_name[i] = ' ';
105 ASCEBC(dcss_name, 8);
106}
107
108
109/*
110 * search all segments in dcss_list, and return the one
111 * namend *name. If not found, return NULL.
112 */
113static struct dcss_segment *
114segment_by_name (char *name)
115{
116 char dcss_name[9];
117 struct list_head *l;
118 struct dcss_segment *tmp, *retval = NULL;
119
120 assert_spin_locked(&dcss_lock);
121 dcss_mkname (name, dcss_name);
122 list_for_each (l, &dcss_list) {
123 tmp = list_entry (l, struct dcss_segment, list);
124 if (memcmp(tmp->dcss_name, dcss_name, 8) == 0) {
125 retval = tmp;
126 break;
127 }
128 }
129 return retval;
130}
131
132
133/*
134 * Perform a function on a dcss segment.
135 */
136static inline int
137dcss_diag (__u8 func, void *parameter,
138 unsigned long *ret1, unsigned long *ret2)
139{
140 unsigned long rx, ry;
141 int rc;
142
143 rx = (unsigned long) parameter;
144 ry = (unsigned long) func;
145 __asm__ __volatile__(
146#ifdef CONFIG_ARCH_S390X
147 " sam31\n" // switch to 31 bit
148 " diag %0,%1,0x64\n"
149 " sam64\n" // switch back to 64 bit
150#else
151 " diag %0,%1,0x64\n"
152#endif
153 " ipm %2\n"
154 " srl %2,28\n"
155 : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc" );
156 *ret1 = rx;
157 *ret2 = ry;
158 return rc;
159}
160
161static inline int
162dcss_diag_translate_rc (int vm_rc) {
163 if (vm_rc == 44)
164 return -ENOENT;
165 return -EIO;
166}
167
168
169/* do a diag to get info about a segment.
170 * fills start_address, end and vm_segtype fields
171 */
172static int
173query_segment_type (struct dcss_segment *seg)
174{
175 struct qin64 *qin = kmalloc (sizeof(struct qin64), GFP_DMA);
176 struct qout64 *qout = kmalloc (sizeof(struct qout64), GFP_DMA);
177
178 int diag_cc, rc, i;
179 unsigned long dummy, vmrc;
180
181 if ((qin == NULL) || (qout == NULL)) {
182 rc = -ENOMEM;
183 goto out_free;
184 }
185
186 /* initialize diag input parameters */
187 qin->qopcode = DCSS_FINDSEGA;
188 qin->qoutptr = (unsigned long) qout;
189 qin->qoutlen = sizeof(struct qout64);
190 memcpy (qin->qname, seg->dcss_name, 8);
191
192 diag_cc = dcss_diag (DCSS_SEGEXT, qin, &dummy, &vmrc);
193
194 if (diag_cc > 1) {
195 rc = dcss_diag_translate_rc (vmrc);
196 goto out_free;
197 }
198
199 if (qout->segcnt > 6) {
200 rc = -ENOTSUPP;
201 goto out_free;
202 }
203
204 if (qout->segcnt == 1) {
205 seg->vm_segtype = qout->range[0].start & 0xff;
206 } else {
207 /* multi-part segment. only one type supported here:
208 - all parts are contiguous
209 - all parts are either EW or EN type
210 - maximum 6 parts allowed */
211 unsigned long start = qout->segstart >> PAGE_SHIFT;
212 for (i=0; i<qout->segcnt; i++) {
213 if (((qout->range[i].start & 0xff) != SEG_TYPE_EW) &&
214 ((qout->range[i].start & 0xff) != SEG_TYPE_EN)) {
215 rc = -ENOTSUPP;
216 goto out_free;
217 }
218 if (start != qout->range[i].start >> PAGE_SHIFT) {
219 rc = -ENOTSUPP;
220 goto out_free;
221 }
222 start = (qout->range[i].end >> PAGE_SHIFT) + 1;
223 }
224 seg->vm_segtype = SEG_TYPE_EWEN;
225 }
226
227 /* analyze diag output and update seg */
228 seg->start_addr = qout->segstart;
229 seg->end = qout->segend;
230
231 memcpy (seg->range, qout->range, 6*sizeof(struct qrange));
232 seg->segcnt = qout->segcnt;
233
234 rc = 0;
235
236 out_free:
237 if (qin) kfree(qin);
238 if (qout) kfree(qout);
239 return rc;
240}
241
242/*
243 * check if the given segment collides with guest storage.
244 * returns 1 if this is the case, 0 if no collision was found
245 */
246static int
247segment_overlaps_storage(struct dcss_segment *seg)
248{
249 int i;
250
251 for (i=0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
252 if (memory_chunk[i].type != 0)
253 continue;
254 if ((memory_chunk[i].addr >> 20) > (seg->end >> 20))
255 continue;
256 if (((memory_chunk[i].addr + memory_chunk[i].size - 1) >> 20)
257 < (seg->start_addr >> 20))
258 continue;
259 return 1;
260 }
261 return 0;
262}
263
264/*
265 * check if segment collides with other segments that are currently loaded
266 * returns 1 if this is the case, 0 if no collision was found
267 */
268static int
269segment_overlaps_others (struct dcss_segment *seg)
270{
271 struct list_head *l;
272 struct dcss_segment *tmp;
273
274 assert_spin_locked(&dcss_lock);
275 list_for_each(l, &dcss_list) {
276 tmp = list_entry(l, struct dcss_segment, list);
277 if ((tmp->start_addr >> 20) > (seg->end >> 20))
278 continue;
279 if ((tmp->end >> 20) < (seg->start_addr >> 20))
280 continue;
281 if (seg == tmp)
282 continue;
283 return 1;
284 }
285 return 0;
286}
287
288/*
289 * check if segment exceeds the kernel mapping range (detected or set via mem=)
290 * returns 1 if this is the case, 0 if segment fits into the range
291 */
292static inline int
293segment_exceeds_range (struct dcss_segment *seg)
294{
295 int seg_last_pfn = (seg->end) >> PAGE_SHIFT;
296 if (seg_last_pfn > max_pfn)
297 return 1;
298 return 0;
299}
300
301/*
302 * get info about a segment
303 * possible return values:
304 * -ENOSYS : we are not running on VM
305 * -EIO : could not perform query diagnose
306 * -ENOENT : no such segment
307 * -ENOTSUPP: multi-part segment cannot be used with linux
308 * -ENOSPC : segment cannot be used (overlaps with storage)
309 * -ENOMEM : out of memory
310 * 0 .. 6 : type of segment as defined in include/asm-s390/extmem.h
311 */
312int
313segment_type (char* name)
314{
315 int rc;
316 struct dcss_segment seg;
317
318 if (!MACHINE_IS_VM)
319 return -ENOSYS;
320
321 dcss_mkname(name, seg.dcss_name);
322 rc = query_segment_type (&seg);
323 if (rc < 0)
324 return rc;
325 return seg.vm_segtype;
326}
327
328/*
329 * real segment loading function, called from segment_load
330 */
331static int
332__segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end)
333{
334 struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment),
335 GFP_DMA);
336 int dcss_command, rc, diag_cc;
337
338 if (seg == NULL) {
339 rc = -ENOMEM;
340 goto out;
341 }
342 dcss_mkname (name, seg->dcss_name);
343 rc = query_segment_type (seg);
344 if (rc < 0)
345 goto out_free;
346 if (segment_exceeds_range(seg)) {
347 PRINT_WARN ("segment_load: not loading segment %s - exceeds"
348 " kernel mapping range\n",name);
349 rc = -ERANGE;
350 goto out_free;
351 }
352 if (segment_overlaps_storage(seg)) {
353 PRINT_WARN ("segment_load: not loading segment %s - overlaps"
354 " storage\n",name);
355 rc = -ENOSPC;
356 goto out_free;
357 }
358 if (segment_overlaps_others(seg)) {
359 PRINT_WARN ("segment_load: not loading segment %s - overlaps"
360 " other segments\n",name);
361 rc = -EBUSY;
362 goto out_free;
363 }
364 if (do_nonshared)
365 dcss_command = DCSS_LOADNSR;
366 else
367 dcss_command = DCSS_LOADNOLY;
368
369 diag_cc = dcss_diag(dcss_command, seg->dcss_name,
370 &seg->start_addr, &seg->end);
371 if (diag_cc > 1) {
372 PRINT_WARN ("segment_load: could not load segment %s - "
373 "diag returned error (%ld)\n",name,seg->end);
374 rc = dcss_diag_translate_rc (seg->end);
375 dcss_diag(DCSS_PURGESEG, seg->dcss_name,
376 &seg->start_addr, &seg->end);
377 goto out_free;
378 }
379 seg->do_nonshared = do_nonshared;
380 atomic_set(&seg->ref_count, 1);
381 list_add(&seg->list, &dcss_list);
382 rc = seg->vm_segtype;
383 *addr = seg->start_addr;
384 *end = seg->end;
385 if (do_nonshared)
386 PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
387 "type %s in non-shared mode\n", name,
388 (void*)seg->start_addr, (void*)seg->end,
389 segtype_string[seg->vm_segtype]);
390 else
391 PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
392 "type %s in shared mode\n", name,
393 (void*)seg->start_addr, (void*)seg->end,
394 segtype_string[seg->vm_segtype]);
395 goto out;
396 out_free:
397 kfree (seg);
398 out:
399 return rc;
400}
401
402/*
403 * this function loads a DCSS segment
404 * name : name of the DCSS
405 * do_nonshared : 0 indicates that the dcss should be shared with other linux images
406 * 1 indicates that the dcss should be exclusive for this linux image
407 * addr : will be filled with start address of the segment
408 * end : will be filled with end address of the segment
409 * return values:
410 * -ENOSYS : we are not running on VM
411 * -EIO : could not perform query or load diagnose
412 * -ENOENT : no such segment
413 * -ENOTSUPP: multi-part segment cannot be used with linux
414 * -ENOSPC : segment cannot be used (overlaps with storage)
415 * -EBUSY : segment can temporarily not be used (overlaps with dcss)
416 * -ERANGE : segment cannot be used (exceeds kernel mapping range)
417 * -EPERM : segment is currently loaded with incompatible permissions
418 * -ENOMEM : out of memory
419 * 0 .. 6 : type of segment as defined in include/asm-s390/extmem.h
420 */
421int
422segment_load (char *name, int do_nonshared, unsigned long *addr,
423 unsigned long *end)
424{
425 struct dcss_segment *seg;
426 int rc;
427
428 if (!MACHINE_IS_VM)
429 return -ENOSYS;
430
431 spin_lock (&dcss_lock);
432 seg = segment_by_name (name);
433 if (seg == NULL)
434 rc = __segment_load (name, do_nonshared, addr, end);
435 else {
436 if (do_nonshared == seg->do_nonshared) {
437 atomic_inc(&seg->ref_count);
438 *addr = seg->start_addr;
439 *end = seg->end;
440 rc = seg->vm_segtype;
441 } else {
442 *addr = *end = 0;
443 rc = -EPERM;
444 }
445 }
446 spin_unlock (&dcss_lock);
447 return rc;
448}
449
450/*
451 * this function modifies the shared state of a DCSS segment. note that
452 * name : name of the DCSS
453 * do_nonshared : 0 indicates that the dcss should be shared with other linux images
454 * 1 indicates that the dcss should be exclusive for this linux image
455 * return values:
456 * -EIO : could not perform load diagnose (segment gone!)
457 * -ENOENT : no such segment (segment gone!)
458 * -EAGAIN : segment is in use by other exploiters, try later
459 * -EINVAL : no segment with the given name is currently loaded - name invalid
460 * 0 : operation succeeded
461 */
462int
463segment_modify_shared (char *name, int do_nonshared)
464{
465 struct dcss_segment *seg;
466 unsigned long dummy;
467 int dcss_command, rc, diag_cc;
468
469 spin_lock (&dcss_lock);
470 seg = segment_by_name (name);
471 if (seg == NULL) {
472 rc = -EINVAL;
473 goto out_unlock;
474 }
475 if (do_nonshared == seg->do_nonshared) {
476 PRINT_INFO ("segment_modify_shared: not reloading segment %s"
477 " - already in requested mode\n",name);
478 rc = 0;
479 goto out_unlock;
480 }
481 if (atomic_read (&seg->ref_count) != 1) {
482 PRINT_WARN ("segment_modify_shared: not reloading segment %s - "
483 "segment is in use by other driver(s)\n",name);
484 rc = -EAGAIN;
485 goto out_unlock;
486 }
487 dcss_diag(DCSS_PURGESEG, seg->dcss_name,
488 &dummy, &dummy);
489 if (do_nonshared)
490 dcss_command = DCSS_LOADNSR;
491 else
492 dcss_command = DCSS_LOADNOLY;
493 diag_cc = dcss_diag(dcss_command, seg->dcss_name,
494 &seg->start_addr, &seg->end);
495 if (diag_cc > 1) {
496 PRINT_WARN ("segment_modify_shared: could not reload segment %s"
497 " - diag returned error (%ld)\n",name,seg->end);
498 rc = dcss_diag_translate_rc (seg->end);
499 goto out_del;
500 }
501 seg->do_nonshared = do_nonshared;
502 rc = 0;
503 goto out_unlock;
504 out_del:
505 list_del(&seg->list);
506 dcss_diag(DCSS_PURGESEG, seg->dcss_name,
507 &dummy, &dummy);
508 kfree (seg);
509 out_unlock:
510 spin_unlock(&dcss_lock);
511 return rc;
512}
513
514/*
515 * Decrease the use count of a DCSS segment and remove
516 * it from the address space if nobody is using it
517 * any longer.
518 */
519void
520segment_unload(char *name)
521{
522 unsigned long dummy;
523 struct dcss_segment *seg;
524
525 if (!MACHINE_IS_VM)
526 return;
527
528 spin_lock(&dcss_lock);
529 seg = segment_by_name (name);
530 if (seg == NULL) {
531 PRINT_ERR ("could not find segment %s in segment_unload, "
532 "please report to linux390@de.ibm.com\n",name);
533 goto out_unlock;
534 }
535 if (atomic_dec_return(&seg->ref_count) == 0) {
536 list_del(&seg->list);
537 dcss_diag(DCSS_PURGESEG, seg->dcss_name,
538 &dummy, &dummy);
539 kfree(seg);
540 }
541out_unlock:
542 spin_unlock(&dcss_lock);
543}
544
545/*
546 * save segment content permanently
547 */
548void
549segment_save(char *name)
550{
551 struct dcss_segment *seg;
552 int startpfn = 0;
553 int endpfn = 0;
554 char cmd1[160];
555 char cmd2[80];
556 int i;
557
558 if (!MACHINE_IS_VM)
559 return;
560
561 spin_lock(&dcss_lock);
562 seg = segment_by_name (name);
563
564 if (seg == NULL) {
565 PRINT_ERR ("could not find segment %s in segment_save, please report to linux390@de.ibm.com\n",name);
566 return;
567 }
568
569 startpfn = seg->start_addr >> PAGE_SHIFT;
570 endpfn = (seg->end) >> PAGE_SHIFT;
571 sprintf(cmd1, "DEFSEG %s", name);
572 for (i=0; i<seg->segcnt; i++) {
573 sprintf(cmd1+strlen(cmd1), " %X-%X %s",
574 seg->range[i].start >> PAGE_SHIFT,
575 seg->range[i].end >> PAGE_SHIFT,
576 segtype_string[seg->range[i].start & 0xff]);
577 }
578 sprintf(cmd2, "SAVESEG %s", name);
579 cpcmd(cmd1, NULL, 0);
580 cpcmd(cmd2, NULL, 0);
581 spin_unlock(&dcss_lock);
582}
583
584EXPORT_SYMBOL(segment_load);
585EXPORT_SYMBOL(segment_unload);
586EXPORT_SYMBOL(segment_save);
587EXPORT_SYMBOL(segment_type);
588EXPORT_SYMBOL(segment_modify_shared);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
new file mode 100644
index 000000000000..80306bc8c799
--- /dev/null
+++ b/arch/s390/mm/fault.c
@@ -0,0 +1,586 @@
1/*
2 * arch/s390/mm/fault.c
3 *
4 * S390 version
5 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Hartmut Penner (hp@de.ibm.com)
7 * Ulrich Weigand (uweigand@de.ibm.com)
8 *
9 * Derived from "arch/i386/mm/fault.c"
10 * Copyright (C) 1995 Linus Torvalds
11 */
12
13#include <linux/config.h>
14#include <linux/signal.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/string.h>
19#include <linux/types.h>
20#include <linux/ptrace.h>
21#include <linux/mman.h>
22#include <linux/mm.h>
23#include <linux/smp.h>
24#include <linux/smp_lock.h>
25#include <linux/init.h>
26#include <linux/console.h>
27#include <linux/module.h>
28#include <linux/hardirq.h>
29
30#include <asm/system.h>
31#include <asm/uaccess.h>
32#include <asm/pgtable.h>
33
34#ifndef CONFIG_ARCH_S390X
35#define __FAIL_ADDR_MASK 0x7ffff000
36#define __FIXUP_MASK 0x7fffffff
37#define __SUBCODE_MASK 0x0200
38#define __PF_RES_FIELD 0ULL
39#else /* CONFIG_ARCH_S390X */
40#define __FAIL_ADDR_MASK -4096L
41#define __FIXUP_MASK ~0L
42#define __SUBCODE_MASK 0x0600
43#define __PF_RES_FIELD 0x8000000000000000ULL
44#endif /* CONFIG_ARCH_S390X */
45
46#ifdef CONFIG_SYSCTL
47extern int sysctl_userprocess_debug;
48#endif
49
50extern void die(const char *,struct pt_regs *,long);
51
52extern spinlock_t timerlist_lock;
53
54/*
55 * Unlock any spinlocks which will prevent us from getting the
56 * message out (timerlist_lock is acquired through the
57 * console unblank code)
58 */
59void bust_spinlocks(int yes)
60{
61 if (yes) {
62 oops_in_progress = 1;
63 } else {
64 int loglevel_save = console_loglevel;
65 console_unblank();
66 oops_in_progress = 0;
67 /*
68 * OK, the message is on the console. Now we call printk()
69 * without oops_in_progress set so that printk will give klogd
70 * a poke. Hold onto your hats...
71 */
72 console_loglevel = 15;
73 printk(" ");
74 console_loglevel = loglevel_save;
75 }
76}
77
78/*
79 * Check which address space is addressed by the access
80 * register in S390_lowcore.exc_access_id.
81 * Returns 1 for user space and 0 for kernel space.
82 */
83static int __check_access_register(struct pt_regs *regs, int error_code)
84{
85 int areg = S390_lowcore.exc_access_id;
86
87 if (areg == 0)
88 /* Access via access register 0 -> kernel address */
89 return 0;
90 save_access_regs(current->thread.acrs);
91 if (regs && areg < NUM_ACRS && current->thread.acrs[areg] <= 1)
92 /*
93 * access register contains 0 -> kernel address,
94 * access register contains 1 -> user space address
95 */
96 return current->thread.acrs[areg];
97
98 /* Something unhealthy was done with the access registers... */
99 die("page fault via unknown access register", regs, error_code);
100 do_exit(SIGKILL);
101 return 0;
102}
103
104/*
105 * Check which address space the address belongs to.
106 * Returns 1 for user space and 0 for kernel space.
107 */
108static inline int check_user_space(struct pt_regs *regs, int error_code)
109{
110 /*
111 * The lowest two bits of S390_lowcore.trans_exc_code indicate
112 * which paging table was used:
113 * 0: Primary Segment Table Descriptor
114 * 1: STD determined via access register
115 * 2: Secondary Segment Table Descriptor
116 * 3: Home Segment Table Descriptor
117 */
118 int descriptor = S390_lowcore.trans_exc_code & 3;
119 if (unlikely(descriptor == 1))
120 return __check_access_register(regs, error_code);
121 if (descriptor == 2)
122 return current->thread.mm_segment.ar4;
123 return descriptor != 0;
124}
125
126/*
127 * Send SIGSEGV to task. This is an external routine
128 * to keep the stack usage of do_page_fault small.
129 */
130static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
131 int si_code, unsigned long address)
132{
133 struct siginfo si;
134
135#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
136#if defined(CONFIG_SYSCTL)
137 if (sysctl_userprocess_debug)
138#endif
139 {
140 printk("User process fault: interruption code 0x%lX\n",
141 error_code);
142 printk("failing address: %lX\n", address);
143 show_regs(regs);
144 }
145#endif
146 si.si_signo = SIGSEGV;
147 si.si_code = si_code;
148 si.si_addr = (void *) address;
149 force_sig_info(SIGSEGV, &si, current);
150}
151
152/*
153 * This routine handles page faults. It determines the address,
154 * and the problem, and then passes it off to one of the appropriate
155 * routines.
156 *
157 * error_code:
158 * 04 Protection -> Write-Protection (suprression)
159 * 10 Segment translation -> Not present (nullification)
160 * 11 Page translation -> Not present (nullification)
161 * 3b Region third trans. -> Not present (nullification)
162 */
163extern inline void
164do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
165{
166 struct task_struct *tsk;
167 struct mm_struct *mm;
168 struct vm_area_struct * vma;
169 unsigned long address;
170 int user_address;
171 const struct exception_table_entry *fixup;
172 int si_code = SEGV_MAPERR;
173
174 tsk = current;
175 mm = tsk->mm;
176
177 /*
178 * Check for low-address protection. This needs to be treated
179 * as a special case because the translation exception code
180 * field is not guaranteed to contain valid data in this case.
181 */
182 if (is_protection && !(S390_lowcore.trans_exc_code & 4)) {
183
184 /* Low-address protection hit in kernel mode means
185 NULL pointer write access in kernel mode. */
186 if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
187 address = 0;
188 user_address = 0;
189 goto no_context;
190 }
191
192 /* Low-address protection hit in user mode 'cannot happen'. */
193 die ("Low-address protection", regs, error_code);
194 do_exit(SIGKILL);
195 }
196
197 /*
198 * get the failing address
199 * more specific the segment and page table portion of
200 * the address
201 */
202 address = S390_lowcore.trans_exc_code & __FAIL_ADDR_MASK;
203 user_address = check_user_space(regs, error_code);
204
205 /*
206 * Verify that the fault happened in user space, that
207 * we are not in an interrupt and that there is a
208 * user context.
209 */
210 if (user_address == 0 || in_interrupt() || !mm)
211 goto no_context;
212
213 /*
214 * When we get here, the fault happened in the current
215 * task's user address space, so we can switch on the
216 * interrupts again and then search the VMAs
217 */
218 local_irq_enable();
219
220 down_read(&mm->mmap_sem);
221
222 vma = find_vma(mm, address);
223 if (!vma)
224 goto bad_area;
225 if (vma->vm_start <= address)
226 goto good_area;
227 if (!(vma->vm_flags & VM_GROWSDOWN))
228 goto bad_area;
229 if (expand_stack(vma, address))
230 goto bad_area;
231/*
232 * Ok, we have a good vm_area for this memory access, so
233 * we can handle it..
234 */
235good_area:
236 si_code = SEGV_ACCERR;
237 if (!is_protection) {
238 /* page not present, check vm flags */
239 if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
240 goto bad_area;
241 } else {
242 if (!(vma->vm_flags & VM_WRITE))
243 goto bad_area;
244 }
245
246survive:
247 /*
248 * If for any reason at all we couldn't handle the fault,
249 * make sure we exit gracefully rather than endlessly redo
250 * the fault.
251 */
252 switch (handle_mm_fault(mm, vma, address, is_protection)) {
253 case VM_FAULT_MINOR:
254 tsk->min_flt++;
255 break;
256 case VM_FAULT_MAJOR:
257 tsk->maj_flt++;
258 break;
259 case VM_FAULT_SIGBUS:
260 goto do_sigbus;
261 case VM_FAULT_OOM:
262 goto out_of_memory;
263 default:
264 BUG();
265 }
266
267 up_read(&mm->mmap_sem);
268 /*
269 * The instruction that caused the program check will
270 * be repeated. Don't signal single step via SIGTRAP.
271 */
272 clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
273 return;
274
275/*
276 * Something tried to access memory that isn't in our memory map..
277 * Fix it, but check if it's kernel or user first..
278 */
279bad_area:
280 up_read(&mm->mmap_sem);
281
282 /* User mode accesses just cause a SIGSEGV */
283 if (regs->psw.mask & PSW_MASK_PSTATE) {
284 tsk->thread.prot_addr = address;
285 tsk->thread.trap_no = error_code;
286 do_sigsegv(regs, error_code, si_code, address);
287 return;
288 }
289
290no_context:
291 /* Are we prepared to handle this kernel fault? */
292 fixup = search_exception_tables(regs->psw.addr & __FIXUP_MASK);
293 if (fixup) {
294 regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
295 return;
296 }
297
298/*
299 * Oops. The kernel tried to access some bad page. We'll have to
300 * terminate things with extreme prejudice.
301 */
302 if (user_address == 0)
303 printk(KERN_ALERT "Unable to handle kernel pointer dereference"
304 " at virtual kernel address %p\n", (void *)address);
305 else
306 printk(KERN_ALERT "Unable to handle kernel paging request"
307 " at virtual user address %p\n", (void *)address);
308
309 die("Oops", regs, error_code);
310 do_exit(SIGKILL);
311
312
313/*
314 * We ran out of memory, or some other thing happened to us that made
315 * us unable to handle the page fault gracefully.
316*/
317out_of_memory:
318 up_read(&mm->mmap_sem);
319 if (tsk->pid == 1) {
320 yield();
321 goto survive;
322 }
323 printk("VM: killing process %s\n", tsk->comm);
324 if (regs->psw.mask & PSW_MASK_PSTATE)
325 do_exit(SIGKILL);
326 goto no_context;
327
328do_sigbus:
329 up_read(&mm->mmap_sem);
330
331 /*
332 * Send a sigbus, regardless of whether we were in kernel
333 * or user mode.
334 */
335 tsk->thread.prot_addr = address;
336 tsk->thread.trap_no = error_code;
337 force_sig(SIGBUS, tsk);
338
339 /* Kernel mode? Handle exceptions or die */
340 if (!(regs->psw.mask & PSW_MASK_PSTATE))
341 goto no_context;
342}
343
344void do_protection_exception(struct pt_regs *regs, unsigned long error_code)
345{
346 regs->psw.addr -= (error_code >> 16);
347 do_exception(regs, 4, 1);
348}
349
350void do_dat_exception(struct pt_regs *regs, unsigned long error_code)
351{
352 do_exception(regs, error_code & 0xff, 0);
353}
354
355#ifndef CONFIG_ARCH_S390X
356
357typedef struct _pseudo_wait_t {
358 struct _pseudo_wait_t *next;
359 wait_queue_head_t queue;
360 unsigned long address;
361 int resolved;
362} pseudo_wait_t;
363
364static pseudo_wait_t *pseudo_lock_queue = NULL;
365static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
366
367/*
368 * This routine handles 'pagex' pseudo page faults.
369 */
370asmlinkage void
371do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
372{
373 pseudo_wait_t wait_struct;
374 pseudo_wait_t *ptr, *last, *next;
375 unsigned long address;
376
377 /*
378 * get the failing address
379 * more specific the segment and page table portion of
380 * the address
381 */
382 address = S390_lowcore.trans_exc_code & 0xfffff000;
383
384 if (address & 0x80000000) {
385 /* high bit set -> a page has been swapped in by VM */
386 address &= 0x7fffffff;
387 spin_lock(&pseudo_wait_spinlock);
388 last = NULL;
389 ptr = pseudo_lock_queue;
390 while (ptr != NULL) {
391 next = ptr->next;
392 if (address == ptr->address) {
393 /*
394 * This is one of the processes waiting
395 * for the page. Unchain from the queue.
396 * There can be more than one process
397 * waiting for the same page. VM presents
398 * an initial and a completion interrupt for
399 * every process that tries to access a
400 * page swapped out by VM.
401 */
402 if (last == NULL)
403 pseudo_lock_queue = next;
404 else
405 last->next = next;
406 /* now wake up the process */
407 ptr->resolved = 1;
408 wake_up(&ptr->queue);
409 } else
410 last = ptr;
411 ptr = next;
412 }
413 spin_unlock(&pseudo_wait_spinlock);
414 } else {
415 /* Pseudo page faults in kernel mode is a bad idea */
416 if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
417 /*
418 * VM presents pseudo page faults if the interrupted
419 * state was not disabled for interrupts. So we can
420 * get pseudo page fault interrupts while running
421 * in kernel mode. We simply access the page here
422 * while we are running disabled. VM will then swap
423 * in the page synchronously.
424 */
425 if (check_user_space(regs, error_code) == 0)
426 /* dereference a virtual kernel address */
427 __asm__ __volatile__ (
428 " ic 0,0(%0)"
429 : : "a" (address) : "0");
430 else
431 /* dereference a virtual user address */
432 __asm__ __volatile__ (
433 " la 2,0(%0)\n"
434 " sacf 512\n"
435 " ic 2,0(2)\n"
436 "0:sacf 0\n"
437 ".section __ex_table,\"a\"\n"
438 " .align 4\n"
439 " .long 0b,0b\n"
440 ".previous"
441 : : "a" (address) : "2" );
442
443 return;
444 }
445 /* initialize and add element to pseudo_lock_queue */
446 init_waitqueue_head (&wait_struct.queue);
447 wait_struct.address = address;
448 wait_struct.resolved = 0;
449 spin_lock(&pseudo_wait_spinlock);
450 wait_struct.next = pseudo_lock_queue;
451 pseudo_lock_queue = &wait_struct;
452 spin_unlock(&pseudo_wait_spinlock);
453 /*
454 * The instruction that caused the program check will
455 * be repeated. Don't signal single step via SIGTRAP.
456 */
457 clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
458 /* go to sleep */
459 wait_event(wait_struct.queue, wait_struct.resolved);
460 }
461}
462#endif /* CONFIG_ARCH_S390X */
463
464#ifdef CONFIG_PFAULT
465/*
466 * 'pfault' pseudo page faults routines.
467 */
468static int pfault_disable = 0;
469
470static int __init nopfault(char *str)
471{
472 pfault_disable = 1;
473 return 1;
474}
475
476__setup("nopfault", nopfault);
477
478typedef struct {
479 __u16 refdiagc;
480 __u16 reffcode;
481 __u16 refdwlen;
482 __u16 refversn;
483 __u64 refgaddr;
484 __u64 refselmk;
485 __u64 refcmpmk;
486 __u64 reserved;
487} __attribute__ ((packed)) pfault_refbk_t;
488
489int pfault_init(void)
490{
491 pfault_refbk_t refbk =
492 { 0x258, 0, 5, 2, __LC_CURRENT, 1ULL << 48, 1ULL << 48,
493 __PF_RES_FIELD };
494 int rc;
495
496 if (pfault_disable)
497 return -1;
498 __asm__ __volatile__(
499 " diag %1,%0,0x258\n"
500 "0: j 2f\n"
501 "1: la %0,8\n"
502 "2:\n"
503 ".section __ex_table,\"a\"\n"
504 " .align 4\n"
505#ifndef CONFIG_ARCH_S390X
506 " .long 0b,1b\n"
507#else /* CONFIG_ARCH_S390X */
508 " .quad 0b,1b\n"
509#endif /* CONFIG_ARCH_S390X */
510 ".previous"
511 : "=d" (rc) : "a" (&refbk) : "cc" );
512 __ctl_set_bit(0, 9);
513 return rc;
514}
515
516void pfault_fini(void)
517{
518 pfault_refbk_t refbk =
519 { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
520
521 if (pfault_disable)
522 return;
523 __ctl_clear_bit(0,9);
524 __asm__ __volatile__(
525 " diag %0,0,0x258\n"
526 "0:\n"
527 ".section __ex_table,\"a\"\n"
528 " .align 4\n"
529#ifndef CONFIG_ARCH_S390X
530 " .long 0b,0b\n"
531#else /* CONFIG_ARCH_S390X */
532 " .quad 0b,0b\n"
533#endif /* CONFIG_ARCH_S390X */
534 ".previous"
535 : : "a" (&refbk) : "cc" );
536}
537
538asmlinkage void
539pfault_interrupt(struct pt_regs *regs, __u16 error_code)
540{
541 struct task_struct *tsk;
542 __u16 subcode;
543
544 /*
545 * Get the external interruption subcode & pfault
546 * initial/completion signal bit. VM stores this
547 * in the 'cpu address' field associated with the
548 * external interrupt.
549 */
550 subcode = S390_lowcore.cpu_addr;
551 if ((subcode & 0xff00) != __SUBCODE_MASK)
552 return;
553
554 /*
555 * Get the token (= address of the task structure of the affected task).
556 */
557 tsk = *(struct task_struct **) __LC_PFAULT_INTPARM;
558
559 if (subcode & 0x0080) {
560 /* signal bit is set -> a page has been swapped in by VM */
561 if (xchg(&tsk->thread.pfault_wait, -1) != 0) {
562 /* Initial interrupt was faster than the completion
563 * interrupt. pfault_wait is valid. Set pfault_wait
564 * back to zero and wake up the process. This can
565 * safely be done because the task is still sleeping
566 * and can't procude new pfaults. */
567 tsk->thread.pfault_wait = 0;
568 wake_up_process(tsk);
569 }
570 } else {
571 /* signal bit not set -> a real page is missing. */
572 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
573 if (xchg(&tsk->thread.pfault_wait, 1) != 0) {
574 /* Completion interrupt was faster than the initial
575 * interrupt (swapped in a -1 for pfault_wait). Set
576 * pfault_wait back to zero and exit. This can be
577 * done safely because tsk is running in kernel
578 * mode and can't produce new pfaults. */
579 tsk->thread.pfault_wait = 0;
580 set_task_state(tsk, TASK_RUNNING);
581 } else
582 set_tsk_need_resched(tsk);
583 }
584}
585#endif
586
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
new file mode 100644
index 000000000000..8e723bc7f795
--- /dev/null
+++ b/arch/s390/mm/init.c
@@ -0,0 +1,310 @@
1/*
2 * arch/s390/mm/init.c
3 *
4 * S390 version
5 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Hartmut Penner (hp@de.ibm.com)
7 *
8 * Derived from "arch/i386/mm/init.c"
9 * Copyright (C) 1995 Linus Torvalds
10 */
11
12#include <linux/config.h>
13#include <linux/signal.h>
14#include <linux/sched.h>
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/string.h>
18#include <linux/types.h>
19#include <linux/ptrace.h>
20#include <linux/mman.h>
21#include <linux/mm.h>
22#include <linux/swap.h>
23#include <linux/smp.h>
24#include <linux/init.h>
25#include <linux/pagemap.h>
26#include <linux/bootmem.h>
27
28#include <asm/processor.h>
29#include <asm/system.h>
30#include <asm/uaccess.h>
31#include <asm/pgtable.h>
32#include <asm/pgalloc.h>
33#include <asm/dma.h>
34#include <asm/lowcore.h>
35#include <asm/tlb.h>
36#include <asm/tlbflush.h>
37
38DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
39
40pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
41char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
42
43void diag10(unsigned long addr)
44{
45 if (addr >= 0x7ff00000)
46 return;
47#ifdef __s390x__
48 asm volatile (
49 " sam31\n"
50 " diag %0,%0,0x10\n"
51 "0: sam64\n"
52 ".section __ex_table,\"a\"\n"
53 " .align 8\n"
54 " .quad 0b, 0b\n"
55 ".previous\n"
56 : : "a" (addr));
57#else
58 asm volatile (
59 " diag %0,%0,0x10\n"
60 "0:\n"
61 ".section __ex_table,\"a\"\n"
62 " .align 4\n"
63 " .long 0b, 0b\n"
64 ".previous\n"
65 : : "a" (addr));
66#endif
67}
68
69void show_mem(void)
70{
71 int i, total = 0, reserved = 0;
72 int shared = 0, cached = 0;
73
74 printk("Mem-info:\n");
75 show_free_areas();
76 printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
77 i = max_mapnr;
78 while (i-- > 0) {
79 total++;
80 if (PageReserved(mem_map+i))
81 reserved++;
82 else if (PageSwapCache(mem_map+i))
83 cached++;
84 else if (page_count(mem_map+i))
85 shared += page_count(mem_map+i) - 1;
86 }
87 printk("%d pages of RAM\n",total);
88 printk("%d reserved pages\n",reserved);
89 printk("%d pages shared\n",shared);
90 printk("%d pages swap cached\n",cached);
91}
92
93/* References to section boundaries */
94
95extern unsigned long _text;
96extern unsigned long _etext;
97extern unsigned long _edata;
98extern unsigned long __bss_start;
99extern unsigned long _end;
100
101extern unsigned long __init_begin;
102extern unsigned long __init_end;
103
104/*
105 * paging_init() sets up the page tables
106 */
107
108#ifndef CONFIG_ARCH_S390X
109void __init paging_init(void)
110{
111 pgd_t * pg_dir;
112 pte_t * pg_table;
113 pte_t pte;
114 int i;
115 unsigned long tmp;
116 unsigned long pfn = 0;
117 unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
118 static const int ssm_mask = 0x04000000L;
119
120 /* unmap whole virtual address space */
121
122 pg_dir = swapper_pg_dir;
123
124 for (i=0;i<KERNEL_PGD_PTRS;i++)
125 pmd_clear((pmd_t*)pg_dir++);
126
127 /*
128 * map whole physical memory to virtual memory (identity mapping)
129 */
130
131 pg_dir = swapper_pg_dir;
132
133 while (pfn < max_low_pfn) {
134 /*
135 * pg_table is physical at this point
136 */
137 pg_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
138
139 pg_dir->pgd0 = (_PAGE_TABLE | __pa(pg_table));
140 pg_dir->pgd1 = (_PAGE_TABLE | (__pa(pg_table)+1024));
141 pg_dir->pgd2 = (_PAGE_TABLE | (__pa(pg_table)+2048));
142 pg_dir->pgd3 = (_PAGE_TABLE | (__pa(pg_table)+3072));
143 pg_dir++;
144
145 for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
146 pte = pfn_pte(pfn, PAGE_KERNEL);
147 if (pfn >= max_low_pfn)
148 pte_clear(&init_mm, 0, &pte);
149 set_pte(pg_table, pte);
150 pfn++;
151 }
152 }
153
154 S390_lowcore.kernel_asce = pgdir_k;
155
156 /* enable virtual mapping in kernel mode */
157 __asm__ __volatile__(" LCTL 1,1,%0\n"
158 " LCTL 7,7,%0\n"
159 " LCTL 13,13,%0\n"
160 " SSM %1"
161 : : "m" (pgdir_k), "m" (ssm_mask));
162
163 local_flush_tlb();
164
165 {
166 unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0};
167
168 zones_size[ZONE_DMA] = max_low_pfn;
169 free_area_init(zones_size);
170 }
171 return;
172}
173
174#else /* CONFIG_ARCH_S390X */
175void __init paging_init(void)
176{
177 pgd_t * pg_dir;
178 pmd_t * pm_dir;
179 pte_t * pt_dir;
180 pte_t pte;
181 int i,j,k;
182 unsigned long pfn = 0;
183 unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) |
184 _KERN_REGION_TABLE;
185 static const int ssm_mask = 0x04000000L;
186
187 unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
188 unsigned long dma_pfn, high_pfn;
189
190 dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
191 high_pfn = max_low_pfn;
192
193 if (dma_pfn > high_pfn)
194 zones_size[ZONE_DMA] = high_pfn;
195 else {
196 zones_size[ZONE_DMA] = dma_pfn;
197 zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
198 }
199
200 /* Initialize mem_map[]. */
201 free_area_init(zones_size);
202
203
204 /*
205 * map whole physical memory to virtual memory (identity mapping)
206 */
207
208 pg_dir = swapper_pg_dir;
209
210 for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) {
211
212 if (pfn >= max_low_pfn) {
213 pgd_clear(pg_dir);
214 continue;
215 }
216
217 pm_dir = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE*4);
218 pgd_populate(&init_mm, pg_dir, pm_dir);
219
220 for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) {
221 if (pfn >= max_low_pfn) {
222 pmd_clear(pm_dir);
223 continue;
224 }
225
226 pt_dir = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
227 pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
228
229 for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
230 pte = pfn_pte(pfn, PAGE_KERNEL);
231 if (pfn >= max_low_pfn) {
232 pte_clear(&init_mm, 0, &pte);
233 continue;
234 }
235 set_pte(pt_dir, pte);
236 pfn++;
237 }
238 }
239 }
240
241 S390_lowcore.kernel_asce = pgdir_k;
242
243 /* enable virtual mapping in kernel mode */
244 __asm__ __volatile__("lctlg 1,1,%0\n\t"
245 "lctlg 7,7,%0\n\t"
246 "lctlg 13,13,%0\n\t"
247 "ssm %1"
248 : :"m" (pgdir_k), "m" (ssm_mask));
249
250 local_flush_tlb();
251
252 return;
253}
254#endif /* CONFIG_ARCH_S390X */
255
256void __init mem_init(void)
257{
258 unsigned long codesize, reservedpages, datasize, initsize;
259
260 max_mapnr = num_physpages = max_low_pfn;
261 high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
262
263 /* clear the zero-page */
264 memset(empty_zero_page, 0, PAGE_SIZE);
265
266 /* this will put all low memory onto the freelists */
267 totalram_pages += free_all_bootmem();
268
269 reservedpages = 0;
270
271 codesize = (unsigned long) &_etext - (unsigned long) &_text;
272 datasize = (unsigned long) &_edata - (unsigned long) &_etext;
273 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
274 printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
275 (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
276 max_mapnr << (PAGE_SHIFT-10),
277 codesize >> 10,
278 reservedpages << (PAGE_SHIFT-10),
279 datasize >>10,
280 initsize >> 10);
281}
282
283void free_initmem(void)
284{
285 unsigned long addr;
286
287 addr = (unsigned long)(&__init_begin);
288 for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
289 ClearPageReserved(virt_to_page(addr));
290 set_page_count(virt_to_page(addr), 1);
291 free_page(addr);
292 totalram_pages++;
293 }
294 printk ("Freeing unused kernel memory: %ldk freed\n",
295 ((unsigned long)&__init_end - (unsigned long)&__init_begin) >> 10);
296}
297
298#ifdef CONFIG_BLK_DEV_INITRD
299void free_initrd_mem(unsigned long start, unsigned long end)
300{
301 if (start < end)
302 printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
303 for (; start < end; start += PAGE_SIZE) {
304 ClearPageReserved(virt_to_page(start));
305 set_page_count(virt_to_page(start), 1);
306 free_page(start);
307 totalram_pages++;
308 }
309}
310#endif
diff --git a/arch/s390/mm/ioremap.c b/arch/s390/mm/ioremap.c
new file mode 100644
index 000000000000..c6c39d868bc8
--- /dev/null
+++ b/arch/s390/mm/ioremap.c
@@ -0,0 +1,138 @@
1/*
2 * arch/s390/mm/ioremap.c
3 *
4 * S390 version
5 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Hartmut Penner (hp@de.ibm.com)
7 *
8 * Derived from "arch/i386/mm/extable.c"
9 * (C) Copyright 1995 1996 Linus Torvalds
10 *
11 * Re-map IO memory to kernel address space so that we can access it.
12 * This is needed for high PCI addresses that aren't mapped in the
13 * 640k-1MB IO memory area on PC's
14 */
15
16#include <linux/vmalloc.h>
17#include <linux/mm.h>
18#include <asm/io.h>
19#include <asm/pgalloc.h>
20#include <asm/cacheflush.h>
21#include <asm/tlbflush.h>
22
23static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
24 unsigned long phys_addr, unsigned long flags)
25{
26 unsigned long end;
27 unsigned long pfn;
28
29 address &= ~PMD_MASK;
30 end = address + size;
31 if (end > PMD_SIZE)
32 end = PMD_SIZE;
33 if (address >= end)
34 BUG();
35 pfn = phys_addr >> PAGE_SHIFT;
36 do {
37 if (!pte_none(*pte)) {
38 printk("remap_area_pte: page already exists\n");
39 BUG();
40 }
41 set_pte(pte, pfn_pte(pfn, __pgprot(flags)));
42 address += PAGE_SIZE;
43 pfn++;
44 pte++;
45 } while (address && (address < end));
46}
47
48static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
49 unsigned long phys_addr, unsigned long flags)
50{
51 unsigned long end;
52
53 address &= ~PGDIR_MASK;
54 end = address + size;
55 if (end > PGDIR_SIZE)
56 end = PGDIR_SIZE;
57 phys_addr -= address;
58 if (address >= end)
59 BUG();
60 do {
61 pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
62 if (!pte)
63 return -ENOMEM;
64 remap_area_pte(pte, address, end - address, address + phys_addr, flags);
65 address = (address + PMD_SIZE) & PMD_MASK;
66 pmd++;
67 } while (address && (address < end));
68 return 0;
69}
70
71static int remap_area_pages(unsigned long address, unsigned long phys_addr,
72 unsigned long size, unsigned long flags)
73{
74 int error;
75 pgd_t * dir;
76 unsigned long end = address + size;
77
78 phys_addr -= address;
79 dir = pgd_offset(&init_mm, address);
80 flush_cache_all();
81 if (address >= end)
82 BUG();
83 spin_lock(&init_mm.page_table_lock);
84 do {
85 pmd_t *pmd;
86 pmd = pmd_alloc(&init_mm, dir, address);
87 error = -ENOMEM;
88 if (!pmd)
89 break;
90 if (remap_area_pmd(pmd, address, end - address,
91 phys_addr + address, flags))
92 break;
93 error = 0;
94 address = (address + PGDIR_SIZE) & PGDIR_MASK;
95 dir++;
96 } while (address && (address < end));
97 spin_unlock(&init_mm.page_table_lock);
98 flush_tlb_all();
99 return 0;
100}
101
102/*
103 * Generic mapping function (not visible outside):
104 */
105
106/*
107 * Remap an arbitrary physical address space into the kernel virtual
108 * address space. Needed when the kernel wants to access high addresses
109 * directly.
110 */
111void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
112{
113 void * addr;
114 struct vm_struct * area;
115
116 if (phys_addr < virt_to_phys(high_memory))
117 return phys_to_virt(phys_addr);
118 if (phys_addr & ~PAGE_MASK)
119 return NULL;
120 size = PAGE_ALIGN(size);
121 if (!size || size > phys_addr + size)
122 return NULL;
123 area = get_vm_area(size, VM_IOREMAP);
124 if (!area)
125 return NULL;
126 addr = area->addr;
127 if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
128 vfree(addr);
129 return NULL;
130 }
131 return addr;
132}
133
134void iounmap(void *addr)
135{
136 if (addr > high_memory)
137 vfree(addr);
138}
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
new file mode 100644
index 000000000000..fb187e5a54b4
--- /dev/null
+++ b/arch/s390/mm/mmap.c
@@ -0,0 +1,86 @@
1/*
2 * linux/arch/s390/mm/mmap.c
3 *
4 * flexible mmap layout support
5 *
6 * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
7 * All Rights Reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 *
24 * Started by Ingo Molnar <mingo@elte.hu>
25 */
26
27#include <linux/personality.h>
28#include <linux/mm.h>
29#include <linux/module.h>
30
31/*
32 * Top of mmap area (just below the process stack).
33 *
34 * Leave an at least ~128 MB hole.
35 */
36#define MIN_GAP (128*1024*1024)
37#define MAX_GAP (TASK_SIZE/6*5)
38
39static inline unsigned long mmap_base(void)
40{
41 unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur;
42
43 if (gap < MIN_GAP)
44 gap = MIN_GAP;
45 else if (gap > MAX_GAP)
46 gap = MAX_GAP;
47
48 return TASK_SIZE - (gap & PAGE_MASK);
49}
50
51static inline int mmap_is_legacy(void)
52{
53#ifdef CONFIG_ARCH_S390X
54 /*
55 * Force standard allocation for 64 bit programs.
56 */
57 if (!test_thread_flag(TIF_31BIT))
58 return 1;
59#endif
60 return sysctl_legacy_va_layout ||
61 (current->personality & ADDR_COMPAT_LAYOUT) ||
62 current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY;
63}
64
65/*
66 * This function, called very early during the creation of a new
67 * process VM image, sets up which VM layout function to use:
68 */
69void arch_pick_mmap_layout(struct mm_struct *mm)
70{
71 /*
72 * Fall back to the standard layout if the personality
73 * bit is set, or if the expected stack growth is unlimited:
74 */
75 if (mmap_is_legacy()) {
76 mm->mmap_base = TASK_UNMAPPED_BASE;
77 mm->get_unmapped_area = arch_get_unmapped_area;
78 mm->unmap_area = arch_unmap_area;
79 } else {
80 mm->mmap_base = mmap_base();
81 mm->get_unmapped_area = arch_get_unmapped_area_topdown;
82 mm->unmap_area = arch_unmap_area_topdown;
83 }
84}
85EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
86
diff --git a/arch/s390/oprofile/Kconfig b/arch/s390/oprofile/Kconfig
new file mode 100644
index 000000000000..208220a5f23f
--- /dev/null
+++ b/arch/s390/oprofile/Kconfig
@@ -0,0 +1,22 @@
1
2menu "Profiling support"
3
4config PROFILING
5 bool "Profiling support"
6 help
7 Say Y here to enable profiling support mechanisms used by
8 profilers such as readprofile or OProfile.
9
10
11config OPROFILE
12 tristate "OProfile system profiling"
13 depends on PROFILING
14 help
15 OProfile is a profiling system capable of profiling the
16 whole system, include the kernel, kernel modules, libraries,
17 and applications.
18
19 If unsure, say N.
20
21endmenu
22
diff --git a/arch/s390/oprofile/Makefile b/arch/s390/oprofile/Makefile
new file mode 100644
index 000000000000..ec349276258a
--- /dev/null
+++ b/arch/s390/oprofile/Makefile
@@ -0,0 +1,9 @@
1obj-$(CONFIG_OPROFILE) += oprofile.o
2
3DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
4 oprof.o cpu_buffer.o buffer_sync.o \
5 event_buffer.o oprofile_files.o \
6 oprofilefs.o oprofile_stats.o \
7 timer_int.o )
8
9oprofile-y := $(DRIVER_OBJS) init.o
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c
new file mode 100644
index 000000000000..a65ead0e200a
--- /dev/null
+++ b/arch/s390/oprofile/init.c
@@ -0,0 +1,22 @@
1/**
2 * arch/s390/oprofile/init.c
3 *
4 * S390 Version
5 * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Thomas Spatzier (tspat@de.ibm.com)
7 *
8 * @remark Copyright 2002 OProfile authors
9 */
10
11#include <linux/oprofile.h>
12#include <linux/init.h>
13#include <linux/errno.h>
14
15int __init oprofile_arch_init(struct oprofile_operations* ops)
16{
17 return -ENODEV;
18}
19
20void oprofile_arch_exit(void)
21{
22}