summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2001-03-09 20:33:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2001-03-09 20:33:35 +0000
commit116674acc97ba75a720329996877077d988443a2 (patch)
tree6a3f2ff0b612ae2ee8a3f3509370c9e6333a53b3 /arch
parent71118c319fcae4a138f16e35b4f7e0a6d53ce2ca (diff)
Merge with Linux 2.4.2.
Diffstat (limited to 'arch')
-rw-r--r--arch/alpha/kernel/Makefile4
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c6
-rw-r--r--arch/alpha/kernel/irq.c2
-rw-r--r--arch/alpha/kernel/irq_alpha.c2
-rw-r--r--arch/alpha/kernel/osf_sys.c4
-rw-r--r--arch/alpha/kernel/pci-noop.c104
-rw-r--r--arch/alpha/kernel/process.c16
-rw-r--r--arch/alpha/kernel/ptrace.c2
-rw-r--r--arch/alpha/kernel/setup.c2
-rw-r--r--arch/alpha/kernel/smc37c669.c2
-rw-r--r--arch/alpha/kernel/smc37c93x.c2
-rw-r--r--arch/alpha/kernel/smp.c2
-rw-r--r--arch/alpha/kernel/sys_ruffian.c74
-rw-r--r--arch/alpha/kernel/traps.c2
-rw-r--r--arch/alpha/lib/Makefile2
-rw-r--r--arch/alpha/lib/clear_page.S39
-rw-r--r--arch/alpha/lib/copy_page.S49
-rw-r--r--arch/alpha/lib/ev6-clear_page.S54
-rw-r--r--arch/alpha/lib/ev6-copy_page.S203
-rw-r--r--arch/arm/Makefile120
-rw-r--r--arch/arm/boot/Makefile13
-rw-r--r--arch/arm/boot/bootp/Makefile3
-rw-r--r--arch/arm/boot/bootp/init.S67
-rw-r--r--arch/arm/boot/compressed/Makefile2
-rw-r--r--arch/arm/boot/compressed/head-ftvpci.S7
-rw-r--r--arch/arm/boot/compressed/head-l7200.S13
-rw-r--r--arch/arm/boot/compressed/head-sa1100.S8
-rw-r--r--arch/arm/boot/compressed/head-shark.S121
-rw-r--r--arch/arm/boot/compressed/head.S8
-rw-r--r--arch/arm/boot/compressed/ofw-shark.c216
-rw-r--r--arch/arm/boot/compressed/setup-sa1100.S14
-rw-r--r--arch/arm/boot/compressed/vmlinux.lds.in5
-rw-r--r--arch/arm/kernel/Makefile42
-rw-r--r--arch/arm/kernel/bios32.c32
-rw-r--r--arch/arm/kernel/dma-arc.c16
-rw-r--r--arch/arm/kernel/dma-rpc.c68
-rw-r--r--arch/arm/kernel/dma.c2
-rw-r--r--arch/arm/kernel/ecard.c2
-rw-r--r--arch/arm/kernel/entry-armo.S6
-rw-r--r--arch/arm/kernel/fiq.c22
-rw-r--r--arch/arm/kernel/irq.c2
-rw-r--r--arch/arm/kernel/process.c23
-rw-r--r--arch/arm/kernel/sys_arm.c2
-rw-r--r--arch/arm/kernel/time.c27
-rw-r--r--arch/arm/kernel/traps.c4
-rw-r--r--arch/arm/lib/Makefile76
-rw-r--r--arch/arm/lib/io-acorn.S24
-rw-r--r--arch/arm/lib/io-pcio.S28
-rw-r--r--arch/arm/lib/io-readsb.S5
-rw-r--r--arch/arm/lib/io-readsl-armv3.S76
-rw-r--r--arch/arm/lib/io-readsl-armv4.S (renamed from arch/arm/lib/io-readsl.S)5
-rw-r--r--arch/arm/lib/io-readsw-armv3.S5
-rw-r--r--arch/arm/lib/io-readsw-armv4.S9
-rw-r--r--arch/arm/lib/io-writesb.S13
-rw-r--r--arch/arm/lib/io-writesl.S2
-rw-r--r--arch/arm/lib/io-writesw-armv3.S6
-rw-r--r--arch/arm/lib/io-writesw-armv4.S45
-rw-r--r--arch/arm/mach-sa1100/Makefile11
-rw-r--r--arch/arm/mach-sa1100/hw.c58
-rw-r--r--arch/arm/mach-shark/Makefile13
-rw-r--r--arch/arm/mm/Makefile28
-rw-r--r--arch/arm/mm/fault-armo.c10
-rw-r--r--arch/arm/mm/fault-armv.c145
-rw-r--r--arch/arm/mm/fault-common.c47
-rw-r--r--arch/arm/mm/init.c28
-rw-r--r--arch/arm/mm/mm-armv.c2
-rw-r--r--arch/arm/mm/proc-arm6,7.S12
-rw-r--r--arch/arm/mm/proc-arm720.S20
-rw-r--r--arch/arm/mm/proc-arm920.S6
-rw-r--r--arch/arm/mm/proc-sa110.S4
-rw-r--r--arch/arm/nwfpe/Makefile34
-rw-r--r--arch/arm/vmlinux-armo.lds.in2
-rw-r--r--arch/arm/vmlinux-armv.lds.in2
-rw-r--r--arch/cris/Makefile96
-rw-r--r--arch/cris/README.mm241
-rw-r--r--arch/cris/boot/Makefile14
-rw-r--r--arch/cris/boot/compressed/Makefile37
-rw-r--r--arch/cris/boot/compressed/README25
-rw-r--r--arch/cris/boot/compressed/decompress.ld26
-rw-r--r--arch/cris/boot/compressed/head.S100
-rw-r--r--arch/cris/boot/compressed/misc.c260
-rw-r--r--arch/cris/config.in223
-rw-r--r--arch/cris/cris.ld81
-rw-r--r--arch/cris/defconfig319
-rw-r--r--arch/cris/drivers/Config.in49
-rw-r--r--arch/cris/drivers/Makefile14
-rw-r--r--arch/cris/drivers/axisflashmap.c311
-rw-r--r--arch/cris/drivers/ethernet.c1041
-rw-r--r--arch/cris/drivers/ide.c818
-rw-r--r--arch/cris/drivers/serial.c3039
-rw-r--r--arch/cris/drivers/serial.h106
-rw-r--r--arch/cris/kernel/Makefile25
-rw-r--r--arch/cris/kernel/debugport.c242
-rw-r--r--arch/cris/kernel/entry.S738
-rw-r--r--arch/cris/kernel/head.S519
-rw-r--r--arch/cris/kernel/hexify.c31
-rw-r--r--arch/cris/kernel/irq.c467
-rw-r--r--arch/cris/kernel/kgdb.c1540
-rw-r--r--arch/cris/kernel/ksyms.c2
-rw-r--r--arch/cris/kernel/process.c327
-rw-r--r--arch/cris/kernel/ptrace.c340
-rw-r--r--arch/cris/kernel/semaphore.c238
-rw-r--r--arch/cris/kernel/setup.c264
-rw-r--r--arch/cris/kernel/shadows.c20
-rw-r--r--arch/cris/kernel/signal.c667
-rw-r--r--arch/cris/kernel/sys_cris.c201
-rw-r--r--arch/cris/kernel/time.c453
-rw-r--r--arch/cris/kernel/traps.c167
-rw-r--r--arch/cris/lib/Makefile11
-rw-r--r--arch/cris/lib/checksum.S113
-rw-r--r--arch/cris/lib/checksumcopy.S120
-rw-r--r--arch/cris/lib/dmacopy.c43
-rw-r--r--arch/cris/lib/memset.c245
-rw-r--r--arch/cris/lib/old_checksum.c127
-rw-r--r--arch/cris/lib/string.c223
-rw-r--r--arch/cris/lib/usercopy.c501
-rw-r--r--arch/cris/mm/Makefile13
-rw-r--r--arch/cris/mm/extable.c55
-rw-r--r--arch/cris/mm/fault.c390
-rw-r--r--arch/cris/mm/init.c506
-rw-r--r--arch/cris/mm/tlb.c301
-rw-r--r--arch/i386/boot/compressed/misc.c1
-rw-r--r--arch/i386/defconfig7
-rw-r--r--arch/i386/kernel/apm.c2
-rw-r--r--arch/i386/kernel/dmi_scan.c50
-rw-r--r--arch/i386/kernel/head.S2
-rw-r--r--arch/i386/kernel/i386_ksyms.c1
-rw-r--r--arch/i386/kernel/i387.c4
-rw-r--r--arch/i386/kernel/i8259.c2
-rw-r--r--arch/i386/kernel/io_apic.c11
-rw-r--r--arch/i386/kernel/irq.c3
-rw-r--r--arch/i386/kernel/microcode.c2
-rw-r--r--arch/i386/kernel/mtrr.c2
-rw-r--r--arch/i386/kernel/pci-irq.c2
-rw-r--r--arch/i386/kernel/pci-pc.c63
-rw-r--r--arch/i386/kernel/process.c2
-rw-r--r--arch/i386/kernel/setup.c45
-rw-r--r--arch/i386/kernel/signal.c1
-rw-r--r--arch/i386/kernel/smp.c2
-rw-r--r--arch/i386/kernel/smpboot.c3
-rw-r--r--arch/i386/kernel/traps.c5
-rw-r--r--arch/i386/kernel/visws_apic.c2
-rw-r--r--arch/i386/mm/extable.c19
-rw-r--r--arch/i386/mm/fault.c2
-rw-r--r--arch/ia64/config.in6
-rw-r--r--arch/ia64/ia32/sys_ia32.c2
-rw-r--r--arch/ia64/kernel/irq.c2
-rw-r--r--arch/ia64/kernel/irq_ia64.c2
-rw-r--r--arch/ia64/kernel/palinfo.c3
-rw-r--r--arch/ia64/kernel/pci.c2
-rw-r--r--arch/ia64/kernel/ptrace.c2
-rw-r--r--arch/ia64/kernel/unwind.c2
-rw-r--r--arch/ia64/lib/copy_user.S2
-rw-r--r--arch/ia64/sn/io/klconflib.c2
-rw-r--r--arch/ia64/sn/io/klgraph_hack.c2
-rw-r--r--arch/ia64/sn/io/l1.c4
-rw-r--r--arch/ia64/sn/io/pcibr.c6
-rw-r--r--arch/ia64/sn/io/xbow.c2
-rw-r--r--arch/ia64/sn/io/xtalk.c2
-rw-r--r--arch/m68k/atari/hades-pci.c4
-rw-r--r--arch/m68k/atari/stram.c2
-rw-r--r--arch/m68k/bvme6000/rtc.c2
-rw-r--r--arch/m68k/ifpsp060/src/fplsp.S4
-rw-r--r--arch/m68k/ifpsp060/src/fpsp.S2
-rw-r--r--arch/m68k/ifpsp060/src/isp.S2
-rw-r--r--arch/m68k/ifpsp060/src/pfpsp.S2
-rw-r--r--arch/m68k/kernel/bios32.c2
-rw-r--r--arch/m68k/kernel/entry.S2
-rw-r--r--arch/m68k/kernel/process.c2
-rw-r--r--arch/m68k/mac/misc.c2
-rw-r--r--arch/m68k/mac/oss.c2
-rw-r--r--arch/m68k/math-emu/fp_cond.S2
-rw-r--r--arch/m68k/math-emu/fp_decode.h2
-rw-r--r--arch/m68k/math-emu/fp_emu.h2
-rw-r--r--arch/m68k/math-emu/fp_entry.S2
-rw-r--r--arch/m68k/math-emu/fp_move.S2
-rw-r--r--arch/m68k/math-emu/fp_movem.S2
-rw-r--r--arch/m68k/math-emu/fp_scan.S2
-rw-r--r--arch/m68k/math-emu/fp_util.S2
-rw-r--r--arch/m68k/mm/kmap.c2
-rw-r--r--arch/m68k/mm/memory.c2
-rw-r--r--arch/m68k/mvme16x/rtc.c2
-rw-r--r--arch/mips/baget/irq.c2
-rw-r--r--arch/mips/baget/vacserial.c2
-rw-r--r--arch/mips/dec/irq.c2
-rw-r--r--arch/mips/defconfig1
-rw-r--r--arch/mips/defconfig-decstation1
-rw-r--r--arch/mips/defconfig-ip221
-rw-r--r--arch/mips/defconfig-rm2001
-rw-r--r--arch/mips/galileo-boards/ev64120/irq.c2
-rw-r--r--arch/mips/galileo-boards/ev64120/pci_bios.c2
-rw-r--r--arch/mips/galileo-boards/ev96100/irq.c2
-rw-r--r--arch/mips/gt64120/common/irq.c2
-rw-r--r--arch/mips/gt64120/common/pci.c2
-rw-r--r--arch/mips/gt64120/momenco_ocelot/irq.c2
-rw-r--r--arch/mips/kernel/irixelf.c2
-rw-r--r--arch/mips/kernel/irq.c2
-rw-r--r--arch/mips/kernel/old-irq.c2
-rw-r--r--arch/mips/kernel/process.c2
-rw-r--r--arch/mips/kernel/setup.c2
-rw-r--r--arch/mips/kernel/sysirix.c2
-rw-r--r--arch/mips/mm/extable.c19
-rw-r--r--arch/mips/sgi/kernel/indy_int.c2
-rw-r--r--arch/mips64/defconfig6
-rw-r--r--arch/mips64/defconfig-ip225
-rw-r--r--arch/mips64/defconfig-ip276
-rw-r--r--arch/mips64/kernel/process.c2
-rw-r--r--arch/mips64/kernel/setup.c2
-rw-r--r--arch/mips64/mm/extable.c19
-rw-r--r--arch/mips64/mm/fault.c2
-rw-r--r--arch/mips64/sgi-ip22/ip22-int.c2
-rw-r--r--arch/mips64/sgi-ip27/ip27-irq.c2
-rw-r--r--arch/parisc/kernel/ccio-dma.c2
-rw-r--r--arch/parisc/kernel/iosapic.c2
-rw-r--r--arch/parisc/kernel/irq.c2
-rw-r--r--arch/parisc/kernel/lba_pci.c2
-rw-r--r--arch/parisc/kernel/pci-dma.c2
-rw-r--r--arch/parisc/kernel/process.c2
-rw-r--r--arch/parisc/kernel/sba_iommu.c2
-rw-r--r--arch/parisc/kernel/setup.c2
-rw-r--r--arch/parisc/mm/kmap.c2
-rw-r--r--arch/ppc/8260_io/enet.c2
-rw-r--r--arch/ppc/8260_io/fcc_enet.c4
-rw-r--r--arch/ppc/8260_io/uart.c2
-rw-r--r--arch/ppc/8xx_io/commproc.h2
-rw-r--r--arch/ppc/8xx_io/enet.c2
-rw-r--r--arch/ppc/8xx_io/fec.c6
-rw-r--r--arch/ppc/8xx_io/uart.c2
-rw-r--r--arch/ppc/amiga/amiints.c2
-rw-r--r--arch/ppc/kernel/checks.c2
-rw-r--r--arch/ppc/kernel/chrp_setup.c2
-rw-r--r--arch/ppc/kernel/idle.c2
-rw-r--r--arch/ppc/kernel/irq.c2
-rw-r--r--arch/ppc/kernel/m8260_setup.c2
-rw-r--r--arch/ppc/kernel/m8xx_setup.c2
-rw-r--r--arch/ppc/kernel/pmac_pic.c2
-rw-r--r--arch/ppc/kernel/pmac_setup.c2
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c1
-rw-r--r--arch/ppc/kernel/prep_nvram.c2
-rw-r--r--arch/ppc/kernel/prep_setup.c2
-rw-r--r--arch/ppc/kernel/process.c2
-rw-r--r--arch/ppc/kernel/residual.c2
-rw-r--r--arch/ppc/kernel/setup.c1
-rw-r--r--arch/ppc/kernel/softemu8xx.c2
-rw-r--r--arch/ppc/kernel/traps.c2
-rw-r--r--arch/s390/Makefile1
-rw-r--r--arch/s390/boot/Makefile3
-rw-r--r--arch/s390/boot/ipldump.S2
-rw-r--r--arch/s390/boot/ipleckd.S40
-rw-r--r--arch/s390/config.in17
-rw-r--r--arch/s390/defconfig87
-rw-r--r--arch/s390/kernel/Makefile42
-rw-r--r--arch/s390/kernel/cpcmd.c8
-rw-r--r--arch/s390/kernel/debug.c1167
-rw-r--r--arch/s390/kernel/ebcdic.c153
-rw-r--r--arch/s390/kernel/entry.S441
-rw-r--r--arch/s390/kernel/head.S645
-rw-r--r--arch/s390/kernel/irq.c10
-rw-r--r--arch/s390/kernel/mathemu.c575
-rw-r--r--arch/s390/kernel/process.c238
-rw-r--r--arch/s390/kernel/ptrace.c52
-rw-r--r--arch/s390/kernel/reipl.S17
-rw-r--r--arch/s390/kernel/s390_ext.c77
-rw-r--r--arch/s390/kernel/s390_ksyms.c80
-rw-r--r--arch/s390/kernel/s390dyn.c36
-rw-r--r--arch/s390/kernel/s390fpu.c5
-rw-r--r--arch/s390/kernel/s390io.c4605
-rw-r--r--arch/s390/kernel/s390mach.c157
-rw-r--r--arch/s390/kernel/semaphore.c2
-rw-r--r--arch/s390/kernel/setup.c65
-rw-r--r--arch/s390/kernel/signal.c83
-rw-r--r--arch/s390/kernel/smp.c283
-rw-r--r--arch/s390/kernel/sys_s390.c26
-rw-r--r--arch/s390/kernel/time.c14
-rw-r--r--arch/s390/kernel/traps.c322
-rw-r--r--arch/s390/lib/Makefile10
-rw-r--r--arch/s390/lib/delay.c37
-rw-r--r--arch/s390/lib/strcmp.S4
-rw-r--r--arch/s390/lib/strncpy.S6
-rw-r--r--arch/s390/lib/uaccess.S51
-rw-r--r--arch/s390/mm/Makefile3
-rw-r--r--arch/s390/mm/fault.c188
-rw-r--r--arch/s390/mm/init.c66
-rw-r--r--arch/s390/mm/ioremap.c4
-rw-r--r--arch/s390/tools/dasdfmt/Makefile2
-rw-r--r--arch/s390/tools/dasdfmt/dasdfmt.828
-rw-r--r--arch/s390/tools/dasdfmt/dasdfmt.c264
-rw-r--r--arch/s390/tools/silo/Makefile6
-rw-r--r--arch/s390/tools/silo/silo.c4
-rw-r--r--arch/s390/vmlinux.lds4
-rw-r--r--arch/s390x/Makefile70
-rw-r--r--arch/s390x/boot/Makefile37
-rw-r--r--arch/s390x/boot/ipldump.S178
-rw-r--r--arch/s390x/boot/ipleckd.S303
-rw-r--r--arch/s390x/boot/iplfba.S131
-rw-r--r--arch/s390x/config.in73
-rw-r--r--arch/s390x/defconfig219
-rw-r--r--arch/s390x/kernel/Makefile38
-rw-r--r--arch/s390x/kernel/binfmt_elf32.c203
-rw-r--r--arch/s390x/kernel/bitmap.S37
-rw-r--r--arch/s390x/kernel/cpcmd.c49
-rw-r--r--arch/s390x/kernel/cpcmd.h14
-rw-r--r--arch/s390x/kernel/cpprintk.c25
-rw-r--r--arch/s390x/kernel/debug.c1167
-rw-r--r--arch/s390x/kernel/ebcdic.c391
-rw-r--r--arch/s390x/kernel/entry.S868
-rw-r--r--arch/s390x/kernel/exec32.c85
-rw-r--r--arch/s390x/kernel/gdb-stub.c575
-rw-r--r--arch/s390x/kernel/head.S598
-rw-r--r--arch/s390x/kernel/ieee.h90
-rw-r--r--arch/s390x/kernel/init_task.c32
-rw-r--r--arch/s390x/kernel/ioctl32.c563
-rw-r--r--arch/s390x/kernel/irq.c423
-rw-r--r--arch/s390x/kernel/irqextras390.c35
-rw-r--r--arch/s390x/kernel/linux32.c4326
-rw-r--r--arch/s390x/kernel/linux32.h246
-rw-r--r--arch/s390x/kernel/lowcore.S28
-rw-r--r--arch/s390x/kernel/mathemu.c920
-rw-r--r--arch/s390x/kernel/process.c516
-rw-r--r--arch/s390x/kernel/ptrace.c613
-rw-r--r--arch/s390x/kernel/reipl.S94
-rw-r--r--arch/s390x/kernel/s390_ext.c77
-rw-r--r--arch/s390x/kernel/s390_ksyms.c157
-rw-r--r--arch/s390x/kernel/s390fpu.c87
-rw-r--r--arch/s390x/kernel/semaphore.c302
-rw-r--r--arch/s390x/kernel/setup.c380
-rw-r--r--arch/s390x/kernel/signal.c595
-rw-r--r--arch/s390x/kernel/signal32.c725
-rw-r--r--arch/s390x/kernel/smp.c760
-rw-r--r--arch/s390x/kernel/sys_s390.c205
-rw-r--r--arch/s390x/kernel/time.c258
-rw-r--r--arch/s390x/kernel/traps.c248
-rw-r--r--arch/s390x/kernel/wrapper32.S1071
-rw-r--r--arch/s390x/lib/Makefile18
-rw-r--r--arch/s390x/lib/checksum.c40
-rw-r--r--arch/s390x/lib/delay.c50
-rw-r--r--arch/s390x/lib/memset.S30
-rw-r--r--arch/s390x/lib/strcmp.S27
-rw-r--r--arch/s390x/lib/strncpy.S30
-rw-r--r--arch/s390x/lib/uaccess.S45
-rw-r--r--arch/s390x/mm/Makefile14
-rw-r--r--arch/s390x/mm/extable.c61
-rw-r--r--arch/s390x/mm/fault.c266
-rw-r--r--arch/s390x/mm/init.c405
-rw-r--r--arch/s390x/mm/ioremap.c129
-rw-r--r--arch/s390x/tools/dasdfmt/Makefile9
-rw-r--r--arch/s390x/tools/dasdfmt/dasdfmt.868
-rw-r--r--arch/s390x/tools/dasdfmt/dasdfmt.c830
-rw-r--r--arch/s390x/tools/silo/Makefile15
-rw-r--r--arch/s390x/tools/silo/cfg.c373
-rw-r--r--arch/s390x/tools/silo/cfg.h58
-rw-r--r--arch/s390x/tools/silo/silo.c573
-rw-r--r--arch/s390x/tools/silo/silo.conf7
-rw-r--r--arch/s390x/vmlinux.lds78
-rw-r--r--arch/sh/kernel/irq.c2
-rw-r--r--arch/sh/kernel/process.c2
-rw-r--r--arch/sh/kernel/setup.c2
-rw-r--r--arch/sparc/config.in6
-rw-r--r--arch/sparc/kernel/ebus.c4
-rw-r--r--arch/sparc/kernel/ioport.c6
-rw-r--r--arch/sparc/kernel/irq.c4
-rw-r--r--arch/sparc/kernel/pcic.c4
-rw-r--r--arch/sparc/kernel/process.c4
-rw-r--r--arch/sparc/kernel/ptrace.c2
-rw-r--r--arch/sparc/kernel/setup.c4
-rw-r--r--arch/sparc/kernel/sun4c_irq.c2
-rw-r--r--arch/sparc/kernel/sun4d_irq.c4
-rw-r--r--arch/sparc/kernel/sun4d_smp.c6
-rw-r--r--arch/sparc/kernel/sun4m_irq.c2
-rw-r--r--arch/sparc/kernel/sun4m_smp.c4
-rw-r--r--arch/sparc/kernel/sys_sunos.c4
-rw-r--r--arch/sparc/mm/io-unit.c4
-rw-r--r--arch/sparc/mm/iommu.c4
-rw-r--r--arch/sparc/mm/srmmu.c4
-rw-r--r--arch/sparc/mm/sun4c.c2
-rw-r--r--arch/sparc64/config.in8
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c2
-rw-r--r--arch/sparc64/kernel/ebus.c4
-rw-r--r--arch/sparc64/kernel/ioctl32.c6
-rw-r--r--arch/sparc64/kernel/irq.c4
-rw-r--r--arch/sparc64/kernel/pci_common.c4
-rw-r--r--arch/sparc64/kernel/pci_psycho.c4
-rw-r--r--arch/sparc64/kernel/pci_sabre.c4
-rw-r--r--arch/sparc64/kernel/pci_schizo.c4
-rw-r--r--arch/sparc64/kernel/process.c4
-rw-r--r--arch/sparc64/kernel/ptrace.c2
-rw-r--r--arch/sparc64/kernel/sbus.c4
-rw-r--r--arch/sparc64/kernel/setup.c4
-rw-r--r--arch/sparc64/kernel/starfire.c4
-rw-r--r--arch/sparc64/kernel/sys_sparc.c4
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c4
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c4
-rw-r--r--arch/sparc64/kernel/traps.c26
-rw-r--r--arch/sparc64/mm/init.c4
-rw-r--r--arch/sparc64/mm/modutil.c4
-rw-r--r--arch/sparc64/solaris/fs.c4
-rw-r--r--arch/sparc64/solaris/socket.c4
-rw-r--r--arch/sparc64/solaris/socksys.c4
398 files changed, 42198 insertions, 7178 deletions
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index abc04cca2..08ec1d613 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -30,9 +30,7 @@ ifdef CONFIG_VGA_HOSE
obj-y += console.o
endif
-
obj-$(CONFIG_SMP) += smp.o irq_smp.o
-
obj-$(CONFIG_PCI) += pci.o pci_iommu.o
ifdef CONFIG_ALPHA_GENERIC
@@ -76,7 +74,7 @@ obj-y += sys_eb64p.o
endif
obj-$(CONFIG_ALPHA_EIGER) += sys_eiger.o
-obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o
+obj-$(CONFIG_ALPHA_JENSEN) += sys_jensen.o pci-noop.o
obj-$(CONFIG_ALPHA_MIATA) += sys_miata.o
obj-$(CONFIG_ALPHA_MIKASA) += sys_mikasa.o
obj-$(CONFIG_ALPHA_NAUTILUS) += sys_nautilus.o
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index 17285ac26..d7bf13ec3 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -98,9 +98,13 @@ EXPORT_SYMBOL(__memcpy);
EXPORT_SYMBOL(__memset);
EXPORT_SYMBOL(__memsetw);
EXPORT_SYMBOL(__constant_c_memset);
+EXPORT_SYMBOL(copy_page);
+EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(__direct_map_base);
EXPORT_SYMBOL(__direct_map_size);
+
+#ifdef CONFIG_PCI
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
EXPORT_SYMBOL(pci_map_single);
@@ -108,6 +112,7 @@ EXPORT_SYMBOL(pci_unmap_single);
EXPORT_SYMBOL(pci_map_sg);
EXPORT_SYMBOL(pci_unmap_sg);
EXPORT_SYMBOL(pci_dma_supported);
+#endif
EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(dump_fpu);
@@ -166,6 +171,7 @@ EXPORT_SYMBOL(__down_failed_interruptible);
EXPORT_SYMBOL(__up_wakeup);
EXPORT_SYMBOL(down);
EXPORT_SYMBOL(down_interruptible);
+EXPORT_SYMBOL(down_trylock);
EXPORT_SYMBOL(up);
EXPORT_SYMBOL(__down_read_failed);
EXPORT_SYMBOL(__down_write_failed);
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index 080e48e43..825eaf2d5 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -18,7 +18,7 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/irq.h>
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index 59f102496..91e99f573 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -18,7 +18,7 @@
unsigned long __irq_attempt[NR_IRQS];
#endif
-/* Hack minimum IPL during interupt processing for broken hardware. */
+/* Hack minimum IPL during interrupt processing for broken hardware. */
#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
int __min_ipl;
#endif
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index cd28b07fc..6159457d9 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -19,7 +19,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/utsname.h>
@@ -74,8 +74,10 @@ asmlinkage int osf_set_program_attributes(
mm = current->mm;
mm->end_code = bss_start + bss_len;
mm->brk = bss_start + bss_len;
+#if 0
printk("set_program_attributes(%lx %lx %lx %lx)\n",
text_start, text_len, bss_start, bss_len);
+#endif
unlock_kernel();
return 0;
}
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
new file mode 100644
index 000000000..d530ebb82
--- /dev/null
+++ b/arch/alpha/kernel/pci-noop.c
@@ -0,0 +1,104 @@
+/*
+ * linux/arch/alpha/kernel/pci-noop.c
+ *
+ * Stub PCI interfaces for Jensen-specific kernels.
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+#include "proto.h"
+
+
+/*
+ * The PCI controler list.
+ */
+
+struct pci_controler *hose_head, **hose_tail = &hose_head;
+struct pci_controler *pci_isa_hose;
+
+
+struct pci_controler * __init
+alloc_pci_controler(void)
+{
+ struct pci_controler *hose;
+
+ hose = alloc_bootmem(sizeof(*hose));
+
+ *hose_tail = hose;
+ hose_tail = &hose->next;
+
+ return hose;
+}
+
+struct resource * __init
+alloc_resource(void)
+{
+ struct resource *res;
+
+ res = alloc_bootmem(sizeof(*res));
+
+ return res;
+}
+
+asmlinkage long
+sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn)
+{
+ struct pci_controler *hose;
+ struct pci_dev *dev;
+
+ /* from hose or from bus.devfn */
+ if (which & IOBASE_FROM_HOSE) {
+ for (hose = hose_head; hose; hose = hose->next)
+ if (hose->index == bus)
+ break;
+ if (!hose)
+ return -ENODEV;
+ } else {
+ /* Special hook for ISA access. */
+ if (bus == 0 && dfn == 0)
+ hose = pci_isa_hose;
+ else
+ return -ENODEV;
+ }
+
+ switch (which & ~IOBASE_FROM_HOSE) {
+ case IOBASE_HOSE:
+ return hose->index;
+ case IOBASE_SPARSE_MEM:
+ return hose->sparse_mem_base;
+ case IOBASE_DENSE_MEM:
+ return hose->dense_mem_base;
+ case IOBASE_SPARSE_IO:
+ return hose->sparse_io_base;
+ case IOBASE_DENSE_IO:
+ return hose->dense_io_base;
+ case IOBASE_ROOT_BUS:
+ return hose->bus->number;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+asmlinkage long
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len, void *buf)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ else
+ return -ENODEV;
+}
+
+asmlinkage long
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len, void *buf)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ else
+ return -ENODEV;
+}
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 508e278b0..2dd505e10 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -18,7 +18,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/utsname.h>
@@ -416,22 +416,20 @@ dump_fpu(struct pt_regs * regs, elf_fpregset_t *r)
* Don't do this at home.
*/
asmlinkage int
-sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs regs)
+sys_execve(char *ufilename, char **argv, char **envp,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs regs)
{
int error;
- char * filename;
+ char *filename;
- lock_kernel();
- filename = getname((char *) a0);
+ filename = getname(ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, (char **) a1, (char **) a2, &regs);
+ error = do_execve(filename, argv, envp, &regs);
putname(filename);
out:
- unlock_kernel();
return error;
}
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 09fcfd787..a919e7c2f 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -12,7 +12,7 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index 2acf56d96..a6443da53 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -16,7 +16,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
diff --git a/arch/alpha/kernel/smc37c669.c b/arch/alpha/kernel/smc37c669.c
index 0b2db18ab..3ffb611f2 100644
--- a/arch/alpha/kernel/smc37c669.c
+++ b/arch/alpha/kernel/smc37c669.c
@@ -3,7 +3,7 @@
*/
#include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/arch/alpha/kernel/smc37c93x.c b/arch/alpha/kernel/smc37c93x.c
index 5448305a3..b0e15d307 100644
--- a/arch/alpha/kernel/smc37c93x.c
+++ b/arch/alpha/kernel/smc37c93x.c
@@ -5,7 +5,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index e91e77895..4f877b10b 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -837,7 +837,7 @@ smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
atomic_set(&data.unstarted_count, smp_num_cpus - 1);
atomic_set(&data.unfinished_count, smp_num_cpus - 1);
- /* Aquire the smp_call_function_data mutex. */
+ /* Acquire the smp_call_function_data mutex. */
if (pointer_lock(&smp_call_function_data, &data, retry))
return -EBUSY;
diff --git a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c
index c9a2e79a4..0d9713377 100644
--- a/arch/alpha/kernel/sys_ruffian.c
+++ b/arch/alpha/kernel/sys_ruffian.c
@@ -92,14 +92,80 @@ ruffian_kill_arch (int mode)
#endif
}
+/*
+ * Interrupt routing:
+ *
+ * Primary bus
+ * IdSel INTA INTB INTC INTD
+ * 21052 13 - - - -
+ * SIO 14 23 - - -
+ * 21143 15 44 - - -
+ * Slot 0 17 43 42 41 40
+ *
+ * Secondary bus
+ * IdSel INTA INTB INTC INTD
+ * Slot 0 8 (18) 19 18 17 16
+ * Slot 1 9 (19) 31 30 29 28
+ * Slot 2 10 (20) 27 26 25 24
+ * Slot 3 11 (21) 39 38 37 36
+ * Slot 4 12 (22) 35 34 33 32
+ * 53c875 13 (23) 20 - - -
+ *
+ */
+
static int __init
ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
- /* We don't know anything about the PCI routing, so leave
- the IRQ unchanged. */
- return dev->irq;
+ static char irq_tab[11][5] __initdata = {
+ /*INT INTA INTB INTC INTD */
+ {-1, -1, -1, -1, -1}, /* IdSel 13, 21052 */
+ {-1, -1, -1, -1, -1}, /* IdSel 14, SIO */
+ {44, 44, 44, 44, 44}, /* IdSel 15, 21143 */
+ {-1, -1, -1, -1, -1}, /* IdSel 16, none */
+ {43, 43, 42, 41, 40}, /* IdSel 17, 64-bit slot */
+ /* the next 6 are actually on PCI bus 1, across the bridge */
+ {19, 19, 18, 17, 16}, /* IdSel 8, slot 0 */
+ {31, 31, 30, 29, 28}, /* IdSel 9, slot 1 */
+ {27, 27, 26, 25, 24}, /* IdSel 10, slot 2 */
+ {39, 39, 38, 37, 36}, /* IdSel 11, slot 3 */
+ {35, 35, 34, 33, 32}, /* IdSel 12, slot 4 */
+ {20, 20, 20, 20, 20}, /* IdSel 13, 53c875 */
+ };
+ const long min_idsel = 13, max_idsel = 23, irqs_per_slot = 5;
+ return COMMON_TABLE_LOOKUP;
}
+static u8 __init
+ruffian_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+ int slot, pin = *pinp;
+
+ if (dev->bus->number == 0) {
+ slot = PCI_SLOT(dev->devfn);
+ }
+ /* Check for the built-in bridge. */
+ else if (PCI_SLOT(dev->bus->self->devfn) == 13) {
+ slot = PCI_SLOT(dev->devfn) + 10;
+ }
+ else
+ {
+ /* Must be a card-based bridge. */
+ do {
+ if (PCI_SLOT(dev->bus->self->devfn) == 13) {
+ slot = PCI_SLOT(dev->devfn) + 10;
+ break;
+ }
+ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+
+ /* Move up the chain of bridges. */
+ dev = dev->bus->self;
+ /* Slot of the next bridge. */
+ slot = PCI_SLOT(dev->devfn);
+ } while (dev->bus->self);
+ }
+ *pinp = pin;
+ return slot;
+}
#ifdef BUILDING_FOR_MILO
/*
@@ -164,6 +230,6 @@ struct alpha_machine_vector ruffian_mv __initmv = {
init_pci: cia_init_pci,
kill_arch: ruffian_kill_arch,
pci_map_irq: ruffian_map_irq,
- pci_swizzle: common_swizzle,
+ pci_swizzle: ruffian_swizzle,
};
ALIAS_MV(ruffian)
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index 7b2f8be03..ed7d2f68e 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -1093,7 +1093,9 @@ alpha_ni_syscall(unsigned long a0, unsigned long a1, unsigned long a2,
{
/* We only get here for OSF system calls, minus #112;
the rest go to sys_ni_syscall. */
+#if 0
printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
+#endif
return -ENOSYS;
}
diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile
index 1e3e485b5..d95ace0d7 100644
--- a/arch/alpha/lib/Makefile
+++ b/arch/alpha/lib/Makefile
@@ -42,6 +42,8 @@ OBJS = __divqu.o __remqu.o __divlu.o __remlu.o \
$(ev6)strncpy_from_user.o \
$(ev67)strlen_user.o \
$(ev6)csum_ipv6_magic.o \
+ $(ev6)clear_page.o \
+ $(ev6)copy_page.o \
strcasecmp.o \
fpreg.o \
callback_srm.o srm_puts.o srm_printk.o
diff --git a/arch/alpha/lib/clear_page.S b/arch/alpha/lib/clear_page.S
new file mode 100644
index 000000000..a221ae266
--- /dev/null
+++ b/arch/alpha/lib/clear_page.S
@@ -0,0 +1,39 @@
+/*
+ * arch/alpha/lib/clear_page.S
+ *
+ * Zero an entire page.
+ */
+
+ .text
+ .align 4
+ .global clear_page
+ .ent clear_page
+clear_page:
+ .prologue 0
+
+ lda $0,128
+ nop
+ unop
+ nop
+
+1: stq $31,0($16)
+ stq $31,8($16)
+ stq $31,16($16)
+ stq $31,24($16)
+
+ stq $31,32($16)
+ stq $31,40($16)
+ stq $31,48($16)
+ subq $0,1,$0
+
+ stq $31,56($16)
+ addq $16,64,$16
+ unop
+ bne $0,1b
+
+ ret
+ nop
+ unop
+ nop
+
+ .end clear_page
diff --git a/arch/alpha/lib/copy_page.S b/arch/alpha/lib/copy_page.S
new file mode 100644
index 000000000..9f3b97459
--- /dev/null
+++ b/arch/alpha/lib/copy_page.S
@@ -0,0 +1,49 @@
+/*
+ * arch/alpha/lib/copy_page.S
+ *
+ * Copy an entire page.
+ */
+
+ .text
+ .align 4
+ .global copy_page
+ .ent copy_page
+copy_page:
+ .prologue 0
+
+ lda $18,128
+ nop
+ unop
+ nop
+
+1: ldq $0,0($17)
+ ldq $1,8($17)
+ ldq $2,16($17)
+ ldq $3,24($17)
+
+ ldq $4,32($17)
+ ldq $5,40($17)
+ ldq $6,48($17)
+ ldq $7,56($17)
+
+ stq $0,0($16)
+ subq $18,1,$18
+ stq $1,8($16)
+ addq $17,64,$17
+
+ stq $2,16($16)
+ stq $3,24($16)
+ stq $4,32($16)
+ stq $5,40($16)
+
+ stq $6,48($16)
+ stq $7,56($16)
+ addq $16,64,$16
+ bne $18, 1b
+
+ ret
+ nop
+ unop
+ nop
+
+ .end copy_page
diff --git a/arch/alpha/lib/ev6-clear_page.S b/arch/alpha/lib/ev6-clear_page.S
new file mode 100644
index 000000000..adf4f7be0
--- /dev/null
+++ b/arch/alpha/lib/ev6-clear_page.S
@@ -0,0 +1,54 @@
+/*
+ * arch/alpha/lib/ev6-clear_page.S
+ *
+ * Zero an entire page.
+ */
+
+ .text
+ .align 4
+ .global clear_page
+ .ent clear_page
+clear_page:
+ .prologue 0
+
+ lda $0,128
+ lda $1,125
+ addq $16,64,$2
+ addq $16,128,$3
+
+ addq $16,192,$17
+ wh64 ($16)
+ wh64 ($2)
+ wh64 ($3)
+
+1: wh64 ($17)
+ stq $31,0($16)
+ subq $0,1,$0
+ subq $1,1,$1
+
+ stq $31,8($16)
+ stq $31,16($16)
+ addq $17,64,$2
+ nop
+
+ stq $31,24($16)
+ stq $31,32($16)
+ cmovgt $1,$2,$17
+ nop
+
+ stq $31,40($16)
+ stq $31,48($16)
+ nop
+ nop
+
+ stq $31,56($16)
+ addq $16,64,$16
+ nop
+ bne $0,1b
+
+ ret
+ nop
+ nop
+ nop
+
+ .end clear_page
diff --git a/arch/alpha/lib/ev6-copy_page.S b/arch/alpha/lib/ev6-copy_page.S
new file mode 100644
index 000000000..b789db192
--- /dev/null
+++ b/arch/alpha/lib/ev6-copy_page.S
@@ -0,0 +1,203 @@
+/*
+ * arch/alpha/lib/ev6-copy_page.S
+ *
+ * Copy an entire page.
+ */
+
+/* The following comparison of this routine vs the normal copy_page.S
+ was written by an unnamed ev6 hardware designer and forwarded to me
+ via Steven Hobbs <hobbs@steven.zko.dec.com>.
+
+ First Problem: STQ overflows.
+ -----------------------------
+
+ It would be nice if EV6 handled every resource overflow efficiently,
+ but for some it doesn't. Including store queue overflows. It causes
+ a trap and a restart of the pipe.
+
+ To get around this we sometimes use (to borrow a term from a VSSAD
+ researcher) "aeration". The idea is to slow the rate at which the
+ processor receives valid instructions by inserting nops in the fetch
+ path. In doing so, you can prevent the overflow and actually make
+ the code run faster. You can, of course, take advantage of the fact
+ that the processor can fetch at most 4 aligned instructions per cycle.
+
+ I inserted enough nops to force it to take 10 cycles to fetch the
+ loop code. In theory, EV6 should be able to execute this loop in
+ 9 cycles but I was not able to get it to run that fast -- the initial
+ conditions were such that I could not reach this optimum rate on
+ (chaotic) EV6. I wrote the code such that everything would issue
+ in order.
+
+ Second Problem: Dcache index matches.
+ -------------------------------------
+
+ If you are going to use this routine on random aligned pages, there
+ is a 25% chance that the pages will be at the same dcache indices.
+ This results in many nasty memory traps without care.
+
+ The solution is to schedule the prefetches to avoid the memory
+ conflicts. I schedule the wh64 prefetches farther ahead of the
+ read prefetches to avoid this problem.
+
+ Third Problem: Needs more prefetching.
+ --------------------------------------
+
+ In order to improve the code I added deeper prefetching to take the
+ most advantage of EV6's bandwidth.
+
+ I also prefetched the read stream. Note that adding the read prefetch
+ forced me to add another cycle to the inner-most kernel - up to 11
+ from the original 8 cycles per iteration. We could improve performance
+ further by unrolling the loop and doing multiple prefetches per cycle.
+
+ I think that the code below will be very robust and fast code for the
+ purposes of copying aligned pages. It is slower when both source and
+ destination pages are in the dcache, but it is my guess that this is
+ less important than the dcache miss case. */
+
+
+ .text
+ .align 4
+ .global copy_page
+ .ent copy_page
+copy_page:
+ .prologue 0
+
+ /* Prefetch 5 read cachelines; write-hint 10 cache lines. */
+ wh64 ($16)
+ ldl $31,0($17)
+ ldl $31,64($17)
+ lda $1,1*64($16)
+
+ wh64 ($1)
+ ldl $31,128($17)
+ ldl $31,192($17)
+ lda $1,2*64($16)
+
+ wh64 ($1)
+ ldl $31,256($17)
+ lda $18,118
+ lda $1,3*64($16)
+
+ wh64 ($1)
+ nop
+ lda $1,4*64($16)
+ lda $2,5*64($16)
+
+ wh64 ($1)
+ wh64 ($2)
+ lda $1,6*64($16)
+ lda $2,7*64($16)
+
+ wh64 ($1)
+ wh64 ($2)
+ lda $1,8*64($16)
+ lda $2,9*64($16)
+
+ wh64 ($1)
+ wh64 ($2)
+ lda $19,10*64($16)
+ nop
+
+ /* Main prefetching/write-hinting loop. */
+1: ldq $0,0($17)
+ ldq $1,8($17)
+ unop
+ unop
+
+ unop
+ unop
+ ldq $2,16($17)
+ ldq $3,24($17)
+
+ ldq $4,32($17)
+ ldq $5,40($17)
+ unop
+ unop
+
+ unop
+ unop
+ ldq $6,48($17)
+ ldq $7,56($17)
+
+ ldl $31,320($17)
+ unop
+ unop
+ unop
+
+ /* This gives the extra cycle of aeration above the minimum. */
+ unop
+ unop
+ unop
+ unop
+
+ wh64 ($19)
+ unop
+ unop
+ unop
+
+ stq $0,0($16)
+ subq $18,1,$18
+ stq $1,8($16)
+ unop
+
+ unop
+ stq $2,16($16)
+ addq $17,64,$17
+ stq $3,24($16)
+
+ stq $4,32($16)
+ stq $5,40($16)
+ addq $19,64,$19
+ unop
+
+ stq $6,48($16)
+ stq $7,56($16)
+ addq $16,64,$16
+ bne $18, 1b
+
+ /* Prefetch the final 5 cache lines of the read stream. */
+ lda $18,10
+ ldl $31,320($17)
+ ldl $31,384($17)
+ ldl $31,448($17)
+
+ ldl $31,512($17)
+ ldl $31,576($17)
+ nop
+ nop
+
+ /* Non-prefetching, non-write-hinting cleanup loop for the
+ final 10 cache lines. */
+2: ldq $0,0($17)
+ ldq $1,8($17)
+ ldq $2,16($17)
+ ldq $3,24($17)
+
+ ldq $4,32($17)
+ ldq $5,40($17)
+ ldq $6,48($17)
+ ldq $7,56($17)
+
+ stq $0,0($16)
+ subq $18,1,$18
+ stq $1,8($16)
+ addq $17,64,$17
+
+ stq $2,16($16)
+ stq $3,24($16)
+ stq $4,32($16)
+ stq $5,40($16)
+
+ stq $6,48($16)
+ stq $7,56($16)
+ addq $16,64,$16
+ bne $18, 2b
+
+ ret
+ nop
+ unop
+ nop
+
+ .end copy_page
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index c19ccddec..0320dba31 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -12,25 +12,18 @@
#
# Copyright (C) 1995-2000 by Russell King
-OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-CPP := $(CC) -E
-LINKFLAGS := -p -X -T arch/arm/vmlinux.lds
-ARCHCC := $(word 1,$(CC))
-
-AFLAGS += -mno-fpu
-CFLAGS_PIPE := -pipe
-CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) -msoft-float
+LINKFLAGS :=-p -X -T arch/arm/vmlinux.lds
+GZFLAGS :=-9
+CFLAGS +=-fno-common -pipe
ifdef CONFIG_FRAME_POINTER
-CFLAGS := $(CFLAGS:-fomit-frame-pointer=)
+CFLAGS :=$(CFLAGS:-fomit-frame-pointer=)
endif
ifdef CONFIG_DEBUG_INFO
-CFLAGS += -g
+CFLAGS +=-g
endif
-GZFLAGS = -9
-
# Ensure this is ld "2.9.4" or later
NEW_LINKER := $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?)
@@ -40,61 +33,42 @@ dummy:; @echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly w
@false
endif
-# GCC 2.7 uses different options to later compilers; sort out which we have
-NEW_GCC := $(shell $(CC) --version 2>&1 | grep '^2\.7' > /dev/null; echo $$?)
-
-#
-# select flags depending on the compiler
+# Select CPU dependent flags. Note that order of declaration is important;
+# the options further down the list override previous items.
#
-ifneq ($(NEW_GCC),0)
-CFLAGS += -mshort-load-bytes
-CFLAGS_PROC_CPU_26 := -mcpu=arm3 -mapcs-26 -Os
-CFLAGS_PROC_CPU_32v3 := -march=armv3
-CFLAGS_PROC_CPU_32v4 := -march=armv4
-else
-CFLAGS += -DNO_TEXT_SECTIONS
-CFLAGS_PROC_CPU_26 := -m3
-CFLAGS_PROC_CPU_32v3 := -m6
-CFLAGS_PROC_CPU_32v4 := -m6
-endif
+apcs-$(CONFIG_CPU_26) :=-mapcs-26 -mcpu=arm3 -Os
+apcs-$(CONFIG_CPU_32) :=-mapcs-32
+
+arch-$(CONFIG_CPU_32v3) :=-march=armv3
+arch-$(CONFIG_CPU_32v4) :=-march=armv4
+arch-$(CONFIG_CPU_32v5) :=-march=armv5
+
+proc-$(CONFIG_CPU_32v3) :=-marmv3m
+proc-$(CONFIG_CPU_32v4) :=-marmv4
+proc-$(CONFIG_CPU_32v5) :=-marmv5
+
+tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610
+tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710
+tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi
+tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi
+tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110
+tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100
+
+CFLAGS += $(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
+AFLAGS += $(apcs-y) $(proc-y) -mno-fpu
+
+LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
-#
-# Select CPU dependent flags
-#
ifeq ($(CONFIG_CPU_26),y)
- PROCESSOR = armo
- TEXTADDR = 0x02080000
- CFLAGS += $(CFLAGS_PROC_CPU_26)
- AFLAGS += -mapcs-26
+PROCESSOR = armo
+TEXTADDR = 0x02080000
endif
ifeq ($(CONFIG_CPU_32),y)
- PROCESSOR = armv
- TEXTADDR = 0xC0008000
- ifeq ($(CONFIG_CPU_32v4),y)
- CFLAGS += $(CFLAGS_PROC_CPU_32v4)
- AFLAGS += -mapcs-32 -marmv4
- else
- CFLAGS += $(CFLAGS_PROC_CPU_32v3)
- AFLAGS += -mapcs-32 -marmv3m
- endif
-
- opt-$(CONFIG_CPU_ARM6) := -mtune=arm6
- opt-$(CONFIG_CPU_ARM7) := -mtune=arm7
- opt-$(CONFIG_CPU_ARM720) := -mtune=arm7tdmi
- opt-$(CONFIG_CPU_ARM920) := -mtune=arm9tdmi
- opt-$(CONFIG_CPU_SA110) := -mtune=strongarm110
- opt-$(CONFIG_CPU_SA1100) := -mtune=strongarm110
-
- ifneq ($(NEW_GCC),0)
- CFLAGS += $(opt-y)
- endif
+PROCESSOR = armv
+TEXTADDR = 0xC0008000
endif
-LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
-
-export LIBGCC MACHINE PROCESSOR TEXTADDR GZFLAGS
-
ifeq ($(CONFIG_ARCH_ARCA5K),y)
MACHINE = arc
endif
@@ -132,6 +106,10 @@ MACHINE = shark
endif
ifeq ($(CONFIG_ARCH_SA1100),y)
+ifeq ($(CONFIG_SA1111),y)
+# SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memory
+TEXTADDR = 0xc0208000
+endif
MACHINE = sa1100
endif
@@ -143,6 +121,13 @@ ifeq ($(CONFIG_ARCH_INTEGRATOR),y)
MACHINE = integrator
endif
+ifeq ($(CONFIG_ARCH_CLPS711X),y)
+TEXTADDR = 0xc0018000
+MACHINE = clps711x
+endif
+
+export LIBGCC MACHINE PROCESSOR TEXTADDR GZFLAGS
+
# Only set INCDIR if its not already defined above
# Grr, ?= doesn't work as all the other assignment operators do. Make bug?
ifeq ($(origin INCDIR), undefined)
@@ -158,8 +143,7 @@ endif
HEAD := arch/arm/kernel/head-$(PROCESSOR).o \
arch/arm/kernel/init_task.o
-SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib \
- arch/arm/nwfpe
+SUBDIRS += arch/arm/kernel arch/arm/mm arch/arm/lib arch/arm/nwfpe
CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES)
LIBS := arch/arm/lib/lib.o arch/arm/lib/lib.a $(LIBS) $(LIBGCC)
@@ -167,14 +151,6 @@ ifeq ($(CONFIG_NWFPE),y)
LIBS := arch/arm/nwfpe/math-emu.o $(LIBS)
endif
-ifeq ($(CONFIG_ARCH_ACORN),y)
-SUBDIRS += drivers/acorn
-DRIVERS += drivers/acorn/block/acorn-block.a
-DRIVERS += drivers/acorn/char/acorn-char.o
-DRIVERS += drivers/acorn/net/acorn-net.o
-DRIVERS += drivers/acorn/scsi/acorn-scsi.a
-endif
-
ifeq ($(CONFIG_ARCH_CLPS7500),y)
SUBDIRS += drivers/acorn/char
DRIVERS += drivers/acorn/char/acorn-char.o
@@ -230,6 +206,7 @@ zImg:; @$(MAKEBOOT) zImage
Img:; @$(MAKEBOOT) Image
i:; @$(MAKEBOOT) install
zi:; @$(MAKEBOOT) zinstall
+bp:; @$(MAKEBOOT) bootpImage
#
# Configuration targets. Use these to select a
@@ -237,9 +214,10 @@ zi:; @$(MAKEBOOT) zinstall
CFGS= a5k_config ebsa110_config \
footbridge_config rpc_config \
brutus_config victor_config \
- empeg_config thinclient_config \
+ empeg_config graphicsclient_config \
assabet_config lart_config \
- cerf_config lusl7200_config
+ cerf_config lusl7200_config \
+ sherman_config pangolin_config
$(CFGS):
@( \
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index f74033b36..7b13b1bcb 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -83,15 +83,18 @@ ZTEXTADDR = 0xc0008000
ZRELADDR = 0xc0008000
ifeq ($(CONFIG_SA1100_VICTOR),y)
ZTEXTADDR = 0x00002000
- ZBSSADDR = 0xc0100000
+ ZBSSADDR = 0xc0200000
endif
ifeq ($(CONFIG_SA1100_SHERMAN),y)
ZTEXTADDR = 0x00050000
- ZBSSADDR = 0xc0100000
+ ZBSSADDR = 0xc0200000
endif
ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y)
ZTEXTADDR = 0xC0200000
endif
+ifeq ($(CONFIG_SA1111),y)
+ ZRELADDR = 0xc0208000
+endif
endif
#
@@ -105,15 +108,15 @@ endif
export SYSTEM ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS INITRD_VIRT PARAMS_PHYS
Image: $(CONFIGURE) $(SYSTEM)
- $(OBJCOPY) $(SYSTEM) $@
+ $(OBJCOPY) -O binary -R .note -R .comment -S $(SYSTEM) $@
bzImage: zImage
zImage: $(CONFIGURE) compressed/vmlinux
- $(OBJCOPY) compressed/vmlinux $@
+ $(OBJCOPY) -O binary -R .note -R .comment -S compressed/vmlinux $@
bootpImage: bootp/bootp
- $(OBJCOPY) bootp/bootp $@
+ $(OBJCOPY) -O binary -R .note -R .comment -S bootp/bootp $@
compressed/vmlinux: $(TOPDIR)/vmlinux dep
@$(MAKE) -C compressed vmlinux
diff --git a/arch/arm/boot/bootp/Makefile b/arch/arm/boot/bootp/Makefile
index 918e3eb9e..adeeeddc5 100644
--- a/arch/arm/boot/bootp/Makefile
+++ b/arch/arm/boot/bootp/Makefile
@@ -7,7 +7,8 @@ INITRD =$(ZSYSTEM)
ZLDFLAGS =-p -X -T bootp.lds \
--defsym initrd_addr=$(INITRD_PHYS) \
--defsym initrd_virt=$(INITRD_VIRT) \
- --defsym params=$(PARAMS_PHYS)
+ --defsym params=$(PARAMS_PHYS) \
+ --defsym kernel_addr=$(ZTEXTADDR)
all: bootp
diff --git a/arch/arm/boot/bootp/init.S b/arch/arm/boot/bootp/init.S
index 2b498b7bb..9963fbc2b 100644
--- a/arch/arm/boot/bootp/init.S
+++ b/arch/arm/boot/bootp/init.S
@@ -12,33 +12,59 @@
*/
.section .start,#alloc,#execinstr
.type _entry, #function
-_entry:
-kernel_addr: adr r10, initdata
- ldmia r10, {r11, r12}
+_entry: adr r10, initdata
+ ldr r11, initdata
sub r11, r10, r11 @ work out exec offset
- add r12, r12, r11 @ correct "splitify"
- mov pc, r12 @ jump to splitify
+ b splitify
.size _entry,. - _entry
.type initdata, #object
initdata: .word initdata @ compiled address of this
- .word splitify
.size initdata,. - initdata
.text
splitify: adr r13, data
- ldmia r13!, {r4-r6} @ move the kernel
+ ldmia r13!, {r4-r6} @ move the initrd
add r4, r4, r11 @ correction
- mov r12, r5
bl move
- ldmia r13!, {r4-r6} @ then the initrd
+ ldmia r13!, {r4-r6} @ then the kernel
+ mov r12, r5
add r4, r4, r11 @ correction
bl move
- ldmib r13, {r5,r6,r7} @ get size and addr of initrd
- add r7, r7, #16*4 @ offset of initrd_start in param_struct
- stmia r7, {r5,r6} @ save in param_struct
+/*
+ * Setup the initrd parameters to pass to the kernel. This can either be
+ * passed in via a param_struct or a tag list. We spot the param_struct
+ * method by looking at the first word; this should either indicate a page
+ * size of 4K, 16K or 32K.
+ */
+ ldmia r13, {r5-r8} @ get size and addr of initrd
+ @ r5 = ATAG_INITRD
+ @ r6 = initrd start
+ @ r7 = initrd end
+ @ r8 = param_struct address
+ ldr r9, [r8, #0] @ no param struct?
+ teq r9, #0x1000 @ 4K?
+ teqne r9, #0x4000 @ 16K?
+ teqne r9, #0x8000 @ 32K?
+ beq no_taglist
+
+/*
+ * find the end of the tag list, and then add an INITRD tag on the end.
+ */
+taglist: ldr r9, [r8, #0] @ tag length
+ teq r9, #0 @ last tag?
+ addne r8, r8, r9
+ bne taglist
+
+ mov r4, #16 @ length of initrd tag
+ mov r9, #0 @ end of tag list terminator
+ stmia r8, {r4, r5, r6, r7, r9}
+ mov pc, r12 @ call kernel
+
+no_taglist: add r8, r8, #16*4
+ stmia r8, {r6,r7} @ save in param_struct
mov pc, r12 @ call kernel
move: ldmia r4!, {r7 - r10} @ move 32-bytes at a time
@@ -49,17 +75,18 @@ move: ldmia r4!, {r7 - r10} @ move 32-bytes at a time
bcs move
mov pc, lr
-data: .word kernel_start
- .word kernel_addr
- .word kernel_len
-
- .word initrd_start
+data: .word initrd_start
.word initrd_addr
.word initrd_len
- .word initrd_virt
- .word initrd_len
- .word params
+ .word kernel_start
+ .word kernel_addr
+ .word kernel_len
+
+ .word 0x54410005 @ r5 = ATAG_INITRD
+ .word initrd_virt @ r6
+ .word initrd_len @ r7
+ .word params @ r8
.type kernel_start,#object
.type initrd_start,#object
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index bf8f1c947..7f077cd21 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -66,7 +66,7 @@ $(HEAD): $(HEAD:.o=.S)
$(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S)
piggy.o: $(SYSTEM)
- $(OBJCOPY) $(SYSTEM) piggy
+ $(OBJCOPY) -O binary -R .note -R .comment -S $(SYSTEM) piggy
gzip $(GZFLAGS) < piggy > piggy.gz
$(LD) -r -o $@ -b binary piggy.gz
rm -f piggy piggy.gz
diff --git a/arch/arm/boot/compressed/head-ftvpci.S b/arch/arm/boot/compressed/head-ftvpci.S
index a8c806ef3..8e10667ca 100644
--- a/arch/arm/boot/compressed/head-ftvpci.S
+++ b/arch/arm/boot/compressed/head-ftvpci.S
@@ -6,6 +6,13 @@
* Special startup code for FTV PCI board.
*/
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
.section ".start", #alloc, #execinstr
ftv_start:
mcr p15, 0, r0, c7, c5, 0 @ flush I cache
diff --git a/arch/arm/boot/compressed/head-l7200.S b/arch/arm/boot/compressed/head-l7200.S
index ecf4d6881..8ab9eafdb 100644
--- a/arch/arm/boot/compressed/head-l7200.S
+++ b/arch/arm/boot/compressed/head-l7200.S
@@ -3,7 +3,7 @@
*
* Copyright (C) 2000 Steve Hill <sjhill@cotw.com>
*
- * Some code borrowed from Nicola Pitre's 'head-sa1100.S' file. This
+ * Some code borrowed from Nicolas Pitre's 'head-sa1100.S' file. This
* is merged with head.S by the linker.
*/
@@ -16,15 +16,14 @@
.section ".start", #alloc, #execinstr
__L7200_start:
-
mov r0, #0x00100000 @ FLASH address of initrd
mov r2, #0xf1000000 @ RAM address of initrd
- add r1, r2, #0x00700000 @ Size of initrd
+ add r3, r2, #0x00700000 @ Size of initrd
1:
- ldmia r0!, {r3, r4, r5, r6}
- stmia r2!, {r3, r4, r5, r6}
- cmp r2, r1
+ ldmia r0!, {r4, r5, r6, r7}
+ stmia r2!, {r4, r5, r6, r7}
+ cmp r2, r3
ble 1b
-
+
mov r8, #0 @ Zero it out
mov r7, #19 @ Set architecture ID
diff --git a/arch/arm/boot/compressed/head-sa1100.S b/arch/arm/boot/compressed/head-sa1100.S
index 73cef4bd8..f49ceb5e6 100644
--- a/arch/arm/boot/compressed/head-sa1100.S
+++ b/arch/arm/boot/compressed/head-sa1100.S
@@ -11,10 +11,6 @@
#include <linux/linkage.h>
#include <asm/mach-types.h>
-#ifndef CONFIG_ARCH_SA1100
-#error What am I doing here...
-#endif
-
.section ".start", #alloc, #execinstr
__SA1100_start:
@@ -54,6 +50,8 @@ __SA1100_start:
bic r0, r0, #0x0d @ clear WB, DC, MMU
bic r0, r0, #0x1000 @ clear Icache
mcr p15, 0, r0, c1, c0, 0
+
+#ifdef CONFIG_ANGELBOOT
/*
* Pause for a short time so that we give enough time
* for the host to start a terminal up.
@@ -61,3 +59,5 @@ __SA1100_start:
mov r0, #0x00200000
1: subs r0, r0, #1
bne 1b
+#endif
+
diff --git a/arch/arm/boot/compressed/head-shark.S b/arch/arm/boot/compressed/head-shark.S
new file mode 100644
index 000000000..817b75366
--- /dev/null
+++ b/arch/arm/boot/compressed/head-shark.S
@@ -0,0 +1,121 @@
+/* The head-file for the Shark
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * Does the following:
+ * - get the memory layout from firmware. This can only be done as long as the mmu
+ * is still on.
+ * - switch the mmu off, so we have physical addresses
+ * - copy the kernel to 0x08508000. This is done to have a fixed address where the
+ * C-parts (misc.c) are executed. This address must be known at compile-time,
+ * but the load-address of the kernel depends on how much memory is installed.
+ * - Jump to this location.
+ * - Set r8 with 0, r7 with the architecture ID for head.S
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+
+ .section ".start", #alloc, #execinstr
+
+ b __beginning
+
+__serial_addr: .long 0xf7eff3f8
+ .long 0 @ space
+__ofw_data: .long 0 @ the number of memory blocks
+ .space 128 @ (startaddr,size) ...
+ .space 128 @ bootargs
+ .align
+
+__beginning: mov r4, r0 @ save the entry to the firmware
+
+ mov r0, #0xC0 @ disable irq and fiq
+ mov r1, r0
+ mrs r3, cpsr_all
+ bic r2, r3, r0
+ eor r2, r2, r1
+ msr cpsr_all, r2
+
+ ldr r0, __serial_addr @ disable serial interrupt
+ mov r1, #0 @ hangs the machine, I don t know why.
+ strb r1, [r0, #0x01]
+
+ mov r0, r4 @ get the Memory layout from firmware
+ adr r1, __ofw_data
+ add r2, r1, #4
+ mov lr, pc
+ b SYMBOL_NAME(ofw_init)
+ mov r1, #0
+
+ adr r2, __mmu_off @ calculate physical address
+ sub r2, r2, #0xf0000000 @ openprom maps us at f000 virt, 0e50 phys
+ adr r0, __ofw_data
+ ldr r0, [r0, #4]
+ add r2, r2, r0
+ add r2, r2, #0x00500000
+
+ mrc p15, 0, r3, c1, c0
+ bic r3, r3, #0xC @ Write Buffer and DCache
+ bic r3, r3, #0x1000 @ ICache
+ mcr p15, 0, r3, c1, c0 @ disabled
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c7 @ flush I,D caches on v4
+ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4
+ mcr p15, 0, r0, c8, c7 @ flush I,D TLBs on v4
+
+ bic r3, r3, #0x1 @ MMU
+ mcr p15, 0, r3, c1, c0 @ disabled
+
+ mov pc, r2
+
+__copy_target: .long 0x08508000
+__copy_end: .long 0x08608000
+
+ .word _start
+ .word __bss_start
+
+ .align
+__temp_stack: .space 128
+
+__mmu_off:
+ adr r0, __ofw_data
+ ldr r0, [r0, #4]
+ orr r0, r0, #0x00600000
+
+ ldr r1, __copy_end
+ ldr r3, __copy_target
+
+/* r0 = 0x0e600000 (current end of kernelcode)
+ * r3 = 0x08508000 (where it should begin)
+ * r1 = 0x08608000 (end of copying area, 1MB)
+ * The kernel is compressed, so 1 MB should be enough.
+ * copy the kernel to the beginning of physical memory
+ * We start from the highest address, so we can copy
+ * from 0x08500000 to 0x08508000 if we have only 8MB
+ */
+
+
+__Copy: ldr r2, [r0], #-4
+ str r2, [r1], #-4
+ teq r1, r3
+ bne __Copy
+ /* and jump to it */
+ adr r2, __go_on
+ adr r0, __ofw_data
+ ldr r0, [r0, #4]
+ sub r2, r2, r0
+ sub r2, r2, #0x00500000
+ ldr r0, __copy_target
+ add r2, r2, r0
+ mov pc, r2
+
+__go_on:
+ adr sp, __temp_stack
+ add sp, sp, #128
+ adr r0, __ofw_data
+ mov lr, pc
+ b SYMBOL_NAME(create_params)
+
+ mov r8, #0
+ mov r7, #15
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 21bdb43c0..0e384ec72 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -112,8 +112,7 @@ start:
*/
.text
-1: mrc p15, 0, r6, c0, c0 @ get processor ID
- adr r2, LC0
+1: adr r2, LC0
ldmia r2, {r2, r3, r4, r5, sp}
mov r0, #0
@@ -124,14 +123,15 @@ start:
cmp r2, r3
blt 1b
+ mrc p15, 0, r6, c0, c0 @ get processor ID
bl cache_on
mov r1, sp @ malloc space above stack
add r2, sp, #0x10000 @ 64k max
teq r4, r5 @ will we overwrite ourselves?
- moveq r5, r2
- movne r5, r4
+ moveq r5, r2 @ decompress after image
+ movne r5, r4 @ decompress to final location
mov r0, r5
mov r3, r7
diff --git a/arch/arm/boot/compressed/ofw-shark.c b/arch/arm/boot/compressed/ofw-shark.c
new file mode 100644
index 000000000..0b4474c59
--- /dev/null
+++ b/arch/arm/boot/compressed/ofw-shark.c
@@ -0,0 +1,216 @@
+/*
+ * linux/arch/arm/boot/compressed/ofw-shark.c
+ *
+ * by Alexander.Schulz@stud.uni-karlsruhe.de
+ *
+ * This file is used to get some basic information
+ * about the memory layout of the shark we are running
+ * on. Memory is usually divided in blocks a 8 MB.
+ * And bootargs are copied from OpenFirmware.
+ */
+
+
+#include <linux/kernel.h>
+#include <asm/setup.h>
+#include <asm/page.h>
+
+
+asmlinkage void
+create_params (unsigned long *buffer)
+{
+ /* Is there a better address? Also change in kernel/arch.c */
+ struct param_struct *params = (struct param_struct *) 0x08003000;
+ int j,i,m,k,nr_banks,size;
+
+ for (j=0;j<256;j++) params->u1.unused[j]=0;
+
+ size=0;
+ nr_banks=(unsigned int) buffer[0];
+ if (nr_banks > NR_BANKS) nr_banks = NR_BANKS;
+ for (j=0;j<nr_banks;j++){
+ /* search the lowest address and put it into the next entry */
+ /* not a fast sort algorithm, but there are at most 8 entries */
+ /* and this is used only once anyway */
+ m=0xffffffff;
+ for (i=0;i<(unsigned int) buffer[0];i++){
+ if (buffer[2*i+1]<m) {
+ m=buffer[2*i+1];
+ k=i;
+ }
+ }
+
+ /* using pages_in_bank for startaddress and size */
+ /* start is in bytes, size in pages and not bigger than 0x2000 */
+ /* This is decoded in fixup_shark in arch/arm/kernel/arch.c */
+ params->u1.s.pages_in_bank[j]=buffer[2*k+1]|(buffer[2*k+2]/PAGE_SIZE);
+ size += buffer[2*k+2];
+
+ buffer[2*k+1]=0xffffffff; /* mark as copied */
+ }
+
+ params->u1.s.page_size = PAGE_SIZE;
+ params->u1.s.nr_pages = size/PAGE_SIZE;
+ params->u1.s.flags = FLAG_READONLY;
+
+ /* Copy over the bootargs */
+ for (j=0;j<128/4;j++) {
+ ((unsigned long *) params->commandline)[j]=buffer[33+j];
+ }
+}
+
+
+typedef int (*ofw_handle_t)(void *);
+
+/* Everything below is called with a wrong MMU setting.
+ * This means: no string constants, no initialization of
+ * arrays, no global variables! This is ugly but I didn't
+ * want to write this in assembler :-)
+ */
+
+int
+of_decode_int(const unsigned char *p)
+{
+ unsigned int i = *p++ << 8;
+ i = (i + *p++) << 8;
+ i = (i + *p++) << 8;
+ return (i + *p);
+}
+
+int
+OF_finddevice(ofw_handle_t openfirmware, char *name)
+{
+ unsigned int args[8];
+ char service[12];
+
+ service[0]='f';
+ service[1]='i';
+ service[2]='n';
+ service[3]='d';
+ service[4]='d';
+ service[5]='e';
+ service[6]='v';
+ service[7]='i';
+ service[8]='c';
+ service[9]='e';
+ service[10]='\0';
+
+ args[0]=(unsigned int)service;
+ args[1]=1;
+ args[2]=1;
+ args[3]=(unsigned int)name;
+
+ if (openfirmware(args) == -1)
+ return -1;
+ return args[4];
+}
+
+int
+OF_getproplen(ofw_handle_t openfirmware, int handle, char *prop)
+{
+ unsigned int args[8];
+ char service[12];
+
+ service[0]='g';
+ service[1]='e';
+ service[2]='t';
+ service[3]='p';
+ service[4]='r';
+ service[5]='o';
+ service[6]='p';
+ service[7]='l';
+ service[8]='e';
+ service[9]='n';
+ service[10]='\0';
+
+ args[0] = (unsigned int)service;
+ args[1] = 2;
+ args[2] = 1;
+ args[3] = (unsigned int)handle;
+ args[4] = (unsigned int)prop;
+
+ if (openfirmware(args) == -1)
+ return -1;
+ return args[5];
+}
+
+int
+OF_getprop(ofw_handle_t openfirmware, int handle, char *prop, void *buf, unsigned int buflen)
+{
+ unsigned int args[8];
+ char service[8];
+
+ service[0]='g';
+ service[1]='e';
+ service[2]='t';
+ service[3]='p';
+ service[4]='r';
+ service[5]='o';
+ service[6]='p';
+ service[7]='\0';
+
+ args[0] = (unsigned int)service;
+ args[1] = 4;
+ args[2] = 1;
+ args[3] = (unsigned int)handle;
+ args[4] = (unsigned int)prop;
+ args[5] = (unsigned int)buf;
+ args[6] = buflen;
+
+ if (openfirmware(args) == -1)
+ return -1;
+ return args[7];
+}
+
+asmlinkage void ofw_init(ofw_handle_t o, int *nomr, int *pointer)
+{
+ int phandle,i,mem_len,buffer[32];
+ char temp[12];
+
+ temp[0]='/';
+ temp[1]='m';
+ temp[2]='e';
+ temp[3]='m';
+ temp[4]='o';
+ temp[5]='r';
+ temp[6]='y';
+ temp[7]='\0';
+
+ phandle=OF_finddevice(o,temp);
+
+ temp[0]='r';
+ temp[1]='e';
+ temp[2]='g';
+ temp[3]='\0';
+
+ mem_len = OF_getproplen(o,phandle, temp);
+ OF_getprop(o,phandle, temp, buffer, mem_len);
+ *nomr=mem_len >> 3;
+
+ for (i=0; i<=mem_len/4; i++) pointer[i]=of_decode_int((const unsigned char *)&buffer[i]);
+
+ temp[0]='/';
+ temp[1]='c';
+ temp[2]='h';
+ temp[3]='o';
+ temp[4]='s';
+ temp[5]='e';
+ temp[6]='n';
+ temp[7]='\0';
+
+ phandle=OF_finddevice(o,temp);
+
+ temp[0]='b';
+ temp[1]='o';
+ temp[2]='o';
+ temp[3]='t';
+ temp[4]='a';
+ temp[5]='r';
+ temp[6]='g';
+ temp[7]='s';
+ temp[8]='\0';
+
+ mem_len = OF_getproplen(o,phandle, temp);
+ OF_getprop(o,phandle, temp, buffer, mem_len);
+ for (i=0; i<=mem_len/4; i++) pointer[i+32]=buffer[i];
+
+}
diff --git a/arch/arm/boot/compressed/setup-sa1100.S b/arch/arm/boot/compressed/setup-sa1100.S
index 3babde180..32e77c285 100644
--- a/arch/arm/boot/compressed/setup-sa1100.S
+++ b/arch/arm/boot/compressed/setup-sa1100.S
@@ -33,13 +33,11 @@ UART3_BASE: .long 0x80050000
#define UTSR0 0x1c
#define UTSR1 0x20
-#define BAUD_DIV_230400 0x000
-#define BAUD_DIV_115200 0x001
-#define BAUD_DIV_57600 0x003
-#define BAUD_DIV_38400 0x005
-#define BAUD_DIV_19200 0x00b
-#define BAUD_DIV_9600 0x017
-#define BAUD_DIV BAUD_DIV_9600
+#ifndef CONFIG_SA1100_DEFAULT_BAUDRATE
+#define CONFIG_SA1100_DEFAULT_BAUDRATE 9600
+#endif
+
+#define BAUD_DIV ((230400/CONFIG_SA1100_DEFAULT_BAUDRATE)-1)
SCR_loc: .long SYMBOL_NAME(SCR_value)
#define GPIO_2_9 0x3fc
@@ -92,7 +90,7 @@ skip_SCR:
bne skip_uart
@ UART3 if Assabet is used with Neponset
- teq r3, #25 @ if Assabet
+ teq r3, #MACH_TYPE_ASSABET @ if Assabet
tsteq r2, #(1 << 9) @ ... and Neponset present
ldreq r0, UART3_BASE
beq uart_init
diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in
index 86ed5e6e3..8608996e9 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.in
+++ b/arch/arm/boot/compressed/vmlinux.lds.in
@@ -19,12 +19,13 @@ SECTIONS
.text : {
_start = .;
- head.o(.start)
*(.start)
- head.o(.text)
*(.text)
*(.fixup)
*(.gnu.warning)
+ *(.rodata)
+ *(.glue_7)
+ *(.glue_7t)
input_data = .;
piggy.o
input_data_end = .;
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index ed5115c53..45956ea07 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -10,16 +10,14 @@ USE_STANDARD_AS_RULE := true
HEAD_OBJ = head-$(PROCESSOR).o
ENTRY_OBJ = entry-$(PROCESSOR).o
-AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional
-AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional
+AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR)
+AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR)
O_OBJS_arc = dma-arc.o oldlatches.o
O_OBJS_rpc = dma-rpc.o
O_OBJS_footbridge = dma-footbridge.o isa.o
O_OBJS_l7200 = fiq.o
-leds-ebsa110 = leds-ebsa110.o
-
pci-nexuspci = plx90x0.o
pci-footbridge = dec21285.o
pci-shark = via82c505.o
@@ -31,37 +29,29 @@ O_TARGET := kernel.o
# Object file lists.
-obj-y := arch.o dma.o $(ENTRY_OBJ) irq.o process.o ptrace.o \
- semaphore.o setup.o signal.o sys_arm.o time.o \
- traps.o $(O_OBJS_$(MACHINE))
-obj-m :=
-obj-n :=
-obj- :=
+obj-y := arch.o dma.o $(ENTRY_OBJ) irq.o process.o ptrace.o \
+ semaphore.o setup.o signal.o sys_arm.o time.o traps.o \
+ $(O_OBJS_$(MACHINE))
+obj-m :=
+obj-n :=
+obj- :=
+
+export-objs := armksyms.o dma.o ecard.o fiq.o oldlatches.o time.o
-export-objs := armksyms.o dma.o ecard.o \
- $(leds-$(MACHINE)) oldlatches.o \
- time.o
+no-irq-arch := $(CONFIG_ARCH_INTEGRATOR) $(CONFIG_ARCH_CLPS711X) \
+ $(CONFIG_ARCH_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110)
+
+ifneq ($(findstring y,$(no-irq-arch)),y)
+ obj-y += irq-arch.o
+endif
obj-$(CONFIG_ARCH_ACORN) += ecard.o fiq.o time-acorn.o
obj-$(CONFIG_DEBUG_LL) += debug-$(PROCESSOR).o
obj-$(CONFIG_MODULES) += armksyms.o
-obj-$(CONFIG_LEDS) += $(leds-$(MACHINE))
obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
-
obj-$(CONFIG_PCI) += bios32.o $(pci-$(MACHINE)) $(pci-y)
-# Files that are both resident and modular; remove from modular.
-
-obj-m := $(filter-out $(obj-y), $(obj-m))
-
-# Translate to Rules.make lists.
-
-O_OBJS := $(filter-out $(export-objs), $(obj-y))
-OX_OBJS := $(filter $(export-objs), $(obj-y))
-M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-
all: kernel.o $(HEAD_OBJ) init_task.o
include $(TOPDIR)/Rules.make
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 868fbd4a7..bbc43c509 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -257,11 +257,30 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
(struct arm_pci_sysdata *)bus->sysdata;
struct arm_bus_sysdata *busdata;
- if (bus->number < MAX_NR_BUS)
- busdata = sysdata->bus + bus->number;
- else
+ if (bus->number >= MAX_NR_BUS)
BUG();
+ if (bus->self) {
+ struct pci_dev *dev = bus->self;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ bus->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES + i];
+ bus->resource[i]->name = bus->name;
+ }
+ bus->resource[0]->start = ioport_resource.start;
+ bus->resource[0]->end = ioport_resource.end;
+ bus->resource[0]->flags |= pci_bridge_check_io(dev);
+ bus->resource[1]->start = iomem_resource.start;
+ bus->resource[1]->end = iomem_resource.end;
+ bus->resource[1]->flags |= IORESOURCE_MEM;
+
+ /* Turn off downsteam prefetchable memory address range */
+ bus->resource[2]->start = 1024*1024;
+ bus->resource[2]->end = bus->resource[2]->start - 1;
+ }
+
+ busdata = sysdata->bus + bus->number;
busdata->max_lat = 255;
/*
@@ -363,10 +382,6 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
void __init
pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
{
- ranges->io_start -= bus->resource[0]->start;
- ranges->io_end -= bus->resource[0]->start;
- ranges->mem_start -= bus->resource[1]->start;
- ranges->mem_end -= bus->resource[1]->start;
}
u8 __init no_swizzle(struct pci_dev *dev, u8 *pin)
@@ -442,7 +457,8 @@ void __init pcibios_init(void)
hw_pci->init(&sysdata);
/*
- * Other architectures don't seem to do this... should we?
+ * Claim the currently allocated resources. This ensures
+ * that we will not allocate an already inuse region.
*/
pcibios_claim_resources();
diff --git a/arch/arm/kernel/dma-arc.c b/arch/arm/kernel/dma-arc.c
index 121a2792b..ad9ca3de5 100644
--- a/arch/arm/kernel/dma-arc.c
+++ b/arch/arm/kernel/dma-arc.c
@@ -40,7 +40,7 @@ static void arc_floppy_data_enable_dma(dmach_t channel, dma_t *dma)
memcpy ((void *)0x1c, (void *)&fdc1772_dma_read,
&fdc1772_dma_read_end - &fdc1772_dma_read);
fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */
- enable_irq (64);
+ enable_fiq(FIQ_FLOPPYDATA);
restore_flags(flags);
}
break;
@@ -55,7 +55,7 @@ static void arc_floppy_data_enable_dma(dmach_t channel, dma_t *dma)
memcpy ((void *)0x1c, (void *)&fdc1772_dma_write,
&fdc1772_dma_write_end - &fdc1772_dma_write);
fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */
- enable_irq (64);
+ enable_fiq(FIQ_FLOPPYDATA;
restore_flags(flags);
}
@@ -102,7 +102,7 @@ static int arc_floppy_cmdend_get_dma_residue(dmach_t channel, dma_t *dma)
static void arc_disable_dma(dmach_t channel, dma_t *dma)
{
- disable_irq(dma->dma_irq);
+ disable_fiq(dma->dma_irq);
}
static struct dma_ops arc_floppy_data_dma_ops = {
@@ -158,12 +158,12 @@ static void a5k_floppy_enable_dma(dmach_t channel, dma_t *dma)
regs.ARM_r10 = dma->buf.address;
regs.ARM_fp = FLOPPYDMA_BASE;
set_fiq_regs(&regs);
- enable_irq(dma->dma_irq);
+ enable_fiq(dma->dma_irq);
}
static void a5k_floppy_disable_dma(dmach_t channel, dma_t *dma)
{
- disable_irq(dma->dma_irq);
+ disable_fiq(dma->dma_irq);
release_fiq(&fh);
}
@@ -192,15 +192,15 @@ void __init arch_dma_init(dma_t *dma)
{
#if defined(CONFIG_BLK_DEV_FD1772) || defined(CONFIG_BLK_DEV_FD1772_MODULE)
if (machine_is_archimedes()) {
- dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64;
+ dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA;
dma[DMA_VIRTUAL_FLOPPY0].d_ops = &arc_floppy_data_dma_ops;
- dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 65;
+ dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 1;
dma[DMA_VIRTUAL_FLOPPY1].d_ops = &arc_floppy_cmdend_dma_ops;
}
#endif
#ifdef CONFIG_ARCH_A5K
if (machine_is_a5k()) {
- dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64;
+ dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA;
dma[DMA_VIRTUAL_FLOPPY0].d_ops = &a5k_floppy_dma_ops;
}
#endif
diff --git a/arch/arm/kernel/dma-rpc.c b/arch/arm/kernel/dma-rpc.c
index b46ca7753..402b71cdb 100644
--- a/arch/arm/kernel/dma-rpc.c
+++ b/arch/arm/kernel/dma-rpc.c
@@ -10,7 +10,7 @@
* DMA functions specific to RiscPC architecture
*/
#include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mman.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -42,11 +42,11 @@ typedef struct {
#define TRANSFER_SIZE 2
#define CURA (0)
-#define ENDA ((IOMD_IO0ENDA - IOMD_IO0CURA) << 2)
-#define CURB ((IOMD_IO0CURB - IOMD_IO0CURA) << 2)
-#define ENDB ((IOMD_IO0ENDB - IOMD_IO0CURA) << 2)
-#define CR ((IOMD_IO0CR - IOMD_IO0CURA) << 2)
-#define ST ((IOMD_IO0ST - IOMD_IO0CURA) << 2)
+#define ENDA (IOMD_IO0ENDA - IOMD_IO0CURA)
+#define CURB (IOMD_IO0CURB - IOMD_IO0CURA)
+#define ENDB (IOMD_IO0ENDB - IOMD_IO0CURA)
+#define CR (IOMD_IO0CR - IOMD_IO0CURA)
+#define ST (IOMD_IO0ST - IOMD_IO0CURA)
#define state_prog_a 0
#define state_wait_a 1
@@ -93,14 +93,14 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
static inline void iomd_setup_dma_a(struct scatterlist *sg, dma_t *dma)
{
- outl_t(sg->dma_address, dma->dma_base + CURA);
- outl_t(sg->length, dma->dma_base + ENDA);
+ iomd_writel(sg->dma_address, dma->dma_base + CURA);
+ iomd_writel(sg->length, dma->dma_base + ENDA);
}
static inline void iomd_setup_dma_b(struct scatterlist *sg, dma_t *dma)
{
- outl_t(sg->dma_address, dma->dma_base + CURB);
- outl_t(sg->length, dma->dma_base + ENDB);
+ iomd_writel(sg->dma_address, dma->dma_base + CURB);
+ iomd_writel(sg->length, dma->dma_base + ENDB);
}
static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
@@ -116,7 +116,7 @@ static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
dma->state = state_wait_a;
case state_wait_a:
- status = inb_t(dma->dma_base + ST);
+ status = iomd_readb(dma->dma_base + ST);
switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
case DMA_ST_OFL|DMA_ST_INT:
iomd_get_next_sg(&dma->cur_sg, dma);
@@ -137,7 +137,7 @@ static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
break;
case state_wait_b:
- status = inb_t(dma->dma_base + ST);
+ status = iomd_readb(dma->dma_base + ST);
switch (status & (DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB)) {
case DMA_ST_OFL|DMA_ST_INT|DMA_ST_AB:
iomd_get_next_sg(&dma->cur_sg, dma);
@@ -193,14 +193,14 @@ static void iomd_enable_dma(dmach_t channel, dma_t *dma)
PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
}
- outb_t(DMA_CR_C, dma_base + CR);
+ iomd_writeb(DMA_CR_C, dma_base + CR);
dma->state = state_prog_a;
}
if (dma->dma_mode == DMA_MODE_READ)
ctrl |= DMA_CR_D;
- outb_t(ctrl, dma_base + CR);
+ iomd_writeb(ctrl, dma_base + CR);
enable_irq(dma->dma_irq);
}
@@ -210,8 +210,8 @@ static void iomd_disable_dma(dmach_t channel, dma_t *dma)
unsigned int ctrl;
disable_irq(dma->dma_irq);
- ctrl = inb_t(dma_base + CR);
- outb_t(ctrl & ~DMA_CR_E, dma_base + CR);
+ ctrl = iomd_readb(dma_base + CR);
+ iomd_writeb(ctrl & ~DMA_CR_E, dma_base + CR);
}
static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle)
@@ -227,7 +227,7 @@ static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle)
else
speed = 0;
- tcr = inb(IOMD_DMATCR);
+ tcr = iomd_readb(IOMD_DMATCR);
speed &= 3;
switch (channel) {
@@ -251,7 +251,7 @@ static int iomd_set_dma_speed(dmach_t channel, dma_t *dma, int cycle)
break;
}
- outb(tcr, IOMD_DMATCR);
+ iomd_writeb(tcr, IOMD_DMATCR);
return speed;
}
@@ -287,7 +287,7 @@ static void floppy_enable_dma(dmach_t channel, dma_t *dma)
regs.ARM_r9 = dma->buf.length;
regs.ARM_r10 = (unsigned long)dma->buf.address;
- regs.ARM_fp = (unsigned long)PCIO_FLOPPYDMABASE;
+ regs.ARM_fp = FLOPPYDMA_BASE;
if (claim_fiq(&fh)) {
printk("floppydma: couldn't claim FIQ.\n");
@@ -296,12 +296,12 @@ static void floppy_enable_dma(dmach_t channel, dma_t *dma)
set_fiq_handler(fiqhandler_start, fiqhandler_length);
set_fiq_regs(&regs);
- enable_irq(dma->dma_irq);
+ enable_fiq(dma->dma_irq);
}
static void floppy_disable_dma(dmach_t channel, dma_t *dma)
{
- disable_irq(dma->dma_irq);
+ disable_fiq(dma->dma_irq);
release_fiq(&fh);
}
@@ -334,32 +334,32 @@ static struct dma_ops sound_dma_ops = {
void __init arch_dma_init(dma_t *dma)
{
- outb(0, IOMD_IO0CR);
- outb(0, IOMD_IO1CR);
- outb(0, IOMD_IO2CR);
- outb(0, IOMD_IO3CR);
+ iomd_writeb(0, IOMD_IO0CR);
+ iomd_writeb(0, IOMD_IO1CR);
+ iomd_writeb(0, IOMD_IO2CR);
+ iomd_writeb(0, IOMD_IO3CR);
- outb(0xa0, IOMD_DMATCR);
+ iomd_writeb(0xa0, IOMD_DMATCR);
- dma[DMA_0].dma_base = ioaddr(IOMD_IO0CURA);
+ dma[DMA_0].dma_base = IOMD_IO0CURA;
dma[DMA_0].dma_irq = IRQ_DMA0;
dma[DMA_0].d_ops = &iomd_dma_ops;
- dma[DMA_1].dma_base = ioaddr(IOMD_IO1CURA);
+ dma[DMA_1].dma_base = IOMD_IO1CURA;
dma[DMA_1].dma_irq = IRQ_DMA1;
dma[DMA_1].d_ops = &iomd_dma_ops;
- dma[DMA_2].dma_base = ioaddr(IOMD_IO2CURA);
+ dma[DMA_2].dma_base = IOMD_IO2CURA;
dma[DMA_2].dma_irq = IRQ_DMA2;
dma[DMA_2].d_ops = &iomd_dma_ops;
- dma[DMA_3].dma_base = ioaddr(IOMD_IO3CURA);
+ dma[DMA_3].dma_base = IOMD_IO3CURA;
dma[DMA_3].dma_irq = IRQ_DMA3;
dma[DMA_3].d_ops = &iomd_dma_ops;
- dma[DMA_S0].dma_base = ioaddr(IOMD_SD0CURA);
+ dma[DMA_S0].dma_base = IOMD_SD0CURA;
dma[DMA_S0].dma_irq = IRQ_DMAS0;
dma[DMA_S0].d_ops = &iomd_dma_ops;
- dma[DMA_S1].dma_base = ioaddr(IOMD_SD1CURA);
+ dma[DMA_S1].dma_base = IOMD_SD1CURA;
dma[DMA_S1].dma_irq = IRQ_DMAS1;
dma[DMA_S1].d_ops = &iomd_dma_ops;
- dma[DMA_VIRTUAL_FLOPPY].dma_irq = 64;
+ dma[DMA_VIRTUAL_FLOPPY].dma_irq = FIQ_FLOPPYDATA;
dma[DMA_VIRTUAL_FLOPPY].d_ops = &floppy_dma_ops;
dma[DMA_VIRTUAL_SOUND].d_ops = &sound_dma_ops;
@@ -367,5 +367,5 @@ void __init arch_dma_init(dma_t *dma)
* Setup DMA channels 2,3 to be for podules
* and channels 0,1 for internal devices
*/
- outb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);
+ iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);
}
diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c
index ad311020f..7f0106953 100644
--- a/arch/arm/kernel/dma.c
+++ b/arch/arm/kernel/dma.c
@@ -12,7 +12,7 @@
* DMA facilities.
*/
#include <linux/module.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/mman.h>
#include <linux/init.h>
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index 3584c3227..07de0170c 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -35,7 +35,7 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
diff --git a/arch/arm/kernel/entry-armo.S b/arch/arm/kernel/entry-armo.S
index e4df9fe1a..65f70c727 100644
--- a/arch/arm/kernel/entry-armo.S
+++ b/arch/arm/kernel/entry-armo.S
@@ -197,8 +197,7 @@ irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
#endif
#define FAULT_CODE_PREFETCH 0x04
#define FAULT_CODE_WRITE 0x02
-#define FAULT_CODE_USER 0x01
-
+#define FAULT_CODE_FORCECOW 0x01
#define SVC_SAVE_ALL \
str sp, [sp, #-16]! ;\
@@ -487,7 +486,6 @@ vector_data: sub lr, lr, #8 @ Correct lr
save_user_regs
teqp pc, #0x00000003 @ NOT a problem - doesnt change mode
mask_pc r0, lr
- mov r2, #FAULT_CODE_USER
bl Ldata_do
b ret_from_exception
@@ -499,7 +497,6 @@ Ldata_not_user:
tst lr, #0x08000000
teqeqp pc, #0x00000003 @ NOT a problem - doesnt change mode
mask_pc r0, lr
- mov r2, #0
bl Ldata_do
SVC_RESTORE_ALL
@@ -510,6 +507,7 @@ Ldata_illegal_mode:
Ldata_do: mov r3, sp
ldr r4, [r0] @ Get instruction
+ mov r2, #0
tst r4, #1 << 20 @ Check to see if it is a write instruction
orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
mov r1, r4, lsr #22 @ Now branch to the relevent processing routine
diff --git a/arch/arm/kernel/fiq.c b/arch/arm/kernel/fiq.c
index 1be23e8fb..da32d69f9 100644
--- a/arch/arm/kernel/fiq.c
+++ b/arch/arm/kernel/fiq.c
@@ -36,12 +36,14 @@
* 6. Goto 3
*/
#include <linux/config.h>
+#include <linux/module.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/init.h>
#include <asm/fiq.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/pgalloc.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -71,7 +73,7 @@ static inline void protect_page_0(void)
* - we always relinquish FIQ control
* - we always reacquire FIQ control
*/
-int fiq_def_op(void *ref, int relinquish)
+static int fiq_def_op(void *ref, int relinquish)
{
if (!relinquish) {
unprotect_page_0();
@@ -214,6 +216,24 @@ void release_fiq(struct fiq_handler *f)
while (current_fiq->fiq_op(current_fiq->dev_id, 0));
}
+void enable_fiq(int fiq)
+{
+ enable_irq(fiq + FIQ_START);
+}
+
+void disable_fiq(int fiq)
+{
+ disable_irq(fiq + FIQ_START);
+}
+
+EXPORT_SYMBOL(set_fiq_handler);
+EXPORT_SYMBOL(set_fiq_regs);
+EXPORT_SYMBOL(get_fiq_regs);
+EXPORT_SYMBOL(claim_fiq);
+EXPORT_SYMBOL(release_fiq);
+EXPORT_SYMBOL(enable_fiq);
+EXPORT_SYMBOL(disable_fiq);
+
void __init init_FIQ(void)
{
no_fiq_insn = *(unsigned long *)FIQ_VECTOR;
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 3c6899264..ae599d255 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -24,7 +24,7 @@
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/init.h>
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 9f50ab6fd..6b045845f 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -17,7 +17,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/delay.h>
#include <linux/reboot.h>
@@ -92,8 +92,10 @@ void cpu_idle(void)
void (*idle)(void) = pm_idle;
if (!idle)
idle = arch_idle;
+ leds_event(led_idle_start);
while (!current->need_resched)
idle();
+ leds_event(led_idle_end);
schedule();
#ifndef CONFIG_NO_PGT_CACHE
check_pgt_cache();
@@ -364,20 +366,23 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
*/
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
- extern long sys_exit(int) __attribute__((noreturn));
pid_t __ret;
__asm__ __volatile__(
- "mov r0, %1 @ kernel_thread sys_clone
+ "orr r0, %1, %2 @ kernel_thread sys_clone
mov r1, #0
"__syscall(clone)"
- teq r0, #0 @ if we are the child
- moveq fp, #0 @ ensure that fp is zero
- mov %0, r0"
+ movs %0, r0 @ if we are the child
+ bne 1f
+ mov fp, #0 @ ensure that fp is zero
+ mov r0, %4
+ mov lr, pc
+ mov pc, %3
+ b sys_exit
+1: "
: "=r" (__ret)
- : "Ir" (flags | CLONE_VM) : "r0", "r1");
- if (__ret == 0)
- sys_exit((fn)(arg));
+ : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg)
+ : "r0", "r1", "lr");
return __ret;
}
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 36bbf3ac8..16b8e59ea 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -14,7 +14,7 @@
*/
#include <linux/errno.h>
#include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/sem.h>
#include <linux/msg.h>
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 926cdff2f..be24bdcfc 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -134,32 +134,17 @@ void (*leds_event)(led_event_t) = dummy_leds_event;
#ifdef CONFIG_MODULES
EXPORT_SYMBOL(leds_event);
#endif
+#endif
+#ifdef CONFIG_LEDS_TIMER
static void do_leds(void)
{
-#ifdef CONFIG_LEDS_CPU
- {
- static int last_pid;
-
- if (current->pid != last_pid) {
- last_pid = current->pid;
- if (last_pid)
- leds_event(led_idle_end);
- else
- leds_event(led_idle_start);
- }
- }
-#endif
-#ifdef CONFIG_LEDS_TIMER
- {
- static unsigned int count = 50;
+ static unsigned int count = 50;
- if (--count == 0) {
- count = 50;
- leds_event(led_timer);
- }
+ if (--count == 0) {
+ count = 50;
+ leds_event(led_timer);
}
-#endif
}
#else
#define do_leds()
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 9d0cc5c69..8455caf78 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -107,7 +107,7 @@ static void dump_instr(struct pt_regs *regs)
bad = __get_user(val, &((u32 *)addr)[i]);
if (!bad)
- printk(i == 0 ? "(%0*x) " : "%0*x", width, val);
+ printk(i == 0 ? "(%0*x) " : "%0*x ", width, val);
else {
printk("bad PC value.");
break;
@@ -133,7 +133,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
printk("no frame pointer");
ok = 0;
} else if (verify_stack(fp)) {
- printk("invalid frame pointer %08lx", fp);
+ printk("invalid frame pointer 0x%08x", fp);
ok = 0;
} else if (fp < 4096+(unsigned long)tsk)
printk("frame pointer underflow");
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index fa7f10117..ee111801f 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -1,58 +1,58 @@
#
# linux/arch/arm/lib/Makefile
#
-# Copyright (C) 1995-1999 Russell King
+# Copyright (C) 1995-2000 Russell King
#
USE_STANDARD_AS_RULE := true
-L_TARGET := lib.a
-L_OBJS := changebit.o csumipv6.o csumpartial.o csumpartialcopy.o \
- csumpartialcopyuser.o clearbit.o copy_page.o findbit.o \
- memchr.o memcpy.o memset.o memzero.o setbit.o \
- strncpy_from_user.o strnlen_user.o strchr.o strrchr.o \
- testchangebit.o testclearbit.o testsetbit.o uaccess.o
-
-l-obj-y :=
-l-obj-n :=
-
-O_TARGET := lib.o
-O_OBJS := backtrace.o delay.o
-
-ifeq ($(CONFIG_ARCH_ACORN),y)
- half := n
- full := y
+L_TARGET := lib.a
+
+obj-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
+ csumpartialcopy.o csumpartialcopyuser.o clearbit.o \
+ copy_page.o delay.o findbit.o memchr.o memcpy.o \
+ memset.o memzero.o setbit.o strncpy_from_user.o \
+ strnlen_user.o strchr.o strrchr.o testchangebit.o \
+ testclearbit.o testsetbit.o uaccess.o
+obj-m :=
+obj-n :=
+
+export-objs := io.o
+
+obj-arc := ecard.o io-acorn.o floppydma.o
+obj-rpc := ecard.o io-acorn.o floppydma.o
+obj-clps7500 := io-acorn.o
+obj-footbridge := io-pcio.o
+obj-l7200 := io-acorn.o
+obj-nexuspci := io-pcio.o
+obj-sa1100 := io-pcio.o
+obj-shark := io-shark.o
+obj-integrator := io-pcio.o
+obj-clps711x := io-shark.o
+
+obj-y += $(obj-$(MACHINE))
+
+ifeq ($(CONFIG_CPU_32v4),y)
+ v3 := n
+ v4 := y
else
- half := y
- full := n
+ v3 := y
+ v4 := n
endif
-L_OBJS_arc := ecard.o io-acorn.o floppydma.o
-L_OBJS_rpc := ecard.o io-acorn.o floppydma.o
-L_OBJS_clps7500 := io-acorn.o
-L_OBJS_footbridge := io-pcio.o
-L_OBJS_l7200 := io-acorn.o
-L_OBJS_nexuspci := io-pcio.o
-L_OBJS_sa1100 := io-pcio.o
-L_OBJS_shark := io-shark.o
-L_OBJS_integrator := io-pcio.o
-L_OBJS_clps711x := io-shark.o
-
-l-obj-y += io-readsb.o io-writesb.o
-l-obj-$(full) += io-readsw-armv3.o io-writesw-armv3.o
-l-obj-$(half) += io-readsw-armv4.o io-writesw-armv4.o
-l-obj-y += io-readsl.o io-writesl.o
+obj-y += io-readsb.o io-writesb.o
+obj-$(v3) += io-readsw-armv3.o io-writesw-armv3.o io-readsl-armv3.o
+obj-$(v4) += io-readsw-armv4.o io-writesw-armv4.o io-readsl-armv4.o
+obj-y += io-writesl.o
ifeq ($(PROCESSOR),armo)
- L_OBJS += uaccess-armo.o
+ obj-y += uaccess-armo.o
endif
ifneq ($(MACHINE),ebsa110)
- OX_OBJS += io.o
+ obj-y += io.o
endif
-L_OBJS += $(L_OBJS_$(MACHINE)) $(l-obj-y)
-
include $(TOPDIR)/Rules.make
constants.h: getconsdata.o extractconstants.pl
diff --git a/arch/arm/lib/io-acorn.S b/arch/arm/lib/io-acorn.S
index a40272fdb..db19d932e 100644
--- a/arch/arm/lib/io-acorn.S
+++ b/arch/arm/lib/io-acorn.S
@@ -60,32 +60,32 @@ ENTRY(outsl)
*/
ENTRY(insw)
- teq r2, #0
- RETINSTR(moveq, pc, lr)
addr r0
- b __arch_readsw
+ teq r2, #0
+ bne __arch_readsw
+ RETINSTR(mov, pc, lr)
ENTRY(insb)
- teq r2, #0
- RETINSTR(moveq, pc, lr)
addr r0
- b __arch_readsb
+ teq r2, #0
+ bne __arch_readsb
+ RETINSTR(mov, pc, lr)
@ Purpose: write a block of data from memory to a hardware register.
@ Proto : outsw(int to_reg, void *from, int len_in_words);
@ Notes : increments from
ENTRY(outsw)
- teq r2, #0
- RETINSTR(moveq, pc, lr)
addr r0
- b __arch_writesw
+ teq r2, #0
+ bne __arch_writesw
+ RETINSTR(mov, pc, lr)
ENTRY(outsb)
- teq r2, #0
- RETINSTR(moveq, pc, lr)
addr r0
- b __arch_writesb
+ teq r2, #0
+ bne __arch_writesb
+ RETINSTR(mov, pc, lr)
@ Purpose: write a memc register
@ Proto : void memc_write(int register, int value);
diff --git a/arch/arm/lib/io-pcio.S b/arch/arm/lib/io-pcio.S
index f57abfc10..243366b86 100644
--- a/arch/arm/lib/io-pcio.S
+++ b/arch/arm/lib/io-pcio.S
@@ -1,4 +1,5 @@
#include <linux/linkage.h>
+#include <asm/assembler.h>
#include <asm/hardware.h>
.equ pcio_high, PCIO_BASE & 0xff000000
@@ -13,26 +14,37 @@
ENTRY(insl)
ioaddr r0, r0
- b __arch_readsl
+ teq r2, #0
+ bne __arch_readsl
+ RETINSTR(mov, pc, lr)
ENTRY(outsl)
ioaddr r0, r0
- b __arch_writesl
-
- /* Nobody could say these are optimal, but not to worry. */
+ teq r2, #0
+ bne __arch_writesl
+ RETINSTR(mov, pc, lr)
ENTRY(outsw)
ioaddr r0, r0
- b __arch_writesw
+ teq r2, #0
+ bne __arch_writesw
+ RETINSTR(mov, pc, lr)
ENTRY(insw)
ioaddr r0, r0
- b __arch_readsw
+ teq r2, #0
+ bne __arch_readsw
+ RETINSTR(mov, pc, lr)
ENTRY(insb)
ioaddr r0, r0
- b __arch_readsb
+ teq r2, #0
+ bne __arch_readsb
+ RETINSTR(mov, pc, lr)
ENTRY(outsb)
ioaddr r0, r0
- b __arch_writesb
+ teq r2, #0
+ bne __arch_writesb
+ RETINSTR(mov, pc, lr)
+
diff --git a/arch/arm/lib/io-readsb.S b/arch/arm/lib/io-readsb.S
index 23cca8929..a31381fd5 100644
--- a/arch/arm/lib/io-readsb.S
+++ b/arch/arm/lib/io-readsb.S
@@ -62,6 +62,7 @@ ENTRY(__arch_readsb)
ldrb ip, [r0]
orr r6, r6, ip, lsl #24
stmia r1!, {r3 - r6}
+
subs r2, r2, #16
bpl .insb_16_lp
@@ -88,7 +89,7 @@ ENTRY(__arch_readsb)
stmia r1!, {r3, r4}
.insb_no_8: tst r2, #4
- bne .insb_no_4
+ beq .insb_no_4
ldrb r3, [r0]
ldrb r4, [r0]
@@ -101,6 +102,7 @@ ENTRY(__arch_readsb)
.insb_no_4: ands r2, r2, #3
LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
cmp r2, #2
ldrb r3, [r0]
strb r3, [r1], #1
@@ -108,4 +110,5 @@ ENTRY(__arch_readsb)
strgeb r3, [r1], #1
ldrgtb r3, [r0]
strgtb r3, [r1]
+
LOADREGS(fd, sp!, {r4 - r6, pc})
diff --git a/arch/arm/lib/io-readsl-armv3.S b/arch/arm/lib/io-readsl-armv3.S
new file mode 100644
index 000000000..0751c3157
--- /dev/null
+++ b/arch/arm/lib/io-readsl-armv3.S
@@ -0,0 +1,76 @@
+/*
+ * linux/arch/arm/lib/io-readsl-armv3.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+
+/*
+ * Note that some reads can be aligned on half-word boundaries.
+ */
+ENTRY(__arch_readsl)
+ ands ip, r1, #3
+ bne 2f
+
+1: ldr r3, [r0]
+ str r3, [r1], #4
+ subs r2, r2, #1
+ bne 1b
+ mov pc, lr
+
+2: cmp ip, #2
+ ldr ip, [r0]
+ blt 4f
+ bgt 6f
+
+ strb ip, [r1], #1
+ mov ip, ip, lsr #8
+ strb ip, [r1], #1
+ mov ip, ip, lsr #8
+3: subs r2, r2, #1
+ ldrne r3, [r0]
+ orrne ip, ip, r3, lsl #16
+ strne ip, [r1], #4
+ movne ip, r3, lsr #16
+ bne 3b
+ strb ip, [r1], #1
+ mov ip, ip, lsr #8
+ strb ip, [r1], #1
+ mov pc, lr
+
+4: strb ip, [r1], #1
+ mov ip, ip, lsr #8
+ strb ip, [r1], #1
+ mov ip, ip, lsr #8
+ strb ip, [r1], #1
+ mov ip, ip, lsr #8
+5: subs r2, r2, #1
+ ldrne r3, [r0]
+ orrne ip, ip, r3, lsl #8
+ strne ip, [r1], #4
+ movne ip, r3, lsr #24
+ bne 5b
+ strb ip, [r1], #1
+ mov pc, lr
+
+6: strb ip, [r1], #1
+ mov ip, ip, lsr #8
+7: subs r2, r2, #1
+ ldrne r3, [r0]
+ orrne ip, ip, r3, lsl #24
+ strne ip, [r1], #4
+ movne ip, r3, lsr #8
+ bne 7b
+ strb ip, [r1], #1
+ mov ip, ip, lsr #8
+ strb ip, [r1], #1
+ mov ip, ip, lsr #8
+ strb ip, [r1], #1
+ mov pc, lr
+
diff --git a/arch/arm/lib/io-readsl.S b/arch/arm/lib/io-readsl-armv4.S
index 530175485..08b3d350f 100644
--- a/arch/arm/lib/io-readsl.S
+++ b/arch/arm/lib/io-readsl-armv4.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/lib/io-readsb.S
+ * linux/arch/arm/lib/io-readsl-armv4.S
*
* Copyright (C) 1995-2000 Russell King
*
@@ -11,6 +11,9 @@
#include <asm/assembler.h>
#include <asm/hardware.h>
+/*
+ * Note that some reads can be aligned on half-word boundaries.
+ */
ENTRY(__arch_readsl)
ands ip, r1, #3
bne 2f
diff --git a/arch/arm/lib/io-readsw-armv3.S b/arch/arm/lib/io-readsw-armv3.S
index 65fb94e2f..cb2d5cee9 100644
--- a/arch/arm/lib/io-readsw-armv3.S
+++ b/arch/arm/lib/io-readsw-armv3.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/lib/io-readsb.S
+ * linux/arch/arm/lib/io-readsw-armv3.S
*
* Copyright (C) 1995-2000 Russell King
*
@@ -62,8 +62,10 @@ ENTRY(__arch_readsw)
orr r6, r6, lr, lsl #16
stmia r1!, {r3 - r6}
+
subs r2, r2, #8
bpl .insw_8_lp
+
tst r2, #7
LOADREGS(eqfd, sp!, {r4, r5, r6, pc})
@@ -97,6 +99,7 @@ ENTRY(__arch_readsw)
strneb r3, [r1], #1
movne r3, r3, lsr #8
strneb r3, [r1]
+
LOADREGS(fd, sp!, {r4, r5, r6, pc})
diff --git a/arch/arm/lib/io-readsw-armv4.S b/arch/arm/lib/io-readsw-armv4.S
index 6f1750a49..10eeee99f 100644
--- a/arch/arm/lib/io-readsw-armv4.S
+++ b/arch/arm/lib/io-readsw-armv4.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/lib/io-readsb.S
+ * linux/arch/arm/lib/io-readsw-armv4.S
*
* Copyright (C) 1995-2000 Russell King
*
@@ -46,16 +46,18 @@ ENTRY(__arch_readsw)
orr r4, r4, r5, lsl #16
ldrh r5, [r0]
- ldrh r6, [r0]
- orr r5, r5, r6, lsl #16
+ ldrh ip, [r0]
+ orr r5, r5, ip, lsl #16
ldrh ip, [r0]
ldrh lr, [r0]
orr ip, ip, lr, lsl #16
stmia r1!, {r3 - r5, ip}
+
subs r2, r2, #8
bpl .insw_8_lp
+
tst r2, #7
LOADREGS(eqfd, sp!, {r4, r5, pc})
@@ -84,4 +86,5 @@ ENTRY(__arch_readsw)
.no_insw_2: tst r2, #1
ldrneh r3, [r0]
strneh r3, [r1]
+
LOADREGS(fd, sp!, {r4, r5, pc})
diff --git a/arch/arm/lib/io-writesb.S b/arch/arm/lib/io-writesb.S
index b919fdaad..a9a8c4af9 100644
--- a/arch/arm/lib/io-writesb.S
+++ b/arch/arm/lib/io-writesb.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/lib/io-readsb.S
+ * linux/arch/arm/lib/io-writesb.S
*
* Copyright (C) 1995-2000 Russell King
*
@@ -13,7 +13,7 @@
.outsb_align: rsb ip, ip, #4
cmp ip, r2
- mov ip, r2
+ movgt ip, r2
cmp ip, #2
ldrb r3, [r1], #1
strb r3, [r0]
@@ -34,6 +34,7 @@ ENTRY(__arch_writesb)
bmi .outsb_no_16
.outsb_16_lp: ldmia r1!, {r3 - r6}
+
strb r3, [r0]
mov r3, r3, lsr #8
strb r3, [r0]
@@ -65,6 +66,7 @@ ENTRY(__arch_writesb)
strb r6, [r0]
mov r6, r6, lsr #8
strb r6, [r0]
+
subs r2, r2, #16
bpl .outsb_16_lp
@@ -74,7 +76,8 @@ ENTRY(__arch_writesb)
.outsb_no_16: tst r2, #8
beq .outsb_no_8
- ldmia r1, {r3, r4}
+ ldmia r1!, {r3, r4}
+
strb r3, [r0]
mov r3, r3, lsr #8
strb r3, [r0]
@@ -92,7 +95,7 @@ ENTRY(__arch_writesb)
strb r4, [r0]
.outsb_no_8: tst r2, #4
- bne .outsb_no_4
+ beq .outsb_no_4
ldr r3, [r1], #4
strb r3, [r0]
@@ -105,6 +108,7 @@ ENTRY(__arch_writesb)
.outsb_no_4: ands r2, r2, #3
LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
cmp r2, #2
ldrb r3, [r1], #1
strb r3, [r0]
@@ -112,4 +116,5 @@ ENTRY(__arch_writesb)
strgeb r3, [r0]
ldrgtb r3, [r1]
strgtb r3, [r0]
+
LOADREGS(fd, sp!, {r4 - r6, pc})
diff --git a/arch/arm/lib/io-writesl.S b/arch/arm/lib/io-writesl.S
index ccda08c39..aa3340bdd 100644
--- a/arch/arm/lib/io-writesl.S
+++ b/arch/arm/lib/io-writesl.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/lib/io-readsb.S
+ * linux/arch/arm/lib/io-writesl.S
*
* Copyright (C) 1995-2000 Russell King
*
diff --git a/arch/arm/lib/io-writesw-armv3.S b/arch/arm/lib/io-writesw-armv3.S
index 29c94cc3d..fce7d5ef5 100644
--- a/arch/arm/lib/io-writesw-armv3.S
+++ b/arch/arm/lib/io-writesw-armv3.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/lib/io-readsb.S
+ * linux/arch/arm/lib/io-writesw-armv3.S
*
* Copyright (C) 1995-2000 Russell King
*
@@ -39,6 +39,7 @@ ENTRY(__arch_writesw)
subs r2, r2, #8
bmi .no_outsw_8
+
.outsw_8_lp: ldmia r1!, {r3, r4, r5, r6}
mov ip, r3, lsl #16
@@ -75,6 +76,7 @@ ENTRY(__arch_writesw)
subs r2, r2, #8
bpl .outsw_8_lp
+
tst r2, #7
LOADREGS(eqfd, sp!, {r4, r5, r6, pc})
@@ -121,5 +123,3 @@ ENTRY(__arch_writesw)
strne ip, [r0]
LOADREGS(fd, sp!, {r4, r5, r6, pc})
-
-
diff --git a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S
index 0f96d1325..bac67a42e 100644
--- a/arch/arm/lib/io-writesw-armv4.S
+++ b/arch/arm/lib/io-writesw-armv4.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/lib/io-readsb.S
+ * linux/arch/arm/lib/io-writesw-armv4.S
*
* Copyright (C) 1995-2000 Russell King
*
@@ -32,11 +32,11 @@ ENTRY(__arch_writesw)
tst r1, #3
bne .outsw_align
+ stmfd sp!, {r4, r5, lr}
+
subs r2, r2, #8
bmi .no_outsw_8
- stmfd sp!, {r4, r5, lr}
-
.outsw_8_lp: ldmia r1!, {r3, r4, r5, ip}
strh r3, [r0]
@@ -54,26 +54,31 @@ ENTRY(__arch_writesw)
subs r2, r2, #8
bpl .outsw_8_lp
- ldmfd sp!, {r4, r5, lr}
+
tst r2, #7
- RETINSTR(moveq, pc, lr)
+ LOADREGS(eqfd, sp!, {r4, r5, pc})
.no_outsw_8: tst r2, #4
- ldmneia r1!, {r3, ip}
- strneh r3, [r0]
- movne r3, r3, lsr #16
- strneh r3, [r0]
- strneh ip, [r0]
- movne ip, ip, lsr #16
- strneh ip, [r0]
- tst r2, #2
- ldrne r3, [r1], #4
- strneh r3, [r0]
- movne r3, r3, lsr #16
- strneh r3, [r0]
- tst r2, #1
+ beq .no_outsw_4
+
+ ldmia r1!, {r3, ip}
+ strh r3, [r0]
+ mov r3, r3, lsr #16
+ strh r3, [r0]
+ strh ip, [r0]
+ mov ip, ip, lsr #16
+ strh ip, [r0]
+
+.no_outsw_4: tst r2, #2
+ beq .no_outsw_2
+
+ ldr r3, [r1], #4
+ strh r3, [r0]
+ mov r3, r3, lsr #16
+ strh r3, [r0]
+
+.no_outsw_2: tst r2, #1
ldrneh r3, [r1]
strneh r3, [r0]
- RETINSTR(mov, pc, lr)
-
+ LOADREGS(fd, sp!, {r4, r5, pc})
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index 441608295..3a61edf39 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -20,15 +20,4 @@ export-objs := hw.o leds.o
obj-$(CONFIG_LEDS) += leds.o
-# Files that are both resident and modular; remove from modular.
-
-obj-m := $(filter-out $(obj-y), $(obj-m))
-
-# Translate to Rules.make lists.
-
-O_OBJS := $(filter-out $(export-objs), $(obj-y))
-OX_OBJS := $(filter $(export-objs), $(obj-y))
-M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-
include $(TOPDIR)/Rules.make
diff --git a/arch/arm/mach-sa1100/hw.c b/arch/arm/mach-sa1100/hw.c
index 1ccc61fe3..a28b28177 100644
--- a/arch/arm/mach-sa1100/hw.c
+++ b/arch/arm/mach-sa1100/hw.c
@@ -90,12 +90,12 @@ static int bitsy_egpio = EGPIO_BITSY_RS232_ON;
void clr_bitsy_egpio(unsigned long x)
{
bitsy_egpio &= ~x;
- *(volatile int *)0xdc000000 = bitsy_egpio;
+ BITSY_EGPIO = bitsy_egpio;
}
void set_bitsy_egpio(unsigned long x)
{
bitsy_egpio |= x;
- *(volatile int *)0xdc000000 = bitsy_egpio;
+ BITSY_EGPIO = bitsy_egpio;
}
EXPORT_SYMBOL(clr_bitsy_egpio);
EXPORT_SYMBOL(set_bitsy_egpio);
@@ -119,8 +119,8 @@ static void __init sa1111_init(void){
/* First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
* (SA-1110 Developer's Manual, section 9.1.2.1)
*/
- GAFR |= GPIO_GPIO27;
- GPDR |= GPIO_GPIO27;
+ GAFR |= GPIO_32_768kHz;
+ GPDR |= GPIO_32_768kHz;
TUCR = TUCR_3_6864MHz;
/* Now, set up the PLL and RCLK in the SA-1111: */
@@ -133,32 +133,32 @@ static void __init sa1111_init(void){
* using the SKPCR.
*/
- {
- /*
- * SA1111 DMA bus master setup
+ /* If the system is going to use the SA-1111 DMA engines, set up
+ * the memory bus request/grant pins. Also configure the shared
+ * memory controller on the SA-1111 (SA-1111 Developer's Manual,
+ * section 3.2.3) and power up the DMA bus clock:
*/
- int cas;
-
- /* SA1111 side */
- switch ( (MDCNFG>>12) & 0x03 ) {
- case 0x02:
- cas = 0; break;
- case 0x03:
- cas = 1; break;
- default:
- cas = 1; break;
- }
- SMCR = 1 /* 1: memory is SDRAM */
- | ( 1 << 1 ) /* 1:MBGNT is enable */
- | ( ((MDCNFG >> 4) & 0x07) << 2 ) /* row address lines */
- | ( cas << 5 ); /* CAS latency */
-
- /* SA1110 side */
- GPDR |= 1<<21;
- GPDR &= ~(1<<22);
- GAFR |= ( (1<<21) | (1<<22) );
-
- TUCR |= (1<<10);
+ if(machine_is_assabet()){
+
+ GAFR |= (GPIO_MBGNT | GPIO_MBREQ);
+ GPDR |= GPIO_MBGNT;
+ GPDR &= ~GPIO_MBREQ;
+ TUCR |= TUCR_MR;
+
+ /* Assabet is populated by default with two Samsung KM416S8030T-G8
+ * 128Mb SDRAMs, which are organized as 12-bit (row addr) x 9-bit
+ * (column addr), according to the data sheet. Apparently, the
+ * bank selects factor into the row address, as Angel sets up the
+ * SA-1110 to use 14x9 addresses. The SDRAM datasheet specifies
+ * that when running at 100-125MHz, the CAS latency for -8 parts
+ * is 3 cycles, which is consistent with Angel.
+ */
+
+ SMCR = (SMCR_DTIM | SMCR_MBGE |
+ FInsrt(FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), SMCR_DRAC) |
+ ((FExtr(MDCNFG, MDCNFG_SA1110_TDL0)==3) ? SMCR_CLAT : 0));
+
+ SKPCR |= SKPCR_DCLKEN;
}
}
diff --git a/arch/arm/mach-shark/Makefile b/arch/arm/mach-shark/Makefile
index 414d0c2e1..c6a4d4023 100644
--- a/arch/arm/mach-shark/Makefile
+++ b/arch/arm/mach-shark/Makefile
@@ -5,6 +5,8 @@
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
+USE_STANDARD_AS_RULE := true
+
O_TARGET := shark.o
# Object file lists.
@@ -18,15 +20,4 @@ export-objs :=
#obj-$(CONFIG_LEDS) += leds.o
-# Files that are both resident and modular; remove from modular.
-
-obj-m := $(filter-out $(obj-y), $(obj-m))
-
-# Translate to Rules.make lists.
-
-O_OBJS := $(filter-out $(export-objs), $(obj-y))
-OX_OBJS := $(filter $(export-objs), $(obj-y))
-M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-
include $(TOPDIR)/Rules.make
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index fe3cf5eac..5cc3ff520 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -9,12 +9,11 @@
USE_STANDARD_AS_RULE := true
-EXTRA_AFLAGS := -traditional
O_TARGET := mm.o
# Object file lists.
-obj-y := extable.o fault-$(PROCESSOR).o init.o \
+obj-y := extable.o fault-common.o fault-$(PROCESSOR).o init.o \
mm-$(PROCESSOR).o small_page.o
obj-m :=
obj-n :=
@@ -22,10 +21,10 @@ obj- :=
export-objs := proc-syms.o
p-$(CONFIG_CPU_26) += proc-arm2,3.o
-p-$(CONFIG_CPU_ARM6) += proc-arm6,7.o
-p-$(CONFIG_CPU_ARM7) += proc-arm6,7.o
-p-$(CONFIG_CPU_ARM720) += proc-arm720.o
-p-$(CONFIG_CPU_ARM920) += proc-arm920.o
+p-$(CONFIG_CPU_ARM610) += proc-arm6,7.o
+p-$(CONFIG_CPU_ARM710) += proc-arm6,7.o
+p-$(CONFIG_CPU_ARM720T) += proc-arm720.o
+p-$(CONFIG_CPU_ARM920T) += proc-arm920.o
p-$(CONFIG_CPU_ARM10) += proc-arm10.o
p-$(CONFIG_CPU_SA110) += proc-sa110.o
p-$(CONFIG_CPU_SA1100) += proc-sa110.o
@@ -37,29 +36,16 @@ endif
# Integrator follows "new style"
# Soon, others will do too, and we can get rid of this
-MMMACH := mm-$(MACHINE).o
+MMMACH := mm-$(MACHINE).c
ifeq ($(MMMACH),$(wildcard $(MMMACH)))
-obj-$(CONFIG_CPU_32) += $(MMMACH)
+obj-$(CONFIG_CPU_32) += $(MMMACH:.c=.o)
endif
obj-y += $(sort $(p-y))
-# Files that are both resident and modular; remove from modular.
-
-obj-m := $(filter-out $(obj-y), $(obj-m))
-
-# Translate to Rules.make lists.
-
-O_OBJS := $(filter-out $(export-objs), $(obj-y))
-OX_OBJS := $(filter $(export-objs), $(obj-y))
-M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
-MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
-
include $(TOPDIR)/Rules.make
# Special dependencies
-fault-armv.o: fault-common.c
-fault-armo.o: fault-common.c
proc-arm2,3.o: ../lib/constants.h
proc-arm6,7.o: ../lib/constants.h
proc-arm720.o: ../lib/constants.h
diff --git a/arch/arm/mm/fault-armo.c b/arch/arm/mm/fault-armo.c
index 85b2dc2f4..a37c625f4 100644
--- a/arch/arm/mm/fault-armo.c
+++ b/arch/arm/mm/fault-armo.c
@@ -23,14 +23,20 @@
#include <asm/uaccess.h>
#include <asm/pgtable.h>
-#define FAULT_CODE_FORCECOW 0x80
+#define FAULT_CODE_LDRSTRPOST 0x80
+#define FAULT_CODE_LDRSTRPRE 0x40
+#define FAULT_CODE_LDRSTRREG 0x20
+#define FAULT_CODE_LDMSTM 0x10
+#define FAULT_CODE_LDCSTC 0x08
#define FAULT_CODE_PREFETCH 0x04
#define FAULT_CODE_WRITE 0x02
+#define FAULT_CODE_FORCECOW 0x01
#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW))
#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE))
-#include "fault-common.c"
+extern int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs);
+extern void show_pte(struct mm_struct *mm, unsigned long addr);
/*
* Handle a data abort. Note that we have to handle a range of addresses
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index f184b4e68..a6a45f091 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -27,27 +27,9 @@
#include <asm/pgtable.h>
#include <asm/unaligned.h>
-#define FAULT_CODE_READ 0x02
-
-#define DO_COW(m) (!((m) & FAULT_CODE_READ))
-#define READ_FAULT(m) ((m) & FAULT_CODE_READ)
-
extern void die_if_kernel(const char *str, struct pt_regs *regs, int err);
-
-#include "fault-common.c"
-
-#ifdef DEBUG
-static int sp_valid(unsigned long *sp)
-{
- unsigned long addr = (unsigned long) sp;
-
- if (addr >= 0xb0000000 && addr < 0xd0000000)
- return 1;
- if (addr >= 0x03ff0000 && addr < 0x04000000)
- return 1;
- return 0;
-}
-#endif
+extern void show_pte(struct mm_struct *mm, unsigned long addr);
+extern int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs);
#ifdef CONFIG_ALIGNMENT_TRAP
/*
@@ -178,6 +160,15 @@ do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
eaddr -= offset.un;
}
+ /*
+ * This is a "hint" - we already have eaddr worked out by the
+ * processor for us.
+ */
+ if (addr != eaddr)
+ printk(KERN_ERR "LDRHSTRH: PC = %08lx, instr = %08x, "
+ "addr = %08lx, eaddr = %08lx\n",
+ instruction_pointer(regs), instr, addr, eaddr);
+
if (LDST_L_BIT(instr))
regs->uregs[rd] = get_unaligned((unsigned short *)eaddr);
else
@@ -253,8 +244,15 @@ do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
}
}
-if (addr != eaddr)
-printk("PC = %08lx, instr = %08x, addr = %08lx, eaddr = %08lx\n", instruction_pointer(regs), instr, addr, eaddr);
+ /*
+ * This is a "hint" - we already have eaddr worked out by the
+ * processor for us.
+ */
+ if (addr != eaddr)
+ printk(KERN_ERR "LDRSTR: PC = %08lx, instr = %08x, "
+ "addr = %08lx, eaddr = %08lx\n",
+ instruction_pointer(regs), instr, addr, eaddr);
+
if (LDST_L_BIT(instr)) {
regs->uregs[rd] = get_unaligned((unsigned long *)eaddr);
if (rd == 15)
@@ -284,6 +282,15 @@ printk("PC = %08lx, instr = %08x, addr = %08lx, eaddr = %08lx\n", instruction_po
if (!LDST_U_BIT(instr))
eaddr -= nr_regs;
+ /*
+ * This is a "hint" - we already have eaddr worked out by the
+ * processor for us.
+ */
+ if (addr != eaddr)
+ printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08x, "
+ "addr = %08lx, eaddr = %08lx\n",
+ instruction_pointer(regs), instr, addr, eaddr);
+
if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) ||
(LDST_U_BIT(instr) && LDST_P_BIT(instr)))
eaddr += 4;
@@ -322,39 +329,39 @@ printk("PC = %08lx, instr = %08x, addr = %08lx, eaddr = %08lx\n", instruction_po
#endif
-#ifdef CONFIG_DEBUG_USER
-
+/*
+ * Some section permission faults need to be handled gracefully, for
+ * instance, when they happen due to a __{get,put}_user during an oops).
+ * In this case, we should return an error to the __{get,put}_user caller
+ * instead of causing another oops. We should also fixup this fault as
+ * the user could pass a pointer to a section to the kernel.
+ */
static int
do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs)
{
+ unsigned long fixup;
+
if (user_mode(regs)) {
+#ifdef CONFIG_DEBUG_USER
printk("%s: permission fault on section, "
"address=0x%08lx, code %d\n",
current->comm, addr, error_code);
+#endif
+ goto fail;
+ }
+
+ fixup = search_exception_table(instruction_pointer(regs));
+ if (fixup != 0) {
#ifdef DEBUG
- {
- unsigned int i, j;
- unsigned long *sp;
-
- sp = (unsigned long *) (regs->ARM_sp - 128);
- for (j = 0; j < 20 && sp_valid(sp); j++) {
- printk("%p: ", sp);
- for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++)
- printk("%08lx ", *sp);
- printk("\n");
- }
- show_regs(regs);
- c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
- }
+ printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
+ tsk->comm, regs->ARM_pc, addr, fixup);
#endif
+ regs->ARM_pc = fixup;
+ return 0;
}
+fail:
return 1; /* not fixed up */
}
-#else
-
-#define do_sect_fault NULL
-
-#endif
static const struct fsr_info {
int (*fn)(unsigned long addr, int error_code, struct pt_regs *regs);
@@ -382,18 +389,19 @@ static const struct fsr_info {
/*
* Currently dropped down to debug level
*/
-#define BUG_PROC_MSG \
- KERN_DEBUG "Weird data abort (%08X).\n" \
- KERN_DEBUG "Please see http://www.arm.linux.org.uk/state.html for " \
- "more information\n"
-
asmlinkage void
do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr)
{
const struct fsr_info *inf = fsr_info + (fsr & 15);
+#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
if (addr == regs->ARM_pc)
- goto weirdness;
+ goto sa1_weirdness;
+#endif
+#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP)
+ if (addr & 3 && (fsr & 13) != 1)
+ goto arm720_weirdness;
+#endif
if (!inf->fn)
goto bad;
@@ -409,26 +417,51 @@ bad:
die_if_kernel("Oops", regs, 0);
return;
-weirdness:
+#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
+sa1_weirdness:
if (user_mode(regs)) {
static int first = 1;
if (first)
- /*
- * I want statistical information on this problem,
- * but we don't want to hastle the users too much.
- */
- printk(BUG_PROC_MSG, fsr);
+ printk(KERN_DEBUG "Weird data abort detected\n");
first = 0;
return;
}
if (!inf->fn || inf->fn(addr, error_code, regs))
goto bad;
+ return;
+#endif
+#if defined(CONFIG_CPU_ARM720T) && defined(CONFIG_ALIGNMENT_TRAP)
+arm720_weirdness:
+ if (!user_mode(regs)) {
+ unsigned long instr;
+
+ instr = *(unsigned long *)instruction_pointer(regs);
+
+ if ((instr & 0x04400000) != 0x04400000) {
+ static int first = 1;
+ if (first)
+ printk("Mis-reported alignment fault at "
+ "0x%08lx, fsr 0x%02x, code 0x%02x, "
+ "PC = 0x%08lx, instr = 0x%08lx\n",
+ addr, fsr, error_code, regs->ARM_pc,
+ instr);
+ first = 0;
+ cpu_tlb_invalidate_all();
+ cpu_cache_clean_invalidate_all();
+ return;
+ }
+ }
+
+ if (!inf->fn || inf->fn(addr, error_code, regs))
+ goto bad;
+ return;
+#endif
}
asmlinkage int
do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
{
- do_page_fault(addr, FAULT_CODE_READ, regs);
+ do_page_fault(addr, 0, regs);
return 1;
}
diff --git a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c
index 1cbdd7790..f79b618a2 100644
--- a/arch/arm/mm/fault-common.c
+++ b/arch/arm/mm/fault-common.c
@@ -9,8 +9,41 @@
* published by the Free Software Foundation.
*/
#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/unaligned.h>
+
+#ifdef CONFIG_CPU_26
+#define FAULT_CODE_WRITE 0x02
+#define FAULT_CODE_FORCECOW 0x01
+#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW))
+#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE))
+#else
+/*
+ * On 32-bit processors, we define "mode" to be zero when reading,
+ * non-zero when writing. This now ties up nicely with the polarity
+ * of the 26-bit machines, and also means that we avoid the horrible
+ * gcc code for "int val = !other_val;".
+ */
+#define DO_COW(m) (m)
+#define READ_FAULT(m) (!(m))
+#endif
-extern void die(const char *msg, struct pt_regs *regs, int err);
+NORET_TYPE void die(const char *msg, struct pt_regs *regs, int err) ATTRIB_NORET;
/*
* This is useful to dump out the page tables associated with
@@ -60,7 +93,9 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
printk("\n");
}
-static int __do_page_fault(struct mm_struct *mm, unsigned long addr, int mode, struct task_struct *tsk)
+static int
+__do_page_fault(struct mm_struct *mm, unsigned long addr, int mode,
+ struct task_struct *tsk)
{
struct vm_area_struct *vma;
int fault, mask;
@@ -159,7 +194,7 @@ bad_area:
return -2;
}
-static int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs)
+int do_page_fault(unsigned long addr, int mode, struct pt_regs *regs)
{
struct task_struct *tsk;
struct mm_struct *mm;
@@ -278,8 +313,10 @@ no_context:
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
- printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
- (addr < PAGE_SIZE) ? "NULL pointer dereference" : "paging request", addr);
+ printk(KERN_ALERT
+ "Unable to handle kernel %s at virtual address %08lx\n",
+ (addr < PAGE_SIZE) ? "NULL pointer dereference" :
+ "paging request", addr);
show_pte(mm, addr);
die("Oops", regs, mode);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index bfa085a52..6ceec5a22 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -49,7 +49,7 @@
#define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(void *))
static unsigned long totalram_pages;
-pgd_t swapper_pg_dir[PTRS_PER_PGD];
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern char _stext, _text, _etext, _end, __init_begin, __init_end;
/*
@@ -418,7 +418,7 @@ static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int boot
if (machine_is_archimedes() || machine_is_a5k())
reserve_bootmem_node(pgdat, 0x02000000, 0x00080000);
if (machine_is_p720t())
- reserve_bootmem_node(pgdat, 0xc0000000, 0x00014000);
+ reserve_bootmem_node(pgdat, PAGE_OFFSET, 0x00014000);
}
/*
@@ -450,8 +450,28 @@ void __init bootmem_init(struct meminfo *mi)
initrd_node = check_initrd(mi);
map_pg = bootmap_pfn;
-
- for (node = 0; node < numnodes; node++, np++) {
+
+ /*
+ * Initialise the bootmem nodes.
+ *
+ * What we really want to do is:
+ *
+ * unmap_all_regions_except_kernel();
+ * for_each_node_in_reverse_order(node) {
+ * map_node(node);
+ * allocate_bootmem_map(node);
+ * init_bootmem_node(node);
+ * free_bootmem_node(node);
+ * }
+ *
+ * but this is a 2.5-type change. For now, we just set
+ * the nodes up in reverse order.
+ *
+ * (we could also do with rolling bootmem_init and paging_init
+ * into one generic "memory_init" type function).
+ */
+ np += numnodes - 1;
+ for (node = numnodes - 1; node >= 0; node--, np--) {
/*
* If there are no pages in this node, ignore it.
* Note that node 0 must always have some pages.
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index d96fcbccb..a2fc69ea4 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -275,7 +275,7 @@ static void __init create_mapping(struct map_desc *md)
off = md->physical - virt;
length = md->length;
- while ((virt & 1048575 || (virt + off) & 1048575) && length >= PAGE_SIZE) {
+ while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
alloc_init_page(virt, virt + off, md->domain, prot_pte);
virt += PAGE_SIZE;
diff --git a/arch/arm/mm/proc-arm6,7.S b/arch/arm/mm/proc-arm6,7.S
index 61e135e19..d26a98f75 100644
--- a/arch/arm/mm/proc-arm6,7.S
+++ b/arch/arm/mm/proc-arm6,7.S
@@ -7,10 +7,8 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * MMU functions for ARM6
- *
* These are the low level assembler for performing cache and TLB
- * functions on the ARM6 & ARM7.
+ * functions on the ARM610 & ARM710.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
@@ -105,9 +103,9 @@ ENTRY(cpu_arm7_tlb_invalidate_page)
ENTRY(cpu_arm6_data_abort)
ldr r4, [r0] @ read instruction causing problem
- mov r1, r4, lsr #19 @ r1 b1 = L
+ tst r4, r4, lsr #21 @ C = bit 20
+ sbc r1, r1, r1 @ r1 = C - 1
and r2, r4, #14 << 24
- and r1, r1, #2 @ check read/write bit
teq r2, #8 << 24 @ was it ldm/stm
bne Ldata_simple
@@ -138,9 +136,9 @@ Ldata_simple: mrc p15, 0, r0, c6, c0, 0 @ get FAR
ENTRY(cpu_arm7_data_abort)
ldr r4, [r0] @ read instruction causing problem
- mov r1, r4, lsr #19 @ r1 b1 = L
+ tst r4, r4, lsr #21 @ C = bit 20
+ sbc r1, r1, r1 @ r1 = C - 1
and r2, r4, #15 << 24
- and r1, r1, #2 @ check read/write bit
add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine
movs pc, lr
diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S
index e6fc86bd1..77b689bdf 100644
--- a/arch/arm/mm/proc-arm720.S
+++ b/arch/arm/mm/proc-arm720.S
@@ -144,9 +144,9 @@ Ldata_simple: mrc p15, 0, r0, c6, c0, 0 @ get FAR
ENTRY(cpu_arm720_data_abort)
ldr r4, [r0] @ read instruction causing problem
- mov r1, r4, lsr #19 @ r1 b1 = L
+ tst r4, r4, lsr #21 @ C = bit 20
+ sbc r1, r1, r1 @ r1 = C - 1
and r2, r4, #15 << 24
- and r1, r1, #2 @ check read/write bit
add pc, pc, r2, lsr #22 @ Now branch to the relevent processing routine
movs pc, lr
@@ -283,23 +283,11 @@ ENTRY(cpu_arm720_proc_fin)
ldmfd sp!, {pc}
/*
- * Function: arm720_proc_do_idle (void)
- *
- * Params : r0 = call type:
- * 0 = slow idle
- * 1 = fast idle
- * 2 = switch to slow processor clock
- * 3 = switch to fast processor clock
- *
+ * Function: arm720_proc_do_idle(void)
+ * Params : r0 = unused
* Purpose : put the processer in proper idle mode
*/
ENTRY(cpu_arm720_do_idle)
-#if 0 /* FIXME: is this part of the processor? */
- ldr r2, =IO_BASE @ Virt addr of IO
- add r2, r2, #0x00050000 @ Start of PMU regs
- mov r1, #0x01 @ Idle mode
- str r1, [r2, #4]
-#endif
mov pc, lr
/*
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index a4306f08a..6f1f11601 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -68,9 +68,9 @@
ENTRY(cpu_arm920_data_abort)
ldr r1, [r0] @ read aborted instruction
mrc p15, 0, r0, c6, c0, 0 @ get FAR
- mov r1, r1, lsr #19 @ b1 = L
+ tst r1, r1, lsr #21 @ C = bit 20
mrc p15, 0, r3, c5, c0, 0 @ get FSR
- and r1, r1, #2
+ sbc r1, r1, r1 @ r1 = C - 1
and r3, r3, #255
mov pc, lr
@@ -330,7 +330,7 @@ ENTRY(cpu_arm920_icache_invalidate_range)
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain WB
ENTRY(cpu_arm920_icache_invalidate_page)
- /* why no invalidate I cache --rmk */
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
mov pc, lr
diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S
index 031ba648a..45b0a31fe 100644
--- a/arch/arm/mm/proc-sa110.S
+++ b/arch/arm/mm/proc-sa110.S
@@ -83,9 +83,9 @@ ENTRY(cpu_sa110_data_abort)
ENTRY(cpu_sa1100_data_abort)
ldr r1, [r0] @ read aborted instruction
mrc p15, 0, r0, c6, c0, 0 @ get FAR
- mov r1, r1, lsr #19 @ b1 = L
+ tst r1, r1, lsr #21 @ C = bit 20
mrc p15, 0, r3, c5, c0, 0 @ get FSR
- and r1, r1, #2
+ sbc r1, r1, r1 @ r1 = C - 1
and r3, r3, #255
mov pc, lr
diff --git a/arch/arm/nwfpe/Makefile b/arch/arm/nwfpe/Makefile
index a7f69d405..16c7c0aed 100644
--- a/arch/arm/nwfpe/Makefile
+++ b/arch/arm/nwfpe/Makefile
@@ -6,27 +6,27 @@
USE_STANDARD_AS_RULE := true
-NWFPE_OBJS := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \
- fpmodule.o fpopcode.o softfloat.o \
- single_cpdo.o double_cpdo.o extended_cpdo.o
+O_TARGET := math-emu.o
-ifeq ($(CONFIG_CPU_26),y)
-NWFPE_OBJS += entry26.o
-else
-NWFPE_OBJS += entry.o
-endif
+obj-y :=
+obj-m :=
+obj-n :=
+
+list-multi := nwfpe.o
-ifeq ($(CONFIG_NWFPE),y)
-O_TARGET := math-emu.o
-O_OBJS = $(NWFPE_OBJS)
+obj-$(CONFIG_NWFPE) += nwfpe.o
+
+nwfpe-objs := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \
+ fpmodule.o fpopcode.o softfloat.o \
+ single_cpdo.o double_cpdo.o extended_cpdo.o
+
+ifeq ($(CONFIG_CPU_26),y)
+nwfpe-objs += entry26.o
else
- ifeq ($(CONFIG_NWFPE),m)
- M_OBJS = nwfpe.o
- MI_OBJS = $(NWFPE_OBJS)
- endif
+nwfpe-objs += entry.o
endif
include $(TOPDIR)/Rules.make
-nwfpe.o: $(MI_OBJS) $(MIX_OBJS)
- $(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
+nwfpe.o: $(nwfpe-objs)
+ $(LD) -r -o $@ $(nwfpe-objs)
diff --git a/arch/arm/vmlinux-armo.lds.in b/arch/arm/vmlinux-armo.lds.in
index 0c0e720aa..f42deb72c 100644
--- a/arch/arm/vmlinux-armo.lds.in
+++ b/arch/arm/vmlinux-armo.lds.in
@@ -47,6 +47,8 @@ SECTIONS
*(.gnu.warning)
*(.text.lock) /* out-of-line lock text */
*(.rodata)
+ *(.glue_7)
+ *(.glue_7t)
*(.kstrtab)
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
diff --git a/arch/arm/vmlinux-armv.lds.in b/arch/arm/vmlinux-armv.lds.in
index b0398852d..10661f414 100644
--- a/arch/arm/vmlinux-armv.lds.in
+++ b/arch/arm/vmlinux-armv.lds.in
@@ -42,6 +42,8 @@ SECTIONS
*(.gnu.warning)
*(.text.lock) /* out-of-line lock text */
*(.rodata)
+ *(.glue_7)
+ *(.glue_7t)
*(.kstrtab)
. = ALIGN(16);
__start___ex_table = .; /* Exception table */
diff --git a/arch/cris/Makefile b/arch/cris/Makefile
new file mode 100644
index 000000000..b63a44711
--- /dev/null
+++ b/arch/cris/Makefile
@@ -0,0 +1,96 @@
+# $Id: Makefile,v 1.11 2000/11/27 17:58:30 bjornw Exp $
+# cris/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+
+LD_SCRIPT=$(TOPDIR)/arch/cris/cris.ld
+
+# A bug in ld prevents us from having a (constant-value) symbol in a
+# "ORIGIN =" or "LENGTH =" expression. We fix that by generating a
+# linker file with the symbolic part of those expressions evaluated.
+# Unfortunately, there is trouble making vmlinux depend on anything we
+# generate here, so we *always* regenerate the final linker script and
+# replace the LD macro to get what we want. Thankfully(?) vmlinux is
+# always rebuilt (due to calling make recursively and not knowing if
+# anything was rebuilt).
+# The shell script to build in some kind of dependency is really not
+# necessary for reasons of speed. It's there because always
+# regenerating stuff (even for incremental linking of subsystems!) is
+# even more nauseating.
+LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \
+ sed -e s/@ETRAX_DRAM_BASE@/0x$(ETRAX_DRAM_BASE)/ \
+ -e s/@ETRAX_DRAM_SIZE_M@/$(ETRAX_DRAM_SIZE)/ \
+ < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \
+ else true; \
+ fi && $(CROSS_COMPILE)ld -mcriself
+
+LINKFLAGS =-qmagic -mcriself -T $(LD_SCRIPT).tmp
+
+# objcopy is used to make binary images from the resulting linked file
+
+OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
+
+# normally, gcc on a linux box adds __linux__ but we do it "manually"
+# gcc-cris defaults to a.out, we need ELF, so -melf
+
+CFLAGS := $(CFLAGS) -march=v10 -fno-strict-aliasing -pipe -D__linux__
+
+ifdef CONFIG_KGDB
+CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g
+CFLAGS += -fno-omit-frame-pointer
+endif
+
+HEAD := arch/cris/kernel/head.o
+
+SUBDIRS += arch/cris/kernel arch/cris/mm arch/cris/lib arch/cris/drivers
+CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o
+LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a)
+LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC)
+
+arch/cris/kernel: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/cris/kernel
+
+arch/cris/mm: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/cris/mm
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+vmlinux.bin: vmlinux
+ $(OBJCOPY) vmlinux vmlinux.bin
+
+timage: vmlinux.bin
+ cat vmlinux.bin cramfs.img >timage
+
+simimage: timage
+ cp vmlinux.bin simvmlinux.bin
+
+# the following will remake timage without compiling the kernel
+# it does of course require that all object files exist...
+
+cramfs:
+## cramfs - Creates a cramfs image
+ mkcramfs -p 8192 root cramfs.img
+ cat vmlinux.bin cramfs.img >timage
+
+zImage: vmlinux
+## zImage - Compressed kernel (gzip)
+ @$(MAKEBOOT) zImage
+
+compressed: zImage
+
+archclean:
+ @$(MAKEBOOT) clean
+ rm -f timage vmlinux.bin cramfs.img
+ rm -rf $(LD_SCRIPT).tmp
+
+archmrproper:
+
+archdep:
+ @$(MAKEBOOT) dep
diff --git a/arch/cris/README.mm b/arch/cris/README.mm
new file mode 100644
index 000000000..6de4e7077
--- /dev/null
+++ b/arch/cris/README.mm
@@ -0,0 +1,241 @@
+Memory management for CRIS/MMU
+------------------------------
+HISTORY:
+
+$Log: README.mm,v $
+Revision 1.1 2000/07/10 16:25:21 bjornw
+Initial revision
+
+Revision 1.4 2000/01/17 02:31:59 bjornw
+Added discussion of paging and VM.
+
+Revision 1.3 1999/12/03 16:43:23 hp
+Blurb about that the 3.5G-limitation is not a MMU limitation
+
+Revision 1.2 1999/12/03 16:04:21 hp
+Picky comment about not mapping the first page
+
+Revision 1.1 1999/12/03 15:41:30 bjornw
+First version of CRIS/MMU memory layout specification.
+
+
+
+
+
+------------------------------
+
+See the ETRAX-NG HSDD for reference.
+
+We use the page-size of 8 kbytes, as opposed to the i386 page-size of 4 kbytes.
+
+The MMU can, apart from the normal mapping of pages, also do a top-level
+segmentation of the kernel memory space. We use this feature to avoid having
+to use page-tables to map the physical memory into the kernel's address
+space. We also use it to keep the user-mode virtual mapping in the same
+map during kernel-mode, so that the kernel easily can access the corresponding
+user-mode process' data.
+
+As a comparision, the Linux/i386 2.0 puts the kernel and physical RAM at
+address 0, overlapping with the user-mode virtual space, so that descriptor
+registers are needed for each memory access to specify which MMU space to
+map through. That changed in 2.2, putting the kernel/physical RAM at
+0xc0000000, to co-exist with the user-mode mapping. We will do something
+quite similar, but with the additional complexity of having to map the
+internal chip I/O registers and the flash memory area (including SRAM
+and peripherial chip-selets).
+
+The kernel-mode segmentation map:
+
+ ------------------------ ------------------------
+FFFFFFFF| | => cached | |
+ | kernel seg_f | flash | |
+F0000000|______________________| | |
+EFFFFFFF| | => uncached | |
+ | kernel seg_e | flash | |
+E0000000|______________________| | DRAM |
+DFFFFFFF| | paged to any | Un-cached |
+ | kernel seg_d | =======> | |
+D0000000|______________________| | |
+CFFFFFFF| | | |
+ | kernel seg_c |==\ | |
+C0000000|______________________| \ |______________________|
+BFFFFFFF| | uncached | |
+ | kernel seg_b |=====\=========>| Registers |
+B0000000|______________________| \c |______________________|
+AFFFFFFF| | \a | |
+ | | \c | FLASH/SRAM/Peripheral|
+ | | \h |______________________|
+ | | \e | |
+ | | \d | |
+ | kernel seg_0 - seg_a | \==>| DRAM |
+ | | | Cached |
+ | | paged to any | |
+ | | =======> |______________________|
+ | | | |
+ | | | Illegal |
+ | | |______________________|
+ | | | |
+ | | | FLASH/SRAM/Peripheral|
+00000000|______________________| |______________________|
+
+In user-mode it looks the same except that only the space 0-AFFFFFFF is
+available. Therefore, in this model, the virtual address space per process
+is limited to 0xb0000000 bytes (minus 8192 bytes, since the first page,
+0..8191, is never mapped, in order to trap NULL references).
+
+It also means that the total physical RAM that can be mapped is 256 MB
+(kseg_c above). More RAM can be mapped by choosing a different segmentation
+and shrinking the user-mode memory space.
+
+The MMU can map all 4 GB in user mode, but doing that would mean that a
+few extra instructions would be needed for each access to user mode
+memory.
+
+The kernel needs access to both cached and uncached flash. Uncached is
+necessary because of the special write/erase sequences. Also, the
+peripherial chip-selects are decoded from that region.
+
+The kernel also needs its own virtual memory space. That is kseg_d. It
+is used by the vmalloc() kernel function to allocate virtual contiguous
+chunks of memory not possible using the normal kmalloc physical RAM
+allocator.
+
+The setting of the actual MMU control registers to use this layout would
+be something like this:
+
+R_MMU_KSEG = ( ( seg_f, seg ) | // Flash cached
+ ( seg_e, seg ) | // Flash uncached
+ ( seg_d, page ) | // kernel vmalloc area
+ ( seg_c, seg ) | // kernel linear segment
+ ( seg_b, seg ) | // kernel linear segment
+ ( seg_a, page ) |
+ ( seg_9, page ) |
+ ( seg_8, page ) |
+ ( seg_7, page ) |
+ ( seg_6, page ) |
+ ( seg_5, page ) |
+ ( seg_4, page ) |
+ ( seg_3, page ) |
+ ( seg_2, page ) |
+ ( seg_1, page ) |
+ ( seg_0, page ) );
+
+R_MMU_KBASE_HI = ( ( base_f, 0x0 ) | // flash/sram/periph cached
+ ( base_e, 0x8 ) | // flash/sram/periph uncached
+ ( base_d, 0x0 ) | // don't care
+ ( base_c, 0x4 ) | // physical RAM cached area
+ ( base_b, 0xb ) | // uncached on-chip registers
+ ( base_a, 0x0 ) | // don't care
+ ( base_9, 0x0 ) | // don't care
+ ( base_8, 0x0 ) ); // don't care
+
+R_MMU_KBASE_LO = ( ( base_7, 0x0 ) | // don't care
+ ( base_6, 0x0 ) | // don't care
+ ( base_5, 0x0 ) | // don't care
+ ( base_4, 0x0 ) | // don't care
+ ( base_3, 0x0 ) | // don't care
+ ( base_2, 0x0 ) | // don't care
+ ( base_1, 0x0 ) | // don't care
+ ( base_0, 0x0 ) ); // don't care
+
+NOTE: while setting up the MMU, we run in a non-mapped mode in the DRAM (0x40
+segment) and need to setup the seg_4 to a unity mapping, so that we don't get
+a fault before we have had time to jump into the real kernel segment (0xc0). This
+is done in head.S temporarily, but fixed by the kernel later in paging_init.
+
+
+Paging - PTE's, PMD's and PGD's
+-------------------------------
+
+[ References: asm/pgtable.h, asm/page.h, asm/mmu.h ]
+
+The paging mechanism uses virtual addresses to split a process memory-space into
+pages, a page being the smallest unit that can be freely remapped in memory. On
+Linux/CRIS, a page is 8192 bytes (for technical reasons not equal to 4096 as in
+most other 32-bit architectures). It would be inefficient to let a virtual memory
+mapping be controlled by a long table of page mappings, so it is broken down into
+a 2-level structure with a Page Directory containing pointers to Page Tables which
+each have maps of up to 2048 pages (8192 / sizeof(void *)). Linux can actually
+handle 3-level structures as well, with a Page Middle Directory in between, but
+in many cases, this is folded into a two-level structure by excluding the Middle
+Directory.
+
+We'll take a look at how an address is translated while we discuss how it's handled
+in the Linux kernel.
+
+The example address is 0xd004000c; in binary this is:
+
+31 23 15 7 0
+11010000 00000100 00000000 00001100
+
+|______| |__________||____________|
+ PGD PTE page offset
+
+Given the top-level Page Directory, the offset in that directory is calculated
+using the upper 8 bits:
+
+extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
+{
+ return mm->pgd + (address >> PGDIR_SHIFT);
+}
+
+PGDIR_SHIFT is the log2 of the amount of memory an entry in the PGD can map; in our
+case it is 24, corresponding to 16 MB. This means that each entry in the PGD
+corresponds to 16 MB of virtual memory.
+
+The pgd_t from our example will therefore be the 208'th (0xd0) entry in mm->pgd.
+
+Since the Middle Directory does not exist, it is a unity mapping:
+
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+ return (pmd_t *) dir;
+}
+
+The Page Table provides the final lookup by using bits 13 to 23 as index:
+
+extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+{
+ return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) &
+ (PTRS_PER_PTE - 1));
+}
+
+PAGE_SHIFT is the log2 of the size of a page; 13 in our case. PTRS_PER_PTE is
+the number of pointers that fit in a Page Table and is used to mask off the
+PGD-part of the address.
+
+The so-far unused bits 0 to 12 are used to index inside a page linearily.
+
+The VM system
+-------------
+
+The kernels own page-directory is the swapper_pg_dir, cleared in paging_init,
+and contains the kernels virtual mappings (the kernel itself is not paged - it
+is mapped linearily using kseg_c as described above). Architectures without
+kernel segments like the i386, need to setup swapper_pg_dir directly in head.S
+to map the kernel itself. swapper_pg_dir is pointed to by init_mm.pgd as the
+init-task's PGD.
+
+To see what support functions are used to setup a page-table, let's look at the
+kernel's internal paged memory system, vmalloc/vfree.
+
+void * vmalloc(unsigned long size)
+
+The vmalloc-system keeps a paged segment in kernel-space at 0xd0000000. What
+happens first is that a virtual address chunk is allocated to the request using
+get_vm_area(size). After that, physical RAM pages are allocated and put into
+the kernel's page-table using alloc_area_pages(addr, size).
+
+static int alloc_area_pages(unsigned long address, unsigned long size)
+
+First the PGD entry is found using init_mm.pgd. This is passed to
+alloc_area_pmd (remember the 3->2 folding). It uses pte_alloc_kernel to
+check if the PGD entry points anywhere - if not, a page table page is
+allocated and the PGD entry updated. Then the alloc_area_pte function is
+used just like alloc_area_pmd to check which page table entry is desired,
+and a physical page is allocated and the table entry updated. All of this
+is repeated at the top-level until the entire address range specified has
+been mapped.
+
+
+
diff --git a/arch/cris/boot/Makefile b/arch/cris/boot/Makefile
new file mode 100644
index 000000000..77b59012e
--- /dev/null
+++ b/arch/cris/boot/Makefile
@@ -0,0 +1,14 @@
+#
+# arch/cris/boot/Makefile
+#
+
+zImage: compressed/vmlinuz
+
+compressed/vmlinuz: $(TOPDIR)/vmlinux
+ @$(MAKE) -C compressed vmlinuz
+
+dep:
+
+clean:
+ rm -f zImage tools/build compressed/vmlinux.out
+ @$(MAKE) -C compressed clean
diff --git a/arch/cris/boot/compressed/Makefile b/arch/cris/boot/compressed/Makefile
new file mode 100644
index 000000000..fbf2bc36b
--- /dev/null
+++ b/arch/cris/boot/compressed/Makefile
@@ -0,0 +1,37 @@
+#
+# linux/arch/etrax100/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux files and romfs
+#
+
+CC = gcc-cris -melf -I $(TOPDIR)/include
+CFLAGS = -O2
+LD = ld-cris
+OBJCOPY = objcopy-cris
+
+OBJECTS = head.o misc.o
+
+# files to compress
+SYSTEM = $(TOPDIR)/vmlinux.bin
+
+all: vmlinuz
+
+vmlinuz: piggy.img $(OBJECTS)
+ $(LD) -mcriself -T decompress.ld -o decompress.o $(OBJECTS)
+ $(OBJCOPY) -O binary --remove-section=.bss decompress.o decompress.bin
+# save it for mkprod in the topdir.
+ cp decompress.bin $(TOPDIR)
+ cat decompress.bin piggy.img $(TOPDIR)/cramfs.img > vmlinuz
+ rm -f piggy.img
+
+head.o: head.S
+ $(CC) -D__ASSEMBLY__ -traditional -c head.S -o head.o
+
+# gzip the kernel image
+
+piggy.img: $(SYSTEM)
+ cat $(SYSTEM) | gzip -f -9 > piggy.img
+
+clean:
+ rm -f piggy.img vmlinuz vmlinuz.o
+
diff --git a/arch/cris/boot/compressed/README b/arch/cris/boot/compressed/README
new file mode 100644
index 000000000..83e1f1e51
--- /dev/null
+++ b/arch/cris/boot/compressed/README
@@ -0,0 +1,25 @@
+Creation of the self-extracting compressed kernel image (vmlinuz)
+-----------------------------------------------------------------
+$Id: README,v 1.1 2000/11/22 17:20:46 bjornw Exp $
+
+This can be slightly confusing because it's a process with many steps.
+
+The kernel object built by the arch/etrax100/Makefile, vmlinux, is split
+by that makefile into text and data binary files, vmlinux.text and
+vmlinux.data.
+
+Those files together with a ROM filesystem can be catted together and
+burned into a flash or executed directly at the DRAM origin.
+
+They can also be catted together and compressed with gzip, which is what
+happens in this makefile. Together they make up piggy.img.
+
+The decompressor is built into the file decompress.o. It is turned into
+the binary file decompress.bin, which is catted together with piggy.img
+into the file vmlinuz. It can be executed in an arbitrary place in flash.
+
+Be careful - it assumes some things about free locations in DRAM. It
+assumes the DRAM starts at 0x40000000 and that it is at least 8 MB,
+so it puts its code at 0x40700000, and initial stack at 0x40800000.
+
+-Bjorn
diff --git a/arch/cris/boot/compressed/decompress.ld b/arch/cris/boot/compressed/decompress.ld
new file mode 100644
index 000000000..8cdef6a60
--- /dev/null
+++ b/arch/cris/boot/compressed/decompress.ld
@@ -0,0 +1,26 @@
+MEMORY
+ {
+ dram : ORIGIN = 0x40700000,
+ LENGTH = 0x00100000
+ }
+
+SECTIONS
+{
+ .text :
+ {
+ _stext = . ;
+ *(.text)
+ *(.rodata)
+ _etext = . ;
+ } > dram
+ .data :
+ {
+ *(.data)
+ _edata = . ;
+ } > dram
+ .bss :
+ {
+ *(.bss)
+ _end = ALIGN( 0x10 ) ;
+ } > dram
+}
diff --git a/arch/cris/boot/compressed/head.S b/arch/cris/boot/compressed/head.S
new file mode 100644
index 000000000..97243ee13
--- /dev/null
+++ b/arch/cris/boot/compressed/head.S
@@ -0,0 +1,100 @@
+/*
+ * arch/etrax100/boot/compressed/head.S
+ *
+ * Copyright (C) 1999 Axis Communications AB
+ *
+ * Code that sets up the DRAM registers, calls the
+ * decompressor to unpack the piggybacked kernel, and jumps.
+ *
+ */
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/sv_addr_ag.h>
+
+ ;; Exported symbols
+
+ .globl _input_data
+
+
+ .text
+
+ nop
+ di
+
+#ifndef CONFIG_SVINTO_SIM
+
+ ;; We need to setup the bus registers before we start using the DRAM
+
+ move.d DEF_R_WAITSTATES, r0
+ move.d r0, [R_WAITSTATES]
+
+ move.d DEF_R_BUS_CONFIG, r0
+ move.d r0, [R_BUS_CONFIG]
+
+ move.d DEF_R_DRAM_CONFIG, r0
+ move.d r0, [R_DRAM_CONFIG]
+
+ move.d DEF_R_DRAM_TIMING, r0
+ move.d r0, [R_DRAM_TIMING]
+
+#endif
+
+ ;; Setup the stack to a suitably high address.
+ ;; We assume 8 MB is the minimum DRAM in an eLinux
+ ;; product and put the sp at the top for now.
+
+ move.d 0x40800000, sp
+
+ ;; Figure out where the compressed piggyback image is
+ ;; in the flash (since we wont try to copy it to DRAM
+ ;; before unpacking). It is at _edata, but in flash.
+ ;; Use (_edata - basse) as offset to the current PC.
+
+basse: move.d pc, r5
+ and.d 0x7fffffff, r5 ; strip any non-cache bit
+ subq 2, r5 ; compensate for the move.d pc instr
+ move.d r5, r0 ; save for later - flash address of 'basse'
+ add.d _edata, r5
+ sub.d basse, r5 ; r5 = flash address of '_edata'
+
+ ;; Copy text+data to DRAM
+
+ move.d basse, r1 ; destination
+ move.d _edata, r2 ; end destination
+1: move.w [r0+], r3
+ move.w r3, [r1+]
+ cmp.d r2, r1
+ bcs 1b
+ nop
+
+ move.d r5, [_input_data] ; for the decompressor
+
+ ;; Clear the decompressors BSS (between _edata and _end)
+
+ moveq 0, r0
+ move.d _edata, r1
+ move.d _end, r2
+1: move.w r0, [r1+]
+ cmp.d r2, r1
+ bcs 1b
+ nop
+
+ ;; Do the decompression and save compressed size in _inptr
+
+ jsr _decompress_kernel
+
+ ;; Put start address of cramfs in r9 so the kernel can use it
+ ;; when mounting from flash
+
+ move.d [_input_data], r9 ; flash address of compressed kernel
+ add.d [_inptr], r9 ; size of compressed kernel
+
+ ;; Enter the decompressed kernel
+
+ jump 0x40004000 ; kernel is linked to this address
+
+ .data
+
+_input_data:
+ .dword 0 ; used by the decompressor
diff --git a/arch/cris/boot/compressed/misc.c b/arch/cris/boot/compressed/misc.c
new file mode 100644
index 000000000..87ce3d8a0
--- /dev/null
+++ b/arch/cris/boot/compressed/misc.c
@@ -0,0 +1,260 @@
+/*
+ * misc.c
+ *
+ * $Id: misc.c,v 1.3 2001/01/17 15:54:18 jonashg Exp $
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ * puts by Nick Holloway 1993, better puts by Martin Mares 1995
+ * adoptation for Linux/CRIS Axis Communications AB, 1999
+ *
+ */
+
+/* where the piggybacked kernel image expects itself to live.
+ * it is the same address we use when we network load an uncompressed
+ * image into DRAM, and it is the address the kernel is linked to live
+ * at by etrax100.ld.
+ */
+
+#define KERNEL_LOAD_ADR 0x40004000
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/svinto.h>
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+#define STATIC static
+
+void* memset(void* s, int c, size_t n);
+void* memcpy(void* __dest, __const void* __src,
+ size_t __n);
+
+#define memzero(s, n) memset ((s), 0, (n))
+
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define WSIZE 0x8000 /* Window size must be at least 32k, */
+ /* and a power of two */
+
+static uch *inbuf; /* input buffer */
+static uch window[WSIZE]; /* Sliding window buffer */
+
+unsigned inptr = 0; /* index of next byte to be processed in inbuf
+ * After decompression it will contain the
+ * compressed size, and head.S will read it.
+ */
+
+static unsigned outcnt = 0; /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define get_byte() inbuf[inptr++]
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern char *input_data; /* lives in head.S */
+
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+static void puts(const char *);
+
+/* the "heap" is put directly after the BSS ends, at end */
+
+extern int end;
+static long free_mem_ptr = (long)&end;
+
+#include "../../../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+ void *p;
+
+ if (size <0) error("Malloc error\n");
+
+ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+ p = (void *)free_mem_ptr;
+ free_mem_ptr += size;
+
+ return p;
+}
+
+static void free(void *where)
+{ /* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+ *ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+ free_mem_ptr = (long) *ptr;
+}
+
+/* decompressor info and error messages to serial console */
+
+static void
+puts(const char *s)
+{
+#ifndef CONFIG_DEBUG_PORT_NULL
+ while(*s) {
+#ifdef CONFIG_DEBUG_PORT0
+ while(!(*R_SERIAL0_STATUS & (1 << 5))) ;
+ *R_SERIAL0_TR_DATA = *s++;
+#endif
+#ifdef CONFIG_DEBUG_PORT1
+ while(!(*R_SERIAL1_STATUS & (1 << 5))) ;
+ *R_SERIAL1_TR_DATA = *s++;
+#endif
+#ifdef CONFIG_DEBUG_PORT2
+ while(!(*R_SERIAL2_STATUS & (1 << 5))) ;
+ *R_SERIAL2_TR_DATA = *s++;
+#endif
+#ifdef CONFIG_DEBUG_PORT3
+ while(!(*R_SERIAL3_STATUS & (1 << 5))) ;
+ *R_SERIAL3_TR_DATA = *s++;
+#endif
+ }
+#endif
+}
+
+void*
+memset(void* s, int c, size_t n)
+{
+ int i;
+ char *ss = (char*)s;
+
+ for (i=0;i<n;i++) ss[i] = c;
+}
+
+void*
+memcpy(void* __dest, __const void* __src,
+ size_t __n)
+{
+ int i;
+ char *d = (char *)__dest, *s = (char *)__src;
+
+ for (i=0;i<__n;i++) d[i] = s[i];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+
+static void
+flush_window()
+{
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, *out, ch;
+
+ in = window;
+ out = &output_data[output_ptr];
+ for (n = 0; n < outcnt; n++) {
+ ch = *out++ = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+ bytes_out += (ulg)outcnt;
+ output_ptr += (ulg)outcnt;
+ outcnt = 0;
+}
+
+static void
+error(char *x)
+{
+ puts("\n\n");
+ puts(x);
+ puts("\n\n -- System halted\n");
+
+ while(1); /* Halt */
+}
+
+void
+setup_normal_output_buffer()
+{
+ output_data = (char *)KERNEL_LOAD_ADR;
+}
+
+void
+decompress_kernel()
+{
+ /* input_data is set in head.S */
+ inbuf = input_data;
+
+#ifdef CONFIG_DEBUG_PORT0
+ *R_SERIAL0_XOFF = 0;
+ *R_SERIAL0_BAUD = 0x99;
+ *R_SERIAL0_TR_CTRL = 0x40;
+#endif
+#ifdef CONFIG_DEBUG_PORT1
+ *R_SERIAL1_XOFF = 0;
+ *R_SERIAL1_BAUD = 0x99;
+ *R_SERIAL1_TR_CTRL = 0x40;
+#endif
+#ifdef CONFIG_DEBUG_PORT2
+ *R_SERIAL2_XOFF = 0;
+ *R_SERIAL2_BAUD = 0x99;
+ *R_SERIAL2_TR_CTRL = 0x40;
+#endif
+#ifdef CONFIG_DEBUG_PORT3
+ *R_SERIAL3_XOFF = 0;
+ *R_SERIAL3_BAUD = 0x99;
+ *R_SERIAL3_TR_CTRL = 0x40;
+#endif
+
+ setup_normal_output_buffer();
+
+ makecrc();
+ puts("Uncompressing Linux...\n");
+ gunzip();
+ puts("Done. Now booting the kernel.\n");
+}
diff --git a/arch/cris/config.in b/arch/cris/config.in
new file mode 100644
index 000000000..3e234ec43
--- /dev/null
+++ b/arch/cris/config.in
@@ -0,0 +1,223 @@
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+mainmenu_name "Linux/CRIS Kernel Configuration"
+
+define_bool CONFIG_UID16 y
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Networking support' CONFIG_NET
+bool 'System V IPC' CONFIG_SYSVIPC
+
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
+fi
+
+bool 'Use kernel gdb debugger' CONFIG_KGDB
+
+bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG
+
+bool 'Use serial console (on the debug port)' CONFIG_USE_SERIAL_CONSOLE
+
+bool 'Use in-kernel ifconfig/route setup' CONFIG_KERNEL_IFCONFIG
+
+endmenu
+
+mainmenu_option next_comment
+comment 'Hardware setup'
+
+choice 'Processor type' \
+ "Etrax-100-LX CONFIG_ETRAX100LX \
+ Etrax-100-LX-for-xsim-simulator CONFIG_SVINTO_SIM" Etrax-100-LX
+
+# For both LX version 1 and the current simulator we enable the low VM mapping
+# Later when LX version 2 and above exist, this should be done with an if
+
+define_bool CONFIG_CRIS_LOW_MAP y
+
+hex 'DRAM base (hex)' ETRAX_DRAM_BASE 40000000
+int 'DRAM size (dec, in MB)' ETRAX_DRAM_SIZE 8
+
+int 'Max possible flash size (dec, in MB)' CONFIG_ETRAX_FLASH_LENGTH 2
+int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2
+
+choice 'Product LED port' \
+ "Port-PA-LEDs CONFIG_ETRAX_PA_LEDS \
+ Port-PB-LEDs CONFIG_ETRAX_PB_LEDS \
+ Mem-0x90000000-LEDs CONFIG_ETRAX_90000000_LEDS \
+ None CONFIG_ETRAX_NO_LEDS" Port-PA-LEDs
+
+if [ "$CONFIG_ETRAX_NO_LEDS" != "y" ]; then
+ int ' First green LED bit' CONFIG_ETRAX_LED1G 2
+ int ' First red LED bit' CONFIG_ETRAX_LED1R 3
+ int ' Second green LED bit' CONFIG_ETRAX_LED2G 4
+ int ' Second red LED bit' CONFIG_ETRAX_LED2R 5
+ int ' Third green LED bit' CONFIG_ETRAX_LED3R 2
+ int ' Third red LED bit' CONFIG_ETRAX_LED3G 2
+fi
+
+choice 'Product debug-port' \
+ "Serial-0 CONFIG_DEBUG_PORT0 \
+ Serial-1 CONFIG_DEBUG_PORT1 \
+ Serial-2 CONFIG_DEBUG_PORT2 \
+ Serial-3 CONFIG_DEBUG_PORT3" Serial-0
+
+hex 'R_WAITSTATES' DEF_R_WAITSTATES 95a6
+hex 'R_BUS_CONFIG' DEF_R_BUS_CONFIG 104
+hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040
+hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611
+hex 'R_PORT_PA_DIR' DEF_R_PORT_PA_DIR 1c
+hex 'R_PORT_PA_DATA' DEF_R_PORT_PA_DATA 00
+hex 'R_PORT_PB_CONFIG' DEF_R_PORT_PB_CONFIG 00
+hex 'R_PORT_PB_DIR' DEF_R_PORT_PB_DIR 00
+hex 'R_PORT_PB_DATA' DEF_R_PORT_PB_DATA ff
+
+endmenu
+
+# only configure IP numbers if the kernel ifconfig/route setup is enabled
+
+if [ "$CONFIG_KERNEL_IFCONFIG" = "y" ]; then
+ mainmenu_option next_comment
+ comment 'IP address selection'
+
+ comment 'All addresses are in hexadecimal form without 0x prefix'
+
+ hex 'IP address' ELTEST_IPADR ab1005af
+ hex 'Network' ELTEST_NETWORK ab100000
+ hex 'Netmask' ELTEST_NETMASK ffff0000
+ hex 'Broadcast' ELTEST_BROADCAST ab10ffff
+ hex 'Gateway' ELTEST_GATEWAY ab100101
+ hwaddr 'Ethernet address' ELTEST_ETHADR 00408ccd0000
+
+ endmenu
+fi
+
+# bring in Etrax built-in drivers
+
+source arch/cris/drivers/Config.in
+
+# standard linux drivers
+
+source drivers/mtd/Config.in
+
+source drivers/parport/Config.in
+
+source drivers/pnp/Config.in
+
+source drivers/block/Config.in
+
+source drivers/md/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+ source net/Config.in
+fi
+
+source drivers/telephony/Config.in
+
+mainmenu_option next_comment
+comment 'ATA/IDE/MFM/RLL support'
+
+tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
+
+if [ "$CONFIG_IDE" != "n" ]; then
+ source drivers/ide/Config.in
+else
+ define_bool CONFIG_BLK_DEV_IDE_MODES n
+ define_bool CONFIG_BLK_DEV_HD n
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+ source drivers/scsi/Config.in
+fi
+endmenu
+
+source drivers/ieee1394/Config.in
+
+source drivers/i2o/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+ mainmenu_option next_comment
+ comment 'Network device support'
+
+ bool 'Network device support' CONFIG_NETDEVICES
+ if [ "$CONFIG_NETDEVICES" = "y" ]; then
+ source drivers/net/Config.in
+ if [ "$CONFIG_ATM" = "y" ]; then
+ source drivers/atm/Config.in
+ fi
+ fi
+ endmenu
+fi
+
+source net/ax25/Config.in
+
+source net/irda/Config.in
+
+mainmenu_option next_comment
+comment 'ISDN subsystem'
+if [ "$CONFIG_NET" != "n" ]; then
+ tristate 'ISDN support' CONFIG_ISDN
+ if [ "$CONFIG_ISDN" != "n" ]; then
+ source drivers/isdn/Config.in
+ fi
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+
+bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+ source drivers/cdrom/Config.in
+fi
+endmenu
+
+#
+# input before char - char/joystick depends on it. As does USB.
+#
+source drivers/input/Config.in
+source drivers/char/Config.in
+
+#source drivers/misc/Config.in
+
+source drivers/media/Config.in
+
+source fs/Config.in
+
+source drivers/char/Config.in
+
+mainmenu_option next_comment
+comment 'Sound'
+
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+ source drivers/sound/Config.in
+fi
+endmenu
+
+source drivers/usb/Config.in
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
+bool 'Kernel profiling support' CONFIG_PROFILE
+if [ "$CONFIG_PROFILE" = "y" ]; then
+ int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
+fi
+endmenu
diff --git a/arch/cris/cris.ld b/arch/cris/cris.ld
new file mode 100644
index 000000000..5ba215959
--- /dev/null
+++ b/arch/cris/cris.ld
@@ -0,0 +1,81 @@
+/* ld script to make the Linux/CRIS kernel
+ * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ * For now, on Etrax-100 LX, the DRAM starts virtually at 0x6. Normally
+ * it should be at 0xc.
+ */
+
+SECTIONS
+{
+ . = 0x60000000; /* DRAM starts virtually at 0x60000000 */
+ _dram_start = .;
+ _ibr_start = .;
+ . = . + 0x4000; /* see head.S and pages reserved at the start */
+
+ _text = .; /* Text and read-only data */
+ _text_start = .; /* lots of aliases */
+ _stext = .;
+ __stext = .;
+ .text : {
+ *(.text)
+ *(.fixup)
+ *(.text.__*)
+ *(.rodata)
+ }
+
+ . = ALIGN(4); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ _etext = . ; /* End of text section */
+ __etext = .;
+
+ . = ALIGN (4);
+ ___data_rom_start = . ;
+ ___data_start = . ;
+ __Sdata = . ;
+ .data : { /* Data */
+ *(.data)
+ }
+ __edata = . ; /* End of data section */
+ _edata = . ;
+
+ . = ALIGN(8192); /* init_task and stack, must be aligned */
+ .data.init_task : { *(.data.init_task) }
+
+ . = ALIGN(8192); /* Init code and data */
+ ___init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(16);
+ ___setup_start = .;
+ .setup.init : { *(.setup.init) }
+ ___setup_end = .;
+ ___initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ ___initcall_end = .;
+ __vmlinux_end = .; /* last address of the physical file */
+ . = ALIGN(8192);
+ ___init_end = .;
+
+ __data_end = . ; /* Move to _edata ? */
+ __bss_start = .; /* BSS */
+ .bss : {
+ *(COMMON)
+ *(.bss)
+ }
+
+ . = ALIGN (0x20);
+ _end = .;
+ __end = .;
+
+ /* Sections to be discarded */
+ /DISCARD/ : {
+ *(.text.exit)
+ *(.data.exit)
+ *(.exitcall.exit)
+ }
+
+ _dram_end = 0x60000000 + @ETRAX_DRAM_SIZE_M@*1024*1024;
+}
diff --git a/arch/cris/defconfig b/arch/cris/defconfig
new file mode 100644
index 000000000..91a25ee23
--- /dev/null
+++ b/arch/cris/defconfig
@@ -0,0 +1,319 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_UID16=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_JAVA is not set
+# CONFIG_KGDB is not set
+# CONFIG_ETRAX_WATCHDOG is not set
+CONFIG_USE_SERIAL_CONSOLE=y
+# CONFIG_KERNEL_IFCONFIG is not set
+
+#
+# Hardware setup
+#
+CONFIG_ETRAX100LX=y
+# CONFIG_SVINTO_SIM is not set
+CONFIG_CRIS_LOW_MAP=y
+ETRAX_DRAM_BASE=40000000
+ETRAX_DRAM_SIZE=8
+CONFIG_ETRAX_PA_LEDS=y
+# CONFIG_ETRAX_PB_LEDS is not set
+# CONFIG_ETRAX_90000000_LEDS is not set
+# CONFIG_ETRAX_NO_LEDS is not set
+CONFIG_ETRAX_LED1G=2
+CONFIG_ETRAX_LED1R=2
+CONFIG_ETRAX_LED2G=2
+CONFIG_ETRAX_LED2R=2
+CONFIG_DEBUG_PORT0=y
+# CONFIG_DEBUG_PORT1 is not set
+# CONFIG_DEBUG_PORT2 is not set
+# CONFIG_DEBUG_PORT3 is not set
+DEF_R_WAITSTATES=95a6
+DEF_R_BUS_CONFIG=104
+DEF_R_DRAM_CONFIG=1a200040
+DEF_R_DRAM_TIMING=5611
+DEF_R_PORT_PA_DIR=1d
+DEF_R_PORT_PA_DATA=f0
+DEF_R_PORT_PB_CONFIG=00
+DEF_R_PORT_PB_DIR=1e
+DEF_R_PORT_PB_DATA=f3
+
+#
+# Drivers for Etrax built-in interfaces
+#
+CONFIG_ETRAX_ETHERNET=y
+CONFIG_NET_ETHERNET=y
+CONFIG_ETRAX_SERIAL=y
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_NET_SB1000 is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_CRAMFS=y
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PROFILE is not set
diff --git a/arch/cris/drivers/Config.in b/arch/cris/drivers/Config.in
new file mode 100644
index 000000000..36055ae04
--- /dev/null
+++ b/arch/cris/drivers/Config.in
@@ -0,0 +1,49 @@
+mainmenu_option next_comment
+comment 'Drivers for Etrax built-in interfaces'
+
+bool 'Ethernet support' CONFIG_ETRAX_ETHERNET y
+if [ "$CONFIG_ETRAX_ETHERNET" = "y" ]; then
+# this is just so that the user does not have to go into the
+# normal ethernet driver section just to enable ethernetworking
+ define_bool CONFIG_NET_ETHERNET y
+fi
+
+bool 'Serial-port support' CONFIG_ETRAX_SERIAL y
+
+bool 'ATA/IDE support' CONFIG_ETRAX_IDE n
+
+if [ "$CONFIG_ETRAX_IDE" = "y" ]; then
+# here we should add the CONFIG_'s necessary to enable the basic
+# general ide drivers so the common case does not need to go
+# into that config submenu. enable disk and CD support. others
+# need to go fiddle in the submenu..
+ define_bool CONFIG_IDE y
+
+ define_bool CONFIG_BLK_DEV_IDE y
+ define_bool CONFIG_BLK_DEV_IDEDISK y
+ define_bool CONFIG_BLK_DEV_IDECD y
+
+ define_bool CONFIG_BLK_DEV_IDEDMA y
+ define_bool CONFIG_DMA_NONPCI y
+
+ choice 'IDE reset pin' \
+ "Port_PB_Bit_7 CONFIG_ETRAX_IDE_PB7_RESET\
+ Port_G_Bit_27 CONFIG_ETRAX_IDE_G27_RESET\
+ Port_CSE1_Bit_16 CONFIG_ETRAX_IDE_CSE1_16_RESET" Port_PB_Bit_7
+fi
+
+bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP n
+
+if [ "$CONFIG_ETRAX_AXISFLASHMAP" = "y" ]; then
+# here we define the CONFIG_'s necessary to enable MTD support
+# for the flash
+ define_bool CONFIG_MTD y
+
+ define_bool CONFIG_MTD_CFI y
+ define_bool CONFIG_MTD_CFI_INTELEXT n
+ define_bool CONFIG_MTD_CFI_AMDSTD y
+
+ define_bool CONFIG_MTD_CHAR y
+fi
+
+endmenu
diff --git a/arch/cris/drivers/Makefile b/arch/cris/drivers/Makefile
new file mode 100644
index 000000000..47754f647
--- /dev/null
+++ b/arch/cris/drivers/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for Etrax-specific drivers
+#
+
+O_TARGET := drivers.o
+
+obj-y :=
+
+obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o
+obj-$(CONFIG_ETRAX_SERIAL) += serial.o
+obj-$(CONFIG_ETRAX_IDE) += ide.o
+obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/cris/drivers/axisflashmap.c b/arch/cris/drivers/axisflashmap.c
new file mode 100644
index 000000000..15b0be262
--- /dev/null
+++ b/arch/cris/drivers/axisflashmap.c
@@ -0,0 +1,311 @@
+/*
+ * Physical mapping layer for MTD using the Axis partitiontable format
+ *
+ * Copyright (c) 2001 Axis Communications AB
+ *
+ * This file is under the GPL.
+ *
+ * First partition is always sector 0 regardless of if we find a partitiontable
+ * or not. In the start of the next sector, there can be a partitiontable that
+ * tells us what other partitions to define. If there isn't, we use a default
+ * partition split defined below.
+ *
+ * $Log: axisflashmap.c,v $
+ * Revision 1.1 2001/01/12 17:01:18 bjornw
+ * * Added axisflashmap.c, a physical mapping for MTD that reads and understands
+ * Axis partition-table format.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/axisflashmap.h>
+#include <asm/mmu.h>
+
+#ifdef CONFIG_CRIS_LOW_MAP
+#define FLASH_UNCACHED_ADDR KSEG_E
+#define FLASH_CACHED_ADDR KSEG_5
+#else
+#define FLASH_UNCACHED_ADDR KSEG_E
+#define FLASH_CACHED_ADDR KSEG_F
+#endif
+
+/*
+ * WINDOW_SIZE is the total size where the flash chips are mapped,
+ * my guess is that this can be the total memory area even if there
+ * are many flash chips inside the area or if they are not all mounted.
+ * So possibly we can get rid of the CONFIG_ here and just write something
+ * like 32 MB always.
+ */
+
+#define WINDOW_SIZE (CONFIG_ETRAX_FLASH_LENGTH * 1024 * 1024)
+
+/* Byte-offset where the partition-table is placed in the first chip
+ */
+
+#define PTABLE_SECTOR 65536
+
+/*
+ * Map driver
+ *
+ * Ok this is the scoop - we need to access the flash both with and without
+ * the cache - without when doing all the fancy flash interfacing, and with
+ * when we do actual copying because otherwise it will be slow like molasses.
+ * I hope this works the way it's intended, so that there won't be any cases
+ * of non-synchronicity because of the different access modes below...
+ */
+
+static __u8 flash_read8(struct map_info *map, unsigned long ofs)
+{
+ return *(__u8 *)(FLASH_UNCACHED_ADDR + ofs);
+}
+
+static __u16 flash_read16(struct map_info *map, unsigned long ofs)
+{
+ return *(__u16 *)(FLASH_UNCACHED_ADDR + ofs);
+}
+
+static __u32 flash_read32(struct map_info *map, unsigned long ofs)
+{
+ return *(volatile unsigned int *)(FLASH_UNCACHED_ADDR + ofs);
+}
+
+static void flash_copy_from(struct map_info *map, void *to,
+ unsigned long from, ssize_t len)
+{
+ memcpy(to, (void *)(FLASH_CACHED_ADDR + from), len);
+}
+
+static void flash_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ *(__u8 *)(FLASH_UNCACHED_ADDR + adr) = d;
+}
+
+static void flash_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ *(__u16 *)(FLASH_UNCACHED_ADDR + adr) = d;
+}
+
+static void flash_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ *(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d;
+}
+
+static void flash_copy_to(struct map_info *map, unsigned long to,
+ const void *from, ssize_t len)
+{
+ memcpy((void *)(FLASH_CACHED_ADDR + to), from, len);
+}
+
+static struct map_info axis_map = {
+ name: "Axis flash",
+ size: WINDOW_SIZE,
+ buswidth: CONFIG_ETRAX_FLASH_BUSWIDTH,
+ read8: flash_read8,
+ read16: flash_read16,
+ read32: flash_read32,
+ copy_from: flash_copy_from,
+ write8: flash_write8,
+ write16: flash_write16,
+ write32: flash_write32,
+ copy_to: flash_copy_to
+};
+
+/* If no partition-table was found, we use this default-set.
+ */
+
+#define MAX_PARTITIONS 7
+#define NUM_DEFAULT_PARTITIONS 3
+
+static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
+ {
+ name: "boot firmware",
+ size: PTABLE_SECTOR,
+ offset: 0
+ },
+ {
+ name: "kernel",
+ size: 0x1a0000,
+ offset: PTABLE_SECTOR
+ },
+ {
+ name: "filesystem",
+ size: 0x50000,
+ offset: (0x1a0000 + PTABLE_SECTOR)
+ }
+};
+
+static struct mtd_partition axis_partitions[MAX_PARTITIONS] = {
+ {
+ name: "part0",
+ size: 0,
+ offset: 0
+ },
+ {
+ name: "part1",
+ size: 0,
+ offset: 0
+ },
+ {
+ name: "part2",
+ size: 0,
+ offset: 0
+ },
+ {
+ name: "part3",
+ size: 0,
+ offset: 0
+ },
+ {
+ name: "part4",
+ size: 0,
+ offset: 0
+ },
+ {
+ name: "part5",
+ size: 0,
+ offset: 0
+ },
+ {
+ name: "part6",
+ size: 0,
+ offset: 0
+ },
+};
+
+/*
+ * This is the master MTD device for which all the others are just
+ * auto-relocating aliases.
+ */
+static struct mtd_info *mymtd;
+
+/* CFI-scan the flash, and if there was a chip, read the partition-table
+ * and register the partitions with MTD.
+ */
+
+static int __init
+init_axis_flash(void)
+{
+ int pidx = 0;
+ struct partitiontable_head *ptable_head;
+ struct partitiontable_entry *ptable;
+ int use_default_ptable = 1; /* Until proven otherwise */
+ const char *pmsg = " /dev/flash%d at 0x%x, size 0x%x\n";
+
+ printk(KERN_NOTICE "Axis flash mapping: %x at %x\n",
+ WINDOW_SIZE, FLASH_CACHED_ADDR);
+
+ mymtd = do_cfi_probe(&axis_map);
+
+ if(!mymtd) {
+ printk("cfi_probe erred %d\n", mymtd);
+ return -ENXIO;
+ }
+
+ mymtd->module = THIS_MODULE;
+
+ /* The partition-table is at an offset within the second
+ * sector of the flash. We _define_ this to be at offset 64k
+ * even if the actual sector-size in the flash changes.. for
+ * now at least.
+ */
+
+ ptable_head = FLASH_CACHED_ADDR + PTABLE_SECTOR + PARTITION_TABLE_OFFSET;
+ pidx++; /* first partition is always set to the default */
+
+ if ((ptable_head->magic == PARTITION_TABLE_MAGIC)
+ && (ptable_head->size
+ < (MAX_PARTITIONS
+ * sizeof(struct partitiontable_entry) + 4))
+ && (*(unsigned long*)
+ ((void*)ptable_head
+ + sizeof(*ptable_head)
+ + ptable_head->size - 4)
+ == PARTITIONTABLE_END_MARKER)) {
+ /* Looks like a start, sane length and end of a
+ * partition table, lets check csum etc.
+ */
+ int ptable_ok = 0;
+ struct partitiontable_entry *max_addr =
+ (struct partitiontable_entry *)
+ ((unsigned long)ptable_head + sizeof(*ptable_head) +
+ ptable_head->size);
+ unsigned long offset = PTABLE_SECTOR;
+ unsigned char *p;
+ unsigned long csum = 0;
+
+ ptable = (struct partitiontable_entry *)
+ ((unsigned long)ptable_head + sizeof(*ptable_head));
+
+ /* Lets be PARANOID, and check the checksum. */
+ p = (unsigned char*) ptable;
+
+ while (p <= (unsigned char*)max_addr) {
+ csum += *p++;
+ csum += *p++;
+ csum += *p++;
+ csum += *p++;
+ }
+ /* printk(" total csum: 0x%08X 0x%08X\n",
+ csum, ptable_head->checksum); */
+ ptable_ok = (csum == ptable_head->checksum);
+
+ /* Read the entries and use/show the info. */
+ ptable = (struct partitiontable_entry *)
+ ((unsigned long)ptable_head + sizeof(*ptable_head));
+
+ printk(" Found %s partition table at 0x%08lX-0x%08lX.\n",
+ (ptable_ok ? "valid" : "invalid"),
+ (unsigned long)ptable_head,
+ (unsigned long)max_addr);
+
+ /* We have found a working bootblock. Now read the
+ partition table. Scan the table. It ends when
+ there is 0xffffffff, that is, empty flash. */
+
+ while (ptable_ok
+ && ptable->offset != 0xffffffff
+ && ptable < max_addr
+ && pidx < MAX_PARTITIONS) {
+#if 0
+ /* wait with multi-chip support until we know
+ * how mtd detects multiple chips
+ */
+ if ((offset + ptable->offset) >= chips[0].size) {
+ partitions[pidx].start
+ = offset + chips[1].start
+ + ptable->offset - chips[0].size;
+ }
+#endif
+ axis_partitions[pidx].offset = offset + ptable->offset;
+ axis_partitions[pidx].size = ptable->size;
+
+ printk(pmsg, pidx, axis_partitions[pidx].offset,
+ axis_partitions[pidx].size);
+ pidx++;
+ ptable++;
+ }
+ use_default_ptable = !ptable_ok;
+ }
+
+ if(use_default_ptable) {
+ printk(" Using default partition table\n");
+ return add_mtd_partitions(mymtd, axis_default_partitions,
+ NUM_DEFAULT_PARTITIONS);
+ } else {
+ return add_mtd_partitions(mymtd, axis_partitions, pidx);
+ }
+}
+
+/* This adds the above to the kernels init-call chain */
+
+module_init(init_axis_flash);
+
diff --git a/arch/cris/drivers/ethernet.c b/arch/cris/drivers/ethernet.c
new file mode 100644
index 000000000..53a9798ae
--- /dev/null
+++ b/arch/cris/drivers/ethernet.c
@@ -0,0 +1,1041 @@
+/* $Id: ethernet.c,v 1.5 2000/11/29 17:22:22 bjornw Exp $
+ *
+ * e100net.c: A network driver for the ETRAX 100LX network controller.
+ *
+ * Copyright (c) 1998-2000 Axis Communications AB.
+ *
+ * The outline of this driver comes from skeleton.c.
+ *
+ * $Log: ethernet.c,v $
+ * Revision 1.5 2000/11/29 17:22:22 bjornw
+ * Get rid of the udword types legacy stuff
+ *
+ * Revision 1.4 2000/11/22 16:36:09 bjornw
+ * Please marketing by using the correct case when spelling Etrax.
+ *
+ * Revision 1.3 2000/11/21 16:43:04 bjornw
+ * Minor short->int change
+ *
+ * Revision 1.2 2000/11/08 14:27:57 bjornw
+ * 2.4 port
+ *
+ * Revision 1.1 2000/11/06 13:56:00 bjornw
+ * Verbatim copy of the 1.24 version of e100net.c from elinux
+ *
+ * Revision 1.24 2000/10/04 15:55:23 bjornw
+ * * Use virt_to_phys etc. for DMA addresses
+ * * Removed bogus CHECKSUM_UNNECESSARY
+ *
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/svinto.h>
+
+//#define ETHDEBUG
+
+#define D(x)
+
+/*
+ * The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+
+static const char* cardname = "ETRAX 100LX built-in ethernet controller";
+
+/* A default ethernet address. Highlevel SW will set the real one later */
+
+static struct sockaddr default_mac = {
+ 0,
+ { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 }
+};
+
+/* Information that need to be kept for each board. */
+struct net_local {
+ struct net_device_stats stats;
+
+ /* Tx control lock. This protects the transmit buffer ring
+ * state along with the "tx full" state of the driver. This
+ * means all netif_queue flow control actions are protected
+ * by this lock as well.
+ */
+ spinlock_t lock;
+};
+
+#define NETWORK_DMARX_IRQ 17 /* irq 17 is the DMA1 irq */
+#define NETWORK_DMATX_IRQ 16 /* irq 16 is the DMA0 irq */
+#define NETWORK_STATUS_IRQ 6 /* irq 6 is the network irq */
+
+/* Dma descriptors etc. */
+
+#define RX_BUF_SIZE 32768
+
+#define MAX_MEDIA_DATA_SIZE 1518
+
+#define MIN_PACKET_LEN 46
+#define ETHER_HEAD_LEN 14
+
+/*
+** MDIO constants.
+*/
+#define MDIO_BASE_STATUS_REG 0x1
+#define MDIO_BASE_CONTROL_REG 0x0
+#define MDIO_LINK_UP_MASK 0x4
+#define MDIO_START 0x1
+#define MDIO_READ 0x2
+#define MDIO_WRITE 0x1
+#define MDIO_PREAMBLE 0xfffffffful
+
+/* Broadcom specific */
+#define MDIO_AUX_CTRL_STATUS_REG 0x18
+#define MDIO_SPEED 0x2
+#define MDIO_PHYS_ADDR 0x0
+
+/* Network flash constants */
+#define NET_FLASH_TIME 2 /* 20 ms */
+#define NET_LINK_UP_CHECK_INTERVAL 200 /* 2 s */
+
+/* RX_DESC_BUF_SIZE should be a multiple of four to avoid the buffer
+ * alignment bug in Etrax 100 release 1
+ */
+
+#define RX_DESC_BUF_SIZE 256
+#define NBR_OF_RX_DESC (RX_BUF_SIZE / \
+ RX_DESC_BUF_SIZE)
+
+#define GET_BIT(bit,val) (((val) >> (bit)) & 0x01)
+
+static etrax_dma_descr *myNextRxDesc; /* Points to the next descriptor to
+ to be processed */
+static etrax_dma_descr *myLastRxDesc; /* The last processed descriptor */
+static etrax_dma_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */
+
+static unsigned char RxBuf[RX_BUF_SIZE];
+
+static etrax_dma_descr RxDescList[NBR_OF_RX_DESC];
+static etrax_dma_descr TxDesc;
+
+static struct sk_buff *tx_skb;
+
+/* Network speed indication. */
+static struct timer_list speed_timer;
+static struct timer_list clear_led_timer;
+static int current_speed;
+static int led_clear_time;
+static int nolink;
+
+/* Index to functions, as function prototypes. */
+
+static int etrax_ethernet_init(struct net_device *dev);
+
+static int e100_open(struct net_device *dev);
+static int e100_set_mac_address(struct net_device *dev, void *addr);
+static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void e100_rx(struct net_device *dev);
+static int e100_close(struct net_device *dev);
+static struct net_device_stats *e100_get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void e100_hardware_send_packet(char *buf, int length);
+static void update_rx_stats(struct net_device_stats *);
+static void update_tx_stats(struct net_device_stats *);
+
+static void e100_check_speed(unsigned long dummy);
+static unsigned short e100_get_mdio_reg(unsigned char reg_num);
+static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd);
+static void e100_send_mdio_bit(unsigned char bit);
+static unsigned char e100_receive_mdio_bit(void);
+static void e100_reset_tranceiver(void);
+
+static void e100_clear_network_leds(unsigned long dummy);
+
+#define tx_done(dev) (*R_DMA_CH0_CMD == 0)
+
+/*
+ * Check for a network adaptor of this type, and return '0' if one exists.
+ * If dev->base_addr == 0, probe all likely locations.
+ * If dev->base_addr == 1, always return failure.
+ * If dev->base_addr == 2, allocate space for the device and return success
+ * (detachable devices only).
+ */
+
+static int __init
+etrax_ethernet_init(struct net_device *dev)
+{
+ int i;
+ int anOffset = 0;
+
+ printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB\n");
+
+ dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */
+
+ printk("%s initialized\n", dev->name);
+
+ /* make Linux aware of the new hardware */
+
+ if (!dev) {
+ printk("dev == NULL. Should this happen?\n");
+ dev = init_etherdev(dev, sizeof(struct net_local));
+ }
+
+ /* setup generic handlers and stuff in the dev struct */
+
+ ether_setup(dev);
+
+ /* make room for the local structure containing stats etc */
+
+ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct net_local));
+
+ /* now setup our etrax specific stuff */
+
+ dev->irq = NETWORK_DMARX_IRQ; /* we really use DMATX as well... */
+ dev->dma = 1;
+
+ /* fill in our handlers so the network layer can talk to us in the future */
+
+ dev->open = e100_open;
+ dev->hard_start_xmit = e100_send_packet;
+ dev->stop = e100_close;
+ dev->get_stats = e100_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->set_mac_address = e100_set_mac_address;
+
+ /* set the default MAC address */
+
+ e100_set_mac_address(dev, &default_mac);
+
+ /* Initialise the list of Etrax DMA-descriptors */
+
+ /* Initialise receive descriptors */
+
+ for(i = 0; i < (NBR_OF_RX_DESC - 1); i++) {
+ RxDescList[i].ctrl = 0;
+ RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+ RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]);
+ RxDescList[i].buf = virt_to_phys(RxBuf + anOffset);
+ RxDescList[i].status = 0;
+ RxDescList[i].hw_len = 0;
+ anOffset += RX_DESC_BUF_SIZE;
+ }
+
+ RxDescList[i].ctrl = d_eol;
+ RxDescList[i].sw_len = RX_DESC_BUF_SIZE;
+ RxDescList[i].next = virt_to_phys(&RxDescList[0]);
+ RxDescList[i].buf = virt_to_phys(RxBuf + anOffset);
+ RxDescList[i].status = 0;
+ RxDescList[i].hw_len = 0;
+
+ /* Initialise initial pointers */
+
+ myNextRxDesc = &RxDescList[0];
+ myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+ myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
+
+ /* Initialize speed indicator stuff. */
+
+ nolink = 0;
+ current_speed = 10;
+ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
+ speed_timer.function = e100_check_speed;
+ add_timer(&speed_timer);
+ clear_led_timer.function = e100_clear_network_leds;
+ clear_led_timer.expires = jiffies + 10;
+ add_timer(&clear_led_timer);
+
+ return 0;
+}
+
+/* set MAC address of the interface. called from the core after a
+ * SIOCSIFADDR ioctl, and from the bootup above.
+ */
+
+static int
+e100_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ int i;
+
+ /* remember it */
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ /* Write it to the hardware.
+ * Note the way the address is wrapped:
+ * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24);
+ * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8);
+ */
+
+ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
+ (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24);
+ *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8);
+ *R_NETWORK_SA_2 = 0;
+
+ /* show it in the log as well */
+
+ printk("%s: changed MAC to ", dev->name);
+
+ for (i = 0; i < 5; i++)
+ printk("%02X:", dev->dev_addr[i]);
+
+ printk("%02X\n", dev->dev_addr[i]);
+
+ return 0;
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+
+static int
+e100_open(struct net_device *dev)
+{
+ unsigned long flags;
+
+ /* disable the ethernet interface while we configure it */
+
+ *R_NETWORK_GEN_CONFIG =
+ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) |
+ IO_STATE(R_NETWORK_GEN_CONFIG, enable, off);
+
+ /* enable the MDIO output pin */
+
+ *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable);
+
+ *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */
+ *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */
+
+ /* Reset and wait for the DMA channels */
+
+ RESET_DMA(0);
+ RESET_DMA(1);
+ WAIT_DMA(0);
+ WAIT_DMA(1);
+
+ /* Initialise the etrax network controller */
+
+ /* allocate the irq corresponding to the receiving DMA */
+
+ if (request_irq(NETWORK_DMARX_IRQ, e100rx_interrupt, 0,
+ cardname, (void *)dev)) {
+ goto grace_exit;
+ }
+
+ /* allocate the irq corresponding to the transmitting DMA */
+
+ if (request_irq(NETWORK_DMATX_IRQ, e100tx_interrupt, 0,
+ cardname, (void *)dev)) {
+ goto grace_exit;
+ }
+
+ /* allocate the irq corresponding to the network errors etc */
+
+ if (request_irq(NETWORK_STATUS_IRQ, e100nw_interrupt, 0,
+ cardname, (void *)dev)) {
+ goto grace_exit;
+ }
+
+ /*
+ * Always allocate the DMA channels after the IRQ,
+ * and clean up on failure.
+ */
+
+ if(request_dma(0, cardname)) {
+ goto grace_exit;
+ }
+
+ if(request_dma(1, cardname)) {
+ grace_exit:
+ /* this will cause some 'trying to free free irq' but what the heck... */
+ free_dma(0);
+ free_irq(NETWORK_DMARX_IRQ, NULL);
+ free_irq(NETWORK_DMATX_IRQ, NULL);
+ free_irq(NETWORK_STATUS_IRQ, NULL);
+ return -EAGAIN;
+ }
+
+ /* give the HW an idea of what MAC address we want */
+
+ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
+ (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24);
+ *R_NETWORK_SA_1 = dev->dev_addr[4] | (dev->dev_addr[5] << 8);
+ *R_NETWORK_SA_2 = 0;
+
+#if 0
+ /* use promiscuous mode for testing */
+ *R_NETWORK_GA_0 = 0xffffffff;
+ *R_NETWORK_GA_1 = 0xffffffff;
+
+ *R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */
+#else
+ *R_NETWORK_REC_CONFIG =
+ IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) |
+ IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable);
+#endif
+
+ *R_NETWORK_GEN_CONFIG =
+ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) |
+ IO_STATE(R_NETWORK_GEN_CONFIG, enable, on);
+
+ save_flags(flags);
+ cli();
+
+ /* enable the irq's for ethernet DMA */
+
+ *R_IRQ_MASK2_SET =
+ IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
+ IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
+
+ *R_IRQ_MASK0_SET =
+ IO_STATE(R_IRQ_MASK0_SET, overrun, set) |
+ IO_STATE(R_IRQ_MASK0_SET, underrun, set) |
+ IO_STATE(R_IRQ_MASK0_SET, excessive_col, set);
+
+ tx_skb = 0;
+
+ /* make sure the irqs are cleared */
+
+ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+ *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
+
+ /* make sure the rec and transmit error counters are cleared */
+
+ (void)*R_REC_COUNTERS; /* dummy read */
+ (void)*R_TR_COUNTERS; /* dummy read */
+
+ /* start the receiving DMA channel so we can receive packets from now on */
+
+ *R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc);
+ *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start);
+
+ restore_flags(flags);
+
+ /* We are now ready to accept transmit requeusts from
+ * the queueing layer of the networking.
+ */
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+
+static void
+e100_check_speed(unsigned long dummy)
+{
+ unsigned long data;
+ data = e100_get_mdio_reg(MDIO_BASE_STATUS_REG);
+ if (!(data & MDIO_LINK_UP_MASK)) {
+ nolink = 1;
+ LED_NETWORK_TX_SET(1); /* Make it red, link is down. */
+ } else {
+ nolink = 0;
+ LED_NETWORK_TX_SET(0); /* Link is up again, clear red LED. */
+ data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG);
+ if (data & MDIO_SPEED) {
+ current_speed = 100;
+ } else {
+ current_speed = 10;
+ }
+ }
+
+ /* Reinitialize the timer. */
+ speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
+ add_timer(&speed_timer);
+}
+
+static unsigned short
+e100_get_mdio_reg(unsigned char reg_num)
+{
+ unsigned long flags;
+ unsigned short cmd; /* Data to be sent on MDIO port */
+ unsigned short data; /* Data read from MDIO */
+ int bitCounter;
+
+ save_flags(flags);
+ cli();
+
+ /* Start of frame, OP Code, Physical Address, Register Address */
+ cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (MDIO_PHYS_ADDR << 7) |
+ (reg_num << 2);
+
+ e100_send_mdio_cmd(cmd, 0);
+
+ data = 0;
+
+ /* Data... */
+ for(bitCounter=15; bitCounter>=0 ; bitCounter--) {
+ data |= (e100_receive_mdio_bit() << bitCounter);
+ }
+
+ restore_flags(flags);
+ return data;
+}
+
+static void
+e100_send_mdio_cmd(unsigned short cmd, int write_cmd)
+{
+ int bitCounter;
+ unsigned char data = 0x2;
+
+ /* Preamble */
+ for(bitCounter = 31; bitCounter>= 0; bitCounter--)
+ e100_send_mdio_bit(GET_BIT(bitCounter, MDIO_PREAMBLE));
+
+ for(bitCounter = 15; bitCounter >= 2; bitCounter--)
+ e100_send_mdio_bit(GET_BIT(bitCounter, cmd));
+
+ /* Turnaround */
+ for(bitCounter = 1; bitCounter >= 0 ; bitCounter--)
+ if (write_cmd)
+ e100_send_mdio_bit(GET_BIT(bitCounter, data));
+ else
+ e100_receive_mdio_bit();
+}
+
+static void
+e100_send_mdio_bit(unsigned char bit)
+{
+ volatile int i;
+ *R_NETWORK_MGM_CTRL = 2 | bit&1;
+ for (i=40; i; i--);
+ *R_NETWORK_MGM_CTRL = 6 | bit&1;
+ for (i=40; i; i--);
+}
+
+static unsigned char
+e100_receive_mdio_bit()
+{
+ unsigned char bit;
+ volatile int i;
+ *R_NETWORK_MGM_CTRL = 0;
+ bit = *R_NETWORK_STAT & 1;
+ for (i=40; i; i--);
+ *R_NETWORK_MGM_CTRL = 4;
+ for (i=40; i; i--);
+ return bit;
+}
+
+static void
+e100_reset_tranceiver(void)
+{
+ unsigned long flags;
+ unsigned short cmd;
+ unsigned short data;
+ int bitCounter;
+
+ save_flags(flags);
+ cli();
+
+ data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG);
+
+ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2);
+
+ e100_send_mdio_cmd(cmd, 0);
+
+ data |= 0x8000;
+
+ for(bitCounter = 15; bitCounter >= 0 ; bitCounter--) {
+ e100_send_mdio_bit(GET_BIT(bitCounter, data));
+ }
+
+ restore_flags(flags);
+}
+
+/* Called by upper layers if they decide it took too long to complete
+ * sending a packet - we need to reset and stuff.
+ */
+
+static void
+e100_tx_timeout(struct net_device *dev)
+{
+ struct net_local *np = (struct net_local *)dev->priv;
+
+ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+ tx_done(dev) ? "IRQ problem" : "network cable problem");
+
+ /* remember we got an error */
+
+ np->stats.tx_errors++;
+
+ /* reset the TX DMA in case it has hung on something */
+
+ RESET_DMA(0);
+ WAIT_DMA(0);
+
+ /* Reset the tranceiver. */
+
+ e100_reset_tranceiver();
+
+ /* and get rid of the packet that never got an interrupt */
+
+ dev_kfree_skb(tx_skb);
+ tx_skb = 0;
+
+ /* tell the upper layers we're ok again */
+
+ netif_wake_queue(dev);
+}
+
+
+/* This will only be invoked if the driver is _not_ in XOFF state.
+ * What this means is that we need not check it, and that this
+ * invariant will hold if we make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+
+static int
+e100_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *np = (struct net_local *)dev->priv;
+ int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+
+#ifdef ETHDEBUG
+ printk("send packet len %d\n", length);
+#endif
+ spin_lock_irq(&np->lock); /* protect from tx_interrupt */
+
+ tx_skb = skb; /* remember it so we can free it in the tx irq handler later */
+ dev->trans_start = jiffies;
+
+ e100_hardware_send_packet(buf, length);
+
+ /* this simple TX driver has only one send-descriptor so we're full
+ * directly. If this had a send-ring instead, we would only do this if
+ * the ring got full.
+ */
+
+ netif_stop_queue(dev);
+
+ spin_unlock_irq(&np->lock);
+
+ return 0;
+}
+
+/*
+ * The typical workload of the driver:
+ * Handle the network interface interrupts.
+ */
+
+static void
+e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ unsigned long irqbits = *R_IRQ_MASK2_RD;
+
+ if(irqbits & (1U << 3)) {
+
+ /* acknowledge the eop interrupt */
+
+ *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
+
+ /* check if one or more complete packets were indeed received */
+
+ while(*R_DMA_CH1_FIRST != virt_to_phys(myNextRxDesc)) {
+ /* Take out the buffer and give it to the OS, then
+ * allocate a new buffer to put a packet in.
+ */
+ e100_rx(dev);
+ ((struct net_local *)dev->priv)->stats.rx_packets++;
+ *R_DMA_CH1_CMD = 3; /* restart/continue on the channel, for safety */
+ *R_DMA_CH1_CLR_INTR = 3; /* clear dma channel 1 eop/descr irq bits */
+ /* now, we might have gotten another packet so we have to loop back
+ and check if so */
+ }
+ }
+}
+
+/* the transmit dma channel interrupt
+ *
+ * this is supposed to free the skbuff which was pending during transmission,
+ * and inform the kernel that we can send one more buffer
+ */
+
+static void
+e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ unsigned long irqbits = *R_IRQ_MASK2_RD;
+ struct net_local *np = (struct net_local *)dev->priv;
+
+ if(irqbits & 2) { /* check for a dma0_eop interrupt */
+
+ /* This protects us from concurrent execution of
+ * our dev->hard_start_xmit function above.
+ */
+
+ spin_lock(&np->lock);
+
+ /* acknowledge the eop interrupt */
+
+ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
+
+ if(*R_DMA_CH0_FIRST == 0 && tx_skb) {
+ np->stats.tx_bytes += tx_skb->len;
+ np->stats.tx_packets++;
+ /* dma is ready with the transmission of the data in tx_skb, so now
+ we can release the skb memory */
+ dev_kfree_skb_irq(tx_skb);
+ tx_skb = 0;
+ netif_wake_queue(dev);
+ } else {
+ printk("tx weird interrupt\n");
+ }
+
+ spin_unlock(&np->lock);
+ }
+}
+
+static void
+e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct net_local *np = (struct net_local *)dev->priv;
+ unsigned long irqbits = *R_IRQ_MASK0_RD;
+
+ if(irqbits & (1 << 19)) { /* check for overrun irq */
+ update_rx_stats(&np->stats); /* this will ack the irq */
+ D(printk("ethernet receiver overrun!\n"));
+ }
+ if(irqbits & (1 << 17)) { /* check for excessive collision irq */
+ *R_NETWORK_TR_CTRL = 1 << 8; /* clear the interrupt */
+ np->stats.tx_errors++;
+ D(printk("ethernet excessive collisions!\n"));
+ }
+
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+e100_rx(struct net_device *dev)
+{
+ struct sk_buff *skb;
+ int length=0;
+ int i;
+ struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc;
+ unsigned char *skb_data_ptr;
+
+ /* light the network rx packet depending on the current speed.
+ ** But only if link has been detected.
+ */
+ if (!nolink)
+ if (current_speed == 10) {
+ LED_NETWORK_TX_SET(1);
+ LED_NETWORK_RX_SET(1);
+ } else
+ LED_NETWORK_RX_SET(1);
+
+ /* Set the earliest time we may clear the LED */
+
+ led_clear_time = jiffies + NET_FLASH_TIME;
+
+ /* If the packet is broken down in many small packages then merge
+ * count how much space we will need to alloc with skb_alloc() for
+ * it to fit.
+ */
+
+ while (!(myNextRxDesc->status & d_eop)) {
+ length += myNextRxDesc->sw_len; /* use sw_len for the first descs */
+ myNextRxDesc->status = 0;
+ myNextRxDesc = phys_to_virt(myNextRxDesc->next);
+ }
+
+ length += myNextRxDesc->hw_len; /* use hw_len for the last descr */
+
+#ifdef ETHDEBUG
+ printk("Got a packet of length %d:\n", length);
+ /* dump the first bytes in the packet */
+ skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf);
+ for(i = 0; i < 8; i++) {
+ printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8,
+ skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3],
+ skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]);
+ skb_data_ptr += 8;
+ }
+#endif
+
+ skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
+ if (!skb) {
+ printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ return;
+ }
+
+ skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */
+ skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */
+
+#if 0
+ printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",
+ skb->head, skb->data, skb->tail, skb->end);
+ printk("copying packet to 0x%x.\n", skb_data_ptr);
+#endif
+
+ /* this loop can be made using max two memcpy's if optimized */
+
+ while(mySaveRxDesc != myNextRxDesc) {
+ memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf),
+ mySaveRxDesc->sw_len);
+ skb_data_ptr += mySaveRxDesc->sw_len;
+ mySaveRxDesc = phys_to_virt(mySaveRxDesc->next);
+ }
+
+ memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf),
+ mySaveRxDesc->hw_len);
+
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* Send the packet to the upper layers */
+
+ netif_rx(skb);
+
+ /* Prepare for next packet */
+
+ myNextRxDesc->status = 0;
+ myPrevRxDesc = myNextRxDesc;
+ myNextRxDesc = phys_to_virt(myNextRxDesc->next);
+
+ myPrevRxDesc->ctrl |= d_eol;
+ myLastRxDesc->ctrl &= ~d_eol;
+ myLastRxDesc = myPrevRxDesc;
+
+ return;
+}
+
+/* The inverse routine to net_open(). */
+static int
+e100_close(struct net_device *dev)
+{
+ struct net_local *np = (struct net_local *)dev->priv;
+
+ printk("Closing %s.\n", dev->name);
+
+ netif_stop_queue(dev);
+
+ *R_NETWORK_GEN_CONFIG =
+ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) |
+ IO_STATE(R_NETWORK_GEN_CONFIG, enable, off);
+
+ *R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */
+ *R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */
+
+ /* Stop the receiver and the transmitter */
+
+ RESET_DMA(0);
+ RESET_DMA(1);
+
+ /* Flush the Tx and disable Rx here. */
+
+ free_irq(NETWORK_DMARX_IRQ, NULL);
+ free_irq(NETWORK_DMATX_IRQ, NULL);
+ free_irq(NETWORK_STATUS_IRQ, NULL);
+
+ free_dma(0);
+ free_dma(1);
+
+ /* Update the statistics here. */
+
+ update_rx_stats(&np->stats);
+ update_tx_stats(&np->stats);
+
+ return 0;
+}
+
+static void
+update_rx_stats(struct net_device_stats *es)
+{
+ unsigned long r = *R_REC_COUNTERS;
+ /* update stats relevant to reception errors */
+ es->rx_fifo_errors += r >> 24; /* fifo overrun */
+ es->rx_crc_errors += r & 0xff; /* crc error */
+ es->rx_frame_errors += (r >> 8) & 0xff; /* alignment error */
+ es->rx_length_errors += (r >> 16) & 0xff; /* oversized frames */
+}
+
+static void
+update_tx_stats(struct net_device_stats *es)
+{
+ unsigned long r = *R_TR_COUNTERS;
+ /* update stats relevant to transmission errors */
+ es->collisions += (r & 0xff) + ((r >> 8) & 0xff); /* single_col + multiple_col */
+ es->tx_errors += (r >> 24) & 0xff; /* deferred transmit frames */
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *
+e100_get_stats(struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+
+ update_rx_stats(&lp->stats);
+ update_tx_stats(&lp->stats);
+
+ return &lp->stats;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1 Promiscuous mode, receive all packets
+ * num_addrs == 0 Normal mode, clear multicast list
+ * num_addrs > 0 Multicast mode, receive normal and MC packets,
+ * and do best-effort filtering.
+ */
+static void
+set_multicast_list(struct net_device *dev)
+{
+ int num_addr = dev->mc_count;
+ unsigned long int lo_bits;
+ unsigned long int hi_bits;
+ if (num_addr == -1)
+ {
+ /* promiscuous mode */
+ lo_bits = 0xfffffffful;
+ hi_bits = 0xfffffffful;
+ } else if (num_addr == 0) {
+ /* Normal, clear the mc list */
+ lo_bits = 0x00000000ul;
+ hi_bits = 0x00000000ul;
+ } else {
+ /* MC mode, receive normal and MC packets */
+ char hash_ix;
+ struct dev_mc_list *dmi = dev->mc_list;
+ int i;
+ char *baddr;
+ lo_bits = 0x00000000ul;
+ hi_bits = 0x00000000ul;
+ for (i=0; i<num_addr; i++) {
+ /* Calculate the hash index for the GA registers */
+
+ hash_ix = 0;
+ baddr = dmi->dmi_addr;
+ hash_ix ^= (*baddr) & 0x3f;
+ hash_ix ^= ((*baddr) >> 6) & 0x03;
+ ++baddr;
+ hash_ix ^= ((*baddr) << 2) & 0x03c;
+ hash_ix ^= ((*baddr) >> 4) & 0xf;
+ ++baddr;
+ hash_ix ^= ((*baddr) << 4) & 0x30;
+ hash_ix ^= ((*baddr) >> 2) & 0x3f;
+ ++baddr;
+ hash_ix ^= (*baddr) & 0x3f;
+ hash_ix ^= ((*baddr) >> 6) & 0x03;
+ ++baddr;
+ hash_ix ^= ((*baddr) << 2) & 0x03c;
+ hash_ix ^= ((*baddr) >> 4) & 0xf;
+ ++baddr;
+ hash_ix ^= ((*baddr) << 4) & 0x30;
+ hash_ix ^= ((*baddr) >> 2) & 0x3f;
+
+ hash_ix &= 0x3f;
+
+ if (hash_ix > 32) {
+ hi_bits |= (1 << (hash_ix-32));
+ }
+ else {
+ lo_bits |= (1 << hash_ix);
+ }
+ dmi = dmi->next;
+ }
+ }
+ *R_NETWORK_GA_0 = lo_bits;
+ *R_NETWORK_GA_1 = hi_bits;
+}
+
+void
+e100_hardware_send_packet(char *buf, int length)
+{
+ D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
+ /* light the network leds depending on the current speed.
+ ** But only if link has been detected.
+ */
+ if (!nolink) {
+ if (current_speed == 10) {
+ LED_NETWORK_TX_SET(1);
+ LED_NETWORK_RX_SET(1);
+ } else {
+ LED_NETWORK_RX_SET(1);
+ }
+ }
+
+ /* Set the earliest time we may clear the LED */
+
+ led_clear_time = jiffies + NET_FLASH_TIME;
+
+ /* configure the tx dma descriptor */
+
+ TxDesc.sw_len = length;
+ TxDesc.ctrl = d_eop | d_eol | d_wait;
+ TxDesc.buf = virt_to_phys(buf);
+
+ /* setup the dma channel and start it */
+
+ *R_DMA_CH0_FIRST = virt_to_phys(&TxDesc);
+ *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, start);
+}
+
+static void
+e100_clear_network_leds(unsigned long dummy)
+{
+ if (jiffies > led_clear_time) {
+ if (nolink)
+ LED_NETWORK_TX_SET(1);
+ else
+ LED_NETWORK_TX_SET(0);
+ LED_NETWORK_RX_SET(0);
+ }
+
+ clear_led_timer.expires = jiffies + 10;
+ add_timer(&clear_led_timer);
+}
+
+static struct net_device dev_etrax_ethernet; /* only got one */
+
+static int
+etrax_init_module(void)
+{
+ struct net_device *d = &dev_etrax_ethernet;
+
+ d->init = etrax_ethernet_init;
+
+ if(register_netdev(d) == 0)
+ return 0;
+ else
+ return -ENODEV;
+}
+
+module_init(etrax_init_module);
diff --git a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c
new file mode 100644
index 000000000..e352fdf32
--- /dev/null
+++ b/arch/cris/drivers/ide.c
@@ -0,0 +1,818 @@
+/* $Id: ide.c,v 1.4 2001/01/10 21:14:32 bjornw Exp $
+ *
+ * Etrax specific IDE functions, like init and PIO-mode setting etc.
+ * Almost the entire ide.c is used for the rest of the Etrax ATA driver.
+ * Copyright (c) 2000, 2001 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen (initial version)
+ * Mikael Starvik (pio setup stuff)
+ *
+ * $Log: ide.c,v $
+ * Revision 1.4 2001/01/10 21:14:32 bjornw
+ * Initialize hwif->ideproc, for the new way of handling ide_xxx_data
+ *
+ * Revision 1.3 2000/12/01 17:48:18 bjornw
+ * - atapi_output_bytes now uses DMA
+ * - dma_active check removed - the kernel does proper serializing and it had
+ * a race-condition anyway
+ * - ide_build_dmatable had a nameclash
+ * - re-added the RESET_DMA thingys because sometimes the interface can get
+ * stuck apparently
+ * - added ide_release_dma
+ *
+ * Revision 1.2 2000/11/29 17:31:29 bjornw
+ * 2.4 port
+ *
+ * - The "register addresses" stored in the hwif are now 32-bit fields that
+ * don't need to be shifted into correct positions in R_ATA_CTRL_DATA
+ * - PIO-mode detection temporarily disabled since ide-modes.c is not compiled
+ * - All DMA uses virt_to_phys conversions for DMA buffers and descriptor ptrs
+ * - Probably correct ide_dma_begin semantics in dmaproc now for ATAPI devices
+ * - Removed RESET_DMA when starting a new transfer - why was this necessary ?
+ * - Indentation fix
+ *
+ *
+ */
+
+/* Regarding DMA:
+ *
+ * There are two forms of DMA - "DMA handshaking" between the interface and the drive,
+ * and DMA between the memory and the interface. We can ALWAYS use the latter, since it's
+ * something built-in in the Etrax. However only some drives support the DMA-mode handshaking
+ * on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the
+ * device can't do DMA handshaking for some stupid reason. We don't need to do that.
+ */
+
+#undef REALLY_SLOW_IO /* most systems can safely undef this */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/svinto.h>
+
+/* number of Etrax DMA descriptors */
+#define MAX_DMA_DESCRS 64
+
+#define LOWDB(x)
+#define D(x)
+
+void OUT_BYTE(unsigned char data, ide_ioreg_t reg) {
+ LOWDB(printk("ob: data 0x%x, reg 0x%x\n", data, reg));
+ while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */
+ *R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */
+ while(!(*R_ATA_STATUS_DATA &
+ IO_MASK(R_ATA_STATUS_DATA, tr_rdy))); /* wait for transmitter ready */
+}
+
+unsigned char IN_BYTE(ide_ioreg_t reg) {
+ int status;
+ while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */
+ *R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */
+ while(!((status = *R_ATA_STATUS_DATA) &
+ IO_MASK(R_ATA_STATUS_DATA, dav))); /* wait for available */
+ LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
+ return (unsigned char)status; /* data was in the lower 16 bits in the status reg */
+}
+
+/* PIO timing (in R_ATA_CONFIG)
+ *
+ * _____________________________
+ * ADDRESS : ________/
+ *
+ * _______________
+ * DIOR : ____________/ \__________
+ *
+ * _______________
+ * DATA : XXXXXXXXXXXXXXXX_______________XXXXXXXX
+ *
+ *
+ * DIOR is unbuffered while address and data is buffered.
+ * This creates two problems:
+ * 1. The DIOR pulse is to early (because it is unbuffered)
+ * 2. The rise time of DIOR is long
+ *
+ * There are at least three different plausible solutions
+ * 1. Use a pad capable of larger currents in Etrax
+ * 2. Use an external buffer
+ * 3. Make the strobe pulse longer
+ *
+ * Some of the strobe timings below are modified to compensate
+ * for this. This implies a slight performance decrease.
+ *
+ * THIS SHOULD NEVER BE CHANGED!
+ *
+ * TODO: Is this true for the latest LX boards still ?
+ */
+
+#define ATA_DMA2_STROBE 4
+#define ATA_DMA2_HOLD 0
+#define ATA_DMA1_STROBE 4
+#define ATA_DMA1_HOLD 1
+#define ATA_DMA0_STROBE 12
+#define ATA_DMA0_HOLD 9
+#define ATA_PIO4_SETUP 1
+#define ATA_PIO4_STROBE 5
+#define ATA_PIO4_HOLD 0
+#define ATA_PIO3_SETUP 1
+#define ATA_PIO3_STROBE 5
+#define ATA_PIO3_HOLD 1
+#define ATA_PIO2_SETUP 1
+#define ATA_PIO2_STROBE 6
+#define ATA_PIO2_HOLD 2
+#define ATA_PIO1_SETUP 2
+#define ATA_PIO1_STROBE 11
+#define ATA_PIO1_HOLD 4
+#define ATA_PIO0_SETUP 4
+#define ATA_PIO0_STROBE 19
+#define ATA_PIO0_HOLD 4
+
+/*
+ * good_dma_drives() lists the model names (from "hdparm -i")
+ * of drives which do not support mword2 DMA but which are
+ * known to work fine with this interface under Linux.
+ */
+
+const char *good_dma_drives[] = {"Micropolis 2112A",
+ "CONNER CTMA 4000",
+ "CONNER CTT8000-A",
+ NULL};
+
+static void tune_e100_ide(ide_drive_t *drive, byte pio)
+{
+ unsigned long flags;
+
+ pio = 4;
+ //pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+ save_flags(flags);
+ cli();
+
+ /* set pio mode! */
+
+ switch(pio) {
+ case 0:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO0_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO0_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO0_HOLD ) );
+ break;
+ case 1:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO1_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO1_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO1_HOLD ) );
+ break;
+ case 2:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO2_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO2_HOLD ) );
+ break;
+ case 3:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO3_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO3_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO3_HOLD ) );
+ break;
+ case 4:
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) );
+ break;
+ }
+ restore_flags(flags);
+}
+
+static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive); /* defined below */
+static void e100_ideproc (ide_ide_action_t func, ide_drive_t *drive,
+ void *buffer, unsigned int length); /* defined below */
+
+void __init init_e100_ide (void)
+{
+ volatile unsigned int dummy;
+ int h;
+
+ printk("ide: ETRAX 100LX built-in ATA DMA controller\n");
+
+ /* first fill in some stuff in the ide_hwifs fields */
+
+ for(h = 0; h < MAX_HWIFS; h++) {
+ ide_hwif_t *hwif = &ide_hwifs[h];
+ hwif->chipset = ide_etrax100;
+ hwif->tuneproc = &tune_e100_ide;
+ hwif->dmaproc = &e100_dmaproc;
+ hwif->ideproc = &e100_ideproc;
+ }
+ /* actually reset and configure the etrax100 ide/ata interface */
+
+ /* de-assert bus-reset */
+#ifdef CONFIG_ETRAX_IDE_PB7_RESET
+ port_pb_dir_shadow = port_pb_dir_shadow |
+ IO_STATE(R_PORT_PB_DIR, dir7, output);
+ *R_PORT_PB_DIR = port_pb_dir_shadow;
+ REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1);
+#endif
+#ifdef CONFIG_ETRAX_IDE_G27_RESET
+ *R_PORT_G_DATA = 0;
+#endif
+
+ *R_ATA_CTRL_DATA = 0;
+ *R_ATA_TRANSFER_CNT = 0;
+ *R_ATA_CONFIG = 0;
+
+ genconfig_shadow = (genconfig_shadow &
+ ~IO_MASK(R_GEN_CONFIG, dma2) &
+ ~IO_MASK(R_GEN_CONFIG, dma3) &
+ ~IO_MASK(R_GEN_CONFIG, ata)) |
+ ( IO_STATE( R_GEN_CONFIG, dma3, ata ) |
+ IO_STATE( R_GEN_CONFIG, dma2, ata ) |
+ IO_STATE( R_GEN_CONFIG, ata, select ) );
+
+ *R_GEN_CONFIG = genconfig_shadow;
+
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+ *(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 0;
+#endif
+
+ /* wait some */
+
+ dummy = 1;
+ dummy = 2;
+ dummy = 3;
+
+#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
+ *(volatile long *)(MEM_CSE1_START | MEM_NON_CACHEABLE) = 1 << 16;
+ *R_PORT_G_DATA = 0; /* de-assert bus-reset */
+#endif
+
+ /* make a dummy read to set the ata controller in a proper state */
+ dummy = *R_ATA_STATUS_DATA;
+
+ *R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
+ IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
+ IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) |
+ IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
+ IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) );
+
+ *R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw, read) |
+ IO_FIELD( R_ATA_CTRL_DATA, addr, 1 ) );
+
+ while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/
+
+ *R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) |
+ IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) |
+ IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
+ IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
+
+ printk("ide: waiting 10 seconds for drives to regain consciousness\n");
+
+ h = jiffies + 1000;
+ while(jiffies < h) ;
+
+ /* reset the dma channels we will use */
+
+ RESET_DMA(2);
+ RESET_DMA(3);
+ WAIT_DMA(2);
+ WAIT_DMA(3);
+
+}
+
+static etrax_dma_descr mydescr;
+
+/*
+ * The following routines are mainly used by the ATAPI drivers.
+ *
+ * These routines will round up any request for an odd number of bytes,
+ * so if an odd bytecount is specified, be sure that there's at least one
+ * extra byte allocated for the buffer.
+ */
+static void
+e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+ ide_ioreg_t data_reg = IDE_DATA_REG;
+ unsigned long status;
+
+ D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+ data_reg, buffer, bytecount));
+
+ if(bytecount & 1) {
+ printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount);
+ bytecount++; /* to round off */
+ }
+
+ /* make sure the DMA channel is available */
+ RESET_DMA(3);
+ WAIT_DMA(3);
+
+ /* setup DMA descriptor */
+
+ mydescr.sw_len = bytecount;
+ mydescr.ctrl = d_eol;
+ mydescr.buf = virt_to_phys(buffer);
+
+ /* start the dma channel */
+
+ *R_DMA_CH3_FIRST = virt_to_phys(&mydescr);
+ *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start);
+
+ /* initiate a multi word dma read using PIO handshaking */
+
+ *R_ATA_TRANSFER_CNT = bytecount >> 1;
+
+ *R_ATA_CTRL_DATA = data_reg |
+ IO_STATE(R_ATA_CTRL_DATA, rw, read) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ /* wait for completion */
+
+ LED_DISK_READ(1);
+ WAIT_DMA(3);
+ LED_DISK_READ(0);
+
+#if 0
+ /* old polled transfer code */
+
+ /* initiate a multi word read */
+
+ *R_ATA_TRANSFER_CNT = wcount << 1;
+
+ *R_ATA_CTRL_DATA = data_reg |
+ IO_STATE(R_ATA_CTRL_DATA, rw, read) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, register) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ /* svinto has a latency until the busy bit actually is set */
+
+ nop(); nop();
+ nop(); nop();
+ nop(); nop();
+ nop(); nop();
+ nop(); nop();
+
+ /* unit should be busy during multi transfer */
+ while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) {
+ while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav)))
+ status = *R_ATA_STATUS_DATA;
+ *ptr++ = (unsigned short)(status & 0xffff);
+ }
+#endif
+}
+
+static void
+e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
+{
+ ide_ioreg_t data_reg = IDE_DATA_REG;
+ unsigned short *ptr = (unsigned short *)buffer;
+ unsigned long ctrl;
+
+ D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
+ data_reg, buffer, bytecount));
+
+ if(bytecount & 1) {
+ printk("odd bytecount %d in atapi_out_bytes!\n", bytecount);
+ bytecount++;
+ }
+
+ /* make sure the DMA channel is available */
+ RESET_DMA(2);
+ WAIT_DMA(2);
+
+ /* setup DMA descriptor */
+
+ mydescr.sw_len = bytecount;
+ mydescr.ctrl = d_eol;
+ mydescr.buf = virt_to_phys(buffer);
+
+ /* start the dma channel */
+
+ *R_DMA_CH2_FIRST = virt_to_phys(&mydescr);
+ *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start);
+
+ /* initiate a multi word dma write using PIO handshaking */
+
+ *R_ATA_TRANSFER_CNT = bytecount >> 1;
+
+ *R_ATA_CTRL_DATA = data_reg |
+ IO_STATE(R_ATA_CTRL_DATA, rw, write) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ /* wait for completion */
+
+ LED_DISK_WRITE(1);
+ WAIT_DMA(2);
+ LED_DISK_WRITE(0);
+
+#if 0
+ /* old polled write code */
+
+ while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */
+
+ /* initiate a multi word write */
+
+ *R_ATA_TRANSFER_CNT = bytecount >> 1;
+
+ ctrl = data_reg |
+ IO_STATE(R_ATA_CTRL_DATA, rw, write) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, register) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ LED_DISK_WRITE(1);
+
+ /* Etrax will set busy = 1 until the multi pio transfer has finished
+ * and tr_rdy = 1 after each succesful word transfer.
+ * When the last byte has been transferred Etrax will first set tr_tdy = 1
+ * and then busy = 0 (not in the same cycle). If we read busy before it
+ * has been set to 0 we will think that we should transfer more bytes
+ * and then tr_rdy would be 0 forever. This is solved by checking busy
+ * in the inner loop.
+ */
+
+ do {
+ *R_ATA_CTRL_DATA = ctrl | *ptr++;
+ while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) &&
+ (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)));
+ } while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
+
+ LED_DISK_WRITE(0);
+#endif
+}
+
+/*
+ * This is used for most PIO data transfers *from* the IDE interface
+ */
+static void
+e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ e100_atapi_input_bytes(drive, buffer, wcount << 2);
+}
+
+/*
+ * This is used for most PIO data transfers *to* the IDE interface
+ */
+static void
+e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+{
+ e100_atapi_output_bytes(drive, buffer, wcount << 2);
+}
+
+/*
+ * The multiplexor for ide_xxxput_data and atapi calls
+ */
+static void
+e100_ideproc (ide_ide_action_t func, ide_drive_t *drive,
+ void *buffer, unsigned int length)
+{
+ switch (func) {
+ case ideproc_ide_input_data:
+ e100_ide_input_data(drive, buffer, length);
+ break;
+ case ideproc_ide_output_data:
+ e100_ide_input_data(drive, buffer, length);
+ break;
+ case ideproc_atapi_input_bytes:
+ e100_atapi_input_bytes(drive, buffer, length);
+ break;
+ case ideproc_atapi_output_bytes:
+ e100_atapi_output_bytes(drive, buffer, length);
+ break;
+ default:
+ printk("e100_ideproc: unsupported func %d!\n", func);
+ break;
+ }
+}
+
+/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
+static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS];
+static unsigned int ata_tot_size;
+
+/*
+ * e100_ide_build_dmatable() prepares a dma request.
+ * Returns 0 if all went okay, returns 1 otherwise.
+ */
+static int e100_ide_build_dmatable (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ struct buffer_head *bh = rq->bh;
+ unsigned long size, addr;
+ unsigned int count = 0;
+
+ ata_tot_size = 0;
+
+ do {
+ /*
+ * Determine addr and size of next buffer area. We assume that
+ * individual virtual buffers are always composed linearly in
+ * physical memory. For example, we assume that any 8kB buffer
+ * is always composed of two adjacent physical 4kB pages rather
+ * than two possibly non-adjacent physical 4kB pages.
+ */
+ if (bh == NULL) { /* paging and tape requests have (rq->bh == NULL) */
+ addr = virt_to_phys (rq->buffer);
+ size = rq->nr_sectors << 9;
+ } else {
+ /* group sequential buffers into one large buffer */
+ addr = virt_to_phys (bh->b_data);
+ size = bh->b_size;
+ while ((bh = bh->b_reqnext) != NULL) {
+ if ((addr + size) != virt_to_phys (bh->b_data))
+ break;
+ size += bh->b_size;
+ }
+ }
+
+ /* did we run out of descriptors? */
+
+ if(count >= MAX_DMA_DESCRS) {
+ printk("%s: too few DMA descriptors\n", drive->name);
+ return 1;
+ }
+
+ /* uh.. I'm lazy.. if size >= 65536, it should loop below and split it in
+ more than one descriptor */
+
+ if(size >= 65536) {
+ printk("too large ATA DMA request block, size = %d!\n", size);
+ return 1;
+ }
+
+ /* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more
+ than 65536 words per transfer, so in that case we need to either
+ 1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with
+ the descriptors, or
+ 2) simply do the request here, and get dma_intr to only ide_end_request on
+ those blocks that were actually set-up for transfer.
+ */
+
+ if(ata_tot_size + size >= 131072) {
+ printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, size);
+ return 1;
+ }
+
+ /* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
+
+ ata_descrs[count].sw_len = size;
+ ata_descrs[count].ctrl = 0;
+ ata_descrs[count].buf = addr;
+ ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
+ count++;
+ ata_tot_size += size;
+
+ } while (bh != NULL);
+
+ if (count) {
+ /* set the end-of-list flag on the last descriptor */
+ ata_descrs[count - 1].ctrl |= d_eol;
+ /* return and say all is ok */
+ return 0;
+ }
+
+ printk("%s: empty DMA table?\n", drive->name);
+ return 1; /* let the PIO routines handle this weirdness */
+}
+
+static int config_drive_for_dma (ide_drive_t *drive)
+{
+ const char **list;
+ struct hd_driveid *id = drive->id;
+
+ if (id && (id->capability & 1)) {
+ /* Enable DMA on any drive that supports mword2 DMA */
+ if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
+ drive->using_dma = 1;
+ return 0; /* DMA enabled */
+ }
+
+ /* Consult the list of known "good" drives */
+ list = good_dma_drives;
+ while (*list) {
+ if (!strcmp(*list++,id->model)) {
+ drive->using_dma = 1;
+ return 0; /* DMA enabled */
+ }
+ }
+ }
+ return 1; /* DMA not enabled */
+}
+
+/*
+ * etrax_dma_intr() is the handler for disk read/write DMA interrupts
+ */
+static ide_startstop_t etrax_dma_intr (ide_drive_t *drive)
+{
+ int i, dma_stat;
+ byte stat;
+
+ LED_DISK_READ(0);
+ LED_DISK_WRITE(0);
+
+ dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+ stat = GET_STAT(); /* get drive status */
+ if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+ if (!dma_stat) {
+ struct request *rq;
+ rq = HWGROUP(drive)->rq;
+ for (i = rq->nr_sectors; i > 0;) {
+ i -= rq->current_nr_sectors;
+ ide_end_request(1, HWGROUP(drive));
+ }
+ return ide_stopped;
+ }
+ printk("%s: bad DMA status\n", drive->name);
+ }
+ return ide_error(drive, "dma_intr", stat);
+}
+
+/*
+ * e100_dmaproc() initiates/aborts DMA read/write operations on a drive.
+ *
+ * The caller is assumed to have selected the drive and programmed the drive's
+ * sector address using CHS or LBA. All that remains is to prepare for DMA
+ * and then issue the actual read/write DMA/PIO command to the drive.
+ *
+ * For ATAPI devices, we just prepare for DMA and return. The caller should
+ * then issue the packet command to the drive and call us again with
+ * ide_dma_begin afterwards.
+ *
+ * Returns 0 if all went well.
+ * Returns 1 if DMA read/write could not be started, in which case
+ * the caller should revert to PIO for the current request.
+ */
+
+static int e100_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
+{
+ static unsigned int reading; /* static to support ide_dma_begin semantics */
+ int atapi = 0;
+
+ D(printk("e100_dmaproc func %d\n", func));
+
+ switch (func) {
+ case ide_dma_verbose:
+ return 0;
+ case ide_dma_check:
+ return config_drive_for_dma (drive);
+ case ide_dma_off:
+ case ide_dma_off_quietly:
+ /* ok.. we don't really need to do anything I think. */
+ return 0;
+ case ide_dma_write:
+ reading = 0;
+ break;
+ case ide_dma_read:
+ reading = 1;
+ break;
+ case ide_dma_begin:
+ /* begin DMA, used by ATAPI devices which want to issue the
+ * appropriate IDE command themselves.
+ *
+ * they have already called ide_dma_read/write to set the
+ * static reading flag, now they call ide_dma_begin to do
+ * the real stuff. we tell our code below not to issue
+ * any IDE commands itself and jump into it.
+ */
+ atapi++;
+ goto dma_begin;
+ case ide_dma_end: /* returns 1 on error, 0 otherwise */
+ /* TODO: check if something went wrong with the DMA */
+ return 0;
+
+ default:
+ printk("e100_dmaproc: unsupported func %d\n", func);
+ return 1;
+ }
+
+ /* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction
+ * then they call ide_dma_begin after they have issued the appropriate drive command
+ * themselves to actually start the chipset DMA. so we just return here if we're
+ * not a diskdrive.
+ */
+
+ if (drive->media != ide_disk)
+ return 0;
+
+ dma_begin:
+
+ if(reading) {
+
+ RESET_DMA(3); /* sometimes the DMA channel get stuck so we need to do this */
+ WAIT_DMA(3);
+
+ /* set up the Etrax DMA descriptors */
+
+ if(e100_ide_build_dmatable (drive))
+ return 1;
+
+ if(!atapi) {
+ /* set the irq handler which will finish the request when DMA is done */
+
+ ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
+
+ /* issue cmd to drive */
+
+ OUT_BYTE(WIN_READDMA, IDE_COMMAND_REG);
+ }
+
+ /* begin DMA */
+
+ *R_DMA_CH3_FIRST = virt_to_phys(ata_descrs);
+ *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start);
+
+ /* initiate a multi word dma read using DMA handshaking */
+
+ *R_ATA_TRANSFER_CNT = ata_tot_size >> 1;
+
+ *R_ATA_CTRL_DATA = IDE_DATA_REG |
+ IO_STATE(R_ATA_CTRL_DATA, rw, read) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ LED_DISK_READ(1);
+
+ D(printk("dma read of %d bytes.\n", ata_tot_size));
+
+ } else {
+ /* writing */
+
+ RESET_DMA(2); /* sometimes the DMA channel get stuck so we need to do this */
+ WAIT_DMA(2);
+
+ /* set up the Etrax DMA descriptors */
+
+ if(e100_ide_build_dmatable (drive))
+ return 1;
+
+ if(!atapi) {
+ /* set the irq handler which will finish the request when DMA is done */
+
+ ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
+
+ /* issue cmd to drive */
+
+ OUT_BYTE(WIN_WRITEDMA, IDE_COMMAND_REG);
+ }
+
+ /* begin DMA */
+
+ *R_DMA_CH2_FIRST = virt_to_phys(ata_descrs);
+ *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start);
+
+ /* initiate a multi word dma write using DMA handshaking */
+
+ *R_ATA_TRANSFER_CNT = ata_tot_size >> 1;
+
+ *R_ATA_CTRL_DATA = IDE_DATA_REG |
+ IO_STATE(R_ATA_CTRL_DATA, rw, write) |
+ IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, handsh, dma) |
+ IO_STATE(R_ATA_CTRL_DATA, multi, on) |
+ IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
+
+ LED_DISK_WRITE(1);
+
+ D(printk("dma write of %d bytes.\n", ata_tot_size));
+ }
+
+ /* DMA started successfully */
+ return 0;
+}
+
+/* ide.c calls this, but we don't need to do anything particular */
+
+int ide_release_dma (ide_hwif_t *hwif)
+{
+ return 1;
+}
diff --git a/arch/cris/drivers/serial.c b/arch/cris/drivers/serial.c
new file mode 100644
index 000000000..2dcb17a5e
--- /dev/null
+++ b/arch/cris/drivers/serial.c
@@ -0,0 +1,3039 @@
+/* $Id: serial.c,v 1.6 2000/11/22 16:36:09 bjornw Exp $
+ *
+ * Serial port driver for the ETRAX 100LX chip
+ *
+ * Copyright (C) 1998, 1999, 2000 Axis Communications AB
+ *
+ * Many, many authors. Based once upon a time on serial.c for 16x50.
+ *
+ * $Log: serial.c,v $
+ * Revision 1.6 2000/11/22 16:36:09 bjornw
+ * Please marketing by using the correct case when spelling Etrax.
+ *
+ * Revision 1.5 2000/11/21 16:43:37 bjornw
+ * Fixed so it compiles under CONFIG_SVINTO_SIM
+ *
+ * Revision 1.4 2000/11/15 17:34:12 bjornw
+ * Added a timeout timer for flushing input channels. The interrupt-based
+ * fast flush system should be easy to merge with this later (works the same
+ * way, only with an irq instead of a system timer_list)
+ *
+ * Revision 1.3 2000/11/13 17:19:57 bjornw
+ * * Incredibly, this almost complete rewrite of serial.c worked (at least
+ * for output) the first time.
+ *
+ * Items worth noticing:
+ *
+ * No Etrax100 port 1 workarounds (does only compile on 2.4 anyway now)
+ * RS485 is not ported (why cant it be done in userspace as on x86 ?)
+ * Statistics done through async_icount - if any more stats are needed,
+ * that's the place to put them or in an arch-dep version of it.
+ * timeout_interrupt and the other fast timeout stuff not ported yet
+ * There be dragons in this 3k+ line driver
+ *
+ * Revision 1.2 2000/11/10 16:50:28 bjornw
+ * First shot at a 2.4 port, does not compile totally yet
+ *
+ * Revision 1.1 2000/11/10 16:47:32 bjornw
+ * Added verbatim copy of rev 1.49 etrax100ser.c from elinux
+ *
+ * Revision 1.49 2000/10/30 15:47:14 tobiasa
+ * Changed version number.
+ *
+ * Revision 1.48 2000/10/25 11:02:43 johana
+ * Changed %ul to %lu in printf's
+ *
+ * Revision 1.47 2000/10/18 15:06:53 pkj
+ * Compile correctly with CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST and
+ * CONFIG_SERIAL_PROC_ENTRY together.
+ * Some clean-up of the /proc/serial file.
+ *
+ * Revision 1.46 2000/10/16 12:59:40 johana
+ * Added CONFIG_SERIAL_PROC_ENTRY for statistics and debug info.
+ *
+ * Revision 1.45 2000/10/13 17:10:59 pkj
+ * Do not flush DMAs while flipping TTY buffers.
+ *
+ * Revision 1.44 2000/10/13 16:34:29 pkj
+ * Added a delay in ser_interrupt() for 2.3ms when an error is detected.
+ * We do not know why this delay is required yet, but without it the
+ * irmaflash program does not work (this was the program that needed
+ * the ser_interrupt() to be needed in the first place). This should not
+ * affect normal use of the serial ports.
+ *
+ * Revision 1.43 2000/10/13 16:30:44 pkj
+ * New version of the fast flush of serial buffers code. This time
+ * it is localized to the serial driver and uses a fast timer to
+ * do the work.
+ *
+ * Revision 1.42 2000/10/13 14:54:26 bennyo
+ * Fix for switching RTS when using rs485
+ *
+ * Revision 1.41 2000/10/12 11:43:44 pkj
+ * Cleaned up a number of comments.
+ *
+ * Revision 1.40 2000/10/10 11:58:39 johana
+ * Made RS485 support generic for all ports.
+ * Toggle rts in interrupt if no delay wanted.
+ * WARNING: No true transmitter empty check??
+ * Set d_wait bit when sending data so interrupt is delayed until
+ * fifo flushed. (Fix tcdrain() problem)
+ *
+ * Revision 1.39 2000/10/04 16:08:02 bjornw
+ * * Use virt_to_phys etc. for DMA addresses
+ * * Removed CONFIG_FLUSH_DMA_FAST hacks
+ * * Indentation fix
+ *
+ * Revision 1.38 2000/10/02 12:27:10 mattias
+ * * added variable used when using fast flush on serial dma.
+ * (CONFIG_FLUSH_DMA_FAST)
+ *
+ * Revision 1.37 2000/09/27 09:44:24 pkj
+ * Uncomment definition of SERIAL_HANDLE_EARLY_ERRORS.
+ *
+ * Revision 1.36 2000/09/20 13:12:52 johana
+ * Support for CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS:
+ * Number of timer ticks between flush of receive fifo (1 tick = 10ms).
+ * Try 0-3 for low latency applications. Approx 5 for high load
+ * applications (e.g. PPP). Maybe this should be more adaptive some day...
+ *
+ * Revision 1.35 2000/09/20 10:36:08 johana
+ * Typo in get_lsr_info()
+ *
+ * Revision 1.34 2000/09/20 10:29:59 johana
+ * Let rs_chars_in_buffer() check fifo content as well.
+ * get_lsr_info() might work now (not tested).
+ * Easier to change the port to debug.
+ *
+ * Revision 1.33 2000/09/13 07:52:11 torbjore
+ * Support RS485
+ *
+ * Revision 1.32 2000/08/31 14:45:37 bjornw
+ * After sending a break we need to reset the transmit DMA channel
+ *
+ * Revision 1.31 2000/06/21 12:13:29 johana
+ * Fixed wait for all chars sent when closing port.
+ * (Used to always take 1 second!)
+ * Added shadows for directions of status/ctrl signals.
+ *
+ * Revision 1.30 2000/05/29 16:27:55 bjornw
+ * Simulator ifdef moved a bit
+ *
+ * Revision 1.29 2000/05/09 09:40:30 mattias
+ * * Added description of dma registers used in timeout_interrupt
+ * * Removed old code
+ *
+ * Revision 1.28 2000/05/08 16:38:58 mattias
+ * * Bugfix for flushing fifo in timeout_interrupt
+ * Problem occurs when bluetooth stack waits for a small number of bytes
+ * containing an event acknowledging free buffers in bluetooth HW
+ * As before, data was stuck in fifo until more data came on uart and
+ * flushed it up to the stack.
+ *
+ * Revision 1.27 2000/05/02 09:52:28 jonasd
+ * Added fix for peculiar etrax behaviour when eop is forced on an empty
+ * fifo. This is used when flashing the IRMA chip. Disabled by default.
+ *
+ * Revision 1.26 2000/03/29 15:32:02 bjornw
+ * 2.0.34 updates
+ *
+ * Revision 1.25 2000/02/16 16:59:36 bjornw
+ * * Receive DMA directly into the flip-buffer, eliminating an intermediary
+ * receive buffer and a memcpy. Will avoid some overruns.
+ * * Error message on debug port if an overrun or flip buffer overrun occurs.
+ * * Just use the first byte in the flag flip buffer for errors.
+ * * Check for timeout on the serial ports only each 5/100 s, not 1/100.
+ *
+ * Revision 1.24 2000/02/09 18:02:28 bjornw
+ * * Clear serial errors (overrun, framing, parity) correctly. Before, the
+ * receiver would get stuck if an error occured and we did not restart
+ * the input DMA.
+ * * Cosmetics (indentation, some code made into inlines)
+ * * Some more debug options
+ * * Actually shut down the serial port (DMA irq, DMA reset, receiver stop)
+ * when the last open is closed. Corresponding fixes in startup().
+ * * rs_close() "tx FIFO wait" code moved into right place, bug & -> && fixed
+ * and make a special case out of port 1 (R_DMA_CHx_STATUS is broken for that)
+ * * e100_disable_rx/enable_rx just disables/enables the receiver, not RTS
+ *
+ * Revision 1.23 2000/01/24 17:46:19 johana
+ * Wait for flush of DMA/FIFO when closing port.
+ *
+ * Revision 1.22 2000/01/20 18:10:23 johana
+ * Added TIOCMGET ioctl to return modem status.
+ * Implemented modem status/control that works with the extra signals
+ * (DTR, DSR, RI,CD) as well.
+ * 3 different modes supported:
+ * ser0 on PB (Bundy), ser1 on PB (Lisa) and ser2 on PA (Bundy)
+ * Fixed DEF_TX value that caused the serial transmitter pin (txd) to go to 0 when
+ * closing the last filehandle, NASTY!.
+ * Added break generation, not tested though!
+ * Use SA_SHIRQ when request_irq() for ser2 and ser3 (shared with) par0 and par1.
+ * You can't use them at the same time (yet..), but you can hopefully switch
+ * between ser2/par0, ser3/par1 with the same kernel config.
+ * Replaced some magic constants with defines
+ *
+ *
+ */
+
+static char *serial_version = "$Revision: 1.6 $";
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#if (LINUX_VERSION_CODE >= 131343)
+#include <linux/init.h>
+#endif
+#if (LINUX_VERSION_CODE >= 131336)
+#include <asm/uaccess.h>
+#endif
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/delay.h>
+
+#include <asm/svinto.h>
+
+/* non-arch dependant serial structures are in linux/serial.h */
+#include <linux/serial.h>
+/* while we keep our own stuff (struct e100_serial) in a local .h file */
+#include "serial.h"
+
+/*
+ * All of the compatibilty code so we can compile serial.c against
+ * older kernels is hidden in serial_compat.h
+ */
+#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
+#include "serial_compat.h"
+#endif
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL 1
+#define SERIAL_TYPE_CALLOUT 2
+#endif
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+//#define SERIAL_DEBUG_INTR
+//#define SERIAL_DEBUG_OPEN
+//#define SERIAL_DEBUG_FLOW
+//#define SERIAL_DEBUG_DATA
+//#define SERIAL_DEBUG_THROTTLE
+//#define SERIAL_DEBUG_IO /* Debug for Extra control and status pins */
+#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */
+
+/* Enable this to use serial interrupts to handle when you
+ expect the first received event on the serial port to
+ be an error, break or similar. Used to be able to flash IRMA
+ from eLinux */
+//#define SERIAL_HANDLE_EARLY_ERRORS
+
+
+#ifndef CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS
+/* Default number of timer ticks before flushing rx fifo
+ * When using "little data, low latency applications: use 0
+ * When using "much data applications (PPP)" use ~5
+ */
+#define CONFIG_ETRAX100_SERIAL_RX_TIMEOUT_TICKS 5
+#endif
+
+#define MAX_FLUSH_TIME 8
+
+#define _INLINE_ inline
+
+static void change_speed(struct e100_serial *info);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+static int rs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count);
+
+#define DEF_BAUD 0x99 /* 115.2 kbit/s */
+#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST )
+#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */
+/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
+#define DEF_TX 0x80 /* or SERIAL_CTRL_B */
+
+/* offsets from R_SERIALx_CTRL */
+
+#define REG_DATA 0
+#define REG_TR_DATA 0
+#define REG_STATUS 1
+#define REG_TR_CTRL 1
+#define REG_REC_CTRL 2
+#define REG_BAUD 3
+#define REG_XOFF 4 /* this is a 32 bit register */
+
+/* this is the data for the four serial ports in the etrax100 */
+/* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
+/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
+
+static struct e100_serial rs_table[] = {
+ { DEF_BAUD, (unsigned char *)R_SERIAL0_CTRL, 1U << 12, /* uses DMA 6 and 7 */
+ R_DMA_CH6_CLR_INTR, R_DMA_CH6_FIRST, R_DMA_CH6_CMD,
+ R_DMA_CH6_STATUS, R_DMA_CH6_HWSW,
+ R_DMA_CH7_CLR_INTR, R_DMA_CH7_FIRST, R_DMA_CH7_CMD,
+ R_DMA_CH7_STATUS, R_DMA_CH7_HWSW,
+ STD_FLAGS, DEF_RX, DEF_TX, 2 }, /* ttyS0 */
+#ifndef CONFIG_SVINTO_SIM
+ { DEF_BAUD, (unsigned char *)R_SERIAL1_CTRL, 1U << 16, /* uses DMA 8 and 9 */
+ R_DMA_CH8_CLR_INTR, R_DMA_CH8_FIRST, R_DMA_CH8_CMD,
+ R_DMA_CH8_STATUS, R_DMA_CH8_HWSW,
+ R_DMA_CH9_CLR_INTR, R_DMA_CH9_FIRST, R_DMA_CH9_CMD,
+ R_DMA_CH9_STATUS, R_DMA_CH9_HWSW,
+ STD_FLAGS, DEF_RX, DEF_TX, 3 }, /* ttyS1 */
+
+ { DEF_BAUD, (unsigned char *)R_SERIAL2_CTRL, 1U << 4, /* uses DMA 2 and 3 */
+ R_DMA_CH2_CLR_INTR, R_DMA_CH2_FIRST, R_DMA_CH2_CMD,
+ R_DMA_CH2_STATUS, R_DMA_CH2_HWSW,
+ R_DMA_CH3_CLR_INTR, R_DMA_CH3_FIRST, R_DMA_CH3_CMD,
+ R_DMA_CH3_STATUS, R_DMA_CH3_HWSW,
+ STD_FLAGS, DEF_RX, DEF_TX, 0 }, /* ttyS2 */
+
+ { DEF_BAUD, (unsigned char *)R_SERIAL3_CTRL, 1U << 8, /* uses DMA 4 and 5 */
+ R_DMA_CH4_CLR_INTR, R_DMA_CH4_FIRST, R_DMA_CH4_CMD,
+ R_DMA_CH4_STATUS, R_DMA_CH4_HWSW,
+ R_DMA_CH5_CLR_INTR, R_DMA_CH5_FIRST, R_DMA_CH5_CMD,
+ R_DMA_CH5_STATUS, R_DMA_CH5_HWSW,
+ STD_FLAGS, DEF_RX, DEF_TX, 1 } /* ttyS3 */
+#endif
+};
+
+
+#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+
+/* RS-485 */
+#if defined(CONFIG_RS485)
+#if defined(CONFIG_RS485_ON_PA)
+static int rs485_pa_bit = CONFIG_RS485_ON_PA_BIT;
+#endif
+#endif
+
+
+/* For now we assume that all bits are on the same port for each serial port */
+
+/* Dummy shadow variables */
+static unsigned char dummy_ser0 = 0x00;
+static unsigned char dummy_ser1 = 0x00;
+static unsigned char dummy_ser2 = 0x00;
+static unsigned char dummy_ser3 = 0x00;
+
+static unsigned char dummy_dir_ser0 = 0x00;
+static unsigned char dummy_dir_ser1 = 0x00;
+static unsigned char dummy_dir_ser2 = 0x00;
+static unsigned char dummy_dir_ser3 = 0x00;
+
+/* Info needed for each ports extra control/status signals.
+ We only supports that all pins uses same register for each port */
+struct control_pins
+{
+ volatile unsigned char *port;
+ volatile unsigned char *shadow;
+ volatile unsigned char *dir_shadow;
+
+ unsigned char dtr_bit;
+ unsigned char ri_bit;
+ unsigned char dsr_bit;
+ unsigned char cd_bit;
+};
+
+static const struct control_pins e100_modem_pins[NR_PORTS] =
+{
+/* Ser 0 */
+ {
+#if defined(CONFIG_ETRAX100_SER0_DTR_RI_DSR_CD_ON_PB)
+ R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
+ CONFIG_ETRAX100_SER0_DTR_ON_PB_BIT,
+ CONFIG_ETRAX100_SER0_RI_ON_PB_BIT,
+ CONFIG_ETRAX100_SER0_DSR_ON_PB_BIT,
+ CONFIG_ETRAX100_SER0_CD_ON_PB_BIT
+#else
+ &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3
+#endif
+ },
+/* Ser 1 */
+ {
+#if defined(CONFIG_ETRAX100_SER1_DTR_RI_DSR_CD_ON_PB)
+ R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow,
+ CONFIG_ETRAX100_SER1_DTR_ON_PB_BIT,
+ CONFIG_ETRAX100_SER1_RI_ON_PB_BIT,
+ CONFIG_ETRAX100_SER1_DSR_ON_PB_BIT,
+ CONFIG_ETRAX100_SER1_CD_ON_PB_BIT
+#else
+ &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3
+#endif
+ },
+/* Ser 2 */
+ {
+#if defined(CONFIG_ETRAX100_SER2_DTR_RI_DSR_CD_ON_PA)
+ R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow,
+ CONFIG_ETRAX100_SER2_DTR_ON_PA_BIT,
+ CONFIG_ETRAX100_SER2_RI_ON_PA_BIT,
+ CONFIG_ETRAX100_SER2_DSR_ON_PA_BIT,
+ CONFIG_ETRAX100_SER2_CD_ON_PA_BIT
+#else
+ &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3
+#endif
+ },
+/* Ser 3 */
+ {
+ &dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3
+ }
+};
+
+#if defined(CONFIG_RS485) && defined(CONFIG_RS485_ON_PA)
+unsigned char rs485_pa_port = CONFIG_RS485_ON_PA_BIT;
+#endif
+
+#define E100_RTS_MASK 0x20
+#define E100_CTS_MASK 0x40
+
+
+/* All serial port signals are active low:
+ * active = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level
+ * inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level
+ *
+ * These macros returns the pin value: 0=0V, >=1 = 3.3V on ETRAX chip
+ */
+
+/* Output */
+#define E100_RTS_GET(info) ((info)->rx_ctrl & E100_RTS_MASK)
+/* Input */
+#define E100_CTS_GET(info) ((info)->port[REG_STATUS] & E100_CTS_MASK)
+
+/* These are typically PA or PB and 0 means 0V, 1 means 3.3V */
+/* Is an output */
+#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].shadow) & (1 << e100_modem_pins[(info)->line].dtr_bit))
+
+/* Normally inputs */
+#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].ri_bit))
+#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].cd_bit))
+
+/* Input */
+#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].dsr_bit))
+
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write. We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+#ifdef DECLARE_MUTEX
+static DECLARE_MUTEX(tmp_buf_sem);
+#else
+static struct semaphore tmp_buf_sem = MUTEX;
+#endif
+
+#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST
+#define TIMER1_IRQ_NBR 3
+
+/* clock select 10 for timer 1 gives 230400 Hz */
+#define FASTTIMER_SELECT (10)
+/* we use a source of 230400 Hz and a divider of 15 => 15360 Hz */
+#define FASTTIMER_DIV (15)
+
+/* fast flush timer stuff */
+static int fast_timer_started = 0;
+static unsigned long int fast_timer_ints = 0;
+
+static void _INLINE_ start_flush_timer(void)
+{
+ if (fast_timer_started)
+ return;
+
+ *R_TIMER_CTRL = r_timer_ctrl_shadow =
+ (r_timer_ctrl_shadow &
+ ~IO_MASK(R_TIMER_CTRL, timerdiv1) &
+ ~IO_MASK(R_TIMER_CTRL, tm1) &
+ ~IO_MASK(R_TIMER_CTRL, clksel1)) |
+ IO_FIELD(R_TIMER_CTRL, timerdiv1, FASTTIMER_DIV) |
+ IO_STATE(R_TIMER_CTRL, tm1, stop_ld) |
+ IO_FIELD(R_TIMER_CTRL, clksel1, FASTTIMER_SELECT);
+
+ *R_TIMER_CTRL = r_timer_ctrl_shadow =
+ (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) |
+ IO_STATE(R_TIMER_CTRL, tm1, run);
+
+ /* enable timer1 irq */
+
+ *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set);
+ fast_timer_started = 1;
+}
+#endif /* CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST */
+
+/*
+ * This function maps from the Bxxxx defines in asm/termbits.h into real
+ * baud rates.
+ */
+
+static int
+cflag_to_baud(unsigned int cflag)
+{
+ static int baud_table[] = {
+ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400 };
+
+ static int ext_baud_table[] = {
+ 0, 57600, 115200, 230400, 460800, 921600, 1843200, 6250000 };
+
+ if(cflag & CBAUDEX)
+ return ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+ else
+ return baud_table[cflag & CBAUD];
+}
+
+/* and this maps to an etrax100 hardware baud constant */
+
+static unsigned char
+cflag_to_etrax_baud(unsigned int cflag)
+{
+ char retval;
+
+ static char baud_table[] = {
+ -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, -1, 3, 4, 5, 6, 7 };
+
+ static char ext_baud_table[] = {
+ -1, 8, 9, 10, 11, 12, 13, 14 };
+
+ if(cflag & CBAUDEX)
+ retval = ext_baud_table[(cflag & CBAUD) & ~CBAUDEX];
+ else
+ retval = baud_table[cflag & CBAUD];
+
+ if(retval < 0) {
+ printk("serdriver tried setting invalid baud rate, flags %x.\n", cflag);
+ retval = 5; /* choose default 9600 instead */
+ }
+
+ return retval | (retval << 4); /* choose same for both TX and RX */
+}
+
+
+/* Various static support functions */
+
+/* Functions to set or clear DTR/RTS on the requested line */
+/* It is complicated by the fact that RTS is a serial port register, while
+ * DTR might not be implemented in the HW at all, and if it is, it can be on
+ * any general port.
+ */
+
+static inline void
+e100_dtr(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+ unsigned char mask = ( 1 << e100_modem_pins[info->line].dtr_bit);
+#ifdef SERIAL_DEBUG_IO
+ printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask);
+ printk("ser%i shadow before 0x%02X get: %i\n",
+ info->line, *e100_modem_pins[info->line].shadow,
+ E100_DTR_GET(info));
+#endif
+ /* DTR is active low */
+ {
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ *e100_modem_pins[info->line].shadow &= ~mask;
+ *e100_modem_pins[info->line].shadow |= (set ? 0 : mask);
+ *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+ restore_flags(flags);
+ }
+
+#if 0
+ REG_SHADOW_SET(e100_modem_pins[info->line].port,
+ *e100_modem_pins[info->line].shadow,
+ e100_modem_pins[info->line].dtr_bit, !set);
+#endif
+#ifdef SERIAL_DEBUG_IO
+ printk("ser%i shadow after 0x%02X get: %i\n",
+ info->line, *e100_modem_pins[info->line].shadow,
+ E100_DTR_GET(info));
+#endif
+#endif
+}
+
+/* set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
+ * 0=0V , 1=3.3V
+ */
+static inline void
+e100_rts(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+#ifdef SERIAL_DEBUG_IO
+ printk("ser%i rts %i\n", info->line, set);
+#endif
+ info->rx_ctrl &= ~E100_RTS_MASK;
+ info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */
+ info->port[REG_REC_CTRL] = info->rx_ctrl;
+#endif
+}
+
+/* If this behaves as a modem, RI and CD is an output */
+static inline void
+e100_ri_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+ /* RI is active low */
+ {
+ unsigned char mask = ( 1 << e100_modem_pins[info->line].ri_bit);
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ *e100_modem_pins[info->line].shadow &= ~mask;
+ *e100_modem_pins[info->line].shadow |= (set ? 0 : mask);
+ *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+ restore_flags(flags);
+ }
+#if 0
+ REG_SHADOW_SET(e100_modem_pins[info->line].port,
+ *e100_modem_pins[info->line].shadow,
+ e100_modem_pins[info->line].ri_bit, !set);
+#endif
+#endif
+}
+static inline void
+e100_cd_out(struct e100_serial *info, int set)
+{
+#ifndef CONFIG_SVINTO_SIM
+ /* CD is active low */
+ {
+ unsigned char mask = ( 1 << e100_modem_pins[info->line].cd_bit);
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ *e100_modem_pins[info->line].shadow &= ~mask;
+ *e100_modem_pins[info->line].shadow |= (set ? 0 : mask);
+ *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow;
+ restore_flags(flags);
+ }
+#if 0
+ REG_SHADOW_SET(e100_modem_pins[info->line].port,
+ *e100_modem_pins[info->line].shadow,
+ e100_modem_pins[info->line].cd_bit, !set);
+#endif
+#endif
+}
+
+static inline void
+e100_disable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+ /* disable the receiver */
+ info->port[REG_REC_CTRL] = (info->rx_ctrl &= ~0x40);
+#endif
+}
+
+static inline void
+e100_enable_rx(struct e100_serial *info)
+{
+#ifndef CONFIG_SVINTO_SIM
+ /* enable the receiver */
+ info->port[REG_REC_CTRL] = (info->rx_ctrl |= 0x40);
+#endif
+}
+
+/* the rx DMA uses both the dma_descr and the dma_eop interrupts */
+
+static inline void
+e100_disable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+ printk("rxdma_irq(%d): 0\n",info->line);
+#endif
+ *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);
+}
+
+static inline void
+e100_enable_rxdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+ printk("rxdma_irq(%d): 1\n",info->line);
+#endif
+ *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);
+}
+
+/* the tx DMA uses only dma_descr interrupt */
+
+static inline void
+e100_disable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+ printk("txdma_irq(%d): 0\n",info->line);
+#endif
+ *R_IRQ_MASK2_CLR = info->irq;
+}
+
+static inline void
+e100_enable_txdma_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+ printk("txdma_irq(%d): 1\n",info->line);
+#endif
+ *R_IRQ_MASK2_SET = info->irq;
+}
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+/* in order to detect and fix errors on the first byte
+ we have to use the serial interrupts as well. */
+
+static inline void
+e100_disable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+ printk("ser_irq(%d): 0\n",info->line);
+#endif
+ *R_IRQ_MASK1_CLR = (1U << (8+2*info->line));
+}
+
+static inline void
+e100_enable_serial_data_irq(struct e100_serial *info)
+{
+#ifdef SERIAL_DEBUG_INTR
+ printk("ser_irq(%d): 1\n",info->line);
+ printk("**** %d = %d\n",
+ (8+2*info->line),
+ (1U << (8+2*info->line)));
+#endif
+ *R_IRQ_MASK1_SET = (1U << (8+2*info->line));
+}
+#endif
+
+#if defined(CONFIG_RS485)
+/* Enable RS-485 mode on selected port. This is UGLY. */
+static int
+e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r)
+{
+ struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+#if defined(CONFIG_RS485_ON_PA)
+ *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
+#endif
+
+ info->rs485.rts_on_send = 0x01 & r->rts_on_send;
+ info->rs485.rts_after_sent = 0x01 & r->rts_after_sent;
+ info->rs485.delay_rts_before_send = r->delay_rts_before_send;
+ info->rs485.enabled = r->enabled;
+
+ return 0;
+}
+
+/* Enable RS-485 mode on selected port. This is UGLY. */
+static int
+e100_write_rs485(struct tty_struct *tty,struct rs485_write *r)
+{
+ int stop_delay;
+ int total, i;
+ int max_j, delay_ms, bits;
+ tcflag_t cflags;
+ int size = (*r).outc_size;
+ struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+ struct wait_queue wait = { current, NULL };
+
+ /* If we are in RS-485 mode, we need to toggle RTS and disable
+ * the receiver before initiating a DMA transfer
+ */
+ e100_rts(info, info->rs485.rts_on_send);
+#if defined(CONFIG_RS485_DISABLE_RECEIVER)
+ e100_disable_rx(info);
+ e100_disable_rxdma_irq(info);
+#endif
+
+ if (info->rs485.delay_rts_before_send > 0){
+ current->timeout = jiffies + (info->rs485.delay_rts_before_send * HZ)/1000;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ current->timeout = 0;
+ }
+ total = rs_write(tty, 1, (*r).outc, (*r).outc_size);
+
+ /* If we are in RS-485 mode the following things has to be done:
+ * wait until DMA is ready
+ * wait on transmit shift register
+ * wait to toggle RTS
+ * enable the receiver
+ */
+
+ /* wait on transmit shift register */
+ /* All is sent, check if we should wait more before toggling rts */
+
+ /* calc. number of bits / data byte */
+ cflags = info->tty->termios->c_cflag;
+ /* databits + startbit and 1 stopbit */
+ if((cflags & CSIZE) == CS7)
+ bits = 9;
+ else
+ bits = 10;
+
+ if(cflags & CSTOPB) /* 2 stopbits ? */
+ bits++;
+
+ if(cflags & PARENB) /* parity bit ? */
+ bits++;
+
+ /* calc timeout */
+ delay_ms = ((bits * size * 1000) / info->baud) + 1;
+ max_j = jiffies + (delay_ms * HZ)/1000 + 10;
+
+ while (jiffies < max_j ) {
+ if (info->port[REG_STATUS] & 0x20) {
+ for( i=0 ; i<100; i++ ) {};
+ if (info->port[REG_STATUS] & 0x20) {
+ /* ~25 for loops per usec */
+ stop_delay = 25 * (1000000 / info->baud);
+ if(cflags & CSTOPB)
+ stop_delay *= 2;
+ for( i=0 ; i<stop_delay; i++ ) {};
+ break;
+ }
+ }
+ }
+
+ e100_rts(info, info->rs485.rts_after_sent);
+
+#if defined(CONFIG_RS485_DISABLE_RECEIVER)
+ e100_enable_rx(info);
+ e100_enable_rxdma_irq(info);
+#endif
+
+ return total;
+}
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+
+/* FIXME - when are these used and what is the purpose ?
+ * In rs_stop we probably just can block the transmit DMA ready irq
+ * and in rs_start we re-enable it (and then the old one will come).
+ */
+
+static void
+rs_stop(struct tty_struct *tty)
+{
+}
+
+static void
+rs_start(struct tty_struct *tty)
+{
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines. All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt(). They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off. People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible. After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void
+rs_sched_event(struct e100_serial *info,
+ int event)
+{
+ info->event |= 1 << event;
+ queue_task(&info->tqueue, &tq_serial);
+ mark_bh(SERIAL_BH);
+}
+
+/* The output DMA channel is free - use it to send as many chars as possible
+ * NOTES:
+ * We don't pay attention to info->x_char, which means if the TTY wants to
+ * use XON/XOFF it will set info->x_char but we won't send any X char!
+ *
+ * To implement this, we'd just start a DMA send of 1 byte pointing at a
+ * buffer containing the X char, and skip updating xmit. We'd also have to
+ * check if the last sent char was the X char when we enter this function
+ * the next time, to avoid updating xmit with the sent X value.
+ */
+
+static void
+transmit_chars(struct e100_serial *info)
+{
+ unsigned int c, sentl;
+ struct etrax_dma_descr *descr;
+
+#ifdef CONFIG_SVINTO_SIM
+ /* This will output too little if tail is not 0 always since
+ * we don't reloop to send the other part. Anyway this SHOULD be a
+ * no-op - transmit_chars would never really be called during sim
+ * since rs_write does not write into the xmit buffer then.
+ */
+ if(info->xmit.tail)
+ printk("Error in serial.c:transmit_chars(), tail!=0\n");
+ if(info->xmit.head != info->xmit.tail) {
+ SIMCOUT(info->xmit.buf + info->xmit.tail,
+ CIRC_CNT(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE));
+ info->xmit.head = info->xmit.tail; /* move back head */
+ info->tr_running = 0;
+ }
+ return;
+#endif
+ /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */
+ *info->oclrintradr = 3;
+
+#ifdef SERIAL_DEBUG_INTR
+ if(info->line == SERIAL_DEBUG_LINE)
+ printk("tc\n");
+#endif
+ if(!info->tr_running) {
+ /* weirdo... we shouldn't get here! */
+ printk("Achtung: transmit_chars with !tr_running\n");
+ return;
+ }
+
+ descr = &info->tr_descr;
+
+ /* first get the amount of bytes sent during the last DMA transfer,
+ and update xmit accordingly */
+
+ /* if the stop bit was not set, all data has been sent */
+ if(!(descr->status & d_stop)) {
+ sentl = descr->sw_len;
+ } else
+ /* otherwise we find the amount of data sent here */
+ sentl = descr->hw_len;
+
+ /* update stats */
+ info->icount.tx += sentl;
+
+ /* update xmit buffer */
+ info->xmit.tail = (info->xmit.tail + sentl) & (SERIAL_XMIT_SIZE - 1);
+
+ /* if there is only a few chars left in the buf, wake up the blocked
+ write if any */
+ if (CIRC_CNT(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+ /* find out the largest amount of consecutive bytes we want to send now */
+
+ c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+
+ if(c <= 0) {
+ /* our job here is done, don't schedule any new DMA transfer */
+ info->tr_running = 0;
+
+#if defined(CONFIG_RS485)
+ /* Check if we should toggle RTS now */
+ if (info->rs485.enabled)
+ {
+ /* Make sure fifo is empty */
+ int in_fifo = 0 ;
+ do{
+ in_fifo = (*info->ostatusadr) & 0x007F ;
+ } while (in_fifo > 0) ;
+ /* Any way to really check transmitter empty? (TEMT) */
+ /* Control RTS to set to RX mode */
+ e100_rts(info, info->rs485.rts_after_sent);
+#if defined(CONFIG_RS485_DISABLE_RECEIVER)
+ e100_enable_rx(info);
+ e100_enable_rxdma_irq(info);
+#endif
+ }
+#endif /* RS485 */
+
+ return;
+ }
+
+ /* ok we can schedule a dma send of c chars starting at info->xmit.tail */
+ /* set up the descriptor correctly for output */
+
+ descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */
+ descr->sw_len = c;
+ descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);
+ descr->status = 0;
+
+ *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */
+ *info->ocmdadr = 1; /* dma command start -> R_DMAx_CMD */
+
+ /* DMA is now running (hopefully) */
+
+}
+
+static void
+start_transmit(struct e100_serial *info)
+{
+#if 0
+ if(info->line == SERIAL_DEBUG_LINE)
+ printk("x\n");
+#endif
+
+ info->tr_descr.sw_len = 0;
+ info->tr_descr.hw_len = 0;
+ info->tr_descr.status = 0;
+ info->tr_running = 1;
+
+ transmit_chars(info);
+}
+
+
+static _INLINE_ void
+receive_chars(struct e100_serial *info)
+{
+ struct tty_struct *tty;
+ unsigned char rstat;
+ unsigned int recvl;
+ struct etrax_dma_descr *descr;
+
+#ifdef CONFIG_SVINTO_SIM
+ /* No receive in the simulator. Will probably be when the rest of
+ * the serial interface works, and this piece will just be removed.
+ */
+ return;
+#endif
+
+ tty = info->tty;
+
+ /* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */
+
+ *info->iclrintradr = 3;
+
+ if(!tty) /* something wrong... */
+ return;
+
+ descr = &info->rec_descr;
+
+ /* find out how many bytes were read */
+
+ /* if the eop bit was not set, all data has been received */
+ if(!(descr->status & d_eop)) {
+ recvl = descr->sw_len;
+ } else {
+ /* otherwise we find the amount of data received here */
+ recvl = descr->hw_len;
+ }
+ if(recvl) {
+ unsigned char *buf;
+ struct async_icount *icount;
+
+ icount = &info->icount;
+
+ /* update stats */
+ icount->rx += recvl;
+
+ /* read the status register so we can detect errors */
+ rstat = info->port[REG_STATUS];
+
+ if(rstat & 0xe) {
+ /* if we got an error, we must reset it by reading the
+ * data_in field
+ */
+ (void)info->port[REG_DATA];
+ }
+
+ /* we only ever write errors into the first byte in the flip
+ * flag buffer, so we dont have to clear it all every time
+ */
+
+ if(rstat & 0x04) {
+ icount->parity++;
+ *tty->flip.flag_buf_ptr = TTY_PARITY;
+ } else if(rstat & 0x08) {
+ icount->overrun++;
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ } else if(rstat & 0x02) {
+ icount->frame++;
+ *tty->flip.flag_buf_ptr = TTY_FRAME;
+ } else
+ *tty->flip.flag_buf_ptr = 0;
+
+ /* use the flip buffer next in turn to restart DMA into */
+
+ if (tty->flip.buf_num) {
+ buf = tty->flip.char_buf;
+ } else {
+ buf = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
+ }
+
+ if(buf == phys_to_virt(descr->buf)) {
+ printk("ttyS%d flip-buffer overrun!\n", info->line);
+ icount->overrun++;
+ *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ /* restart old buffer */
+ } else {
+ descr->buf = virt_to_phys(buf);
+
+ /* schedule or push a flip of the buffer */
+
+ info->tty->flip.count = recvl;
+
+#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
+ /* this includes a check for low-latency */
+ tty_flip_buffer_push(tty);
+#else
+ queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif
+ }
+ }
+
+ /* restart the receiving dma */
+
+ descr->sw_len = TTY_FLIPBUF_SIZE;
+ descr->ctrl = d_int | d_eol | d_eop;
+ descr->hw_len = 0;
+ descr->status = 0;
+
+ *info->ifirstadr = virt_to_phys(descr);
+ *info->icmdadr = 1; /* start */
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+ e100_enable_serial_data_irq(info);
+#endif
+ /* input dma should be running now */
+}
+
+static void
+start_receive(struct e100_serial *info)
+{
+ struct etrax_dma_descr *descr;
+
+#ifdef CONFIG_SVINTO_SIM
+ /* No receive in the simulator. Will probably be when the rest of
+ * the serial interface works, and this piece will just be removed.
+ */
+ return;
+#endif
+
+ /* reset the input dma channel to be sure it works */
+
+ *info->icmdadr = 4;
+ while((*info->icmdadr & 7) == 4);
+
+ descr = &info->rec_descr;
+
+ /* start the receiving dma into the flip buffer */
+
+ descr->ctrl = d_int | d_eol | d_eop;
+ descr->sw_len = TTY_FLIPBUF_SIZE;
+ descr->buf = virt_to_phys(info->tty->flip.char_buf_ptr);
+ descr->hw_len = 0;
+ descr->status = 0;
+
+ info->tty->flip.count = 0;
+
+ *info->ifirstadr = virt_to_phys(descr);
+ *info->icmdadr = 1; /* start */
+}
+
+
+static _INLINE_ void
+status_handle(struct e100_serial *info, unsigned short status)
+{
+}
+
+/* the bits in the MASK2 register are laid out like this:
+ DMAI_EOP DMAI_DESCR DMAO_EOP DMAO_DESCR
+ where I is the input channel and O is the output channel for the port.
+ info->irq is the bit number for the DMAO_DESCR so to check the others we
+ shift info->irq to the left.
+*/
+
+/* dma output channel interrupt handler
+ this interrupt is called from DMA2(ser2), DMA4(ser3), DMA6(ser0) or
+ DMA8(ser1) when they have finished a descriptor with the intr flag set.
+*/
+
+static void
+tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct e100_serial *info;
+ unsigned long ireg;
+ int i;
+
+#ifdef CONFIG_SVINTO_SIM
+ /* No receive in the simulator. Will probably be when the rest of
+ * the serial interface works, and this piece will just be removed.
+ */
+ {
+ const char *s = "What? tr_interrupt in simulator??\n";
+ SIMCOUT(s,strlen(s));
+ }
+ return;
+#endif
+
+ /* find out the line that caused this irq and get it from rs_table */
+
+ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */
+
+ for(i = 0; i < NR_PORTS; i++) {
+ info = rs_table + i;
+ /* check for dma_descr (dont need to check for dma_eop in output dma for serial */
+ if(ireg & info->irq) {
+ /* we can send a new dma bunch. make it so. */
+ transmit_chars(info);
+ }
+
+ /* FIXME: here we should really check for a change in the
+ status lines and if so call status_handle(info) */
+ }
+}
+
+/* dma input channel interrupt handler */
+
+static void
+rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+ struct e100_serial *info;
+ unsigned long ireg;
+ int i;
+
+#ifdef CONFIG_SVINTO_SIM
+ /* No receive in the simulator. Will probably be when the rest of
+ * the serial interface works, and this piece will just be removed.
+ */
+ {
+ const char *s = "What? rec_interrupt in simulator??\n";
+ SIMCOUT(s,strlen(s));
+ }
+ return;
+#endif
+
+ /* find out the line that caused this irq and get it from rs_table */
+
+ ireg = *R_IRQ_MASK2_RD; /* get the active irq bits for the dma channels */
+
+ for(i = 0; i < NR_PORTS; i++) {
+ info = rs_table + i;
+ /* check for both dma_eop and dma_descr for the input dma channel */
+ if(ireg & ((info->irq << 2) | (info->irq << 3))) {
+ /* we have received something */
+ receive_chars(info);
+ }
+
+ /* FIXME: here we should really check for a change in the
+ status lines and if so call status_handle(info) */
+ }
+}
+
+/* dma fifo/buffer timeout handler
+ forces an end-of-packet for the dma input channel if no chars
+ have been received for CONFIG_ETRAX100_RX_TIMEOUT_TICKS/100 s.
+ If CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST is configured then this
+ handler is instead run at 15360 Hz.
+*/
+
+#ifndef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST
+static int timeout_divider = 0;
+#endif
+
+static struct timer_list flush_timer;
+
+static void
+timed_flush_handler(void)
+{
+ struct e100_serial *info;
+ int i;
+ unsigned int magic;
+
+#ifdef CONFIG_SVINTO_SIM
+ return;
+#endif
+
+ for(i = 0; i < NR_PORTS; i++) {
+ info = rs_table + i;
+ if(!(info->flags & ASYNC_INITIALIZED))
+ continue;
+
+ /* istatusadr (bit 6-0) hold number of bytes in fifo
+ * ihwswadr (bit 31-16) holds number of bytes in dma buffer
+ * ihwswadr (bit 15-0) specifies size of dma buffer
+ */
+
+ magic = (*info->istatusadr & 0x3f);
+ magic += ((*info->ihwswadr&0xffff ) - (*info->ihwswadr >> 16));
+
+ /* if magic is equal to fifo_magic (magic in previous
+ * timeout_interrupt) then no new data has arrived since last
+ * interrupt and we'll force eop to flush fifo+dma buffers
+ */
+
+ if(magic != info->fifo_magic) {
+ info->fifo_magic = magic;
+ info->fifo_didmagic = 0;
+ } else {
+ /* hit the timeout, force an EOP for the input
+ * dma channel if we haven't already
+ */
+ if(!info->fifo_didmagic && magic) {
+ info->fifo_didmagic = 1;
+ info->fifo_magic = 0;
+ *R_SET_EOP = 1U << info->iseteop;
+ }
+ }
+ }
+
+ /* restart flush timer */
+
+ mod_timer(&flush_timer, jiffies + MAX_FLUSH_TIME);
+}
+
+
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+
+/* If there is an error (ie break) when the DMA is running and
+ * there are no bytes in the fifo the DMA is stopped and we get no
+ * eop interrupt. Thus we have to monitor the first bytes on a DMA
+ * transfer, and if it is without error we can turn the serial
+ * interrupts off.
+ */
+
+static void
+ser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct e100_serial *info;
+ int i;
+ unsigned char rstat;
+
+ for(i = 0; i < NR_PORTS; i++) {
+
+ info = rs_table + i;
+ rstat = info->port[REG_STATUS];
+
+ if(*R_IRQ_MASK1_RD & (1U << (8+2*info->line))) { /* This line caused the irq */
+#ifdef SERIAL_DEBUG_INTR
+ printk("Interrupt from serport %d\n", i);
+#endif
+ if(rstat & 0x0e) {
+ /* FIXME: This is weird, but if this delay is
+ * not present then irmaflash does not work...
+ */
+ udelay(2300);
+
+ /* if we got an error, we must reset it by
+ * reading the data_in field
+ */
+ (void)info->port[REG_DATA];
+
+ PROCSTAT(early_errors_cnt[info->line]++);
+
+ /* restart the DMA */
+ *info->icmdadr = 3;
+ }
+ else { /* it was a valid byte, now let the dma do the rest */
+#ifdef SERIAL_DEBUG_INTR
+ printk("** OK, disabling ser_interupts\n");
+#endif
+ e100_disable_serial_data_irq(info);
+ }
+ }
+ }
+}
+#endif
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void
+do_serial_bh(void)
+{
+ run_task_queue(&tq_serial);
+}
+
+static void
+do_softint(void *private_)
+{
+ struct e100_serial *info = (struct e100_serial *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred. The path of
+ * hangup processing is:
+ *
+ * serial interrupt routine -> (scheduler tqueue) ->
+ * do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ *
+ */
+static void
+do_serial_hangup(void *private_)
+{
+ struct e100_serial *info = (struct e100_serial *) private_;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty)
+ return;
+
+ tty_hangup(tty);
+}
+
+static int
+startup(struct e100_serial * info)
+{
+ unsigned long flags;
+ unsigned long page;
+
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ save_flags(flags); cli();
+
+ /* if it was already initialized, skip this */
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ restore_flags(flags);
+ return -EBUSY;
+ }
+
+ if (info->xmit.buf)
+ free_page(page);
+ else
+ info->xmit.buf = (unsigned char *) page;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("starting up ttyS%d (xmit_buf 0x%x)...\n", info->line, info->xmit_buf);
+#endif
+
+ if(info->tty) {
+
+ /* clear the tty flip flag buffer since we will not
+ * be using it (we only use the first byte..)
+ */
+
+ memset(info->tty->flip.flag_buf, 0, TTY_FLIPBUF_SIZE * 2);
+ }
+
+ save_flags(flags);
+ cli();
+
+#ifdef CONFIG_SVINTO_SIM
+ /* Bits and pieces collected from below. Better to have them
+ in one ifdef:ed clause than to mix in a lot of ifdefs,
+ right? */
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit.head = info->xmit.tail = 0;
+
+ /* No real action in the simulator, but may set info important
+ to ioctl. */
+ change_speed(info);
+#else
+
+ /*
+ * Clear the FIFO buffers and disable them
+ * (they will be reenabled in change_speed())
+ */
+
+ /*
+ * Reset the DMA channels and make sure their interrupts are cleared
+ */
+
+ *info->icmdadr = 4; /* reset command */
+ *info->ocmdadr = 4; /* reset command */
+
+ while((*info->icmdadr & 7) == 4); /* wait until reset cycle is complete */
+ while((*info->ocmdadr & 7) == 4);
+
+ *info->iclrintradr = 3; /* make sure the irqs are cleared */
+ *info->oclrintradr = 3;
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->xmit.head = info->xmit.tail = 0;
+
+ /*
+ * and set the speed and other flags of the serial port
+ * this will start the rx/tx as well
+ */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+ e100_enable_serial_data_irq(info);
+#endif
+ change_speed(info);
+
+ /* dummy read to reset any serial errors */
+
+ (void)info->port[REG_DATA];
+
+ /* enable the interrupts */
+
+ e100_enable_txdma_irq(info);
+ e100_enable_rxdma_irq(info);
+
+ info->tr_running = 0; /* to be sure we dont lock up the transmitter */
+
+ /* setup the dma input descriptor and start dma */
+
+ start_receive(info);
+
+ /* for safety, make sure the descriptors last result is 0 bytes written */
+
+ info->tr_descr.sw_len = 0;
+ info->tr_descr.hw_len = 0;
+ info->tr_descr.status = 0;
+
+ /* enable RTS/DTR last */
+
+ e100_rts(info, 1);
+ e100_dtr(info, 1);
+
+#endif /* CONFIG_SVINTO_SIM */
+
+ info->flags |= ASYNC_INITIALIZED;
+
+ restore_flags(flags);
+ return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void
+shutdown(struct e100_serial * info)
+{
+ unsigned long flags;
+
+#ifndef CONFIG_SVINTO_SIM
+ /* shut down the transmitter and receiver */
+
+ e100_disable_rx(info);
+ info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
+
+ e100_disable_rxdma_irq(info);
+ e100_disable_txdma_irq(info);
+
+ info->tr_running = 0;
+
+ /* reset both dma channels */
+
+ *info->icmdadr = 4;
+ *info->ocmdadr = 4;
+
+#endif /* CONFIG_SVINTO_SIM */
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("Shutting down serial port %d (irq %d)....\n", info->line,
+ info->irq);
+#endif
+
+ save_flags(flags);
+ cli(); /* Disable interrupts */
+
+ if (info->xmit.buf) {
+ unsigned long pg = (unsigned long) info->xmit.buf;
+ info->xmit.buf = 0;
+ free_page(pg);
+ }
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ /* hang up DTR and RTS if HUPCL is enabled */
+ e100_dtr(info, 0);
+ e100_rts(info, 0); /* could check CRTSCTS before doing this */
+ }
+
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+}
+
+
+/* change baud rate and other assorted parameters */
+
+static void
+change_speed(struct e100_serial *info)
+{
+ unsigned int cflag;
+
+ /* first some safety checks */
+
+ if(!info->tty || !info->tty->termios)
+ return;
+ if (!info->port)
+ return;
+
+ cflag = info->tty->termios->c_cflag;
+
+ /* possibly, the tx/rx should be disabled first to do this safely */
+
+ /* change baud-rate and write it to the hardware */
+
+ info->baud = cflag_to_baud(cflag);
+
+#ifndef CONFIG_SVINTO_SIM
+ info->port[REG_BAUD] = cflag_to_etrax_baud(cflag);
+ /* start with default settings and then fill in changes */
+
+ info->rx_ctrl &= ~(0x07); /* 8 bit, no/even parity */
+ info->tx_ctrl &= ~(0x37); /* 8 bit, no/even parity, 1 stop bit, no cts */
+
+ if ((cflag & CSIZE) == CS7) {
+ /* set 7 bit mode */
+ info->tx_ctrl |= 0x01;
+ info->rx_ctrl |= 0x01;
+ }
+
+ if (cflag & CSTOPB) {
+ /* set 2 stop bit mode */
+ info->tx_ctrl |= 0x10;
+ }
+
+ if (cflag & PARENB) {
+ /* enable parity */
+ info->tx_ctrl |= 0x02;
+ info->rx_ctrl |= 0x02;
+ }
+
+ if (cflag & PARODD) {
+ /* set odd parity */
+ info->tx_ctrl |= 0x04;
+ info->rx_ctrl |= 0x04;
+ }
+
+ if (cflag & CRTSCTS) {
+ /* enable automatic CTS handling */
+ info->tx_ctrl |= 0x20;
+ }
+
+ /* make sure the tx and rx are enabled */
+
+ info->tx_ctrl |= 0x40;
+ info->rx_ctrl |= 0x40;
+
+ /* actually write the control regs to the hardware */
+
+ info->port[REG_TR_CTRL] = info->tx_ctrl;
+ info->port[REG_REC_CTRL] = info->rx_ctrl;
+ *((unsigned long *)&info->port[REG_XOFF]) = 0;
+
+#endif /* CONFIG_SVINTO_SIM */
+}
+
+/* start transmitting chars NOW */
+
+static void
+rs_flush_chars(struct tty_struct *tty)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (info->tr_running
+ || info->xmit.head == info->xmit.tail
+ || tty->stopped
+ || tty->hw_stopped
+ || !info->xmit.buf)
+ return;
+
+#ifdef SERIAL_DEBUG_FLOW
+ printk("rs_flush_chars\n");
+#endif
+
+ /* this protection might not exactly be necessary here */
+
+ save_flags(flags);
+ cli();
+ start_transmit(info);
+ restore_flags(flags);
+}
+
+static int
+rs_write(struct tty_struct * tty, int from_user,
+ const unsigned char *buf, int count)
+{
+ int c, ret = 0;
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+
+ /* first some sanity checks */
+
+ if (!tty || !info->xmit.buf || !tmp_buf)
+ return 0;
+
+#ifdef SERIAL_DEBUG_DATA
+ if(info->line == SERIAL_DEBUG_LINE)
+ printk("rs_write (%d), status %d\n",
+ count, info->port[REG_STATUS]);
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+ /* Really simple. The output is here and now. */
+ SIMCOUT(buf, count);
+ return;
+#endif
+ save_flags(flags);
+
+ /* the cli/restore_flags pairs below are needed because the
+ * DMA interrupt handler moves the info->xmit values. the memcpy
+ * needs to be in the critical region unfortunately, because we
+ * need to read xmit values, memcpy, write xmit values in one
+ * atomic operation... this could perhaps be avoided by more clever
+ * design.
+ */
+ if(from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ int c1;
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ cli();
+ c1 = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+ if (c1 < c)
+ c = c1;
+ memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+ info->xmit.head = ((info->xmit.head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ cli();
+ while(1) {
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ SERIAL_XMIT_SIZE);
+
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+
+ memcpy(info->xmit.buf + info->xmit.head, buf, c);
+ info->xmit.head = (info->xmit.head + c) &
+ (SERIAL_XMIT_SIZE-1);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ restore_flags(flags);
+ }
+
+ /* enable transmitter if not running, unless the tty is stopped
+ * this does not need IRQ protection since if tr_running == 0
+ * the IRQ's are not running anyway for this port.
+ */
+
+ if(info->xmit.head != info->xmit.tail
+ && !tty->stopped &&
+ !tty->hw_stopped &&
+ !info->tr_running) {
+ start_transmit(info);
+ }
+
+ return ret;
+}
+
+/* how much space is available in the xmit buffer? */
+
+static int
+rs_write_room(struct tty_struct *tty)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+ return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* How many chars are in the xmit buffer?
+ * This does not include any chars in the transmitter FIFO.
+ * Use wait_until_sent for waiting for FIFO drain.
+ */
+
+static int
+rs_chars_in_buffer(struct tty_struct *tty)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+ return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+}
+
+/* discard everything in the xmit buffer */
+
+static void
+rs_flush_buffer(struct tty_struct *tty)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ info->xmit.head = info->xmit.tail = 0;
+ restore_flags(flags);
+
+ wake_up_interruptible(&tty->write_wait);
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ *
+ * Since we don't bother to check for info->x_char in transmit_chars yet,
+ * we don't really implement this function yet.
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+ printk("serial.c:rs_send_xchar not implemented!\n");
+
+ info->x_char = ch;
+ if (ch) {
+ /* Make sure transmit interrupts are on */
+ /* TODO. */
+ }
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ *
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void
+rs_throttle(struct tty_struct * tty)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("throttle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (I_IXOFF(tty))
+ info->x_char = STOP_CHAR(tty);
+
+ /* Turn off RTS line (do this atomic) should here be an else ?? */
+
+ save_flags(flags);
+ cli();
+ e100_rts(info, 0);
+ restore_flags(flags);
+}
+
+static void
+rs_unthrottle(struct tty_struct * tty)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+ char buf[64];
+
+ printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+ tty->ldisc.chars_in_buffer(tty));
+#endif
+
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ info->x_char = START_CHAR(tty);
+ }
+
+ /* Assert RTS line (do this atomic) */
+
+ save_flags(flags);
+ cli();
+ e100_rts(info, 1);
+ restore_flags(flags);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int
+get_serial_info(struct e100_serial * info,
+ struct serial_struct * retinfo)
+{
+ struct serial_struct tmp;
+
+ /* this is all probably wrong, there are a lot of fields
+ * here that we don't have in e100_serial and maybe we
+ * should set them to something else than 0.
+ */
+
+ if (!retinfo)
+ return -EFAULT;
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = info->type;
+ tmp.line = info->line;
+ tmp.port = (int)info->port;
+ tmp.irq = info->irq;
+ tmp.flags = info->flags;
+ tmp.close_delay = info->close_delay;
+ tmp.closing_wait = info->closing_wait;
+ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int
+set_serial_info(struct e100_serial * info,
+ struct serial_struct * new_info)
+{
+ struct serial_struct new_serial;
+ struct e100_serial old_info;
+ int retval = 0;
+
+ if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+ return -EFAULT;
+
+ old_info = *info;
+
+ if(!capable(CAP_SYS_ADMIN)) {
+ if((new_serial.type != info->type) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) !=
+ (info->flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ goto check_and_exit;
+ }
+
+ if (info->count > 1)
+ return -EBUSY;
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+
+ info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
+ info->type = new_serial.type;
+ info->close_delay = new_serial.close_delay;
+ info->closing_wait = new_serial.closing_wait;
+#if (LINUX_VERSION_CODE > 0x20100)
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
+
+ check_and_exit:
+ if(info->flags & ASYNC_INITIALIZED) {
+ change_speed(info);
+ } else
+ retval = startup(info);
+ return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int
+get_lsr_info(struct e100_serial * info, unsigned int *value)
+{
+ unsigned int result;
+
+#ifdef CONFIG_SVINTO_SIM
+ /* Always open. */
+ result = TIOCSER_TEMT;
+#else
+ if (*info->ostatusadr & 0x007F) /* something in fifo */
+ result = 0;
+ else
+ result = TIOCSER_TEMT;
+#endif
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+#ifdef SERIAL_DEBUG_IO
+struct state_str
+{
+ int state;
+ const char *str;
+
+};
+
+const struct state_str control_state_str[]={
+ {TIOCM_DTR, "DTR" },
+ {TIOCM_RTS, "RTS"},
+ {TIOCM_ST, "ST?" },
+ {TIOCM_SR, "SR?" },
+ {TIOCM_CTS, "CTS" },
+ {TIOCM_CD, "CD" },
+ {TIOCM_RI, "RI" },
+ {TIOCM_DSR, "DSR" },
+ {0, NULL }
+};
+
+char *get_control_state_str(int MLines, char *s)
+{
+ int i = 0;
+ s[0]='\0';
+ while (control_state_str[i].str != NULL) {
+ if (MLines & control_state_str[i].state) {
+ if (s[0] != '\0') {
+ strcat(s, ", ");
+ }
+ strcat(s, control_state_str[i].str);
+ }
+ i++;
+ }
+ return s;
+}
+#endif
+
+static int
+get_modem_info(struct e100_serial * info, unsigned int *value)
+{
+ unsigned int result;
+ /* Polarity isn't verified */
+#if 0 /*def SERIAL_DEBUG_IO */
+
+ printk("get_modem_info: RTS: %i DTR: %i CD: %i RI: %i DSR: %i CTS: %i\n",
+ E100_RTS_GET(info),
+ E100_DTR_GET(info),
+ E100_CD_GET(info),
+ E100_RI_GET(info),
+ E100_DSR_GET(info),
+ E100_CTS_GET(info));
+#endif
+ result =
+ (!E100_RTS_GET(info) ? TIOCM_RTS : 0)
+ | (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
+ | (!E100_CD_GET(info) ? TIOCM_CAR : 0)
+ | (!E100_RI_GET(info) ? TIOCM_RNG : 0)
+ | (!E100_DSR_GET(info) ? TIOCM_DSR : 0)
+ | (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
+
+#ifdef SERIAL_DEBUG_IO
+ printk("e100ser: modem state: %i 0x%08X\n", result, result);
+ {
+ char s[100];
+
+ get_control_state_str(result, s);
+ printk("state: %s\n", s);
+ }
+#endif
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+
+static int
+set_modem_info(struct e100_serial * info, unsigned int cmd,
+ unsigned int *value)
+{
+ unsigned int arg;
+
+ if (copy_from_user(&arg, value, sizeof(int)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS) {
+ e100_rts(info, 1);
+ }
+ if (arg & TIOCM_DTR) {
+ e100_dtr(info, 1);
+ }
+ /* Handle FEMALE behaviour */
+ if (arg & TIOCM_RI) {
+ e100_ri_out(info, 1);
+ }
+ if (arg & TIOCM_CD) {
+ e100_cd_out(info, 1);
+ }
+ break;
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS) {
+ e100_rts(info, 0);
+ }
+ if (arg & TIOCM_DTR) {
+ e100_dtr(info, 0);
+ }
+ /* Handle FEMALE behaviour */
+ if (arg & TIOCM_RI) {
+ e100_ri_out(info, 0);
+ }
+ if (arg & TIOCM_CD) {
+ e100_cd_out(info, 0);
+ }
+ break;
+ case TIOCMSET:
+ e100_rts(info, arg & TIOCM_RTS);
+ e100_dtr(info, arg & TIOCM_DTR);
+ /* Handle FEMALE behaviour */
+ e100_ri_out(info, arg & TIOCM_RI);
+ e100_cd_out(info, arg & TIOCM_CD);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static void
+send_break(struct e100_serial * info, int duration)
+{
+ unsigned long flags;
+
+ if (!info->port)
+ return;
+
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + duration;
+
+ save_flags(flags);
+ cli();
+
+ /* Go to manual mode and set the txd pin to 0 */
+
+ info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */
+ info->port[REG_TR_CTRL] = info->tx_ctrl;
+
+ /* wait for "duration" jiffies */
+
+ schedule();
+
+ info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */
+ info->port[REG_TR_CTRL] = info->tx_ctrl;
+
+ /* the DMA gets awfully confused if we toggle the tranceiver like this
+ * so we need to reset it
+ */
+ *info->ocmdadr = 4;
+
+ restore_flags(flags);
+}
+#else
+static void
+rs_break(struct tty_struct *tty, int break_state)
+{
+ struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (!info->port)
+ return;
+
+ save_flags(flags);
+ cli();
+ if (break_state == -1) {
+ /* Go to manual mode and set the txd pin to 0 */
+ info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */
+ } else {
+ info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */
+ }
+ info->port[REG_TR_CTRL] = info->tx_ctrl;
+ restore_flags(flags);
+}
+#endif
+
+static int
+rs_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ int error;
+ struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+ int retval;
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
+ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ if (!arg) {
+ send_break(info, HZ/4); /* 1/4 second */
+ if (signal_pending(current))
+ return -EINTR;
+ }
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ tty_wait_until_sent(tty, 0);
+ if (signal_pending(current))
+ return -EINTR;
+ send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ if (signal_pending(current))
+ return -EINTR;
+ return 0;
+ case TIOCGSOFTCAR:
+ error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+ if (error)
+ return error;
+ put_fs_long(C_CLOCAL(tty) ? 1 : 0,
+ (unsigned long *) arg);
+ return 0;
+ case TIOCSSOFTCAR:
+ arg = get_fs_long((unsigned long *) arg);
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ return 0;
+#endif
+ case TIOCMGET:
+ return get_modem_info(info, (unsigned int *) arg);
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return set_modem_info(info, cmd, (unsigned int *) arg);
+ case TIOCGSERIAL:
+ return get_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info(info, (unsigned int *) arg);
+
+ case TIOCSERGSTRUCT:
+ if (copy_to_user((struct e100_serial *) arg,
+ info, sizeof(struct e100_serial)))
+ return -EFAULT;
+ return 0;
+
+#if defined(CONFIG_RS485)
+ case TIOCSERSETRS485:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct rs485_control));
+
+ if (error)
+ return error;
+
+ return e100_enable_rs485(tty, (struct rs485_control *) arg);
+
+ case TIOCSERWRRS485:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct rs485_write));
+
+ if (error)
+ return error;
+
+ return e100_write_rs485(tty, (struct rs485_write *) arg);
+#endif
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void
+rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+ if (tty->termios->c_cflag == old_termios->c_cflag)
+ return;
+
+ change_speed(info);
+
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ rs_start(tty);
+ }
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ *
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * S structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void
+rs_close(struct tty_struct *tty, struct file * filp)
+{
+ struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (!info)
+ return;
+
+ /* interrupts are disabled for this entire function */
+
+ save_flags(flags);
+ cli();
+
+ if (tty_hung_up_p(filp)) {
+ restore_flags(flags);
+ return;
+ }
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
+ info->line, info->count);
+#endif
+ if ((tty->count == 1) && (info->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. Info->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("rs_close: bad serial port count; tty->count is 1, "
+ "info->count is %d\n", info->count);
+ info->count = 1;
+ }
+ if (--info->count < 0) {
+ printk("rs_close: bad serial port count for ttyS%d: %d\n",
+ info->line, info->count);
+ info->count = 0;
+ }
+ if (info->count) {
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ info->normal_termios = *tty->termios;
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ info->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->closing_wait);
+ /*
+ * At this point we stop accepting input. To do this, we
+ * disable the serial receiver and the DMA receive interrupt.
+ */
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+ e100_disable_serial_data_irq(info);
+#endif
+
+#ifndef CONFIG_SVINTO_SIM
+ e100_disable_rx(info);
+ e100_disable_rxdma_irq(info);
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important as we have a transmit FIFO!
+ */
+ rs_wait_until_sent(tty, HZ);
+ }
+#endif
+
+ shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = 0;
+ if (info->blocked_open) {
+ if (info->close_delay) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(info->close_delay);
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+ ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+ restore_flags(flags);
+
+ /* port closed */
+
+#if defined(CONFIG_RS485)
+ if (info->rs485.enabled) {
+ info->rs485.enabled = 0;
+#if defined(CONFIG_RS485_ON_PA)
+ *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
+#endif
+ }
+#endif
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ unsigned long orig_jiffies;
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+
+ /*
+ * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
+ * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
+ */
+ orig_jiffies = jiffies;
+ while(info->xmit.head != info->xmit.tail || /* More in send queue */
+ (*info->ostatusadr & 0x007f)) { /* more in FIFO */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ if (signal_pending(current))
+ break;
+ if (timeout && time_after(jiffies, orig_jiffies + timeout))
+ break;
+ }
+ set_current_state(TASK_RUNNING);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void
+rs_hangup(struct tty_struct *tty)
+{
+ struct e100_serial * info = (struct e100_serial *)tty->driver_data;
+
+ rs_flush_buffer(tty);
+ shutdown(info);
+ info->event = 0;
+ info->count = 0;
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+ info->tty = 0;
+ wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int
+block_til_ready(struct tty_struct *tty, struct file * filp,
+ struct e100_serial *info)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int retval;
+ int do_clocal = 0, extra_count = 0;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ return -EAGAIN;
+ else
+ return -ERESTARTSYS;
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return -EBUSY;
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return -EBUSY;
+ info->flags |= ASYNC_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+ if (info->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, info->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready before block: ttyS%d, count = %d\n",
+ info->line, info->count);
+#endif
+ save_flags(flags);
+ cli();
+ if (!tty_hung_up_p(filp)) {
+ extra_count++;
+ info->count--;
+ }
+ restore_flags(flags);
+ info->blocked_open++;
+ while (1) {
+ save_flags(flags);
+ cli();
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) {
+ /* assert RTS and DTR */
+ e100_rts(info, 1);
+ e100_dtr(info, 1);
+ }
+ restore_flags(flags);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ !(info->flags & ASYNC_CLOSING) && do_clocal)
+ /* && (do_clocal || DCD_IS_ASSERTED) */
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready blocking: ttyS%d, count = %d\n",
+ info->line, info->count);
+#endif
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&info->open_wait, &wait);
+ if (extra_count)
+ info->count++;
+ info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+ printk("block_til_ready after blocking: ttyS%d, count = %d\n",
+ info->line, info->count);
+#endif
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.
+ * It performs the serial-specific initialization for the tty structure.
+ */
+static int
+rs_open(struct tty_struct *tty, struct file * filp)
+{
+ struct e100_serial *info;
+ int retval, line;
+ unsigned long page;
+
+ /* find which port we want to open */
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+
+ if (line < 0 || line >= NR_PORTS)
+ return -ENODEV;
+
+ /* dont allow opening ports that are not enabled in the HW config */
+
+#ifndef CONFIG_ETRAX100_SERIAL_PORT2
+ if (line == 2)
+ return -ENODEV;
+#endif
+#ifndef CONFIG_ETRAX100_SERIAL_PORT3
+ if (line == 3)
+ return -ENODEV;
+#endif
+
+ /* find the corresponding e100_serial struct in the table */
+
+ info = rs_table + line;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("[%d] rs_open %s%d, count = %d\n", current->pid,
+ tty->driver.name, info->line,
+ info->count);
+#endif
+
+ info->count++;
+ tty->driver_data = info;
+ info->tty = tty;
+
+#if (LINUX_VERSION_CODE > 0x20100)
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
+
+ if (!tmp_buf) {
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page) {
+ return -ENOMEM;
+ }
+ if (tmp_buf)
+ free_page(page);
+ else
+ tmp_buf = (unsigned char *) page;
+ }
+
+ /*
+ * If the port is the middle of closing, bail out now
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+ return ((info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS);
+#else
+ return -EAGAIN;
+#endif
+ }
+
+ /*
+ * Start up the serial port
+ */
+
+ retval = startup(info);
+ if (retval)
+ return retval;
+
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open returning after block_til_ready with %d\n",
+ retval);
+#endif
+ return retval;
+ }
+
+ if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->normal_termios;
+ else
+ *tty->termios = info->callout_termios;
+ change_speed(info);
+ }
+
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+ printk("rs_open ttyS%d successful...\n", info->line);
+#endif
+ return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct e100_serial *info)
+{
+ char stat_buf[30], control, status;
+ int ret;
+ unsigned long flags;
+
+ ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d",
+ info->line, info->port, info->irq);
+
+ if (!info->port || (info->type == PORT_UNKNOWN)) {
+ ret += sprintf(buf+ret, "\n");
+ return ret;
+ }
+
+ stat_buf[0] = 0;
+ stat_buf[1] = 0;
+ if (E100_RTS_GET(info))
+ strcat(stat_buf, "|RTS");
+ if (E100_CTS_GET(info))
+ strcat(stat_buf, "|CTS");
+ if (E100_DTR_GET(info))
+ strcat(stat_buf, "|DTR");
+ if (E100_DSR_GET(info))
+ strcat(stat_buf, "|DSR");
+ if (E100_CD_GET(info))
+ strcat(stat_buf, "|CD");
+ if (E100_RI_GET(info))
+ strcat(stat_buf, "|RI");
+
+ ret += sprintf(buf+ret, " baud:%d", info->baud);
+
+ ret += sprintf(buf+ret, " tx:%d rx:%d",
+ info->icount.tx, info->icount.rx);
+
+ if (info->icount.frame)
+ ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+
+ if (info->icount.parity)
+ ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+
+ if (info->icount.brk)
+ ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+
+ if (info->icount.overrun)
+ ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+
+ /*
+ * Last thing is the RS-232 status lines
+ */
+ ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+ return ret;
+}
+
+int rs_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int i, len = 0, l;
+ off_t begin = 0;
+
+ len += sprintf(page, "serinfo:1.0 driver:%s\n",
+ serial_version);
+ for (i = 0; i < NR_PORTS && len < 4000; i++) {
+ l = line_info(page + len, &rs_table[i]);
+ len += l;
+ if (len+begin > off+count)
+ goto done;
+ if (len+begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+ *eof = 1;
+done:
+ if (off >= len+begin)
+ return 0;
+ *start = page + (off-begin);
+ return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void
+show_serial_version(void)
+{
+ printk("ETRAX 100LX serial-driver %s, (c) 2000 Axis Communications AB\r\n",
+ serial_version);
+}
+
+/* rs_init inits the driver at boot (using the module_init chain) */
+
+static int __init
+rs_init(void)
+{
+ int i;
+ struct e100_serial *info;
+
+ show_serial_version();
+
+ init_bh(SERIAL_BH, do_serial_bh);
+
+ /* Setup the timed flush handler system */
+
+ init_timer(&flush_timer);
+ flush_timer.function = timed_flush_handler;
+ mod_timer(&flush_timer, jiffies + MAX_FLUSH_TIME);
+
+ /* Initialize the tty_driver structure */
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
+ serial_driver.driver_name = "serial";
+#endif
+ serial_driver.name = "ttyS";
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = NR_PORTS; /* etrax100 has 4 serial ports */
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+ serial_driver.init_termios.c_cflag =
+ B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
+ serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = rs_open;
+ serial_driver.close = rs_close;
+ serial_driver.write = rs_write;
+ /* should we have an rs_put_char as well here ? */
+ serial_driver.flush_chars = rs_flush_chars;
+ serial_driver.write_room = rs_write_room;
+ serial_driver.chars_in_buffer = rs_chars_in_buffer;
+ serial_driver.flush_buffer = rs_flush_buffer;
+ serial_driver.ioctl = rs_ioctl;
+ serial_driver.throttle = rs_throttle;
+ serial_driver.unthrottle = rs_unthrottle;
+ serial_driver.set_termios = rs_set_termios;
+ serial_driver.stop = rs_stop;
+ serial_driver.start = rs_start;
+ serial_driver.hangup = rs_hangup;
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+ serial_driver.break_ctl = rs_break;
+#endif
+#if (LINUX_VERSION_CODE >= 131343)
+ serial_driver.send_xchar = rs_send_xchar;
+ serial_driver.wait_until_sent = rs_wait_until_sent;
+ serial_driver.read_proc = rs_read_proc;
+#endif
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+ callout_driver.name = "cua";
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+#if (LINUX_VERSION_CODE >= 131343)
+ callout_driver.read_proc = 0;
+ callout_driver.proc_entry = 0;
+#endif
+
+ if (tty_register_driver(&serial_driver))
+ panic("Couldn't register serial driver\n");
+ if (tty_register_driver(&callout_driver))
+ panic("Couldn't register callout driver\n");
+
+ /* do some initializing for the separate ports */
+
+ for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
+ info->line = i;
+ info->tty = 0;
+ info->type = PORT_ETRAX100;
+ info->tr_running = 0;
+ info->fifo_magic = 0;
+ info->fifo_didmagic = 0;
+ info->flags = 0;
+ info->close_delay = 5*HZ/10;
+ info->closing_wait = 30*HZ;
+ info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+ info->callout_termios = callout_driver.init_termios;
+ info->normal_termios = serial_driver.init_termios;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ info->xmit.buf = 0;
+ info->xmit.tail = info->xmit.head = 0;
+
+ printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n",
+ serial_driver.name, info->line, (unsigned int)info->port);
+ }
+
+#ifndef CONFIG_SVINTO_SIM
+ /* Not needed in simulator. May only complicate stuff. */
+ /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
+ if(request_irq(22, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL))
+ panic("irq22");
+ if(request_irq(23, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL))
+ panic("irq23");
+#ifdef SERIAL_HANDLE_EARLY_ERRORS
+ if(request_irq(8, ser_interrupt, SA_INTERRUPT, "serial ", NULL))
+ panic("irq8");
+#endif
+ if(request_irq(24, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL))
+ panic("irq24");
+ if(request_irq(25, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL))
+ panic("irq25");
+#ifdef CONFIG_ETRAX100_SERIAL_PORT2
+ /* DMA Shared with par0 (and SCSI0 and ATA) */
+ if(request_irq(18, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL))
+ panic("irq18");
+ if(request_irq(19, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL))
+ panic("irq19");
+#endif
+#ifdef CONFIG_ETRAX100_SERIAL_PORT3
+ /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */
+ if(request_irq(20, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL))
+ panic("irq20");
+ if(request_irq(21, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL))
+ panic("irq21");
+#endif
+#ifdef CONFIG_ETRAX100_SERIAL_FLUSH_DMA_FAST
+ /* TODO: a timeout_interrupt needs to be written that calls timeout_handler */
+ if(request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ,
+ "fast serial dma timeout", NULL)) {
+ printk("err: timer1 irq\n");
+ }
+#endif
+#endif /* CONFIG_SVINTO_SIM */
+
+ return 0;
+}
+
+/* this makes sure that rs_init is called during kernel boot */
+
+module_init(rs_init);
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+int
+register_serial(struct serial_struct *req)
+{
+ return -1;
+}
+
+void unregister_serial(int line)
+{
+}
diff --git a/arch/cris/drivers/serial.h b/arch/cris/drivers/serial.h
new file mode 100644
index 000000000..650c5e9b4
--- /dev/null
+++ b/arch/cris/drivers/serial.h
@@ -0,0 +1,106 @@
+/*
+ * serial.h: Arch-dep definitions for the Etrax100 serial driver.
+ *
+ * Copyright (C) 1998, 1999, 2000 Axis Communications AB
+ */
+
+#ifndef _ETRAX100_SERIAL_H
+#define _ETRAX100_SERIAL_H
+
+#include <linux/config.h>
+#include <linux/circ_buf.h>
+#include <asm/termios.h>
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct e100_serial {
+ int baud;
+ volatile unsigned char * port; /* R_SERIALx_CTRL */
+ unsigned long irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+
+ volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */
+ volatile unsigned long *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */
+ volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */
+ const volatile unsigned short *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */
+ volatile unsigned long *ohwswadr; /* adr to R_DMA_CHx_HWSW, output */
+
+ volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */
+ volatile unsigned long *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */
+ volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */
+ const volatile unsigned short *istatusadr; /* adr to R_DMA_CHx_STATUS, input */
+ volatile unsigned long *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */
+
+ int flags; /* defined in tty.h */
+
+ unsigned char rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
+ unsigned char tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
+ unsigned char iseteop; /* bit number for R_SET_EOP for the input dma */
+/* end of fields defined in rs_table[] in .c-file */
+ unsigned char fifo_didmagic; /* a fifo eop has been forced */
+
+ struct etrax_dma_descr tr_descr, rec_descr;
+
+ int fifo_magic; /* fifo amount - bytes left in dma buffer */
+
+ volatile int tr_running; /* 1 if output is running */
+
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int x_char; /* xon/xoff character */
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ unsigned long event;
+ unsigned long last_active;
+ int line;
+ int type; /* PORT_ETRAX100 */
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ struct circ_buf xmit;
+
+ struct tq_struct tqueue;
+ struct async_icount icount; /* error-statistics etc.*/
+ struct termios normal_termios;
+ struct termios callout_termios;
+#ifdef DECLARE_WAITQUEUE
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+#else
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+#endif
+
+#ifdef CONFIG_RS485
+ struct rs485_control rs485; /* RS-485 support */
+#endif
+};
+
+/* this PORT is not in the standard serial.h. it's not actually used for
+ * anything since we only have one type of async serial-port anyway in this
+ * system.
+ */
+
+#define PORT_ETRAX100 1
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP 0
+
+#endif /* __KERNEL__ */
+
+#endif /* !(_ETRAX100_SERIAL_H) */
diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile
new file mode 100644
index 000000000..0681e4807
--- /dev/null
+++ b/arch/cris/kernel/Makefile
@@ -0,0 +1,25 @@
+# $Id: Makefile,v 1.3 2001/01/10 21:11:07 bjornw Exp $
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.o:
+ $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+
+all: kernel.o head.o
+
+O_TARGET := kernel.o
+obj-y := process.o signal.o entry.o traps.o irq.o \
+ ptrace.o setup.o time.o sys_cris.o shadows.o \
+ debugport.o semaphore.o
+
+obj-$(CONFIG_KGDB) += kgdb.o
+
+clean:
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/cris/kernel/debugport.c b/arch/cris/kernel/debugport.c
new file mode 100644
index 000000000..a2b29be95
--- /dev/null
+++ b/arch/cris/kernel/debugport.c
@@ -0,0 +1,242 @@
+/* Serialport functions for debugging
+ *
+ * Copyright (c) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen
+ *
+ * Exports:
+ * console_print_etrax(char *buf)
+ * int getDebugChar()
+ * putDebugChar(int)
+ * enableDebugIRQ()
+ * init_etrax_debug()
+ *
+ * $Log: debugport.c,v $
+ * Revision 1.4 2000/10/06 12:37:26 bjornw
+ * Use physical addresses when talking to DMA
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/major.h>
+
+#include <asm/system.h>
+#include <asm/svinto.h>
+#include <asm/io.h> /* Get SIMCOUT. */
+
+/* Which serial-port is our debug port ? */
+
+#if defined(CONFIG_DEBUG_PORT0) || defined(CONFIG_DEBUG_PORT_NULL)
+#define DEBUG_PORT_IDX 0
+#define DEBUG_OCMD R_DMA_CH6_CMD
+#define DEBUG_FIRST R_DMA_CH6_FIRST
+#define DEBUG_OCLRINT R_DMA_CH6_CLR_INTR
+#define DEBUG_STATUS R_DMA_CH6_STATUS
+#define DEBUG_READ R_SERIAL0_READ
+#define DEBUG_WRITE R_SERIAL0_TR_DATA
+#define DEBUG_TR_CTRL R_SERIAL0_TR_CTRL
+#define DEBUG_REC_CTRL R_SERIAL0_REC_CTRL
+#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser0_data, set)
+#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma6_descr, clr)
+#endif
+
+#ifdef CONFIG_DEBUG_PORT1
+#define DEBUG_PORT_IDX 1
+#define DEBUG_OCMD R_DMA_CH8_CMD
+#define DEBUG_FIRST R_DMA_CH8_FIRST
+#define DEBUG_OCLRINT R_DMA_CH8_CLR_INTR
+#define DEBUG_STATUS R_DMA_CH8_STATUS
+#define DEBUG_READ R_SERIAL1_READ
+#define DEBUG_WRITE R_SERIAL1_TR_DATA
+#define DEBUG_TR_CTRL R_SERIAL1_TR_CTRL
+#define DEBUG_REC_CTRL R_SERIAL1_REC_CTRL
+#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser1_data, set)
+#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma8_descr, clr)
+#endif
+
+#ifdef CONFIG_DEBUG_PORT2
+#define DEBUG_PORT_IDX 2
+#define DEBUG_OCMD R_DMA_CH2_CMD
+#define DEBUG_FIRST R_DMA_CH2_FIRST
+#define DEBUG_OCLRINT R_DMA_CH2_CLR_INTR
+#define DEBUG_STATUS R_DMA_CH2_STATUS
+#define DEBUG_READ R_SERIAL2_READ
+#define DEBUG_WRITE R_SERIAL2_TR_DATA
+#define DEBUG_TR_CTRL R_SERIAL2_TR_CTRL
+#define DEBUG_REC_CTRL R_SERIAL2_REC_CTRL
+#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser2_data, set)
+#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma2_descr, clr)
+#endif
+
+#ifdef CONFIG_DEBUG_PORT3
+#define DEBUG_PORT_IDX 3
+#define DEBUG_OCMD R_DMA_CH4_CMD
+#define DEBUG_FIRST R_DMA_CH4_FIRST
+#define DEBUG_OCLRINT R_DMA_CH4_CLR_INTR
+#define DEBUG_STATUS R_DMA_CH4_STATUS
+#define DEBUG_READ R_SERIAL3_READ
+#define DEBUG_WRITE R_SERIAL3_TR_DATA
+#define DEBUG_TR_CTRL R_SERIAL3_TR_CTRL
+#define DEBUG_REC_CTRL R_SERIAL3_REC_CTRL
+#define DEBUG_IRQ IO_STATE(R_IRQ_MASK1_SET, ser3_data, set)
+#define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma4_descr, clr)
+#endif
+
+/* Write a string of count length to the console (debug port) using DMA, polled
+ * for completion. Interrupts are disabled during the whole process. Some
+ * caution needs to be taken to not interfere with ttyS business on this port.
+ */
+
+static void
+console_write(struct console *co, const char *buf, unsigned int len)
+{
+ static struct etrax_dma_descr descr;
+ unsigned long flags;
+ int in_progress;
+
+#ifdef CONFIG_DEBUG_PORT_NULL
+ /* no debug printout at all */
+ return;
+#endif
+
+#ifdef CONFIG_SVINTO_SIM
+ /* no use to simulate the serial debug output */
+ SIMCOUT(buf,len);
+ return;
+#endif
+
+ save_flags(flags);
+ cli();
+
+#ifdef CONFIG_KGDB
+ /* kgdb needs to output debug info using the gdb protocol */
+ putDebugString(buf, len);
+ restore_flags(flags);
+ return;
+#endif
+
+ /* make sure the transmitter is enabled.
+ * NOTE: this overrides any setting done in ttySx, to 8N1, no auto-CTS.
+ * in the future, move the tr/rec_ctrl shadows from etrax100ser.c to
+ * shadows.c and use it here as well...
+ */
+
+ *DEBUG_TR_CTRL = 0x40;
+
+ /* if the tty has some ongoing business, remember it */
+
+ in_progress = *DEBUG_OCMD & 7;
+
+ if(in_progress) {
+ /* wait until the output dma channel is ready */
+
+ while(*DEBUG_OCMD & 7) /* nothing */ ;
+ }
+
+ descr.ctrl = d_eol;
+ descr.sw_len = len;
+ descr.buf = __pa(buf);
+
+ *DEBUG_FIRST = __pa(&descr); /* write to R_DMAx_FIRST */
+ *DEBUG_OCMD = 1; /* dma command start -> R_DMAx_CMD */
+
+ /* wait until the output dma channel is ready again */
+
+ while(*DEBUG_OCMD & 7) /* nothing */;
+
+ /* clear pending interrupts so we don't get a surprise below */
+
+ if(in_progress)
+ *DEBUG_OCLRINT = 2; /* only clear EOP, leave DESCR for the tty */
+ else
+ *DEBUG_OCLRINT = 3; /* clear both EOP and DESCR */
+
+ while(*DEBUG_STATUS & 0x7f); /* wait until output FIFO is empty as well */
+
+ restore_flags(flags);
+}
+
+/* legacy function */
+
+void
+console_print_etrax(const char *buf)
+{
+ console_write(NULL, buf, strlen(buf));
+}
+
+/* Use polling to get a single character FROM the debug port */
+
+int
+getDebugChar(void)
+{
+ unsigned long readval;
+
+ do {
+ readval = *DEBUG_READ;
+ } while(!(readval & IO_MASK(R_SERIAL0_READ, data_avail)));
+
+ return (readval & IO_MASK(R_SERIAL0_READ, data_in));
+}
+
+/* Use polling to put a single character to the debug port */
+
+void
+putDebugChar(int val)
+{
+ while(!(*DEBUG_READ & IO_MASK(R_SERIAL0_READ, tr_ready))) ;
+;
+ *DEBUG_WRITE = val;
+}
+
+/* Enable irq for receiving chars on the debug port, used by kgdb */
+
+void
+enableDebugIRQ(void)
+{
+ *R_IRQ_MASK1_SET = DEBUG_IRQ;
+ /* use R_VECT_MASK directly, since we really bypass Linux normal
+ * IRQ handling in kgdb anyway, we don't need to use enable_irq
+ */
+ *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
+
+ *DEBUG_REC_CTRL = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
+}
+
+static kdev_t
+console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static int __init
+console_setup(struct console *co, char *options)
+{
+ return 0;
+}
+
+static struct console sercons = {
+ "ttyS",
+ console_write,
+ NULL,
+ console_device,
+ NULL,
+ NULL,
+ console_setup,
+ CON_PRINTBUFFER,
+ DEBUG_PORT_IDX,
+ 0,
+ NULL
+};
+
+/*
+ * Register console (for printk's etc)
+ */
+
+void __init
+init_etrax_debug(void)
+{
+ register_console(&sercons);
+}
diff --git a/arch/cris/kernel/entry.S b/arch/cris/kernel/entry.S
new file mode 100644
index 000000000..1af62eb2c
--- /dev/null
+++ b/arch/cris/kernel/entry.S
@@ -0,0 +1,738 @@
+/* $Id: entry.S,v 1.11 2001/01/10 21:13:29 bjornw Exp $
+ *
+ * linux/arch/cris/entry.S
+ *
+ * Copyright (C) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ * $Log: entry.S,v $
+ * Revision 1.11 2001/01/10 21:13:29 bjornw
+ * SYMBOL_NAME is defined incorrectly for the compiler options we currently use
+ *
+ * Revision 1.10 2000/12/18 23:47:56 bjornw
+ * * Added syscall trace support (ptrace), completely untested of course
+ * * Removed redundant check for NULL entries in syscall_table
+ *
+ * Revision 1.9 2000/11/21 16:40:51 bjornw
+ * * New frame type used when an SBFS frame needs to be popped without
+ * actually restarting the instruction
+ * * Enable interrupts in signal_return (they did so in x86, I hope it's a good
+ * idea)
+ *
+ * Revision 1.8 2000/11/17 16:53:35 bjornw
+ * Added detection of frame-type in Rexit, so that mmu_bus_fault can
+ * use ret_from_intr in the return-path to check for signals (like SEGV)
+ * and other foul things that might have occured during the fault.
+ *
+ * Revision 1.7 2000/10/06 15:04:28 bjornw
+ * Include mof in register savings
+ *
+ * Revision 1.6 2000/09/12 16:02:44 bjornw
+ * Linux-2.4.0-test7 derived updates
+ *
+ * Revision 1.5 2000/08/17 15:35:15 bjornw
+ * 2.4.0-test6 changed local_irq_count and friends API
+ *
+ * Revision 1.4 2000/08/02 13:59:30 bjornw
+ * Removed olduname and uname from the syscall list
+ *
+ * Revision 1.3 2000/07/31 13:32:58 bjornw
+ * * Export ret_from_intr
+ * * _resume updated (prev/last tjohejsan)
+ * * timer_interrupt obsolete
+ * * SIGSEGV detection in mmu_bus_fault temporarily disabled
+ *
+ *
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * Stack layout in 'ret_from_system_call':
+ * ptrace needs to have all regs on the stack.
+ * if the order here is changed, it needs to be
+ * updated in fork.c:copy_process, signal.c:do_signal,
+ * ptrace.c and ptrace.h
+ *
+ */
+
+#include <linux/linkage.h>
+#include <linux/sys.h>
+
+ ;; functions exported from this file
+
+ .globl _system_call
+ .globl _ret_from_intr
+ .globl _ret_from_sys_call
+ .globl _resume
+ .globl _multiple_interrupt
+ .globl _hwbreakpoint
+ .globl _IRQ1_interrupt
+ .globl _timer_interrupt
+ .globl _timer_shortcut
+ .globl _spurious_interrupt
+ .globl _hw_bp_trigs
+ .globl _mmu_bus_fault
+
+ .globl _sys_call_table
+
+ ;; syscall error codes
+
+LENOSYS = 38
+
+ ;; offsets into the task_struct (found at sp aligned to THREAD_SIZE, 8192)
+ ;; linux/sched.h
+
+LTASK_SIGPENDING = 8
+LTASK_NEEDRESCHED = 20
+LTASK_PTRACE = 24
+
+ ;; some pt_regs offsets (from ptrace.h)
+
+LORIG_R10 = 4
+LR13 = 8
+LR12 = 12
+LR11 = 16
+LR10 = 20
+LR1 = 56
+LR0 = 60
+LDCCR = 68
+LSRP = 72
+LIRP = 76
+
+ ;; below are various parts of system_call which are not in the fast-path
+
+ ;; handle software irqs
+
+handle_softirq:
+ push r9
+ jsr _do_softirq ; call the C routine for softirq handling
+ pop r9
+
+ ;; fall-through
+
+_ret_from_intr:
+ ;; check for resched only if we're going back to user-mode
+
+ move ccr, r0
+ btstq 8, r0 ; U-flag
+ bpl Rexit ; go back directly
+ nop
+ ba ret_with_reschedule ; go back but check schedule and signals first
+ nop
+
+reschedule:
+ ;; keep r9 intact
+ push r9
+ jsr _schedule
+ pop r9
+ ba _ret_from_sys_call
+ nop
+
+ ;; return but call do_signal first
+signal_return:
+ ei ; we can get here from an interrupt
+ move.d r9,r10 ; do_signals syscall/irq param
+ moveq 0,r11 ; oldset param - 0 in this case
+ move.d sp,r12 ; another argument to do_signal (the regs param)
+ jsr _do_signal ; arch/cris/kernel/signal.c
+ ba Rexit
+ nop
+
+ ;; The system_call is called by a BREAK instruction, which works like
+ ;; an interrupt call but it stores the return PC in BRP instead of IRP.
+ ;; Since we dont really want to have two epilogues (one for system calls
+ ;; and one for interrupts) we push the contents of BRP instead of IRP in the
+ ;; system call prologue, to make it look like an ordinary interrupt on the
+ ;; stackframe.
+ ;;
+ ;; Since we can't have system calls inside interrupts, it should not matter
+ ;; that we don't stack IRP.
+ ;;
+ ;; In r1 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,r0
+ ;;
+ ;; This function looks on the _surface_ like spaghetti programming, but it's
+ ;; really designed so that the fast-path does not force cache-loading of non-used
+ ;; instructions. Only the non-common cases cause the outlined code to run..
+
+_system_call:
+ ;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call
+ push brp ; this is normally push irp
+ push srp
+ push dccr
+ push mof
+ subq 14*4,sp ; make room for r0-r13
+ movem r13,[sp] ; push r0-r13
+ push r10 ; push orig_r10
+ clear.d [sp=sp-4] ; frametype == 0, normal stackframe
+
+ move.d r10,r2 ; save for later
+
+ movs.w -LENOSYS,r10
+ move.d r10,[sp+LR10] ; put the default return value in r10 in the frame
+
+ move.d sp,r10
+ jsr _set_esp0 ; save top of frame (clobbers r9...)
+
+ ;; check if this process is syscall-traced
+
+ move.d sp, r10
+ and.d -8192, r10 ; THREAD_SIZE == 8192
+ move.d [r10+LTASK_PTRACE],r10
+ btstq 2, r10 ; PT_TRACESYS
+ bmi tracesys
+ nop
+
+ ;; check for sanity in the requested syscall number
+
+ cmpu.w NR_syscalls,r1
+ bcc _ret_from_sys_call
+ lslq 2,r1 ; multiply by 4, in the delay slot
+
+ ;; read the system call vector into r1
+
+ move.d [r1+_sys_call_table],r1
+
+ ;; the parameter carrying registers r11, r12 and 13 are intact - restore r10.
+ ;; the fifth parameter (if any) was in r0, and we need to put it on the stack
+
+ push r0
+ move.d r2,r10
+
+ jsr r1 ; actually call the corresponding system call
+ addq 4,sp ; pop the r0 parameter
+ move.d r10,[sp+LR10] ; save the return value
+
+ moveq 1,r9 ; "parameter" to ret_from_sys_call to show it was a sys call
+
+ ;; fall through into ret_from_sys_call to return
+
+_ret_from_sys_call:
+ ;; r9 is a parameter - if 1, we came from a syscall, if 0, from an irq
+
+ ;; check if any bottom halves need service
+
+ move.d [_irq_stat],r0 ; softirq_active
+ and.d [_irq_stat+4],r0 ; softirq_mask
+ bne handle_softirq
+ nop
+
+ret_with_reschedule:
+ ;; first get the current task-struct pointer (see top for defs)
+
+ move.d sp, r0
+ and.d -8192, r0 ; THREAD_SIZE == 8192
+
+ ;; see if we want to reschedule into another process
+
+ test.d [r0+LTASK_NEEDRESCHED]
+ bne reschedule
+ nop
+
+ ;; see if we need to run signal checks (important that r9 is intact here)
+
+ test.d [r0+LTASK_SIGPENDING]
+ bne signal_return
+ nop
+
+Rexit:
+ ;; this epilogue MUST match the prologues in multiple_interrupt, irq.h and ptregs.h
+ pop r10 ; frametype
+ bne RBFexit ; was not CRIS_FRAME_NORMAL, handle otherwise
+ addq 4,sp ; skip orig_r10, in delayslot
+ movem [sp+],r13 ; registers r0-r13
+ pop mof ; multiply overflow register
+ pop dccr ; condition codes
+ pop srp ; subroutine return pointer
+ jmpu [sp+] ; return by popping irp and jumping there
+ ;; jmpu takes the U-flag into account to see if we return to
+ ;; user-mode or kernel mode.
+
+RBFexit:
+ cmpq 2, r10 ; was it CRIS_FRAME_FIXUP ?
+ beq 2f
+ movem [sp+],r13 ; registers r0-r13, in delay slot
+ pop mof ; multiply overflow register
+ pop dccr ; condition codes
+ pop srp ; subroutine return pointer
+ rbf [sp+] ; return by popping the CPU status
+
+2: pop mof ; multiply overflow register
+ pop dccr ; condition codes
+ pop srp ; subroutine return pointer
+ ;; now we have a 4-word SBFS frame which we do not want to restore
+ ;; using RBF since we have made a fixup. instead we would like to
+ ;; just get the PC value to restart it with, and skip the rest of
+ ;; the frame.
+ pop irp ; fixup location will be here
+ pop p8 ; null pop
+ pop p8 ; null pop
+ reti ; return to IRP, taking U-flag into account
+ pop p8 ; null pop in delayslot
+
+
+tracesys:
+ ;; this first invocation of syscall_trace _requires_ that
+ ;; LR10 in the frame contains -LENOSYS (as is set in the beginning
+ ;; of system_call
+
+ jsr _syscall_trace
+
+ ;; now we should more or less do the same things as in the system_call
+ ;; but since our argument regs got clobbered during syscall_trace and
+ ;; because syscall_trace might want to alter them, we need to reload them
+ ;; from the stack-frame as we use them.
+
+ ;; check for sanity in the requested syscall number
+
+ move.d [sp+LR1], r1
+ movs.w -LENOSYS, r10
+ cmpu.w NR_syscalls,r1
+ bcc 1f
+ lslq 2,r1 ; multiply by 4, in the delay slot
+
+ ;; read the system call vector entry into r1
+
+ move.d [r1+_sys_call_table],r1
+
+ ;; restore r10, r11, r12, r13 and r0 into the needed registers
+
+ move.d [sp+LORIG_R10], r10 ; LR10 is already filled with -LENOSYS
+ move.d [sp+LR11], r11
+ move.d [sp+LR12], r12
+ move.d [sp+LR13], r13
+ move.d [sp+LR0], r0
+
+ ;; the fifth parameter needs to be put on the stack for the system
+ ;; call to find it
+
+ push r0
+ jsr r1 ; actually call the system-call
+ addq 4,sp ; pop the r0 parameter
+
+1: move.d r10,[sp+LR10] ; save the return value
+
+ ;; second call of syscall_trace, to let it grab the results
+
+ jsr _syscall_trace
+
+ moveq 1,r9 ; "parameter" to ret_from_sys_call to show it was a sys call
+ ba _ret_from_sys_call
+ nop
+
+ ;; from asm/processor.h, the thread_struct
+
+LTHREAD_KSP = 0
+LTHREAD_USP = 4
+LTHREAD_ESP0 = 8
+LTHREAD_DCCR = 12
+
+ ;; _resume performs the actual task-switching, by switching stack pointers
+ ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct
+ ;; returns old current in r10
+ ;;
+ ;; TODO: see the i386 version. The switch_to which calls resume in our version
+ ;; could really be an inline asm of this.
+
+_resume:
+ push srp ; we keep the old/new PC on the stack
+ add.d r12, r10 ; r10 = current tasks tss
+ move dccr, [r10+LTHREAD_DCCR] ; save irq enable state
+ di
+
+ move usp, [r10+LTHREAD_USP] ; save user-mode stackpointer
+
+ subq 10*4, sp
+ movem r9, [sp] ; save non-scratch registers
+
+ move.d sp, [r10+LTHREAD_KSP] ; save the kernel stack pointer for the old task
+ move.d sp, r10 ; return last running task in r10
+ and.d -8192, r10 ; get task ptr from stackpointer
+ add.d r12, r11 ; find the new tasks tss
+ move.d [r11+LTHREAD_KSP], sp ; switch into the new stackframe by restoring kernel sp
+
+ movem [sp+], r9 ; restore non-scratch registers
+
+ move [r11+LTHREAD_USP], usp ; restore user-mode stackpointer
+
+ move [r11+LTHREAD_DCCR], dccr ; restore irq enable status
+ jump [sp+] ; restore PC
+
+ ;; This is the MMU bus fault handler.
+ ;; It needs to stack the CPU status and overall is different
+ ;; from the other interrupt handlers.
+
+_mmu_bus_fault:
+ sbfs [sp=sp-16] ; push the internal CPU status
+ ;; the first longword in the sbfs frame was the interrupted PC
+ ;; which fits nicely with the "IRP" slot in pt_regs normally used to
+ ;; contain the return address. used by Oops to print kernel errors..
+ push srp ; make a stackframe similar to pt_regs
+ push dccr
+ push mof
+ di
+ subq 14*4, sp
+ movem r13, [sp]
+ push r10 ; dummy orig_r10
+ moveq 1, r10
+ push r10 ; frametype == 1, BUSFAULT frame type
+
+ moveq 0, r9 ; busfault is equivalent to an irq
+
+ move.d sp, r10 ; pt_regs argument to handle_mmu_bus_fault
+
+ jsr _handle_mmu_bus_fault ; in arch/cris/mm/fault.c
+
+ ;; now we need to return through the normal path, we cannot just
+ ;; do the RBFexit since we might have killed off the running
+ ;; process due to a SEGV, scheduled due to a page blocking or
+ ;; whatever.
+
+ ba _ret_from_intr
+ nop
+
+ ;; special handlers for breakpoint and NMI
+#if 0
+_hwbreakpoint:
+ push dccr
+ di
+ push r10
+ push r11
+ push r12
+ push r13
+ clearf b
+ move brp,r11
+ move.d [_hw_bp_msg],r10
+ jsr _printk
+ setf b
+ pop r13
+ pop r12
+ pop r11
+ pop r10
+ pop dccr
+ retb
+ nop
+#else
+_hwbreakpoint:
+ push dccr
+ di
+#if 1
+ push r10
+ push r11
+ move.d [_hw_bp_trig_ptr],r10
+ move.d [r10],r11
+ cmp.d 42,r11
+ beq nobp
+ nop
+ move brp,r11
+ move.d r11,[r10+]
+ move.d r10,[_hw_bp_trig_ptr]
+nobp: pop r11
+ pop r10
+#endif
+ pop dccr
+ retb
+ nop
+#endif
+
+_IRQ1_interrupt:
+_spurious_interrupt:
+ di
+ move.b 4,r0
+ move.b r0,[0xb0000030]
+basse2: ba basse2
+ nop
+
+ ;; this handles the case when multiple interrupts arrive at the same time
+ ;; we jump to the first set interrupt bit in a priority fashion
+ ;; the hardware will call the unserved interrupts after the handler finishes
+
+_multiple_interrupt:
+ ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
+ push irp
+ push srp
+ push dccr
+ push mof
+ di
+ subq 14*4,sp
+ movem r13,[sp]
+ push r10 ; push orig_r10
+ clear.d [sp=sp-4] ; frametype == 0, normal frame
+
+ move.d _irq_shortcuts + 8,r1
+ moveq 2,r2 ; first bit we care about is the timer0 irq
+ move.d [0xb00000d8],r0 ; read the irq bits that triggered the multiple irq
+multloop:
+ btst r2,r0 ; check for the irq given by bit r2
+ bmi do_shortcut ; actually do the shortcut
+ nop
+ addq 1,r2 ; next vector bit - remember this is in the delay slot!
+ addq 4,r1 ; next vector
+ cmpq 26,r2
+ bne multloop ; process all irq's up to and including number 25
+ nop
+
+ ;; strange, we didn't get any set vector bits.. oh well, just return
+
+ ba Rexit
+ nop
+
+do_shortcut:
+ test.d [r1]
+ beq Rexit
+ nop
+ jump [r1] ; jump to the irq handlers shortcut
+
+
+ .data
+
+_hw_bp_trigs:
+ .space 64*4
+_hw_bp_trig_ptr:
+ .dword _hw_bp_trigs
+
+/* linux/linkage.h got it wrong for this compiler currently */
+
+#undef SYMBOL_NAME
+#define SYMBOL_NAME(X) _/**/X
+
+_sys_call_table:
+ .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/
+ .long SYMBOL_NAME(sys_exit)
+ .long SYMBOL_NAME(sys_fork)
+ .long SYMBOL_NAME(sys_read)
+ .long SYMBOL_NAME(sys_write)
+ .long SYMBOL_NAME(sys_open) /* 5 */
+ .long SYMBOL_NAME(sys_close)
+ .long SYMBOL_NAME(sys_waitpid)
+ .long SYMBOL_NAME(sys_creat)
+ .long SYMBOL_NAME(sys_link)
+ .long SYMBOL_NAME(sys_unlink) /* 10 */
+ .long SYMBOL_NAME(sys_execve)
+ .long SYMBOL_NAME(sys_chdir)
+ .long SYMBOL_NAME(sys_time)
+ .long SYMBOL_NAME(sys_mknod)
+ .long SYMBOL_NAME(sys_chmod) /* 15 */
+ .long SYMBOL_NAME(sys_lchown16)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */
+ .long SYMBOL_NAME(sys_stat)
+ .long SYMBOL_NAME(sys_lseek)
+ .long SYMBOL_NAME(sys_getpid) /* 20 */
+ .long SYMBOL_NAME(sys_mount)
+ .long SYMBOL_NAME(sys_oldumount)
+ .long SYMBOL_NAME(sys_setuid16)
+ .long SYMBOL_NAME(sys_getuid16)
+ .long SYMBOL_NAME(sys_stime) /* 25 */
+ .long SYMBOL_NAME(sys_ptrace)
+ .long SYMBOL_NAME(sys_alarm)
+ .long SYMBOL_NAME(sys_fstat)
+ .long SYMBOL_NAME(sys_pause)
+ .long SYMBOL_NAME(sys_utime) /* 30 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */
+ .long SYMBOL_NAME(sys_access)
+ .long SYMBOL_NAME(sys_nice)
+ .long SYMBOL_NAME(sys_ni_syscall) /* 35 old ftime syscall holder */
+ .long SYMBOL_NAME(sys_sync)
+ .long SYMBOL_NAME(sys_kill)
+ .long SYMBOL_NAME(sys_rename)
+ .long SYMBOL_NAME(sys_mkdir)
+ .long SYMBOL_NAME(sys_rmdir) /* 40 */
+ .long SYMBOL_NAME(sys_dup)
+ .long SYMBOL_NAME(sys_pipe)
+ .long SYMBOL_NAME(sys_times)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */
+ .long SYMBOL_NAME(sys_brk) /* 45 */
+ .long SYMBOL_NAME(sys_setgid16)
+ .long SYMBOL_NAME(sys_getgid16)
+ .long SYMBOL_NAME(sys_signal)
+ .long SYMBOL_NAME(sys_geteuid16)
+ .long SYMBOL_NAME(sys_getegid16) /* 50 */
+ .long SYMBOL_NAME(sys_acct)
+ .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */
+ .long SYMBOL_NAME(sys_ioctl)
+ .long SYMBOL_NAME(sys_fcntl) /* 55 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */
+ .long SYMBOL_NAME(sys_setpgid)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old sys_olduname holder */
+ .long SYMBOL_NAME(sys_umask) /* 60 */
+ .long SYMBOL_NAME(sys_chroot)
+ .long SYMBOL_NAME(sys_ustat)
+ .long SYMBOL_NAME(sys_dup2)
+ .long SYMBOL_NAME(sys_getppid)
+ .long SYMBOL_NAME(sys_getpgrp) /* 65 */
+ .long SYMBOL_NAME(sys_setsid)
+ .long SYMBOL_NAME(sys_sigaction)
+ .long SYMBOL_NAME(sys_sgetmask)
+ .long SYMBOL_NAME(sys_ssetmask)
+ .long SYMBOL_NAME(sys_setreuid16) /* 70 */
+ .long SYMBOL_NAME(sys_setregid16)
+ .long SYMBOL_NAME(sys_sigsuspend)
+ .long SYMBOL_NAME(sys_sigpending)
+ .long SYMBOL_NAME(sys_sethostname)
+ .long SYMBOL_NAME(sys_setrlimit) /* 75 */
+ .long SYMBOL_NAME(sys_old_getrlimit)
+ .long SYMBOL_NAME(sys_getrusage)
+ .long SYMBOL_NAME(sys_gettimeofday)
+ .long SYMBOL_NAME(sys_settimeofday)
+ .long SYMBOL_NAME(sys_getgroups16) /* 80 */
+ .long SYMBOL_NAME(sys_setgroups16)
+ .long SYMBOL_NAME(sys_select) /* was old_select in Linux/E100 */
+ .long SYMBOL_NAME(sys_symlink)
+ .long SYMBOL_NAME(sys_lstat)
+ .long SYMBOL_NAME(sys_readlink) /* 85 */
+ .long SYMBOL_NAME(sys_uselib)
+ .long SYMBOL_NAME(sys_swapon)
+ .long SYMBOL_NAME(sys_reboot)
+ .long SYMBOL_NAME(old_readdir)
+ .long SYMBOL_NAME(old_mmap) /* 90 */
+ .long SYMBOL_NAME(sys_munmap)
+ .long SYMBOL_NAME(sys_truncate)
+ .long SYMBOL_NAME(sys_ftruncate)
+ .long SYMBOL_NAME(sys_fchmod)
+ .long SYMBOL_NAME(sys_fchown16) /* 95 */
+ .long SYMBOL_NAME(sys_getpriority)
+ .long SYMBOL_NAME(sys_setpriority)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */
+ .long SYMBOL_NAME(sys_statfs)
+ .long SYMBOL_NAME(sys_fstatfs) /* 100 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_ioperm in i386 */
+ .long SYMBOL_NAME(sys_socketcall)
+ .long SYMBOL_NAME(sys_syslog)
+ .long SYMBOL_NAME(sys_setitimer)
+ .long SYMBOL_NAME(sys_getitimer) /* 105 */
+ .long SYMBOL_NAME(sys_newstat)
+ .long SYMBOL_NAME(sys_newlstat)
+ .long SYMBOL_NAME(sys_newfstat)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old sys_uname holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_iopl in i386 */
+ .long SYMBOL_NAME(sys_vhangup)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old "idle" system call */
+ .long SYMBOL_NAME(sys_ni_syscall) /* vm86old in i386 */
+ .long SYMBOL_NAME(sys_wait4)
+ .long SYMBOL_NAME(sys_swapoff) /* 115 */
+ .long SYMBOL_NAME(sys_sysinfo)
+ .long SYMBOL_NAME(sys_ipc)
+ .long SYMBOL_NAME(sys_fsync)
+ .long SYMBOL_NAME(sys_sigreturn)
+ .long SYMBOL_NAME(sys_clone) /* 120 */
+ .long SYMBOL_NAME(sys_setdomainname)
+ .long SYMBOL_NAME(sys_newuname)
+ .long SYMBOL_NAME(sys_ni_syscall) /* TODO sys_modify_ldt - do something ?*/
+ .long SYMBOL_NAME(sys_adjtimex)
+ .long SYMBOL_NAME(sys_mprotect) /* 125 */
+ .long SYMBOL_NAME(sys_sigprocmask)
+ .long SYMBOL_NAME(sys_create_module)
+ .long SYMBOL_NAME(sys_init_module)
+ .long SYMBOL_NAME(sys_delete_module)
+ .long SYMBOL_NAME(sys_get_kernel_syms) /* 130 */
+ .long SYMBOL_NAME(sys_quotactl)
+ .long SYMBOL_NAME(sys_getpgid)
+ .long SYMBOL_NAME(sys_fchdir)
+ .long SYMBOL_NAME(sys_bdflush)
+ .long SYMBOL_NAME(sys_sysfs) /* 135 */
+ .long SYMBOL_NAME(sys_personality)
+ .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */
+ .long SYMBOL_NAME(sys_setfsuid16)
+ .long SYMBOL_NAME(sys_setfsgid16)
+ .long SYMBOL_NAME(sys_llseek) /* 140 */
+ .long SYMBOL_NAME(sys_getdents)
+ .long SYMBOL_NAME(sys_select)
+ .long SYMBOL_NAME(sys_flock)
+ .long SYMBOL_NAME(sys_msync)
+ .long SYMBOL_NAME(sys_readv) /* 145 */
+ .long SYMBOL_NAME(sys_writev)
+ .long SYMBOL_NAME(sys_getsid)
+ .long SYMBOL_NAME(sys_fdatasync)
+ .long SYMBOL_NAME(sys_sysctl)
+ .long SYMBOL_NAME(sys_mlock) /* 150 */
+ .long SYMBOL_NAME(sys_munlock)
+ .long SYMBOL_NAME(sys_mlockall)
+ .long SYMBOL_NAME(sys_munlockall)
+ .long SYMBOL_NAME(sys_sched_setparam)
+ .long SYMBOL_NAME(sys_sched_getparam) /* 155 */
+ .long SYMBOL_NAME(sys_sched_setscheduler)
+ .long SYMBOL_NAME(sys_sched_getscheduler)
+ .long SYMBOL_NAME(sys_sched_yield)
+ .long SYMBOL_NAME(sys_sched_get_priority_max)
+ .long SYMBOL_NAME(sys_sched_get_priority_min) /* 160 */
+ .long SYMBOL_NAME(sys_sched_rr_get_interval)
+ .long SYMBOL_NAME(sys_nanosleep)
+ .long SYMBOL_NAME(sys_mremap)
+ .long SYMBOL_NAME(sys_setresuid16)
+ .long SYMBOL_NAME(sys_getresuid16) /* 165 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_vm86 */
+ .long SYMBOL_NAME(sys_query_module)
+ .long SYMBOL_NAME(sys_poll)
+ .long SYMBOL_NAME(sys_nfsservctl)
+ .long SYMBOL_NAME(sys_setresgid16) /* 170 */
+ .long SYMBOL_NAME(sys_getresgid16)
+ .long SYMBOL_NAME(sys_prctl)
+ .long SYMBOL_NAME(sys_rt_sigreturn)
+ .long SYMBOL_NAME(sys_rt_sigaction)
+ .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */
+ .long SYMBOL_NAME(sys_rt_sigpending)
+ .long SYMBOL_NAME(sys_rt_sigtimedwait)
+ .long SYMBOL_NAME(sys_rt_sigqueueinfo)
+ .long SYMBOL_NAME(sys_rt_sigsuspend)
+ .long SYMBOL_NAME(sys_pread) /* 180 */
+ .long SYMBOL_NAME(sys_pwrite)
+ .long SYMBOL_NAME(sys_chown16)
+ .long SYMBOL_NAME(sys_getcwd)
+ .long SYMBOL_NAME(sys_capget)
+ .long SYMBOL_NAME(sys_capset) /* 185 */
+ .long SYMBOL_NAME(sys_sigaltstack)
+ .long SYMBOL_NAME(sys_sendfile)
+ .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
+ .long SYMBOL_NAME(sys_vfork) /* 190 */
+ .long SYMBOL_NAME(sys_getrlimit)
+ .long SYMBOL_NAME(sys_mmap2)
+ .long SYMBOL_NAME(sys_truncate64)
+ .long SYMBOL_NAME(sys_ftruncate64)
+ .long SYMBOL_NAME(sys_stat64) /* 195 */
+ .long SYMBOL_NAME(sys_lstat64)
+ .long SYMBOL_NAME(sys_fstat64)
+ .long SYMBOL_NAME(sys_lchown)
+ .long SYMBOL_NAME(sys_getuid)
+ .long SYMBOL_NAME(sys_getgid) /* 200 */
+ .long SYMBOL_NAME(sys_geteuid)
+ .long SYMBOL_NAME(sys_getegid)
+ .long SYMBOL_NAME(sys_setreuid)
+ .long SYMBOL_NAME(sys_setregid)
+ .long SYMBOL_NAME(sys_getgroups) /* 205 */
+ .long SYMBOL_NAME(sys_setgroups)
+ .long SYMBOL_NAME(sys_fchown)
+ .long SYMBOL_NAME(sys_setresuid)
+ .long SYMBOL_NAME(sys_getresuid)
+ .long SYMBOL_NAME(sys_setresgid) /* 210 */
+ .long SYMBOL_NAME(sys_getresgid)
+ .long SYMBOL_NAME(sys_chown)
+ .long SYMBOL_NAME(sys_setuid)
+ .long SYMBOL_NAME(sys_setgid)
+ .long SYMBOL_NAME(sys_setfsuid) /* 215 */
+ .long SYMBOL_NAME(sys_setfsgid)
+ .long SYMBOL_NAME(sys_pivot_root)
+ .long SYMBOL_NAME(sys_mincore)
+ .long SYMBOL_NAME(sys_madvise)
+ .long SYMBOL_NAME(sys_getdents64) /* 220 */
+
+ /*
+ * NOTE!! This doesn't have to be exact - we just have
+ * to make sure we have _enough_ of the "sys_ni_syscall"
+ * entries. Don't panic if you notice that this hasn't
+ * been shrunk every time we add a new system call.
+ */
+
+ ;; TODO: this needs to actually generate sys_ni_syscall entires
+ ;; since we now have removed the check for NULL entries in this
+ ;; table in system_call!
+
+ .space (NR_syscalls-220)*4
+
diff --git a/arch/cris/kernel/head.S b/arch/cris/kernel/head.S
new file mode 100644
index 000000000..b436aa843
--- /dev/null
+++ b/arch/cris/kernel/head.S
@@ -0,0 +1,519 @@
+ ;; $Id: head.S,v 1.11 2001/01/16 16:31:38 bjornw Exp $
+ ;;
+ ;; Head of the kernel - alter with care
+ ;;
+ ;; Copyright (C) 2000, 2001 Axis Communications AB
+ ;;
+ ;; Authors: Bjorn Wesen (bjornw@axis.com)
+ ;;
+ ;; $Log: head.S,v $
+ ;; Revision 1.11 2001/01/16 16:31:38 bjornw
+ ;; * Changed name and semantics of running_from_flash to romfs_in_flash,
+ ;; set by head.S to indicate to setup.c whether there is a cramfs image
+ ;; after the kernels BSS or not. Should work for all three boot-cases
+ ;; (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot),
+ ;; and flash with cramfs in flash)
+ ;;
+ ;; Revision 1.10 2001/01/16 14:12:21 bjornw
+ ;; * Check for cramfs start passed in r9 from the decompressor, if all other
+ ;; cramfs options fail (if we boot from DRAM but don't find a cramfs image
+ ;; after the kernel in DRAM, it is probably still in the flash)
+ ;; * Check magic in cramfs detection when booting from flash directly
+ ;;
+ ;; Revision 1.9 2001/01/15 17:17:02 bjornw
+ ;; * Corrected the code that detects the cramfs lengths
+ ;; * Added a comment saying that the above does not work due to other
+ ;; reasons..
+ ;;
+ ;; Revision 1.8 2001/01/15 16:27:51 jonashg
+ ;; Made boot after flashing work.
+ ;; * end destination is __vmlinux_end in RAM.
+ ;; * _romfs_start moved because of virtual memory.
+ ;;
+ ;; Revision 1.7 2000/11/21 13:55:29 bjornw
+ ;; Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type
+ ;;
+ ;; Revision 1.6 2000/10/06 12:36:55 bjornw
+ ;; Forgot swapper_pg_dir when changing memory map..
+ ;;
+ ;; Revision 1.5 2000/10/04 16:49:30 bjornw
+ ;; * Fixed memory mapping in LX
+ ;; * Check for cramfs instead of romfs
+ ;;
+ ;;
+
+#include <linux/config.h>
+#define ASSEMBLER_MACROS_ONLY
+#include <asm/sv_addr_ag.h>
+
+#define CRAMFS_MAGIC 0x28cd3d45
+
+ ;; exported symbols
+
+ .globl _etrax_irv
+ .globl _romfs_start
+ .globl _romfs_length
+ .globl _romfs_in_flash
+ .globl _swapper_pg_dir
+
+ .text
+
+ ;; This is the entry point of the kernel. We are in supervisor mode.
+ ;; 0x00000000 if Flash, 0x40004000 if DRAM
+ ;; since etrax actually starts at address 2 when booting from flash, we
+ ;; put a nop (2 bytes) here first so we dont accidentally skip the di
+ ;;
+ ;; NOTICE! The register r9 is used as a parameter carrying register from
+ ;; the decompressor (if the kernel was compressed). It should not be
+ ;; used in the code below until it is read.
+
+ nop
+ di
+
+ ;; First setup the kseg_c mapping from where the kernel is linked
+ ;; to 0x40000000 (where the actual DRAM resides) otherwise
+ ;; we cannot do very much! See arch/cris/README.mm
+ ;;
+ ;; Notice that since we're potentially running at 0x00 or 0x40 right now,
+ ;; we will get a fault as soon as we enable the MMU if we dont
+ ;; temporarily map those segments linearily.
+ ;;
+ ;; Due to a bug in Etrax-100 LX version 1 we need to map the memory
+ ;; slightly different. We also let the simulator get this mapping for now.
+
+#ifdef CONFIG_CRIS_LOW_MAP
+ move.d 0x0800b000, r0 ; kseg mappings
+ move.d r0, [R_MMU_KBASE_HI]
+
+ move.d 0x04040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00
+ move.d r0, [R_MMU_KBASE_LO]
+
+ move.d 0x80074871, r0 ; mmu enable, segs e,b,6,5,4,0 segment mapped
+ move.d r0, [R_MMU_CONFIG]
+#else
+ move.d 0x0804b000, r0 ; kseg mappings
+ move.d r0, [R_MMU_KBASE_HI]
+
+ move.d 0x00040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00
+ move.d r0, [R_MMU_KBASE_LO]
+
+ move.d 0x8007d811, r0 ; mmu enable, segs f,e,c,b,4,0 segment mapped
+ move.d r0, [R_MMU_CONFIG]
+#endif
+
+ ;; Now we need to sort out the segments and their locations in RAM or
+ ;; Flash. The image in the Flash (or in DRAM) consists of 3 pieces:
+ ;; 1) kernel text, 2) kernel data, 3) ROM filesystem image
+ ;; But the linker has linked the kernel to expect this layout in
+ ;; DRAM memory:
+ ;; 1) kernel text, 2) kernel data, 3) kernel BSS
+ ;; (the location of the ROM filesystem is determined by the krom driver)
+ ;; If we boot this from Flash, we want to keep the ROM filesystem in
+ ;; the flash, we want to copy the text and need to copy the data to DRAM.
+ ;; But if we boot from DRAM, we need to move the ROMFS image
+ ;; from its position after kernel data, to after kernel BSS, BEFORE the
+ ;; kernel starts using the BSS area (since its "overlayed" with the ROMFS)
+ ;;
+ ;; In both cases, we start in un-cached mode, and need to jump into a
+ ;; cached PC after we're done fiddling around with the segments.
+ ;;
+ ;; arch/etrax100/etrax100.ld sets some symbols that define the start
+ ;; and end of each segment.
+
+ ;; Check if we start from DRAM or FLASH by testing PC
+
+ move.d pc,r0
+ and.d 0x7fffffff,r0 ; get rid of the non-cache bit
+ cmp.d 0x10000,r0 ; arbitrary... just something above this code
+ bcs inflash
+ nop
+
+ jump inram ; enter cached ram
+
+inflash:
+
+#ifndef CONFIG_SVINTO_SIM
+
+ ;; We need to setup the bus registers before we start using the DRAM
+
+ move.d DEF_R_WAITSTATES, r0
+ move.d r0, [R_WAITSTATES]
+
+ move.d DEF_R_BUS_CONFIG, r0
+ move.d r0, [R_BUS_CONFIG]
+
+ move.d DEF_R_DRAM_CONFIG, r0
+ move.d r0, [R_DRAM_CONFIG]
+
+ move.d DEF_R_DRAM_TIMING, r0
+ move.d r0, [R_DRAM_TIMING]
+
+#endif
+ ;; Copy text+data to DRAM
+ ;; This is fragile - the calculation of r4 as the image size depends
+ ;; on that the labels below actually are the first and last positions
+ ;; in the linker-script.
+ ;;
+ ;; Then the locating of the cramfs image depends on the aforementioned
+ ;; image being located in the flash at 0. This is most often not true,
+ ;; thus the following does not work (normally there is a rescue-block
+ ;; between the physical start of the flash and the flash-image start,
+ ;; and when run with compression, the kernel is actually unpacked to
+ ;; DRAM and we never get here in the first place :))
+
+ moveq 0, r0 ; source
+ move.d _text_start, r1 ; destination
+ move.d __vmlinux_end, r2 ; end destination
+ move.d r2, r4
+ sub.d r1, r4 ; r4=__vmlinux_end in flash, used below
+1: move.w [r0+], r3
+ move.w r3, [r1+]
+ cmp.d r2, r1
+ bcs 1b
+ nop
+
+ ;; We keep the cramfs in the flash.
+ ;; There might be none, but that does not matter because
+ ;; we don't do anything than read some bytes here.
+
+ moveq 0, r0
+ move.d r0, [_romfs_length] ; default if there is no cramfs
+
+ move.d [r4], r0 ; cramfs_super.magic
+ cmp.d CRAMFS_MAGIC, r0
+ bne 1f
+ nop
+ move.d [r4 + 4], r0 ; cramfs_super.size
+ move.d r0, [_romfs_length]
+#ifdef CONFIG_CRIS_LOW_MAP
+ add.d 0x50000000, r4 ; add flash start in virtual memory (cached)
+#else
+ add.d 0xf0000000, r4 ; add flash start in virtual memory (cached)
+#endif
+ move.d r4, [_romfs_start]
+1:
+ moveq 1, r0
+ move.d r0, [_romfs_in_flash]
+
+ jump start_it ; enter code, cached this time
+
+inram:
+ ;; Move the ROM fs to after BSS end. This assumes that the cramfs
+ ;; second longword contains the length of the cramfs
+
+ moveq 0, r0
+ move.d r0, [_romfs_length] ; default if there is no cramfs
+
+ ;; First check if there is a cramfs (magic value)
+ ;; Notice that we check for cramfs magic value - which is
+ ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does
+ ;; not need this mechanism anyway)
+
+ move.d __vmlinux_end, r0 ; the image will be after the vmlinux end address
+ move.d [r0], r1 ; cramfs assumes same endian on host/target
+ cmp.d CRAMFS_MAGIC, r1; magic value in cramfs superblock
+ bne no_romfs_in_ram
+ nop
+
+ ;; Ok. What is its size ?
+
+ move.d [r0 + 4], r2 ; cramfs_super.size (again, no need to swapwb)
+
+ ;; We want to copy it to the end of the BSS
+
+ move.d _end, r1
+
+ ;; Remember values so cramfs and setup can find this info
+
+ move.d r1, [_romfs_start] ; new romfs location
+ move.d r2, [_romfs_length]
+
+ ;; We need to copy it backwards, since they can be overlapping
+
+ add.d r2, r0
+ add.d r2, r1
+
+ ;; Go ahead. Make my loop.
+
+ lsrq 1, r2 ; size is in bytes, we copy words
+
+1: move.w [r0=r0-2],r3
+ move.w r3,[r1=r1-2]
+ subq 1, r2
+ bne 1b
+ nop
+
+ ;; Dont worry that the BSS is tainted. It will be cleared later.
+
+ moveq 0, r0
+ move.d r0, [_romfs_in_flash]
+
+ jump start_it ; better skip the additional cramfs check below
+
+no_romfs_in_ram:
+
+ ;; We have still one other possibility at this point - the kernel
+ ;; could have been unpacked to DRAM by the loader, but the cramfs
+ ;; image was still in the Flash directly after the compressed kernel
+ ;; image. The loader passes the address of the byte succeeding the
+ ;; last compressed byte in the flash in the register r9 when starting
+ ;; the kernel. Check if r9 points to a decent cramfs image!
+ ;; (Notice that if this is not booted from the loader, r9 will be
+ ;; garbage but we do sanity checks on it, the chance that it points
+ ;; to a cramfs magic is small.. )
+
+ cmp.d 0x0ffffff8, r9
+ bcc 1f ; r9 points outside the flash area
+ nop
+ move.d [r9], r0 ; cramfs_super.magic
+ cmp.d CRAMFS_MAGIC, r0
+ bne 1f
+ nop
+ move.d [r9+4], r0 ; cramfs_super.length
+ move.d r0, [_romfs_length]
+#ifdef CONFIG_CRIS_LOW_MAP
+ add.d 0x50000000, r9 ; add flash start in virtual memory (cached)
+#else
+ add.d 0xf0000000, r9 ; add flash start in virtual memory (cached)
+#endif
+ move.d r9, [_romfs_start]
+
+ moveq 1, r0
+ move.d r0, [_romfs_in_flash]
+1:
+
+ jump start_it ; enter code, cached this time
+
+start_it:
+ ;; the kernel stack is overlayed with the task structure for each
+ ;; task. thus the initial kernel stack is in the same page as the
+ ;; init_task (but starts in the top of the page, size 8192)
+ move.d _init_task_union + 8192,sp
+ move.d _ibr_start,r0 ; this symbol is set by the linker script
+ move r0,ibr
+ move.d r0,[_etrax_irv] ; set the interrupt base register and pointer
+
+ ;; Clear BSS region, from _bss_start to _end
+
+ move.d __bss_start, r0
+ move.d _end, r1
+1: clear.d [r0+]
+ cmp.d r1, r0
+ bcs 1b
+ nop
+
+#ifdef CONFIG_BLK_DEV_ETRAXIDE
+ ;; disable ATA before enabling it in genconfig below
+ moveq 0,r0
+ move.d r0,[R_ATA_CTRL_DATA]
+ move.d r0,[R_ATA_TRANSFER_CNT]
+ move.d r0,[R_ATA_CONFIG]
+#if 0
+ move.d R_PORT_G_DATA,r1
+ move.d r0,[r1]; assert ATA bus-reset
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ move.d 0x08000000,r0
+ move.d r0,[r1]
+#endif
+#endif
+
+#ifdef CONFIG_JULIETTE
+ ;; configure external DMA channel 0 before enabling it in genconfig
+
+ moveq 0,r0
+ move.d r0,[R_EXT_DMA_0_ADDR]
+ move.d 0x860000,r0 ; cnt enable, word size, output, stop, size 0
+ move.d r0,[R_EXT_DMA_0_CMD]
+
+ ;; reset dma4 and wait for completion
+
+ moveq 4,r0
+ move.b r0,[R_DMA_CH4_CMD]
+w4u: move.b [R_DMA_CH4_CMD],r0
+ and.b 7,r0
+ cmp.b 4,r0
+ beq w4u
+ nop
+
+ ;; reset dma5 and wait for completion
+
+ moveq 4,r0
+ move.b r0,[R_DMA_CH5_CMD]
+w5u: move.b [R_DMA_CH5_CMD],r0
+ and.b 7,r0
+ cmp.b 4,r0
+ beq w5u
+ nop
+#endif
+
+ ;; Etrax product HW genconfig setup
+
+ moveq 0,r0
+#if !defined(CONFIG_KGDB) && !defined(CONFIG_DMA_MEMCPY)
+ or.d 0x140000,r0 ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
+#endif
+#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1)
+ or.d 0xc00000,r0 ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
+#endif
+#ifdef CONFIG_DMA_MEMCPY
+ or.d 0x003c0000,r0 ; 6/7 memory-memory DMA
+#endif
+#ifdef CONFIG_ETRAX100_SERIAL_PORT2
+ or.d 0x2808,r0 ; DMA channels 2 and 3 to serport 2, port 2 enabled
+#endif
+#ifdef CONFIG_ETRAX100_SERIAL_PORT3
+ or.d 0x28100,r0 ; DMA channels 4 and 5 to serport 3, port 3 enabled
+#endif
+#if defined(CONFIG_ETRAX100_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
+ or.w 0x4,r0 ; parport 0 enabled using DMA 2/3
+#endif
+#if defined(CONFIG_ETRAX100_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
+ or.w 0x80,r0 ; parport 1 enabled using DMA 4/5
+#endif
+#ifdef CONFIG_BLK_DEV_ETRAXIDE
+ or.d 0x3c02,r0 ; DMA channels 2 and 3 to ATA, ATA enabled
+#endif
+#ifdef CONFIG_JULIETTE
+ or.d 0x3c000,r0 ; DMA channels 4 and 5 to EXTDMA0, for Juliette
+#ifndef CONFIG_BLK_DEV_ETRAXIDE
+ or.d 0x41,r0 ; HACK for now! To make G27 connected for the RTC
+#endif
+#endif
+ move.d r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG
+
+#ifndef CONFIG_SVINTO_SIM
+ move.d r0,[R_GEN_CONFIG]
+
+#if 0
+ moveq 4,r0
+ move.b r0,[R_DMA_CH6_CMD] ; reset (ser0 dma out)
+ move.b r0,[R_DMA_CH7_CMD] ; reset (ser0 dma in)
+w61: move.b [R_DMA_CH6_CMD],r0 ; wait for reset cycle to finish
+ and.b 7,r0
+ cmp.b 4,r0
+ beq w61
+ nop
+w71: move.b [R_DMA_CH7_CMD],r0 ; wait for reset cycle to finish
+ and.b 7,r0
+ cmp.b 4,r0
+ beq w71
+ nop
+#endif
+
+ moveq 4,r0
+ move.b r0,[R_DMA_CH8_CMD] ; reset (ser1 dma out)
+ move.b r0,[R_DMA_CH9_CMD] ; reset (ser1 dma in)
+w81: move.b [R_DMA_CH8_CMD],r0 ; wait for reset cycle to finish
+ and.b 7,r0
+ cmp.b 4,r0
+ beq w81
+ nop
+w91: move.b [R_DMA_CH9_CMD],r0 ; wait for reset cycle to finish
+ and.b 7,r0
+ cmp.b 4,r0
+ beq w91
+ nop
+
+ ;; setup port PA and PB default initial directions and data
+ ;; including their shadow registers
+
+ move.b DEF_R_PORT_PA_DIR,r0
+ move.b r0,[_port_pa_dir_shadow]
+ move.b r0,[R_PORT_PA_DIR]
+ move.b DEF_R_PORT_PA_DATA,r0
+ move.b r0,[_port_pa_data_shadow]
+ move.b r0,[R_PORT_PA_DATA]
+
+ move.b DEF_R_PORT_PB_CONFIG,r0
+ move.b r0,[_port_pb_config_shadow]
+ move.b r0,[R_PORT_PB_CONFIG]
+ move.b DEF_R_PORT_PB_DIR,r0
+ move.b r0,[_port_pb_dir_shadow]
+ move.b r0,[R_PORT_PB_DIR]
+ move.b DEF_R_PORT_PB_DATA,r0
+ move.b r0,[_port_pb_data_shadow]
+ move.b r0,[R_PORT_PB_DATA]
+
+ moveq 0,r0
+ move.d r0,[_port_g_data_shadow]
+ move.d r0,[R_PORT_G_DATA]
+
+ ;; setup the serial port 0 at 115200 baud for debug purposes
+
+ moveq 0,r0
+ move.d r0,[R_SERIAL0_XOFF]
+
+ move.b 0x99,r0
+ move.b r0,[R_SERIAL0_BAUD] ; 115.2kbaud for both transmit and receive
+
+ move.b 0x40,r0 ; rec enable
+ move.b r0,[R_SERIAL0_REC_CTRL]
+
+ move.b 0x40,r0 ; tr enable
+ move.b r0,[R_SERIAL0_TR_CTRL]
+
+ ;; setup the serial port 1 at 115200 baud for debug purposes
+
+ moveq 0,r0
+ move.d r0,[R_SERIAL1_XOFF]
+
+ move.b 0x99,r0
+ move.b r0,[R_SERIAL1_BAUD] ; 115.2kbaud for both transmit and receive
+
+ move.b 0x40,r0 ; rec enable
+ move.b r0,[R_SERIAL1_REC_CTRL]
+
+ move.b 0x40,r0 ; tr enable
+ move.b r0,[R_SERIAL1_TR_CTRL]
+
+#ifdef CONFIG_ETRAX_90000000_LEDS
+ ;; clear LED's on Stallone and Olga boards
+ moveq -1,r0
+ move.d r0,[_port_90000000_shadow]
+ move.d r0,[0x90000000]
+#endif
+
+#ifdef CONFIG_ETRAX100_SERIAL_PORT3
+ ;; setup the serial port 3 at 115200 baud for debug purposes
+
+ moveq 0,r0
+ move.d r0,[R_SERIAL3_XOFF]
+
+ move.b 0x99,r0
+ move.b r0,[R_SERIAL3_BAUD] ; 115.2kbaud for both transmit and receive
+
+ move.b 0x40,r0 ; rec enable
+ move.b r0,[R_SERIAL3_REC_CTRL]
+
+ move.b 0x40,r0 ; tr enable
+ move.b r0,[R_SERIAL3_TR_CTRL]
+#endif
+
+#endif /* CONFIG_SVINTO_SIM */
+
+ jump _start_kernel ; jump into the C-function _start_kernel in init/main.c
+
+
+ .data
+_etrax_irv:
+ .dword 0
+_romfs_start:
+ .dword 0
+_romfs_length:
+ .dword 0
+_romfs_in_flash:
+ .dword 0
+
+ ;; put some special pages at the beginning of the kernel aligned
+ ;; to page boundaries - the kernel cannot start until after this
+
+#ifdef CONFIG_CRIS_LOW_MAP
+_swapper_pg_dir = 0x60002000
+#else
+_swapper_pg_dir = 0xc0002000
+#endif
diff --git a/arch/cris/kernel/hexify.c b/arch/cris/kernel/hexify.c
new file mode 100644
index 000000000..daa331fec
--- /dev/null
+++ b/arch/cris/kernel/hexify.c
@@ -0,0 +1,31 @@
+#include <stdio.h>
+
+
+void main()
+{
+ int c;
+ int comma=0;
+ int count=0;
+ while((c=getchar())!=EOF)
+ {
+ unsigned char x=c;
+ if(comma)
+ printf(",");
+ else
+ comma=1;
+ if(count==8)
+ {
+ count=0;
+ printf("\n");
+ }
+ if(count==0)
+ printf("\t");
+ printf("0x%02X",c);
+ count++;
+ }
+ if(count)
+ printf("\n");
+ exit(0);
+}
+
+
diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c
new file mode 100644
index 000000000..e55f94d20
--- /dev/null
+++ b/arch/cris/kernel/irq.c
@@ -0,0 +1,467 @@
+/* $Id: irq.c,v 1.5 2000/08/17 15:35:15 bjornw Exp $
+ *
+ * linux/arch/cris/kernel/irq.c
+ *
+ * Copyright (c) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ *
+ * Notice Linux/CRIS: these routines do not care about SMP
+ *
+ */
+
+/*
+ * IRQ's are in fact implemented a bit like signal handlers for the kernel.
+ * Naturally it's not a 1:1 relation, but there are similarities.
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#include <asm/svinto.h>
+
+char *hw_bp_msg = "BP 0x%x\n";
+
+static inline void
+mask_irq(unsigned int irq_nr)
+{
+ *R_VECT_MASK_CLR = 1 << irq_nr;
+}
+
+static inline void
+unmask_irq(unsigned int irq_nr)
+{
+ *R_VECT_MASK_SET = 1 << irq_nr;
+}
+
+void
+disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ mask_irq(irq_nr);
+ restore_flags(flags);
+}
+
+void
+enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ unmask_irq(irq_nr);
+ restore_flags(flags);
+}
+
+unsigned long
+probe_irq_on()
+{
+ return 0;
+}
+
+int
+probe_irq_off(unsigned long x)
+{
+ return 0;
+}
+
+irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */
+
+/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
+ * global just so that the kernel gdb can use it.
+ */
+
+void
+set_int_vector(int n, irqvectptr addr, irqvectptr saddr)
+{
+ /* remember the shortcut entry point, after the prologue */
+
+ irq_shortcuts[n] = saddr;
+
+ etrax_irv->v[n + 0x20] = (irqvectptr)addr;
+}
+
+/* the breakpoint vector is obviously not made just like the normal irq handlers
+ * but needs to contain _code_ to jump to addr.
+ *
+ * the BREAK n instruction jumps to IBR + n * 8
+ */
+
+void
+set_break_vector(int n, irqvectptr addr)
+{
+ unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2];
+ unsigned long *jaddr = (unsigned long *)(jinstr + 1);
+
+ /* if you don't know what this does, do not touch it! */
+
+ *jinstr = 0x0d3f;
+ *jaddr = (unsigned long)addr;
+
+ /* 00000026 <clrlop+1a> 3f0d82000000 jump 0x82 */
+}
+
+
+/*
+ * This builds up the IRQ handler stubs using some ugly macros in irq.h
+ *
+ * These macros create the low-level assembly IRQ routines that do all
+ * the operations that are needed. They are also written to be fast - and to
+ * disable interrupts as little as humanly possible.
+ *
+ */
+
+/* IRQ0 and 1 are special traps */
+void hwbreakpoint(void);
+void IRQ1_interrupt(void);
+BUILD_IRQ(2, 0x04) /* the timer interrupt */
+BUILD_IRQ(3, 0x08)
+BUILD_IRQ(4, 0x10)
+BUILD_IRQ(5, 0x20)
+BUILD_IRQ(6, 0x40)
+BUILD_IRQ(7, 0x80)
+BUILD_IRQ(8, 0x100)
+BUILD_IRQ(9, 0x200)
+BUILD_IRQ(10, 0x400)
+BUILD_IRQ(11, 0x800)
+BUILD_IRQ(12, 0x1000)
+BUILD_IRQ(13, 0x2000)
+void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */
+void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */
+BUILD_IRQ(16, 0x10000)
+BUILD_IRQ(17, 0x20000)
+BUILD_IRQ(18, 0x40000)
+BUILD_IRQ(19, 0x80000)
+BUILD_IRQ(20, 0x100000)
+BUILD_IRQ(21, 0x200000)
+BUILD_IRQ(22, 0x400000)
+BUILD_IRQ(23, 0x800000)
+BUILD_IRQ(24, 0x1000000)
+BUILD_IRQ(25, 0x2000000)
+
+/*
+ * Pointers to the low-level handlers
+ */
+
+static void (*interrupt[NR_IRQS])(void) = {
+ NULL, NULL, IRQ2_interrupt, IRQ3_interrupt,
+ IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
+ IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
+ IRQ12_interrupt, IRQ13_interrupt, NULL, NULL,
+ IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt,
+ IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt,
+ IRQ24_interrupt, IRQ25_interrupt
+};
+
+static void (*sinterrupt[NR_IRQS])(void) = {
+ NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt,
+ sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt,
+ sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt,
+ sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL,
+ sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt,
+ sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt,
+ sIRQ24_interrupt, sIRQ25_interrupt
+};
+
+static void (*bad_interrupt[NR_IRQS])(void) = {
+ NULL, NULL,
+ NULL, bad_IRQ3_interrupt,
+ bad_IRQ4_interrupt, bad_IRQ5_interrupt,
+ bad_IRQ6_interrupt, bad_IRQ7_interrupt,
+ bad_IRQ8_interrupt, bad_IRQ9_interrupt,
+ bad_IRQ10_interrupt, bad_IRQ11_interrupt,
+ bad_IRQ12_interrupt, bad_IRQ13_interrupt,
+ NULL, NULL,
+ bad_IRQ16_interrupt, bad_IRQ17_interrupt,
+ bad_IRQ18_interrupt, bad_IRQ19_interrupt,
+ bad_IRQ20_interrupt, bad_IRQ21_interrupt,
+ bad_IRQ22_interrupt, bad_IRQ23_interrupt,
+ bad_IRQ24_interrupt, bad_IRQ25_interrupt
+};
+
+/*
+ * Initial irq handlers.
+ */
+
+static struct irqaction *irq_action[NR_IRQS] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL
+};
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ struct irqaction * action;
+
+ for (i = 0; i < NR_IRQS; i++) {
+ action = irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %10u %c %s",
+ i, kstat.irqs[0][i],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action = action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, "\n");
+ }
+ return len;
+}
+
+/* called by the assembler IRQ entry functions defined in irq.h
+ * to dispatch the interrupts to registred handlers
+ * interrupts are disabled upon entry - depending on if the
+ * interrupt was registred with SA_INTERRUPT or not, interrupts
+ * are re-enabled or not.
+ */
+
+asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
+{
+ struct irqaction *action;
+ int do_random, cpu;
+
+ cpu = smp_processor_id();
+ irq_enter(cpu);
+ kstat.irqs[cpu][irq]++;
+
+ action = *(irq + irq_action);
+ if (action) {
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ action = *(irq + irq_action);
+ do_random = 0;
+ do {
+ do_random |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ if (do_random & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ __cli();
+ }
+ irq_exit(cpu);
+
+ if (softirq_active(cpu) & softirq_mask(cpu))
+ do_softirq();
+
+ /* unmasking and bottom half handling is done magically for us. */
+}
+
+/* this function links in a handler into the chain of handlers for the
+ given irq, and if the irq has never been registred, the appropriate
+ handler is entered into the interrupt vector
+*/
+
+int setup_etrax_irq(int irq, struct irqaction * new)
+{
+ int shared = 0;
+ struct irqaction *old, **p;
+ unsigned long flags;
+
+ p = irq_action + irq;
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ))
+ return -EBUSY;
+
+ /* Can't share interrupts unless both are same type */
+ if ((old->flags ^ new->flags) & SA_INTERRUPT)
+ return -EBUSY;
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ if (new->flags & SA_SAMPLE_RANDOM)
+ rand_initialize_irq(irq);
+
+ save_flags(flags);
+ cli();
+ *p = new;
+
+ if (!shared) {
+ /* if the irq wasn't registred before, enter it into the vector table
+ and unmask it physically
+ */
+ set_int_vector(irq, interrupt[irq], sinterrupt[irq]);
+ unmask_irq(irq);
+ }
+
+ restore_flags(flags);
+ return 0;
+}
+
+/* this function is called by a driver to register an irq handler
+ Valid flags:
+ SA_INTERRUPT -> it's a fast interrupt, handler called with irq disabled and
+ no signal checking etc is performed upon exit
+ SA_SHIRQ -> the interrupt can be shared between different handlers, the handler
+ is required to check if the irq was "aimed" at it explicitely
+ SA_RANDOM -> the interrupt will add to the random generators entropy
+*/
+
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
+{
+ int retval;
+ struct irqaction * action;
+
+ /* interrupts 0 and 1 are hardware breakpoint and NMI and we can't support
+ these yet. interrupt 15 is the multiple irq, it's special. */
+
+ if(irq < 2 || irq == 15 || irq >= NR_IRQS)
+ return -EINVAL;
+
+ if(!handler)
+ return -EINVAL;
+
+ /* allocate and fill in a handler structure and setup the irq */
+
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->next = NULL;
+ action->dev_id = dev_id;
+
+ retval = setup_etrax_irq(irq, action);
+
+ if (retval)
+ kfree(action);
+ return retval;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction * action, **p;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+ for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now free it */
+ save_flags(flags);
+ cli();
+ *p = action->next;
+ if (!irq[irq_action]) {
+ mask_irq(irq);
+ set_int_vector(irq, bad_interrupt[irq], 0);
+ }
+ restore_flags(flags);
+ kfree(action);
+ return;
+ }
+ printk("Trying to free free IRQ%d\n",irq);
+}
+
+void weird_irq(void)
+{
+ __asm__("di");
+ printk("weird irq\n");
+ while(1);
+}
+
+/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and
+ setting the irq vector table to point to bad_interrupt ptrs.
+*/
+
+void system_call(void); /* from entry.S */
+
+void init_IRQ(void)
+{
+ int i;
+
+ /* clear all interrupt masks */
+
+#ifndef CONFIG_SVINTO_SIM
+ *R_IRQ_MASK0_CLR = 0xffffffff;
+ *R_IRQ_MASK1_CLR = 0xffffffff;
+ *R_IRQ_MASK2_CLR = 0xffffffff;
+#endif
+
+ *R_VECT_MASK_CLR = 0xffffffff;
+
+ /* clear the shortcut entry points */
+
+ for(i = 0; i < NR_IRQS; i++)
+ irq_shortcuts[i] = NULL;
+
+ for (i = 0; i < 256; i++)
+ etrax_irv->v[i] = weird_irq;
+
+ /* set all etrax irq's to the bad handlers */
+ for (i = 2; i < NR_IRQS; i++)
+ set_int_vector(i, bad_interrupt[i], 0);
+
+ /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
+
+ set_int_vector(15, multiple_interrupt, 0);
+
+ /* 0 and 1 which are special breakpoint/NMI traps */
+
+ set_int_vector(0, hwbreakpoint, 0);
+ set_int_vector(1, IRQ1_interrupt, 0);
+
+ /* and irq 14 which is the mmu bus fault handler */
+
+ set_int_vector(14, mmu_bus_fault, 0);
+
+ /* setup the system-call trap, which is reached by BREAK 13 */
+
+ set_break_vector(13, system_call);
+
+#ifdef CONFIG_KGDB
+ /* setup kgdb if its enabled, and break into the debugger */
+
+ kgdb_init();
+
+ breakpoint();
+#endif
+
+}
diff --git a/arch/cris/kernel/kgdb.c b/arch/cris/kernel/kgdb.c
new file mode 100644
index 000000000..98d427b05
--- /dev/null
+++ b/arch/cris/kernel/kgdb.c
@@ -0,0 +1,1540 @@
+/*!**************************************************************************
+*!
+*! FILE NAME : kgdb.c
+*!
+*! DESCRIPTION: Implementation of the gdb stub with respect to ETRAX 100.
+*! It is a mix of arch/m68k/kernel/kgdb.c and cris_stub.c.
+*!
+*!---------------------------------------------------------------------------
+*! HISTORY
+*!
+*! DATE NAME CHANGES
+*! ---- ---- -------
+*! Apr 26 1999 Hendrik Ruijter Initial version.
+*! May 6 1999 Hendrik Ruijter Removed call to strlen in libc and removed
+*! struct assignment as it generates calls to
+*! memcpy in libc.
+*! Jun 17 1999 Hendrik Ruijter Added gdb 4.18 support. 'X', 'qC' and 'qL'.
+*! Jul 21 1999 Bjorn Wesen eLinux port
+*!
+*! $Log: kgdb.c,v $
+*! Revision 1.2 2001/01/12 14:22:25 orjanf
+*! Updated kernel debugging support to work with ETRAX 100LX.
+*!
+*! Revision 1.1 2000/07/10 16:25:21 bjornw
+*! Initial revision
+*!
+*! Revision 1.1.1.1 1999/12/03 14:57:31 bjornw
+*! * Initial version of arch/cris, the latest CRIS architecture with an MMU.
+*! Mostly copied from arch/etrax100 with appropriate renames of files.
+*! The mm/ subdir is copied from arch/i386.
+*! This does not compile yet at all.
+*!
+*!
+*! Revision 1.4 1999/07/22 17:25:25 bjornw
+*! Dont wait for + in putpacket if we havent hit the initial breakpoint yet. Added a kgdb_init function which sets up the break and irq vectors.
+*!
+*! Revision 1.3 1999/07/21 19:51:18 bjornw
+*! Check if the interrupting char is a ctrl-C, ignore otherwise.
+*!
+*! Revision 1.2 1999/07/21 18:09:39 bjornw
+*! Ported to eLinux architecture, and added some kgdb documentation.
+*!
+*!
+*!---------------------------------------------------------------------------
+*!
+*! $Id: kgdb.c,v 1.2 2001/01/12 14:22:25 orjanf Exp $
+*!
+*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
+*!
+*!**************************************************************************/
+/* @(#) cris_stub.c 1.3 06/17/99 */
+
+/*
+ * kgdb usage notes:
+ * -----------------
+ *
+ * If you select CONFIG_KGDB in the configuration, the kernel will be built
+ * with different gcc flags: "-g" is added to get debug infos, and
+ * "-fomit-frame-pointer" is omitted to make debugging easier. Since the
+ * resulting kernel will be quite big (approx. > 7 MB), it will be stripped
+ * before compresion. Such a kernel will behave just as usually, except if
+ * given a "debug=<device>" command line option. (Only serial devices are
+ * allowed for <device>, i.e. no printers or the like; possible values are
+ * machine depedend and are the same as for the usual debug device, the one
+ * for logging kernel messages.) If that option is given and the device can be
+ * initialized, the kernel will connect to the remote gdb in trap_init(). The
+ * serial parameters are fixed to 8N1 and 115200 bps, for easyness of
+ * implementation.
+ *
+ * To start a debugging session, start that gdb with the debugging kernel
+ * image (the one with the symbols, vmlinux.debug) named on the command line.
+ * This file will be used by gdb to get symbol and debugging infos about the
+ * kernel. Next, select remote debug mode by
+ * target remote <device>
+ * where <device> is the name of the serial device over which the debugged
+ * machine is connected. Maybe you have to adjust the baud rate by
+ * set remotebaud <rate>
+ * or also other parameters with stty:
+ * shell stty ... </dev/...
+ * If the kernel to debug has already booted, it waited for gdb and now
+ * connects, and you'll see a breakpoint being reported. If the kernel isn't
+ * running yet, start it now. The order of gdb and the kernel doesn't matter.
+ * Another thing worth knowing about in the getting-started phase is how to
+ * debug the remote protocol itself. This is activated with
+ * set remotedebug 1
+ * gdb will then print out each packet sent or received. You'll also get some
+ * messages about the gdb stub on the console of the debugged machine.
+ *
+ * If all that works, you can use lots of the usual debugging techniques on
+ * the kernel, e.g. inspecting and changing variables/memory, setting
+ * breakpoints, single stepping and so on. It's also possible to interrupt the
+ * debugged kernel by pressing C-c in gdb. Have fun! :-)
+ *
+ * The gdb stub is entered (and thus the remote gdb gets control) in the
+ * following situations:
+ *
+ * - If breakpoint() is called. This is just after kgdb initialization, or if
+ * a breakpoint() call has been put somewhere into the kernel source.
+ * (Breakpoints can of course also be set the usual way in gdb.)
+ * In eLinux, we call breakpoint() in init/main.c after IRQ initialization.
+ *
+ * - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel()
+ * are entered. All the CPU exceptions are mapped to (more or less..., see
+ * the hard_trap_info array below) appropriate signal, which are reported
+ * to gdb. die_if_kernel() is usually called after some kind of access
+ * error and thus is reported as SIGSEGV.
+ *
+ * - When panic() is called. This is reported as SIGABRT.
+ *
+ * - If C-c is received over the serial line, which is treated as
+ * SIGINT.
+ *
+ * Of course, all these signals are just faked for gdb, since there is no
+ * signal concept as such for the kernel. It also isn't possible --obviously--
+ * to set signal handlers from inside gdb, or restart the kernel with a
+ * signal.
+ *
+ * Current limitations:
+ *
+ * - While the kernel is stopped, interrupts are disabled for safety reasons
+ * (i.e., variables not changing magically or the like). But this also
+ * means that the clock isn't running anymore, and that interrupts from the
+ * hardware may get lost/not be served in time. This can cause some device
+ * errors...
+ *
+ * - When single-stepping, only one instruction of the current thread is
+ * executed, but interrupts are allowed for that time and will be serviced
+ * if pending. Be prepared for that.
+ *
+ * - All debugging happens in kernel virtual address space. There's no way to
+ * access physical memory not mapped in kernel space, or to access user
+ * space. A way to work around this is using get_user_long & Co. in gdb
+ * expressions, but only for the current process.
+ *
+ * - Interrupting the kernel only works if interrupts are currently allowed,
+ * and the interrupt of the serial line isn't blocked by some other means
+ * (IPL too high, disabled, ...)
+ *
+ * - The gdb stub is currently not reentrant, i.e. errors that happen therein
+ * (e.g. accesing invalid memory) may not be caught correctly. This could
+ * be removed in future by introducing a stack of struct registers.
+ *
+ */
+
+/*
+ * To enable debugger support, two things need to happen. One, a
+ * call to kgdb_init() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint().
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * G set the value of the CPU registers OK or ENN
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
+ * baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer. '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host: Reply:
+ * $m0,10#2a +$00010203040506070809101112131415#42
+ *
+ */
+
+
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/linkage.h>
+
+#include <asm/setup.h>
+#include <asm/ptrace.h>
+
+#include <asm/svinto.h>
+#include <asm/irq.h>
+
+static int kgdb_started = 0;
+
+/********************************* Register image ****************************/
+/* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's
+ Reference", p. 1-1, with the additional register definitions of the
+ ETRAX 100LX in cris-opc.h.
+ There are 16 general 32-bit registers, R0-R15, where R14 is the stack
+ pointer, SP, and R15 is the program counter, PC.
+ There are 16 special registers, P0-P15, where three of the unimplemented
+ registers, P0, P4 and P8, are reserved as zero-registers. A read from
+ any of these registers returns zero and a write has no effect. */
+
+typedef
+struct register_image
+{
+ /* Offset */
+ unsigned int r0; /* 0x00 */
+ unsigned int r1; /* 0x04 */
+ unsigned int r2; /* 0x08 */
+ unsigned int r3; /* 0x0C */
+ unsigned int r4; /* 0x10 */
+ unsigned int r5; /* 0x14 */
+ unsigned int r6; /* 0x18 */
+ unsigned int r7; /* 0x1C */
+ unsigned int r8; /* 0x20 Frame pointer */
+ unsigned int r9; /* 0x24 */
+ unsigned int r10; /* 0x28 */
+ unsigned int r11; /* 0x2C */
+ unsigned int r12; /* 0x30 */
+ unsigned int r13; /* 0x34 */
+ unsigned int sp; /* 0x38 Stack pointer */
+ unsigned int pc; /* 0x3C Program counter */
+
+ unsigned char p0; /* 0x40 8-bit zero-register */
+ unsigned char vr; /* 0x41 Version register */
+
+ unsigned short p4; /* 0x42 16-bit zero-register */
+ unsigned short ccr; /* 0x44 Condition code register */
+
+ unsigned int mof; /* 0x46 Multiply overflow register */
+
+ unsigned int p8; /* 0x4A 32-bit zero-register */
+ unsigned int ibr; /* 0x4E Interrupt base register */
+ unsigned int irp; /* 0x52 Interrupt return pointer */
+ unsigned int srp; /* 0x56 Subroutine return pointer */
+ unsigned int bar; /* 0x5A Breakpoint address register */
+ unsigned int dccr; /* 0x5E Double condition code register */
+ unsigned int brp; /* 0x62 Breakpoint return pointer (pc in caller) */
+ unsigned int usp; /* 0x66 User mode stack pointer */
+} registers;
+
+/************** Prototypes for local library functions ***********************/
+
+/* Copy of strcpy from libc. */
+static char *gdb_cris_strcpy (char *s1, const char *s2);
+
+/* Copy of strlen from libc. */
+static int gdb_cris_strlen (const char *s);
+
+/* Copy of memchr from libc. */
+static void *gdb_cris_memchr (const void *s, int c, int n);
+
+/* Copy of strtol from libc. Does only support base 16. */
+static int gdb_cris_strtol (const char *s, char **endptr, int base);
+
+/********************** Prototypes for local functions. **********************/
+/* Copy the content of a register image into another. The size n is
+ the size of the register image. Due to struct assignment generation of
+ memcpy in libc. */
+static void copy_registers (registers *dptr, registers *sptr, int n);
+
+/* Copy the stored registers from the stack. Put the register contents
+ of thread thread_id in the struct reg. */
+static void copy_registers_from_stack (int thread_id, registers *reg);
+
+/* Copy the registers to the stack. Put the register contents of thread
+ thread_id from struct reg to the stack. */
+static void copy_registers_to_stack (int thread_id, registers *reg);
+
+/* Write a value to a specified register regno in the register image
+ of the current thread. */
+static int write_register (int regno, char *val);
+
+/* Write a value to a specified register in the stack of a thread other
+ than the current thread. */
+static write_stack_register (int thread_id, int regno, char *valptr);
+
+/* Read a value from a specified register in the register image. Returns the
+ status of the read operation. The register value is returned in valptr. */
+static int read_register (char regno, unsigned int *valptr);
+
+/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
+int getDebugChar (void);
+
+/* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
+void putDebugChar (int val);
+
+void enableDebugIRQ (void);
+
+/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
+ represented by int x. */
+static char highhex (int x);
+
+/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
+ represented by int x. */
+static char lowhex (int x);
+
+/* Returns the integer equivalent of a hexadecimal character. */
+static int hex (char ch);
+
+/* Convert the memory, pointed to by mem into hexadecimal representation.
+ Put the result in buf, and return a pointer to the last character
+ in buf (null). */
+static char *mem2hex (char *buf, unsigned char *mem, int count);
+
+/* Convert the array, in hexadecimal representation, pointed to by buf into
+ binary representation. Put the result in mem, and return a pointer to
+ the character after the last byte written. */
+static unsigned char *hex2mem (unsigned char *mem, char *buf, int count);
+
+/* Put the content of the array, in binary representation, pointed to by buf
+ into memory pointed to by mem, and return a pointer to
+ the character after the last byte written. */
+static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count);
+
+/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
+ returned. */
+static void getpacket (char *buffer);
+
+/* Send $<data>#<checksum> from the <data> in the array buffer. */
+static void putpacket (char *buffer);
+
+/* Build and send a response packet in order to inform the host the
+ stub is stopped. */
+static void stub_is_stopped (int sigval);
+
+/* All expected commands are sent from remote.c. Send a response according
+ to the description in remote.c. */
+static void handle_exception (int sigval);
+
+/* Performs a complete re-start from scratch. ETRAX specific. */
+static void kill_restart (void);
+
+/******************** Prototypes for global functions. ***********************/
+
+/* The string str is prepended with the GDB printout token and sent. */
+void putDebugString (const unsigned char *str, int length); /* used by etrax100ser.c */
+
+/* The hook for both static (compiled) and dynamic breakpoints set by GDB.
+ ETRAX 100 specific. */
+void handle_breakpoint (void); /* used by irq.c */
+
+/* The hook for an interrupt generated by GDB. ETRAX 100 specific. */
+void handle_interrupt (void); /* used by irq.c */
+
+/* A static breakpoint to be used at startup. */
+void breakpoint (void); /* called by init/main.c */
+
+/* From osys_int.c, executing_task contains the number of the current
+ executing task in osys. Does not know of object-oriented threads. */
+extern unsigned char executing_task;
+
+/* The number of characters used for a 64 bit thread identifier. */
+#define HEXCHARS_IN_THREAD_ID 16
+
+/* Avoid warning as the internal_stack is not used in the C-code. */
+#define USEDVAR(name) { if (name) { ; } }
+#define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) }
+
+/********************************** Packet I/O ******************************/
+/* BUFMAX defines the maximum number of characters in
+ inbound/outbound buffers */
+#define BUFMAX 512
+
+/* Run-length encoding maximum length. Send 64 at most. */
+#define RUNLENMAX 64
+
+/* Definition of all valid hexadecimal characters */
+static const char hexchars[] = "0123456789abcdef";
+
+/* The inbound/outbound buffers used in packet I/O */
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+
+/* Error and warning messages. */
+enum error_type
+{
+ SUCCESS, E01, E02, E03, E04, E05, E06, E07
+};
+static char *error_message[] =
+{
+ "",
+ "E01 Set current or general thread - H[c,g] - internal error.",
+ "E02 Change register content - P - cannot change read-only register.",
+ "E03 Thread is not alive.", /* T, not used. */
+ "E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.",
+ "E05 Change register content - P - the register is not implemented..",
+ "E06 Change memory content - M - internal error.",
+ "E07 Change register content - P - the register is not stored on the stack"
+};
+/********************************* Register image ****************************/
+/* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's
+ Reference", p. 1-1, with the additional register definitions of the
+ ETRAX 100LX in cris-opc.h.
+ There are 16 general 32-bit registers, R0-R15, where R14 is the stack
+ pointer, SP, and R15 is the program counter, PC.
+ There are 16 special registers, P0-P15, where three of the unimplemented
+ registers, P0, P4 and P8, are reserved as zero-registers. A read from
+ any of these registers returns zero and a write has no effect. */
+enum register_name
+{
+ R0, R1, R2, R3,
+ R4, R5, R6, R7,
+ R8, R9, R10, R11,
+ R12, R13, SP, PC,
+ P0, VR, P2, P3,
+ P4, CCR, P6, MOF,
+ P8, IBR, IRP, SRP,
+ BAR, DCCR, BRP, USP
+};
+
+/* The register sizes of the registers in register_name. An unimplemented register
+ is designated by size 0 in this array. */
+static int register_size[] =
+{
+ 4, 4, 4, 4,
+ 4, 4, 4, 4,
+ 4, 4, 4, 4,
+ 4, 4, 4, 4,
+ 1, 1, 0, 0,
+ 2, 2, 0, 4,
+ 4, 4, 4, 4,
+ 4, 4, 4, 4
+};
+
+/* Contains the register image of the executing thread in the assembler
+ part of the code in order to avoid horrible addressing modes. */
+static registers reg;
+
+/* FIXME: Should this be used? Delete otherwise. */
+/* Contains the assumed consistency state of the register image. Uses the
+ enum error_type for state information. */
+static int consistency_status = SUCCESS;
+
+/********************************** Handle exceptions ************************/
+/* The variable reg contains the register image associated with the
+ current_thread_c variable. It is a complete register image created at
+ entry. The reg_g contains a register image of a task where the general
+ registers are taken from the stack and all special registers are taken
+ from the executing task. It is associated with current_thread_g and used
+ in order to provide access mainly for 'g', 'G' and 'P'.
+*/
+
+/* Need two task id pointers in order to handle Hct and Hgt commands. */
+static int current_thread_c = 0;
+static int current_thread_g = 0;
+
+/* Need two register images in order to handle Hct and Hgt commands. The
+ variable reg_g is in addition to reg above. */
+static registers reg_g;
+
+/********************************** Breakpoint *******************************/
+/* Use an internal stack in the breakpoint and interrupt response routines */
+#define INTERNAL_STACK_SIZE 1024
+static char internal_stack[INTERNAL_STACK_SIZE];
+
+/* Due to the breakpoint return pointer, a state variable is needed to keep
+ track of whether it is a static (compiled) or dynamic (gdb-invoked)
+ breakpoint to be handled. A static breakpoint uses the content of register
+ BRP as it is whereas a dynamic breakpoint requires subtraction with 2
+ in order to execute the instruction. The first breakpoint is static. */
+static unsigned char is_dyn_brkp = 0;
+
+/********************************* String library ****************************/
+/* Single-step over library functions creates trap loops. */
+
+/* Copy char s2[] to s1[]. */
+static char*
+gdb_cris_strcpy (char *s1, const char *s2)
+{
+ char *s = s1;
+
+ for (s = s1; (*s++ = *s2++) != '\0'; )
+ ;
+ return (s1);
+}
+
+/* Find length of s[]. */
+static int
+gdb_cris_strlen (const char *s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; sc++)
+ ;
+ return (sc - s);
+}
+
+/* Find first occurrence of c in s[n]. */
+static void*
+gdb_cris_memchr (const void *s, int c, int n)
+{
+ const unsigned char uc = c;
+ const unsigned char *su;
+
+ for (su = s; 0 < n; ++su, --n)
+ if (*su == uc)
+ return ((void *)su);
+ return (NULL);
+}
+/******************************* Standard library ****************************/
+/* Single-step over library functions creates trap loops. */
+/* Convert string to long. */
+static int
+gdb_cris_strtol (const char *s, char **endptr, int base)
+{
+ char *s1;
+ char *sd;
+ int x = 0;
+
+ for (s1 = (char*)s; (sd = gdb_cris_memchr(hexchars, *s1, base)) != NULL; ++s1)
+ x = x * base + (sd - hexchars);
+
+ if (endptr)
+ {
+ /* Unconverted suffix is stored in endptr unless endptr is NULL. */
+ *endptr = s1;
+ }
+
+ return x;
+}
+
+int
+double_this(int x)
+{
+ return 2 * x;
+}
+
+/********************************* Register image ****************************/
+/* Copy the content of a register image into another. The size n is
+ the size of the register image. Due to struct assignment generation of
+ memcpy in libc. */
+static void
+copy_registers (registers *dptr, registers *sptr, int n)
+{
+ unsigned char *dreg;
+ unsigned char *sreg;
+
+ for (dreg = (unsigned char*)dptr, sreg = (unsigned char*)sptr; n > 0; n--)
+ *dreg++ = *sreg++;
+}
+
+#ifdef PROCESS_SUPPORT
+/* Copy the stored registers from the stack. Put the register contents
+ of thread thread_id in the struct reg. */
+static void
+copy_registers_from_stack (int thread_id, registers *regptr)
+{
+ int j;
+ stack_registers *s = (stack_registers *)stack_list[thread_id];
+ unsigned int *d = (unsigned int *)regptr;
+
+ for (j = 13; j >= 0; j--)
+ *d++ = s->r[j];
+ regptr->sp = (unsigned int)stack_list[thread_id];
+ regptr->pc = s->pc;
+ regptr->dccr = s->dccr;
+ regptr->srp = s->srp;
+}
+
+/* Copy the registers to the stack. Put the register contents of thread
+ thread_id from struct reg to the stack. */
+static void
+copy_registers_to_stack (int thread_id, registers *regptr)
+{
+ int i;
+ stack_registers *d = (stack_registers *)stack_list[thread_id];
+ unsigned int *s = (unsigned int *)regptr;
+
+ for (i = 0; i < 14; i++) {
+ d->r[i] = *s++;
+ }
+ d->pc = regptr->pc;
+ d->dccr = regptr->dccr;
+ d->srp = regptr->srp;
+}
+#endif
+
+/* Write a value to a specified register in the register image of the current
+ thread. Returns status code SUCCESS, E02 or E05. */
+static int
+write_register (int regno, char *val)
+{
+ int status = SUCCESS;
+ registers *current_reg = &reg;
+
+ if (regno >= R0 && regno <= PC) {
+ /* 32-bit register with simple offset. */
+ hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int),
+ val, sizeof(unsigned int));
+ }
+ else if (regno == P0 || regno == VR || regno == P4 || regno == P8) {
+ /* Do not support read-only registers. */
+ status = E02;
+ }
+ else if (regno == CCR) {
+ /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented,
+ and P7 (MOF) is 32 bits in ETRAX 100LX. */
+ hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short),
+ val, sizeof(unsigned short));
+ }
+ else if (regno >= MOF && regno <= USP) {
+ /* 32 bit register with complex offset. (P8 has been taken care of.) */
+ hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int),
+ val, sizeof(unsigned int));
+ }
+ else {
+ /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+ status = E05;
+ }
+ return status;
+}
+
+#ifdef PROCESS_SUPPORT
+/* Write a value to a specified register in the stack of a thread other
+ than the current thread. Returns status code SUCCESS or E07. */
+static int
+write_stack_register (int thread_id, int regno, char *valptr)
+{
+ int status = SUCCESS;
+ stack_registers *d = (stack_registers *)stack_list[thread_id];
+ unsigned int val;
+
+ hex2mem ((unsigned char *)&val, valptr, sizeof(unsigned int));
+ if (regno >= R0 && regno < SP) {
+ d->r[regno] = val;
+ }
+ else if (regno == SP) {
+ stack_list[thread_id] = val;
+ }
+ else if (regno == PC) {
+ d->pc = val;
+ }
+ else if (regno == SRP) {
+ d->srp = val;
+ }
+ else if (regno == DCCR) {
+ d->dccr = val;
+ }
+ else {
+ /* Do not support registers in the current thread. */
+ status = E07;
+ }
+ return status;
+}
+#endif
+
+/* Read a value from a specified register in the register image. Returns the
+ value in the register or -1 for non-implemented registers.
+ Should check consistency_status after a call which may be E05 after changes
+ in the implementation. */
+static int
+read_register (char regno, unsigned int *valptr)
+{
+ registers *current_reg = &reg;
+
+ if (regno >= R0 && regno <= PC) {
+ /* 32-bit register with simple offset. */
+ *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int));
+ return SUCCESS;
+ }
+ else if (regno == P0 || regno == VR) {
+ /* 8 bit register with complex offset. */
+ *valptr = (unsigned int)(*(unsigned char *)
+ ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char)));
+ return SUCCESS;
+ }
+ else if (regno == P4 || regno == CCR) {
+ /* 16 bit register with complex offset. */
+ *valptr = (unsigned int)(*(unsigned short *)
+ ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short)));
+ return SUCCESS;
+ }
+ else if (regno >= MOF && regno <= USP) {
+ /* 32 bit register with complex offset. */
+ *valptr = *(unsigned int *)((char *)&(current_reg->p8)
+ + (regno-P8) * sizeof(unsigned int));
+ return SUCCESS;
+ }
+ else {
+ /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+ consistency_status = E05;
+ return E05;
+ }
+}
+
+/********************************** Packet I/O ******************************/
+/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte,
+ represented by int x. */
+static inline char
+highhex(int x)
+{
+ return hexchars[(x >> 4) & 0xf];
+}
+
+/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte,
+ represented by int x. */
+static inline char
+lowhex(int x)
+{
+ return hexchars[x & 0xf];
+}
+
+/* Returns the integer equivalent of a hexadecimal character. */
+static int
+hex (char ch)
+{
+ if ((ch >= 'a') && (ch <= 'f'))
+ return (ch - 'a' + 10);
+ if ((ch >= '0') && (ch <= '9'))
+ return (ch - '0');
+ if ((ch >= 'A') && (ch <= 'F'))
+ return (ch - 'A' + 10);
+ return (-1);
+}
+
+/* Convert the memory, pointed to by mem into hexadecimal representation.
+ Put the result in buf, and return a pointer to the last character
+ in buf (null). */
+
+static int do_printk = 0;
+
+static char *
+mem2hex(char *buf, unsigned char *mem, int count)
+{
+ int i;
+ int ch;
+
+ if (mem == NULL) {
+ /* Bogus read from m0. FIXME: What constitutes a valid address? */
+ for (i = 0; i < count; i++) {
+ *buf++ = '0';
+ *buf++ = '0';
+ }
+ } else {
+ /* Valid mem address. */
+ for (i = 0; i < count; i++) {
+ ch = *mem++;
+ *buf++ = highhex (ch);
+ *buf++ = lowhex (ch);
+ }
+ }
+
+ /* Terminate properly. */
+ *buf = '\0';
+ return (buf);
+}
+
+/* Convert the array, in hexadecimal representation, pointed to by buf into
+ binary representation. Put the result in mem, and return a pointer to
+ the character after the last byte written. */
+static unsigned char*
+hex2mem (unsigned char *mem, char *buf, int count)
+{
+ int i;
+ unsigned char ch;
+ for (i = 0; i < count; i++) {
+ ch = hex (*buf++) << 4;
+ ch = ch + hex (*buf++);
+ *mem++ = ch;
+ }
+ return (mem);
+}
+
+/* Put the content of the array, in binary representation, pointed to by buf
+ into memory pointed to by mem, and return a pointer to the character after
+ the last byte written.
+ Gdb will escape $, #, and the escape char (0x7d). */
+static unsigned char*
+bin2mem (unsigned char *mem, unsigned char *buf, int count)
+{
+ int i;
+ unsigned char *next;
+ for (i = 0; i < count; i++) {
+ /* Check for any escaped characters. Be paranoid and
+ only unescape chars that should be escaped. */
+ if (*buf == 0x7d) {
+ next = buf + 1;
+ if (*next == 0x3 || *next == 0x4 || *next == 0x5D) /* #, $, ESC */
+ {
+ buf++;
+ *buf += 0x20;
+ }
+ }
+ *mem++ = *buf++;
+ }
+ return (mem);
+}
+
+/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
+ returned. */
+static void
+getpacket (char *buffer)
+{
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int i;
+ int count;
+ char ch;
+ do {
+ while ((ch = getDebugChar ()) != '$')
+ /* Wait for the start character $ and ignore all other characters */;
+ checksum = 0;
+ xmitcsum = -1;
+ count = 0;
+ /* Read until a # or the end of the buffer is reached */
+ while (count < BUFMAX) {
+ ch = getDebugChar ();
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+ buffer[count] = '\0';
+
+ if (ch == '#') {
+ xmitcsum = hex (getDebugChar ()) << 4;
+ xmitcsum += hex (getDebugChar ());
+ if (checksum != xmitcsum) {
+ /* Wrong checksum */
+ putDebugChar ('-');
+ }
+ else {
+ /* Correct checksum */
+ putDebugChar ('+');
+ /* If sequence characters are received, reply with them */
+ if (buffer[2] == ':') {
+ putDebugChar (buffer[0]);
+ putDebugChar (buffer[1]);
+ /* Remove the sequence characters from the buffer */
+ count = gdb_cris_strlen (buffer);
+ for (i = 3; i <= count; i++)
+ buffer[i - 3] = buffer[i];
+ }
+ }
+ }
+ } while (checksum != xmitcsum);
+}
+
+/* Send $<data>#<checksum> from the <data> in the array buffer. */
+
+static void
+putpacket(char *buffer)
+{
+ int checksum;
+ int runlen;
+ int encode;
+
+ do {
+ char *src = buffer;
+ putDebugChar ('$');
+ checksum = 0;
+ while (*src) {
+ /* Do run length encoding */
+ putDebugChar (*src);
+ checksum += *src;
+ runlen = 0;
+ while (runlen < RUNLENMAX && *src == src[runlen]) {
+ runlen++;
+ }
+ if (runlen > 3) {
+ /* Got a useful amount */
+ putDebugChar ('*');
+ checksum += '*';
+ encode = runlen + ' ' - 4;
+ putDebugChar (encode);
+ checksum += encode;
+ src += runlen;
+ }
+ else {
+ src++;
+ }
+ }
+ putDebugChar ('#');
+ putDebugChar (highhex (checksum));
+ putDebugChar (lowhex (checksum));
+ } while(kgdb_started && (getDebugChar() != '+'));
+}
+
+/* The string str is prepended with the GDB printout token and sent. Required
+ in traditional implementations. */
+void
+putDebugString (const unsigned char *str, int length)
+{
+ remcomOutBuffer[0] = 'O';
+ mem2hex(&remcomOutBuffer[1], (unsigned char *)str, length);
+ putpacket(remcomOutBuffer);
+}
+
+/********************************** Handle exceptions ************************/
+/* Build and send a response packet in order to inform the host the
+ stub is stopped. TAAn...:r...;n...:r...;n...:r...;
+ AA = signal number
+ n... = register number (hex)
+ r... = register contents
+ n... = `thread'
+ r... = thread process ID. This is a hex integer.
+ n... = other string not starting with valid hex digit.
+ gdb should ignore this n,r pair and go on to the next.
+ This way we can extend the protocol. */
+static void
+stub_is_stopped(int sigval)
+{
+ char *ptr = remcomOutBuffer;
+ int regno;
+
+ unsigned int reg_cont;
+ int status;
+
+ /* Send trap type (converted to signal) */
+
+ *ptr++ = 'T';
+ *ptr++ = highhex (sigval);
+ *ptr++ = lowhex (sigval);
+
+ /* Send register contents. We probably only need to send the
+ * PC, frame pointer and stack pointer here. Other registers will be
+ * explicitely asked for. But for now, send all.
+ */
+
+ for (regno = R0; regno <= USP; regno++) {
+ /* Store n...:r...; for the registers in the buffer. */
+
+ status = read_register (regno, &reg_cont);
+
+ if (status == SUCCESS) {
+
+ *ptr++ = highhex (regno);
+ *ptr++ = lowhex (regno);
+ *ptr++ = ':';
+
+ ptr = mem2hex(ptr, (unsigned char *)&reg_cont,
+ register_size[regno]);
+ *ptr++ = ';';
+ }
+
+ }
+
+#ifdef PROCESS_SUPPORT
+ /* Store the registers of the executing thread. Assume that both step,
+ continue, and register content requests are with respect to this
+ thread. The executing task is from the operating system scheduler. */
+
+ current_thread_c = executing_task;
+ current_thread_g = executing_task;
+
+ /* A struct assignment translates into a libc memcpy call. Avoid
+ all libc functions in order to prevent recursive break points. */
+ copy_registers (&reg_g, &reg, sizeof(registers));
+
+ /* Store thread:r...; with the executing task TID. */
+ gdb_cris_strcpy (&remcomOutBuffer[pos], "thread:");
+ pos += gdb_cris_strlen ("thread:");
+ remcomOutBuffer[pos++] = highhex (executing_task);
+ remcomOutBuffer[pos++] = lowhex (executing_task);
+ gdb_cris_strcpy (&remcomOutBuffer[pos], ";");
+#endif
+
+ /* null-terminate and send it off */
+
+ *ptr = 0;
+
+ putpacket (remcomOutBuffer);
+}
+
+/* All expected commands are sent from remote.c. Send a response according
+ to the description in remote.c. */
+static void
+handle_exception (int sigval)
+{
+ /* Avoid warning of not used. */
+
+ USEDFUN(handle_exception);
+ USEDVAR(internal_stack[0]);
+
+ /* Send response. */
+
+ stub_is_stopped (sigval);
+
+ for (;;) {
+ remcomOutBuffer[0] = '\0';
+ getpacket (remcomInBuffer);
+ switch (remcomInBuffer[0]) {
+ case 'g':
+ /* Read registers: g
+ Success: Each byte of register data is described by two hex digits.
+ Registers are in the internal order for GDB, and the bytes
+ in a register are in the same order the machine uses.
+ Failure: void. */
+
+ {
+#ifdef PROCESS_SUPPORT
+ /* Use the special register content in the executing thread. */
+ copy_registers (&reg_g, &reg, sizeof(registers));
+ /* Replace the content available on the stack. */
+ if (current_thread_g != executing_task) {
+ copy_registers_from_stack (current_thread_g, &reg_g);
+ }
+ mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)&reg_g, sizeof(registers));
+#else
+ mem2hex(remcomOutBuffer, (char *)&reg, sizeof(registers));
+#endif
+ }
+ break;
+
+ case 'G':
+ /* Write registers. GXX..XX
+ Each byte of register data is described by two hex digits.
+ Success: OK
+ Failure: void. */
+#ifdef PROCESS_SUPPORT
+ hex2mem ((unsigned char *)&reg_g, &remcomInBuffer[1], sizeof(registers));
+ if (current_thread_g == executing_task) {
+ copy_registers (&reg, &reg_g, sizeof(registers));
+ }
+ else {
+ copy_registers_to_stack(current_thread_g, &reg_g);
+ }
+#else
+ hex2mem((char *)&reg, &remcomInBuffer[1], sizeof(registers));
+#endif
+ gdb_cris_strcpy (remcomOutBuffer, "OK");
+ break;
+
+ case 'P':
+ /* Write register. Pn...=r...
+ Write register n..., hex value without 0x, with value r...,
+ which contains a hex value without 0x and two hex digits
+ for each byte in the register (target byte order). P1f=11223344 means
+ set register 31 to 44332211.
+ Success: OK
+ Failure: E02, E05 */
+ {
+ char *suffix;
+ int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16);
+ int status;
+#ifdef PROCESS_SUPPORT
+ if (current_thread_g =! executing_task)
+ status = write_stack_register (current_thread_g, regno, suffix+1);
+ else
+#endif
+ status = write_register (regno, suffix+1);
+
+ switch (status) {
+ case E02:
+ /* Do not support read-only registers. */
+ gdb_cris_strcpy (remcomOutBuffer, error_message[E02]);
+ break;
+ case E05:
+ /* Do not support non-existing registers. */
+ gdb_cris_strcpy (remcomOutBuffer, error_message[E05]);
+ break;
+ case E07:
+ /* Do not support non-existing registers on the stack. */
+ gdb_cris_strcpy (remcomOutBuffer, error_message[E07]);
+ break;
+ default:
+ /* Valid register number. */
+ gdb_cris_strcpy (remcomOutBuffer, "OK");
+ break;
+ }
+ }
+ break;
+
+ case 'm':
+ /* Read from memory. mAA..AA,LLLL
+ AA..AA is the address and LLLL is the length.
+ Success: XX..XX is the memory content. Can be fewer bytes than
+ requested if only part of the data may be read. m6000120a,6c means
+ retrieve 108 byte from base address 6000120a.
+ Failure: void. */
+ {
+ char *suffix;
+ unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1],
+ &suffix, 16); int length = gdb_cris_strtol(suffix+1, 0, 16);
+
+ mem2hex(remcomOutBuffer, addr, length);
+ }
+ break;
+
+ case 'X':
+ /* Write to memory. XAA..AA,LLLL:XX..XX
+ AA..AA is the start address, LLLL is the number of bytes, and
+ XX..XX is the binary data.
+ Success: OK
+ Failure: void. */
+ case 'M':
+ /* Write to memory. MAA..AA,LLLL:XX..XX
+ AA..AA is the start address, LLLL is the number of bytes, and
+ XX..XX is the hexadecimal data.
+ Success: OK
+ Failure: void. */
+ {
+ char *lenptr;
+ char *dataptr;
+ unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1],
+ &lenptr, 16);
+ int length = gdb_cris_strtol(lenptr+1, &dataptr, 16);
+ if (*lenptr == ',' && *dataptr == ':') {
+ if (remcomInBuffer[0] == 'M') {
+ hex2mem(addr, dataptr + 1, length);
+ }
+ else /* X */ {
+ bin2mem(addr, dataptr + 1, length);
+ }
+ gdb_cris_strcpy (remcomOutBuffer, "OK");
+ }
+ else {
+ gdb_cris_strcpy (remcomOutBuffer, error_message[E06]);
+ }
+ }
+ break;
+
+ case 'c':
+ /* Continue execution. cAA..AA
+ AA..AA is the address where execution is resumed. If AA..AA is
+ omitted, resume at the present address.
+ Success: return to the executing thread.
+ Failure: will never know. */
+ if (remcomInBuffer[1] != '\0') {
+ reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
+ }
+ enableDebugIRQ();
+ return;
+
+ case 's':
+ /* Step. sAA..AA
+ AA..AA is the address where execution is resumed. If AA..AA is
+ omitted, resume at the present address. Success: return to the
+ executing thread. Failure: will never know.
+
+ Should never be invoked. The single-step is implemented on
+ the host side. If ever invoked, it is an internal error E04. */
+ gdb_cris_strcpy (remcomOutBuffer, error_message[E04]);
+ putpacket (remcomOutBuffer);
+ return;
+
+ case '?':
+ /* The last signal which caused a stop. ?
+ Success: SAA, where AA is the signal number.
+ Failure: void. */
+ remcomOutBuffer[0] = 'S';
+ remcomOutBuffer[1] = highhex (sigval);
+ remcomOutBuffer[2] = lowhex (sigval);
+ remcomOutBuffer[3] = 0;
+ break;
+
+ case 'D':
+ /* Detach from host. D
+ Success: OK, and return to the executing thread.
+ Failure: will never know */
+ putpacket ("OK");
+ return;
+
+ case 'k':
+ case 'r':
+ /* kill request or reset request.
+ Success: restart of target.
+ Failure: will never know. */
+ kill_restart ();
+ break;
+
+ case 'C':
+ case 'S':
+ case '!':
+ case 'R':
+ case 'd':
+ /* Continue with signal sig. Csig;AA..AA
+ Step with signal sig. Ssig;AA..AA
+ Use the extended remote protocol. !
+ Restart the target system. R0
+ Toggle debug flag. d
+ Search backwards. tAA:PP,MM
+ Not supported: E04 */
+ gdb_cris_strcpy (remcomOutBuffer, error_message[E04]);
+ break;
+#ifdef PROCESS_SUPPORT
+
+ case 'T':
+ /* Thread alive. TXX
+ Is thread XX alive?
+ Success: OK, thread XX is alive.
+ Failure: E03, thread XX is dead. */
+ {
+ int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
+ /* Cannot tell whether it is alive or not. */
+ if (thread_id >= 0 && thread_id < number_of_tasks)
+ gdb_cris_strcpy (remcomOutBuffer, "OK");
+ }
+ break;
+
+ case 'H':
+ /* Set thread for subsequent operations: Hct
+ c = 'c' for thread used in step and continue;
+ t can be -1 for all threads.
+ c = 'g' for thread used in other operations.
+ t = 0 means pick any thread.
+ Success: OK
+ Failure: E01 */
+ {
+ int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16);
+ if (remcomInBuffer[1] == 'c') {
+ /* c = 'c' for thread used in step and continue */
+ /* Do not change current_thread_c here. It would create a mess in
+ the scheduler. */
+ gdb_cris_strcpy (remcomOutBuffer, "OK");
+ }
+ else if (remcomInBuffer[1] == 'g') {
+ /* c = 'g' for thread used in other operations.
+ t = 0 means pick any thread. Impossible since the scheduler does
+ not allow that. */
+ if (thread_id >= 0 && thread_id < number_of_tasks) {
+ current_thread_g = thread_id;
+ gdb_cris_strcpy (remcomOutBuffer, "OK");
+ }
+ else {
+ /* Not expected - send an error message. */
+ gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
+ }
+ }
+ else {
+ /* Not expected - send an error message. */
+ gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
+ }
+ }
+ break;
+
+ case 'q':
+ case 'Q':
+ /* Query of general interest. qXXXX
+ Set general value XXXX. QXXXX=yyyy */
+ {
+ int pos;
+ int nextpos;
+ int thread_id;
+
+ switch (remcomInBuffer[1]) {
+ case 'C':
+ /* Identify the remote current thread. */
+ gdb_cris_strcpy (&remcomOutBuffer[0], "QC");
+ remcomOutBuffer[2] = highhex (current_thread_c);
+ remcomOutBuffer[3] = lowhex (current_thread_c);
+ remcomOutBuffer[4] = '\0';
+ break;
+ case 'L':
+ gdb_cris_strcpy (&remcomOutBuffer[0], "QM");
+ /* Reply with number of threads. */
+ if (os_is_started()) {
+ remcomOutBuffer[2] = highhex (number_of_tasks);
+ remcomOutBuffer[3] = lowhex (number_of_tasks);
+ }
+ else {
+ remcomOutBuffer[2] = highhex (0);
+ remcomOutBuffer[3] = lowhex (1);
+ }
+ /* Done with the reply. */
+ remcomOutBuffer[4] = lowhex (1);
+ pos = 5;
+ /* Expects the argument thread id. */
+ for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++)
+ remcomOutBuffer[pos] = remcomInBuffer[pos];
+ /* Reply with the thread identifiers. */
+ if (os_is_started()) {
+ /* Store the thread identifiers of all tasks. */
+ for (thread_id = 0; thread_id < number_of_tasks; thread_id++) {
+ nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
+ for (; pos < nextpos; pos ++)
+ remcomOutBuffer[pos] = lowhex (0);
+ remcomOutBuffer[pos++] = lowhex (thread_id);
+ }
+ }
+ else {
+ /* Store the thread identifier of the boot task. */
+ nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
+ for (; pos < nextpos; pos ++)
+ remcomOutBuffer[pos] = lowhex (0);
+ remcomOutBuffer[pos++] = lowhex (current_thread_c);
+ }
+ remcomOutBuffer[pos] = '\0';
+ break;
+ default:
+ /* Not supported: "" */
+ /* Request information about section offsets: qOffsets. */
+ remcomOutBuffer[0] = 0;
+ break;
+ }
+ }
+ break;
+#endif /* PROCESS_SUPPORT */
+
+ default:
+ /* The stub should ignore other request and send an empty
+ response ($#<checksum>). This way we can extend the protocol and GDB
+ can tell whether the stub it is talking to uses the old or the new. */
+ remcomOutBuffer[0] = 0;
+ break;
+ }
+ putpacket(remcomOutBuffer);
+ }
+}
+
+/* The jump is to the address 0x00000002. Performs a complete re-start
+ from scratch. */
+static void
+kill_restart ()
+{
+ __asm__ volatile ("jump 2");
+}
+
+/********************************** Breakpoint *******************************/
+/* The hook for both a static (compiled) and a dynamic breakpoint set by GDB.
+ An internal stack is used by the stub. The register image of the caller is
+ stored in the structure register_image.
+ Interactive communication with the host is handled by handle_exception and
+ finally the register image is restored. */
+
+void kgdb_handle_breakpoint(void);
+
+asm ("
+ .global _kgdb_handle_breakpoint
+_kgdb_handle_breakpoint:
+;;
+;; Response to the break-instruction
+;;
+;; Create a register image of the caller
+;;
+ move dccr,[_reg+0x5E] ; Save the flags in DCCR before disable interrupts
+ di ; Disable interrupts
+ move.d r0,[_reg] ; Save R0
+ move.d r1,[_reg+0x04] ; Save R1
+ move.d r2,[_reg+0x08] ; Save R2
+ move.d r3,[_reg+0x0C] ; Save R3
+ move.d r4,[_reg+0x10] ; Save R4
+ move.d r5,[_reg+0x14] ; Save R5
+ move.d r6,[_reg+0x18] ; Save R6
+ move.d r7,[_reg+0x1C] ; Save R7
+ move.d r8,[_reg+0x20] ; Save R8
+ move.d r9,[_reg+0x24] ; Save R9
+ move.d r10,[_reg+0x28] ; Save R10
+ move.d r11,[_reg+0x2C] ; Save R11
+ move.d r12,[_reg+0x30] ; Save R12
+ move.d r13,[_reg+0x34] ; Save R13
+ move.d sp,[_reg+0x38] ; Save SP (R14)
+;; Due to the old assembler-versions BRP might not be recognized
+ .word 0xE670 ; move brp,r0
+ subq 2,r0 ; Set to address of previous instruction.
+ move.d r0,[_reg+0x3c] ; Save the address in PC (R15)
+ clear.b [_reg+0x40] ; Clear P0
+ move vr,[_reg+0x41] ; Save special register P1
+ clear.w [_reg+0x42] ; Clear P4
+ move ccr,[_reg+0x44] ; Save special register CCR
+ move mof,[_reg+0x46] ; P7
+ clear.d [_reg+0x4A] ; Clear P8
+ move ibr,[_reg+0x4E] ; P9,
+ move irp,[_reg+0x52] ; P10,
+ move srp,[_reg+0x56] ; P11,
+ move dtp0,[_reg+0x5A] ; P12, register BAR, assembler might not know BAR
+ ; P13, register DCCR already saved
+;; Due to the old assembler-versions BRP might not be recognized
+ .word 0xE670 ; move brp,r0
+;; Static (compiled) breakpoints must return to the next instruction in order
+;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction
+;; in order to execute it when execution is continued.
+ test.b [_is_dyn_brkp] ; Is this a dynamic breakpoint?
+ beq is_static ; No, a static breakpoint
+ nop
+ subq 2,r0 ; rerun the instruction the break replaced
+is_static:
+ moveq 1,r1
+ move.b r1,[_is_dyn_brkp] ; Set the state variable to dynamic breakpoint
+ move.d r0,[_reg+0x62] ; Save the return address in BRP
+ move usp,[_reg+0x66] ; USP
+;;
+;; Handle the communication
+;;
+ move.d _internal_stack+1020,sp ; Use the internal stack which grows upward
+ moveq 5,r10 ; SIGTRAP
+ jsr _handle_exception ; Interactive routine
+;;
+;; Return to the caller
+;;
+ move.d [_reg],r0 ; Restore R0
+ move.d [_reg+0x04],r1 ; Restore R1
+ move.d [_reg+0x08],r2 ; Restore R2
+ move.d [_reg+0x0C],r3 ; Restore R3
+ move.d [_reg+0x10],r4 ; Restore R4
+ move.d [_reg+0x14],r5 ; Restore R5
+ move.d [_reg+0x18],r6 ; Restore R6
+ move.d [_reg+0x1C],r7 ; Restore R7
+ move.d [_reg+0x20],r8 ; Restore R8
+ move.d [_reg+0x24],r9 ; Restore R9
+ move.d [_reg+0x28],r10 ; Restore R10
+ move.d [_reg+0x2C],r11 ; Restore R11
+ move.d [_reg+0x30],r12 ; Restore R12
+ move.d [_reg+0x34],r13 ; Restore R13
+;;
+;; FIXME: Which registers should be restored?
+;;
+ move.d [_reg+0x38],sp ; Restore SP (R14)
+ move [_reg+0x56],srp ; Restore the subroutine return pointer.
+ move [_reg+0x5E],dccr ; Restore DCCR
+ move [_reg+0x66],usp ; Restore USP
+ jump [_reg+0x62] ; A jump to the content in register BRP works.
+ nop ;
+");
+
+/* The hook for an interrupt generated by GDB. An internal stack is used
+ by the stub. The register image of the caller is stored in the structure
+ register_image. Interactive communication with the host is handled by
+ handle_exception and finally the register image is restored. Due to the
+ old assembler which does not recognise the break instruction and the
+ breakpoint return pointer hex-code is used. */
+
+void kgdb_handle_serial(void);
+
+asm ("
+ .global _kgdb_handle_serial
+_kgdb_handle_serial:
+;;
+;; Response to a serial interrupt
+;;
+
+ move dccr,[_reg+0x5E] ; Save the flags in DCCR
+ di ; Disable interrupts
+ move.d r0,[_reg] ; Save R0
+ move.d r1,[_reg+0x04] ; Save R1
+ move.d r2,[_reg+0x08] ; Save R2
+ move.d r3,[_reg+0x0C] ; Save R3
+ move.d r4,[_reg+0x10] ; Save R4
+ move.d r5,[_reg+0x14] ; Save R5
+ move.d r6,[_reg+0x18] ; Save R6
+ move.d r7,[_reg+0x1C] ; Save R7
+ move.d r8,[_reg+0x20] ; Save R8
+ move.d r9,[_reg+0x24] ; Save R9
+ move.d r10,[_reg+0x28] ; Save R10
+ move.d r11,[_reg+0x2C] ; Save R11
+ move.d r12,[_reg+0x30] ; Save R12
+ move.d r13,[_reg+0x34] ; Save R13
+ move.d sp,[_reg+0x38] ; Save SP (R14)
+ move irp,[_reg+0x3c] ; Save the address in PC (R15)
+ clear.b [_reg+0x40] ; Clear P0
+ move vr,[_reg+0x41] ; Save special register P1,
+ clear.w [_reg+0x42] ; Clear P4
+ move ccr,[_reg+0x44] ; Save special register CCR
+ move mof,[_reg+0x46] ; P7
+ clear.d [_reg+0x4A] ; Clear P8
+ move ibr,[_reg+0x4E] ; P9,
+ move irp,[_reg+0x52] ; P10,
+ move srp,[_reg+0x56] ; P11,
+ move dtp0,[_reg+0x5A] ; P12, register BAR, assembler might not know BAR
+ ; P13, register DCCR already saved
+;; Due to the old assembler-versions BRP might not be recognized
+ .word 0xE670 ; move brp,r0
+ move.d r0,[_reg+0x62] ; Save the return address in BRP
+ move usp,[_reg+0x66] ; USP
+
+;; get the serial character (from debugport.c) and check if its a ctrl-c
+
+ jsr _getDebugChar
+ cmp.b 3, r10
+ bne goback
+ nop
+
+;;
+;; Handle the communication
+;;
+ move.d _internal_stack+1020,sp ; Use the internal stack
+ moveq 2,r10 ; SIGINT
+ jsr _handle_exception ; Interactive routine
+
+goback:
+;;
+;; Return to the caller
+;;
+ move.d [_reg],r0 ; Restore R0
+ move.d [_reg+0x04],r1 ; Restore R1
+ move.d [_reg+0x08],r2 ; Restore R2
+ move.d [_reg+0x0C],r3 ; Restore R3
+ move.d [_reg+0x10],r4 ; Restore R4
+ move.d [_reg+0x14],r5 ; Restore R5
+ move.d [_reg+0x18],r6 ; Restore R6
+ move.d [_reg+0x1C],r7 ; Restore R7
+ move.d [_reg+0x20],r8 ; Restore R8
+ move.d [_reg+0x24],r9 ; Restore R9
+ move.d [_reg+0x28],r10 ; Restore R10
+ move.d [_reg+0x2C],r11 ; Restore R11
+ move.d [_reg+0x30],r12 ; Restore R12
+ move.d [_reg+0x34],r13 ; Restore R13
+;;
+;; FIXME: Which registers should be restored?
+;;
+ move.d [_reg+0x38],sp ; Restore SP (R14)
+ move [_reg+0x56],srp ; Restore the subroutine return pointer.
+ move [_reg+0x5E],dccr ; Restore DCCR
+ move [_reg+0x66],usp ; Restore USP
+ reti ; Return from the interrupt routine
+ nop
+");
+
+/* Use this static breakpoint in the start-up only. */
+
+void
+breakpoint(void)
+{
+ kgdb_started = 1;
+ is_dyn_brkp = 0; /* This is a static, not a dynamic breakpoint. */
+ __asm__ volatile ("break 8"); /* Jump to handle_breakpoint. */
+}
+
+/* initialize kgdb. doesn't break into the debugger, but sets up irq and ports */
+
+void
+kgdb_init(void)
+{
+ /* could initialize debug port as well but it's done in head.S already... */
+
+ set_break_vector(8, kgdb_handle_breakpoint);
+ set_int_vector(8, kgdb_handle_serial, 0);
+
+ enableDebugIRQ();
+}
+
+/****************************** End of file **********************************/
diff --git a/arch/cris/kernel/ksyms.c b/arch/cris/kernel/ksyms.c
new file mode 100644
index 000000000..fa48796dc
--- /dev/null
+++ b/arch/cris/kernel/ksyms.c
@@ -0,0 +1,2 @@
+/* no kernel support yet */
+
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
new file mode 100644
index 000000000..901449879
--- /dev/null
+++ b/arch/cris/kernel/process.c
@@ -0,0 +1,327 @@
+/* $Id: process.c,v 1.8 2000/09/13 14:34:13 bjornw Exp $
+ *
+ * linux/arch/cris/kernel/process.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright (C) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/smp.h>
+
+//#define DEBUG
+
+/*
+ * Initial task structure. Make this a per-architecture thing,
+ * because different architectures tend to have different
+ * alignment requirements and potentially different initial
+ * setup.
+ */
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+
+union task_union init_task_union
+ __attribute__((__section__(".data.init_task"))) =
+ { INIT_TASK(init_task_union.task) };
+
+static int hlt_counter=0;
+
+/* in a system call, set_esp0 is called to remember the stack frame, therefore
+ in the implementation of syscalls we can use that value to access the stack
+ frame and saved registers.
+*/
+
+#define currentregs ((struct pt_regs *)current->thread.esp0)
+
+asmlinkage void set_esp0(unsigned long ssp)
+{
+ current->thread.esp0 = ssp;
+}
+
+void disable_hlt(void)
+{
+ hlt_counter++;
+}
+
+void enable_hlt(void)
+{
+ hlt_counter--;
+}
+
+int cpu_idle(void *unused)
+{
+ while(1) {
+ current->counter = -100;
+ schedule();
+ }
+}
+
+/* if the watchdog is enabled, we can simply disable interrupts and go
+ * into an eternal loop, and the watchdog will reset the CPU after 0.1s
+ */
+
+void hard_reset_now (void)
+{
+ printk("*** HARD RESET ***\n");
+ cli();
+ while(1) /* waiting for RETRIBUTION! */ ;
+}
+
+void machine_restart(void)
+{
+ hard_reset_now();
+}
+
+/* can't do much here... */
+
+void machine_halt(void)
+{
+}
+
+void machine_power_off(void)
+{
+}
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ register long __a __asm__ ("r10");
+
+ __asm__ __volatile__
+ ("movu.w %1,r1\n\t" /* r1 contains syscall number, to sys_clone */
+ "clear.d r10\n\t" /* r10 is argument 1 to clone */
+ "move.d %2,r11\n\t" /* r11 is argument 2 to clone, the flags */
+ "break 13\n\t" /* call sys_clone, this will fork */
+ "test.d r10\n\t" /* parent or child? child returns 0 here. */
+ "bne 1f\n\t" /* jump if parent */
+ "nop\n\t" /* delay slot */
+ "move.d %4,r10\n\t" /* set argument to function to call */
+ "jsr %5\n\t" /* call specified function */
+ "movu.w %3,r1\n\t" /* r1 is sys_exit syscall number */
+ "moveq -1,r10\n\t" /* Give a really bad exit-value */
+ "break 13\n\t" /* call sys_exit, killing the child */
+ "1:\n\t"
+ : "=r" (__a)
+ : "g" (__NR_clone), "r" (flags | CLONE_VM), "g" (__NR_exit),
+ "r" (arg), "r" (fn)
+ : "r10", "r11", "r1");
+
+ return __a;
+}
+
+
+
+void flush_thread(void)
+{
+}
+
+asmlinkage void ret_from_sys_call(void);
+
+/* setup the child's kernel stack with a pt_regs and switch_stack on it.
+ * it will be un-nested during _resume and _ret_from_sys_call when the
+ * new thread is scheduled.
+ *
+ * also setup the thread switching structure which is used to keep
+ * thread-specific data during _resumes.
+ *
+ */
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ unsigned long unused,
+ struct task_struct *p, struct pt_regs *regs)
+{
+ struct pt_regs * childregs;
+ struct switch_stack *swstack;
+
+ /* put the pt_regs structure at the end of the new kernel stack page and fix it up
+ * remember that the task_struct doubles as the kernel stack for the task
+ */
+
+ childregs = ((struct pt_regs *) ((unsigned long)p + THREAD_SIZE)) - 1;
+
+ *childregs = *regs; /* struct copy of pt_regs */
+
+ childregs->r10 = 0; /* child returns 0 after a fork/clone */
+
+ /* put the switch stack right below the pt_regs */
+
+ swstack = ((struct switch_stack *)childregs) - 1;
+
+ swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */
+
+ /* we want to return into ret_from_sys_call after the _resume */
+
+ swstack->return_ip = (unsigned long) ret_from_sys_call;
+
+ /* fix the user-mode stackpointer */
+
+ p->thread.usp = usp;
+
+ /* and the kernel-mode one */
+
+ p->thread.ksp = (unsigned long) swstack;
+
+ /* esp0 keeps the pt_regs stacked structure pointer */
+
+ p->thread.esp0 = (unsigned long) childregs;
+
+#ifdef DEBUG
+ printk("kern_stack_page 0x%x, used stack %d, thread.usp 0x%x, usp 0x%x\n",
+ current->kernel_stack_page, usedstack, p->thread.usp, usp);
+#endif
+ return 0;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+ int i;
+#if 0
+/* changed the size calculations - should hopefully work better. lbt */
+ dump->magic = CMAGIC;
+ dump->start_code = 0;
+ dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
+ dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
+ dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
+ dump->u_dsize -= dump->u_tsize;
+ dump->u_ssize = 0;
+ for (i = 0; i < 8; i++)
+ dump->u_debugreg[i] = current->debugreg[i];
+
+ if (dump->start_stack < TASK_SIZE)
+ dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
+
+ dump->regs = *regs;
+
+ dump->u_fpvalid = dump_fpu (regs, &dump->i387);
+#endif
+}
+
+asmlinkage int sys_fork(void)
+{
+ return do_fork(SIGCHLD, rdusp(), currentregs, 0);
+}
+
+/* if newusp is 0, we just grab the old usp */
+
+asmlinkage int sys_clone(unsigned long newusp, unsigned long flags)
+{
+ if (!newusp)
+ newusp = rdusp();
+ return do_fork(flags, newusp, currentregs, 0);
+}
+
+/* vfork is a system call in i386 because of register-pressure - maybe
+ * we can remove it and handle it in libc but we put it here until then.
+ */
+
+asmlinkage int sys_vfork(void)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), currentregs, 0);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(const char *fname, char **argv, char **envp)
+{
+ int error;
+ char *filename;
+
+ filename = getname(fname);
+ error = PTR_ERR(filename);
+
+ if (IS_ERR(filename))
+ goto out;
+ error = do_execve(filename, argv, envp, currentregs);
+ putname(filename);
+ out:
+ return error;
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched ((unsigned long) scheduling_functions_start_here)
+#define last_sched ((unsigned long) scheduling_functions_end_here)
+
+unsigned long get_wchan(struct task_struct *p)
+{
+#if 0
+ /* YURGH. TODO. */
+
+ unsigned long ebp, esp, eip;
+ unsigned long stack_page;
+ int count = 0;
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+ stack_page = (unsigned long)p;
+ esp = p->thread.esp;
+ if (!stack_page || esp < stack_page || esp > 8188+stack_page)
+ return 0;
+ /* include/asm-i386/system.h:switch_to() pushes ebp last. */
+ ebp = *(unsigned long *) esp;
+ do {
+ if (ebp < stack_page || ebp > 8184+stack_page)
+ return 0;
+ eip = *(unsigned long *) (ebp+4);
+ if (eip < first_sched || eip >= last_sched)
+ return eip;
+ ebp = *(unsigned long *) ebp;
+ } while (count++ < 16);
+#endif
+ return 0;
+}
+#undef last_sched
+#undef first_sched
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c
new file mode 100644
index 000000000..384952211
--- /dev/null
+++ b/arch/cris/kernel/ptrace.c
@@ -0,0 +1,340 @@
+/*
+ * linux/arch/cris/kernel/ptrace.c
+ *
+ * Parts taken from the m68k port.
+ *
+ * Copyright (c) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen
+ *
+ * $Log: ptrace.c,v $
+ * Revision 1.3 2000/12/18 23:45:25 bjornw
+ * Linux/CRIS first version
+ *
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which bits in DCCR the user has access to. */
+/* 1 = access 0 = no access */
+#define DCCR_MASK 0x0000001f /* XNZVC */
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, unsigned int regno)
+{
+ /* USP is a special case, it's not in the pt_regs struct but
+ * in the tasks thread struct
+ */
+
+ if (regno == PT_USP)
+ return task->thread.usp;
+ else if (regno <= PT_MAX)
+ return ((unsigned long *)(task->thread.esp0))[regno];
+ else
+ return 0;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int put_reg(struct task_struct *task, unsigned int regno,
+ unsigned long data)
+{
+ unsigned long *addr;
+
+ if (regno == PT_USP)
+ task->thread.usp = data;
+ else if (regno <= PT_MAX)
+ ((unsigned long *)(task->thread.esp0))[regno] = data;
+ else
+ return -1;
+ return 0;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+ struct task_struct *child;
+ int ret;
+
+ lock_kernel();
+ ret = -EPERM;
+ if (request == PTRACE_TRACEME) {
+ /* are we already being traced? */
+ if (current->ptrace & PT_PTRACED)
+ goto out;
+ /* set the ptrace bit in the process flags. */
+ current->ptrace |= PT_PTRACED;
+ ret = 0;
+ goto out;
+ }
+ ret = -ESRCH;
+ read_lock(&tasklist_lock);
+ child = find_task_by_pid(pid);
+ if (child)
+ get_task_struct(child);
+ read_unlock(&tasklist_lock);
+ if (!child)
+ goto out;
+ ret = -EPERM;
+ if (pid == 1) /* you may not mess with init */
+ goto out_tsk;
+ if (request == PTRACE_ATTACH) {
+ if (child == current)
+ goto out_tsk;
+ if ((!child->dumpable ||
+ (current->uid != child->euid) ||
+ (current->uid != child->suid) ||
+ (current->uid != child->uid) ||
+ (current->gid != child->egid) ||
+ (current->gid != child->sgid) ||
+ (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
+ (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+ goto out_tsk;
+ /* the same process cannot be attached many times */
+ if (child->ptrace & PT_PTRACED)
+ goto out_tsk;
+ child->ptrace |= PT_PTRACED;
+
+ write_lock_irq(&tasklist_lock);
+ if (child->p_pptr != current) {
+ REMOVE_LINKS(child);
+ child->p_pptr = current;
+ SET_LINKS(child);
+ }
+ write_unlock_irq(&tasklist_lock);
+
+ send_sig(SIGSTOP, child, 1);
+ ret = 0;
+ goto out_tsk;
+ }
+ ret = -ESRCH;
+ if (!(child->ptrace & PT_PTRACED))
+ goto out_tsk;
+ if (child->state != TASK_STOPPED) {
+ if (request != PTRACE_KILL)
+ goto out_tsk;
+ }
+ if (child->p_pptr != current)
+ goto out_tsk;
+
+ switch (request) {
+ /* when I and D space are separate, these will need to be fixed. */
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA: {
+ unsigned long tmp;
+ int copied;
+
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ ret = -EIO;
+ if (copied != sizeof(tmp))
+ break;
+ ret = put_user(tmp,(unsigned long *) data);
+ break;
+ }
+
+ /* read the word at location addr in the USER area. */
+ case PTRACE_PEEKUSR: {
+ unsigned long tmp;
+
+ ret = -EIO;
+ if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+ break;
+
+ tmp = 0; /* Default return condition */
+ ret = -EIO;
+ if (addr < sizeof(struct pt_regs)) {
+ tmp = get_reg(child, addr >> 2);
+ ret = put_user(tmp, (unsigned long *)data);
+ }
+ break;
+ }
+
+ /* when I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ ret = 0;
+ if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+ break;
+ ret = -EIO;
+ break;
+
+ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ ret = -EIO;
+ if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+ break;
+
+ if (addr < sizeof(struct pt_regs)) {
+ addr >>= 2;
+
+ if (addr == PT_DCCR) {
+ /* don't allow the tracing process to change stuff like
+ * interrupt enable, kernel/user bit, dma enables etc.
+ */
+ data &= DCCR_MASK;
+ data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
+ }
+ if (put_reg(child, addr, data))
+ break;
+ ret = 0;
+ }
+ break;
+
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: { /* restart after signal. */
+ long tmp;
+
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+ if (request == PTRACE_SYSCALL)
+ child->ptrace |= PT_TRACESYS;
+ else
+ child->ptrace &= ~PT_TRACESYS;
+ child->exit_code = data;
+ /* TODO: make sure any pending breakpoint is killed */
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
+
+/*
+ * make the child exit. Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
+ * exit.
+ */
+ case PTRACE_KILL: {
+ long tmp;
+
+ ret = 0;
+ if (child->state == TASK_ZOMBIE) /* already dead */
+ break;
+ child->exit_code = SIGKILL;
+ /* TODO: make sure any pending breakpoint is killed */
+ wake_up_process(child);
+ break;
+ }
+
+ case PTRACE_SINGLESTEP: { /* set the trap flag. */
+ long tmp;
+
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+ child->ptrace &= ~PT_TRACESYS;
+
+ /* TODO: set some clever breakpoint mechanism... */
+
+ child->exit_code = data;
+ /* give it a chance to run. */
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
+
+ case PTRACE_DETACH: { /* detach a process that was attached. */
+ long tmp;
+
+ ret = -EIO;
+ if ((unsigned long) data > _NSIG)
+ break;
+ child->ptrace &= ~(PT_PTRACED | PT_TRACESYS);
+ child->exit_code = data;
+ write_lock_irq(&tasklist_lock);
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ write_unlock_irq(&tasklist_lock);
+ /* TODO: make sure any pending breakpoint is killed */
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
+
+ case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+ int i;
+ unsigned long tmp;
+ for (i = 0; i <= PT_MAX; i++) {
+ tmp = get_reg(child, i);
+ if (put_user(tmp, (unsigned long *) data)) {
+ ret = -EFAULT;
+ break;
+ }
+ data += sizeof(long);
+ }
+ ret = 0;
+ break;
+ }
+
+ case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+ int i;
+ unsigned long tmp;
+ for (i = 0; i <= PT_MAX; i++) {
+ if (get_user(tmp, (unsigned long *) data)) {
+ ret = -EFAULT;
+ break;
+ }
+ if (i == PT_DCCR) {
+ tmp &= DCCR_MASK;
+ tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
+ }
+ put_reg(child, i, tmp);
+ data += sizeof(long);
+ }
+ ret = 0;
+ break;
+ }
+
+ default:
+ ret = -EIO;
+ break;
+ }
+out_tsk:
+ free_task_struct(child);
+out:
+ unlock_kernel();
+ return ret;
+}
+
+asmlinkage void syscall_trace(void)
+{
+ if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) !=
+ (PT_PTRACED | PT_TRACESYS))
+ return;
+ /* TODO: make a way to distinguish between a syscall stop and SIGTRAP
+ * delivery like in the i386 port ?
+ */
+ current->exit_code = SIGTRAP;
+ current->state = TASK_STOPPED;
+ notify_parent(current, SIGCHLD);
+ schedule();
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+ * for normal use. strace only continues with a signal if the
+ * stopping signal is not SIGTRAP. -brl
+ */
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
+}
diff --git a/arch/cris/kernel/semaphore.c b/arch/cris/kernel/semaphore.c
new file mode 100644
index 000000000..5a9478f03
--- /dev/null
+++ b/arch/cris/kernel/semaphore.c
@@ -0,0 +1,238 @@
+/*
+ * Generic semaphore code. Buyer beware. Do your own
+ * specific changes in <asm/semaphore-helper.h>
+ */
+
+#include <linux/sched.h>
+#include <asm/semaphore-helper.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit. ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore. The others will go back
+ * to sleep.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+void __up(struct semaphore *sem)
+{
+ wake_one_more(sem);
+ wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function. Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible. This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return. If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+#define DOWN_VAR \
+ struct task_struct *tsk = current; \
+ wait_queue_t wait; \
+ init_waitqueue_entry(&wait, tsk);
+
+#define DOWN_HEAD(task_state) \
+ \
+ \
+ tsk->state = (task_state); \
+ add_wait_queue(&sem->wait, &wait); \
+ \
+ /* \
+ * Ok, we're set up. sem->count is known to be less than zero \
+ * so we must wait. \
+ * \
+ * We can let go the lock for purposes of waiting. \
+ * We re-acquire it after awaking so as to protect \
+ * all semaphore operations. \
+ * \
+ * If "up()" is called before we call waking_non_zero() then \
+ * we will catch it right away. If it is called later then \
+ * we will have to go through a wakeup cycle to catch it. \
+ * \
+ * Multiple waiters contend for the semaphore lock to see \
+ * who gets to gate through and who has to wait some more. \
+ */ \
+ for (;;) {
+
+#define DOWN_TAIL(task_state) \
+ tsk->state = (task_state); \
+ } \
+ tsk->state = TASK_RUNNING; \
+ remove_wait_queue(&sem->wait, &wait);
+
+void __down(struct semaphore * sem)
+{
+ DOWN_VAR
+ DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+ if (waking_non_zero(sem))
+ break;
+ schedule();
+ DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __down_interruptible(struct semaphore * sem)
+{
+ int ret = 0;
+ DOWN_VAR
+ DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+ ret = waking_non_zero_interruptible(sem, tsk);
+ if (ret)
+ {
+ if (ret == 1)
+ /* ret != 0 only if we get interrupted -arca */
+ ret = 0;
+ break;
+ }
+ schedule();
+ DOWN_TAIL(TASK_INTERRUPTIBLE)
+ return ret;
+}
+
+int __down_trylock(struct semaphore * sem)
+{
+ return waking_non_zero_trylock(sem);
+}
+
+/*
+ * RW Semaphores
+ */
+void
+__down_read(struct rw_semaphore *sem, int count)
+{
+ DOWN_VAR;
+
+ retry_down:
+ if (count < 0) {
+ /* Wait for the lock to become unbiased. Readers
+ are non-exclusive. */
+
+ /* This takes care of granting the lock. */
+ up_read(sem);
+
+ add_wait_queue(&sem->wait, &wait);
+ while (atomic_read(&sem->count) < 0) {
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (atomic_read(&sem->count) >= 0)
+ break;
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+
+ mb();
+ count = atomic_dec_return(&sem->count);
+ if (count <= 0)
+ goto retry_down;
+ } else {
+ add_wait_queue(&sem->wait, &wait);
+
+ while (1) {
+ if (test_and_clear_bit(0, &sem->granted))
+ break;
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if ((sem->granted & 1) == 0)
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+ }
+}
+
+void
+__down_write(struct rw_semaphore *sem, int count)
+{
+ DOWN_VAR;
+
+ retry_down:
+ if (count + RW_LOCK_BIAS < 0) {
+ up_write(sem);
+
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ while (atomic_read(&sem->count) < 0) {
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (atomic_read(&sem->count) >= RW_LOCK_BIAS)
+ break;
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+
+ mb();
+ count = atomic_sub_return(RW_LOCK_BIAS, &sem->count);
+ if (count != 0)
+ goto retry_down;
+ } else {
+ /* Put ourselves at the end of the list. */
+ add_wait_queue_exclusive(&sem->write_bias_wait, &wait);
+
+ while (1) {
+ if (test_and_clear_bit(1, &sem->granted))
+ break;
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if ((sem->granted & 2) == 0)
+ schedule();
+ }
+
+ remove_wait_queue(&sem->write_bias_wait, &wait);
+ tsk->state = TASK_RUNNING;
+
+ /* If the lock is currently unbiased, awaken the sleepers.
+ FIXME: This wakes up the readers early in a bit of a
+ stampede -> bad! */
+ if (atomic_read(&sem->count) >= 0)
+ wake_up(&sem->wait);
+ }
+}
+
+void
+__rwsem_wake(struct rw_semaphore *sem, unsigned long readers)
+{
+ if (readers) {
+ if (test_and_set_bit(0, &sem->granted))
+ BUG();
+ wake_up(&sem->wait);
+ } else {
+ if (test_and_set_bit(1, &sem->granted))
+ BUG();
+ wake_up(&sem->write_bias_wait);
+ }
+}
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c
new file mode 100644
index 000000000..ff7b3e6ac
--- /dev/null
+++ b/arch/cris/kernel/setup.c
@@ -0,0 +1,264 @@
+/* $Id: setup.c,v 1.8 2001/01/16 16:31:38 bjornw Exp $
+ *
+ * linux/arch/cris/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright (c) 2000 Axis Communications AB
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+#include <asm/types.h>
+#include <asm/svinto.h>
+
+/*
+ * Setup options
+ */
+struct drive_info_struct { char dummy[32]; } drive_info;
+struct screen_info screen_info;
+
+unsigned char aux_device_present;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start; /* starting block # of image */
+#endif
+
+extern int root_mountflags;
+extern char _etext, _edata, _end;
+
+#define COMMAND_LINE_SIZE 256
+
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+ char saved_command_line[COMMAND_LINE_SIZE];
+
+extern const unsigned long text_start, edata; /* set by the linker script */
+
+extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S */
+
+/* This mainly sets up the memory area, and can be really confusing.
+ *
+ * The physical DRAM is virtually mapped into dram_start to dram_end
+ * (usually c0000000 to c0000000 + DRAM size). The physical address is
+ * given by the macro __pa().
+ *
+ * In this DRAM, the kernel code and data is loaded, in the beginning.
+ * It really starts at c00a0000 to make room for some special pages -
+ * the start address is text_start. The kernel data ends at _end. After
+ * this the ROM filesystem is appended (if there is any).
+ *
+ * Between this address and dram_end, we have RAM pages usable to the
+ * boot code and the system.
+ *
+ */
+
+void __init setup_arch(char **cmdline_p)
+{
+ unsigned long bootmap_size;
+ unsigned long start_pfn, max_pfn;
+ unsigned long memory_start;
+ extern void console_print_etrax(const char *b);
+
+#if (defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH))
+ /* TODO: move this into flash_init I think */
+ flash_probe();
+#endif
+
+ /* register an initial console printing routine for printk's */
+
+ init_etrax_debug();
+
+ /* we should really poll for DRAM size! */
+
+ high_memory = &dram_end;
+
+ if(romfs_in_flash || !romfs_length) {
+ /* if we have the romfs in flash, or if there is no rom filesystem,
+ * our free area starts directly after the BSS
+ */
+ memory_start = (unsigned long) &_end;
+ } else {
+ /* otherwise the free area starts after the ROM filesystem */
+ printk("ROM fs in RAM, size %d bytes\n", romfs_length);
+ memory_start = romfs_start + romfs_length;
+ }
+
+ /* process 1's initial memory region is the kernel code/data */
+
+ init_mm.start_code = (unsigned long) &text_start;
+ init_mm.end_code = (unsigned long) &_etext;
+ init_mm.end_data = (unsigned long) &_edata;
+ init_mm.brk = (unsigned long) &_end;
+
+#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
+
+ /* min_low_pfn points to the start of DRAM, start_pfn points
+ * to the first DRAM pages after the kernel, and max_low_pfn
+ * to the end of DRAM.
+ */
+
+ /*
+ * partially used pages are not usable - thus
+ * we are rounding upwards:
+ */
+
+ start_pfn = PFN_UP(memory_start); /* usually c0000000 + kernel + romfs */
+ max_pfn = PFN_DOWN((unsigned long)high_memory); /* usually c0000000 + dram size */
+
+ /*
+ * Initialize the boot-time allocator (start, end)
+ *
+ * We give it access to all our DRAM, but we could as well just have
+ * given it a small slice. No point in doing that though, unless we
+ * have non-contiguous memory and want the boot-stuff to be in, say,
+ * the smallest area.
+ *
+ * It will put a bitmap of the allocated pages in the beginning
+ * of the range we give it, but it won't mark the bitmaps pages
+ * as reserved. We have to do that ourselves below.
+ *
+ * We need to use init_bootmem_node instead of init_bootmem
+ * because our map starts at a quite high address (min_low_pfn).
+ */
+
+ max_low_pfn = max_pfn;
+ min_low_pfn = PAGE_OFFSET >> PAGE_SHIFT;
+
+ bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
+ min_low_pfn,
+ max_low_pfn);
+
+ /* And free all memory not belonging to the kernel (addr, size) */
+
+ free_bootmem(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn - start_pfn));
+
+ /*
+ * Reserve the bootmem bitmap itself as well. We do this in two
+ * steps (first step was init_bootmem()) because this catches
+ * the (very unlikely) case of us accidentally initializing the
+ * bootmem allocator with an invalid RAM area.
+ *
+ * Arguments are start, size
+ */
+
+ reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size);
+
+ /* paging_init() sets up the MMU and marks all pages as reserved */
+
+ paging_init();
+
+ /* we dont use a command line yet, so just let it be an empty string */
+
+ *cmdline_p = command_line;
+ strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */
+
+ /* give credit for the CRIS port */
+
+ printk("Linux/CRIS port on ETRAX 100LX (c) 2000 Axis Communications AB\n");
+
+}
+
+#ifdef CONFIG_PROC_FS
+#define HAS_FPU 0x0001
+#define HAS_MMU 0x0002
+#define HAS_ETHERNET100 0x0004
+#define HAS_TOKENRING 0x0008
+#define HAS_SCSI 0x0010
+#define HAS_ATA 0x0020
+#define HAS_USB 0x0040
+#define HAS_IRQ_BUG 0x0080
+
+static struct cpu_info {
+ char *model;
+ unsigned short cache;
+ unsigned short flags;
+} cpu_info[] = {
+ { "ETRAX 1", 0, 0 },
+ { "ETRAX 2", 0, 0 }, /* Don't say it HAS_TOKENRING - there are
+ lethal bugs in that chip that
+ prevents T-R from ever working.
+ Never go there, and never lead anyone
+ into believing it can work. BTW:
+ Anyone working on a T-R network
+ driver? :-) :-) :-) :-/ */
+ { "ETRAX 3", 0, HAS_TOKENRING },
+ { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI },
+ { "Unknown", 0, 0 },
+ { "Unknown", 0, 0 },
+ { "Unknown", 0, 0 },
+ { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
+ { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG },
+ { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA },
+ { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU },
+ { "Unknown", 0, 0 },
+};
+
+/*
+ * BUFFER is PAGE_SIZE bytes long.
+ */
+int get_cpuinfo(char *buffer)
+{
+ int revision;
+#ifndef CONFIG_SVINTO_SIM
+ unsigned char tmp;
+
+ __asm__ volatile ("move vr,%0" : "=rm" (tmp));
+ revision = tmp;
+#else
+ /* Fake a revision for the simulator */
+ revision = 7;
+#endif
+
+ return sprintf(buffer,
+ "cpu\t\t: CRIS\n"
+ "cpu revision\t: %d\n"
+ "cpu model\t: %s\n"
+ "cache size\t: %d kB\n"
+ "fpu\t\t: %s\n"
+ "mmu\t\t: %s\n"
+ "ethernet\t: %s Mbps\n"
+ "token ring\t: %s\n"
+ "scsi\t\t: %s\n"
+ "ata\t\t: %s\n"
+ "usb\t\t: %s\n"
+ "bogomips\t: %lu.%02lu\n",
+
+ revision,
+ cpu_info[revision].model,
+ cpu_info[revision].cache,
+ cpu_info[revision].flags & HAS_FPU ? "yes" : "no",
+ cpu_info[revision].flags & HAS_MMU ? "yes" : "no",
+ cpu_info[revision].flags & HAS_ETHERNET100 ? "10/100" : "10",
+ cpu_info[revision].flags & HAS_TOKENRING ? "4/16 Mbps" : "no",
+ cpu_info[revision].flags & HAS_SCSI ? "yes" : "no",
+ cpu_info[revision].flags & HAS_ATA ? "yes" : "no",
+ cpu_info[revision].flags & HAS_USB ? "yes" : "no",
+ (loops_per_jiffy * HZ + 500) / 100000,
+ ((loops_per_jiffy * HZ + 500) / 1000) % 100);
+}
+#endif /* CONFIG_PROC_FS */
diff --git a/arch/cris/kernel/shadows.c b/arch/cris/kernel/shadows.c
new file mode 100644
index 000000000..0a6449f4c
--- /dev/null
+++ b/arch/cris/kernel/shadows.c
@@ -0,0 +1,20 @@
+/* $Id: shadows.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $
+ *
+ * Various Etrax shadow registers. Defines for these are in include/asm-etrax100/io.h
+ */
+
+#include <linux/config.h>
+
+unsigned long genconfig_shadow = 42;
+unsigned long port_g_data_shadow = 42;
+unsigned char port_pa_dir_shadow = 42;
+unsigned char port_pa_data_shadow = 42;
+unsigned char port_pb_i2c_shadow = 42;
+unsigned char port_pb_config_shadow = 42;
+unsigned char port_pb_dir_shadow = 42;
+unsigned char port_pb_data_shadow = 42;
+unsigned long r_timer_ctrl_shadow = 42;
+
+#ifdef CONFIG_ETRAX_90000000_LEDS
+unsigned long port_90000000_shadow = 42;
+#endif
diff --git a/arch/cris/kernel/signal.c b/arch/cris/kernel/signal.c
new file mode 100644
index 000000000..8aab31a45
--- /dev/null
+++ b/arch/cris/kernel/signal.c
@@ -0,0 +1,667 @@
+/*
+ * linux/arch/cris/kernel/signal.c
+ *
+ * Based on arch/i386/kernel/signal.c by
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson *
+ *
+ * Ideas also taken from arch/arm.
+ *
+ * Copyright (C) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+
+#include <asm/processor.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */
+/* manipulate regs so that upon return, it will be re-executed */
+
+#define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2;
+
+int sys_wait4(pid_t pid, unsigned long *stat_addr,
+ int options, unsigned long *ru);
+
+int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs);
+
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+int
+sys_sigsuspend(old_sigset_t mask)
+{
+ struct pt_regs * regs = (struct pt_regs *)current_regs();
+ sigset_t saveset;
+
+ mask &= _BLOCKABLE;
+ spin_lock_irq(&current->sigmask_lock);
+ saveset = current->blocked;
+ siginitset(&current->blocked, mask);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ regs->r10 = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(0, &saveset, regs))
+ return -EINTR;
+ }
+}
+
+int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
+{
+ struct pt_regs * regs = (struct pt_regs *)current_regs();
+ sigset_t saveset, newset;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user(&newset, unewset, sizeof(newset)))
+ return -EFAULT;
+ sigdelsetmask(&newset, ~_BLOCKABLE);
+
+ spin_lock_irq(&current->sigmask_lock);
+ saveset = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ regs->r10 = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(0, &saveset, regs))
+ return -EINTR;
+ }
+}
+
+int
+sys_sigaction(int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ return -EFAULT;
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+ return do_sigaltstack(uss, uoss, rdusp());
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe {
+ struct sigcontext sc;
+ unsigned long extramask[_NSIG_WORDS-1];
+ unsigned char retcode[8]; /* trampoline code */
+};
+
+struct rt_sigframe {
+ struct siginfo *pinfo;
+ void *puc;
+ struct siginfo info;
+ struct ucontext uc;
+ unsigned char retcode[8]; /* trampoline code */
+};
+
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+{
+ unsigned int err = 0;
+ unsigned long old_usp;
+
+ /* restore the regs from &sc->regs (same as sc, since regs is first)
+ * (sc is already checked for VERIFY_READ since the sigframe was
+ * checked in sys_sigreturn previously)
+ */
+
+ if (__copy_from_user(regs, sc, sizeof(struct pt_regs)))
+ goto badframe;
+
+ /* make sure the U-flag is set so user-mode cannot fool us */
+
+ regs->dccr |= 1 << 8;
+
+ /* restore the old USP as it was before we stacked the sc etc.
+ * (we cannot just pop the sigcontext since we aligned the sp and
+ * stuff after pushing it)
+ */
+
+ err |= __get_user(old_usp, &sc->usp);
+
+ wrusp(old_usp);
+
+ /* TODO: the other ports use regs->orig_XX to disable syscall checks
+ * after this completes, but we don't use that mechanism. maybe we can
+ * use it now ?
+ */
+
+ return err;
+
+badframe:
+ return 1;
+}
+
+asmlinkage int sys_sigreturn(void)
+{
+ struct pt_regs *regs = (struct pt_regs *)current_regs();
+ struct sigframe *frame = (struct sigframe *)rdusp();
+ sigset_t set;
+
+ /*
+ * Since we stacked the signal on a dword boundary,
+ * then frame should be dword aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ if (((long)frame) & 3)
+ goto badframe;
+
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__get_user(set.sig[0], &frame->sc.oldmask)
+ || (_NSIG_WORDS > 1
+ && __copy_from_user(&set.sig[1], &frame->extramask,
+ sizeof(frame->extramask))))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ if (restore_sigcontext(regs, &frame->sc))
+ goto badframe;
+
+ /* TODO: SIGTRAP when single-stepping as in arm ? */
+
+ return regs->r10;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+asmlinkage int sys_rt_sigreturn(void)
+{
+ struct pt_regs *regs = (struct pt_regs *)current_regs();
+ struct rt_sigframe *frame = (struct rt_sigframe *)rdusp();
+ sigset_t set;
+ stack_t st;
+
+ /*
+ * Since we stacked the signal on a dword boundary,
+ * then frame should be dword aligned here. If it's
+ * not, then the user is trying to mess with us.
+ */
+ if (((long)frame) & 3)
+ goto badframe;
+
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+ goto badframe;
+
+ if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+ goto badframe;
+ /* It is more difficult to avoid calling this function than to
+ call it and ignore errors. */
+ do_sigaltstack(&st, NULL, rdusp());
+
+ return regs->r10;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask)
+{
+ int err = 0;
+ unsigned long usp = rdusp();
+
+ /* copy the regs. they are first in sc so we can use sc directly */
+
+ err |= __copy_to_user(sc, regs, sizeof(struct pt_regs));
+
+ /* then some other stuff */
+
+ err |= __put_user(mask, &sc->oldmask);
+
+ err |= __put_user(usp, &sc->usp);
+
+ return err;
+}
+
+/* figure out where we want to put the new signal frame - usually on the stack */
+
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+ unsigned long sp = rdusp();
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (! on_sig_stack(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+ }
+
+ /* make sure the frame is dword-aligned */
+
+ sp &= ~3;
+
+ return (void *)(sp - frame_size);
+}
+
+/* grab and setup a signal frame.
+ *
+ * basically we stack a lot of state info, and arrange for the
+ * user-mode program to return to the kernel using either a
+ * trampoline which performs the syscall sigreturn, or a provided
+ * user-mode trampoline.
+ */
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs * regs)
+{
+ struct sigframe *frame;
+ unsigned long return_ip;
+ int err = 0;
+
+ frame = get_sigframe(ka, regs, sizeof(*frame));
+
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+ if (err)
+ goto give_sigsegv;
+
+ if (_NSIG_WORDS > 1) {
+ err |= __copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
+ }
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ return_ip = (unsigned long)ka->sa.sa_restorer;
+ } else {
+ /* trampoline - the desired return ip is the retcode itself */
+ return_ip = (unsigned long)&frame->retcode;
+ /* This is movu.w __NR_sigreturn, r1; break 13; */
+ /* TODO: check byteorder */
+ err |= __put_user(0x1c5f, (short *)(frame->retcode+0));
+ err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2));
+ err |= __put_user(0xe93d, (short *)(frame->retcode+4));
+ }
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up registers for signal handler */
+
+ regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */
+ regs->srp = return_ip; /* what we enter LATER */
+
+ /* actually move the usp to reflect the stacked frame */
+
+ wrusp((unsigned long)frame);
+
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs * regs)
+{
+ struct rt_sigframe *frame;
+ unsigned long return_ip;
+ int err = 0;
+
+ frame = get_sigframe(ka, regs, sizeof(*frame));
+
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ err |= __put_user(&frame->info, &frame->pinfo);
+ err |= __put_user(&frame->uc, &frame->puc);
+ err |= copy_siginfo_to_user(&frame->info, info);
+ if (err)
+ goto give_sigsegv;
+
+ /* Clear all the bits of the ucontext we don't use. */
+ err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
+
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ return_ip = (unsigned long)ka->sa.sa_restorer;
+ } else {
+ /* trampoline - the desired return ip is the retcode itself */
+ return_ip = (unsigned long)&frame->retcode;
+ /* This is movu.w __NR_sigreturn, r1; break 13; */
+ /* TODO: check byteorder */
+ err |= __put_user(0x1c5f, (short *)(frame->retcode+0));
+ err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2));
+ err |= __put_user(0xe93d, (short *)(frame->retcode+4));
+ }
+
+ if (err)
+ goto give_sigsegv;
+
+ /* TODO what is the current->exec_domain stuff and invmap ? */
+
+ /* Set up registers for signal handler */
+
+ regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */
+ regs->srp = return_ip; /* what we enter LATER */
+
+ /* actually move the usp to reflect the stacked frame */
+
+ wrusp((unsigned long)frame);
+
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+static inline void
+handle_signal(int canrestart, unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+{
+ /* Are we from a system call? */
+ if (canrestart) {
+ /* If so, check system call restarting.. */
+ switch (regs->r10) {
+ case -ERESTARTNOHAND:
+ /* ERESTARTNOHAND means that the syscall should only be
+ restarted if there was no handler for the signal, and since
+ we only get here if there is a handler, we dont restart */
+ regs->r10 = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ /* ERESTARTSYS means to restart the syscall if there is no
+ handler or the handler was registered with SA_RESTART */
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ regs->r10 = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ /* ERESTARTNOINTR means that the syscall should be called again
+ after the signal handler returns. */
+ RESTART_CRIS_SYS(regs);
+ }
+ }
+
+ /* Set up the stack frame */
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(sig, ka, info, oldset, regs);
+ else
+ setup_frame(sig, ka, oldset, regs);
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+
+ if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ spin_lock_irq(&current->sigmask_lock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ }
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
+{
+ siginfo_t info;
+ struct k_sigaction *ka;
+
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (!user_mode(regs))
+ return 1;
+
+ if (!oldset)
+ oldset = &current->blocked;
+
+ for (;;) {
+ unsigned long signr;
+
+ spin_lock_irq(&current->sigmask_lock);
+ signr = dequeue_signal(&current->blocked, &info);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ if (!signr)
+ break;
+
+ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+ /* Let the debugger run. */
+ current->exit_code = signr;
+ current->state = TASK_STOPPED;
+ notify_parent(current, SIGCHLD);
+ schedule();
+
+ /* We're back. Did the debugger cancel the sig? */
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+
+ /* The debugger continued. Ignore SIGSTOP. */
+ if (signr == SIGSTOP)
+ continue;
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(&current->blocked, signr)) {
+ send_sig_info(signr, &info, current);
+ continue;
+ }
+ }
+
+ ka = &current->sig->action[signr-1];
+ if (ka->sa.sa_handler == SIG_IGN) {
+ if (signr != SIGCHLD)
+ continue;
+ /* Check for SIGCHLD: it's special. */
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ /* nothing */;
+ continue;
+ }
+
+ if (ka->sa.sa_handler == SIG_DFL) {
+ int exit_code = signr;
+
+ /* Init gets no signals it doesn't want. */
+ if (current->pid == 1)
+ continue;
+
+ switch (signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
+ continue;
+
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ /* FALLTHRU */
+
+ case SIGSTOP:
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+ notify_parent(current, SIGCHLD);
+ schedule();
+ continue;
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV:
+ case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ:
+ if (do_coredump(signr, regs))
+ exit_code |= 0x80;
+ /* FALLTHRU */
+
+ default:
+ lock_kernel();
+ sigaddset(&current->pending.signal, signr);
+ recalc_sigpending(current);
+ current->flags |= PF_SIGNALED;
+ do_exit(exit_code);
+ /* NOTREACHED */
+ }
+ }
+
+ /* Whee! Actually deliver the signal. */
+ handle_signal(canrestart, signr, ka, &info, oldset, regs);
+ return 1;
+ }
+
+ /* Did we come from a system call? */
+ if (canrestart) {
+ /* Restart the system call - no handlers present */
+ if (regs->r10 == -ERESTARTNOHAND ||
+ regs->r10 == -ERESTARTSYS ||
+ regs->r10 == -ERESTARTNOINTR) {
+ RESTART_CRIS_SYS(regs);
+ }
+ }
+ return 0;
+}
diff --git a/arch/cris/kernel/sys_cris.c b/arch/cris/kernel/sys_cris.c
new file mode 100644
index 000000000..cfcb097f9
--- /dev/null
+++ b/arch/cris/kernel/sys_cris.c
@@ -0,0 +1,201 @@
+/* $Id: sys_cris.c,v 1.3 2000/08/02 13:59:02 bjornw Exp $
+ *
+ * linux/arch/cris/kernel/sys_etrax.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on some platforms.
+ * Since we don't have to do any backwards compatibility, our
+ * versions are done in the most "normal" way possible.
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+#include <asm/segment.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way Unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+ int fd[2];
+ int error;
+
+ lock_kernel();
+ error = do_pipe(fd);
+ unlock_kernel();
+ if (!error) {
+ if (copy_to_user(fildes, fd, 2*sizeof(int)))
+ error = -EFAULT;
+ }
+ return error;
+}
+
+/* sys_mmap used to take a ptr to a buffer instead containing the args
+ * but we support syscalls with 6 arguments now
+ */
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, off_t offset)
+{
+ struct file * file = NULL;
+ int ret = -EBADF;
+
+ lock_kernel();
+ if (!(flags & MAP_ANONYMOUS)) {
+ if (!(file = fget(fd)))
+ goto out;
+ }
+
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ down(&current->mm->mmap_sem);
+ ret = do_mmap(file, addr, len, prot, flags, offset);
+ up(&current->mm->mmap_sem);
+ if (file)
+ fput(file);
+ out:
+ unlock_kernel();
+ return ret;
+}
+
+/* common code for old and new mmaps */
+static inline long
+do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+ unsigned long flags, unsigned long fd, unsigned long pgoff)
+{
+ int error = -EBADF;
+ struct file * file = NULL;
+
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ if (!(flags & MAP_ANONYMOUS)) {
+ file = fget(fd);
+ if (!file)
+ goto out;
+ }
+
+ down(&current->mm->mmap_sem);
+ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ up(&current->mm->mmap_sem);
+
+ if (file)
+ fput(file);
+out:
+ return error;
+}
+
+asmlinkage unsigned long old_mmap(unsigned long addr, size_t len, int prot,
+ int flags, int fd, off_t offset)
+{
+ return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+}
+
+asmlinkage long
+sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+ unsigned long flags, unsigned long fd, unsigned long pgoff)
+{
+ return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly. (same as arch/i386)
+ */
+
+asmlinkage int sys_ipc (uint call, int first, int second,
+ int third, void *ptr, long fifth)
+{
+ int version, ret;
+
+ version = call >> 16; /* hack for backward compatibility */
+ call &= 0xffff;
+
+ switch (call) {
+ case SEMOP:
+ return sys_semop (first, (struct sembuf *)ptr, second);
+ case SEMGET:
+ return sys_semget (first, second, third);
+ case SEMCTL: {
+ union semun fourth;
+ if (!ptr)
+ return -EINVAL;
+ if (get_user(fourth.__pad, (void **) ptr))
+ return -EFAULT;
+ return sys_semctl (first, second, third, fourth);
+ }
+
+ case MSGSND:
+ return sys_msgsnd (first, (struct msgbuf *) ptr,
+ second, third);
+ case MSGRCV:
+ switch (version) {
+ case 0: {
+ struct ipc_kludge tmp;
+ if (!ptr)
+ return -EINVAL;
+
+ if (copy_from_user(&tmp,
+ (struct ipc_kludge *) ptr,
+ sizeof (tmp)))
+ return -EFAULT;
+ return sys_msgrcv (first, tmp.msgp, second,
+ tmp.msgtyp, third);
+ }
+ default:
+ return sys_msgrcv (first,
+ (struct msgbuf *) ptr,
+ second, fifth, third);
+ }
+ case MSGGET:
+ return sys_msgget ((key_t) first, second);
+ case MSGCTL:
+ return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+
+ case SHMAT:
+ switch (version) {
+ default: {
+ ulong raddr;
+ ret = sys_shmat (first, (char *) ptr, second, &raddr);
+ if (ret)
+ return ret;
+ return put_user (raddr, (ulong *) third);
+ }
+ case 1: /* iBCS2 emulator entry point */
+ if (!segment_eq(get_fs(), get_ds()))
+ return -EINVAL;
+ return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+ }
+ case SHMDT:
+ return sys_shmdt ((char *)ptr);
+ case SHMGET:
+ return sys_shmget (first, second, third);
+ case SHMCTL:
+ return sys_shmctl (first, second,
+ (struct shmid_ds *) ptr);
+ default:
+ return -EINVAL;
+ }
+}
+
+/* apparently this is legacy - if we don't need this in Linux/CRIS we can remove it. */
+
+asmlinkage int sys_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c
new file mode 100644
index 000000000..d46ed47fa
--- /dev/null
+++ b/arch/cris/kernel/time.c
@@ -0,0 +1,453 @@
+/* $Id: time.c,v 1.4 2000/10/17 14:44:58 bjornw Exp $
+ *
+ * linux/arch/cris/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ * Copyright (C) 1999, 2000 Axis Communications AB
+ *
+ * 1994-07-02 Alan Modra
+ * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
+ * 1995-03-26 Markus Kuhn
+ * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
+ * precision CMOS clock update
+ * 1996-05-03 Ingo Molnar
+ * fixed time warps in do_[slow|fast]_gettimeoffset()
+ * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
+ *
+ * Linux/CRIS specific code:
+ *
+ * Authors: Bjorn Wesen
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/rtc.h>
+
+#include <linux/timex.h>
+#include <linux/config.h>
+
+#include <asm/svinto.h>
+
+static int have_rtc; /* used to remember if we have an RTC or not */
+
+/* define this if you need to use print_timestamp */
+/* it will make jiffies at 96 hz instead of 100 hz though */
+#undef USE_CASCADE_TIMERS
+
+extern int setup_etrax_irq(int, struct irqaction *);
+
+#define TICK_SIZE tick
+
+static unsigned long do_slow_gettimeoffset(void)
+{
+ unsigned long count;
+
+ static unsigned long count_p = LATCH; /* for the first call after boot */
+ static unsigned long jiffies_p = 0;
+
+ /*
+ * cache volatile jiffies temporarily; we have IRQs turned off.
+ */
+ unsigned long jiffies_t;
+
+ /* The timer interrupt comes from Etrax timer 0. In order to get
+ * better precision, we check the current value. It might have
+ * underflowed already though.
+ */
+
+#ifndef CONFIG_SVINTO_SIM
+ /* Not available in the xsim simulator. */
+ count = *R_TIMER0_DATA;
+#else
+ count = 0;
+#endif
+
+ jiffies_t = jiffies;
+
+ /*
+ * avoiding timer inconsistencies (they are rare, but they happen)...
+ * there are three kinds of problems that must be avoided here:
+ * 1. the timer counter underflows
+ * 2. hardware problem with the timer, not giving us continuous time,
+ * the counter does small "jumps" upwards on some Pentium systems,
+ * thus causes time warps
+ * 3. we are after the timer interrupt, but the bottom half handler
+ * hasn't executed yet.
+ */
+ if( jiffies_t == jiffies_p ) {
+ if( count > count_p ) {
+ }
+ } else
+ jiffies_p = jiffies_t;
+
+ count_p = count;
+
+ count = ((LATCH-1) - count) * TICK_SIZE;
+ count = (count + LATCH/2) / LATCH;
+
+ return count;
+}
+
+static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ *tv = xtime;
+ tv->tv_usec += do_gettimeoffset();
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ cli();
+ /* This is revolting. We need to set the xtime.tv_usec
+ * correctly. However, the value in this location is
+ * is value at the last tick.
+ * Discover what correction gettimeofday
+ * would have done, and then undo it!
+ */
+ tv->tv_usec -= do_gettimeoffset();
+
+ if (tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ xtime = *tv;
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_state = TIME_ERROR; /* p. 24, (a) */
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
+ sti();
+}
+
+
+/*
+ * BUG: This routine does not handle hour overflow properly; it just
+ * sets the minutes. Usually you'll only notice that after reboot!
+ */
+
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned char save_control, save_freq_select;
+
+ printk("set_rtc_mmss(%d)\n", nowtime);
+
+ if(!have_rtc)
+ return 0;
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+ BCD_TO_BIN(cmos_minutes);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ return retval;
+}
+
+/* Except from the Etrax100 HSDD about the built-in watchdog:
+ *
+ * 3.10.4 Watchdog timer
+
+ * When the watchdog timer is started, it generates an NMI if the watchdog
+ * isn't restarted or stopped within 0.1 s. If it still isn't restarted or
+ * stopped after an additional 3.3 ms, the watchdog resets the chip.
+ * The watchdog timer is stopped after reset. The watchdog timer is controlled
+ * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit
+ * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is
+ * described in the table below:
+ *
+ * Watchdog Value written:
+ * state: To enable: To key: Operation:
+ * -------- ---------- ------- ----------
+ * stopped 0 X No effect.
+ * stopped 1 key_val Start watchdog with key = key_val.
+ * started 0 ~key Stop watchdog
+ * started 1 ~key Restart watchdog with key = ~key.
+ * started X new_key_val Change key to new_key_val.
+ *
+ * Note: '~' is the bitwise NOT operator.
+ *
+ */
+
+/* right now, starting the watchdog is the same as resetting it */
+#define start_watchdog reset_watchdog
+
+static int watchdog_key = 0; /* arbitrary number */
+
+/* number of pages to consider "out of memory". it is normal that the memory
+ * is used though, so put this really low.
+ */
+
+#define WATCHDOG_MIN_FREE_PAGES 8
+
+extern int nr_free_pages;
+
+static inline void
+reset_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+ /* only keep watchdog happy as long as we have memory left! */
+ if(nr_free_pages > WATCHDOG_MIN_FREE_PAGES) {
+ /* reset the watchdog with the inverse of the old key */
+ watchdog_key ^= 0x7; /* invert key, which is 3 bits */
+ *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
+ IO_STATE(R_WATCHDOG, enable, start);
+ }
+#endif
+}
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+//static unsigned short myjiff; /* used by our debug routine print_timestamp */
+
+static inline void
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ /* acknowledge the timer irq */
+
+#ifdef USE_CASCADE_TIMERS
+ *R_TIMER_CTRL =
+ IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
+ IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
+ IO_STATE( R_TIMER_CTRL, i1, clr) |
+ IO_STATE( R_TIMER_CTRL, tm1, run) |
+ IO_STATE( R_TIMER_CTRL, clksel1, cascade0) |
+ IO_STATE( R_TIMER_CTRL, i0, clr) |
+ IO_STATE( R_TIMER_CTRL, tm0, run) |
+ IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
+#else
+ *R_TIMER_CTRL = r_timer_ctrl_shadow |
+ IO_STATE(R_TIMER_CTRL, i0, clr);
+#endif
+
+ /* reset watchdog otherwise it resets us! */
+
+ reset_watchdog();
+
+ /* call the real timer interrupt handler */
+
+ do_timer(regs);
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec > 500000 - (tick >> 1) &&
+ xtime.tv_usec < 500000 + (tick >> 1))
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600;
+
+}
+
+#if 0
+/* some old debug code for testing the microsecond timing of packets */
+static unsigned int lastjiff;
+
+void print_timestamp(const char *s)
+{
+ unsigned long flags;
+ unsigned int newjiff;
+ save_flags(flags);
+ cli();
+ newjiff = (myjiff << 16) | (unsigned short)(-*R_TIMER01_DATA);
+ printk("%s: %x (%x)\n", s, newjiff, newjiff - lastjiff);
+ lastjiff = newjiff;
+ restore_flags(flags);
+}
+#endif
+
+/* grab the time from the RTC chip */
+
+unsigned long
+get_cmos_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+
+ printk("rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n",
+ sec, min, hour, day, mon, year);
+
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+
+ if ((year += 1900) < 1970)
+ year += 100;
+
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+/* update xtime from the CMOS settings. used when /dev/rtc gets a SET_TIME.
+ * TODO: this doesn't reset the fancy NTP phase stuff as do_settimeofday does.
+ */
+
+void
+update_xtime_from_cmos(void)
+{
+ if(have_rtc) {
+ xtime.tv_sec = get_cmos_time();
+ xtime.tv_usec = 0;
+ }
+}
+
+/* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain
+ * it needs to be SA_INTERRUPT to make the jiffies update work properly
+ */
+
+static struct irqaction irq2 = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT,
+ 0, "timer", NULL, NULL};
+
+void __init
+time_init(void)
+{
+ /* probe for the RTC and read it if it exists */
+
+ if(RTC_INIT() < 0) {
+ /* no RTC, start at 1980 */
+ xtime.tv_sec = 0;
+ xtime.tv_usec = 0;
+ have_rtc = 0;
+ } else {
+ /* get the current time */
+ have_rtc = 1;
+ update_xtime_from_cmos();
+ }
+
+ /* Setup the etrax timers
+ * Base frequency is 19200 hz, divider 192 -> 100 hz as Linux wants
+ * In normal mode, we use timer0, so timer1 is free. In cascade
+ * mode (which we sometimes use for debugging) both timers are used.
+ * Remember that linux/timex.h contains #defines that rely on the
+ * timer settings below (hz and divide factor) !!!
+ */
+
+#ifdef USE_CASCADE_TIMERS
+ *R_TIMER_CTRL =
+ IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
+ IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
+ IO_STATE( R_TIMER_CTRL, i1, nop) |
+ IO_STATE( R_TIMER_CTRL, tm1, stop_ld) |
+ IO_STATE( R_TIMER_CTRL, clksel1, cascade0) |
+ IO_STATE( R_TIMER_CTRL, i0, nop) |
+ IO_STATE( R_TIMER_CTRL, tm0, stop_ld) |
+ IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
+
+ *R_TIMER_CTRL = r_timer_ctrl_shadow =
+ IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
+ IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
+ IO_STATE( R_TIMER_CTRL, i1, nop) |
+ IO_STATE( R_TIMER_CTRL, tm1, run) |
+ IO_STATE( R_TIMER_CTRL, clksel1, cascade0) |
+ IO_STATE( R_TIMER_CTRL, i0, nop) |
+ IO_STATE( R_TIMER_CTRL, tm0, run) |
+ IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
+#else
+ *R_TIMER_CTRL =
+ IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) |
+ IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) |
+ IO_STATE(R_TIMER_CTRL, i1, nop) |
+ IO_STATE(R_TIMER_CTRL, tm1, stop_ld) |
+ IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) |
+ IO_STATE(R_TIMER_CTRL, i0, nop) |
+ IO_STATE(R_TIMER_CTRL, tm0, stop_ld) |
+ IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz);
+
+ *R_TIMER_CTRL = r_timer_ctrl_shadow =
+ IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) |
+ IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) |
+ IO_STATE(R_TIMER_CTRL, i1, nop) |
+ IO_STATE(R_TIMER_CTRL, tm1, run) |
+ IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) |
+ IO_STATE(R_TIMER_CTRL, i0, nop) |
+ IO_STATE(R_TIMER_CTRL, tm0, run) |
+ IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz);
+#endif
+
+ *R_IRQ_MASK0_SET =
+ IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */
+
+ /* now actually register the timer irq handler that calls timer_interrupt() */
+
+ setup_etrax_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */
+
+ /* enable watchdog if we should use one */
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+ printk("Enabling watchdog...\n");
+ start_watchdog();
+#endif
+
+}
diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c
new file mode 100644
index 000000000..9994487d4
--- /dev/null
+++ b/arch/cris/kernel/traps.c
@@ -0,0 +1,167 @@
+/* $Id: traps.c,v 1.3 2000/10/04 16:50:06 bjornw Exp $
+ *
+ * linux/arch/cris/traps.c
+ *
+ * Etrax100 does not have any hardware traps, only IRQ's, which we setup
+ * in irq.c instead. Here we just define the die_if_kernel Oops'er.
+ *
+ * Copyright (C) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+int kstack_depth_to_print = 24;
+
+/*
+ * These constants are for searching for possible module text
+ * segments. MODULE_RANGE is a guess of how much space is likely
+ * to be vmalloced.
+ */
+
+#define MODULE_RANGE (8*1024*1024)
+
+void show_stack(unsigned long *sp)
+{
+ unsigned long *stack, addr, module_start, module_end;
+ int i;
+ extern char _stext, _etext;
+
+ // debugging aid: "show_stack(NULL);" prints the
+ // back trace for this cpu.
+
+ if(sp == NULL)
+ sp = (unsigned long*)rdsp();
+
+ stack = sp;
+
+ for(i = 0; i < kstack_depth_to_print; i++) {
+ if (((long) stack & (THREAD_SIZE-1)) == 0)
+ break;
+ if (i && ((i % 8) == 0))
+ printk("\n ");
+ printk("%08lx ", *stack++);
+ }
+
+ printk("\nCall Trace: ");
+ stack = sp;
+ i = 1;
+ module_start = VMALLOC_START;
+ module_end = VMALLOC_END;
+ while (((long) stack & (THREAD_SIZE-1)) != 0) {
+ addr = *stack++;
+ /*
+ * If the address is either in the text segment of the
+ * kernel, or in the region which contains vmalloc'ed
+ * memory, it *may* be the address of a calling
+ * routine; if so, print it so that someone tracing
+ * down the cause of the crash will be able to figure
+ * out the call path that was taken.
+ */
+ if (((addr >= (unsigned long) &_stext) &&
+ (addr <= (unsigned long) &_etext)) ||
+ ((addr >= module_start) && (addr <= module_end))) {
+ if (i && ((i % 8) == 0))
+ printk("\n ");
+ printk("[<%08lx>] ", addr);
+ i++;
+ }
+ }
+}
+
+#if 0
+/* displays a short stack trace */
+
+int show_stack()
+{
+ unsigned long *sp = (unsigned long *)rdusp();
+ int i;
+ printk("Stack dump [0x%08lx]:\n", (unsigned long)sp);
+ for(i = 0; i < 16; i++)
+ printk("sp + %d: 0x%08lx\n", i*4, sp[i]);
+ return 0;
+}
+#endif
+
+void show_registers(struct pt_regs * regs)
+{
+ unsigned long usp = rdusp();
+
+ printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx\n",
+ regs->irp, regs->srp, regs->dccr, usp );
+ printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
+ regs->r0, regs->r1, regs->r2, regs->r3);
+ printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
+ regs->r4, regs->r5, regs->r6, regs->r7);
+ printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
+ regs->r8, regs->r9, regs->r10, regs->r11);
+ printk("r12: %08lx r13: %08lx oR10: %08lx\n",
+ regs->r12, regs->r13, regs->orig_r10);
+ printk("Process %s (pid: %d, stackpage=%08lx)\n",
+ current->comm, current->pid, (unsigned long)current);
+
+ // TODO, fix in_kernel detection
+
+#if 0
+ /*
+ * When in-kernel, we also print out the stack and code at the
+ * time of the fault..
+ */
+ if (1) {
+
+ printk("\nStack: ");
+ show_stack((unsigned long*)usp);
+
+ printk("\nCode: ");
+ if(regs->irp < PAGE_OFFSET)
+ goto bad;
+
+ for(i = 0; i < 20; i++)
+ {
+ unsigned char c;
+ if(__get_user(c, &((unsigned char*)regs->irp)[i])) {
+bad:
+ printk(" Bad IP value.");
+ break;
+ }
+ printk("%02x ", c);
+ }
+ }
+ printk("\n");
+#endif
+}
+
+
+
+void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+{
+ if(user_mode(regs))
+ return;
+
+ printk("%s: %04lx\n", str, err & 0xffff);
+
+ show_registers(regs);
+ show_stack(NULL); /* print backtrace for kernel stack on this CPU */
+
+ do_exit(SIGSEGV);
+}
+
+void __init trap_init(void)
+{
+
+
+}
diff --git a/arch/cris/lib/Makefile b/arch/cris/lib/Makefile
new file mode 100644
index 000000000..6ede712e3
--- /dev/null
+++ b/arch/cris/lib/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for Etrax-specific library files..
+#
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+
+L_TARGET = lib.a
+obj-y = checksum.o checksumcopy.o string.o usercopy.o memset.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/cris/lib/checksum.S b/arch/cris/lib/checksum.S
new file mode 100644
index 000000000..4ee0daa0c
--- /dev/null
+++ b/arch/cris/lib/checksum.S
@@ -0,0 +1,113 @@
+ ;; $Id: checksum.S,v 1.1 2000/07/10 16:25:21 bjornw Exp $
+ ;; A fast checksum routine using movem
+ ;; Copyright (c) 1998 Bjorn Wesen/Axis Communications AB
+
+ ;; csum_partial(const unsigned char * buff, int len, unsigned int sum)
+
+ .globl _csum_partial
+_csum_partial:
+
+ ;; check for breakeven length between movem and normal word looping versions
+
+ cmpu.w 80,r11
+ bcs no_movem
+ nop
+
+ ;; need to save the registers we use below in the movem loop
+ ;; this overhead is why we have a check above for breakeven length
+
+ subq 9*4,sp
+ movem r8,[sp]
+
+ ;; do a movem checksum
+
+ ;; r10 - src
+ ;; r11 - length
+ ;; r12 - checksum
+
+ subq 10*4,r11 ; update length for the first loop
+
+mloop: movem [r10+],r9 ; read 10 longwords
+
+ ;; perform dword checksumming on the 10 longwords
+
+ add.d r0,r12
+ ax
+ add.d r1,r12
+ ax
+ add.d r2,r12
+ ax
+ add.d r3,r12
+ ax
+ add.d r4,r12
+ ax
+ add.d r5,r12
+ ax
+ add.d r6,r12
+ ax
+ add.d r7,r12
+ ax
+ add.d r8,r12
+ ax
+ add.d r9,r12
+
+ ;; fold the carry into the checksum, to avoid having to loop the carry
+ ;; back into the top
+
+ ax
+ addq 0,r12
+ ax ; do it again, since we might have generated a carry
+ addq 0,r12
+
+ subq 10*4,r11
+ bge mloop
+ nop
+
+ addq 10*4,r11 ; compensate for last loop underflowing length
+
+ ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below
+
+ moveq -1,r1 ; put 0xffff in r1, faster than move.d 0xffff,r1
+ lsrq 16,r1
+
+ move.d r12,r0
+ lsrq 16,r0 ; r0 = checksum >> 16
+ and.d r1,r12 ; checksum = checksum & 0xffff
+ add.d r0,r12 ; checksum += r0
+ move.d r12,r0 ; do the same again, maybe we got a carry last add
+ lsrq 16,r0
+ and.d r1,r12
+ add.d r0,r12
+
+ movem [sp+],r8 ; restore regs
+
+no_movem:
+ cmpq 2,r11
+ blt no_words
+ nop
+
+ ;; checksum the rest of the words
+
+ subq 2,r11
+
+wloop: subq 2,r11
+ bge wloop
+ addu.w [r10+],r12
+
+ addq 2,r11
+
+no_words:
+ ;; see if we have one odd byte more
+ cmpq 1,r11
+ beq do_byte
+ nop
+ ret
+ move.d r12, r10
+
+do_byte:
+ ;; copy and checksum the last byte
+ addu.b [r10],r12
+ ret
+ move.d r12, r10
+
+ \ No newline at end of file
diff --git a/arch/cris/lib/checksumcopy.S b/arch/cris/lib/checksumcopy.S
new file mode 100644
index 000000000..eae9c7ace
--- /dev/null
+++ b/arch/cris/lib/checksumcopy.S
@@ -0,0 +1,120 @@
+ ;; $Id: checksumcopy.S,v 1.2 2000/08/08 16:57:31 bjornw Exp $
+ ;; A fast checksum+copy routine using movem
+ ;; Copyright (c) 1998, 2000 Axis Communications AB
+ ;;
+ ;; Authors: Bjorn Wesen
+ ;;
+ ;; csum_partial_copy_nocheck(const char *src, char *dst,
+ ;; int len, unsigned int sum)
+
+ .globl _csum_partial_copy_nocheck
+_csum_partial_copy_nocheck:
+
+ ;; check for breakeven length between movem and normal word looping versions
+
+ cmpu.w 80,r12
+ bcs no_movem
+ nop
+
+ ;; need to save the registers we use below in the movem loop
+ ;; this overhead is why we have a check above for breakeven length
+
+ subq 9*4,sp
+ movem r8,[sp]
+
+ ;; do a movem copy and checksum
+
+ ;; r10 - src
+ ;; r11 - dst
+ ;; r12 - length
+ ;; r13 - checksum
+
+ subq 10*4,r12 ; update length for the first loop
+
+mloop: movem [r10+],r9 ; read 10 longwords
+ movem r9,[r11+] ; write 10 longwords
+
+ ;; perform dword checksumming on the 10 longwords
+
+ add.d r0,r13
+ ax
+ add.d r1,r13
+ ax
+ add.d r2,r13
+ ax
+ add.d r3,r13
+ ax
+ add.d r4,r13
+ ax
+ add.d r5,r13
+ ax
+ add.d r6,r13
+ ax
+ add.d r7,r13
+ ax
+ add.d r8,r13
+ ax
+ add.d r9,r13
+
+ ;; fold the carry into the checksum, to avoid having to loop the carry
+ ;; back into the top
+
+ ax
+ addq 0,r13
+
+ subq 10*4,r12
+ bge mloop
+ nop
+
+ addq 10*4,r12 ; compensate for last loop underflowing length
+
+ ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below
+
+ moveq -1,r1 ; put 0xffff in r1, faster than move.d 0xffff,r1
+ lsrq 16,r1
+
+ move.d r13,r0
+ lsrq 16,r0 ; r0 = checksum >> 16
+ and.d r1,r13 ; checksum = checksum & 0xffff
+ add.d r0,r13 ; checksum += r0
+ move.d r13,r0 ; do the same again, maybe we got a carry last add
+ lsrq 16,r0
+ and.d r1,r13
+ add.d r0,r13
+
+ movem [sp+],r8 ; restore regs
+
+no_movem:
+ cmpq 2,r12
+ blt no_words
+ nop
+
+ ;; copy and checksum the rest of the words
+
+ subq 2,r12
+
+wloop: move.w [r10+],r9
+ addu.w r9,r13
+ subq 2,r12
+ bge wloop
+ move.w r9,[r11+]
+
+ addq 2,r12
+
+no_words:
+ ;; see if we have one odd byte more
+ cmpq 1,r12
+ beq do_byte
+ nop
+ ret
+ move.d r13, r10
+
+do_byte:
+ ;; copy and checksum the last byte
+ move.b [r10],r9
+ addu.b r9,r13
+ move.b r9,[r11]
+ ret
+ move.d r13, r10
+
+ \ No newline at end of file
diff --git a/arch/cris/lib/dmacopy.c b/arch/cris/lib/dmacopy.c
new file mode 100644
index 000000000..318577a2d
--- /dev/null
+++ b/arch/cris/lib/dmacopy.c
@@ -0,0 +1,43 @@
+/* $Id: dmacopy.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $
+ *
+ * memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax
+ */
+
+#include <asm/svinto.h>
+#include <asm/io.h>
+
+#define D(x)
+
+void *dma_memcpy(void *pdst,
+ const void *psrc,
+ unsigned int pn)
+{
+ static etrax_dma_descr indma, outdma;
+
+ D(printk("dma_memcpy %d bytes... ", pn));
+
+#if 0
+ *R_GEN_CONFIG = genconfig_shadow =
+ (genconfig_shadow & ~0x3c0000) |
+ IO_STATE(R_GEN_CONFIG, dma6, intdma7) |
+ IO_STATE(R_GEN_CONFIG, dma7, intdma6);
+#endif
+ indma.sw_len = outdma.sw_len = pn;
+ indma.ctrl = d_eol | d_eop;
+ outdma.ctrl = d_eol;
+ indma.buf = psrc;
+ outdma.buf = pdst;
+
+ *R_DMA_CH6_FIRST = &indma;
+ *R_DMA_CH7_FIRST = &outdma;
+ *R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+ *R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, start);
+
+ while(*R_DMA_CH7_CMD == 1) /* wait for completion */ ;
+
+ D(printk("done\n"));
+
+}
+
+
+
diff --git a/arch/cris/lib/memset.c b/arch/cris/lib/memset.c
new file mode 100644
index 000000000..2f9f3fe37
--- /dev/null
+++ b/arch/cris/lib/memset.c
@@ -0,0 +1,245 @@
+/*#************************************************************************#*/
+/*#-------------------------------------------------------------------------*/
+/*# */
+/*# FUNCTION NAME: memset() */
+/*# */
+/*# PARAMETERS: void* dst; Destination address. */
+/*# int c; Value of byte to write. */
+/*# int len; Number of bytes to write. */
+/*# */
+/*# RETURNS: dst. */
+/*# */
+/*# DESCRIPTION: Sets the memory dst of length len bytes to c, as standard. */
+/*# Framework taken from memcpy. This routine is */
+/*# very sensitive to compiler changes in register allocation. */
+/*# Should really be rewritten to avoid this problem. */
+/*# */
+/*#-------------------------------------------------------------------------*/
+/*# */
+/*# HISTORY */
+/*# */
+/*# DATE NAME CHANGES */
+/*# ---- ---- ------- */
+/*# 990713 HP Tired of watching this function (or */
+/*# really, the nonoptimized generic */
+/*# implementation) take up 90% of simulator */
+/*# output. Measurements needed. */
+/*# */
+/*#-------------------------------------------------------------------------*/
+
+/* No, there's no macro saying 12*4, since it is "hard" to get it into
+ the asm in a good way. Thus better to expose the problem everywhere.
+ */
+
+/* Assuming 1 cycle per dword written or read (ok, not really true), and
+ one per instruction, then 43+3*(n/48-1) <= 24+24*(n/48-1)
+ so n >= 45.7; n >= 0.9; we win on the first full 48-byte block to set. */
+
+#define ZERO_BLOCK_SIZE (1*12*4)
+
+void *memset(void *pdst,
+ int c,
+ unsigned int plen)
+{
+ /* Ok. Now we want the parameters put in special registers.
+ Make sure the compiler is able to make something useful of this. */
+
+ register char *return_dst __asm__ ("r10") = pdst;
+ register int n __asm__ ("r12") = plen;
+ register int lc __asm__ ("r11") = c;
+
+ /* Most apps use memset sanely. Only those memsetting about 3..4
+ bytes or less get penalized compared to the generic implementation
+ - and that's not really sane use. */
+
+ /* Ugh. This is fragile at best. Check with newer GCC releases, if
+ they compile cascaded "x |= x << 8" sanely! */
+ __asm__("movu.b %0,r13\n\tlslq 8,r13\n\tmove.b %0,r13\n\tmove.d r13,%0\n\tlslq 16,r13\n\tor.d r13,%0"
+ : "=r" (lc) : "0" (lc) : "r13");
+
+ {
+ register char *dst __asm__ ("r13") = pdst;
+
+ /* This is NONPORTABLE, but since this whole routine is */
+ /* grossly nonportable that doesn't matter. */
+
+ if (((unsigned long) pdst & 3) != 0
+ /* Oops! n=0 must be a legal call, regardless of alignment. */
+ && n >= 3)
+ {
+ if ((unsigned long)dst & 1)
+ {
+ *dst = (char) lc;
+ n--;
+ dst++;
+ }
+
+ if ((unsigned long)dst & 2)
+ {
+ *(short *)dst = lc;
+ n -= 2;
+ dst += 2;
+ }
+ }
+
+ /* Now the fun part. For the threshold value of this, check the equation
+ above. */
+ /* Decide which copying method to use. */
+ if (n >= ZERO_BLOCK_SIZE)
+ {
+ /* For large copies we use 'movem' */
+
+ /* It is not optimal to tell the compiler about clobbering any
+ registers; that will move the saving/restoring of those registers
+ to the function prologue/epilogue, and make non-movem sizes
+ suboptimal.
+
+ This method is not foolproof; it assumes that the "asm reg"
+ declarations at the beginning of the function really are used
+ here (beware: they may be moved to temporary registers).
+ This way, we do not have to save/move the registers around into
+ temporaries; we can safely use them straight away.
+
+ If you want to check that the allocation was right; then
+ check the equalities in the first comment. It should say
+ "r13=r13, r12=r12, r11=r11" */
+ __asm__ volatile ("
+ ;; Check that the following is true (same register names on
+ ;; both sides of equal sign, as in r8=r8):
+ ;; %0=r13, %1=r12, %4=r11
+ ;;
+ ;; Save the registers we'll clobber in the movem process
+ ;; on the stack. Don't mention them to gcc, it will only be
+ ;; upset.
+ subq 11*4,sp
+ movem r10,[sp]
+
+ move.d r11,r0
+ move.d r11,r1
+ move.d r11,r2
+ move.d r11,r3
+ move.d r11,r4
+ move.d r11,r5
+ move.d r11,r6
+ move.d r11,r7
+ move.d r11,r8
+ move.d r11,r9
+ move.d r11,r10
+
+ ;; Now we've got this:
+ ;; r13 - dst
+ ;; r12 - n
+
+ ;; Update n for the first loop
+ subq 12*4,r12
+0:
+ subq 12*4,r12
+ bge 0b
+ movem r11,[r13+]
+
+ addq 12*4,r12 ;; compensate for last loop underflowing n
+
+ ;; Restore registers from stack
+ movem [sp+],r10"
+
+ /* Outputs */ : "=r" (dst), "=r" (n)
+ /* Inputs */ : "0" (dst), "1" (n), "r" (lc));
+
+ }
+
+ /* Either we directly starts copying, using dword copying
+ in a loop, or we copy as much as possible with 'movem'
+ and then the last block (<44 bytes) is copied here.
+ This will work since 'movem' will have updated src,dst,n. */
+
+ while ( n >= 16 )
+ {
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ n -= 16;
+ }
+
+ /* A switch() is definitely the fastest although it takes a LOT of code.
+ * Particularly if you inline code this.
+ */
+ switch (n)
+ {
+ case 0:
+ break;
+ case 1:
+ *(char*)dst = (char) lc;
+ break;
+ case 2:
+ *(short*)dst = (short) lc;
+ break;
+ case 3:
+ *((short*)dst)++ = (short) lc;
+ *(char*)dst = (char) lc;
+ break;
+ case 4:
+ *((long*)dst)++ = lc;
+ break;
+ case 5:
+ *((long*)dst)++ = lc;
+ *(char*)dst = (char) lc;
+ break;
+ case 6:
+ *((long*)dst)++ = lc;
+ *(short*)dst = (short) lc;
+ break;
+ case 7:
+ *((long*)dst)++ = lc;
+ *((short*)dst)++ = (short) lc;
+ *(char*)dst = (char) lc;
+ break;
+ case 8:
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ break;
+ case 9:
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *(char*)dst = (char) lc;
+ break;
+ case 10:
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *(short*)dst = (short) lc;
+ break;
+ case 11:
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *((short*)dst)++ = (short) lc;
+ *(char*)dst = (char) lc;
+ break;
+ case 12:
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ break;
+ case 13:
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *(char*)dst = (char) lc;
+ break;
+ case 14:
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *(short*)dst = (short) lc;
+ break;
+ case 15:
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *((long*)dst)++ = lc;
+ *((short*)dst)++ = (short) lc;
+ *(char*)dst = (char) lc;
+ break;
+ }
+ }
+
+ return return_dst; /* destination pointer. */
+} /* memset() */
diff --git a/arch/cris/lib/old_checksum.c b/arch/cris/lib/old_checksum.c
new file mode 100644
index 000000000..6035a48ae
--- /dev/null
+++ b/arch/cris/lib/old_checksum.c
@@ -0,0 +1,127 @@
+/* $Id: old_checksum.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $
+ *
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IP/TCP/UDP checksumming routines
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Tom May, <ftom@netcom.com>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <net/checksum.h>
+
+#undef PROFILE_CHECKSUM
+
+#ifdef PROFILE_CHECKSUM
+/* these are just for profiling the checksum code with an oscillioscope.. uh */
+#if 0
+#define BITOFF *((unsigned char *)0xb0000030) = 0xff
+#define BITON *((unsigned char *)0xb0000030) = 0x0
+#endif
+#include <asm/io.h>
+#define CBITON LED_ACTIVE_SET(1)
+#define CBITOFF LED_ACTIVE_SET(0)
+#define BITOFF
+#define BITON
+#else
+#define BITOFF
+#define BITON
+#define CBITOFF
+#define CBITON
+#endif
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+#include <asm/delay.h>
+
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+{
+ /*
+ * Experiments with ethernet and slip connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary.
+ */
+ const unsigned char *endMarker = buff + len;
+ const unsigned char *marker = endMarker - (len % 16);
+#if 0
+ if((int)buff & 0x3)
+ printk("unaligned buff %p\n", buff);
+ __delay(900); /* extra delay of 90 us to test performance hit */
+#endif
+ BITON;
+ while (buff < marker) {
+ sum += *((unsigned short *)buff)++;
+ sum += *((unsigned short *)buff)++;
+ sum += *((unsigned short *)buff)++;
+ sum += *((unsigned short *)buff)++;
+ sum += *((unsigned short *)buff)++;
+ sum += *((unsigned short *)buff)++;
+ sum += *((unsigned short *)buff)++;
+ sum += *((unsigned short *)buff)++;
+ }
+ marker = endMarker - (len % 2);
+ while(buff < marker) {
+ sum += *((unsigned short *)buff)++;
+ }
+ if(endMarker - buff > 0) {
+ sum += *buff; /* add extra byte seperately */
+ }
+ BITOFF;
+ return(sum);
+}
+
+#if 0
+
+/*
+ * copy while checksumming, otherwise like csum_partial
+ */
+
+unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
+ int len, unsigned int sum)
+{
+ const unsigned char *endMarker;
+ const unsigned char *marker;
+ printk("csum_partial_copy len %d.\n", len);
+#if 0
+ if((int)src & 0x3)
+ printk("unaligned src %p\n", src);
+ if((int)dst & 0x3)
+ printk("unaligned dst %p\n", dst);
+ __delay(1800); /* extra delay of 90 us to test performance hit */
+#endif
+ endMarker = src + len;
+ marker = endMarker - (len % 16);
+ CBITON;
+ while(src < marker) {
+ sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
+ sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
+ sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
+ sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
+ sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
+ sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
+ sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
+ sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
+ }
+ marker = endMarker - (len % 2);
+ while(src < marker) {
+ sum += (*((unsigned short *)dst)++ = *((unsigned short *)src)++);
+ }
+ if(endMarker - src > 0) {
+ sum += (*dst = *src); /* add extra byte seperately */
+ }
+ CBITOFF;
+ return(sum);
+}
+
+#endif
diff --git a/arch/cris/lib/string.c b/arch/cris/lib/string.c
new file mode 100644
index 000000000..6218cad56
--- /dev/null
+++ b/arch/cris/lib/string.c
@@ -0,0 +1,223 @@
+/*#************************************************************************#*/
+/*#-------------------------------------------------------------------------*/
+/*# */
+/*# FUNCTION NAME: memcpy() */
+/*# */
+/*# PARAMETERS: void* dst; Destination address. */
+/*# void* src; Source address. */
+/*# int len; Number of bytes to copy. */
+/*# */
+/*# RETURNS: dst. */
+/*# */
+/*# DESCRIPTION: Copies len bytes of memory from src to dst. No guarantees */
+/*# about copying of overlapping memory areas. This routine is */
+/*# very sensitive to compiler changes in register allocation. */
+/*# Should really be rewritten to avoid this problem. */
+/*# */
+/*#-------------------------------------------------------------------------*/
+/*# */
+/*# HISTORY */
+/*# */
+/*# DATE NAME CHANGES */
+/*# ---- ---- ------- */
+/*# 941007 Kenny R Creation */
+/*# 941011 Kenny R Lots of optimizations and inlining. */
+/*# 941129 Ulf A Adapted for use in libc. */
+/*# 950216 HP N==0 forgotten if non-aligned src/dst. */
+/*# Added some optimizations. */
+/*# 001025 HP Make src and dst char *. Align dst to */
+/*# dword, not just word-if-both-src-and-dst- */
+/*# are-misaligned. */
+/*# */
+/*#-------------------------------------------------------------------------*/
+
+void *memcpy(void *pdst,
+ const void *psrc,
+ unsigned int pn)
+{
+ /* Ok. Now we want the parameters put in special registers.
+ Make sure the compiler is able to make something useful of this.
+ As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+ If gcc was allright, it really would need no temporaries, and no
+ stack space to save stuff on. */
+
+ register void *return_dst __asm__ ("r10") = pdst;
+ register char *dst __asm__ ("r13") = pdst;
+ register const char *src __asm__ ("r11") = psrc;
+ register int n __asm__ ("r12") = pn;
+
+
+ /* When src is aligned but not dst, this makes a few extra needless
+ cycles. I believe it would take as many to check that the
+ re-alignment was unnecessary. */
+ if (((unsigned long) dst & 3) != 0
+ /* Don't align if we wouldn't copy more than a few bytes; so we
+ don't have to check further for overflows. */
+ && n >= 3)
+ {
+ if ((unsigned long) dst & 1)
+ {
+ n--;
+ *(char*)dst = *(char*)src;
+ src++;
+ dst++;
+ }
+
+ if ((unsigned long) dst & 2)
+ {
+ n -= 2;
+ *(short*)dst = *(short*)src;
+ src += 2;
+ dst += 2;
+ }
+ }
+
+ /* Decide which copying method to use. */
+ if (n >= 44*2) /* Break even between movem and
+ move16 is at 38.7*2, but modulo 44. */
+ {
+ /* For large copies we use 'movem' */
+
+ /* It is not optimal to tell the compiler about clobbering any
+ registers; that will move the saving/restoring of those registers
+ to the function prologue/epilogue, and make non-movem sizes
+ suboptimal.
+
+ This method is not foolproof; it assumes that the "asm reg"
+ declarations at the beginning of the function really are used
+ here (beware: they may be moved to temporary registers).
+ This way, we do not have to save/move the registers around into
+ temporaries; we can safely use them straight away.
+
+ If you want to check that the allocation was right; then
+ check the equalities in the first comment. It should say
+ "r13=r13, r11=r11, r12=r12" */
+ __asm__ volatile ("
+ ;; Check that the following is true (same register names on
+ ;; both sides of equal sign, as in r8=r8):
+ ;; %0=r13, %1=r11, %2=r12
+ ;;
+ ;; Save the registers we'll use in the movem process
+ ;; on the stack.
+ subq 11*4,sp
+ movem r10,[sp]
+
+ ;; Now we've got this:
+ ;; r11 - src
+ ;; r13 - dst
+ ;; r12 - n
+
+ ;; Update n for the first loop
+ subq 44,r12
+0:
+ movem [r11+],r10
+ subq 44,r12
+ bge 0b
+ movem r10,[r13+]
+
+ addq 44,r12 ;; compensate for last loop underflowing n
+
+ ;; Restore registers from stack
+ movem [sp+],r10"
+
+ /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n)
+ /* Inputs */ : "0" (dst), "1" (src), "2" (n));
+
+ }
+
+ /* Either we directly starts copying, using dword copying
+ in a loop, or we copy as much as possible with 'movem'
+ and then the last block (<44 bytes) is copied here.
+ This will work since 'movem' will have updated src,dst,n. */
+
+ while ( n >= 16 )
+ {
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ n -= 16;
+ }
+
+ /* A switch() is definitely the fastest although it takes a LOT of code.
+ * Particularly if you inline code this.
+ */
+ switch (n)
+ {
+ case 0:
+ break;
+ case 1:
+ *(char*)dst = *(char*)src;
+ break;
+ case 2:
+ *(short*)dst = *(short*)src;
+ break;
+ case 3:
+ *((short*)dst)++ = *((short*)src)++;
+ *(char*)dst = *(char*)src;
+ break;
+ case 4:
+ *((long*)dst)++ = *((long*)src)++;
+ break;
+ case 5:
+ *((long*)dst)++ = *((long*)src)++;
+ *(char*)dst = *(char*)src;
+ break;
+ case 6:
+ *((long*)dst)++ = *((long*)src)++;
+ *(short*)dst = *(short*)src;
+ break;
+ case 7:
+ *((long*)dst)++ = *((long*)src)++;
+ *((short*)dst)++ = *((short*)src)++;
+ *(char*)dst = *(char*)src;
+ break;
+ case 8:
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ break;
+ case 9:
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *(char*)dst = *(char*)src;
+ break;
+ case 10:
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *(short*)dst = *(short*)src;
+ break;
+ case 11:
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *((short*)dst)++ = *((short*)src)++;
+ *(char*)dst = *(char*)src;
+ break;
+ case 12:
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ break;
+ case 13:
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *(char*)dst = *(char*)src;
+ break;
+ case 14:
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *(short*)dst = *(short*)src;
+ break;
+ case 15:
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *((long*)dst)++ = *((long*)src)++;
+ *((short*)dst)++ = *((short*)src)++;
+ *(char*)dst = *(char*)src;
+ break;
+ }
+
+ return return_dst; /* destination pointer. */
+} /* memcpy() */
diff --git a/arch/cris/lib/usercopy.c b/arch/cris/lib/usercopy.c
new file mode 100644
index 000000000..17eebf2ee
--- /dev/null
+++ b/arch/cris/lib/usercopy.c
@@ -0,0 +1,501 @@
+/*
+ * User address space access functions.
+ * The non-inlined parts of asm-cris/uaccess.h are here.
+ *
+ * Copyright (C) 2000, Axis Communications AB.
+ *
+ * Written by Hans-Peter Nilsson.
+ * Pieces used from memcpy, originally by Kenny Ranerup long time ago.
+ */
+
+#include <asm/uaccess.h>
+
+/* Asm:s have been tweaked (within the domain of correctness) to give
+ satisfactory results for "gcc version 2.96 20000427 (experimental)".
+
+ Check regularly...
+
+ Note that the PC saved at a bus-fault is the address *after* the
+ faulting instruction, which means the branch-target for instructions in
+ delay-slots for taken branches. Note also that the postincrement in
+ the instruction is performed regardless of bus-fault; the register is
+ seen updated in fault handlers.
+
+ Oh, and on the code formatting issue, to whomever feels like "fixing
+ it" to Conformity: I'm too "lazy", but why don't you go ahead and "fix"
+ string.c too. I just don't think too many people will hack this file
+ for the code format to be an issue. */
+
+
+/* Copy to userspace. This is based on the memcpy used for
+ kernel-to-kernel copying; see "string.c". */
+
+unsigned long
+__copy_user (void *pdst, const void *psrc, unsigned long pn)
+{
+ /* We want the parameters put in special registers.
+ Make sure the compiler is able to make something useful of this.
+ As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+ FIXME: Comment for old gcc version. Check.
+ If gcc was allright, it really would need no temporaries, and no
+ stack space to save stuff on. */
+
+ register char *dst __asm__ ("r13") = pdst;
+ register const char *src __asm__ ("r11") = psrc;
+ register int n __asm__ ("r12") = pn;
+ register int retn __asm__ ("r10") = 0;
+
+
+ /* When src is aligned but not dst, this makes a few extra needless
+ cycles. I believe it would take as many to check that the
+ re-alignment was unnecessary. */
+ if (((unsigned long) dst & 3) != 0
+ /* Don't align if we wouldn't copy more than a few bytes; so we
+ don't have to check further for overflows. */
+ && n >= 3)
+ {
+ if ((unsigned long) dst & 1)
+ {
+ __asm_copy_to_user_1 (dst, src, retn);
+ n--;
+ }
+
+ if ((unsigned long) dst & 2)
+ {
+ __asm_copy_to_user_2 (dst, src, retn);
+ n -= 2;
+ }
+ }
+
+ /* Decide which copying method to use. */
+ if (n >= 44*2) /* Break even between movem and
+ move16 is at 38.7*2, but modulo 44. */
+ {
+ /* For large copies we use 'movem'. */
+
+ /* It is not optimal to tell the compiler about clobbering any
+ registers; that will move the saving/restoring of those registers
+ to the function prologue/epilogue, and make non-movem sizes
+ suboptimal.
+
+ This method is not foolproof; it assumes that the "asm reg"
+ declarations at the beginning of the function really are used
+ here (beware: they may be moved to temporary registers).
+ This way, we do not have to save/move the registers around into
+ temporaries; we can safely use them straight away.
+
+ If you want to check that the allocation was right; then
+ check the equalities in the first comment. It should say
+ "r13=r13, r11=r11, r12=r12". */
+ __asm__ volatile ("
+ ;; Check that the following is true (same register names on
+ ;; both sides of equal sign, as in r8=r8):
+ ;; %0=r13, %1=r11, %2=r12 %3=r10
+ ;;
+ ;; Save the registers we'll use in the movem process
+ ;; on the stack.
+ subq 11*4,sp
+ movem r10,[sp]
+
+ ;; Now we've got this:
+ ;; r11 - src
+ ;; r13 - dst
+ ;; r12 - n
+
+ ;; Update n for the first loop
+ subq 44,r12
+
+; Since the noted PC of a faulting instruction in a delay-slot of a taken
+; branch, is that of the branch target, we actually point at the from-movem
+; for this case. There is no ambiguity here; if there was a fault in that
+; instruction (meaning a kernel oops), the faulted PC would be the address
+; after *that* movem.
+
+0:
+ movem [r11+],r10
+ subq 44,r12
+ bge 0b
+ movem r10,[r13+]
+1:
+ addq 44,r12 ;; compensate for last loop underflowing n
+
+ ;; Restore registers from stack
+ movem [sp+],r10
+2:
+ .section .fixup,\"ax\"
+
+; To provide a correct count in r10 of bytes that failed to be copied,
+; we jump back into the loop if the loop-branch was taken. There is no
+; performance penalty for sany use; the program will segfault soon enough.
+
+3:
+ move.d [sp],r10
+ addq 44,r10
+ move.d r10,[sp]
+ jump 0b
+4:
+ movem [sp+],r10
+ addq 44,r10
+ addq 44,r12
+ jump 2b
+
+ .previous
+ .section __ex_table,\"a\"
+ .dword 0b,3b
+ .dword 1b,4b
+ .previous"
+
+ /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn)
+ /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn));
+
+ }
+
+ /* Either we directly start copying, using dword copying in a loop, or
+ we copy as much as possible with 'movem' and then the last block (<44
+ bytes) is copied here. This will work since 'movem' will have
+ updated SRC, DST and N. */
+
+ while (n >= 16)
+ {
+ __asm_copy_to_user_16 (dst, src, retn);
+ n -= 16;
+ }
+
+ /* Having a separate by-four loops cuts down on cache footprint.
+ FIXME: Test with and without; increasing switch to be 0..15. */
+ while (n >= 4)
+ {
+ __asm_copy_to_user_4 (dst, src, retn);
+ n -= 4;
+ }
+
+ switch (n)
+ {
+ case 0:
+ break;
+ case 1:
+ __asm_copy_to_user_1 (dst, src, retn);
+ break;
+ case 2:
+ __asm_copy_to_user_2 (dst, src, retn);
+ break;
+ case 3:
+ __asm_copy_to_user_3 (dst, src, retn);
+ break;
+ }
+
+ return retn;
+}
+
+/* Copy from user to kernel, zeroing the bytes that were inaccessible in
+ userland. */
+
+unsigned long
+__copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn)
+{
+ /* We want the parameters put in special registers.
+ Make sure the compiler is able to make something useful of this.
+ As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+ FIXME: Comment for old gcc version. Check.
+ If gcc was allright, it really would need no temporaries, and no
+ stack space to save stuff on. */
+
+ register char *dst __asm__ ("r13") = pdst;
+ register const char *src __asm__ ("r11") = psrc;
+ register int n __asm__ ("r12") = pn;
+ register int retn __asm__ ("r10") = 0;
+
+ /* When src is aligned but not dst, this makes a few extra needless
+ cycles. I believe it would take as many to check that the
+ re-alignment was unnecessary. */
+ if (((unsigned long) dst & 3) != 0
+ /* Don't align if we wouldn't copy more than a few bytes; so we
+ don't have to check further for overflows. */
+ && n >= 3)
+ {
+ if ((unsigned long) dst & 1)
+ {
+ __asm_copy_from_user_1 (dst, src, retn);
+ n--;
+ }
+
+ if ((unsigned long) dst & 2)
+ {
+ __asm_copy_from_user_2 (dst, src, retn);
+ n -= 2;
+ }
+ }
+
+ /* Decide which copying method to use. */
+ if (n >= 44*2) /* Break even between movem and
+ move16 is at 38.7*2, but modulo 44. */
+ {
+ /* For large copies we use 'movem' */
+
+ /* It is not optimal to tell the compiler about clobbering any
+ registers; that will move the saving/restoring of those registers
+ to the function prologue/epilogue, and make non-movem sizes
+ suboptimal.
+
+ This method is not foolproof; it assumes that the "asm reg"
+ declarations at the beginning of the function really are used
+ here (beware: they may be moved to temporary registers).
+ This way, we do not have to save/move the registers around into
+ temporaries; we can safely use them straight away.
+
+ If you want to check that the allocation was right; then
+ check the equalities in the first comment. It should say
+ "r13=r13, r11=r11, r12=r12" */
+ __asm__ volatile ("
+ ;; Check that the following is true (same register names on
+ ;; both sides of equal sign, as in r8=r8):
+ ;; %0=r13, %1=r11, %2=r12 %3=r10
+ ;;
+ ;; Save the registers we'll use in the movem process
+ ;; on the stack.
+ subq 11*4,sp
+ movem r10,[sp]
+
+ ;; Now we've got this:
+ ;; r11 - src
+ ;; r13 - dst
+ ;; r12 - n
+
+ ;; Update n for the first loop
+ subq 44,r12
+0:
+ movem [r11+],r10
+1:
+ subq 44,r12
+ bge 0b
+ movem r10,[r13+]
+
+ addq 44,r12 ;; compensate for last loop underflowing n
+
+ ;; Restore registers from stack
+ movem [sp+],r10
+
+ .section .fixup,\"ax\"
+
+; To provide a correct count in r10 of bytes that failed to be copied,
+; we jump back into the loop if the loop-branch was taken.
+; There is no performance penalty; the program will segfault soon
+; enough.
+
+3:
+ move.d [sp],r10
+ addq 44,r10
+ move.d r10,[sp]
+ clear.d r0
+ clear.d r1
+ clear.d r2
+ clear.d r3
+ clear.d r4
+ clear.d r5
+ clear.d r6
+ clear.d r7
+ clear.d r8
+ clear.d r9
+ clear.d r10
+ jump 1b
+
+ .previous
+ .section __ex_table,\"a\"
+ .dword 1b,3b
+ .previous"
+
+ /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn)
+ /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn));
+
+ }
+
+ /* Either we directly start copying here, using dword copying in a loop,
+ or we copy as much as possible with 'movem' and then the last block
+ (<44 bytes) is copied here. This will work since 'movem' will have
+ updated src, dst and n. */
+
+ while (n >= 16)
+ {
+ __asm_copy_from_user_16 (dst, src, retn);
+ n -= 16;
+ }
+
+ /* Having a separate by-four loops cuts down on cache footprint.
+ FIXME: Test with and without; increasing switch to be 0..15. */
+ while (n >= 4)
+ {
+ __asm_copy_from_user_4 (dst, src, retn);
+ n -= 4;
+ }
+
+ switch (n)
+ {
+ case 0:
+ break;
+ case 1:
+ __asm_copy_from_user_1 (dst, src, retn);
+ break;
+ case 2:
+ __asm_copy_from_user_2 (dst, src, retn);
+ break;
+ case 3:
+ __asm_copy_from_user_3 (dst, src, retn);
+ break;
+ }
+
+ return retn;
+}
+
+/* Zero userspace. */
+
+unsigned long
+__do_clear_user (void *pto, unsigned long pn)
+{
+ /* We want the parameters put in special registers.
+ Make sure the compiler is able to make something useful of this.
+ As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop).
+
+ FIXME: Comment for old gcc version. Check.
+ If gcc was allright, it really would need no temporaries, and no
+ stack space to save stuff on. */
+
+ register char *dst __asm__ ("r13") = pto;
+ register int n __asm__ ("r12") = pn;
+ register int retn __asm__ ("r10") = 0;
+
+
+ if (((unsigned long) dst & 3) != 0
+ /* Don't align if we wouldn't copy more than a few bytes. */
+ && n >= 3)
+ {
+ if ((unsigned long) dst & 1)
+ {
+ __asm_clear_1 (dst, retn);
+ n--;
+ }
+
+ if ((unsigned long) dst & 2)
+ {
+ __asm_clear_2 (dst, retn);
+ n -= 2;
+ }
+ }
+
+ /* Decide which copying method to use.
+ FIXME: This number is from the "ordinary" kernel memset. */
+ if (n >= (1*48))
+ {
+ /* For large clears we use 'movem' */
+
+ /* It is not optimal to tell the compiler about clobbering any
+ call-saved registers; that will move the saving/restoring of
+ those registers to the function prologue/epilogue, and make
+ non-movem sizes suboptimal.
+
+ This method is not foolproof; it assumes that the "asm reg"
+ declarations at the beginning of the function really are used
+ here (beware: they may be moved to temporary registers).
+ This way, we do not have to save/move the registers around into
+ temporaries; we can safely use them straight away.
+
+ If you want to check that the allocation was right; then
+ check the equalities in the first comment. It should say
+ something like "r13=r13, r11=r11, r12=r12". */
+ __asm__ volatile ("
+ ;; Check that the following is true (same register names on
+ ;; both sides of equal sign, as in r8=r8):
+ ;; %0=r13, %1=r12 %2=r10
+ ;;
+ ;; Save the registers we'll clobber in the movem process
+ ;; on the stack. Don't mention them to gcc, it will only be
+ ;; upset.
+ subq 11*4,sp
+ movem r10,[sp]
+
+ clear.d r0
+ clear.d r1
+ clear.d r2
+ clear.d r3
+ clear.d r4
+ clear.d r5
+ clear.d r6
+ clear.d r7
+ clear.d r8
+ clear.d r9
+ clear.d r10
+ clear.d r11
+
+ ;; Now we've got this:
+ ;; r13 - dst
+ ;; r12 - n
+
+ ;; Update n for the first loop
+ subq 12*4,r12
+0:
+ subq 12*4,r12
+ bge 0b
+ movem r11,[r13+]
+1:
+ addq 12*4,r12 ;; compensate for last loop underflowing n
+
+ ;; Restore registers from stack
+ movem [sp+],r10
+2:
+ .section .fixup,\"ax\"
+3:
+ move.d [sp],r10
+ addq 12*4,r10
+ move.d r10,[sp]
+ clear.d r10
+ jump 0b
+
+4:
+ movem [sp+],r10
+ addq 12*4,r10
+ addq 12*4,r12
+ jump 2b
+
+ .previous
+ .section __ex_table,\"a\"
+ .dword 0b,3b
+ .dword 1b,4b
+ .previous"
+
+ /* Outputs */ : "=r" (dst), "=r" (n), "=r" (retn)
+ /* Inputs */ : "0" (dst), "1" (n), "2" (retn)
+ /* Clobber */ : "r11");
+ }
+
+ while (n >= 16)
+ {
+ __asm_clear_16 (dst, retn);
+ n -= 16;
+ }
+
+ /* Having a separate by-four loops cuts down on cache footprint.
+ FIXME: Test with and without; increasing switch to be 0..15. */
+ while (n >= 4)
+ {
+ __asm_clear_4 (dst, retn);
+ n -= 4;
+ }
+
+ switch (n)
+ {
+ case 0:
+ break;
+ case 1:
+ __asm_clear_1 (dst, retn);
+ break;
+ case 2:
+ __asm_clear_2 (dst, retn);
+ break;
+ case 3:
+ __asm_clear_3 (dst, retn);
+ break;
+ }
+
+ return retn;
+}
diff --git a/arch/cris/mm/Makefile b/arch/cris/mm/Makefile
new file mode 100644
index 000000000..d1d21a7b7
--- /dev/null
+++ b/arch/cris/mm/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux cris-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := mm.o
+obj-y := init.o fault.o tlb.o extable.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/cris/mm/extable.c b/arch/cris/mm/extable.c
new file mode 100644
index 000000000..a4cf00f14
--- /dev/null
+++ b/arch/cris/mm/extable.c
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/cris/mm/extable.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry _start___ex_table[];
+extern const struct exception_table_entry _stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ long diff;
+
+ mid = (last - first) / 2 + first;
+ diff = mid->insn - value;
+ if (diff == 0)
+ return mid->fixup;
+ else if (diff < 0)
+ first = mid+1;
+ else
+ last = mid-1;
+ }
+ return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+ unsigned long ret;
+
+#ifndef CONFIG_MODULES
+ /* There is only the kernel to search. */
+ ret = search_one_table(_start___ex_table, _stop___ex_table-1, addr);
+ if (ret) return ret;
+#else
+ /* The kernel is the last "module" -- no need to treat it special. */
+ struct module *mp;
+ for (mp = module_list; mp != NULL; mp = mp->next) {
+ if (mp->ex_table_start == NULL)
+ continue;
+ ret = search_one_table(mp->ex_table_start,
+ mp->ex_table_end - 1, addr);
+ if (ret) return ret;
+ }
+#endif
+
+ return 0;
+}
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
new file mode 100644
index 000000000..a4bb237b4
--- /dev/null
+++ b/arch/cris/mm/fault.c
@@ -0,0 +1,390 @@
+/*
+ * linux/arch/cris/mm/fault.c
+ *
+ * Copyright (C) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen
+ *
+ * $Log: fault.c,v $
+ * Revision 1.8 2000/11/22 14:45:31 bjornw
+ * * 2.4.0-test10 removed the set_pgdir instantaneous kernel global mapping
+ * into all processes. Instead we fill in the missing PTE entries on demand.
+ *
+ * Revision 1.7 2000/11/21 16:39:09 bjornw
+ * fixup switches frametype
+ *
+ * Revision 1.6 2000/11/17 16:54:08 bjornw
+ * More detailed siginfo reporting
+ *
+ *
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/svinto.h>
+
+extern void die_if_kernel(const char *,struct pt_regs *,long);
+
+asmlinkage void do_invalid_op (struct pt_regs *, unsigned long);
+asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
+ int error_code);
+
+/* debug of low-level TLB reload */
+#define D(x)
+/* debug of higher-level faults */
+#define DPG(x)
+
+/* fast TLB-fill fault handler */
+
+void
+handle_mmu_bus_fault(struct pt_regs *regs)
+{
+ int cause, select;
+ int index;
+ int page_id;
+ int miss, we, acc, inv;
+ struct mm_struct *mm = current->active_mm;
+ pmd_t *pmd;
+ pte_t pte;
+ int errcode = 0;
+ unsigned long address;
+
+ cause = *R_MMU_CAUSE;
+ select = *R_TLB_SELECT;
+
+ address = cause & PAGE_MASK; /* get faulting address */
+
+ page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause);
+ miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause);
+ we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause);
+ acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause);
+ inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause);
+ index = IO_EXTRACT(R_TLB_SELECT, index, select);
+
+ D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, "
+ "idx %d pid %d\n",
+ regs->irp, address, miss, inv, we, acc, index, page_id));
+
+ /* for a miss, we need to reload the TLB entry */
+
+ if(miss) {
+
+ /* see if the pte exists at all */
+
+ pmd = (pmd_t *)pgd_offset(mm, address);
+ if(pmd_none(*pmd))
+ goto dofault;
+ if(pmd_bad(*pmd)) {
+ printk("bad pgdir entry 0x%x at 0x%x\n", *pmd, pmd);
+ pmd_clear(pmd);
+ return;
+ }
+ pte = *pte_offset(pmd, address);
+ if(!pte_present(pte))
+ goto dofault;
+
+ D(printk(" found pte %x pg %x ", pte_val(pte), pte_page(pte)));
+ D(
+ {
+ if(pte_val(pte) & _PAGE_SILENT_WRITE)
+ printk("Silent-W ");
+ if(pte_val(pte) & _PAGE_KERNEL)
+ printk("Kernel ");
+ if(pte_val(pte) & _PAGE_SILENT_READ)
+ printk("Silent-R ");
+ if(pte_val(pte) & _PAGE_GLOBAL)
+ printk("Global ");
+ if(pte_val(pte) & _PAGE_PRESENT)
+ printk("Present ");
+ if(pte_val(pte) & _PAGE_ACCESSED)
+ printk("Accessed ");
+ if(pte_val(pte) & _PAGE_MODIFIED)
+ printk("Modified ");
+ if(pte_val(pte) & _PAGE_READ)
+ printk("Readable ");
+ if(pte_val(pte) & _PAGE_WRITE)
+ printk("Writeable ");
+ printk("\n");
+ });
+
+ /* load up the chosen TLB entry
+ * this assumes the pte format is the same as the TLB_LO layout.
+ *
+ * the write to R_TLB_LO also writes the vpn and page_id fields from
+ * R_MMU_CAUSE, which we in this case obviously want to keep
+ */
+
+ *R_TLB_LO = pte_val(pte);
+
+ return;
+ }
+
+ errcode = 0x01 | (we << 1);
+
+ dofault:
+ /* leave it to the MM system fault handler below */
+ D(printk("do_page_fault %p errcode %d\n", address, errcode));
+ do_page_fault(address, regs, errcode);
+}
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * Notice that the address we're given is aligned to the page the fault
+ * occured in, since we only get the PFN in R_MMU_CAUSE not the complete
+ * address.
+ *
+ * error_code:
+ * bit 0 == 0 means no page found, 1 means protection fault
+ * bit 1 == 0 means read, 1 means write
+ *
+ * If this routine detects a bad access, it returns 1, otherwise it
+ * returns 0.
+ */
+
+asmlinkage void
+do_page_fault(unsigned long address, struct pt_regs *regs,
+ int error_code)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct * vma;
+ int writeaccess;
+ int fault;
+ unsigned long fixup;
+ siginfo_t info;
+
+ tsk = current;
+
+ /*
+ * We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
+ *
+ * NOTE2: This is done so that, when updating the vmalloc
+ * mappings we don't have to walk all processes pgdirs and
+ * add the high mappings all at once. Instead we do it as they
+ * are used.
+ *
+ * TODO: On CRIS, we have a PTE Global bit which should be set in
+ * all the PTE's related to vmalloc in all processes - that means if
+ * we switch process and a vmalloc PTE is still in the TLB, it won't
+ * need to be reloaded. It's an optimization.
+ *
+ * Linux/CRIS's kernel is not page-mapped, so the comparision below
+ * should really be >= VMALLOC_START, however, kernel fixup errors
+ * will be handled more quickly by going through vmalloc_fault and then
+ * into bad_area_nosemaphore than falling through the find_vma user-mode
+ * tests.
+ */
+
+ if (address >= TASK_SIZE)
+ goto vmalloc_fault;
+
+ mm = tsk->mm;
+ writeaccess = error_code & 2;
+ info.si_code = SEGV_MAPERR;
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+
+ if (in_interrupt() || !mm)
+ goto no_context;
+
+ down(&mm->mmap_sem);
+ vma = find_vma(mm, address);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (user_mode(regs)) {
+ /*
+ * accessing the stack below usp is always a bug.
+ * we get page-aligned addresses so we can only check
+ * if we're within a page from usp, but that might be
+ * enough to catch brutal errors at least.
+ */
+ if (address + PAGE_SIZE < rdusp())
+ goto bad_area;
+ }
+ if (expand_stack(vma, address))
+ goto bad_area;
+
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+
+ good_area:
+ info.si_code = SEGV_ACCERR;
+
+ /* first do some preliminary protection checks */
+
+ if (writeaccess) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else {
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto bad_area;
+ }
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+
+ switch (handle_mm_fault(mm, vma, address, writeaccess)) {
+ case 1:
+ tsk->min_flt++;
+ break;
+ case 2:
+ tsk->maj_flt++;
+ break;
+ case 0:
+ goto do_sigbus;
+ default:
+ goto out_of_memory;
+ }
+
+ up(&mm->mmap_sem);
+ return;
+
+ /*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+
+ bad_area:
+
+ up(&mm->mmap_sem);
+
+ bad_area_nosemaphore:
+ DPG(show_registers(regs));
+
+ /* User mode accesses just cause a SIGSEGV */
+
+ if (user_mode(regs)) {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code has been set above */
+ info.si_addr = (void *)address;
+ force_sig_info(SIGSEGV, &info, tsk);
+ return;
+ }
+
+ no_context:
+
+ /* Are we prepared to handle this kernel fault?
+ *
+ * (The kernel has valid exception-points in the source
+ * when it acesses user-memory. When it fails in one
+ * of those points, we find it in a table and do a jump
+ * to some fixup code that loads an appropriate error
+ * code)
+ */
+
+ if ((fixup = search_exception_table(regs->irp)) != 0) {
+ regs->irp = fixup;
+ regs->frametype = CRIS_FRAME_FIXUP;
+ D(printk("doing fixup to 0x%x\n", fixup));
+ return;
+ }
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ if ((unsigned long) (address) < PAGE_SIZE)
+ printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+ else
+ printk(KERN_ALERT "Unable to handle kernel access");
+ printk(" at virtual address %08lx\n",address);
+
+ die_if_kernel("Oops", regs, error_code);
+
+ do_exit(SIGKILL);
+
+ /*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+
+ out_of_memory:
+ up(&mm->mmap_sem);
+ printk("VM: killing process %s\n", tsk->comm);
+ if(user_mode(regs))
+ do_exit(SIGKILL);
+ goto no_context;
+
+ do_sigbus:
+ up(&mm->mmap_sem);
+
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ info.si_code = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+ force_sig_info(SIGBUS, &info, tsk);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ goto no_context;
+ return;
+
+vmalloc_fault:
+ {
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ */
+ int offset = pgd_index(address);
+ pgd_t *pgd, *pgd_k;
+ pmd_t *pmd, *pmd_k;
+
+ pgd = tsk->active_mm->pgd + offset;
+ pgd_k = init_mm.pgd + offset;
+
+ if (!pgd_present(*pgd)) {
+ if (!pgd_present(*pgd_k))
+ goto bad_area_nosemaphore;
+ set_pgd(pgd, *pgd_k);
+ return;
+ }
+
+ pmd = pmd_offset(pgd, address);
+ pmd_k = pmd_offset(pgd_k, address);
+
+ if (pmd_present(*pmd) || !pmd_present(*pmd_k))
+ goto bad_area_nosemaphore;
+ set_pmd(pmd, *pmd_k);
+ return;
+ }
+
+}
diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c
new file mode 100644
index 000000000..3d0ceeffb
--- /dev/null
+++ b/arch/cris/mm/init.c
@@ -0,0 +1,506 @@
+/*
+ * linux/arch/cris/mm/init.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright (C) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ * $Log: init.c,v $
+ * Revision 1.15 2001/01/10 21:12:10 bjornw
+ * loops_per_sec -> loops_per_jiffy
+ *
+ * Revision 1.14 2000/11/22 16:23:20 bjornw
+ * Initialize totalhigh counters to 0 to make /proc/meminfo look nice.
+ *
+ * Revision 1.13 2000/11/21 16:37:51 bjornw
+ * Temporarily disable initmem freeing
+ *
+ * Revision 1.12 2000/11/21 13:55:07 bjornw
+ * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type
+ *
+ * Revision 1.11 2000/10/06 12:38:22 bjornw
+ * Cast empty_bad_page correctly (should really be of * type from the start..
+ *
+ * Revision 1.10 2000/10/04 16:53:57 bjornw
+ * Fix memory-map due to LX features
+ *
+ * Revision 1.9 2000/09/13 15:47:49 bjornw
+ * Wrong count in reserved-pages loop
+ *
+ * Revision 1.8 2000/09/13 14:35:10 bjornw
+ * 2.4.0-test8 added a new arg to free_area_init_node
+ *
+ * Revision 1.7 2000/08/17 15:35:55 bjornw
+ * 2.4.0-test6 removed MAP_NR and inserted virt_to_page
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/bootmem.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/svinto.h>
+
+static unsigned long totalram_pages;
+
+struct pgtable_cache_struct quicklists; /* see asm/pgalloc.h */
+
+const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
+
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void show_net_buffers(void);
+extern void tlb_init(void);
+
+/*
+ * empty_bad_page is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * the main point is that when a page table error occurs, we want to get
+ * out of the kernel safely before killing the process, so we need something
+ * to feed the MMU with when the fault occurs even if we don't have any
+ * real PTE's or page tables.
+ *
+ * empty_bad_page_table is the accompanying page-table: it is initialized
+ * to point to empty_bad_page writable-shared entries.
+ *
+ * empty_zero_page is a special page that is used for zero-initialized
+ * data and COW.
+ */
+
+unsigned long empty_bad_page_table;
+unsigned long empty_bad_page;
+unsigned long empty_zero_page;
+
+pte_t * __bad_pagetable(void)
+{
+ /* somehow it is enough to just clear it and not fill it with
+ * bad page PTE's...
+ */
+ memset((void *)empty_bad_page_table, 0, PAGE_SIZE);
+
+ return (pte_t *) empty_bad_page_table;
+}
+
+pte_t __bad_page(void)
+{
+
+ /* clear the empty_bad_page page. this should perhaps be
+ * a more simple inlined loop like it is on the other
+ * architectures.
+ */
+
+ memset((void *)empty_bad_page, 0, PAGE_SIZE);
+
+ return pte_mkdirty(__mk_pte((void *)empty_bad_page, PAGE_SHARED));
+}
+
+static pte_t * get_bad_pte_table(void)
+{
+ pte_t *empty_bad_pte_table = (pte_t *)empty_bad_page_table;
+ pte_t v;
+ int i;
+
+ v = __bad_page();
+
+ for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++)
+ empty_bad_pte_table[i] = v;
+
+ return empty_bad_pte_table;
+}
+
+void __handle_bad_pmd(pmd_t *pmd)
+{
+ pmd_ERROR(*pmd);
+ pmd_set(pmd, get_bad_pte_table());
+}
+
+void __handle_bad_pmd_kernel(pmd_t *pmd)
+{
+ pmd_ERROR(*pmd);
+ pmd_set_kernel(pmd, get_bad_pte_table());
+}
+
+pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) __get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (pte) {
+ clear_page(pte);
+ pmd_set_kernel(pmd, pte);
+ return pte + offset;
+ }
+ pmd_set_kernel(pmd, get_bad_pte_table());
+ return NULL;
+ }
+ free_page((unsigned long)pte);
+ if (pmd_bad(*pmd)) {
+ __handle_bad_pmd_kernel(pmd);
+ return NULL;
+ }
+ return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) __get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (pte) {
+ clear_page(pte);
+ pmd_set(pmd, pte);
+ return pte + offset;
+ }
+ pmd_set(pmd, get_bad_pte_table());
+ return NULL;
+ }
+ free_page((unsigned long)pte);
+ if (pmd_bad(*pmd)) {
+ __handle_bad_pmd(pmd);
+ return NULL;
+ }
+ return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+#ifndef CONFIG_NO_PGT_CACHE
+struct pgtable_cache_struct quicklists;
+
+/* trim the page-table cache if necessary */
+
+int do_check_pgt_cache(int low, int high)
+{
+ int freed = 0;
+
+ if(pgtable_cache_size > high) {
+ do {
+ if(pgd_quicklist) {
+ free_pgd_slow(get_pgd_fast());
+ freed++;
+ }
+ if(pmd_quicklist) {
+ free_pmd_slow(get_pmd_fast());
+ freed++;
+ }
+ if(pte_quicklist) {
+ free_pte_slow(get_pte_fast());
+ freed++;
+ }
+ } while(pgtable_cache_size > low);
+ }
+ return freed;
+}
+#else
+int do_check_pgt_cache(int low, int high)
+{
+ return 0;
+}
+#endif
+
+void show_mem(void)
+{
+ int i,free = 0,total = 0,cached = 0, reserved = 0, nonshared = 0;
+ int shared = 0;
+
+ printk("\nMem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+ i = max_mapnr;
+ while (i-- > 0) {
+ total++;
+ if (PageReserved(mem_map+i))
+ reserved++;
+ else if (PageSwapCache(mem_map+i))
+ cached++;
+ else if (!page_count(mem_map+i))
+ free++;
+ else if (page_count(mem_map+i) == 1)
+ nonshared++;
+ else
+ shared += page_count(mem_map+i) - 1;
+ }
+ printk("%d pages of RAM\n",total);
+ printk("%d free pages\n",free);
+ printk("%d reserved pages\n",reserved);
+ printk("%d pages nonshared\n",nonshared);
+ printk("%d pages shared\n",shared);
+ printk("%d pages swap cached\n",cached);
+ printk("%ld pages in page table cache\n",pgtable_cache_size);
+ show_buffers();
+}
+
+/*
+ * The kernel is already mapped with a kernel segment at kseg_c so
+ * we don't need to map it with a page table. However head.S also
+ * temporarily mapped it at kseg_4 so we should set up the ksegs again,
+ * clear the TLB and do some other paging setup stuff.
+ */
+
+void __init
+paging_init(void)
+{
+ int i;
+ unsigned long zones_size[MAX_NR_ZONES];
+
+ printk("Setting up paging and the MMU.\n");
+
+ /* clear out the init_mm.pgd that will contain the kernel's mappings */
+
+ for(i = 0; i < PTRS_PER_PGD; i++)
+ swapper_pg_dir[i] = __pgd(0);
+
+ /* initialise the TLB (tlb.c) */
+
+ tlb_init();
+
+ /* see README.mm for details on the KSEG setup */
+
+#ifdef CONFIG_CRIS_LOW_MAP
+
+ /* Etrax-100 LX version 1 has a bug so that we cannot map anything
+ * across the 0x80000000 boundary, so we need to shrink the user-virtual
+ * area to 0x50000000 instead of 0xb0000000 and map things slightly
+ * different. The unused areas are marked as paged so that we can catch
+ * freak kernel accesses there.
+ *
+ * The Juliette chip is mapped at 0xa so we pass that segment straight
+ * through. We cannot vremap it because the vmalloc area is below 0x8
+ * and Juliette needs an uncached area above 0x8.
+ */
+
+ *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, page ) |
+ IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */
+ IO_STATE(R_MMU_KSEG, seg_d, page ) |
+ IO_STATE(R_MMU_KSEG, seg_c, page ) |
+ IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */
+ IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* Juliette etc. */
+ IO_STATE(R_MMU_KSEG, seg_9, page ) |
+ IO_STATE(R_MMU_KSEG, seg_8, page ) |
+ IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */
+ IO_STATE(R_MMU_KSEG, seg_6, seg ) | /* kernel DRAM area */
+ IO_STATE(R_MMU_KSEG, seg_5, seg ) | /* cached flash */
+ IO_STATE(R_MMU_KSEG, seg_4, page ) | /* user area */
+ IO_STATE(R_MMU_KSEG, seg_3, page ) | /* user area */
+ IO_STATE(R_MMU_KSEG, seg_2, page ) | /* user area */
+ IO_STATE(R_MMU_KSEG, seg_1, page ) | /* user area */
+ IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */
+
+ *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) );
+
+ *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) );
+#else
+ /* This code is for the hopefully corrected Etrax-100 LX version 2... */
+
+ *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */
+ IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */
+ IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */
+ IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */
+ IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */
+ IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */
+ IO_STATE(R_MMU_KSEG, seg_9, page ) |
+ IO_STATE(R_MMU_KSEG, seg_8, page ) |
+ IO_STATE(R_MMU_KSEG, seg_7, page ) |
+ IO_STATE(R_MMU_KSEG, seg_6, page ) |
+ IO_STATE(R_MMU_KSEG, seg_5, page ) |
+ IO_STATE(R_MMU_KSEG, seg_4, page ) |
+ IO_STATE(R_MMU_KSEG, seg_3, page ) |
+ IO_STATE(R_MMU_KSEG, seg_2, page ) |
+ IO_STATE(R_MMU_KSEG, seg_1, page ) |
+ IO_STATE(R_MMU_KSEG, seg_0, page ) );
+
+ *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) );
+
+ *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) |
+ IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) );
+#endif
+
+ *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) );
+
+ /* The MMU has been enabled ever since head.S but just to make
+ * it totally obvious we do it here as well.
+ */
+
+ *R_MMU_CTRL = ( IO_STATE(R_MMU_CTRL, inv_excp, enable ) |
+ IO_STATE(R_MMU_CTRL, acc_excp, enable ) |
+ IO_STATE(R_MMU_CTRL, we_excp, enable ) );
+
+ *R_MMU_ENABLE = IO_STATE(R_MMU_ENABLE, mmu_enable, enable);
+
+ /*
+ * initialize the bad page table and bad page to point
+ * to a couple of allocated pages
+ */
+
+ empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+ empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+ empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+ memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+ /* All pages are DMA'able in Etrax, so put all in the DMA'able zone */
+
+ zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+
+ for (i = 1; i < MAX_NR_ZONES; i++)
+ zones_size[i] = 0;
+
+ /* Use free_area_init_node instead of free_area_init, because the former
+ * is designed for systems where the DRAM starts at an address substantially
+ * higher than 0, like us (we start at PAGE_OFFSET). This saves space in the
+ * mem_map page array.
+ */
+
+ free_area_init_node(0, 0, 0, zones_size, PAGE_OFFSET, 0);
+}
+
+extern unsigned long loops_per_jiffy; /* init/main.c */
+unsigned long loops_per_usec;
+
+extern char _stext, _edata, _etext;
+extern char __init_begin, __init_end;
+
+void __init
+mem_init(void)
+{
+ int codesize, reservedpages, datasize, initsize;
+ unsigned long tmp;
+
+ if(!mem_map)
+ BUG();
+
+ /* max/min_low_pfn was set by setup.c
+ * now we just copy it to some other necessary places...
+ *
+ * high_memory was also set in setup.c
+ */
+
+ max_mapnr = num_physpages = max_low_pfn - min_low_pfn;
+
+ /* this will put all memory onto the freelists */
+ totalram_pages = free_all_bootmem();
+
+ reservedpages = 0;
+ for (tmp = 0; tmp < max_mapnr; tmp++) {
+ /*
+ * Only count reserved RAM pages
+ */
+ if (PageReserved(mem_map + tmp))
+ reservedpages++;
+ }
+
+ codesize = (unsigned long) &_etext - (unsigned long) &_stext;
+ datasize = (unsigned long) &_edata - (unsigned long) &_etext;
+ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
+
+ printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, "
+ "%dk init)\n" ,
+ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+ max_mapnr << (PAGE_SHIFT-10),
+ codesize >> 10,
+ reservedpages << (PAGE_SHIFT-10),
+ datasize >> 10,
+ initsize >> 10
+ );
+
+ /* HACK alert - calculate a loops_per_usec for asm/delay.h here
+ * since this is called just after calibrate_delay in init/main.c
+ * but before places which use udelay. cannot be in time.c since
+ * that is called _before_ calibrate_delay
+ */
+
+ loops_per_usec = (loops_per_jiffy * HZ) / 1000000;
+
+ return;
+}
+
+/* free the pages occupied by initialization code */
+
+void free_initmem(void)
+{
+#if 0
+ /* currently this is a bad idea since the cramfs image is catted onto
+ * the vmlinux image, and the end of that image is not page-padded so
+ * part of the cramfs image will be freed here
+ */
+ unsigned long addr;
+
+ addr = (unsigned long)(&__init_begin);
+ for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(addr));
+ set_page_count(virt_to_page(addr), 1);
+ free_page(addr);
+ totalram_pages++;
+ }
+ printk ("Freeing unused kernel memory: %dk freed\n",
+ (&__init_end - &__init_begin) >> 10);
+#endif
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+ int i;
+
+ i = max_mapnr;
+ val->totalram = 0;
+ val->sharedram = 0;
+ val->freeram = nr_free_pages();
+ val->bufferram = atomic_read(&buffermem_pages);
+ while (i-- > 0) {
+ if (PageReserved(mem_map+i))
+ continue;
+ val->totalram++;
+ if (!atomic_read(&mem_map[i].count))
+ continue;
+ val->sharedram += atomic_read(&mem_map[i].count) - 1;
+ }
+ val->mem_unit = PAGE_SIZE;
+ val->totalhigh = 0;
+ val->freehigh = 0;
+}
diff --git a/arch/cris/mm/tlb.c b/arch/cris/mm/tlb.c
new file mode 100644
index 000000000..ed74305ae
--- /dev/null
+++ b/arch/cris/mm/tlb.c
@@ -0,0 +1,301 @@
+/*
+ * linux/arch/cris/mm/tlb.c
+ *
+ * Copyright (C) 2000 Axis Communications AB
+ *
+ * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+#include <asm/svinto.h>
+
+#define D(x)
+
+/* CRIS in Etrax100LX TLB */
+
+#define NUM_TLB_ENTRIES 64
+#define NUM_PAGEID 64
+#define INVALID_PAGEID 63
+#define NO_CONTEXT -1
+
+/* The TLB can host up to 64 different mm contexts at the same time.
+ * The running context is R_MMU_CONTEXT, and each TLB entry contains a
+ * page_id that has to match to give a hit. In page_id_map, we keep track
+ * of which mm's we have assigned which page_id's, so that we know when
+ * to invalidate TLB entries.
+ *
+ * The last page_id is never running - it is used as an invalid page_id
+ * so we can make TLB entries that will never match.
+ */
+
+struct mm_struct *page_id_map[NUM_PAGEID];
+
+static int map_replace_ptr = 1; /* which page_id_map entry to replace next */
+
+/* invalidate all TLB entries */
+
+void
+flush_tlb_all()
+{
+ int i;
+
+ /* the vpn of i & 0xf is so we dont write similar TLB entries
+ * in the same 4-way entry group. details..
+ */
+
+ for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+ *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
+
+ *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
+ IO_FIELD(R_TLB_HI, vpn, i & 0xf ) );
+
+ *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) |
+ IO_STATE(R_TLB_LO, valid, no ) |
+ IO_STATE(R_TLB_LO, kernel,no ) |
+ IO_STATE(R_TLB_LO, we, no ) |
+ IO_FIELD(R_TLB_LO, pfn, 0 ) );
+ }
+ D(printk("tlb: flushed all\n"));
+}
+
+/* invalidate the selected mm context only */
+
+void
+flush_tlb_mm(struct mm_struct *mm)
+{
+ int i;
+ int page_id = mm->context;
+
+ D(printk("tlb: flush mm context %d (%p)\n", page_id, mm));
+
+ if(page_id == NO_CONTEXT)
+ return;
+
+ /* mark the TLB entries that match the page_id as invalid.
+ * here we could also check the _PAGE_GLOBAL bit and NOT flush
+ * global pages. is it worth the extra I/O ?
+ */
+
+ for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+ *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
+ if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) {
+ *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
+ IO_FIELD(R_TLB_HI, vpn, i & 0xf ) );
+
+ *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) |
+ IO_STATE(R_TLB_LO, valid, no ) |
+ IO_STATE(R_TLB_LO, kernel,no ) |
+ IO_STATE(R_TLB_LO, we, no ) |
+ IO_FIELD(R_TLB_LO, pfn, 0 ) );
+ }
+ }
+}
+
+/* invalidate a single page */
+
+void
+flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ struct mm_struct *mm = vma->vm_mm;
+ int page_id = mm->context;
+ int i;
+
+ D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm));
+
+ if(page_id == NO_CONTEXT)
+ return;
+
+ addr &= PAGE_MASK; /* perhaps not necessary */
+
+ /* invalidate those TLB entries that match both the mm context
+ * and the virtual address requested
+ */
+
+ for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+ unsigned long tlb_hi;
+ *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
+ tlb_hi = *R_TLB_HI;
+ if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id &&
+ (tlb_hi & PAGE_MASK) == addr) {
+ *R_TLB_HI = IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
+ addr; /* same addr as before works. */
+
+ *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) |
+ IO_STATE(R_TLB_LO, valid, no ) |
+ IO_STATE(R_TLB_LO, kernel,no ) |
+ IO_STATE(R_TLB_LO, we, no ) |
+ IO_FIELD(R_TLB_LO, pfn, 0 ) );
+ }
+ }
+}
+
+/* invalidate a page range */
+
+void
+flush_tlb_range(struct mm_struct *mm,
+ unsigned long start,
+ unsigned long end)
+{
+ int page_id = mm->context;
+ int i;
+
+ D(printk("tlb: flush range %p<->%p in context %d (%p)\n",
+ start, end, page_id, mm));
+
+ if(page_id == NO_CONTEXT)
+ return;
+
+ start &= PAGE_MASK; /* probably not necessary */
+ end &= PAGE_MASK; /* dito */
+
+ /* invalidate those TLB entries that match both the mm context
+ * and the virtual address range
+ */
+
+ for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+ unsigned long tlb_hi, vpn;
+ *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
+ tlb_hi = *R_TLB_HI;
+ vpn = tlb_hi & PAGE_MASK;
+ if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id &&
+ vpn >= start && vpn < end) {
+ *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
+ IO_FIELD(R_TLB_HI, vpn, i & 0xf ) );
+
+ *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) |
+ IO_STATE(R_TLB_LO, valid, no ) |
+ IO_STATE(R_TLB_LO, kernel,no ) |
+ IO_STATE(R_TLB_LO, we, no ) |
+ IO_FIELD(R_TLB_LO, pfn, 0 ) );
+ }
+ }
+}
+
+/*
+ * Initialize the context related info for a new mm_struct
+ * instance.
+ */
+
+int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ mm->context = NO_CONTEXT;
+ return 0;
+}
+
+/* the following functions are similar to those used in the PPC port */
+
+static inline void
+alloc_context(struct mm_struct *mm)
+{
+ struct mm_struct *old_mm;
+
+ D(printk("tlb: alloc context %d (%p)\n", map_replace_ptr, mm));
+
+ /* did we replace an mm ? */
+
+ old_mm = page_id_map[map_replace_ptr];
+
+ if(old_mm) {
+ /* throw out any TLB entries belonging to the mm we replace
+ * in the map
+ */
+ flush_tlb_mm(old_mm);
+
+ old_mm->context = NO_CONTEXT;
+ }
+
+ /* insert it into the page_id_map */
+
+ mm->context = map_replace_ptr;
+ page_id_map[map_replace_ptr] = mm;
+
+ map_replace_ptr++;
+
+ if(map_replace_ptr == INVALID_PAGEID)
+ map_replace_ptr = 0; /* wrap around */
+
+}
+
+/*
+ * if needed, get a new MMU context for the mm. otherwise nothing is done.
+ */
+
+void
+get_mmu_context(struct mm_struct *mm)
+{
+ if(mm->context == NO_CONTEXT)
+ alloc_context(mm);
+}
+
+/* called in schedule() just before actually doing the switch_to */
+
+void
+switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ struct task_struct *tsk, int cpu)
+{
+ /* make sure we have a context */
+
+ get_mmu_context(next);
+
+ /* switch context in the MMU */
+
+ D(printk("switching mmu_context to %d (%p)\n", next->context, next));
+
+ *R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context);
+}
+
+
+/* called by __exit_mm to destroy the used MMU context if any before
+ * destroying the mm itself. this is only called when the last user of the mm
+ * drops it.
+ *
+ * the only thing we really need to do here is mark the used PID slot
+ * as empty.
+ */
+
+void
+destroy_context(struct mm_struct *mm)
+{
+ if(mm->context != NO_CONTEXT) {
+ D(printk("destroy_context %d (%p)\n", mm->context, mm));
+ flush_tlb_mm(mm); /* TODO this might be redundant ? */
+ page_id_map[mm->context] = NULL;
+ /* mm->context = NO_CONTEXT; redundant.. mm will be freed */
+ }
+}
+
+/* called once during VM initialization, from init.c */
+
+void __init
+tlb_init(void)
+{
+ int i;
+
+ /* clear the page_id map */
+
+ for(i = 0; i < 64; i++)
+ page_id_map[i] = NULL;
+
+ /* invalidate the entire TLB */
+
+ flush_tlb_all();
+
+ /* the init_mm has context 0 from the boot */
+
+ page_id_map[0] = &init_mm;
+}
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
index abb382d8f..0baa87ea9 100644
--- a/arch/i386/boot/compressed/misc.c
+++ b/arch/i386/boot/compressed/misc.c
@@ -10,6 +10,7 @@
*/
#include <linux/vmalloc.h>
+#include <linux/tty.h>
#include <asm/io.h>
/*
* gzip declarations
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 05a2e3725..875a84bf9 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -162,6 +162,11 @@ CONFIG_IP_MULTICAST=y
# CONFIG_BRIDGE is not set
#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
# Telephony Support
#
# CONFIG_PHONE is not set
@@ -628,6 +633,8 @@ CONFIG_SOUND=y
CONFIG_SOUND_ES1371=y
# CONFIG_SOUND_ESSSOLO1 is not set
# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
# CONFIG_SOUND_SONICVIBES is not set
# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 9703e3304..4e1ee2f83 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -176,7 +176,7 @@
#include <linux/stddef.h>
#include <linux/timer.h>
#include <linux/fcntl.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/proc_fs.h>
#include <linux/miscdevice.h>
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
index 8d5a9efb3..4029a8d14 100644
--- a/arch/i386/kernel/dmi_scan.c
+++ b/arch/i386/kernel/dmi_scan.c
@@ -12,6 +12,8 @@ struct dmi_header
u16 handle;
};
+#define dmi_printk(x)
+
static char * __init dmi_string(struct dmi_header *dm, u8 s)
{
u8 *bp=(u8 *)dm;
@@ -73,13 +75,13 @@ int __init dmi_iterate(void (*decode)(struct dmi_header *))
u16 len=buf[7]<<8|buf[6];
u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
- printk(KERN_INFO "DMI %d.%d present.\n",
- buf[14]>>4, buf[14]&0x0F);
- printk(KERN_INFO "%d structures occupying %d bytes.\n",
+ dmi_printk((KERN_INFO "DMI %d.%d present.\n",
+ buf[14]>>4, buf[14]&0x0F));
+ dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
buf[13]<<8|buf[12],
- buf[7]<<8|buf[6]);
- printk(KERN_INFO "DMI table at 0x%08X.\n",
- buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]);
+ buf[7]<<8|buf[6]));
+ dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
+ buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]));
if(dmi_table(base,len, num, decode)==0)
return 0;
}
@@ -106,11 +108,11 @@ static void __init dmi_decode(struct dmi_header *dm)
if(*p && *p!=' ')
{
- printk("BIOS Vendor: %s\n", p);
- printk("BIOS Version: %s\n",
- dmi_string(dm, data[5]));
- printk("BIOS Release: %s\n",
- dmi_string(dm, data[8]));
+ dmi_printk(("BIOS Vendor: %s\n", p));
+ dmi_printk(("BIOS Version: %s\n",
+ dmi_string(dm, data[5])));
+ dmi_printk(("BIOS Release: %s\n",
+ dmi_string(dm, data[8])));
}
/*
@@ -144,13 +146,13 @@ static void __init dmi_decode(struct dmi_header *dm)
if(*p && *p!=' ')
{
- printk("System Vendor: %s.\n",p);
- printk("Product Name: %s.\n",
- dmi_string(dm, data[5]));
- printk("Version %s.\n",
- dmi_string(dm, data[6]));
- printk("Serial Number %s.\n",
- dmi_string(dm, data[7]));
+ dmi_printk(("System Vendor: %s.\n",p));
+ dmi_printk(("Product Name: %s.\n",
+ dmi_string(dm, data[5])));
+ dmi_printk(("Version %s.\n",
+ dmi_string(dm, data[6])));
+ dmi_printk(("Serial Number %s.\n",
+ dmi_string(dm, data[7])));
}
break;
case 2:
@@ -158,17 +160,17 @@ static void __init dmi_decode(struct dmi_header *dm)
if(*p && *p!=' ')
{
- printk("Board Vendor: %s.\n",p);
- printk("Board Name: %s.\n",
- dmi_string(dm, data[5]));
- printk("Board Version: %s.\n",
- dmi_string(dm, data[6]));
+ dmi_printk(("Board Vendor: %s.\n",p));
+ dmi_printk(("Board Name: %s.\n",
+ dmi_string(dm, data[5])));
+ dmi_printk(("Board Version: %s.\n",
+ dmi_string(dm, data[6])));
}
break;
case 3:
p=dmi_string(dm,data[8]);
if(*p && *p!=' ')
- printk("Asset Tag: %s.\n", p);
+ dmi_printk(("Asset Tag: %s.\n", p));
break;
}
}
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index c74b80135..400216f37 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -34,7 +34,7 @@
#define X86_HARD_MATH CPU_PARAMS+6
#define X86_CPUID CPU_PARAMS+8
#define X86_CAPABILITY CPU_PARAMS+12
-#define X86_VENDOR_ID CPU_PARAMS+16
+#define X86_VENDOR_ID CPU_PARAMS+28
/*
* swapper_pg_dir is the main page directory, address 0x00101000
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index 071b3991a..20bc14fc6 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -13,6 +13,7 @@
#include <linux/apm_bios.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/tty.h>
#include <asm/semaphore.h>
#include <asm/processor.h>
diff --git a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c
index a3a526b4b..ba97ca4bc 100644
--- a/arch/i386/kernel/i387.c
+++ b/arch/i386/kernel/i387.c
@@ -216,7 +216,7 @@ void set_fpu_twd( struct task_struct *tsk, unsigned short twd )
void set_fpu_mxcsr( struct task_struct *tsk, unsigned short mxcsr )
{
if ( cpu_has_xmm ) {
- tsk->thread.i387.fxsave.mxcsr = mxcsr;
+ tsk->thread.i387.fxsave.mxcsr = (mxcsr & 0xffbf);
}
}
@@ -354,6 +354,8 @@ static inline int restore_i387_fxsave( struct _fpstate *buf )
if ( __copy_from_user( &tsk->thread.i387.fxsave, &buf->_fxsr_env[0],
sizeof(struct i387_fxsave_struct) ) )
return 1;
+ /* mxcsr bit 6 and 31-16 must be zero for security reasons */
+ tsk->thread.i387.fxsave.mxcsr &= 0xffbf;
return convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf );
}
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index 570614282..ce8bc8737 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -6,7 +6,7 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index b17f499b4..e7fe3957b 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -1509,15 +1509,16 @@ static inline void check_timer(void)
* - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ.
* Linux doesn't really care, as it's not actually used
* for any interrupt handling anyway.
- * - IRQ13 is the FPU error IRQ, and may be connected
- * directly from the FPU to the old PIC. Linux doesn't
- * really care, because Linux doesn't want to use IRQ13
- * anyway (exception 16 is the proper FPU error signal)
+ * - There used to be IRQ13 here as well, but all
+ * MPS-compliant must not use it for FPU coupling and we
+ * want to use exception 16 anyway. And there are
+ * systems who connect it to an I/O APIC for other uses.
+ * Thus we don't mark it special any longer.
*
* Additionally, something is definitely wrong with irq9
* on PIIX4 boards.
*/
-#define PIC_IRQS ((1<<2)|(1<<13))
+#define PIC_IRQS (1<<2)
void __init setup_IO_APIC(void)
{
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index cf6878787..2c935207a 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -25,7 +25,7 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
@@ -312,6 +312,7 @@ static inline void get_irqlock(int cpu)
/* Uhhuh.. Somebody else got it. Wait.. */
do {
do {
+ rep_nop();
} while (test_bit(0,&global_irq_lock));
} while (test_and_set_bit(0,&global_irq_lock));
}
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index f0a88c20e..0bc04116d 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -52,7 +52,7 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/module.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/miscdevice.h>
#include <linux/devfs_fs_kernel.h>
diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
index 60764e3cd..7d85ce240 100644
--- a/arch/i386/kernel/mtrr.c
+++ b/arch/i386/kernel/mtrr.c
@@ -241,7 +241,7 @@
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/string.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/fs.h>
diff --git a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c
index 8281e3f82..bc1dd9c7e 100644
--- a/arch/i386/kernel/pci-irq.c
+++ b/arch/i386/kernel/pci-irq.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
index 258e63627..d2a8afbbb 100644
--- a/arch/i386/kernel/pci-pc.c
+++ b/arch/i386/kernel/pci-pc.c
@@ -843,30 +843,40 @@ static void __init pci_fixup_i450gx(struct pci_dev *d)
pcibios_last_bus = -1;
}
+/*
+ * ServerWorks host bridges -- Find and scan all secondary buses.
+ * Register 0x44 contains first, 0x45 last bus number routed there.
+ */
static void __init pci_fixup_serverworks(struct pci_dev *d)
{
- /*
- * ServerWorks host bridges -- Find and scan all secondary buses.
- * Register 0x44 contains first, 0x45 last bus number routed there.
- */
- u8 busno;
- pci_read_config_byte(d, 0x44, &busno);
- printk("PCI: ServerWorks host bridge: secondary bus %02x\n", busno);
- pci_scan_bus(busno, pci_root_ops, NULL);
- pcibios_last_bus = -1;
+ u8 busno1, busno2;
+
+ pci_read_config_byte(d, 0x44, &busno1);
+ pci_read_config_byte(d, 0x45, &busno2);
+ if (busno2 < busno1)
+ busno2 = busno1;
+ if (busno2 > pcibios_last_bus) {
+ pcibios_last_bus = busno2;
+ printk("PCI: ServerWorks host bridge: last bus %02x\n", pcibios_last_bus);
+ }
}
+/*
+ * Compaq host bridges -- Find and scan all secondary buses.
+ * This time registers 0xc8 and 0xc9.
+ */
static void __init pci_fixup_compaq(struct pci_dev *d)
{
- /*
- * Compaq host bridges -- Find and scan all secondary buses.
- * This time registers 0xc8 and 0xc9.
- */
- u8 busno;
- pci_read_config_byte(d, 0xc8, &busno);
- printk("PCI: Compaq host bridge: secondary bus %02x\n", busno);
- pci_scan_bus(busno, pci_root_ops, NULL);
- pcibios_last_bus = -1;
+ u8 busno1, busno2;
+
+ pci_read_config_byte(d, 0xc8, &busno1);
+ pci_read_config_byte(d, 0xc9, &busno2);
+ if (busno2 < busno1)
+ busno2 = busno1;
+ if (busno2 > pcibios_last_bus) {
+ pcibios_last_bus = busno2;
+ printk("PCI: Compaq host bridge: last bus %02x\n", busno2);
+ }
}
static void __init pci_fixup_umc_ide(struct pci_dev *d)
@@ -924,6 +934,22 @@ static void __init pci_fixup_latency(struct pci_dev *d)
pcibios_max_latency = 32;
}
+static void __init pci_fixup_vt8363(struct pci_dev *d)
+{
+ /*
+ * VIA VT8363 host bridge has broken feature 'PCI Master Read
+ * Caching'. It caches more than is good for it, sometimes
+ * serving the bus master with stale data. Some BIOSes enable
+ * it by default, so we disable it.
+ */
+ u8 tmp;
+ pci_read_config_byte(d, 0x70, &tmp);
+ if(tmp & 4) {
+ printk("PCI: Bus master read caching disabled\n");
+ pci_write_config_byte(d, 0x70, tmp & ~4);
+ }
+}
+
struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx },
@@ -936,6 +962,7 @@ struct pci_fixup pcibios_fixups[] = {
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, pci_fixup_vt8363 },
{ 0 }
};
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 35f11f20f..65f517966 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -23,7 +23,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 2c3f61f7f..03eeabc2f 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -71,7 +71,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
@@ -1104,6 +1104,9 @@ static inline void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
/*
* Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
* order to identify the Cyrix CPU model after we're out of setup.c
+ *
+ * Actually since bugs.h doesnt even reference this perhaps someone should
+ * fix the documentation ???
*/
unsigned char Cx86_dir0_msb __initdata = 0;
@@ -1129,6 +1132,8 @@ static char cyrix_model_mult2[] __initdata = "12233445";
* Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
* BIOSes for compatability with DOS games. This makes the udelay loop
* work correctly, and improves performance.
+ *
+ * FIXME: our newer udelay uses the tsc. We dont need to frob with SLOP
*/
extern void calibrate_delay(void) __init;
@@ -1401,6 +1406,7 @@ static void __init init_centaur(struct cpuinfo_x86 *c)
wrmsr (0x1107, lo, hi);
set_bit(X86_FEATURE_CX8, &c->x86_capability);
+ set_bit(X86_FEATURE_3DNOW, &c->x86_capability);
get_model_name(c);
display_cacheinfo(c);
@@ -1565,12 +1571,10 @@ static void __init init_intel(struct cpuinfo_x86 *c)
case 4:
if ( c->x86 > 6 && dl ) {
/* P4 family */
- if ( dl ) {
- /* L3 cache */
- cs = 128 << (dl-1);
- l3 += cs;
- break;
- }
+ /* L3 cache */
+ cs = 128 << (dl-1);
+ l3 += cs;
+ break;
}
/* else same as 8 - fall through */
case 8:
@@ -1870,8 +1874,34 @@ static int __init id_and_try_enable_cpuid(struct cpuinfo_x86 *c)
/* Detect Cyrix with disabled CPUID */
if ( c->x86 == 4 && test_cyrix_52div() ) {
+ unsigned char dir0, dir1;
+
strcpy(c->x86_vendor_id, "CyrixInstead");
c->x86_vendor = X86_VENDOR_CYRIX;
+
+ /* Actually enable cpuid on the older cyrix */
+
+ /* Retrieve CPU revisions */
+
+ do_cyrix_devid(&dir0, &dir1);
+
+ dir0>>=4;
+
+ /* Check it is an affected model */
+
+ if (dir0 == 5 || dir0 == 3)
+ {
+ unsigned char ccr3, ccr4;
+
+ printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n");
+ cli();
+ ccr3 = getCx86(CX86_CCR3);
+ setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
+ ccr4 = getCx86(CX86_CCR4);
+ setCx86(CX86_CCR4, ccr4 | 0x80); /* enable cpuid */
+ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
+ sti();
+ }
} else
/* Detect NexGen with old hypercode */
@@ -1914,7 +1944,6 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
(int *)&c->x86_vendor_id[4]);
get_cpu_vendor(c);
-
/* Initialize the standard set of capabilities */
/* Note that the vendor-specific code below might override */
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 7df9c875c..7b096279f 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -18,6 +18,7 @@
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
+#include <linux/tty.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/i387.h>
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 6607edf8a..6d6463542 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -4,7 +4,7 @@
* (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
* (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
*
- * This code is released under the GNU public license version 2 or
+ * This code is released under the GNU General Public License version 2 or
* later.
*/
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index aab31e839..a16965ac5 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -11,7 +11,7 @@
* Pentium Pro and Pentium-II/Xeon MP machines.
* Original development of Linux SMP code supported by Caldera.
*
- * This code is released under the GNU public license version 2 or
+ * This code is released under the GNU General Public License version 2 or
* later.
*
* Fixes
@@ -389,6 +389,7 @@ void __init smp_callin(void)
*/
if (test_bit(cpuid, &cpu_callout_map))
break;
+ rep_nop();
}
if (!time_before(jiffies, timeout)) {
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 7c02813af..6fa43476a 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -127,6 +127,11 @@ void show_trace(unsigned long * stack)
printk("\n");
}
+void show_trace_task(struct task_struct *tsk)
+{
+ show_trace(&tsk->thread.esp);
+}
+
void show_stack(unsigned long * esp)
{
unsigned long *stack;
diff --git a/arch/i386/kernel/visws_apic.c b/arch/i386/kernel/visws_apic.c
index 017b8eb58..995d0cdcd 100644
--- a/arch/i386/kernel/visws_apic.c
+++ b/arch/i386/kernel/visws_apic.c
@@ -20,7 +20,7 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
diff --git a/arch/i386/mm/extable.c b/arch/i386/mm/extable.c
index ba34c0395..2eb7ca6aa 100644
--- a/arch/i386/mm/extable.c
+++ b/arch/i386/mm/extable.c
@@ -4,6 +4,7 @@
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
extern const struct exception_table_entry __start___ex_table[];
@@ -30,26 +31,32 @@ search_one_table(const struct exception_table_entry *first,
return 0;
}
+extern spinlock_t modlist_lock;
+
unsigned long
search_exception_table(unsigned long addr)
{
- unsigned long ret;
-
+ unsigned long ret = 0;
+ unsigned long flags;
+
#ifndef CONFIG_MODULES
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
- if (ret) return ret;
+ return ret;
#else
/* The kernel is the last "module" -- no need to treat it special. */
struct module *mp;
+
+ spin_lock_irqsave(&modlist_lock, flags);
for (mp = module_list; mp != NULL; mp = mp->next) {
if (mp->ex_table_start == NULL)
continue;
ret = search_one_table(mp->ex_table_start,
mp->ex_table_end - 1, addr);
- if (ret) return ret;
+ if (ret)
+ break;
}
+ spin_unlock_irqrestore(&modlist_lock, flags);
+ return ret;
#endif
-
- return 0;
}
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index e2a9ee9fe..ccbc5dce1 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -81,7 +81,7 @@ extern spinlock_t console_lock, timerlist_lock;
/*
* Unlock any spinlocks which will prevent us from getting the
- * message out (timerlist_lock is aquired through the
+ * message out (timerlist_lock is acquired through the
* console unblank code)
*/
void bust_spinlocks(void)
diff --git a/arch/ia64/config.in b/arch/ia64/config.in
index ae49891c5..45a0793a6 100644
--- a/arch/ia64/config.in
+++ b/arch/ia64/config.in
@@ -70,7 +70,7 @@ if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC
fi
- bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM n
+ bool ' Enable SGI Medusa Simulator Support' CONFIG_IA64_SGI_SN1_SIM
define_bool CONFIG_DEVFS_DEBUG y
define_bool CONFIG_DEVFS_FS y
define_bool CONFIG_IA64_BRL_EMU y
@@ -79,8 +79,8 @@ if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
define_bool CONFIG_SGI_IOC3_ETH y
define_bool CONFIG_PERCPU_IRQ y
define_int CONFIG_CACHE_LINE_SHIFT 7
- bool ' Enable DISCONTIGMEM support' CONFIG_DISCONTIGMEM y
- bool ' Enable NUMA support' CONFIG_NUMA y
+ bool ' Enable DISCONTIGMEM support' CONFIG_DISCONTIGMEM
+ bool ' Enable NUMA support' CONFIG_NUMA
fi
define_bool CONFIG_KCORE_ELF y # On IA-64, we always want an ELF /proc/kcore.
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index 25007aa43..555c6097e 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -31,7 +31,7 @@
#include <linux/msg.h>
#include <linux/mm.h>
#include <linux/shm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/uio.h>
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index ab8961a54..cf2cbbb45 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -25,7 +25,7 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 155ee66b7..e4b8e8980 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -20,7 +20,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/kernel_stat.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/ptrace.h>
#include <linux/random.h> /* for rand_initialize_irq() */
#include <linux/signal.h>
diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
index de71a2d22..a48ad1120 100644
--- a/arch/ia64/kernel/palinfo.c
+++ b/arch/ia64/kernel/palinfo.c
@@ -23,9 +23,6 @@
#include <linux/proc_fs.h>
#include <linux/mm.h>
#include <linux/module.h>
-#if defined(MODVERSIONS)
-#include <linux/modversions.h>
-#endif
#include <asm/pal.h>
#include <asm/sal.h>
diff --git a/arch/ia64/kernel/pci.c b/arch/ia64/kernel/pci.c
index 37dbf811a..91e11dc51 100644
--- a/arch/ia64/kernel/pci.c
+++ b/arch/ia64/kernel/pci.c
@@ -10,7 +10,7 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 0b49bdcaa..71827cd69 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -447,7 +447,7 @@ ia64_poke (struct pt_regs *regs, struct task_struct *child, unsigned long addr,
* When new_bsp is zero and force_loadrs_to_zero is 1 (non-zero),
* loadrs is set to 0, and the bspstore value is set to the old bsp
* value. This will cause the stacked registers (r32 and up) to be
- * obtained entirely from the the child's memory space rather than
+ * obtained entirely from the child's memory space rather than
* from the kernel. (This makes it easier to write code for
* modifying the stacked registers in multi-threaded programs.)
*
diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
index f5ae7e497..7642df0c6 100644
--- a/arch/ia64/kernel/unwind.c
+++ b/arch/ia64/kernel/unwind.c
@@ -5,7 +5,7 @@
/*
* This file implements call frame unwind support for the Linux
* kernel. Parsing and processing the unwind information is
- * time-consuming, so this implementation translates the the unwind
+ * time-consuming, so this implementation translates the unwind
* descriptors into unwind scripts. These scripts are very simple
* (basically a sequence of assignments) and efficient to execute.
* They are cached for later re-use. Each script is specific for a
diff --git a/arch/ia64/lib/copy_user.S b/arch/ia64/lib/copy_user.S
index cabbf6653..ec9e2bf0a 100644
--- a/arch/ia64/lib/copy_user.S
+++ b/arch/ia64/lib/copy_user.S
@@ -518,7 +518,7 @@ failure_in_pipe2:
// Other key point:
// - if you fail on the ld8 in the head, it means you went straight
// to it, i.e. 8byte alignment within an unexisting page.
- // Again this comes from the fact that if you crossed just for the the ld8 then
+ // Again this comes from the fact that if you crossed just for the ld8 then
// you are 8byte aligned but also 16byte align, therefore you would
// either go for the 16byte copy loop OR the ld8 in the tail part.
// The combination ld1, ld2, ld4, ld8 where you fail on ld8 is impossible
diff --git a/arch/ia64/sn/io/klconflib.c b/arch/ia64/sn/io/klconflib.c
index 6fd745a0b..a156da166 100644
--- a/arch/ia64/sn/io/klconflib.c
+++ b/arch/ia64/sn/io/klconflib.c
@@ -511,7 +511,7 @@ find_gfxpipe(int pipenum)
moduleid_t kgm, pkgm;
int kgs, pkgs;
-#if defined(DEBUG) && (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1 || defined(CONFIG_IA64_GENERIC))) && defined(BRINGUP)
+#if defined(DEBUG) && (defined(CONFIG_SGI_IP35) || defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP)
printf("find_gfxpipe(): PIPE: %s mod %M slot %d\n",lb?lb->brd_name:"!LBRD",
lb->brd_module,lb->brd_slot);
#endif
diff --git a/arch/ia64/sn/io/klgraph_hack.c b/arch/ia64/sn/io/klgraph_hack.c
index cc9d77871..71bf25bc4 100644
--- a/arch/ia64/sn/io/klgraph_hack.c
+++ b/arch/ia64/sn/io/klgraph_hack.c
@@ -139,7 +139,7 @@ klgraph_hack_init(void)
uint64_t *tmp;
volatile u32 *tmp32;
-#ifdef 0
+#if 0
/* Preset some values */
/* Write IOERR clear to clear the CRAZY bit in the status */
tmp = (uint64_t *)0xc0000a0001c001f8; *tmp = (uint64_t)0xffffffff;
diff --git a/arch/ia64/sn/io/l1.c b/arch/ia64/sn/io/l1.c
index b8c5af674..6f4bf9f47 100644
--- a/arch/ia64/sn/io/l1.c
+++ b/arch/ia64/sn/io/l1.c
@@ -1462,7 +1462,7 @@ brl1_intrd( struct eframe_s *ep )
isr_reg = READ_L1_UART_REG(sc->nasid, REG_ISR);
}
- /* uart interrupts were blocked at bedrock when the the interrupt
+ /* uart interrupts were blocked at bedrock when the interrupt
* was initially answered; reenable them now
*/
intr_unblock_bit( sc->intr_cpu, UART_INTR );
@@ -2865,7 +2865,7 @@ _elscuart_readc( l1sc_t *sc )
/*
- * _elscuart_flush flushes queued output to the the L1.
+ * _elscuart_flush flushes queued output to the L1.
* This routine blocks until the queue is flushed.
*/
int
diff --git a/arch/ia64/sn/io/pcibr.c b/arch/ia64/sn/io/pcibr.c
index e5279fefd..9c71b8569 100644
--- a/arch/ia64/sn/io/pcibr.c
+++ b/arch/ia64/sn/io/pcibr.c
@@ -3753,7 +3753,7 @@ pcibr_attach(devfs_handle_t xconn_vhdl)
* completion interrupts will reach a CPU
* after all DMA data has reached memory.
* (Of course, there may be a few special
- * drivers/controlers that explicitly manage
+ * drivers/controllers that explicitly manage
* this ordering problem.)
*/
@@ -8609,7 +8609,7 @@ pcibr_dmard_error(
BRIDGE_ERRUPPR_ADDRMASK) << 32)));
/*
- * need to ensure that the xtalk adress in ioe
+ * need to ensure that the xtalk address in ioe
* maps to PCI error address read from bridge.
* How to convert PCI address back to Xtalk address ?
* (better idea: convert XTalk address to PCI address
@@ -9108,7 +9108,7 @@ pcibr_device_flags_set(devfs_handle_t pconn_vhdl,
#ifdef LITTLE_ENDIAN
/*
- * on sn-ia we need to twiddle the the addresses going out
+ * on sn-ia we need to twiddle the addresses going out
* the pci bus because we use the unswizzled synergy space
* (the alternative is to use the swizzled synergy space
* and byte swap the data)
diff --git a/arch/ia64/sn/io/xbow.c b/arch/ia64/sn/io/xbow.c
index 904cf732c..5becaa918 100644
--- a/arch/ia64/sn/io/xbow.c
+++ b/arch/ia64/sn/io/xbow.c
@@ -314,7 +314,7 @@ xbow_attach(devfs_handle_t conn)
/*
* get the name of this xbow vertex and keep the info.
- * This is needed during errors and interupts, but as
+ * This is needed during errors and interrupts, but as
* long as we have it, we can use it elsewhere.
*/
s = dev_to_name(vhdl, devnm, MAXDEVNAME);
diff --git a/arch/ia64/sn/io/xtalk.c b/arch/ia64/sn/io/xtalk.c
index 22810d54c..fedcffe22 100644
--- a/arch/ia64/sn/io/xtalk.c
+++ b/arch/ia64/sn/io/xtalk.c
@@ -959,7 +959,7 @@ xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */
widget_info->w_einfo = 0;
/*
* get the name of this xwidget vertex and keep the info.
- * This is needed during errors and interupts, but as
+ * This is needed during errors and interrupts, but as
* long as we have it, we can use it elsewhere.
*/
s = dev_to_name(widget,devnm,MAXDEVNAME);
diff --git a/arch/m68k/atari/hades-pci.c b/arch/m68k/atari/hades-pci.c
index 2c82e4a7b..6d8ec7333 100644
--- a/arch/m68k/atari/hades-pci.c
+++ b/arch/m68k/atari/hades-pci.c
@@ -17,7 +17,7 @@
#if defined(CONFIG_PCI) && defined(CONFIG_HADES)
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/pci.h>
@@ -372,6 +372,8 @@ struct pci_bus_info * __init init_hades_pci(void)
*/
bus = kmalloc(sizeof(struct pci_bus_info), GFP_KERNEL);
+ if (!bus)
+ return NULL;
memset(bus, 0, sizeof(struct pci_bus_info));
/*
diff --git a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
index b4a797f2e..b7b7b9553 100644
--- a/arch/m68k/atari/stram.c
+++ b/arch/m68k/atari/stram.c
@@ -16,7 +16,7 @@
#include <linux/major.h>
#include <linux/init.h>
#include <linux/swap.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/shm.h>
diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c
index 263cdaff7..23f9a9f1a 100644
--- a/arch/m68k/bvme6000/rtc.c
+++ b/arch/m68k/bvme6000/rtc.c
@@ -9,7 +9,7 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/init.h>
diff --git a/arch/m68k/ifpsp060/src/fplsp.S b/arch/m68k/ifpsp060/src/fplsp.S
index fc4939b17..903e4d544 100644
--- a/arch/m68k/ifpsp060/src/fplsp.S
+++ b/arch/m68k/ifpsp060/src/fplsp.S
@@ -9963,7 +9963,7 @@ mns_tiny:
# ALGORITHM *********************************************************** #
# An underflow should occur as the result of transcendental #
# emulation in the 060FPLSP. Create an underflow by using "fmul" #
-# and two very small numbers of appropriate sign so the the operating #
+# and two very small numbers of appropriate sign so the operating #
# system can log the event. #
# #
#########################################################################
@@ -10020,7 +10020,7 @@ unf_pos:
# ALGORITHM *********************************************************** #
# An overflow should occur as the result of transcendental #
# emulation in the 060FPLSP. Create an overflow by using "fmul" #
-# and two very lareg numbers of appropriate sign so the the operating #
+# and two very lareg numbers of appropriate sign so the operating #
# system can log the event. #
# For t_ovfl_sc() we take special care not to lose the INEX2 bit. #
# #
diff --git a/arch/m68k/ifpsp060/src/fpsp.S b/arch/m68k/ifpsp060/src/fpsp.S
index 1099d5e53..400d556c1 100644
--- a/arch/m68k/ifpsp060/src/fpsp.S
+++ b/arch/m68k/ifpsp060/src/fpsp.S
@@ -2944,7 +2944,7 @@ iea_fmovm_trace:
# The FPU is disabled and so we should really have taken the "Line
# F Emulator" exception. So, here we create an 8-word stack frame
# from our 4-word stack frame. This means we must calculate the length
-# the the faulting instruction to get the "next PC". This is trivial for
+# the faulting instruction to get the "next PC". This is trivial for
# immediate operands but requires some extra work for fmovm dynamic
# which can use most addressing modes.
iea_disabled:
diff --git a/arch/m68k/ifpsp060/src/isp.S b/arch/m68k/ifpsp060/src/isp.S
index 0fa431ab9..f779e2c8f 100644
--- a/arch/m68k/ifpsp060/src/isp.S
+++ b/arch/m68k/ifpsp060/src/isp.S
@@ -2516,7 +2516,7 @@ _mul64:
cmpi.b %d0, &0x7 # is src mode Dn or other?
bgt.w mul64_memop # src is in memory
-# multiplier operand in the the data register file.
+# multiplier operand in the data register file.
# must extract the register number and fetch the operand from the stack.
mul64_regop:
andi.w &0x7, %d0 # extract Dn
diff --git a/arch/m68k/ifpsp060/src/pfpsp.S b/arch/m68k/ifpsp060/src/pfpsp.S
index ec749785a..d175f7af0 100644
--- a/arch/m68k/ifpsp060/src/pfpsp.S
+++ b/arch/m68k/ifpsp060/src/pfpsp.S
@@ -2943,7 +2943,7 @@ iea_fmovm_trace:
# The FPU is disabled and so we should really have taken the "Line
# F Emulator" exception. So, here we create an 8-word stack frame
# from our 4-word stack frame. This means we must calculate the length
-# the the faulting instruction to get the "next PC". This is trivial for
+# the faulting instruction to get the "next PC". This is trivial for
# immediate operands but requires some extra work for fmovm dynamic
# which can use most addressing modes.
iea_disabled:
diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c
index c3b5dacba..d9cf9d9b8 100644
--- a/arch/m68k/kernel/bios32.c
+++ b/arch/m68k/kernel/bios32.c
@@ -26,7 +26,7 @@
*/
#include <linux/pci.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <asm/io.h>
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 3e62e6fe1..fcb7b915c 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -140,7 +140,7 @@ SYMBOL_NAME_LABEL(ret_from_exception)
bnes 2f | if so, skip resched, signals
| only allow interrupts when we are really the last one on the
| kernel stack, otherwise stack overflow can occur during
- | heavy interupt load
+ | heavy interrupt load
andw #ALLOWINT,%sr
tstl %curptr@(TASK_NEEDRESCHED)
jne SYMBOL_NAME(reschedule)
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 6934e4168..7fd40aaa4 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -20,7 +20,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/reboot.h>
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index d6065716a..afc769d42 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -10,7 +10,7 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/time.h>
#include <linux/kd.h>
#include <linux/mm.h>
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index 87d155ee0..f39171648 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -123,7 +123,7 @@ void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
/*
* Nubus IRQ handler, OSS style
*
- * Unlike the VIA/RBV this is on its own autovector interupt level.
+ * Unlike the VIA/RBV this is on its own autovector interrupt level.
*/
void oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
diff --git a/arch/m68k/math-emu/fp_cond.S b/arch/m68k/math-emu/fp_cond.S
index d9981d6a8..db53cbe54 100644
--- a/arch/m68k/math-emu/fp_cond.S
+++ b/arch/m68k/math-emu/fp_cond.S
@@ -17,7 +17,7 @@
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
+ * the GNU General Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
diff --git a/arch/m68k/math-emu/fp_decode.h b/arch/m68k/math-emu/fp_decode.h
index 233269415..259785f34 100644
--- a/arch/m68k/math-emu/fp_decode.h
+++ b/arch/m68k/math-emu/fp_decode.h
@@ -17,7 +17,7 @@
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
+ * the GNU General Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
diff --git a/arch/m68k/math-emu/fp_emu.h b/arch/m68k/math-emu/fp_emu.h
index 1a4e16802..bf2d88b29 100644
--- a/arch/m68k/math-emu/fp_emu.h
+++ b/arch/m68k/math-emu/fp_emu.h
@@ -17,7 +17,7 @@
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
+ * the GNU General Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
diff --git a/arch/m68k/math-emu/fp_entry.S b/arch/m68k/math-emu/fp_entry.S
index 55088e8e8..d270b9cb0 100644
--- a/arch/m68k/math-emu/fp_entry.S
+++ b/arch/m68k/math-emu/fp_entry.S
@@ -17,7 +17,7 @@
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
+ * the GNU General Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
diff --git a/arch/m68k/math-emu/fp_move.S b/arch/m68k/math-emu/fp_move.S
index 45fb02bfe..71bdf83ba 100644
--- a/arch/m68k/math-emu/fp_move.S
+++ b/arch/m68k/math-emu/fp_move.S
@@ -17,7 +17,7 @@
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
+ * the GNU General Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
diff --git a/arch/m68k/math-emu/fp_movem.S b/arch/m68k/math-emu/fp_movem.S
index 01058b33b..8354d39e6 100644
--- a/arch/m68k/math-emu/fp_movem.S
+++ b/arch/m68k/math-emu/fp_movem.S
@@ -17,7 +17,7 @@
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
+ * the GNU General Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
diff --git a/arch/m68k/math-emu/fp_scan.S b/arch/m68k/math-emu/fp_scan.S
index 4f404914c..97b73c1de 100644
--- a/arch/m68k/math-emu/fp_scan.S
+++ b/arch/m68k/math-emu/fp_scan.S
@@ -17,7 +17,7 @@
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
+ * the GNU General Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
diff --git a/arch/m68k/math-emu/fp_util.S b/arch/m68k/math-emu/fp_util.S
index a909d813b..12e1e7863 100644
--- a/arch/m68k/math-emu/fp_util.S
+++ b/arch/m68k/math-emu/fp_util.S
@@ -17,7 +17,7 @@
* written permission.
*
* ALTERNATIVELY, this product may be distributed under the terms of
- * the GNU Public License, in which case the provisions of the GPL are
+ * the GNU General Public License, in which case the provisions of the GPL are
* required INSTEAD OF the above restrictions. (This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD-style copyright.)
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index 55a455423..da23f36ec 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/setup.h>
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index a3c4f38c5..164c5cc72 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/pagemap.h>
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
index 677621629..0c118ceb0 100644
--- a/arch/m68k/mvme16x/rtc.c
+++ b/arch/m68k/mvme16x/rtc.c
@@ -9,7 +9,7 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/init.h>
diff --git a/arch/mips/baget/irq.c b/arch/mips/baget/irq.c
index 2fd91c9c9..3a7e9b177 100644
--- a/arch/mips/baget/irq.c
+++ b/arch/mips/baget/irq.c
@@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/delay.h>
diff --git a/arch/mips/baget/vacserial.c b/arch/mips/baget/vacserial.c
index 12021daf4..61e459dfe 100644
--- a/arch/mips/baget/vacserial.c
+++ b/arch/mips/baget/vacserial.c
@@ -56,7 +56,7 @@
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#ifdef CONFIG_SERIAL_CONSOLE
diff --git a/arch/mips/dec/irq.c b/arch/mips/dec/irq.c
index e57485d25..95bdc9ca2 100644
--- a/arch/mips/dec/irq.c
+++ b/arch/mips/dec/irq.c
@@ -13,7 +13,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <asm/bitops.h>
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index 9cea1dad3..1f78df82e 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -323,6 +323,7 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
diff --git a/arch/mips/defconfig-decstation b/arch/mips/defconfig-decstation
index 872744d32..6da63e12a 100644
--- a/arch/mips/defconfig-decstation
+++ b/arch/mips/defconfig-decstation
@@ -317,6 +317,7 @@ CONFIG_OSF_PARTITION=y
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
# CONFIG_SGI_PARTITION is not set
diff --git a/arch/mips/defconfig-ip22 b/arch/mips/defconfig-ip22
index 9cea1dad3..1f78df82e 100644
--- a/arch/mips/defconfig-ip22
+++ b/arch/mips/defconfig-ip22
@@ -323,6 +323,7 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
diff --git a/arch/mips/defconfig-rm200 b/arch/mips/defconfig-rm200
index a9c2aee2f..d5196eb35 100644
--- a/arch/mips/defconfig-rm200
+++ b/arch/mips/defconfig-rm200
@@ -340,6 +340,7 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
diff --git a/arch/mips/galileo-boards/ev64120/irq.c b/arch/mips/galileo-boards/ev64120/irq.c
index 44b0bf092..ff2d0c25f 100644
--- a/arch/mips/galileo-boards/ev64120/irq.c
+++ b/arch/mips/galileo-boards/ev64120/irq.c
@@ -41,7 +41,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/irq.h>
#include <asm/bitops.h>
diff --git a/arch/mips/galileo-boards/ev64120/pci_bios.c b/arch/mips/galileo-boards/ev64120/pci_bios.c
index 75d2b4c8b..8500c4c0a 100644
--- a/arch/mips/galileo-boards/ev64120/pci_bios.c
+++ b/arch/mips/galileo-boards/ev64120/pci_bios.c
@@ -36,7 +36,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/version.h>
#include <asm/pci.h>
#include <asm/io.h>
diff --git a/arch/mips/galileo-boards/ev96100/irq.c b/arch/mips/galileo-boards/ev96100/irq.c
index 3cff158fa..7a7b7d9de 100644
--- a/arch/mips/galileo-boards/ev96100/irq.c
+++ b/arch/mips/galileo-boards/ev96100/irq.c
@@ -43,7 +43,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <asm/bitops.h>
diff --git a/arch/mips/gt64120/common/irq.c b/arch/mips/gt64120/common/irq.c
index c0fdcc44a..5192dfa1e 100644
--- a/arch/mips/gt64120/common/irq.c
+++ b/arch/mips/gt64120/common/irq.c
@@ -41,7 +41,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/irq.h>
#include <asm/bitops.h>
diff --git a/arch/mips/gt64120/common/pci.c b/arch/mips/gt64120/common/pci.c
index d6b647e11..e74b86bd6 100644
--- a/arch/mips/gt64120/common/pci.c
+++ b/arch/mips/gt64120/common/pci.c
@@ -39,7 +39,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/version.h>
#include <asm/pci.h>
#include <asm/io.h>
diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c
index 8d832aadb..407031e6a 100644
--- a/arch/mips/gt64120/momenco_ocelot/irq.c
+++ b/arch/mips/gt64120/momenco_ocelot/irq.c
@@ -37,7 +37,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/irq.h>
#include <asm/bitops.h>
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 5f63b0910..8daf876c1 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -24,7 +24,7 @@
#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/shm.h>
#include <linux/personality.h>
#include <linux/elfcore.h>
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index 39b3b8ce2..1b8da2b85 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -13,7 +13,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/random.h>
#include <linux/sched.h>
diff --git a/arch/mips/kernel/old-irq.c b/arch/mips/kernel/old-irq.c
index 090da659a..a13948d32 100644
--- a/arch/mips/kernel/old-irq.c
+++ b/arch/mips/kernel/old-irq.c
@@ -22,7 +22,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <asm/bitops.h>
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index d3ef5124f..dd2810109 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -14,7 +14,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mman.h>
#include <linux/sys.h>
#include <linux/user.h>
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 34b1691eb..8815cbb20 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -20,7 +20,7 @@
#include <linux/string.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/utsname.h>
#include <linux/a.out.h>
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 3577d89e9..ab051858e 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -10,7 +10,7 @@
#include <linux/pagemap.h>
#include <linux/mm.h>
#include <linux/mman.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/errno.h>
#include <linux/timex.h>
diff --git a/arch/mips/mm/extable.c b/arch/mips/mm/extable.c
index bc7cb7ab9..72d4c9040 100644
--- a/arch/mips/mm/extable.c
+++ b/arch/mips/mm/extable.c
@@ -3,6 +3,7 @@
*/
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
extern const struct exception_table_entry __start___ex_table[];
@@ -29,26 +30,32 @@ search_one_table(const struct exception_table_entry *first,
return 0;
}
+extern spinlock_t modlist_lock;
+
unsigned long
search_exception_table(unsigned long addr)
{
- unsigned long ret;
-
+ unsigned long ret = 0;
+ unsigned long flags;
+
#ifndef CONFIG_MODULES
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
- if (ret) return ret;
+ return ret;
#else
/* The kernel is the last "module" -- no need to treat it special. */
struct module *mp;
+
+ spin_lock_irqsave(&modlist_lock, flags);
for (mp = module_list; mp != NULL; mp = mp->next) {
if (mp->ex_table_start == NULL)
continue;
ret = search_one_table(mp->ex_table_start,
mp->ex_table_end - 1, addr);
- if (ret) return ret;
+ if (ret)
+ break;
}
+ spin_unlock_irqrestore(&modlist_lock, flags);
+ return ret;
#endif
-
- return 0;
}
diff --git a/arch/mips/sgi/kernel/indy_int.c b/arch/mips/sgi/kernel/indy_int.c
index ab9168cb6..dca960944 100644
--- a/arch/mips/sgi/kernel/indy_int.c
+++ b/arch/mips/sgi/kernel/indy_int.c
@@ -18,7 +18,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
diff --git a/arch/mips64/defconfig b/arch/mips64/defconfig
index 8c2747bba..a15cc5785 100644
--- a/arch/mips64/defconfig
+++ b/arch/mips64/defconfig
@@ -121,6 +121,11 @@ CONFIG_IP_PNP=y
# CONFIG_BRIDGE is not set
#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
# Telephony Support
#
# CONFIG_PHONE is not set
@@ -422,6 +427,7 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
diff --git a/arch/mips64/defconfig-ip22 b/arch/mips64/defconfig-ip22
index 43b521604..2a9aab549 100644
--- a/arch/mips64/defconfig-ip22
+++ b/arch/mips64/defconfig-ip22
@@ -111,6 +111,11 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_BRIDGE is not set
#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
# Telephony Support
#
# CONFIG_PHONE is not set
diff --git a/arch/mips64/defconfig-ip27 b/arch/mips64/defconfig-ip27
index 8c2747bba..a15cc5785 100644
--- a/arch/mips64/defconfig-ip27
+++ b/arch/mips64/defconfig-ip27
@@ -121,6 +121,11 @@ CONFIG_IP_PNP=y
# CONFIG_BRIDGE is not set
#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
# Telephony Support
#
# CONFIG_PHONE is not set
@@ -422,6 +427,7 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
CONFIG_SGI_PARTITION=y
diff --git a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c
index b45f23a36..7060ce768 100644
--- a/arch/mips64/kernel/process.c
+++ b/arch/mips64/kernel/process.c
@@ -13,7 +13,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mman.h>
#include <linux/sys.h>
#include <linux/user.h>
diff --git a/arch/mips64/kernel/setup.c b/arch/mips64/kernel/setup.c
index 74511142b..7c996a336 100644
--- a/arch/mips64/kernel/setup.c
+++ b/arch/mips64/kernel/setup.c
@@ -18,7 +18,7 @@
#include <linux/string.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/utsname.h>
#include <linux/a.out.h>
diff --git a/arch/mips64/mm/extable.c b/arch/mips64/mm/extable.c
index f9ae91ae0..af21d4ad1 100644
--- a/arch/mips64/mm/extable.c
+++ b/arch/mips64/mm/extable.c
@@ -9,6 +9,7 @@
*/
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/spinlock.h>
#include <asm/uaccess.h>
extern const struct exception_table_entry __start___ex_table[];
@@ -35,26 +36,32 @@ search_one_table(const struct exception_table_entry *first,
return 0;
}
+extern spinlock_t modlist_lock;
+
unsigned long
search_exception_table(unsigned long addr)
{
- unsigned long ret;
-
+ unsigned long ret = 0;
+ unsigned long flags;
+
#ifndef CONFIG_MODULES
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
- if (ret) return ret;
+ return ret;
#else
/* The kernel is the last "module" -- no need to treat it special. */
struct module *mp;
+
+ spin_lock_irqsave(&modlist_lock, flags);
for (mp = module_list; mp != NULL; mp = mp->next) {
if (mp->ex_table_start == NULL)
continue;
ret = search_one_table(mp->ex_table_start,
mp->ex_table_end - 1, addr);
- if (ret) return ret;
+ if (ret)
+ break;
}
+ spin_unlock_irqrestore(&modlist_lock, flags);
+ return ret;
#endif
-
- return 0;
}
diff --git a/arch/mips64/mm/fault.c b/arch/mips64/mm/fault.c
index c8f4534d4..710b6b309 100644
--- a/arch/mips64/mm/fault.c
+++ b/arch/mips64/mm/fault.c
@@ -61,7 +61,7 @@ extern spinlock_t console_lock, timerlist_lock;
/*
* Unlock any spinlocks which will prevent us from getting the
- * message out (timerlist_lock is aquired through the
+ * message out (timerlist_lock is acquired through the
* console unblank code)
*/
void bust_spinlocks(void)
diff --git a/arch/mips64/sgi-ip22/ip22-int.c b/arch/mips64/sgi-ip22/ip22-int.c
index 70a5fdf3a..774b4fc33 100644
--- a/arch/mips64/sgi-ip22/ip22-int.c
+++ b/arch/mips64/sgi-ip22/ip22-int.c
@@ -17,7 +17,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c
index 446e3df41..651dc7b41 100644
--- a/arch/mips64/sgi-ip27/ip27-irq.c
+++ b/arch/mips64/sgi-ip27/ip27-irq.c
@@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp_lock.h>
#include <linux/kernel_stat.h>
diff --git a/arch/parisc/kernel/ccio-dma.c b/arch/parisc/kernel/ccio-dma.c
index c8f72c813..1df06d59d 100644
--- a/arch/parisc/kernel/ccio-dma.c
+++ b/arch/parisc/kernel/ccio-dma.c
@@ -36,7 +36,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <linux/pci.h>
diff --git a/arch/parisc/kernel/iosapic.c b/arch/parisc/kernel/iosapic.c
index 688cbf9bb..917fa76eb 100644
--- a/arch/parisc/kernel/iosapic.c
+++ b/arch/parisc/kernel/iosapic.c
@@ -162,7 +162,7 @@
#include <linux/spinlock.h>
#include <linux/pci.h> /* pci cfg accessor functions */
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h> /* irqaction */
#include <linux/irq.h> /* irq_region support */
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index aec36f7cc..b3914a1b1 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -35,7 +35,7 @@
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
diff --git a/arch/parisc/kernel/lba_pci.c b/arch/parisc/kernel/lba_pci.c
index 6096d0153..490b4659b 100644
--- a/arch/parisc/kernel/lba_pci.c
+++ b/arch/parisc/kernel/lba_pci.c
@@ -36,7 +36,7 @@
#include <linux/init.h> /* for __init and __devinit */
#include <linux/pci.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <asm/byteorder.h>
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
index 88a9ddc77..f885584f5 100644
--- a/arch/parisc/kernel/pci-dma.c
+++ b/arch/parisc/kernel/pci-dma.c
@@ -26,7 +26,7 @@
#include <linux/pci.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index a8d7a707e..d699f5dab 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -19,7 +19,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
diff --git a/arch/parisc/kernel/sba_iommu.c b/arch/parisc/kernel/sba_iommu.c
index b7b541478..701bf38cf 100644
--- a/arch/parisc/kernel/sba_iommu.c
+++ b/arch/parisc/kernel/sba_iommu.c
@@ -23,7 +23,7 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/mm.h>
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index 16a35df30..a14b5ac62 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -28,7 +28,7 @@
#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
diff --git a/arch/parisc/mm/kmap.c b/arch/parisc/mm/kmap.c
index 686d540d9..4bd5dd4b4 100644
--- a/arch/parisc/mm/kmap.c
+++ b/arch/parisc/mm/kmap.c
@@ -7,7 +7,7 @@
#include <linux/string.h>
#include <linux/pci.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c
index 77b0eb279..95d58d523 100644
--- a/arch/ppc/8260_io/enet.c
+++ b/arch/ppc/8260_io/enet.c
@@ -30,7 +30,7 @@
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
index c8c31bd42..faf267700 100644
--- a/arch/ppc/8260_io/fcc_enet.c
+++ b/arch/ppc/8260_io/fcc_enet.c
@@ -23,7 +23,7 @@
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -46,7 +46,7 @@
#define TX_TIMEOUT (2*HZ)
/* The number of Tx and Rx buffers. These are allocated from the page
- * pool. The code may assume these are power of two, so it it best
+ * pool. The code may assume these are power of two, so it is best
* to keep them that size.
* We don't need to allocate pages for the transmitter. We just use
* the skbuffer directly.
diff --git a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c
index e6e223b61..ad61c9b7f 100644
--- a/arch/ppc/8260_io/uart.c
+++ b/arch/ppc/8260_io/uart.c
@@ -38,7 +38,7 @@
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
diff --git a/arch/ppc/8xx_io/commproc.h b/arch/ppc/8xx_io/commproc.h
index 7faae4ca3..a8194cb21 100644
--- a/arch/ppc/8xx_io/commproc.h
+++ b/arch/ppc/8xx_io/commproc.h
@@ -76,7 +76,7 @@ typedef struct cpm_buf_desc {
uint cbd_bufaddr; /* Buffer address in host memory */
} cbd_t;
-#define BD_SC_EMPTY ((ushort)0x8000) /* Recieve is empty */
+#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */
#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */
#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */
#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index 01eb2758b..39628da04 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -29,7 +29,7 @@
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c
index 6e5e9e686..33849ea0e 100644
--- a/arch/ppc/8xx_io/fec.c
+++ b/arch/ppc/8xx_io/fec.c
@@ -33,7 +33,7 @@
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -73,7 +73,7 @@ typedef struct {
} phy_info_t;
/* The number of Tx and Rx buffers. These are allocated from the page
- * pool. The code may assume these are power of two, so it it best
+ * pool. The code may assume these are power of two, so it is best
* to keep them that size.
* We don't need to allocate pages for the transmitter. We just use
* the skbuffer directly.
@@ -953,7 +953,7 @@ static phy_info_t phy_info_lxt970 = {
/*
* I had some nice ideas of running the MDIO faster...
* The 971 should support 8MHz and I tried it, but things acted really
- * wierd, so 2.5 MHz ought to be enough for anyone...
+ * weird, so 2.5 MHz ought to be enough for anyone...
*/
static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
diff --git a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
index 598e13ac0..4688d57a8 100644
--- a/arch/ppc/8xx_io/uart.c
+++ b/arch/ppc/8xx_io/uart.c
@@ -34,7 +34,7 @@
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
diff --git a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c
index b895e6c02..b919e6bff 100644
--- a/arch/ppc/amiga/amiints.c
+++ b/arch/ppc/amiga/amiints.c
@@ -119,7 +119,7 @@ void amiga_init_IRQ(void)
custom.intreq = 0x7fff;
#ifdef CONFIG_APUS
- /* Clear any inter-CPU interupt requests. Circumvents bug in
+ /* Clear any inter-CPU interrupt requests. Circumvents bug in
Blizzard IPL emulation HW (or so it appears). */
APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
diff --git a/arch/ppc/kernel/checks.c b/arch/ppc/kernel/checks.c
index 9bb8e690e..41e35f878 100644
--- a/arch/ppc/kernel/checks.c
+++ b/arch/ppc/kernel/checks.c
@@ -7,7 +7,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c
index 5682f3fad..04b812268 100644
--- a/arch/ppc/kernel/chrp_setup.c
+++ b/arch/ppc/kernel/chrp_setup.c
@@ -18,7 +18,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
index 6ca616979..5aaabccfa 100644
--- a/arch/ppc/kernel/idle.c
+++ b/arch/ppc/kernel/idle.c
@@ -21,7 +21,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index 02ff4d964..279bccf0a 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -40,7 +40,7 @@
#include <linux/timex.h>
#include <linux/config.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/irq.h>
diff --git a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c
index a55f5235d..91114e459 100644
--- a/arch/ppc/kernel/m8260_setup.c
+++ b/arch/ppc/kernel/m8260_setup.c
@@ -22,7 +22,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
diff --git a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c
index f9813fa75..fb585641c 100644
--- a/arch/ppc/kernel/m8xx_setup.c
+++ b/arch/ppc/kernel/m8xx_setup.c
@@ -22,7 +22,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c
index a9a1777ca..1593b3b1c 100644
--- a/arch/ppc/kernel/pmac_pic.c
+++ b/arch/ppc/kernel/pmac_pic.c
@@ -457,7 +457,7 @@ pmac_pic_init(void)
/*
* These procedures are used in implementing sleep on the powerbooks.
* sleep_save_intrs() saves the states of all interrupt enables
- * and disables all interupts except for the nominated one.
+ * and disables all interrupts except for the nominated one.
* sleep_restore_intrs() restores the states of all interrupt enables.
*/
unsigned int sleep_save_mask[2];
diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c
index e7be1114e..839f66d80 100644
--- a/arch/ppc/kernel/pmac_setup.c
+++ b/arch/ppc/kernel/pmac_setup.c
@@ -30,7 +30,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index 6de2d94fe..43a05659d 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -6,6 +6,7 @@
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/interrupt.h>
+#include <linux/tty.h>
#include <linux/vt_kern.h>
#include <linux/nvram.h>
#include <linux/spinlock.h>
diff --git a/arch/ppc/kernel/prep_nvram.c b/arch/ppc/kernel/prep_nvram.c
index 3d34a853f..770808c6e 100644
--- a/arch/ppc/kernel/prep_nvram.c
+++ b/arch/ppc/kernel/prep_nvram.c
@@ -6,7 +6,7 @@
*/
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/ioport.h>
#include <asm/init.h>
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c
index 64ad519cb..0c23c51ac 100644
--- a/arch/ppc/kernel/prep_setup.c
+++ b/arch/ppc/kernel/prep_setup.c
@@ -19,7 +19,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index c4c76adec..259481bcd 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -29,7 +29,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/elf.h>
#include <linux/init.h>
diff --git a/arch/ppc/kernel/residual.c b/arch/ppc/kernel/residual.c
index 1c4bdfbd8..7aa75dbbb 100644
--- a/arch/ppc/kernel/residual.c
+++ b/arch/ppc/kernel/residual.c
@@ -30,7 +30,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 58fb87e9c..73afefc56 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -12,6 +12,7 @@
#include <linux/delay.h>
#include <linux/blk.h>
#include <linux/ide.h>
+#include <linux/tty.h>
#include <linux/bootmem.h>
#include <asm/init.h>
diff --git a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c
index a97c272d3..26a8fe165 100644
--- a/arch/ppc/kernel/softemu8xx.c
+++ b/arch/ppc/kernel/softemu8xx.c
@@ -21,7 +21,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 8bd9ebded..0269254cf 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -23,7 +23,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/interrupt.h>
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 7af7bb937..3023d54a2 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -14,6 +14,7 @@
#
LD=$(CROSS_COMPILE)ld -m elf_s390
+CPP=$(CC) -E
OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
LDFLAGS=-e start
LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS)
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index 817152810..fb112b964 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -10,12 +10,11 @@
OBJCOPY = $(CROSS_COMPILE)objcopy
O_TARGET :=
-O_OBJS :=
include $(TOPDIR)/Rules.make
.S.o:
- $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
%.lnk: %.o
$(LD) -Ttext 0x0 -o $@ $<
diff --git a/arch/s390/boot/ipldump.S b/arch/s390/boot/ipldump.S
index 7868268af..3a09d1fea 100644
--- a/arch/s390/boot/ipldump.S
+++ b/arch/s390/boot/ipldump.S
@@ -38,7 +38,7 @@ _start:
#
# find out memory size
#
- mvc 104(8,0),.Lpcmem0 # setup program check handler
+ mvc 104(8),.Lpcmem0 # setup program check handler
slr %r3,%r3
lhi %r2,1
sll %r2,20
diff --git a/arch/s390/boot/ipleckd.S b/arch/s390/boot/ipleckd.S
index 63b0330b2..d66a8d684 100644
--- a/arch/s390/boot/ipleckd.S
+++ b/arch/s390/boot/ipleckd.S
@@ -3,7 +3,7 @@
# IPL record for 3380/3390 DASD
#
# S390 version
-# Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+# Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
# Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
#
#
@@ -11,6 +11,8 @@
# FIXME: should insert zeroes into memory when filling holes
# FIXME: calculate blkpertrack from rdc data and blksize
+# change 09/20/00 removed obsolete store of ipldevice to textesegment
+
# Usage of registers
# r1: ipl subchannel ( general use, dont overload without save/restore !)
# r10:
@@ -39,7 +41,7 @@
.org 0xf0 # Lets start now...
_start: .globl _start
- l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore
+ l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore
st %r1,__LC_IPLDEV # keep it for reipl
stsch .Lrdcdata
oi .Lrdcdata+5,0x84 # enable ssch and multipath mode
@@ -111,10 +113,10 @@ _start: .globl _start
mvc 0x600(256,%r3),0x180(%r4)
mvc 0x700(256,%r3),0x280(%r4)
.Lrunkern:
- lhi %r2,17
- sll %r2,12
- st %r1,0xc6c(%r2) # store iplsubchannel to lowcore
- st %r1,0xc6c # store iplsubchannel to lowcore
+# lhi %r2,17
+# sll %r2,12
+# st %r1,0xc6c(%r2) # store iplsubchannel to lowcore
+# st %r1,0xc6c # store iplsubchannel to lowcore
br %r3
# This function does the start IO
# r2: number of first block to read ( input by caller )
@@ -140,17 +142,16 @@ _start: .globl _start
lr %r15,%r4 # save number or blocks
slr %r7,%r7
icm %r7,3,.Lrdcdata+14 # load heads to r7
+ lhi %r6,9
+ clc .Lrdcdata+3(2),.L9345
+ je .L011
+ lhi %r6,10
+ clc .Lrdcdata+3(2),.L3380
+ je .L011
+ lhi %r6,12
clc .Lrdcdata+3(2),.L3390
- jne .L010 # 3380 or 3390 ?
- lhi %r6,12 # setup r6 correct!
- j .L011
-.L010:
- clc .Lrdcdata+3(2),.L9343
- jne .L013
- lhi %r6,9
- j .L011
-.L013:
- lhi %r6,10
+ je .L011
+ bras %r14,.Ldisab
.L011:
# loop for nbl times
.Lrdloop:
@@ -245,10 +246,13 @@ _start: .globl _start
.long 0x00008000 # they are loaded with a LM
.L3390:
.word 0x3390
-.L9343:
- .word 0x9343
+.L9345:
+ .word 0x9345
+.L3380:
+ .word 0x3380
.Lnull:
.long 0x00000000,0x00000000
+ .align 4
.Lrdcdata:
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
diff --git a/arch/s390/config.in b/arch/s390/config.in
index 4415799ff..fc3b430a6 100644
--- a/arch/s390/config.in
+++ b/arch/s390/config.in
@@ -44,31 +44,20 @@ bool 'Networking support' CONFIG_NET
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
bool 'Sysctl support' CONFIG_SYSCTL
+define CONFIG_KCORE ELF
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
endmenu
source drivers/s390/Config.in
-mainmenu_option next_comment
-comment 'Character devices'
-bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
-if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
- int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
-fi
-
-endmenu
-
if [ "$CONFIG_NET" = "y" ]; then
source net/Config.in
fi
source fs/Config.in
-# source drivers/char/Config.in
-
-# source drivers/media/Config.in
-
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 459d51ebb..c4e590e75 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,6 +1,9 @@
#
# Automatically generated by make menuconfig: don't edit
#
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
CONFIG_UID16=y
CONFIG_ARCH_S390=y
@@ -20,7 +23,7 @@ CONFIG_IEEEFPU_EMULATION=y
#
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_KMOD=y
#
# General setup
@@ -34,41 +37,60 @@ CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PROCESS_DEBUG is not set
#
-# S/390 block device drivers
+# Block device drivers
#
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=24576
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_MDISK is not set
+CONFIG_BLK_DEV_XPRAM=m
CONFIG_DASD=y
CONFIG_DASD_ECKD=y
-# CONFIG_DASD_MDSK is not set
+CONFIG_DASD_FBA=y
#
-# S/390 Network device support
+# Multi-device support (RAID and LVM)
#
-# CONFIG_CHANDEV is not set
-CONFIG_NETDEVICES=y
-CONFIG_CTC=y
-CONFIG_IUCV=y
-# CONFIG_DUMMY is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_TR=y
-# CONFIG_FDDI is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+# CONFIG_MD_LINEAR is not set
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_BLK_DEV_LVM=m
+CONFIG_LVM_PROC_FS=y
#
-# S/390 Terminal and Console options
+# Character device drivers
#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
CONFIG_3215=y
CONFIG_3215_CONSOLE=y
CONFIG_HWC=y
CONFIG_HWC_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_S390_TAPE=m
+CONFIG_S390_TAPE_CHAR=y
+CONFIG_S390_TAPE_BLOCK=y
+CONFIG_S390_TAPE_3490=y
+CONFIG_S390_TAPE_3480=y
+
+#
+# Network device drivers
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_TR=y
+# CONFIG_FDDI is not set
+# CONFIG_CHANDEV is not set
+CONFIG_CTC=m
+CONFIG_IUCV=m
#
# Networking options
@@ -82,25 +104,24 @@ CONFIG_NETLINK=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
+# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
-CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -118,6 +139,7 @@ CONFIG_SKB_LARGE=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
@@ -126,28 +148,37 @@ CONFIG_SKB_LARGE=y
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
# CONFIG_DEVFS_DEBUG is not set
# CONFIG_DEVPTS_FS is not set
# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
@@ -155,6 +186,16 @@ CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
@@ -168,10 +209,10 @@ CONFIG_IBM_PARTITION=y
# CONFIG_MAC_PARTITION is not set
# CONFIG_MSDOS_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
#
# Kernel hacking
#
-# CONFIG_REMOTE_DEBUG is not set
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index f04b1cd74..dfaadc490 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -8,47 +8,25 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
all: kernel.o head.o init_task.o
O_TARGET := kernel.o
-O_OBJS := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
+
+export-objs := s390_ksyms.o
+obj-y := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
- semaphore.o s390fpu.o s390io.o s390mach.o s390dyn.o reipl.o
-OX_OBJS := s390_ksyms.o
-MX_OBJS :=
-
-ifdef CONFIG_SMP
-O_OBJS += smp.o
-endif
-
-ifdef CONFIG_PCI
-O_OBJS += bios32.o
-endif
-
-ifdef CONFIG_MCA
-O_OBJS += mca.o
-endif
-
-ifeq ($(CONFIG_MTRR),y)
-OX_OBJS += mtrr.o
-else
- ifeq ($(CONFIG_MTRR),m)
- MX_OBJS += mtrr.o
- endif
-endif
-
-ifeq ($(CONFIG_IEEEFPU_EMULATION),y)
- O_OBJS += mathemu.o floatlib.o
-endif
+ semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
+
+obj-$(CONFIG_MODULES) += s390_ksyms.o
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_IEEEFPU_EMULATION) += mathemu.o floatlib.o
#
# Kernel debugging
#
-ifdef CONFIG_REMOTE_DEBUG
-O_OBJS += gdb-stub.o #gdb-low.o
-endif
+obj-$(CONFIG_REMOTE_DEBUG) += gdb-stub.o #gdb-low.o
include $(TOPDIR)/Rules.make
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index 818958b4f..68abd7d50 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -8,7 +8,7 @@
#include <linux/stddef.h>
#include <linux/kernel.h>
-#include <asm/string.h>
+#include <linux/string.h>
#include <asm/ebcdic.h>
void cpcmd(char *cmd, char *response, int rlen)
@@ -22,10 +22,10 @@ void cpcmd(char *cmd, char *response, int rlen)
ASCEBC(obuffer,olen);
if (response != NULL && rlen > 0) {
- asm volatile ("LRA 2,0(0,%0)\n\t"
+ asm volatile ("LRA 2,0(%0)\n\t"
"LR 4,%1\n\t"
"O 4,%4\n\t"
- "LRA 3,0(0,%2)\n\t"
+ "LRA 3,0(%2)\n\t"
"LR 5,%3\n\t"
".long 0x83240008 # Diagnose 83\n\t"
: /* no output */
@@ -34,7 +34,7 @@ void cpcmd(char *cmd, char *response, int rlen)
: "2", "3", "4", "5" );
EBCASC(response, rlen);
} else {
- asm volatile ("LRA 2,0(0,%0)\n\t"
+ asm volatile ("LRA 2,0(%0)\n\t"
"LR 3,%1\n\t"
".long 0x83230008 # Diagnose 83\n\t"
: /* no output */
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
new file mode 100644
index 000000000..bb3dfe5de
--- /dev/null
+++ b/arch/s390/kernel/debug.c
@@ -0,0 +1,1167 @@
+/*
+ * arch/s390/kernel/debug.c
+ * S/390 debug facility
+ *
+ * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
+ * IBM Corporation
+ * Author(s): Michael Holzheu (holzheu@de.ibm.com),
+ * Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ *
+ * Bugreports to: <Linux390@de.ibm.com>
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <asm/debug.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#if defined(CONFIG_ARCH_S390X)
+#define DEBUG_PROC_HEADER_SIZE 46
+#else
+#define DEBUG_PROC_HEADER_SIZE 38
+#endif
+
+#define ADD_BUFFER 1000
+
+/* typedefs */
+
+typedef struct file_private_info {
+ loff_t len; /* length of output in byte */
+ int size; /* size of buffer for output */
+ char *data; /* buffer for output */
+ debug_info_t *debug_info; /* the debug information struct */
+ struct debug_view *view; /* used view of debug info */
+} file_private_info_t;
+
+extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
+
+/* internal function prototyes */
+
+static int debug_init(void);
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+ int size, struct debug_view *view);
+static ssize_t debug_output(struct file *file, char *user_buf,
+ size_t user_len, loff_t * offset);
+static ssize_t debug_input(struct file *file, const char *user_buf,
+ size_t user_len, loff_t * offset);
+static int debug_open(struct inode *inode, struct file *file);
+static int debug_close(struct inode *inode, struct file *file);
+static struct proc_dir_entry
+*debug_create_proc_dir_entry(struct proc_dir_entry *root,
+ const char *name, mode_t mode,
+ struct inode_operations *iops,
+ struct file_operations *fops);
+static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
+ struct proc_dir_entry *entry);
+static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
+static void debug_info_get(debug_info_t *);
+static void debug_info_put(debug_info_t *);
+static int debug_prolog_level_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf);
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char *user_buf,
+ size_t user_buf_size, loff_t * offset);
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf);
+static int debug_raw_format_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf,
+ const char *in_buf);
+static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf);
+
+/* globals */
+
+struct debug_view debug_raw_view = {
+ "raw",
+ NULL,
+ &debug_raw_header_fn,
+ &debug_raw_format_fn,
+ NULL
+};
+
+struct debug_view debug_hex_ascii_view = {
+ "hex_ascii",
+ NULL,
+ &debug_dflt_header_fn,
+ &debug_hex_ascii_format_fn,
+ NULL
+};
+
+struct debug_view debug_level_view = {
+ "level",
+ &debug_prolog_level_fn,
+ NULL,
+ NULL,
+ &debug_input_level_fn
+};
+
+/* static globals */
+
+static debug_info_t *debug_area_first = NULL;
+static debug_info_t *debug_area_last = NULL;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+static struct semaphore debug_lock = MUTEX;
+#else
+DECLARE_MUTEX(debug_lock);
+#endif
+
+static int initialized = 0;
+
+static struct file_operations debug_file_ops = {
+ read: debug_output,
+ write: debug_input,
+ open: debug_open,
+ release: debug_close,
+};
+
+static struct inode_operations debug_inode_ops = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ default_file_ops: &debug_file_ops, /* file ops */
+#endif
+};
+
+
+static struct proc_dir_entry *debug_proc_root_entry;
+
+
+/* functions */
+
+/*
+ * debug_info_create
+ * - create new debug-info
+ */
+
+static debug_info_t* debug_info_create(char *name, int page_order,
+ int nr_areas, int buf_size)
+{
+ debug_info_t* rc;
+ int i;
+
+ /* alloc everything */
+
+ rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
+ if(!rc)
+ goto fail_malloc_rc;
+ rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC);
+ if(!rc->active_entry)
+ goto fail_malloc_active_entry;
+ memset(rc->active_entry, 0, nr_areas * sizeof(int));
+ rc->areas = (debug_entry_t **) kmalloc(nr_areas *
+ sizeof(debug_entry_t *),
+ GFP_ATOMIC);
+ if (!rc->areas)
+ goto fail_malloc_areas;
+ for (i = 0; i < nr_areas; i++) {
+ rc->areas[i] =
+ (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
+ page_order);
+ if (!rc->areas[i]) {
+ for (i--; i >= 0; i--) {
+ free_pages((unsigned long) rc->areas[i],
+ page_order);
+ }
+ goto fail_malloc_areas2;
+ } else {
+ memset(rc->areas[i], 0, PAGE_SIZE << page_order);
+ }
+ }
+
+ /* initialize members */
+
+ spin_lock_init(&rc->lock);
+ rc->page_order = page_order;
+ rc->nr_areas = nr_areas;
+ rc->active_area = 0;
+ rc->level = DEBUG_DEFAULT_LEVEL;
+ rc->buf_size = buf_size;
+ rc->entry_size = sizeof(debug_entry_t) + buf_size;
+ strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
+ rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
+ memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+ memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
+ sizeof(struct proc_dir_entry*));
+ atomic_set(&(rc->ref_count), 0);
+ rc->proc_root_entry =
+ debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
+ S_IFDIR | S_IRUGO | S_IXUGO |
+ S_IWUSR | S_IWGRP, NULL, NULL);
+
+ /* append new element to linked list */
+
+ if(debug_area_first == NULL){
+ /* first element in list */
+ debug_area_first = rc;
+ rc->prev = NULL;
+ }
+ else{
+ /* append element to end of list */
+ debug_area_last->next = rc;
+ rc->prev = debug_area_last;
+ }
+ debug_area_last = rc;
+ rc->next = NULL;
+
+ debug_info_get(rc);
+ return rc;
+
+fail_malloc_areas2:
+ kfree(rc->areas);
+fail_malloc_areas:
+ kfree(rc->active_entry);
+fail_malloc_active_entry:
+ kfree(rc);
+fail_malloc_rc:
+ return NULL;
+}
+
+/*
+ * debug_info_get
+ * - increments reference count for debug-info
+ */
+
+static void debug_info_get(debug_info_t * db_info)
+{
+ if (db_info)
+ atomic_inc(&db_info->ref_count);
+}
+
+/*
+ * debug_info_put:
+ * - decreases reference count for debug-info and frees it if necessary
+ */
+
+static void debug_info_put(debug_info_t *db_info)
+{
+ int i;
+
+ if (!db_info)
+ return;
+ if (atomic_dec_and_test(&db_info->ref_count)) {
+ printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
+ db_info, db_info->name);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (db_info->views[i] != NULL)
+ debug_delete_proc_dir_entry
+ (db_info->proc_root_entry,
+ db_info->proc_entries[i]);
+ }
+ debug_delete_proc_dir_entry(debug_proc_root_entry,
+ db_info->proc_root_entry);
+ for (i = 0; i < db_info->nr_areas; i++) {
+ free_pages((unsigned long) db_info->areas[i],
+ db_info->page_order);
+ }
+ kfree(db_info->areas);
+ kfree(db_info->active_entry);
+ if(db_info == debug_area_first)
+ debug_area_first = db_info->next;
+ if(db_info == debug_area_last)
+ debug_area_last = db_info->prev;
+ if(db_info->prev) db_info->prev->next = db_info->next;
+ if(db_info->next) db_info->next->prev = db_info->prev;
+ kfree(db_info);
+ }
+}
+
+
+/*
+ * debug_output:
+ * - called for user read()
+ * - copies formated output form private_data of the file
+ * handle to the user buffer
+ */
+
+static ssize_t debug_output(struct file *file, /* file descriptor */
+ char *user_buf, /* user buffer */
+ size_t user_len, /* length of buffer */
+ loff_t *offset /* offset in the file */ )
+{
+ loff_t len;
+ int rc;
+ file_private_info_t *p_info;
+
+ p_info = ((file_private_info_t *) file->private_data);
+ if (*offset >= p_info->len) {
+ return 0; /* EOF */
+ } else {
+ len = MIN(user_len, (p_info->len - *offset));
+ if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len)))
+ return rc;;
+ (*offset) += len;
+ return len; /* number of bytes "read" */
+ }
+}
+
+/*
+ * debug_input:
+ * - called for user write()
+ * - calls input function of view
+ */
+
+static ssize_t debug_input(struct file *file,
+ const char *user_buf, size_t length,
+ loff_t *offset)
+{
+ int rc = 0;
+ file_private_info_t *p_info;
+
+ down(&debug_lock);
+ p_info = ((file_private_info_t *) file->private_data);
+ if (p_info->view->input_proc)
+ rc = p_info->view->input_proc(p_info->debug_info,
+ p_info->view, file, user_buf,
+ length, offset);
+ up(&debug_lock);
+ return rc; /* number of input characters */
+}
+
+/*
+ * debug_format_output:
+ * - calls prolog, header and format functions of view to format output
+ */
+
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+ int size, struct debug_view *view)
+{
+ int len = 0;
+ int i, j;
+ int nr_of_entries;
+ debug_entry_t *act_entry;
+
+ /* print prolog */
+ if (view->prolog_proc)
+ len += view->prolog_proc(debug_area, view, buf);
+ /* print debug records */
+ if (!(view->format_proc) && !(view->header_proc))
+ goto out;
+ nr_of_entries = PAGE_SIZE / debug_area->entry_size
+ << debug_area->page_order;
+ for (i = 0; i < debug_area->nr_areas; i++) {
+ act_entry = debug_area->areas[i];
+ for (j = 0; j < nr_of_entries; j++) {
+ if (act_entry->id.fields.used == 0)
+ break; /* empty entry */
+ if (view->header_proc)
+ len += view->header_proc(debug_area, view, i,
+ act_entry, buf + len);
+ if (view->format_proc)
+ len += view->format_proc(debug_area, view,
+ buf + len,
+ DEBUG_DATA(act_entry));
+ if (len > size) {
+ printk(KERN_ERR
+ "debug: error -- memory exceeded for (%s/%s)\n",
+ debug_area->name, view->name);
+ printk(KERN_ERR "debug: fix view %s!!\n",
+ view->name);
+ printk(KERN_ERR
+ "debug: area: %i (0 - %i) entry: %i (0 - %i)\n",
+ i, debug_area->nr_areas - 1, j,
+ nr_of_entries - 1);
+ goto out;
+ }
+ act_entry = (debug_entry_t *) (((char *) act_entry) +
+ debug_area->entry_size);
+ }
+ }
+ out:
+ return len;
+}
+
+
+/*
+ * debug_open:
+ * - called for user open()
+ * - copies formated output to private_data area of the file
+ * handle
+ */
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ int i = 0, size = 0, rc = 0, f_entry_size = 0;
+ file_private_info_t *p_info;
+ debug_info_t* debug_info;
+
+#ifdef DEBUG
+ printk("debug_open\n");
+#endif
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ down(&debug_lock);
+
+ /* find debug log and view */
+
+ debug_info = debug_area_first;
+ while(debug_info != NULL){
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (debug_info->views[i] == NULL)
+ continue;
+ else if (debug_info->proc_entries[i]->low_ino ==
+ file->f_dentry->d_inode->i_ino) {
+ goto found; /* found view ! */
+ }
+ }
+ debug_info = debug_info->next;
+ }
+ /* no entry found */
+ rc = -EINVAL;
+ goto out;
+ found:
+ if ((file->private_data =
+ kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
+ printk(KERN_ERR "debug_open: kmalloc failed\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ p_info = (file_private_info_t *) file->private_data;
+
+ /*
+ * the size for the formated output is calculated
+ * with the following formula:
+ *
+ * prolog-size
+ * +
+ * (record header size + record data field size)
+ * * number of entries per page
+ * * number of pages per area
+ * * number of areas
+ */
+
+ if (debug_info->views[i]->prolog_proc)
+ size +=
+ debug_info->views[i]->prolog_proc(debug_info,
+ debug_info->
+ views[i], NULL);
+
+ if (debug_info->views[i]->header_proc)
+ f_entry_size =
+ debug_info->views[i]->header_proc(debug_info,
+ debug_info->
+ views[i], 0, NULL,
+ NULL);
+ if (debug_info->views[i]->format_proc)
+ f_entry_size +=
+ debug_info->views[i]->format_proc(debug_info,
+ debug_info->
+ views[i], NULL,
+ NULL);
+
+ size += f_entry_size
+ * (PAGE_SIZE / debug_info->entry_size
+ << debug_info->page_order)
+ * debug_info->nr_areas + 1; /* terminating \0 */
+#ifdef DEBUG
+ printk("debug_open: size: %i\n", size);
+#endif
+
+ /* alloc some bytes more to be safe against bad views */
+ if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) {
+ printk(KERN_ERR "debug_open: vmalloc failed\n");
+ vfree(file->private_data);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ p_info->size = size;
+ p_info->debug_info = debug_info;
+ p_info->view = debug_info->views[i];
+
+ spin_lock_irq(&debug_info->lock);
+
+ p_info->len =
+ debug_format_output(debug_info, p_info->data, size,
+ debug_info->views[i]);
+#ifdef DEBUG
+ {
+ int ilen = p_info->len;
+ printk("debug_open: len: %i\n", ilen);
+ }
+#endif
+
+ spin_unlock_irq(&debug_info->lock);
+ debug_info_get(debug_info);
+
+ out:
+ up(&debug_lock);
+#ifdef MODULE
+ if (rc != 0)
+ MOD_DEC_USE_COUNT;
+#endif
+ return rc;
+}
+
+/*
+ * debug_close:
+ * - called for user close()
+ * - deletes private_data area of the file handle
+ */
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+ file_private_info_t *p_info;
+#ifdef DEBUG
+ printk("debug_close\n");
+#endif
+ down(&debug_lock);
+ p_info = (file_private_info_t *) file->private_data;
+ debug_info_put(p_info->debug_info);
+ if (p_info->data) {
+ vfree(p_info->data);
+ kfree(file->private_data);
+ }
+ up(&debug_lock);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0; /* success */
+}
+
+/*
+ * debug_create_proc_dir_entry:
+ * - initializes proc-dir-entry and registers it
+ */
+
+static struct proc_dir_entry *debug_create_proc_dir_entry
+ (struct proc_dir_entry *root, const char *name, mode_t mode,
+ struct inode_operations *iops, struct file_operations *fops)
+{
+ struct proc_dir_entry *rc = NULL;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ const char *fn = name;
+ int len;
+ len = strlen(fn);
+
+ rc = (struct proc_dir_entry *) kmalloc(sizeof(struct proc_dir_entry)
+ + len + 1, GFP_ATOMIC);
+ if (!rc)
+ goto out;
+
+ memset(rc, 0, sizeof(struct proc_dir_entry));
+ memcpy(((char *) rc) + sizeof(*rc), fn, len + 1);
+ rc->name = ((char *) rc) + sizeof(*rc);
+ rc->namelen = len;
+ rc->low_ino = 0, rc->mode = mode;
+ rc->nlink = 1;
+ rc->uid = 0;
+ rc->gid = 0;
+ rc->size = 0;
+ rc->get_info = NULL;
+ rc->ops = iops;
+
+ proc_register(root, rc);
+#else
+ rc = create_proc_entry(name, mode, root);
+ if (!rc)
+ goto out;
+ if (fops)
+ rc->proc_fops = fops;
+#endif
+
+ out:
+ return rc;
+}
+
+
+/*
+ * delete_proc_dir_entry:
+ */
+
+static void debug_delete_proc_dir_entry
+ (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry)
+{
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ proc_unregister(root, proc_entry->low_ino);
+ kfree(proc_entry);
+#else
+ remove_proc_entry(proc_entry->name, root);
+#endif
+}
+
+/*
+ * debug_register:
+ * - creates and initializes debug area for the caller
+ * - returns handle for debug area
+ */
+
+debug_info_t *debug_register
+ (char *name, int page_order, int nr_areas, int buf_size)
+{
+ debug_info_t *rc = NULL;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ if (!initialized)
+ debug_init();
+ down(&debug_lock);
+
+ /* create new debug_info */
+
+ rc = debug_info_create(name, page_order, nr_areas, buf_size);
+ if(!rc)
+ goto out;
+ debug_register_view(rc, &debug_level_view);
+ printk(KERN_INFO
+ "debug: reserved %d areas of %d pages for debugging %s\n",
+ nr_areas, 1 << page_order, rc->name);
+ out:
+ if (rc == NULL){
+ printk(KERN_ERR "debug: debug_register failed for %s\n",name);
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ }
+ up(&debug_lock);
+ return rc;
+}
+
+/*
+ * debug_unregister:
+ * - give back debug area
+ */
+
+void debug_unregister(debug_info_t * id)
+{
+ if (!id)
+ goto out;
+ down(&debug_lock);
+ printk(KERN_INFO "debug: unregistering %s\n", id->name);
+ debug_info_put(id);
+ up(&debug_lock);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ out:
+ return;
+}
+
+/*
+ * debug_set_level:
+ * - set actual debug level
+ */
+
+void debug_set_level(debug_info_t* id, int new_level)
+{
+ long flags;
+ if(!id)
+ return;
+ spin_lock_irqsave(&id->lock,flags);
+ if(new_level == DEBUG_OFF_LEVEL){
+ id->level = DEBUG_OFF_LEVEL;
+ printk(KERN_INFO "debug: %s: switched off\n",id->name);
+ } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
+ printk(KERN_INFO
+ "debug: %s: level %i is out of range (%i - %i)\n",
+ id->name, new_level, 0, DEBUG_MAX_LEVEL);
+ } else {
+ id->level = new_level;
+ printk(KERN_INFO
+ "debug: %s: new level %i\n",id->name,id->level);
+ }
+ spin_unlock_irqrestore(&id->lock,flags);
+}
+
+
+/*
+ * proceed_active_entry:
+ * - set active entry to next in the ring buffer
+ */
+
+static inline void proceed_active_entry(debug_info_t * id)
+{
+ if ((id->active_entry[id->active_area] += id->entry_size)
+ > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
+ id->active_entry[id->active_area] = 0;
+}
+
+/*
+ * proceed_active_area:
+ * - set active area to next in the ring buffer
+ */
+
+static inline void proceed_active_area(debug_info_t * id)
+{
+ id->active_area++;
+ id->active_area = id->active_area % id->nr_areas;
+}
+
+/*
+ * get_active_entry:
+ */
+
+static inline debug_entry_t *get_active_entry(debug_info_t * id)
+{
+ return (debug_entry_t *) ((char *) id->areas[id->active_area] +
+ id->active_entry[id->active_area]);
+}
+
+/*
+ * debug_common:
+ * - set timestamp, caller address, cpu number etc.
+ */
+
+static inline debug_entry_t *debug_common(debug_info_t * id)
+{
+ debug_entry_t *active;
+
+ active = get_active_entry(id);
+ STCK(active->id.stck);
+ active->id.fields.cpuid = smp_processor_id();
+ active->id.fields.used = 1;
+ active->caller = __builtin_return_address(0);
+ return active;
+}
+
+/*
+ * debug_event:
+ */
+
+debug_entry_t *debug_event(debug_info_t * id, int level, void *buf,
+ int len)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 0;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size));
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_int_event:
+ */
+
+debug_entry_t *debug_int_event(debug_info_t * id, int level,
+ unsigned int tag)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 0;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), &tag, MIN(sizeof(unsigned int), id->buf_size));
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_text_event:
+ */
+
+debug_entry_t *debug_text_event(debug_info_t * id, int level,
+ const char *txt)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size));
+ active->id.fields.exception = 0;
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+
+}
+
+/*
+ * debug_exception:
+ */
+
+debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf,
+ int len)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 1;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size));
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_int_exception:
+ */
+
+debug_entry_t *debug_int_exception(debug_info_t * id, int level,
+ unsigned int tag)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 1;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), &tag,
+ MIN(sizeof(unsigned int), id->buf_size));
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_text_exception:
+ */
+
+debug_entry_t *debug_text_exception(debug_info_t * id, int level,
+ const char *txt)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size));
+ active->id.fields.exception = 1;
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+
+}
+
+/*
+ * debug_init:
+ * - is called exactly once to initialize the debug feature
+ */
+
+int debug_init(void)
+{
+ int rc = 0;
+
+ down(&debug_lock);
+ if (!initialized) {
+ debug_proc_root_entry =
+ debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT,
+ S_IFDIR | S_IRUGO | S_IXUGO
+ | S_IWUSR | S_IWGRP, NULL,
+ NULL);
+ printk(KERN_INFO "debug: Initialization complete\n");
+ initialized = 1;
+ }
+ up(&debug_lock);
+
+ return rc;
+}
+
+/*
+ * debug_register_view:
+ */
+
+int debug_register_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ long flags;
+ mode_t mode = S_IFREG;
+
+ if (!id)
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (id->views[i] == NULL)
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS) {
+ printk(KERN_WARNING "debug: cannot register view %s/%s\n",
+ id->name,view->name);
+ printk(KERN_WARNING
+ "debug: maximum number of views reached (%i)!\n", i);
+ rc = -1;
+ }
+ else {
+ id->views[i] = view;
+ if (view->prolog_proc || view->format_proc || view->header_proc)
+ mode |= S_IRUSR;
+ if (view->input_proc)
+ mode |= S_IWUSR;
+ id->proc_entries[i] =
+ debug_create_proc_dir_entry(id->proc_root_entry,
+ view->name, mode,
+ &debug_inode_ops,
+ &debug_file_ops);
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return rc;
+}
+
+/*
+ * debug_unregister_view:
+ */
+
+int debug_unregister_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ long flags;
+
+ if (!id)
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (id->views[i] == view)
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS)
+ rc = -1;
+ else {
+ debug_delete_proc_dir_entry(id->proc_root_entry,
+ id->proc_entries[i]);
+ id->views[i] = NULL;
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return rc;
+}
+
+/*
+ * functions for debug-views
+ ***********************************
+*/
+
+/*
+ * prints out actual debug level
+ */
+
+static int debug_prolog_level_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf)
+{
+ int rc = 0;
+
+ if (out_buf == NULL) {
+ rc = 2;
+ goto out;
+ }
+ if(id->level == -1) rc = sprintf(out_buf,"-\n");
+ else rc = sprintf(out_buf, "%i\n", id->level);
+ out:
+ return rc;
+}
+
+/*
+ * reads new debug level
+ */
+
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char *user_buf,
+ size_t in_buf_size, loff_t * offset)
+{
+ char input_buf[1];
+ int rc = in_buf_size;
+
+ if (*offset != 0)
+ goto out;
+ if ((rc = copy_from_user(input_buf, user_buf, 1)))
+ goto out;
+ if (isdigit(input_buf[0])) {
+ int new_level = ((int) input_buf[0] - (int) '0');
+ debug_set_level(id, new_level);
+ } else if(input_buf[0] == '-') {
+ debug_set_level(id, DEBUG_OFF_LEVEL);
+ } else {
+ printk(KERN_INFO "debug: level `%c` is not valid\n",
+ input_buf[0]);
+ }
+ out:
+ *offset += in_buf_size;
+ return rc; /* number of input characters */
+}
+
+/*
+ * prints debug header in raw format
+ */
+
+int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
+{
+ int rc;
+
+ rc = sizeof(debug_entry_t);
+ if (out_buf == NULL)
+ goto out;
+ memcpy(out_buf,entry,sizeof(debug_entry_t));
+ out:
+ return rc;
+}
+
+/*
+ * prints debug data in raw format
+ */
+
+static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int rc;
+
+ rc = id->buf_size;
+ if (out_buf == NULL || in_buf == NULL)
+ goto out;
+ memcpy(out_buf, in_buf, id->buf_size);
+ out:
+ return rc;
+}
+
+/*
+ * prints debug data in hex/ascii format
+ */
+
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int i, rc = 0;
+
+ if (out_buf == NULL || in_buf == NULL) {
+ rc = id->buf_size * 4 + 3;
+ goto out;
+ }
+ for (i = 0; i < id->buf_size; i++) {
+ rc += sprintf(out_buf + rc, "%02x ",
+ ((unsigned char *) in_buf)[i]);
+ }
+ rc += sprintf(out_buf + rc, "| ");
+ for (i = 0; i < id->buf_size; i++) {
+ unsigned char c = in_buf[i];
+ if (!isprint(c))
+ rc += sprintf(out_buf + rc, ".");
+ else
+ rc += sprintf(out_buf + rc, "%c", c);
+ }
+ rc += sprintf(out_buf + rc, "\n");
+ out:
+ return rc;
+}
+
+/*
+ * prints header for debug entry
+ */
+
+int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
+{
+ struct timeval time_val;
+ unsigned long long time;
+ char *except_str;
+ unsigned long caller;
+ int rc = 0;
+
+ if (out_buf == NULL) {
+ rc = DEBUG_PROC_HEADER_SIZE;
+ goto out;
+ }
+
+ time = entry->id.stck;
+ /* adjust todclock to 1970 */
+ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
+ tod_to_timeval(time, &time_val);
+
+ if (entry->id.fields.exception)
+ except_str = "*";
+ else
+ except_str = "-";
+ caller = (unsigned long) entry->caller;
+#if defined(CONFIG_ARCH_S390X)
+ rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx ",
+ area, time_val.tv_sec,
+ time_val.tv_usec, except_str,
+ entry->id.fields.cpuid, caller);
+#else
+ caller &= 0x7fffffff;
+ rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ",
+ area, time_val.tv_sec,
+ time_val.tv_usec, except_str,
+ entry->id.fields.cpuid, caller);
+#endif
+ out:
+ return rc;
+}
+
+/*
+ * init_module:
+ */
+
+#ifdef MODULE
+int init_module(void)
+{
+ int rc = 0;
+#ifdef DEBUG
+ printk("debug_module_init: \n");
+#endif
+ rc = debug_init();
+ if (rc)
+ printk(KERN_INFO "debug: an error occurred with debug_init\n");
+ return rc;
+}
+
+/*
+ * cleanup_module:
+ */
+
+void cleanup_module(void)
+{
+#ifdef DEBUG
+ printk("debug_cleanup_module: \n");
+#endif
+ debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry);
+ return;
+}
+
+#endif /* MODULE */
diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c
index 3c70c4aa5..fc7740649 100644
--- a/arch/s390/kernel/ebcdic.c
+++ b/arch/s390/kernel/ebcdic.c
@@ -161,7 +161,156 @@ __u8 _ebcasc[256] =
/*
- * EBCDIC 037 conversion table:
+ * ASCII (IBM PC 437) -> EBCDIC 500
+ */
+__u8 _ascebc_500[256] =
+{
+ /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ /* ->NL */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN EM SUB ESC FS GS RS US */
+ /* ->IGS ->IRS ->IUS */
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x4F, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0x4A, 0xE0, 0x5A, 0x5F, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0xBB, 0xD0, 0xA1, 0x07,
+ /*80*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0 sz */
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+/*
+ * EBCDIC 500 -> ASCII (IBM PC 437)
+ */
+__u8 _ebcasc_500[256] =
+{
+ /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08 -GE -SPS -RPT VT FF CR SO SI */
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
+ -ENP ->LF */
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
+ -IUS */
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
+ -INP */
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
+ -SW */
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40 SP RSP ä ---- */
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48 [ . < ( + ! */
+ 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
+ /* 0x50 & ---- */
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58 ß ] $ * ) ; ^ */
+ 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
+ /* 0x60 - / ---- Ä ---- ---- ---- */
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68 ---- , % _ > ? */
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70 ---- ---- ---- ---- ---- ---- ---- */
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78 * ` : # @ ' = " */
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80 * a b c d e f g */
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88 h i ---- ---- ---- */
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90 ° j k l m n o p */
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98 q r ---- ---- */
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0 ~ s t u v w x */
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8 y z ---- ---- ---- ---- */
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0 ---- § ---- */
+ 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8 ---- | ---- ---- ---- ---- */
+ 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0 { A B C D E F G */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8 H I ---- ö ---- */
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0 } J K L M N O P */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8 Q R ---- ü */
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0 \ S T U V W X */
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8 Y Z ---- Ö ---- ---- ---- */
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0 0 1 2 3 4 5 6 7 */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+
+/*
+ * EBCDIC 037/500 conversion table:
* from upper to lower case
*/
__u8 _ebc_tolower[256] =
@@ -202,7 +351,7 @@ __u8 _ebc_tolower[256] =
/*
- * EBCDIC 037 conversion table:
+ * EBCDIC 037/500 conversion table:
* from lower to upper case
*/
__u8 _ebc_toupper[256] =
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index e39e18623..a1125e933 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -81,6 +81,7 @@ state = 0
flags = 4
sigpending = 8
need_resched = 24
+tsk_ptrace = 28
processor = 60
/* PSW related defines */
@@ -88,6 +89,13 @@ disable = 0xFC
enable = 0x03
daton = 0x04
+/*
+ * Base Address of this Module --- saved in __LC_ENTRY_BASE
+ */
+ .globl entry_base
+entry_base:
+
+#define BASED(name) name-entry_base(%r13)
#if 0
/* some code left lying around in case we need a
@@ -118,39 +126,37 @@ sysc_dn:
*/
#define SAVE_ALL(psworg) \
- st %r15,__LC_SAVE_AREA ; \
+ stm %r13,%r15,__LC_SAVE_AREA ; \
+ stam %a2,%a4,__LC_SAVE_AREA+12 ; \
+ basr %r13,0 ; /* temp base pointer */ \
+ l %r13,.Lentry_base-.(%r13) ; /* load &entry_base to %r13 */ \
tm psworg+1,0x01 ; /* test problem state bit */ \
- jz 0f ; /* skip stack setup save */ \
+ bz BASED(.+12) ; /* skip stack setup save */ \
l %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \
-0: ahi %r15,-SP_SIZE ; /* make room for registers & psw */ \
- srl %r15,3 ; \
- sll %r15,3 ; /* align stack pointer to 8 */ \
- stm %r0,%r14,SP_R0(%r15) ; /* store gprs 0-14 to kernel stack */ \
+ lam %a2,%a4,BASED(.Lc_ac) ; /* set ac.reg. 2 to primary space */ \
+ /* and access reg. 4 to home space */ \
+0: s %r15,BASED(.Lc_spsize); /* make room for registers & psw */ \
+ n %r15,BASED(.Lc0xfffffff8) ; /* align stack pointer to 8 */ \
+ stm %r0,%r12,SP_R0(%r15) ; /* store gprs 0-12 to kernel stack */ \
st %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \
- mvc SP_RF(4,%r15),__LC_SAVE_AREA ; /* move R15 to stack */ \
+ mvc SP_RD(12,%r15),__LC_SAVE_AREA ; /* move R13-R15 to stack */ \
stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \
+ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 ; /* store ac. regs */ \
mvc SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \
- lhi %r0,psworg ; /* store trap indication */ \
+ la %r0,psworg ; /* store trap indication */ \
st %r0,SP_TRAP(%r15) ; \
- xc 0(4,%r15),0(%r15) ; /* clear back chain */ \
- tm psworg+1,0x01 ; /* kmod.c .wishes the set_fs & gs */ \
- jz 1f ; /* to work across syscalls */ \
- slr %r0,%r0 ; \
- sar %a2,%r0 ; /* set ac.reg. 2 to primary space */ \
- lhi %r0,1 ; \
- sar %a4,%r0 ; /* set access reg. 4 to home space */ \
-1:
+ xc 0(4,%r15),0(%r15) ; /* clear back chain */
#define RESTORE_ALL \
- mvc __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
- lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
- lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \
- ni __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \
- lpsw __LC_RETURN_PSW /* back to caller */
+ mvc __LC_RETURN_PSW(8),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
+ lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
+ lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \
+ ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \
+ lpsw __LC_RETURN_PSW /* back to caller */
#define GET_CURRENT /* load pointer to task_struct to R9 */ \
- lhi %r9,-8192 ; \
- nr %r9,15
+ lr %r9,%r15 ; \
+ n %r9,BASED(.Lc0xffffe000)
/*
@@ -162,22 +168,24 @@ sysc_dn:
*/
.globl resume
resume:
+ basr %r1,0
+resume_base:
l %r4,_TSS_PTREGS(%r3)
tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
- jz RES_DN1 # if not we're fine
- stctl %r9,%r11,24(%r15) # We are using per stuff
+ bz resume_noper-resume_base(%r1) # if not we're fine
+ stctl %r9,%r11,24(%r15) # We are using per stuff
clc _TSS_PER(12,%r3),24(%r15)
- je RES_DN1 # we got away without bashing TLB's
- lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't
-RES_DN1:
+ be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's
+ lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't
+resume_noper:
stm %r6,%r15,24(%r15) # store resume registers of prev task
st %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
- lhi %r0,-8192
- nr %r0,%r15
+ lr %r0,%r15
+ n %r0,.Lc0xffffe000-resume_base(%r1)
l %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp
- lhi %r1,8191
+ l %r1,.Lc8191-resume_base(%r1)
or %r1,%r15
- ahi %r1,1
+ la %r1,1(%r1)
st %r1,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
stam %a2,%a2,_TSS_AR2(%r2) # store kernel access reg. 2
stam %a4,%a4,_TSS_AR4(%r2) # store kernel access reg. 4
@@ -192,38 +200,19 @@ RES_DN1:
* are executed with interrupts enabled.
*/
-sysc_lit:
- sysc_do_signal: .long do_signal
- sysc_do_softirq: .long do_softirq
- sysc_schedule: .long schedule
- sysc_trace: .long syscall_trace
-#ifdef CONFIG_SMP
- sysc_schedtail: .long schedule_tail
-#endif
- sysc_clone: .long sys_clone
- sysc_fork: .long sys_fork
- sysc_vfork: .long sys_vfork
- sysc_sigreturn: .long sys_sigreturn
- sysc_rt_sigreturn: .long sys_rt_sigreturn
- sysc_execve: .long sys_execve
- sysc_sigsuspend: .long sys_sigsuspend
- sysc_rt_sigsuspend: .long sys_rt_sigsuspend
-
.globl system_call
system_call:
SAVE_ALL(0x20)
- XC SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
+ xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
pgm_system_call:
- basr %r13,0
- ahi %r13,sysc_lit-. # setup base pointer R13 to sysc_lit
slr %r8,%r8 # gpr 8 is call save (-> tracesys)
ic %r8,0x8B # get svc number from lowcore
stosm 24(%r15),0x03 # reenable interrupts
GET_CURRENT # load pointer to task_struct to R9
sll %r8,2
- l %r8,sys_call_table-sysc_lit(8,%r13) # get address of system call
- tm flags+3(%r9),0x20 # PF_TRACESYS
- jnz sysc_tracesys
+ l %r8,sys_call_table-entry_base(8,%r13) # get address of system call
+ tm tsk_ptrace+3(%r9),0x02 # PT_TRACESYS
+ bnz BASED(sysc_tracesys)
basr %r14,%r8 # call sys_xxxx
st %r2,SP_R2(%r15) # store return value (change R2 on stack)
# ATTENTION: check sys_execve_glue before
@@ -232,24 +221,24 @@ pgm_system_call:
sysc_return:
GET_CURRENT # load pointer to task_struct to R9
tm SP_PSW+1(%r15),0x01 # returning to user ?
- jno sysc_leave # no-> skip bottom half, resched & signal
+ bno BASED(sysc_leave) # no-> skip bottom half, resched & signal
#
# check, if bottom-half has to be done
#
l %r0,__LC_IRQ_STAT # get softirq_active
n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
- jnz sysc_handle_bottom_half
+ bnz BASED(sysc_handle_bottom_half)
#
# check, if reschedule is needed
#
sysc_return_bh:
icm %r0,15,need_resched(%r9) # get need_resched from task_struct
- jnz sysc_reschedule
+ bnz BASED(sysc_reschedule)
icm %r0,15,sigpending(%r9) # get sigpending from task_struct
- jnz sysc_signal_return
+ bnz BASED(sysc_signal_return)
sysc_leave:
icm %r0,15,SP_SVC_STEP(%r15) # get sigpending from task_struct
- jnz pgm_svcret
+ bnz BASED(pgm_svcret)
stnsm 24(%r15),disable # disable I/O and ext. interrupts
RESTORE_ALL
@@ -259,24 +248,24 @@ sysc_leave:
sysc_signal_return:
la %r2,SP_PTREGS(%r15) # load pt_regs
sr %r3,%r3 # clear *oldset
- l %r1,sysc_do_signal-sysc_lit(%r13)
- la %r14,sysc_leave-sysc_lit(%r13)
+ l %r1,BASED(.Ldo_signal)
+ la %r14,BASED(sysc_leave)
br %r1 # return point is sysc_leave
#
# call trace before and after sys_call
#
sysc_tracesys:
- l %r1,sysc_trace-sysc_lit(%r13)
- lhi %r2,-ENOSYS
+ l %r1,BASED(.Ltrace)
+ l %r2,BASED(.Lc_ENOSYS)
st %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval
basr %r14,%r1
lm %r3,%r6,SP_R3(%r15)
l %r2,SP_ORIG_R2(%r15)
basr %r14,%r8 # call sys_xxx
st %r2,SP_R2(%r15) # store return value
- l %r1,sysc_trace-sysc_lit(%r13)
- la %r14,sysc_return-sysc_lit(%r13)
+ l %r1,BASED(.Ltrace)
+ la %r14,BASED(sysc_return)
br %r1 # return point is sysc_return
@@ -285,16 +274,16 @@ sysc_tracesys:
# is zero
#
sysc_handle_bottom_half:
- l %r1,sysc_do_softirq-sysc_lit(%r13)
- la %r14,sysc_return_bh-sysc_lit(%r13)
+ l %r1,BASED(.Ldo_softirq)
+ la %r14,BASED(sysc_return_bh)
br %r1 # call do_softirq
#
# call schedule with sysc_return as return-address
#
sysc_reschedule:
- l %r1,sysc_schedule-sysc_lit(%r13)
- la %r14,sysc_return-sysc_lit(%r13)
+ l %r1,BASED(.Lschedule)
+ la %r14,BASED(sysc_return)
br %r1 # call scheduler, return to sysc_return
#
@@ -303,17 +292,17 @@ sysc_reschedule:
.globl ret_from_fork
ret_from_fork:
basr %r13,0
- ahi %r13,sysc_lit-. # setup base pointer R13 to $SYSCDAT
+ l %r13,.Lentry_base-.(%r13) # setup base pointer to &entry_base
GET_CURRENT # load pointer to task_struct to R9
stosm 24(%r15),0x03 # reenable interrupts
sr %r0,%r0 # child returns 0
st %r0,SP_R2(%r15) # store return value (change R2 on stack)
#ifdef CONFIG_SMP
- l %r1,sysc_schedtail-sysc_lit(%r13)
- la %r14,sysc_return-sysc_lit(%r13)
+ l %r1,BASED(.Lschedtail)
+ la %r14,BASED(sysc_return)
br %r1 # call schedule_tail, return to sysc_return
#else
- j sysc_return
+ b BASED(sysc_return)
#endif
#
@@ -324,22 +313,22 @@ ret_from_fork:
#
sys_clone_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,sysc_clone-sysc_lit(%r13)
+ l %r1,BASED(.Lclone)
br %r1 # branch to sys_clone
sys_fork_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,sysc_fork-sysc_lit(%r13)
+ l %r1,BASED(.Lfork)
br %r1 # branch to sys_fork
sys_vfork_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,sysc_vfork-sysc_lit(%r13)
+ l %r1,BASED(.Lvfork)
br %r1 # branch to sys_vfork
sys_execve_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,sysc_execve-sysc_lit(%r13)
+ l %r1,BASED(.Lexecve)
lr %r12,%r14 # save return address
basr %r14,%r1 # call sys_execve
ltr %r2,%r2 # check if execve failed
@@ -349,12 +338,12 @@ sys_execve_glue:
sys_sigreturn_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- l %r1,sysc_sigreturn-sysc_lit(%r13)
+ l %r1,BASED(.Lsigreturn)
br %r1 # branch to sys_sigreturn
sys_rt_sigreturn_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- l %r1,sysc_rt_sigreturn-sysc_lit(%r13)
+ l %r1,BASED(.Lrt_sigreturn)
br %r1 # branch to sys_sigreturn
#
@@ -369,7 +358,7 @@ sys_sigsuspend_glue:
lr %r4,%r3 # move history1 parameter
lr %r3,%r2 # move history0 parameter
la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
- l %r1,sysc_sigsuspend-sysc_lit(%r13)
+ l %r1,BASED(.Lsigsuspend)
la %r14,4(%r14) # skip store of return value
br %r1 # branch to sys_sigsuspend
@@ -377,10 +366,15 @@ sys_rt_sigsuspend_glue:
lr %r4,%r3 # move sigsetsize parameter
lr %r3,%r2 # move unewset parameter
la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
- l %r1,sysc_rt_sigsuspend-sysc_lit(%r13)
+ l %r1,BASED(.Lrt_sigsuspend)
la %r14,4(%r14) # skip store of return value
br %r1 # branch to sys_rt_sigsuspend
+sys_sigaltstack_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ l %r1,BASED(.Lsigaltstack)
+ br %r1 # branch to sys_sigreturn
+
.globl sys_call_table
sys_call_table:
.long sys_ni_syscall /* 0 */
@@ -459,7 +453,7 @@ sys_call_table:
.long sys_sigpending
.long sys_sethostname
.long sys_setrlimit /* 75 */
- .long sys_getrlimit
+ .long sys_old_getrlimit
.long sys_getrusage
.long sys_gettimeofday
.long sys_settimeofday
@@ -569,13 +563,13 @@ sys_call_table:
.long sys_getcwd
.long sys_capget
.long sys_capset /* 185 */
- .long sys_sigaltstack
+ .long sys_sigaltstack_glue
.long sys_sendfile
.long sys_ni_syscall /* streams1 */
.long sys_ni_syscall /* streams2 */
.long sys_vfork_glue /* 190 */
.long sys_getrlimit
- .long sys_ni_syscall /* FIXME: problem with sys_mmap2: 6 parms */
+ .long sys_mmap2
.long sys_truncate64
.long sys_ftruncate64
.long sys_stat64 /* 195 */
@@ -604,7 +598,8 @@ sys_call_table:
.long sys_mincore
.long sys_madvise
.long sys_getdents64 /* 220 */
- .rept 255-220
+ .long sys_fcntl64
+ .rept 255-221
.long sys_ni_syscall
.endr
@@ -612,13 +607,6 @@ sys_call_table:
* Program check handler routine
*/
-pgm_lit:
- pgm_handle_per: .long handle_per_exception
- pgm_jump_table: .long pgm_check_table
- pgm_sysc_ret: .long sysc_return
- pgm_sysc_lit: .long sysc_lit
- pgm_do_signal: .long do_signal
-
.globl pgm_check_handler
pgm_check_handler:
/*
@@ -634,110 +622,131 @@ pgm_check_handler:
* we just ignore the PER event (FIXME: is there anything we have to do
* for LPSW?).
*/
+ stm %r13,%r15,__LC_SAVE_AREA
+ stam %a2,%a4,__LC_SAVE_AREA+12
+ basr %r13,0 # temp base pointer
+ l %r13,.Lentry_base-.(%r13)# load &entry_base to %r13
tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
- jz pgm_sv # skip if not
+ bz BASED(pgm_sv) # skip if not
tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
- jnz pgm_sv # skip if it is
+ bnz BASED(pgm_sv) # skip if it is
# ok its one of the special cases, now we need to find out which one
clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
- je pgm_svcper
+ be BASED(pgm_svcper)
# no interesting special case, ignore PER event
- lpsw 0x28
+ lm %r13,%r15,__LC_SAVE_AREA
+ lpsw 0x28
# it was a single stepped SVC that is causing all the trouble
pgm_svcper:
- SAVE_ALL(0x20)
+ tm 0x21,0x01 # test problem state bit
+ bz BASED(.+12) # skip stack & access regs setup
+ l %r15,__LC_KERNEL_STACK # problem state -> load ksp
+ lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space
+ # and access reg. 4 to home space
+ s %r15,BASED(.Lc_spsize) # make room for registers & psw
+ n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
+ stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack
+ st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
+ mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
+ stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst.
+ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
+ mvc SP_PSW(8,%r15),0x20 # move user PSW to stack
+ la %r0,0x20 # store trap indication
+ st %r0,SP_TRAP(%r15)
+ xc 0(4,%r15),0(%r15) # clear back chain
mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero
mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
- j pgm_system_call # now do the svc
+ b BASED(pgm_system_call) # now do the svc
pgm_svcret:
- lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
- lhi %r0,0x28
- st %r0,SP_TRAP(%r15) # set new trap indicator
+ mvi SP_TRAP+3(%r15),0x28 # set trap indication back to pgm_chk
+ lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
- basr %r13,0
- ahi %r13,pgm_lit-. # setup base pointer
- j pgm_no_sv
+ b BASED(pgm_no_sv)
pgm_sv:
- SAVE_ALL(0x28)
- XC SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
- basr %r13,0
- ahi %r13,pgm_lit-. # setup base pointer R13 to $PGMDAT
+ tm 0x29,0x01 # test problem state bit
+ bz BASED(.+12) # skip stack & access regs setup
+ l %r15,__LC_KERNEL_STACK # problem state -> load ksp
+ lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space
+ # and access reg. 4 to home space
+ s %r15,BASED(.Lc_spsize) # make room for registers & psw
+ n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
+ stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack
+ st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
+ mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
+ stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst.
+ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
+ mvc SP_PSW(8,%r15),0x28 # move user PSW to stack
+ la %r0,0x28 # store trap indication
+ st %r0,SP_TRAP(%r15)
+ xc 0(4,%r15),0(%r15) # clear back chain
+ xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
lh %r7,__LC_PGM_ILC # load instruction length
pgm_no_sv:
lh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it
stosm 24(%r15),0x03 # reenable interrupts
lr %r3,%r8
- lhi %r0,0x7f
+ la %r0,0x7f
nr %r3,%r0 # clear per-event-bit
- je pgm_dn # none of Martins exceptions occured bypass
- l %r9,pgm_jump_table-pgm_lit(%r13)
+ be BASED(pgm_dn) # none of Martins exceptions occured bypass
+ l %r9,BASED(.Ljump_table)
sll %r3,2
l %r9,0(%r3,%r9) # load address of handler routine
la %r2,SP_PTREGS(%r15) # address of register-save area
srl %r3,2
- chi %r3,0x4 # protection-exception ?
- jne pgm_go # if not,
+ cl %r3,BASED(.Lc4) # protection-exception ?
+ bne BASED(pgm_go) # if not,
l %r5,SP_PSW+4(15) # load psw addr
sr %r5,%r7 # substract ilc from psw
st %r5,SP_PSW+4(15) # store corrected psw addr
pgm_go: basr %r14,%r9 # branch to interrupt-handler
-pgm_dn: lhi %r0,0x80
+pgm_dn: la %r0,0x80
nr %r8,%r0 # check for per exception
- je pgm_return
+ be BASED(pgm_return)
la %r2,SP_PTREGS(15) # address of register-save area
- l %r9,pgm_handle_per-pgm_lit(%r13) # load adr. of per handler
- l %r14,pgm_sysc_ret-pgm_lit(%r13) # load adr. of system return
- l %r13,pgm_sysc_lit-pgm_lit(%r13)
+ l %r9,BASED(.Lhandle_per) # load adr. of per handler
+ la %r14,BASED(sysc_return) # load adr. of system return
br %r9 # branch to handle_per_exception
+
#
# the backend code is the same as for sys-call
#
pgm_return:
- l %r14,pgm_sysc_ret-pgm_lit(%r13)
- l %r13,pgm_sysc_lit-pgm_lit(%r13)
- br %r14
+ b BASED(sysc_return)
/*
* IO interrupt handler routine
*/
-io_lit:
- io_do_IRQ: .long do_IRQ
- io_schedule: .long schedule
- io_do_signal: .long do_signal
- io_do_softirq: .long do_softirq
-
.globl io_int_handler
io_int_handler:
SAVE_ALL(0x38)
- basr %r13,0
- ahi %r13,io_lit-. # setup base pointer R13 to $IODAT
la %r2,SP_PTREGS(%r15) # address of register-save area
sr %r3,%r3
icm %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int
- l %r4,__LC_IO_INT_PARM # load interuption parm
- l %r9,io_do_IRQ-io_lit(%r13) # load address of do_IRQ
+ l %r4,__LC_IO_INT_PARM # load interruption parm
+ l %r5,__LC_IO_INT_WORD # load interruption word
+ l %r9,BASED(.Ldo_IRQ) # load address of do_IRQ
basr %r14,%r9 # branch to standard irq handler
io_return:
GET_CURRENT # load pointer to task_struct to R9
tm SP_PSW+1(%r15),0x01 # returning to user ?
- jz io_leave # no-> skip resched & signal
+ bz BASED(io_leave) # no-> skip resched & signal
stosm 24(%r15),0x03 # reenable interrupts
#
# check, if bottom-half has to be done
#
l %r0,__LC_IRQ_STAT # get softirq_active
n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
- jnz io_handle_bottom_half
+ bnz BASED(io_handle_bottom_half)
io_return_bh:
#
# check, if reschedule is needed
#
icm %r0,15,need_resched(%r9) # get need_resched from task_struct
- jnz io_reschedule
+ bnz BASED(io_reschedule)
icm %r0,15,sigpending(%r9) # get sigpending from task_struct
- jnz io_signal_return
+ bnz BASED(io_signal_return)
io_leave:
stnsm 24(%r15),disable # disable I/O and ext. interrupts
RESTORE_ALL
@@ -747,16 +756,16 @@ io_leave:
# is zero
#
io_handle_bottom_half:
- l %r1,io_do_softirq-io_lit(%r13)
- la %r14,io_return_bh-io_lit(%r13)
+ l %r1,BASED(.Ldo_softirq)
+ la %r14,BASED(io_return_bh)
br %r1 # call do_softirq
#
# call schedule with io_return as return-address
#
io_reschedule:
- l %r1,io_schedule-io_lit(%r13)
- la %r14,io_return-io_lit(%r13)
+ l %r1,BASED(.Lschedule)
+ la %r14,BASED(io_return)
br %r1 # call scheduler, return to io_return
#
@@ -765,103 +774,46 @@ io_reschedule:
io_signal_return:
la %r2,SP_PTREGS(%r15) # load pt_regs
sr %r3,%r3 # clear *oldset
- l %r1,io_do_signal-io_lit(%r13)
- la %r14,io_leave-io_lit(%r13)
+ l %r1,BASED(.Ldo_signal)
+ la %r14,BASED(io_leave)
br %r1 # return point is io_leave
/*
* External interrupt handler routine
*/
-ext_lit:
- ext_timer_int: .long do_timer_interrupt
-#ifdef CONFIG_SMP
- ext_call_int: .long do_ext_call_interrupt
-#endif
-#ifdef CONFIG_HWC
- ext_hwc_int: .long do_hwc_interrupt
-#endif
-#ifdef CONFIG_MDISK
- ext_mdisk_int: .long do_mdisk_interrupt
-#endif
-#ifdef CONFIG_IUCV
- ext_iucv_int: .long do_iucv_interrupt
-#endif
- ext_io_lit: .long io_lit
- ext_io_return: .long io_return
-
.globl ext_int_handler
ext_int_handler:
SAVE_ALL(0x18)
- basr %r13,0
- ahi %r13,ext_lit-. # setup base pointer R13 to $EXTDAT
la %r2,SP_PTREGS(%r15) # address of register-save area
lh %r3,__LC_EXT_INT_CODE # error code
-#ifdef CONFIG_SMP
- chi %r3,0x1202 # EXTERNAL_CALL
- jne ext_no_extcall
- l %r9,ext_call_int-ext_lit(%r13) # load ext_call_interrupt
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_extcall:
-#endif
- chi %r3,0x1004 # CPU_TIMER
- jne ext_no_timer
- l %r9,ext_timer_int-ext_lit(%r13) # load timer_interrupt
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_timer:
-#ifdef CONFIG_HWC
- chi %r3,0x2401 # HWC interrupt
- jne ext_no_hwc
- l %r9,ext_hwc_int-ext_lit(%r13) # load addr. of hwc routine
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_hwc:
-#endif
-#ifdef CONFIG_MDISK
- chi %r3,0x2603 # diag 250 (VM) interrupt
- jne ext_no_mdisk
- l %r9,ext_mdisk_int-ext_lit(%r13)
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_mdisk:
-#endif
-#ifdef CONFIG_IUCV
- chi %r3,0x4000 # diag 250 (VM) interrupt
- jne ext_no_iucv
- l %r9,ext_iucv_int-ext_lit(%r13)
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_iucv:
-#endif
-
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r14 # use backend code of io_int_handler
+ lr %r1,%r3 # calculate index = code & 0xff
+ n %r1,BASED(.Lc0xff)
+ sll %r1,2
+ l %r9,BASED(.Lext_hash)
+ l %r9,0(%r1,%r9) # get first list entry for hash value
+ ltr %r9,%r9 # == NULL ?
+ bz BASED(io_return) # yes, nothing to do, exit
+ext_int_loop:
+ ch %r3,8(%r9) # compare external interrupt code
+ be BASED(ext_int_found)
+ icm %r9,15,0(%r9) # next list entry
+ bnz BASED(ext_int_loop)
+ b BASED(io_return)
+ext_int_found:
+ l %r9,4(%r9) # get handler address
+ la %r14,BASED(io_return)
+ br %r9 # branch to ext call handler
/*
* Machine check handler routines
*/
-mcck_lit:
- mcck_crw_pending: .long do_crw_pending
-
.globl mcck_int_handler
mcck_int_handler:
SAVE_ALL(0x30)
- basr %r13,0
- ahi %r13,mcck_lit-. # setup base pointer R13 to $MCCKDAT
- tm __LC_MCCK_CODE+1,0x40
- jno mcck_no_crw
- l %r1,mcck_crw_pending-mcck_lit(%r13)
- basr %r14,%r1 # call do_crw_pending
-mcck_no_crw:
+ l %r1,BASED(.Ls390_mcck)
+ basr %r14,%r1 # call machine check handler
mcck_return:
RESTORE_ALL
@@ -876,11 +828,11 @@ restart_int_handler:
lam %a0,%a15,__LC_AREGS_SAVE_AREA
stosm 0(%r15),daton # now we can turn dat on
lm %r6,%r15,24(%r15) # load registers from clone
- bras %r14,restart_go
- .long start_secondary
-restart_go:
- l %r14,0(%r14)
+ basr %r14,0
+ l %r14,restart_addr-.(%r14)
br %r14 # branch to start_secondary
+restart_addr:
+ .long start_secondary
#else
/*
* If we do not run with SMP enabled, let the new CPU crash ...
@@ -896,3 +848,48 @@ restart_crash:
restart_go:
#endif
+/*
+ * Integer constants
+ */
+ .align 4
+.Lc0xfffffff8: .long -8 # to align stack pointer to 8
+.Lc0xffffe000: .long -8192 # to round stack pointer to &task_struct
+.Lc8191: .long 8191
+.Lc_spsize: .long SP_SIZE
+.Lc_ac: .long 0,0,1
+.Lc_ENOSYS: .long -ENOSYS
+.Lc4: .long 4
+.Lc0x1202: .long 0x1202
+.Lc0x1004: .long 0x1004
+.Lc0x2401: .long 0x2401
+.Lc0x4000: .long 0x4000
+.Lc0xff: .long 0xff
+
+/*
+ * Symbol constants
+ */
+.Ls390_mcck: .long s390_do_machine_check
+.Ldo_IRQ: .long do_IRQ
+.Ldo_signal: .long do_signal
+.Ldo_softirq: .long do_softirq
+.Lentry_base: .long entry_base
+.Lext_hash: .long ext_int_hash
+.Lhandle_per: .long handle_per_exception
+.Ljump_table: .long pgm_check_table
+.Lschedule: .long schedule
+.Lclone: .long sys_clone
+.Lexecve: .long sys_execve
+.Lfork: .long sys_fork
+.Lrt_sigreturn:.long sys_rt_sigreturn
+.Lrt_sigsuspend:
+ .long sys_rt_sigsuspend
+.Lsigreturn: .long sys_sigreturn
+.Lsigsuspend: .long sys_sigsuspend
+.Lsigaltstack: .long sys_sigaltstack
+.Ltrace: .long syscall_trace
+.Lvfork: .long sys_vfork
+
+#ifdef CONFIG_SMP
+.Lschedtail: .long schedule_tail
+#endif
+
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index a3b5df25c..d41f398d8 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -2,20 +2,29 @@
* arch/s390/kernel/head.S
*
* S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Hartmut Penner (hp@de.ibm.com),
* Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Rob van der Heij (rvdhei@iae.nl)
*
- * There are 4 different IPL methods
+ * There are 5 different IPL methods
* 1) load the image directly into ram at address 0 and do an PSW restart
* 2) linload will load the image from address 0x10000 to memory 0x10000
* and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
* 3) generate the tape ipl header, store the generated image on a tape
* and ipl from it
+ * In case of SL tape you need to IPL 5 times to get past VOL1 etc
* 4) generate the vm reader ipl header, move the generated image to the
* VM reader (use option NOH!) and do a ipl from reader (VM only)
+ * 5) direct call of start by the SALIPL loader
* We use the cpuid to distinguish between VM and native ipl
* params for kernel are pushed to 0x10400 (see setup.h)
+
+ Changes:
+ Okt 25 2000 <rvdheij@iae.nl>
+ added code to skip HDR and EOF to allow SL tape IPL (5 retries)
+ changed first CCW from rewind to backspace block
+
*/
#include <linux/config.h>
@@ -24,40 +33,13 @@
#ifndef CONFIG_IPL
.org 0
- .long 0x00080000,0x80000000+iplstart # Just a restart PSW
-
-iplstart:
- l %r12,.Lparm # pointer to parameter area
-#
-# find out memory size
-#
- mvc 104(8,0),.Lpcmem0 # setup program check handler
- slr %r2,%r2
- lhi %r3,1
- sll %r3,20
-.Lloop0:
- l %r0,0(%r2) # test page
- ar %r2,%r3 # add 1M
- jnm .Lloop0 # r1 < 0x80000000 -> loop
-.Lchkmem0:
- n %r2,.L4malign0 # align to multiples of 4M
- st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size
- slr %r2,%r2
- st %r2,INITRD_SIZE-PARMAREA(%r12) # null ramdisk
- st %r2,INITRD_START-PARMAREA(%r12)
- j start
-
-.Lparm: .long PARMAREA
-.L4malign0:.long 0xffc00000
- .align 8
-.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0
-
+ .long 0x00080000,0x80000000+startup # Just a restart PSW
#else
#ifdef CONFIG_IPL_TAPE
#define IPL_BS 1024
.org 0
.long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
- .long 0x07000000,0x60000001 # by ipl to addresses 0-23.
+ .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
.long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
.long 0x00000000,0x00000000 # external old psw
.long 0x00000000,0x00000000 # svc old psw
@@ -74,92 +56,6 @@ iplstart:
.long 0x00080000,0x80000000+.Lioint # io new psw
.org 0x100
-iplstart:
- l %r1,0xb8 # load ipl subchannel number
- lhi %r2,IPL_BS # load start address
- bras %r14,.Lloader # load rest of ipl image
- st %r1,__LC_IPLDEV # store ipl device number
- l %r12,.Lparm # pointer to parameter area
-
-#
-# find out memory size
-#
- mvc 104(8,0),.Lpcmem0 # setup program check handler
- slr %r2,%r2
- lhi %r3,1
- sll %r3,20
-.Lloop0:
- l %r0,0(%r2) # test page
- ar %r2,%r3 # add 1M
- jnm .Lloop0 # r1 < 0x80000000 -> loop
-.Lchkmem0:
- n %r2,.L4malign0 # align to multiples of 4M
- st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size
- c %r2,.Lbigmem # more than 64 MB of memory ?
- jl .Lmemok # if yes load ramdisk to 32 MB
- mvc INITRD_START-PARMAREA(4,%r12),.Lrdstart
-.Lmemok:
-
-#
-# load parameter file from tape
-#
- l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp
- bras %r14,.Lloader # load parameter file
- ltr %r2,%r2 # got anything ?
- jz .Lnopf
- chi %r2,895
- jnh .Lnotrunc
- lhi %r2,895
-.Lnotrunc:
- l %r4,INITRD_START-PARMAREA(%r12)
- la %r5,0(%r4,%r2)
- lr %r3,%r2
-.Lidebc:
- tm 0(%r5),0x80 # high order bit set ?
- jo .Ldocv # yes -> convert from EBCDIC
- ahi %r5,-1
- brct %r3,.Lidebc
- j .Lnocv
-.Ldocv:
- l %r3,.Lcvtab
- tr 0(256,%r4),0(%r3) # convert parameters to ascii
- tr 256(256,%r4),0(%r3)
- tr 512(256,%r4),0(%r3)
- tr 768(122,%r4),0(%r3)
-.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
- mvc 0(256,%r3),0(%r4)
- mvc 256(256,%r3),256(%r4)
- mvc 512(256,%r3),512(%r4)
- mvc 768(122,%r3),768(%r4)
- slr %r0,%r0
- j .Lcntlp
-.Ldelspc:
- ic %r0,0(%r2,%r3)
- chi %r0,0x20 # is it a space ?
- je .Lcntlp
- ahi %r2,1
- j .Leolp
-.Lcntlp:
- brct %r2,.Ldelspc
-.Leolp:
- slr %r0,%r0
- stc %r0,0(%r2,%r3) # terminate buffer
-.Lnopf:
-
-#
-# load ramdisk from tape
-#
- l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
- bras %r14,.Lloader # load ramdisk
- st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
- ltr %r2,%r2
- jnz .Lrdcont
- st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it
-.Lrdcont:
-#
-# everything loaded, go for it
-#
- j start
#
# subroutine for loading from tape
# Paramters:
@@ -173,32 +69,32 @@ iplstart:
lctl %c6,%c6,.Lcr6
slr %r2,%r2
.Lldlp:
- lhi %r6,3 # 3 retries
+ la %r6,3 # 3 retries
.Lssch:
ssch 0(%r3) # load chunk of IPL_BS bytes
- jnz .Llderr
+ bnz .Llderr
.Lw4end:
- bras %r14,.Lwait4io
+ bas %r14,.Lwait4io
tm 8(%r5),0x82 # do we have a problem ?
- jnz .Lrecov
+ bnz .Lrecov
slr %r7,%r7
icm %r7,3,10(%r5) # get residual count
lcr %r7,%r7
- ahi %r7,IPL_BS # IPL_BS-residual=#bytes read
+ la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
ar %r2,%r7 # add to total size
tm 8(%r5),0x01 # found a tape mark ?
- jnz .Ldone
+ bnz .Ldone
l %r0,.Lccwread+4 # update CCW data addresses
ar %r0,%r7
st %r0,.Lccwread+4
- j .Lldlp
+ b .Lldlp
.Ldone:
l %r14,.Lldret
br %r14 # r2 contains the total size
.Lrecov:
- bras %r14,.Lsense # do the sensing
- brct %r6,.Lssch # dec. retry count & branch
- j .Llderr
+ bas %r14,.Lsense # do the sensing
+ bct %r6,.Lssch # dec. retry count & branch
+ b .Llderr
#
# Sense subroutine
#
@@ -206,11 +102,11 @@ iplstart:
st %r14,.Lsnsret
la %r7,.Lorbsense
ssch 0(%r7) # start sense command
- jnz .Llderr
- bras %r14,.Lwait4io
+ bnz .Llderr
+ bas %r14,.Lwait4io
l %r14,.Lsnsret
tm 8(%r5),0x82 # do we have a problem ?
- jnz .Llderr
+ bnz .Llderr
br %r14
#
# Wait for interrupt subroutine
@@ -219,13 +115,13 @@ iplstart:
lpsw .Lwaitpsw
.Lioint:
c %r1,0xb8 # compare subchannel number
- jne .Lwait4io
+ bne .Lwait4io
tsch 0(%r5)
slr %r0,%r0
tm 8(%r5),0x82 # do we have a problem ?
- jnz .Lwtexit
+ bnz .Lwtexit
tm 8(%r5),0x04 # got device end ?
- jz .Lwait4io
+ bz .Lwait4io
.Lwtexit:
br %r14
.Llderr:
@@ -249,18 +145,12 @@ iplstart:
.Lcr6: .long 0xff000000
.align 8
.Lcrash:.long 0x000a0000,0x00000000
-.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0
-.Lparm: .long PARMAREA
-.L4malign0:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
.Lldret:.long 0
.Lsnsret: .long 0
-.Lcvtab:.long _ebcasc # ebcdic to ascii table
-
#endif /* CONFIG_IPL_TAPE */
#ifdef CONFIG_IPL_VM
+#define IPL_BS 0x730
.org 0
.long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
.long 0x02000018,0x60000050 # by ipl to addresses 0-23.
@@ -287,103 +177,7 @@ iplstart:
.long 0x02000690,0x60000050
.long 0x020006e0,0x20000050
-
.org 0xf0
-iplstart:
- l %r1,0xb8 # load ipl subchannel number
- lhi %r2,0x730 # load start address
- bras %r14,.Lloader # load rest of ipl image
- st %r1,__LC_IPLDEV # store ipl device number
- l %r12,.Lparm # pointer to parameter area
-
-#
-# find out memory size
-#
- mvc 104(8,0),.Lpcmem0 # setup program check handler
- slr %r2,%r2
- lhi %r3,1
- sll %r3,20
-.Lloop0:
- l %r0,0(%r2) # test page
- ar %r2,%r3 # add 1M
- jnm .Lloop0 # r1 < 0x80000000 -> loop
-.Lchkmem0:
- n %r2,.L4malign0 # align to multiples of 4M
- st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size
- c %r2,.Lbigmem # more than 64 MB of memory ?
- jl .Lmemok # if yes load ramdisk to 32 MB
- mvc INITRD_START-PARMAREA(4,%r12),.Lrdstart
-.Lmemok:
-
-#
-# load parameter file from reader
-#
- l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp
- bras %r14,.Lloader # load parameter file
- ltr %r2,%r2 # got anything ?
- jz .Lnopf
- chi %r2,895
- jnh .Lnotrunc
- lhi %r2,895
-.Lnotrunc:
- l %r4,INITRD_START-PARMAREA(%r12)
- la %r5,0(%r4,%r2)
- lr %r3,%r2
-.Lidebc:
- tm 0(%r5),0x80 # high order bit set ?
- jo .Ldocv # yes -> convert from EBCDIC
- ahi %r5,-1
- brct %r3,.Lidebc
- j .Lnocv
-.Ldocv:
- l %r3,.Lcvtab
- tr 0(256,%r4),0(%r3) # convert parameters to ascii
- tr 256(256,%r4),0(%r3)
- tr 512(256,%r4),0(%r3)
- tr 768(122,%r4),0(%r3)
-.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
- mvc 0(256,%r3),0(%r4)
- mvc 256(256,%r3),256(%r4)
- mvc 512(256,%r3),512(%r4)
- mvc 768(122,%r3),768(%r4)
- slr %r0,%r0
- j .Lcntlp
-.Ldelspc:
- ic %r0,0(%r2,%r3)
- chi %r0,0x20 # is it a space ?
- je .Lcntlp
- ahi %r2,1
- j .Leolp
-.Lcntlp:
- brct %r2,.Ldelspc
-.Leolp:
- slr %r0,%r0
- stc %r0,0(%r2,%r3) # terminate buffer
-.Lnopf:
-
-#
-# load ramdisk from reader
-#
- l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
- bras %r14,.Lloader # load ramdisk
- st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
- ltr %r2,%r2
- jnz .Lrdcont
- st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it
-.Lrdcont:
-
-#
-# everything loaded, reset files in reader, then go for it
-#
- stidp __LC_CPUID # store cpuid
- lh %r0,__LC_CPUID+4 # get cpu version
- chi %r0,0x7490 # running on P/390 ?
- je start # no -> skip reset
- la %r2,.Lreset
- lhi %r3,26
- .long 0x83230008
- j start
-
#
# subroutine for loading cards from the reader
#
@@ -394,29 +188,29 @@ iplstart:
la %r7,20
.Linit:
st %r2,4(%r6) # initialize CCW data addresses
- ahi %r2,0x50
- ahi %r6,8
- brct 7,.Linit
+ la %r2,0x50(%r2)
+ la %r6,8(%r6)
+ bct 7,.Linit
lctl %c6,%c6,.Lcr6 # set IO subclass mask
slr %r2,%r2
.Lldlp:
ssch 0(%r3) # load chunk of 1600 bytes
- jnz .Llderr
+ bnz .Llderr
.Lwait4irq:
mvc __LC_IO_NEW_PSW(8),.Lnewpsw # set up IO interrupt psw
lpsw .Lwaitpsw
.Lioint:
c %r1,0xb8 # compare subchannel number
- jne .Lwait4irq
+ bne .Lwait4irq
tsch 0(%r5)
slr %r0,%r0
ic %r0,8(%r5) # get device status
chi %r0,8 # channel end ?
- je .Lcont
+ be .Lcont
chi %r0,12 # channel end + device end ?
- je .Lcont
+ be .Lcont
l %r0,4(%r5)
s %r0,8(%r3) # r0/8 = number of ccws executed
@@ -436,9 +230,9 @@ iplstart:
ahi %r0,0x640
st %r0,4(%r6)
ahi %r6,8
- brct 7,.Lincr
+ bct 7,.Lincr
- j .Lldlp
+ b .Lldlp
.Llderr:
lpsw .Lcrash
@@ -447,16 +241,7 @@ iplstart:
.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.Lcr6: .long 0xff000000
.Lloadp:.long 0,0
-.Lparm: .long PARMAREA
-.L4malign0:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
-.Lcvtab:.long _ebcasc # ebcdic to ascii table
-.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
- .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
- .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
.align 8
-.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0
.Lcrash:.long 0x000a0000,0x00000000
.Lnewpsw:
.long 0x00080000,0x80000000+.Lioint
@@ -468,79 +253,330 @@ iplstart:
.long 0x02600050,0x00000000
.endr
.long 0x02200050,0x00000000
-
- .org 0x730 # end of the area loaded by the ipl channel program
#endif /* CONFIG_IPL_VM */
+iplstart:
+ lh %r1,0xb8 # test if subchannel number
+ bct %r1,.Lnoload # is valid
+ l %r1,0xb8 # load ipl subchannel number
+ la %r2,IPL_BS # load start address
+ bas %r14,.Lloader # load rest of ipl image
+ st %r1,__LC_IPLDEV # store ipl device number
+ l %r12,.Lparm # pointer to parameter area
+
+#
+# load parameter file from ipl device
+#
+.Lagain1:
+ l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp
+ bas %r14,.Lloader # load parameter file
+ ltr %r2,%r2 # got anything ?
+ bz .Lnopf
+ chi %r2,895
+ bnh .Lnotrunc
+ la %r2,895
+.Lnotrunc:
+ l %r4,INITRD_START-PARMAREA(%r12)
+ clc 0(3,%r4),.L_hdr # if it is HDRx
+ bz .Lagain1 # skip dataset header
+ clc 0(3,%r4),.L_eof # if it is EOFx
+ bz .Lagain1 # skip dateset trailer
+ la %r5,0(%r4,%r2)
+ lr %r3,%r2
+.Lidebc:
+ tm 0(%r5),0x80 # high order bit set ?
+ bo .Ldocv # yes -> convert from EBCDIC
+ ahi %r5,-1
+ bct %r3,.Lidebc
+ b .Lnocv
+.Ldocv:
+ l %r3,.Lcvtab
+ tr 0(256,%r4),0(%r3) # convert parameters to ascii
+ tr 256(256,%r4),0(%r3)
+ tr 512(256,%r4),0(%r3)
+ tr 768(122,%r4),0(%r3)
+.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+ mvc 0(256,%r3),0(%r4)
+ mvc 256(256,%r3),256(%r4)
+ mvc 512(256,%r3),512(%r4)
+ mvc 768(122,%r3),768(%r4)
+ slr %r0,%r0
+ b .Lcntlp
+.Ldelspc:
+ ic %r0,0(%r2,%r3)
+ chi %r0,0x20 # is it a space ?
+ be .Lcntlp
+ ahi %r2,1
+ b .Leolp
+.Lcntlp:
+ brct %r2,.Ldelspc
+.Leolp:
+ slr %r0,%r0
+ stc %r0,0(%r2,%r3) # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from ipl device
+#
+.Lagain2:
+ l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
+ bas %r14,.Lloader # load ramdisk
+ st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
+ ltr %r2,%r2
+ bnz .Lrdcont
+ st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it
+.Lrdcont:
+ l %r2,INITRD_START-PARMAREA(%r12)
+
+ clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
+ bz .Lagain2
+ clc 0(3,%r2),.L_eof
+ bz .Lagain2
+
+#ifdef CONFIG_IPL_VM
+#
+# reset files in VM reader
+#
+ stidp __LC_CPUID # store cpuid
+ lh %r0,__LC_CPUID+4 # get cpu version
+ chi %r0,0x7490 # running on P/390 ?
+ be start # no -> skip reset
+ la %r2,.Lreset
+ lhi %r3,26
+ .long 0x83230008
+#endif
+
+#
+# everything loaded, go for it
+#
+.Lnoload:
+ l %r1,.Lstartup
+ br %r1
+
+.Lparm: .long PARMAREA
+.Lstartup: .long startup
+.Lcvtab:.long _ebcasc # ebcdic to ascii table
+.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+ .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+ .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
+.L_eof: .long 0xc5d6c600 /* C'EOF' */
+.L_hdr: .long 0xc8c4d900 /* C'HDR' */
+
#endif /* CONFIG_IPL */
#
+# SALIPL loader support. Based on a patch by Rob van der Heij.
+# This entry point is called directly from the SALIPL loader and
+# doesn't need a builtin ipl record.
+#
+ .org 0x800
+ .globl start
+start:
+ stm %r0,%r15,0x07b0 # store registers
+ basr %r12,%r0
+.base:
+ l %r11,.parm
+ l %r8,.cmd # pointer to command buffer
+
+ ltr %r9,%r9 # do we have SALIPL parameters?
+ bp .sk8x8
+
+ mvc 0(64,%r8),0x00b0 # copy saved registers
+ xc 64(240-64,%r8),0(%r8) # remainder of buffer
+ tr 0(64,%r8),.lowcase
+ b .gotr
+.sk8x8:
+ mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
+.gotr:
+ l %r10,.tbl # EBCDIC to ASCII table
+ tr 0(240,%r8),0(%r10)
+ stidp __LC_CPUID # Are we running on VM maybe
+ cli __LC_CPUID,0xff
+ bnz .test
+ .long 0x83300060 # diag 3,0,x'0060' - storage size
+ b .done
+.test:
+ mvc 0x68(8),.pgmnw # set up pgm check handler
+ l %r2,.fourmeg
+ lr %r3,%r2
+ bctr %r3,%r0 # 4M-1
+.loop: iske %r0,%r3
+ ar %r3,%r2
+.pgmx:
+ sr %r3,%r2
+ la %r3,1(%r3)
+.done:
+ st %r3,MEMORY_SIZE-PARMAREA(%r11)
+ slr %r0,%r0
+ st %r0,INITRD_SIZE-PARMAREA(%r11)
+ st %r0,INITRD_START-PARMAREA(%r11)
+ j startup # continue with startup
+.tbl: .long _ebcasc # translate table
+.cmd: .long COMMAND_LINE # address of command line buffer
+.parm: .long PARMAREA
+.fourmeg: .long 0x00400000 # 4M
+.pgmnw: .long 0x00080000,.pgmx
+.lowcase:
+ .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
+ .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+ .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
+ .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
+ .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
+ .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+ .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
+ .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
+ .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
+ .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
+ .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
+ .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
+ .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
+ .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
+ .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
+ .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
+
+ .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
+ .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
+ .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
+ .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
+ .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
+ .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
+ .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
+ .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
+ .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
+ .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi
+ .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
+ .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr
+ .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx
+ .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz
+ .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
+ .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+
+#
# startup-code at 0x10000, running in real mode
-# this is called either by the ipl loader or directly by PSW restart or linload
+# this is called either by the ipl loader or directly by PSW restart
+# or linload or SALIPL
#
.org 0x10000
- .globl start
-start: basr %r13,0 # get base
-.LPG1: lctl %c1,%c1,.Lpstd-.LPG1(%r13) # load pstd
- lctl %c7,%c7,.Lpstd-.LPG1(%r13) # load sstd
- lctl %c13,%c13,.Lpstd-.LPG1(%r13) # load hstd
- lctl %c0,%c0,.Lcr0-.LPG1(%r13) # set CR0
+startup:basr %r13,0 # get base
+.LPG1: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
l %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area
#
-# find out memory size. That is done in the ipl loader too but for
-# ipl from dasd the size of the memory has to be detected too...
+# find out memory size.
#
- icm %r0,15,MEMORY_SIZE-PARMAREA(%r12)
- jnz .Lsizeok
- mvc 104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler
- slr %r1,%r1
+ mvc 104(8),.Lpcmem-.LPG1(%r13) # setup program check handler
lhi %r2,1
- sll %r2,20
+ sll %r2,17 # test in increments of 128KB
+ lr %r1,%r2
+ ahi %r1,-4 # test last word in the segment
.Lloop:
- l %r0,0(%r1) # test page
- ar %r1,%r2 # add 1M
- jnm .Lloop # r1 < 0x80000000 -> loop
+ l %r0,0(%r1) # test 128KB segment
+ st %r0,0(%r1)
+ ar %r1,%r2 # add 128KB
+ bnm .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop
.Lchkmem:
n %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M
st %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size
.Lsizeok:
#
+# Now we have to move the ramdisk to a location approriate for the
+# memory size. If we have more than 64 MB of memory we move it to 32MB
+# to make room for the page tables set up by paging_init.
+#
+ l %r1,MEMORY_SIZE-PARMAREA(%r12)
+ cl %r1,.Lbigmem-.LPG1(%r13) # memory < 64mb ?
+ bl .Lnomove-.LPG1(%r13) # if yes ramdisk @8MB is ok
+ icm %r4,15,INITRD_START-PARMAREA(%r12)
+ bz .Lnomove-.LPG1(%r13)
+ l %r2,.Lrdstart-.LPG1(%r13) # new address of ramdisk
+ st %r2,INITRD_START-PARMAREA(%r12)
+ l %r1,INITRD_SIZE-PARMAREA(%r12)
+ ar %r2,%r1 # we start moving at the end
+ ar %r4,%r1 # because new location > old location
+.Lmove: lr %r0,%r2 # new - old is the maximum we can move
+ sr %r0,%r4 # because of overlapping
+ cr %r0,%r1 # we shouldn't move more than there is
+ bnh .Lnoend-.LPG1(%r13)
+ lr %r0,%r1
+.Lnoend:cl %r0,.Lmaxchunk-.LPG1(%r13) # mvcl can move 2^24-1 in one go
+ bnh .Lchunk-.LPG1(%r13)
+ l %r0,.Lmaxchunk-.LPG1(%r13)
+.Lchunk:sr %r2,%r0 # make source & destination pointer
+ sr %r4,%r0
+ lr %r3,%r0 # set source & destination length
+ lr %r5,%r0
+ mvcl %r2,%r4
+ sr %r2,%r0 # substract length again, since
+ sr %r4,%r0 # mvcl added it to the pointers
+ sr %r1,%r0 # substract chunk size from length
+ bnz .Lmove-.LPG1(%r13)
+.Lnomove:
+
+#
# find out if we are running under VM
#
stidp __LC_CPUID # store cpuid
tm __LC_CPUID,0xff # running under VM ?
- jno .Lnovm
+ bno .Lnovm-.LPG1(%r13)
oi MACHINE_FLAGS+3-PARMAREA(%r12),1 # set VM flag
.Lnovm:
lh %r0,__LC_CPUID+4 # get cpu version
chi %r0,0x7490 # running on a P/390 ?
- jne .Lnop390
+ bne .Lnop390-.LPG1(%r13)
oi MACHINE_FLAGS+3-PARMAREA(%r12),4 # set P/390 flag
.Lnop390:
#
# find out if we have an IEEE fpu
#
- mvc 104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler
+ mvc 104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler
ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0
ldr %f2,%f0
adbr %f0,%f2 # test IEEE add instruction
oi MACHINE_FLAGS+3-PARMAREA(%r12),2 # set IEEE fpu flag
.Lchkfpu:
+#
+# find out if we have the CSP instruction
+#
+ mvc 104(8),.Lpccsp-.LPG1(%r13) # setup program check handler
+ la %r0,0
+ lr %r1,%r0
+ la %r2,.Lflt0-.LPG1(%r13)
+ csp %r0,%r2 # Test CSP instruction
+ oi MACHINE_FLAGS+3-PARMAREA(%r12),8 # set CSP flag
+.Lchkcsp:
+
lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
# virtual and never return ...
.align 8
-.Lentry:.long 0x04080000,0x80000000 + _stext
-.Lpstd: .long .Lpgd+0x7F # segment-table
-.Lcr0: .long 0x04b50002
+.Lentry:.long 0x00080000,0x80000000 + _stext
+.Lctl: .long 0x04b50002 # cr0: various things
+ .long 0 # cr1: primary space segment table
+ .long 0 # cr2: access register translation
+ .long 0 # cr3: instruction authorization
+ .long 0 # cr4: instruction authorization
+ .long 0 # cr5: various things
+ .long 0 # cr6: I/O interrupts
+ .long 0 # cr7: secondary space segment table
+ .long 0 # cr8: access registers translation
+ .long 0 # cr9: tracing off
+ .long 0 # cr10: tracing off
+ .long 0 # cr11: tracing off
+ .long 0 # cr12: tracing off
+ .long 0 # cr13: home space segment table
+ .long 0xc0000000 # cr14: machine check handling off
+ .long 0 # cr15: linkage stack operations
.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem
.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
+.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
.Lflt0: .double 0
.Lparm1:.long PARMAREA
.L4malign:.long 0xffc00000
+.Lbigmem:.long 0x04000000
+.Lrdstart:.long 0x02000000
+.Lmaxchunk:.long 0x00ffffff
#
# params at 10400 (setup.h)
@@ -555,17 +591,8 @@ start: basr %r13,0 # get base
.word 0 # RAMDISK_FLAGS
.org COMMAND_LINE
-# .byte "root=/dev/nfs rw nfsroot=9.164.160.7:/home/mschwide/nfsboot "
-# .byte "ip=9.164.147.12:9.164.160.7:9.164.147.1:255.255.255.0:vmlinux:tr0:off"
-# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/mschwide/nfsboot "
-# .byte "ip=9.164.181.228:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
-# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/pasch/nfsboot "
-# .byte "ip=9.164.185.120:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
-# .byte "mdisk=402:65536:1229,403:131072:2780 root=/dev/mnda ro"
-# .byte "root=/dev/nfs rw nfsroot=9.164.160.209:/usr/local/nfsboot "
-# .byte "ip=9.164.181.228:9.164.160.209:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
.byte "root=/dev/ram0 ro"
-# .byte 0
+ .byte 0
#
# startup-code, running in virtual mode
@@ -626,43 +653,3 @@ _stext: basr %r13,0 # get base
.align 8
.Ldw: .long 0x000a0000,0x00000000
-#
-# tempory segment-table at 0x11000
-#
- .org 0x11000
-.Lpgd: .long .Lpt0+0x1f # 00000000-000fffff
- .long .Lpt1+0x1f # 00100000-001fffff
- .long .Lpt2+0x1f # 00200000-002fffff
- .long .Lpt3+0x1f # 00300000-003fffff
- .fill 2044,4,0x20 # 00400000-7fffffff
-
-#
-# tempory page-tables at 0x12000-0x15fff
-#
- .macro mktable from,to
- .long \from*0x10000
- .long \from*0x10000+0x1000
- .long \from*0x10000+0x2000
- .long \from*0x10000+0x3000
- .long \from*0x10000+0x4000
- .long \from*0x10000+0x5000
- .long \from*0x10000+0x6000
- .long \from*0x10000+0x7000
- .long \from*0x10000+0x8000
- .long \from*0x10000+0x9000
- .long \from*0x10000+0xa000
- .long \from*0x10000+0xb000
- .long \from*0x10000+0xc000
- .long \from*0x10000+0xd000
- .long \from*0x10000+0xe000
- .long \from*0x10000+0xf000
- .if \to-\from
- mktable "(\from+1)",\to
- .endif
- .endm
-
-.Lpt0: mktable 0,15
-.Lpt1: mktable 16,31
-.Lpt2: mktable 32,47
-.Lpt3: mktable 48,63
-
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index ba513325a..989aa0720 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -20,11 +20,11 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/smp.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
@@ -205,6 +205,8 @@ static inline void wait_on_irq(int cpu)
if (!local_bh_count(cpu)
&& atomic_read(&global_bh_count))
continue;
+ /* this works even though global_irq_lock not
+ a long, but is arch-specific --RR */
if (!test_and_set_bit(0,&global_irq_lock))
break;
}
@@ -243,6 +245,8 @@ void synchronize_irq(void)
static inline void get_irqlock(int cpu)
{
+ /* this works even though global_irq_lock not a long, but is
+ arch-specific --RR */
if (test_and_set_bit(0,&global_irq_lock)) {
/* do we already hold the lock? */
if ( cpu == atomic_read(&global_irq_holder))
@@ -398,7 +402,7 @@ void enable_nop(int irq)
void __init init_IRQ(void)
{
- s390_init_IRQ();
+ s390_init_IRQ();
}
diff --git a/arch/s390/kernel/mathemu.c b/arch/s390/kernel/mathemu.c
index 78b6e5ec6..23c6c72a2 100644
--- a/arch/s390/kernel/mathemu.c
+++ b/arch/s390/kernel/mathemu.c
@@ -9,6 +9,7 @@
* that does not have the IEEE fpu
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
@@ -16,7 +17,59 @@
#include <asm/uaccess.h>
#include <asm/mathemu.h>
-static void set_CC_df(__u64 val1,__u64 val2) {
+#ifdef CONFIG_SYSCTL
+int sysctl_ieee_emulation_warnings=1;
+#endif
+
+#define mathemu_put_user(x, ptr) \
+{ \
+ if(put_user((x),(ptr))) \
+ return 1; \
+}
+
+#define mathemu_get_user(x, ptr) \
+{ \
+ if(get_user((x),(ptr))) \
+ return 1; \
+}
+
+
+#define mathemu_copy_from_user(to,from,n) \
+{ \
+ if(copy_from_user((to),(from),(n))==-EFAULT) \
+ return 1; \
+}
+
+
+#define mathemu_copy_to_user(to, from, n) \
+{ \
+ if(copy_to_user((to),(from),(n))==-EFAULT) \
+ return 1; \
+}
+
+
+
+static void display_emulation_not_implemented(char *instr)
+{
+ struct pt_regs *regs;
+ __u16 *location;
+
+#if CONFIG_SYSCTL
+ if(sysctl_ieee_emulation_warnings)
+#endif
+ {
+ regs=current->thread.regs;
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n",
+ instr,
+ current->comm, current->pid);
+ printk("%s's PSW: %08lx %08lx\n",instr,
+ (unsigned long) regs->psw.mask,
+ (unsigned long) location);
+ }
+}
+
+static int set_CC_df(__u64 val1,__u64 val2) {
int rc;
rc = __cmpdf2(val1,val2);
current->thread.regs->psw.mask &= 0xFFFFCFFF;
@@ -28,9 +81,10 @@ static void set_CC_df(__u64 val1,__u64 val2) {
current->thread.regs->psw.mask |= 0x00002000;
break;
}
+ return 0;
}
-static void set_CC_sf(__u32 val1,__u32 val2) {
+static int set_CC_sf(__u32 val1,__u32 val2) {
int rc;
rc = __cmpsf2(val1,val2);
current->thread.regs->psw.mask &= 0xFFFFCFFF;
@@ -42,384 +96,473 @@ static void set_CC_sf(__u32 val1,__u32 val2) {
current->thread.regs->psw.mask |= 0x00002000;
break;
}
+ return 0;
}
-static void emu_adb (int rx, __u64 val) {
+static int emu_adb (int rx, __u64 val) {
current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_adbr (int rx, int ry) {
+static int emu_adbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,
current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_aeb (int rx, __u32 val) {
+static int emu_aeb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_aebr (int rx, int ry) {
+static int emu_aebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,
current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_axbr (int rx, int ry) {
- printk("axbr emulation not implemented!\n");
+static int emu_axbr (int rx, int ry) {
+ display_emulation_not_implemented("axbr");
+ return 0;
}
-static void emu_cdb (int rx, __u64 val) {
+static int emu_cdb (int rx, __u64 val) {
set_CC_df(current->thread.fp_regs.fprs[rx].d,val);
+ return 0;
}
-static void emu_cdbr (int rx, int ry) {
+static int emu_cdbr (int rx, int ry) {
set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d);
+ return 0;
}
-static void emu_cdfbr (int rx, int ry) {
+static int emu_cdfbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d =
__floatsidf(current->thread.regs->gprs[ry]);
+ return 0;
}
-static void emu_ceb (int rx, __u32 val) {
+static int emu_ceb (int rx, __u32 val) {
set_CC_sf(current->thread.fp_regs.fprs[rx].f,val);
+ return 0;
}
-static void emu_cebr (int rx, int ry) {
+static int emu_cebr (int rx, int ry) {
set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f);
+ return 0;
}
-static void emu_cefbr (int rx, int ry) {
+static int emu_cefbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f =
__floatsisf(current->thread.regs->gprs[ry]);
+ return 0;
}
-static void emu_cfdbr (int rx, int ry, int mask) {
+static int emu_cfdbr (int rx, int ry, int mask) {
current->thread.regs->gprs[rx] =
__fixdfsi(current->thread.fp_regs.fprs[ry].d);
+ return 0;
}
-static void emu_cfebr (int rx, int ry, int mask) {
+static int emu_cfebr (int rx, int ry, int mask) {
current->thread.regs->gprs[rx] =
__fixsfsi(current->thread.fp_regs.fprs[ry].f);
+ return 0;
}
-static void emu_cfxbr (int rx, int ry, int mask) {
- printk("cfxbr emulation not implemented!\n");
+static int emu_cfxbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("cfxbr");
+ return 0;
}
-static void emu_cxbr (int rx, int ry) {
- printk("cxbr emulation not implemented!\n");
+static int emu_cxbr (int rx, int ry) {
+ display_emulation_not_implemented("cxbr");
+ return 0;
}
-static void emu_cxfbr (int rx, int ry) {
- printk("cxfbr emulation not implemented!\n");
+static int emu_cxfbr (int rx, int ry) {
+ display_emulation_not_implemented("cxfbr");
+ return 0;
}
-static void emu_ddb (int rx, __u64 val) {
+static int emu_ddb (int rx, __u64 val) {
current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_ddbr (int rx, int ry) {
+static int emu_ddbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,
current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_deb (int rx, __u32 val) {
+static int emu_deb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_debr (int rx, int ry) {
+static int emu_debr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,
current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_didbr (int rx, int ry, int mask) {
- printk("didbr emulation not implemented!\n");
+static int emu_didbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("didbr");
+ return 0;
}
-static void emu_diebr (int rx, int ry, int mask) {
- printk("diebr emulation not implemented!\n");
+static int emu_diebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("diebr");
+ return 0;
}
-static void emu_dxbr (int rx, int ry) {
- printk("dxbr emulation not implemented!\n");
+static int emu_dxbr (int rx, int ry) {
+ display_emulation_not_implemented("dxbr");
+ return 0;
}
-static void emu_efpc (int rx, int ry) {
- printk("efpc emulation not implemented!\n");
+static int emu_efpc (int rx, int ry) {
+ current->thread.regs->gprs[rx]=current->thread.fp_regs.fpc;
+ return 0;
}
-static void emu_fidbr (int rx, int ry, int mask) {
- printk("fidbr emulation not implemented!\n");
+static int emu_fidbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("fidbr");
+ return 0;
}
-static void emu_fiebr (int rx, int ry, int mask) {
- printk("fiebr emulation not implemented!\n");
+static int emu_fiebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("fiebr");
+ return 0;
}
-static void emu_fixbr (int rx, int ry, int mask) {
- printk("fixbr emulation not implemented!\n");
+static int emu_fixbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("fixbr");
+ return 0;
}
-static void emu_kdb (int rx, __u64 val) {
- printk("kdb emulation not implemented!\n");
+static int emu_kdb (int rx, __u64 val) {
+ display_emulation_not_implemented("kdb");
+ return 0;
}
-static void emu_kdbr (int rx, int ry) {
- printk("kdbr emulation not implemented!\n");
+static int emu_kdbr (int rx, int ry) {
+ display_emulation_not_implemented("kdbr");
+ return 0;
}
-static void emu_keb (int rx, __u32 val) {
- printk("keb emulation not implemented!\n");
+static int emu_keb (int rx, __u32 val) {
+ display_emulation_not_implemented("keb");
+ return 0;
}
-static void emu_kebr (int rx, int ry) {
- printk("kebr emulation not implemented!\n");
+static int emu_kebr (int rx, int ry) {
+ display_emulation_not_implemented("kebr");
+ return 0;
}
-static void emu_kxbr (int rx, int ry) {
- printk("kxbr emulation not implemented!\n");
+static int emu_kxbr (int rx, int ry) {
+ display_emulation_not_implemented("kxbr");
+ return 0;
}
-static void emu_lcdbr (int rx, int ry) {
+static int emu_lcdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d =
__negdf2(current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_lcebr (int rx, int ry) {
+static int emu_lcebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f =
__negsf2(current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_lcxbr (int rx, int ry) {
- printk("lcxbr emulation not implemented!\n");
+static int emu_lcxbr (int rx, int ry) {
+ display_emulation_not_implemented("lcxbr");
+ return 0;
}
-static void emu_ldeb (int rx, __u32 val) {
+static int emu_ldeb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val);
+ return 0;
}
-static void emu_ldebr (int rx, int ry) {
+static int emu_ldebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d =
__extendsfdf2(current->thread.fp_regs.fprs[ry].f);
+ return 0;
}
-static void emu_ldxbr (int rx, int ry) {
- printk("ldxbr emulation not implemented!\n");
+static int emu_ldxbr (int rx, int ry) {
+ display_emulation_not_implemented("ldxbr");
+ return 0;
}
-static void emu_ledbr (int rx, int ry) {
+static int emu_ledbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_lexbr (int rx, int ry) {
- printk("lexbr emulation not implemented!\n");
+static int emu_lexbr (int rx, int ry) {
+ display_emulation_not_implemented("lexbr");
+ return 0;
}
-static void emu_lndbr (int rx, int ry) {
- printk("lndbr emulation not implemented!\n");
+static int emu_lndbr (int rx, int ry) {
+ display_emulation_not_implemented("lndbr");
+ return 0;
}
-static void emu_lnebr (int rx, int ry) {
- printk("lnebr emulation not implemented!\n");
+static int emu_lnebr (int rx, int ry) {
+ display_emulation_not_implemented("lnebr");
+ return 0;
}
-static void emu_lnxbr (int rx, int ry) {
- printk("lnxbr emulation not implemented!\n");
+static int emu_lnxbr (int rx, int ry) {
+ display_emulation_not_implemented("lnxbr");
+ return 0;
}
-static void emu_lpdbr (int rx, int ry) {
+static int emu_lpdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0);
+ return 0;
}
-static void emu_lpebr (int rx, int ry) {
+static int emu_lpebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_lpxbr (int rx, int ry) {
- printk("lpxbr emulation not implemented!\n");
+static int emu_lpxbr (int rx, int ry) {
+ display_emulation_not_implemented("lpxbr");
+ return 0;
}
-static void emu_ltdbr (int rx, int ry) {
+static int emu_ltdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d;
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_ltebr (int rx, int ry) {
+static int emu_ltebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f;
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_ltxbr (int rx, int ry) {
- printk("ltxbr emulation not implemented!\n");
+static int emu_ltxbr (int rx, int ry) {
+ display_emulation_not_implemented("ltxbr");
+ return 0;
}
-static void emu_lxdb (int rx, __u64 val) {
- printk("lxdb emulation not implemented!\n");
+static int emu_lxdb (int rx, __u64 val) {
+ display_emulation_not_implemented("lxdb");
+ return 0;
}
-static void emu_lxdbr (int rx, int ry) {
- printk("lxdbr emulation not implemented!\n");
+static int emu_lxdbr (int rx, int ry) {
+ display_emulation_not_implemented("lxdbr");
+ return 0;
}
-static void emu_lxeb (int rx, __u32 val) {
- printk("lxeb emulation not implemented!\n");
+static int emu_lxeb (int rx, __u32 val) {
+ display_emulation_not_implemented("lxeb");
+ return 0;
}
-static void emu_lxebr (int rx, int ry) {
- printk("lxebr emulation not implemented!\n");
+static int emu_lxebr (int rx, int ry) {
+ display_emulation_not_implemented("lxebr");
+ return 0;
}
-static void emu_madb (int rx, __u64 val, int mask) {
- printk("madb emulation not implemented!\n");
+static int emu_madb (int rx, __u64 val, int mask) {
+ display_emulation_not_implemented("madb");
+ return 0;
}
-static void emu_madbr (int rx, int ry, int mask) {
- printk(" emulation not implemented!\n");
+static int emu_madbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("madbr");
+ return 0;
}
-static void emu_maeb (int rx, __u32 val, int mask) {
- printk("maeb emulation not implemented!\n");
+static int emu_maeb (int rx, __u32 val, int mask) {
+ display_emulation_not_implemented("maeb");
+ return 0;
}
-static void emu_maebr (int rx, int ry, int mask) {
- printk("maebr emulation not implemented!\n");
+static int emu_maebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("maebr");
+ return 0;
}
-static void emu_mdb (int rx, __u64 val) {
+static int emu_mdb (int rx, __u64 val) {
current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_mdbr (int rx, int ry) {
+static int emu_mdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,
current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_mdeb (int rx, __u32 val) {
- printk("mdeb emulation not implemented!\n");
+static int emu_mdeb (int rx, __u32 val) {
+ display_emulation_not_implemented("mdeb");
+ return 0;
}
-static void emu_mdebr (int rx, int ry) {
- printk("mdebr emulation not implemented!\n");
+static int emu_mdebr (int rx, int ry) {
+ display_emulation_not_implemented("mdebr");
+ return 0;
}
-static void emu_meeb (int rx, __u32 val) {
+static int emu_meeb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
val);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_meebr (int rx, int ry) {
+static int emu_meebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_msdb (int rx, __u64 val, int mask) {
- printk("msdb emulation not implemented!\n");
+static int emu_msdb (int rx, __u64 val, int mask) {
+ display_emulation_not_implemented("msdb");
+ return 0;
}
-static void emu_msdbr (int rx, int ry, int mask) {
- printk("msdbr emulation not implemented!\n");
+static int emu_msdbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("msdbr");
+ return 0;
}
-static void emu_mseb (int rx, __u32 val, int mask) {
- printk("mseb emulation not implemented!\n");
+static int emu_mseb (int rx, __u32 val, int mask) {
+ display_emulation_not_implemented("mseb");
+ return 0;
}
-static void emu_msebr (int rx, int ry, int mask) {
- printk("msebr emulation not implemented!\n");
+static int emu_msebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("msebr");
+ return 0;
}
-static void emu_mxbr (int rx, int ry) {
- printk("mxbr emulation not implemented!\n");
+static int emu_mxbr (int rx, int ry) {
+ display_emulation_not_implemented("mxbr");
+ return 0;
}
-static void emu_mxdb (int rx, __u64 val) {
- printk("mxdb emulation not implemented!\n");
+static int emu_mxdb (int rx, __u64 val) {
+ display_emulation_not_implemented("mxdb");
+ return 0;
}
-static void emu_mxdbr (int rx, int ry) {
- printk("mxdbr emulation not implemented!\n");
+static int emu_mxdbr (int rx, int ry) {
+ display_emulation_not_implemented("mxdbr");
+ return 0;
}
-static void emu_sdb (int rx, __u64 val) {
+static int emu_sdb (int rx, __u64 val) {
current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
val);
set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_sdbr (int rx, int ry) {
+static int emu_sdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
current->thread.fp_regs.fprs[ry].d);
set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_seb (int rx, __u32 val) {
+static int emu_seb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
val);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_sebr (int rx, int ry) {
+static int emu_sebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_sfpc (int rx, int ry) {
- printk("sfpc emulation not implemented!\n");
+static int emu_sfpc (int rx, int ry) {
+ __u32 val=current->thread.regs->gprs[rx];
+ if(val==0)
+ current->thread.fp_regs.fpc=val;
+ else
+ display_emulation_not_implemented("sfpc");
+ return 0;
}
-static void emu_sqdb (int rx, __u64 val) {
- printk("sqdb emulation not implemented!\n");
+static int emu_sqdb (int rx, __u64 val) {
+ display_emulation_not_implemented("sqdb");
+ return 0;
}
-static void emu_sqdbr (int rx, int ry) {
- printk("sqdbr emulation not implemented!\n");
+static int emu_sqdbr (int rx, int ry) {
+ display_emulation_not_implemented("sqdbr");
+ return 0;
}
-static void emu_sqeb (int rx, __u32 val) {
- printk("sqeb emulation not implemented!\n");
+static int emu_sqeb (int rx, __u32 val) {
+ display_emulation_not_implemented("sqeb");
+ return 0;
}
-static void emu_sqebr (int rx, int ry) {
- printk("sqebr emulation not implemented!\n");
+static int emu_sqebr (int rx, int ry) {
+ display_emulation_not_implemented("sqebr");
+ return 0;
}
-static void emu_sqxbr (int rx, int ry) {
- printk("sqxbr emulation not implemented!\n");
+static int emu_sqxbr (int rx, int ry) {
+ display_emulation_not_implemented("sqxbr");
+ return 0;
}
-static void emu_sxbr (int rx, int ry) {
- printk("sxbr emulation not implemented!\n");
+static int emu_sxbr (int rx, int ry) {
+ display_emulation_not_implemented("sxbr");
+ return 0;
}
-static void emu_tcdb (int rx, __u64 val) {
- printk("tcdb emulation not implemented!\n");
+static int emu_tcdb (int rx, __u64 val) {
+ display_emulation_not_implemented("tcdb");
+ return 0;
}
-static void emu_tceb (int rx, __u32 val) {
- printk("tceb emulation not implemented!\n");
+static int emu_tceb (int rx, __u32 val) {
+ display_emulation_not_implemented("tceb");
+ return 0;
}
-static void emu_tcxb (int rx, __u64 val) {
- printk("tcxb emulation not implemented!\n");
+static int emu_tcxb (int rx, __u64 val) {
+ display_emulation_not_implemented("tcxb");
+ return 0;
}
@@ -473,6 +616,7 @@ static inline void emu_store_rege(int reg) {
}
int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
+ int rc=0;
static const __u8 format_table[] = {
2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4,
1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3,
@@ -538,84 +682,82 @@ int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
emu_store_regd((opcode[3]>>4)&15);
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_regd((opcode[3]>>4)&15);
- emu_load_regd(opcode[3]&15);
- return 0;
+ emu_load_regd((opcode[3]>>4)&15);
+ emu_load_regd(opcode[3]&15);
+ return rc;
case 2: /* RRE format, float operation */
emu_store_rege((opcode[3]>>4)&15);
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_rege((opcode[3]>>4)&15);
- emu_load_rege(opcode[3]&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ emu_load_rege(opcode[3]&15);
+ return rc;
case 3: /* RRF format, double operation */
emu_store_regd((opcode[3]>>4)&15);
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- emu_load_regd((opcode[3]>>4)&15);
- emu_load_regd(opcode[3]&15);
- return 0;
+ emu_load_regd((opcode[3]>>4)&15);
+ emu_load_regd(opcode[3]&15);
+ return rc;
case 4: /* RRF format, float operation */
emu_store_rege((opcode[3]>>4)&15);
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- emu_load_rege((opcode[3]>>4)&15);
- emu_load_rege(opcode[3]&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ emu_load_rege(opcode[3]&15);
+ return rc;
case 5: /* RRE format, cefbr instruction */
emu_store_rege((opcode[3]>>4)&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_rege((opcode[3]>>4)&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ return rc;
case 6: /* RRE format, cdfbr & cxfbr instruction */
emu_store_regd((opcode[3]>>4)&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_regd((opcode[3]>>4)&15);
- return 0;
- /* FIXME !! */
- return 0;
- case 7: /* RRF format, cfebr instruction */
+ emu_load_regd((opcode[3]>>4)&15);
+ return rc;
+ case 7: /* RRF format, cfebr instruction */
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- return 0;
+ return rc;
case 8: /* RRF format, cfdbr & cfxbr instruction */
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- return 0;
+ return rc;
case 9: /* RRE format, ldebr & mdebr instruction */
/* float store but double load */
emu_store_rege((opcode[3]>>4)&15);
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_regd((opcode[3]>>4)&15);
- return 0;
+ emu_load_regd((opcode[3]>>4)&15);
+ return rc;
case 10: /* RRE format, ledbr instruction */
/* double store but float load */
emu_store_regd((opcode[3]>>4)&15);
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_rege((opcode[3]>>4)&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ return rc;
default:
return 1;
}
@@ -632,6 +774,8 @@ static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp)
}
int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
+ int rc=0;
+
static const __u8 format_table[] = {
0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4,
2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3,
@@ -669,13 +813,12 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
emu_store_regd((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_from_user fails ? */
- copy_from_user(&temp, dxb, 8);
+ mathemu_copy_from_user(&temp, dxb, 8);
/* call the emulation function */
- ((void (*)(int, __u64))jump_table[opcode[5]])
+ rc=((int (*)(int, __u64))jump_table[opcode[5]])
(opcode[1]>>4,temp);
- emu_load_regd((opcode[1]>>4)&15);
- return 0;
+ emu_load_regd((opcode[1]>>4)&15);
+ return rc;
}
case 2: /* RXE format, __u32 constant */ {
__u32 *dxb, temp;
@@ -684,13 +827,12 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
emu_store_rege((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
- get_user(temp, dxb);
+ mathemu_get_user(temp, dxb);
/* call the emulation function */
- ((void (*)(int, __u32))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32))jump_table[opcode[5]])
(opcode[1]>>4,temp);
- emu_load_rege((opcode[1]>>4)&15);
- return 0;
+ emu_load_rege((opcode[1]>>4)&15);
+ return rc;
}
case 3: /* RXF format, __u64 constant */ {
__u32 *dxb, temp;
@@ -699,13 +841,12 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
emu_store_regd((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_from_user fails ? */
- copy_from_user(&temp, dxb, 8);
+ mathemu_copy_from_user(&temp, dxb, 8);
/* call the emulation function */
- ((void (*)(int, __u32, int))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
(opcode[1]>>4,temp,opcode[4]>>4);
- emu_load_regd((opcode[1]>>4)&15);
- return 0;
+ emu_load_regd((opcode[1]>>4)&15);
+ return rc;
}
case 4: /* RXF format, __u32 constant */ {
__u32 *dxb, temp;
@@ -714,29 +855,27 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
emu_store_rege((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
- get_user(temp, dxb);
+ mathemu_get_user(temp, dxb);
/* call the emulation function */
- ((void (*)(int, __u32, int))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
(opcode[1]>>4,temp,opcode[4]>>4);
emu_load_rege((opcode[1]>>4)&15);
- return 0;
+ return rc;
}
case 5: /* RXE format, __u32 constant */
/* store_rege and load_regd */
- {
+ {
__u32 *dxb, temp;
__u32 opc;
emu_store_rege((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
- get_user(temp, dxb);
+ mathemu_get_user(temp, dxb);
/* call the emulation function */
- ((void (*)(int, __u32))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32))jump_table[opcode[5]])
(opcode[1]>>4,temp);
emu_load_regd((opcode[1]>>4)&15);
- return 0;
+ return rc;
}
default:
return 1;
@@ -746,7 +885,7 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
/*
* Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
*/
-void math_emu_ldr(__u8 *opcode) {
+int math_emu_ldr(__u8 *opcode) {
__u16 opc = *((__u16 *) opcode);
if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */
@@ -772,12 +911,13 @@ void math_emu_ldr(__u8 *opcode) {
current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
current->thread.fp_regs.fprs[opc&0x000f];
}
+ return 0;
}
/*
* Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
*/
-void math_emu_ler(__u8 *opcode) {
+int math_emu_ler(__u8 *opcode) {
__u16 opc = *((__u16 *) opcode);
if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */
@@ -803,61 +943,68 @@ void math_emu_ler(__u8 *opcode) {
current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
current->thread.fp_regs.fprs[opc&0x000f];
}
+ return 0;
}
/*
* Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u64 *dxb;
dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_from_user fails ? */
- copy_from_user(&current->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+ mathemu_copy_from_user(&current->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+ return 0;
}
/*
* Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_le(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_le(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u32 *mem, *dxb;
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
- get_user(mem[0], dxb);
+ mathemu_get_user(mem[0], dxb);
+ return 0;
}
/*
* Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_std(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_std(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u64 *dxb;
dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_to_user fails ? */
- copy_to_user(dxb, &current->thread.fp_regs.fprs[(opc>>20)&15].d, 8);
+ mathemu_copy_to_user(dxb, &current->thread.fp_regs.fprs[(opc>>20)&15].d, 8);
+ return 0;
}
/*
* Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u32 *mem, *dxb;
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if put_user fails ? */
+ /* FIXME: how to react if mathemu_put_user fails ? */
mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
- put_user(mem[0], dxb);
+ mathemu_put_user(mem[0], dxb);
+ return 0;
}
/*
* Emulate LFPC D(B)
*/
int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
- /* FIXME: how to do that ?!? */
+ __u32 *dxb,temp;
+ __u32 opc = *((__u32 *) opcode);
+ dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
+ mathemu_get_user(temp, dxb);
+ if(temp!=0)
+ display_emulation_not_implemented("lfpc");
return 0;
}
@@ -865,7 +1012,10 @@ int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
* Emulate STFPC D(B)
*/
int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
- /* FIXME: how to do that ?!? */
+ __u32 *dxb;
+ __u32 opc = *((__u32 *) opcode);
+ dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
+ mathemu_put_user(current->thread.fp_regs.fpc, dxb);
return 0;
}
@@ -874,6 +1024,7 @@ int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
*/
int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
/* FIXME: how to do that ?!? */
+ display_emulation_not_implemented("srnm");
return 0;
}
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 2fc6d08fa..f8238de1e 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -28,7 +28,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
@@ -67,7 +67,9 @@ int cpu_idle(void *unused)
if (softirq_active(smp_processor_id()) &
softirq_mask(smp_processor_id())) {
do_softirq();
- continue;
+ __sti();
+ if (!current->need_resched)
+ continue;
}
if (current->need_resched) {
schedule();
@@ -92,12 +94,13 @@ idle_wakeup:
0 returned you know you've got all the lines
*/
-int sprintf_regs(int line, char *buff, struct task_struct * task,
- struct thread_struct *thread, struct pt_regs * regs)
-{
+static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs)
+{
int linelen=0;
int regno,chaincnt;
u32 backchain,prev_backchain,endchain;
+ u32 ksp = 0;
+ char *mode = "???";
enum
{
@@ -118,106 +121,125 @@ int sprintf_regs(int line, char *buff, struct task_struct * task,
sp_kern_backchain1
};
- if(task)
- thread = &task->thread;
- if(thread)
- regs = thread->regs;
- switch (line) {
- case sp_linefeed:
+ if (task)
+ ksp = task->thread.ksp;
+ if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE))
+ ksp = regs->gprs[15];
+
+ if (regs)
+ mode = (regs->psw.mask & PSW_PROBLEM_STATE)?
+ "User" : "Kernel";
+
+ switch(line)
+ {
+ case sp_linefeed:
linelen=sprintf(buff,"\n");
break;
case sp_psw:
if(regs)
- linelen = sprintf(buff,"User PSW: %08lx %08lx\n",
- (unsigned long) regs->psw.mask,
- (unsigned long) regs->psw.addr);
+ linelen=sprintf(buff, "%s PSW: %08lx %08lx\n", mode,
+ (unsigned long) regs->psw.mask,
+ (unsigned long) regs->psw.addr);
else
- linelen = sprintf(buff,"pt_regs=NULL some info unavailable\n");
+ linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
break;
case sp_ksp:
- if (task)
- linelen += sprintf(&buff[linelen],
- "task: %08x ", (addr_t)task);
- if (thread)
- linelen += sprintf(&buff[linelen],
- "thread: %08x ksp: %08x ",
- (addr_t)thread,(addr_t)thread->ksp);
- if (regs)
- linelen += sprintf(&buff[linelen],
- "pt_regs: %08x\n", (addr_t)regs);
+ linelen=sprintf(&buff[linelen],
+ "task: %08x ksp: %08x pt_regs: %08x\n",
+ (addr_t)task, (addr_t)ksp, (addr_t)regs);
break;
case sp_gprs:
- if (regs)
- linelen = sprintf(buff,"User GPRS:\n");
+ if(regs)
+ linelen=sprintf(buff, "%s GPRS:\n", mode);
break;
case sp_gprs1 ... sp_gprs4:
- if (regs) {
- regno = (line-sp_gprs1)*4;
- linelen = sprintf(buff,"%08x %08x %08x %08x\n",
- regs->gprs[regno],
- regs->gprs[regno+1],
- regs->gprs[regno+2],
- regs->gprs[regno+3]);
+ if(regs)
+ {
+ regno=(line-sp_gprs1)*4;
+ linelen=sprintf(buff,"%08x %08x %08x %08x\n",
+ regs->gprs[regno],
+ regs->gprs[regno+1],
+ regs->gprs[regno+2],
+ regs->gprs[regno+3]);
}
break;
case sp_acrs:
- if (regs)
- linelen = sprintf(buff,"User ACRS:\n");
+ if(regs)
+ linelen=sprintf(buff, "%s ACRS:\n", mode);
break;
case sp_acrs1 ... sp_acrs4:
- if (regs) {
- regno = (line-sp_acrs1)*4;
- linelen = sprintf(buff,"%08x %08x %08x %08x\n",
- regs->acrs[regno],
- regs->acrs[regno+1],
- regs->acrs[regno+2],
- regs->acrs[regno+3]);
+ if(regs)
+ {
+ regno=(line-sp_acrs1)*4;
+ linelen=sprintf(buff,"%08x %08x %08x %08x\n",
+ regs->acrs[regno],
+ regs->acrs[regno+1],
+ regs->acrs[regno+2],
+ regs->acrs[regno+3]);
}
break;
case sp_kern_backchain:
- if (thread && thread->ksp && regs)
- linelen = sprintf(buff,"Kernel BackChain CallChain BackChain CallChain\n");
+ if (regs && (regs->psw.mask & PSW_PROBLEM_STATE))
+ break;
+ if (ksp)
+ linelen=sprintf(buff, "Kernel BackChain CallChain\n");
break;
default:
- if(thread && thread->ksp && regs) {
- backchain = (thread->ksp & PSW_ADDR_MASK);
- endchain = ((backchain & (-8192)) + 8192);
- prev_backchain = backchain - 1;
- line -= sp_kern_backchain1;
- for (chaincnt = 0; ; chaincnt++) {
- if ((backchain == 0) ||
- (backchain >= endchain) ||
- (chaincnt >= 8) ||
- (prev_backchain >= backchain))
+ if (ksp)
+ {
+
+ backchain=ksp&PSW_ADDR_MASK;
+ endchain=((backchain&(-8192))+8192);
+ prev_backchain=backchain-1;
+ line-=sp_kern_backchain1;
+ for(chaincnt=0;;chaincnt++)
+ {
+ if((backchain==0)||(backchain>=endchain)
+ ||(chaincnt>=8)||(prev_backchain>=backchain))
break;
- if ((chaincnt >> 1) == line) {
- linelen += sprintf(&buff[linelen],"%s%08x %08x ",
- (chaincnt&1) ? "":" ",
- backchain,*(u32 *)(backchain+56));
- }
- if ((chaincnt >> 1) > line)
+ if(chaincnt==line)
+ {
+ linelen+=sprintf(&buff[linelen]," %08x [<%08lx>]\n",
+ backchain,
+ *(u32 *)(backchain+56)&PSW_ADDR_MASK);
break;
- prev_backchain = backchain;
- backchain = (*((u32 *)backchain)) & PSW_ADDR_MASK;
+ }
+ prev_backchain=backchain;
+ backchain=(*((u32 *)backchain))&PSW_ADDR_MASK;
}
- if (linelen)
- linelen += sprintf(&buff[linelen],"\n");
}
}
- return linelen;
+ return(linelen);
}
-void show_regs(struct task_struct *task, struct thread_struct *thread,
- struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
{
char buff[80];
int line;
+
+ printk("CPU: %d\n",smp_processor_id());
+ printk("Process %s (pid: %d, stackpage=%08X)\n",
+ current->comm, current->pid, 4096+(addr_t)current);
- for (line = 0; sprintf_regs(line,buff,task,thread,regs); line++)
+ for (line = 0; sprintf_regs(line, buff, current, regs); line++)
printk(buff);
}
+char *task_show_regs(struct task_struct *task, char *buffer)
+{
+ int line, len;
+
+ for (line = 0; ; line++)
+ {
+ len = sprintf_regs(line, buffer, task, task->thread.regs);
+ if (!len) break;
+ buffer += len;
+ }
+ return buffer;
+}
+
+
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
int clone_arg = flags | CLONE_VM;
@@ -327,7 +349,7 @@ asmlinkage int sys_clone(struct pt_regs regs)
lock_kernel();
clone_flags = regs.gprs[3];
- newsp = regs.gprs[2];
+ newsp = regs.orig_gpr2;
if (!newsp)
newsp = regs.gprs[15];
ret = do_fork(clone_flags, newsp, &regs, 0);
@@ -365,7 +387,19 @@ asmlinkage int sys_execve(struct pt_regs regs)
goto out;
error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
if (error == 0)
- current->flags &= ~PF_DTRACE;
+ {
+ current->ptrace &= ~PT_DTRACE;
+ current->thread.fp_regs.fpc=0;
+ if(MACHINE_HAS_IEEE)
+ {
+ __asm__ __volatile__
+ ("sr 0,0\n\t"
+ "sfpc 0,0\n\t"
+ :
+ :
+ :"0");
+ }
+ }
putname(filename);
out:
return error;
@@ -412,21 +446,77 @@ extern void scheduling_functions_end_here(void);
unsigned long get_wchan(struct task_struct *p)
{
- unsigned long r14, r15;
+ unsigned long r14, r15, bc;
unsigned long stack_page;
int count = 0;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
stack_page = (unsigned long) p;
r15 = p->thread.ksp;
+ if (!stack_page || r15 < stack_page || r15 >= 8188+stack_page)
+ return 0;
+ bc = (*(unsigned long *) r15) & 0x7fffffff;
do {
- r14 = *(unsigned long *) (r15+56);
+ if (bc < stack_page || bc >= 8188+stack_page)
+ return 0;
+ r14 = (*(unsigned long *) (bc+56)) & 0x7fffffff;
if (r14 < first_sched || r14 >= last_sched)
return r14;
- r15 = *(unsigned long *) (r15+60);
+ bc = (*(unsigned long *) bc) & 0x7fffffff;
} while (count++ < 16);
return 0;
}
#undef last_sched
#undef first_sched
+/*
+ * This should be safe even if called from tq_scheduler
+ * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0.
+ *
+ */
+void s390_daemonize(char *name,unsigned long mask,int use_init_fs)
+{
+ struct fs_struct *fs;
+ extern struct task_struct *child_reaper;
+ struct task_struct *this_process=current;
+
+ /*
+ * If we were started as result of loading a module, close all of the
+ * user space pages. We don't need them, and if we didn't close them
+ * they would be locked into memory.
+ */
+ exit_mm(current);
+
+ this_process->session = 1;
+ this_process->pgrp = 1;
+ if(name)
+ {
+ strncpy(current->comm,name,15);
+ current->comm[15]=0;
+ }
+ else
+ current->comm[0]=0;
+ /* set signal mask to what we want to respond */
+ siginitsetinv(&current->blocked,mask);
+ /* exit_signal isn't set up */
+ /* if we inherit from cpu idle */
+ this_process->exit_signal=SIGCHLD;
+ /* if priority=0 schedule can go into a tight loop */
+ this_process->policy= SCHED_OTHER;
+ /* nice goes priority=20-nice; */
+ this_process->nice=10;
+ if(use_init_fs)
+ {
+ exit_fs(this_process); /* current->fs->count--; */
+ fs = init_task.fs;
+ current->fs = fs;
+ atomic_inc(&fs->count);
+ exit_files(current);
+ }
+ write_lock_irq(&tasklist_lock);
+ /* We want init as our parent */
+ REMOVE_LINKS(this_process);
+ this_process->p_opptr=this_process->p_pptr=child_reaper;
+ SET_LINKS(this_process);
+ write_unlock_irq(&tasklist_lock);
+}
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 2643f100a..29a81418a 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -66,10 +66,16 @@ void FixPerRegisters(struct task_struct *task)
regs->psw.mask |=PSW_PER_MASK;
else
regs->psw.mask &= ~PSW_PER_MASK;
- if(per_info->control_regs.bits.storage_alt_space_ctl)
- task->thread.user_seg|=USER_STD_MASK;
+ if (per_info->control_regs.bits.em_storage_alteration)
+ {
+ per_info->control_regs.bits.storage_alt_space_ctl=1;
+ //((pgd_t *)__pa(task->mm->pgd))->pgd |= USER_STD_MASK;
+ }
else
- task->thread.user_seg&=~USER_STD_MASK;
+ {
+ per_info->control_regs.bits.storage_alt_space_ctl=0;
+ //((pgd_t *)__pa(task->mm->pgd))->pgd &= ~USER_STD_MASK;
+ }
}
void set_single_step(struct task_struct *task)
@@ -209,10 +215,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (request == PTRACE_TRACEME)
{
/* are we already being traced? */
- if (current->flags & PF_PTRACED)
+ if (current->ptrace & PT_PTRACED)
goto out;
/* set the ptrace bit in the process flags. */
- current->flags |= PF_PTRACED;
+ current->ptrace |= PT_PTRACED;
ret = 0;
goto out;
}
@@ -237,9 +243,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
(current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE))
goto out;
/* the same process cannot be attached many times */
- if (child->flags & PF_PTRACED)
+ if (child->ptrace & PT_PTRACED)
goto out;
- child->flags |= PF_PTRACED;
+ child->ptrace |= PT_PTRACED;
write_lock_irqsave(&tasklist_lock, flags);
if (child->p_pptr != current)
@@ -256,16 +262,20 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
ret = -ESRCH;
// printk("child=%lX child->flags=%lX",child,child->flags);
- if (!(child->flags & PF_PTRACED))
- goto out;
- if (child->state != TASK_STOPPED)
+ /* I added child!=current line so we can get the */
+ /* ieee_instruction_pointer from the user structure DJB */
+ if(child!=current)
{
- if (request != PTRACE_KILL)
+ if (!(child->ptrace & PT_PTRACED))
+ goto out;
+ if (child->state != TASK_STOPPED)
+ {
+ if (request != PTRACE_KILL)
+ goto out;
+ }
+ if (child->p_pptr != current)
goto out;
}
- if (child->p_pptr != current)
- goto out;
-
switch (request)
{
/* If I and D space are separate, these will need to be fixed. */
@@ -303,9 +313,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if ((unsigned long) data >= _NSIG)
break;
if (request == PTRACE_SYSCALL)
- child->flags |= PF_TRACESYS;
+ child->ptrace |= PT_TRACESYS;
else
- child->flags &= ~PF_TRACESYS;
+ child->ptrace &= ~PT_TRACESYS;
child->exit_code = data;
/* make sure the single step bit is not set. */
clear_single_step(child);
@@ -332,7 +342,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = -EIO;
if ((unsigned long) data >= _NSIG)
break;
- child->flags &= ~PF_TRACESYS;
+ child->ptrace &= ~PT_TRACESYS;
child->exit_code = data;
set_single_step(child);
/* give it a chance to run. */
@@ -344,7 +354,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = -EIO;
if ((unsigned long) data >= _NSIG)
break;
- child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
child->exit_code = data;
write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
@@ -374,11 +384,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
asmlinkage void syscall_trace(void)
{
lock_kernel();
- if ((current->flags & (PF_PTRACED|PF_TRACESYS))
- != (PF_PTRACED|PF_TRACESYS))
+ if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
+ != (PT_PTRACED|PT_TRACESYS))
goto out;
current->exit_code = SIGTRAP;
- current->state = TASK_STOPPED;
+ set_current_state(TASK_STOPPED);
notify_parent(current, SIGCHLD);
schedule();
/*
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
index a77940905..c30fe433c 100644
--- a/arch/s390/kernel/reipl.S
+++ b/arch/s390/kernel/reipl.S
@@ -1,4 +1,13 @@
+/*
+ * arch/s390/kernel/reipl.S
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ */
+
#include <asm/lowcore.h>
+
.globl do_reipl
do_reipl: basr %r13,0
.Lpg0: lpsw .Lnewpsw-.Lpg0(%r13)
@@ -7,7 +16,7 @@ do_reipl: basr %r13,0
ni .Lctlsave-.Lpg0(%r13),0xef
lctl %c0,%c0,.Lctlsave-.Lpg0(%r13)
lr %r1,%r2
- mvc __LC_PGM_NEW_PSW(8,0),.Lpcnew-.Lpg0(%r13)
+ mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
stsch .Lschib-.Lpg0(%r13)
oi .Lschib+5-.Lpg0(%r13),0x84
.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
@@ -15,9 +24,9 @@ do_reipl: basr %r13,0
ssch .Liplorb-.Lpg0(%r13)
jz .L001
bas %r14,.Ldisab-.Lpg0(%r13)
-.L001: mvc __LC_IO_NEW_PSW(8,0),.Lionew-.Lpg0(%r13)
+.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)
.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13)
-.Lcont: c %r1,__LC_SUBCHANNEL_ID(%r0)
+.Lcont: c %r1,__LC_SUBCHANNEL_ID
jnz .Ltpi
clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
jnz .Ltpi
@@ -29,7 +38,7 @@ do_reipl: basr %r13,0
jz .L003
bas %r14,.Ldisab-.Lpg0(%r13)
.L003: spx .Lnull-.Lpg0(%r13)
- st %r1,__LC_SUBCHANNEL_ID(%r0)
+ st %r1,__LC_SUBCHANNEL_ID
lpsw 0
sigp 0,0,0(6)
.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
new file mode 100644
index 000000000..6a7be9496
--- /dev/null
+++ b/arch/s390/kernel/s390_ext.c
@@ -0,0 +1,77 @@
+/*
+ * arch/s390/kernel/s390_ext.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <asm/lowcore.h>
+#include <asm/s390_ext.h>
+
+/*
+ * Simple hash strategy: index = code & 0xff;
+ * ext_int_hash[index] is the start of the list for all external interrupts
+ * that hash to this index. With the current set of external interrupts
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
+ * iucv) this is always the first element.
+ */
+ext_int_info_t *ext_int_hash[256] = { 0, };
+ext_int_info_t ext_int_info_timer;
+ext_int_info_t ext_int_info_hwc;
+
+int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
+ ext_int_info_t *p;
+ int index;
+
+ index = code & 0xff;
+ p = ext_int_hash[index];
+ while (p != NULL) {
+ if (p->code == code)
+ return -EBUSY;
+ p = p->next;
+ }
+ if (code == 0x1004) /* time_init is done before kmalloc works :-/ */
+ p = &ext_int_info_timer;
+ else if (code == 0x2401) /* hwc_init is done too early too */
+ p = &ext_int_info_hwc;
+ else
+ p = (ext_int_info_t *)
+ kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
+ if (p == NULL)
+ return -ENOMEM;
+ p->code = code;
+ p->handler = handler;
+ p->next = ext_int_hash[index];
+ ext_int_hash[index] = p;
+ return 0;
+}
+
+int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
+ ext_int_info_t *p, *q;
+ int index;
+
+ index = code & 0xff;
+ q = NULL;
+ p = ext_int_hash[index];
+ while (p != NULL) {
+ if (p->code == code && p->handler == handler)
+ break;
+ q = p;
+ p = p->next;
+ }
+ if (p == NULL)
+ return -ENOENT;
+ if (q != NULL)
+ q->next = p->next;
+ else
+ ext_int_hash[index] = p->next;
+ if (code != 0x1004 && code != 0x2401)
+ kfree(p);
+ return 0;
+}
+
+
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
index 85ecb5ce0..b0a6d0225 100644
--- a/arch/s390/kernel/s390_ksyms.c
+++ b/arch/s390/kernel/s390_ksyms.c
@@ -5,14 +5,27 @@
*/
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/string.h>
+#include <asm/ccwcache.h>
+#include <asm/debug.h>
#include <asm/irq.h>
-#include <asm/string.h>
+#include <asm/s390_ext.h>
+#include <asm/s390dyn.h>
+#include <asm/ebcdic.h>
#include <asm/checksum.h>
+#include <asm/delay.h>
+#if CONFIG_CHANDEV
+#include <asm/chandev.h>
+#endif
+#if CONFIG_IP_MULTICAST
+#include <net/arp.h>
+#endif
/*
* I/O subsystem
*/
EXPORT_SYMBOL(halt_IO);
+EXPORT_SYMBOL(clear_IO);
EXPORT_SYMBOL(do_IO);
EXPORT_SYMBOL(resume_IO);
EXPORT_SYMBOL(ioinfo);
@@ -22,6 +35,35 @@ EXPORT_SYMBOL(get_irq_by_devno);
EXPORT_SYMBOL(get_devno_by_irq);
EXPORT_SYMBOL(get_irq_first);
EXPORT_SYMBOL(get_irq_next);
+EXPORT_SYMBOL(read_conf_data);
+EXPORT_SYMBOL(read_dev_chars);
+EXPORT_SYMBOL(s390_request_irq_special);
+EXPORT_SYMBOL(s390_device_register);
+EXPORT_SYMBOL(s390_device_unregister);
+
+EXPORT_SYMBOL(ccw_alloc_request);
+EXPORT_SYMBOL(ccw_free_request);
+
+EXPORT_SYMBOL(register_external_interrupt);
+EXPORT_SYMBOL(unregister_external_interrupt);
+
+/*
+ * debug feature
+ */
+EXPORT_SYMBOL(debug_register);
+EXPORT_SYMBOL(debug_unregister);
+EXPORT_SYMBOL(debug_set_level);
+EXPORT_SYMBOL(debug_register_view);
+EXPORT_SYMBOL(debug_unregister_view);
+EXPORT_SYMBOL(debug_event);
+EXPORT_SYMBOL(debug_int_event);
+EXPORT_SYMBOL(debug_text_event);
+EXPORT_SYMBOL(debug_exception);
+EXPORT_SYMBOL(debug_int_exception);
+EXPORT_SYMBOL(debug_text_exception);
+EXPORT_SYMBOL(debug_hex_ascii_view);
+EXPORT_SYMBOL(debug_raw_view);
+EXPORT_SYMBOL(debug_dflt_header_fn);
/*
* memory management
@@ -29,6 +71,16 @@ EXPORT_SYMBOL(get_irq_next);
EXPORT_SYMBOL(_oi_bitmap);
EXPORT_SYMBOL(_ni_bitmap);
EXPORT_SYMBOL(_zb_findmap);
+EXPORT_SYMBOL(__copy_from_user_fixup);
+EXPORT_SYMBOL(__copy_to_user_fixup);
+
+/*
+ * semaphore ops
+ */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_trylock);
/*
* string functions
@@ -36,6 +88,7 @@ EXPORT_SYMBOL(_zb_findmap);
EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memmove);
+EXPORT_SYMBOL_NOVERS(strlen);
EXPORT_SYMBOL_NOVERS(strchr);
EXPORT_SYMBOL_NOVERS(strcmp);
EXPORT_SYMBOL_NOVERS(strncat);
@@ -46,19 +99,42 @@ EXPORT_SYMBOL_NOVERS(strrchr);
EXPORT_SYMBOL_NOVERS(strtok);
EXPORT_SYMBOL_NOVERS(strpbrk);
+EXPORT_SYMBOL_NOVERS(_ascebc_500);
+EXPORT_SYMBOL_NOVERS(_ebcasc_500);
+EXPORT_SYMBOL_NOVERS(_ascebc);
+EXPORT_SYMBOL_NOVERS(_ebcasc);
+EXPORT_SYMBOL_NOVERS(_ebc_tolower);
+EXPORT_SYMBOL_NOVERS(_ebc_toupper);
+
/*
* misc.
*/
+EXPORT_SYMBOL(module_list);
+EXPORT_SYMBOL(__udelay);
#ifdef CONFIG_SMP
#include <asm/smplock.h>
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(lowcore_ptr);
EXPORT_SYMBOL(global_bh_lock);
EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(smp_ctl_set_bit);
+EXPORT_SYMBOL(smp_ctl_clear_bit);
#endif
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(csum_fold);
-
+#if CONFIG_CHANDEV
+EXPORT_SYMBOL(chandev_register_and_probe);
+EXPORT_SYMBOL(chandev_request_irq);
+EXPORT_SYMBOL(chandev_unregister);
+EXPORT_SYMBOL(chandev_initdevice);
+EXPORT_SYMBOL(chandev_initnetdevice);
+#endif
+#if CONFIG_IP_MULTICAST
+/* Required for lcs gigabit ethernet multicast support */
+EXPORT_SYMBOL(arp_mc_map);
+#endif
+EXPORT_SYMBOL(s390_daemonize);
diff --git a/arch/s390/kernel/s390dyn.c b/arch/s390/kernel/s390dyn.c
deleted file mode 100644
index 0a5625830..000000000
--- a/arch/s390/kernel/s390dyn.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/s390/kernel/s390dyn.c
- * S/390 dynamic device attachment
- *
- * S390 version
- * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Ingo Adlung (adlung@de.ibm.com)
- */
-
-#include <linux/init.h>
-
-#include <asm/irq.h>
-#include <asm/s390io.h>
-#include <asm/s390dyn.h>
-
-int s390_device_register( devreg_t *drinfo )
-{
- return -EOPNOTSUPP;
-}
-
-
-int s390_device_deregister ( devreg_t *dreg )
-{
- return -EOPNOTSUPP;
-}
-
-int s390_request_irq_special( int irq,
- io_handler_func_t io_handler,
- not_oper_handler_func_t not_oper_handler,
- unsigned long irqflags,
- const char *devname,
- void *dev_id)
-{
- return -EOPNOTSUPP;
-}
-
diff --git a/arch/s390/kernel/s390fpu.c b/arch/s390/kernel/s390fpu.c
index 42048abbc..c56c50d66 100644
--- a/arch/s390/kernel/s390fpu.c
+++ b/arch/s390/kernel/s390fpu.c
@@ -81,6 +81,11 @@ int restore_fp_regs1(s390_fp_regs *fpregs)
{
int has_ieee=MACHINE_HAS_IEEE;
+ /* If we don't mask with the FPC_VALID_MASK here
+ * we've got a very quick shutdown -h now command
+ * via a kernel specification exception.
+ */
+ fpregs->fpc&=FPC_VALID_MASK;
asm volatile ("LD 0,8(%0)\n\t"
"LD 2,24(%0)\n\t"
"LD 4,40(%0)\n\t"
diff --git a/arch/s390/kernel/s390io.c b/arch/s390/kernel/s390io.c
deleted file mode 100644
index b1db16707..000000000
--- a/arch/s390/kernel/s390io.c
+++ /dev/null
@@ -1,4605 +0,0 @@
-/*
- * arch/s390/kernel/s390io.c
- * S/390 common I/O routines
- *
- * S390 version
- * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
- * IBM Corporation
- * Author(s): Ingo Adlung (adlung@de.ibm.com)
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/smp.h>
-#include <linux/tasks.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/bitops.h>
-#include <asm/smp.h>
-#include <asm/pgtable.h>
-#include <asm/delay.h>
-#include <asm/processor.h>
-#include <asm/lowcore.h>
-
-#include <asm/s390io.h>
-#include <asm/s390dyn.h>
-#include <asm/s390mach.h>
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#undef CONFIG_DEBUG_IO
-
-#define REIPL_DEVID_MAGIC 0x87654321
-
-struct irqaction init_IRQ_action;
-unsigned int highest_subchannel;
-ioinfo_t *ioinfo_head = NULL;
-ioinfo_t *ioinfo_tail = NULL;
-ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = {
- [0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA
-};
-
-static spinlock_t sync_isc; // synchronous irq processing lock
-static psw_t io_sync_wait; // wait PSW for sync IO, prot. by sync_isc
-static psw_t io_new_psw; // save I/O new PSW, prot. by sync_isc
-static int cons_dev = -1; // identify console device
-static int init_IRQ_complete = 0;
-static schib_t init_schib;
-static __u64 irq_IPL_TOD;
-
-/*
- * Dummy controller type for unused interrupts
- */
-int do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;}
-int enable_none(unsigned int irq) { return(-ENODEV); }
-int disable_none(unsigned int irq) { return(-ENODEV); }
-
-struct hw_interrupt_type no_irq_type = {
- "none",
- do_none,
- enable_none,
- disable_none
-};
-
-static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
-static int s390_setup_irq(unsigned int irq, struct irqaction * new);
-static void s390_process_subchannels( void);
-static void s390_device_recognition( void);
-static int s390_validate_subchannel( int irq);
-static int s390_SenseID( int irq, senseid_t *sid);
-static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
-static int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid);
-static int s390_process_IRQ( unsigned int irq );
-static int s390_DevicePathVerification( int irq );
-
-extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs);
-extern int enable_none(unsigned int irq);
-extern int disable_none(unsigned int irq);
-extern void tod_wait(unsigned long usecs);
-
-asmlinkage void do_IRQ( struct pt_regs regs,
- unsigned int irq,
- __u32 s390_intparm );
-
-void s390_displayhex(char *str,void *ptr,s32 cnt);
-
-void s390_displayhex(char *str,void *ptr,s32 cnt)
-{
- s32 cnt1,cnt2,maxcnt2;
- u32 *currptr=(__u32 *)ptr;
-
- printk("\n%s\n",str);
-
- for(cnt1=0;cnt1<cnt;cnt1+=16)
- {
- printk("%08lX ",(unsigned long)currptr);
- maxcnt2=cnt-cnt1;
- if(maxcnt2>16)
- maxcnt2=16;
- for(cnt2=0;cnt2<maxcnt2;cnt2+=4)
- printk("%08X ",*currptr++);
- printk("\n");
- }
-}
-
-int s390_request_irq( unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags,
- const char *devname,
- void *dev_id)
-{
- int retval;
- struct irqaction *action;
-
- if (irq >= __MAX_SUBCHANNELS)
- return -EINVAL;
-
- if ( !handler || !dev_id )
- return -EINVAL;
-
- /*
- * during init_IRQ() processing we don't have memory
- * management yet, thus need to use a statically
- * allocated irqaction control block
- */
- if ( init_IRQ_complete )
- {
- action = (struct irqaction *)
- kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- }
- else
- {
- action = &init_IRQ_action;
-
- } /* endif */
-
- if (!action)
- {
- return -ENOMEM;
-
- } /* endif */
-
- action->handler = handler;
- action->flags = irqflags;
- action->mask = 0;
- action->name = devname;
- action->next = NULL;
- action->dev_id = dev_id;
-
- retval = s390_setup_irq( irq, action);
-
- if ( !retval )
- {
- retval = s390_DevicePathVerification( irq );
- }
- else if ( retval && init_IRQ_complete )
- {
- kfree(action);
-
- } /* endif */
-
- return retval;
-}
-
-void s390_free_irq(unsigned int irq, void *dev_id)
-{
- unsigned int flags;
- int ret;
-
- unsigned int count = 0;
-
- if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return;
-
- } /* endif */
-
- s390irq_spin_lock_irqsave( irq, flags);
-
-#ifdef CONFIG_KERNEL_DEBUG
- if ( irq != cons_dev )
- {
- printk("Trying to free IRQ%d\n",irq);
-
- } /* endif */
-#endif
-
- /*
- * disable the device and reset all IRQ info if
- * the IRQ is actually owned by the handler ...
- */
- if ( ioinfo[irq]->irq_desc.action )
- {
- if ( (dev_id == ioinfo[irq]->irq_desc.action->dev_id )
- || (dev_id == (devstat_t *)REIPL_DEVID_MAGIC) )
- {
- /* start deregister */
- ioinfo[irq]->ui.flags.unready = 1;
-
- do
- {
- ret = ioinfo[irq]->irq_desc.handler->disable(irq);
-
- count++;
-
- if ( ret == -EBUSY )
- {
- int iret;
-
- /*
- * kill it !
- * ... we first try sync and eventually
- * try terminating the current I/O by
- * an async request, twice halt, then
- * clear.
- */
- if ( count < 3 )
- {
- iret = halt_IO( irq,
- 0xC8C1D3E3,
- DOIO_WAIT_FOR_INTERRUPT );
-
- if ( iret == -EBUSY )
- {
- halt_IO( irq, 0xC8C1D3E3, 0);
- s390irq_spin_unlock_irqrestore( irq, flags);
- tod_wait( 200000 ); /* 200 ms */
- s390irq_spin_lock_irqsave( irq, flags);
-
- } /* endif */
- }
- else
- {
- iret = clear_IO( irq,
- 0x40C3D3D9,
- DOIO_WAIT_FOR_INTERRUPT );
-
- if ( iret == -EBUSY )
- {
- clear_IO( irq, 0xC8C1D3E3, 0);
- s390irq_spin_unlock_irqrestore( irq, flags);
- tod_wait( 1000000 ); /* 1000 ms */
- s390irq_spin_lock_irqsave( irq, flags);
-
- } /* endif */
-
- } /* endif */
-
- if ( count == 3 )
- {
- /* give it a very last try ... */
- ioinfo[irq]->irq_desc.handler->disable(irq);
-
- if ( ioinfo[irq]->ui.flags.busy )
- {
- printk( KERN_CRIT"free_irq(%04X) "
- "- device %04X busy, retry "
- "count exceeded\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- } /* endif */
-
- break; /* sigh, let's give up ... */
-
- } /* endif */
-
- } /* endif */
-
- } while ( ret == -EBUSY );
-
- if ( init_IRQ_complete )
- kfree( ioinfo[irq]->irq_desc.action );
-
- ioinfo[irq]->irq_desc.action = NULL;
- ioinfo[irq]->ui.flags.ready = 0;
-
- ioinfo[irq]->irq_desc.handler->enable = &enable_none;
- ioinfo[irq]->irq_desc.handler->disable = &disable_none;
-
- ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
-
- s390irq_spin_unlock_irqrestore( irq, flags);
- }
- else
- {
- s390irq_spin_unlock_irqrestore( irq, flags);
-
- printk("free_irq() : error, dev_id does not match !");
-
- } /* endif */
-
- }
- else
- {
- s390irq_spin_unlock_irqrestore( irq, flags);
-
- printk("free_irq() : error, no action block ... !");
-
- } /* endif */
-
-}
-
-/*
- * Generic enable/disable code
- */
-int disable_irq(unsigned int irq)
-{
- unsigned long flags;
- int ret;
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return( -ENODEV);
-
- s390irq_spin_lock_irqsave(irq, flags);
-
- /*
- * At this point we may actually have a pending interrupt being active
- * on another CPU. So don't touch the IRQ_INPROGRESS bit..
- */
- ioinfo[irq]->irq_desc.status |= IRQ_DISABLED;
- ret = ioinfo[irq]->irq_desc.handler->disable(irq);
- s390irq_spin_unlock_irqrestore(irq, flags);
-
- synchronize_irq();
-
- return( ret);
-}
-
-int enable_irq(unsigned int irq)
-{
- unsigned long flags;
- int ret;
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return( -ENODEV);
-
- s390irq_spin_lock_irqsave(irq, flags);
-
- ioinfo[irq]->irq_desc.status = 0;
- ret = ioinfo[irq]->irq_desc.handler->enable(irq);
-
- s390irq_spin_unlock_irqrestore(irq, flags);
-
- return(ret);
-}
-
-/*
- * Enable IRQ by modifying the subchannel
- */
-static int enable_subchannel( unsigned int irq)
-{
- int ret;
- int ccode;
- int retry = 5;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return( -ENODEV);
-
- /*
- * If a previous disable request is pending we reset it. However, this
- * status implies that the device may (still) be not-operational.
- */
- if ( ioinfo[irq]->ui.flags.d_disable )
- {
- ioinfo[irq]->ui.flags.d_disable = 0;
- ret = 0;
- }
- else
- {
-
- ccode = stsch(irq, &(ioinfo[irq]->schib) );
-
- if ( ccode )
- {
- ret = -ENODEV;
- }
- else
- {
- ioinfo[irq]->schib.pmcw.ena = 1;
-
- do
- {
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- switch (ccode) {
- case 0:
- ret = 0;
- break;
-
- case 1:
- /*
- * very bad, requires interrupt alike
- * processing, where "rbh" is a dummy
- * parameter for interface compatibility
- * only. Bottom-half handling cannot be
- * required as this must be an
- * unsolicited interrupt (!busy).
- */
-
- ioinfo[irq]->ui.flags.s_pend = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
-
- ret = -EIO; /* might be overwritten */
- /* ... on re-driving */
- /* ... the msch() */
- retry--;
- break;
-
- case 3:
- ioinfo[irq]->ui.flags.oper = 0;
- ret = -ENODEV;
- break;
-
- default:
- printk( KERN_CRIT"enable_subchannel(%04X) "
- " : ccode 2 on msch() for device "
- "%04X received !\n",
- irq,
- ioinfo[irq]->devstat.devno);
- ret = -ENODEV; // never reached
- }
-
- } while ( (ccode == 1) && retry );
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-
-/*
- * Disable IRQ by modifying the subchannel
- */
-static int disable_subchannel( unsigned int irq)
-{
- int cc; /* condition code */
- int ret; /* function return value */
- int retry = 5;
-
- if ( irq > highest_subchannel )
- {
- ret = -ENODEV;
- }
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else if ( ioinfo[irq]->ui.flags.busy )
- {
- /*
- * the disable function must not be called while there are
- * requests pending for completion !
- */
- ret = -EBUSY;
- }
- else
- {
- /*
- * If device isn't operational we have to perform delayed
- * disabling when the next interrupt occurs - unless the
- * irq is re-requested prior to the interrupt to occur.
- */
- cc = stsch(irq, &(ioinfo[irq]->schib) );
-
- if ( cc == 3 )
- {
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.d_disable = 1;
-
- ret = 0;
- }
- else // cc == 0
- {
- ioinfo[irq]->schib.pmcw.ena = 0;
-
- do
- {
- cc = msch( irq, &(ioinfo[irq]->schib) );
-
- switch (cc) {
- case 0 :
- ret = 0; /* done */
- break;
-
- case 1 :
- /*
- * very bad, requires interrupt alike
- * processing, where "rbh" is a dummy
- * parm for interface compatibility
- * only. Bottom-half handling cannot
- * be required as this must be an
- * unsolicited interrupt (!busy).
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- s390_process_IRQ( irq );
- ioinfo[irq]->ui.flags.s_pend = 0;
-
- ret = -EBUSY; /* might be overwritten */
- /* ... on re-driving the */
- /* ... msch() call */
- retry--;
- break;
-
- case 2 :
- /*
- * *** must not occur ! ***
- * *** ***
- * *** indicates our internal ***
- * *** interrupt accounting is out ***
- * *** of sync ===> panic() ***
- */
- printk( KERN_CRIT"disable_subchannel(%04X) "
- "- unexpected busy condition for "
- "device %04X received !\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- ret = -ENODEV; // never reached
- break;
-
- case 3 :
- /*
- * should hardly occur ?!
- */
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.d_disable = 1;
-
- ret = 0; /* if the device has gone we */
- /* ... don't need to disable */
- /* ... it anymore ! */
- break;
-
- default :
- ret = -ENODEV; // never reached ...
- break;
-
- } /* endswitch */
-
- } while ( (cc == 1) && retry );
-
- } /* endif */
-
- } /* endif */
-
- return( ret);
-}
-
-
-
-int s390_setup_irq( unsigned int irq, struct irqaction * new)
-{
- unsigned long flags;
- int rc = 0;
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * The following block of code has to be executed atomically
- */
- s390irq_spin_lock_irqsave( irq, flags);
-
- if ( ioinfo[irq]->irq_desc.action == NULL )
- {
- ioinfo[irq]->irq_desc.action = new;
- ioinfo[irq]->irq_desc.status = 0;
- ioinfo[irq]->irq_desc.handler->enable = &enable_subchannel;
- ioinfo[irq]->irq_desc.handler->disable = &disable_subchannel;
- ioinfo[irq]->irq_desc.handler->handle = &handle_IRQ_event;
-
- ioinfo[irq]->ui.flags.ready = 1;
-
- ioinfo[irq]->irq_desc.handler->enable(irq);
- }
- else
- {
- /*
- * interrupt already owned, and shared interrupts
- * aren't supported on S/390.
- */
- rc = -EBUSY;
-
- } /* endif */
-
- s390irq_spin_unlock_irqrestore(irq,flags);
-
- return( rc);
-}
-
-void s390_init_IRQ( void )
-{
- unsigned long flags; /* PSW flags */
- long cr6 __attribute__ ((aligned (8)));
-
- // Hopefully bh_count's will get set when we copy the prefix lowcore
- // structure to other CPI's ( DJB )
- softirq_active(smp_processor_id()) = 0;
- softirq_mask(smp_processor_id()) = 0;
- local_bh_count(smp_processor_id()) = 0;
- local_irq_count(smp_processor_id()) = 0;
- syscall_count(smp_processor_id()) = 0;
-
- asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
-
- /*
- * As we don't know about the calling environment
- * we assure running disabled. Before leaving the
- * function we resestablish the old environment.
- *
- * Note : as we don't need a system wide lock, therefore
- * we shouldn't use cli(), but __cli() as this
- * affects the current CPU only.
- */
- __save_flags(flags);
- __cli();
-
- /*
- * disable all interrupts
- */
- cr6 = 0;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- s390_process_subchannels();
-
- /*
- * enable default I/O-interrupt sublass 3
- */
- cr6 = 0x10000000;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- s390_device_recognition();
-
- init_IRQ_complete = 1;
-
- s390_init_machine_check();
-
- __restore_flags(flags);
-
- return;
-}
-
-
-/*
- * dummy handler, used during init_IRQ() processing for compatibility only
- */
-void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs)
-{
- /* this is a dummy handler only ... */
-}
-
-
-int s390_start_IO( int irq, /* IRQ */
- ccw1_t *cpa, /* logical channel prog addr */
- unsigned long user_intparm, /* interruption parameter */
- __u8 lpm, /* logical path mask */
- unsigned long flag) /* flags */
-{
- int ccode;
- unsigned long psw_flags;
-
- int sync_isc_locked = 0;
- int ret = 0;
-
- /*
- * The flag usage is mutal exclusive ...
- */
- if ( (flag & DOIO_RETURN_CHAN_END)
- && (flag & DOIO_REPORT_ALL ) )
- {
- return( -EINVAL );
-
- } /* endif */
-
- memset( &(ioinfo[irq]->orb), '\0', sizeof( orb_t) );
-
- /*
- * setup ORB
- */
- ioinfo[irq]->orb.intparm = (__u32)&ioinfo[irq]->u_intparm;
- ioinfo[irq]->orb.fmt = 1;
-
- ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
- ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND);
- ioinfo[irq]->orb.ssic = ( (flag & DOIO_ALLOW_SUSPEND )
- && (flag & DOIO_SUPPRESS_INTER) );
-
- if ( flag & DOIO_VALID_LPM )
- {
- ioinfo[irq]->orb.lpm = lpm;
- }
- else
- {
- ioinfo[irq]->orb.lpm = ioinfo[irq]->opm;
-
- } /* endif */
-
- ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);
-
- /*
- * If sync processing was requested we lock the sync ISC, modify the
- * device to present interrupts for this ISC only and switch the
- * CPU to handle this ISC + the console ISC exclusively.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- //
- // check whether we run recursively (sense processing)
- //
- if ( !ioinfo[irq]->ui.flags.syncio )
- {
- spin_lock_irqsave( &sync_isc, psw_flags);
-
- ret = enable_cpu_sync_isc( irq);
-
- if ( ret )
- {
- spin_unlock_irqrestore( &sync_isc, psw_flags);
- return( ret);
- }
- else
- {
- sync_isc_locked = 1; // local
- ioinfo[irq]->ui.flags.syncio = 1; // global
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * Issue "Start subchannel" and process condition code
- */
- ccode = ssch( irq, &(ioinfo[irq]->orb) );
-
- switch ( ccode ) {
- case 0:
-
- if ( !ioinfo[irq]->ui.flags.w4sense )
- {
- /*
- * init the device driver specific devstat irb area
- *
- * Note : don´t clear saved irb info in case of sense !
- */
- memset( &((devstat_t *)ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
- } /* endif */
-
- /*
- * initialize device status information
- */
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- ioinfo[irq]->u_intparm = user_intparm;
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.lpum = 0;
- ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION;
- ioinfo[irq]->devstat.scnt = 0;
-
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
-
- /*
- * Check for either early (FAST) notification requests
- * or if we are to return all interrupt info.
- * Default is to call IRQ handler at secondary status only
- */
- if ( flag & DOIO_RETURN_CHAN_END )
- {
- ioinfo[irq]->ui.flags.fast = 1;
- }
- else if ( flag & DOIO_REPORT_ALL )
- {
- ioinfo[irq]->ui.flags.repall = 1;
-
- } /* endif */
-
- ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;
-
- /*
- * If synchronous I/O processing is requested, we have
- * to wait for the corresponding interrupt to occur by
- * polling the interrupt condition. However, as multiple
- * interrupts may be outstanding, we must not just wait
- * for the first interrupt, but must poll until ours
- * pops up.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- // __u32 io_parm;
- psw_t io_new_psw;
- int ccode;
-
- int ready = 0;
- int io_sub = -1;
- struct _lowcore *lc = NULL;
- int count = 30000;
-
- /*
- * We shouldn't perform a TPI loop, waiting for an
- * interrupt to occur, but should load a WAIT PSW
- * instead. Otherwise we may keep the channel subsystem
- * busy, not able to present the interrupt. When our
- * sync. interrupt arrived we reset the I/O old PSW to
- * its original value.
- */
- memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
-
- ccode = iac();
-
- switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "start_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
- } /* endswitch */
-
- io_sync_wait.addr = FIX_PSW(&&io_wakeup);
-
- /*
- * Martin didn't like modifying the new PSW, now we take
- * a fast exit in do_IRQ() instead
- */
- *(__u32 *)__LC_SYNC_IO_WORD = 1;
-
- do
- {
- if ( flag & DOIO_TIMEOUT )
- {
- tpi_info_t tpi_info;
-
- do
- {
- if ( tpi(&tpi_info) == 1 )
- {
- io_sub = tpi_info.irq;
- break;
- }
- else
- {
- count--;
- tod_wait(100); /* usecs */
-
- } /* endif */
-
- } while ( count );
- }
- else
- {
- asm volatile ("lpsw %0" : : "m" (io_sync_wait));
-
-io_wakeup:
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
- } /* endif */
-
- if ( count )
- ready = s390_process_IRQ( io_sub );
-
- /*
- * surrender when retry count's exceeded ...
- */
-
- } while ( !( ( io_sub == irq )
- && ( ready == 1 ))
- && count );
-
- *(__u32 *)__LC_SYNC_IO_WORD = 0;
-
- if ( !count )
- ret = -ETIMEDOUT;
-
- } /* endif */
-
- break;
-
- case 1 : /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- /*
- * initialize the device driver specific devstat irb area
- */
- memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
-
- /*
- * Let the common interrupt handler process the pending status.
- * However, we must avoid calling the user action handler, as
- * it won't be prepared to handle a pending status during
- * do_IO() processing inline. This also implies that process_IRQ
- * must terminate synchronously - especially if device sensing
- * is required.
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * In multipath mode a condition code 3 implies the last path
- * has gone, except we have previously restricted the I/O to
- * a particular path. A condition code 1 (0 won't occur)
- * results in return code EIO as well as 3 with another path
- * than the one used (i.e. path available mask is non-zero).
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
- {
- ret = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 0;
-
-#if CONFIG_DEBUG_IO
- {
- char buffer[80];
-
- stsch(irq, &(ioinfo[irq]->schib) );
-
- sprintf( buffer, "s390_start_IO(%04X) - irb for "
- "device %04X, after status pending\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->devstat.ii.irb) ,
- sizeof(irb_t));
-
- sprintf( buffer, "s390_start_IO(%04X) - schib for "
- "device %04X, after status pending\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->schib) ,
- sizeof(schib_t));
-
-
- if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL)
- {
- sprintf( buffer, "s390_start_IO(%04X) - sense "
- "data for "
- "device %04X, after status pending\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->ii.sense.data,
- ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt);
-
- }
- }
-#endif
- }
- else
- {
- ret = -EIO;
- ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 1;
-
- } /* endif */
-
- break;
-
- case 2 : /* busy */
-
- ret = -EBUSY;
- break;
-
- default: /* device not operational */
-
- ret = -ENODEV;
- ioinfo[irq]->ui.flags.oper = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-
- memcpy( ioinfo[irq]->irq_desc.action->dev_id,
- &(ioinfo[irq]->devstat),
- sizeof( devstat_t) );
-
-#if CONFIG_DEBUG_IO
- {
- char buffer[80];
-
- stsch(irq, &(ioinfo[irq]->schib) );
-
- sprintf( buffer, "s390_start_IO(%04X) - schib for "
- "device %04X, after 'not oper' status\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->schib),
- sizeof(schib_t));
- }
-#endif
- break;
-
- } /* endswitch */
-
- if ( ( flag & DOIO_WAIT_FOR_INTERRUPT )
- && ( sync_isc_locked ) )
- {
- disable_cpu_sync_isc( irq );
-
- spin_unlock_irqrestore( &sync_isc, psw_flags);
-
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
-
- } /* endif */
-
- return( ret);
-}
-
-int do_IO( int irq, /* IRQ */
- ccw1_t *cpa, /* channel program address */
- unsigned long user_intparm, /* interruption parameter */
- __u8 lpm, /* logical path mask */
- unsigned long flag) /* flags : see above */
-{
- int ret = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /* handler registered ? or free_irq() in process already ? */
- if ( !ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready )
- {
- return( -ENODEV );
-
- } /* endif */
-
- /*
- * Note: We ignore the device operational status - if not operational,
- * the SSCH will lead to an -ENODEV condition ...
- */
- if ( !ioinfo[irq]->ui.flags.busy ) /* last I/O completed ? */
- {
- ret = s390_start_IO( irq, cpa, user_intparm, lpm, flag);
- }
- else if ( ioinfo[irq]->ui.flags.fast )
- {
- /*
- * If primary status was received and ending status is missing,
- * the device driver won't be notified on the ending status
- * if early (fast) interrupt notification was requested.
- * Therefore we have to queue the next incoming request. If
- * halt_IO() is issued while there is a request queued, a HSCH
- * needs to be issued and the queued request must be deleted
- * but its intparm must be returned (see halt_IO() processing)
- */
- if ( ioinfo[irq]->ui.flags.w4final
- && !ioinfo[irq]->ui.flags.doio_q )
- {
- ioinfo[irq]->qflag = flag;
- ioinfo[irq]->qcpa = cpa;
- ioinfo[irq]->qintparm = user_intparm;
- ioinfo[irq]->qlpm = lpm;
- }
- else
- {
- ret = -EBUSY;
-
- } /* endif */
- }
- else
- {
- ret = -EBUSY;
-
- } /* endif */
-
- return( ret );
-
-}
-
-/*
- * resume suspended I/O operation
- */
-int resume_IO( int irq)
-{
- int ret = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * We allow for 'resume' requests only for active I/O operations
- */
- if ( ioinfo[irq]->ui.flags.busy )
- {
- int ccode;
-
- ccode = rsch( irq);
-
- switch (ccode) {
- case 0 :
- break;
-
- case 1 :
- s390_process_IRQ( irq );
- ret = -EBUSY;
- break;
-
- case 2 :
- ret = -EINVAL;
- break;
-
- case 3 :
- /*
- * useless to wait for request completion
- * as device is no longer operational !
- */
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ret = -ENODEV;
- break;
-
- } /* endswitch */
-
- }
- else
- {
- ret = -ENOTCONN;
-
- } /* endif */
-
- return( ret);
-}
-
-/*
- * Note: The "intparm" parameter is not used by the halt_IO() function
- * itself, as no ORB is built for the HSCH instruction. However,
- * it allows the device interrupt handler to associate the upcoming
- * interrupt with the halt_IO() request.
- */
-int halt_IO( int irq,
- unsigned long user_intparm,
- unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
- int ret;
- int ccode;
- unsigned long psw_flags;
-
- int sync_isc_locked = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- ret = -ENODEV;
- }
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * we only allow for halt_IO if the device has an I/O handler associated
- */
- else if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = -ENODEV;
- }
- /*
- * we ignore the halt_io() request if ending_status was received but
- * a SENSE operation is waiting for completion.
- */
- else if ( ioinfo[irq]->ui.flags.w4sense )
- {
- ret = 0;
- }
- /*
- * We don't allow for halt_io with a sync do_IO() requests pending.
- */
- else if ( ioinfo[irq]->ui.flags.syncio )
- {
- ret = -EBUSY;
- }
- else
- {
- /*
- * If sync processing was requested we lock the sync ISC,
- * modify the device to present interrupts for this ISC only
- * and switch the CPU to handle this ISC + the console ISC
- * exclusively.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- //
- // check whether we run recursively (sense processing)
- //
- if ( !ioinfo[irq]->ui.flags.syncio )
- {
- spin_lock_irqsave( &sync_isc, psw_flags);
-
- ret = enable_cpu_sync_isc( irq);
-
- if ( ret )
- {
- spin_unlock_irqrestore( &sync_isc,
- psw_flags);
- return( ret);
- }
- else
- {
- sync_isc_locked = 1; // local
- ioinfo[irq]->ui.flags.syncio = 1; // global
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * Issue "Halt subchannel" and process condition code
- */
- ccode = hsch( irq );
-
- switch ( ccode ) {
- case 0:
-
- ioinfo[irq]->ui.flags.haltio = 1;
-
- if ( !ioinfo[irq]->ui.flags.doio )
- {
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->u_intparm = user_intparm;
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.lpum = 0;
- ioinfo[irq]->devstat.flag = DEVSTAT_HALT_FUNCTION;
- ioinfo[irq]->devstat.scnt = 0;
-
- }
- else
- {
- ioinfo[irq]->devstat.flag |= DEVSTAT_HALT_FUNCTION;
-
- } /* endif */
-
- /*
- * If synchronous I/O processing is requested, we have
- * to wait for the corresponding interrupt to occur by
- * polling the interrupt condition. However, as multiple
- * interrupts may be outstanding, we must not just wait
- * for the first interrupt, but must poll until ours
- * pops up.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- int io_sub;
- __u32 io_parm;
- psw_t io_new_psw;
- int ccode;
-
- int ready = 0;
- struct _lowcore *lc = NULL;
-
- /*
- * We shouldn't perform a TPI loop, waiting for
- * an interrupt to occur, but should load a
- * WAIT PSW instead. Otherwise we may keep the
- * channel subsystem busy, not able to present
- * the interrupt. When our sync. interrupt
- * arrived we reset the I/O old PSW to its
- * original value.
- */
- memcpy( &io_new_psw,
- &lc->io_new_psw,
- sizeof(psw_t));
-
- ccode = iac();
-
- switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "halt_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
- } /* endswitch */
-
- io_sync_wait.addr = FIX_PSW(&&hio_wakeup);
-
- /*
- * Martin didn't like modifying the new PSW, now we take
- * a fast exit in do_IRQ() instead
- */
- *(__u32 *)__LC_SYNC_IO_WORD = 1;
-
- do
- {
-
- asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
-hio_wakeup:
- io_parm = *(__u32 *)__LC_IO_INT_PARM;
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
- ready = s390_process_IRQ( io_sub );
-
- } while ( !((io_sub == irq) && (ready == 1)) );
-
- *(__u32 *)__LC_SYNC_IO_WORD = 0;
-
- } /* endif */
-
- ret = 0;
- break;
-
- case 1 : /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- /*
- * initialize the device driver specific devstat irb area
- */
- memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
-
- /*
- * Let the common interrupt handler process the pending
- * status. However, we must avoid calling the user
- * action handler, as it won't be prepared to handle
- * a pending status during do_IO() processing inline.
- * This also implies that s390_process_IRQ must
- * terminate synchronously - especially if device
- * sensing is required.
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * In multipath mode a condition code 3 implies the last
- * path has gone, except we have previously restricted
- * the I/O to a particular path. A condition code 1
- * (0 won't occur) results in return code EIO as well
- * as 3 with another path than the one used (i.e. path available mask is non-zero).
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
- {
- ret = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
- ret = -EIO;
- ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 1;
-
- } /* endif */
-
- break;
-
- case 2 : /* busy */
-
- ret = -EBUSY;
- break;
-
- default: /* device not operational */
-
- ret = -ENODEV;
- break;
-
- } /* endswitch */
-
- if ( ( flag & DOIO_WAIT_FOR_INTERRUPT )
- && ( sync_isc_locked ) )
- {
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
-
- disable_cpu_sync_isc( irq );
-
- spin_unlock_irqrestore( &sync_isc, psw_flags);
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-/*
- * Note: The "intparm" parameter is not used by the clear_IO() function
- * itself, as no ORB is built for the CSCH instruction. However,
- * it allows the device interrupt handler to associate the upcoming
- * interrupt with the clear_IO() request.
- */
-int clear_IO( int irq,
- unsigned long user_intparm,
- unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
- int ret;
- int ccode;
- unsigned long psw_flags;
-
- int sync_isc_locked = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- ret = -ENODEV;
- }
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * we only allow for halt_IO if the device has an I/O handler associated
- */
- else if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = -ENODEV;
- }
- /*
- * we ignore the halt_io() request if ending_status was received but
- * a SENSE operation is waiting for completion.
- */
- else if ( ioinfo[irq]->ui.flags.w4sense )
- {
- ret = 0;
- }
- /*
- * We don't allow for halt_io with a sync do_IO() requests pending.
- * Concurrent I/O is possible in SMP environments only, but the
- * sync. I/O request can be gated to one CPU at a time only.
- */
- else if ( ioinfo[irq]->ui.flags.syncio )
- {
- ret = -EBUSY;
- }
- else
- {
- /*
- * If sync processing was requested we lock the sync ISC,
- * modify the device to present interrupts for this ISC only
- * and switch the CPU to handle this ISC + the console ISC
- * exclusively.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- //
- // check whether we run recursively (sense processing)
- //
- if ( !ioinfo[irq]->ui.flags.syncio )
- {
- spin_lock_irqsave( &sync_isc, psw_flags);
-
- ret = enable_cpu_sync_isc( irq);
-
- if ( ret )
- {
- spin_unlock_irqrestore( &sync_isc,
- psw_flags);
- return( ret);
- }
- else
- {
- sync_isc_locked = 1; // local
- ioinfo[irq]->ui.flags.syncio = 1; // global
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * Issue "Halt subchannel" and process condition code
- */
- ccode = csch( irq );
-
- switch ( ccode ) {
- case 0:
-
- ioinfo[irq]->ui.flags.haltio = 1;
-
- if ( !ioinfo[irq]->ui.flags.doio )
- {
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->u_intparm = user_intparm;
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.lpum = 0;
- ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION;
- ioinfo[irq]->devstat.scnt = 0;
-
- }
- else
- {
- ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION;
-
- } /* endif */
-
- /*
- * If synchronous I/O processing is requested, we have
- * to wait for the corresponding interrupt to occur by
- * polling the interrupt condition. However, as multiple
- * interrupts may be outstanding, we must not just wait
- * for the first interrupt, but must poll until ours
- * pops up.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- int io_sub;
- __u32 io_parm;
- psw_t io_new_psw;
- int ccode;
-
- int ready = 0;
- struct _lowcore *lc = NULL;
-
- /*
- * We shouldn't perform a TPI loop, waiting for
- * an interrupt to occur, but should load a
- * WAIT PSW instead. Otherwise we may keep the
- * channel subsystem busy, not able to present
- * the interrupt. When our sync. interrupt
- * arrived we reset the I/O old PSW to its
- * original value.
- */
- memcpy( &io_new_psw,
- &lc->io_new_psw,
- sizeof(psw_t));
-
- ccode = iac();
-
- switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "halt_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
- } /* endswitch */
-
- io_sync_wait.addr = FIX_PSW(&&cio_wakeup);
-
- /*
- * Martin didn't like modifying the new PSW, now we take
- * a fast exit in do_IRQ() instead
- */
- *(__u32 *)__LC_SYNC_IO_WORD = 1;
-
- do
- {
-
- asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
-cio_wakeup:
- io_parm = *(__u32 *)__LC_IO_INT_PARM;
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
- ready = s390_process_IRQ( io_sub );
-
- } while ( !((io_sub == irq) && (ready == 1)) );
-
- *(__u32 *)__LC_SYNC_IO_WORD = 0;
-
- } /* endif */
-
- ret = 0;
- break;
-
- case 1 : /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- /*
- * initialize the device driver specific devstat irb area
- */
- memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
-
- /*
- * Let the common interrupt handler process the pending
- * status. However, we must avoid calling the user
- * action handler, as it won't be prepared to handle
- * a pending status during do_IO() processing inline.
- * This also implies that s390_process_IRQ must
- * terminate synchronously - especially if device
- * sensing is required.
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * In multipath mode a condition code 3 implies the last
- * path has gone, except we have previously restricted
- * the I/O to a particular path. A condition code 1
- * (0 won't occur) results in return code EIO as well
- * as 3 with another path than the one used (i.e. path available mask is non-zero).
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
- {
- ret = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
- ret = -EIO;
- ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 1;
-
- } /* endif */
-
- break;
-
- case 2 : /* busy */
-
- ret = -EBUSY;
- break;
-
- default: /* device not operational */
-
- ret = -ENODEV;
- break;
-
- } /* endswitch */
-
- if ( ( flag & DOIO_WAIT_FOR_INTERRUPT )
- && ( sync_isc_locked ) )
- {
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
-
- disable_cpu_sync_isc( irq );
-
- spin_unlock_irqrestore( &sync_isc, psw_flags);
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-
-/*
- * do_IRQ() handles all normal I/O device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- *
- * Returns: 0 - no ending status received, no further action taken
- * 1 - interrupt handler was called with ending status
- */
-asmlinkage void do_IRQ( struct pt_regs regs,
- unsigned int irq,
- __u32 s390_intparm )
-{
-#ifdef CONFIG_FAST_IRQ
- int ccode;
- tpi_info_t tpi_info;
- int new_irq;
-#endif
- int use_irq = irq;
-// __u32 use_intparm = s390_intparm;
-
- //
- // fix me !!!
- //
- // We need to schedule device recognition, the interrupt stays
- // pending. We need to dynamically allocate an ioinfo structure.
- //
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return; /* this keeps the device boxed ... */
- }
-
- /*
- * take fast exit if CPU is in sync. I/O state
- *
- * Note: we have to turn off the WAIT bit and re-disable
- * interrupts prior to return as this was the initial
- * entry condition to synchronous I/O.
- */
- if ( *(__u32 *)__LC_SYNC_IO_WORD )
- {
- regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
-
- return;
-
- } /* endif */
-
- s390irq_spin_lock(use_irq);
-
-#ifdef CONFIG_FAST_IRQ
- do {
-#endif /* CONFIG_FAST_IRQ */
-
- s390_process_IRQ( use_irq );
-
-#ifdef CONFIG_FAST_IRQ
-
- /*
- * more interrupts pending ?
- */
- ccode = tpi( &tpi_info );
-
- if ( ! ccode )
- break; // no, leave ...
-
- new_irq = tpi_info.irq;
-// use_intparm = tpi_info.intparm;
-
- /*
- * if the interrupt is for a different irq we
- * release the current irq lock and obtain
- * a new one ...
- */
- if ( new_irq != use_irq )
- {
- s390irq_spin_unlock(use_irq);
- use_irq = new_irq;
- s390irq_spin_lock(use_irq);
-
- } /* endif */
-
- } while ( 1 );
-
-#endif /* CONFIG_FAST_IRQ */
-
- s390irq_spin_unlock(use_irq);
-
- return;
-}
-
-/*
- * s390_process_IRQ() handles status pending situations and interrupts
- *
- * Called by : do_IRQ() - for "real" interrupts
- * s390_start_IO, halt_IO()
- * - status pending cond. after SSCH, or HSCH
- * disable_subchannel() - status pending conditions (after MSCH)
- *
- * Returns: 0 - no ending status received, no further action taken
- * 1 - interrupt handler was called with ending status
- */
-int s390_process_IRQ( unsigned int irq )
-{
- int ccode; /* condition code from tsch() operation */
- int irb_cc; /* condition code from irb */
- int sdevstat; /* effective struct devstat size to copy */
- unsigned int fctl; /* function control */
- unsigned int stctl; /* status control */
- unsigned int actl; /* activity control */
- struct irqaction *action;
- struct pt_regs regs; /* for interface compatibility only */
-
- int issense = 0;
- int ending_status = 0;
- int allow4handler = 1;
- int chnchk = 0;
-#if 0
- int cpu = smp_processor_id();
-
- kstat.irqs[cpu][irq]++;
-#endif
- action = ioinfo[irq]->irq_desc.action;
-
- /*
- * It might be possible that a device was not-oper. at the time
- * of free_irq() processing. This means the handler is no longer
- * available when the device possibly becomes ready again. In
- * this case we perform delayed disable_subchannel() processing.
- */
- if ( action == NULL )
- {
- if ( !ioinfo[irq]->ui.flags.d_disable )
- {
- printk( KERN_CRIT"s390_process_IRQ(%04X) "
- "- no interrupt handler registered"
- "for device %04X !\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- } /* endif */
-
- } /* endif */
-
- /*
- * retrieve the i/o interrupt information (irb),
- * update the device specific status information
- * and possibly call the interrupt handler.
- *
- * Note 1: At this time we don't process the resulting
- * condition code (ccode) from tsch(), although
- * we probably should.
- *
- * Note 2: Here we will have to check for channel
- * check conditions and call a channel check
- * handler.
- *
- * Note 3: If a start function was issued, the interruption
- * parameter relates to it. If a halt function was
- * issued for an idle device, the intparm must not
- * be taken from lowcore, but from the devstat area.
- */
- ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
-
- //
- // We must only accumulate the status if initiated by do_IO() or halt_IO()
- //
- if ( ioinfo[irq]->ui.flags.busy )
- {
- ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat;
- ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat;
- }
- else
- {
- ioinfo[irq]->devstat.dstat = ioinfo[irq]->devstat.ii.irb.scsw.dstat;
- ioinfo[irq]->devstat.cstat = ioinfo[irq]->devstat.ii.irb.scsw.cstat;
-
- ioinfo[irq]->devstat.flag = 0; // reset status flags
-
- } /* endif */
-
- ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum;
-
- if ( ioinfo[irq]->ui.flags.busy)
- {
- ioinfo[irq]->devstat.intparm = ioinfo[irq]->u_intparm;
-
- } /* endif */
-
- /*
- * reset device-busy bit if no longer set in irb
- */
- if ( (ioinfo[irq]->devstat.dstat & DEV_STAT_BUSY )
- && ((ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))
- {
- ioinfo[irq]->devstat.dstat &= ~DEV_STAT_BUSY;
-
- } /* endif */
-
- /*
- * Save residual count and CCW information in case primary and
- * secondary status are presented with different interrupts.
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl & SCSW_STCTL_PRIM_STATUS )
- {
- ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count;
-
-#if CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "residual count from irb after tsch() %d\n",
- irq, ioinfo[irq]->devstat.rescnt );
-#endif
- } /* endif */
-
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cpa != 0 )
- {
- ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa;
-
- } /* endif */
-
- irb_cc = ioinfo[irq]->devstat.ii.irb.scsw.cc;
-
- //
- // check for any kind of channel or interface control check but don't
- // issue the message for the console device
- //
- if ( (ioinfo[irq]->devstat.ii.irb.scsw.cstat
- & ( SCHN_STAT_CHN_DATA_CHK
- | SCHN_STAT_CHN_CTRL_CHK
- | SCHN_STAT_INTF_CTRL_CHK ) )
- && (irq != cons_dev ) )
- {
- printk( "Channel-Check or Interface-Control-Check "
- "received\n"
- " ... device %04X on subchannel %04X, dev_stat "
- ": %02X sch_stat : %02X\n",
- ioinfo[irq]->devstat.devno,
- irq,
- ioinfo[irq]->devstat.dstat,
- ioinfo[irq]->devstat.cstat);
-
- chnchk = 1;
-
- } /* endif */
-
- issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons;
-
- if ( issense )
- {
- ioinfo[irq]->devstat.scnt =
- ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt;
- ioinfo[irq]->devstat.flag |=
- DEVSTAT_FLAG_SENSE_AVAIL;
-
- sdevstat = sizeof( devstat_t);
-
-#if CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "concurrent sense bytes avail %d\n",
- irq, ioinfo[irq]->devstat.scnt );
-#endif
- }
- else
- {
- /* don't copy the sense data area ! */
- sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;
-
- } /* endif */
-
- switch ( irb_cc ) {
- case 1: /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- case 0: /* normal i/o interruption */
-
- fctl = ioinfo[irq]->devstat.ii.irb.scsw.fctl;
- stctl = ioinfo[irq]->devstat.ii.irb.scsw.stctl;
- actl = ioinfo[irq]->devstat.ii.irb.scsw.actl;
-
- if ( chnchk && (ioinfo[irq]->senseid.cu_type == 0x3088))
- {
- char buffer[80];
-
- sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
- "device %04X after channel check\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->devstat.ii.irb) ,
- sizeof(irb_t));
- } /* endif */
-
- ioinfo[irq]->stctl |= stctl;
-
- ending_status = ( stctl & SCSW_STCTL_SEC_STATUS )
- || ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND) )
- || ( (fctl == SCSW_FCTL_HALT_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) );
-
- /*
- * Check for unsolicited interrupts - for debug purposes only
- *
- * We only consider an interrupt as unsolicited, if the device was not
- * actively in use (busy) and an interrupt other than an ALERT status
- * was received.
- *
- * Note: We must not issue a message to the console, if the
- * unsolicited interrupt applies to the console device
- * itself !
- */
-#if CONFIG_DEBUG_IO
- if ( ( irq != cons_dev )
- && !( stctl & SCSW_STCTL_ALERT_STATUS )
- && ( ioinfo[irq]->ui.flags.busy == 0 ) )
- {
- char buffer[80];
-
- printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
- " ... device status : %02X subchannel status : %02X\n",
- ioinfo[irq]->devstat.devno,
- irq,
- ioinfo[irq]->devstat.dstat,
- ioinfo[irq]->devstat.cstat);
-
- sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
- "device %04X, ending_status %d\n",
- irq,
- ioinfo[irq]->devstat.devno,
- ending_status);
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->devstat.ii.irb) ,
- sizeof(irb_t));
-
- } /* endif */
-
- /*
- * take fast exit if no handler is available
- */
- if ( !action )
- return( ending_status );
-
-#endif
- /*
- * Check whether we must issue a SENSE CCW ourselves if there is no
- * concurrent sense facility installed for the subchannel.
- *
- * Note: We should check for ioinfo[irq]->ui.flags.consns but VM
- * violates the ESA/390 architecture and doesn't present an
- * operand exception for virtual devices without concurrent
- * sense facility available/supported when enabling the
- * concurrent sense facility.
- */
- if ( ( ( ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK )
- && ( !issense ) )
- || ( ioinfo[irq]->ui.flags.delsense && ending_status ) )
- {
- int ret_io;
- ccw1_t *s_ccw = &ioinfo[irq]->senseccw;
- unsigned long s_flag = 0;
-
- if ( ending_status )
- {
- /*
- * We copy the current status information into the device driver
- * status area. Then we can use the local devstat area for device
- * sensing. When finally calling the IRQ handler we must not overlay
- * the original device status but copy the sense data only.
- */
- memcpy( action->dev_id,
- &(ioinfo[irq]->devstat),
- sizeof( devstat_t) );
-
- s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
- s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->devstat.ii.sense.data);
- s_ccw->count = SENSE_MAX_COUNT;
- s_ccw->flags = CCW_FLAG_SLI;
-
- /*
- * If free_irq() or a sync do_IO/s390_start_IO() is in
- * process we have to sense synchronously
- */
- if ( ioinfo[irq]->ui.flags.unready || ioinfo[irq]->ui.flags.syncio )
- {
- s_flag = DOIO_WAIT_FOR_INTERRUPT;
-
- } /* endif */
-
- /*
- * Reset status info
- *
- * It does not matter whether this is a sync. or async.
- * SENSE request, but we have to assure we don't call
- * the irq handler now, but keep the irq in busy state.
- * In sync. mode s390_process_IRQ() is called recursively,
- * while in async. mode we re-enter do_IRQ() with the
- * next interrupt.
- *
- * Note : this may be a delayed sense request !
- */
- allow4handler = 0;
-
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
- ioinfo[irq]->ui.flags.delsense = 0;
-
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.rescnt = SENSE_MAX_COUNT;
-
- ioinfo[irq]->ui.flags.w4sense = 1;
-
- ret_io = s390_start_IO( irq,
- s_ccw,
- 0xE2C5D5E2, // = SENSe
- 0, // n/a
- s_flag);
- }
- else
- {
- /*
- * we received an Unit Check but we have no final
- * status yet, therefore we must delay the SENSE
- * processing. However, we must not report this
- * intermediate status to the device interrupt
- * handler.
- */
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
-
- ioinfo[irq]->ui.flags.delsense = 1;
- allow4handler = 0;
-
- } /* endif */
-
- } /* endif */
-
- /*
- * we allow for the device action handler if .
- * - we received ending status
- * - the action handler requested to see all interrupts
- * - we received a PCI
- * - fast notification was requested (primary status)
- * - unsollicited interrupts
- *
- */
- if ( allow4handler )
- {
- allow4handler = ending_status
- || ( ioinfo[irq]->ui.flags.repall )
- || ( ioinfo[irq]->devstat.ii.irb.scsw.cstat & SCHN_STAT_PCI )
- || ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) )
- || ( ioinfo[irq]->ui.flags.oper == 0 );
-
- } /* endif */
-
- /*
- * We used to copy the device status information right before
- * calling the device action handler. However, in status
- * pending situations during do_IO() or halt_IO(), as well as
- * enable_subchannel/disable_subchannel processing we must
- * synchronously return the status information and must not
- * call the device action handler.
- *
- */
- if ( allow4handler )
- {
- /*
- * if we were waiting for sense data we copy the sense
- * bytes only as the original status information was
- * saved prior to sense already.
- */
- if ( ioinfo[irq]->ui.flags.w4sense )
- {
- int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt;
-
-#if CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "BASIC SENSE bytes avail %d\n",
- irq, sense_count );
-#endif
- ioinfo[irq]->ui.flags.w4sense = 0;
- ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
- ((devstat_t *)(action->dev_id))->scnt = sense_count;
-
- if ( sense_count >= 0 )
- {
- memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data,
- &(ioinfo[irq]->devstat.ii.sense.data),
- sense_count);
- }
- else
- {
-#if 1
- panic( "s390_process_IRQ(%04x) encountered "
- "negative sense count\n",
- irq);
-#else
- printk( KERN_CRIT"s390_process_IRQ(%04x) encountered "
- "negative sense count\n",
- irq);
-#endif
- } /* endif */
- }
- else
- {
- memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat );
-
- } /* endif */
-
- } /* endif */
-
- /*
- * for status pending situations other than deferred interrupt
- * conditions detected by s390_process_IRQ() itself we must not
- * call the handler. This will synchronously be reported back
- * to the caller instead, e.g. when detected during do_IO().
- */
- if ( ioinfo[irq]->ui.flags.s_pend || ioinfo[irq]->ui.flags.unready )
- allow4handler = 0;
-
- /*
- * Call device action handler if applicable
- */
- if ( allow4handler )
- {
-
- /*
- * We only reset the busy condition when we are sure that no further
- * interrupt is pending for the current I/O request (ending_status).
- */
- if ( ending_status || !ioinfo[irq]->ui.flags.oper )
- {
- ioinfo[irq]->ui.flags.oper = 1; /* dev IS oper */
-
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.haltio = 0;
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
- ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FINAL_STATUS;
-
- action->handler( irq, action->dev_id, &regs);
-
- //
- // reset intparm after final status or we will badly present unsolicited
- // interrupts with a intparm value possibly no longer valid.
- //
- ioinfo[irq]->devstat.intparm = 0;
-
- //
- // Was there anything queued ? Start the pending channel program
- // if there is one.
- //
- if ( ioinfo[irq]->ui.flags.doio_q )
- {
- int ret;
-
- ret = s390_start_IO( irq,
- ioinfo[irq]->qcpa,
- ioinfo[irq]->qintparm,
- ioinfo[irq]->qlpm,
- ioinfo[irq]->qflag);
-
- ioinfo[irq]->ui.flags.doio_q = 0;
-
- /*
- * If s390_start_IO() failed call the device's interrupt
- * handler, the IRQ related devstat area was setup by
- * s390_start_IO() accordingly already (status pending
- * condition).
- */
- if ( ret )
- {
- action->handler( irq, action->dev_id, &regs);
-
- } /* endif */
-
- } /* endif */
-
- }
- else
- {
- ioinfo[irq]->ui.flags.w4final = 1;
- action->handler( irq, action->dev_id, &regs);
-
- } /* endif */
-
- } /* endif */
-
- break;
-
- case 3: /* device not operational */
-
- ioinfo[irq]->ui.flags.oper = 0;
-
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.haltio = 0;
-
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * When we find a device "not oper" we save the status
- * information into the device status area and call the
- * device specific interrupt handler.
- *
- * Note: currently we don't have any way to reenable
- * the device unless an unsolicited interrupt
- * is presented. We don't check for spurious
- * interrupts on "not oper" conditions.
- */
-
- if ( ( ioinfo[irq]->ui.flags.fast )
- && ( ioinfo[irq]->ui.flags.w4final ) )
- {
- /*
- * If a new request was queued already, we have
- * to simulate the "not oper" status for the
- * queued request by switching the "intparm" value
- * and notify the interrupt handler.
- */
- if ( ioinfo[irq]->ui.flags.doio_q )
- {
- ioinfo[irq]->devstat.intparm = ioinfo[irq]->qintparm;
-
- } /* endif */
-
- } /* endif */
-
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat );
-
- ioinfo[irq]->devstat.intparm = 0;
-
- if ( !ioinfo[irq]->ui.flags.s_pend )
- action->handler( irq, action->dev_id, &regs);
-
- ending_status = 1;
-
- break;
-
- } /* endswitch */
-
- return( ending_status );
-}
-
-/*
- * Set the special i/o-interruption sublass 7 for the
- * device specified by parameter irq. There can only
- * be a single device been operated on this special
- * isc. This function is aimed being able to check
- * on special device interrupts in disabled state,
- * without having to delay I/O processing (by queueing)
- * for non-console devices.
- *
- * Setting of this isc is done by set_cons_dev(), while
- * reset_cons_dev() resets this isc and re-enables the
- * default isc3 for this device. wait_cons_dev() allows
- * to actively wait on an interrupt for this device in
- * disabed state. When the interrupt condition is
- * encountered, wait_cons_dev(9 calls do_IRQ() to have
- * the console device driver processing the interrupt.
- */
-int set_cons_dev( int irq )
-{
- int ccode;
- unsigned long cr6 __attribute__ ((aligned (8)));
- int rc = 0;
-
- if ( cons_dev != -1 )
- {
- rc = -EBUSY;
- }
- else if ( (irq > highest_subchannel) || (irq < 0) )
- {
- rc = -ENODEV;
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else
- {
- /*
- * modify the indicated console device to operate
- * on special console interrupt sublass 7
- */
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- }
- else
- {
- ioinfo[irq]->schib.pmcw.isc = 7;
-
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -EIO;
- }
- else
- {
- cons_dev = irq;
-
- /*
- * enable console I/O-interrupt sublass 7
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 |= 0x01000000;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- return( rc);
-}
-
-int reset_cons_dev( int irq)
-{
- int rc = 0;
- int ccode;
- long cr6 __attribute__ ((aligned (8)));
-
- if ( cons_dev != -1 )
- {
- rc = -EBUSY;
- }
- else if ( (irq > highest_subchannel) || (irq < 0) )
- {
- rc = -ENODEV;
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else
- {
- /*
- * reset the indicated console device to operate
- * on default console interrupt sublass 3
- */
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- }
- else
- {
-
- ioinfo[irq]->schib.pmcw.isc = 3;
-
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -EIO;
- }
- else
- {
- cons_dev = -1;
-
- /*
- * disable special console I/O-interrupt sublass 7
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 &= 0xFEFFFFFF;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- return( rc);
-}
-
-int wait_cons_dev( int irq )
-{
- int rc = 0;
- long save_cr6;
-
- if ( irq == cons_dev )
- {
-
- /*
- * before entering the spinlock we may already have
- * processed the interrupt on a different CPU ...
- */
- if ( ioinfo[irq]->ui.flags.busy == 1 )
- {
- long cr6 __attribute__ ((aligned (8)));
-
- /*
- * disable all, but isc 7 (console device)
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- save_cr6 = cr6;
- cr6 &= 0x01FFFFFF;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- do {
- tpi_info_t tpi_info;
- if (tpi(&tpi_info) == 1) {
- s390_process_IRQ( tpi_info.irq );
- } else {
- s390irq_spin_unlock(irq);
- tod_wait(100);
- s390irq_spin_lock(irq);
- }
- eieio();
- } while (ioinfo[irq]->ui.flags.busy == 1);
-
- /*
- * restore previous isc value
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 = save_cr6;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- } /* endif */
-
- }
- else
- {
- rc = EINVAL;
-
- } /* endif */
-
-
- return(rc);
-}
-
-
-int enable_cpu_sync_isc( int irq )
-{
- int ccode;
- long cr6 __attribute__ ((aligned (8)));
-
- int count = 0;
- int rc = 0;
-
- if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- if ( !ccode )
- {
- ioinfo[irq]->schib.pmcw.isc = 5;
-
- do
- {
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode == 0 )
- {
- /*
- * enable interrupt subclass in CPU
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 |= 0x04000000; // enable sync isc 5
- cr6 &= 0xEFFFFFFF; // disable standard isc 3
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
- }
- else if (ccode == 3)
- {
- rc = -ENODEV; // device not-oper - very unlikely
-
- }
- else if (ccode == 2)
- {
- rc = -EBUSY; // device busy - should not happen
-
- }
- else if (ccode == 1)
- {
- //
- // process pending status
- //
- ioinfo[irq]->ui.flags.s_pend = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
-
- count++;
-
- } /* endif */
-
- } while ( ccode == 1 && count < 3 );
-
- if ( count == 3)
- {
- rc = -EIO;
-
- } /* endif */
- }
- else
- {
- rc = -ENODEV; // device is not-operational
-
- } /* endif */
- }
- else
- {
- rc = -EINVAL;
-
- } /* endif */
-
- return( rc);
-}
-
-int disable_cpu_sync_isc( int irq)
-{
- int rc = 0;
- int ccode;
- long cr6 __attribute__ ((aligned (8)));
-
- if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- ioinfo[irq]->schib.pmcw.isc = 3;
-
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -EIO;
- }
- else
- {
-
- /*
- * enable interrupt subclass in CPU
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 &= 0xFBFFFFFF; // disable sync isc 5
- cr6 |= 0x10000000; // enable standard isc 3
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- } /* endif */
-
- }
- else
- {
- rc = -EINVAL;
-
- } /* endif */
-
- return( rc);
-}
-
-//
-// Input :
-// devno - device number
-// ps - pointer to sense ID data area
-//
-// Output : none
-//
-void VM_virtual_device_info( __u16 devno,
- senseid_t *ps )
-{
- diag210_t diag_data;
- int ccode;
-
- int error = 0;
-
- diag_data.vrdcdvno = devno;
- diag_data.vrdclen = sizeof( diag210_t);
- ccode = diag210( (diag210_t *)virt_to_phys( &diag_data ) );
- ps->reserved = 0xff;
-
- switch (diag_data.vrdcvcla) {
- case 0x80:
-
- switch (diag_data.vrdcvtyp) {
- case 00:
-
- ps->cu_type = 0x3215;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x40:
-
- switch (diag_data.vrdcvtyp) {
- case 0xC0:
-
- ps->cu_type = 0x5080;
-
- break;
-
- case 0x80:
-
- ps->cu_type = 0x2250;
-
- break;
-
- case 0x04:
-
- ps->cu_type = 0x3277;
-
- break;
-
- case 0x01:
-
- ps->cu_type = 0x3278;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x20:
-
- switch (diag_data.vrdcvtyp) {
- case 0x84:
-
- ps->cu_type = 0x3505;
-
- break;
-
- case 0x82:
-
- ps->cu_type = 0x2540;
-
- break;
-
- case 0x81:
-
- ps->cu_type = 0x2501;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x10:
-
- switch (diag_data.vrdcvtyp) {
- case 0x84:
-
- ps->cu_type = 0x3525;
-
- break;
-
- case 0x82:
-
- ps->cu_type = 0x2540;
-
- break;
-
- case 0x4F:
- case 0x4E:
- case 0x48:
-
- ps->cu_type = 0x3820;
-
- break;
-
- case 0x4D:
- case 0x49:
- case 0x45:
-
- ps->cu_type = 0x3800;
-
- break;
-
- case 0x4B:
-
- ps->cu_type = 0x4248;
-
- break;
-
- case 0x4A:
-
- ps->cu_type = 0x4245;
-
- break;
-
- case 0x47:
-
- ps->cu_type = 0x3262;
-
- break;
-
- case 0x43:
-
- ps->cu_type = 0x3203;
-
- break;
-
- case 0x42:
-
- ps->cu_type = 0x3211;
-
- break;
-
- case 0x41:
-
- ps->cu_type = 0x1403;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x08:
-
- switch (diag_data.vrdcvtyp) {
- case 0x82:
-
- ps->cu_type = 0x3422;
-
- break;
-
- case 0x81:
-
- ps->cu_type = 0x3490;
-
- break;
-
- case 0x10:
-
- ps->cu_type = 0x3420;
-
- break;
-
- case 0x02:
-
- ps->cu_type = 0x3430;
-
- break;
-
- case 0x01:
-
- ps->cu_type = 0x3480;
-
- break;
-
- case 0x42:
-
- ps->cu_type = 0x3424;
-
- break;
-
- case 0x44:
-
- ps->cu_type = 0x9348;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- if ( error )
- {printk( "DIAG X'210' for device %04X returned (cc = %d): vdev class : %02X, "
- "vdev type : %04X \n ... rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
- devno,
- ccode,
- diag_data.vrdcvcla,
- diag_data.vrdcvtyp,
- diag_data.vrdcrccl,
- diag_data.vrdccrty,
- diag_data.vrdccrmd );
-
- } /* endif */
-
-}
-
-/*
- * This routine returns the characteristics for the device
- * specified. Some old devices might not provide the necessary
- * command code information during SenseID processing. In this
- * case the function returns -EINVAL. Otherwise the function
- * allocates a decice specific data buffer and provides the
- * device characteristics together with the buffer size. Its
- * the callers responability to release the kernel memory if
- * not longer needed. In case of persistent I/O problems -EBUSY
- * is returned.
- *
- * The function may be called enabled or disabled. However, the
- * caller must have locked the irq it is requesting data for.
- *
- * Note : It would have been nice to collect this information
- * during init_IRQ() processing but this is not possible
- *
- * a) without statically pre-allocation fixed size buffers
- * as virtual memory management isn't available yet.
- *
- * b) without unnecessarily increase system startup by
- * evaluating devices eventually not used at all.
- */
-int read_dev_chars( int irq, void **buffer, int length )
-{
- unsigned int flags;
- ccw1_t *rdc_ccw;
- devstat_t devstat;
- char *rdc_buf;
- int devflag;
-
- int ret = 0;
- int emulated = 0;
- int retry = 5;
-
- if ( !buffer || !length )
- {
- return( -EINVAL );
-
- } /* endif */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- /*
- * Before playing around with irq locks we should assure
- * running disabled on (just) our CPU. Sync. I/O requests
- * also require to run disabled.
- *
- * Note : as no global lock is required, we must not use
- * cli(), but __cli() instead.
- */
- __save_flags(flags);
- __cli();
-
- rdc_ccw = &ioinfo[irq]->senseccw;
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = request_irq( irq,
- init_IRQ_handler,
- 0, "RDC", &devstat );
-
- if ( !ret )
- {
- emulated = 1;
-
- } /* endif */
-
- } /* endif */
-
- if ( !ret )
- {
- if ( ! *buffer )
- {
- rdc_buf = kmalloc( length, GFP_KERNEL);
- }
- else
- {
- rdc_buf = *buffer;
-
- } /* endif */
-
- if ( !rdc_buf )
- {
- ret = -ENOMEM;
- }
- else
- {
- do
- {
- rdc_ccw->cmd_code = CCW_CMD_RDC;
- rdc_ccw->cda = (__u32)virt_to_phys( rdc_buf );
- rdc_ccw->count = length;
- rdc_ccw->flags = CCW_FLAG_SLI;
-
- ret = s390_start_IO( irq,
- rdc_ccw,
- 0x00524443, // RDC
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT );
- retry--;
- devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag;
-
- } while ( ( retry )
- && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
-
- } /* endif */
-
- if ( !retry )
- {
- ret = -EBUSY;
-
- } /* endif */
-
- __restore_flags(flags);
-
- /*
- * on success we update the user input parms
- */
- if ( !ret )
- {
- *buffer = rdc_buf;
-
- } /* endif */
-
- if ( emulated )
- {
- free_irq( irq, &devstat);
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-/*
- * Read Configuration data
- */
-int read_conf_data( int irq, void **buffer, int *length )
-{
- int found = 0;
- int ciw_cnt = 0;
- unsigned int flags;
-
- int ret = 0;
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- /*
- * scan for RCD command in extended SenseID data
- */
- for ( ; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
- {
- if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD )
- {
- found = 1;
- break;
- } /* endif */
-
- } /* endfor */
-
- if ( found )
- {
- ccw1_t *rcd_ccw = &ioinfo[irq]->senseccw;
- devstat_t devstat;
- char *rcd_buf;
- int devflag;
-
- int emulated = 0;
- int retry = 5;
-
- __save_flags(flags);
- __cli();
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = request_irq( irq,
- init_IRQ_handler,
- 0, "RCD", &devstat );
-
- if ( !ret )
- {
- emulated = 1;
-
- } /* endif */
-
- } /* endif */
-
- if ( !ret )
- {
- rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count,
- GFP_KERNEL);
-
- do
- {
- rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd;
- rcd_ccw->cda = (__u32)virt_to_phys( rcd_buf );
- rcd_ccw->count = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
- rcd_ccw->flags = CCW_FLAG_SLI;
-
- ret = s390_start_IO( irq,
- rcd_ccw,
- 0x00524344, // == RCD
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT );
-
- retry--;
-
- devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag;
-
- } while ( ( retry )
- && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
-
- if ( !retry )
- ret = -EBUSY;
-
- __restore_flags(flags);
-
- } /* endif */
-
- /*
- * on success we update the user input parms
- */
- if ( !ret )
- {
- *length = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
- *buffer = rcd_buf;
-
- } /* endif */
-
- if ( emulated )
- free_irq( irq, &devstat);
- }
- else
- {
- ret = -EINVAL;
-
- } /* endif */
-
- return( ret );
-
-}
-
-int get_dev_info( int irq, dev_info_t * pdi)
-{
- return( get_dev_info_by_irq( irq, pdi));
-}
-
-static int __inline__ get_next_available_irq( ioinfo_t *pi)
-{
- int ret_val;
-
- while ( TRUE )
- {
- if ( pi->ui.flags.oper )
- {
- ret_val = pi->irq;
- break;
- }
- else
- {
- pi = pi->next;
-
- //
- // leave at end of list unconditionally
- //
- if ( pi == NULL )
- {
- ret_val = -ENODEV;
- break;
- }
-
- } /* endif */
-
- } /* endwhile */
-
- return ret_val;
-}
-
-
-int get_irq_first( void )
-{
- int ret_irq;
-
- if ( ioinfo_head )
- {
- if ( ioinfo_head->ui.flags.oper )
- {
- ret_irq = ioinfo_head->irq;
- }
- else if ( ioinfo_head->next )
- {
- ret_irq = get_next_available_irq( ioinfo_head->next );
-
- }
- else
- {
- ret_irq = -ENODEV;
-
- } /* endif */
- }
- else
- {
- ret_irq = -ENODEV;
-
- } /* endif */
-
- return ret_irq;
-}
-
-int get_irq_next( int irq )
-{
- int ret_irq;
-
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- if ( ioinfo[irq]->next )
- {
- if ( ioinfo[irq]->next->ui.flags.oper )
- {
- ret_irq = ioinfo[irq]->next->irq;
- }
- else
- {
- ret_irq = get_next_available_irq( ioinfo[irq]->next );
-
- } /* endif */
- }
- else
- {
- ret_irq = -ENODEV;
-
- } /* endif */
- }
- else
- {
- ret_irq = -EINVAL;
-
- } /* endif */
-
- return ret_irq;
-}
-
-int get_dev_info_by_irq( int irq, dev_info_t *pdi)
-{
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return -ENODEV;
- }
- else if ( pdi == NULL )
- {
- return -EINVAL;
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else
- {
- pdi->devno = ioinfo[irq]->schib.pmcw.dev;
- pdi->irq = irq;
-
- if ( ioinfo[irq]->ui.flags.oper )
- {
- pdi->status = 0;
- memcpy( &(pdi->sid_data),
- &ioinfo[irq]->senseid,
- sizeof( senseid_t));
- }
- else
- {
- pdi->status = DEVSTAT_NOT_OPER;
- memcpy( &(pdi->sid_data),
- '\0',
- sizeof( senseid_t));
- pdi->sid_data.cu_type = 0xFFFF;
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.ready )
- pdi->status |= DEVSTAT_DEVICE_OWNED;
-
- return 0;
-
- } /* endif */
-
-}
-
-
-int get_dev_info_by_devno( __u16 devno, dev_info_t *pdi)
-{
- int i;
- int rc = -ENODEV;
-
- if ( devno > 0x0000ffff )
- {
- return -ENODEV;
- }
- else if ( pdi == NULL )
- {
- return -EINVAL;
- }
- else
- {
-
- for ( i=0; i <= highest_subchannel; i++ )
- {
-
- if ( ioinfo[i] != INVALID_STORAGE_AREA
- && ioinfo[i]->schib.pmcw.dev == devno )
- {
- if ( ioinfo[i]->ui.flags.oper )
- {
- pdi->status = 0;
- pdi->irq = i;
- pdi->devno = devno;
-
- memcpy( &(pdi->sid_data),
- &ioinfo[i]->senseid,
- sizeof( senseid_t));
- }
- else
- {
- pdi->status = DEVSTAT_NOT_OPER;
- pdi->irq = i;
- pdi->devno = devno;
-
- memcpy( &(pdi->sid_data), '\0', sizeof( senseid_t));
- pdi->sid_data.cu_type = 0xFFFF;
-
- } /* endif */
-
- if ( ioinfo[i]->ui.flags.ready )
- pdi->status |= DEVSTAT_DEVICE_OWNED;
-
- rc = 0; /* found */
- break;
-
- } /* endif */
-
- } /* endfor */
-
- return( rc);
-
- } /* endif */
-
-}
-
-int get_irq_by_devno( __u16 devno )
-{
- int i;
- int rc = -1;
-
- if ( devno <= 0x0000ffff )
- {
- for ( i=0; i <= highest_subchannel; i++ )
- {
- if ( (ioinfo[i] != INVALID_STORAGE_AREA )
- && (ioinfo[i]->schib.pmcw.dev == devno)
- && (ioinfo[i]->schib.pmcw.dnv == 1 ) )
- {
- rc = i;
- break;
-
- } /* endif */
-
- } /* endfor */
-
- } /* endif */
-
- return( rc);
-}
-
-unsigned int get_devno_by_irq( int irq )
-{
-
- if ( ( irq > highest_subchannel )
- || ( irq < 0 )
- || ( ioinfo[irq] == INVALID_STORAGE_AREA ) )
- {
- return -1;
-
- } /* endif */
-
- /*
- * we don't need to check for the device be operational
- * as the initial STSCH will always present the device
- * number defined by the IOCDS regardless of the device
- * existing or not. However, there could be subchannels
- * defined who's device number isn't valid ...
- */
- if ( ioinfo[irq]->schib.pmcw.dnv )
- return( ioinfo[irq]->schib.pmcw.dev );
- else
- return -1;
-}
-
-/*
- * s390_device_recognition
- *
- * Used for system wide device recognition. Issues the device
- * independant SenseID command to obtain info the device type.
- *
- */
-void s390_device_recognition( void)
-{
-
- int irq = 0; /* let's start with subchannel 0 ... */
-
- do
- {
- /*
- * We issue the SenseID command on I/O subchannels we think are
- * operational only.
- */
- if ( ( ioinfo[irq] != INVALID_STORAGE_AREA )
- && ( ioinfo[irq]->schib.pmcw.st == 0 )
- && ( ioinfo[irq]->ui.flags.oper == 1 ) )
- {
- s390_SenseID( irq, &ioinfo[irq]->senseid );
-
- } /* endif */
-
- irq ++;
-
- } while ( irq <= highest_subchannel );
-
-}
-
-
-/*
- * s390_search_devices
- *
- * Determines all subchannels available to the system.
- *
- */
-void s390_process_subchannels( void)
-{
- int isValid;
- int irq = 0; /* Evaluate all subchannels starting with 0 ... */
-
- do
- {
- isValid = s390_validate_subchannel( irq);
-
- irq++;
-
- } while ( isValid && irq < __MAX_SUBCHANNELS );
-
- highest_subchannel = --irq;
-
- printk( "\nHighest subchannel number detected: %u\n",
- highest_subchannel);
-}
-
-/*
- * s390_validate_subchannel()
- *
- * Process the subchannel for the requested irq. Returns 1 for valid
- * subchannels, otherwise 0.
- */
-int s390_validate_subchannel( int irq )
-{
-
- int retry; /* retry count for status pending conditions */
- int ccode; /* condition code for stsch() only */
- int ccode2; /* condition code for other I/O routines */
- schib_t *p_schib;
-
- /*
- * The first subchannel that is not-operational (ccode==3)
- * indicates that there aren't any more devices available.
- */
- if ( ( init_IRQ_complete )
- && ( ioinfo[irq] != INVALID_STORAGE_AREA ) )
- {
- p_schib = &ioinfo[irq]->schib;
- }
- else
- {
- p_schib = &init_schib;
-
- } /* endif */
-
- ccode = stsch( irq, p_schib);
-
- if ( ccode == 0)
- {
- /*
- * ... just being curious we check for non I/O subchannels
- */
- if ( p_schib->pmcw.st )
- {
- printk( "Subchannel %04X reports "
- "non-I/O subchannel type %04X\n",
- irq,
- p_schib->pmcw.st);
-
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- if ( p_schib->pmcw.dnv )
- {
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
-
- if ( !init_IRQ_complete )
- {
- ioinfo[irq] =
- (ioinfo_t *)alloc_bootmem( sizeof(ioinfo_t));
- }
- else
- {
- ioinfo[irq] =
- (ioinfo_t *)kmalloc( sizeof(ioinfo_t),
- GFP_KERNEL );
-
- } /* endif */
-
- memset( ioinfo[irq], '\0', sizeof( ioinfo_t));
- memcpy( &ioinfo[irq]->schib,
- &init_schib,
- sizeof( schib_t));
- ioinfo[irq]->irq_desc.status = IRQ_DISABLED;
- ioinfo[irq]->irq_desc.handler = &no_irq_type;
-
- /*
- * We have to insert the new ioinfo element
- * into the linked list, either at its head,
- * its tail or insert it.
- */
- if ( ioinfo_head == NULL ) /* first element */
- {
- ioinfo_head = ioinfo[irq];
- ioinfo_tail = ioinfo[irq];
- }
- else if ( irq < ioinfo_head->irq ) /* new head */
- {
- ioinfo[irq]->next = ioinfo_head;
- ioinfo_head->prev = ioinfo[irq];
- ioinfo_head = ioinfo[irq];
- }
- else if ( irq > ioinfo_tail->irq ) /* new tail */
- {
- ioinfo_tail->next = ioinfo[irq];
- ioinfo[irq]->prev = ioinfo_tail;
- ioinfo_tail = ioinfo[irq];
- }
- else /* insert element */
- {
- ioinfo_t *pi = ioinfo_head;
-
- do
- {
- if ( irq < pi->next->irq )
- {
- ioinfo[irq]->next = pi->next;
- ioinfo[irq]->prev = pi;
- pi->next->prev = ioinfo[irq];
- pi->next = ioinfo[irq];
- break;
-
- } /* endif */
-
- pi = pi->next;
-
- } while ( 1 );
-
- } /* endif */
-
- } /* endif */
-
- // initialize some values ...
- ioinfo[irq]->ui.flags.pgid_supp = 1;
-
- ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom;
-
- printk( "Detected device %04X on subchannel %04X"
- " - PIM = %02X, PAM = %02X, POM = %02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- ioinfo[irq]->schib.pmcw.pim,
- ioinfo[irq]->schib.pmcw.pam,
- ioinfo[irq]->schib.pmcw.pom);
-
- /*
- * We should have at least one CHPID ...
- */
- if ( ioinfo[irq]->schib.pmcw.pim
- & ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom )
- {
- ioinfo[irq]->ui.flags.oper = 0;
-
- /*
- * We now have to initially ...
- * ... set "interruption sublass"
- * ... enable "concurrent sense"
- * ... enable "multipath mode" if more than one
- * CHPID is available. This is done regardless
- * whether multiple paths are available for us.
- *
- * Note : we don't enable the device here, this is temporarily
- * done during device sensing below.
- */
- ioinfo[irq]->schib.pmcw.isc = 3; /* could be smth. else */
- ioinfo[irq]->schib.pmcw.csense = 1; /* concurrent sense */
- ioinfo[irq]->schib.pmcw.ena = 0; /* force disable it */
- ioinfo[irq]->schib.pmcw.intparm =
- ioinfo[irq]->schib.pmcw.dev;
-
- if ( ( ioinfo[irq]->schib.pmcw.pim != 0 )
- && ( ioinfo[irq]->schib.pmcw.pim != 0x80 ) )
- {
- ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
-
- } /* endif */
-
- /*
- * initialize ioinfo structure
- */
- ioinfo[irq]->irq = irq;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.ready = 0;
- ioinfo[irq]->ui.flags.oper = 1;
- ioinfo[irq]->devstat.intparm = 0;
- ioinfo[irq]->devstat.devno = ioinfo[irq]->schib.pmcw.dev;
-
- retry = 5;
-
- do
- {
- ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
- switch (ccode2) {
- case 0: // successful completion
- //
- // concurrent sense facility available ...
- //
- ioinfo[irq]->ui.flags.consns = 1;
- break;
-
- case 1: // status pending
- //
- // How can we have a pending status as device is
- // disabled for interrupts ? Anyway, clear it ...
- //
- tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
- retry--;
- break;
-
- case 2: // busy
- retry--;
- break;
-
- case 3: // not operational
- ioinfo[irq]->ui.flags.oper = 0;
- retry = 0;
- break;
-
- default:
-#define PGMCHK_OPERAND_EXC 0x15
-
- if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC )
- {
- /*
- * re-issue the modify subchannel without trying to
- * enable the concurrent sense facility
- */
- ioinfo[irq]->schib.pmcw.csense = 0;
-
- ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
- if ( ccode2 != 0 )
- {
- printk( " ... modify subchannel (2) failed with CC = %X\n",
- ccode2 );
- ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
- ioinfo[irq]->ui.flags.consns = 0;
-
- } /* endif */
- }
- else
- {
- printk( " ... modify subchannel (1) failed with CC = %X\n",
- ccode2);
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- retry = 0;
- break;
-
- } /* endswitch */
-
- } while ( ccode2 && retry );
-
- if ( (ccode2 < 3) && (!retry) )
- {
- printk( " ... msch() retry count for "
- "subchannel %04X exceeded, CC = %d\n",
- irq,
- ccode2);
-
- } /* endif */
-
- }
- else
- {
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * indicate whether the subchannel is valid
- */
- if ( ccode == 3)
- return(0);
- else
- return(1);
-}
-
-/*
- * s390_SenseID
- *
- * Try to obtain the 'control unit'/'device type' information
- * associated with the subchannel.
- *
- * The function is primarily meant to be called without irq
- * action handler in place. However, it also allows for
- * use with an action handler in place. If there is already
- * an action handler registered assure it can handle the
- * s390_SenseID() related device interrupts - interruption
- * parameter used is 0x00E2C9C4 ( SID ).
- */
-int s390_SenseID( int irq, senseid_t *sid )
-{
- ccw1_t sense_ccw; /* ccw area for SenseID command */
- devstat_t devstat; /* required by request_irq() */
-
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE ID command processing. We have to request device
- * ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
- irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat);
-
- if ( irq_ret == 0 )
- inlreq = 1;
-
- } /* endif */
-
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock( irq);
-
- sense_ccw.cmd_code = CCW_CMD_SENSE_ID;
- sense_ccw.cda = (__u32)virt_to_phys( sid );
- sense_ccw.count = sizeof( senseid_t);
- sense_ccw.flags = CCW_FLAG_SLI;
-
- ioinfo[irq]->senseid.cu_type = 0xFFFF; /* initialize fields ... */
- ioinfo[irq]->senseid.cu_model = 0;
- ioinfo[irq]->senseid.dev_type = 0;
- ioinfo[irq]->senseid.dev_model = 0;
-
- /*
- * We now issue a SenseID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( &devstat, '\0', sizeof( devstat_t) );
-
- irq_ret = s390_start_IO( irq,
- &sense_ccw,
- 0x00E2C9C4, // == SID
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_TIMEOUT );
-
- if ( irq_ret == -ETIMEDOUT )
- {
- halt_IO( irq,
- 0x80E2C9C4,
- DOIO_WAIT_FOR_INTERRUPT);
- devstat.flag |= DEVSTAT_NOT_OPER;
-
- } /* endif */
-
- if ( sid->cu_type == 0xFFFF && devstat.flag != DEVSTAT_NOT_OPER )
- {
- if ( devstat.flag & DEVSTAT_STATUS_PENDING )
- {
-#if CONFIG_DEBUG_IO
- printk( "Device %04X on Subchannel %04X "
- "reports pending status, retry : %d\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
-#endif
- } /* endif */
-
- if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * if the device doesn't support the SenseID
- * command further retries wouldn't help ...
- */
- if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- retry = 0;
- }
-#if CONFIG_DEBUG_IO
- else
- {
- printk( "Device %04X,"
- " UC/SenseID,"
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- devstat.scnt,
- devstat.ii.sense.data[0],
- devstat.ii.sense.data[1],
- devstat.ii.sense.data[2],
- devstat.ii.sense.data[3],
- devstat.ii.sense.data[4],
- devstat.ii.sense.data[5],
- devstat.ii.sense.data[6],
- devstat.ii.sense.data[7]);
-
- } /* endif */
-#endif
- }
- else if ( devstat.flag & DEVSTAT_NOT_OPER )
- {
- printk( "Device %04X on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
-
- retry = 0;
-
- } /* endif */
- }
- else // we got it or the device is not-operational ...
- {
- retry = 0;
-
- } /* endif */
-
- retry--;
-
- } while ( retry > 0 );
-
- s390irq_spin_unlock( irq);
-
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, &devstat);
-
- /*
- * if running under VM check there ... perhaps we should do
- * only if we suffered a command reject, but it doesn't harm
- */
- if ( ( sid->cu_type == 0xFFFF )
- && ( MACHINE_IS_VM ) )
- {
- VM_virtual_device_info( ioinfo[irq]->schib.pmcw.dev,
- sid );
- } /* endif */
-
- if ( sid->cu_type == 0xFFFF )
- {
- /*
- * SenseID CU-type of 0xffff indicates that no device
- * information could be retrieved (pre-init value).
- *
- * If we can't couldn't identify the device type we
- * consider the device "not operational".
- */
- printk( "Unknown device %04X on subchannel %04X\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- /*
- * Issue device info message if unit was operational .
- */
- if ( ioinfo[irq]->ui.flags.oper )
- {
- if ( sid->dev_type != 0 )
- {
- printk( "Device %04X reports: CU Type/Mod = %04X/%02X,"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model,
- sid->dev_type,
- sid->dev_model);
- }
- else
- {
- printk( "Device %04X reports:"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model);
-
- } /* endif */
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper )
- irq_ret = 0;
- else
- irq_ret = -ENODEV;
-
- } /* endif */
-
- return( irq_ret );
-}
-
-static int __inline__ s390_SetMultiPath( int irq )
-{
- int cc;
-
- cc = stsch( irq, &ioinfo[irq]->schib );
-
- if ( !cc )
- {
- ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
-
- cc = msch( irq, &ioinfo[irq]->schib );
-
- } /* endif */
-
- return( cc);
-}
-
-/*
- * Device Path Verification
- *
- * Path verification is accomplished by checking which paths (CHPIDs) are
- * available. Further, a path group ID is set, if possible in multipath
- * mode, otherwise in single path mode.
- *
- */
-int s390_DevicePathVerification( int irq )
-{
-#if 0
- int ccode;
- __u8 pathmask;
-
- int ret = 0;
-
- if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
- {
- ret = -EOPNOTSUPP;
-
- } /* endif */
-
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- if ( ccode )
- {
- ret = -ENODEV;
- }
- else
- {
- int i;
- pgid_t pgid;
-
- int first = 1;
- __u8 dev_path = ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom;
-
- /*
- * let's build a path group ID if we don't have one yet
- */
- if ( ioinfo[irq]->ui.flags.pgid == 0)
- {
- struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
-
- ioinfo->pgid.cpu_addr = lowcore->cpu_data.cpu_addr;
- ioinfo->pgid.cpu_id = lowcore->cpu_data.cpu_id.ident;
- ioinfo->pgid.cpu_model = lowcore->cpu_data.cpu_id.machine;
- ioinfo->pgid.tod_high = *(__u32 *)&irq_IPL_TOD;
-
- ioinfo[irq]->ui.flags.pgid = 1;
-
- } /* endif */
-
- memcpy( &pgid, ioinfo[irq]->pgid, sizeof(pgid_t));
-
- for ( i = 0; i < 8 && !ret ; i++)
- {
- pathmask = 0x80 >> i;
-
- if ( dev_path & pathmask )
- {
- ret = s390_SetPGID( irq, pathmask, &pgid );
-
- /*
- * For the *first* path we are prepared
- * for recovery
- *
- * - If we fail setting the PGID we assume its
- * using a different PGID already (VM) we
- * try to sense.
- */
- if ( ret == -EOPNOTSUPP && first )
- {
- *(int *)&pgid = 0;
-
- ret = s390_SensePGID( irq, pathmask, &pgid);
- first = 0;
-
- if ( !ret )
- {
- /*
- * Check whether we retrieved
- * a reasonable PGID ...
- */
- if ( !ret && (*(int *)&pgid == 0) )
- {
- ret = -EOPNOTSUPP;
- }
- else
- {
- ret = s390_SetPGID( irq, pathmask, &pgid );
-
- } /* endif */
-
- } /* endif */
-
- if ( ret )
- {
- ioinfo[irq]->ui.flags.pgid_supp = 0;
-
- printk( "PathVerification(%04X) "
- "- Device %04X doesn't "
- " support path grouping",
- irq,
- ioinfo[irq]->schib.pmcw.dev);
-
- } /* endif */
- }
- else if ( ret )
- {
- ioinfo[irq]->ui.flags.pgid_supp = 0;
-
- } /* endif */
-
- } /* endif */
-
- } /* endfor */
-
- } /* endif */
-
- return ret;
-#else
- return 0;
-#endif
-}
-
-/*
- * s390_SetPGID
- *
- * Set Path Group ID
- *
- */
-int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
-{
- ccw1_t spid_ccw; /* ccw area for SPID command */
- devstat_t devstat; /* required by request_irq() */
-
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
- int mpath = 1; /* try multi-path first */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE ID command processing. We have to request device
- * ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
- irq_ret = request_irq( irq, init_IRQ_handler, 0, "SPID", &devstat);
-
- if ( irq_ret == 0 )
- inlreq = 1;
-
- } /* endif */
-
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock( irq);
-
- spid_ccw.cmd_code = CCW_CMD_SET_PGID;
- spid_ccw.cda = (__u32)virt_to_phys( pgid );
- spid_ccw.count = sizeof( pgid_t);
- spid_ccw.flags = CCW_FLAG_SLI;
-
-
- /*
- * We now issue a SenseID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( &devstat, '\0', sizeof( devstat_t) );
-
- irq_ret = s390_start_IO( irq,
- &spid_ccw,
- 0xE2D7C9C4, // == SPID
- lpm, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_VALID_LPM );
-
- if ( !irq_ret )
- {
- if ( devstat.flag & DEVSTAT_STATUS_PENDING )
- {
-#if CONFIG_DEBUG_IO
- printk( "SPID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %d\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
-#endif
- } /* endif */
-
- if ( devstat.flag == ( DEVSTAT_START_FUNCTION
- | DEVSTAT_FINAL_STATUS ) )
- {
- retry = 0; // successfully set ...
- }
- else if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * If the device doesn't support the
- * Sense Path Group ID command
- * further retries wouldn't help ...
- */
- if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- if ( mpath )
- {
- pgid->inf.fc = SPID_FUNC_ESTABLISH;
- mpath = 0;
- retry--;
- }
- else
- {
- irq_ret = -EOPNOTSUPP;
- retry = 0;
-
- } /* endif */
- }
-#if CONFIG_DEBUG_IO
- else
- {
- printk( "SPID - device %04X,"
- " unit check,"
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- devstat.scnt,
- devstat.ii.sense.data[0],
- devstat.ii.sense.data[1],
- devstat.ii.sense.data[2],
- devstat.ii.sense.data[3],
- devstat.ii.sense.data[4],
- devstat.ii.sense.data[5],
- devstat.ii.sense.data[6],
- devstat.ii.sense.data[7]);
-
- } /* endif */
-#endif
- }
- else if ( devstat.flag & DEVSTAT_NOT_OPER )
- {
- printk( "SPID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
-
- retry = 0;
-
- } /* endif */
- }
- else if ( irq_ret != -ENODEV )
- {
- retry--;
- }
- else
- {
- retry = 0;
-
- } /* endif */
-
- } while ( retry > 0 );
-
- s390irq_spin_unlock( irq);
-
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, &devstat);
-
- } /* endif */
-
- return( irq_ret );
-}
-
-
-/*
- * s390_SensePGID
- *
- * Sense Path Group ID
- *
- */
-int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
-{
- ccw1_t snid_ccw; /* ccw area for SNID command */
- devstat_t devstat; /* required by request_irq() */
-
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE ID command processing. We have to request device
- * ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
- irq_ret = request_irq( irq, init_IRQ_handler, 0, "SNID", &devstat);
-
- if ( irq_ret == 0 )
- inlreq = 1;
-
- } /* endif */
-
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock( irq);
-
- snid_ccw.cmd_code = CCW_CMD_SENSE_PGID;
- snid_ccw.cda = (__u32)virt_to_phys( pgid );
- snid_ccw.count = sizeof( pgid_t);
- snid_ccw.flags = CCW_FLAG_SLI;
-
- /*
- * We now issue a SenseID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( &devstat, '\0', sizeof( devstat_t) );
-
- irq_ret = s390_start_IO( irq,
- &snid_ccw,
- 0xE2D5C9C4, // == SNID
- lpm, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_VALID_LPM );
-
- if ( !irq_ret )
- {
- if ( devstat.flag & DEVSTAT_STATUS_PENDING )
- {
-#if CONFIG_DEBUG_IO
- printk( "SNID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %d\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
-#endif
- } /* endif */
-
- if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * If the device doesn't support the
- * Sense Path Group ID command
- * further retries wouldn't help ...
- */
- if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- retry = 0;
- irq_ret = -EOPNOTSUPP;
- }
-#if CONFIG_DEBUG_IO
- else
- {
- printk( "SNID - device %04X,"
- " unit check,"
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- devstat.scnt,
- devstat.ii.sense.data[0],
- devstat.ii.sense.data[1],
- devstat.ii.sense.data[2],
- devstat.ii.sense.data[3],
- devstat.ii.sense.data[4],
- devstat.ii.sense.data[5],
- devstat.ii.sense.data[6],
- devstat.ii.sense.data[7]);
-
- } /* endif */
-#endif
- }
- else if ( devstat.flag & DEVSTAT_NOT_OPER )
- {
- printk( "SNID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
-
- retry = 0;
-
- } /* endif */
- }
- else if ( irq_ret != -ENODEV )
- {
- retry--;
- }
- else
- {
- retry = 0;
-
- } /* endif */
-
- } while ( retry > 0 );
-
- s390irq_spin_unlock( irq);
-
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, &devstat);
-
- } /* endif */
-
- return( irq_ret );
-}
-
-
-void do_crw_pending( void )
-{
- return;
-}
-
-
-/* added by Holger Smolinski for reipl support in reipl.S */
-void
-reipl ( int sch )
-{
- int i;
-
- for ( i = 0; i < highest_subchannel; i ++ ) {
- free_irq ( i, (void*)REIPL_DEVID_MAGIC );
- }
- do_reipl( 0x10000 | sch );
-}
-
diff --git a/arch/s390/kernel/s390mach.c b/arch/s390/kernel/s390mach.c
deleted file mode 100644
index 750e50c30..000000000
--- a/arch/s390/kernel/s390mach.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * arch/s390/kernel/s390mach.c
- * S/390 machine check handler,
- * currently only channel-reports are supported
- *
- * S390 version
- * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Ingo Adlung (adlung@de.ibm.com)
- */
-
-#include <linux/init.h>
-
-#include <asm/irq.h>
-#include <asm/lowcore.h>
-#include <asm/semaphore.h>
-#include <asm/s390io.h>
-#include <asm/s390dyn.h>
-#include <asm/s390mach.h>
-
-#define S390_MACHCHK_DEBUG
-
-static mchchk_queue_element_t *mchchk_queue_head = NULL;
-static mchchk_queue_element_t *mchchk_queue_tail = NULL;
-static mchchk_queue_element_t *mchchk_queue_free = NULL;
-static spinlock_t mchchk_queue_lock;
-static struct semaphore s_sem[2];
-
-//
-// initialize machine check handling
-//
-void s390_init_machine_check( void )
-{
- init_MUTEX_LOCKED( &s_sem[0] );
- init_MUTEX_LOCKED( &s_sem[1] );
-
-#if 0
- //
- // fix me ! initialize a machine check queue with 100 elements
- //
-#ifdef S390_MACHCHK_DEBUG
- printk( "init_mach : starting kernel thread\n");
-#endif
-
- kernel_thread( s390_machine_check_handler, s_sem, 0);
-
- //
- // wait for the machine check handler to be ready
- //
-#ifdef S390_MACHCHK_DEBUG
- printk( "init_mach : waiting for kernel thread\n");
-#endif
-
- down( &sem[0]);
-
-#ifdef S390_MACHCHK_DEBUG
- printk( "init_mach : kernel thread ready\n");
-#endif
-
- //
- // fix me ! we have to initialize CR14 to allow for CRW pending
- // conditions
-
- //
- // fix me ! enable machine checks in the PSW
- //
-#endif
- return;
-}
-
-//
-// machine check pre-processor
-//
-void __init s390_do_machine_check( void )
-{
- // fix me ! we have to check for machine check and
- // post the handler eventually
-
- return;
-}
-
-//
-// machine check handler
-//
-static void __init s390_machine_check_handler( struct semaphore *sem )
-{
-#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : kernel thread up\n");
-#endif
-
- up( &sem[0] );
-
-#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : kernel thread ready\n");
-#endif
-
- do {
-
-#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : waiting for wakeup\n");
-#endif
-
- down_interruptible( &sem[1] );
-#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : wakeup\n");
-#endif
-
- break; // fix me ! unconditional surrender ...
-
- // fix me ! check for machine checks and
- // call do_crw_pending() eventually
-
- } while (1);
-
- return;
-}
-
-mchchk_queue_element_t *s390_get_mchchk( void )
-{
- unsigned long flags;
- mchchk_queue_element_t *qe;
-
- spin_lock_irqsave( &mchchk_queue_lock, flags );
-
- // fix me ! dequeue first element if available
- qe = NULL;
-
- spin_unlock_irqrestore( &mchchk_queue_lock, flags );
-
- return qe;
-}
-
-void s390_free_mchchk( mchchk_queue_element_t *mchchk )
-{
- unsigned long flags;
-
- if ( mchchk != NULL)
- {
- spin_lock_irqsave( &mchchk_queue_lock, flags );
-
- mchchk->next = mchchk_queue_free;
-
- if ( mchchk_queue_free != NULL )
- {
- mchchk_queue_free->prev = mchchk;
-
- } /* endif */
-
- mchchk->prev = NULL;
- mchchk_queue_free = mchchk;
-
- spin_unlock_irqrestore( &mchchk_queue_lock, flags );
-
- } /* endif */
-
- return;
-}
-
diff --git a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c
index a0a434581..8af6d8277 100644
--- a/arch/s390/kernel/semaphore.c
+++ b/arch/s390/kernel/semaphore.c
@@ -2,7 +2,7 @@
* linux/arch/S390/kernel/semaphore.c
*
* S390 version
- * Copyright (C) 1998 IBM Corporation
+ * Copyright (C) 1998-2000 IBM Corporation
* Author(s): Martin Schwidefsky
*
* Derived from "linux/arch/i386/kernel/semaphore.c
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 109af4e76..628d7bcf7 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -21,7 +21,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
@@ -45,6 +45,7 @@
__u16 boot_cpu_addr;
int cpus_initialized = 0;
unsigned long cpu_initialized = 0;
+volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
/*
* Setup options
@@ -80,6 +81,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 };
void __init cpu_init (void)
{
int nr = smp_processor_id();
+ int addr = hard_smp_processor_id();
if (test_and_set_bit(nr,&cpu_initialized)) {
printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr);
@@ -91,7 +93,7 @@ void __init cpu_init (void)
* Store processor id in lowcore (used e.g. in timer_interrupt)
*/
asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
- S390_lowcore.cpu_data.cpu_addr = hard_smp_processor_id();
+ S390_lowcore.cpu_data.cpu_addr = addr;
S390_lowcore.cpu_data.cpu_nr = nr;
/*
@@ -158,33 +160,18 @@ void machine_halt(void)
{
if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
cpcmd(vmhalt_cmd, NULL, 0);
- disabled_wait(0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
}
void machine_power_off(void)
{
if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
cpcmd(vmpoff_cmd, NULL, 0);
- disabled_wait(0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
}
#endif
/*
- * Waits for 'delay' microseconds using the tod clock
- */
-void tod_wait(unsigned long delay)
-{
- uint64_t start_cc, end_cc;
-
- if (delay == 0)
- return;
- asm volatile ("STCK %0" : "=m" (start_cc));
- do {
- asm volatile ("STCK %0" : "=m" (end_cc));
- } while (((end_cc - start_cc)/4096) < delay);
-}
-
-/*
* Setup function called from init/main.c just after the banner
* was printed.
*/
@@ -192,12 +179,11 @@ void __init setup_arch(char **cmdline_p)
{
unsigned long bootmap_size;
unsigned long memory_start, memory_end;
- char c = ' ', *to = command_line, *from = COMMAND_LINE;
+ char c = ' ', cn, *to = command_line, *from = COMMAND_LINE;
struct resource *res;
unsigned long start_pfn, end_pfn;
static unsigned int smptrap=0;
unsigned long delay = 0;
- int len = 0;
if (smptrap)
return;
@@ -210,6 +196,7 @@ void __init setup_arch(char **cmdline_p)
*/
cpu_init();
boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+ __cpu_logical_map[0] = boot_cpu_addr;
/*
* print what head.S has found out about the machine
@@ -227,10 +214,15 @@ void __init setup_arch(char **cmdline_p)
rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
#endif
- /* nasty stuff with PARMAREAs. we use head.S or parameterline
- if (!MOUNT_ROOT_RDONLY)
- root_mountflags &= ~MS_RDONLY;
- */
+ memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/
+ memory_end = MEMORY_SIZE;
+ /*
+ * We need some free virtual space to be able to do vmalloc.
+ * On a machine with 2GB memory we make sure that we have at
+ * least 128 MB free space for vmalloc.
+ */
+ if (memory_end > 1920*1024*1024)
+ memory_end = 1920*1024*1024;
memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/
memory_end = MEMORY_SIZE; /* detected in head.s */
init_mm.start_code = PAGE_OFFSET;
@@ -252,7 +244,6 @@ void __init setup_arch(char **cmdline_p)
* "mem=XXX[kKmM]" sets memsize
*/
if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
- if (to != command_line) to--;
memory_end = simple_strtoul(from+4, &from, 0);
if ( *from == 'K' || *from == 'k' ) {
memory_end = memory_end << 10;
@@ -275,16 +266,22 @@ void __init setup_arch(char **cmdline_p)
delay = delay*60*1000000;
from++;
}
- /* now wait for the requestion amount of time */
- tod_wait(delay);
+ /* now wait for the requestedn amount of time */
+ udelay(delay);
}
- c = *(from++);
- if (!c)
+ cn = *(from++);
+ if (!cn)
break;
- if (COMMAND_LINE_SIZE <= ++len)
+ if (cn == '\n')
+ cn = ' '; /* replace newlines with space */
+ if (cn == ' ' && c == ' ')
+ continue; /* remove additional spaces */
+ c = cn;
+ if (to - command_line >= COMMAND_LINE_SIZE)
break;
*(to++) = c;
}
+ if (c == ' ' && to > command_line) to--;
*to = '\0';
*cmdline_p = command_line;
@@ -317,7 +314,7 @@ void __init setup_arch(char **cmdline_p)
paging_init();
#ifdef CONFIG_BLK_DEV_INITRD
if (INITRD_START) {
- if (INITRD_START + INITRD_SIZE < memory_end) {
+ if (INITRD_START + INITRD_SIZE <= memory_end) {
reserve_bootmem(INITRD_START, INITRD_SIZE);
initrd_start = INITRD_START;
initrd_end = initrd_start + INITRD_SIZE;
@@ -368,8 +365,8 @@ int get_cpuinfo(char * buffer)
p += sprintf(p,"vendor_id : IBM/S390\n"
"# processors : %i\n"
"bogomips per cpu: %lu.%02lu\n",
- smp_num_cpus, loops_per_sec/500000,
- (loops_per_sec/5000)%100);
+ smp_num_cpus, loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ))%100);
for (i = 0; i < smp_num_cpus; i++) {
cpuinfo = &safe_get_cpu_lowcore(i).cpu_data;
p += sprintf(p,"processor %i: "
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 7809a4a2b..de05ec764 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -2,7 +2,7 @@
* arch/s390/kernel/signal.c
*
* S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
*
* Based on Intel version
@@ -37,7 +37,7 @@
#define SIGFRAME_COMMON \
__u8 callee_used_stack[__SIGNAL_FRAMESIZE]; \
struct sigcontext sc; \
-sigregs sregs; \
+_sigregs sregs; \
__u8 retcode[S390_SYSCALL_SIZE];
typedef struct
@@ -54,6 +54,41 @@ typedef struct
asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -71,7 +106,7 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma
regs->gprs[2] = -EINTR;
while (1) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
@@ -99,7 +134,7 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize)
regs->gprs[2] = -EINTR;
while (1) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
@@ -139,16 +174,15 @@ sys_sigaction(int sig, const struct old_sigaction *act,
}
asmlinkage int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)
{
- struct pt_regs *regs = (struct pt_regs *) &uss;
return do_sigaltstack(uss, uoss, regs->gprs[15]);
}
-static int save_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int save_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
@@ -163,7 +197,7 @@ static int save_sigregs(struct pt_regs *regs,sigregs *sregs)
}
-static int restore_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
@@ -185,13 +219,13 @@ static int restore_sigregs(struct pt_regs *regs,sigregs *sregs)
static int
restore_sigcontext(struct sigcontext *sc, pt_regs *regs,
- sigregs *sregs,sigset_t *set)
+ _sigregs *sregs,sigset_t *set)
{
unsigned int err;
err=restore_sigregs(regs,sregs);
if(!err)
- err=__copy_from_user(&set->sig,&sc->oldmask,SIGMASK_COPY_SIZE);
+ err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE);
return(err);
}
@@ -227,15 +261,12 @@ badframe:
asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
- stack_t st;
if (sigreturn_common(regs,sizeof(rt_sigframe)))
goto badframe;
- if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
- goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs->gprs[15]);
+ do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
return regs->gprs[2];
badframe:
@@ -290,7 +321,7 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka,
err=__put_user(&frame->sregs,&frame->sc.sregs);
if(!err)
- err=__copy_to_user(&frame->sc.oldmask,&set->sig,SIGMASK_COPY_SIZE);
+ err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE);
if(!err)
{
regs->gprs[2]=(current->exec_domain
@@ -316,14 +347,17 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka,
static void setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs * regs)
{
+ sigframe *frame;
- if(!setup_frame_common(sig,ka,set,regs,sizeof(sigframe),
- (S390_SYSCALL_OPCODE|__NR_sigreturn)))
+ if((frame=setup_frame_common(sig,ka,set,regs,sizeof(sigframe),
+ (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0)
goto give_sigsegv;
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->eip, frame->pretcode);
#endif
+ /* Martin wants this for pthreads */
+ regs->gprs[3] = (addr_t)&frame->sc;
return;
give_sigsegv:
@@ -343,7 +377,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
(S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0)
goto give_sigsegv;
- err = __copy_to_user(&frame->info, info, sizeof(*info));
+ err = copy_siginfo_to_user(&frame->info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
@@ -352,8 +386,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(sas_ss_flags(orig_sp),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
- regs->gprs[3] = (u32)&frame->info;
- regs->gprs[4] = (u32)&frame->uc;
+ err |= __put_user(&frame->sc,&frame->uc.sc);
+ regs->gprs[3] = (addr_t)&frame->info;
+ regs->gprs[4] = (addr_t)&frame->uc;
if (err)
goto give_sigsegv;
@@ -452,10 +487,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (!signr)
break;
- if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
/* Let the debugger run. */
current->exit_code = signr;
- current->state = TASK_STOPPED;
+ set_current_state(TASK_STOPPED);
notify_parent(current, SIGCHLD);
schedule();
@@ -511,7 +546,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
/* FALLTHRU */
case SIGSTOP:
- current->state = TASK_STOPPED;
+ set_current_state(TASK_STOPPED);
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
@@ -540,7 +575,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
}
/* Did we come from a system call? */
- if ( regs->trap == 0x20 /* System Call! */ ) {
+ if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) {
/* Restart the system call - no handlers present */
if (regs->gprs[2] == -ERESTARTNOHAND ||
regs->gprs[2] == -ERESTARTSYS ||
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 6cf2e6918..4b15b5501 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -32,16 +32,15 @@
#include <asm/sigp.h>
#include <asm/pgalloc.h>
#include <asm/irq.h>
+#include <asm/s390_ext.h>
#include "cpcmd.h"
/* prototypes */
-extern void update_one_process( struct task_struct *p,
- unsigned long ticks, unsigned long user,
- unsigned long system, int cpu);
extern int cpu_idle(void * unused);
extern __u16 boot_cpu_addr;
+extern volatile int __cpu_logical_map[];
/*
* An array with a pointer the lowcore of every CPU.
@@ -52,10 +51,8 @@ struct _lowcore *lowcore_ptr[NR_CPUS];
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_old_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
-volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
cycles_t cacheflush_time=0;
int smp_threads_ready=0; /* Set when the idlers are all forked. */
-unsigned long ipi_count=0; /* Number of IPIs delivered. */
static atomic_t smp_commenced = ATOMIC_INIT(0);
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
@@ -104,7 +101,7 @@ void do_machine_restart(void)
void machine_restart(char * __unused)
{
if (smp_processor_id() != 0) {
- smp_ext_call_async(0, ec_restart);
+ smp_ext_bitcall(0, ec_restart);
for (;;);
} else
do_machine_restart();
@@ -115,13 +112,13 @@ void do_machine_halt(void)
smp_send_stop();
if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
cpcmd(vmhalt_cmd, NULL, 0);
- disabled_wait(0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
}
void machine_halt(void)
{
if (smp_processor_id() != 0) {
- smp_ext_call_async(0, ec_halt);
+ smp_ext_bitcall(0, ec_halt);
for (;;);
} else
do_machine_halt();
@@ -132,13 +129,13 @@ void do_machine_power_off(void)
smp_send_stop();
if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
cpcmd(vmpoff_cmd, NULL, 0);
- disabled_wait(0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
}
void machine_power_off(void)
{
if (smp_processor_id() != 0) {
- smp_ext_call_async(0, ec_power_off);
+ smp_ext_bitcall(0, ec_power_off);
for (;;);
} else
do_machine_power_off();
@@ -149,7 +146,7 @@ void machine_power_off(void)
* cpus are handled.
*/
-void do_ext_call_interrupt(__u16 source_cpu_addr)
+void do_ext_call_interrupt(struct pt_regs *regs, __u16 code)
{
ec_ext_call *ec, *next;
int bits;
@@ -172,6 +169,8 @@ void do_ext_call_interrupt(__u16 source_cpu_addr)
do_machine_halt();
if (test_bit(ec_power_off, &bits))
do_machine_power_off();
+ if (test_bit(ec_ptlb, &bits))
+ local_flush_tlb();
/*
* Handle external call commands with a parameter area
@@ -184,7 +183,7 @@ void do_ext_call_interrupt(__u16 source_cpu_addr)
return; /* no command signals */
/* Make a fifo out of the lifo */
- next = ec;
+ next = ec->next;
ec->next = NULL;
while (next != NULL) {
ec_ext_call *tmp = next->next;
@@ -196,61 +195,21 @@ void do_ext_call_interrupt(__u16 source_cpu_addr)
/* Execute every sigp command on the queue */
while (ec != NULL) {
switch (ec->cmd) {
- case ec_get_ctl: {
- ec_creg_parms *pp;
- pp = (ec_creg_parms *) ec->parms;
+ case ec_callback_async: {
+ void (*func)(void *info);
+ void *info;
+
+ func = ec->func;
+ info = ec->info;
atomic_set(&ec->status,ec_executing);
- asm volatile (
- " bras 1,0f\n"
- " stctl 0,0,0(%0)\n"
- "0: ex %1,0(1)\n"
- : : "a" (pp->cregs+pp->start_ctl),
- "a" ((pp->start_ctl<<4) + pp->end_ctl)
- : "memory", "1" );
- atomic_set(&ec->status,ec_done);
+ (func)(info);
return;
}
- case ec_set_ctl: {
- ec_creg_parms *pp;
- pp = (ec_creg_parms *) ec->parms;
+ case ec_callback_sync:
atomic_set(&ec->status,ec_executing);
- asm volatile (
- " bras 1,0f\n"
- " lctl 0,0,0(%0)\n"
- "0: ex %1,0(1)\n"
- : : "a" (pp->cregs+pp->start_ctl),
- "a" ((pp->start_ctl<<4) + pp->end_ctl)
- : "memory", "1" );
+ (ec->func)(ec->info);
atomic_set(&ec->status,ec_done);
return;
- }
- case ec_set_ctl_masked: {
- ec_creg_mask_parms *pp;
- u32 cregs[16];
- int i;
-
- pp = (ec_creg_mask_parms *) ec->parms;
- atomic_set(&ec->status,ec_executing);
- asm volatile (
- " bras 1,0f\n"
- " stctl 0,0,0(%0)\n"
- "0: ex %1,0(1)\n"
- : : "a" (cregs+pp->start_ctl),
- "a" ((pp->start_ctl<<4) + pp->end_ctl)
- : "memory", "1" );
- for (i = pp->start_ctl; i <= pp->end_ctl; i++)
- cregs[i] = (cregs[i] & pp->andvals[i])
- | pp->orvals[i];
- asm volatile (
- " bras 1,0f\n"
- " lctl 0,0,0(%0)\n"
- "0: ex %1,0(1)\n"
- : : "a" (cregs+pp->start_ctl),
- "a" ((pp->start_ctl<<4) + pp->end_ctl)
- : "memory", "1" );
- atomic_set(&ec->status,ec_done);
- return;
- }
default:
}
ec = ec->next;
@@ -258,17 +217,19 @@ void do_ext_call_interrupt(__u16 source_cpu_addr)
}
/*
- * Send an external call sigp to another cpu and wait for its completion.
+ * Send a callback sigp to another cpu.
*/
-sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd, void *parms)
+sigp_ccode
+smp_ext_call(int cpu, void (*func)(void *info), void *info, int wait)
{
struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
sigp_ccode ccode;
ec_ext_call ec;
- ec.cmd = cmd;
+ ec.cmd = wait ? ec_callback_sync : ec_callback_async;
atomic_set(&ec.status, ec_pending);
- ec.parms = parms;
+ ec.func = func;
+ ec.info = info;
do {
ec.next = (ec_ext_call*) atomic_read(&lowcore->ext_call_queue);
} while (atomic_compare_and_swap((int) ec.next, (int)(&ec),
@@ -288,34 +249,15 @@ sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd, void *parms)
if (ccode != sigp_not_operational)
/* wait for completion, FIXME: possible seed of a deadlock */
- while (atomic_read(&ec.status) != ec_done);
+ while (atomic_read(&ec.status) != (wait?ec_done:ec_executing));
return ccode;
}
/*
- * Send an external call sigp to another cpu and return without waiting
- * for its completion. Currently we do not support parameters with
- * asynchronous sigps.
+ * Send a callback sigp to every other cpu in the system.
*/
-sigp_ccode smp_ext_call_async(int cpu, ec_bit_sig sig)
-{
- struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
- sigp_ccode ccode;
-
- /*
- * Set signaling bit in lowcore of target cpu and kick it
- */
- atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
- ccode = signal_processor(cpu, sigp_external_call);
- return ccode;
-}
-
-/*
- * Send an external call sigp to every other cpu in the system and
- * wait for the completion of the sigps.
- */
-void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms)
+void smp_ext_call_others(void (*func)(void *info), void *info, int wait)
{
struct _lowcore *lowcore;
ec_ext_call ec[NR_CPUS];
@@ -326,9 +268,10 @@ void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms)
if (smp_processor_id() == i)
continue;
lowcore = &get_cpu_lowcore(i);
- ec[i].cmd = cmd;
- atomic_set(&ec[i].status, ec_pending);
- ec[i].parms = parms;
+ ec[i].cmd = wait ? ec_callback_sync : ec_callback_async;
+ atomic_set(&ec[i].status, ec_pending);
+ ec[i].func = func;
+ ec[i].info = info;
do {
ec[i].next = (ec_ext_call *)
atomic_read(&lowcore->ext_call_queue);
@@ -341,16 +284,33 @@ void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms)
for (i = 0; i < smp_num_cpus; i++) {
if (smp_processor_id() == i)
continue;
- while (atomic_read(&ec[i].status) != ec_done);
+ while (atomic_read(&ec[i].status) !=
+ (wait ? ec_done:ec_executing));
}
}
/*
+ * Send an external call sigp to another cpu and return without waiting
+ * for its completion.
+ */
+sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
+{
+ struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
+ sigp_ccode ccode;
+
+ /*
+ * Set signaling bit in lowcore of target cpu and kick it
+ */
+ atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
+ ccode = signal_processor(cpu, sigp_external_call);
+ return ccode;
+}
+
+/*
* Send an external call sigp to every other cpu in the system and
- * return without waiting for the completion of the sigps. Currently
- * we do not support parameters with asynchronous sigps.
+ * return without waiting for its completion.
*/
-void smp_ext_call_async_others(ec_bit_sig sig)
+void smp_ext_bitcall_others(ec_bit_sig sig)
{
struct _lowcore *lowcore;
sigp_ccode ccode;
@@ -420,7 +380,46 @@ int smp_signal_others(sigp_order_code order_code, u32 parameter,
void smp_send_stop(void)
{
- smp_signal_others(sigp_stop, 0, 1, NULL);
+ int i;
+ u32 dummy;
+ unsigned long low_core_addr;
+
+ /* write magic number to zero page (absolute 0) */
+
+ get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC;
+
+ /* stop all processors */
+
+ smp_signal_others(sigp_stop, 0, TRUE, NULL);
+
+ /* store status of all processors in their lowcores (real 0) */
+
+ for (i = 0; i < smp_num_cpus; i++) {
+ if (smp_processor_id() != i) {
+ int ccode;
+ low_core_addr = (unsigned long)&get_cpu_lowcore(i);
+ do {
+ ccode = signal_processor_ps(
+ &dummy,
+ low_core_addr,
+ i,
+ sigp_store_status_at_address);
+ } while(ccode == sigp_busy);
+ }
+ }
+}
+
+/*
+ * this function sends a 'purge tlb' signal to another CPU.
+ */
+void smp_ptlb_callback(void *info)
+{
+ local_flush_tlb();
+}
+
+void smp_ptlb_all(void)
+{
+ smp_ext_call_others(smp_ptlb_callback, NULL, 1);
}
/*
@@ -431,7 +430,44 @@ void smp_send_stop(void)
void smp_send_reschedule(int cpu)
{
- smp_ext_call_async(cpu, ec_schedule);
+ smp_ext_bitcall(cpu, ec_schedule);
+}
+
+/*
+ * parameter area for the set/clear control bit callbacks
+ */
+typedef struct
+{
+ __u16 start_ctl;
+ __u16 end_ctl;
+ __u32 orvals[16];
+ __u32 andvals[16];
+} ec_creg_mask_parms;
+
+/*
+ * callback for setting/clearing control bits
+ */
+void smp_ctl_bit_callback(void *info) {
+ ec_creg_mask_parms *pp;
+ u32 cregs[16];
+ int i;
+
+ pp = (ec_creg_mask_parms *) info;
+ asm volatile (" bras 1,0f\n"
+ " stctl 0,0,0(%0)\n"
+ "0: ex %1,0(1)\n"
+ : : "a" (cregs+pp->start_ctl),
+ "a" ((pp->start_ctl<<4) + pp->end_ctl)
+ : "memory", "1" );
+ for (i = pp->start_ctl; i <= pp->end_ctl; i++)
+ cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
+ asm volatile (" bras 1,0f\n"
+ " lctl 0,0,0(%0)\n"
+ "0: ex %1,0(1)\n"
+ : : "a" (cregs+pp->start_ctl),
+ "a" ((pp->start_ctl<<4) + pp->end_ctl)
+ : "memory", "1" );
+ return;
}
/*
@@ -445,7 +481,7 @@ void smp_ctl_set_bit(int cr, int bit) {
parms.end_ctl = cr;
parms.orvals[cr] = 1 << bit;
parms.andvals[cr] = 0xFFFFFFFF;
- smp_ext_call_sync_others(ec_set_ctl_masked,&parms);
+ smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
}
__ctl_set_bit(cr, bit);
}
@@ -461,11 +497,35 @@ void smp_ctl_clear_bit(int cr, int bit) {
parms.end_ctl = cr;
parms.orvals[cr] = 0x00000000;
parms.andvals[cr] = ~(1 << bit);
- smp_ext_call_sync_others(ec_set_ctl_masked,&parms);
+ smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
}
__ctl_clear_bit(cr, bit);
}
+/*
+ * Call a function on all other processors
+ */
+
+int
+smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
+/*
+ * [SUMMARY] Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <retry> currently unused.
+ * <wait> If true, wait (atomically) until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler, you may call it from a bottom half handler.
+ */
+{
+ if (atomic_read(&smp_commenced) != 0)
+ smp_ext_call_others(func, info, 1);
+ (func)(info);
+ return 0;
+}
/*
* Lets check how many CPUs we have.
@@ -475,7 +535,6 @@ void smp_count_cpus(void)
{
int curr_cpu;
- __cpu_logical_map[0] = boot_cpu_addr;
current->processor = 0;
smp_num_cpus = 1;
for (curr_cpu = 0;
@@ -527,7 +586,7 @@ static int __init fork_by_hand(void)
struct pt_regs regs;
/* don't care about the psw and regs settings since we'll never
reschedule the forked task. */
- memset(&regs,sizeof(pt_regs),0);
+ memset(&regs,0,sizeof(pt_regs));
return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
}
@@ -594,7 +653,10 @@ void __init smp_boot_cpus(void)
struct _lowcore *curr_lowcore;
sigp_ccode ccode;
int i;
-
+
+ /* request the 0x1202 external interrupt */
+ if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
+ panic("Couldn't request external interrupt 0x1202");
smp_count_cpus();
memset(lowcore_ptr,0,sizeof(lowcore_ptr));
@@ -705,24 +767,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
*/
irq_enter(cpu, 0);
- update_one_process(p, 1, user, system, cpu);
- if (p->pid) {
- p->counter -= 1;
- if (p->counter <= 0) {
- p->counter = 0;
- p->need_resched = 1;
- }
- if (p->nice > 0) {
- kstat.cpu_nice += user;
- kstat.per_cpu_nice[cpu] += user;
- } else {
- kstat.cpu_user += user;
- kstat.per_cpu_user[cpu] += user;
- }
- kstat.cpu_system += system;
- kstat.per_cpu_system[cpu] += system;
-
- }
+ update_process_times(user);
irq_exit(cpu, 0);
}
}
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
index b00d88a62..cc7700864 100644
--- a/arch/s390/kernel/sys_s390.c
+++ b/arch/s390/kernel/sys_s390.c
@@ -71,18 +71,10 @@ out:
return error;
}
-/* FIXME: 6 parameters is one too much ... */
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff)
-{
- return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
/*
* Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/i386 didn't use to be able to handle more than
- * 4 system call parameters, so these system calls used a memory
+ * calls. Linux for S/390 isn't able to handle more than 5
+ * system call parameters, so these system calls used a memory
* block for parameter passing..
*/
@@ -95,6 +87,18 @@ struct mmap_arg_struct {
unsigned long offset;
};
+asmlinkage long sys_mmap2(struct mmap_arg_struct *arg)
+{
+ struct mmap_arg_struct a;
+ int error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+out:
+ return error;
+}
+
asmlinkage int old_mmap(struct mmap_arg_struct *arg)
{
struct mmap_arg_struct a;
@@ -239,7 +243,7 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
asmlinkage int sys_pause(void)
{
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
return -ERESTARTNOHAND;
}
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 8cd84ee54..f4bde27b3 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -11,7 +11,6 @@
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -27,15 +26,14 @@
#include <asm/uaccess.h>
#include <asm/delay.h>
+#include <asm/s390_ext.h>
-#include <linux/mc146818rtc.h>
#include <linux/timex.h>
+#include <linux/config.h>
#include <asm/irq.h>
-extern volatile unsigned long lost_ticks;
-
/* change this if you have some constant time drift */
#define USECS_PER_JIFFY ((signed long)1000000/HZ)
#define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12)
@@ -45,6 +43,7 @@ extern volatile unsigned long lost_ticks;
static uint64_t init_timer_cc, last_timer_cc;
extern rwlock_t xtime_lock;
+extern unsigned long wall_jiffies;
void tod_to_timeval(uint64_t todval, struct timeval *xtime)
{
@@ -94,9 +93,9 @@ unsigned long do_gettimeoffset(void)
*/
void do_gettimeofday(struct timeval *tv)
{
- extern volatile unsigned long lost_ticks;
unsigned long flags;
unsigned long usec, sec;
+ unsigned long lost_ticks = jiffies - wall_jiffies;
read_lock_irqsave(&xtime_lock, flags);
usec = do_gettimeoffset();
@@ -149,7 +148,7 @@ void do_settimeofday(struct timeval *tv)
extern __u16 boot_cpu_addr;
#endif
-void do_timer_interrupt(struct pt_regs *regs,int error_code)
+void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
{
unsigned long flags;
@@ -242,6 +241,9 @@ void __init time_init(void)
printk("time_init: TOD clock stopped/non-operational\n");
break;
}
+ /* request the 0x1004 external interrupt */
+ if (register_external_interrupt(0x1004, do_timer_interrupt) != 0)
+ panic("Couldn't request external interrupts 0x1004");
init_100hz_timer();
init_timer_cc = S390_lowcore.jiffy_timer_cc;
init_timer_cc -= 0x8126d60e46000000LL -
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 4af4f6565..fc774a7db 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -42,122 +42,15 @@ extern void handle_per_exception(struct pt_regs *regs);
typedef void pgm_check_handler_t(struct pt_regs *, long);
pgm_check_handler_t *pgm_check_table[128];
-extern pgm_check_handler_t default_trap_handler;
-extern pgm_check_handler_t do_page_fault;
-
-asmlinkage int system_call(void);
-
-#define DO_ERROR(trapnr, signr, str, name, tsk) \
-asmlinkage void name(struct pt_regs * regs, long error_code) \
-{ \
- tsk->thread.error_code = error_code; \
- tsk->thread.trap_no = trapnr; \
- die_if_no_fixup(str,regs,error_code); \
- force_sig(signr, tsk); \
-}
-
-/* TODO: define these as 'pgm_check_handler_t xxx;'
-asmlinkage void divide_error(void);
-asmlinkage void debug(void);
-asmlinkage void nmi(void);
-asmlinkage void int3(void);
-asmlinkage void overflow(void);
-asmlinkage void bounds(void);
-asmlinkage void invalid_op(void);
-asmlinkage void device_not_available(void);
-asmlinkage void double_fault(void);
-asmlinkage void coprocessor_segment_overrun(void);
-asmlinkage void invalid_TSS(void);
-asmlinkage void segment_not_present(void);
-asmlinkage void stack_segment(void);
-asmlinkage void general_protection(void);
-asmlinkage void coprocessor_error(void);
-asmlinkage void reserved(void);
-asmlinkage void alignment_check(void);
-asmlinkage void spurious_interrupt_bug(void);
-*/
-
-int kstack_depth_to_print = 24;
-
-/*
- * These constants are for searching for possible module text
- * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-#define MODULE_RANGE (8*1024*1024)
-
-void show_crashed_task_info(void)
-{
- printk("CPU: %d\n",smp_processor_id());
- printk("Process %s (pid: %d, stackpage=%08X)\n",
- current->comm, current->pid, 4096+(addr_t)current);
- show_regs(current,NULL,NULL);
-}
-#if 0
-static void show_registers(struct pt_regs *regs)
-{
- printk("CPU: %d\nPSW: %08lx %08lx\n",
- smp_processor_id(), (unsigned long) regs->psw.mask,
- (unsigned long) regs->psw.addr);
- printk("GPRS:\n");
-
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[0], regs->gprs[1],
- regs->gprs[2], regs->gprs[3]);
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[4], regs->gprs[5],
- regs->gprs[6], regs->gprs[7]);
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[8], regs->gprs[9],
- regs->gprs[10], regs->gprs[11]);
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[12], regs->gprs[13],
- regs->gprs[14], regs->gprs[15]);
- printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 4096+(unsigned long)current);
-/*
- stack = (unsigned long *) esp;
- for(i=0; i < kstack_depth_to_print; i++) {
- if (((long) stack & 4095) == 0)
- break;
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("%08lx ", get_seg_long(ss,stack++));
- }
- printk("\nCall Trace: ");
- stack = (unsigned long *) esp;
- i = 1;
- module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT);
- module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
- module_end = module_start + MODULE_RANGE;
- while (((long) stack & 4095) != 0) {
- addr = get_seg_long(ss, stack++); */
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
-/* if (((addr >= (unsigned long) &_stext) &&
- (addr <= (unsigned long) &_etext)) ||
- ((addr >= module_start) && (addr <= module_end))) {
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("[<%08lx>] ", addr);
- i++;
- }
- }
- printk("\nCode: ");
- for(i=0;i<20;i++)
- printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip)));
- printk("\n");
-*/
-}
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
+int sysctl_userprocess_debug = 1;
+#else
+int sysctl_userprocess_debug = 0;
+#endif
#endif
+extern pgm_check_handler_t do_page_fault;
spinlock_t die_lock;
@@ -166,29 +59,65 @@ void die(const char * str, struct pt_regs * regs, long err)
console_verbose();
spin_lock_irq(&die_lock);
printk("%s: %04lx\n", str, err & 0xffff);
- show_crashed_task_info();
+ show_regs(regs);
spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
-int check_for_fixup(struct pt_regs * regs)
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+ do_trap(interruption_code, signr, str, regs, NULL); \
+}
+
+#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+ siginfo_t info; \
+ info.si_signo = signr; \
+ info.si_errno = 0; \
+ info.si_code = sicode; \
+ info.si_addr = (void *)siaddr; \
+ do_trap(interruption_code, signr, str, regs, &info); \
+}
+
+static void inline do_trap(long interruption_code, int signr, char *str,
+ struct pt_regs *regs, siginfo_t *info)
{
- if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
- unsigned long fixup;
- fixup = search_exception_table(regs->psw.addr);
- if (fixup) {
- regs->psw.addr = fixup;
- return 1;
+ if (regs->psw.mask & PSW_PROBLEM_STATE) {
+ struct task_struct *tsk = current;
+ tsk->thread.trap_no = interruption_code;
+ if (info)
+ force_sig_info(signr, info, tsk);
+ else
+ force_sig(signr, tsk);
+#ifndef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
+ printk("User process fault: interruption code 0x%lX\n",
+ interruption_code);
+ show_regs(regs);
+#endif
+#else
+ if (sysctl_userprocess_debug) {
+ printk("User process fault: interruption code 0x%lX\n",
+ interruption_code);
+ show_regs(regs);
}
- }
- return 0;
+#endif
+ } else {
+ unsigned long fixup = search_exception_table(regs->psw.addr);
+ if (fixup)
+ regs->psw.addr = fixup;
+ else
+ die(str, regs, interruption_code);
+ }
}
int do_debugger_trap(struct pt_regs *regs,int signal)
{
if(regs->psw.mask&PSW_PROBLEM_STATE)
{
- if(current->flags & PF_PTRACED)
+ if(current->ptrace & PT_PTRACED)
force_sig(signal,current);
else
return 1;
@@ -207,50 +136,16 @@ int do_debugger_trap(struct pt_regs *regs,int signal)
return 0;
}
-static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
-{
- if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
- unsigned long fixup;
- fixup = search_exception_table(regs->psw.addr);
- if (fixup) {
- regs->psw.addr = fixup;
- return;
- }
- die(str, regs, err);
- }
-}
-
-asmlinkage void default_trap_handler(struct pt_regs * regs, long error_code)
-{
- current->thread.error_code = error_code;
- current->thread.trap_no = error_code;
- die_if_no_fixup("Unknown program exception",regs,error_code);
- force_sig(SIGSEGV, current);
-}
-
-DO_ERROR(2, SIGILL, "privileged operation", privileged_op, current)
-DO_ERROR(3, SIGILL, "execute exception", execute_exception, current)
-DO_ERROR(5, SIGSEGV, "addressing exception", addressing_exception, current)
-DO_ERROR(9, SIGFPE, "fixpoint divide exception", divide_exception, current)
-DO_ERROR(0x12, SIGILL, "translation exception", translation_exception, current)
-DO_ERROR(0x13, SIGILL, "special operand exception", special_op_exception, current)
-DO_ERROR(0x15, SIGILL, "operand exception", operand_exception, current)
+DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
+DO_ERROR(SIGILL, "privileged operation", privileged_op)
+DO_ERROR(SIGILL, "execute exception", execute_exception)
+DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
+DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception)
+DO_ERROR(SIGILL, "translation exception", translation_exception)
+DO_ERROR(SIGILL, "special operand exception", special_op_exception)
+DO_ERROR(SIGILL, "operand exception", operand_exception)
-/* need to define
-DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current)
-DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current)
-DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current)
-DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current)
-DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
-DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
-DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
-*/
-
-#ifdef CONFIG_IEEEFPU_EMULATION
-
-asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
+asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
__u16 *location;
@@ -268,6 +163,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
if(do_debugger_trap(regs,SIGTRAP))
do_sig=1;
}
+#ifdef CONFIG_IEEEFPU_EMULATION
else if (problem_state )
{
if (opcode[0] == 0xb3) {
@@ -288,18 +184,19 @@ asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
do_sig = math_emu_lfpc(opcode, regs);
} else
do_sig = 1;
- } else
- do_sig = 1;
- if (do_sig) {
- current->thread.error_code = error_code;
- current->thread.trap_no = 1;
- force_sig(SIGILL, current);
- die_if_no_fixup("illegal operation", regs, error_code);
}
+#endif
+ else
+ do_sig = 1;
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL);
unlock_kernel();
}
-asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
+
+
+#ifdef CONFIG_IEEEFPU_EMULATION
+asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
__u16 *location;
@@ -311,26 +208,26 @@ asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
get_user(*((__u16 *) opcode), location);
switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */
- math_emu_ldr(opcode);
+ do_sig=math_emu_ldr(opcode);
break;
case 0x38: /* LER Rx,Ry */
- math_emu_ler(opcode);
+ do_sig=math_emu_ler(opcode);
break;
case 0x60: /* STD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_std(opcode, regs);
+ do_sig=math_emu_std(opcode, regs);
break;
case 0x68: /* LD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ld(opcode, regs);
+ do_sig=math_emu_ld(opcode, regs);
break;
case 0x70: /* STE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ste(opcode, regs);
+ do_sig=math_emu_ste(opcode, regs);
break;
case 0x78: /* LE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_le(opcode, regs);
+ do_sig=math_emu_le(opcode, regs);
break;
default:
do_sig = 1;
@@ -338,47 +235,59 @@ asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
}
} else
do_sig = 1;
- if (do_sig) {
- current->thread.error_code = error_code;
- current->thread.trap_no = 1;
- force_sig(SIGILL, current);
- die_if_no_fixup("illegal operation", regs, error_code);
- }
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "specification exception", regs, NULL);
unlock_kernel();
}
+#else
+DO_ERROR(SIGILL, "specification exception", specification_exception)
+#endif
-asmlinkage void data_exception(struct pt_regs * regs, long error_code)
+asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
__u16 *location;
int do_sig = 0;
lock_kernel();
- if (regs->psw.mask & 0x00010000L) {
- location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ if(MACHINE_HAS_IEEE)
+ {
+ __asm__ volatile ("stfpc %0\n\t"
+ : "=m" (current->thread.fp_regs.fpc));
+ }
+ /* Same code should work when we implement fpu emulation */
+ /* provided we call data exception from the fpu emulator */
+ if(current->thread.fp_regs.fpc&FPC_DXC_MASK)
+ {
+ current->thread.ieee_instruction_pointer=(addr_t)location;
+ force_sig(SIGFPE, current);
+ }
+#ifdef CONFIG_IEEEFPU_EMULATION
+ else if (regs->psw.mask & 0x00010000L) {
get_user(*((__u16 *) opcode), location);
switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */
- math_emu_ldr(opcode);
+ do_sig=math_emu_ldr(opcode);
break;
case 0x38: /* LER Rx,Ry */
- math_emu_ler(opcode);
+ do_sig=math_emu_ler(opcode);
break;
case 0x60: /* STD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_std(opcode, regs);
+ do_sig=math_emu_std(opcode, regs);
break;
case 0x68: /* LD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ld(opcode, regs);
+ do_sig=math_emu_ld(opcode, regs);
break;
case 0x70: /* STE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ste(opcode, regs);
+ do_sig=math_emu_ste(opcode, regs);
break;
case 0x78: /* LE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_le(opcode, regs);
+ do_sig=math_emu_le(opcode, regs);
break;
case 0xb3:
get_user(*((__u16 *) (opcode+2)), location+1);
@@ -406,22 +315,15 @@ asmlinkage void data_exception(struct pt_regs * regs, long error_code)
do_sig = 1;
break;
}
- } else
- do_sig = 1;
- if (do_sig) {
- current->thread.error_code = error_code;
- current->thread.trap_no = 1;
- force_sig(SIGILL, current);
- die_if_no_fixup("illegal operation", regs, error_code);
}
+#endif
+ else
+ do_sig = 1;
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "data exception", regs, NULL);
unlock_kernel();
}
-#else
-DO_ERROR(1, SIGILL, "illegal operation", illegal_op, current)
-DO_ERROR(6, SIGILL, "specification exception", specification_exception, current)
-DO_ERROR(7, SIGILL, "data exception", data_exception, current)
-#endif /* CONFIG_IEEEFPU_EMULATION */
/* init is done in lowcore.S and head.S */
@@ -463,7 +365,7 @@ void handle_per_exception(struct pt_regs *regs)
/* I've seen this possibly a task structure being reused ? */
printk("Spurious per exception detected\n");
printk("switching off per tracing for this task.\n");
- show_crashed_task_info();
+ show_regs(regs);
/* Hopefully switching off per tracing will help us survive */
regs->psw.mask &= ~PSW_PER_MASK;
}
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index aa8b0e5da..40ae70e8c 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -2,11 +2,17 @@
# Makefile for s390-specific library files..
#
+ifdef SMP
.S.o:
- $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+else
+.S.o:
+ $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+endif
L_TARGET = lib.a
-L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o
+
+obj-y = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o
include $(TOPDIR)/Rules.make
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index ec3274487..012a95308 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -21,25 +21,30 @@
void __delay(unsigned long loops)
{
- __asm__ __volatile__(
- "0: ahi %0,-1\n"
- " jnm 0b"
- : /* no outputs */ : "r" (loops) );
+ /*
+ * To end the bloody studid and useless discussion about the
+ * BogoMips number I took the liberty to define the __delay
+ * function in a way that that resulting BogoMips number will
+ * yield the megahertz number of the cpu. The important function
+ * is udelay and that is done using the tod clock. -- martin.
+ */
+ __asm__ __volatile__(
+ "0: brct %0,0b"
+ : /* no outputs */ : "r" (loops/2) );
}
-inline void __const_udelay(unsigned long xloops)
+/*
+ * Waits for 'usecs' microseconds using the tod clock
+ */
+void __udelay(unsigned long usecs)
{
+ uint64_t start_cc, end_cc;
- __asm__("LR 3,%1\n\t"
- "MR 2,%2\n\t"
- "LR %0,2\n\t"
- : "=r" (xloops)
- : "r" (xloops) , "r" (loops_per_sec)
- : "2" , "3");
- __delay(xloops);
+ if (usecs == 0)
+ return;
+ asm volatile ("STCK %0" : "=m" (start_cc));
+ do {
+ asm volatile ("STCK %0" : "=m" (end_cc));
+ } while (((end_cc - start_cc)/4096) < usecs);
}
-void __udelay(unsigned long usecs)
-{
- __const_udelay(usecs * 0x000010c6); /* 2**32 / 1000000 */
-}
diff --git a/arch/s390/lib/strcmp.S b/arch/s390/lib/strcmp.S
index d3f63942f..340edffb5 100644
--- a/arch/s390/lib/strcmp.S
+++ b/arch/s390/lib/strcmp.S
@@ -18,8 +18,8 @@ strcmp:
CLST 2,3
JO .-4
JE strcmp_equal
- IC 0,0(0,3)
- IC 1,0(0,2)
+ IC 0,0(3)
+ IC 1,0(2)
SR 1,0
strcmp_equal:
LR 2,1
diff --git a/arch/s390/lib/strncpy.S b/arch/s390/lib/strncpy.S
index 83578909c..3065be2b4 100644
--- a/arch/s390/lib/strncpy.S
+++ b/arch/s390/lib/strncpy.S
@@ -20,9 +20,9 @@ strncpy:
SR 0,0
strncpy_loop:
ICM 0,1,0(3) # ICM sets the cc, IC does not
- LA 3,1(0,3)
- STC 0,0(0,1)
- LA 1,1(0,1)
+ LA 3,1(3)
+ STC 0,0(1)
+ LA 1,1(1)
JZ strncpy_exit # ICM inserted a 0x00
BRCT 4,strncpy_loop # R4 -= 1, jump to strncpy_loop if > 0
strncpy_exit:
diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S
new file mode 100644
index 000000000..8044d156d
--- /dev/null
+++ b/arch/s390/lib/uaccess.S
@@ -0,0 +1,51 @@
+/*
+ * arch/s390/lib/uaccess.S
+ * fixup routines for copy_{from|to}_user functions.
+ *
+ * s390
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * These functions have a non-standard call interface
+ */
+
+#include <asm/lowcore.h>
+
+ .text
+ .align 4
+ .globl __copy_from_user_fixup
+__copy_from_user_fixup:
+ l 1,__LC_PGM_OLD_PSW+4
+ sll 4,1
+ srl 4,1
+0: lhi 3,-4096
+ sll 3,1
+ srl 3,1
+ n 3,__LC_TRANS_EXC_ADDR
+ sr 3,4
+ bm 4(1)
+1: mvcle 2,4,0
+ b 4(1)
+ .section __ex_table,"a"
+ .long 1b,0b
+ .previous
+
+ .align 4
+ .text
+ .globl __copy_to_user_fixup
+__copy_to_user_fixup:
+ l 1,__LC_PGM_OLD_PSW+4
+ sll 4,1
+ srl 4,1
+0: lhi 5,-4096
+ sll 5,1
+ srl 5,1
+ n 5,__LC_TRANS_EXC_ADDR
+ sr 5,4
+ bm 4(1)
+1: mvcle 4,2,0
+ b 4(1)
+ .section __ex_table,"a"
+ .long 1b,0b
+ .previous
+
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index cee7d4e6d..73e25bd30 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -8,6 +8,7 @@
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := mm.o
-O_OBJS := init.o fault.o ioremap.o extable.o
+
+obj-y := init.o fault.o ioremap.o extable.o
include $(TOPDIR)/Rules.make
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index f20a9d49e..2c75918af 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -9,6 +9,7 @@
* Copyright (C) 1995 Linus Torvalds
*/
+#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -26,6 +27,10 @@
#include <asm/pgtable.h>
#include <asm/hardirq.h>
+#ifdef CONFIG_SYSCTL
+extern int sysctl_userprocess_debug;
+#endif
+
extern void die(const char *,struct pt_regs *,long);
/*
@@ -48,6 +53,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
int write;
unsigned long psw_mask;
unsigned long psw_addr;
+ int si_code = SEGV_MAPERR;
+ int kernel_address = 0;
/*
* get psw mask of Program old psw to find out,
@@ -65,58 +72,106 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
address = S390_lowcore.trans_exc_code&0x7ffff000;
- if (in_irq())
- die("page fault from irq handler",regs,error_code);
-
tsk = current;
mm = tsk->mm;
+ if (in_interrupt() || !mm)
+ goto no_context;
+
+
+ /*
+ * Check which address space the address belongs to
+ */
+ switch (S390_lowcore.trans_exc_code & 3)
+ {
+ case 0: /* Primary Segment Table Descriptor */
+ kernel_address = 1;
+ goto no_context;
+
+ case 1: /* STD determined via access register */
+ if (S390_lowcore.exc_access_id == 0)
+ {
+ kernel_address = 1;
+ goto no_context;
+ }
+ if (regs && S390_lowcore.exc_access_id < NUM_ACRS)
+ {
+ if (regs->acrs[S390_lowcore.exc_access_id] == 0)
+ {
+ kernel_address = 1;
+ goto no_context;
+ }
+ if (regs->acrs[S390_lowcore.exc_access_id] == 1)
+ {
+ /* user space address */
+ break;
+ }
+ }
+ die("page fault via unknown access register", regs, error_code);
+ break;
+
+ case 2: /* Secondary Segment Table Descriptor */
+ case 3: /* Home Segment Table Descriptor */
+ /* user space address */
+ break;
+ }
+
+
+ /*
+ * When we get here, the fault happened in the current
+ * task's user address space, so we search the VMAs
+ */
+
down(&mm->mmap_sem);
vma = find_vma(mm, address);
- if (!vma) {
- printk("no vma for address %lX\n",address);
+ if (!vma)
goto bad_area;
- }
if (vma->vm_start <= address)
goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN)) {
- printk("VM_GROWSDOWN not set, but address %lX \n",address);
- printk("not in vma %p (start %lX end %lX)\n",vma,
- vma->vm_start,vma->vm_end);
+ if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
- }
- if (expand_stack(vma, address)) {
- printk("expand of vma failed address %lX\n",address);
- printk("vma %p (start %lX end %lX)\n",vma,
- vma->vm_start,vma->vm_end);
+ if (expand_stack(vma, address))
goto bad_area;
- }
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
write = 0;
+ si_code = SEGV_ACCERR;
+
switch (error_code & 0xFF) {
case 0x04: /* write, present*/
write = 1;
break;
case 0x10: /* not present*/
case 0x11: /* not present*/
- if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) {
- printk("flags %X of vma for address %lX wrong \n",
- vma->vm_flags,address);
- printk("vma %p (start %lX end %lX)\n",vma,
- vma->vm_start,vma->vm_end);
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area;
- }
break;
default:
printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF);
goto bad_area;
}
- handle_mm_fault(tsk, vma, address, write);
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ switch (handle_mm_fault(mm, vma, address, write)) {
+ case 1:
+ tsk->min_flt++;
+ break;
+ case 2:
+ tsk->maj_flt++;
+ break;
+ case 0:
+ goto do_sigbus;
+ default:
+ goto out_of_memory;
+ }
up(&mm->mmap_sem);
return;
@@ -130,19 +185,32 @@ bad_area:
/* User mode accesses just cause a SIGSEGV */
if (psw_mask & PSW_PROBLEM_STATE) {
+ struct siginfo si;
tsk->thread.prot_addr = address;
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = 14;
-
+ tsk->thread.trap_no = error_code;
+#ifndef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
printk("User process fault: interruption code 0x%lX\n",error_code);
printk("failing address: %lX\n",address);
- show_crashed_task_info();
- force_sig(SIGSEGV, tsk);
+ show_regs(regs);
+#endif
+#else
+ if (sysctl_userprocess_debug) {
+ printk("User process fault: interruption code 0x%lX\n",
+ error_code);
+ printk("failing address: %lX\n", address);
+ show_regs(regs);
+ }
+#endif
+ si.si_signo = SIGSEGV;
+ si.si_code = si_code;
+ si.si_addr = (void*) address;
+ force_sig_info(SIGSEGV, &si, tsk);
return;
}
+no_context:
/* Are we prepared to handle this kernel fault? */
-
if ((fixup = search_exception_table(regs->psw.addr)) != 0) {
regs->psw.addr = fixup;
return;
@@ -151,53 +219,47 @@ bad_area:
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
- *
- * First we check if it was the bootup rw-test, though..
*/
- if (address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+
+ if (kernel_address)
+ printk(KERN_ALERT "Unable to handle kernel pointer dereference"
+ " at virtual kernel address %08lx\n", address);
else
- printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at virtual address %08lx\n",address);
+ printk(KERN_ALERT "Unable to handle kernel paging request"
+ " at virtual user address %08lx\n", address);
/*
* need to define, which information is useful here
*/
- lock_kernel();
die("Oops", regs, error_code);
do_exit(SIGKILL);
- unlock_kernel();
-}
-/*
- {
- char c;
- int i,j;
- char *addr;
- addr = ((char*) psw_addr)-0x20;
- for (i=0;i<16;i++) {
- if (i == 2)
- printk("\n");
- printk ("%08X: ",(unsigned long) addr);
- for (j=0;j<4;j++) {
- printk("%08X ",*(unsigned long*)addr);
- addr += 4;
- }
- addr -=0x10;
- printk(" | ");
- for (j=0;j<16;j++) {
- printk("%c",(c=*addr++) < 0x20 ? '.' : c );
- }
-
- printk("\n");
- }
- printk("\n");
- }
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
*/
+out_of_memory:
+ up(&mm->mmap_sem);
+ printk("VM: killing process %s\n", tsk->comm);
+ if (psw_mask & PSW_PROBLEM_STATE)
+ do_exit(SIGKILL);
+ goto no_context;
+do_sigbus:
+ up(&mm->mmap_sem);
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->thread.prot_addr = address;
+ tsk->thread.trap_no = error_code;
+ force_sig(SIGBUS, tsk);
-
+ /* Kernel mode? Handle exceptions or die */
+ if (!(psw_mask & PSW_PROBLEM_STATE))
+ goto no_context;
+}
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 177e5e8f2..e1acfa063 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -52,10 +52,10 @@ static unsigned long totalram_pages;
* data and COW.
*/
-pgd_t swapper_pg_dir[512] __attribute__ ((__aligned__ (4096)));
-unsigned long empty_bad_page[1024] __attribute__ ((__aligned__ (4096)));
-unsigned long empty_zero_page[1024] __attribute__ ((__aligned__ (4096)));
-pte_t empty_bad_pte_table[1024] __attribute__ ((__aligned__ (4096)));
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
+char empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE)));
static int test_access(unsigned long loc)
{
@@ -104,47 +104,6 @@ static inline void invalidate_page(pte_t *pte)
pte_clear(pte++);
}
-void __handle_bad_pmd(pmd_t *pmd)
-{
- pmd_ERROR(*pmd);
- pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table());
-}
-
-void __handle_bad_pmd_kernel(pmd_t *pmd)
-{
- pmd_ERROR(*pmd);
- pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table());
-}
-
-pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
-{
- pte_t *pte;
-
- pte = (pte_t *) __get_free_page(GFP_KERNEL);
- if (pmd_none(*pmd)) {
- if (pte) {
- invalidate_page(pte);
- pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(pte);
- pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(pte)+1024;
- pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(pte)+2048;
- pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(pte)+3072;
- return pte + offset;
- }
- pte = get_bad_pte_table();
- pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(pte);
- pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(pte)+1024;
- pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(pte)+2048;
- pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(pte)+3072;
- return NULL;
- }
- free_page((unsigned long)pte);
- if (pmd_bad(*pmd)) {
- __handle_bad_pmd_kernel(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + offset;
-}
-
pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
{
unsigned long pte;
@@ -167,10 +126,8 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
return NULL;
}
free_page(pte);
- if (pmd_bad(*pmd)) {
- __handle_bad_pmd(pmd);
- return NULL;
- }
+ if (pmd_bad(*pmd))
+ BUG();
return (pte_t *) pmd_page(*pmd) + offset;
}
@@ -180,7 +137,7 @@ int do_check_pgt_cache(int low, int high)
if(pgtable_cache_size > high) {
do {
if(pgd_quicklist)
- free_pgd_slow(get_pgd_fast()), freed++;
+ free_pgd_slow(get_pgd_fast()), freed += 2;
if(pmd_quicklist)
free_pmd_slow(get_pmd_fast()), freed++;
if(pte_quicklist)
@@ -245,6 +202,7 @@ void __init paging_init(void)
unsigned long address=0;
unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE);
+ static const int ssm_mask = 0x04000000L;
/* unmap whole virtual address space */
@@ -283,8 +241,9 @@ void __init paging_init(void)
/* enable virtual mapping in kernel mode */
__asm__ __volatile__(" LCTL 1,1,%0\n"
" LCTL 7,7,%0\n"
- " LCTL 13,13,%0"
- : :"m" (pgdir_k));
+ " LCTL 13,13,%0\n"
+ " SSM %1"
+ : : "m" (pgdir_k), "m" (ssm_mask));
local_flush_tlb();
@@ -378,6 +337,7 @@ void si_meminfo(struct sysinfo *val)
val->sharedram = 0;
val->freeram = nr_free_pages();
val->bufferram = atomic_read(&buffermem_pages);
+ val->totalhigh = 0;
+ val->freehigh = 0;
val->mem_unit = PAGE_SIZE;
- return;
}
diff --git a/arch/s390/mm/ioremap.c b/arch/s390/mm/ioremap.c
index f9f0024c4..38acc4a22 100644
--- a/arch/s390/mm/ioremap.c
+++ b/arch/s390/mm/ioremap.c
@@ -33,8 +33,8 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned l
printk("remap_area_pte: page already exists\n");
BUG();
}
- set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT |
- _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
+ set_pte(pte, mk_pte_phys(phys_addr,
+ __pgprot(_PAGE_PRESENT | flags)));
address += PAGE_SIZE;
phys_addr += PAGE_SIZE;
pte++;
diff --git a/arch/s390/tools/dasdfmt/Makefile b/arch/s390/tools/dasdfmt/Makefile
index f63ff468b..b60641bbc 100644
--- a/arch/s390/tools/dasdfmt/Makefile
+++ b/arch/s390/tools/dasdfmt/Makefile
@@ -1,7 +1,7 @@
all: dasdfmt
dasdfmt: dasdfmt.c
- $(CROSS_COMPILE)gcc -o $@ $^
+ $(CC) -o $@ $^
$(STRIP) $@
clean:
diff --git a/arch/s390/tools/dasdfmt/dasdfmt.8 b/arch/s390/tools/dasdfmt/dasdfmt.8
index b08244322..9e6a4e89e 100644
--- a/arch/s390/tools/dasdfmt/dasdfmt.8
+++ b/arch/s390/tools/dasdfmt/dasdfmt.8
@@ -3,8 +3,7 @@
.SH NAME
dasdfmt \- formatting of DSAD (ECKD) disk drives.
.SH SYNOPSIS
-\fBdasdfmt\fR [-tvyV] [-b \fIblockSize\fR] [\fIblockRange\fI]
- \fIdiskSpec\fR
+\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
.SH DESCRIPTION
\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
@@ -25,6 +24,10 @@ Increases verbosity.
Start formatting without further user-confirmation.
.TP
+\fB-L\fR
+Omit the writing of a disk label after formatting.
+
+.TP
\fB-V\fR
Print version number and exit.
@@ -35,26 +38,17 @@ and always be a power of two. Due due some limitations in the driver,
it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
.TP
-\fIblockRange\fR
-This parameter specifies the number of the first and last block to be
-formatted. If this parameter is \fBomitted\fR, formatting the \fBwhole\fR disk
-is assumed. The \fIblockRange\fR can be specified in two different formats:
-.sp
- \fB-s\fR \fIstartBlock\fR \fB-e\fR \fIendBlock\fR
-.br
-or
-.br
- \fB-r\fR \fIstartBlock\fR-\fIendBlock\fR
-.sp
-If \fIstartBlock\fR is omitted, block \fB0\fR is assumed. If
-\fIendBlock\fR is omitted, the last block of the disk is assumed.
+\fB-l\fR \fIdiskLabel\fR
+Specify the label to be written to disk after formatting. If no label is
+specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
+ASCII string and is automatically converted to EBCDIC.
.TP
\fIdiskSpec\fR
This parameter specified the device to be formatted. It also can be
given in two variants:
.sp
- \fB-f\fR \fB/dev/dd\fR\fIX\fR
+ \fB-f\fR \fB/dev/dasd\fR\fIX\fR
.br
or
.br
@@ -63,7 +57,7 @@ or
The first form uses the commonly used
.SM UNIX
device notation where \fIX\fR is a single lowercase letter.
-The second form uses simply the VM vdev number.
+The second form uses simply the device number.
.SH BUGS
None so far ;-)
diff --git a/arch/s390/tools/dasdfmt/dasdfmt.c b/arch/s390/tools/dasdfmt/dasdfmt.c
index 1726e7061..2820fc91d 100644
--- a/arch/s390/tools/dasdfmt/dasdfmt.c
+++ b/arch/s390/tools/dasdfmt/dasdfmt.c
@@ -12,6 +12,8 @@
* detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them
*/
+/* #define _LINUX_BLKDEV_H */
+
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
@@ -25,19 +27,25 @@
#include <string.h>
#include <dirent.h>
#include <mntent.h>
-#include "../../../drivers/s390/block/dasd.h" /* uses DASD_PARTN_BITS */
#define __KERNEL__ /* we want to use kdev_t and not have to define it */
#include <linux/kdev_t.h>
#undef __KERNEL__
+#include <linux/fs.h>
+#include <asm/dasd.h>
+#include <linux/hdreg.h>
+
#define EXIT_MISUSE 1
#define EXIT_BUSY 2
#define TEMPFILENAME "/tmp/ddfXXXXXX"
#define TEMPFILENAMECHARS 8 /* 8 characters are fixed in all temp filenames */
-#define IOCTL_COMMAND 'D' << 8
#define SLASHDEV "/dev/"
#define PROC_DASD_DEVICES "/proc/dasd/devices"
+/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */
+#define PROC_MOUNTS _PATH_MOUNTED
+#define PROC_SWAPS "/proc/swaps"
#define DASD_DRIVER_NAME "dasd"
+#define LABEL_LENGTH 10
#define PROC_LINE_LENGTH 80
#define ERR_LENGTH 80
@@ -66,24 +74,108 @@
ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
"is in invalid format\n",prog_name);}
-typedef struct {
- int start_unit;
- int stop_unit;
- int blksize;
-} format_data_t;
-
-char prog_name[]="dasd_format";
+char *prog_name;/*="dasdfmt";*/
char tempfilename[]=TEMPFILENAME;
+__u8 _ascebc[256] =
+{
+ /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ /* ->NL */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN EM SUB ESC FS GS RS US */
+ /* ->IGS ->IRS ->IUS */
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ /*80*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0 sz */
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+void convert_label(char *str)
+{
+ int i;
+ for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]];
+}
+
void
exit_usage(int exitcode)
{
- printf("Usage: %s [-htvyV] [-b blocksize] <range> <diskspec>\n\n",
- prog_name);
- printf(" where <range> is either\n");
- printf(" -s start_track -e end_track\n");
+#ifdef RANGE_FORMATTING
+ printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \
+ "<diskspec>\n\n",prog_name);
+#else /* RANGE_FORMATTING */
+ printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \
+ "<diskspec>\n\n",prog_name);
+#endif /* RANGE_FORMATTING */
+ printf(" -t means testmode\n");
+ printf(" -v means verbose mode\n");
+ printf(" -V means print version\n");
+ printf(" -L means don't write disk label\n");
+ printf(" <label> is a label which is converted to EBCDIC and " \
+ "written to disk\n");
+ printf(" <blocksize> has to be power of 2 and at least 512\n");
+#ifdef RANGE_FORMATTING
+ printf(" <range> is either\n");
+ printf(" -s <start_track> -e <end_track>\n");
printf(" or\n");
- printf(" -r start_track-end_track\n");
+ printf(" -r <start_track>-<end_track>\n");
+#endif /* RANGE_FORMATTING */
printf(" and <diskspec> is either\n");
printf(" -f /dev/dasdX\n");
printf(" or\n");
@@ -106,9 +198,9 @@ get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
PROC_DASD_DEVICES ": %s (do you have the /proc " \
"filesystem enabled?)\n",prog_name,strerror(errno));
- fgets(line,sizeof(line),file); /* omit first line */
+ /* fgets(line,sizeof(line),file); omit first line */
while (fgets(line,sizeof(line),file)!=NULL) {
- rc=sscanf(line,"%X%d%d",&d,&ma_i,&mi_i);
+ rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i);
ma=ma_i;
mi=mi_i;
if ( (rc==3) &&
@@ -253,6 +345,7 @@ ask_user_for_data(format_data_t params)
char *str;
char output[60],o2[12];
+#ifdef RANGE_FORMATTING
i=params.start_unit;
do {
params.start_unit=i;
@@ -284,6 +377,7 @@ ask_user_for_data(format_data_t params)
ASK_CHECK_PARAM(CHECK_END);
}
} while (rc!=1);
+#endif /* RANGE_FORMATTING */
i=params.blksize;
do {
@@ -320,8 +414,8 @@ check_mounted(int major, int minor)
/*
* first, check filesystems
*/
- if (!(f = fopen(_PATH_MOUNTED, "r")))
- ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", _PATH_MOUNTED,
+ if (!(f = fopen(PROC_MOUNTS, "r")))
+ ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS,
strerror(errno));
while ((ment = getmntent(f))) {
if (stat(ment->mnt_fsname, &stbuf) == 0)
@@ -337,8 +431,8 @@ check_mounted(int major, int minor)
/*
* second, check active swap spaces
*/
- if (!(f = fopen("/proc/swaps", "r")))
- ERRMSG_EXIT(EXIT_FAILURE, "/proc/swaps: %s", strerror(errno));
+ if (!(f = fopen(PROC_SWAPS, "r")))
+ ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno));
/*
* skip header line
*/
@@ -362,12 +456,15 @@ check_mounted(int major, int minor)
void
do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
- int verbosity,int withoutprompt)
+ int verbosity,int writenolabel,int labelspec,
+ char *label,int withoutprompt,int devno)
{
int fd,rc;
struct stat stat_buf;
kdev_t minor_no,major_no;
- int devno;
+ int new_blksize;
+ unsigned int label_position;
+ struct hd_geometry new_geometry;
char inp_buffer[5]; /* to contain yes */
fd=open(dev_name,O_RDWR);
@@ -390,6 +487,10 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
minor_no=MINOR(stat_buf.st_rdev);
}
check_mounted(major_no, minor_no);
+
+ if ((!writenolabel) && (!labelspec)) {
+ sprintf(label,"LNX1 x%04x",devno);
+ }
if ( ((withoutprompt)&&(verbosity>=1)) ||
(!withoutprompt) ) {
@@ -400,6 +501,11 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
printf(" Device number of device : 0x%x\n",devno);
printf(" Major number of device : %u\n",major_no);
printf(" Minor number of device : %u\n",minor_no);
+ printf(" Labelling device : %s\n",(writenolabel)?
+ "no":"yes");
+ if (!writenolabel)
+ printf(" Disk label : %s\n",label);
+#ifdef RANGE_FORMATTING
printf(" Start track : %d\n" \
,format_params.start_unit);
printf(" End track : ");
@@ -407,6 +513,7 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
printf("last track of disk\n");
else
printf("%d\n",format_params.stop_unit);
+#endif /* RANGE_FORMATTING */
printf(" Blocksize : %d\n" \
,format_params.blksize);
if (testmode) printf("Test mode active, omitting ioctl.\n");
@@ -416,8 +523,8 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
if (!withoutprompt) {
printf("\n--->> ATTENTION! <<---\n");
printf("All data in the specified range of that " \
- "device will be lost.\nType yes to continue" \
- ", no will leave the disk untouched: ");
+ "device will be lost.\nType \"yes\" to " \
+ "continue, no will leave the disk untouched: ");
fgets(inp_buffer,sizeof(inp_buffer),stdin);
if (strcasecmp(inp_buffer,"yes") &&
strcasecmp(inp_buffer,"yes\n")) {
@@ -430,13 +537,70 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
if ( !( (withoutprompt)&&(verbosity<1) ))
printf("Formatting the device. This may take a " \
"while (get yourself a coffee).\n");
- rc=ioctl(fd,IOCTL_COMMAND,format_params);
+ rc=ioctl(fd,BIODASDFORMAT,format_params);
if (rc)
ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
"returned with the following error " \
"message:\n%s\n",prog_name,strerror(errno));
printf("Finished formatting the device.\n");
+ if (!writenolabel) {
+ if (verbosity>0)
+ printf("Retrieving disk geometry... ");
+
+ rc=ioctl(fd,HDIO_GETGEO,&new_geometry);
+ if (rc) {
+ ERRMSG("%s: the ioctl call to get geometry " \
+ "returned with the following error " \
+ "message:\n%s\n",prog_name,
+ strerror(errno));
+ goto reread;
+ }
+
+
+ rc=ioctl(fd,BLKGETSIZE,&new_blksize);
+ if (rc) {
+ ERRMSG("%s: the ioctl call to get blocksize " \
+ "returned with the following error " \
+ "message:\n%s\n",prog_name,
+ strerror(errno));
+ goto reread;
+ }
+
+ if (verbosity>0) printf("done\n");
+
+ label_position=new_geometry.start*new_blksize;
+
+ if (verbosity>0) printf("Writing label... ");
+ convert_label(label);
+ rc=lseek(fd,label_position,SEEK_SET);
+ if (rc!=label_position) {
+ ERRMSG("%s: lseek on the device to %i " \
+ "failed with the following error " \
+ "message:\n%s\n",prog_name,
+ label_position,strerror(errno));
+ goto reread;
+ }
+ rc=write(fd,label,LABEL_LENGTH);
+ if (rc!=LABEL_LENGTH) {
+ ERRMSG("%s: writing the label only wrote %d " \
+ "bytes.\n",prog_name,rc);
+ goto reread;
+ }
+
+ sync();
+ sync();
+
+ if (verbosity>0) printf("done\n");
+ }
+ reread:
+ printf("Rereading the partition table... ");
+ rc=ioctl(fd,BLKRRPART,NULL);
+ if (rc) {
+ ERRMSG("%s: error during rereading the partition " \
+ "table: %s.\n",prog_name,strerror(errno));
+ } else printf("done.\n");
+
break;
}
@@ -452,11 +616,13 @@ int main(int argc,char *argv[]) {
int verbosity;
int testmode;
int withoutprompt;
+ int writenolabel,labelspec;
char *dev_name;
int devno;
char *dev_filename,*devno_param_str,*range_param_str;
char *start_param_str,*end_param_str,*blksize_param_str;
+ char label[LABEL_LENGTH+1];
format_data_t format_params;
@@ -465,23 +631,30 @@ int main(int argc,char *argv[]) {
char *endptr;
char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
- int i1,i2;
+ int i,i1,i2;
char *str;
int start_specified,end_specified,blksize_specified;
int devfile_specified,devno_specified,range_specified;
/******************* initialization ********************/
+ prog_name=argv[0];
endptr=NULL;
/* set default values */
- format_params.start_unit=0;
- format_params.stop_unit=-1;
- format_params.blksize=4096;
+ format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
+ format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
+ format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
+ format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
testmode=0;
verbosity=0;
withoutprompt=0;
+ writenolabel=0;
+ labelspec=0;
+ for (i=0;i<LABEL_LENGTH;i++) label[i]=' ';
+ label[LABEL_LENGTH]=0;
+
start_specified=end_specified=blksize_specified=0;
devfile_specified=devno_specified=range_specified=0;
@@ -490,7 +663,10 @@ int main(int argc,char *argv[]) {
/* avoid error message generated by getopt */
opterr=0;
- while ( (oc=getopt(argc,argv,"r:s:e:b:n:f:hty?vV")) !=EOF) {
+#ifdef RANGE_FORMATTING
+ while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) {
+#endif /* RANGE_FORMATTING */
+ while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) {
switch (oc) {
case 'y':
withoutprompt=1;
@@ -515,6 +691,18 @@ int main(int argc,char *argv[]) {
printf("%s version 0.99\n",prog_name);
exit(0);
+ case 'l':
+ strncpy(label,optarg,LABEL_LENGTH);
+ if (strlen(optarg)<LABEL_LENGTH)
+ label[strlen(optarg)]=' ';
+ labelspec++;
+ break;
+
+ case 'L':
+ writenolabel++;
+ break;
+
+#ifdef RANGE_FORMATTING
case 's' :
start_param_str=optarg;
start_specified++;
@@ -525,6 +713,12 @@ int main(int argc,char *argv[]) {
end_specified++;
break;
+ case 'r' :
+ range_param_str=optarg;
+ range_specified++;
+ break;
+#endif /* RANGE_FORMATTING */
+
case 'b' :
blksize_param_str=optarg;
blksize_specified++;
@@ -539,10 +733,6 @@ int main(int argc,char *argv[]) {
dev_filename=optarg;
devfile_specified++;
break;
- case 'r' :
- range_param_str=optarg;
- range_specified++;
- break;
}
}
@@ -594,6 +784,8 @@ int main(int argc,char *argv[]) {
CHECK_SPEC_MAX_ONCE(start_specified,"start track");
CHECK_SPEC_MAX_ONCE(end_specified,"end track");
CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
+ CHECK_SPEC_MAX_ONCE(labelspec,"label");
+ CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag");
if (devno_specified)
PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
@@ -616,9 +808,9 @@ int main(int argc,char *argv[]) {
str=check_param(CHECK_ALL,format_params);
if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
- /*************** issue the real command *****************/
+ /******* issue the real command and reread part table *******/
do_format_dasd(dev_name,format_params,testmode,verbosity,
- withoutprompt);
+ writenolabel,labelspec,label,withoutprompt,devno);
/*************** cleanup ********************************/
if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
diff --git a/arch/s390/tools/silo/Makefile b/arch/s390/tools/silo/Makefile
index fb100e1b9..62b11d7da 100644
--- a/arch/s390/tools/silo/Makefile
+++ b/arch/s390/tools/silo/Makefile
@@ -1,13 +1,13 @@
all: silo
silo.o: silo.c
- $(CROSS_COMPILE)gcc -c -o silo.o -O2 silo.c
+ $(CC) -c -o silo.o -O2 silo.c
cfg.o: cfg.c
- $(CROSS_COMPILE)gcc -c -o cfg.o -O2 cfg.c
+ $(CC) -c -o cfg.o -O2 cfg.c
silo: silo.o cfg.o
- $(CROSS_COMPILE)gcc -o $@ $^
+ $(CC) -o $@ $^
$(STRIP) $@
clean:
diff --git a/arch/s390/tools/silo/silo.c b/arch/s390/tools/silo/silo.c
index 827082f5c..9ac04ac2b 100644
--- a/arch/s390/tools/silo/silo.c
+++ b/arch/s390/tools/silo/silo.c
@@ -45,7 +45,7 @@ CONFIG cf_options[] = {
/* from dasd.h */
#define DASD_PARTN_BITS 2
-#define BIODASDRWTB _IOWR('D',5,int)
+#define BIODASDRWTB _IOWR('D',0,int)
/* end */
#define SILO_CFG "/etc/silo.conf"
@@ -554,7 +554,7 @@ int
main (int argct, char *argv[])
{
int rc = 0;
- char *save;
+ char *save=NULL;
char *tmpdir=getenv("TMPDIR");
if (tmpdir) {
NTRY( save=(char*)malloc(strlen(tmpdir)));
diff --git a/arch/s390/vmlinux.lds b/arch/s390/vmlinux.lds
index b1b556d14..4d93bcc7a 100644
--- a/arch/s390/vmlinux.lds
+++ b/arch/s390/vmlinux.lds
@@ -26,6 +26,10 @@ SECTIONS
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
+ __start___kallsyms = .; /* All kernel symbols */
+ __kallsyms : { *(__kallsyms) }
+ __stop___kallsyms = .;
+
_etext = .; /* End of text section */
.data : { /* Data */
diff --git a/arch/s390x/Makefile b/arch/s390x/Makefile
new file mode 100644
index 000000000..7ea330273
--- /dev/null
+++ b/arch/s390x/Makefile
@@ -0,0 +1,70 @@
+
+# s390/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+#
+
+LD=$(CROSS_COMPILE)ld -m elf64_s390
+CPP=$(CC) -E
+OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
+LDFLAGS=-e start
+LINKFLAGS =-T $(TOPDIR)/arch/s390x/vmlinux.lds $(LDFLAGS)
+MODFLAGS += -fpic
+
+CFLAGS_PIPE := -pipe
+CFLAGS_NSR := -fno-strength-reduce
+CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR)
+
+HEAD := arch/s390x/kernel/head.o arch/s390x/kernel/init_task.o
+
+SUBDIRS := $(SUBDIRS) arch/s390x/mm arch/s390x/kernel arch/s390x/lib \
+ drivers/s390
+CORE_FILES := arch/s390x/mm/mm.o arch/s390x/kernel/kernel.o $(CORE_FILES) \
+ drivers/s390/io.o
+LIBS := $(TOPDIR)/arch/s390x/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390x/lib/lib.a
+
+all: image listing
+
+listing: vmlinux
+ @$(MAKEBOOT) listing
+
+arch/s390x/kernel: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/s390x/kernel
+
+arch/s390x/mm: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=arch/s390x/mm
+
+drivers/s390: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=drivers/s390
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+MAKESILO = $(MAKE) -C arch/$(ARCH)/tools/silo
+
+MAKEDASDFMT = $(MAKE) -C arch/$(ARCH)/tools/dasdfmt
+
+silo:
+ @$(MAKE) -C arch/$(ARCH)/tools/silo
+
+dasdfmt:
+ @$(MAKE) -C arch/$(ARCH)/tools/dasdfmt
+
+image: vmlinux
+ @$(MAKEBOOT) image
+
+archclean:
+ @$(MAKEBOOT) clean
+
+archmrproper:
+
+archdep:
+ @$(MAKEBOOT) dep
diff --git a/arch/s390x/boot/Makefile b/arch/s390x/boot/Makefile
new file mode 100644
index 000000000..fb112b964
--- /dev/null
+++ b/arch/s390x/boot/Makefile
@@ -0,0 +1,37 @@
+#
+# Makefile for the linux s390-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+OBJCOPY = $(CROSS_COMPILE)objcopy
+
+O_TARGET :=
+
+include $(TOPDIR)/Rules.make
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+
+%.lnk: %.o
+ $(LD) -Ttext 0x0 -o $@ $<
+
+%.boot: %.lnk
+ $(OBJCOPY) -O binary $< $@
+
+image: $(CONFIGURE) $(TOPDIR)/vmlinux \
+ iplfba.boot ipleckd.boot ipldump.boot
+ $(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
+ $(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aU] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
+
+listing: ../../../vmlinux
+ $(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing
+
+dep:
+
+clean:
+ rm -f image listing iplfba.boot ipleckd.boot ipldump.boot
+
diff --git a/arch/s390x/boot/ipldump.S b/arch/s390x/boot/ipldump.S
new file mode 100644
index 000000000..84150b5af
--- /dev/null
+++ b/arch/s390x/boot/ipldump.S
@@ -0,0 +1,178 @@
+/*
+ * arch/s390/boot/ipldump.S
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * Tape dump ipl record. Put it on a tape and ipl from it and it will
+ * write a dump of the real storage after the ipl record on that tape.
+ */
+
+#include <asm/setup.h>
+#include <asm/lowcore.h>
+
+#define IPL_BS 1024
+ .org 0
+ .long 0x00080000,0x80000000+_start # The first 24 bytes are loaded
+ .long 0x07000000,0x60000001 # by ipl to addresses 0-23.
+ .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000 # svc old psw
+ .long 0x00000000,0x00000000 # program check old psw
+ .long 0x00000000,0x00000000 # machine check old psw
+ .long 0x00000000,0x00000000 # io old psw
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x000a0000,0x00000058 # external new psw
+ .long 0x000a0000,0x00000060 # svc new psw
+ .long 0x000a0000,0x00000068 # program check new psw
+ .long 0x000a0000,0x00000070 # machine check new psw
+ .long 0x00080000,0x80000000+.Lioint # io new psw
+
+ .org 0x100
+ .globl _start
+_start:
+ l %r1,0xb8 # load ipl subchannel number
+#
+# find out memory size
+#
+ mvc 104(8),.Lpcmem0 # setup program check handler
+ slr %r3,%r3
+ lhi %r2,1
+ sll %r2,20
+.Lloop0:
+ l %r0,0(%r3) # test page
+ ar %r3,%r2 # add 1M
+ jnm .Lloop0 # r1 < 0x80000000 -> loop
+.Lchkmem0:
+ n %r3,.L4malign0 # align to multiples of 4M
+ st %r3,.Lmemsize # store memory size
+.Lmemok:
+
+#
+# first write a tape mark
+#
+ bras %r14,.Ltapemark
+#
+# write real storage to tape
+#
+ slr %r2,%r2 # start at address 0
+ bras %r14,.Lwriter # load ramdisk
+#
+# write another tape mark
+#
+ bras %r14,.Ltapemark
+#
+# everything written, stop processor
+#
+ lpsw .Lstopped
+#
+# subroutine for writing to tape
+# Paramters:
+# R1 = device number
+# R2 = start address
+# R3 = length
+.Lwriter:
+ st %r14,.Lldret
+ la %r12,.Lorbread # r12 = address of orb
+ la %r5,.Lirb # r5 = address of irb
+ st %r2,.Lccwwrite+4 # initialize CCW data addresses
+ lctl %c6,%c6,.Lcr6
+ slr %r2,%r2
+.Lldlp:
+ lhi %r6,3 # 3 retries
+.Lssch:
+ ssch 0(%r12) # write chunk of IPL_BS bytes
+ jnz .Llderr
+.Lw4end:
+ bras %r14,.Lwait4io
+ tm 8(%r5),0x82 # do we have a problem ?
+ jnz .Lrecov
+ l %r0,.Lccwwrite+4 # update CCW data addresses
+ ahi %r0,IPL_BS
+ st %r0,.Lccwwrite+4
+ clr %r0,%r3 # enough ?
+ jl .Lldlp
+.Ldone:
+ l %r14,.Lldret
+ br %r14 # r2 contains the total size
+.Lrecov:
+ bras %r14,.Lsense # do the sensing
+ brct %r6,.Lssch # dec. retry count & branch
+ j .Llderr
+.Ltapemark:
+ st %r14,.Lldret
+ la %r12,.Lorbmark # r12 = address of orb
+ la %r5,.Lirb # r5 = address of irb
+ lctl %c6,%c6,.Lcr6
+ ssch 0(%r12) # write a tape mark
+ jnz .Llderr
+ bras %r14,.Lwait4io
+ l %r14,.Lldret
+ br %r14
+#
+# Sense subroutine
+#
+.Lsense:
+ st %r14,.Lsnsret
+ la %r7,.Lorbsense
+ ssch 0(%r7) # start sense command
+ jnz .Llderr
+ bras %r14,.Lwait4io
+ l %r14,.Lsnsret
+ tm 8(%r5),0x82 # do we have a problem ?
+ jnz .Llderr
+ br %r14
+#
+# Wait for interrupt subroutine
+#
+.Lwait4io:
+ lpsw .Lwaitpsw
+.Lioint:
+ c %r1,0xb8 # compare subchannel number
+ jne .Lwait4io
+ tsch 0(%r5)
+ slr %r0,%r0
+ tm 8(%r5),0x82 # do we have a problem ?
+ jnz .Lwtexit
+ tm 8(%r5),0x04 # got device end ?
+ jz .Lwait4io
+.Lwtexit:
+ br %r14
+.Llderr:
+ lpsw .Lcrash
+
+ .align 8
+.Lorbread:
+ .long 0x00000000,0x0080ff00,.Lccwwrite
+ .align 8
+.Lorbsense:
+ .long 0x00000000,0x0080ff00,.Lccwsense
+ .align 8
+.Lorbmark:
+ .long 0x00000000,0x0080ff00,.Lccwmark
+ .align 8
+.Lccwwrite:
+ .long 0x01200000+IPL_BS,0x00000000
+.Lccwsense:
+ .long 0x04200001,0x00000000
+.Lccwmark:
+ .long 0x1f200001,0x00000000
+.Lwaitpsw:
+ .long 0x020a0000,0x80000000+.Lioint
+
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6: .long 0xff000000
+ .align 8
+.Lcrash:.long 0x000a0000,0x00000000
+.Lstopped: .long 0x000a0000,0x00001234
+.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0
+.L4malign0:.long 0xffc00000
+.Lmemsize:.long 0
+.Lldret:.long 0
+.Lsnsret: .long 0
+
+ .org IPL_BS
+
diff --git a/arch/s390x/boot/ipleckd.S b/arch/s390x/boot/ipleckd.S
new file mode 100644
index 000000000..d66a8d684
--- /dev/null
+++ b/arch/s390x/boot/ipleckd.S
@@ -0,0 +1,303 @@
+#
+# arch/s390/boot/ipleckd.S
+# IPL record for 3380/3390 DASD
+#
+# S390 version
+# Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+# Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
+#
+#
+# FIXME: should use the countarea to determine the blocksize
+# FIXME: should insert zeroes into memory when filling holes
+# FIXME: calculate blkpertrack from rdc data and blksize
+
+# change 09/20/00 removed obsolete store of ipldevice to textesegment
+
+# Usage of registers
+# r1: ipl subchannel ( general use, dont overload without save/restore !)
+# r10:
+# r13: base register index to 0x0000
+# r14: callers address
+# r15: temporary save register (we have no stack!)
+
+# storage layout:
+
+#include <asm/lowcore.h>
+
+ .org 0
+.psw: .long 0x00080000,0x80000000+_start
+.ccw1: .long 0x06000000,0x00001000 # Re-Read enough of bootsector to start
+.ccw2: .long 0x00000000,0x00000000 # read countarea of record 1 to s/w.
+
+ .org 0x58
+.Lextn: .long 0x000a0000,0x00000000+.Lextn
+.Lsvcn: .long 0x000a0000,0x00000000+.Lsvcn
+.Lprgn: .long 0x00080000,0x00000000+.Lecs
+.Lmcn: .long 0x000a0000,0x00000000+.Lmcn
+.Lion: .long 0x00080000,0x80000000+.Lionewaddr
+
+ .org 0xe0
+.Llstad:.long 0x00000000,0x00000000 # sectorno + ct of bootlist
+
+ .org 0xf0 # Lets start now...
+_start: .globl _start
+ l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore
+ st %r1,__LC_IPLDEV # keep it for reipl
+ stsch .Lrdcdata
+ oi .Lrdcdata+5,0x84 # enable ssch and multipath mode
+.Lecs: xi .Lrdcdata+27,0x01 # enable concurrent sense
+ msch .Lrdcdata
+ xi .Lprgn,6 # restore Wait and d/a bit in PCnew PSW
+ l %r2,.Lparm
+ mvc 0x0(8,%r2),.Lnull # set parmarea to null
+ lctl %c6,%c6,.Lc6 # enable all interrupts
+.Lrdc: # read device characteristics
+ la %r6,.Lrdcccw
+ st %r6,.Lorb+8 # store cp-address to orb
+ bras %r15,.Lssch # start I/O
+ oi .Llodata+1,0x80
+ lh %r5,.Lcountarea+6 # init r5 from countarea
+ stcm %r5,3,.Lrdccw+2 # and store into rd template *FIXME*
+ stcm %r5,3,.Llodata+14 # and store into lodata *FIXME*
+.Lbootlist:
+ l %r2,.Llstad
+ l %r3,.Lblklst
+ lhi %r4,1
+ bras %r14,.Lreadblks
+.Lloader:
+ l %r10,.Lblklst # r10 is index to bootlist
+ lhi %r5,4 # r5: skip 4 blocks = firstpage....
+.Lkloop:
+ clc .Lnull(8),0(%r10) # test blocklist
+ jz .Lchkparm # end of list?
+ l %r2,0(%r10) # get startblock to r2
+ slr %r4,%r4 # erase r4
+ icm %r4,1,7(%r10) # get blockcount
+ slr %r3,%r3 # get address to r3
+ icm %r3,0xe,4(%r10)
+ chi %r5,0 # still blocks to skip?
+ jz .Ldoread # no: start reading
+ cr %r5,%r4 # #skipblocks >= blockct?
+ jm .L007 # no: skip the blocks one by one
+.L006:
+ sr %r5,%r4 # decrease number of blocks to skip
+ j .Lkcont # advance to next entry
+.L007:
+ ahi %r2,1 # skip 1 block...
+ bctr %r4,0 # update blockct
+ ah %r3,.Lcountarea+6 # increment address
+ bct %r5,.L007 # 4 blocks skipped?
+.Ldoread:
+ ltr %r2,%r2 # test startblock
+ jz .Lzeroes # startblocks is zero (hole)
+.Ldiskread:
+ bras %r14,.Lreadblks
+ j .Lkcont
+.Lzeroes:
+ lr %r2,%r3
+.L001: slr %r3,%r3
+ icm %r3,3,.Lcountarea+6 # get blocksize
+ slr %r5,%r5 # no bytes to move
+.L008: mvcle %r2,%r4,0 # fill zeroes to storage
+ jo .L008 # until block is filled
+ brct %r4,.L001 # skip to next block
+.Lkcont:
+ ahi %r10,8
+ j .Lkloop
+.Lchkparm:
+ lm %r3,%r4,.Lstart # load .Lstart and .Lparm
+ clc 0x0(4,%r4),.Lnull
+ je .Lrunkern
+ mvc 0x480(128,%r3),0(%r4) # move 1k-0x80 to parmarea
+ mvc 0x500(256,%r3),0x80(%r4)
+ mvc 0x600(256,%r3),0x180(%r4)
+ mvc 0x700(256,%r3),0x280(%r4)
+.Lrunkern:
+# lhi %r2,17
+# sll %r2,12
+# st %r1,0xc6c(%r2) # store iplsubchannel to lowcore
+# st %r1,0xc6c # store iplsubchannel to lowcore
+ br %r3
+# This function does the start IO
+# r2: number of first block to read ( input by caller )
+# r3: address to read data to ( input by caller )
+# r4: number of blocks to read ( input by caller )
+# r5: destroyed
+# r6: blocks per track ( input by caller )
+# r7: number of heads
+# r8:
+# r9:
+# r10:
+# r11: temporary register
+# r12: local use for base address
+# r13: base address for module
+# r14: address of caller for subroutine
+# r15: temporary save register (since we have no stack)
+.Lreadblks:
+ la %r12,.Ldeccw
+ st %r12,8+.Lorb # store cpaddr to orb
+ ahi %r12,0x10 # increment r12 to point to rdccw
+ oi 1(%r12),0x40 # set CC in rd template
+ # first setup the read CCWs
+ lr %r15,%r4 # save number or blocks
+ slr %r7,%r7
+ icm %r7,3,.Lrdcdata+14 # load heads to r7
+ lhi %r6,9
+ clc .Lrdcdata+3(2),.L9345
+ je .L011
+ lhi %r6,10
+ clc .Lrdcdata+3(2),.L3380
+ je .L011
+ lhi %r6,12
+ clc .Lrdcdata+3(2),.L3390
+ je .L011
+ bras %r14,.Ldisab
+.L011:
+ # loop for nbl times
+.Lrdloop:
+ mvc 0(8,%r12),.Lrdccw # copy template to this ccw
+ st %r3,4(%r12) # store target address to this ccw
+ bct %r4,.L005 # decrement no of blks still to do
+ ni 1(%r12),0x3f # delete CC from last ccw
+ lr %r4,%r15 # restore number of blocks
+ # read CCWs are setup now
+ stcm %r4,3,.Llodata+2 # store blockno to lodata clears r4
+ ar %r4,%r2 # r4 (clear): ebl = blk + nbl
+ bctr %r4,0 # decrement r4 ( last blk touched
+ srda %r2,32 # trk = blk / bpt, bot = blk % bpt
+ dr %r2,%r6 # r3: trk, r2: bot
+ ahi %r2,1 # bot++ ( we start counting at 1 )
+ stcm %r2,1,.Llodata+12 # store bot to lodata
+ xr %r2,%r2 # cy = trk / heads, hd = trk % heads
+ dr %r2,%r7 # r3: cy, r2: hd
+ sll %r3,16 # combine to CCHH in r3
+ or %r3,%r2
+ st %r3,.Ldedata+8 # store cchh to dedata
+ st %r3,.Llodata+4 # store cchh to lodata
+ st %r3,.Llodata+8 # store cchh to lodata
+ lr %r15,%r5 # save r5
+ srda %r4,32 # tr2 = ebl / bpt
+ dr %r4,%r6 # r5: tr2, r4: bot2
+ xr %r4,%r4 # cy2 = tr2 / heads, hd2 = hd2 % heads
+ dr %r4,%r7 # r5: cy2, r4: hd2
+ stcm %r5,3,.Ldedata+12 # store cy2,hd2 to dedata
+ stcm %r4,3,.Ldedata+14 # store cy2,hd2 to dedata
+ lr %r5,%r15 # restore r5
+ # CCWs are setup now, arent they?
+ bras %r15,.Lssch # start I/O
+ br %r14 # return to caller
+.L005:
+ ah %r3,.Lcountarea+6 # add blocksize to target address
+ ahi %r12,8 # add sizeof(ccw) to base address
+ j .Lrdloop
+# end of function
+# This function does the start IO
+# r1: Subchannel number
+# r8: ORB address
+# r9: IRB address
+.Lssch:
+ lhi %r13,10 # initialize retries
+.L012:
+ ssch .Lorb # start I/O
+ jz .Ltpi # ok?
+ bras %r14,.Ldisab # error
+.Ltpi:
+ lpsw .Lwaitpsw # load wait-PSW
+.Lionewaddr:
+ c %r1,0xb8 # compare to ipl subhchannel
+ jnz .Ltpi # not equal: loop
+ clc 0xbc(4),.Lorb # cross check the intparm
+ jnz .Ltpi # not equal: loop
+ tsch .Lirb # get status
+ tm .Lirb+9,0xff # channel status ?
+ jz .L003 # CS == 0x00
+ bras %r14,.Ldisab # error
+.L003:
+ tm .Lirb+8,0xf3 # DS different from CE/DE
+ jz .L004 # ok ?
+ bct %r13,.L012 # retries <= 5 ?
+ bras %r14,.Ldisab # error
+.L004:
+ tm .Lirb+8,0x04 # DE set?
+ jz .Ltpi # DE not set, loop
+.Lsschend:
+ br %r15 # return to caller
+# end of function
+# In case of error goto disabled wait with %r14 containing the caller
+.Ldisab:
+ st %r14,.Ldisabpsw+4
+ lpsw .Ldisabpsw
+
+# FIXME pre-initialized data should be listed first
+# NULLed storage can be taken from anywhere ;)
+.Lblklst:
+ .long 0x00002000
+ .align 8
+.Ldisabpsw:
+ .long 0x000a0000,0x00000000
+.Lwaitpsw:
+ .long 0x020a0000,0x00000000+.Ltpi
+.Lorb:
+ .long 0x0049504c,0x0080ff00 # intparm is " IPL"
+.Lc6: .long 0xff000000
+.Lstart:
+ .long 0x00010000 # do not separate .Lstart and .Lparm
+.Lparm:
+ .long 0x00008000 # they are loaded with a LM
+.L3390:
+ .word 0x3390
+.L9345:
+ .word 0x9345
+.L3380:
+ .word 0x3380
+.Lnull:
+ .long 0x00000000,0x00000000
+ .align 4
+.Lrdcdata:
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+.Lirb:
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+.Lcountarea:
+ .word 0x0000 # cyl;
+ .word 0x0000 # head;
+ .byte 0x00 # record;
+ .byte 0x00 # key length;
+ .word 0x0000 # data length == blocksize;
+.Ldedata:
+ .long 0x40c00000,0x00000000
+ .long 0x00000000,0x00000000
+.Llodata:
+ .long 0x06000001,0x00000000
+ .long 0x00000000,0x01000000
+ .long 0x12345678
+ .org 0x7c8
+.Lrdcccw: # CCW read device characteristics
+ .long 0x64400040,0x00000000+.Lrdcdata
+ .long 0x63400010,0x00000000+.Ldedata
+ .long 0x47400010,0x00000000+.Llodata
+ .long 0x12000008,0x00000000+.Lcountarea
+.Ldeccw:
+ .long 0x63400010,0x00000000+.Ldedata
+.Lloccw:
+ .long 0x47400010,0x00000000+.Llodata
+.Lrdccw:
+ .long 0x86400000,0x00000000
+ .org 0x800
+# end of pre initialized data is here CCWarea follows
+# from here we load 1k blocklist
+# end of function
+
diff --git a/arch/s390x/boot/iplfba.S b/arch/s390x/boot/iplfba.S
new file mode 100644
index 000000000..732a9848c
--- /dev/null
+++ b/arch/s390x/boot/iplfba.S
@@ -0,0 +1,131 @@
+#
+# Ipl block for fba devices
+# Copyright (C) 1998 IBM Corporation
+# Author(s): Martin Schwidefsky
+#
+# startup for ipl at address 0
+# start with restart
+
+# The first 24 byes are loaded by ipl to addresses 0-23 (a PSW and two CCWs).
+# The CCWs on 8-23 are used as a continuation of the implicit ipl channel
+# program. The fba ipl loader only uses the CCW on 8-15 to load the first 512
+# byte block to location 0-511 (the reading starts again at block 0, byte 0).
+# The second CCW is used to store the location of the load list.
+ .org 0
+ .long 0x00080000,0x80000000+_start # The first 24 byte are loaded
+ .long 0x02000000,0x20000200 # by ipl to addresses 0-23.
+ .long 0x00000001,0x00000001 # (PSW, one CCW & loadlist info).
+
+ .globl _start
+_start:
+ basr %r13,0
+.LPG0:
+ l %r1,0xb8 # load ipl subchannel number
+ lhi %r2,0x200 # location for the loadlist
+ lm %r3,%r4,0x10 # blocknr and length of loadlist
+ bras %r14,.Lloader # load loadlist
+
+ lhi %r11,0x400
+ lhi %r12,0x200 # load address of loadlist
+ l %r3,0(%r12) # get first block number
+ l %r4,4(%r12) # get first block count
+ la %r12,8(%r12)
+ j .Llistloop
+ .org 0x50
+.Llistloop:
+ lr %r2,%r11 # load address
+ lr %r5,%r4 # block count
+ mhi %r5,512
+ la %r11,0(%r5,%r11) # update load address
+ bras %r14,.Lloader # load chunk of the image
+ l %r3,0(%r12) # get next block number
+ icm %r4,15,4(%r12) # get next block count
+ la %r12,8(%r12)
+ jnz .Llistloop
+
+#
+# everything loaded, go for it
+#
+ l %r1,.Lstart-.LPG0(%r13)
+ br %r1
+
+#
+# subroutine for loading a sequence of block from fba
+# %r2: load address (24 bit address)
+# %r3: number of first block (unsigned long)
+# %r4: number of blocks to load (unsigned short)
+#
+ .org 0xC0
+.Lloader:
+ la %r5,.Llo-.LPG0(%r13)
+ sth %r4,2(%r5) # initialize block count
+ st %r3,4(%r5) # initialize block number
+ la %r5,.Lccws-.LPG0(%r13)
+ mhi %r4,512
+ sth %r4,22(%r5) # initialize byte count
+ icm %r2,8,16(%r5)
+ st %r2,16(%r5) # initialize CCW data address
+
+ slr %r2,%r2
+ la %r3,.Lorb-.LPG0(%r13) # r2 = address of orb into r2
+ la %r4,.Ltinfo-.LPG0(%r13) # r3 = address of tpi info block
+ la %r5,.Lirb-.LPG0(%r13) # r4 = address of irb
+
+ lctl %c6,%c6,.Lc6-.LPG0(%r13)
+.Lldlp:
+ ssch 0(%r3) # read blocks
+.Ltpi:
+ tpi 0(%r4) # test pending interrupt
+ jz .Ltpi
+ c %r1,0(%r4) # compare subchannel number
+ jne .Ltpi
+ tsch 0(%r5)
+ slr %r0,%r0
+ tm 8(%r5),0x82 # do we have a problem ?
+ jnz .Ldwpsw
+ tm 8(%r5),0x04 # got device end ?
+ jz .Ltpi
+.Lexit:
+ br %r14
+
+ .align 8
+.Ldwpsw:.long 0x000a0000,0x00000000
+.Lorb: .long 0x00000000,0x0000ff00,.Lccws
+.Ltinfo:.long 0
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lc6: .long 0xff000000
+.Lloadp:.long 0,0
+.Lparm: .long 0x10400
+.Lstart:.long 0x10000
+ .align 8
+.Lccws: .long 0x63000000+.Lde,0x60000010 # define extent
+ .long 0x43000000+.Llo,0x60000008 # locate
+# offset 1 in read CCW: data address (24 bit)
+# offset 6 in read CCW: number of bytes (16 bit)
+ .long 0x42000000,0x20000000 # read
+.Lde: .long 0x40000200,0x00000000
+ .long 0x00000000,0x00001000
+# offset 2 in .Llo: block count (unsigned short)
+# offset 4 in .Llo: block number (unsigned long)
+.Llo: .long 0x06000000,0x00000000
+
+ .org 0x200
+ .long 0x00000002,0x0000007f
+ .long 0x00000081,0x0000007f
+ .long 0x00000100,0x0000007f
+ .long 0x0000017f,0x0000007f
+ .long 0x000001fe,0x0000007f
+ .long 0x0000027d,0x0000007f
+ .long 0x000002fc,0x0000007f
+ .long 0x0000037b,0x0000007f
+ .long 0x000003fa,0x0000007f
+ .long 0x00000479,0x0000007f
+ .long 0x000004f8,0x0000007f
+ .long 0x00000577,0x0000007f
+ .long 0x000005f6,0x0000007f
+ .long 0x00000675,0x0000007f
+ .long 0x000006f4,0x0000007f
+ .long 0x00000773,0x0000003f
+ .long 0x00000000,0x00000000
+ .org 0x400
+
diff --git a/arch/s390x/config.in b/arch/s390x/config.in
new file mode 100644
index 000000000..a94f4b7ba
--- /dev/null
+++ b/arch/s390x/config.in
@@ -0,0 +1,73 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/config-language.txt.
+#
+
+define_bool CONFIG_ISA n
+define_bool CONFIG_EISA n
+define_bool CONFIG_MCA n
+
+mainmenu_name "Linux Kernel Configuration"
+define_bool CONFIG_ARCH_S390 y
+define_bool CONFIG_ARCH_S390X y
+
+mainmenu_option next_comment
+comment 'Code maturity level options'
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+endmenu
+
+mainmenu_option next_comment
+comment 'Processor type and features'
+bool 'Symmetric multi-processing support' CONFIG_SMP
+bool 'Kernel support for 31 bit emulation' CONFIG_S390_SUPPORT
+if [ "$CONFIG_S390_SUPPORT" = "y" ]; then
+ tristate 'Kernel support for 31 bit ELF binaries' CONFIG_BINFMT_ELF32
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+ bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+ bool 'Kernel module loader' CONFIG_KMOD
+fi
+endmenu
+
+mainmenu_option next_comment
+comment 'General setup'
+bool 'Fast IRQ handling' CONFIG_FAST_IRQ
+bool 'Builtin IPL record support' CONFIG_IPL
+if [ "$CONFIG_IPL" = "y" ]; then
+ choice 'IPL method generated into head.S' \
+ "tape CONFIG_IPL_TAPE \
+ vm_reader CONFIG_IPL_VM" tape
+fi
+bool 'Networking support' CONFIG_NET
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
+define CONFIG_KCORE ELF
+tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
+endmenu
+
+source drivers/s390/Config.in
+
+if [ "$CONFIG_NET" = "y" ]; then
+ source net/Config.in
+fi
+
+source fs/Config.in
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
+if [ "$CONFIG_CTC" = "y" ]; then
+ bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
+fi
+# this does not work. bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+endmenu
+
diff --git a/arch/s390x/defconfig b/arch/s390x/defconfig
new file mode 100644
index 000000000..391f42823
--- /dev/null
+++ b/arch/s390x/defconfig
@@ -0,0 +1,219 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+CONFIG_ARCH_S390=y
+CONFIG_ARCH_S390X=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Processor type and features
+#
+CONFIG_SMP=y
+CONFIG_S390_SUPPORT=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+CONFIG_FAST_IRQ=y
+CONFIG_IPL=y
+# CONFIG_IPL_TAPE is not set
+CONFIG_IPL_VM=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PROCESS_DEBUG is not set
+
+#
+# Block device drivers
+#
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=24576
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_XPRAM=m
+CONFIG_DASD=y
+CONFIG_DASD_ECKD=y
+CONFIG_DASD_FBA=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+# CONFIG_MD_LINEAR is not set
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_BLK_DEV_LVM=m
+CONFIG_LVM_PROC_FS=y
+
+#
+# Character device drivers
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_3215=y
+CONFIG_3215_CONSOLE=y
+CONFIG_HWC=y
+CONFIG_HWC_CONSOLE=y
+CONFIG_S390_TAPE=m
+CONFIG_S390_TAPE_CHAR=y
+CONFIG_S390_TAPE_BLOCK=y
+CONFIG_S390_TAPE_3490=y
+CONFIG_S390_TAPE_3480=y
+
+#
+# Network device drivers
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_TR=y
+# CONFIG_FDDI is not set
+# CONFIG_CHANDEV is not set
+CONFIG_CTC=m
+CONFIG_IUCV=m
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK=y
+# CONFIG_RTNETLINK is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_IBM_PARTITION=y
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
diff --git a/arch/s390x/kernel/Makefile b/arch/s390x/kernel/Makefile
new file mode 100644
index 000000000..21f353f67
--- /dev/null
+++ b/arch/s390x/kernel/Makefile
@@ -0,0 +1,38 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+
+all: kernel.o head.o init_task.o
+
+O_TARGET := kernel.o
+
+export-objs := s390_ksyms.o
+obj-y := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
+ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
+ semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
+
+obj-$(CONFIG_MODULES) += s390_ksyms.o
+obj-$(CONFIG_SMP) += smp.o
+
+#
+# Kernel debugging
+#
+obj-$(CONFIG_REMOTE_DEBUG) += gdb-stub.o #gdb-low.o
+
+obj-$(CONFIG_S390_SUPPORT) += linux32.o signal32.o ioctl32.o wrapper32.o exec32.o
+obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
+
+#
+# This is just to get the dependencies...
+#
+binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/s390x/kernel/binfmt_elf32.c b/arch/s390x/kernel/binfmt_elf32.c
new file mode 100644
index 000000000..b08f0f686
--- /dev/null
+++ b/arch/s390x/kernel/binfmt_elf32.c
@@ -0,0 +1,203 @@
+/*
+ * Support for 32-bit Linux for S390 ELF binaries.
+ *
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Gerhard Tonn (ton@de.ibm.com)
+ *
+ * Heavily inspired by the 32-bit Sparc compat code which is
+ * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+
+#define __ASMS390_ELF_H
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_S390
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) \
+ ((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS)
+
+/* ELF register definitions */
+#define NUM_GPRS 16
+#define NUM_FPRS 16
+#define NUM_ACRS 16
+
+#define TASK31_SIZE (0x80000000UL)
+
+/* For SVR4/S390 the function pointer to be registered with `atexit` is
+ passed in R14. */
+#define ELF_PLAT_INIT(_r) \
+ do { \
+ _r->gprs[14] = 0; \
+ current->thread.flags |= S390_FLAG_31BIT; \
+ } while(0)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ use of this is to invoke "./ld.so someprog" to test out a new version of
+ the loader. We need to make sure that it is out of the way of the program
+ that it will "exec", and that there is sufficient room for the brk. */
+
+#define ELF_ET_DYN_BASE ((TASK31_SIZE & 0x80000000) \
+ ? TASK31_SIZE / 3 * 2 \
+ : 2 * TASK31_SIZE / 3)
+
+/* Wow, the "main" arch needs arch dependent functions too.. :) */
+
+/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
+ now struct_user_regs, they are different) */
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs) \
+ { \
+ int i; \
+ memcpy(&pr_reg.psw.mask, &regs->psw.mask, 4); \
+ memcpy(&pr_reg.psw.addr, ((char*)&regs->psw.addr)+4, 4); \
+ for(i=0; i<NUM_GPRS; i++) \
+ pr_reg.gprs[i] = regs->gprs[i]; \
+ for(i=0; i<NUM_ACRS; i++) \
+ pr_reg.acrs[i] = regs->acrs[i]; \
+ pr_reg.orig_gpr2 = regs->orig_gpr2; \
+ }
+
+
+
+/* This yields a mask that user programs can use to figure out what
+ instruction set this CPU supports. */
+
+#define ELF_HWCAP (0)
+
+/* This yields a string that ld.so will use to load implementation
+ specific libraries for optimization. This is more specific in
+ intent than poking at uname or /proc/cpuinfo.
+
+ For the moment, we have only optimizations for the Intel generations,
+ but that could change... */
+
+#define ELF_PLATFORM (NULL)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+#endif
+
+#include "linux32.h"
+
+typedef _s390_fp_regs32 elf_fpregset_t;
+
+typedef struct
+{
+
+ _psw_t32 psw;
+ __u32 gprs[__NUM_GPRS];
+ __u32 acrs[__NUM_ACRS];
+ __u32 orig_gpr2;
+} s390_regs32;
+typedef s390_regs32 elf_gregset_t;
+
+#include <asm/processor.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/elfcore.h>
+
+int setup_arg_pages32(struct linux_binprm *bprm);
+
+struct timeval32
+{
+ int tv_sec, tv_usec;
+};
+
+#define elf_prstatus elf_prstatus32
+struct elf_prstatus32
+{
+ struct elf_siginfo pr_info; /* Info associated with signal */
+ short pr_cursig; /* Current signal */
+ u32 pr_sigpend; /* Set of pending signals */
+ u32 pr_sighold; /* Set of held signals */
+ pid_t pr_pid;
+ pid_t pr_ppid;
+ pid_t pr_pgrp;
+ pid_t pr_sid;
+ struct timeval32 pr_utime; /* User time */
+ struct timeval32 pr_stime; /* System time */
+ struct timeval32 pr_cutime; /* Cumulative user time */
+ struct timeval32 pr_cstime; /* Cumulative system time */
+ elf_gregset_t pr_reg; /* GP registers */
+ int pr_fpvalid; /* True if math co-processor being used. */
+};
+
+#define elf_prpsinfo elf_prpsinfo32
+struct elf_prpsinfo32
+{
+ char pr_state; /* numeric process state */
+ char pr_sname; /* char for pr_state */
+ char pr_zomb; /* zombie */
+ char pr_nice; /* nice val */
+ u32 pr_flag; /* flags */
+ u16 pr_uid;
+ u16 pr_gid;
+ pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
+ /* Lots missing */
+ char pr_fname[16]; /* filename of executable */
+ char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+#include <linux/highuid.h>
+
+#undef NEW_TO_OLD_UID
+#undef NEW_TO_OLD_GID
+#define NEW_TO_OLD_UID(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
+#define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
+
+#define elf_addr_t u32
+#define elf_caddr_t u32
+/*
+#define init_elf_binfmt init_elf32_binfmt
+*/
+#undef CONFIG_BINFMT_ELF
+#ifdef CONFIG_BINFMT_ELF32
+#define CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF32
+#endif
+#undef CONFIG_BINFMT_ELF_MODULE
+#ifdef CONFIG_BINFMT_ELF32_MODULE
+#define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE
+#endif
+
+#undef start_thread
+#define start_thread start_thread31
+#define setup_arg_pages(bprm) setup_arg_pages32(bprm)
+#define elf_map elf_map32
+
+MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries,"
+ " Copyright 2000 IBM Corporation");
+MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
+
+#undef MODULE_DESCRIPTION
+#undef MODULE_AUTHOR
+
+#include "../../../fs/binfmt_elf.c"
+
+static unsigned long
+elf_map32 (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
+{
+ unsigned long map_addr;
+
+ if(!addr)
+ addr = 0x40000000;
+
+ down(&current->mm->mmap_sem);
+ map_addr = do_mmap(filep, ELF_PAGESTART(addr),
+ eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type,
+ eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
+ up(&current->mm->mmap_sem);
+ return(map_addr);
+}
+
diff --git a/arch/s390x/kernel/bitmap.S b/arch/s390x/kernel/bitmap.S
new file mode 100644
index 000000000..a212ba450
--- /dev/null
+++ b/arch/s390x/kernel/bitmap.S
@@ -0,0 +1,37 @@
+/*
+ * arch/s390/kernel/bitmap.S
+ * Bitmaps for set_bit, clear_bit, test_and_set_bit, ...
+ * See include/asm-s390/{bitops.h|posix_types.h} for details
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+ .globl _oi_bitmap
+_oi_bitmap:
+ .byte 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
+
+ .globl _ni_bitmap
+_ni_bitmap:
+ .byte 0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F
+
+ .globl _zb_findmap
+_zb_findmap:
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
+ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8
+
diff --git a/arch/s390x/kernel/cpcmd.c b/arch/s390x/kernel/cpcmd.c
new file mode 100644
index 000000000..7329b9b6c
--- /dev/null
+++ b/arch/s390x/kernel/cpcmd.c
@@ -0,0 +1,49 @@
+/*
+ * arch/s390/kernel/cpcmd.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/ebcdic.h>
+
+void cpcmd(char *cmd, char *response, int rlen)
+{
+ const int mask = 0x40000000L;
+ char obuffer[128];
+ int olen;
+
+ olen = strlen(cmd);
+ strcpy(obuffer, cmd);
+ ASCEBC(obuffer,olen);
+
+ if (response != NULL && rlen > 0) {
+ asm volatile (" lrag 2,0(%0)\n"
+ " lgr 4,%1\n"
+ " o 4,%4\n"
+ " lrag 3,0(%2)\n"
+ " lgr 5,%3\n"
+ " sam31\n"
+ " .long 0x83240008 # Diagnose 83\n"
+ " sam64"
+ : /* no output */
+ : "a" (obuffer), "d" (olen),
+ "a" (response), "d" (rlen), "m" (mask)
+ : "2", "3", "4", "5" );
+ EBCASC(response, rlen);
+ } else {
+ asm volatile (" lrag 2,0(%0)\n"
+ " lgr 3,%1\n"
+ " sam31\n"
+ " .long 0x83230008 # Diagnose 83\n"
+ " sam64"
+ : /* no output */
+ : "a" (obuffer), "d" (olen)
+ : "2", "3" );
+ }
+}
+
diff --git a/arch/s390x/kernel/cpcmd.h b/arch/s390x/kernel/cpcmd.h
new file mode 100644
index 000000000..38b88d9ea
--- /dev/null
+++ b/arch/s390x/kernel/cpcmd.h
@@ -0,0 +1,14 @@
+/*
+ * arch/s390/kernel/cpcmd.h
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#ifndef __CPCMD__
+#define __CPCMD__
+
+extern void cpcmd(char *cmd, char *response, int rlen);
+
+#endif
diff --git a/arch/s390x/kernel/cpprintk.c b/arch/s390x/kernel/cpprintk.c
new file mode 100644
index 000000000..aa6d3b41e
--- /dev/null
+++ b/arch/s390x/kernel/cpprintk.c
@@ -0,0 +1,25 @@
+#include "cpcmd.h"
+#include <linux/mm.h>
+#include <linux/tty_driver.h>
+#include <linux/smp_lock.h>
+#include <linux/console.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+
+static char buf[1024];
+
+asmlinkage int s390printk(const char *fmt, ...)
+{
+ va_list args;
+ int i;
+ unsigned long flags;
+ spin_lock_irqsave(&console_lock, flags);
+ va_start(args, fmt);
+ i = vsprintf(&buf[0],"MSG * ",args);
+ i = vsprintf(&buf[i], fmt, args);
+ va_end(args);
+ cpcmd(buf,0,0);
+ spin_unlock_irqrestore(&console_lock, flags);
+ return i;
+}
diff --git a/arch/s390x/kernel/debug.c b/arch/s390x/kernel/debug.c
new file mode 100644
index 000000000..bb3dfe5de
--- /dev/null
+++ b/arch/s390x/kernel/debug.c
@@ -0,0 +1,1167 @@
+/*
+ * arch/s390/kernel/debug.c
+ * S/390 debug facility
+ *
+ * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
+ * IBM Corporation
+ * Author(s): Michael Holzheu (holzheu@de.ibm.com),
+ * Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ *
+ * Bugreports to: <Linux390@de.ibm.com>
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <asm/debug.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#if defined(CONFIG_ARCH_S390X)
+#define DEBUG_PROC_HEADER_SIZE 46
+#else
+#define DEBUG_PROC_HEADER_SIZE 38
+#endif
+
+#define ADD_BUFFER 1000
+
+/* typedefs */
+
+typedef struct file_private_info {
+ loff_t len; /* length of output in byte */
+ int size; /* size of buffer for output */
+ char *data; /* buffer for output */
+ debug_info_t *debug_info; /* the debug information struct */
+ struct debug_view *view; /* used view of debug info */
+} file_private_info_t;
+
+extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
+
+/* internal function prototyes */
+
+static int debug_init(void);
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+ int size, struct debug_view *view);
+static ssize_t debug_output(struct file *file, char *user_buf,
+ size_t user_len, loff_t * offset);
+static ssize_t debug_input(struct file *file, const char *user_buf,
+ size_t user_len, loff_t * offset);
+static int debug_open(struct inode *inode, struct file *file);
+static int debug_close(struct inode *inode, struct file *file);
+static struct proc_dir_entry
+*debug_create_proc_dir_entry(struct proc_dir_entry *root,
+ const char *name, mode_t mode,
+ struct inode_operations *iops,
+ struct file_operations *fops);
+static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
+ struct proc_dir_entry *entry);
+static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
+static void debug_info_get(debug_info_t *);
+static void debug_info_put(debug_info_t *);
+static int debug_prolog_level_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf);
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char *user_buf,
+ size_t user_buf_size, loff_t * offset);
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf);
+static int debug_raw_format_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf,
+ const char *in_buf);
+static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf);
+
+/* globals */
+
+struct debug_view debug_raw_view = {
+ "raw",
+ NULL,
+ &debug_raw_header_fn,
+ &debug_raw_format_fn,
+ NULL
+};
+
+struct debug_view debug_hex_ascii_view = {
+ "hex_ascii",
+ NULL,
+ &debug_dflt_header_fn,
+ &debug_hex_ascii_format_fn,
+ NULL
+};
+
+struct debug_view debug_level_view = {
+ "level",
+ &debug_prolog_level_fn,
+ NULL,
+ NULL,
+ &debug_input_level_fn
+};
+
+/* static globals */
+
+static debug_info_t *debug_area_first = NULL;
+static debug_info_t *debug_area_last = NULL;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+static struct semaphore debug_lock = MUTEX;
+#else
+DECLARE_MUTEX(debug_lock);
+#endif
+
+static int initialized = 0;
+
+static struct file_operations debug_file_ops = {
+ read: debug_output,
+ write: debug_input,
+ open: debug_open,
+ release: debug_close,
+};
+
+static struct inode_operations debug_inode_ops = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ default_file_ops: &debug_file_ops, /* file ops */
+#endif
+};
+
+
+static struct proc_dir_entry *debug_proc_root_entry;
+
+
+/* functions */
+
+/*
+ * debug_info_create
+ * - create new debug-info
+ */
+
+static debug_info_t* debug_info_create(char *name, int page_order,
+ int nr_areas, int buf_size)
+{
+ debug_info_t* rc;
+ int i;
+
+ /* alloc everything */
+
+ rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
+ if(!rc)
+ goto fail_malloc_rc;
+ rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC);
+ if(!rc->active_entry)
+ goto fail_malloc_active_entry;
+ memset(rc->active_entry, 0, nr_areas * sizeof(int));
+ rc->areas = (debug_entry_t **) kmalloc(nr_areas *
+ sizeof(debug_entry_t *),
+ GFP_ATOMIC);
+ if (!rc->areas)
+ goto fail_malloc_areas;
+ for (i = 0; i < nr_areas; i++) {
+ rc->areas[i] =
+ (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
+ page_order);
+ if (!rc->areas[i]) {
+ for (i--; i >= 0; i--) {
+ free_pages((unsigned long) rc->areas[i],
+ page_order);
+ }
+ goto fail_malloc_areas2;
+ } else {
+ memset(rc->areas[i], 0, PAGE_SIZE << page_order);
+ }
+ }
+
+ /* initialize members */
+
+ spin_lock_init(&rc->lock);
+ rc->page_order = page_order;
+ rc->nr_areas = nr_areas;
+ rc->active_area = 0;
+ rc->level = DEBUG_DEFAULT_LEVEL;
+ rc->buf_size = buf_size;
+ rc->entry_size = sizeof(debug_entry_t) + buf_size;
+ strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
+ rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
+ memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+ memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
+ sizeof(struct proc_dir_entry*));
+ atomic_set(&(rc->ref_count), 0);
+ rc->proc_root_entry =
+ debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
+ S_IFDIR | S_IRUGO | S_IXUGO |
+ S_IWUSR | S_IWGRP, NULL, NULL);
+
+ /* append new element to linked list */
+
+ if(debug_area_first == NULL){
+ /* first element in list */
+ debug_area_first = rc;
+ rc->prev = NULL;
+ }
+ else{
+ /* append element to end of list */
+ debug_area_last->next = rc;
+ rc->prev = debug_area_last;
+ }
+ debug_area_last = rc;
+ rc->next = NULL;
+
+ debug_info_get(rc);
+ return rc;
+
+fail_malloc_areas2:
+ kfree(rc->areas);
+fail_malloc_areas:
+ kfree(rc->active_entry);
+fail_malloc_active_entry:
+ kfree(rc);
+fail_malloc_rc:
+ return NULL;
+}
+
+/*
+ * debug_info_get
+ * - increments reference count for debug-info
+ */
+
+static void debug_info_get(debug_info_t * db_info)
+{
+ if (db_info)
+ atomic_inc(&db_info->ref_count);
+}
+
+/*
+ * debug_info_put:
+ * - decreases reference count for debug-info and frees it if necessary
+ */
+
+static void debug_info_put(debug_info_t *db_info)
+{
+ int i;
+
+ if (!db_info)
+ return;
+ if (atomic_dec_and_test(&db_info->ref_count)) {
+ printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
+ db_info, db_info->name);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (db_info->views[i] != NULL)
+ debug_delete_proc_dir_entry
+ (db_info->proc_root_entry,
+ db_info->proc_entries[i]);
+ }
+ debug_delete_proc_dir_entry(debug_proc_root_entry,
+ db_info->proc_root_entry);
+ for (i = 0; i < db_info->nr_areas; i++) {
+ free_pages((unsigned long) db_info->areas[i],
+ db_info->page_order);
+ }
+ kfree(db_info->areas);
+ kfree(db_info->active_entry);
+ if(db_info == debug_area_first)
+ debug_area_first = db_info->next;
+ if(db_info == debug_area_last)
+ debug_area_last = db_info->prev;
+ if(db_info->prev) db_info->prev->next = db_info->next;
+ if(db_info->next) db_info->next->prev = db_info->prev;
+ kfree(db_info);
+ }
+}
+
+
+/*
+ * debug_output:
+ * - called for user read()
+ * - copies formated output form private_data of the file
+ * handle to the user buffer
+ */
+
+static ssize_t debug_output(struct file *file, /* file descriptor */
+ char *user_buf, /* user buffer */
+ size_t user_len, /* length of buffer */
+ loff_t *offset /* offset in the file */ )
+{
+ loff_t len;
+ int rc;
+ file_private_info_t *p_info;
+
+ p_info = ((file_private_info_t *) file->private_data);
+ if (*offset >= p_info->len) {
+ return 0; /* EOF */
+ } else {
+ len = MIN(user_len, (p_info->len - *offset));
+ if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len)))
+ return rc;;
+ (*offset) += len;
+ return len; /* number of bytes "read" */
+ }
+}
+
+/*
+ * debug_input:
+ * - called for user write()
+ * - calls input function of view
+ */
+
+static ssize_t debug_input(struct file *file,
+ const char *user_buf, size_t length,
+ loff_t *offset)
+{
+ int rc = 0;
+ file_private_info_t *p_info;
+
+ down(&debug_lock);
+ p_info = ((file_private_info_t *) file->private_data);
+ if (p_info->view->input_proc)
+ rc = p_info->view->input_proc(p_info->debug_info,
+ p_info->view, file, user_buf,
+ length, offset);
+ up(&debug_lock);
+ return rc; /* number of input characters */
+}
+
+/*
+ * debug_format_output:
+ * - calls prolog, header and format functions of view to format output
+ */
+
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+ int size, struct debug_view *view)
+{
+ int len = 0;
+ int i, j;
+ int nr_of_entries;
+ debug_entry_t *act_entry;
+
+ /* print prolog */
+ if (view->prolog_proc)
+ len += view->prolog_proc(debug_area, view, buf);
+ /* print debug records */
+ if (!(view->format_proc) && !(view->header_proc))
+ goto out;
+ nr_of_entries = PAGE_SIZE / debug_area->entry_size
+ << debug_area->page_order;
+ for (i = 0; i < debug_area->nr_areas; i++) {
+ act_entry = debug_area->areas[i];
+ for (j = 0; j < nr_of_entries; j++) {
+ if (act_entry->id.fields.used == 0)
+ break; /* empty entry */
+ if (view->header_proc)
+ len += view->header_proc(debug_area, view, i,
+ act_entry, buf + len);
+ if (view->format_proc)
+ len += view->format_proc(debug_area, view,
+ buf + len,
+ DEBUG_DATA(act_entry));
+ if (len > size) {
+ printk(KERN_ERR
+ "debug: error -- memory exceeded for (%s/%s)\n",
+ debug_area->name, view->name);
+ printk(KERN_ERR "debug: fix view %s!!\n",
+ view->name);
+ printk(KERN_ERR
+ "debug: area: %i (0 - %i) entry: %i (0 - %i)\n",
+ i, debug_area->nr_areas - 1, j,
+ nr_of_entries - 1);
+ goto out;
+ }
+ act_entry = (debug_entry_t *) (((char *) act_entry) +
+ debug_area->entry_size);
+ }
+ }
+ out:
+ return len;
+}
+
+
+/*
+ * debug_open:
+ * - called for user open()
+ * - copies formated output to private_data area of the file
+ * handle
+ */
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ int i = 0, size = 0, rc = 0, f_entry_size = 0;
+ file_private_info_t *p_info;
+ debug_info_t* debug_info;
+
+#ifdef DEBUG
+ printk("debug_open\n");
+#endif
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ down(&debug_lock);
+
+ /* find debug log and view */
+
+ debug_info = debug_area_first;
+ while(debug_info != NULL){
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (debug_info->views[i] == NULL)
+ continue;
+ else if (debug_info->proc_entries[i]->low_ino ==
+ file->f_dentry->d_inode->i_ino) {
+ goto found; /* found view ! */
+ }
+ }
+ debug_info = debug_info->next;
+ }
+ /* no entry found */
+ rc = -EINVAL;
+ goto out;
+ found:
+ if ((file->private_data =
+ kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
+ printk(KERN_ERR "debug_open: kmalloc failed\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ p_info = (file_private_info_t *) file->private_data;
+
+ /*
+ * the size for the formated output is calculated
+ * with the following formula:
+ *
+ * prolog-size
+ * +
+ * (record header size + record data field size)
+ * * number of entries per page
+ * * number of pages per area
+ * * number of areas
+ */
+
+ if (debug_info->views[i]->prolog_proc)
+ size +=
+ debug_info->views[i]->prolog_proc(debug_info,
+ debug_info->
+ views[i], NULL);
+
+ if (debug_info->views[i]->header_proc)
+ f_entry_size =
+ debug_info->views[i]->header_proc(debug_info,
+ debug_info->
+ views[i], 0, NULL,
+ NULL);
+ if (debug_info->views[i]->format_proc)
+ f_entry_size +=
+ debug_info->views[i]->format_proc(debug_info,
+ debug_info->
+ views[i], NULL,
+ NULL);
+
+ size += f_entry_size
+ * (PAGE_SIZE / debug_info->entry_size
+ << debug_info->page_order)
+ * debug_info->nr_areas + 1; /* terminating \0 */
+#ifdef DEBUG
+ printk("debug_open: size: %i\n", size);
+#endif
+
+ /* alloc some bytes more to be safe against bad views */
+ if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) {
+ printk(KERN_ERR "debug_open: vmalloc failed\n");
+ vfree(file->private_data);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ p_info->size = size;
+ p_info->debug_info = debug_info;
+ p_info->view = debug_info->views[i];
+
+ spin_lock_irq(&debug_info->lock);
+
+ p_info->len =
+ debug_format_output(debug_info, p_info->data, size,
+ debug_info->views[i]);
+#ifdef DEBUG
+ {
+ int ilen = p_info->len;
+ printk("debug_open: len: %i\n", ilen);
+ }
+#endif
+
+ spin_unlock_irq(&debug_info->lock);
+ debug_info_get(debug_info);
+
+ out:
+ up(&debug_lock);
+#ifdef MODULE
+ if (rc != 0)
+ MOD_DEC_USE_COUNT;
+#endif
+ return rc;
+}
+
+/*
+ * debug_close:
+ * - called for user close()
+ * - deletes private_data area of the file handle
+ */
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+ file_private_info_t *p_info;
+#ifdef DEBUG
+ printk("debug_close\n");
+#endif
+ down(&debug_lock);
+ p_info = (file_private_info_t *) file->private_data;
+ debug_info_put(p_info->debug_info);
+ if (p_info->data) {
+ vfree(p_info->data);
+ kfree(file->private_data);
+ }
+ up(&debug_lock);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0; /* success */
+}
+
+/*
+ * debug_create_proc_dir_entry:
+ * - initializes proc-dir-entry and registers it
+ */
+
+static struct proc_dir_entry *debug_create_proc_dir_entry
+ (struct proc_dir_entry *root, const char *name, mode_t mode,
+ struct inode_operations *iops, struct file_operations *fops)
+{
+ struct proc_dir_entry *rc = NULL;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ const char *fn = name;
+ int len;
+ len = strlen(fn);
+
+ rc = (struct proc_dir_entry *) kmalloc(sizeof(struct proc_dir_entry)
+ + len + 1, GFP_ATOMIC);
+ if (!rc)
+ goto out;
+
+ memset(rc, 0, sizeof(struct proc_dir_entry));
+ memcpy(((char *) rc) + sizeof(*rc), fn, len + 1);
+ rc->name = ((char *) rc) + sizeof(*rc);
+ rc->namelen = len;
+ rc->low_ino = 0, rc->mode = mode;
+ rc->nlink = 1;
+ rc->uid = 0;
+ rc->gid = 0;
+ rc->size = 0;
+ rc->get_info = NULL;
+ rc->ops = iops;
+
+ proc_register(root, rc);
+#else
+ rc = create_proc_entry(name, mode, root);
+ if (!rc)
+ goto out;
+ if (fops)
+ rc->proc_fops = fops;
+#endif
+
+ out:
+ return rc;
+}
+
+
+/*
+ * delete_proc_dir_entry:
+ */
+
+static void debug_delete_proc_dir_entry
+ (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry)
+{
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ proc_unregister(root, proc_entry->low_ino);
+ kfree(proc_entry);
+#else
+ remove_proc_entry(proc_entry->name, root);
+#endif
+}
+
+/*
+ * debug_register:
+ * - creates and initializes debug area for the caller
+ * - returns handle for debug area
+ */
+
+debug_info_t *debug_register
+ (char *name, int page_order, int nr_areas, int buf_size)
+{
+ debug_info_t *rc = NULL;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ if (!initialized)
+ debug_init();
+ down(&debug_lock);
+
+ /* create new debug_info */
+
+ rc = debug_info_create(name, page_order, nr_areas, buf_size);
+ if(!rc)
+ goto out;
+ debug_register_view(rc, &debug_level_view);
+ printk(KERN_INFO
+ "debug: reserved %d areas of %d pages for debugging %s\n",
+ nr_areas, 1 << page_order, rc->name);
+ out:
+ if (rc == NULL){
+ printk(KERN_ERR "debug: debug_register failed for %s\n",name);
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ }
+ up(&debug_lock);
+ return rc;
+}
+
+/*
+ * debug_unregister:
+ * - give back debug area
+ */
+
+void debug_unregister(debug_info_t * id)
+{
+ if (!id)
+ goto out;
+ down(&debug_lock);
+ printk(KERN_INFO "debug: unregistering %s\n", id->name);
+ debug_info_put(id);
+ up(&debug_lock);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ out:
+ return;
+}
+
+/*
+ * debug_set_level:
+ * - set actual debug level
+ */
+
+void debug_set_level(debug_info_t* id, int new_level)
+{
+ long flags;
+ if(!id)
+ return;
+ spin_lock_irqsave(&id->lock,flags);
+ if(new_level == DEBUG_OFF_LEVEL){
+ id->level = DEBUG_OFF_LEVEL;
+ printk(KERN_INFO "debug: %s: switched off\n",id->name);
+ } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
+ printk(KERN_INFO
+ "debug: %s: level %i is out of range (%i - %i)\n",
+ id->name, new_level, 0, DEBUG_MAX_LEVEL);
+ } else {
+ id->level = new_level;
+ printk(KERN_INFO
+ "debug: %s: new level %i\n",id->name,id->level);
+ }
+ spin_unlock_irqrestore(&id->lock,flags);
+}
+
+
+/*
+ * proceed_active_entry:
+ * - set active entry to next in the ring buffer
+ */
+
+static inline void proceed_active_entry(debug_info_t * id)
+{
+ if ((id->active_entry[id->active_area] += id->entry_size)
+ > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
+ id->active_entry[id->active_area] = 0;
+}
+
+/*
+ * proceed_active_area:
+ * - set active area to next in the ring buffer
+ */
+
+static inline void proceed_active_area(debug_info_t * id)
+{
+ id->active_area++;
+ id->active_area = id->active_area % id->nr_areas;
+}
+
+/*
+ * get_active_entry:
+ */
+
+static inline debug_entry_t *get_active_entry(debug_info_t * id)
+{
+ return (debug_entry_t *) ((char *) id->areas[id->active_area] +
+ id->active_entry[id->active_area]);
+}
+
+/*
+ * debug_common:
+ * - set timestamp, caller address, cpu number etc.
+ */
+
+static inline debug_entry_t *debug_common(debug_info_t * id)
+{
+ debug_entry_t *active;
+
+ active = get_active_entry(id);
+ STCK(active->id.stck);
+ active->id.fields.cpuid = smp_processor_id();
+ active->id.fields.used = 1;
+ active->caller = __builtin_return_address(0);
+ return active;
+}
+
+/*
+ * debug_event:
+ */
+
+debug_entry_t *debug_event(debug_info_t * id, int level, void *buf,
+ int len)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 0;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size));
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_int_event:
+ */
+
+debug_entry_t *debug_int_event(debug_info_t * id, int level,
+ unsigned int tag)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 0;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), &tag, MIN(sizeof(unsigned int), id->buf_size));
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_text_event:
+ */
+
+debug_entry_t *debug_text_event(debug_info_t * id, int level,
+ const char *txt)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size));
+ active->id.fields.exception = 0;
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+
+}
+
+/*
+ * debug_exception:
+ */
+
+debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf,
+ int len)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 1;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size));
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_int_exception:
+ */
+
+debug_entry_t *debug_int_exception(debug_info_t * id, int level,
+ unsigned int tag)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 1;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), &tag,
+ MIN(sizeof(unsigned int), id->buf_size));
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_text_exception:
+ */
+
+debug_entry_t *debug_text_exception(debug_info_t * id, int level,
+ const char *txt)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size));
+ active->id.fields.exception = 1;
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+
+}
+
+/*
+ * debug_init:
+ * - is called exactly once to initialize the debug feature
+ */
+
+int debug_init(void)
+{
+ int rc = 0;
+
+ down(&debug_lock);
+ if (!initialized) {
+ debug_proc_root_entry =
+ debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT,
+ S_IFDIR | S_IRUGO | S_IXUGO
+ | S_IWUSR | S_IWGRP, NULL,
+ NULL);
+ printk(KERN_INFO "debug: Initialization complete\n");
+ initialized = 1;
+ }
+ up(&debug_lock);
+
+ return rc;
+}
+
+/*
+ * debug_register_view:
+ */
+
+int debug_register_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ long flags;
+ mode_t mode = S_IFREG;
+
+ if (!id)
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (id->views[i] == NULL)
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS) {
+ printk(KERN_WARNING "debug: cannot register view %s/%s\n",
+ id->name,view->name);
+ printk(KERN_WARNING
+ "debug: maximum number of views reached (%i)!\n", i);
+ rc = -1;
+ }
+ else {
+ id->views[i] = view;
+ if (view->prolog_proc || view->format_proc || view->header_proc)
+ mode |= S_IRUSR;
+ if (view->input_proc)
+ mode |= S_IWUSR;
+ id->proc_entries[i] =
+ debug_create_proc_dir_entry(id->proc_root_entry,
+ view->name, mode,
+ &debug_inode_ops,
+ &debug_file_ops);
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return rc;
+}
+
+/*
+ * debug_unregister_view:
+ */
+
+int debug_unregister_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ long flags;
+
+ if (!id)
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (id->views[i] == view)
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS)
+ rc = -1;
+ else {
+ debug_delete_proc_dir_entry(id->proc_root_entry,
+ id->proc_entries[i]);
+ id->views[i] = NULL;
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return rc;
+}
+
+/*
+ * functions for debug-views
+ ***********************************
+*/
+
+/*
+ * prints out actual debug level
+ */
+
+static int debug_prolog_level_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf)
+{
+ int rc = 0;
+
+ if (out_buf == NULL) {
+ rc = 2;
+ goto out;
+ }
+ if(id->level == -1) rc = sprintf(out_buf,"-\n");
+ else rc = sprintf(out_buf, "%i\n", id->level);
+ out:
+ return rc;
+}
+
+/*
+ * reads new debug level
+ */
+
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char *user_buf,
+ size_t in_buf_size, loff_t * offset)
+{
+ char input_buf[1];
+ int rc = in_buf_size;
+
+ if (*offset != 0)
+ goto out;
+ if ((rc = copy_from_user(input_buf, user_buf, 1)))
+ goto out;
+ if (isdigit(input_buf[0])) {
+ int new_level = ((int) input_buf[0] - (int) '0');
+ debug_set_level(id, new_level);
+ } else if(input_buf[0] == '-') {
+ debug_set_level(id, DEBUG_OFF_LEVEL);
+ } else {
+ printk(KERN_INFO "debug: level `%c` is not valid\n",
+ input_buf[0]);
+ }
+ out:
+ *offset += in_buf_size;
+ return rc; /* number of input characters */
+}
+
+/*
+ * prints debug header in raw format
+ */
+
+int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
+{
+ int rc;
+
+ rc = sizeof(debug_entry_t);
+ if (out_buf == NULL)
+ goto out;
+ memcpy(out_buf,entry,sizeof(debug_entry_t));
+ out:
+ return rc;
+}
+
+/*
+ * prints debug data in raw format
+ */
+
+static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int rc;
+
+ rc = id->buf_size;
+ if (out_buf == NULL || in_buf == NULL)
+ goto out;
+ memcpy(out_buf, in_buf, id->buf_size);
+ out:
+ return rc;
+}
+
+/*
+ * prints debug data in hex/ascii format
+ */
+
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int i, rc = 0;
+
+ if (out_buf == NULL || in_buf == NULL) {
+ rc = id->buf_size * 4 + 3;
+ goto out;
+ }
+ for (i = 0; i < id->buf_size; i++) {
+ rc += sprintf(out_buf + rc, "%02x ",
+ ((unsigned char *) in_buf)[i]);
+ }
+ rc += sprintf(out_buf + rc, "| ");
+ for (i = 0; i < id->buf_size; i++) {
+ unsigned char c = in_buf[i];
+ if (!isprint(c))
+ rc += sprintf(out_buf + rc, ".");
+ else
+ rc += sprintf(out_buf + rc, "%c", c);
+ }
+ rc += sprintf(out_buf + rc, "\n");
+ out:
+ return rc;
+}
+
+/*
+ * prints header for debug entry
+ */
+
+int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
+{
+ struct timeval time_val;
+ unsigned long long time;
+ char *except_str;
+ unsigned long caller;
+ int rc = 0;
+
+ if (out_buf == NULL) {
+ rc = DEBUG_PROC_HEADER_SIZE;
+ goto out;
+ }
+
+ time = entry->id.stck;
+ /* adjust todclock to 1970 */
+ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
+ tod_to_timeval(time, &time_val);
+
+ if (entry->id.fields.exception)
+ except_str = "*";
+ else
+ except_str = "-";
+ caller = (unsigned long) entry->caller;
+#if defined(CONFIG_ARCH_S390X)
+ rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx ",
+ area, time_val.tv_sec,
+ time_val.tv_usec, except_str,
+ entry->id.fields.cpuid, caller);
+#else
+ caller &= 0x7fffffff;
+ rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ",
+ area, time_val.tv_sec,
+ time_val.tv_usec, except_str,
+ entry->id.fields.cpuid, caller);
+#endif
+ out:
+ return rc;
+}
+
+/*
+ * init_module:
+ */
+
+#ifdef MODULE
+int init_module(void)
+{
+ int rc = 0;
+#ifdef DEBUG
+ printk("debug_module_init: \n");
+#endif
+ rc = debug_init();
+ if (rc)
+ printk(KERN_INFO "debug: an error occurred with debug_init\n");
+ return rc;
+}
+
+/*
+ * cleanup_module:
+ */
+
+void cleanup_module(void)
+{
+#ifdef DEBUG
+ printk("debug_cleanup_module: \n");
+#endif
+ debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry);
+ return;
+}
+
+#endif /* MODULE */
diff --git a/arch/s390x/kernel/ebcdic.c b/arch/s390x/kernel/ebcdic.c
new file mode 100644
index 000000000..fc7740649
--- /dev/null
+++ b/arch/s390x/kernel/ebcdic.c
@@ -0,0 +1,391 @@
+/*
+ * arch/s390/kernel/ebcdic.c
+ * ECBDIC -> ASCII, ASCII -> ECBDIC,
+ * upper to lower case (EBCDIC) conversion tables.
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Martin Peschke <peschke@fh-brandenburg.de>
+ */
+
+#include <asm/types.h>
+
+/*
+ * ASCII (IBM PC 437) -> EBCDIC 037
+ */
+__u8 _ascebc[256] =
+{
+ /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ /* ->NL */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN EM SUB ESC FS GS RS US */
+ /* ->IGS ->IRS ->IUS */
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ /*80*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0 sz */
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+/*
+ * EBCDIC 037 -> ASCII (IBM PC 437)
+ */
+__u8 _ebcasc[256] =
+{
+ /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08 -GE -SPS -RPT VT FF CR SO SI */
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
+ -ENP ->LF */
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
+ -IUS */
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
+ -INP */
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
+ -SW */
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40 SP RSP ä ---- */
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48 . < ( + | */
+ 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+ /* 0x50 & ---- */
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58 ß ! $ * ) ; */
+ 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+ /* 0x60 - / ---- Ä ---- ---- ---- */
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68 ---- , % _ > ? */
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70 ---- ---- ---- ---- ---- ---- ---- */
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78 * ` : # @ ' = " */
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80 * a b c d e f g */
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88 h i ---- ---- ---- */
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90 ° j k l m n o p */
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98 q r ---- ---- */
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0 ~ s t u v w x */
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8 y z ---- ---- ---- ---- */
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0 ^ ---- § ---- */
+ 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8 ---- [ ] ---- ---- ---- ---- */
+ 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0 { A B C D E F G */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8 H I ---- ö ---- */
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0 } J K L M N O P */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8 Q R ---- ü */
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0 \ S T U V W X */
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8 Y Z ---- Ö ---- ---- ---- */
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0 0 1 2 3 4 5 6 7 */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+
+/*
+ * ASCII (IBM PC 437) -> EBCDIC 500
+ */
+__u8 _ascebc_500[256] =
+{
+ /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ /* ->NL */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN EM SUB ESC FS GS RS US */
+ /* ->IGS ->IRS ->IUS */
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x4F, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0x4A, 0xE0, 0x5A, 0x5F, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0xBB, 0xD0, 0xA1, 0x07,
+ /*80*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0 sz */
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+/*
+ * EBCDIC 500 -> ASCII (IBM PC 437)
+ */
+__u8 _ebcasc_500[256] =
+{
+ /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08 -GE -SPS -RPT VT FF CR SO SI */
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
+ -ENP ->LF */
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
+ -IUS */
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
+ -INP */
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
+ -SW */
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40 SP RSP ä ---- */
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48 [ . < ( + ! */
+ 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
+ /* 0x50 & ---- */
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58 ß ] $ * ) ; ^ */
+ 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
+ /* 0x60 - / ---- Ä ---- ---- ---- */
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68 ---- , % _ > ? */
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70 ---- ---- ---- ---- ---- ---- ---- */
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78 * ` : # @ ' = " */
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80 * a b c d e f g */
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88 h i ---- ---- ---- */
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90 ° j k l m n o p */
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98 q r ---- ---- */
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0 ~ s t u v w x */
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8 y z ---- ---- ---- ---- */
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0 ---- § ---- */
+ 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8 ---- | ---- ---- ---- ---- */
+ 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0 { A B C D E F G */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8 H I ---- ö ---- */
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0 } J K L M N O P */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8 Q R ---- ü */
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0 \ S T U V W X */
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8 Y Z ---- Ö ---- ---- ---- */
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0 0 1 2 3 4 5 6 7 */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+
+/*
+ * EBCDIC 037/500 conversion table:
+ * from upper to lower case
+ */
+__u8 _ebc_tolower[256] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x61, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9C, 0x9F,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB, 0x8C, 0x8D, 0x8E, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xEA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF
+};
+
+
+/*
+ * EBCDIC 037/500 conversion table:
+ * from lower to upper case
+ */
+__u8 _ebc_toupper[256] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x40, 0x41, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+ 0x50, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+ 0x80, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0x8A, 0x8B, 0xAC, 0xAD, 0xAE, 0x8F,
+ 0x90, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0x9A, 0x9B, 0x9E, 0x9D, 0x9E, 0x9F,
+ 0xA0, 0xA1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xFB, 0xFC, 0xFD, 0xFE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+};
diff --git a/arch/s390x/kernel/entry.S b/arch/s390x/kernel/entry.S
new file mode 100644
index 000000000..c5fbdd61f
--- /dev/null
+++ b/arch/s390x/kernel/entry.S
@@ -0,0 +1,868 @@
+/*
+ * arch/s390/kernel/entry.S
+ * S390 low-level entry points.
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Hartmut Penner (hp@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <linux/config.h>
+#include <asm/lowcore.h>
+#include <asm/errno.h>
+#define ASSEMBLY
+#include <asm/smp.h>
+#include <asm/s390-regs-common.h>
+
+
+/*
+ * stack layout for the system_call stack entry
+ * Martin please don't modify these back to hard coded values
+ * You know how bad I'm at mental arithmetic DJB & it gives
+ * me grief when I modify the pt_regs
+ */
+SP_PTREGS = STACK_FRAME_OVERHEAD
+SP_PSW = SP_PTREGS
+SP_R0 = (SP_PSW+PSW_MASK_SIZE+PSW_ADDR_SIZE)
+SP_R1 = (SP_R0+GPR_SIZE)
+SP_R2 = (SP_R1+GPR_SIZE)
+SP_R3 = (SP_R2+GPR_SIZE)
+SP_R4 = (SP_R3+GPR_SIZE)
+SP_R5 = (SP_R4+GPR_SIZE)
+SP_R6 = (SP_R5+GPR_SIZE)
+SP_R7 = (SP_R6+GPR_SIZE)
+SP_R8 = (SP_R7+GPR_SIZE)
+SP_R9 = (SP_R8+GPR_SIZE)
+SP_RA = (SP_R9+GPR_SIZE)
+SP_RB = (SP_RA+GPR_SIZE)
+SP_RC = (SP_RB+GPR_SIZE)
+SP_RD = (SP_RC+GPR_SIZE)
+SP_RE = (SP_RD+GPR_SIZE)
+SP_RF = (SP_RE+GPR_SIZE)
+SP_AREGS = (SP_RF+GPR_SIZE)
+SP_ORIG_R2 = (SP_AREGS+(NUM_ACRS*ACR_SIZE))
+SP_TRAP = (SP_ORIG_R2+GPR_SIZE)
+#if CONFIG_REMOTE_DEBUG
+SP_CRREGS = (SP_TRAP+4)
+/* fpu registers are saved & restored by the gdb stub itself */
+SP_FPC = (SP_CRREGS+(NUM_CRS*CR_SIZE))
+SP_FPRS = (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
+/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not
+ defined in ptrace.h but space is needed for this too */
+SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE))
+#else
+SP_PGM_OLD_ILC= (SP_TRAP+4)
+#endif
+SP_SVC_STEP = (SP_PGM_OLD_ILC+4)
+SP_SIZE = (SP_SVC_STEP+4)
+/*
+ * these defines are offsets into the thread_struct
+ */
+_TSS_PTREGS = 0
+_TSS_FPRS = (_TSS_PTREGS+8)
+_TSS_AR2 = (_TSS_FPRS+136)
+_TSS_AR4 = (_TSS_AR2+4)
+_TSS_KSP = (_TSS_AR4+4)
+_TSS_USERSEG = (_TSS_KSP+8)
+_TSS_PROT = (_TSS_USERSEG+8)
+_TSS_ERROR = (_TSS_PROT+8)
+_TSS_TRAP = (_TSS_ERROR+4)
+_TSS_PER = (_TSS_TRAP+4)
+
+/*
+ * these are offsets into the task-struct.
+ */
+state = 0
+flags = 8
+sigpending = 16
+need_resched = 32
+tsk_ptrace = 40
+processor = 100
+
+/* PSW related defines */
+disable = 0xFC
+enable = 0x03
+daton = 0x04
+
+
+#if 0
+/* some code left lying around in case we need a
+ * printk for debugging purposes
+ */
+ sysc_printk: .long printk
+ sysc_msg: .string "<2>r15 %X\n"
+ .align 4
+
+# basr %r13,0
+ lg %r0,SP_PSW+8(%r15)
+ sllg %r0,%r0,1
+ chi %r0,0
+ jnz sysc_dn
+ la %r2,sysc_msg-sysc_lit(%r13)
+ lgr %r3,%r15
+ brasl %r14,sysc_printk
+sysc_dn:
+#endif
+
+/*
+ * Register usage in interrupt handlers:
+ * R9 - pointer to current task structure
+ * R13 - pointer to literal pool
+ * R14 - return register for function calls
+ * R15 - kernel stack pointer
+ */
+
+#define SAVE_ALL(psworg) \
+ stmg %r14,%r15,__LC_SAVE_AREA ; \
+ stam %a2,%a4,__LC_SAVE_AREA+16 ; \
+ tm psworg+1,0x01 ; /* test problem state bit */ \
+ jz 0f ; /* skip stack setup save */ \
+ lg %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \
+ slr %r14,%r14 ; \
+ sar %a2,%r14 ; /* set ac.reg. 2 to primary space */ \
+ lhi %r14,1 ; \
+ sar %a4,%r14 ; /* set access reg. 4 to home space */ \
+0: aghi %r15,-SP_SIZE ; /* make room for registers & psw */ \
+ nill %r15,0xfff8 ; /* align stack pointer to 8 */ \
+ stmg %r0,%r14,SP_R0(%r15) ; /* store gprs 0-14 to kernel stack */ \
+ stg %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \
+ mvc SP_RE(16,%r15),__LC_SAVE_AREA ; /* move R15 to stack */ \
+ stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */\
+ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 ; /* store ac. regs */ \
+ mvc SP_PSW(16,%r15),psworg; /* move user PSW to stack */ \
+ lhi %r0,psworg ; /* store trap indication */ \
+ st %r0,SP_TRAP(%r15) ; \
+ xc 0(8,%r15),0(%r15) ; /* clear back chain */
+
+#define RESTORE_ALL \
+ mvc __LC_RETURN_PSW(16),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
+ lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
+ lmg %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \
+ ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \
+ lpswe __LC_RETURN_PSW /* back to caller */
+
+#define GET_CURRENT /* load pointer to task_struct to R9 */ \
+ lghi %r9,-16384 ; \
+ ngr %r9,15
+
+
+/*
+ * Scheduler resume function, called by switch_to
+ * grp2 = (thread_struct *) prev->tss
+ * grp3 = (thread_struct *) next->tss
+ * Returns:
+ * gpr2 = prev
+ */
+ .globl resume
+resume:
+ lg %r4,_TSS_PTREGS(%r3)
+ tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
+ jz resume_noper # if not we're fine
+ stctg %r9,%r11,48(%r15) # We are using per stuff
+ clc _TSS_PER(24,%r3),48(%r15)
+ je resume_noper # we got away without bashing TLB's
+ lctlg %c9,%c11,_TSS_PER(%r3) # Nope we didn't
+resume_noper:
+ stmg %r6,%r15,48(%r15) # store resume registers of prev task
+ stg %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
+ lghi %r0,-16384
+ ngr %r0,%r15
+ lg %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp
+ lghi %r1,16383
+ ogr %r1,%r15
+ aghi %r1,1
+ stg %r1,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
+ stam %a2,%a2,_TSS_AR2(%r2) # store kernel access reg. 2
+ stam %a4,%a4,_TSS_AR4(%r2) # store kernel access reg. 4
+ lam %a2,%a2,_TSS_AR2(%r3) # load kernel access reg. 2
+ lam %a4,%a4,_TSS_AR4(%r3) # load kernel access reg. 4
+ lgr %r2,%r0 # return task_struct of last task
+ lmg %r6,%r15,48(%r15) # load resume registers of next task
+ br %r14
+
+/*
+ * SVC interrupt handler routine. System calls are synchronous events and
+ * are executed with interrupts enabled.
+ */
+
+ .globl system_call
+system_call:
+ SAVE_ALL(__LC_SVC_OLD_PSW)
+ xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
+pgm_system_call:
+ larl %r1,sys_call_table
+ llgc %r8,__LC_SVC_INT_CODE+1 # get svc number from lowcore
+ stosm 48(%r15),0x03 # reenable interrupts
+ sll %r8,3
+ tm SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ?
+ jo sysc_noemu
+ la %r8,4(%r8) # use 31 bit emulation system calls
+sysc_noemu:
+ GET_CURRENT # load pointer to task_struct to R9
+ lgf %r8,0(%r8,%r1) # load address of system call routine
+ tm tsk_ptrace+7(%r9),0x02 # PT_TRACESYS
+ jnz sysc_tracesys
+ basr %r14,%r8 # call sys_xxxx
+ stg %r2,SP_R2(%r15) # store return value (change R2 on stack)
+ # ATTENTION: check sys_execve_glue before
+ # changing anything here !!
+
+sysc_return:
+ GET_CURRENT # load pointer to task_struct to R9
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jno sysc_leave # no-> skip bottom half, resched & signal
+#
+# check, if bottom-half has to be done
+#
+ l %r0,__LC_IRQ_STAT # get softirq_active
+ n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
+ jnz sysc_handle_bottom_half
+#
+# check, if reschedule is needed
+#
+sysc_return_bh:
+ lg %r0,need_resched(%r9) # get need_resched from task_struct
+ ltgr %r0,%r0
+ jnz sysc_reschedule
+ icm %r0,15,sigpending(%r9) # get sigpending from task_struct
+ jnz sysc_signal_return
+sysc_leave:
+ icm %r0,15,SP_SVC_STEP(%r15) # get sigpending from task_struct
+ jnz pgm_svcret
+ stnsm 48(%r15),disable # disable I/O and ext. interrupts
+ RESTORE_ALL
+
+#
+# call do_signal before return
+#
+sysc_signal_return:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ sgr %r3,%r3 # clear *oldset
+ larl %r14,sysc_leave
+ jg do_signal # return point is sysc_leave
+
+#
+# call trace before and after sys_call
+#
+sysc_tracesys:
+ lghi %r2,-ENOSYS
+ stg %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval
+ brasl %r14,syscall_trace
+ lmg %r3,%r6,SP_R3(%r15)
+ lg %r2,SP_ORIG_R2(%r15)
+ basr %r14,%r8 # call sys_xxx
+ stg %r2,SP_R2(%r15) # store return value
+ larl %r14,sysc_return
+ jg syscall_trace # return point is sysc_return
+
+
+#
+# call do_softirq and return from syscall, if interrupt-level
+# is zero
+#
+sysc_handle_bottom_half:
+ larl %r14,sysc_return_bh
+ jg do_softirq # return point is sysc_return_bh
+
+#
+# call schedule with sysc_return as return-address
+#
+sysc_reschedule:
+ larl %r14,sysc_return
+ jg schedule # return point is sysc_return
+
+#
+# a new process exits the kernel with ret_from_fork
+#
+ .globl ret_from_fork
+ret_from_fork:
+ GET_CURRENT # load pointer to task_struct to R9
+ stosm 48(%r15),0x03 # reenable interrupts
+ xc SP_R2(8,%r15),SP_R2(%r15) # child returns 0
+#ifdef CONFIG_SMP
+ larl %r14,sysc_return
+ jg schedule_tail # return to sysc_return
+#else
+ j sysc_return
+#endif
+
+#
+# clone, fork, vfork, exec and sigreturn need glue,
+# because they all expect pt_regs as parameter,
+# but are called with different parameter.
+# return-address is set up above
+#
+sys_clone_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ jg sys_clone # branch to sys_clone
+
+sys_fork_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ jg sys_fork # branch to sys_fork
+
+sys_vfork_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ jg sys_vfork # branch to sys_vfork
+
+sys_execve_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ lgr %r12,%r14 # save return address
+ brasl %r14,sys_execve # call sys_execve
+ ltgr %r2,%r2 # check if execve failed
+ bnz 0(%r12) # it did fail -> store result in gpr2
+ b 6(%r12) # SKIP STG 2,SP_R2(15) in
+ # system_call/sysc_tracesys
+#ifdef CONFIG_S390_SUPPORT
+sys32_execve_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ lgr %r12,%r14 # save return address
+ brasl %r14,sys32_execve # call sys32_execve
+ ltgr %r2,%r2 # check if execve failed
+ bnz 0(%r12) # it did fail -> store result in gpr2
+ b 6(%r12) # SKIP STG 2,SP_R2(15) in
+ # system_call/sysc_tracesys
+#endif
+
+sys_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys_sigreturn # branch to sys_sigreturn
+
+#ifdef CONFIG_S390_SUPPORT
+sys32_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys32_sigreturn # branch to sys32_sigreturn
+#endif
+
+sys_rt_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys_rt_sigreturn # branch to sys_sigreturn
+
+#ifdef CONFIG_S390_SUPPORT
+sys32_rt_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys32_rt_sigreturn # branch to sys32_sigreturn
+#endif
+
+#
+# sigsuspend and rt_sigsuspend need pt_regs as an additional
+# parameter and they have to skip the store of %r2 into the
+# user register %r2 because the return value was set in
+# sigsuspend and rt_sigsuspend already and must not be overwritten!
+#
+
+sys_sigsuspend_glue:
+ lgr %r5,%r4 # move mask back
+ lgr %r4,%r3 # move history1 parameter
+ lgr %r3,%r2 # move history0 parameter
+ la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
+ la %r14,6(%r14) # skip store of return value
+ jg sys_sigsuspend # branch to sys_sigsuspend
+
+#ifdef CONFIG_S390_SUPPORT
+sys32_sigsuspend_glue:
+ llgfr %r4,%r4 # unsigned long
+ lgr %r5,%r4 # move mask back
+ lgfr %r3,%r3 # int
+ lgr %r4,%r3 # move history1 parameter
+ lgfr %r2,%r2 # int
+ lgr %r3,%r2 # move history0 parameter
+ la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
+ la %r14,6(%r14) # skip store of return value
+ jg sys32_sigsuspend # branch to sys32_sigsuspend
+#endif
+
+sys_rt_sigsuspend_glue:
+ lgr %r4,%r3 # move sigsetsize parameter
+ lgr %r3,%r2 # move unewset parameter
+ la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
+ la %r14,6(%r14) # skip store of return value
+ jg sys_rt_sigsuspend # branch to sys_rt_sigsuspend
+
+#ifdef CONFIG_S390_SUPPORT
+sys32_rt_sigsuspend_glue:
+ llgfr %r3,%r3 # size_t
+ lgr %r4,%r3 # move sigsetsize parameter
+ llgtr %r2,%r2 # sigset_emu31_t *
+ lgr %r3,%r2 # move unewset parameter
+ la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
+ la %r14,6(%r14) # skip store of return value
+ jg sys32_rt_sigsuspend # branch to sys32_rt_sigsuspend
+#endif
+
+sys_sigaltstack_glue:
+ la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys_sigaltstack # branch to sys_sigreturn
+
+#ifdef CONFIG_S390_SUPPORT
+sys32_sigaltstack_glue:
+ la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys32_sigaltstack_wrapper # branch to sys_sigreturn
+#endif
+
+#ifdef CONFIG_S390_SUPPORT
+#define SYSCALL(esame,esa) esame,esa
+#else
+#define SYSCALL(esame,esa) esame,sys_ni_syscall
+#endif
+
+ .globl sys_call_table
+sys_call_table:
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 0 */
+ .long SYSCALL(sys_exit,sys32_exit_wrapper)
+ .long SYSCALL(sys_fork_glue,sys_fork_glue)
+ .long SYSCALL(sys_read,sys32_read_wrapper)
+ .long SYSCALL(sys_write,sys32_write_wrapper)
+ .long SYSCALL(sys_open,sys32_open_wrapper) /* 5 */
+ .long SYSCALL(sys_close,sys32_close_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old waitpid syscall */
+ .long SYSCALL(sys_creat,sys32_creat_wrapper)
+ .long SYSCALL(sys_link,sys32_link_wrapper)
+ .long SYSCALL(sys_unlink,sys32_unlink_wrapper) /* 10 */
+ .long SYSCALL(sys_execve_glue,sys32_execve_glue)
+ .long SYSCALL(sys_chdir,sys32_chdir_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_time_wrapper) /* old time syscall */
+ .long SYSCALL(sys_mknod,sys32_mknod_wrapper)
+ .long SYSCALL(sys_chmod,sys32_chmod_wrapper) /* 15 */
+ .long SYSCALL(sys_ni_syscall,sys32_lchown16_wrapper) /* old lchown16 syscall*/
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old break syscall */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old stat syscall */
+ .long SYSCALL(sys_lseek,sys32_lseek_wrapper)
+ .long SYSCALL(sys_getpid,sys_getpid) /* 20 */
+ .long SYSCALL(sys_mount,sys32_mount_wrapper)
+ .long SYSCALL(sys_oldumount,sys32_oldumount_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_setuid16_wrapper) /* old setuid16 syscall*/
+ .long SYSCALL(sys_ni_syscall,sys32_getuid16) /* old getuid16 syscall*/
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 25 old stime syscall */
+ .long SYSCALL(sys_ptrace,sys32_ptrace_wrapper)
+ .long SYSCALL(sys_alarm,sys32_alarm_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old fstat syscall */
+ .long SYSCALL(sys_pause,sys32_pause)
+ .long SYSCALL(sys_utime,sys32_utime_wrapper) /* 30 */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old stty syscall */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old gtty syscall */
+ .long SYSCALL(sys_access,sys32_access_wrapper)
+ .long SYSCALL(sys_nice,sys32_nice_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old ftime syscall */
+ .long SYSCALL(sys_sync,sys_sync)
+ .long SYSCALL(sys_kill,sys32_kill_wrapper)
+ .long SYSCALL(sys_rename,sys32_rename_wrapper)
+ .long SYSCALL(sys_mkdir,sys32_mkdir_wrapper)
+ .long SYSCALL(sys_rmdir,sys32_rmdir_wrapper) /* 40 */
+ .long SYSCALL(sys_dup,sys32_dup_wrapper)
+ .long SYSCALL(sys_pipe,sys32_pipe_wrapper)
+ .long SYSCALL(sys_times,sys32_times_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old prof syscall */
+ .long SYSCALL(sys_brk,sys32_brk_wrapper) /* 45 */
+ .long SYSCALL(sys_ni_syscall,sys32_setgid16) /* old setgid16 syscall*/
+ .long SYSCALL(sys_ni_syscall,sys32_getgid16) /* old getgid16 syscall*/
+ .long SYSCALL(sys_signal,sys32_signal_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_geteuid16) /* old geteuid16 syscall */
+ .long SYSCALL(sys_ni_syscall,sys32_getegid16) /* old getegid16 syscall */
+ .long SYSCALL(sys_acct,sys32_acct_wrapper)
+ .long SYSCALL(sys_umount,sys32_umount_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old lock syscall */
+ .long SYSCALL(sys_ioctl,sys32_ioctl_wrapper)
+ .long SYSCALL(sys_fcntl,sys32_fcntl_wrapper) /* 55 */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* intel mpx syscall */
+ .long SYSCALL(sys_setpgid,sys32_setpgid_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old ulimit syscall */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old uname syscall */
+ .long SYSCALL(sys_umask,sys32_umask_wrapper) /* 60 */
+ .long SYSCALL(sys_chroot,sys32_chroot_wrapper)
+ .long SYSCALL(sys_ustat,sys32_ustat_wrapper)
+ .long SYSCALL(sys_dup2,sys32_dup2_wrapper)
+ .long SYSCALL(sys_getppid,sys_getppid)
+ .long SYSCALL(sys_getpgrp,sys_getpgrp) /* 65 */
+ .long SYSCALL(sys_setsid,sys_setsid)
+ .long SYSCALL(sys_sigaction,sys32_sigaction_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old sgetmask syscall*/
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old ssetmask syscall*/
+ .long SYSCALL(sys_ni_syscall,sys32_setreuid16_wrapper) /* old setreuid16 syscall */
+ .long SYSCALL(sys_ni_syscall,sys32_setregid16_wrapper) /* old setregid16 syscall */
+ .long SYSCALL(sys_sigsuspend_glue,sys32_sigsuspend_glue)
+ .long SYSCALL(sys_sigpending,sys32_sigpending_wrapper)
+ .long SYSCALL(sys_sethostname,sys32_sethostname_wrapper)
+ .long SYSCALL(sys_setrlimit,sys32_setrlimit_wrapper) /* 75 */
+ .long SYSCALL(sys_getrlimit,sys32_old_getrlimit_wrapper)
+ .long SYSCALL(sys_getrusage,sys32_getrusage_wrapper)
+ .long SYSCALL(sys_gettimeofday,sys32_gettimeofday_wrapper)
+ .long SYSCALL(sys_settimeofday,sys32_settimeofday_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_getgroups16_wrapper) /* old getgroups16 syscall */
+ .long SYSCALL(sys_ni_syscall,sys32_setgroups16_wrapper) /* old setgroups16 syscall */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old select syscall */
+ .long SYSCALL(sys_symlink,sys32_symlink_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old lstat syscall */
+ .long SYSCALL(sys_readlink,sys32_readlink_wrapper) /* 85 */
+ .long SYSCALL(sys_uselib,sys32_uselib_wrapper)
+ .long SYSCALL(sys_swapon,sys32_swapon_wrapper)
+ .long SYSCALL(sys_reboot,sys32_reboot_wrapper)
+ .long SYSCALL(sys_ni_syscall,old32_readdir_wrapper) /* old readdir syscall */
+ .long SYSCALL(old_mmap,old32_mmap_wrapper) /* 90 */
+ .long SYSCALL(sys_munmap,sys32_munmap_wrapper)
+ .long SYSCALL(sys_truncate,sys32_truncate_wrapper)
+ .long SYSCALL(sys_ftruncate,sys32_ftruncate_wrapper)
+ .long SYSCALL(sys_fchmod,sys32_fchmod_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_fchown16_wrapper) /* old fchown16 syscall*/
+ .long SYSCALL(sys_getpriority,sys32_getpriority_wrapper)
+ .long SYSCALL(sys_setpriority,sys32_setpriority_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old profil syscall */
+ .long SYSCALL(sys_statfs,sys32_statfs_wrapper)
+ .long SYSCALL(sys_fstatfs,sys32_fstatfs_wrapper) /* 100 */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall)
+ .long SYSCALL(sys_socketcall,sys32_socketcall_wrapper)
+ .long SYSCALL(sys_syslog,sys32_syslog_wrapper)
+ .long SYSCALL(sys_setitimer,sys32_setitimer_wrapper)
+ .long SYSCALL(sys_getitimer,sys32_getitimer_wrapper) /* 105 */
+ .long SYSCALL(sys_newstat,sys32_newstat_wrapper)
+ .long SYSCALL(sys_newlstat,sys32_newlstat_wrapper)
+ .long SYSCALL(sys_newfstat,sys32_newfstat_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old uname syscall */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* iopl for i386 */
+ .long SYSCALL(sys_vhangup,sys_vhangup)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old "idle" system call */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* vm86old for i386 */
+ .long SYSCALL(sys_wait4,sys32_wait4_wrapper)
+ .long SYSCALL(sys_swapoff,sys32_swapoff_wrapper) /* 115 */
+ .long SYSCALL(sys_sysinfo,sys32_sysinfo_wrapper)
+ .long SYSCALL(sys_ipc,sys32_ipc_wrapper)
+ .long SYSCALL(sys_fsync,sys32_fsync_wrapper)
+ .long SYSCALL(sys_sigreturn_glue,sys32_sigreturn_glue)
+ .long SYSCALL(sys_clone_glue,sys_clone_glue) /* 120 */
+ .long SYSCALL(sys_setdomainname,sys32_setdomainname_wrapper)
+ .long SYSCALL(sys_newuname,sys32_newuname_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* modify_ldt for i386 */
+ .long SYSCALL(sys_adjtimex,sys32_adjtimex_wrapper)
+ .long SYSCALL(sys_mprotect,sys32_mprotect_wrapper) /* 125 */
+ .long SYSCALL(sys_sigprocmask,sys32_sigprocmask_wrapper)
+ .long SYSCALL(sys_create_module,sys32_create_module_wrapper)
+ .long SYSCALL(sys_init_module,sys32_init_module_wrapper)
+ .long SYSCALL(sys_delete_module,sys32_delete_module_wrapper)
+ .long SYSCALL(sys_get_kernel_syms,sys32_get_kernel_syms_wrapper) /* 130 */
+ .long SYSCALL(sys_quotactl,sys32_quotactl_wrapper)
+ .long SYSCALL(sys_getpgid,sys32_getpgid_wrapper)
+ .long SYSCALL(sys_fchdir,sys32_fchdir_wrapper)
+ .long SYSCALL(sys_bdflush,sys32_bdflush_wrapper)
+ .long SYSCALL(sys_sysfs,sys32_sysfs_wrapper) /* 135 */
+ .long SYSCALL(sys_personality,sys32_personality_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* for afs_syscall */
+ .long SYSCALL(sys_ni_syscall,sys32_setfsuid16_wrapper) /* old setfsuid16 syscall */
+ .long SYSCALL(sys_ni_syscall,sys32_setfsgid16_wrapper) /* old setfsgid16 syscall */
+ .long SYSCALL(sys_llseek,sys32_llseek_wrapper) /* 140 */
+ .long SYSCALL(sys_getdents,sys32_getdents_wrapper)
+ .long SYSCALL(sys_select,sys32_select_wrapper)
+ .long SYSCALL(sys_flock,sys32_flock_wrapper)
+ .long SYSCALL(sys_msync,sys32_msync_wrapper)
+ .long SYSCALL(sys_readv,sys32_readv_wrapper) /* 145 */
+ .long SYSCALL(sys_writev,sys32_writev_wrapper)
+ .long SYSCALL(sys_getsid,sys32_getsid_wrapper)
+ .long SYSCALL(sys_fdatasync,sys32_fdatasync_wrapper)
+ .long SYSCALL(sys_sysctl,sys_ni_syscall)
+ .long SYSCALL(sys_mlock,sys32_mlock_wrapper) /* 150 */
+ .long SYSCALL(sys_munlock,sys32_munlock_wrapper)
+ .long SYSCALL(sys_mlockall,sys32_mlockall_wrapper)
+ .long SYSCALL(sys_munlockall,sys_munlockall)
+ .long SYSCALL(sys_sched_setparam,sys32_sched_setparam_wrapper)
+ .long SYSCALL(sys_sched_getparam,sys32_sched_getparam_wrapper) /* 155 */
+ .long SYSCALL(sys_sched_setscheduler,sys32_sched_setscheduler_wrapper)
+ .long SYSCALL(sys_sched_getscheduler,sys32_sched_getscheduler_wrapper)
+ .long SYSCALL(sys_sched_yield,sys_sched_yield)
+ .long SYSCALL(sys_sched_get_priority_max,sys32_sched_get_priority_max_wrapper)
+ .long SYSCALL(sys_sched_get_priority_min,sys32_sched_get_priority_min_wrapper)
+ .long SYSCALL(sys_sched_rr_get_interval,sys32_sched_rr_get_interval_wrapper)
+ .long SYSCALL(sys_nanosleep,sys32_nanosleep_wrapper)
+ .long SYSCALL(sys_mremap,sys32_mremap_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_setresuid16_wrapper) /* old setresuid16 syscall */
+ .long SYSCALL(sys_ni_syscall,sys32_getresuid16_wrapper) /* old getresuid16 syscall */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* for vm86 */
+ .long SYSCALL(sys_query_module,sys32_query_module_wrapper)
+ .long SYSCALL(sys_poll,sys32_poll_wrapper)
+ .long SYSCALL(sys_nfsservctl,sys32_nfsservctl_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_setresgid16_wrapper) /* old setresgid16 syscall */
+ .long SYSCALL(sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */
+ .long SYSCALL(sys_prctl,sys32_prctl_wrapper)
+ .long SYSCALL(sys_rt_sigreturn_glue,sys32_rt_sigreturn_glue)
+ .long SYSCALL(sys_rt_sigaction,sys32_rt_sigaction_wrapper)
+ .long SYSCALL(sys_rt_sigprocmask,sys32_rt_sigprocmask_wrapper) /* 175 */
+ .long SYSCALL(sys_rt_sigpending,sys32_rt_sigpending_wrapper)
+ .long SYSCALL(sys_rt_sigtimedwait,sys32_rt_sigtimedwait_wrapper)
+ .long SYSCALL(sys_rt_sigqueueinfo,sys32_rt_sigqueueinfo_wrapper)
+ .long SYSCALL(sys_rt_sigsuspend_glue,sys32_rt_sigsuspend_glue)
+ .long SYSCALL(sys_pread,sys32_pread_wrapper) /* 180 */
+ .long SYSCALL(sys_pwrite,sys32_pwrite_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall */
+ .long SYSCALL(sys_getcwd,sys32_getcwd_wrapper)
+ .long SYSCALL(sys_capget,sys32_capget_wrapper)
+ .long SYSCALL(sys_capset,sys32_capset_wrapper) /* 185 */
+ .long SYSCALL(sys_sigaltstack_glue,sys32_sigaltstack_glue)
+ .long SYSCALL(sys_sendfile,sys32_sendfile_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* streams1 */
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* streams2 */
+ .long SYSCALL(sys_vfork_glue,sys_vfork_glue) /* 190 */
+ .long SYSCALL(sys_getrlimit,sys32_old_getrlimit_wrapper)
+ .long SYSCALL(sys_mmap2,sys32_mmap2_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_truncate64_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_ftruncate64_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_stat64) /* 195 */
+ .long SYSCALL(sys_ni_syscall,sys32_lstat64)
+ .long SYSCALL(sys_ni_syscall,sys32_fstat64)
+ .long SYSCALL(sys_lchown,sys32_lchown_wrapper)
+ .long SYSCALL(sys_getuid,sys_getuid)
+ .long SYSCALL(sys_getgid,sys_getgid) /* 200 */
+ .long SYSCALL(sys_geteuid,sys_geteuid)
+ .long SYSCALL(sys_getegid,sys_getegid)
+ .long SYSCALL(sys_setreuid,sys32_setreuid_wrapper)
+ .long SYSCALL(sys_setregid,sys32_setregid_wrapper)
+ .long SYSCALL(sys_getgroups,sys32_getgroups_wrapper) /* 205 */
+ .long SYSCALL(sys_setgroups,sys32_setgroups_wrapper)
+ .long SYSCALL(sys_fchown,sys32_fchown_wrapper)
+ .long SYSCALL(sys_setresuid,sys32_setresuid_wrapper)
+ .long SYSCALL(sys_getresuid,sys32_getresuid_wrapper)
+ .long SYSCALL(sys_setresgid,sys32_setresgid_wrapper) /* 210 */
+ .long SYSCALL(sys_getresgid,sys32_getresgid_wrapper)
+ .long SYSCALL(sys_chown,sys32_chown_wrapper)
+ .long SYSCALL(sys_setuid,sys32_setuid_wrapper)
+ .long SYSCALL(sys_setgid,sys32_setgid_wrapper)
+ .long SYSCALL(sys_setfsuid,sys32_setfsuid_wrapper) /* 215 */
+ .long SYSCALL(sys_setfsgid,sys32_setfsgid_wrapper)
+ .long SYSCALL(sys_pivot_root,sys32_pivot_root_wrapper)
+ .long SYSCALL(sys_mincore,sys32_mincore_wrapper)
+ .long SYSCALL(sys_madvise,sys32_madvise_wrapper)
+ .long SYSCALL(sys_ni_syscall,sys32_getdents64_wrapper)/* 220 */
+ .long SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
+ .rept 255-221
+ .long SYSCALL(sys_ni_syscall,sys_ni_syscall)
+ .endr
+
+/*
+ * Program check handler routine
+ */
+
+ .globl pgm_check_handler
+pgm_check_handler:
+/*
+ * First we need to check for a special case:
+ * Single stepping an instruction that disables the PER event mask will
+ * cause a PER event AFTER the mask has been set. Example: SVC or LPSW.
+ * For a single stepped SVC the program check handler gets control after
+ * the SVC new PSW has been loaded. But we want to execute the SVC first and
+ * then handle the PER event. Therefore we update the SVC old PSW to point
+ * to the pgm_check_handler and branch to the SVC handler after we checked
+ * if we have to load the kernel stack register.
+ * For every other possible cause for PER event without the PER mask set
+ * we just ignore the PER event (FIXME: is there anything we have to do
+ * for LPSW?).
+ */
+ stmg %r14,%r15,__LC_SAVE_AREA
+ stam %a2,%a4,__LC_SAVE_AREA+16
+ tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
+ jz pgm_sv # skip if not
+ tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
+ jnz pgm_sv # skip if it is
+# ok its one of the special cases, now we need to find out which one
+ clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
+ je pgm_svcper
+# no interesting special case, ignore PER event
+ lm %r13,%r15,__LC_SAVE_AREA
+ lpsw __LC_PGM_OLD_PSW
+# it was a single stepped SVC that is causing all the trouble
+pgm_svcper:
+ tm __LC_SVC_OLD_PSW+1,0x01 # test problem state bit
+ jz 0f # skip stack & access regs setup
+ lg %r15,__LC_KERNEL_STACK # problem state -> load ksp
+ slr %r14,%r14
+ sar %a2,%r14 # set ac.reg. 2 to primary space
+ lhi %r14,1
+ sar %a4,%r14 # and access reg. 4 to home space
+0: aghi %r15,-SP_SIZE # make room for registers & psw
+ nill %r15,0xfff8 # align stack pointer to 8
+ stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack
+ stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
+ mvc SP_RE(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack
+ stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst.
+ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs
+ mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW # move user PSW to stack
+ lhi %r0,__LC_SVC_OLD_PSW # store trap indication
+ st %r0,SP_TRAP(%r15)
+ xc 0(8,%r15),0(%r15) # clear back chain
+
+ mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero
+ mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
+ j pgm_system_call # now do the svc
+pgm_svcret:
+ lhi %r0,__LC_PGM_OLD_PSW # set trap indication back to pgm_chk
+ st %r0,SP_TRAP(%r15)
+ llgh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
+ xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
+ j pgm_no_sv
+pgm_sv:
+ tm __LC_PGM_OLD_PSW+1,0x01 # test problem state bit
+ jz 1f # skip stack setup save
+ lg %r15,__LC_KERNEL_STACK # problem state -> load ksp
+ slr %r14,%r14
+ sar %a2,%r14 # set ac.reg. 2 to primary space
+ lhi %r14,1
+ sar %a4,%r14 # set access reg. 4 to home space
+1: aghi %r15,-SP_SIZE # make room for registers & psw
+ nill %r15,0xfff8 # align stack pointer to 8
+ stmg %r0,%r14,SP_R0(%r15) # store gprs 0-14 to kernel stack
+ stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
+ mvc SP_RE(16,%r15),__LC_SAVE_AREA # move R14-R15 to stack
+ stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst.
+ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs
+ mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW # move user PSW to stack
+ lhi %r0,__LC_PGM_OLD_PSW # store trap indication
+ st %r0,SP_TRAP(%r15)
+ xc 0(8,%r15),0(%r15) # clear back chain
+ xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
+ llgh %r7,__LC_PGM_ILC # load instruction length
+pgm_no_sv:
+ llgh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it
+ stosm 48(%r15),0x03 # reenable interrupts
+ lghi %r3,0x7f
+ nr %r3,%r8 # clear per-event-bit & move to r3
+ je pgm_dn # none of Martins exceptions occured bypass
+ sll %r3,3
+ larl %r9,pgm_check_table
+ lg %r9,0(%r3,%r9) # load address of handler routine
+ srl %r3,3
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ chi %r3,0x4 # protection-exception ?
+ jne pgm_go # if not,
+ lg %r5,SP_PSW+8(15) # load psw addr
+ slgr %r5,%r7 # substract ilc from psw
+ stg %r5,SP_PSW+8(15) # store corrected psw addr
+pgm_go: basr %r14,%r9 # branch to interrupt-handler
+pgm_dn: nill %r8,0x80 # check for per exception
+ je sysc_return
+ la %r2,SP_PTREGS(15) # address of register-save area
+ larl %r14,sysc_return # load adr. of system return
+ jg handle_per_exception
+
+/*
+ * IO interrupt handler routine
+ */
+ .globl io_int_handler
+io_int_handler:
+ SAVE_ALL(__LC_IO_OLD_PSW)
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ llgh %r3,__LC_SUBCHANNEL_NR # load subchannel number
+ llgf %r4,__LC_IO_INT_PARM # load interruption parm
+ llgf %r5,__LC_IO_INT_WORD # load interruption word
+ brasl %r14,do_IRQ # call standard irq handler
+
+io_return:
+ GET_CURRENT # load pointer to task_struct to R9
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jz io_leave # no-> skip resched & signal
+ stosm 48(%r15),0x03 # reenable interrupts
+#
+# check, if bottom-half has to be done
+#
+ l %r0,__LC_IRQ_STAT # get softirq_active
+ n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
+ jnz io_handle_bottom_half
+io_return_bh:
+#
+# check, if reschedule is needed
+#
+ lg %r0,need_resched(%r9) # get need_resched from task_struct
+ ltgr %r0,%r0
+ jnz io_reschedule
+ icm %r0,15,sigpending(%r9) # get sigpending from task_struct
+ jnz io_signal_return
+io_leave:
+ stnsm 48(%r15),disable # disable I/O and ext. interrupts
+ RESTORE_ALL
+
+#
+# call do_softirq and return from syscall, if interrupt-level
+# is zero
+#
+io_handle_bottom_half:
+ larl %r14,io_return_bh
+ jg do_softirq # return point is io_return_bh
+
+#
+# call schedule with io_return as return-address
+#
+io_reschedule:
+ larl %r14,io_return
+ jg schedule # call scheduler, return to io_return
+
+#
+# call do_signal before return
+#
+io_signal_return:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ slgr %r3,%r3 # clear *oldset
+ larl %r14,io_leave
+ jg do_signal # return point is io_leave
+
+/*
+ * External interrupt handler routine
+ */
+ .globl ext_int_handler
+ext_int_handler:
+ SAVE_ALL(__LC_EXT_OLD_PSW)
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ llgh %r3,__LC_EXT_INT_CODE # error code
+ lgr %r1,%r3 # calculate index = code & 0xff
+ nill %r1,0xff
+ sll %r1,3
+ larl %r9,ext_int_hash
+ lg %r9,0(%r1,%r9) # get first list entry for hash value
+ ltgr %r9,%r9 # == NULL ?
+ jz io_return # yes, nothing to do, exit
+ext_int_loop:
+ ch %r3,16(%r9) # compare external interrupt code
+ je ext_int_found
+ lg %r9,0(%r9) # next list entry
+ ltgr %r9,%r9
+ jnz ext_int_loop
+ j io_return
+ext_int_found:
+ lg %r9,8(%r9) # get handler address
+ larl %r14,io_return
+ br %r9 # branch to ext call handler
+
+/*
+ * Machine check handler routines
+ */
+ .globl mcck_int_handler
+mcck_int_handler:
+ SAVE_ALL(__LC_MCK_OLD_PSW)
+ brasl %r14,s390_do_machine_check
+mcck_return:
+ RESTORE_ALL
+
+#ifdef CONFIG_SMP
+/*
+ * Restart interruption handler, kick starter for additional CPUs
+ */
+ .globl restart_int_handler
+restart_int_handler:
+ lg %r15,__LC_KERNEL_STACK # load ksp
+ lctlg %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
+ lam %a0,%a15,__LC_AREGS_SAVE_AREA
+ stosm 0(%r15),daton # now we can turn dat on
+ lmg %r6,%r15,48(%r15) # load registers from clone
+ jg start_secondary
+#else
+/*
+ * If we do not run with SMP enabled, let the new CPU crash ...
+ */
+ .globl restart_int_handler
+restart_int_handler:
+ basr %r1,0
+restart_base:
+ lpswe restart_crash-restart_base(%r1)
+ .align 8
+restart_crash:
+ .long 0x000a0000,0x00000000,0x00000000,0x00000000
+restart_go:
+#endif
+
diff --git a/arch/s390x/kernel/exec32.c b/arch/s390x/kernel/exec32.c
new file mode 100644
index 000000000..3e6f44558
--- /dev/null
+++ b/arch/s390x/kernel/exec32.c
@@ -0,0 +1,85 @@
+/*
+ * Support for 32-bit Linux for S390 ELF binaries.
+ *
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Gerhard Tonn (ton@de.ibm.com)
+ *
+ * Seperated from binfmt_elf32.c to reduce exports for module enablement.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/file.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/spinlock.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+
+extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
+
+#undef STACK_TOP
+#define STACK_TOP TASK31_SIZE
+
+int setup_arg_pages32(struct linux_binprm *bprm)
+{
+ unsigned long stack_base;
+ struct vm_area_struct *mpnt;
+ int i;
+
+ stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
+
+ bprm->p += stack_base;
+ if (bprm->loader)
+ bprm->loader += stack_base;
+ bprm->exec += stack_base;
+
+ mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+ if (!mpnt)
+ return -ENOMEM;
+
+ down(&current->mm->mmap_sem);
+ {
+ mpnt->vm_mm = current->mm;
+ mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
+ mpnt->vm_end = STACK_TOP;
+ mpnt->vm_page_prot = PAGE_COPY;
+ mpnt->vm_flags = VM_STACK_FLAGS;
+ mpnt->vm_ops = NULL;
+ mpnt->vm_pgoff = 0;
+ mpnt->vm_file = NULL;
+ mpnt->vm_private_data = (void *) 0;
+ insert_vm_struct(current->mm, mpnt);
+ current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+ }
+
+ for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+ struct page *page = bprm->page[i];
+ if (page) {
+ bprm->page[i] = NULL;
+ current->mm->rss++;
+ put_dirty_page(current,page,stack_base);
+ }
+ stack_base += PAGE_SIZE;
+ }
+ up(&current->mm->mmap_sem);
+
+ return 0;
+}
+
diff --git a/arch/s390x/kernel/gdb-stub.c b/arch/s390x/kernel/gdb-stub.c
new file mode 100644
index 000000000..06e3adbb0
--- /dev/null
+++ b/arch/s390x/kernel/gdb-stub.c
@@ -0,0 +1,575 @@
+/*
+ * arch/s390/kernel/gdb-stub.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * Originally written by Glenn Engel, Lake Stevens Instrument Division
+ *
+ * Contributed by HP Systems
+ *
+ * Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
+ * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
+ *
+ * Copyright (C) 1995 Andreas Busse
+ */
+
+/*
+ * To enable debugger support, two things need to happen. One, a
+ * call to set_debug_traps() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint(). Breakpoint()
+ * simulates a breakpoint by executing a BREAK instruction.
+ *
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * G set the value of the CPU registers OK or ENN
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer. '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host: Reply:
+ * $m0,10#2a +$00010203040506070809101112131415#42
+ *
+ */
+
+#include <asm/gdb-stub.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+
+/*
+ * external low-level support routines
+ */
+
+extern int putDebugChar(char c); /* write a single character */
+extern char getDebugChar(void); /* read and return a single char */
+extern void fltr_set_mem_err(void);
+extern void trap_low(void);
+
+/*
+ * breakpoint and test functions
+ */
+extern void breakpoint(void);
+extern void breakinst(void);
+
+/*
+ * local prototypes
+ */
+
+static void getpacket(char *buffer);
+static void putpacket(char *buffer);
+static int hex(unsigned char ch);
+static int hexToInt(char **ptr, int *intValue);
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
+
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+
+static char input_buffer[BUFMAX];
+static char output_buffer[BUFMAX];
+int gdb_stub_initialised = FALSE;
+static const char hexchars[]="0123456789abcdef";
+
+
+/*
+ * Convert ch from a hex digit to an int
+ */
+static int hex(unsigned char ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return ch-'a'+10;
+ if (ch >= '0' && ch <= '9')
+ return ch-'0';
+ if (ch >= 'A' && ch <= 'F')
+ return ch-'A'+10;
+ return -1;
+}
+
+/*
+ * scan for the sequence $<data>#<checksum>
+ */
+static void getpacket(char *buffer)
+{
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int i;
+ int count;
+ unsigned char ch;
+
+ do {
+ /*
+ * wait around for the start character,
+ * ignore all other characters
+ */
+ while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+
+ checksum = 0;
+ xmitcsum = -1;
+ count = 0;
+
+ /*
+ * now, read until a # or end of buffer is found
+ */
+ while (count < BUFMAX) {
+ ch = getDebugChar() & 0x7f;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+
+ if (count >= BUFMAX)
+ continue;
+
+ buffer[count] = 0;
+
+ if (ch == '#') {
+ xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+ xmitcsum |= hex(getDebugChar() & 0x7f);
+
+ if (checksum != xmitcsum)
+ putDebugChar('-'); /* failed checksum */
+ else {
+ putDebugChar('+'); /* successful transfer */
+
+ /*
+ * if a sequence char is present,
+ * reply the sequence ID
+ */
+ if (buffer[2] == ':') {
+ putDebugChar(buffer[0]);
+ putDebugChar(buffer[1]);
+
+ /*
+ * remove sequence chars from buffer
+ */
+ count = strlen(buffer);
+ for (i=3; i <= count; i++)
+ buffer[i-3] = buffer[i];
+ }
+ }
+ }
+ }
+ while (checksum != xmitcsum);
+}
+
+/*
+ * send the packet in buffer.
+ */
+static void putpacket(char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ unsigned char ch;
+
+ /*
+ * $<packet info>#<checksum>.
+ */
+
+ do {
+ putDebugChar('$');
+ checksum = 0;
+ count = 0;
+
+ while ((ch = buffer[count]) != 0) {
+ if (!(putDebugChar(ch)))
+ return;
+ checksum += ch;
+ count += 1;
+ }
+
+ putDebugChar('#');
+ putDebugChar(hexchars[checksum >> 4]);
+ putDebugChar(hexchars[checksum & 0xf]);
+
+ }
+ while ((getDebugChar() & 0x7f) != '+');
+}
+
+
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ * If MAY_FAULT is non-zero, then we will handle memory faults by returning
+ * a 0, else treat a fault like any other fault in the stub.
+ */
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+ unsigned char ch;
+
+/* set_mem_fault_trap(may_fault); */
+
+ while (count-- > 0) {
+ ch = *(mem++);
+ if (mem_err)
+ return 0;
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch & 0xf];
+ }
+
+ *buf = 0;
+
+/* set_mem_fault_trap(0); */
+
+ return buf;
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ */
+static char *hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+ int i;
+ unsigned char ch;
+
+/* set_mem_fault_trap(may_fault); */
+
+ for (i=0; i<count; i++)
+ {
+ ch = hex(*buf++) << 4;
+ ch |= hex(*buf++);
+ *(mem++) = ch;
+ if (mem_err)
+ return 0;
+ }
+
+/* set_mem_fault_trap(0); */
+
+ return mem;
+}
+
+
+
+/*
+ * Set up exception handlers for tracing and breakpoints
+ */
+void set_debug_traps(void)
+{
+// unsigned long flags;
+ unsigned char c;
+
+// save_and_cli(flags);
+ /*
+ * In case GDB is started before us, ack any packets
+ * (presumably "$?#xx") sitting there.
+ */
+ while((c = getDebugChar()) != '$');
+ while((c = getDebugChar()) != '#');
+ c = getDebugChar(); /* eat first csum byte */
+ c = getDebugChar(); /* eat second csum byte */
+ putDebugChar('+'); /* ack it */
+
+ gdb_stub_initialised = TRUE;
+// restore_flags(flags);
+}
+
+
+/*
+ * Trap handler for memory errors. This just sets mem_err to be non-zero. It
+ * assumes that %l1 is non-zero. This should be safe, as it is doubtful that
+ * 0 would ever contain code that could mem fault. This routine will skip
+ * past the faulting instruction after setting mem_err.
+ */
+extern void fltr_set_mem_err(void)
+{
+ /* FIXME: Needs to be written... */
+}
+
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int hexToInt(char **ptr, int *intValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *intValue = 0;
+
+ while (**ptr)
+ {
+ hexValue = hex(**ptr);
+ if (hexValue < 0)
+ break;
+
+ *intValue = (*intValue << 4) | hexValue;
+ numChars ++;
+
+ (*ptr)++;
+ }
+
+ return (numChars);
+}
+
+void gdb_stub_get_non_pt_regs(gdb_pt_regs *regs)
+{
+ s390_fp_regs *fpregs=&regs->fp_regs;
+ int has_ieee=save_fp_regs1(fpregs);
+
+ if(!has_ieee)
+ {
+ fpregs->fpc=0;
+ fpregs->fprs[1].d=
+ fpregs->fprs[3].d=
+ fpregs->fprs[5].d=
+ fpregs->fprs[7].d=0;
+ memset(&fpregs->fprs[8].d,0,sizeof(freg_t)*8);
+ }
+}
+
+void gdb_stub_set_non_pt_regs(gdb_pt_regs *regs)
+{
+ restore_fp_regs1(&regs->fp_regs);
+}
+
+void gdb_stub_send_signal(int sigval)
+{
+ char *ptr;
+ ptr = output_buffer;
+
+ /*
+ * Send trap type (converted to signal)
+ */
+ *ptr++ = 'S';
+ *ptr++ = hexchars[sigval >> 4];
+ *ptr++ = hexchars[sigval & 0xf];
+ *ptr++ = 0;
+ putpacket(output_buffer); /* send it off... */
+}
+
+/*
+ * This function does all command processing for interfacing to gdb. It
+ * returns 1 if you should skip the instruction at the trap address, 0
+ * otherwise.
+ */
+void gdb_stub_handle_exception(gdb_pt_regs *regs,int sigval)
+{
+ int trap; /* Trap type */
+ int addr;
+ int length;
+ char *ptr;
+ unsigned long *stack;
+
+
+ /*
+ * reply to host that an exception has occurred
+ */
+ send_signal(sigval);
+
+ /*
+ * Wait for input from remote GDB
+ */
+ while (1) {
+ output_buffer[0] = 0;
+ getpacket(input_buffer);
+
+ switch (input_buffer[0])
+ {
+ case '?':
+ send_signal(sigval);
+ continue;
+
+ case 'd':
+ /* toggle debug flag */
+ break;
+
+ /*
+ * Return the value of the CPU registers
+ */
+ case 'g':
+ gdb_stub_get_non_pt_regs(regs);
+ ptr = output_buffer;
+ ptr= mem2hex((char *)regs,ptr,sizeof(s390_regs_common),FALSE);
+ ptr= mem2hex((char *)&regs->crs[0],ptr,NUM_CRS*CR_SIZE,FALSE);
+ ptr = mem2hex((char *)&regs->fp_regs, ptr,sizeof(s390_fp_regs));
+ break;
+
+ /*
+ * set the value of the CPU registers - return OK
+ * FIXME: Needs to be written
+ */
+ case 'G':
+ ptr=input_buffer;
+ hex2mem (ptr, (char *)regs,sizeof(s390_regs_common), FALSE);
+ ptr+=sizeof(s390_regs_common)*2;
+ hex2mem (ptr, (char *)regs->crs[0],NUM_CRS*CR_SIZE, FALSE);
+ ptr+=NUM_CRS*CR_SIZE*2;
+ hex2mem (ptr, (char *)regs->fp_regs,sizeof(s390_fp_regs), FALSE);
+ gdb_stub_set_non_pt_regs(regs);
+ strcpy(output_buffer,"OK");
+ break;
+
+ /*
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA
+ */
+ case 'm':
+ ptr = &input_buffer[1];
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)) {
+ if (mem2hex((char *)addr, output_buffer, length, 1))
+ break;
+ strcpy (output_buffer, "E03");
+ } else
+ strcpy(output_buffer,"E01");
+ break;
+
+ /*
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
+ */
+ case 'M':
+ ptr = &input_buffer[1];
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)
+ && *ptr++ == ':') {
+ if (hex2mem(ptr, (char *)addr, length, 1))
+ strcpy(output_buffer, "OK");
+ else
+ strcpy(output_buffer, "E03");
+ }
+ else
+ strcpy(output_buffer, "E02");
+ break;
+
+ /*
+ * cAA..AA Continue at address AA..AA(optional)
+ */
+ case 'c':
+ /* try to read optional parameter, pc unchanged if no parm */
+
+ ptr = &input_buffer[1];
+ if (hexToInt(&ptr, &addr))
+ regs->cp0_epc = addr;
+
+ /*
+ * Need to flush the instruction cache here, as we may
+ * have deposited a breakpoint, and the icache probably
+ * has no way of knowing that a data ref to some location
+ * may have changed something that is in the instruction
+ * cache.
+ * NB: We flush both caches, just to be sure...
+ */
+
+ flush_cache_all();
+ return;
+ /* NOTREACHED */
+ break;
+
+
+ /*
+ * kill the program
+ */
+ case 'k' :
+ break; /* do nothing */
+
+
+ /*
+ * Reset the whole machine (FIXME: system dependent)
+ */
+ case 'r':
+ break;
+
+
+ /*
+ * Step to next instruction
+ */
+ case 's':
+ /*
+ * There is no single step insn in the MIPS ISA, so we
+ * use breakpoints and continue, instead.
+ */
+ single_step(regs);
+ flush_cache_all();
+ return;
+ /* NOTREACHED */
+
+ }
+ break;
+
+ } /* switch */
+
+ /*
+ * reply to the request
+ */
+
+ putpacket(output_buffer);
+
+ } /* while */
+}
+
+/*
+ * This function will generate a breakpoint exception. It is used at the
+ * beginning of a program to sync up with a debugger and can be used
+ * otherwise as a quick means to stop program execution and "break" into
+ * the debugger.
+ */
+void breakpoint(void)
+{
+ if (!gdb_stub_initialised)
+ return;
+ __asm__ __volatile__(
+ ".globl breakinst\n"
+ "breakinst:\t.word %0\n\t"
+ :
+ : "i" (S390_BREAKPOINT_U16)
+ :
+ );
+}
+
+
+
+
+
+
+
diff --git a/arch/s390x/kernel/head.S b/arch/s390x/kernel/head.S
new file mode 100644
index 000000000..2b72a62c8
--- /dev/null
+++ b/arch/s390x/kernel/head.S
@@ -0,0 +1,598 @@
+/*
+ * arch/s390/kernel/head.S
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Rob van der Heij (rvdhei@iae.nl)
+ *
+ * There are 5 different IPL methods
+ * 1) load the image directly into ram at address 0 and do an PSW restart
+ * 2) linload will load the image from address 0x10000 to memory 0x10000
+ * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
+ * 3) generate the tape ipl header, store the generated image on a tape
+ * and ipl from it
+ * In case of SL tape you need to IPL 5 times to get past VOL1 etc
+ * 4) generate the vm reader ipl header, move the generated image to the
+ * VM reader (use option NOH!) and do a ipl from reader (VM only)
+ * 5) direct call of start by the SALIPL loader
+ * We use the cpuid to distinguish between VM and native ipl
+ * params for kernel are pushed to 0x10400 (see setup.h)
+
+ Changes:
+ Okt 25 2000 <rvdheij@iae.nl>
+ added code to skip HDR and EOF to allow SL tape IPL (5 retries)
+ changed first CCW from rewind to backspace block
+
+ */
+
+#include <linux/config.h>
+#include <asm/setup.h>
+#include <asm/lowcore.h>
+
+#ifndef CONFIG_IPL
+ .org 0
+ .long 0x00080000,0x80000000+startup # Just a restart PSW
+#else
+#ifdef CONFIG_IPL_TAPE
+#define IPL_BS 1024
+ .org 0
+ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+ .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
+ .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
+ .long 0x00000000,0x00000000 # external old psw
+ .long 0x00000000,0x00000000 # svc old psw
+ .long 0x00000000,0x00000000 # program check old psw
+ .long 0x00000000,0x00000000 # machine check old psw
+ .long 0x00000000,0x00000000 # io old psw
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x000a0000,0x00000058 # external new psw
+ .long 0x000a0000,0x00000060 # svc new psw
+ .long 0x000a0000,0x00000068 # program check new psw
+ .long 0x000a0000,0x00000070 # machine check new psw
+ .long 0x00080000,0x80000000+.Lioint # io new psw
+
+ .org 0x100
+#
+# subroutine for loading from tape
+# Paramters:
+# R1 = device number
+# R2 = load address
+.Lloader:
+ st %r14,.Lldret
+ la %r3,.Lorbread # r3 = address of orb
+ la %r5,.Lirb # r5 = address of irb
+ st %r2,.Lccwread+4 # initialize CCW data addresses
+ lctl %c6,%c6,.Lcr6
+ slr %r2,%r2
+.Lldlp:
+ la %r6,3 # 3 retries
+.Lssch:
+ ssch 0(%r3) # load chunk of IPL_BS bytes
+ bnz .Llderr
+.Lw4end:
+ bas %r14,.Lwait4io
+ tm 8(%r5),0x82 # do we have a problem ?
+ bnz .Lrecov
+ slr %r7,%r7
+ icm %r7,3,10(%r5) # get residual count
+ lcr %r7,%r7
+ la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
+ ar %r2,%r7 # add to total size
+ tm 8(%r5),0x01 # found a tape mark ?
+ bnz .Ldone
+ l %r0,.Lccwread+4 # update CCW data addresses
+ ar %r0,%r7
+ st %r0,.Lccwread+4
+ b .Lldlp
+.Ldone:
+ l %r14,.Lldret
+ br %r14 # r2 contains the total size
+.Lrecov:
+ bas %r14,.Lsense # do the sensing
+ bct %r6,.Lssch # dec. retry count & branch
+ b .Llderr
+#
+# Sense subroutine
+#
+.Lsense:
+ st %r14,.Lsnsret
+ la %r7,.Lorbsense
+ ssch 0(%r7) # start sense command
+ bnz .Llderr
+ bas %r14,.Lwait4io
+ l %r14,.Lsnsret
+ tm 8(%r5),0x82 # do we have a problem ?
+ bnz .Llderr
+ br %r14
+#
+# Wait for interrupt subroutine
+#
+.Lwait4io:
+ lpsw .Lwaitpsw
+.Lioint:
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwait4io
+ tsch 0(%r5)
+ slr %r0,%r0
+ tm 8(%r5),0x82 # do we have a problem ?
+ bnz .Lwtexit
+ tm 8(%r5),0x04 # got device end ?
+ bz .Lwait4io
+.Lwtexit:
+ br %r14
+.Llderr:
+ lpsw .Lcrash
+
+ .align 8
+.Lorbread:
+ .long 0x00000000,0x0080ff00,.Lccwread
+ .align 8
+.Lorbsense:
+ .long 0x00000000,0x0080ff00,.Lccwsense
+ .align 8
+.Lccwread:
+ .long 0x02200000+IPL_BS,0x00000000
+.Lccwsense:
+ .long 0x04200001,0x00000000
+.Lwaitpsw:
+ .long 0x020a0000,0x80000000+.Lioint
+
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6: .long 0xff000000
+ .align 8
+.Lcrash:.long 0x000a0000,0x00000000
+.Lldret:.long 0
+.Lsnsret: .long 0
+#endif /* CONFIG_IPL_TAPE */
+
+#ifdef CONFIG_IPL_VM
+#define IPL_BS 0x730
+ .org 0
+ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+ .long 0x02000018,0x60000050 # by ipl to addresses 0-23.
+ .long 0x02000068,0x60000050 # (a PSW and two CCWs).
+ .fill 80-24,1,0x40 # bytes 24-79 are discarded !!
+ .long 0x020000f0,0x60000050 # The next 160 byte are loaded
+ .long 0x02000140,0x60000050 # to addresses 0x18-0xb7
+ .long 0x02000190,0x60000050 # They form the continuation
+ .long 0x020001e0,0x60000050 # of the CCW program started
+ .long 0x02000230,0x60000050 # by ipl and load the range
+ .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image
+ .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730
+ .long 0x02000320,0x60000050 # in memory. At the end of
+ .long 0x02000370,0x60000050 # the channel program the PSW
+ .long 0x020003c0,0x60000050 # at location 0 is loaded.
+ .long 0x02000410,0x60000050 # Initial processing starts
+ .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
+ .long 0x020004b0,0x60000050
+ .long 0x02000500,0x60000050
+ .long 0x02000550,0x60000050
+ .long 0x020005a0,0x60000050
+ .long 0x020005f0,0x60000050
+ .long 0x02000640,0x60000050
+ .long 0x02000690,0x60000050
+ .long 0x020006e0,0x20000050
+
+ .org 0xf0
+#
+# subroutine for loading cards from the reader
+#
+.Lloader:
+ la %r3,.Lorb # r2 = address of orb into r2
+ la %r5,.Lirb # r4 = address of irb
+ la %r6,.Lccws
+ la %r7,20
+.Linit:
+ st %r2,4(%r6) # initialize CCW data addresses
+ la %r2,0x50(%r2)
+ la %r6,8(%r6)
+ bct 7,.Linit
+
+ lctl %c6,%c6,.Lcr6 # set IO subclass mask
+ slr %r2,%r2
+.Lldlp:
+ ssch 0(%r3) # load chunk of 1600 bytes
+ bnz .Llderr
+.Lwait4irq:
+ mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
+ lpsw .Lwaitpsw
+.Lioint:
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwait4irq
+ tsch 0(%r5)
+
+ slr %r0,%r0
+ ic %r0,8(%r5) # get device status
+ chi %r0,8 # channel end ?
+ be .Lcont
+ chi %r0,12 # channel end + device end ?
+ be .Lcont
+
+ l %r0,4(%r5)
+ s %r0,8(%r3) # r0/8 = number of ccws executed
+ mhi %r0,10 # *10 = number of bytes in ccws
+ lh %r3,10(%r5) # get residual count
+ sr %r0,%r3 # #ccws*80-residual=#bytes read
+ ar %r2,%r0
+
+ br %r14 # r2 contains the total size
+
+.Lcont:
+ ahi %r2,0x640 # add 0x640 to total size
+ la %r6,.Lccws
+ la %r7,20
+.Lincr:
+ l %r0,4(%r6) # update CCW data addresses
+ ahi %r0,0x640
+ st %r0,4(%r6)
+ ahi %r6,8
+ bct 7,.Lincr
+
+ b .Lldlp
+.Llderr:
+ lpsw .Lcrash
+
+ .align 8
+.Lorb: .long 0x00000000,0x0080ff00,.Lccws
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6: .long 0xff000000
+.Lloadp:.long 0,0
+ .align 8
+.Lcrash:.long 0x000a0000,0x00000000
+.Lnewpsw:
+ .long 0x00080000,0x80000000+.Lioint
+.Lwaitpsw:
+ .long 0x020a0000,0x80000000+.Lioint
+
+ .align 8
+.Lccws: .rept 19
+ .long 0x02600050,0x00000000
+ .endr
+ .long 0x02200050,0x00000000
+#endif /* CONFIG_IPL_VM */
+
+iplstart:
+ lh %r1,0xb8 # test if subchannel number
+ bct %r1,.Lnoload # is valid
+ l %r1,0xb8 # load ipl subchannel number
+ la %r2,IPL_BS # load start address
+ bas %r14,.Lloader # load rest of ipl image
+ st %r1,__LC_IPLDEV # store ipl device number
+ l %r12,.Lparm # pointer to parameter area
+
+#
+# load parameter file from ipl device
+#
+.Lagain1:
+ l %r2,INITRD_START+4-PARMAREA(%r12)# use ramdisk location as temp
+ bas %r14,.Lloader # load parameter file
+ ltr %r2,%r2 # got anything ?
+ bz .Lnopf
+ chi %r2,895
+ bnh .Lnotrunc
+ la %r2,895
+.Lnotrunc:
+ l %r4,INITRD_START+4-PARMAREA(%r12)
+ clc 0(3,%r4),.L_hdr # if it is HDRx
+ bz .Lagain1 # skip dataset header
+ clc 0(3,%r4),.L_eof # if it is EOFx
+ bz .Lagain1 # skip dateset trailer
+ la %r5,0(%r4,%r2)
+ lr %r3,%r2
+.Lidebc:
+ tm 0(%r5),0x80 # high order bit set ?
+ bo .Ldocv # yes -> convert from EBCDIC
+ ahi %r5,-1
+ bct %r3,.Lidebc
+ b .Lnocv
+.Ldocv:
+ l %r3,.Lcvtab
+ tr 0(256,%r4),0(%r3) # convert parameters to ascii
+ tr 256(256,%r4),0(%r3)
+ tr 512(256,%r4),0(%r3)
+ tr 768(122,%r4),0(%r3)
+.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+ mvc 0(256,%r3),0(%r4)
+ mvc 256(256,%r3),256(%r4)
+ mvc 512(256,%r3),512(%r4)
+ mvc 768(122,%r3),768(%r4)
+ slr %r0,%r0
+ b .Lcntlp
+.Ldelspc:
+ ic %r0,0(%r3)
+ ic %r0,0(%r2,%r3)
+ chi %r0,0x20 # is it a space ?
+ be .Lcntlp
+ ahi %r2,1
+ b .Leolp
+.Lcntlp:
+ brct %r2,.Ldelspc
+.Leolp:
+ slr %r0,%r0
+ stc %r0,0(%r2,%r3) # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from ipl device
+#
+.Lagain2:
+ l %r2,INITRD_START+4-PARMAREA(%r12)# load adr. of ramdisk
+ bas %r14,.Lloader # load ramdisk
+ st %r2,INITRD_SIZE+4-PARMAREA(%r12) # store size of ramdisk
+ ltr %r2,%r2
+ bnz .Lrdcont
+ st %r2,INITRD_START+4-PARMAREA(%r12)# no ramdisk found, null it
+.Lrdcont:
+ l %r2,INITRD_START-PARMAREA(%r12)
+ clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
+ bz .Lagain2
+ clc 0(3,%r2),.L_eof
+ bz .Lagain2
+
+#ifdef CONFIG_IPL_VM
+#
+# reset files in VM reader
+#
+ stidp __LC_CPUID # store cpuid
+ lh %r0,__LC_CPUID+4 # get cpu version
+ chi %r0,0x7490 # running on P/390 ?
+ be start # no -> skip reset
+ la %r2,.Lreset
+ lhi %r3,26
+ .long 0x83230008
+#endif
+
+#
+# everything loaded, go for it
+#
+.Lnoload:
+ l %r1,.Lstartup
+ br %r1
+
+.Lparm: .long PARMAREA
+.Lstartup: .long startup
+.Lcvtab:.long _ebcasc # ebcdic to ascii table
+.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+ .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+ .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
+.L_eof: .long 0xc5d6c600 /* C'EOF' */
+.L_hdr: .long 0xc8c4d900 /* C'HDR' */
+#endif /* CONFIG_IPL */
+
+#
+# SALIPL loader support. Based on a patch by Rob van der Heij.
+# This entry point is called directly from the SALIPL loader and
+# doesn't need a builtin ipl record.
+#
+ .org 0x800
+ .globl start
+start:
+ stm %r0,%r15,0x07b0 # store registers
+ basr %r12,%r0
+.base:
+ l %r11,.parm
+ l %r8,.cmd # pointer to command buffer
+
+ ltr %r9,%r9 # do we have SALIPL parameters?
+ bp .sk8x8
+
+ mvc 0(64,%r8),0x00b0 # copy saved registers
+ xc 64(240-64,%r8),0(%r8) # remainder of buffer
+ tr 0(64,%r8),.lowcase
+ b .gotr
+.sk8x8:
+ mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
+.gotr:
+ l %r10,.tbl # EBCDIC to ASCII table
+ tr 0(240,%r8),0(%r10)
+ stidp __LC_CPUID # Are we running on VM maybe
+ cli __LC_CPUID,0xff
+ bnz .test
+ .long 0x83300060 # diag 3,0,x'0060' - storage size
+ b .done
+.test:
+ mvc 0x68(8),.pgmnw # set up pgm check handler
+ l %r2,.fourmeg
+ lr %r3,%r2
+ bctr %r3,%r0 # 4M-1
+.loop: iske %r0,%r3
+ ar %r3,%r2
+.pgmx:
+ sr %r3,%r2
+ la %r3,1(%r3)
+.done:
+ st %r3,MEMORY_SIZE-PARMAREA(%r11)
+ slr %r0,%r0
+ st %r0,INITRD_SIZE-PARMAREA(%r11)
+ st %r0,INITRD_START-PARMAREA(%r11)
+ j startup # continue with startup
+.tbl: .long _ebcasc # translate table
+.cmd: .long COMMAND_LINE # address of command line buffer
+.parm: .long PARMAREA
+.fourmeg: .long 0x00400000 # 4M
+.pgmnw: .long 0x00080000,.pgmx
+.lowcase:
+ .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
+ .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+ .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
+ .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
+ .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
+ .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+ .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
+ .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
+ .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
+ .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
+ .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
+ .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
+ .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
+ .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
+ .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
+ .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
+
+ .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
+ .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
+ .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
+ .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
+ .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
+ .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
+ .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
+ .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
+ .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
+ .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi
+ .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
+ .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr
+ .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx
+ .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz
+ .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
+ .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+
+#
+# startup-code at 0x10000, running in real mode
+# this is called either by the ipl loader or directly by PSW restart
+# or linload or SALIPL
+#
+ .org 0x10000
+startup:basr %r13,0 # get base
+.LPG1: n %r13,.Lhighoff-.LPG1(%r13) # remove high order bit
+ lhi %r1,1 # mode 1 = esame
+ slr %r0,%r0 # set cpuid to zero
+ sigp %r1,%r0,0x12 # switch to esame mode
+ sam64 # switch to 64 bit mode
+ lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
+ lg %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area
+
+#
+# find out memory size.
+#
+ mvc 0x1d0(16),.Lpcmem-.LPG1(%r13) # setup program check handler
+ lghi %r2,1
+ sllg %r2,%r2,17 # test in increments of 128KB
+ lgr %r1,%r2
+ aghi %r1,-8 # test last word in the segment
+.Lloop:
+ lg %r0,0(%r1) # test 128KB segment
+ stg %r0,0(%r1)
+ agr %r1,%r2 # add 128KB
+ bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop
+.Lchkmem:
+ ng %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M
+ stg %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size
+#
+# find out if we are running under VM
+#
+ stidp __LC_CPUID # store cpuid
+ tm __LC_CPUID,0xff # running under VM ?
+ bno .Lnovm-.LPG1(%r13)
+ oi MACHINE_FLAGS+7-PARMAREA(%r12),1 # set VM flag
+.Lnovm:
+ lh %r0,__LC_CPUID+4 # get cpu version
+ chi %r0,0x7490 # running on a P/390 ?
+ bne .Lnop390-.LPG1(%r13)
+ oi MACHINE_FLAGS+7-PARMAREA(%r12),4 # set P/390 flag
+.Lnop390:
+
+ lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
+ # virtual and never return ...
+ .align 16
+.Lentry:.quad 0x0000000180000000,_stext
+.Lctl: .quad 0x04b50002 # cr0: various things
+ .quad 0 # cr1: primary space segment table
+ .quad 0 # cr2: access register translation
+ .quad 0 # cr3: instruction authorization
+ .quad 0 # cr4: instruction authorization
+ .quad 0 # cr5: various things
+ .quad 0 # cr6: I/O interrupts
+ .quad 0 # cr7: secondary space segment table
+ .quad 0 # cr8: access registers translation
+ .quad 0 # cr9: tracing off
+ .quad 0 # cr10: tracing off
+ .quad 0 # cr11: tracing off
+ .quad 0 # cr12: tracing off
+ .quad 0 # cr13: home space segment table
+ .quad 0xc0000000 # cr14: machine check handling off
+ .quad 0 # cr15: linkage stack operations
+.Lpcmem:.quad 0x0000000180000000,.Lchkmem
+.Lflt0: .double 0
+.Lparm1:.quad PARMAREA
+.Lhighoff:.long 0x7fffffff
+.L4malign:.quad 0xffffffffffc00000
+.Lbigmem:.quad 0x04000000
+.Lmaxchunk:.quad 0x00ffffff
+
+#
+# params at 10400 (setup.h)
+#
+ .org PARMAREA
+ .quad 0x0100 # ORIG_ROOT_DEV: ramdisk major/minor
+ .word 0 # MOUNT_ROOT_RDONLY: no
+ .quad 0 # MEMORY_SIZE
+ .quad 0 # MACHINE_FLAGS (bit 0:VM)
+ .quad RAMDISK_ORIGIN # INITRD_START
+ .quad RAMDISK_SIZE # INITRD_SIZE
+ .word 0 # RAMDISK_FLAGS
+
+ .org COMMAND_LINE
+ .byte "root=/dev/ram0 ro"
+ .byte 0
+
+#
+# startup-code, running in virtual mode
+#
+ .org 0x10800
+ .globl _stext
+_stext: basr %r13,0 # get base
+.LPG2:
+#
+# Setup lowcore
+#
+ l %r1,__LC_IPLDEV # load ipl device number
+ spx .Lprefix-.LPG2(%r13) # set prefix to linux lowcore
+ st %r1,__LC_IPLDEV # store ipl device number
+ lg %r15,.Linittu-.LPG2(%r13)
+ aghi %r15,16384 # init_task_union + 16384
+ stg %r15,__LC_KERNEL_STACK # set end of kernel stack
+ aghi %r15,-160
+ xc 0(8,%r15),0(%r15) # set backchain to zero
+ lghi %r0,-1
+ stg %r0,__LC_KERNEL_LEVEL # set interrupt count to -1
+#
+# clear bss memory
+#
+ lg %r2,.Lbss_bgn-.LPG2(%r13) # start of bss
+ lg %r3,.Lbss_end-.LPG2(%r13) # end of bss
+ sgr %r3,%r2 # length of bss
+ sgr %r4,%r4 #
+ sgr %r5,%r5 # set src,length and pad to zero
+ mvcle %r2,%r4,0 # clear mem
+ jo .-4 # branch back, if not finish
+# check control registers
+ stctg %c0,%c15,0(%r15)
+ oc 6(1,%r15),.Locbits+5-.LPG2(%r13) # enable sigp external ints.
+ oc 4(1,%r15),.Locbits+4-.LPG2(%r13) # low addresss proctection
+ lctlg %c0,%c15,0(%r15)
+
+#
+ lam 0,15,.Laregs-.LPG2(%r13) # load access regs needed by uaccess
+ brasl %r14,start_kernel # go to C code
+#
+# We returned from start_kernel ?!? PANIK
+#
+ basr %r13,0
+ lpswe .Ldw-.(%r13) # load disabled wait psw
+#
+.Lstart: .quad start_kernel
+ .align 8
+.Lprefix: .long init_S390_lowcore
+.Linittu: .quad init_task_union
+.Lbss_bgn: .quad __bss_start
+.Lbss_end: .quad _end
+.Locbits: .quad 0x0102040810204080
+ .align 4
+.Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
+ .align 8
+.Ldw: .quad 0x0002000180000000,0x0000000000000000
+
diff --git a/arch/s390x/kernel/ieee.h b/arch/s390x/kernel/ieee.h
new file mode 100644
index 000000000..ef7cc29de
--- /dev/null
+++ b/arch/s390x/kernel/ieee.h
@@ -0,0 +1,90 @@
+/*
+ * arch/s390/kernel/ieee.h
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#include <linux/sched.h>
+
+static inline void _adddf(int R1,int R2)
+{
+ current->tss.fprs[R1].fd = current->tss.fprs[R1].fd +
+ current->tss.fprs[R2].fd;
+}
+
+static inline void _subdf(int R1,int R2)
+{
+ current->tss.fprs[R1].fd = current->tss.fprs[R1].fd -
+ current->tss.fprs[R2].fd;
+}
+
+static inline void _muldf(int R1,int R2)
+{
+ current->tss.fprs[R1].fd = current->tss.fprs[R1].fd *
+ current->tss.fprs[R2].fd;
+}
+
+static inline void _divdf(int R1,int R2)
+{
+ current->tss.fprs[R1].fd = current->tss.fprs[R1].fd /
+ current->tss.fprs[R2].fd;
+}
+
+static inline void _negdf(int R1,int R2)
+{
+ current->tss.fprs[R1].fd = -current->tss.fprs[R1].fd;
+}
+
+static inline void _fixdfsi(int R1,int R2)
+{
+ current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].fd;
+}
+
+static inline void _extendsidf(int R1,int R2)
+{
+ current->tss.fprs[R1].fd = (double) current->tss.regs->gprs[R2];
+}
+
+
+static inline void _addsf(int R1,int R2)
+{
+ current->tss.fprs[R1].ff = current->tss.fprs[R1].ff +
+ current->tss.fprs[R2].ff;
+}
+
+static inline void _subsf(int R1,int R2)
+{
+ current->tss.fprs[R1].ff = current->tss.fprs[R1].ff -
+ current->tss.fprs[R2].ff;
+}
+
+static inline void _mulsf(int R1,int R2)
+{
+ current->tss.fprs[R1].ff = current->tss.fprs[R1].ff *
+ current->tss.fprs[R2].ff;
+}
+
+static inline void _divsf(int R1,int R2)
+{
+ current->tss.fprs[R1].ff = current->tss.fprs[R1].ff /
+ current->tss.fprs[R2].ff;
+}
+
+static inline void _negsf(int R1,int R2)
+{
+ current->tss.fprs[R1].ff = -current->tss.fprs[R1].ff;
+}
+
+static inline void _fixsfsi(int R1,int R2)
+{
+ current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].ff;
+}
+
+static inline void _extendsisf(int R1,int R2)
+{
+ current->tss.fprs[R1].ff = (double) current->tss.regs->gprs[R2];
+}
+
+
diff --git a/arch/s390x/kernel/init_task.c b/arch/s390x/kernel/init_task.c
new file mode 100644
index 000000000..74cf730b0
--- /dev/null
+++ b/arch/s390x/kernel/init_task.c
@@ -0,0 +1,32 @@
+/*
+ * arch/s390/kernel/init_task.c
+ *
+ * S390 version
+ *
+ * Derived from "arch/i386/kernel/init_task.c"
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+static struct vm_area_struct init_mmap = INIT_MMAP;
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS;
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+/*
+ * Initial task structure.
+ *
+ * We need to make sure that this is 16384-byte aligned due to the
+ * way process stacks are handled. This is done by making sure
+ * the linker maps this in the .text segment right after head.S,
+ * and making head.S ensure the proper alignment.
+ *
+ * The things we do for performance..
+ */
+union task_union init_task_union __attribute__((aligned(16384))) =
+ { INIT_TASK(init_task_union.task) };
diff --git a/arch/s390x/kernel/ioctl32.c b/arch/s390x/kernel/ioctl32.c
new file mode 100644
index 000000000..fbc63aac2
--- /dev/null
+++ b/arch/s390x/kernel/ioctl32.c
@@ -0,0 +1,563 @@
+/*
+ * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Gerhard Tonn (ton@de.ibm.com)
+ *
+ * Heavily inspired by the 32-bit Sparc compat code which is
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Written by Ulf Carlsson (ulfc@engr.sgi.com)
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/vt.h>
+#include <linux/kd.h>
+#include <linux/netdevice.h>
+#include <linux/route.h>
+#include <linux/ext2_fs.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+#include <asm/dasd.h>
+
+#include "linux32.h"
+
+long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+struct hd_geometry32 {
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ __u32 start;
+};
+
+static inline int hd_geometry_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct hd_geometry32 *hg32 = (struct hd_geometry32 *) A(arg);
+ struct hd_geometry hg;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_ioctl (fd, cmd, (long)&hg);
+ set_fs (old_fs);
+
+ if (ret)
+ return ret;
+
+ ret = put_user (hg.heads, &(hg32->heads));
+ ret |= __put_user (hg.sectors, &(hg32->sectors));
+ ret |= __put_user (hg.cylinders, &(hg32->cylinders));
+ ret |= __put_user (hg.start, &(hg32->start));
+
+ return ret;
+}
+
+struct timeval32 {
+ int tv_sec;
+ int tv_usec;
+};
+
+#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int)
+#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int)
+#define EXT2_IOC32_GETVERSION _IOR('v', 1, int)
+#define EXT2_IOC32_SETVERSION _IOW('v', 2, int)
+
+struct ifmap32 {
+ unsigned int mem_start;
+ unsigned int mem_end;
+ unsigned short base_addr;
+ unsigned char irq;
+ unsigned char dma;
+ unsigned char port;
+};
+
+struct ifreq32 {
+#define IFHWADDRLEN 6
+#define IFNAMSIZ 16
+ union {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ } ifr_ifrn;
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_ivalue;
+ int ifru_mtu;
+ struct ifmap32 ifru_map;
+ char ifru_slave[IFNAMSIZ]; /* Just fits the size */
+ char ifru_newname[IFNAMSIZ];
+ __u32 ifru_data;
+ } ifr_ifru;
+};
+
+struct ifconf32 {
+ int ifc_len; /* size of buffer */
+ __u32 ifcbuf;
+};
+
+static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct ireq32 *uir32 = (struct ireq32 *) A(arg);
+ struct net_device *dev;
+ struct ifreq32 ifr32;
+
+ if (copy_from_user(&ifr32, uir32, sizeof(struct ifreq32)))
+ return -EFAULT;
+
+ read_lock(&dev_base_lock);
+ dev = __dev_get_by_index(ifr32.ifr_ifindex);
+ if (!dev) {
+ read_unlock(&dev_base_lock);
+ return -ENODEV;
+ }
+
+ strcpy(ifr32.ifr_name, dev->name);
+ read_unlock(&dev_base_lock);
+
+ if (copy_to_user(uir32, &ifr32, sizeof(struct ifreq32)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static inline int dev_ifconf(unsigned int fd, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ioconf32 *uifc32 = (struct ioconf32 *) A(arg);
+ struct ifconf32 ifc32;
+ struct ifconf ifc;
+ struct ifreq32 *ifr32;
+ struct ifreq *ifr;
+ mm_segment_t old_fs;
+ int len;
+ int err;
+
+ if (copy_from_user(&ifc32, uifc32, sizeof(struct ifconf32)))
+ return -EFAULT;
+
+ if(ifc32.ifcbuf == 0) {
+ ifc32.ifc_len = 0;
+ ifc.ifc_len = 0;
+ ifc.ifc_buf = NULL;
+ } else {
+ ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32))) *
+ sizeof (struct ifreq);
+ ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
+ if (!ifc.ifc_buf)
+ return -ENOMEM;
+ }
+ ifr = ifc.ifc_req;
+ ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf);
+ len = ifc32.ifc_len / sizeof (struct ifreq32);
+ while (len--) {
+ if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) {
+ err = -EFAULT;
+ goto out;
+ }
+ }
+
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);
+ set_fs (old_fs);
+ if (err)
+ goto out;
+
+ ifr = ifc.ifc_req;
+ ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf);
+ len = ifc.ifc_len / sizeof (struct ifreq);
+ ifc32.ifc_len = len * sizeof (struct ifreq32);
+
+ while (len--) {
+ if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) {
+ err = -EFAULT;
+ goto out;
+ }
+ }
+
+ if (copy_to_user(uifc32, &ifc32, sizeof(struct ifconf32))) {
+ err = -EFAULT;
+ goto out;
+ }
+out:
+ if(ifc.ifc_buf != NULL)
+ kfree (ifc.ifc_buf);
+ return err;
+}
+
+static inline int dev_ifsioc(unsigned int fd, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ifreq32 *uifr = (struct ifreq32 *) A(arg);
+ struct ifreq ifr;
+ mm_segment_t old_fs;
+ int err;
+
+ switch (cmd) {
+ case SIOCSIFMAP:
+ err = copy_from_user(&ifr, uifr, sizeof(ifr.ifr_name));
+ err |= __get_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
+ err |= __get_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
+ err |= __get_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
+ err |= __get_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
+ err |= __get_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
+ err |= __get_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
+ if (err)
+ return -EFAULT;
+ break;
+ default:
+ if (copy_from_user(&ifr, uifr, sizeof(struct ifreq32)))
+ return -EFAULT;
+ break;
+ }
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+ set_fs (old_fs);
+ if (!err) {
+ switch (cmd) {
+ case SIOCGIFFLAGS:
+ case SIOCGIFMETRIC:
+ case SIOCGIFMTU:
+ case SIOCGIFMEM:
+ case SIOCGIFHWADDR:
+ case SIOCGIFINDEX:
+ case SIOCGIFADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCGIFNETMASK:
+ case SIOCGIFTXQLEN:
+ if (copy_to_user(uifr, &ifr, sizeof(struct ifreq32)))
+ return -EFAULT;
+ break;
+ case SIOCGIFMAP:
+ err = copy_to_user(uifr, &ifr, sizeof(ifr.ifr_name));
+ err |= __put_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start));
+ err |= __put_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end));
+ err |= __put_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr));
+ err |= __put_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq));
+ err |= __put_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma));
+ err |= __put_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port));
+ if (err)
+ err = -EFAULT;
+ break;
+ }
+ }
+ return err;
+}
+
+struct rtentry32
+{
+ unsigned int rt_pad1;
+ struct sockaddr rt_dst; /* target address */
+ struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */
+ struct sockaddr rt_genmask; /* target network mask (IP) */
+ unsigned short rt_flags;
+ short rt_pad2;
+ unsigned int rt_pad3;
+ unsigned int rt_pad4;
+ short rt_metric; /* +1 for binary compatibility! */
+ unsigned int rt_dev; /* forcing the device at add */
+ unsigned int rt_mtu; /* per route MTU/Window */
+#ifndef __KERNEL__
+#define rt_mss rt_mtu /* Compatibility :-( */
+#endif
+ unsigned int rt_window; /* Window clamping */
+ unsigned short rt_irtt; /* Initial RTT */
+};
+
+static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct rtentry32 *ur = (struct rtentry32 *) A(arg);
+ struct rtentry r;
+ char devname[16];
+ u32 rtdev;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ ret = copy_from_user (&r.rt_dst, &(ur->rt_dst), 3 * sizeof(struct sockaddr));
+ ret |= __get_user (r.rt_flags, &(ur->rt_flags));
+ ret |= __get_user (r.rt_metric, &(ur->rt_metric));
+ ret |= __get_user (r.rt_mtu, &(ur->rt_mtu));
+ ret |= __get_user (r.rt_window, &(ur->rt_window));
+ ret |= __get_user (r.rt_irtt, &(ur->rt_irtt));
+ ret |= __get_user (rtdev, &(ur->rt_dev));
+ if (rtdev) {
+ ret |= copy_from_user (devname, (char *) A(rtdev), 15);
+ r.rt_dev = devname; devname[15] = 0;
+ } else
+ r.rt_dev = 0;
+ if (ret)
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_ioctl (fd, cmd, (long)&r);
+ set_fs (old_fs);
+ return ret;
+}
+
+static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ /* These are just misnamed, they actually get/put from/to user an int */
+ switch (cmd) {
+ case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
+ case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
+ case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
+ case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
+ }
+ return sys_ioctl(fd, cmd, arg);
+}
+
+static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ mm_segment_t old_fs = get_fs();
+ int err;
+ unsigned long val;
+
+ set_fs (KERNEL_DS);
+ err = sys_ioctl(fd, cmd, (unsigned long)&val);
+ set_fs (old_fs);
+ if (!err && put_user((unsigned int) val, (u32 *)arg))
+ return -EFAULT;
+ return err;
+}
+
+struct ioctl32_handler {
+ unsigned int cmd;
+ int (*function)(unsigned int, unsigned int, unsigned long);
+};
+
+struct ioctl32_list {
+ struct ioctl32_handler handler;
+ struct ioctl32_list *next;
+};
+
+#define IOCTL32_DEFAULT(cmd) { { cmd, (void *) sys_ioctl }, 0 }
+#define IOCTL32_HANDLER(cmd, handler) { { cmd, (void *) handler }, 0 }
+
+static struct ioctl32_list ioctl32_handler_table[] = {
+ IOCTL32_DEFAULT(FIBMAP),
+ IOCTL32_DEFAULT(FIGETBSZ),
+
+ IOCTL32_DEFAULT(BIODASDDISABLE),
+ IOCTL32_DEFAULT(BIODASDENABLE),
+ IOCTL32_DEFAULT(BIODASDRSRV),
+ IOCTL32_DEFAULT(BIODASDRLSE),
+ IOCTL32_DEFAULT(BIODASDSLCK),
+ IOCTL32_DEFAULT(BIODASDRSID),
+ IOCTL32_DEFAULT(BIODASDFORMAT),
+ IOCTL32_DEFAULT(BIODASDRWTB),
+
+ IOCTL32_DEFAULT(BLKRRPART),
+
+ IOCTL32_HANDLER(HDIO_GETGEO, hd_geometry_ioctl),
+
+ IOCTL32_DEFAULT(TCGETA),
+ IOCTL32_DEFAULT(TCSETA),
+ IOCTL32_DEFAULT(TCSETAW),
+ IOCTL32_DEFAULT(TCSETAF),
+ IOCTL32_DEFAULT(TCSBRK),
+ IOCTL32_DEFAULT(TCXONC),
+ IOCTL32_DEFAULT(TCFLSH),
+ IOCTL32_DEFAULT(TCGETS),
+ IOCTL32_DEFAULT(TCSETS),
+ IOCTL32_DEFAULT(TCSETSW),
+ IOCTL32_DEFAULT(TCSETSF),
+ IOCTL32_DEFAULT(TIOCLINUX),
+
+ IOCTL32_DEFAULT(TIOCGETD),
+ IOCTL32_DEFAULT(TIOCSETD),
+ IOCTL32_DEFAULT(TIOCEXCL),
+ IOCTL32_DEFAULT(TIOCNXCL),
+ IOCTL32_DEFAULT(TIOCCONS),
+ IOCTL32_DEFAULT(TIOCGSOFTCAR),
+ IOCTL32_DEFAULT(TIOCSSOFTCAR),
+ IOCTL32_DEFAULT(TIOCSWINSZ),
+ IOCTL32_DEFAULT(TIOCGWINSZ),
+ IOCTL32_DEFAULT(TIOCMGET),
+ IOCTL32_DEFAULT(TIOCMBIC),
+ IOCTL32_DEFAULT(TIOCMBIS),
+ IOCTL32_DEFAULT(TIOCMSET),
+ IOCTL32_DEFAULT(TIOCPKT),
+ IOCTL32_DEFAULT(TIOCNOTTY),
+ IOCTL32_DEFAULT(TIOCSTI),
+ IOCTL32_DEFAULT(TIOCOUTQ),
+ IOCTL32_DEFAULT(TIOCSPGRP),
+ IOCTL32_DEFAULT(TIOCGPGRP),
+ IOCTL32_DEFAULT(TIOCSCTTY),
+ IOCTL32_DEFAULT(TIOCGPTN),
+ IOCTL32_DEFAULT(TIOCSPTLCK),
+ IOCTL32_DEFAULT(TIOCGSERIAL),
+ IOCTL32_DEFAULT(TIOCSSERIAL),
+ IOCTL32_DEFAULT(TIOCSERGETLSR),
+
+ IOCTL32_DEFAULT(FIOCLEX),
+ IOCTL32_DEFAULT(FIONCLEX),
+ IOCTL32_DEFAULT(FIOASYNC),
+ IOCTL32_DEFAULT(FIONBIO),
+ IOCTL32_DEFAULT(FIONREAD),
+
+ IOCTL32_DEFAULT(PIO_FONT),
+ IOCTL32_DEFAULT(GIO_FONT),
+ IOCTL32_DEFAULT(KDSIGACCEPT),
+ IOCTL32_DEFAULT(KDGETKEYCODE),
+ IOCTL32_DEFAULT(KDSETKEYCODE),
+ IOCTL32_DEFAULT(KIOCSOUND),
+ IOCTL32_DEFAULT(KDMKTONE),
+ IOCTL32_DEFAULT(KDGKBTYPE),
+ IOCTL32_DEFAULT(KDSETMODE),
+ IOCTL32_DEFAULT(KDGETMODE),
+ IOCTL32_DEFAULT(KDSKBMODE),
+ IOCTL32_DEFAULT(KDGKBMODE),
+ IOCTL32_DEFAULT(KDSKBMETA),
+ IOCTL32_DEFAULT(KDGKBMETA),
+ IOCTL32_DEFAULT(KDGKBENT),
+ IOCTL32_DEFAULT(KDSKBENT),
+ IOCTL32_DEFAULT(KDGKBSENT),
+ IOCTL32_DEFAULT(KDSKBSENT),
+ IOCTL32_DEFAULT(KDGKBDIACR),
+ IOCTL32_DEFAULT(KDSKBDIACR),
+ IOCTL32_DEFAULT(KDGKBLED),
+ IOCTL32_DEFAULT(KDSKBLED),
+ IOCTL32_DEFAULT(KDGETLED),
+ IOCTL32_DEFAULT(KDSETLED),
+ IOCTL32_DEFAULT(GIO_SCRNMAP),
+ IOCTL32_DEFAULT(PIO_SCRNMAP),
+ IOCTL32_DEFAULT(GIO_UNISCRNMAP),
+ IOCTL32_DEFAULT(PIO_UNISCRNMAP),
+ IOCTL32_DEFAULT(PIO_FONTRESET),
+ IOCTL32_DEFAULT(PIO_UNIMAPCLR),
+
+ IOCTL32_DEFAULT(VT_SETMODE),
+ IOCTL32_DEFAULT(VT_GETMODE),
+ IOCTL32_DEFAULT(VT_GETSTATE),
+ IOCTL32_DEFAULT(VT_OPENQRY),
+ IOCTL32_DEFAULT(VT_ACTIVATE),
+ IOCTL32_DEFAULT(VT_WAITACTIVE),
+ IOCTL32_DEFAULT(VT_RELDISP),
+ IOCTL32_DEFAULT(VT_DISALLOCATE),
+ IOCTL32_DEFAULT(VT_RESIZE),
+ IOCTL32_DEFAULT(VT_RESIZEX),
+ IOCTL32_DEFAULT(VT_LOCKSWITCH),
+ IOCTL32_DEFAULT(VT_UNLOCKSWITCH),
+
+ IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32),
+ IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf),
+ IOCTL32_HANDLER(SIOCGIFFLAGS, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFFLAGS, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFMETRIC, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFMETRIC, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFMTU, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFMTU, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFMEM, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFMEM, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFHWADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFHWADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCADDMULTI, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCDELMULTI, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFINDEX, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFMAP, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFMAP, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFBRDADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFBRDADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFDSTADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFDSTADDR, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFNETMASK, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFNETMASK, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFPFLAGS, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFPFLAGS, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCGIFTXQLEN, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCSIFTXQLEN, dev_ifsioc),
+ IOCTL32_HANDLER(SIOCADDRT, routing_ioctl),
+ IOCTL32_HANDLER(SIOCDELRT, routing_ioctl),
+
+ IOCTL32_HANDLER(EXT2_IOC32_GETFLAGS, do_ext2_ioctl),
+ IOCTL32_HANDLER(EXT2_IOC32_SETFLAGS, do_ext2_ioctl),
+ IOCTL32_HANDLER(EXT2_IOC32_GETVERSION, do_ext2_ioctl),
+ IOCTL32_HANDLER(EXT2_IOC32_SETVERSION, do_ext2_ioctl),
+
+ IOCTL32_HANDLER(BLKGETSIZE, w_long)
+
+};
+
+#define NR_IOCTL32_HANDLERS (sizeof(ioctl32_handler_table) / \
+ sizeof(ioctl32_handler_table[0]))
+
+static struct ioctl32_list *ioctl32_hash_table[1024];
+
+static inline int ioctl32_hash(unsigned int cmd)
+{
+ return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff;
+}
+
+int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+ struct file *filp;
+ struct ioctl32_list *l;
+ int error;
+
+ l = ioctl32_hash_table[ioctl32_hash(cmd)];
+
+ error = -EBADF;
+
+ filp = fget(fd);
+ if (!filp)
+ return error;
+
+ if (!filp->f_op || !filp->f_op->ioctl) {
+ error = sys_ioctl (fd, cmd, arg);
+ goto out;
+ }
+
+ while (l && l->handler.cmd != cmd)
+ l = l->next;
+
+ if (l) {
+ handler = (void *)l->handler.function;
+ error = handler(fd, cmd, arg, filp);
+ } else {
+ error = -EINVAL;
+ printk("unknown ioctl: %08x\n", cmd);
+ }
+out:
+ fput(filp);
+ return error;
+}
+
+static void ioctl32_insert(struct ioctl32_list *entry)
+{
+ int hash = ioctl32_hash(entry->handler.cmd);
+ if (!ioctl32_hash_table[hash])
+ ioctl32_hash_table[hash] = entry;
+ else {
+ struct ioctl32_list *l;
+ l = ioctl32_hash_table[hash];
+ while (l->next)
+ l = l->next;
+ l->next = entry;
+ entry->next = 0;
+ }
+}
+
+static int __init init_ioctl32(void)
+{
+ int i;
+ for (i = 0; i < NR_IOCTL32_HANDLERS; i++)
+ ioctl32_insert(&ioctl32_handler_table[i]);
+ return 0;
+}
+
+__initcall(init_ioctl32);
diff --git a/arch/s390x/kernel/irq.c b/arch/s390x/kernel/irq.c
new file mode 100644
index 000000000..5177a5ae8
--- /dev/null
+++ b/arch/s390x/kernel/irq.c
@@ -0,0 +1,423 @@
+/*
+ * arch/s390/kernel/irq.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *
+ * Derived from "arch/i386/kernel/irq.c"
+ * Copyright (C) 1992, 1999 Linus Torvalds, Ingo Molnar
+ *
+ * S/390 I/O interrupt processing and I/O request processing is
+ * implemented in arch/s390/kernel/s390io.c
+ */
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/smp.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/lowcore.h>
+
+void s390_init_IRQ ( void );
+void s390_free_irq ( unsigned int irq, void *dev_id);
+int s390_request_irq( unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id);
+
+#if 0
+/*
+ * The following vectors are part of the Linux architecture, there
+ * is no hardware IRQ pin equivalent for them, they are triggered
+ * through the ICC by us (IPIs), via smp_message_pass():
+ */
+BUILD_SMP_INTERRUPT(reschedule_interrupt)
+BUILD_SMP_INTERRUPT(invalidate_interrupt)
+BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
+BUILD_SMP_INTERRUPT(mtrr_interrupt)
+BUILD_SMP_INTERRUPT(spurious_interrupt)
+#endif
+
+#if 0
+int get_irq_list(char *buf)
+{
+ int i, j;
+ struct irqaction * action;
+ char *p = buf;
+
+ p += sprintf(p, " ");
+
+ for (j=0; j<smp_num_cpus; j++)
+ p += sprintf(p, "CPU%d ",j);
+
+ *p++ = '\n';
+
+ for (i = 0 ; i < NR_IRQS ; i++)
+ {
+ if (ioinfo[i] == INVALID_STORAGE_AREA)
+ continue;
+
+ action = ioinfo[i]->irq_desc.action;
+
+ if (!action)
+ continue;
+
+ p += sprintf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+ p += sprintf(p, "%10u ", kstat_irqs(i));
+#else
+ for (j=0; j<smp_num_cpus; j++)
+ p += sprintf( p, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
+#endif
+ p += sprintf(p, " %14s", ioinfo[i]->irq_desc.handler->typename);
+ p += sprintf(p, " %s", action->name);
+
+ for (action=action->next; action; action = action->next)
+ {
+ p += sprintf(p, ", %s", action->name);
+
+ } /* endfor */
+
+ *p++ = '\n';
+
+ } /* endfor */
+
+ p += sprintf(p, "NMI: %10u\n", nmi_counter);
+#ifdef CONFIG_SMP
+ p += sprintf(p, "IPI: %10u\n", atomic_read(&ipi_count));
+#endif
+
+ return p - buf;
+}
+#endif
+
+/*
+ * Global interrupt locks for SMP. Allow interrupts to come in on any
+ * CPU, yet make cli/sti act globally to protect critical regions..
+ */
+#ifdef CONFIG_SMP
+atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
+atomic_t global_irq_lock = ATOMIC_INIT(0);
+atomic_t global_irq_count = ATOMIC_INIT(0);
+atomic_t global_bh_count;
+
+/*
+ * "global_cli()" is a special case, in that it can hold the
+ * interrupts disabled for a longish time, and also because
+ * we may be doing TLB invalidates when holding the global
+ * IRQ lock for historical reasons. Thus we may need to check
+ * SMP invalidate events specially by hand here (but not in
+ * any normal spinlocks)
+ *
+ * Thankfully we don't need this as we can deliver flush tlbs with
+ * interrupts disabled DJB :-)
+ */
+#define check_smp_invalidate(cpu)
+
+static void show(char * str)
+{
+ int i;
+ unsigned long *stack;
+ int cpu = smp_processor_id();
+
+ printk("\n%s, CPU %d:\n", str, cpu);
+ printk("irq: %d [%d]\n",
+ atomic_read(&global_irq_count),local_irq_count(smp_processor_id()));
+ printk("bh: %d [%d]\n",
+ atomic_read(&global_bh_count),local_bh_count(smp_processor_id()));
+ stack = (unsigned long *) &str;
+ for (i = 40; i ; i--) {
+ unsigned long x = *++stack;
+ if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) {
+ printk("<[%08lx]> ", x);
+ }
+ }
+}
+
+#define MAXCOUNT 100000000
+
+static inline void wait_on_bh(void)
+{
+ int count = MAXCOUNT;
+ do {
+ if (!--count) {
+ show("wait_on_bh");
+ count = ~0;
+ }
+ /* nothing .. wait for the other bh's to go away */
+ } while (atomic_read(&global_bh_count) != 0);
+}
+
+static inline void wait_on_irq(int cpu)
+{
+ int count = MAXCOUNT;
+
+ for (;;) {
+
+ /*
+ * Wait until all interrupts are gone. Wait
+ * for bottom half handlers unless we're
+ * already executing in one..
+ */
+ if (!atomic_read(&global_irq_count)) {
+ if (local_bh_count(cpu)||
+ !atomic_read(&global_bh_count))
+ break;
+ }
+
+ /* Duh, we have to loop. Release the lock to avoid deadlocks */
+ atomic_set(&global_irq_lock, 0);
+
+ for (;;) {
+ if (!--count) {
+ show("wait_on_irq");
+ count = ~0;
+ }
+ __sti();
+ SYNC_OTHER_CORES(cpu);
+ __cli();
+ check_smp_invalidate(cpu);
+ if (atomic_read(&global_irq_count))
+ continue;
+ if (atomic_read(&global_irq_lock))
+ continue;
+ if (!local_bh_count(cpu)
+ && atomic_read(&global_bh_count))
+ continue;
+ if (!atomic_compare_and_swap(0, 1, &global_irq_lock))
+ break;
+ }
+ }
+}
+
+/*
+ * This is called when we want to synchronize with
+ * bottom half handlers. We need to wait until
+ * no other CPU is executing any bottom half handler.
+ *
+ * Don't wait if we're already running in an interrupt
+ * context or are inside a bh handler.
+ */
+void synchronize_bh(void)
+{
+ if (atomic_read(&global_bh_count) && !in_interrupt())
+ wait_on_bh();
+}
+
+/*
+ * This is called when we want to synchronize with
+ * interrupts. We may for example tell a device to
+ * stop sending interrupts: but to make sure there
+ * are no interrupts that are executing on another
+ * CPU we need to call this function.
+ */
+void synchronize_irq(void)
+{
+ if (atomic_read(&global_irq_count)) {
+ /* Stupid approach */
+ cli();
+ sti();
+ }
+}
+
+static inline void get_irqlock(int cpu)
+{
+ if (atomic_compare_and_swap(0,1,&global_irq_lock) != 0) {
+ /* do we already hold the lock? */
+ if ( cpu == atomic_read(&global_irq_holder))
+ return;
+ /* Uhhuh.. Somebody else got it. Wait.. */
+ do {
+ check_smp_invalidate(cpu);
+ } while (atomic_compare_and_swap(0,1,&global_irq_lock) != 0);
+ }
+ /*
+ * We also to make sure that nobody else is running
+ * in an interrupt context.
+ */
+ wait_on_irq(cpu);
+
+ /*
+ * Ok, finally..
+ */
+ atomic_set(&global_irq_holder,cpu);
+}
+
+#define EFLAGS_I_SHIFT 57
+
+/*
+ * A global "cli()" while in an interrupt context
+ * turns into just a local cli(). Interrupts
+ * should use spinlocks for the (very unlikely)
+ * case that they ever want to protect against
+ * each other.
+ *
+ * If we already have local interrupts disabled,
+ * this will not turn a local disable into a
+ * global one (problems with spinlocks: this makes
+ * save_flags+cli+sti usable inside a spinlock).
+ */
+void __global_cli(void)
+{
+ unsigned long flags;
+
+ __save_flags(flags);
+ if (flags & (1UL << EFLAGS_I_SHIFT)) {
+ int cpu = smp_processor_id();
+ __cli();
+ if (!in_irq())
+ get_irqlock(cpu);
+ }
+}
+
+void __global_sti(void)
+{
+
+ if (!in_irq())
+ release_irqlock(smp_processor_id());
+ __sti();
+}
+
+/*
+ * SMP flags value to restore to:
+ * 0 - global cli
+ * 1 - global sti
+ * 2 - local cli
+ * 3 - local sti
+ */
+unsigned long __global_save_flags(void)
+{
+ int retval;
+ int local_enabled;
+ unsigned long flags;
+
+ __save_flags(flags);
+ local_enabled = (flags >> EFLAGS_I_SHIFT) & 1;
+ /* default to local */
+ retval = 2 + local_enabled;
+
+ /* check for global flags if we're not in an interrupt */
+ if (!in_irq())
+ {
+ if (local_enabled)
+ retval = 1;
+ if (atomic_read(&global_irq_holder)== smp_processor_id())
+ retval = 0;
+ }
+ return retval;
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ switch (flags) {
+ case 0:
+ __global_cli();
+ break;
+ case 1:
+ __global_sti();
+ break;
+ case 2:
+ __cli();
+ break;
+ case 3:
+ __sti();
+ break;
+ default:
+ printk("global_restore_flags: %08lx (%08lx)\n",
+ flags, (&flags)[-1]);
+ }
+}
+
+#endif
+
+/*
+ * Note : This fuction should be eliminated as it doesn't comply with the
+ * S/390 irq scheme we have implemented ...
+ */
+int handle_IRQ_event(unsigned int irq, int cpu, struct pt_regs * regs)
+{
+ struct irqaction * action;
+ int status;
+
+ status = 0;
+
+ if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+ return( -ENODEV);
+
+ action = ioinfo[irq]->irq_desc.action;
+
+ if (action)
+ {
+ status |= 1;
+
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+
+ do
+ {
+ status |= action->flags;
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+
+ if (status & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ __cli();
+
+ } /* endif */
+
+ return status;
+}
+
+void enable_nop(int irq)
+{
+}
+
+void __init init_IRQ(void)
+{
+ s390_init_IRQ();
+}
+
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ s390_free_irq( irq, dev_id);
+}
+
+
+int request_irq( unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id)
+{
+ return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
+
+}
+
+void init_irq_proc(void)
+{
+ /* For now, nothing... */
+}
+
diff --git a/arch/s390x/kernel/irqextras390.c b/arch/s390x/kernel/irqextras390.c
new file mode 100644
index 000000000..e1e455813
--- /dev/null
+++ b/arch/s390x/kernel/irqextras390.c
@@ -0,0 +1,35 @@
+/*
+ * arch/s390/kernel/irqextras390.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * Some channel code by D.J. Barrow
+ */
+
+/*
+
+*/
+#include<asm/irqextras390.h>
+#include<asm/lowcore.h>
+
+#if 0
+// fixchannelprogram is now obselete
+void fixchannelprogram(orb_bits_t *orbptr)
+{
+ __u32 newAddress=orbptr->ccw_program_address;
+ fixccws(orbptr->ccw_program_address);
+ orbptr->ccw_program_address=newAddress;
+ orbptr->ccw_program_address=(ccw1_t *)(((__u32)orbptr->ccw_program_address));
+}
+#endif
+
+void fixccws(ccw1_bits_t *ccwptr)
+{
+ for(;;ccwptr++)
+ { // Just hope nobody starts doing prefixing
+ if(!ccwptr->cc)
+ break;
+ }
+}
diff --git a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c
new file mode 100644
index 000000000..668ac46c4
--- /dev/null
+++ b/arch/s390x/kernel/linux32.c
@@ -0,0 +1,4326 @@
+/*
+ * arch/s390x/kernel/linux32.c
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Gerhard Tonn (ton@de.ibm.com)
+ *
+ * Conversion between 31bit and 64bit native syscalls.
+ *
+ * Heavily inspired by the 32-bit Sparc compat code which is
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/signal.h>
+#include <linux/utime.h>
+#include <linux/resource.h>
+#include <linux/times.h>
+#include <linux/utsname.h>
+#include <linux/timex.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/malloc.h>
+#include <linux/uio.h>
+#include <linux/nfs_fs.h>
+#include <linux/smb_fs.h>
+#include <linux/smb_mount.h>
+#include <linux/ncp_fs.h>
+#include <linux/quota.h>
+#include <linux/module.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/cache.h>
+#include <linux/nfsd/xdr.h>
+#include <linux/nfsd/syscall.h>
+#include <linux/poll.h>
+#include <linux/personality.h>
+#include <linux/stat.h>
+#include <linux/filter.h>
+#include <linux/highmem.h>
+#include <linux/highuid.h>
+#include <linux/mman.h>
+#include <linux/ipv6.h>
+#include <linux/in.h>
+#include <linux/icmpv6.h>
+#include <linux/sysctl.h>
+
+#include <asm/types.h>
+#include <asm/ipc.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include <net/scm.h>
+
+#include "linux32.h"
+
+extern asmlinkage long sys_chown(const char *, uid_t,gid_t);
+extern asmlinkage long sys_lchown(const char *, uid_t,gid_t);
+extern asmlinkage long sys_fchown(unsigned int, uid_t,gid_t);
+extern asmlinkage long sys_setregid(gid_t, gid_t);
+extern asmlinkage long sys_setgid(gid_t);
+extern asmlinkage long sys_setreuid(uid_t, uid_t);
+extern asmlinkage long sys_setuid(uid_t);
+extern asmlinkage long sys_setresuid(uid_t, uid_t, uid_t);
+extern asmlinkage long sys_setresgid(gid_t, gid_t, gid_t);
+extern asmlinkage long sys_setfsuid(uid_t);
+extern asmlinkage long sys_setfsgid(gid_t);
+
+/* For this source file, we want overflow handling. */
+
+#undef high2lowuid
+#undef high2lowgid
+#undef low2highuid
+#undef low2highgid
+#undef SET_UID16
+#undef SET_GID16
+#undef NEW_TO_OLD_UID
+#undef NEW_TO_OLD_GID
+#undef SET_OLDSTAT_UID
+#undef SET_OLDSTAT_GID
+#undef SET_STAT_UID
+#undef SET_STAT_GID
+
+#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
+#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
+#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
+#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
+#define SET_UID16(var, uid) var = high2lowuid(uid)
+#define SET_GID16(var, gid) var = high2lowgid(gid)
+#define NEW_TO_OLD_UID(uid) high2lowuid(uid)
+#define NEW_TO_OLD_GID(gid) high2lowgid(gid)
+#define SET_OLDSTAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
+#define SET_OLDSTAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
+#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid)
+#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid)
+
+asmlinkage long sys32_chown16(const char * filename, u16 user, u16 group)
+{
+ return sys_chown(filename, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys32_lchown16(const char * filename, u16 user, u16 group)
+{
+ return sys_lchown(filename, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group)
+{
+ return sys_fchown(fd, low2highuid(user), low2highgid(group));
+}
+
+asmlinkage long sys32_setregid16(u16 rgid, u16 egid)
+{
+ return sys_setregid(low2highgid(rgid), low2highgid(egid));
+}
+
+asmlinkage long sys32_setgid16(u16 gid)
+{
+ return sys_setgid((gid_t)gid);
+}
+
+asmlinkage long sys32_setreuid16(u16 ruid, u16 euid)
+{
+ return sys_setreuid(low2highuid(ruid), low2highuid(euid));
+}
+
+asmlinkage long sys32_setuid16(u16 uid)
+{
+ return sys_setuid((uid_t)uid);
+}
+
+asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid)
+{
+ return sys_setresuid(low2highuid(ruid), low2highuid(euid),
+ low2highuid(suid));
+}
+
+asmlinkage long sys32_getresuid16(u16 *ruid, u16 *euid, u16 *suid)
+{
+ int retval;
+
+ if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
+ !(retval = put_user(high2lowuid(current->euid), euid)))
+ retval = put_user(high2lowuid(current->suid), suid);
+
+ return retval;
+}
+
+asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid)
+{
+ return sys_setresgid(low2highgid(rgid), low2highgid(egid),
+ low2highgid(sgid));
+}
+
+asmlinkage long sys32_getresgid16(u16 *rgid, u16 *egid, u16 *sgid)
+{
+ int retval;
+
+ if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
+ !(retval = put_user(high2lowgid(current->egid), egid)))
+ retval = put_user(high2lowgid(current->sgid), sgid);
+
+ return retval;
+}
+
+asmlinkage long sys32_setfsuid16(u16 uid)
+{
+ return sys_setfsuid((uid_t)uid);
+}
+
+asmlinkage long sys32_setfsgid16(u16 gid)
+{
+ return sys_setfsgid((gid_t)gid);
+}
+
+asmlinkage long sys32_getgroups16(int gidsetsize, u16 *grouplist)
+{
+ u16 groups[NGROUPS];
+ int i,j;
+
+ if (gidsetsize < 0)
+ return -EINVAL;
+ i = current->ngroups;
+ if (gidsetsize) {
+ if (i > gidsetsize)
+ return -EINVAL;
+ for(j=0;j<i;j++)
+ groups[j] = current->groups[j];
+ if (copy_to_user(grouplist, groups, sizeof(u16)*i))
+ return -EFAULT;
+ }
+ return i;
+}
+
+asmlinkage long sys32_setgroups16(int gidsetsize, u16 *grouplist)
+{
+ u16 groups[NGROUPS];
+ int i;
+
+ if (!capable(CAP_SETGID))
+ return -EPERM;
+ if ((unsigned) gidsetsize > NGROUPS)
+ return -EINVAL;
+ if (copy_from_user(groups, grouplist, gidsetsize * sizeof(u16)))
+ return -EFAULT;
+ for (i = 0 ; i < gidsetsize ; i++)
+ current->groups[i] = (gid_t)groups[i];
+ current->ngroups = gidsetsize;
+ return 0;
+}
+
+asmlinkage long sys32_getuid16(void)
+{
+ return high2lowuid(current->uid);
+}
+
+asmlinkage long sys32_geteuid16(void)
+{
+ return high2lowuid(current->euid);
+}
+
+asmlinkage long sys32_getgid16(void)
+{
+ return high2lowgid(current->gid);
+}
+
+asmlinkage long sys32_getegid16(void)
+{
+ return high2lowgid(current->egid);
+}
+
+/* 32-bit timeval and related flotsam. */
+
+struct timeval32
+{
+ int tv_sec, tv_usec;
+};
+
+struct itimerval32
+{
+ struct timeval32 it_interval;
+ struct timeval32 it_value;
+};
+
+static inline long get_tv32(struct timeval *o, struct timeval32 *i)
+{
+ return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) ||
+ (__get_user(o->tv_sec, &i->tv_sec) |
+ __get_user(o->tv_usec, &i->tv_usec)));
+}
+
+static inline long put_tv32(struct timeval32 *o, struct timeval *i)
+{
+ return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
+ (__put_user(i->tv_sec, &o->tv_sec) |
+ __put_user(i->tv_usec, &o->tv_usec)));
+}
+
+static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
+{
+ return (!access_ok(VERIFY_READ, i32, sizeof(*i32)) ||
+ (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) |
+ __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) |
+ __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) |
+ __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
+}
+
+static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
+{
+ return (!access_ok(VERIFY_WRITE, i32, sizeof(*i32)) ||
+ (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
+ __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
+ __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
+ __put_user(i->it_value.tv_usec, &o->it_value.tv_usec)));
+}
+
+struct msgbuf32 { s32 mtype; char mtext[1]; };
+
+struct ipc_perm32
+{
+ key_t key;
+ __kernel_uid_t32 uid;
+ __kernel_gid_t32 gid;
+ __kernel_uid_t32 cuid;
+ __kernel_gid_t32 cgid;
+ __kernel_mode_t32 mode;
+ unsigned short seq;
+};
+
+struct semid_ds32 {
+ struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */
+ __kernel_time_t32 sem_otime; /* last semop time */
+ __kernel_time_t32 sem_ctime; /* last change time */
+ u32 sem_base; /* ptr to first semaphore in array */
+ u32 sem_pending; /* pending operations to be processed */
+ u32 sem_pending_last; /* last pending operation */
+ u32 undo; /* undo requests on this array */
+ unsigned short sem_nsems; /* no. of semaphores in array */
+};
+
+struct semid64_ds32 {
+ struct ipc64_perm sem_perm; /* this structure is the same on sparc32 and sparc64 */
+ unsigned int __pad1;
+ __kernel_time_t32 sem_otime;
+ unsigned int __pad2;
+ __kernel_time_t32 sem_ctime;
+ u32 sem_nsems;
+ u32 __unused1;
+ u32 __unused2;
+};
+
+struct msqid_ds32
+{
+ struct ipc_perm32 msg_perm;
+ u32 msg_first;
+ u32 msg_last;
+ __kernel_time_t32 msg_stime;
+ __kernel_time_t32 msg_rtime;
+ __kernel_time_t32 msg_ctime;
+ u32 wwait;
+ u32 rwait;
+ unsigned short msg_cbytes;
+ unsigned short msg_qnum;
+ unsigned short msg_qbytes;
+ __kernel_ipc_pid_t32 msg_lspid;
+ __kernel_ipc_pid_t32 msg_lrpid;
+};
+
+struct msqid64_ds32 {
+ struct ipc64_perm msg_perm;
+ unsigned int __pad1;
+ __kernel_time_t32 msg_stime;
+ unsigned int __pad2;
+ __kernel_time_t32 msg_rtime;
+ unsigned int __pad3;
+ __kernel_time_t32 msg_ctime;
+ unsigned int msg_cbytes;
+ unsigned int msg_qnum;
+ unsigned int msg_qbytes;
+ __kernel_pid_t32 msg_lspid;
+ __kernel_pid_t32 msg_lrpid;
+ unsigned int __unused1;
+ unsigned int __unused2;
+};
+
+
+struct shmid_ds32 {
+ struct ipc_perm32 shm_perm;
+ int shm_segsz;
+ __kernel_time_t32 shm_atime;
+ __kernel_time_t32 shm_dtime;
+ __kernel_time_t32 shm_ctime;
+ __kernel_ipc_pid_t32 shm_cpid;
+ __kernel_ipc_pid_t32 shm_lpid;
+ unsigned short shm_nattch;
+};
+
+struct shmid64_ds32 {
+ struct ipc64_perm shm_perm;
+ unsigned int __pad1;
+ __kernel_time_t32 shm_atime;
+ unsigned int __pad2;
+ __kernel_time_t32 shm_dtime;
+ unsigned int __pad3;
+ __kernel_time_t32 shm_ctime;
+ __kernel_size_t32 shm_segsz;
+ __kernel_pid_t32 shm_cpid;
+ __kernel_pid_t32 shm_lpid;
+ unsigned int shm_nattch;
+ unsigned int __unused1;
+ unsigned int __unused2;
+};
+
+
+/*
+ * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation..
+ *
+ * This is really horribly ugly.
+ */
+#define IPCOP_MASK(__x) (1UL << (__x))
+static int do_sys32_semctl(int first, int second, int third, void *uptr)
+{
+ union semun fourth;
+ u32 pad;
+ int err = -EINVAL;
+
+ if (!uptr)
+ goto out;
+ err = -EFAULT;
+ if (get_user (pad, (u32 *)uptr))
+ goto out;
+ if(third == SETVAL)
+ fourth.val = (int)pad;
+ else
+ fourth.__pad = (void *)A(pad);
+ if (IPCOP_MASK (third) &
+ (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) | IPCOP_MASK (GETVAL) |
+ IPCOP_MASK (GETPID) | IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) |
+ IPCOP_MASK (GETALL) | IPCOP_MASK (SETALL) | IPCOP_MASK (IPC_RMID))) {
+ err = sys_semctl (first, second, third, fourth);
+ } else if (third & IPC_64) {
+ struct semid64_ds s;
+ struct semid64_ds32 *usp = (struct semid64_ds32 *)A(pad);
+ mm_segment_t old_fs;
+ int need_back_translation;
+
+ if (third == (IPC_SET|IPC_64)) {
+ err = get_user (s.sem_perm.uid, &usp->sem_perm.uid);
+ err |= __get_user (s.sem_perm.gid, &usp->sem_perm.gid);
+ err |= __get_user (s.sem_perm.mode, &usp->sem_perm.mode);
+ if (err)
+ goto out;
+ fourth.__pad = &s;
+ }
+ need_back_translation =
+ (IPCOP_MASK (third) &
+ (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0;
+ if (need_back_translation)
+ fourth.__pad = &s;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_semctl (first, second, third, fourth);
+ set_fs (old_fs);
+ if (need_back_translation) {
+ int err2 = put_user (s.sem_perm.key, &usp->sem_perm.key);
+ err2 |= __put_user (high2lowuid(s.sem_perm.uid), &usp->sem_perm.uid);
+ err2 |= __put_user (high2lowgid(s.sem_perm.gid), &usp->sem_perm.gid);
+ err2 |= __put_user (high2lowuid(s.sem_perm.cuid), &usp->sem_perm.cuid);
+ err2 |= __put_user (high2lowgid(s.sem_perm.cgid), &usp->sem_perm.cgid);
+ err2 |= __put_user (s.sem_perm.mode, &usp->sem_perm.mode);
+ err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq);
+ err2 |= __put_user (s.sem_otime, &usp->sem_otime);
+ err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
+ err2 |= __put_user (s.sem_nsems, &usp->sem_nsems);
+ if (err2) err = -EFAULT;
+ }
+ } else {
+ struct semid_ds s;
+ struct semid_ds32 *usp = (struct semid_ds32 *)A(pad);
+ mm_segment_t old_fs;
+ int need_back_translation;
+
+ if (third == IPC_SET) {
+ err = get_user (s.sem_perm.uid, &usp->sem_perm.uid);
+ err |= __get_user (s.sem_perm.gid, &usp->sem_perm.gid);
+ err |= __get_user (s.sem_perm.mode, &usp->sem_perm.mode);
+ if (err)
+ goto out;
+ fourth.__pad = &s;
+ }
+ need_back_translation =
+ (IPCOP_MASK (third) &
+ (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0;
+ if (need_back_translation)
+ fourth.__pad = &s;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_semctl (first, second, third, fourth);
+ set_fs (old_fs);
+ if (need_back_translation) {
+ int err2 = put_user (s.sem_perm.key, &usp->sem_perm.key);
+ err2 |= __put_user (high2lowuid(s.sem_perm.uid), &usp->sem_perm.uid);
+ err2 |= __put_user (high2lowgid(s.sem_perm.gid), &usp->sem_perm.gid);
+ err2 |= __put_user (high2lowuid(s.sem_perm.cuid), &usp->sem_perm.cuid);
+ err2 |= __put_user (high2lowgid(s.sem_perm.cgid), &usp->sem_perm.cgid);
+ err2 |= __put_user (s.sem_perm.mode, &usp->sem_perm.mode);
+ err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq);
+ err2 |= __put_user (s.sem_otime, &usp->sem_otime);
+ err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
+ err2 |= __put_user (s.sem_nsems, &usp->sem_nsems);
+ if (err2) err = -EFAULT;
+ }
+ }
+out:
+ return err;
+}
+
+static int do_sys32_msgsnd (int first, int second, int third, void *uptr)
+{
+ struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+ struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+ mm_segment_t old_fs;
+ int err;
+
+ if (!p)
+ return -ENOMEM;
+ err = get_user (p->mtype, &up->mtype);
+ err |= __copy_from_user (p->mtext, &up->mtext, second);
+ if (err)
+ goto out;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_msgsnd (first, p, second, third);
+ set_fs (old_fs);
+out:
+ kfree (p);
+ return err;
+}
+
+static int do_sys32_msgrcv (int first, int second, int msgtyp, int third,
+ int version, void *uptr)
+{
+ struct msgbuf32 *up;
+ struct msgbuf *p;
+ mm_segment_t old_fs;
+ int err;
+
+ if (!version) {
+ struct ipc_kludge_32 *uipck = (struct ipc_kludge_32 *)uptr;
+ struct ipc_kludge_32 ipck;
+
+ err = -EINVAL;
+ if (!uptr)
+ goto out;
+ err = -EFAULT;
+ if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge_32)))
+ goto out;
+ uptr = (void *)A(ipck.msgp);
+ msgtyp = ipck.msgtyp;
+ }
+ err = -ENOMEM;
+ p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+ if (!p)
+ goto out;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_msgrcv (first, p, second + 4, msgtyp, third);
+ set_fs (old_fs);
+ if (err < 0)
+ goto free_then_out;
+ up = (struct msgbuf32 *)uptr;
+ if (put_user (p->mtype, &up->mtype) ||
+ __copy_to_user (&up->mtext, p->mtext, err))
+ err = -EFAULT;
+free_then_out:
+ kfree (p);
+out:
+ return err;
+}
+
+static int do_sys32_msgctl (int first, int second, void *uptr)
+{
+ int err;
+
+ if (IPCOP_MASK (second) &
+ (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (MSG_INFO) |
+ IPCOP_MASK (IPC_RMID))) {
+ err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
+ } else if (second & IPC_64) {
+ struct msqid64_ds m;
+ struct msqid64_ds32 *up = (struct msqid64_ds32 *)uptr;
+ mm_segment_t old_fs;
+
+ if (second == (IPC_SET|IPC_64)) {
+ err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
+ err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
+ err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
+ err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
+ if (err)
+ goto out;
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_msgctl (first, second, (struct msqid_ds *)&m);
+ set_fs (old_fs);
+ if (IPCOP_MASK (second) &
+ (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) {
+ int err2 = put_user (m.msg_perm.key, &up->msg_perm.key);
+ err2 |= __put_user (high2lowuid(m.msg_perm.uid), &up->msg_perm.uid);
+ err2 |= __put_user (high2lowgid(m.msg_perm.gid), &up->msg_perm.gid);
+ err2 |= __put_user (high2lowuid(m.msg_perm.cuid), &up->msg_perm.cuid);
+ err2 |= __put_user (high2lowgid(m.msg_perm.cgid), &up->msg_perm.cgid);
+ err2 |= __put_user (m.msg_perm.mode, &up->msg_perm.mode);
+ err2 |= __put_user (m.msg_perm.seq, &up->msg_perm.seq);
+ err2 |= __put_user (m.msg_stime, &up->msg_stime);
+ err2 |= __put_user (m.msg_rtime, &up->msg_rtime);
+ err2 |= __put_user (m.msg_ctime, &up->msg_ctime);
+ err2 |= __put_user (m.msg_cbytes, &up->msg_cbytes);
+ err2 |= __put_user (m.msg_qnum, &up->msg_qnum);
+ err2 |= __put_user (m.msg_qbytes, &up->msg_qbytes);
+ err2 |= __put_user (m.msg_lspid, &up->msg_lspid);
+ err2 |= __put_user (m.msg_lrpid, &up->msg_lrpid);
+ if (err2)
+ err = -EFAULT;
+ }
+ } else {
+ struct msqid_ds m;
+ struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
+ mm_segment_t old_fs;
+
+ if (second == IPC_SET) {
+ err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
+ err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
+ err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
+ err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
+ if (err)
+ goto out;
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_msgctl (first, second, &m);
+ set_fs (old_fs);
+ if (IPCOP_MASK (second) &
+ (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) {
+ int err2 = put_user (m.msg_perm.key, &up->msg_perm.key);
+ err2 |= __put_user (high2lowuid(m.msg_perm.uid), &up->msg_perm.uid);
+ err2 |= __put_user (high2lowgid(m.msg_perm.gid), &up->msg_perm.gid);
+ err2 |= __put_user (high2lowuid(m.msg_perm.cuid), &up->msg_perm.cuid);
+ err2 |= __put_user (high2lowgid(m.msg_perm.cgid), &up->msg_perm.cgid);
+ err2 |= __put_user (m.msg_perm.mode, &up->msg_perm.mode);
+ err2 |= __put_user (m.msg_perm.seq, &up->msg_perm.seq);
+ err2 |= __put_user (m.msg_stime, &up->msg_stime);
+ err2 |= __put_user (m.msg_rtime, &up->msg_rtime);
+ err2 |= __put_user (m.msg_ctime, &up->msg_ctime);
+ err2 |= __put_user (m.msg_cbytes, &up->msg_cbytes);
+ err2 |= __put_user (m.msg_qnum, &up->msg_qnum);
+ err2 |= __put_user (m.msg_qbytes, &up->msg_qbytes);
+ err2 |= __put_user (m.msg_lspid, &up->msg_lspid);
+ err2 |= __put_user (m.msg_lrpid, &up->msg_lrpid);
+ if (err2)
+ err = -EFAULT;
+ }
+ }
+
+out:
+ return err;
+}
+
+static int do_sys32_shmat (int first, int second, int third, int version, void *uptr)
+{
+ unsigned long raddr;
+ u32 *uaddr = (u32 *)A((u32)third);
+ int err = -EINVAL;
+
+ if (version == 1)
+ goto out;
+ err = sys_shmat (first, uptr, second, &raddr);
+ if (err)
+ goto out;
+ err = put_user (raddr, uaddr);
+out:
+ return err;
+}
+
+static int do_sys32_shmctl (int first, int second, void *uptr)
+{
+ int err;
+
+ if (IPCOP_MASK (second) &
+ (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SHM_LOCK) | IPCOP_MASK (SHM_UNLOCK) |
+ IPCOP_MASK (IPC_RMID))) {
+ if (second == (IPC_INFO|IPC_64))
+ second = IPC_INFO; /* So that we don't have to translate it */
+ err = sys_shmctl (first, second, (struct shmid_ds *)uptr);
+ } else if ((second & IPC_64) && second != (SHM_INFO|IPC_64)) {
+ struct shmid64_ds s;
+ struct shmid64_ds32 *up = (struct shmid64_ds32 *)uptr;
+ mm_segment_t old_fs;
+
+ if (second == (IPC_SET|IPC_64)) {
+ err = get_user (s.shm_perm.uid, &up->shm_perm.uid);
+ err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid);
+ err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode);
+ if (err)
+ goto out;
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_shmctl (first, second, (struct shmid_ds *)&s);
+ set_fs (old_fs);
+ if (err < 0)
+ goto out;
+
+ /* Mask it even in this case so it becomes a CSE. */
+ if (IPCOP_MASK (second) &
+ (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) {
+ int err2 = put_user (s.shm_perm.key, &up->shm_perm.key);
+ err2 |= __put_user (high2lowuid(s.shm_perm.uid), &up->shm_perm.uid);
+ err2 |= __put_user (high2lowgid(s.shm_perm.gid), &up->shm_perm.gid);
+ err2 |= __put_user (high2lowuid(s.shm_perm.cuid), &up->shm_perm.cuid);
+ err2 |= __put_user (high2lowgid(s.shm_perm.cgid), &up->shm_perm.cgid);
+ err2 |= __put_user (s.shm_perm.mode, &up->shm_perm.mode);
+ err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq);
+ err2 |= __put_user (s.shm_atime, &up->shm_atime);
+ err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
+ err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
+ err2 |= __put_user (s.shm_segsz, &up->shm_segsz);
+ err2 |= __put_user (s.shm_nattch, &up->shm_nattch);
+ err2 |= __put_user (s.shm_cpid, &up->shm_cpid);
+ err2 |= __put_user (s.shm_lpid, &up->shm_lpid);
+ if (err2)
+ err = -EFAULT;
+ }
+ } else {
+ struct shmid_ds s;
+ struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
+ mm_segment_t old_fs;
+
+ second &= ~IPC_64;
+ if (second == IPC_SET) {
+ err = get_user (s.shm_perm.uid, &up->shm_perm.uid);
+ err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid);
+ err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode);
+ if (err)
+ goto out;
+ }
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_shmctl (first, second, &s);
+ set_fs (old_fs);
+ if (err < 0)
+ goto out;
+
+ /* Mask it even in this case so it becomes a CSE. */
+ if (second == SHM_INFO) {
+ struct shm_info32 {
+ int used_ids;
+ u32 shm_tot, shm_rss, shm_swp;
+ u32 swap_attempts, swap_successes;
+ } *uip = (struct shm_info32 *)uptr;
+ struct shm_info *kp = (struct shm_info *)&s;
+ int err2 = put_user (kp->used_ids, &uip->used_ids);
+ err2 |= __put_user (kp->shm_tot, &uip->shm_tot);
+ err2 |= __put_user (kp->shm_rss, &uip->shm_rss);
+ err2 |= __put_user (kp->shm_swp, &uip->shm_swp);
+ err2 |= __put_user (kp->swap_attempts, &uip->swap_attempts);
+ err2 |= __put_user (kp->swap_successes, &uip->swap_successes);
+ if (err2)
+ err = -EFAULT;
+ } else if (IPCOP_MASK (second) &
+ (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) {
+ int err2 = put_user (s.shm_perm.key, &up->shm_perm.key);
+ err2 |= __put_user (high2lowuid(s.shm_perm.uid), &up->shm_perm.uid);
+ err2 |= __put_user (high2lowgid(s.shm_perm.gid), &up->shm_perm.gid);
+ err2 |= __put_user (high2lowuid(s.shm_perm.cuid), &up->shm_perm.cuid);
+ err2 |= __put_user (high2lowgid(s.shm_perm.cgid), &up->shm_perm.cgid);
+ err2 |= __put_user (s.shm_perm.mode, &up->shm_perm.mode);
+ err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq);
+ err2 |= __put_user (s.shm_atime, &up->shm_atime);
+ err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
+ err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
+ err2 |= __put_user (s.shm_segsz, &up->shm_segsz);
+ err2 |= __put_user (s.shm_nattch, &up->shm_nattch);
+ err2 |= __put_user (s.shm_cpid, &up->shm_cpid);
+ err2 |= __put_user (s.shm_lpid, &up->shm_lpid);
+ if (err2)
+ err = -EFAULT;
+ }
+ }
+out:
+ return err;
+}
+
+asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+{
+ int version, err;
+
+ version = call >> 16; /* hack for backward compatibility */
+ call &= 0xffff;
+
+ if(version)
+ return -EINVAL;
+
+ if (call <= SEMCTL)
+ switch (call) {
+ case SEMOP:
+ /* struct sembuf is the same on 32 and 64bit :)) */
+ err = sys_semop (first, (struct sembuf *)AA(ptr), second);
+ goto out;
+ case SEMGET:
+ err = sys_semget (first, second, third);
+ goto out;
+ case SEMCTL:
+ err = do_sys32_semctl (first, second, third, (void *)AA(ptr));
+ goto out;
+ default:
+ err = -EINVAL;
+ goto out;
+ };
+ if (call <= MSGCTL)
+ switch (call) {
+ case MSGSND:
+ err = do_sys32_msgsnd (first, second, third, (void *)AA(ptr));
+ goto out;
+ case MSGRCV:
+ err = do_sys32_msgrcv (first, second, 0, third,
+ version, (void *)AA(ptr));
+ goto out;
+ case MSGGET:
+ err = sys_msgget ((key_t) first, second);
+ goto out;
+ case MSGCTL:
+ err = do_sys32_msgctl (first, second, (void *)AA(ptr));
+ goto out;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+ if (call <= SHMCTL)
+ switch (call) {
+ case SHMAT:
+ err = do_sys32_shmat (first, second, third,
+ version, (void *)AA(ptr));
+ goto out;
+ case SHMDT:
+ err = sys_shmdt ((char *)AA(ptr));
+ goto out;
+ case SHMGET:
+ err = sys_shmget (first, second, third);
+ goto out;
+ case SHMCTL:
+ err = do_sys32_shmctl (first, second, (void *)AA(ptr));
+ goto out;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = -EINVAL;
+
+out:
+ return err;
+}
+
+static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
+{
+ int err;
+
+ err = get_user(kfl->l_type, &ufl->l_type);
+ err |= __get_user(kfl->l_whence, &ufl->l_whence);
+ err |= __get_user(kfl->l_start, &ufl->l_start);
+ err |= __get_user(kfl->l_len, &ufl->l_len);
+ err |= __get_user(kfl->l_pid, &ufl->l_pid);
+ return err;
+}
+
+static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
+{
+ int err;
+
+ err = __put_user(kfl->l_type, &ufl->l_type);
+ err |= __put_user(kfl->l_whence, &ufl->l_whence);
+ err |= __put_user(kfl->l_start, &ufl->l_start);
+ err |= __put_user(kfl->l_len, &ufl->l_len);
+ err |= __put_user(kfl->l_pid, &ufl->l_pid);
+ return err;
+}
+
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case F_GETLK:
+ case F_SETLK:
+ case F_SETLKW:
+ {
+ struct flock f;
+ mm_segment_t old_fs;
+ long ret;
+
+ if(get_flock(&f, (struct flock32 *)arg))
+ return -EFAULT;
+ old_fs = get_fs(); set_fs (KERNEL_DS);
+ ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+ set_fs (old_fs);
+ if (ret) return ret;
+ if (f.l_start >= 0x7fffffffUL ||
+ f.l_len >= 0x7fffffffUL ||
+ f.l_start + f.l_len >= 0x7fffffffUL)
+ return -EOVERFLOW;
+ if(put_flock(&f, (struct flock32 *)arg))
+ return -EFAULT;
+ return 0;
+ }
+ default:
+ return sys_fcntl(fd, cmd, (unsigned long)arg);
+ }
+}
+
+asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ if (cmd >= F_GETLK64 && cmd <= F_SETLKW64)
+ return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg);
+ return sys32_fcntl(fd, cmd, arg);
+}
+
+struct dqblk32 {
+ __u32 dqb_bhardlimit;
+ __u32 dqb_bsoftlimit;
+ __u32 dqb_curblocks;
+ __u32 dqb_ihardlimit;
+ __u32 dqb_isoftlimit;
+ __u32 dqb_curinodes;
+ __kernel_time_t32 dqb_btime;
+ __kernel_time_t32 dqb_itime;
+};
+
+extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
+{
+ int cmds = cmd >> SUBCMDSHIFT;
+ int err;
+ struct mem_dqblk d;
+ mm_segment_t old_fs;
+ char *spec;
+
+ switch (cmds) {
+ case Q_GETQUOTA:
+ break;
+ case Q_SETQUOTA:
+ case Q_SETUSE:
+ case Q_SETQLIM:
+ if (copy_from_user (&d, (struct dqblk32 *)addr,
+ sizeof (struct dqblk32)))
+ return -EFAULT;
+ d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
+ d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
+ break;
+ default:
+ return sys_quotactl(cmd, special,
+ id, (caddr_t)addr);
+ }
+ spec = getname (special);
+ err = PTR_ERR(spec);
+ if (IS_ERR(spec)) return err;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
+ set_fs (old_fs);
+ putname (spec);
+ if (cmds == Q_GETQUOTA) {
+ __kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
+ ((struct dqblk32 *)&d)->dqb_itime = i;
+ ((struct dqblk32 *)&d)->dqb_btime = b;
+ if (copy_to_user ((struct dqblk32 *)addr, &d,
+ sizeof (struct dqblk32)))
+ return -EFAULT;
+ }
+ return err;
+}
+
+static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
+{
+ int err;
+
+ err = put_user (kbuf->f_type, &ubuf->f_type);
+ err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize);
+ err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks);
+ err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree);
+ err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail);
+ err |= __put_user (kbuf->f_files, &ubuf->f_files);
+ err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree);
+ err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen);
+ err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]);
+ err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]);
+ return err;
+}
+
+extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
+
+asmlinkage int sys32_statfs(const char * path, struct statfs32 *buf)
+{
+ int ret;
+ struct statfs s;
+ mm_segment_t old_fs = get_fs();
+ char *pth;
+
+ pth = getname (path);
+ ret = PTR_ERR(pth);
+ if (!IS_ERR(pth)) {
+ set_fs (KERNEL_DS);
+ ret = sys_statfs((const char *)pth, &s);
+ set_fs (old_fs);
+ putname (pth);
+ if (put_statfs(buf, &s))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf);
+
+asmlinkage int sys32_fstatfs(unsigned int fd, struct statfs32 *buf)
+{
+ int ret;
+ struct statfs s;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_fstatfs(fd, &s);
+ set_fs (old_fs);
+ if (put_statfs(buf, &s))
+ return -EFAULT;
+ return ret;
+}
+
+extern asmlinkage long sys_truncate(const char * path, unsigned long length);
+extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
+
+asmlinkage int sys32_truncate64(const char * path, unsigned long high, unsigned long low)
+{
+ if ((int)high < 0)
+ return -EINVAL;
+ else
+ return sys_truncate(path, (high << 32) | low);
+}
+
+asmlinkage int sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
+{
+ if ((int)high < 0)
+ return -EINVAL;
+ else
+ return sys_ftruncate(fd, (high << 32) | low);
+}
+
+extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
+
+struct utimbuf32 {
+ __kernel_time_t32 actime, modtime;
+};
+
+asmlinkage int sys32_utime(char * filename, struct utimbuf32 *times)
+{
+ struct utimbuf t;
+ mm_segment_t old_fs;
+ int ret;
+ char *filenam;
+
+ if (!times)
+ return sys_utime(filename, NULL);
+ if (get_user (t.actime, &times->actime) ||
+ __get_user (t.modtime, &times->modtime))
+ return -EFAULT;
+ filenam = getname (filename);
+ ret = PTR_ERR(filenam);
+ if (!IS_ERR(filenam)) {
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ ret = sys_utime(filenam, &t);
+ set_fs (old_fs);
+ putname (filenam);
+ }
+ return ret;
+}
+
+struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };
+
+typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
+typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
+
+static long do_readv_writev32(int type, struct file *file,
+ const struct iovec32 *vector, u32 count)
+{
+ unsigned long tot_len;
+ struct iovec iovstack[UIO_FASTIOV];
+ struct iovec *iov=iovstack, *ivp;
+ struct inode *inode;
+ long retval, i;
+ io_fn_t fn;
+ iov_fn_t fnv;
+
+ /* First get the "struct iovec" from user memory and
+ * verify all the pointers
+ */
+ if (!count)
+ return 0;
+ if (verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
+ return -EFAULT;
+ if (count > UIO_MAXIOV)
+ return -EINVAL;
+ if (count > UIO_FASTIOV) {
+ iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+ if (!iov)
+ return -ENOMEM;
+ }
+
+ tot_len = 0;
+ i = count;
+ ivp = iov;
+ while(i > 0) {
+ u32 len;
+ u32 buf;
+
+ __get_user(len, &vector->iov_len);
+ __get_user(buf, &vector->iov_base);
+ tot_len += len;
+ ivp->iov_base = (void *)A(buf);
+ ivp->iov_len = (__kernel_size_t) len;
+ vector++;
+ ivp++;
+ i--;
+ }
+
+ inode = file->f_dentry->d_inode;
+ /* VERIFY_WRITE actually means a read, as we write to user space */
+ retval = locks_verify_area((type == VERIFY_WRITE
+ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+ inode, file, file->f_pos, tot_len);
+ if (retval)
+ goto out;
+
+ /* VERIFY_WRITE actually means a read, as we write to user space */
+ fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
+ if (fnv) {
+ retval = fnv(file, iov, count, &file->f_pos);
+ goto out;
+ }
+
+ fn = (type == VERIFY_WRITE ? file->f_op->read :
+ (io_fn_t) file->f_op->write);
+
+ ivp = iov;
+ while (count > 0) {
+ void * base;
+ int len, nr;
+
+ base = ivp->iov_base;
+ len = ivp->iov_len;
+ ivp++;
+ count--;
+ nr = fn(file, base, len, &file->f_pos);
+ if (nr < 0) {
+ if (!retval)
+ retval = nr;
+ break;
+ }
+ retval += nr;
+ if (nr != len)
+ break;
+ }
+out:
+ if (iov != iovstack)
+ kfree(iov);
+
+ return retval;
+}
+
+asmlinkage long sys32_readv(int fd, struct iovec32 *vector, u32 count)
+{
+ struct file *file;
+ long ret = -EBADF;
+
+ file = fget(fd);
+ if(!file)
+ goto bad_file;
+
+ if (file->f_op && (file->f_mode & FMODE_READ) &&
+ (file->f_op->readv || file->f_op->read))
+ ret = do_readv_writev32(VERIFY_WRITE, file, vector, count);
+ fput(file);
+
+bad_file:
+ return ret;
+}
+
+asmlinkage long sys32_writev(int fd, struct iovec32 *vector, u32 count)
+{
+ struct file *file;
+ int ret = -EBADF;
+
+ file = fget(fd);
+ if(!file)
+ goto bad_file;
+ if (file->f_op && (file->f_mode & FMODE_WRITE) &&
+ (file->f_op->writev || file->f_op->write))
+ ret = do_readv_writev32(VERIFY_READ, file, vector, count);
+ fput(file);
+
+bad_file:
+ return ret;
+}
+
+/* readdir & getdents */
+
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
+
+struct old_linux_dirent32 {
+ u32 d_ino;
+ u32 d_offset;
+ unsigned short d_namlen;
+ char d_name[1];
+};
+
+struct readdir_callback32 {
+ struct old_linux_dirent32 * dirent;
+ int count;
+};
+
+static int fillonedir(void * __buf, const char * name, int namlen,
+ off_t offset, ino_t ino, unsigned int d_type)
+{
+ struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
+ struct old_linux_dirent32 * dirent;
+
+ if (buf->count)
+ return -EINVAL;
+ buf->count++;
+ dirent = buf->dirent;
+ put_user(ino, &dirent->d_ino);
+ put_user(offset, &dirent->d_offset);
+ put_user(namlen, &dirent->d_namlen);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+ return 0;
+}
+
+asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, unsigned int count)
+{
+ int error = -EBADF;
+ struct file * file;
+ struct readdir_callback32 buf;
+
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ buf.count = 0;
+ buf.dirent = dirent;
+
+ error = vfs_readdir(file, fillonedir, &buf);
+ if (error < 0)
+ goto out_putf;
+ error = buf.count;
+
+out_putf:
+ fput(file);
+out:
+ return error;
+}
+
+struct linux_dirent32 {
+ u32 d_ino;
+ u32 d_off;
+ unsigned short d_reclen;
+ char d_name[1];
+};
+
+struct getdents_callback32 {
+ struct linux_dirent32 * current_dir;
+ struct linux_dirent32 * previous;
+ int count;
+ int error;
+};
+
+static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino,
+ unsigned int d_type)
+{
+ struct linux_dirent32 * dirent;
+ struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+ buf->error = -EINVAL; /* only used if we fail.. */
+ if (reclen > buf->count)
+ return -EINVAL;
+ dirent = buf->previous;
+ if (dirent)
+ put_user(offset, &dirent->d_off);
+ dirent = buf->current_dir;
+ buf->previous = dirent;
+ put_user(ino, &dirent->d_ino);
+ put_user(reclen, &dirent->d_reclen);
+ copy_to_user(dirent->d_name, name, namlen);
+ put_user(0, dirent->d_name + namlen);
+ ((char *) dirent) += reclen;
+ buf->current_dir = dirent;
+ buf->count -= reclen;
+ return 0;
+}
+
+asmlinkage int sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count)
+{
+ struct file * file;
+ struct linux_dirent32 * lastdirent;
+ struct getdents_callback32 buf;
+ int error = -EBADF;
+
+ file = fget(fd);
+ if (!file)
+ goto out;
+
+ buf.current_dir = dirent;
+ buf.previous = NULL;
+ buf.count = count;
+ buf.error = 0;
+
+ error = vfs_readdir(file, filldir, &buf);
+ if (error < 0)
+ goto out_putf;
+ lastdirent = buf.previous;
+ error = buf.error;
+ if(lastdirent) {
+ put_user(file->f_pos, &lastdirent->d_off);
+ error = count - buf.count;
+ }
+out_putf:
+ fput(file);
+out:
+ return error;
+}
+
+/* end of readdir & getdents */
+
+/*
+ * Ooo, nasty. We need here to frob 32-bit unsigned longs to
+ * 64-bit unsigned longs.
+ */
+
+static inline int
+get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
+{
+ if (ufdset) {
+ unsigned long odd;
+
+ if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
+ return -EFAULT;
+
+ odd = n & 1UL;
+ n &= ~1UL;
+ while (n) {
+ unsigned long h, l;
+ __get_user(l, ufdset);
+ __get_user(h, ufdset+1);
+ ufdset += 2;
+ *fdset++ = h << 32 | l;
+ n -= 2;
+ }
+ if (odd)
+ __get_user(*fdset, ufdset);
+ } else {
+ /* Tricky, must clear full unsigned long in the
+ * kernel fdset at the end, this makes sure that
+ * actually happens.
+ */
+ memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
+ }
+ return 0;
+}
+
+static inline void
+set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
+{
+ unsigned long odd;
+
+ if (!ufdset)
+ return;
+
+ odd = n & 1UL;
+ n &= ~1UL;
+ while (n) {
+ unsigned long h, l;
+ l = *fdset++;
+ h = l >> 32;
+ __put_user(l, ufdset);
+ __put_user(h, ufdset+1);
+ ufdset += 2;
+ n -= 2;
+ }
+ if (odd)
+ __put_user(*fdset, ufdset);
+}
+
+#define MAX_SELECT_SECONDS \
+ ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+
+asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
+{
+ fd_set_bits fds;
+ struct timeval32 *tvp = (struct timeval32 *)AA(tvp_x);
+ char *bits;
+ unsigned long nn;
+ long timeout;
+ int ret, size;
+
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ if (tvp) {
+ time_t sec, usec;
+
+ if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
+ || (ret = __get_user(sec, &tvp->tv_sec))
+ || (ret = __get_user(usec, &tvp->tv_usec)))
+ goto out_nofds;
+
+ ret = -EINVAL;
+ if(sec < 0 || usec < 0)
+ goto out_nofds;
+
+ if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+ timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
+ timeout += sec * (unsigned long) HZ;
+ }
+ }
+
+ ret = -EINVAL;
+ if (n < 0)
+ goto out_nofds;
+ if (n > current->files->max_fdset)
+ n = current->files->max_fdset;
+
+ /*
+ * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
+ * since we used fdset we need to allocate memory in units of
+ * long-words.
+ */
+ ret = -ENOMEM;
+ size = FDS_BYTES(n);
+ bits = kmalloc(6 * size, GFP_KERNEL);
+ if (!bits)
+ goto out_nofds;
+ fds.in = (unsigned long *) bits;
+ fds.out = (unsigned long *) (bits + size);
+ fds.ex = (unsigned long *) (bits + 2*size);
+ fds.res_in = (unsigned long *) (bits + 3*size);
+ fds.res_out = (unsigned long *) (bits + 4*size);
+ fds.res_ex = (unsigned long *) (bits + 5*size);
+
+ nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
+ if ((ret = get_fd_set32(nn, fds.in, inp)) ||
+ (ret = get_fd_set32(nn, fds.out, outp)) ||
+ (ret = get_fd_set32(nn, fds.ex, exp)))
+ goto out;
+ zero_fd_set(n, fds.res_in);
+ zero_fd_set(n, fds.res_out);
+ zero_fd_set(n, fds.res_ex);
+
+ ret = do_select(n, &fds, &timeout);
+
+ if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
+ time_t sec = 0, usec = 0;
+ if (timeout) {
+ sec = timeout / HZ;
+ usec = timeout % HZ;
+ usec *= (1000000/HZ);
+ }
+ put_user(sec, &tvp->tv_sec);
+ put_user(usec, &tvp->tv_usec);
+ }
+
+ if (ret < 0)
+ goto out;
+ if (!ret) {
+ ret = -ERESTARTNOHAND;
+ if (signal_pending(current))
+ goto out;
+ ret = 0;
+ }
+
+ set_fd_set32(nn, inp, fds.res_in);
+ set_fd_set32(nn, outp, fds.res_out);
+ set_fd_set32(nn, exp, fds.res_ex);
+
+out:
+ kfree(bits);
+out_nofds:
+ return ret;
+}
+
+static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf)
+{
+ unsigned long ino, blksize, blocks;
+ kdev_t dev, rdev;
+ umode_t mode;
+ nlink_t nlink;
+ uid_t uid;
+ gid_t gid;
+ off_t size;
+ time_t atime, mtime, ctime;
+ int err;
+
+ /* Stream the loads of inode data into the load buffer,
+ * then we push it all into the store buffer below. This
+ * should give optimal cache performance.
+ */
+ ino = inode->i_ino;
+ dev = inode->i_dev;
+ mode = inode->i_mode;
+ nlink = inode->i_nlink;
+ uid = inode->i_uid;
+ gid = inode->i_gid;
+ rdev = inode->i_rdev;
+ size = inode->i_size;
+ atime = inode->i_atime;
+ mtime = inode->i_mtime;
+ ctime = inode->i_ctime;
+ blksize = inode->i_blksize;
+ blocks = inode->i_blocks;
+
+ err = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
+ err |= put_user(ino, &statbuf->st_ino);
+ err |= put_user(mode, &statbuf->st_mode);
+ err |= put_user(nlink, &statbuf->st_nlink);
+ err |= put_user(high2lowuid(uid), &statbuf->st_uid);
+ err |= put_user(high2lowgid(gid), &statbuf->st_gid);
+ err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
+ err |= put_user(size, &statbuf->st_size);
+ err |= put_user(atime, &statbuf->st_atime);
+ err |= put_user(0, &statbuf->__unused1);
+ err |= put_user(mtime, &statbuf->st_mtime);
+ err |= put_user(0, &statbuf->__unused2);
+ err |= put_user(ctime, &statbuf->st_ctime);
+ err |= put_user(0, &statbuf->__unused3);
+ if (blksize) {
+ err |= put_user(blksize, &statbuf->st_blksize);
+ err |= put_user(blocks, &statbuf->st_blocks);
+ } else {
+ unsigned int tmp_blocks;
+
+#define D_B 7
+#define I_B (BLOCK_SIZE / sizeof(unsigned short))
+ tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ if (tmp_blocks > D_B) {
+ unsigned int indirect;
+
+ indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
+ tmp_blocks += indirect;
+ if (indirect > 1) {
+ indirect = (indirect - 1 + I_B - 1) / I_B;
+ tmp_blocks += indirect;
+ if (indirect > 1)
+ tmp_blocks++;
+ }
+ }
+ err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
+ err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
+#undef D_B
+#undef I_B
+ }
+/* fixme
+ err |= put_user(0, &statbuf->__unused4[0]);
+ err |= put_user(0, &statbuf->__unused4[1]);
+*/
+
+ return err;
+}
+
+/* Perhaps this belongs in fs.h or similar. -DaveM */
+static __inline__ int
+do_revalidate(struct dentry *dentry)
+{
+ struct inode * inode = dentry->d_inode;
+ if (inode->i_op && inode->i_op->revalidate)
+ return inode->i_op->revalidate(dentry);
+ return 0;
+}
+
+asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
+{
+ struct nameidata nd;
+ int error;
+
+ error = user_path_walk(filename, &nd);
+ if (!error) {
+ error = do_revalidate(nd.dentry);
+ if (!error)
+ error = cp_new_stat32(nd.dentry->d_inode, statbuf);
+ path_release(&nd);
+ }
+ return error;
+}
+
+asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
+{
+ struct nameidata nd;
+ int error;
+
+ error = user_path_walk_link(filename, &nd);
+ if (!error) {
+ error = do_revalidate(nd.dentry);
+ if (!error)
+ error = cp_new_stat32(nd.dentry->d_inode, statbuf);
+
+ path_release(&nd);
+ }
+ return error;
+}
+
+asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
+{
+ struct file *f;
+ int err = -EBADF;
+
+ f = fget(fd);
+ if (f) {
+ struct dentry * dentry = f->f_dentry;
+
+ err = do_revalidate(dentry);
+ if (!err)
+ err = cp_new_stat32(dentry->d_inode, statbuf);
+ fput(f);
+ }
+ return err;
+}
+
+extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
+
+asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
+{
+ return sys_sysfs(option, arg1, arg2);
+}
+
+struct ncp_mount_data32 {
+ int version;
+ unsigned int ncp_fd;
+ __kernel_uid_t32 mounted_uid;
+ __kernel_pid_t32 wdog_pid;
+ unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
+ unsigned int time_out;
+ unsigned int retry_count;
+ unsigned int flags;
+ __kernel_uid_t32 uid;
+ __kernel_gid_t32 gid;
+ __kernel_mode_t32 file_mode;
+ __kernel_mode_t32 dir_mode;
+};
+
+static void *do_ncp_super_data_conv(void *raw_data)
+{
+ struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data;
+ struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
+
+ n->dir_mode = n32->dir_mode;
+ n->file_mode = n32->file_mode;
+ n->gid = low2highgid(n32->gid);
+ n->uid = low2highuid(n32->uid);
+ memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
+ n->wdog_pid = n32->wdog_pid;
+ n->mounted_uid = low2highuid(n32->mounted_uid);
+ return raw_data;
+}
+
+struct smb_mount_data32 {
+ int version;
+ __kernel_uid_t32 mounted_uid;
+ __kernel_uid_t32 uid;
+ __kernel_gid_t32 gid;
+ __kernel_mode_t32 file_mode;
+ __kernel_mode_t32 dir_mode;
+};
+
+static void *do_smb_super_data_conv(void *raw_data)
+{
+ struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
+ struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
+
+ s->version = s32->version;
+ s->mounted_uid = low2highuid(s32->mounted_uid);
+ s->uid = low2highuid(s32->uid);
+ s->gid = low2highgid(s32->gid);
+ s->file_mode = s32->file_mode;
+ s->dir_mode = s32->dir_mode;
+ return raw_data;
+}
+
+static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
+{
+ int i;
+ unsigned long page;
+ struct vm_area_struct *vma;
+
+ *kernel = 0;
+ if(!user)
+ return 0;
+ vma = find_vma(current->mm, (unsigned long)user);
+ if(!vma || (unsigned long)user < vma->vm_start)
+ return -EFAULT;
+ if(!(vma->vm_flags & VM_READ))
+ return -EFAULT;
+ i = vma->vm_end - (unsigned long) user;
+ if(PAGE_SIZE <= (unsigned long) i)
+ i = PAGE_SIZE - 1;
+ if(!(page = __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ if(copy_from_user((void *) page, user, i)) {
+ free_page(page);
+ return -EFAULT;
+ }
+ *kernel = page;
+ return 0;
+}
+
+#define SMBFS_NAME "smbfs"
+#define NCPFS_NAME "ncpfs"
+
+asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
+{
+ unsigned long type_page = 0;
+ unsigned long data_page = 0;
+ unsigned long dev_page = 0;
+ unsigned long dir_page = 0;
+ int err, is_smb, is_ncp;
+
+ is_smb = is_ncp = 0;
+
+ err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
+ if (err)
+ goto out;
+
+ if (!type_page) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ is_smb = !strcmp((char *)type_page, SMBFS_NAME);
+ is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
+
+ err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page);
+ if (err)
+ goto type_out;
+
+ err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
+ if (err)
+ goto data_out;
+
+ err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
+ if (err)
+ goto dev_out;
+
+ if (!is_smb && !is_ncp) {
+ lock_kernel();
+ err = do_mount((char*)dev_page, (char*)dir_page,
+ (char*)type_page, new_flags, (char*)data_page);
+ unlock_kernel();
+ } else {
+ if (is_ncp)
+ do_ncp_super_data_conv((void *)data_page);
+ else
+ do_smb_super_data_conv((void *)data_page);
+
+ lock_kernel();
+ err = do_mount((char*)dev_page, (char*)dir_page,
+ (char*)type_page, new_flags, (char*)data_page);
+ unlock_kernel();
+ }
+ free_page(dir_page);
+
+dev_out:
+ free_page(dev_page);
+
+data_out:
+ free_page(data_page);
+
+type_out:
+ free_page(type_page);
+
+out:
+ return err;
+}
+
+struct rusage32 {
+ struct timeval32 ru_utime;
+ struct timeval32 ru_stime;
+ s32 ru_maxrss;
+ s32 ru_ixrss;
+ s32 ru_idrss;
+ s32 ru_isrss;
+ s32 ru_minflt;
+ s32 ru_majflt;
+ s32 ru_nswap;
+ s32 ru_inblock;
+ s32 ru_oublock;
+ s32 ru_msgsnd;
+ s32 ru_msgrcv;
+ s32 ru_nsignals;
+ s32 ru_nvcsw;
+ s32 ru_nivcsw;
+};
+
+static int put_rusage (struct rusage32 *ru, struct rusage *r)
+{
+ int err;
+
+ err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
+ err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
+ err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
+ err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
+ err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
+ err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
+ err |= __put_user (r->ru_idrss, &ru->ru_idrss);
+ err |= __put_user (r->ru_isrss, &ru->ru_isrss);
+ err |= __put_user (r->ru_minflt, &ru->ru_minflt);
+ err |= __put_user (r->ru_majflt, &ru->ru_majflt);
+ err |= __put_user (r->ru_nswap, &ru->ru_nswap);
+ err |= __put_user (r->ru_inblock, &ru->ru_inblock);
+ err |= __put_user (r->ru_oublock, &ru->ru_oublock);
+ err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
+ err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
+ err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
+ err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
+ err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
+ return err;
+}
+
+asmlinkage int sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, struct rusage32 *ru)
+{
+ if (!ru)
+ return sys_wait4(pid, stat_addr, options, NULL);
+ else {
+ struct rusage r;
+ int ret;
+ unsigned int status;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
+ set_fs (old_fs);
+ if (put_rusage (ru, &r)) return -EFAULT;
+ if (stat_addr && put_user (status, stat_addr))
+ return -EFAULT;
+ return ret;
+ }
+}
+
+struct sysinfo32 {
+ s32 uptime;
+ u32 loads[3];
+ u32 totalram;
+ u32 freeram;
+ u32 sharedram;
+ u32 bufferram;
+ u32 totalswap;
+ u32 freeswap;
+ unsigned short procs;
+ char _f[22];
+};
+
+extern asmlinkage int sys_sysinfo(struct sysinfo *info);
+
+asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
+{
+ struct sysinfo s;
+ int ret, err;
+ mm_segment_t old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+ ret = sys_sysinfo(&s);
+ set_fs (old_fs);
+ err = put_user (s.uptime, &info->uptime);
+ err |= __put_user (s.loads[0], &info->loads[0]);
+ err |= __put_user (s.loads[1], &info->loads[1]);
+ err |= __put_user (s.loads[2], &info->loads[2]);
+ err |= __put_user (s.totalram, &info->totalram);
+ err |= __put_user (s.freeram, &info->freeram);
+ err |= __put_user (s.sharedram, &info->sharedram);
+ err |= __put_user (s.bufferram, &info->bufferram);
+ err |= __put_user (s.totalswap, &info->totalswap);
+ err |= __put_user (s.freeswap, &info->freeswap);
+ err |= __put_user (s.procs, &info->procs);
+ if (err)
+ return -EFAULT;
+ return ret;
+}
+
+struct timespec32 {
+ s32 tv_sec;
+ s32 tv_nsec;
+};
+
+extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
+
+asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval)
+{
+ struct timespec t;
+ int ret;
+ mm_segment_t old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+ ret = sys_sched_rr_get_interval(pid, &t);
+ set_fs (old_fs);
+ if (put_user (t.tv_sec, &interval->tv_sec) ||
+ __put_user (t.tv_nsec, &interval->tv_nsec))
+ return -EFAULT;
+ return ret;
+}
+
+extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+
+asmlinkage int sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
+{
+ struct timespec t;
+ int ret;
+ mm_segment_t old_fs = get_fs ();
+
+ if (get_user (t.tv_sec, &rqtp->tv_sec) ||
+ __get_user (t.tv_nsec, &rqtp->tv_nsec))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_nanosleep(&t, rmtp ? &t : NULL);
+ set_fs (old_fs);
+ if (rmtp && ret == -EINTR) {
+ if (__put_user (t.tv_sec, &rmtp->tv_sec) ||
+ __put_user (t.tv_nsec, &rmtp->tv_nsec))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset);
+
+asmlinkage int sys32_sigprocmask(int how, old_sigset_t32 *set, old_sigset_t32 *oset)
+{
+ old_sigset_t s;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ if (set && get_user (s, set)) return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL);
+ set_fs (old_fs);
+ if (ret) return ret;
+ if (oset && put_user (s, oset)) return -EFAULT;
+ return 0;
+}
+
+extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize);
+
+asmlinkage int sys32_rt_sigprocmask(int how, sigset_t32 *set, sigset_t32 *oset, __kernel_size_t32 sigsetsize)
+{
+ sigset_t s;
+ sigset_t32 s32;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ if (set) {
+ if (copy_from_user (&s32, set, sizeof(sigset_t32)))
+ return -EFAULT;
+ switch (_NSIG_WORDS) {
+ case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
+ case 3: s.sig[2] = s32.sig[4] | (((long)s32.sig[5]) << 32);
+ case 2: s.sig[1] = s32.sig[2] | (((long)s32.sig[3]) << 32);
+ case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
+ }
+ }
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL, sigsetsize);
+ set_fs (old_fs);
+ if (ret) return ret;
+ if (oset) {
+ switch (_NSIG_WORDS) {
+ case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+ case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+ case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+ case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+ }
+ if (copy_to_user (oset, &s32, sizeof(sigset_t32)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+extern asmlinkage int sys_sigpending(old_sigset_t *set);
+
+asmlinkage int sys32_sigpending(old_sigset_t32 *set)
+{
+ old_sigset_t s;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_sigpending(&s);
+ set_fs (old_fs);
+ if (put_user (s, set)) return -EFAULT;
+ return ret;
+}
+
+extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
+
+asmlinkage int sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize)
+{
+ sigset_t s;
+ sigset_t32 s32;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigpending(&s, sigsetsize);
+ set_fs (old_fs);
+ if (!ret) {
+ switch (_NSIG_WORDS) {
+ case 4: s32.sig[7] = (s.sig[3] >> 32); s32.sig[6] = s.sig[3];
+ case 3: s32.sig[5] = (s.sig[2] >> 32); s32.sig[4] = s.sig[2];
+ case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
+ case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
+ }
+ if (copy_to_user (set, &s32, sizeof(sigset_t32)))
+ return -EFAULT;
+ }
+ return ret;
+}
+
+extern int
+copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from);
+
+asmlinkage int
+sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
+ struct timespec32 *uts, __kernel_size_t32 sigsetsize)
+{
+ int ret, sig;
+ sigset_t these;
+ sigset_t32 these32;
+ struct timespec ts;
+ siginfo_t info;
+ long timeout = 0;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user (&these32, uthese, sizeof(sigset_t32)))
+ return -EFAULT;
+
+ switch (_NSIG_WORDS) {
+ case 4: these.sig[3] = these32.sig[6] | (((long)these32.sig[7]) << 32);
+ case 3: these.sig[2] = these32.sig[4] | (((long)these32.sig[5]) << 32);
+ case 2: these.sig[1] = these32.sig[2] | (((long)these32.sig[3]) << 32);
+ case 1: these.sig[0] = these32.sig[0] | (((long)these32.sig[1]) << 32);
+ }
+
+ /*
+ * Invert the set of allowed signals to get those we
+ * want to block.
+ */
+ sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP));
+ signotset(&these);
+
+ if (uts) {
+ if (get_user (ts.tv_sec, &uts->tv_sec) ||
+ get_user (ts.tv_nsec, &uts->tv_nsec))
+ return -EINVAL;
+ if (ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0
+ || ts.tv_sec < 0)
+ return -EINVAL;
+ }
+
+ spin_lock_irq(&current->sigmask_lock);
+ sig = dequeue_signal(&these, &info);
+ if (!sig) {
+ /* None ready -- temporarily unblock those we're interested
+ in so that we'll be awakened when they arrive. */
+ sigset_t oldblocked = current->blocked;
+ sigandsets(&current->blocked, &current->blocked, &these);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ if (uts)
+ timeout = (timespec_to_jiffies(&ts)
+ + (ts.tv_sec || ts.tv_nsec));
+
+ current->state = TASK_INTERRUPTIBLE;
+ timeout = schedule_timeout(timeout);
+
+ spin_lock_irq(&current->sigmask_lock);
+ sig = dequeue_signal(&these, &info);
+ current->blocked = oldblocked;
+ recalc_sigpending(current);
+ }
+ spin_unlock_irq(&current->sigmask_lock);
+
+ if (sig) {
+ ret = sig;
+ if (uinfo) {
+ if (copy_siginfo_to_user32(uinfo, &info))
+ ret = -EFAULT;
+ }
+ } else {
+ ret = -EAGAIN;
+ if (timeout)
+ ret = -EINTR;
+ }
+
+ return ret;
+}
+
+extern asmlinkage int
+sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
+
+asmlinkage int
+sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
+{
+ siginfo_t info;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ if (copy_from_user (&info, uinfo, 3*sizeof(int)) ||
+ copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE))
+ return -EFAULT;
+ set_fs (KERNEL_DS);
+ ret = sys_rt_sigqueueinfo(pid, sig, &info);
+ set_fs (old_fs);
+ return ret;
+}
+
+struct tms32 {
+ __kernel_clock_t32 tms_utime;
+ __kernel_clock_t32 tms_stime;
+ __kernel_clock_t32 tms_cutime;
+ __kernel_clock_t32 tms_cstime;
+};
+
+extern asmlinkage long sys_times(struct tms * tbuf);
+
+asmlinkage long sys32_times(struct tms32 *tbuf)
+{
+ struct tms t;
+ long ret;
+ mm_segment_t old_fs = get_fs ();
+ int err;
+
+ set_fs (KERNEL_DS);
+ ret = sys_times(tbuf ? &t : NULL);
+ set_fs (old_fs);
+ if (tbuf) {
+ err = put_user (t.tms_utime, &tbuf->tms_utime);
+ err |= __put_user (t.tms_stime, &tbuf->tms_stime);
+ err |= __put_user (t.tms_cutime, &tbuf->tms_cutime);
+ err |= __put_user (t.tms_cstime, &tbuf->tms_cstime);
+ if (err)
+ ret = -EFAULT;
+ }
+ return ret;
+}
+
+#define RLIM_INFINITY32 0x7fffffff
+#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
+
+struct rlimit32 {
+ u32 rlim_cur;
+ u32 rlim_max;
+};
+
+extern asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim);
+
+asmlinkage int sys32_old_getrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+ struct rlimit r;
+ int ret;
+ mm_segment_t old_fs = get_fs ();
+
+ set_fs (KERNEL_DS);
+ ret = sys_old_getrlimit(resource, &r);
+ set_fs (old_fs);
+ if (!ret) {
+ ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
+ ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max);
+ }
+ return ret;
+}
+
+extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
+
+asmlinkage int sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+ struct rlimit r;
+ int ret;
+ mm_segment_t old_fs = get_fs ();
+
+ if (resource >= RLIM_NLIMITS) return -EINVAL;
+ if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
+ __get_user (r.rlim_max, &rlim->rlim_max))
+ return -EFAULT;
+ if (r.rlim_cur == RLIM_INFINITY32)
+ r.rlim_cur = RLIM_INFINITY;
+ if (r.rlim_max == RLIM_INFINITY32)
+ r.rlim_max = RLIM_INFINITY;
+ set_fs (KERNEL_DS);
+ ret = sys_setrlimit(resource, &r);
+ set_fs (old_fs);
+ return ret;
+}
+
+extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
+
+asmlinkage int sys32_getrusage(int who, struct rusage32 *ru)
+{
+ struct rusage r;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_getrusage(who, &r);
+ set_fs (old_fs);
+ if (put_rusage (ru, &r)) return -EFAULT;
+ return ret;
+}
+
+/* XXX This really belongs in some header file... -DaveM */
+#define MAX_SOCK_ADDR 128 /* 108 for Unix domain -
+ 16 for IP, 16 for IPX,
+ 24 for IPv6,
+ about 80 for AX.25 */
+
+extern struct socket *sockfd_lookup(int fd, int *err);
+
+/* XXX This as well... */
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+ fput(sock->file);
+}
+
+struct msghdr32 {
+ u32 msg_name;
+ int msg_namelen;
+ u32 msg_iov;
+ __kernel_size_t32 msg_iovlen;
+ u32 msg_control;
+ __kernel_size_t32 msg_controllen;
+ unsigned msg_flags;
+};
+
+struct cmsghdr32 {
+ __kernel_size_t32 cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+};
+
+/* Bleech... */
+#define __CMSG32_NXTHDR(ctl, len, cmsg, cmsglen) __cmsg32_nxthdr((ctl),(len),(cmsg),(cmsglen))
+#define CMSG32_NXTHDR(mhdr, cmsg, cmsglen) cmsg32_nxthdr((mhdr), (cmsg), (cmsglen))
+
+#define CMSG32_ALIGN(len) ( ((len)+sizeof(int)-1) & ~(sizeof(int)-1) )
+
+#define CMSG32_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG32_ALIGN(sizeof(struct cmsghdr32))))
+#define CMSG32_SPACE(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + CMSG32_ALIGN(len))
+#define CMSG32_LEN(len) (CMSG32_ALIGN(sizeof(struct cmsghdr32)) + (len))
+
+#define __CMSG32_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr32) ? \
+ (struct cmsghdr32 *)(ctl) : \
+ (struct cmsghdr32 *)NULL)
+#define CMSG32_FIRSTHDR(msg) __CMSG32_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+
+__inline__ struct cmsghdr32 *__cmsg32_nxthdr(void *__ctl, __kernel_size_t __size,
+ struct cmsghdr32 *__cmsg, int __cmsg_len)
+{
+ struct cmsghdr32 * __ptr;
+
+ __ptr = (struct cmsghdr32 *)(((unsigned char *) __cmsg) +
+ CMSG32_ALIGN(__cmsg_len));
+ if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
+ return NULL;
+
+ return __ptr;
+}
+
+__inline__ struct cmsghdr32 *cmsg32_nxthdr (struct msghdr *__msg,
+ struct cmsghdr32 *__cmsg,
+ int __cmsg_len)
+{
+ return __cmsg32_nxthdr(__msg->msg_control, __msg->msg_controllen,
+ __cmsg, __cmsg_len);
+}
+
+static inline int iov_from_user32_to_kern(struct iovec *kiov,
+ struct iovec32 *uiov32,
+ int niov)
+{
+ int tot_len = 0;
+
+ while(niov > 0) {
+ u32 len, buf;
+
+ if(get_user(len, &uiov32->iov_len) ||
+ get_user(buf, &uiov32->iov_base)) {
+ tot_len = -EFAULT;
+ break;
+ }
+ tot_len += len;
+ kiov->iov_base = (void *)A(buf);
+ kiov->iov_len = (__kernel_size_t) len;
+ uiov32++;
+ kiov++;
+ niov--;
+ }
+ return tot_len;
+}
+
+static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
+ struct msghdr32 *umsg)
+{
+ u32 tmp1, tmp2, tmp3;
+ int err;
+
+ err = get_user(tmp1, &umsg->msg_name);
+ err |= __get_user(tmp2, &umsg->msg_iov);
+ err |= __get_user(tmp3, &umsg->msg_control);
+ if (err)
+ return -EFAULT;
+
+ kmsg->msg_name = (void *)A(tmp1);
+ kmsg->msg_iov = (struct iovec *)A(tmp2);
+ kmsg->msg_control = (void *)A(tmp3);
+
+ err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
+ err |= get_user(kmsg->msg_iovlen, &umsg->msg_iovlen);
+ err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
+ err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
+
+ return err;
+}
+
+/* I've named the args so it is easy to tell whose space the pointers are in. */
+static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
+ char *kern_address, int mode)
+{
+ int tot_len;
+
+ if(kern_msg->msg_namelen) {
+ if(mode==VERIFY_READ) {
+ int err = move_addr_to_kernel(kern_msg->msg_name,
+ kern_msg->msg_namelen,
+ kern_address);
+ if(err < 0)
+ return err;
+ }
+ kern_msg->msg_name = kern_address;
+ } else
+ kern_msg->msg_name = NULL;
+
+ if(kern_msg->msg_iovlen > UIO_FASTIOV) {
+ kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
+ GFP_KERNEL);
+ if(!kern_iov)
+ return -ENOMEM;
+ }
+
+ tot_len = iov_from_user32_to_kern(kern_iov,
+ (struct iovec32 *)kern_msg->msg_iov,
+ kern_msg->msg_iovlen);
+ if(tot_len >= 0)
+ kern_msg->msg_iov = kern_iov;
+ else if(kern_msg->msg_iovlen > UIO_FASTIOV)
+ kfree(kern_iov);
+
+ return tot_len;
+}
+
+/* There is a lot of hair here because the alignment rules (and
+ * thus placement) of cmsg headers and length are different for
+ * 32-bit apps. -DaveM
+ */
+static int cmsghdr_from_user32_to_kern(struct msghdr *kmsg,
+ unsigned char *stackbuf, int stackbuf_size)
+{
+ struct cmsghdr32 *ucmsg;
+ struct cmsghdr *kcmsg, *kcmsg_base;
+ __kernel_size_t32 ucmlen;
+ __kernel_size_t kcmlen, tmp;
+
+ kcmlen = 0;
+ kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf;
+ ucmsg = CMSG32_FIRSTHDR(kmsg);
+ while(ucmsg != NULL) {
+ if(get_user(ucmlen, &ucmsg->cmsg_len))
+ return -EFAULT;
+
+ /* Catch bogons. */
+ if(CMSG32_ALIGN(ucmlen) <
+ CMSG32_ALIGN(sizeof(struct cmsghdr32)))
+ return -EINVAL;
+ if((unsigned long)(((char *)ucmsg - (char *)kmsg->msg_control)
+ + ucmlen) > kmsg->msg_controllen)
+ return -EINVAL;
+
+ tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+ CMSG_ALIGN(sizeof(struct cmsghdr)));
+ kcmlen += tmp;
+ ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+ }
+ if(kcmlen == 0)
+ return -EINVAL;
+
+ /* The kcmlen holds the 64-bit version of the control length.
+ * It may not be modified as we do not stick it into the kmsg
+ * until we have successfully copied over all of the data
+ * from the user.
+ */
+ if(kcmlen > stackbuf_size)
+ kcmsg_base = kcmsg = kmalloc(kcmlen, GFP_KERNEL);
+ if(kcmsg == NULL)
+ return -ENOBUFS;
+
+ /* Now copy them over neatly. */
+ memset(kcmsg, 0, kcmlen);
+ ucmsg = CMSG32_FIRSTHDR(kmsg);
+ while(ucmsg != NULL) {
+ __get_user(ucmlen, &ucmsg->cmsg_len);
+ tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) +
+ CMSG_ALIGN(sizeof(struct cmsghdr)));
+ kcmsg->cmsg_len = tmp;
+ __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level);
+ __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type);
+
+ /* Copy over the data. */
+ if(copy_from_user(CMSG_DATA(kcmsg),
+ CMSG32_DATA(ucmsg),
+ (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg)))))
+ goto out_free_efault;
+
+ /* Advance. */
+ kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp));
+ ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen);
+ }
+
+ /* Ok, looks like we made it. Hook it up and return success. */
+ kmsg->msg_control = kcmsg_base;
+ kmsg->msg_controllen = kcmlen;
+ return 0;
+
+out_free_efault:
+ if(kcmsg_base != (struct cmsghdr *)stackbuf)
+ kfree(kcmsg_base);
+ return -EFAULT;
+}
+
+static void put_cmsg32(struct msghdr *kmsg, int level, int type,
+ int len, void *data)
+{
+ struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+ struct cmsghdr32 cmhdr;
+ int cmlen = CMSG32_LEN(len);
+
+ if(cm == NULL || kmsg->msg_controllen < sizeof(*cm)) {
+ kmsg->msg_flags |= MSG_CTRUNC;
+ return;
+ }
+
+ if(kmsg->msg_controllen < cmlen) {
+ kmsg->msg_flags |= MSG_CTRUNC;
+ cmlen = kmsg->msg_controllen;
+ }
+ cmhdr.cmsg_level = level;
+ cmhdr.cmsg_type = type;
+ cmhdr.cmsg_len = cmlen;
+
+ if(copy_to_user(cm, &cmhdr, sizeof cmhdr))
+ return;
+ if(copy_to_user(CMSG32_DATA(cm), data, cmlen - sizeof(struct cmsghdr32)))
+ return;
+ cmlen = CMSG32_SPACE(len);
+ kmsg->msg_control += cmlen;
+ kmsg->msg_controllen -= cmlen;
+}
+
+static void scm_detach_fds32(struct msghdr *kmsg, struct scm_cookie *scm)
+{
+ struct cmsghdr32 *cm = (struct cmsghdr32 *) kmsg->msg_control;
+ int fdmax = (kmsg->msg_controllen - sizeof(struct cmsghdr32)) / sizeof(int);
+ int fdnum = scm->fp->count;
+ struct file **fp = scm->fp->fp;
+ int *cmfptr;
+ int err = 0, i;
+
+ if (fdnum < fdmax)
+ fdmax = fdnum;
+
+ for (i = 0, cmfptr = (int *) CMSG32_DATA(cm); i < fdmax; i++, cmfptr++) {
+ int new_fd;
+ err = get_unused_fd();
+ if (err < 0)
+ break;
+ new_fd = err;
+ err = put_user(new_fd, cmfptr);
+ if (err) {
+ put_unused_fd(new_fd);
+ break;
+ }
+ /* Bump the usage count and install the file. */
+ get_file(fp[i]);
+ fd_install(new_fd, fp[i]);
+ }
+
+ if (i > 0) {
+ int cmlen = CMSG32_LEN(i * sizeof(int));
+ if (!err)
+ err = put_user(SOL_SOCKET, &cm->cmsg_level);
+ if (!err)
+ err = put_user(SCM_RIGHTS, &cm->cmsg_type);
+ if (!err)
+ err = put_user(cmlen, &cm->cmsg_len);
+ if (!err) {
+ cmlen = CMSG32_SPACE(i * sizeof(int));
+ kmsg->msg_control += cmlen;
+ kmsg->msg_controllen -= cmlen;
+ }
+ }
+ if (i < fdnum)
+ kmsg->msg_flags |= MSG_CTRUNC;
+
+ /*
+ * All of the files that fit in the message have had their
+ * usage counts incremented, so we just free the list.
+ */
+ __scm_destroy(scm);
+}
+
+/* In these cases we (currently) can just copy to data over verbatim
+ * because all CMSGs created by the kernel have well defined types which
+ * have the same layout in both the 32-bit and 64-bit API. One must add
+ * some special cased conversions here if we start sending control messages
+ * with incompatible types.
+ *
+ * SCM_RIGHTS and SCM_CREDENTIALS are done by hand in recvmsg32 right after
+ * we do our work. The remaining cases are:
+ *
+ * SOL_IP IP_PKTINFO struct in_pktinfo 32-bit clean
+ * IP_TTL int 32-bit clean
+ * IP_TOS __u8 32-bit clean
+ * IP_RECVOPTS variable length 32-bit clean
+ * IP_RETOPTS variable length 32-bit clean
+ * (these last two are clean because the types are defined
+ * by the IPv4 protocol)
+ * IP_RECVERR struct sock_extended_err +
+ * struct sockaddr_in 32-bit clean
+ * SOL_IPV6 IPV6_RECVERR struct sock_extended_err +
+ * struct sockaddr_in6 32-bit clean
+ * IPV6_PKTINFO struct in6_pktinfo 32-bit clean
+ * IPV6_HOPLIMIT int 32-bit clean
+ * IPV6_FLOWINFO u32 32-bit clean
+ * IPV6_HOPOPTS ipv6 hop exthdr 32-bit clean
+ * IPV6_DSTOPTS ipv6 dst exthdr(s) 32-bit clean
+ * IPV6_RTHDR ipv6 routing exthdr 32-bit clean
+ * IPV6_AUTHHDR ipv6 auth exthdr 32-bit clean
+ */
+static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
+{
+ unsigned char *workbuf, *wp;
+ unsigned long bufsz, space_avail;
+ struct cmsghdr *ucmsg;
+
+ bufsz = ((unsigned long)kmsg->msg_control) - orig_cmsg_uptr;
+ space_avail = kmsg->msg_controllen + bufsz;
+ wp = workbuf = kmalloc(bufsz, GFP_KERNEL);
+ if(workbuf == NULL)
+ goto fail;
+
+ /* To make this more sane we assume the kernel sends back properly
+ * formatted control messages. Because of how the kernel will truncate
+ * the cmsg_len for MSG_TRUNC cases, we need not check that case either.
+ */
+ ucmsg = (struct cmsghdr *) orig_cmsg_uptr;
+ while(((unsigned long)ucmsg) <=
+ (((unsigned long)kmsg->msg_control) - sizeof(struct cmsghdr))) {
+ struct cmsghdr32 *kcmsg32 = (struct cmsghdr32 *) wp;
+ int clen64, clen32;
+
+ /* UCMSG is the 64-bit format CMSG entry in user-space.
+ * KCMSG32 is within the kernel space temporary buffer
+ * we use to convert into a 32-bit style CMSG.
+ */
+ __get_user(kcmsg32->cmsg_len, &ucmsg->cmsg_len);
+ __get_user(kcmsg32->cmsg_level, &ucmsg->cmsg_level);
+ __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+
+ clen64 = kcmsg32->cmsg_len;
+ copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+ clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+ clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+ CMSG32_ALIGN(sizeof(struct cmsghdr32)));
+ kcmsg32->cmsg_len = clen32;
+
+ ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64));
+ wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32));
+ }
+
+ /* Copy back fixed up data, and adjust pointers. */
+ bufsz = (wp - workbuf);
+ copy_to_user((void *)orig_cmsg_uptr, workbuf, bufsz);
+
+ kmsg->msg_control = (struct cmsghdr *)
+ (((char *)orig_cmsg_uptr) + bufsz);
+ kmsg->msg_controllen = space_avail - bufsz;
+
+ kfree(workbuf);
+ return;
+
+fail:
+ /* If we leave the 64-bit format CMSG chunks in there,
+ * the application could get confused and crash. So to
+ * ensure greater recovery, we report no CMSGs.
+ */
+ kmsg->msg_controllen += bufsz;
+ kmsg->msg_control = (void *) orig_cmsg_uptr;
+}
+
+asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
+{
+ struct socket *sock;
+ char address[MAX_SOCK_ADDR];
+ struct iovec iov[UIO_FASTIOV];
+ unsigned char ctl[sizeof(struct cmsghdr) + 20];
+ unsigned char *ctl_buf = ctl;
+ struct msghdr kern_msg;
+ int err, total_len;
+
+ if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+ return -EFAULT;
+ if(kern_msg.msg_iovlen > UIO_MAXIOV)
+ return -EINVAL;
+ err = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
+ if (err < 0)
+ goto out;
+ total_len = err;
+
+ if(kern_msg.msg_controllen) {
+ err = cmsghdr_from_user32_to_kern(&kern_msg, ctl, sizeof(ctl));
+ if(err)
+ goto out_freeiov;
+ ctl_buf = kern_msg.msg_control;
+ }
+ kern_msg.msg_flags = user_flags;
+
+ sock = sockfd_lookup(fd, &err);
+ if (sock != NULL) {
+ if (sock->file->f_flags & O_NONBLOCK)
+ kern_msg.msg_flags |= MSG_DONTWAIT;
+ err = sock_sendmsg(sock, &kern_msg, total_len);
+ sockfd_put(sock);
+ }
+
+ /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */
+ if(ctl_buf != ctl)
+ kfree(ctl_buf);
+out_freeiov:
+ if(kern_msg.msg_iov != iov)
+ kfree(kern_msg.msg_iov);
+out:
+ return err;
+}
+
+asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
+{
+ struct iovec iovstack[UIO_FASTIOV];
+ struct msghdr kern_msg;
+ char addr[MAX_SOCK_ADDR];
+ struct socket *sock;
+ struct iovec *iov = iovstack;
+ struct sockaddr *uaddr;
+ int *uaddr_len;
+ unsigned long cmsg_ptr;
+ int err, total_len, len = 0;
+
+ if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+ return -EFAULT;
+ if(kern_msg.msg_iovlen > UIO_MAXIOV)
+ return -EINVAL;
+
+ uaddr = kern_msg.msg_name;
+ uaddr_len = &user_msg->msg_namelen;
+ err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
+ if (err < 0)
+ goto out;
+ total_len = err;
+
+ cmsg_ptr = (unsigned long) kern_msg.msg_control;
+ kern_msg.msg_flags = 0;
+
+ sock = sockfd_lookup(fd, &err);
+ if (sock != NULL) {
+ struct scm_cookie scm;
+
+ if (sock->file->f_flags & O_NONBLOCK)
+ user_flags |= MSG_DONTWAIT;
+ memset(&scm, 0, sizeof(scm));
+ err = sock->ops->recvmsg(sock, &kern_msg, total_len,
+ user_flags, &scm);
+ if(err >= 0) {
+ len = err;
+ if(!kern_msg.msg_control) {
+ if(sock->passcred || scm.fp)
+ kern_msg.msg_flags |= MSG_CTRUNC;
+ if(scm.fp)
+ __scm_destroy(&scm);
+ } else {
+ /* If recvmsg processing itself placed some
+ * control messages into user space, it's is
+ * using 64-bit CMSG processing, so we need
+ * to fix it up before we tack on more stuff.
+ */
+ if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+ cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
+
+ /* Wheee... */
+ if(sock->passcred)
+ put_cmsg32(&kern_msg,
+ SOL_SOCKET, SCM_CREDENTIALS,
+ sizeof(scm.creds), &scm.creds);
+ if(scm.fp != NULL)
+ scm_detach_fds32(&kern_msg, &scm);
+ }
+ }
+ sockfd_put(sock);
+ }
+
+ if(uaddr != NULL && err >= 0)
+ err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
+ if(cmsg_ptr != 0 && err >= 0) {
+ unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control);
+ __kernel_size_t32 uclen = (__kernel_size_t32) (ucmsg_ptr - cmsg_ptr);
+ err |= __put_user(uclen, &user_msg->msg_controllen);
+ }
+ if(err >= 0)
+ err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
+ if(kern_msg.msg_iov != iov)
+ kfree(kern_msg.msg_iov);
+out:
+ if(err < 0)
+ return err;
+ return len;
+}
+
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+ char *optval, int optlen);
+
+static int do_set_attach_filter(int fd, int level, int optname,
+ char *optval, int optlen)
+{
+ struct sock_fprog32 {
+ __u16 len;
+ __u32 filter;
+ } *fprog32 = (struct sock_fprog32 *)optval;
+ struct sock_fprog kfprog;
+ struct sock_filter *kfilter;
+ unsigned int fsize;
+ mm_segment_t old_fs;
+ __u32 uptr;
+ int ret;
+
+ if (get_user(kfprog.len, &fprog32->len) ||
+ __get_user(uptr, &fprog32->filter))
+ return -EFAULT;
+
+ kfprog.filter = (struct sock_filter *)A(uptr);
+ fsize = kfprog.len * sizeof(struct sock_filter);
+
+ kfilter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
+ if (kfilter == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(kfilter, kfprog.filter, fsize)) {
+ kfree(kfilter);
+ return -EFAULT;
+ }
+
+ kfprog.filter = kfilter;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_setsockopt(fd, level, optname,
+ (char *)&kfprog, sizeof(kfprog));
+ set_fs(old_fs);
+
+ kfree(kfilter);
+
+ return ret;
+}
+
+static int do_set_icmpv6_filter(int fd, int level, int optname,
+ char *optval, int optlen)
+{
+ struct icmp6_filter kfilter;
+ mm_segment_t old_fs;
+ int ret, i;
+
+ if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
+ return -EFAULT;
+
+
+ for (i = 0; i < 8; i += 2) {
+ u32 tmp = kfilter.data[i];
+
+ kfilter.data[i] = kfilter.data[i + 1];
+ kfilter.data[i + 1] = tmp;
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_setsockopt(fd, level, optname,
+ (char *) &kfilter, sizeof(kfilter));
+ set_fs(old_fs);
+
+ return ret;
+}
+
+asmlinkage int sys32_setsockopt(int fd, int level, int optname,
+ char *optval, int optlen)
+{
+ if (optname == SO_ATTACH_FILTER)
+ return do_set_attach_filter(fd, level, optname,
+ optval, optlen);
+ if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
+ return do_set_icmpv6_filter(fd, level, optname,
+ optval, optlen);
+
+ return sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
+extern void check_pending(int signum);
+
+/*
+ * count32() counts the number of arguments/envelopes
+ */
+static int count32(u32 * argv)
+{
+ int i = 0;
+
+ if (argv != NULL) {
+ for (;;) {
+ u32 p; int error;
+
+ error = get_user(p,argv);
+ if (error) return error;
+ if (!p) break;
+ argv++; i++;
+ }
+ }
+ return i;
+}
+
+/*
+ * 'copy_string32()' copies argument/envelope strings from user
+ * memory to free pages in kernel mem. These are in a format ready
+ * to be put directly into the top of new user memory.
+ */
+static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
+{
+ while (argc-- > 0) {
+ u32 str;
+ int len;
+ unsigned long pos;
+
+ if (get_user(str, argv + argc) ||
+ !str ||
+ !(len = strnlen_user((char *)A(str), bprm->p)))
+ return -EFAULT;
+
+ if (bprm->p < len)
+ return -E2BIG;
+
+ bprm->p -= len;
+
+ pos = bprm->p;
+ while (len) {
+ char *kaddr;
+ struct page *page;
+ int offset, bytes_to_copy, new, err;
+
+ offset = pos % PAGE_SIZE;
+ page = bprm->page[pos / PAGE_SIZE];
+ new = 0;
+ if (!page) {
+ page = alloc_page(GFP_USER);
+ bprm->page[pos / PAGE_SIZE] = page;
+ if (!page)
+ return -ENOMEM;
+ new = 1;
+ }
+ kaddr = (char *)kmap(page);
+
+ if (new && offset)
+ memset(kaddr, 0, offset);
+ bytes_to_copy = PAGE_SIZE - offset;
+ if (bytes_to_copy > len) {
+ bytes_to_copy = len;
+ if (new)
+ memset(kaddr+offset+len, 0,
+ PAGE_SIZE-offset-len);
+ }
+
+ err = copy_from_user(kaddr + offset, (char *)A(str),
+ bytes_to_copy);
+ flush_page_to_ram(page);
+ kunmap((unsigned long)kaddr);
+
+ if (err)
+ return -EFAULT;
+
+ pos += bytes_to_copy;
+ str += bytes_to_copy;
+ len -= bytes_to_copy;
+ }
+ }
+ return 0;
+}
+
+/*
+ * sys32_execve() executes a new program.
+ */
+static inline int
+do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
+{
+ struct linux_binprm bprm;
+ struct file * file;
+ int retval;
+ int i;
+
+ bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+ memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
+
+ file = open_exec(filename);
+
+ retval = PTR_ERR(file);
+ if (IS_ERR(file))
+ return retval;
+
+ bprm.file = file;
+ bprm.filename = filename;
+ bprm.sh_bang = 0;
+ bprm.loader = 0;
+ bprm.exec = 0;
+ if ((bprm.argc = count32(argv)) < 0) {
+ allow_write_access(file);
+ fput(file);
+ return bprm.argc;
+ }
+ if ((bprm.envc = count32(envp)) < 0) {
+ allow_write_access(file);
+ fput(file);
+ return bprm.envc;
+ }
+
+ retval = prepare_binprm(&bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = copy_strings_kernel(1, &bprm.filename, &bprm);
+ if (retval < 0)
+ goto out;
+
+ bprm.exec = bprm.p;
+ retval = copy_strings32(bprm.envc, envp, &bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = copy_strings32(bprm.argc, argv, &bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = search_binary_handler(&bprm, regs);
+ if (retval >= 0)
+ /* execve success */
+ return retval;
+
+out:
+ /* Something went wrong, return the inode and free the argument pages*/
+ allow_write_access(bprm.file);
+ if (bprm.file)
+ fput(bprm.file);
+
+ for (i=0 ; i<MAX_ARG_PAGES ; i++)
+ if (bprm.page[i])
+ __free_page(bprm.page[i]);
+
+ return retval;
+}
+
+/*
+ * sys32_execve() executes a new program after the asm stub has set
+ * things up for us. This should basically do what I want it to.
+ */
+asmlinkage int
+sys32_execve(struct pt_regs regs)
+{
+ int error;
+ char * filename;
+
+ filename = getname((char *)A(regs.orig_gpr2));
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+ error = do_execve32(filename, (u32 *)A(regs.gprs[3]), (u32 *)A(regs.gprs[4]), &regs);
+ if (error == 0)
+ {
+ current->ptrace &= ~PT_DTRACE;
+ current->thread.fp_regs.fpc=0;
+ __asm__ __volatile__
+ ("sr 0,0\n\t"
+ "sfpc 0,0\n\t"
+ : : :"0");
+ }
+ putname(filename);
+out:
+ return error;
+}
+
+
+#ifdef CONFIG_MODULES
+
+extern asmlinkage unsigned long sys_create_module(const char *name_user, size_t size);
+
+asmlinkage unsigned long sys32_create_module(const char *name_user, __kernel_size_t32 size)
+{
+ return sys_create_module(name_user, (size_t)size);
+}
+
+extern asmlinkage int sys_init_module(const char *name_user, struct module *mod_user);
+
+/* Hey, when you're trying to init module, take time and prepare us a nice 64bit
+ * module structure, even if from 32bit modutils... Why to pollute kernel... :))
+ */
+asmlinkage int sys32_init_module(const char *name_user, struct module *mod_user)
+{
+ return sys_init_module(name_user, mod_user);
+}
+
+extern asmlinkage int sys_delete_module(const char *name_user);
+
+asmlinkage int sys32_delete_module(const char *name_user)
+{
+ return sys_delete_module(name_user);
+}
+
+struct module_info32 {
+ u32 addr;
+ u32 size;
+ u32 flags;
+ s32 usecount;
+};
+
+/* Query various bits about modules. */
+
+static inline long
+get_mod_name(const char *user_name, char **buf)
+{
+ unsigned long page;
+ long retval;
+
+ if ((unsigned long)user_name >= TASK_SIZE
+ && !segment_eq(get_fs (), KERNEL_DS))
+ return -EFAULT;
+
+ page = __get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE);
+ if (retval > 0) {
+ if (retval < PAGE_SIZE) {
+ *buf = (char *)page;
+ return retval;
+ }
+ retval = -ENAMETOOLONG;
+ } else if (!retval)
+ retval = -EINVAL;
+
+ free_page(page);
+ return retval;
+}
+
+static inline void
+put_mod_name(char *buf)
+{
+ free_page((unsigned long)buf);
+}
+
+static __inline__ struct module *find_module(const char *name)
+{
+ struct module *mod;
+
+ for (mod = module_list; mod ; mod = mod->next) {
+ if (mod->flags & MOD_DELETED)
+ continue;
+ if (!strcmp(mod->name, name))
+ break;
+ }
+
+ return mod;
+}
+
+static int
+qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ struct module *mod;
+ size_t nmod, space, len;
+
+ nmod = space = 0;
+
+ for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) {
+ len = strlen(mod->name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+ if (copy_to_user(buf, mod->name, len))
+ return -EFAULT;
+ buf += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(nmod, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ space += len;
+ while ((mod = mod->next)->next != NULL)
+ space += strlen(mod->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static int
+qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ size_t i, space, len;
+
+ if (mod->next == NULL)
+ return -EINVAL;
+ if (!MOD_CAN_QUERY(mod))
+ return put_user(0, ret);
+
+ space = 0;
+ for (i = 0; i < mod->ndeps; ++i) {
+ const char *dep_name = mod->deps[i].dep->name;
+
+ len = strlen(dep_name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+ if (copy_to_user(buf, dep_name, len))
+ return -EFAULT;
+ buf += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ return put_user(i, ret);
+
+calc_space_needed:
+ space += len;
+ while (++i < mod->ndeps)
+ space += strlen(mod->deps[i].dep->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static int
+qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ size_t nrefs, space, len;
+ struct module_ref *ref;
+
+ if (mod->next == NULL)
+ return -EINVAL;
+ if (!MOD_CAN_QUERY(mod))
+ if (put_user(0, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+ space = 0;
+ for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) {
+ const char *ref_name = ref->ref->name;
+
+ len = strlen(ref_name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+ if (copy_to_user(buf, ref_name, len))
+ return -EFAULT;
+ buf += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(nrefs, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ space += len;
+ while ((ref = ref->next_ref) != NULL)
+ space += strlen(ref->ref->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static inline int
+qm_symbols(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ size_t i, space, len;
+ struct module_symbol *s;
+ char *strings;
+ unsigned *vals;
+
+ if (!MOD_CAN_QUERY(mod))
+ if (put_user(0, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+ space = mod->nsyms * 2*sizeof(u32);
+
+ i = len = 0;
+ s = mod->syms;
+
+ if (space > bufsize)
+ goto calc_space_needed;
+
+ if (!access_ok(VERIFY_WRITE, buf, space))
+ return -EFAULT;
+
+ bufsize -= space;
+ vals = (unsigned *)buf;
+ strings = buf+space;
+
+ for (; i < mod->nsyms ; ++i, ++s, vals += 2) {
+ len = strlen(s->name)+1;
+ if (len > bufsize)
+ goto calc_space_needed;
+
+ if (copy_to_user(strings, s->name, len)
+ || __put_user(s->value, vals+0)
+ || __put_user(space, vals+1))
+ return -EFAULT;
+
+ strings += len;
+ bufsize -= len;
+ space += len;
+ }
+
+ if (put_user(i, ret))
+ return -EFAULT;
+ else
+ return 0;
+
+calc_space_needed:
+ for (; i < mod->nsyms; ++i, ++s)
+ space += strlen(s->name)+1;
+
+ if (put_user(space, ret))
+ return -EFAULT;
+ else
+ return -ENOSPC;
+}
+
+static inline int
+qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
+{
+ int error = 0;
+
+ if (mod->next == NULL)
+ return -EINVAL;
+
+ if (sizeof(struct module_info32) <= bufsize) {
+ struct module_info32 info;
+ info.addr = (unsigned long)mod;
+ info.size = mod->size;
+ info.flags = mod->flags;
+ info.usecount =
+ ((mod_member_present(mod, can_unload)
+ && mod->can_unload)
+ ? -1 : atomic_read(&mod->uc.usecount));
+
+ if (copy_to_user(buf, &info, sizeof(struct module_info32)))
+ return -EFAULT;
+ } else
+ error = -ENOSPC;
+
+ if (put_user(sizeof(struct module_info32), ret))
+ return -EFAULT;
+
+ return error;
+}
+
+asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kernel_size_t32 bufsize, u32 ret)
+{
+ struct module *mod;
+ int err;
+
+ lock_kernel();
+ if (name_user == 0) {
+ /* This finds "kernel_module" which is not exported. */
+ for(mod = module_list; mod->next != NULL; mod = mod->next)
+ ;
+ } else {
+ long namelen;
+ char *name;
+
+ if ((namelen = get_mod_name(name_user, &name)) < 0) {
+ err = namelen;
+ goto out;
+ }
+ err = -ENOENT;
+ if (namelen == 0) {
+ /* This finds "kernel_module" which is not exported. */
+ for(mod = module_list; mod->next != NULL; mod = mod->next)
+ ;
+ } else if ((mod = find_module(name)) == NULL) {
+ put_mod_name(name);
+ goto out;
+ }
+ put_mod_name(name);
+ }
+
+ switch (which)
+ {
+ case 0:
+ err = 0;
+ break;
+ case QM_MODULES:
+ err = qm_modules(buf, bufsize, (__kernel_size_t32 *)AA(ret));
+ break;
+ case QM_DEPS:
+ err = qm_deps(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
+ break;
+ case QM_REFS:
+ err = qm_refs(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
+ break;
+ case QM_SYMBOLS:
+ err = qm_symbols(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
+ break;
+ case QM_INFO:
+ err = qm_info(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+out:
+ unlock_kernel();
+ return err;
+}
+
+struct kernel_sym32 {
+ u32 value;
+ char name[60];
+};
+
+extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table);
+
+asmlinkage int sys32_get_kernel_syms(struct kernel_sym32 *table)
+{
+ int len, i;
+ struct kernel_sym *tbl;
+ mm_segment_t old_fs;
+
+ len = sys_get_kernel_syms(NULL);
+ if (!table) return len;
+ tbl = kmalloc (len * sizeof (struct kernel_sym), GFP_KERNEL);
+ if (!tbl) return -ENOMEM;
+ old_fs = get_fs();
+ set_fs (KERNEL_DS);
+ sys_get_kernel_syms(tbl);
+ set_fs (old_fs);
+ for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) {
+ if (put_user (tbl[i].value, &table->value) ||
+ copy_to_user (table->name, tbl[i].name, 60))
+ break;
+ }
+ kfree (tbl);
+ return i;
+}
+
+#else /* CONFIG_MODULES */
+
+asmlinkage unsigned long
+sys32_create_module(const char *name_user, size_t size)
+{
+ return -ENOSYS;
+}
+
+asmlinkage int
+sys32_init_module(const char *name_user, struct module *mod_user)
+{
+ return -ENOSYS;
+}
+
+asmlinkage int
+sys32_delete_module(const char *name_user)
+{
+ return -ENOSYS;
+}
+
+asmlinkage int
+sys32_query_module(const char *name_user, int which, char *buf, size_t bufsize,
+ size_t *ret)
+{
+ /* Let the program know about the new interface. Not that
+ it'll do them much good. */
+ if (which == 0)
+ return 0;
+
+ return -ENOSYS;
+}
+
+asmlinkage int
+sys32_get_kernel_syms(struct kernel_sym *table)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_MODULES */
+
+/* Stuff for NFS server syscalls... */
+struct nfsctl_svc32 {
+ u16 svc32_port;
+ s32 svc32_nthreads;
+};
+
+struct nfsctl_client32 {
+ s8 cl32_ident[NFSCLNT_IDMAX+1];
+ s32 cl32_naddr;
+ struct in_addr cl32_addrlist[NFSCLNT_ADDRMAX];
+ s32 cl32_fhkeytype;
+ s32 cl32_fhkeylen;
+ u8 cl32_fhkey[NFSCLNT_KEYMAX];
+};
+
+struct nfsctl_export32 {
+ s8 ex32_client[NFSCLNT_IDMAX+1];
+ s8 ex32_path[NFS_MAXPATHLEN+1];
+ __kernel_dev_t32 ex32_dev;
+ __kernel_ino_t32 ex32_ino;
+ s32 ex32_flags;
+ __kernel_uid_t32 ex32_anon_uid;
+ __kernel_gid_t32 ex32_anon_gid;
+};
+
+struct nfsctl_uidmap32 {
+ u32 ug32_ident; /* char * */
+ __kernel_uid_t32 ug32_uidbase;
+ s32 ug32_uidlen;
+ u32 ug32_udimap; /* uid_t * */
+ __kernel_uid_t32 ug32_gidbase;
+ s32 ug32_gidlen;
+ u32 ug32_gdimap; /* gid_t * */
+};
+
+struct nfsctl_fhparm32 {
+ struct sockaddr gf32_addr;
+ __kernel_dev_t32 gf32_dev;
+ __kernel_ino_t32 gf32_ino;
+ s32 gf32_version;
+};
+
+struct nfsctl_fdparm32 {
+ struct sockaddr gd32_addr;
+ s8 gd32_path[NFS_MAXPATHLEN+1];
+ s32 gd32_version;
+};
+
+struct nfsctl_fsparm32 {
+ struct sockaddr gd32_addr;
+ s8 gd32_path[NFS_MAXPATHLEN+1];
+ s32 gd32_maxlen;
+};
+
+struct nfsctl_arg32 {
+ s32 ca32_version; /* safeguard */
+ union {
+ struct nfsctl_svc32 u32_svc;
+ struct nfsctl_client32 u32_client;
+ struct nfsctl_export32 u32_export;
+ struct nfsctl_uidmap32 u32_umap;
+ struct nfsctl_fhparm32 u32_getfh;
+ struct nfsctl_fdparm32 u32_getfd;
+ struct nfsctl_fsparm32 u32_getfs;
+ } u;
+#define ca32_svc u.u32_svc
+#define ca32_client u.u32_client
+#define ca32_export u.u32_export
+#define ca32_umap u.u32_umap
+#define ca32_getfh u.u32_getfh
+#define ca32_getfd u.u32_getfd
+#define ca32_getfs u.u32_getfs
+#define ca32_authd u.u32_authd
+};
+
+union nfsctl_res32 {
+ __u8 cr32_getfh[NFS_FHSIZE];
+ struct knfsd_fh cr32_getfs;
+};
+
+static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+ int err;
+
+ err = __get_user(karg->ca_version, &arg32->ca32_version);
+ err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
+ err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads);
+ return err;
+}
+
+static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+ int err;
+
+ err = __get_user(karg->ca_version, &arg32->ca32_version);
+ err |= copy_from_user(&karg->ca_client.cl_ident[0],
+ &arg32->ca32_client.cl32_ident[0],
+ NFSCLNT_IDMAX);
+ err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr);
+ err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
+ &arg32->ca32_client.cl32_addrlist[0],
+ (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
+ err |= __get_user(karg->ca_client.cl_fhkeytype,
+ &arg32->ca32_client.cl32_fhkeytype);
+ err |= __get_user(karg->ca_client.cl_fhkeylen,
+ &arg32->ca32_client.cl32_fhkeylen);
+ err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
+ &arg32->ca32_client.cl32_fhkey[0],
+ NFSCLNT_KEYMAX);
+ return err;
+}
+
+static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+ int err;
+
+ err = __get_user(karg->ca_version, &arg32->ca32_version);
+ err |= copy_from_user(&karg->ca_export.ex_client[0],
+ &arg32->ca32_export.ex32_client[0],
+ NFSCLNT_IDMAX);
+ err |= copy_from_user(&karg->ca_export.ex_path[0],
+ &arg32->ca32_export.ex32_path[0],
+ NFS_MAXPATHLEN);
+ err |= __get_user(karg->ca_export.ex_dev,
+ &arg32->ca32_export.ex32_dev);
+ err |= __get_user(karg->ca_export.ex_ino,
+ &arg32->ca32_export.ex32_ino);
+ err |= __get_user(karg->ca_export.ex_flags,
+ &arg32->ca32_export.ex32_flags);
+ err |= __get_user(karg->ca_export.ex_anon_uid,
+ &arg32->ca32_export.ex32_anon_uid);
+ err |= __get_user(karg->ca_export.ex_anon_gid,
+ &arg32->ca32_export.ex32_anon_gid);
+ karg->ca_export.ex_anon_uid = high2lowuid(karg->ca_export.ex_anon_uid);
+ karg->ca_export.ex_anon_gid = high2lowgid(karg->ca_export.ex_anon_gid);
+ return err;
+}
+
+static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+ u32 uaddr;
+ int i;
+ int err;
+
+ memset(karg, 0, sizeof(*karg));
+ if(__get_user(karg->ca_version, &arg32->ca32_version))
+ return -EFAULT;
+ karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
+ if(!karg->ca_umap.ug_ident)
+ return -ENOMEM;
+ err = __get_user(uaddr, &arg32->ca32_umap.ug32_ident);
+ if(strncpy_from_user(karg->ca_umap.ug_ident,
+ (char *)A(uaddr), PAGE_SIZE) <= 0)
+ return -EFAULT;
+ err |= __get_user(karg->ca_umap.ug_uidbase,
+ &arg32->ca32_umap.ug32_uidbase);
+ err |= __get_user(karg->ca_umap.ug_uidlen,
+ &arg32->ca32_umap.ug32_uidlen);
+ err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap);
+ if (err)
+ return -EFAULT;
+ karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * karg->ca_umap.ug_uidlen),
+ GFP_USER);
+ if(!karg->ca_umap.ug_udimap)
+ return -ENOMEM;
+ for(i = 0; i < karg->ca_umap.ug_uidlen; i++)
+ err |= __get_user(karg->ca_umap.ug_udimap[i],
+ &(((__kernel_uid_t32 *)A(uaddr))[i]));
+ err |= __get_user(karg->ca_umap.ug_gidbase,
+ &arg32->ca32_umap.ug32_gidbase);
+ err |= __get_user(karg->ca_umap.ug_uidlen,
+ &arg32->ca32_umap.ug32_gidlen);
+ err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap);
+ if (err)
+ return -EFAULT;
+ karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * karg->ca_umap.ug_uidlen),
+ GFP_USER);
+ if(!karg->ca_umap.ug_gdimap)
+ return -ENOMEM;
+ for(i = 0; i < karg->ca_umap.ug_gidlen; i++)
+ err |= __get_user(karg->ca_umap.ug_gdimap[i],
+ &(((__kernel_gid_t32 *)A(uaddr))[i]));
+
+ return err;
+}
+
+static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+ int err;
+
+ err = __get_user(karg->ca_version, &arg32->ca32_version);
+ err |= copy_from_user(&karg->ca_getfh.gf_addr,
+ &arg32->ca32_getfh.gf32_addr,
+ (sizeof(struct sockaddr)));
+ err |= __get_user(karg->ca_getfh.gf_dev,
+ &arg32->ca32_getfh.gf32_dev);
+ err |= __get_user(karg->ca_getfh.gf_ino,
+ &arg32->ca32_getfh.gf32_ino);
+ err |= __get_user(karg->ca_getfh.gf_version,
+ &arg32->ca32_getfh.gf32_version);
+ return err;
+}
+
+static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+ int err;
+
+ err = __get_user(karg->ca_version, &arg32->ca32_version);
+ err |= copy_from_user(&karg->ca_getfd.gd_addr,
+ &arg32->ca32_getfd.gd32_addr,
+ (sizeof(struct sockaddr)));
+ err |= copy_from_user(&karg->ca_getfd.gd_path,
+ &arg32->ca32_getfd.gd32_path,
+ (NFS_MAXPATHLEN+1));
+ err |= __get_user(karg->ca_getfd.gd_version,
+ &arg32->ca32_getfd.gd32_version);
+ return err;
+}
+
+static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+ int err;
+
+ err = __get_user(karg->ca_version, &arg32->ca32_version);
+ err |= copy_from_user(&karg->ca_getfs.gd_addr,
+ &arg32->ca32_getfs.gd32_addr,
+ (sizeof(struct sockaddr)));
+ err |= copy_from_user(&karg->ca_getfs.gd_path,
+ &arg32->ca32_getfs.gd32_path,
+ (NFS_MAXPATHLEN+1));
+ err |= __get_user(karg->ca_getfs.gd_maxlen,
+ &arg32->ca32_getfs.gd32_maxlen);
+ return err;
+}
+
+/* This really doesn't need translations, we are only passing
+ * back a union which contains opaque nfs file handle data.
+ */
+static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
+{
+ return copy_to_user(res32, kres, sizeof(*res32));
+}
+
+/*
+asmlinkage long sys_ni_syscall(void);
+*/
+
+int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
+{
+ struct nfsctl_arg *karg = NULL;
+ union nfsctl_res *kres = NULL;
+ mm_segment_t oldfs;
+ int err;
+
+ karg = kmalloc(sizeof(*karg), GFP_USER);
+ if(!karg)
+ return -ENOMEM;
+ if(res32) {
+ kres = kmalloc(sizeof(*kres), GFP_USER);
+ if(!kres) {
+ kfree(karg);
+ return -ENOMEM;
+ }
+ }
+ switch(cmd) {
+ case NFSCTL_SVC:
+ err = nfs_svc32_trans(karg, arg32);
+ break;
+ case NFSCTL_ADDCLIENT:
+ err = nfs_clnt32_trans(karg, arg32);
+ break;
+ case NFSCTL_DELCLIENT:
+ err = nfs_clnt32_trans(karg, arg32);
+ break;
+ case NFSCTL_EXPORT:
+ case NFSCTL_UNEXPORT:
+ err = nfs_exp32_trans(karg, arg32);
+ break;
+ /* This one is unimplemented, be we're ready for it. */
+ case NFSCTL_UGIDUPDATE:
+ err = nfs_uud32_trans(karg, arg32);
+ break;
+ case NFSCTL_GETFH:
+ err = nfs_getfh32_trans(karg, arg32);
+ break;
+ case NFSCTL_GETFD:
+ err = nfs_getfd32_trans(karg, arg32);
+ break;
+ case NFSCTL_GETFS:
+ err = nfs_getfs32_trans(karg, arg32);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ if(err)
+ goto done;
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ err = sys_nfsservctl(cmd, karg, kres);
+ set_fs(oldfs);
+
+ if (err)
+ goto done;
+
+ if((cmd == NFSCTL_GETFH) ||
+ (cmd == NFSCTL_GETFD) ||
+ (cmd == NFSCTL_GETFS))
+ err = nfs_getfh32_res_trans(kres, res32);
+
+done:
+ if(karg) {
+ if(cmd == NFSCTL_UGIDUPDATE) {
+ if(karg->ca_umap.ug_ident)
+ kfree(karg->ca_umap.ug_ident);
+ if(karg->ca_umap.ug_udimap)
+ kfree(karg->ca_umap.ug_udimap);
+ if(karg->ca_umap.ug_gdimap)
+ kfree(karg->ca_umap.ug_gdimap);
+ }
+ kfree(karg);
+ }
+ if(kres)
+ kfree(kres);
+ return err;
+}
+
+/* Translations due to time_t size differences. Which affects all
+ sorts of things, like timeval and itimerval. */
+
+extern struct timezone sys_tz;
+extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
+asmlinkage int sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+ if (tv) {
+ struct timeval ktv;
+ do_gettimeofday(&ktv);
+ if (put_tv32(tv, &ktv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+asmlinkage int sys32_settimeofday(struct timeval32 *tv, struct timezone *tz)
+{
+ struct timeval ktv;
+ struct timezone ktz;
+
+ if (tv) {
+ if (get_tv32(&ktv, tv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_from_user(&ktz, tz, sizeof(ktz)))
+ return -EFAULT;
+ }
+
+ return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL);
+}
+
+extern int do_getitimer(int which, struct itimerval *value);
+
+asmlinkage int sys32_getitimer(int which, struct itimerval32 *it)
+{
+ struct itimerval kit;
+ int error;
+
+ error = do_getitimer(which, &kit);
+ if (!error && put_it32(it, &kit))
+ error = -EFAULT;
+
+ return error;
+}
+
+extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
+
+asmlinkage int sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out)
+{
+ struct itimerval kin, kout;
+ int error;
+
+ if (in) {
+ if (get_it32(&kin, in))
+ return -EFAULT;
+ } else
+ memset(&kin, 0, sizeof(kin));
+
+ error = do_setitimer(which, &kin, out ? &kout : NULL);
+ if (error || !out)
+ return error;
+ if (put_it32(out, &kout))
+ return -EFAULT;
+
+ return 0;
+
+}
+
+asmlinkage int sys_utimes(char *, struct timeval *);
+
+asmlinkage int sys32_utimes(char *filename, struct timeval32 *tvs)
+{
+ char *kfilename;
+ struct timeval ktvs[2];
+ mm_segment_t old_fs;
+ int ret;
+
+ kfilename = getname(filename);
+ ret = PTR_ERR(kfilename);
+ if (!IS_ERR(kfilename)) {
+ if (tvs) {
+ if (get_tv32(&ktvs[0], tvs) ||
+ get_tv32(&ktvs[1], 1+tvs))
+ return -EFAULT;
+ }
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_utimes(kfilename, &ktvs[0]);
+ set_fs(old_fs);
+
+ putname(kfilename);
+ }
+ return ret;
+}
+
+/* These are here just in case some old sparc32 binary calls it. */
+asmlinkage int sys32_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
+
+extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5);
+
+asmlinkage int sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+{
+ return sys_prctl(option,
+ (unsigned long) arg2,
+ (unsigned long) arg3,
+ (unsigned long) arg4,
+ (unsigned long) arg5);
+}
+
+
+extern asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
+ size_t count, loff_t pos);
+
+extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
+ size_t count, loff_t pos);
+
+typedef __kernel_ssize_t32 ssize_t32;
+
+asmlinkage ssize_t32 sys32_pread(unsigned int fd, char *ubuf,
+ __kernel_size_t32 count, u32 poshi, u32 poslo)
+{
+ return sys_pread(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf,
+ __kernel_size_t32 count, u32 poshi, u32 poslo)
+{
+ return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+
+extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
+
+asmlinkage int sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count)
+{
+ mm_segment_t old_fs = get_fs();
+ int ret;
+ off_t of;
+
+ if (offset && get_user(of, offset))
+ return -EFAULT;
+
+ set_fs(KERNEL_DS);
+ ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
+ set_fs(old_fs);
+
+ if (!ret && offset && put_user(of, offset))
+ return -EFAULT;
+
+ return ret;
+}
+
+/* Handle adjtimex compatability. */
+
+struct timex32 {
+ u32 modes;
+ s32 offset, freq, maxerror, esterror;
+ s32 status, constant, precision, tolerance;
+ struct timeval32 time;
+ s32 tick;
+ s32 ppsfreq, jitter, shift, stabil;
+ s32 jitcnt, calcnt, errcnt, stbcnt;
+ s32 :32; s32 :32; s32 :32; s32 :32;
+ s32 :32; s32 :32; s32 :32; s32 :32;
+ s32 :32; s32 :32; s32 :32; s32 :32;
+};
+
+extern int do_adjtimex(struct timex *);
+
+asmlinkage int sys32_adjtimex(struct timex32 *utp)
+{
+ struct timex txc;
+ int ret;
+
+ memset(&txc, 0, sizeof(struct timex));
+
+ if(get_user(txc.modes, &utp->modes) ||
+ __get_user(txc.offset, &utp->offset) ||
+ __get_user(txc.freq, &utp->freq) ||
+ __get_user(txc.maxerror, &utp->maxerror) ||
+ __get_user(txc.esterror, &utp->esterror) ||
+ __get_user(txc.status, &utp->status) ||
+ __get_user(txc.constant, &utp->constant) ||
+ __get_user(txc.precision, &utp->precision) ||
+ __get_user(txc.tolerance, &utp->tolerance) ||
+ __get_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+ __get_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+ __get_user(txc.tick, &utp->tick) ||
+ __get_user(txc.ppsfreq, &utp->ppsfreq) ||
+ __get_user(txc.jitter, &utp->jitter) ||
+ __get_user(txc.shift, &utp->shift) ||
+ __get_user(txc.stabil, &utp->stabil) ||
+ __get_user(txc.jitcnt, &utp->jitcnt) ||
+ __get_user(txc.calcnt, &utp->calcnt) ||
+ __get_user(txc.errcnt, &utp->errcnt) ||
+ __get_user(txc.stbcnt, &utp->stbcnt))
+ return -EFAULT;
+
+ ret = do_adjtimex(&txc);
+
+ if(put_user(txc.modes, &utp->modes) ||
+ __put_user(txc.offset, &utp->offset) ||
+ __put_user(txc.freq, &utp->freq) ||
+ __put_user(txc.maxerror, &utp->maxerror) ||
+ __put_user(txc.esterror, &utp->esterror) ||
+ __put_user(txc.status, &utp->status) ||
+ __put_user(txc.constant, &utp->constant) ||
+ __put_user(txc.precision, &utp->precision) ||
+ __put_user(txc.tolerance, &utp->tolerance) ||
+ __put_user(txc.time.tv_sec, &utp->time.tv_sec) ||
+ __put_user(txc.time.tv_usec, &utp->time.tv_usec) ||
+ __put_user(txc.tick, &utp->tick) ||
+ __put_user(txc.ppsfreq, &utp->ppsfreq) ||
+ __put_user(txc.jitter, &utp->jitter) ||
+ __put_user(txc.shift, &utp->shift) ||
+ __put_user(txc.stabil, &utp->stabil) ||
+ __put_user(txc.jitcnt, &utp->jitcnt) ||
+ __put_user(txc.calcnt, &utp->calcnt) ||
+ __put_user(txc.errcnt, &utp->errcnt) ||
+ __put_user(txc.stbcnt, &utp->stbcnt))
+ ret = -EFAULT;
+
+ return ret;
+}
+
+extern asmlinkage long sys_setpriority(int which, int who, int niceval);
+
+asmlinkage int sys_setpriority32(u32 which, u32 who, u32 niceval)
+{
+ return sys_setpriority((int) which,
+ (int) who,
+ (int) niceval);
+}
+
+struct __sysctl_args32 {
+ u32 name;
+ int nlen;
+ u32 oldval;
+ u32 oldlenp;
+ u32 newval;
+ u32 newlen;
+ u32 __unused[4];
+};
+
+extern asmlinkage long sys32_sysctl(struct __sysctl_args32 *args)
+{
+ struct __sysctl_args32 tmp;
+ int error;
+ size_t oldlen, *oldlenp = NULL;
+ unsigned long addr = (((long)&args->__unused[0]) + 7) & ~7;
+
+ if (copy_from_user(&tmp, args, sizeof(tmp)))
+ return -EFAULT;
+
+ if (tmp.oldval && tmp.oldlenp) {
+ /* Duh, this is ugly and might not work if sysctl_args
+ is in read-only memory, but do_sysctl does indirectly
+ a lot of uaccess in both directions and we'd have to
+ basically copy the whole sysctl.c here, and
+ glibc's __sysctl uses rw memory for the structure
+ anyway. */
+ if (get_user(oldlen, (u32 *)A(tmp.oldlenp)) ||
+ put_user(oldlen, (size_t *)addr))
+ return -EFAULT;
+ oldlenp = (size_t *)addr;
+ }
+
+ lock_kernel();
+ error = do_sysctl((int *)A(tmp.name), tmp.nlen, (void *)A(tmp.oldval),
+ oldlenp, (void *)A(tmp.newval), tmp.newlen);
+ unlock_kernel();
+ if (oldlenp) {
+ if (!error) {
+ if (get_user(oldlen, (size_t *)addr) ||
+ put_user(oldlen, (u32 *)A(tmp.oldlenp)))
+ error = -EFAULT;
+ }
+ copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
+ }
+ return error;
+}
+
+struct stat64_emu31 {
+ unsigned short st_dev;
+ unsigned char __pad0[6];
+
+ long long st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+
+ __u32 st_uid;
+ __u32 st_gid;
+
+ unsigned short st_rdev;
+ unsigned char __pad3[10];
+
+ long long st_size;
+ __u32 st_blksize;
+
+ __u32 st_blocks; /* Number 512-byte blocks allocated. */
+ __u32 __pad4; /* future possible st_blocks high bits */
+
+ __u32 st_atime;
+ __u32 __pad5;
+
+ __u32 st_mtime;
+ __u32 __pad6;
+
+ __u32 st_ctime;
+ __u32 __pad7; /* will be high 32 bits of ctime someday */
+
+ __u32 __unused1;
+ __u32 __unused2;
+};
+
+static inline int
+putstat64 (struct stat64_emu31 *ubuf, struct stat *kbuf)
+{
+ int err;
+
+ err = put_user (kbuf->st_dev, &ubuf->st_dev);
+ err |= __put_user (kbuf->st_ino, &ubuf->st_ino);
+ err |= __put_user (kbuf->st_mode, &ubuf->st_mode);
+ err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink);
+ err |= __put_user (kbuf->st_uid, &ubuf->st_uid);
+ err |= __put_user (kbuf->st_gid, &ubuf->st_gid);
+ err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev);
+ err |= __put_user (kbuf->st_size, &ubuf->st_size);
+ err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize);
+ err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks);
+ err |= __put_user (kbuf->st_atime, &ubuf->st_atime);
+ err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime);
+ err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime);
+ return err;
+}
+
+extern asmlinkage long sys_newstat(char * filename, struct stat * statbuf);
+
+asmlinkage long sys32_stat64(char * filename, struct stat64_emu31 * statbuf, long flags)
+{
+ int ret;
+ struct stat s;
+ char * tmp;
+ int err;
+ mm_segment_t old_fs = get_fs();
+
+ tmp = getname(filename);
+ err = PTR_ERR(tmp);
+ if (IS_ERR(tmp))
+ return err;
+
+ set_fs (KERNEL_DS);
+ ret = sys_newstat(tmp, &s);
+ set_fs (old_fs);
+ putname(tmp);
+ if (putstat64 (statbuf, &s))
+ return -EFAULT;
+ return ret;
+}
+
+extern asmlinkage long sys_newlstat(char * filename, struct stat * statbuf);
+
+asmlinkage long sys32_lstat64(char * filename, struct stat64_emu31 * statbuf, long flags)
+{
+ int ret;
+ struct stat s;
+ char * tmp;
+ int err;
+ mm_segment_t old_fs = get_fs();
+
+ tmp = getname(filename);
+ err = PTR_ERR(tmp);
+ if (IS_ERR(tmp))
+ return err;
+
+ set_fs (KERNEL_DS);
+ ret = sys_newstat(tmp, &s);
+ set_fs (old_fs);
+ putname(tmp);
+ if (putstat64 (statbuf, &s))
+ return -EFAULT;
+ return ret;
+}
+
+extern asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf);
+
+asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 * statbuf, long flags)
+{
+ int ret;
+ struct stat s;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs (KERNEL_DS);
+ ret = sys_newfstat(fd, &s);
+ set_fs (old_fs);
+ if (putstat64 (statbuf, &s))
+ return -EFAULT;
+ return ret;
+}
+
+/*
+ * Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct_emu31 {
+ u32 addr;
+ u32 len;
+ u32 prot;
+ u32 flags;
+ u32 fd;
+ u32 offset;
+};
+
+/* common code for old and new mmaps */
+static inline long do_mmap2(
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+{
+ int error = -EBADF;
+ struct file * file = NULL;
+
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ if (!(flags & MAP_ANONYMOUS)) {
+ file = fget(fd);
+ if (!file)
+ goto out;
+ }
+
+ down(&current->mm->mmap_sem);
+ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ up(&current->mm->mmap_sem);
+
+ if (file)
+ fput(file);
+out:
+ return error;
+}
+
+
+asmlinkage unsigned long
+old32_mmap(struct mmap_arg_struct_emu31 *arg)
+{
+ struct mmap_arg_struct_emu31 a;
+ int error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+
+ error = -EINVAL;
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+out:
+ return error;
+}
+
+asmlinkage long
+sys32_mmap2(struct mmap_arg_struct_emu31 *arg)
+{
+ struct mmap_arg_struct_emu31 a;
+ int error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+out:
+ return error;
+}
+
+extern asmlinkage long sys_socket(int family, int type, int protocol);
+extern asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+extern asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
+extern asmlinkage long sys_listen(int fd, int backlog);
+extern asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);
+extern asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
+extern asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
+extern asmlinkage long sys_socketpair(int family, int type, int protocol, int usockvec[2]);
+extern asmlinkage long sys_send(int fd, void * buff, size_t len, unsigned flags);
+extern asmlinkage long sys_sendto(int fd, void * buff, size_t len, unsigned flags,
+ struct sockaddr *addr, int addr_len);
+extern asmlinkage long sys_recv(int fd, void * ubuf, size_t size, unsigned flags);
+extern asmlinkage long sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags,
+ struct sockaddr *addr, int *addr_len);
+extern asmlinkage long sys_shutdown(int fd, int how);
+extern asmlinkage long sys_getsockopt(int fd, int level, int optname, char *optval, int * optlen);
+
+/* Argument list sizes for sys_socketcall */
+#define AL(x) ((x) * sizeof(u32))
+static unsigned char nas[18] = {AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+ AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
+ AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
+#undef AL
+
+asmlinkage long sys32_socketcall(int call, u32 *args)
+{
+ int ret;
+ u32 a[6];
+
+ if (call < SYS_SOCKET || call > SYS_RECVMSG)
+ return -EINVAL;
+ if (copy_from_user(a, args, nas[call]))
+ return -EFAULT;
+ switch(call) {
+ case SYS_SOCKET:
+ ret = sys_socket(a[0], a[1], a[2]);
+ break;
+ case SYS_BIND:
+ ret = sys_bind(a[0], (struct sockaddr *) A(a[1]), a[2]);
+ break;
+ case SYS_CONNECT:
+ ret = sys_connect(a[0], (struct sockaddr *) A(a[1]), a[2]);
+ break;
+ case SYS_LISTEN:
+ ret = sys_listen(a[0], a[1]);
+ break;
+ case SYS_ACCEPT:
+ ret = sys_accept(a[0], (struct sockaddr *) A(a[1]),
+ (int *) A(a[2]));
+ break;
+ case SYS_GETSOCKNAME:
+ ret = sys_getsockname(a[0], (struct sockaddr *) A(a[1]),
+ (int *) A(a[2]));
+ break;
+ case SYS_GETPEERNAME:
+ ret = sys_getpeername(a[0], (struct sockaddr *) A(a[1]),
+ (int *) A(a[2]));
+ break;
+ case SYS_SOCKETPAIR:
+ ret = sys_socketpair(a[0], a[1], a[2], (int *) A(a[3]));
+ break;
+ case SYS_SEND:
+ ret = sys_send(a[0], (void *) A(a[1]), a[2], a[3]);
+ break;
+ case SYS_SENDTO:
+ ret = sys_sendto(a[0], (void*) A(a[1]), a[2], a[3], (struct sockaddr *) A(a[4]), a[5]);
+ break;
+ case SYS_RECV:
+ ret = sys_recv(a[0], (void *) A(a[1]), a[2], a[3]);
+ break;
+ case SYS_RECVFROM:
+ ret = sys_recvfrom(a[0], (void *) A(a[1]), a[2], a[3], (struct sockaddr *) A(a[4]), (int *) A(a[5]) );
+ break;
+ case SYS_SHUTDOWN:
+ ret = sys_shutdown(a[0], a[1]);
+ break;
+ case SYS_SETSOCKOPT:
+ ret = sys32_setsockopt(a[0], a[1], a[2], (char *) A(a[3]),
+ a[4]);
+ break;
+ case SYS_GETSOCKOPT:
+ ret = sys_getsockopt(a[0], a[1], a[2], (char *) A(a[3]), (int *) A(a[4]) );
+ break;
+ case SYS_SENDMSG:
+ ret = sys32_sendmsg(a[0], (struct msghdr32 *) A(a[1]),
+ a[2]);
+ break;
+ case SYS_RECVMSG:
+ ret = sys32_recvmsg(a[0], (struct msghdr32 *) A(a[1]),
+ a[2]);
+ break;
+ default:
+ ret = EINVAL;
+ break;
+ }
+ return ret;
+}
+
diff --git a/arch/s390x/kernel/linux32.h b/arch/s390x/kernel/linux32.h
new file mode 100644
index 000000000..c3641b0a0
--- /dev/null
+++ b/arch/s390x/kernel/linux32.h
@@ -0,0 +1,246 @@
+#ifndef _ASM_S390X_S390_H
+#define _ASM_S390X_S390_H
+
+#include <linux/config.h>
+#include <linux/socket.h>
+#include <linux/nfs_fs.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/export.h>
+
+#ifdef CONFIG_S390_SUPPORT
+
+/* Macro that masks the high order bit of an 32 bit pointer and converts it*/
+/* to a 64 bit pointer */
+#define A(__x) ((unsigned long)((__x) & 0x7FFFFFFFUL))
+#define AA(__x) \
+ ((unsigned long)(__x))
+
+/* Now 32bit compatibility types */
+typedef unsigned int __kernel_size_t32;
+typedef int __kernel_ssize_t32;
+typedef int __kernel_ptrdiff_t32;
+typedef int __kernel_time_t32;
+typedef int __kernel_clock_t32;
+typedef int __kernel_pid_t32;
+typedef unsigned short __kernel_ipc_pid_t32;
+typedef unsigned short __kernel_uid_t32;
+typedef unsigned short __kernel_gid_t32;
+typedef unsigned short __kernel_dev_t32;
+typedef unsigned int __kernel_ino_t32;
+typedef unsigned short __kernel_mode_t32;
+typedef unsigned short __kernel_umode_t32;
+typedef short __kernel_nlink_t32;
+typedef int __kernel_daddr_t32;
+typedef int __kernel_off_t32;
+typedef unsigned int __kernel_caddr_t32;
+typedef long __kernel_loff_t32;
+typedef __kernel_fsid_t __kernel_fsid_t32;
+
+struct ipc_kludge_32 {
+ __u32 msgp; /* pointer */
+ __s32 msgtyp;
+};
+
+#define F_GETLK64 12
+#define F_SETLK64 13
+#define F_SETLKW64 14
+
+struct flock32 {
+ short l_type;
+ short l_whence;
+ __kernel_off_t32 l_start;
+ __kernel_off_t32 l_len;
+ __kernel_pid_t32 l_pid;
+ short __unused;
+};
+
+struct stat32 {
+ unsigned short st_dev;
+ unsigned short __pad1;
+ __u32 st_ino;
+ unsigned short st_mode;
+ unsigned short st_nlink;
+ unsigned short st_uid;
+ unsigned short st_gid;
+ unsigned short st_rdev;
+ unsigned short __pad2;
+ __u32 st_size;
+ __u32 st_blksize;
+ __u32 st_blocks;
+ __u32 st_atime;
+ __u32 __unused1;
+ __u32 st_mtime;
+ __u32 __unused2;
+ __u32 st_ctime;
+ __u32 __unused3;
+ __u32 __unused4;
+ __u32 __unused5;
+};
+
+struct statfs32 {
+ __s32 f_type;
+ __s32 f_bsize;
+ __s32 f_blocks;
+ __s32 f_bfree;
+ __s32 f_bavail;
+ __s32 f_files;
+ __s32 f_ffree;
+ __kernel_fsid_t f_fsid;
+ __s32 f_namelen;
+ __s32 f_spare[6];
+};
+
+typedef __u32 old_sigset_t32; /* at least 32 bits */
+
+struct old_sigaction32 {
+ __u32 sa_handler; /* Really a pointer, but need to deal with 32 bits */
+ old_sigset_t32 sa_mask; /* A 32 bit mask */
+ __u32 sa_flags;
+ __u32 sa_restorer; /* Another 32 bit pointer */
+};
+
+#define _SIGCONTEXT_NSIG_WORDS32 2
+typedef struct {
+ __u32 sig[_SIGCONTEXT_NSIG_WORDS32];
+} sigset_t32;
+
+typedef union sigval32 {
+ int sival_int;
+ __u32 sival_ptr;
+} sigval_t32;
+
+typedef struct siginfo32 {
+ int si_signo;
+ int si_errno;
+ int si_code;
+
+ union {
+ int _pad[((128/sizeof(int)) - 3)];
+
+ /* kill() */
+ struct {
+ pid_t _pid; /* sender's pid */
+ uid_t _uid; /* sender's uid */
+ } _kill;
+
+ /* POSIX.1b timers */
+ struct {
+ unsigned int _timer1;
+ unsigned int _timer2;
+
+ } _timer;
+
+ /* POSIX.1b signals */
+ struct {
+ pid_t _pid; /* sender's pid */
+ uid_t _uid; /* sender's uid */
+ sigval_t32 _sigval;
+ } _rt;
+
+ /* SIGCHLD */
+ struct {
+ pid_t _pid; /* which child */
+ uid_t _uid; /* sender's uid */
+ int _status;/* exit code */
+ __kernel_clock_t32 _utime;
+ __kernel_clock_t32 _stime;
+ } _sigchld;
+
+ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+ struct {
+ __u32 _addr; /* faulting insn/memory ref. - pointer */
+ } _sigfault;
+
+ /* SIGPOLL */
+ struct {
+ int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ int _fd;
+ } _sigpoll;
+ } _sifields;
+} siginfo_t32;
+
+/*
+ * How these fields are to be accessed.
+ */
+#define si_pid _sifields._kill._pid
+#define si_uid _sifields._kill._uid
+#define si_status _sifields._sigchld._status
+#define si_utime _sifields._sigchld._utime
+#define si_stime _sifields._sigchld._stime
+#define si_value _sifields._rt._sigval
+#define si_int _sifields._rt._sigval.sival_int
+#define si_ptr _sifields._rt._sigval.sival_ptr
+#define si_addr _sifields._sigfault._addr
+#define si_band _sifields._sigpoll._band
+#define si_fd _sifields._sigpoll._fd
+
+/* asm/sigcontext.h */
+typedef union
+{
+ __u64 d;
+ __u32 f;
+} freg_t32;
+
+typedef struct
+{
+ unsigned int fpc;
+ freg_t32 fprs[__NUM_FPRS];
+} _s390_fp_regs32;
+
+typedef struct
+{
+ __u32 mask;
+ __u32 addr;
+} _psw_t32 __attribute__ ((aligned(8)));
+
+typedef struct
+{
+ _psw_t32 psw;
+ __u32 gprs[__NUM_GPRS];
+ __u32 acrs[__NUM_ACRS];
+} _s390_regs_common32;
+
+typedef struct
+{
+ _s390_regs_common32 regs;
+ _s390_fp_regs32 fpregs;
+} _sigregs32;
+
+#define _SIGCONTEXT_NSIG32 64
+#define _SIGCONTEXT_NSIG_BPW32 32
+#define __SIGNAL_FRAMESIZE32 96
+#define _SIGMASK_COPY_SIZE32 (sizeof(u32)*2)
+
+struct sigcontext32
+{
+ __u32 oldmask[_SIGCONTEXT_NSIG_WORDS32];
+ __u32 sregs; /* pointer */
+};
+
+/* asm/signal.h */
+struct sigaction32 {
+ __u32 sa_handler; /* pointer */
+ __u32 sa_flags;
+ __u32 sa_restorer; /* pointer */
+ sigset_t32 sa_mask; /* mask last for extensibility */
+};
+
+typedef struct {
+ __u32 ss_sp; /* pointer */
+ int ss_flags;
+ __kernel_size_t32 ss_size;
+} stack_t32;
+
+/* asm/ucontext.h */
+struct ucontext32 {
+ __u32 uc_flags;
+ __u32 uc_link; /* pointer */
+ stack_t32 uc_stack;
+ sigset_t32 uc_sigmask; /* mask last for extensibility */
+ __u32 sc; /* pointer */
+};
+
+#endif /* !CONFIG_S390_SUPPORT */
+
+#endif /* _ASM_S390X_S390_H */
diff --git a/arch/s390x/kernel/lowcore.S b/arch/s390x/kernel/lowcore.S
new file mode 100644
index 000000000..4cf3bf8f2
--- /dev/null
+++ b/arch/s390x/kernel/lowcore.S
@@ -0,0 +1,28 @@
+/*
+ * arch/s390/kernel/lowcore.S
+ * S390 lowcore definition.
+ *
+ * S390 64 bit Version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hpenner@de.ibm.com)
+ * Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+#include <asm/lowcore.h>
+
+ .align 8192
+ .globl init_S390_lowcore
+init_S390_lowcore:
+ .fill 0x1a0-0x000,1,0
+ .quad _RESTART_PSW_MASK
+ .quad restart_int_handler
+ .quad _EXT_PSW_MASK
+ .quad ext_int_handler
+ .quad _SVC_PSW_MASK
+ .quad system_call
+ .quad _PGM_PSW_MASK
+ .quad pgm_check_handler
+ .quad _MCCK_PSW_MASK
+ .quad mcck_int_handler
+EXT_PSW: .quad _IO_PSW_MASK
+ .quad io_int_handler
+ .fill 0x2000-0x200,1,0
diff --git a/arch/s390x/kernel/mathemu.c b/arch/s390x/kernel/mathemu.c
new file mode 100644
index 000000000..db6dc9431
--- /dev/null
+++ b/arch/s390x/kernel/mathemu.c
@@ -0,0 +1,920 @@
+/*
+ * arch/s390/kernel/mathemu.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * 'mathemu.c' handles IEEE instructions on a S390 processor
+ * that does not have the IEEE fpu
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+
+#include <asm/uaccess.h>
+#include <asm/mathemu.h>
+
+#ifdef CONFIG_SYSCTL
+int sysctl_ieee_emulation_warnings=1;
+#endif
+
+static void display_emulation_not_implemented(char *instr)
+{
+ struct pt_regs *regs;
+ __u16 *location;
+
+#if CONFIG_SYSCTL
+ if(sysctl_ieee_emulation_warnings)
+#endif
+ {
+ regs=current->thread.regs;
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n",
+ instr,
+ current->comm, current->pid);
+ printk("%s's PSW: %08lx %08lx\n",instr,
+ (unsigned long) regs->psw.mask,
+ (unsigned long) location);
+ }
+}
+
+
+static void set_CC_df(__u64 val1,__u64 val2) {
+ int rc;
+ rc = __cmpdf2(val1,val2);
+ current->thread.regs->psw.mask &= 0xFFFFCFFFFFFFFFFFL;
+ switch (rc) {
+ case -1:
+ current->thread.regs->psw.mask |= 0x0000100000000000L;
+ break;
+ case 1:
+ current->thread.regs->psw.mask |= 0x0000200000000000L;
+ break;
+ }
+}
+
+static void set_CC_sf(__u32 val1,__u32 val2) {
+ int rc;
+ rc = __cmpsf2(val1,val2);
+ current->thread.regs->psw.mask &= 0xFFFFCFFFFFFFFFFF;
+ switch (rc) {
+ case -1:
+ current->thread.regs->psw.mask |= 0x0000100000000000L;
+ break;
+ case 1:
+ current->thread.regs->psw.mask |= 0x0000200000000000L;
+ break;
+ }
+}
+
+
+static void emu_adb (int rx, __u64 val) {
+ current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val);
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_adbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,
+ current->thread.fp_regs.fprs[ry].d);
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_aeb (int rx, __u32 val) {
+ current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_aebr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,
+ current->thread.fp_regs.fprs[ry].f);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_axbr (int rx, int ry) {
+ display_emulation_not_implemented("axbr");
+}
+
+static void emu_cdb (int rx, __u64 val) {
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,val);
+}
+
+static void emu_cdbr (int rx, int ry) {
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d);
+}
+
+static void emu_cdfbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].d =
+ __floatsidf(current->thread.regs->gprs[ry]);
+}
+
+static void emu_ceb (int rx, __u32 val) {
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,val);
+}
+
+static void emu_cebr (int rx, int ry) {
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f);
+}
+
+static void emu_cefbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].f =
+ __floatsisf(current->thread.regs->gprs[ry]);
+}
+
+static void emu_cfdbr (int rx, int ry, int mask) {
+ current->thread.regs->gprs[rx] =
+ __fixdfsi(current->thread.fp_regs.fprs[ry].d);
+}
+
+static void emu_cfebr (int rx, int ry, int mask) {
+ current->thread.regs->gprs[rx] =
+ __fixsfsi(current->thread.fp_regs.fprs[ry].f);
+}
+
+static void emu_cfxbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("cfxbr");
+}
+
+static void emu_cxbr (int rx, int ry) {
+ display_emulation_not_implemented("cxbr");
+}
+
+static void emu_cxfbr (int rx, int ry) {
+ display_emulation_not_implemented("cxfbr");
+}
+
+static void emu_ddb (int rx, __u64 val) {
+ current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val);
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_ddbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,
+ current->thread.fp_regs.fprs[ry].d);
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_deb (int rx, __u32 val) {
+ current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_debr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,
+ current->thread.fp_regs.fprs[ry].f);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_didbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("didbr");
+}
+
+static void emu_diebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("diebr");
+}
+
+static void emu_dxbr (int rx, int ry) {
+ display_emulation_not_implemented("dxbr");
+}
+
+static void emu_efpc (int rx, int ry) {
+ display_emulation_not_implemented("efpc");
+}
+
+static void emu_fidbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("fidbr");
+}
+
+static void emu_fiebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("fiebr");
+}
+
+static void emu_fixbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("fixbr");
+}
+
+static void emu_kdb (int rx, __u64 val) {
+ display_emulation_not_implemented("kdb");
+}
+
+static void emu_kdbr (int rx, int ry) {
+ display_emulation_not_implemented("kdbr");
+}
+
+static void emu_keb (int rx, __u32 val) {
+ display_emulation_not_implemented("keb");
+}
+
+static void emu_kebr (int rx, int ry) {
+ display_emulation_not_implemented("kebr");
+}
+
+static void emu_kxbr (int rx, int ry) {
+ display_emulation_not_implemented("kxbr");
+}
+
+static void emu_lcdbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].d =
+ __negdf2(current->thread.fp_regs.fprs[ry].d);
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_lcebr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].f =
+ __negsf2(current->thread.fp_regs.fprs[ry].f);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_lcxbr (int rx, int ry) {
+ display_emulation_not_implemented("lcxbr");
+}
+
+static void emu_ldeb (int rx, __u32 val) {
+ current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val);
+}
+
+static void emu_ldebr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].d =
+ __extendsfdf2(current->thread.fp_regs.fprs[ry].f);
+}
+
+static void emu_ldxbr (int rx, int ry) {
+ display_emulation_not_implemented("ldxbr");
+}
+
+static void emu_ledbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_lexbr (int rx, int ry) {
+ display_emulation_not_implemented("lexbr");
+}
+
+static void emu_lndbr (int rx, int ry) {
+ display_emulation_not_implemented("lndbr");
+}
+
+static void emu_lnebr (int rx, int ry) {
+ display_emulation_not_implemented("lnebr");
+}
+
+static void emu_lnxbr (int rx, int ry) {
+ display_emulation_not_implemented("lnxbr");
+}
+
+static void emu_lpdbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d);
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,0);
+}
+
+static void emu_lpebr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_lpxbr (int rx, int ry) {
+ display_emulation_not_implemented("lpxbr");
+}
+
+static void emu_ltdbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d;
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_ltebr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f;
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_ltxbr (int rx, int ry) {
+ display_emulation_not_implemented("ltxbr");
+}
+
+static void emu_lxdb (int rx, __u64 val) {
+ display_emulation_not_implemented("lxdb");
+}
+
+static void emu_lxdbr (int rx, int ry) {
+ display_emulation_not_implemented("lxdbr");
+}
+
+static void emu_lxeb (int rx, __u32 val) {
+ display_emulation_not_implemented("lxeb");
+}
+
+static void emu_lxebr (int rx, int ry) {
+ display_emulation_not_implemented("lxebr");
+}
+
+static void emu_madb (int rx, __u64 val, int mask) {
+ display_emulation_not_implemented("madb");
+}
+
+static void emu_madbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("madbr");
+}
+
+static void emu_maeb (int rx, __u32 val, int mask) {
+ display_emulation_not_implemented("maeb");
+}
+
+static void emu_maebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("maebr");
+}
+
+static void emu_mdb (int rx, __u64 val) {
+ current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val);
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_mdbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,
+ current->thread.fp_regs.fprs[ry].d);
+ set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_mdeb (int rx, __u32 val) {
+ display_emulation_not_implemented("mdeb");
+}
+
+static void emu_mdebr (int rx, int ry) {
+ display_emulation_not_implemented("mdebr");
+}
+
+static void emu_meeb (int rx, __u32 val) {
+ current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
+ val);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_meebr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
+ current->thread.fp_regs.fprs[ry].f);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_msdb (int rx, __u64 val, int mask) {
+ display_emulation_not_implemented("msdb");
+}
+
+static void emu_msdbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("msdbr");
+}
+
+static void emu_mseb (int rx, __u32 val, int mask) {
+ display_emulation_not_implemented("mseb");
+}
+
+static void emu_msebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("msebr");
+}
+
+static void emu_mxbr (int rx, int ry) {
+ display_emulation_not_implemented("mxbr");
+}
+
+static void emu_mxdb (int rx, __u64 val) {
+ display_emulation_not_implemented("mxdb");
+}
+
+static void emu_mxdbr (int rx, int ry) {
+ display_emulation_not_implemented("mxdbr");
+}
+
+static void emu_sdb (int rx, __u64 val) {
+ current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
+ val);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_sdbr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
+ current->thread.fp_regs.fprs[ry].d);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
+}
+
+static void emu_seb (int rx, __u32 val) {
+ current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
+ val);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_sebr (int rx, int ry) {
+ current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
+ current->thread.fp_regs.fprs[ry].f);
+ set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+}
+
+static void emu_sfpc (int rx, int ry) {
+ display_emulation_not_implemented("sfpc");
+}
+
+static void emu_sqdb (int rx, __u64 val) {
+ display_emulation_not_implemented("sqdb");
+}
+
+static void emu_sqdbr (int rx, int ry) {
+ display_emulation_not_implemented("sqdbr");
+}
+
+static void emu_sqeb (int rx, __u32 val) {
+ display_emulation_not_implemented("sqeb");
+}
+
+static void emu_sqebr (int rx, int ry) {
+ display_emulation_not_implemented("sqebr");
+}
+
+static void emu_sqxbr (int rx, int ry) {
+ display_emulation_not_implemented("sqxbr");
+}
+
+static void emu_sxbr (int rx, int ry) {
+ display_emulation_not_implemented("sxbr");
+}
+
+static void emu_tcdb (int rx, __u64 val) {
+ display_emulation_not_implemented("tcdb");
+}
+
+static void emu_tceb (int rx, __u32 val) {
+ display_emulation_not_implemented("tceb");
+}
+
+static void emu_tcxb (int rx, __u64 val) {
+ display_emulation_not_implemented("tcxb");
+}
+
+
+static inline void emu_load_regd(int reg) {
+ if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */
+ __asm__ __volatile ( /* load reg from fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " ld 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
+ : "1" );
+ }
+}
+
+static inline void emu_load_rege(int reg) {
+ if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */
+ __asm__ __volatile ( /* load reg from fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " le 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
+ : "1" );
+ }
+}
+
+static inline void emu_store_regd(int reg) {
+ if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */
+ __asm__ __volatile ( /* store reg to fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " std 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
+ : "1" );
+ }
+}
+
+
+static inline void emu_store_rege(int reg) {
+ if ((reg&9) == 0) { /* test if reg in {0,2,4,6} */
+ __asm__ __volatile ( /* store reg to fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " ste 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
+ : "1" );
+ }
+}
+
+int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
+ static const __u8 format_table[] = {
+ 2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4,
+ 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1,10, 1, 1, 3, 1, 1, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 5, 6, 6, 0, 7, 8, 8, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ static const void *jump_table[]= {
+ emu_lpebr, emu_lnebr, emu_ltebr, emu_lcebr,
+ emu_ldebr, emu_lxdbr, emu_lxebr, emu_mxdbr,
+ emu_kebr, emu_cebr, emu_aebr, emu_sebr,
+ emu_mdebr, emu_debr, emu_maebr, emu_msebr,
+ emu_lpdbr, emu_lndbr, emu_ltdbr, emu_lcdbr,
+ emu_sqebr, emu_sqdbr, emu_sqxbr, emu_meebr,
+ emu_kdbr, emu_cdbr, emu_adbr, emu_sdbr,
+ emu_mdbr, emu_ddbr, emu_madbr, emu_msdbr,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ emu_lpxbr, emu_lnxbr, emu_ltxbr, emu_lcxbr,
+ emu_ledbr, emu_ldxbr, emu_lexbr, emu_fixbr,
+ emu_kxbr, emu_cxbr, emu_axbr, emu_sxbr,
+ emu_mxbr, emu_dxbr, NULL, NULL,
+ NULL, NULL, NULL, emu_diebr,
+ NULL, NULL, NULL, emu_fiebr,
+ NULL, NULL, NULL, emu_didbr,
+ NULL, NULL, NULL, emu_fidbr,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ emu_sfpc, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ emu_efpc, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ emu_cefbr, emu_cdfbr, emu_cxfbr, NULL,
+ emu_cfebr, emu_cfdbr, emu_cfxbr
+ };
+
+ switch (format_table[opcode[1]]) {
+ case 1: /* RRE format, double operation */
+ emu_store_regd((opcode[3]>>4)&15);
+ emu_store_regd(opcode[3]&15);
+ /* call the emulation function */
+ ((void (*)(int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15);
+ emu_load_regd((opcode[3]>>4)&15);
+ emu_load_regd(opcode[3]&15);
+ return 0;
+ case 2: /* RRE format, float operation */
+ emu_store_rege((opcode[3]>>4)&15);
+ emu_store_rege(opcode[3]&15);
+ /* call the emulation function */
+ ((void (*)(int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15);
+ emu_load_rege((opcode[3]>>4)&15);
+ emu_load_rege(opcode[3]&15);
+ return 0;
+ case 3: /* RRF format, double operation */
+ emu_store_regd((opcode[3]>>4)&15);
+ emu_store_regd(opcode[3]&15);
+ /* call the emulation function */
+ ((void (*)(int, int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
+ emu_load_regd((opcode[3]>>4)&15);
+ emu_load_regd(opcode[3]&15);
+ return 0;
+ case 4: /* RRF format, float operation */
+ emu_store_rege((opcode[3]>>4)&15);
+ emu_store_rege(opcode[3]&15);
+ /* call the emulation function */
+ ((void (*)(int, int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
+ emu_load_rege((opcode[3]>>4)&15);
+ emu_load_rege(opcode[3]&15);
+ return 0;
+ case 5: /* RRE format, cefbr instruction */
+ emu_store_rege((opcode[3]>>4)&15);
+ /* call the emulation function */
+ ((void (*)(int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15);
+ emu_load_rege((opcode[3]>>4)&15);
+ return 0;
+ case 6: /* RRE format, cdfbr & cxfbr instruction */
+ emu_store_regd((opcode[3]>>4)&15);
+ /* call the emulation function */
+ ((void (*)(int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15);
+ emu_load_regd((opcode[3]>>4)&15);
+ return 0;
+ /* FIXME !! */
+ return 0;
+ case 7: /* RRF format, cfebr instruction */
+ emu_store_rege(opcode[3]&15);
+ /* call the emulation function */
+ ((void (*)(int, int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
+ return 0;
+ case 8: /* RRF format, cfdbr & cfxbr instruction */
+ emu_store_regd(opcode[3]&15);
+ /* call the emulation function */
+ ((void (*)(int, int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
+ return 0;
+ case 9: /* RRE format, ldebr & mdebr instruction */
+ /* float store but double load */
+ emu_store_rege((opcode[3]>>4)&15);
+ emu_store_rege(opcode[3]&15);
+ /* call the emulation function */
+ ((void (*)(int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15);
+ emu_load_regd((opcode[3]>>4)&15);
+ return 0;
+ case 10: /* RRE format, ledbr instruction */
+ /* double store but float load */
+ emu_store_regd((opcode[3]>>4)&15);
+ emu_store_regd(opcode[3]&15);
+ /* call the emulation function */
+ ((void (*)(int, int))jump_table[opcode[1]])
+ (opcode[3]>>4,opcode[3]&15);
+ emu_load_rege((opcode[3]>>4)&15);
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp)
+{
+ rx &= 0xf;
+ rb &= 0xf;
+ disp &= 0xfff;
+ return (void*) ((rx != 0 ? regs->gprs[rx] : 0) + /* index */
+ (rb != 0 ? regs->gprs[rb] : 0) + /* base */
+ disp);
+}
+
+int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
+ static const __u8 format_table[] = {
+ 0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4,
+ 2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ static const void *jump_table[]= {
+ NULL, NULL, NULL, NULL,
+ emu_ldeb, emu_lxdb, emu_lxeb, emu_mxdb,
+ emu_keb, emu_ceb, emu_aeb, emu_seb,
+ emu_mdeb, emu_deb, emu_maeb, emu_mseb,
+ emu_tceb, emu_tcdb, emu_tcxb, NULL,
+ emu_sqeb, emu_sqdb, NULL, emu_meeb,
+ emu_kdb, emu_cdb, emu_adb, emu_sdb,
+ emu_mdb, emu_ddb, emu_madb, emu_msdb
+ };
+
+ switch (format_table[opcode[5]]) {
+ case 1: /* RXE format, __u64 constant */ {
+ __u64 *dxb, temp;
+ __u32 opc;
+
+ emu_store_regd((opcode[1]>>4)&15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
+ /* FIXME: how to react if copy_from_user fails ? */
+ copy_from_user(&temp, dxb, 8);
+ /* call the emulation function */
+ ((void (*)(int, __u64))jump_table[opcode[5]])
+ (opcode[1]>>4,temp);
+ emu_load_regd((opcode[1]>>4)&15);
+ return 0;
+ }
+ case 2: /* RXE format, __u32 constant */ {
+ __u32 *dxb, temp;
+ __u32 opc;
+
+ emu_store_rege((opcode[1]>>4)&15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+ /* FIXME: how to react if get_user fails ? */
+ get_user(temp, dxb);
+ /* call the emulation function */
+ ((void (*)(int, __u32))jump_table[opcode[5]])
+ (opcode[1]>>4,temp);
+ emu_load_rege((opcode[1]>>4)&15);
+ return 0;
+ }
+ case 3: /* RXF format, __u64 constant */ {
+ __u32 *dxb, temp;
+ __u32 opc;
+
+ emu_store_regd((opcode[1]>>4)&15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+ /* FIXME: how to react if copy_from_user fails ? */
+ copy_from_user(&temp, dxb, 8);
+ /* call the emulation function */
+ ((void (*)(int, __u32, int))jump_table[opcode[5]])
+ (opcode[1]>>4,temp,opcode[4]>>4);
+ emu_load_regd((opcode[1]>>4)&15);
+ return 0;
+ }
+ case 4: /* RXF format, __u32 constant */ {
+ __u32 *dxb, temp;
+ __u32 opc;
+
+ emu_store_rege((opcode[1]>>4)&15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+ /* FIXME: how to react if get_user fails ? */
+ get_user(temp, dxb);
+ /* call the emulation function */
+ ((void (*)(int, __u32, int))jump_table[opcode[5]])
+ (opcode[1]>>4,temp,opcode[4]>>4);
+ emu_load_rege((opcode[1]>>4)&15);
+ return 0;
+ }
+ case 5: /* RXE format, __u32 constant */
+ /* store_rege and load_regd */
+ {
+ __u32 *dxb, temp;
+ __u32 opc;
+ emu_store_rege((opcode[1]>>4)&15);
+ opc = *((__u32 *) opcode);
+ dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+ /* FIXME: how to react if get_user fails ? */
+ get_user(temp, dxb);
+ /* call the emulation function */
+ ((void (*)(int, __u32))jump_table[opcode[5]])
+ (opcode[1]>>4,temp);
+ emu_load_regd((opcode[1]>>4)&15);
+ return 0;
+ }
+ default:
+ return 1;
+ }
+}
+
+/*
+ * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
+ */
+void math_emu_ldr(__u8 *opcode) {
+ __u16 opc = *((__u16 *) opcode);
+
+ if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */
+ /* we got an exception therfore ry can't be in {0,2,4,6} */
+ __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
+ " bras 1,0f\n"
+ " ld 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (opc&0x00f0),
+ "a" (&current->thread.fp_regs.fprs[opc&0x000f].d)
+ : "1" );
+ } else if ((opc & 0x0009) == 0) { /* test if ry in {0,2,4,6} */
+ __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
+ " bras 1,0f\n"
+ " std 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" ((opc&0x000f)<<4),
+ "a" (&current->thread.fp_regs.fprs[(opc&0x00f0)>>4].d)
+ : "1" );
+ } else { /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+ current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
+ current->thread.fp_regs.fprs[opc&0x000f];
+ }
+}
+
+/*
+ * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
+ */
+void math_emu_ler(__u8 *opcode) {
+ __u16 opc = *((__u16 *) opcode);
+
+ if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */
+ /* we got an exception therfore ry can't be in {0,2,4,6} */
+ __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
+ " bras 1,0f\n"
+ " le 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (opc&0x00f0),
+ "a" (&current->thread.fp_regs.fprs[opc&0x000f].f)
+ : "1" );
+ } else if ((opc & 0x0009) == 0) { /* test if ry in {0,2,4,6} */
+ __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
+ " bras 1,0f\n"
+ " ste 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" ((opc&0x000f)<<4),
+ "a" (&current->thread.fp_regs.fprs[(opc&0x00f0)>>4].f)
+ : "1" );
+ } else { /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
+ current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
+ current->thread.fp_regs.fprs[opc&0x000f];
+ }
+}
+
+/*
+ * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+void math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
+ __u32 opc = *((__u32 *) opcode);
+ __u64 *dxb;
+
+ dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
+ /* FIXME: how to react if copy_from_user fails ? */
+ copy_from_user(&current->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+}
+
+/*
+ * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+void math_emu_le(__u8 *opcode, struct pt_regs * regs) {
+ __u32 opc = *((__u32 *) opcode);
+ __u32 *mem, *dxb;
+
+ dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+ /* FIXME: how to react if get_user fails ? */
+ mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
+ get_user(mem[0], dxb);
+}
+
+/*
+ * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+void math_emu_std(__u8 *opcode, struct pt_regs * regs) {
+ __u32 opc = *((__u32 *) opcode);
+ __u64 *dxb;
+ dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
+ /* FIXME: how to react if copy_to_user fails ? */
+ copy_to_user(dxb, &current->thread.fp_regs.fprs[(opc>>20)&15].d, 8);
+}
+
+/*
+ * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
+ */
+void math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
+ __u32 opc = *((__u32 *) opcode);
+ __u32 *mem, *dxb;
+ dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
+ /* FIXME: how to react if put_user fails ? */
+ mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
+ put_user(mem[0], dxb);
+}
+
+/*
+ * Emulate LFPC D(B)
+ */
+int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
+ /* FIXME: how to do that ?!? */
+ return 0;
+}
+
+/*
+ * Emulate STFPC D(B)
+ */
+int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
+ /* FIXME: how to do that ?!? */
+ return 0;
+}
+
+/*
+ * Emulate SRNM D(B)
+ */
+int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
+ /* FIXME: how to do that ?!? */
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/arch/s390x/kernel/process.c b/arch/s390x/kernel/process.c
new file mode 100644
index 000000000..4533ad528
--- /dev/null
+++ b/arch/s390x/kernel/process.c
@@ -0,0 +1,516 @@
+/*
+ * arch/s390/kernel/process.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Hartmut Penner (hp@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * Derived from "arch/i386/kernel/process.c"
+ * Copyright (C) 1995, Linus Torvalds
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/misc390.h>
+#include <asm/irq.h>
+
+spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
+
+asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+
+/*
+ * The idle loop on a S390...
+ */
+
+static psw_t wait_psw;
+
+int cpu_idle(void *unused)
+{
+ /* endless idle loop with no priority at all */
+ init_idle();
+ current->nice = 20;
+ current->counter = -100;
+ wait_psw.mask = _WAIT_PSW_MASK;
+ wait_psw.addr = (unsigned long) &&idle_wakeup;
+ while(1) {
+ if (softirq_active(smp_processor_id()) &
+ softirq_mask(smp_processor_id())) {
+ do_softirq();
+ __sti();
+ if (!current->need_resched)
+ continue;
+ }
+ if (current->need_resched) {
+ schedule();
+ check_pgt_cache();
+ continue;
+ }
+
+ /* load wait psw */
+ asm volatile (
+ "lpswe %0"
+ : : "m" (wait_psw) );
+idle_wakeup:
+ }
+}
+
+/*
+ As all the register will only be made displayable to the root
+ user ( via printk ) or checking if the uid of the user is 0 from
+ the /proc filesystem please god this will be secure enough DJB.
+ The lines are given one at a time so as not to chew stack space in
+ printk on a crash & also for the proc filesystem when you get
+ 0 returned you know you've got all the lines
+ */
+
+static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs)
+{
+ int linelen=0;
+ int regno,chaincnt;
+ u64 backchain,prev_backchain,endchain;
+ u64 ksp = 0;
+ char *mode = "???";
+
+ enum
+ {
+ sp_linefeed,
+ sp_psw,
+ sp_ksp,
+ sp_gprs,
+ sp_gprs1,
+ sp_gprs2,
+ sp_gprs3,
+ sp_gprs4,
+ sp_gprs5,
+ sp_gprs6,
+ sp_gprs7,
+ sp_gprs8,
+ sp_acrs,
+ sp_acrs1,
+ sp_acrs2,
+ sp_acrs3,
+ sp_acrs4,
+ sp_kern_backchain,
+ sp_kern_backchain1
+ };
+
+ if (task)
+ ksp = task->thread.ksp;
+ if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE))
+ ksp = regs->gprs[15];
+
+ if (regs)
+ mode = (regs->psw.mask & PSW_PROBLEM_STATE)?
+ "User" : "Kernel";
+
+ switch(line)
+ {
+ case sp_linefeed:
+ linelen=sprintf(buff,"\n");
+ break;
+ case sp_psw:
+ if(regs)
+ linelen=sprintf(buff, "%s PSW: %016lx %016lx\n", mode,
+ (unsigned long) regs->psw.mask,
+ (unsigned long) regs->psw.addr);
+ else
+ linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
+ break;
+ case sp_ksp:
+ linelen=sprintf(&buff[linelen],
+ "task: %016lx ksp: %016lx pt_regs: %016lx\n",
+ (addr_t)task, (addr_t)ksp, (addr_t)regs);
+ break;
+ case sp_gprs:
+ if(regs)
+ linelen=sprintf(buff, "%s GPRS:\n", mode);
+ break;
+ case sp_gprs1 ... sp_gprs8:
+ if(regs)
+ {
+ regno=(line-sp_gprs1)*2;
+ linelen = sprintf(buff,"%016lx %016lx\n",
+ regs->gprs[regno],
+ regs->gprs[regno+1]);
+ }
+ break;
+ case sp_acrs:
+ if(regs)
+ linelen=sprintf(buff, "%s ACRS:\n", mode);
+ break;
+ case sp_acrs1 ... sp_acrs4:
+ if(regs)
+ {
+ regno=(line-sp_acrs1)*4;
+ linelen=sprintf(buff,"%08x %08x %08x %08x\n",
+ regs->acrs[regno],
+ regs->acrs[regno+1],
+ regs->acrs[regno+2],
+ regs->acrs[regno+3]);
+ }
+ break;
+ case sp_kern_backchain:
+ if (regs && (regs->psw.mask & PSW_PROBLEM_STATE))
+ break;
+ if (ksp)
+ linelen=sprintf(buff, "Kernel BackChain CallChain\n");
+ break;
+ default:
+ if (ksp)
+ {
+
+ backchain=ksp&PSW_ADDR_MASK;
+ endchain=((backchain&(-THREAD_SIZE))+THREAD_SIZE);
+ prev_backchain=backchain-1;
+ line-=sp_kern_backchain1;
+ for(chaincnt=0;;chaincnt++)
+ {
+ if((backchain==0)||(backchain>=endchain)
+ ||(chaincnt>=8)||(prev_backchain>=backchain))
+ break;
+ if(chaincnt==line)
+ {
+ linelen+=sprintf(&buff[linelen]," %016lx [<%016lx>]\n",
+ backchain,
+ *(u64 *)(backchain+112)&PSW_ADDR_MASK);
+ break;
+ }
+ prev_backchain=backchain;
+ backchain=(*((u64 *)backchain))&PSW_ADDR_MASK;
+ }
+ }
+ }
+ return(linelen);
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ char buff[80];
+ int line;
+
+ printk("CPU: %d\n",smp_processor_id());
+ printk("Process %s (pid: %d, stackpage=%016lX)\n",
+ current->comm, current->pid, 4096+(addr_t)current);
+
+ for (line = 0; sprintf_regs(line, buff, current, regs); line++)
+ printk(buff);
+}
+
+char *task_show_regs(struct task_struct *task, char *buffer)
+{
+ int line, len;
+
+ for (line = 0; ; line++)
+ {
+ len = sprintf_regs(line, buffer, task, NULL);
+ if (!len) break;
+ buffer += len;
+ }
+ return buffer;
+}
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ int clone_arg = flags | CLONE_VM;
+ int retval;
+
+ __asm__ __volatile__(
+ " slgr 2,2\n"
+ " lgr 3,%1\n"
+ " lg 4,%6\n" /* load kernel stack ptr of parent */
+ " svc %b2\n" /* Linux system call*/
+ " clg 4,%6\n" /* compare ksp's: child or parent ? */
+ " je 0f\n" /* parent - jump*/
+ " lg 15,%6\n" /* fix kernel stack pointer*/
+ " aghi 15,%7\n"
+ " xc 0(160,15),0(15)\n" /* clear save area */
+ " lgr 2,%4\n" /* load argument*/
+ " basr 14,%5\n" /* call fn*/
+ " svc %b3\n" /* Linux system call*/
+ "0: lgr %0,2"
+ : "=a" (retval)
+ : "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
+ "d" (arg), "a" (fn), "i" (__LC_KERNEL_STACK) ,
+ "i" (-STACK_FRAME_OVERHEAD)
+ : "2", "3", "4" );
+ return retval;
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+
+ current->used_math = 0;
+ current->flags &= ~PF_USEDFPU;
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
+ unsigned long unused,
+ struct task_struct * p, struct pt_regs * regs)
+{
+ struct stack_frame
+ {
+ unsigned long back_chain;
+ unsigned long eos;
+ unsigned long glue1;
+ unsigned long glue2;
+ unsigned long scratch[2];
+ unsigned long gprs[10]; /* gprs 6 -15 */
+ unsigned long fprs[2]; /* fpr 4 and 6 */
+ unsigned long empty[2];
+#if CONFIG_REMOTE_DEBUG
+ gdb_pt_regs childregs;
+#else
+ pt_regs childregs;
+#endif
+ __u32 pgm_old_ilc; /* single step magic from entry.S */
+ __u32 pgm_svc_step;
+ } *frame;
+
+ frame = (struct stack_frame *) (4*PAGE_SIZE + (unsigned long) p) -1;
+ frame = (struct stack_frame *) (((unsigned long) frame)&-8L);
+ p->thread.regs = &frame->childregs;
+ p->thread.ksp = (unsigned long) frame;
+ frame->childregs = *regs;
+ frame->childregs.gprs[15] = new_stackp;
+ frame->eos = 0;
+
+ /* new return point is ret_from_sys_call */
+ frame->gprs[8] = (unsigned long) &ret_from_fork;
+
+ /* fake return stack for resume(), don't go back to schedule */
+ frame->gprs[9] = (unsigned long) frame;
+ frame->pgm_svc_step = 0; /* Nope we aren't single stepping an svc */
+ /* save fprs, if used in last task */
+ save_fp_regs(&p->thread.fp_regs);
+ p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
+ /* Don't copy debug registers */
+ memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
+ return 0;
+}
+
+asmlinkage int sys_fork(struct pt_regs regs)
+{
+ int ret;
+
+ lock_kernel();
+ ret = do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
+ unlock_kernel();
+ return ret;
+}
+
+asmlinkage int sys_clone(struct pt_regs regs)
+{
+ unsigned long clone_flags;
+ unsigned long newsp;
+ int ret;
+
+ lock_kernel();
+ clone_flags = regs.gprs[3];
+ newsp = regs.orig_gpr2;
+ if (!newsp)
+ newsp = regs.gprs[15];
+ ret = do_fork(clone_flags, newsp, &regs, 0);
+ unlock_kernel();
+ return ret;
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(struct pt_regs regs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+ regs.gprs[15], &regs, 0);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(struct pt_regs regs)
+{
+ int error;
+ char * filename;
+
+ filename = getname((char *) regs.orig_gpr2);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+ error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
+ if (error == 0)
+ {
+ current->ptrace &= ~PT_DTRACE;
+ current->thread.fp_regs.fpc=0;
+ __asm__ __volatile__
+ ("sr 0,0\n\t"
+ "sfpc 0,0\n\t"
+ : : :"0");
+ }
+ putname(filename);
+out:
+ return error;
+}
+
+
+/*
+ * fill in the FPU structure for a core dump.
+ */
+int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
+{
+ save_fp_regs(fpregs);
+ return 1;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+
+/* changed the size calculations - should hopefully work better. lbt */
+ dump->magic = CMAGIC;
+ dump->start_code = 0;
+ dump->start_stack = regs->gprs[15] & ~(PAGE_SIZE - 1);
+ dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
+ dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
+ dump->u_dsize -= dump->u_tsize;
+ dump->u_ssize = 0;
+ if (dump->start_stack < TASK_SIZE)
+ dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
+ memcpy(&dump->regs.gprs[0],regs,sizeof(s390_regs));
+ dump_fpu (regs, &dump->regs.fp_regs);
+ memcpy(&dump->regs.per_info,&current->thread.per_info,sizeof(per_struct));
+}
+
+/*
+ * These bracket the sleeping functions..
+ */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched ((unsigned long) scheduling_functions_start_here)
+#define last_sched ((unsigned long) scheduling_functions_end_here)
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long r14, r15, bc;
+ unsigned long stack_page;
+ int count = 0;
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+ stack_page = (unsigned long) p;
+ r15 = p->thread.ksp;
+ if (!stack_page || r15 < stack_page || r15 >= 16380+stack_page)
+ return 0;
+ bc = *(unsigned long *) r15;
+ do {
+ if (bc < stack_page || bc >= 16380+stack_page)
+ return 0;
+ r14 = *(unsigned long *) (bc+112);
+ if (r14 < first_sched || r14 >= last_sched)
+ return r14;
+ bc = *(unsigned long *) bc;
+ } while (count++ < 16);
+ return 0;
+}
+#undef last_sched
+#undef first_sched
+
+/*
+ * This should be safe even if called from tq_scheduler
+ * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0.
+ *
+ */
+void s390_daemonize(char *name,unsigned long mask,int use_init_fs)
+{
+ struct fs_struct *fs;
+ extern struct task_struct *child_reaper;
+ struct task_struct *this_process=current;
+
+ /*
+ * If we were started as result of loading a module, close all of the
+ * user space pages. We don't need them, and if we didn't close them
+ * they would be locked into memory.
+ */
+ exit_mm(current);
+
+ this_process->session = 1;
+ this_process->pgrp = 1;
+ if(name)
+ {
+ strncpy(current->comm,name,15);
+ current->comm[15]=0;
+ }
+ else
+ current->comm[0]=0;
+ /* set signal mask to what we want to respond */
+ siginitsetinv(&current->blocked,mask);
+ /* exit_signal isn't set up */
+ /* if we inherit from cpu idle */
+ this_process->exit_signal=SIGCHLD;
+ /* if priority=0 schedule can go into a tight loop */
+ this_process->policy= SCHED_OTHER;
+ /* nice goes priority=20-nice; */
+ this_process->nice=10;
+ if(use_init_fs)
+ {
+ exit_fs(this_process); /* current->fs->count--; */
+ fs = init_task.fs;
+ current->fs = fs;
+ atomic_inc(&fs->count);
+ exit_files(current);
+ }
+ write_lock_irq(&tasklist_lock);
+ /* We want init as our parent */
+ REMOVE_LINKS(this_process);
+ this_process->p_opptr=this_process->p_pptr=child_reaper;
+ SET_LINKS(this_process);
+ write_unlock_irq(&tasklist_lock);
+}
diff --git a/arch/s390x/kernel/ptrace.c b/arch/s390x/kernel/ptrace.c
new file mode 100644
index 000000000..d70b76d2b
--- /dev/null
+++ b/arch/s390x/kernel/ptrace.c
@@ -0,0 +1,613 @@
+/*
+ * arch/s390/kernel/ptrace.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * Based on PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/m68k/kernel/ptrace.c"
+ * Copyright (C) 1994 by Hamish Macdonald
+ * Taken from linux/kernel/ptrace.c and modified for M680x0.
+ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ *
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#include <stddef.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+void FixPerRegisters(struct task_struct *task)
+{
+ struct pt_regs *regs = task->thread.regs;
+ per_struct *per_info=
+ (per_struct *)&task->thread.per_info;
+
+ per_info->control_regs.bits.em_instruction_fetch =
+ per_info->single_step | per_info->instruction_fetch;
+
+ if (per_info->single_step) {
+ per_info->control_regs.bits.starting_addr=0;
+#ifdef CONFIG_S390_SUPPORT
+ if (current->thread.flags & S390_FLAG_31BIT) {
+ per_info->control_regs.bits.ending_addr=0x7fffffffUL;
+ }
+ else
+#endif
+ {
+ per_info->control_regs.bits.ending_addr=-1L;
+ }
+ } else {
+ per_info->control_regs.bits.starting_addr=
+ per_info->starting_addr;
+ per_info->control_regs.bits.ending_addr=
+ per_info->ending_addr;
+ }
+ /* if any of the control reg tracing bits are on
+ we switch on per in the psw */
+ if (per_info->control_regs.words.cr[0] & PER_EM_MASK)
+ regs->psw.mask |= PSW_PER_MASK;
+ else
+ regs->psw.mask &= ~PSW_PER_MASK;
+ if (per_info->control_regs.bits.storage_alt_space_ctl)
+ task->thread.user_seg |= USER_STD_MASK;
+ else
+ task->thread.user_seg &= ~USER_STD_MASK;
+}
+
+void set_single_step(struct task_struct *task)
+{
+ per_struct *per_info= (per_struct *) &task->thread.per_info;
+
+ per_info->single_step = 1; /* Single step */
+ FixPerRegisters (task);
+}
+
+void clear_single_step(struct task_struct *task)
+{
+ per_struct *per_info= (per_struct *) &task->thread.per_info;
+
+ per_info->single_step = 0;
+ FixPerRegisters (task);
+}
+
+int ptrace_usercopy(addr_t realuseraddr, addr_t copyaddr, int len,
+ int tofromuser, int writeuser, unsigned long mask)
+{
+ unsigned long *realuserptr, *copyptr;
+ unsigned long tempuser;
+ int retval;
+
+ retval = 0;
+ realuserptr = (unsigned long *) realuseraddr;
+ copyptr = (unsigned long *) copyaddr;
+
+ if (writeuser && realuserptr == NULL)
+ return 0;
+
+ if (mask != -1L) {
+ tempuser = *realuserptr;
+ if (!writeuser) {
+ tempuser &= mask;
+ realuserptr = &tempuser;
+ }
+ }
+ if (tofromuser) {
+ if (writeuser) {
+ retval = copy_from_user(realuserptr, copyptr, len);
+ } else {
+ if (realuserptr == NULL)
+ retval = clear_user(copyptr, len);
+ else
+ retval = copy_to_user(copyptr,realuserptr,len);
+ retval = (retval == -EFAULT) ? -EIO : 0;
+ }
+ } else {
+ if (writeuser)
+ memcpy(realuserptr, copyptr, len);
+ else
+ memcpy(copyptr, realuserptr, len);
+ }
+ if (mask != -1L && writeuser)
+ *realuserptr = (*realuserptr & mask) | (tempuser & ~mask);
+ return retval;
+}
+
+int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr,
+ int len, int tofromuser, int writingtouser)
+{
+ int copylen=0,copymax;
+ addr_t realuseraddr;
+ saddr_t enduseraddr;
+
+ unsigned long mask;
+
+#ifdef CONFIG_S390_SUPPORT
+ if (current->thread.flags & S390_FLAG_31BIT) {
+ /* adjust user offsets to 64 bit structure */
+ if (useraddr < PT_PSWADDR / 2)
+ useraddr = 2 * useraddr;
+ else if(useraddr < PT_ACR0 / 2)
+ useraddr = 2 * useraddr + sizeof(addr_t) / 2;
+ else if(useraddr < PT_ACR0 / 2 + (PT_ORIGGPR2 - PT_ACR0))
+ useraddr = useraddr + PT_ACR0 / 2;
+ else if(useraddr < PT_ACR0 / 2 + (sizeof(user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0))
+ useraddr = useraddr + PT_ACR0 / 2 + sizeof(addr_t) / 2;
+ }
+#endif
+
+ enduseraddr=useraddr+len;
+
+ if (useraddr < 0 || enduseraddr > sizeof(struct user)||
+ (useraddr < PT_ENDREGS && (useraddr&3))||
+ (enduseraddr < PT_ENDREGS && (enduseraddr&3)))
+ return (-EIO);
+ while(len>0)
+ {
+ mask=PSW_ADDR_MASK;
+ if(useraddr<PT_FPC)
+ {
+ realuseraddr=(addr_t)&(((u8 *)task->thread.regs)[useraddr]);
+ if(useraddr<PT_PSWMASK)
+ {
+ copymax=PT_PSWMASK;
+ }
+ else if(useraddr<(PT_PSWMASK+PSW_MASK_SIZE))
+ {
+ copymax=(PT_PSWMASK+PSW_MASK_SIZE);
+ if(writingtouser)
+ mask=PSW_MASK_DEBUGCHANGE;
+ }
+ else if(useraddr<(PT_PSWADDR+PSW_ADDR_SIZE))
+ {
+ copymax=PT_PSWADDR+PSW_ADDR_SIZE;
+ mask=PSW_ADDR_DEBUGCHANGE;
+ }
+ else
+ copymax=PT_FPC;
+
+ }
+ else if(useraddr<(PT_FPR15+sizeof(freg_t)))
+ {
+ copymax=(PT_FPR15+sizeof(freg_t));
+ realuseraddr=(addr_t)&(((u8 *)&task->thread.fp_regs)[useraddr-PT_FPC]);
+ }
+ else if(useraddr<sizeof(user_regs_struct))
+ {
+ copymax=sizeof(user_regs_struct);
+ realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
+ }
+ else
+ {
+ copymax=sizeof(struct user);
+ realuseraddr=(addr_t)NULL;
+ }
+ copylen=copymax-useraddr;
+ copylen=(copylen>len ? len:copylen);
+ if(ptrace_usercopy(realuseraddr,copyaddr,copylen,tofromuser,writingtouser,mask))
+ return (-EIO);
+ copyaddr+=copylen;
+ len-=copylen;
+ useraddr+=copylen;
+ }
+ FixPerRegisters(task);
+ return(0);
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+ struct task_struct *child;
+ int ret = -EPERM;
+ unsigned long flags;
+ unsigned long tmp;
+ int copied;
+ ptrace_area parea;
+
+ lock_kernel();
+ if (request == PTRACE_TRACEME)
+ {
+ /* are we already being traced? */
+ if (current->ptrace & PT_PTRACED)
+ goto out;
+ /* set the ptrace bit in the process flags. */
+ current->ptrace |= PT_PTRACED;
+ ret = 0;
+ goto out;
+ }
+ ret = -ESRCH;
+ read_lock(&tasklist_lock);
+ child = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock);
+ if (!child)
+ goto out;
+ ret = -EPERM;
+ if (pid == 1) /* you may not mess with init */
+ goto out;
+ if (request == PTRACE_ATTACH)
+ {
+ if (child == current)
+ goto out;
+ if ((!child->dumpable ||
+ (current->uid != child->euid) ||
+ (current->uid != child->suid) ||
+ (current->uid != child->uid) ||
+ (current->gid != child->egid) ||
+ (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE))
+ goto out;
+ /* the same process cannot be attached many times */
+ if (child->ptrace & PT_PTRACED)
+ goto out;
+ child->ptrace |= PT_PTRACED;
+
+ write_lock_irqsave(&tasklist_lock, flags);
+ if (child->p_pptr != current)
+ {
+ REMOVE_LINKS(child);
+ child->p_pptr = current;
+ SET_LINKS(child);
+ }
+ write_unlock_irqrestore(&tasklist_lock, flags);
+
+ send_sig(SIGSTOP, child, 1);
+ ret = 0;
+ goto out;
+ }
+ ret = -ESRCH;
+ // printk("child=%lX child->flags=%lX",child,child->flags);
+ /* I added child!=current line so we can get the */
+ /* ieee_instruction_pointer from the user structure DJB */
+ if(child!=current)
+ {
+ if (!(child->ptrace & PT_PTRACED))
+ goto out;
+ if (child->state != TASK_STOPPED)
+ {
+ if (request != PTRACE_KILL)
+ goto out;
+ }
+ if (child->p_pptr != current)
+ goto out;
+ }
+ switch (request)
+ {
+ /* If I and D space are separate, these will need to be fixed. */
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA:
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ ret = -EIO;
+ if (copied != sizeof(tmp))
+ goto out;
+ ret = put_user(tmp,(unsigned long *) data);
+ goto out;
+
+ /* read the word at location addr in the USER area. */
+ case PTRACE_PEEKUSR:
+ ret=copy_user(child,addr,data,sizeof(unsigned long),1,0);
+ break;
+
+ /* If I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ ret = 0;
+ if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+ goto out;
+ ret = -EIO;
+ goto out;
+ break;
+
+ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned long),0,1);
+ break;
+
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: /* restart after signal. */
+ ret = -EIO;
+ if ((unsigned long) data >= _NSIG)
+ break;
+ if (request == PTRACE_SYSCALL)
+ child->ptrace |= PT_TRACESYS;
+ else
+ child->ptrace &= ~PT_TRACESYS;
+ child->exit_code = data;
+ /* make sure the single step bit is not set. */
+ clear_single_step(child);
+ wake_up_process(child);
+ ret = 0;
+ break;
+
+/*
+ * make the child exit. Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
+ * exit.
+ */
+ case PTRACE_KILL:
+ ret = 0;
+ if (child->state == TASK_ZOMBIE) /* already dead */
+ break;
+ child->exit_code = SIGKILL;
+ clear_single_step(child);
+ wake_up_process(child);
+ /* make sure the single step bit is not set. */
+ break;
+
+ case PTRACE_SINGLESTEP: /* set the trap flag. */
+ ret = -EIO;
+ if ((unsigned long) data >= _NSIG)
+ break;
+ child->ptrace &= ~PT_TRACESYS;
+ child->exit_code = data;
+ set_single_step(child);
+ /* give it a chance to run. */
+ wake_up_process(child);
+ ret = 0;
+ break;
+
+ case PTRACE_DETACH: /* detach a process that was attached. */
+ ret = -EIO;
+ if ((unsigned long) data >= _NSIG)
+ break;
+ child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
+ child->exit_code = data;
+ write_lock_irqsave(&tasklist_lock, flags);
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
+ /* make sure the single step bit is not set. */
+ clear_single_step(child);
+ wake_up_process(child);
+ ret = 0;
+ break;
+ case PTRACE_PEEKUSR_AREA:
+ case PTRACE_POKEUSR_AREA:
+ if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)
+ ret=copy_user(child,parea.kernel_addr,parea.process_addr,
+ parea.len,1,(request==PTRACE_POKEUSR_AREA));
+ break;
+ default:
+ ret = -EIO;
+ break;
+ }
+ out:
+ unlock_kernel();
+ return ret;
+}
+
+typedef struct
+{
+__u32 len;
+__u32 kernel_addr;
+__u32 process_addr;
+} ptrace_area_emu31;
+
+asmlinkage int sys32_ptrace(long request, long pid, long addr, s32 data)
+{
+ struct task_struct *child;
+ int ret = -EPERM;
+ unsigned long flags;
+ u32 tmp;
+ int copied;
+ ptrace_area parea;
+
+ lock_kernel();
+ if (request == PTRACE_TRACEME)
+ {
+ /* are we already being traced? */
+ if (current->ptrace & PT_PTRACED)
+ goto out;
+ /* set the ptrace bit in the process flags. */
+ current->ptrace |= PT_PTRACED;
+ ret = 0;
+ goto out;
+ }
+ ret = -ESRCH;
+ read_lock(&tasklist_lock);
+ child = find_task_by_pid(pid);
+ read_unlock(&tasklist_lock);
+ if (!child)
+ goto out;
+ ret = -EPERM;
+ if (pid == 1) /* you may not mess with init */
+ goto out;
+ if (request == PTRACE_ATTACH)
+ {
+ if (child == current)
+ goto out;
+ if ((!child->dumpable ||
+ (current->uid != child->euid) ||
+ (current->uid != child->suid) ||
+ (current->uid != child->uid) ||
+ (current->gid != child->egid) ||
+ (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE))
+ goto out;
+ /* the same process cannot be attached many times */
+ if (child->ptrace & PT_PTRACED)
+ goto out;
+ child->ptrace |= PT_PTRACED;
+
+ write_lock_irqsave(&tasklist_lock, flags);
+ if (child->p_pptr != current)
+ {
+ REMOVE_LINKS(child);
+ child->p_pptr = current;
+ SET_LINKS(child);
+ }
+ write_unlock_irqrestore(&tasklist_lock, flags);
+
+ send_sig(SIGSTOP, child, 1);
+ ret = 0;
+ goto out;
+ }
+ ret = -ESRCH;
+ // printk("child=%lX child->flags=%lX",child,child->flags);
+ /* I added child!=current line so we can get the */
+ /* ieee_instruction_pointer from the user structure DJB */
+ if(child!=current)
+ {
+ if (!(child->ptrace & PT_PTRACED))
+ goto out;
+ if (child->state != TASK_STOPPED)
+ {
+ if (request != PTRACE_KILL)
+ goto out;
+ }
+ if (child->p_pptr != current)
+ goto out;
+ }
+ switch (request)
+ {
+ /* If I and D space are separate, these will need to be fixed. */
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA:
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ ret = -EIO;
+ if (copied != sizeof(tmp))
+ goto out;
+ ret = put_user(tmp,(u32 *)(unsigned long)data);
+ goto out;
+
+ /* read the word at location addr in the USER area. */
+ case PTRACE_PEEKUSR:
+ ret=copy_user(child,addr,data,sizeof(u32),1,0);
+ break;
+
+ /* If I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ ret = 0;
+ if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+ goto out;
+ ret = -EIO;
+ goto out;
+ break;
+
+ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ ret=copy_user(child,addr,(addr_t)&data,sizeof(u32),0,1);
+ break;
+
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT: /* restart after signal. */
+ ret = -EIO;
+ if ((unsigned long) data >= _NSIG)
+ break;
+ if (request == PTRACE_SYSCALL)
+ child->ptrace |= PT_TRACESYS;
+ else
+ child->ptrace &= ~PT_TRACESYS;
+ child->exit_code = data;
+ /* make sure the single step bit is not set. */
+ clear_single_step(child);
+ wake_up_process(child);
+ ret = 0;
+ break;
+
+/*
+ * make the child exit. Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
+ * exit.
+ */
+ case PTRACE_KILL:
+ ret = 0;
+ if (child->state == TASK_ZOMBIE) /* already dead */
+ break;
+ child->exit_code = SIGKILL;
+ clear_single_step(child);
+ wake_up_process(child);
+ /* make sure the single step bit is not set. */
+ break;
+
+ case PTRACE_SINGLESTEP: /* set the trap flag. */
+ ret = -EIO;
+ if ((unsigned long) data >= _NSIG)
+ break;
+ child->ptrace &= ~PT_TRACESYS;
+ child->exit_code = data;
+ set_single_step(child);
+ /* give it a chance to run. */
+ wake_up_process(child);
+ ret = 0;
+ break;
+
+ case PTRACE_DETACH: /* detach a process that was attached. */
+ ret = -EIO;
+ if ((unsigned long) data >= _NSIG)
+ break;
+ child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
+ child->exit_code = data;
+ write_lock_irqsave(&tasklist_lock, flags);
+ REMOVE_LINKS(child);
+ child->p_pptr = child->p_opptr;
+ SET_LINKS(child);
+ write_unlock_irqrestore(&tasklist_lock, flags);
+ /* make sure the single step bit is not set. */
+ clear_single_step(child);
+ wake_up_process(child);
+ ret = 0;
+ break;
+ case PTRACE_PEEKUSR_AREA:
+ case PTRACE_POKEUSR_AREA:
+ {
+ ptrace_area_emu31 * parea31 = (void *)addr;
+ if (!access_ok(VERIFY_READ, parea31, sizeof(*parea31)))
+ return(-EFAULT);
+ ret = __get_user(parea.len, &parea31->len);
+ ret |= __get_user(parea.kernel_addr, &parea31->kernel_addr);
+ ret |= __get_user(parea.process_addr, &parea31->process_addr);
+ if(ret==0)
+ ret=copy_user(child,parea.kernel_addr,parea.process_addr,
+ parea.len,1,(request==PTRACE_POKEUSR_AREA));
+ break;
+ }
+ default:
+ ret = -EIO;
+ break;
+ }
+ out:
+ unlock_kernel();
+ return ret;
+}
+
+asmlinkage void syscall_trace(void)
+{
+ lock_kernel();
+ if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
+ != (PT_PTRACED|PT_TRACESYS))
+ goto out;
+ current->exit_code = SIGTRAP;
+ set_current_state(TASK_STOPPED);
+ notify_parent(current, SIGCHLD);
+ schedule();
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+ * for normal use. strace only continues with a signal if the
+ * stopping signal is not SIGTRAP. -brl
+ */
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
+ out:
+ unlock_kernel();
+}
diff --git a/arch/s390x/kernel/reipl.S b/arch/s390x/kernel/reipl.S
new file mode 100644
index 000000000..d8af95ce1
--- /dev/null
+++ b/arch/s390x/kernel/reipl.S
@@ -0,0 +1,94 @@
+/*
+ * arch/s390/kernel/reipl.S
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ */
+
+#include <asm/lowcore.h>
+ .globl do_reipl
+do_reipl: basr %r13,0
+.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13)
+.Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13)
+ stctg %c0,%c0,.Lctlsave-.Lpg0(%r13)
+ ni .Lctlsave+4-.Lpg0(%r13),0xef
+ lctlg %c0,%c0,.Lctlsave-.Lpg0(%r13)
+ lgr %r1,%r2
+ mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
+ stsch .Lschib-.Lpg0(%r13)
+ oi .Lschib+5-.Lpg0(%r13),0x84
+.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
+ msch .Lschib-.Lpg0(%r13)
+ ssch .Liplorb-.Lpg0(%r13)
+ jz .L001
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)
+.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13)
+.Lcont: c %r1,__LC_SUBCHANNEL_ID
+ jnz .Ltpi
+ clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
+ jnz .Ltpi
+ tsch .Liplirb-.Lpg0(%r13)
+ tm .Liplirb+9-.Lpg0(%r13),0xbf
+ jz .L002
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
+ jz .L003
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L003: spx .Lnull-.Lpg0(%r13)
+ st %r1,__LC_SUBCHANNEL_ID
+ lhi %r1,0 # mode 0 = esa
+ slr %r0,%r0 # set cpuid to zero
+ sigp %r1,%r0,0x12 # switch to esa mode
+ lpsw 0
+.Ldisab: sll %r14,1
+ srl %r14,1 # need to kill hi bit to avoid specification exceptions.
+ st %r14,.Ldispsw+12-.Lpg0(%r13)
+ lpswe .Ldispsw-.Lpg0(%r13)
+ .align 8
+.Lall: .quad 0x00000000ff000000
+.Lctlsave: .quad 0x0000000000000000
+.Lnull: .long 0x0000000000000000
+ .align 16
+/*
+ * These addresses have to be 31 bit otherwise
+ * the sigp will throw a specifcation exception
+ * when switching to ESA mode as bit 31 be set
+ * in the ESA psw.
+ * Bit 31 of the addresses has to be 0 for the
+ * 31bit lpswe instruction a fact they appear to have
+ * ommited from the pop.
+ */
+.Lnewpsw: .quad 0x0000000080000000
+ .quad .Lpg1
+.Lpcnew: .quad 0x0000000080000000
+ .quad .Lecs
+.Lionew: .quad 0x0000000080000000
+ .quad .Lcont
+.Lwaitpsw: .quad 0x0202000080000000
+ .quad .Ltpi
+.Ldispsw: .quad 0x0002000080000000
+ .quad 0x0000000000000000
+.Liplccws: .long 0x02000000,0x60000018
+ .long 0x08000008,0x20000001
+.Liplorb: .long 0x0049504c,0x0000ff80
+ .long 0x00000000+.Liplccws
+.Lschib: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+.Liplirb: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+
+
+
diff --git a/arch/s390x/kernel/s390_ext.c b/arch/s390x/kernel/s390_ext.c
new file mode 100644
index 000000000..6a7be9496
--- /dev/null
+++ b/arch/s390x/kernel/s390_ext.c
@@ -0,0 +1,77 @@
+/*
+ * arch/s390/kernel/s390_ext.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <asm/lowcore.h>
+#include <asm/s390_ext.h>
+
+/*
+ * Simple hash strategy: index = code & 0xff;
+ * ext_int_hash[index] is the start of the list for all external interrupts
+ * that hash to this index. With the current set of external interrupts
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
+ * iucv) this is always the first element.
+ */
+ext_int_info_t *ext_int_hash[256] = { 0, };
+ext_int_info_t ext_int_info_timer;
+ext_int_info_t ext_int_info_hwc;
+
+int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
+ ext_int_info_t *p;
+ int index;
+
+ index = code & 0xff;
+ p = ext_int_hash[index];
+ while (p != NULL) {
+ if (p->code == code)
+ return -EBUSY;
+ p = p->next;
+ }
+ if (code == 0x1004) /* time_init is done before kmalloc works :-/ */
+ p = &ext_int_info_timer;
+ else if (code == 0x2401) /* hwc_init is done too early too */
+ p = &ext_int_info_hwc;
+ else
+ p = (ext_int_info_t *)
+ kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
+ if (p == NULL)
+ return -ENOMEM;
+ p->code = code;
+ p->handler = handler;
+ p->next = ext_int_hash[index];
+ ext_int_hash[index] = p;
+ return 0;
+}
+
+int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
+ ext_int_info_t *p, *q;
+ int index;
+
+ index = code & 0xff;
+ q = NULL;
+ p = ext_int_hash[index];
+ while (p != NULL) {
+ if (p->code == code && p->handler == handler)
+ break;
+ q = p;
+ p = p->next;
+ }
+ if (p == NULL)
+ return -ENOENT;
+ if (q != NULL)
+ q->next = p->next;
+ else
+ ext_int_hash[index] = p->next;
+ if (code != 0x1004 && code != 0x2401)
+ kfree(p);
+ return 0;
+}
+
+
diff --git a/arch/s390x/kernel/s390_ksyms.c b/arch/s390x/kernel/s390_ksyms.c
new file mode 100644
index 000000000..5ab122488
--- /dev/null
+++ b/arch/s390x/kernel/s390_ksyms.c
@@ -0,0 +1,157 @@
+/*
+ * arch/s390/kernel/s390_ksyms.c
+ *
+ * S390 version
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/highuid.h>
+#include <asm/ccwcache.h>
+#include <asm/debug.h>
+#include <asm/irq.h>
+#include <asm/s390_ext.h>
+#include <asm/s390dyn.h>
+#include <asm/ebcdic.h>
+#include <asm/checksum.h>
+#include <asm/delay.h>
+#include <asm/pgalloc.h>
+#include <asm/idals.h>
+#if CONFIG_CHANDEV
+#include <asm/chandev.h>
+#endif
+#if CONFIG_IP_MULTICAST
+#include <net/arp.h>
+#endif
+
+/*
+ * I/O subsystem
+ */
+EXPORT_SYMBOL(halt_IO);
+EXPORT_SYMBOL(clear_IO);
+EXPORT_SYMBOL(do_IO);
+EXPORT_SYMBOL(resume_IO);
+EXPORT_SYMBOL(ioinfo);
+EXPORT_SYMBOL(get_dev_info_by_irq);
+EXPORT_SYMBOL(get_dev_info_by_devno);
+EXPORT_SYMBOL(get_irq_by_devno);
+EXPORT_SYMBOL(get_devno_by_irq);
+EXPORT_SYMBOL(get_irq_first);
+EXPORT_SYMBOL(get_irq_next);
+EXPORT_SYMBOL(read_conf_data);
+EXPORT_SYMBOL(read_dev_chars);
+EXPORT_SYMBOL(s390_request_irq_special);
+EXPORT_SYMBOL(s390_device_register);
+EXPORT_SYMBOL(s390_device_unregister);
+
+EXPORT_SYMBOL(ccw_alloc_request);
+EXPORT_SYMBOL(ccw_free_request);
+
+EXPORT_SYMBOL(register_external_interrupt);
+EXPORT_SYMBOL(unregister_external_interrupt);
+
+/*
+ * debug feature
+ */
+EXPORT_SYMBOL(debug_register);
+EXPORT_SYMBOL(debug_unregister);
+EXPORT_SYMBOL(debug_set_level);
+EXPORT_SYMBOL(debug_register_view);
+EXPORT_SYMBOL(debug_unregister_view);
+EXPORT_SYMBOL(debug_event);
+EXPORT_SYMBOL(debug_int_event);
+EXPORT_SYMBOL(debug_text_event);
+EXPORT_SYMBOL(debug_exception);
+EXPORT_SYMBOL(debug_int_exception);
+EXPORT_SYMBOL(debug_text_exception);
+EXPORT_SYMBOL(debug_hex_ascii_view);
+EXPORT_SYMBOL(debug_raw_view);
+EXPORT_SYMBOL(debug_dflt_header_fn);
+
+/*
+ * memory management
+ */
+EXPORT_SYMBOL(_oi_bitmap);
+EXPORT_SYMBOL(_ni_bitmap);
+EXPORT_SYMBOL(_zb_findmap);
+EXPORT_SYMBOL(__copy_from_user_fixup);
+EXPORT_SYMBOL(__copy_to_user_fixup);
+
+/*
+ * semaphore ops
+ */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_trylock);
+
+/*
+ * string functions
+ */
+EXPORT_SYMBOL_NOVERS(memcmp);
+EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(memmove);
+EXPORT_SYMBOL_NOVERS(strlen);
+EXPORT_SYMBOL_NOVERS(strchr);
+EXPORT_SYMBOL_NOVERS(strcmp);
+EXPORT_SYMBOL_NOVERS(strncat);
+EXPORT_SYMBOL_NOVERS(strncmp);
+EXPORT_SYMBOL_NOVERS(strncpy);
+EXPORT_SYMBOL_NOVERS(strnlen);
+EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strpbrk);
+
+EXPORT_SYMBOL_NOVERS(_ascebc_500);
+EXPORT_SYMBOL_NOVERS(_ebcasc_500);
+EXPORT_SYMBOL_NOVERS(_ascebc);
+EXPORT_SYMBOL_NOVERS(_ebcasc);
+EXPORT_SYMBOL_NOVERS(_ebc_tolower);
+EXPORT_SYMBOL_NOVERS(_ebc_toupper);
+
+/*
+ * binfmt_elf loader
+ */
+EXPORT_SYMBOL(get_pte_slow);
+EXPORT_SYMBOL(get_pmd_slow);
+extern int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs);
+EXPORT_SYMBOL(dump_fpu);
+#ifdef CONFIG_S390_SUPPORT
+extern int setup_arg_pages32(struct linux_binprm *bprm);
+EXPORT_SYMBOL(setup_arg_pages32);
+#endif
+EXPORT_SYMBOL(overflowuid);
+EXPORT_SYMBOL(overflowgid);
+
+/*
+ * misc.
+ */
+EXPORT_SYMBOL(module_list);
+EXPORT_SYMBOL(__udelay);
+#ifdef CONFIG_SMP
+#include <asm/smplock.h>
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(lowcore_ptr);
+EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(smp_ctl_set_bit);
+EXPORT_SYMBOL(smp_ctl_clear_bit);
+#endif
+EXPORT_SYMBOL(kernel_thread);
+#if CONFIG_CHANDEV
+EXPORT_SYMBOL(chandev_register_and_probe);
+EXPORT_SYMBOL(chandev_request_irq);
+EXPORT_SYMBOL(chandev_unregister);
+EXPORT_SYMBOL(chandev_initdevice);
+EXPORT_SYMBOL(chandev_initnetdevice);
+#endif
+#if CONFIG_IP_MULTICAST
+/* Required for lcs gigibit ethernet multicast support */
+EXPORT_SYMBOL(arp_mc_map);
+#endif
+EXPORT_SYMBOL(s390_daemonize);
+EXPORT_SYMBOL (set_normalized_cda);
+
diff --git a/arch/s390x/kernel/s390fpu.c b/arch/s390x/kernel/s390fpu.c
new file mode 100644
index 000000000..7dfea3fba
--- /dev/null
+++ b/arch/s390x/kernel/s390fpu.c
@@ -0,0 +1,87 @@
+/*
+ * arch/s390/kernel/s390fpu.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ * s390fpu.h functions for saving & restoring the fpu state.
+ *
+ * I couldn't inline these as linux/sched.h included half the world
+ * & was required to at the task structure.
+ * & the functions were too complex to make macros from.
+ * ( & as usual I didn't feel like debugging inline code ).
+ */
+
+#include <linux/sched.h>
+
+void save_fp_regs(s390_fp_regs *fpregs)
+{
+/*
+ * I don't think we can use STE here as this would load
+ * fp registers 0 & 2 into memory locations 0 & 1 etc.
+ */
+ asm volatile ("STFPC 0(%0)\n\t"
+ "STD 0,8(%0)\n\t"
+ "STD 1,16(%0)\n\t"
+ "STD 2,24(%0)\n\t"
+ "STD 3,32(%0)\n\t"
+ "STD 4,40(%0)\n\t"
+ "STD 5,48(%0)\n\t"
+ "STD 6,56(%0)\n\t"
+ "STD 7,64(%0)\n\t"
+ "STD 8,72(%0)\n\t"
+ "STD 9,80(%0)\n\t"
+ "STD 10,88(%0)\n\t"
+ "STD 11,96(%0)\n\t"
+ "STD 12,104(%0)\n\t"
+ "STD 13,112(%0)\n\t"
+ "STD 14,120(%0)\n\t"
+ "STD 15,128(%0)\n\t"
+ :
+ : "a" (fpregs)
+ : "memory"
+ );
+}
+
+void restore_fp_regs(s390_fp_regs *fpregs)
+{
+ /* If we don't mask with the FPC_VALID_MASK here
+ * we've got a very quick shutdown -h now command
+ * via a kernel specification exception.
+ */
+ fpregs->fpc&=FPC_VALID_MASK;
+ asm volatile ("LFPC 0(%0)\n\t"
+ "LD 0,8(%0)\n\t"
+ "LD 1,16(%0)\n\t"
+ "LD 2,24(%0)\n\t"
+ "LD 3,32(%0)\n\t"
+ "LD 4,40(%0)\n\t"
+ "LD 5,48(%0)\n\t"
+ "LD 6,56(%0)\n\t"
+ "LD 7,64(%0)\n\t"
+ "LD 8,72(%0)\n\t"
+ "LD 9,80(%0)\n\t"
+ "LD 10,88(%0)\n\t"
+ "LD 11,96(%0)\n\t"
+ "LD 12,104(%0)\n\t"
+ "LD 13,112(%0)\n\t"
+ "LD 14,120(%0)\n\t"
+ "LD 15,128(%0)\n\t"
+ :
+ : "a" (fpregs)
+ : "memory"
+ );
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/arch/s390x/kernel/semaphore.c b/arch/s390x/kernel/semaphore.c
new file mode 100644
index 000000000..8af6d8277
--- /dev/null
+++ b/arch/s390x/kernel/semaphore.c
@@ -0,0 +1,302 @@
+/*
+ * linux/arch/S390/kernel/semaphore.c
+ *
+ * S390 version
+ * Copyright (C) 1998-2000 IBM Corporation
+ * Author(s): Martin Schwidefsky
+ *
+ * Derived from "linux/arch/i386/kernel/semaphore.c
+ * Copyright (C) 1999, Linus Torvalds
+ *
+ */
+#include <linux/sched.h>
+
+#include <asm/semaphore.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to acquire the semaphore, while the "sleeping"
+ * variable is a count of such acquires.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * "sleeping" and the contention routine ordering is
+ * protected by the semaphore spinlock.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+
+/*
+ * Logic:
+ * - only on a boundary condition do we need to care. When we go
+ * from a negative count to a non-negative, we wake people up.
+ * - when we go from a non-negative count to a negative do we
+ * (a) synchronize with the "sleeper" count and (b) make sure
+ * that we're on the wakeup list before we synchronize so that
+ * we cannot lose wakeup events.
+ */
+
+void __up(struct semaphore *sem)
+{
+ wake_up(&sem->wait);
+}
+
+static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
+
+void __down(struct semaphore * sem)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+ tsk->state = TASK_UNINTERRUPTIBLE;
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ spin_lock_irq(&semaphore_lock);
+ sem->sleepers++;
+ for (;;) {
+ int sleepers = sem->sleepers;
+
+ /*
+ * Add "everybody else" into it. They aren't
+ * playing, because we own the spinlock.
+ */
+ if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+ sem->sleepers = 0;
+ break;
+ }
+ sem->sleepers = 1; /* us - see -1 above */
+ spin_unlock_irq(&semaphore_lock);
+
+ schedule();
+ tsk->state = TASK_UNINTERRUPTIBLE;
+ spin_lock_irq(&semaphore_lock);
+ }
+ spin_unlock_irq(&semaphore_lock);
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+ wake_up(&sem->wait);
+}
+
+int __down_interruptible(struct semaphore * sem)
+{
+ int retval = 0;
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+ tsk->state = TASK_INTERRUPTIBLE;
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ spin_lock_irq(&semaphore_lock);
+ sem->sleepers ++;
+ for (;;) {
+ int sleepers = sem->sleepers;
+
+ /*
+ * With signals pending, this turns into
+ * the trylock failure case - we won't be
+ * sleeping, and we* can't get the lock as
+ * it has contention. Just correct the count
+ * and exit.
+ */
+ if (signal_pending(current)) {
+ retval = -EINTR;
+ sem->sleepers = 0;
+ atomic_add(sleepers, &sem->count);
+ break;
+ }
+
+ /*
+ * Add "everybody else" into it. They aren't
+ * playing, because we own the spinlock. The
+ * "-1" is because we're still hoping to get
+ * the lock.
+ */
+ if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+ sem->sleepers = 0;
+ break;
+ }
+ sem->sleepers = 1; /* us - see -1 above */
+ spin_unlock_irq(&semaphore_lock);
+
+ schedule();
+ tsk->state = TASK_INTERRUPTIBLE;
+ spin_lock_irq(&semaphore_lock);
+ }
+ spin_unlock_irq(&semaphore_lock);
+ tsk->state = TASK_RUNNING;
+ remove_wait_queue(&sem->wait, &wait);
+ wake_up(&sem->wait);
+ return retval;
+}
+
+/*
+ * Trylock failed - make sure we correct for
+ * having decremented the count.
+ */
+int __down_trylock(struct semaphore * sem)
+{
+ unsigned long flags;
+ int sleepers;
+
+ spin_lock_irqsave(&semaphore_lock, flags);
+ sleepers = sem->sleepers + 1;
+ sem->sleepers = 0;
+
+ /*
+ * Add "everybody else" and us into it. They aren't
+ * playing, because we own the spinlock.
+ */
+ if (!atomic_add_negative(sleepers, &sem->count))
+ wake_up(&sem->wait);
+
+ spin_unlock_irqrestore(&semaphore_lock, flags);
+ return 1;
+}
+
+void down_read_failed_biased(struct rw_semaphore *sem)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ add_wait_queue(&sem->wait, &wait); /* put ourselves at the head of the list */
+
+ for (;;) {
+ if (sem->read_bias_granted && xchg(&sem->read_bias_granted, 0))
+ break;
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (!sem->read_bias_granted)
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+}
+
+void down_write_failed_biased(struct rw_semaphore *sem)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ add_wait_queue_exclusive(&sem->write_bias_wait, &wait); /* put ourselves at the end of the list */
+
+ for (;;) {
+ if (sem->write_bias_granted && xchg(&sem->write_bias_granted, 0))
+ break;
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (!sem->write_bias_granted)
+ schedule();
+ }
+
+ remove_wait_queue(&sem->write_bias_wait, &wait);
+ tsk->state = TASK_RUNNING;
+
+ /* if the lock is currently unbiased, awaken the sleepers
+ * FIXME: this wakes up the readers early in a bit of a
+ * stampede -> bad!
+ */
+ if (atomic_read(&sem->count) >= 0)
+ wake_up(&sem->wait);
+}
+
+/* Wait for the lock to become unbiased. Readers
+ * are non-exclusive. =)
+ */
+void down_read_failed(struct rw_semaphore *sem)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ up_read(sem); /* this takes care of granting the lock */
+
+ add_wait_queue(&sem->wait, &wait);
+
+ while (atomic_read(&sem->count) < 0) {
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (atomic_read(&sem->count) >= 0)
+ break;
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+}
+
+/* Wait for the lock to become unbiased. Since we're
+ * a writer, we'll make ourselves exclusive.
+ */
+void down_write_failed(struct rw_semaphore *sem)
+{
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ up_write(sem); /* this takes care of granting the lock */
+
+ add_wait_queue_exclusive(&sem->wait, &wait);
+
+ while (atomic_read(&sem->count) < 0) {
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
+ if (atomic_read(&sem->count) >= 0)
+ break; /* we must attempt to acquire or bias the lock */
+ schedule();
+ }
+
+ remove_wait_queue(&sem->wait, &wait);
+ tsk->state = TASK_RUNNING;
+}
+
+/* Called when someone has done an up that transitioned from
+ * negative to non-negative, meaning that the lock has been
+ * granted to whomever owned the bias.
+ */
+void rwsem_wake_readers(struct rw_semaphore *sem)
+{
+ if (xchg(&sem->read_bias_granted, 1))
+ BUG();
+ wake_up(&sem->wait);
+}
+
+void rwsem_wake_writers(struct rw_semaphore *sem)
+{
+ if (xchg(&sem->write_bias_granted, 1))
+ BUG();
+ wake_up(&sem->write_bias_wait);
+}
+
+void __down_read_failed(int count, struct rw_semaphore *sem)
+{
+ do {
+ if (count == -1) {
+ down_read_failed_biased(sem);
+ break;
+ }
+ down_read_failed(sem);
+ count = atomic_dec_return(&sem->count);
+ } while (count != 0);
+}
+
+void __down_write_failed(int count, struct rw_semaphore *sem)
+{
+ do {
+ if (count < 0 && count > -RW_LOCK_BIAS) {
+ down_write_failed_biased(sem);
+ break;
+ }
+ down_write_failed(sem);
+ count = atomic_add_return(-RW_LOCK_BIAS, &sem->count);
+ } while (count != 0);
+}
+
+void __rwsem_wake(int count, struct rw_semaphore *sem)
+{
+ if (count == 0)
+ rwsem_wake_readers(sem);
+ else
+ rwsem_wake_writers(sem);
+}
+
diff --git a/arch/s390x/kernel/setup.c b/arch/s390x/kernel/setup.c
new file mode 100644
index 000000000..528793cfc
--- /dev/null
+++ b/arch/s390x/kernel/setup.c
@@ -0,0 +1,380 @@
+/*
+ * arch/s390/kernel/setup.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * Derived from "arch/i386/kernel/setup.c"
+ * Copyright (C) 1995, Linus Torvalds
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#ifdef CONFIG_BLK_DEV_RAM
+#include <linux/blk.h>
+#endif
+#include <linux/bootmem.h>
+#include <linux/console.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/smp.h>
+#include <asm/mmu_context.h>
+
+/*
+ * Machine setup..
+ */
+__u16 boot_cpu_addr;
+int cpus_initialized = 0;
+unsigned long cpu_initialized = 0;
+volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
+
+/*
+ * Setup options
+ */
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt*/
+extern int rd_image_start; /* starting block # of image */
+#endif
+
+extern int root_mountflags;
+extern int _text,_etext, _edata, _end;
+
+
+/*
+ * This is set up by the setup-routine at boot-time
+ * for S390 need to find out, what we have to setup
+ * using address 0x10400 ...
+ */
+
+#include <asm/setup.h>
+
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+ char saved_command_line[COMMAND_LINE_SIZE];
+
+static struct resource code_resource = { "Kernel code", 0x100000, 0 };
+static struct resource data_resource = { "Kernel data", 0, 0 };
+
+/*
+ * cpu_init() initializes state that is per-CPU.
+ */
+void __init cpu_init (void)
+{
+ int nr = smp_processor_id();
+ int addr = hard_smp_processor_id();
+
+ if (test_and_set_bit(nr,&cpu_initialized)) {
+ printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr);
+ for (;;) __sti();
+ }
+ cpus_initialized++;
+
+ /*
+ * Store processor id in lowcore (used e.g. in timer_interrupt)
+ */
+ asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
+ S390_lowcore.cpu_data.cpu_addr = addr;
+ S390_lowcore.cpu_data.cpu_nr = nr;
+
+ /*
+ * Force FPU initialization:
+ */
+ current->flags &= ~PF_USEDFPU;
+ current->used_math = 0;
+
+ /* Setup active_mm for idle_task */
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
+ if (current->mm)
+ BUG();
+ enter_lazy_tlb(&init_mm, current, nr);
+}
+
+/*
+ * VM halt and poweroff setup routines
+ */
+char vmhalt_cmd[128] = "";
+char vmpoff_cmd[128] = "";
+
+static inline void strncpy_skip_quote(char *dst, char *src, int n)
+{
+ int sx, dx;
+
+ dx = 0;
+ for (sx = 0; src[sx] != 0; sx++) {
+ if (src[sx] == '"') continue;
+ dst[dx++] = src[sx];
+ if (dx >= n) break;
+ }
+}
+
+static int __init vmhalt_setup(char *str)
+{
+ strncpy_skip_quote(vmhalt_cmd, str, 127);
+ vmhalt_cmd[127] = 0;
+ return 1;
+}
+
+__setup("vmhalt=", vmhalt_setup);
+
+static int __init vmpoff_setup(char *str)
+{
+ strncpy_skip_quote(vmpoff_cmd, str, 127);
+ vmpoff_cmd[127] = 0;
+ return 1;
+}
+
+__setup("vmpoff=", vmpoff_setup);
+
+/*
+ * Reboot, halt and power_off routines for non SMP.
+ */
+#ifndef CONFIG_SMP
+void machine_restart(char * __unused)
+{
+ reipl(S390_lowcore.ipl_device);
+}
+
+void machine_halt(void)
+{
+ if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+ cpcmd(vmhalt_cmd, NULL, 0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+}
+
+void machine_power_off(void)
+{
+ if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+ cpcmd(vmpoff_cmd, NULL, 0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+}
+#endif
+
+/*
+ * Setup function called from init/main.c just after the banner
+ * was printed.
+ */
+void __init setup_arch(char **cmdline_p)
+{
+ unsigned long bootmap_size;
+ unsigned long memory_start, memory_end;
+ char c = ' ', cn, *to = command_line, *from = COMMAND_LINE;
+ struct resource *res;
+ unsigned long start_pfn, end_pfn;
+ static unsigned int smptrap=0;
+ unsigned long delay = 0;
+ int len = 0;
+
+ if (smptrap)
+ return;
+ smptrap=1;
+
+ printk("Command line is: %s\n", COMMAND_LINE);
+
+ /*
+ * Setup lowcore information for boot cpu
+ */
+ cpu_init();
+ boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+ __cpu_logical_map[0] = boot_cpu_addr;
+
+ /*
+ * print what head.S has found out about the machine
+ */
+ printk((MACHINE_IS_VM) ?
+ "We are running under VM\n" :
+ "We are running native\n");
+
+ ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
+#ifdef CONFIG_BLK_DEV_RAM
+ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+ /* nasty stuff with PARMAREAs. we use head.S or parameterline
+ if (!MOUNT_ROOT_RDONLY)
+ root_mountflags &= ~MS_RDONLY;
+ */
+ memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/
+ memory_end = MEMORY_SIZE; /* detected in head.s */
+ init_mm.start_code = PAGE_OFFSET;
+ init_mm.end_code = (unsigned long) &_etext;
+ init_mm.end_data = (unsigned long) &_edata;
+ init_mm.brk = (unsigned long) &_end;
+
+ code_resource.start = (unsigned long) &_text;
+ code_resource.end = (unsigned long) &_etext - 1;
+ data_resource.start = (unsigned long) &_etext;
+ data_resource.end = (unsigned long) &_edata - 1;
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+ saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+
+ for (;;) {
+ /*
+ * "mem=XXX[kKmM]" sets memsize
+ */
+ if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
+ if (to != command_line) to--;
+ memory_end = simple_strtoul(from+4, &from, 0);
+ if ( *from == 'K' || *from == 'k' ) {
+ memory_end = memory_end << 10;
+ from++;
+ } else if ( *from == 'M' || *from == 'm' ) {
+ memory_end = memory_end << 20;
+ from++;
+ }
+ }
+ /*
+ * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
+ */
+ if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
+ if (to != command_line) to--;
+ delay = simple_strtoul(from+9, &from, 0);
+ if (*from == 's' || *from == 'S') {
+ delay = delay*1000000;
+ from++;
+ } else if (*from == 'm' || *from == 'M') {
+ delay = delay*60*1000000;
+ from++;
+ }
+ /* now wait for the requestion amount of time */
+ udelay(delay);
+ }
+ cn = *(from++);
+ if (!cn)
+ break;
+ if (cn == '\n')
+ cn = ' '; /* replace newlines with space */
+ if (cn == ' ' && c == ' ')
+ continue; /* remove additional spaces */
+ c = cn;
+ if (COMMAND_LINE_SIZE <= ++len)
+ break;
+ *(to++) = c;
+ }
+ if (c == ' ' && to > command_line) to--;
+ *to = '\0';
+ *cmdline_p = command_line;
+
+ /*
+ * partially used pages are not usable - thus
+ * we are rounding upwards:
+ */
+ start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ end_pfn = memory_end >> PAGE_SHIFT;
+
+ /*
+ * Initialize the boot-time allocator
+ */
+ bootmap_size = init_bootmem(start_pfn, end_pfn);
+
+ /*
+ * Register RAM pages with the bootmem allocator.
+ */
+ free_bootmem(start_pfn << PAGE_SHIFT,
+ (end_pfn - start_pfn) << PAGE_SHIFT);
+
+ /*
+ * Reserve the bootmem bitmap itself as well. We do this in two
+ * steps (first step was init_bootmem()) because this catches
+ * the (very unlikely) case of us accidentally initializing the
+ * bootmem allocator with an invalid RAM area.
+ */
+ reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size);
+
+
+
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (INITRD_START) {
+ if (INITRD_START + INITRD_SIZE <= memory_end) {
+ reserve_bootmem(INITRD_START, INITRD_SIZE);
+ initrd_start = INITRD_START;
+ initrd_end = initrd_start + INITRD_SIZE;
+ } else {
+ printk("initrd extends beyond end of memory "
+ "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+ initrd_start + INITRD_SIZE, memory_end);
+ initrd_start = initrd_end = 0;
+ }
+ }
+#endif
+
+ paging_init();
+
+ res = alloc_bootmem_low(sizeof(struct resource));
+ res->start = 0;
+ res->end = memory_end;
+ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ request_resource(&iomem_resource, res);
+ request_resource(res, &code_resource);
+ request_resource(res, &data_resource);
+}
+
+void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
+{
+ printk("cpu %d "
+#ifdef CONFIG_SMP
+ "phys_idx=%d "
+#endif
+ "vers=%02X ident=%06X machine=%04X unused=%04X\n",
+ cpuinfo->cpu_nr,
+#ifdef CONFIG_SMP
+ cpuinfo->cpu_addr,
+#endif
+ cpuinfo->cpu_id.version,
+ cpuinfo->cpu_id.ident,
+ cpuinfo->cpu_id.machine,
+ cpuinfo->cpu_id.unused);
+}
+
+/*
+ * Get CPU information for use by the procfs.
+ */
+
+int get_cpuinfo(char * buffer)
+{
+ struct cpuinfo_S390 *cpuinfo;
+ char *p = buffer;
+ int i;
+
+ p += sprintf(p,"vendor_id : IBM/S390\n"
+ "# processors : %i\n"
+ "bogomips per cpu: %lu.%02lu\n",
+ smp_num_cpus, loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ))%100);
+ for (i = 0; i < smp_num_cpus; i++) {
+ cpuinfo = &safe_get_cpu_lowcore(i).cpu_data;
+ p += sprintf(p,"processor %i: "
+ "version = %02X, "
+ "identification = %06X, "
+ "machine = %04X\n",
+ i, cpuinfo->cpu_id.version,
+ cpuinfo->cpu_id.ident,
+ cpuinfo->cpu_id.machine);
+ }
+ return p - buffer;
+}
+
diff --git a/arch/s390x/kernel/signal.c b/arch/s390x/kernel/signal.c
new file mode 100644
index 000000000..4728336c4
--- /dev/null
+++ b/arch/s390x/kernel/signal.c
@@ -0,0 +1,595 @@
+/*
+ * arch/s390/kernel/signal.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ * Based on Intel version
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/* pretcode & sig are used to store the return addr on Intel
+ & the signal no as the first parameter we do this differently
+ using gpr14 & gpr2. */
+
+#define SIGFRAME_COMMON \
+__u8 callee_used_stack[__SIGNAL_FRAMESIZE]; \
+struct sigcontext sc; \
+_sigregs sregs; \
+__u8 retcode[S390_SYSCALL_SIZE];
+
+typedef struct
+{
+ SIGFRAME_COMMON
+} sigframe;
+
+typedef struct
+{
+ SIGFRAME_COMMON
+ struct siginfo info;
+ struct ucontext uc;
+} rt_sigframe;
+
+asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t mask)
+{
+ sigset_t saveset;
+
+ mask &= _BLOCKABLE;
+ spin_lock_irq(&current->sigmask_lock);
+ saveset = current->blocked;
+ siginitset(&current->blocked, mask);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ regs->gprs[2] = -EINTR;
+
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (do_signal(regs, &saveset))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize)
+{
+ sigset_t saveset, newset;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user(&newset, unewset, sizeof(newset)))
+ return -EFAULT;
+ sigdelsetmask(&newset, ~_BLOCKABLE);
+
+ spin_lock_irq(&current->sigmask_lock);
+ saveset = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ regs->gprs[2] = -EINTR;
+
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (do_signal(regs, &saveset))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ return -EFAULT;
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)
+{
+ return do_sigaltstack(uss, uoss, regs->gprs[15]);
+}
+
+
+
+
+static int save_sigregs(struct pt_regs *regs,_sigregs *sregs)
+{
+ int err;
+ s390_fp_regs fpregs;
+
+ err = __copy_to_user(&sregs->regs,regs,sizeof(s390_regs_common));
+ if(!err)
+ {
+ save_fp_regs(&fpregs);
+ err=__copy_to_user(&sregs->fpregs,&fpregs,sizeof(fpregs));
+ }
+ return(err);
+
+}
+
+static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs)
+{
+ int err;
+ s390_fp_regs fpregs;
+ psw_t saved_psw=regs->psw;
+ err=__copy_from_user(regs,&sregs->regs,sizeof(s390_regs_common));
+ if(!err)
+ {
+ regs->orig_gpr2 = -1; /* disable syscall checks */
+ regs->psw.mask=(saved_psw.mask&~PSW_MASK_DEBUGCHANGE)|
+ (regs->psw.mask&PSW_MASK_DEBUGCHANGE);
+ regs->psw.addr=(saved_psw.addr&~PSW_ADDR_DEBUGCHANGE)|
+ (regs->psw.addr&PSW_ADDR_DEBUGCHANGE);
+ err=__copy_from_user(&fpregs,&sregs->fpregs,sizeof(fpregs));
+ if(!err)
+ restore_fp_regs(&fpregs);
+ }
+ return(err);
+}
+
+static int
+restore_sigcontext(struct sigcontext *sc, pt_regs *regs,
+ _sigregs *sregs,sigset_t *set)
+{
+ unsigned int err;
+
+ err=restore_sigregs(regs,sregs);
+ if(!err)
+ err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE);
+ return(err);
+}
+
+int sigreturn_common(struct pt_regs *regs,int framesize)
+{
+ sigframe *frame = (sigframe *)regs->gprs[15];
+ sigset_t set;
+
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ return -1;
+ if (restore_sigcontext(&frame->sc,regs,&frame->sregs,&set))
+ return -1;
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ return 0;
+}
+
+asmlinkage long sys_sigreturn(struct pt_regs *regs)
+{
+
+ if (sigreturn_common(regs,sizeof(sigframe)))
+ goto badframe;
+ return regs->gprs[2];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+{
+ rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
+
+ if (sigreturn_common(regs,sizeof(rt_sigframe)))
+ goto badframe;
+ /* It is more difficult to avoid calling this function than to
+ call it and ignore errors. */
+ do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
+ return regs->gprs[2];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+ unsigned long sp;
+
+ /* Default to using normal stack */
+ sp = regs->gprs[15];
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (! on_sig_stack(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+ }
+
+ /* This is the legacy signal stack switching. */
+ else if (!user_mode(regs) &&
+ !(ka->sa.sa_flags & SA_RESTORER) &&
+ ka->sa.sa_restorer) {
+ sp = (unsigned long) ka->sa.sa_restorer;
+ }
+
+ return (void *)((sp - frame_size) & -8ul);
+}
+
+static void *setup_frame_common(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs * regs,
+ int frame_size,u16 retcode)
+{
+ sigframe *frame;
+ int err;
+
+ frame = get_sigframe(ka, regs,frame_size);
+ if (!access_ok(VERIFY_WRITE, frame,frame_size))
+ return 0;
+ err = save_sigregs(regs,&frame->sregs);
+ if(!err)
+ err=__put_user(&frame->sregs,&frame->sc.sregs);
+ if(!err)
+
+ err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE);
+ if(!err)
+ {
+ regs->gprs[2]=(current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig);
+ /* Set up registers for signal handler */
+ regs->gprs[15] = (addr_t)frame;
+ regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+ }
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+ } else {
+ regs->gprs[14] = FIX_PSW(frame->retcode);
+ err |= __put_user(retcode, (u16 *)(frame->retcode));
+ }
+ return(err ? 0:frame);
+}
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs * regs)
+{
+ sigframe *frame;
+
+ if((frame=setup_frame_common(sig,ka,set,regs,sizeof(sigframe),
+ (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0)
+ goto give_sigsegv;
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->eip, frame->pretcode);
+#endif
+ /* Martin wants this for pthreads */
+ regs->gprs[3] = (addr_t)&frame->sc;
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs * regs)
+{
+ rt_sigframe *frame;
+ addr_t orig_sp=regs->gprs[15];
+ int err;
+
+ if((frame=setup_frame_common(sig,ka,set,regs,sizeof(rt_sigframe),
+ (S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0)
+ goto give_sigsegv;
+
+ err = copy_siginfo_to_user(&frame->info, info);
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(orig_sp),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __put_user(&frame->sc,&frame->uc.sc);
+ regs->gprs[3] = (addr_t)&frame->info;
+ regs->gprs[4] = (addr_t)&frame->uc;
+
+ if (err)
+ goto give_sigsegv;
+
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->eip, frame->pretcode);
+#endif
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+static void
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+{
+ /* Are we from a system call? */
+ if (regs->orig_gpr2 >= 0) {
+ /* If so, check system call restarting.. */
+ switch (regs->gprs[2]) {
+ case -ERESTARTNOHAND:
+ regs->gprs[2] = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ regs->gprs[2] = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ regs->gprs[2] = regs->orig_gpr2;
+ regs->psw.addr -= 2;
+ }
+ }
+
+ /* Set up the stack frame */
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(sig, ka, info, oldset, regs);
+ else
+ setup_frame(sig, ka, oldset, regs);
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+
+ if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ spin_lock_irq(&current->sigmask_lock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ }
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+ siginfo_t info;
+ struct k_sigaction *ka;
+
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (!user_mode(regs))
+ return 1;
+
+ if (!oldset)
+ oldset = &current->blocked;
+#ifdef CONFIG_S390_SUPPORT
+ if (current->thread.flags & S390_FLAG_31BIT) {
+ extern asmlinkage int do_signal32(struct pt_regs *regs, sigset_t *oldset);
+ return do_signal32(regs, oldset);
+ }
+#endif
+
+ for (;;) {
+ unsigned long signr;
+
+ spin_lock_irq(&current->sigmask_lock);
+ signr = dequeue_signal(&current->blocked, &info);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ if (!signr)
+ break;
+
+ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+ /* Let the debugger run. */
+ current->exit_code = signr;
+ set_current_state(TASK_STOPPED);
+ notify_parent(current, SIGCHLD);
+ schedule();
+
+ /* We're back. Did the debugger cancel the sig? */
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+
+ /* The debugger continued. Ignore SIGSTOP. */
+ if (signr == SIGSTOP)
+ continue;
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(&current->blocked, signr)) {
+ send_sig_info(signr, &info, current);
+ continue;
+ }
+ }
+
+ ka = &current->sig->action[signr-1];
+ if (ka->sa.sa_handler == SIG_IGN) {
+ if (signr != SIGCHLD)
+ continue;
+ /* Check for SIGCHLD: it's special. */
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ /* nothing */;
+ continue;
+ }
+
+ if (ka->sa.sa_handler == SIG_DFL) {
+ int exit_code = signr;
+
+ /* Init gets no signals it doesn't want. */
+ if (current->pid == 1)
+ continue;
+
+ switch (signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
+ continue;
+
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ /* FALLTHRU */
+
+ case SIGSTOP:
+ set_current_state(TASK_STOPPED);
+ current->exit_code = signr;
+ if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+ notify_parent(current, SIGCHLD);
+ schedule();
+ continue;
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV:
+ if (do_coredump(signr, regs))
+ exit_code |= 0x80;
+ /* FALLTHRU */
+
+ default:
+ lock_kernel();
+ sigaddset(&current->pending.signal, signr);
+ recalc_sigpending(current);
+ current->flags |= PF_SIGNALED;
+ do_exit(exit_code);
+ /* NOTREACHED */
+ }
+ }
+
+ /* Whee! Actually deliver the signal. */
+ handle_signal(signr, ka, &info, oldset, regs);
+ return 1;
+ }
+
+ /* Did we come from a system call? */
+ if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) {
+ /* Restart the system call - no handlers present */
+ if (regs->gprs[2] == -ERESTARTNOHAND ||
+ regs->gprs[2] == -ERESTARTSYS ||
+ regs->gprs[2] == -ERESTARTNOINTR) {
+ regs->gprs[2] = regs->orig_gpr2;
+ regs->psw.addr -= 2;
+ }
+ }
+ return 0;
+}
diff --git a/arch/s390x/kernel/signal32.c b/arch/s390x/kernel/signal32.c
new file mode 100644
index 000000000..81e5417ba
--- /dev/null
+++ b/arch/s390x/kernel/signal32.c
@@ -0,0 +1,725 @@
+/*
+ * arch/s390/kernel/signal32.c
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ * Gerhard Tonn (ton@de.ibm.com)
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include "linux32.h"
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/* pretcode & sig are used to store the return addr on Intel
+ & the signal no as the first parameter we do this differently
+ using gpr14 & gpr2. */
+
+#define SIGFRAME_COMMON32 \
+__u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; \
+struct sigcontext32 sc; \
+_sigregs32 sregs; \
+__u8 retcode[S390_SYSCALL_SIZE];
+
+typedef struct
+{
+ SIGFRAME_COMMON32
+} sigframe32;
+
+typedef struct
+{
+ SIGFRAME_COMMON32
+ struct siginfo32 info;
+ struct ucontext32 uc;
+} rt_sigframe32;
+
+asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+
+int do_signal32(struct pt_regs *regs, sigset_t *oldset);
+
+int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
+{
+ int err;
+
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t32)))
+ return -EFAULT;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member.
+ This routine must convert siginfo from 64bit to 32bit as well
+ at the same time. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ if (from->si_code < 0)
+ err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+ else {
+ switch (from->si_code >> 16) {
+ case __SI_KILL >> 16:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ break;
+ case __SI_FAULT >> 16:
+ err |= __put_user(from->si_addr, &to->si_addr);
+ break;
+ case __SI_POLL >> 16:
+ case __SI_TIMER >> 16:
+ err |= __put_user(from->si_band, &to->si_band);
+ err |= __put_user(from->si_fd, &to->si_fd);
+ break;
+ default:
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ }
+ return err;
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys32_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t mask)
+{
+ sigset_t saveset;
+
+ mask &= _BLOCKABLE;
+ spin_lock_irq(&current->sigmask_lock);
+ saveset = current->blocked;
+ siginitset(&current->blocked, mask);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ regs->gprs[2] = -EINTR;
+
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (do_signal32(regs, &saveset))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+sys32_rt_sigsuspend(struct pt_regs * regs,sigset_t32 *unewset, size_t sigsetsize)
+{
+ sigset_t saveset, newset;
+ sigset_t32 set32;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user(&set32, unewset, sizeof(set32)))
+ return -EFAULT;
+ switch (_NSIG_WORDS) {
+ case 4: newset.sig[3] = set32.sig[6] + (((long)set32.sig[7]) << 32);
+ case 3: newset.sig[2] = set32.sig[4] + (((long)set32.sig[5]) << 32);
+ case 2: newset.sig[1] = set32.sig[2] + (((long)set32.sig[3]) << 32);
+ case 1: newset.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32);
+ }
+ sigdelsetmask(&newset, ~_BLOCKABLE);
+
+ spin_lock_irq(&current->sigmask_lock);
+ saveset = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ regs->gprs[2] = -EINTR;
+
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (do_signal32(regs, &saveset))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+sys32_sigaction(int sig, const struct old_sigaction32 *act,
+ struct old_sigaction32 *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t32 mask;
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user((unsigned long)new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user((unsigned long)new_ka.sa.sa_restorer, &act->sa_restorer))
+ return -EFAULT;
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user((unsigned long)old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+int
+do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact);
+
+asmlinkage long
+sys32_rt_sigaction(int sig, const struct sigaction32 *act,
+ struct sigaction32 *oact, size_t sigsetsize)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+ sigset_t32 set32;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t32))
+ return -EINVAL;
+
+ if (act) {
+ ret = get_user((unsigned long)new_ka.sa.sa_handler, &act->sa_handler);
+ ret |= __copy_from_user(&set32, &act->sa_mask,
+ sizeof(sigset_t32));
+ switch (_NSIG_WORDS) {
+ case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
+ | (((long)set32.sig[7]) << 32);
+ case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
+ | (((long)set32.sig[5]) << 32);
+ case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
+ | (((long)set32.sig[3]) << 32);
+ case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
+ | (((long)set32.sig[1]) << 32);
+ }
+ ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+
+ if (ret)
+ return -EFAULT;
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ switch (_NSIG_WORDS) {
+ case 4:
+ set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
+ set32.sig[6] = old_ka.sa.sa_mask.sig[3];
+ case 3:
+ set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
+ set32.sig[4] = old_ka.sa.sa_mask.sig[2];
+ case 2:
+ set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
+ set32.sig[2] = old_ka.sa.sa_mask.sig[1];
+ case 1:
+ set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
+ set32.sig[0] = old_ka.sa.sa_mask.sig[0];
+ }
+ ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler);
+ ret |= __copy_to_user(&oact->sa_mask, &set32,
+ sizeof(sigset_t32));
+ ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ }
+
+ return ret;
+}
+
+asmlinkage int
+sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs)
+{
+ stack_t kss, koss;
+ int ret, err = 0;
+ mm_segment_t old_fs = get_fs();
+
+ if (uss) {
+ if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
+ return -EFAULT;
+ err |= __get_user(kss.ss_sp, &uss->ss_sp);
+ err |= __get_user(kss.ss_size, &uss->ss_size);
+ err |= __get_user(kss.ss_flags, &uss->ss_flags);
+ if (err)
+ return -EFAULT;
+ }
+
+ set_fs (KERNEL_DS);
+ ret = do_sigaltstack(uss ? &kss : NULL , uoss ? &koss : NULL, regs->gprs[15]);
+ set_fs (old_fs);
+
+ if (!ret && uoss) {
+ if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
+ return -EFAULT;
+ err |= __put_user(koss.ss_sp, &uoss->ss_sp);
+ err |= __put_user(koss.ss_size, &uoss->ss_size);
+ err |= __put_user(koss.ss_flags, &uoss->ss_flags);
+ if (err)
+ return -EFAULT;
+ }
+ return ret;
+}
+
+static int save_sigregs32(struct pt_regs *regs,_sigregs32 *sregs)
+{
+ int err = 0;
+ s390_fp_regs fpregs;
+ int i;
+
+ for(i=0; i<NUM_GPRS; i++)
+ err |= __put_user(regs->gprs[i], &sregs->regs.gprs[i]);
+ for(i=0; i<NUM_ACRS; i++)
+ err |= __put_user(regs->acrs[i], &sregs->regs.acrs[i]);
+ err |= __copy_to_user(&sregs->regs.psw.mask, &regs->psw.mask, 4);
+ err |= __copy_to_user(&sregs->regs.psw.addr, ((char*)&regs->psw.addr)+4, 4);
+ if(!err)
+ {
+ save_fp_regs(&fpregs);
+ __put_user(fpregs.fpc, &sregs->fpregs.fpc);
+ for(i=0; i<NUM_FPRS; i++)
+ err |= __put_user(fpregs.fprs[i].d, &sregs->fpregs.fprs[i].d);
+ }
+ return(err);
+
+}
+
+static int restore_sigregs32(struct pt_regs *regs,_sigregs32 *sregs)
+{
+ int err = 0;
+ s390_fp_regs fpregs;
+ psw_t saved_psw=regs->psw;
+ int i;
+
+ for(i=0; i<NUM_GPRS; i++)
+ err |= __get_user(regs->gprs[i], &sregs->regs.gprs[i]);
+ for(i=0; i<NUM_ACRS; i++)
+ err |= __get_user(regs->acrs[i], &sregs->regs.acrs[i]);
+ err |= __copy_from_user(&regs->psw.mask, &sregs->regs.psw.mask, 4);
+ err |= __copy_from_user(((char*)&regs->psw.addr)+4, &sregs->regs.psw.addr, 4);
+
+ if(!err)
+ {
+ regs->orig_gpr2 = -1; /* disable syscall checks */
+ regs->psw.mask=(saved_psw.mask&~PSW_MASK_DEBUGCHANGE)|
+ (regs->psw.mask&PSW_MASK_DEBUGCHANGE);
+ regs->psw.addr=(saved_psw.addr&~PSW_ADDR_DEBUGCHANGE)|
+ (regs->psw.addr&PSW_ADDR_DEBUGCHANGE);
+ __get_user(fpregs.fpc, &sregs->fpregs.fpc);
+ for(i=0; i<NUM_FPRS; i++)
+ err |= __get_user(fpregs.fprs[i].d, &sregs->fpregs.fprs[i].d);
+ if(!err)
+ restore_fp_regs(&fpregs);
+ }
+ return(err);
+}
+
+static int
+restore_sigcontext32(struct sigcontext32 *sc, pt_regs *regs,
+ _sigregs32 *sregs,sigset_t *set)
+{
+ unsigned int err;
+
+ err=restore_sigregs32(regs,sregs);
+ if(!err)
+ err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE32);
+ return(err);
+}
+
+int sigreturn_common32(struct pt_regs *regs)
+{
+ sigframe32 *frame = (sigframe32 *)regs->gprs[15];
+ sigset_t set;
+
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ return -1;
+ if (restore_sigcontext32(&frame->sc,regs,&frame->sregs,&set))
+ return -1;
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ return 0;
+}
+
+asmlinkage long sys32_sigreturn(struct pt_regs *regs)
+{
+
+ if (sigreturn_common32(regs))
+ goto badframe;
+ return regs->gprs[2];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
+{
+ rt_sigframe32 *frame = (rt_sigframe32 *)regs->gprs[15];
+ stack_t st;
+ int err;
+ mm_segment_t old_fs = get_fs();
+
+ if (sigreturn_common32(regs))
+ goto badframe;
+
+ err = __get_user(st.ss_sp, &frame->uc.uc_stack.ss_sp);
+ st.ss_sp = (void *) A((unsigned long)st.ss_sp);
+ err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);
+ err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
+ if (err)
+ goto badframe;
+ set_fs (KERNEL_DS);
+ /* It is more difficult to avoid calling this function than to
+ call it and ignore errors. */
+ do_sigaltstack(&st, NULL, regs->gprs[15]);
+ set_fs (old_fs);
+
+ return regs->gprs[2];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
+{
+ unsigned long sp;
+
+ /* Default to using normal stack */
+ sp = (unsigned long) A(regs->gprs[15]);
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (! on_sig_stack(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+ }
+
+ /* This is the legacy signal stack switching. */
+ else if (!user_mode(regs) &&
+ !(ka->sa.sa_flags & SA_RESTORER) &&
+ ka->sa.sa_restorer) {
+ sp = (unsigned long) ka->sa.sa_restorer;
+ }
+
+ return (void *)((sp - frame_size) & -8ul);
+}
+
+static void *setup_frame_common32(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs * regs,
+ int frame_size,u16 retcode)
+{
+ sigframe32 *frame;
+ int err;
+
+ frame = get_sigframe(ka, regs,frame_size);
+ if (!access_ok(VERIFY_WRITE, frame,frame_size))
+ return 0;
+ err = save_sigregs32(regs,&frame->sregs);
+ if(!err)
+ err=__put_user(&frame->sregs,&frame->sc.sregs);
+ if(!err)
+
+ err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE32);
+ if(!err)
+ {
+ regs->gprs[2]=(current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig);
+ /* Set up registers for signal handler */
+ regs->gprs[15] = (addr_t)frame;
+ regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+ }
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
+ } else {
+ regs->gprs[14] = FIX_PSW(frame->retcode);
+ err |= __put_user(retcode, (u16 *)(frame->retcode));
+ }
+ return(err ? 0:frame);
+}
+
+static void setup_frame32(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs * regs)
+{
+ sigframe32 *frame;
+
+ if((frame=setup_frame_common32(sig,ka,set,regs,sizeof(sigframe32),
+ (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0)
+ goto give_sigsegv;
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->eip, frame->pretcode);
+#endif
+ /* Martin wants this for pthreads */
+ regs->gprs[3] = (addr_t)&frame->sc;
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs * regs)
+{
+ rt_sigframe32 *frame;
+ addr_t orig_sp=regs->gprs[15];
+ int err;
+
+ if((frame=setup_frame_common32(sig,ka,set,regs,sizeof(rt_sigframe32),
+ (S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0)
+ goto give_sigsegv;
+
+ err = copy_siginfo_to_user32(&frame->info, info);
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(orig_sp),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ regs->gprs[3] = (addr_t)&frame->info;
+ regs->gprs[4] = (addr_t)&frame->uc;
+
+ if (err)
+ goto give_sigsegv;
+
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->eip, frame->pretcode);
+#endif
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+static void
+handle_signal32(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
+{
+ /* Are we from a system call? */
+ if (regs->orig_gpr2 >= 0) {
+ /* If so, check system call restarting.. */
+ switch (regs->gprs[2]) {
+ case -ERESTARTNOHAND:
+ regs->gprs[2] = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ regs->gprs[2] = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ regs->gprs[2] = regs->orig_gpr2;
+ regs->psw.addr -= 2;
+ }
+ }
+
+ /* Set up the stack frame */
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame32(sig, ka, info, oldset, regs);
+ else
+ setup_frame32(sig, ka, oldset, regs);
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = SIG_DFL;
+
+ if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ spin_lock_irq(&current->sigmask_lock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ }
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+int do_signal32(struct pt_regs *regs, sigset_t *oldset)
+{
+ siginfo_t info;
+ struct k_sigaction *ka;
+
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (!user_mode(regs))
+ return 1;
+
+ if (!oldset)
+ oldset = &current->blocked;
+
+ for (;;) {
+ unsigned long signr;
+
+ spin_lock_irq(&current->sigmask_lock);
+ signr = dequeue_signal(&current->blocked, &info);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ if (!signr)
+ break;
+
+ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
+ /* Let the debugger run. */
+ current->exit_code = signr;
+ set_current_state(TASK_STOPPED);
+ notify_parent(current, SIGCHLD);
+ schedule();
+
+ /* We're back. Did the debugger cancel the sig? */
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+
+ /* The debugger continued. Ignore SIGSTOP. */
+ if (signr == SIGSTOP)
+ continue;
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(&current->blocked, signr)) {
+ send_sig_info(signr, &info, current);
+ continue;
+ }
+ }
+
+ ka = &current->sig->action[signr-1];
+ if (ka->sa.sa_handler == SIG_IGN) {
+ if (signr != SIGCHLD)
+ continue;
+ /* Check for SIGCHLD: it's special. */
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ /* nothing */;
+ continue;
+ }
+
+ if (ka->sa.sa_handler == SIG_DFL) {
+ int exit_code = signr;
+
+ /* Init gets no signals it doesn't want. */
+ if (current->pid == 1)
+ continue;
+
+ switch (signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
+ continue;
+
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ /* FALLTHRU */
+
+ case SIGSTOP:
+ set_current_state(TASK_STOPPED);
+ current->exit_code = signr;
+ if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
+ notify_parent(current, SIGCHLD);
+ schedule();
+ continue;
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV:
+ if (do_coredump(signr, regs))
+ exit_code |= 0x80;
+ /* FALLTHRU */
+
+ default:
+ lock_kernel();
+ sigaddset(&current->pending.signal, signr);
+ recalc_sigpending(current);
+ current->flags |= PF_SIGNALED;
+ do_exit(exit_code);
+ /* NOTREACHED */
+ }
+ }
+
+ /* Whee! Actually deliver the signal. */
+ handle_signal32(signr, ka, &info, oldset, regs);
+ return 1;
+ }
+
+ /* Did we come from a system call? */
+ if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) {
+ /* Restart the system call - no handlers present */
+ if (regs->gprs[2] == -ERESTARTNOHAND ||
+ regs->gprs[2] == -ERESTARTSYS ||
+ regs->gprs[2] == -ERESTARTNOINTR) {
+ regs->gprs[2] = regs->orig_gpr2;
+ regs->psw.addr -= 2;
+ }
+ }
+ return 0;
+}
diff --git a/arch/s390x/kernel/smp.c b/arch/s390x/kernel/smp.c
new file mode 100644
index 000000000..19d8e3dad
--- /dev/null
+++ b/arch/s390x/kernel/smp.c
@@ -0,0 +1,760 @@
+/*
+ * arch/s390/kernel/smp.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * based on other smp stuff by
+ * (c) 1995 Alan Cox, CymruNET Ltd <alan@cymru.net>
+ * (c) 1998 Ingo Molnar
+ *
+ * We work with logical cpu numbering everywhere we can. The only
+ * functions using the real cpu address (got from STAP) are the sigp
+ * functions. For all other functions we use the identity mapping.
+ * That means that cpu_number_map[i] == i for every cpu. cpu_number_map is
+ * used e.g. to find the idle task belonging to a logical cpu. Every array
+ * in the kernel is sorted by the logical cpu number and not by the physical
+ * one which is causing all the confusion with __cpu_logical_map and
+ * cpu_number_map in other architectures.
+ */
+
+#include <linux/init.h>
+
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/kernel_stat.h>
+#include <linux/smp_lock.h>
+
+#include <linux/delay.h>
+
+#include <asm/sigp.h>
+#include <asm/pgalloc.h>
+#include <asm/irq.h>
+#include <asm/s390_ext.h>
+
+#include "cpcmd.h"
+
+/* prototypes */
+extern int cpu_idle(void * unused);
+
+extern __u16 boot_cpu_addr;
+extern volatile int __cpu_logical_map[];
+
+/*
+ * An array with a pointer the lowcore of every CPU.
+ */
+static int max_cpus = NR_CPUS; /* Setup configured maximum number of CPUs to activate */
+int smp_num_cpus;
+struct _lowcore *lowcore_ptr[NR_CPUS];
+unsigned int prof_multiplier[NR_CPUS];
+unsigned int prof_old_multiplier[NR_CPUS];
+unsigned int prof_counter[NR_CPUS];
+cycles_t cacheflush_time=0;
+int smp_threads_ready=0; /* Set when the idlers are all forked. */
+static atomic_t smp_commenced = ATOMIC_INIT(0);
+
+spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Setup routine for controlling SMP activation
+ *
+ * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+ * activation entirely (the MPS table probe still happens, though).
+ *
+ * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
+ * greater than 0, limits the maximum number of CPUs activated in
+ * SMP mode to <NUM>.
+ */
+
+static int __init nosmp(char *str)
+{
+ max_cpus = 0;
+ return 1;
+}
+
+__setup("nosmp", nosmp);
+
+static int __init maxcpus(char *str)
+{
+ get_option(&str, &max_cpus);
+ return 1;
+}
+
+__setup("maxcpus=", maxcpus);
+
+/*
+ * Reboot, halt and power_off routines for SMP.
+ */
+extern char vmhalt_cmd[];
+extern char vmpoff_cmd[];
+
+extern void reipl(unsigned long devno);
+
+void do_machine_restart(void)
+{
+ smp_send_stop();
+ reipl(S390_lowcore.ipl_device);
+}
+
+void machine_restart(char * __unused)
+{
+ if (smp_processor_id() != 0) {
+ smp_ext_bitcall(0, ec_restart);
+ for (;;);
+ } else
+ do_machine_restart();
+}
+
+void do_machine_halt(void)
+{
+ smp_send_stop();
+ if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+ cpcmd(vmhalt_cmd, NULL, 0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+}
+
+void machine_halt(void)
+{
+ if (smp_processor_id() != 0) {
+ smp_ext_bitcall(0, ec_halt);
+ for (;;);
+ } else
+ do_machine_halt();
+}
+
+void do_machine_power_off(void)
+{
+ smp_send_stop();
+ if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+ cpcmd(vmpoff_cmd, NULL, 0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+}
+
+void machine_power_off(void)
+{
+ if (smp_processor_id() != 0) {
+ smp_ext_bitcall(0, ec_power_off);
+ for (;;);
+ } else
+ do_machine_power_off();
+}
+
+/*
+ * This is the main routine where commands issued by other
+ * cpus are handled.
+ */
+
+void do_ext_call_interrupt(struct pt_regs *regs, __u16 code)
+{
+ ec_ext_call *ec, *next;
+ unsigned long bits;
+
+ /*
+ * handle bit signal external calls
+ *
+ * For the ec_schedule signal we have to do nothing. All the work
+ * is done automatically when we return from the interrupt.
+ * For the ec_restart, ec_halt and ec_power_off we call the
+ * appropriate routine.
+ */
+ bits = xchg(&S390_lowcore.ext_call_fast, 0);
+
+ if (test_bit(ec_restart, &bits))
+ do_machine_restart();
+ if (test_bit(ec_halt, &bits))
+ do_machine_halt();
+ if (test_bit(ec_power_off, &bits))
+ do_machine_power_off();
+
+ /*
+ * Handle external call commands with a parameter area
+ */
+ ec = (ec_ext_call *) xchg(&S390_lowcore.ext_call_queue, 0);
+ if (ec == NULL)
+ return; /* no command signals */
+
+ /* Make a fifo out of the lifo */
+ next = ec->next;
+ ec->next = NULL;
+ while (next != NULL) {
+ ec_ext_call *tmp = next->next;
+ next->next = ec;
+ ec = next;
+ next = tmp;
+ }
+
+ /* Execute every sigp command on the queue */
+ while (ec != NULL) {
+ switch (ec->cmd) {
+ case ec_callback_async: {
+ void (*func)(void *info);
+ void *info;
+
+ func = ec->func;
+ info = ec->info;
+ atomic_set(&ec->status,ec_executing);
+ (func)(info);
+ return;
+ }
+ case ec_callback_sync:
+ atomic_set(&ec->status,ec_executing);
+ (ec->func)(ec->info);
+ atomic_set(&ec->status,ec_done);
+ return;
+ default:
+ }
+ ec = ec->next;
+ }
+}
+
+/*
+ * Swap in a new request to external call queue
+ */
+static inline void smp_add_ext_call(ec_ext_call *ec, struct _lowcore *lowcore)
+{
+ int success;
+
+ while (1) {
+ ec->next = (ec_ext_call*) lowcore->ext_call_queue;
+ __asm__ __volatile__ (
+ " lgr 0,%2\n"
+ " csg 0,%3,%1\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (success), "+m" (lowcore->ext_call_queue)
+ : "d" (ec->next), "d" (ec)
+ : "cc", "0" );
+ if (success == 0) break;
+ }
+}
+
+/*
+ * Send an external call sigp to another cpu and wait for its completion.
+ */
+sigp_ccode
+smp_ext_call(int cpu, void (*func)(void *info), void *info, int wait)
+{
+ sigp_ccode ccode;
+ ec_ext_call ec;
+
+ ec.cmd = wait ? ec_callback_sync:ec_callback_async;
+ atomic_set(&ec.status, ec_pending);
+ ec.func = func;
+ ec.info = info;
+ /* swap in new request to external call queue */
+ smp_add_ext_call(&ec, &get_cpu_lowcore(cpu));
+ /*
+ * We try once to deliver the signal. There are four possible
+ * return codes:
+ * 0) Order code accepted - can't show up on an external call
+ * 1) Status stored - fine, wait for completion.
+ * 2) Busy - there is another signal pending. Thats fine too, because
+ * do_ext_call from the pending signal will execute all signals on
+ * the queue. We wait for completion.
+ * 3) Not operational - something very bad has happened to the cpu.
+ * do not wait for completion.
+ */
+ ccode = signal_processor(cpu, sigp_external_call);
+
+ if (ccode != sigp_not_operational)
+ /* wait for completion, FIXME: possible seed of a deadlock */
+ while (atomic_read(&ec.status) != (wait?ec_done:ec_executing));
+
+ return ccode;
+}
+
+/*
+ * Send a callback sigp to every other cpu in the system.
+ */
+void smp_ext_call_others(void (*func)(void *info), void *info, int wait)
+{
+ ec_ext_call ec[NR_CPUS];
+ sigp_ccode ccode;
+ int i;
+
+ for (i = 0; i < smp_num_cpus; i++) {
+ if (smp_processor_id() == i)
+ continue;
+ ec[i].cmd = wait ? ec_callback_sync : ec_callback_async;
+ atomic_set(&ec[i].status, ec_pending);
+ ec[i].func = func;
+ ec[i].info = info;
+ smp_add_ext_call(ec+i, &get_cpu_lowcore(i));
+ ccode = signal_processor(i, sigp_external_call);
+ }
+
+ /* wait for completion, FIXME: possible seed of a deadlock */
+ for (i = 0; i < smp_num_cpus; i++) {
+ if (smp_processor_id() == i)
+ continue;
+ while (atomic_read(&ec[i].status) !=
+ (wait ? ec_done:ec_executing));
+ }
+}
+
+/*
+ * Send an external call sigp to another cpu and return without waiting
+ * for its completion.
+ */
+sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
+{
+ sigp_ccode ccode;
+
+ /*
+ * Set signaling bit in lowcore of target cpu and kick it
+ */
+ set_bit(sig, &(get_cpu_lowcore(cpu).ext_call_fast));
+ ccode = signal_processor(cpu, sigp_external_call);
+ return ccode;
+}
+
+/*
+ * Send an external call sigp to every other cpu in the system and
+ * return without waiting for its completion.
+ */
+void smp_ext_bitcall_others(ec_bit_sig sig)
+{
+ sigp_ccode ccode;
+ int i;
+
+ for (i = 0; i < smp_num_cpus; i++) {
+ if (smp_processor_id() == i)
+ continue;
+ /*
+ * Set signaling bit in lowcore of target cpu and kick it
+ */
+ set_bit(sig, &(get_cpu_lowcore(i).ext_call_fast));
+ ccode = signal_processor(i, sigp_external_call);
+ }
+}
+
+/*
+ * cycles through all the cpus,
+ * returns early if info is not NULL & the processor has something
+ * of intrest to report in the info structure.
+ * it returns the next cpu to check if it returns early.
+ * i.e. it should be used as follows if you wish to receive info.
+ * next_cpu=0;
+ * do
+ * {
+ * info->cpu=next_cpu;
+ * next_cpu=smp_signal_others(order_code,parameter,1,info);
+ * ... check info here
+ * } while(next_cpu<=smp_num_cpus)
+ *
+ * if you are lazy just use it like
+ * smp_signal_others(order_code,parameter,0,1,NULL);
+ */
+int smp_signal_others(sigp_order_code order_code, u32 parameter,
+ int spin, sigp_info *info)
+{
+ sigp_ccode ccode;
+ u32 dummy;
+ u16 i;
+
+ if (info)
+ info->intresting = 0;
+ for (i = (info ? info->cpu : 0); i < smp_num_cpus; i++) {
+ if (smp_processor_id() != i) {
+ do {
+ ccode = signal_processor_ps(
+ (info ? &info->status : &dummy),
+ parameter, i, order_code);
+ } while(spin && ccode == sigp_busy);
+ if (info && ccode != sigp_order_code_accepted) {
+ info->intresting = 1;
+ info->cpu = i;
+ info->ccode = ccode;
+ i++;
+ break;
+ }
+ }
+ }
+ return i;
+}
+
+/*
+ * this function sends a 'stop' sigp to all other CPUs in the system.
+ * it goes straight through.
+ */
+
+void smp_send_stop(void)
+{
+ int i;
+ u32 dummy;
+ unsigned long low_core_addr;
+
+ /* write magic number to zero page (absolute 0) */
+
+ get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC;
+
+ /* stop all processors */
+
+ smp_signal_others(sigp_stop, 0, TRUE, NULL);
+
+ /* store status of all processors in their lowcores (real 0) */
+
+ for (i = 0; i < smp_num_cpus; i++) {
+ if (smp_processor_id() != i) {
+ int ccode;
+ low_core_addr = (unsigned long)&get_cpu_lowcore(i);
+ do {
+ ccode = signal_processor_ps(
+ &dummy,
+ low_core_addr,
+ i,
+ sigp_store_status_at_address);
+ } while(ccode == sigp_busy);
+ }
+ }
+}
+
+/*
+ * this function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+ * anything. Worst case is that we lose a reschedule ...
+ */
+
+void smp_send_reschedule(int cpu)
+{
+ smp_ext_bitcall(cpu, ec_schedule);
+}
+
+/*
+ * parameter area for the set/clear control bit callbacks
+ */
+typedef struct
+{
+ __u16 start_ctl;
+ __u16 end_ctl;
+ __u64 orvals[16];
+ __u64 andvals[16];
+} ec_creg_mask_parms;
+
+/*
+ * callback for setting/clearing control bits
+ */
+void smp_ctl_bit_callback(void *info) {
+ ec_creg_mask_parms *pp;
+ u64 cregs[16];
+ int i;
+
+ pp = (ec_creg_mask_parms *) info;
+ asm volatile (" bras 1,0f\n"
+ " stctg 0,0,0(%0)\n"
+ "0: ex %1,0(1)\n"
+ : : "a" (cregs+pp->start_ctl),
+ "a" ((pp->start_ctl<<4) + pp->end_ctl)
+ : "memory", "1" );
+ for (i = pp->start_ctl; i <= pp->end_ctl; i++)
+ cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
+ asm volatile (" bras 1,0f\n"
+ " lctlg 0,0,0(%0)\n"
+ "0: ex %1,0(1)\n"
+ : : "a" (cregs+pp->start_ctl),
+ "a" ((pp->start_ctl<<4) + pp->end_ctl)
+ : "memory", "1" );
+}
+
+/*
+ * Set a bit in a control register of all cpus
+ */
+void smp_ctl_set_bit(int cr, int bit) {
+ ec_creg_mask_parms parms;
+
+ if (atomic_read(&smp_commenced) != 0) {
+ parms.start_ctl = cr;
+ parms.end_ctl = cr;
+ parms.orvals[cr] = 1 << bit;
+ parms.andvals[cr] = -1L;
+ smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
+ }
+ __ctl_set_bit(cr, bit);
+}
+
+/*
+ * Clear a bit in a control register of all cpus
+ */
+void smp_ctl_clear_bit(int cr, int bit) {
+ ec_creg_mask_parms parms;
+
+ if (atomic_read(&smp_commenced) != 0) {
+ parms.start_ctl = cr;
+ parms.end_ctl = cr;
+ parms.orvals[cr] = 0;
+ parms.andvals[cr] = ~(1L << bit);
+ smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
+ }
+ __ctl_clear_bit(cr, bit);
+}
+
+/*
+ * Call a function on all other processors
+ */
+
+int
+smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
+/*
+ * [SUMMARY] Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <retry> currently unused.
+ * <wait> If true, wait (atomically) until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler, you may call it from a bottom half handler.
+ */
+{
+ if (atomic_read(&smp_commenced) != 0)
+ smp_ext_call_others(func, info, 1);
+ (func)(info);
+ return 0;
+}
+
+/*
+ * Lets check how many CPUs we have.
+ */
+
+void smp_count_cpus(void)
+{
+ int curr_cpu;
+
+ current->processor = 0;
+ smp_num_cpus = 1;
+ for (curr_cpu = 0;
+ curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) {
+ if ((__u16) curr_cpu == boot_cpu_addr)
+ continue;
+ __cpu_logical_map[smp_num_cpus] = (__u16) curr_cpu;
+ if (signal_processor(smp_num_cpus, sigp_sense) ==
+ sigp_not_operational)
+ continue;
+ smp_num_cpus++;
+ }
+ printk("Detected %d CPU's\n",(int) smp_num_cpus);
+ printk("Boot cpu address %2X\n", boot_cpu_addr);
+}
+
+
+/*
+ * Activate a secondary processor.
+ */
+extern void init_100hz_timer(void);
+
+int __init start_secondary(void *cpuvoid)
+{
+ /* Setup the cpu */
+ cpu_init();
+ /* Print info about this processor */
+ print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data);
+ /* Wait for completion of smp startup */
+ while (!atomic_read(&smp_commenced))
+ /* nothing */ ;
+ /* init per CPU 100 hz timer */
+ init_100hz_timer();
+ /* cpu_idle will call schedule for us */
+ return cpu_idle(NULL);
+}
+
+/*
+ * The restart interrupt handler jumps to start_secondary directly
+ * without the detour over initialize_secondary. We defined it here
+ * so that the linker doesn't complain.
+ */
+void __init initialize_secondary(void)
+{
+}
+
+static int __init fork_by_hand(void)
+{
+ struct pt_regs regs;
+ /* don't care about the psw and regs settings since we'll never
+ reschedule the forked task. */
+ memset(&regs,0,sizeof(pt_regs));
+ return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
+}
+
+static void __init do_boot_cpu(int cpu)
+{
+ struct task_struct *idle;
+ struct _lowcore *cpu_lowcore;
+
+ /* We can't use kernel_thread since we must _avoid_ to reschedule
+ the child. */
+ if (fork_by_hand() < 0)
+ panic("failed fork for CPU %d", cpu);
+
+ /*
+ * We remove it from the pidhash and the runqueue
+ * once we got the process:
+ */
+ idle = init_task.prev_task;
+ if (!idle)
+ panic("No idle process for CPU %d",cpu);
+ idle->processor = cpu;
+ idle->has_cpu = 1; /* we schedule the first task manually */
+
+ del_from_runqueue(idle);
+ unhash_process(idle);
+ init_tasks[cpu] = idle;
+
+ cpu_lowcore=&get_cpu_lowcore(cpu);
+ cpu_lowcore->kernel_stack=idle->thread.ksp;
+ __asm__ __volatile__("stctg 0,15,%0\n\t"
+ "stam 0,15,%1"
+ : "=m" (cpu_lowcore->cregs_save_area[0]),
+ "=m" (cpu_lowcore->access_regs_save_area[0])
+ : : "memory");
+
+ eieio();
+ signal_processor(cpu,sigp_restart);
+}
+
+/*
+ * Architecture specific routine called by the kernel just before init is
+ * fired off. This allows the BP to have everything in order [we hope].
+ * At the end of this all the APs will hit the system scheduling and off
+ * we go. Each AP will load the system gdt's and jump through the kernel
+ * init into idle(). At this point the scheduler will one day take over
+ * and give them jobs to do. smp_callin is a standard routine
+ * we use to track CPUs as they power up.
+ */
+
+void __init smp_commence(void)
+{
+ /*
+ * Lets the callins below out of their loop.
+ */
+ atomic_set(&smp_commenced,1);
+}
+
+/*
+ * Cycle through the processors sending restart sigps to boot each.
+ */
+
+void __init smp_boot_cpus(void)
+{
+ struct _lowcore *curr_lowcore;
+ sigp_ccode ccode;
+ int i;
+
+ /* request the 0x1202 external interrupt */
+ if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
+ panic("Couldn't request external interrupt 0x1202");
+ smp_count_cpus();
+ memset(lowcore_ptr,0,sizeof(lowcore_ptr));
+
+ /*
+ * Initialize the logical to physical CPU number mapping
+ * and the per-CPU profiling counter/multiplier
+ */
+
+ for (i = 0; i < NR_CPUS; i++) {
+ prof_counter[i] = 1;
+ prof_old_multiplier[i] = 1;
+ prof_multiplier[i] = 1;
+ }
+
+ print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data);
+
+ for(i = 0; i < smp_num_cpus; i++)
+ {
+ curr_lowcore = (struct _lowcore *)
+ __get_free_pages(GFP_KERNEL|GFP_DMA, 1);
+ if (curr_lowcore == NULL) {
+ printk("smp_boot_cpus failed to allocate prefix memory\n");
+ break;
+ }
+ lowcore_ptr[i] = curr_lowcore;
+ memcpy(curr_lowcore, &S390_lowcore, sizeof(struct _lowcore));
+ /*
+ * Most of the parameters are set up when the cpu is
+ * started up.
+ */
+ if (smp_processor_id() == i)
+ set_prefix((u32)(u64)curr_lowcore);
+ else {
+ ccode = signal_processor_p((u64)(curr_lowcore),
+ i, sigp_set_prefix);
+ if(ccode) {
+ /* if this gets troublesome I'll have to do
+ * something about it. */
+ printk("ccode %d for cpu %d returned when "
+ "setting prefix in smp_boot_cpus not good.\n",
+ (int) ccode, (int) i);
+ }
+ else
+ do_boot_cpu(i);
+ }
+ }
+}
+
+/*
+ * the frequency of the profiling timer can be changed
+ * by writing a multiplier value into /proc/profile.
+ *
+ * usually you want to run this on all CPUs ;)
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+ return 0;
+}
+
+/*
+ * Local timer interrupt handler. It does both profiling and
+ * process statistics/rescheduling.
+ *
+ * We do profiling in every local tick, statistics/rescheduling
+ * happen only every 'profiling multiplier' ticks. The default
+ * multiplier is 1 and it can be changed by writing the new multiplier
+ * value into /proc/profile.
+ */
+
+void smp_local_timer_interrupt(struct pt_regs * regs)
+{
+ int user = (user_mode(regs) != 0);
+ int cpu = smp_processor_id();
+
+ /*
+ * The profiling function is SMP safe. (nothing can mess
+ * around with "current", and the profiling counters are
+ * updated with atomic operations). This is especially
+ * useful with a profiling multiplier != 1
+ */
+ if (!user_mode(regs))
+ s390_do_profile(regs->psw.addr);
+
+ if (!--prof_counter[cpu]) {
+ int system = 1-user;
+ struct task_struct * p = current;
+
+ /*
+ * The multiplier may have changed since the last time we got
+ * to this point as a result of the user writing to
+ * /proc/profile. In this case we need to adjust the APIC
+ * timer accordingly.
+ *
+ * Interrupts are already masked off at this point.
+ */
+ prof_counter[cpu] = prof_multiplier[cpu];
+ if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
+ prof_old_multiplier[cpu] = prof_counter[cpu];
+ }
+
+ /*
+ * After doing the above, we need to make like
+ * a normal interrupt - otherwise timer interrupts
+ * ignore the global interrupt lock, which is the
+ * WrongThing (tm) to do.
+ */
+
+ irq_enter(cpu, 0);
+ update_process_times(user);
+ irq_exit(cpu, 0);
+ }
+}
+
diff --git a/arch/s390x/kernel/sys_s390.c b/arch/s390x/kernel/sys_s390.c
new file mode 100644
index 000000000..4c06bd326
--- /dev/null
+++ b/arch/s390x/kernel/sys_s390.c
@@ -0,0 +1,205 @@
+/*
+ * arch/s390/kernel/sys_s390.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * Derived from "arch/i386/kernel/sys_i386.c"
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/s390
+ * platform.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way Unix traditionally does this, though.
+ */
+asmlinkage long sys_pipe(unsigned long * fildes)
+{
+ int fd[2];
+ int error;
+
+ error = do_pipe(fd);
+ if (!error) {
+ if (copy_to_user(fildes, fd, 2*sizeof(int)))
+ error = -EFAULT;
+ }
+ return error;
+}
+
+/* common code for old and new mmaps */
+static inline long do_mmap2(
+ unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+{
+ long error = -EBADF;
+ struct file * file = NULL;
+
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ if (!(flags & MAP_ANONYMOUS)) {
+ file = fget(fd);
+ if (!file)
+ goto out;
+ }
+
+ down(&current->mm->mmap_sem);
+ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ up(&current->mm->mmap_sem);
+
+ if (file)
+ fput(file);
+out:
+ return error;
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/i386 didn't use to be able to handle more than
+ * 4 system call parameters, so these system calls used a memory
+ * block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+ unsigned long addr;
+ unsigned long len;
+ unsigned long prot;
+ unsigned long flags;
+ unsigned long fd;
+ unsigned long offset;
+};
+
+asmlinkage long sys_mmap2(struct mmap_arg_struct *arg)
+{
+ struct mmap_arg_struct a;
+ int error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+out:
+ return error;
+}
+
+asmlinkage long old_mmap(struct mmap_arg_struct *arg)
+{
+ struct mmap_arg_struct a;
+ long error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+
+ error = -EINVAL;
+ if (a.offset & ~PAGE_MASK)
+ goto out;
+
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+out:
+ return error;
+}
+
+extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage int sys_ipc (uint call, int first, int second,
+ unsigned long third, void *ptr)
+{
+ struct ipc_kludge tmp;
+ int ret;
+
+ switch (call) {
+ case SEMOP:
+ return sys_semop (first, (struct sembuf *)ptr, second);
+ case SEMGET:
+ return sys_semget (first, second, third);
+ case SEMCTL: {
+ union semun fourth;
+ if (!ptr)
+ return -EINVAL;
+ if (get_user(fourth.__pad, (void **) ptr))
+ return -EFAULT;
+ return sys_semctl (first, second, third, fourth);
+ }
+ case MSGSND:
+ return sys_msgsnd (first, (struct msgbuf *) ptr,
+ second, third);
+ break;
+ case MSGRCV:
+ if (!ptr)
+ return -EINVAL;
+ if (copy_from_user (&tmp, (struct ipc_kludge *) ptr,
+ sizeof (struct ipc_kludge)))
+ return -EFAULT;
+ return sys_msgrcv (first, tmp.msgp,
+ second, tmp.msgtyp, third);
+ case MSGGET:
+ return sys_msgget ((key_t) first, second);
+ case MSGCTL:
+ return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+
+ case SHMAT: {
+ ulong raddr;
+ ret = sys_shmat (first, (char *) ptr, second, &raddr);
+ if (ret)
+ return ret;
+ return put_user (raddr, (ulong *) third);
+ break;
+ }
+ case SHMDT:
+ return sys_shmdt ((char *)ptr);
+ case SHMGET:
+ return sys_shmget (first, second, third);
+ case SHMCTL:
+ return sys_shmctl (first, second,
+ (struct shmid_ds *) ptr);
+ default:
+ return -EINVAL;
+
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Old cruft
+ */
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+ int err;
+ if (!name)
+ return -EFAULT;
+ down_read(&uts_sem);
+ err=copy_to_user(name, &system_utsname, sizeof (*name));
+ up_read(&uts_sem);
+ return err?-EFAULT:0;
+}
+
+asmlinkage int sys_pause(void)
+{
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ return -ERESTARTNOHAND;
+}
+
diff --git a/arch/s390x/kernel/time.c b/arch/s390x/kernel/time.c
new file mode 100644
index 000000000..d4e91842e
--- /dev/null
+++ b/arch/s390x/kernel/time.c
@@ -0,0 +1,258 @@
+/*
+ * arch/s390/kernel/time.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ * Derived from "arch/i386/kernel/time.c"
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+#include <asm/delay.h>
+
+#include <linux/timex.h>
+#include <linux/config.h>
+
+#include <asm/irq.h>
+#include <asm/s390_ext.h>
+
+
+/* change this if you have some constant time drift */
+#define USECS_PER_JIFFY ((signed long)1000000/HZ)
+#define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12)
+
+#define TICK_SIZE tick
+
+static uint64_t init_timer_cc, last_timer_cc;
+
+extern rwlock_t xtime_lock;
+extern unsigned long wall_jiffies;
+
+void tod_to_timeval(uint64_t todval, struct timeval *xtime)
+{
+#if 0
+ const int high_bit = 0x80000000L;
+ const int c_f4240 = 0xf4240L;
+ const int c_7a120 = 0x7a120;
+ /* We have to divide the 64 bit value todval by 4096
+ * (because the 2^12 bit is the one that changes every
+ * microsecond) and then split it into seconds and
+ * microseconds. A value of max (2^52-1) divided by
+ * the value 0xF4240 can yield a max result of approx
+ * (2^32.068). Thats to big to fit into a signed int
+ * ... hacking time!
+ */
+ asm volatile ("L 2,%1\n\t"
+ "LR 3,2\n\t"
+ "SRL 2,12\n\t"
+ "SLL 3,20\n\t"
+ "L 4,%O1+4(%R1)\n\t"
+ "SRL 4,12\n\t"
+ "OR 3,4\n\t" /* now R2/R3 contain (todval >> 12) */
+ "SR 4,4\n\t"
+ "CL 2,%2\n\t"
+ "JL .+12\n\t"
+ "S 2,%2\n\t"
+ "L 4,%3\n\t"
+ "D 2,%4\n\t"
+ "OR 3,4\n\t"
+ "ST 2,%O0+4(%R0)\n\t"
+ "ST 3,%0"
+ : "=m" (*xtime) : "m" (todval),
+ "m" (c_7a120), "m" (high_bit), "m" (c_f4240)
+ : "cc", "memory", "2", "3", "4" );
+#else
+ todval >>= 12;
+ xtime->tv_sec = todval / 1000000;
+ xtime->tv_usec = todval % 1000000;
+#endif
+}
+
+unsigned long do_gettimeoffset(void)
+{
+ __u64 timer_cc;
+
+ asm volatile ("STCK %0" : "=m" (timer_cc));
+ /* We require the offset from the previous interrupt */
+ return ((unsigned long)((timer_cc - last_timer_cc)>>12));
+}
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ unsigned long usec, sec;
+ unsigned long lost_ticks = jiffies - wall_jiffies;
+
+ read_lock_irqsave(&xtime_lock, flags);
+ usec = do_gettimeoffset();
+ if (lost_ticks)
+ usec +=(USECS_PER_JIFFY*lost_ticks);
+ sec = xtime.tv_sec;
+ usec += xtime.tv_usec;
+ read_unlock_irqrestore(&xtime_lock, flags);
+
+ while (usec >= 1000000) {
+ usec -= 1000000;
+ sec++;
+ }
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+
+ write_lock_irq(&xtime_lock);
+ /* This is revolting. We need to set the xtime.tv_usec
+ * correctly. However, the value in this location is
+ * is value at the last tick.
+ * Discover what correction gettimeofday
+ * would have done, and then undo it!
+ */
+ tv->tv_usec -= do_gettimeoffset();
+
+ while (tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ xtime = *tv;
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
+ write_unlock_irq(&xtime_lock);
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+#ifdef CONFIG_SMP
+extern __u16 boot_cpu_addr;
+#endif
+
+void do_timer_interrupt(struct pt_regs *regs,int error_code)
+{
+ unsigned long flags;
+
+ /*
+ * reset timer to 10ms minus time already elapsed
+ * since timer-interrupt pending
+ */
+
+ save_flags(flags);
+ cli();
+#ifdef CONFIG_SMP
+ if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) {
+ write_lock(&xtime_lock);
+ last_timer_cc = S390_lowcore.jiffy_timer_cc;
+ }
+#else
+ last_timer_cc = S390_lowcore.jiffy_timer_cc;
+#endif
+ /* set clock comparator */
+ S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
+ asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
+
+/*
+ * In the SMP case we use the local timer interrupt to do the
+ * profiling, except when we simulate SMP mode on a uniprocessor
+ * system, in that case we have to call the local interrupt handler.
+ */
+#ifdef CONFIG_SMP
+ /* when SMP, do smp_local_timer_interrupt for *all* CPUs,
+ but only do the rest for the boot CPU */
+ smp_local_timer_interrupt(regs);
+#else
+ if (!user_mode(regs))
+ s390_do_profile(regs->psw.addr);
+#endif
+
+#ifdef CONFIG_SMP
+ if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr)
+#endif
+ {
+ do_timer(regs);
+#ifdef CONFIG_SMP
+ write_unlock(&xtime_lock);
+#endif
+ }
+ restore_flags(flags);
+
+}
+
+/*
+ * Start the clock comparator on the current CPU
+ */
+static unsigned long cr0 __attribute__ ((aligned (8)));
+
+void init_100hz_timer(void)
+{
+ /* allow clock comparator timer interrupt */
+ asm volatile ("STCTG 0,0,%0" : "=m" (cr0) : : "memory");
+ cr0 |= 0x800;
+ asm volatile ("LCTLG 0,0,%0" : : "m" (cr0) : "memory");
+ /* set clock comparator */
+ /* read the TOD clock */
+ asm volatile ("STCK %0" : "=m" (S390_lowcore.jiffy_timer_cc));
+ S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
+ asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
+}
+
+/*
+ * Initialize the TOD clock and the CPU timer of
+ * the boot cpu.
+ */
+void __init time_init(void)
+{
+ int cc;
+
+ /* kick the TOD clock */
+ asm volatile ("STCK %1\n\t"
+ "IPM %0\n\t"
+ "SRL %0,28" : "=r" (cc), "=m" (init_timer_cc));
+ switch (cc) {
+ case 0: /* clock in set state: all is fine */
+ break;
+ case 1: /* clock in non-set state: FIXME */
+ printk("time_init: TOD clock in non-set state\n");
+ break;
+ case 2: /* clock in error state: FIXME */
+ printk("time_init: TOD clock in error state\n");
+ break;
+ case 3: /* clock in stopped or not-operational state: FIXME */
+ printk("time_init: TOD clock stopped/non-operational\n");
+ break;
+ }
+ /* request the 0x1004 external interrupt */
+ if (register_external_interrupt(0x1004, do_timer_interrupt) != 0)
+ panic("Couldn't request external interrupts 0x1004");
+ init_100hz_timer();
+ init_timer_cc = S390_lowcore.jiffy_timer_cc;
+ init_timer_cc -= 0x8126d60e46000000LL -
+ (0x3c26700LL*1000000*4096);
+ tod_to_timeval(init_timer_cc, &xtime);
+}
diff --git a/arch/s390x/kernel/traps.c b/arch/s390x/kernel/traps.c
new file mode 100644
index 000000000..3301ddc18
--- /dev/null
+++ b/arch/s390x/kernel/traps.c
@@ -0,0 +1,248 @@
+/*
+ * arch/s390/kernel/traps.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * Derived from "arch/i386/kernel/traps.c"
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'asm.s'.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/mathemu.h>
+#if CONFIG_REMOTE_DEBUG
+#include <asm/gdb-stub.h>
+#endif
+
+/* Called from entry.S only */
+extern void handle_per_exception(struct pt_regs *regs);
+
+typedef void pgm_check_handler_t(struct pt_regs *, long);
+pgm_check_handler_t *pgm_check_table[128];
+
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
+int sysctl_userprocess_debug = 1;
+#else
+int sysctl_userprocess_debug = 0;
+#endif
+#endif
+
+extern pgm_check_handler_t do_page_fault;
+
+spinlock_t die_lock;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+ console_verbose();
+ spin_lock_irq(&die_lock);
+ printk("%s: %04lx\n", str, err & 0xffff);
+ show_regs(regs);
+ spin_unlock_irq(&die_lock);
+ do_exit(SIGSEGV);
+}
+
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+ do_trap(interruption_code, signr, str, regs, NULL); \
+}
+
+#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+ siginfo_t info; \
+ info.si_signo = signr; \
+ info.si_errno = 0; \
+ info.si_code = sicode; \
+ info.si_addr = (void *)siaddr; \
+ do_trap(interruption_code, signr, str, regs, &info); \
+}
+
+static void inline do_trap(long interruption_code, int signr, char *str,
+ struct pt_regs *regs, siginfo_t *info)
+{
+ if (regs->psw.mask & PSW_PROBLEM_STATE) {
+ struct task_struct *tsk = current;
+ tsk->thread.trap_no = interruption_code;
+ if (info)
+ force_sig_info(signr, info, tsk);
+ else
+ force_sig(signr, tsk);
+#ifndef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
+ printk("User process fault: interruption code 0x%lX\n",
+ interruption_code);
+ show_regs(regs);
+#endif
+#else
+ if (sysctl_userprocess_debug) {
+ printk("User process fault: interruption code 0x%lX\n",
+ interruption_code);
+ show_regs(regs);
+ }
+#endif
+ } else {
+ unsigned long fixup = search_exception_table(regs->psw.addr);
+ if (fixup)
+ regs->psw.addr = fixup;
+ else
+ die(str, regs, interruption_code);
+ }
+}
+
+int do_debugger_trap(struct pt_regs *regs,int signal)
+{
+ if(regs->psw.mask&PSW_PROBLEM_STATE)
+ {
+ if(current->ptrace & PT_PTRACED)
+ force_sig(signal,current);
+ else
+ return 1;
+ }
+ else
+ {
+#if CONFIG_REMOTE_DEBUG
+ if(gdb_stub_initialised)
+ {
+ gdb_stub_handle_exception((gdb_pt_regs *)regs,signal);
+ return 0;
+ }
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
+DO_ERROR(SIGILL, "privileged operation", privileged_op)
+DO_ERROR(SIGILL, "execute exception", execute_exception)
+DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
+DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception)
+DO_ERROR(SIGILL, "translation exception", translation_exception)
+DO_ERROR(SIGILL, "special operand exception", special_op_exception)
+DO_ERROR(SIGILL, "operand exception", operand_exception)
+DO_ERROR(SIGILL, "specification exception", specification_exception);
+
+asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
+{
+ __u8 opcode[6];
+ __u16 *location;
+ int do_sig = 0;
+
+ lock_kernel();
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ /* WARNING don't change this check back to */
+ /* int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); */
+ /* & then doing if(problem_state) an int is too small for this */
+ /* check on 64 bit. */
+ if(regs->psw.mask & PSW_PROBLEM_STATE)
+ get_user(*((__u16 *) opcode), location);
+ else
+ *((__u16 *)opcode)=*((__u16 *)location);
+ if(*((__u16 *)opcode)==S390_BREAKPOINT_U16)
+ {
+ if(do_debugger_trap(regs,SIGTRAP))
+ do_sig=1;
+ }
+ else
+ do_sig = 1;
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL);
+ unlock_kernel();
+}
+
+asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
+{
+ __u16 *location;
+ int do_sig = 0;
+
+ lock_kernel();
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ __asm__ volatile ("stfpc %0\n\t"
+ : "=m" (current->thread.fp_regs.fpc));
+ /* Same code should work when we implement fpu emulation */
+ /* provided we call data exception from the fpu emulator */
+ if(current->thread.fp_regs.fpc&FPC_DXC_MASK)
+ {
+ current->thread.ieee_instruction_pointer=(addr_t)location;
+ force_sig(SIGFPE, current);
+ }
+ else
+ do_sig = 1;
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "data exception", regs, NULL);
+ unlock_kernel();
+}
+
+
+
+/* init is done in lowcore.S and head.S */
+
+void __init trap_init(void)
+{
+ int i;
+
+ for (i = 0; i < 128; i++)
+ pgm_check_table[i] = &default_trap_handler;
+ pgm_check_table[1] = &illegal_op;
+ pgm_check_table[2] = &privileged_op;
+ pgm_check_table[3] = &execute_exception;
+ pgm_check_table[5] = &addressing_exception;
+ pgm_check_table[6] = &specification_exception;
+ pgm_check_table[7] = &data_exception;
+ pgm_check_table[9] = &divide_exception;
+ pgm_check_table[0x12] = &translation_exception;
+ pgm_check_table[0x13] = &special_op_exception;
+ pgm_check_table[0x15] = &operand_exception;
+ pgm_check_table[4] = &do_page_fault;
+ pgm_check_table[0x10] = &do_page_fault;
+ pgm_check_table[0x11] = &do_page_fault;
+ pgm_check_table[0x1C] = &privileged_op;
+ pgm_check_table[0x38] = &addressing_exception;
+ pgm_check_table[0x3B] = &do_page_fault;
+}
+
+
+void handle_per_exception(struct pt_regs *regs)
+{
+ if(regs->psw.mask&PSW_PROBLEM_STATE)
+ {
+ per_struct *per_info=&current->thread.per_info;
+ per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
+ per_info->lowcore.words.address=S390_lowcore.per_address;
+ per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
+ }
+ if(do_debugger_trap(regs,SIGTRAP))
+ {
+ /* I've seen this possibly a task structure being reused ? */
+ printk("Spurious per exception detected\n");
+ printk("switching off per tracing for this task.\n");
+ show_regs(regs);
+ /* Hopefully switching off per tracing will help us survive */
+ regs->psw.mask &= ~PSW_PER_MASK;
+ }
+}
+
diff --git a/arch/s390x/kernel/wrapper32.S b/arch/s390x/kernel/wrapper32.S
new file mode 100644
index 000000000..2cc5cb6cf
--- /dev/null
+++ b/arch/s390x/kernel/wrapper32.S
@@ -0,0 +1,1071 @@
+/*
+* arch/s390/kernel/sys_wrapper31.S
+* wrapper for 31 bit compatible system calls.
+*
+* S390 version
+* Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+* Author(s): Gerhard Tonn (ton@de.ibm.com),
+*/
+
+ .globl sys32_exit_wrapper
+sys32_exit_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_exit # branch to sys_exit
+
+ .globl sys32_read_wrapper
+sys32_read_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # char *
+ llgfr %r4,%r4 # size_t
+ jg sys_read # branch to sys_read
+
+ .globl sys32_write_wrapper
+sys32_write_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # size_t
+ jg sys_write # branch to system call
+
+ .globl sys32_open_wrapper
+sys32_open_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ jg sys_open # branch to system call
+
+ .globl sys32_close_wrapper
+sys32_close_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_close # branch to system call
+
+ .globl sys32_creat_wrapper
+sys32_creat_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_creat # branch to system call
+
+ .globl sys32_link_wrapper
+sys32_link_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_link # branch to system call
+
+ .globl sys32_unlink_wrapper
+sys32_unlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_unlink # branch to system call
+
+ .globl sys32_chdir_wrapper
+sys32_chdir_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_chdir # branch to system call
+
+ .globl sys32_time_wrapper
+sys32_time_wrapper:
+ llgtr %r2,%r2 # int *
+ jg sys_time # branch to system call
+
+ .globl sys32_mknod_wrapper
+sys32_mknod_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ llgfr %r4,%r4 # dev
+ jg sys_mknod # branch to system call
+
+ .globl sys32_chmod_wrapper
+sys32_chmod_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # mode_t
+ jg sys_chmod # branch to system call
+
+ .globl sys32_lchown16_wrapper
+sys32_lchown16_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_uid_emu31_t
+ jg sys32_lchown16 # branch to system call
+
+ .globl sys32_lseek_wrapper
+sys32_lseek_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ lgfr %r3,%r3 # off_t
+ llgfr %r4,%r4 # unsigned int
+ jg sys_lseek # branch to system call
+
+#sys32_getpid_wrapper # void
+
+ .globl sys32_mount_wrapper
+sys32_mount_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # char *
+ llgtr %r4,%r4 # char *
+ llgfr %r5,%r5 # unsigned long
+ llgtr %r6,%r6 # void *
+ jg sys32_mount # branch to system call
+
+ .globl sys32_oldumount_wrapper
+sys32_oldumount_wrapper:
+ llgtr %r2,%r2 # char *
+ jg sys_oldumount # branch to system call
+
+ .globl sys32_setuid16_wrapper
+sys32_setuid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ jg sys32_setuid16 # branch to system call
+
+#sys32_getuid16_wrapper # void
+
+ .globl sys32_ptrace_wrapper
+sys32_ptrace_wrapper:
+ lgfr %r2,%r2 # long
+ lgfr %r3,%r3 # long
+ llgtr %r4,%r4 # long
+ lgfr %r5,%r5 # long
+ jg sys32_ptrace # branch to system call
+
+ .globl sys32_alarm_wrapper
+sys32_alarm_wrapper:
+ llgtr %r2,%r2 # unsigned int
+ jg sys_alarm # branch to system call
+
+#sys32_pause_wrapper # void
+
+ .globl sys32_utime_wrapper
+sys32_utime_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct utimbuf_emu31 *
+ jg sys32_utime # branch to system call
+
+ .globl sys32_access_wrapper
+sys32_access_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_access # branch to system call
+
+ .globl sys32_nice_wrapper
+sys32_nice_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_nice # branch to system call
+
+#sys32_sync_wrapper # void
+
+ .globl sys32_kill_wrapper
+sys32_kill_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ jg sys_kill # branch to system call
+
+ .globl sys32_rename_wrapper
+sys32_rename_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_rename # branch to system call
+
+ .globl sys32_mkdir_wrapper
+sys32_mkdir_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_mkdir # branch to system call
+
+ .globl sys32_rmdir_wrapper
+sys32_rmdir_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_rmdir # branch to system call
+
+ .globl sys32_dup_wrapper
+sys32_dup_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_dup # branch to system call
+
+ .globl sys32_pipe_wrapper
+sys32_pipe_wrapper:
+ llgtr %r2,%r2 # u32 *
+ jg sys_pipe # branch to system call
+
+ .globl sys32_times_wrapper
+sys32_times_wrapper:
+ llgtr %r2,%r2 # struct tms_emu31 *
+ jg sys32_times # branch to system call
+
+ .globl sys32_brk_wrapper
+sys32_brk_wrapper:
+ llgtr %r2,%r2 # unsigned long
+ jg sys_brk # branch to system call
+
+ .globl sys32_setgid16_wrapper
+sys32_setgid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ jg sys32_setgid16 # branch to system call
+
+#sys32_getgid16_wrapper # void
+
+ .globl sys32_signal_wrapper
+sys32_signal_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # __sighandler_t
+ jg sys_signal
+
+#sys32_geteuid16_wrapper # void
+
+#sys32_getegid16_wrapper # void
+
+ .globl sys32_acct_wrapper
+sys32_acct_wrapper:
+ llgtr %r2,%r2 # char *
+ jg sys_acct # branch to system call
+
+ .globl sys32_umount_wrapper
+sys32_umount_wrapper:
+ llgtr %r2,%r2 # char *
+ lgfr %r3,%r3 # int
+ jg sys_umount # branch to system call
+
+ .globl sys32_ioctl_wrapper
+sys32_ioctl_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ llgfr %r4,%r4 # unsigned int
+ jg sys32_ioctl # branch to system call
+
+ .globl sys32_fcntl_wrapper
+sys32_fcntl_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ llgfr %r4,%r4 # unsigned long
+ jg sys32_fcntl # branch to system call
+
+ .globl sys32_setpgid_wrapper
+sys32_setpgid_wrapper:
+ lgfr %r2,%r2 # pid_t
+ lgfr %r3,%r3 # pid_t
+ jg sys_setpgid # branch to system call
+
+ .globl sys32_umask_wrapper
+sys32_umask_wrapper:
+ lgfr %r3,%r3 # int
+ jg sys_umask # branch to system call
+
+ .globl sys32_chroot_wrapper
+sys32_chroot_wrapper:
+ llgtr %r2,%r2 # char *
+ jg sys_chroot # branch to system call
+
+ .globl sys32_ustat_wrapper
+sys32_ustat_wrapper:
+ llgfr %r2,%r2 # dev_t
+ llgtr %r3,%r3 # struct ustat *
+ jg sys_ustat
+
+ .globl sys32_dup2_wrapper
+sys32_dup2_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ jg sys_dup2 # branch to system call
+
+#sys32_getppid_wrapper # void
+
+#sys32_getpgrp_wrapper # void
+
+#sys32_setsid_wrapper # void
+
+ .globl sys32_sigaction_wrapper
+sys32_sigaction_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct old_sigaction *
+ jg sys32_sigaction # branch to system call
+
+ .globl sys32_setreuid16_wrapper
+sys32_setreuid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ jg sys32_setreuid16 # branch to system call
+
+ .globl sys32_setregid16_wrapper
+sys32_setregid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_gid_emu31_t
+ jg sys32_setregid16 # branch to system call
+
+#sys32_sigsuspend_wrapper # done in sigsuspend_glue
+
+ .globl sys32_sigpending_wrapper
+sys32_sigpending_wrapper:
+ llgtr %r2,%r2 # old_sigset_emu31_t *
+ jg sys32_sigpending # branch to system call
+
+ .globl sys32_sethostname_wrapper
+sys32_sethostname_wrapper:
+ llgtr %r2,%r2 # char *
+ lgfr %r3,%r3 # int
+ jg sys_sethostname # branch to system call
+
+ .globl sys32_setrlimit_wrapper
+sys32_setrlimit_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct rlimit_emu31 *
+ jg sys32_setrlimit # branch to system call
+
+ .globl sys32_old_getrlimit_wrapper
+sys32_old_getrlimit_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct rlimit_emu31 *
+ jg sys32_old_getrlimit # branch to system call
+
+ .globl sys32_mmap2_wrapper
+sys32_mmap2_wrapper:
+ llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
+ jg sys32_mmap2 # branch to system call
+
+ .globl sys32_getrusage_wrapper
+sys32_getrusage_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct rusage_emu31 *
+ jg sys32_getrusage # branch to system call
+
+ .globl sys32_gettimeofday_wrapper
+sys32_gettimeofday_wrapper:
+ llgtr %r2,%r2 # struct timeval_emu31 *
+ llgtr %r3,%r3 # struct timezone *
+ jg sys32_gettimeofday # branch to system call
+
+ .globl sys32_settimeofday_wrapper
+sys32_settimeofday_wrapper:
+ llgtr %r2,%r2 # struct timeval_emu31 *
+ llgtr %r3,%r3 # struct timezone *
+ jg sys32_settimeofday # branch to system call
+
+ .globl sys32_getgroups16_wrapper
+sys32_getgroups16_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
+ jg sys32_getgroups16 # branch to system call
+
+ .globl sys32_setgroups16_wrapper
+sys32_setgroups16_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
+ jg sys32_setgroups16 # branch to system call
+
+ .globl sys32_symlink_wrapper
+sys32_symlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_symlink # branch to system call
+
+ .globl sys32_readlink_wrapper
+sys32_readlink_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # char *
+ lgfr %r4,%r4 # int
+ jg sys_readlink # branch to system call
+
+ .globl sys32_uselib_wrapper
+sys32_uselib_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_uselib # branch to system call
+
+ .globl sys32_swapon_wrapper
+sys32_swapon_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ jg sys_swapon # branch to system call
+
+ .globl sys32_reboot_wrapper
+sys32_reboot_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ llgfr %r4,%r4 # unsigned int
+ llgtr %r5,%r5 # void *
+ jg sys_reboot # branch to system call
+
+ .globl old32_readdir_wrapper
+old32_readdir_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # void *
+ llgfr %r4,%r4 # unsigned int
+ jg old32_readdir # branch to system call
+
+ .globl old32_mmap_wrapper
+old32_mmap_wrapper:
+ llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
+ jg old32_mmap # branch to system call
+
+ .globl sys32_munmap_wrapper
+sys32_munmap_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ jg sys_munmap # branch to system call
+
+ .globl sys32_truncate_wrapper
+sys32_truncate_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # unsigned long
+ jg sys_truncate # branch to system call
+
+ .globl sys32_ftruncate_wrapper
+sys32_ftruncate_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned long
+ jg sys_ftruncate # branch to system call
+
+ .globl sys32_fchmod_wrapper
+sys32_fchmod_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # mode_t
+ jg sys_fchmod # branch to system call
+
+ .globl sys32_fchown16_wrapper
+sys32_fchown16_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # __kernel_old_uid_emu31_t *
+ llgtr %r4,%r4 # __kernel_old_gid_emu31_t *
+ jg sys32_fchown16 # branch to system call
+
+ .globl sys32_getpriority_wrapper
+sys32_getpriority_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ jg sys_getpriority # branch to system call
+
+ .globl sys32_setpriority_wrapper
+sys32_setpriority_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ jg sys_setpriority # branch to system call
+
+ .globl sys32_statfs_wrapper
+sys32_statfs_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct statfs_emu31 *
+ jg sys32_statfs # branch to system call
+
+ .globl sys32_fstatfs_wrapper
+sys32_fstatfs_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct statfs_emu31 *
+ jg sys32_fstatfs # branch to system call
+
+ .globl sys32_socketcall_wrapper
+sys32_socketcall_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # u32 *
+ jg sys32_socketcall # branch to system call
+
+ .globl sys32_syslog_wrapper
+sys32_syslog_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # char *
+ lgfr %r4,%r4 # int
+ jg sys_syslog # branch to system call
+
+ .globl sys32_setitimer_wrapper
+sys32_setitimer_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct itimerval_emu31 *
+ llgtr %r4,%r4 # struct itimerval_emu31 *
+ jg sys32_setitimer # branch to system call
+
+ .globl sys32_getitimer_wrapper
+sys32_getitimer_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct itimerval_emu31 *
+ jg sys32_getitimer # branch to system call
+
+ .globl sys32_newstat_wrapper
+sys32_newstat_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct stat_emu31 *
+ jg sys32_newstat # branch to system call
+
+ .globl sys32_newlstat_wrapper
+sys32_newlstat_wrapper:
+ llgtr %r2,%r2 # char *
+ llgtr %r3,%r3 # struct stat_emu31 *
+ jg sys32_newlstat # branch to system call
+
+ .globl sys32_newfstat_wrapper
+sys32_newfstat_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # struct stat_emu31 *
+ jg sys32_newfstat # branch to system call
+
+#sys32_vhangup_wrapper # void
+
+ .globl sys32_wait4_wrapper
+sys32_wait4_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # unsigned int *
+ lgfr %r4,%r4 # int
+ llgtr %r5,%r5 # struct rusage *
+ jg sys32_wait4 # branch to system call
+
+ .globl sys32_swapoff_wrapper
+sys32_swapoff_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys_swapoff # branch to system call
+
+ .globl sys32_sysinfo_wrapper
+sys32_sysinfo_wrapper:
+ llgtr %r2,%r2 # struct sysinfo_emu31 *
+ jg sys32_sysinfo # branch to system call
+
+ .globl sys32_ipc_wrapper
+sys32_ipc_wrapper:
+ llgfr %r2,%r2 # uint
+ lgfr %r3,%r3 # int
+ lgfr %r4,%r4 # int
+ lgfr %r5,%r5 # int
+ llgtr %r6,%r6 # void *
+ jg sys32_ipc # branch to system call
+
+ .globl sys32_fsync_wrapper
+sys32_fsync_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_fsync # branch to system call
+
+#sys32_sigreturn_wrapper # done in sigreturn_glue
+
+#sys32_clone_wrapper # done in clone_glue
+
+ .globl sys32_setdomainname_wrapper
+sys32_setdomainname_wrapper:
+ llgtr %r2,%r2 # char *
+ lgfr %r3,%r3 # int
+ jg sys_setdomainname # branch to system call
+
+ .globl sys32_newuname_wrapper
+sys32_newuname_wrapper:
+ llgtr %r2,%r2 # struct new_utsname *
+ jg sys_newuname # branch to system call
+
+ .globl sys32_adjtimex_wrapper
+sys32_adjtimex_wrapper:
+ llgtr %r2,%r2 # struct timex_emu31 *
+ jg sys32_adjtimex # branch to system call
+
+ .globl sys32_mprotect_wrapper
+sys32_mprotect_wrapper:
+ llgtr %r2,%r2 # unsigned long (actually pointer
+ llgfr %r3,%r3 # size_t
+ llgfr %r4,%r4 # unsigned long
+ jg sys_mprotect # branch to system call
+
+ .globl sys32_sigprocmask_wrapper
+sys32_sigprocmask_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # old_sigset_emu31 *
+ llgtr %r4,%r4 # old_sigset_emu31 *
+ jg sys32_sigprocmask # branch to system call
+
+ .globl sys32_create_module_wrapper
+sys32_create_module_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # size_t
+ jg sys32_create_module # branch to system call
+
+ .globl sys32_init_module_wrapper
+sys32_init_module_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # struct module *
+ jg sys32_init_module # branch to system call
+
+ .globl sys32_delete_module_wrapper
+sys32_delete_module_wrapper:
+ llgtr %r2,%r2 # const char *
+ jg sys32_delete_module # branch to system call
+
+ .globl sys32_get_kernel_syms_wrapper
+sys32_get_kernel_syms_wrapper:
+ llgtr %r2,%r2 # struct kernel_sym_emu31 *
+ jg sys32_get_kernel_syms # branch to system call
+
+ .globl sys32_quotactl_wrapper
+sys32_quotactl_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const char *
+ lgfr %r4,%r4 # int
+ llgtr %r5,%r5 # caddr_t
+ jg sys32_quotactl # branch to system call
+
+ .globl sys32_getpgid_wrapper
+sys32_getpgid_wrapper:
+ lgfr %r2,%r2 # pid_t
+ jg sys_getpgid # branch to system call
+
+ .globl sys32_fchdir_wrapper
+sys32_fchdir_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_fchdir # branch to system call
+
+ .globl sys32_bdflush_wrapper
+sys32_bdflush_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # long
+ jg sys_bdflush # branch to system call
+
+ .globl sys32_sysfs_wrapper
+sys32_sysfs_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ jg sys_sysfs # branch to system call
+
+ .globl sys32_personality_wrapper
+sys32_personality_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ jg sys_personality # branch to system call
+
+ .globl sys32_setfsuid16_wrapper
+sys32_setfsuid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ jg sys32_setfsuid16 # branch to system call
+
+ .globl sys32_setfsgid16_wrapper
+sys32_setfsgid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ jg sys32_setfsgid16 # branch to system call
+
+ .globl sys32_llseek_wrapper
+sys32_llseek_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ lgfr %r3,%r3 # off_t
+ llgfr %r4,%r4 # unsigned int
+ jg sys_llseek # branch to system call
+
+ .globl sys32_getdents_wrapper
+sys32_getdents_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # void *
+ llgfr %r4,%r4 # unsigned int
+ jg sys32_getdents # branch to system call
+
+ .globl sys32_select_wrapper
+sys32_select_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # fd_set *
+ llgtr %r4,%r4 # fd_set *
+ llgtr %r5,%r5 # fd_set *
+ llgtr %r6,%r6 # struct timeval_emu31 *
+ jg sys32_select # branch to system call
+
+ .globl sys32_flock_wrapper
+sys32_flock_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ jg sys_flock # branch to system call
+
+ .globl sys32_msync_wrapper
+sys32_msync_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ lgfr %r4,%r4 # int
+ jg sys_msync # branch to system call
+
+ .globl sys32_readv_wrapper
+sys32_readv_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgtr %r3,%r3 # const struct iovec_emu31 *
+ llgfr %r4,%r4 # unsigned long
+ jg sys32_readv # branch to system call
+
+ .globl sys32_writev_wrapper
+sys32_writev_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgtr %r3,%r3 # const struct iovec_emu31 *
+ llgfr %r4,%r4 # unsigned long
+ jg sys32_writev # branch to system call
+
+ .globl sys32_getsid_wrapper
+sys32_getsid_wrapper:
+ lgfr %r2,%r2 # pid_t
+ jg sys_getsid # branch to system call
+
+ .globl sys32_fdatasync_wrapper
+sys32_fdatasync_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ jg sys_fdatasync # branch to system call
+
+#sys32_sysctl_wrapper # tbd
+
+ .globl sys32_mlock_wrapper
+sys32_mlock_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ jg sys_mlock # branch to system call
+
+ .globl sys32_munlock_wrapper
+sys32_munlock_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ jg sys_munlock # branch to system call
+
+ .globl sys32_mlockall_wrapper
+sys32_mlockall_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_mlockall # branch to system call
+
+#sys32_munlockall_wrapper # void
+
+ .globl sys32_sched_setparam_wrapper
+sys32_sched_setparam_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # struct sched_param *
+ jg sys_sched_setparam # branch to system call
+
+ .globl sys32_sched_getparam_wrapper
+sys32_sched_getparam_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # struct sched_param *
+ jg sys_sched_getparam # branch to system call
+
+ .globl sys32_sched_setscheduler_wrapper
+sys32_sched_setscheduler_wrapper:
+ lgfr %r2,%r2 # pid_t
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # struct sched_param *
+ jg sys_sched_setscheduler # branch to system call
+
+ .globl sys32_sched_getscheduler_wrapper
+sys32_sched_getscheduler_wrapper:
+ lgfr %r2,%r2 # pid_t
+ jg sys_sched_getscheduler # branch to system call
+
+#sys32_sched_yield_wrapper # void
+
+ .globl sys32_sched_get_priority_max_wrapper
+sys32_sched_get_priority_max_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_sched_get_priority_max # branch to system call
+
+ .globl sys32_sched_get_priority_min_wrapper
+sys32_sched_get_priority_min_wrapper:
+ lgfr %r2,%r2 # int
+ jg sys_sched_get_priority_min # branch to system call
+
+ .globl sys32_sched_rr_get_interval_wrapper
+sys32_sched_rr_get_interval_wrapper:
+ lgfr %r2,%r2 # pid_t
+ llgtr %r3,%r3 # struct timespec_emu31 *
+ jg sys32_sched_rr_get_interval # branch to system call
+
+ .globl sys32_nanosleep_wrapper
+sys32_nanosleep_wrapper:
+ llgtr %r2,%r2 # struct timespec_emu31 *
+ llgtr %r3,%r3 # struct timespec_emu31 *
+ jg sys32_nanosleep # branch to system call
+
+ .globl sys32_mremap_wrapper
+sys32_mremap_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ llgfr %r5,%r5 # unsigned long
+ llgfr %r6,%r6 # unsigned long
+ jg sys_mremap # branch to system call
+
+ .globl sys32_setresuid16_wrapper
+sys32_setresuid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_uid_emu31_t
+ jg sys32_setresuid16 # branch to system call
+
+ .globl sys32_getresuid16_wrapper
+sys32_getresuid16_wrapper:
+ llgtr %r2,%r2 # __kernel_old_uid_emu31_t *
+ llgtr %r3,%r3 # __kernel_old_uid_emu31_t *
+ llgtr %r4,%r4 # __kernel_old_uid_emu31_t *
+ jg sys32_getresuid16 # branch to system call
+
+ .globl sys32_query_module_wrapper
+sys32_query_module_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # char *
+ llgfr %r5,%r5 # size_t
+ llgtr %r6,%r6 # size_t *
+ jg sys32_query_module # branch to system call
+
+ .globl sys32_poll_wrapper
+sys32_poll_wrapper:
+ llgtr %r2,%r2 # struct pollfd *
+ llgfr %r3,%r3 # unsigned int
+ lgfr %r4,%r4 # long
+ jg sys_poll # branch to system call
+
+ .globl sys32_nfsservctl_wrapper
+sys32_nfsservctl_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # struct nfsctl_arg_emu31 *
+ llgtr %r4,%r4 # union nfsctl_res_emu31 *
+ jg sys32_nfsservctl # branch to system call
+
+ .globl sys32_setresgid16_wrapper
+sys32_setresgid16_wrapper:
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_gid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_gid_emu31_t
+ jg sys32_setresgid16 # branch to system call
+
+ .globl sys32_getresgid16_wrapper
+sys32_getresgid16_wrapper:
+ llgtr %r2,%r2 # __kernel_old_gid_emu31_t *
+ llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
+ llgtr %r4,%r4 # __kernel_old_gid_emu31_t *
+ jg sys32_getresgid16 # branch to system call
+
+ .globl sys32_prctl_wrapper
+sys32_prctl_wrapper:
+ lgfr %r2,%r2 # int
+ llgfr %r3,%r3 # unsigned long
+ llgfr %r4,%r4 # unsigned long
+ llgfr %r5,%r5 # unsigned long
+ llgfr %r6,%r6 # unsigned long
+ jg sys_prctl # branch to system call
+
+#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
+
+ .globl sys32_rt_sigaction_wrapper
+sys32_rt_sigaction_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # const struct sigaction_emu31 *
+ llgtr %r4,%r4 # const struct sigaction_emu31 *
+ llgfr %r5,%r5 # size_t
+ jg sys32_rt_sigaction # branch to system call
+
+ .globl sys32_rt_sigprocmask_wrapper
+sys32_rt_sigprocmask_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # old_sigset_emu31 *
+ llgtr %r4,%r4 # old_sigset_emu31 *
+ jg sys32_rt_sigprocmask # branch to system call
+
+ .globl sys32_rt_sigpending_wrapper
+sys32_rt_sigpending_wrapper:
+ llgtr %r2,%r2 # sigset_emu31 *
+ llgfr %r3,%r3 # size_t
+ jg sys32_rt_sigpending # branch to system call
+
+ .globl sys32_rt_sigtimedwait_wrapper
+sys32_rt_sigtimedwait_wrapper:
+ llgtr %r2,%r2 # const sigset_emu31_t *
+ llgtr %r3,%r3 # siginfo_emu31_t *
+ llgtr %r4,%r4 # const struct timespec_emu31 *
+ llgfr %r5,%r5 # size_t
+ jg sys32_rt_sigtimedwait # branch to system call
+
+ .globl sys32_rt_sigqueueinfo_wrapper
+sys32_rt_sigqueueinfo_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # siginfo_emu31_t *
+ jg sys32_rt_sigqueueinfo # branch to system call
+
+#sys32_rt_sigsuspend_wrapper # done in rt_sigsuspend_glue
+
+ .globl sys32_pread_wrapper
+sys32_pread_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # char *
+ llgfr %r4,%r4 # size_t
+ llgfr %r5,%r5 # u32
+ llgfr %r6,%r6 # u32
+ jg sys32_pread # branch to system call
+
+ .globl sys32_pwrite_wrapper
+sys32_pwrite_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # const char *
+ llgfr %r4,%r4 # size_t
+ llgfr %r5,%r5 # u32
+ llgfr %r6,%r6 # u32
+ jg sys32_pwrite # branch to system call
+
+ .globl sys32_chown16_wrapper
+sys32_chown16_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_gid_emu31_t
+ jg sys32_chown16 # branch to system call
+
+ .globl sys32_getcwd_wrapper
+sys32_getcwd_wrapper:
+ llgtr %r2,%r2 # char *
+ llgfr %r3,%r3 # unsigned long
+ jg sys_getcwd # branch to system call
+
+ .globl sys32_capget_wrapper
+sys32_capget_wrapper:
+ llgtr %r2,%r2 # cap_user_header_t
+ llgtr %r3,%r3 # cap_user_data_t
+ jg sys_capget # branch to system call
+
+ .globl sys32_capset_wrapper
+sys32_capset_wrapper:
+ llgtr %r2,%r2 # cap_user_header_t
+ llgtr %r3,%r3 # const cap_user_data_t
+ jg sys_capset # branch to system call
+
+ .globl sys32_sigaltstack_wrapper
+sys32_sigaltstack_wrapper:
+ llgtr %r2,%r2 # const stack_emu31_t *
+ llgtr %r3,%r3 # stack_emu31_t *
+ jg sys32_sigaltstack
+
+ .globl sys32_sendfile_wrapper
+sys32_sendfile_wrapper:
+ lgfr %r2,%r2 # int
+ lgfr %r3,%r3 # int
+ llgtr %r4,%r4 # __kernel_off_emu31_t *
+ llgfr %r5,%r5 # size_t
+ jg sys32_sendfile # branch to system call
+
+#sys32_vfork_wrapper # done in vfork_glue
+
+ .globl sys32_truncate64_wrapper
+sys32_truncate64_wrapper:
+ llgtr %r2,%r2 # const char *
+ lgfr %r3,%r3 # s32
+ llgfr %r4,%r4 # u32
+ jg sys32_truncate64 # branch to system call
+
+ .globl sys32_ftruncate64_wrapper
+sys32_ftruncate64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ lgfr %r3,%r3 # s32
+ llgfr %r4,%r4 # u32
+ jg sys32_ftruncate64 # branch to system call
+
+ .globl sys32_lchown_wrapper
+sys32_lchown_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_lchown # branch to system call
+
+#sys32_getuid_wrapper # void
+#sys32_getgid_wrapper # void
+#sys32_geteuid_wrapper # void
+#sys32_getegid_wrapper # void
+
+ .globl sys32_setreuid_wrapper
+sys32_setreuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ llgfr %r3,%r3 # uid_t
+ jg sys_setreuid # branch to system call
+
+ .globl sys32_setregid_wrapper
+sys32_setregid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ llgfr %r3,%r3 # gid_t
+ jg sys_setregid # branch to system call
+
+ .globl sys32_getgroups_wrapper
+sys32_getgroups_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # gid_t *
+ jg sys_getgroups # branch to system call
+
+ .globl sys32_setgroups_wrapper
+sys32_setgroups_wrapper:
+ lgfr %r2,%r2 # int
+ llgtr %r3,%r3 # gid_t *
+ jg sys_setgroups # branch to system call
+
+ .globl sys32_fchown_wrapper
+sys32_fchown_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_fchown # branch to system call
+
+ .globl sys32_setresuid_wrapper
+sys32_setresuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # uid_t
+ jg sys_setresuid # branch to system call
+
+ .globl sys32_getresuid_wrapper
+sys32_getresuid_wrapper:
+ llgtr %r2,%r2 # uid_t *
+ llgtr %r3,%r3 # uid_t *
+ llgtr %r4,%r4 # uid_t *
+ jg sys_getresuid # branch to system call
+
+ .globl sys32_setresgid_wrapper
+sys32_setresgid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ llgfr %r3,%r3 # gid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_setresgid # branch to system call
+
+ .globl sys32_getresgid_wrapper
+sys32_getresgid_wrapper:
+ llgtr %r2,%r2 # gid_t *
+ llgtr %r3,%r3 # gid_t *
+ llgtr %r4,%r4 # gid_t *
+ jg sys_getresgid # branch to system call
+
+ .globl sys32_chown_wrapper
+sys32_chown_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgfr %r3,%r3 # uid_t
+ llgfr %r4,%r4 # gid_t
+ jg sys_chown # branch to system call
+
+ .globl sys32_setuid_wrapper
+sys32_setuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ jg sys_setuid # branch to system call
+
+ .globl sys32_setgid_wrapper
+sys32_setgid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ jg sys_setgid # branch to system call
+
+ .globl sys32_setfsuid_wrapper
+sys32_setfsuid_wrapper:
+ llgfr %r2,%r2 # uid_t
+ jg sys_setfsuid # branch to system call
+
+ .globl sys32_setfsgid_wrapper
+sys32_setfsgid_wrapper:
+ llgfr %r2,%r2 # gid_t
+ jg sys_setfsgid # branch to system call
+
+ .globl sys32_pivot_root_wrapper
+sys32_pivot_root_wrapper:
+ llgtr %r2,%r2 # const char *
+ llgtr %r3,%r3 # const char *
+ jg sys_pivot_root # branch to system call
+
+ .globl sys32_mincore_wrapper
+sys32_mincore_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ llgtr %r4,%r4 # unsigned char *
+ jg sys_mincore # branch to system call
+
+ .globl sys32_madvise_wrapper
+sys32_madvise_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # size_t
+ lgfr %r4,%r4 # int
+ jg sys_madvise # branch to system call
+
+ .globl sys32_getdents64_wrapper
+sys32_getdents64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgtr %r3,%r3 # void *
+ llgfr %r4,%r4 # unsigned int
+ jg sys_getdents64 # branch to system call
+
+ .globl sys32_fcntl64_wrapper
+sys32_fcntl64_wrapper:
+ llgfr %r2,%r2 # unsigned int
+ llgfr %r3,%r3 # unsigned int
+ llgfr %r4,%r4 # unsigned long
+ jg sys32_fcntl64 # branch to system call
+
diff --git a/arch/s390x/lib/Makefile b/arch/s390x/lib/Makefile
new file mode 100644
index 000000000..30ee0f662
--- /dev/null
+++ b/arch/s390x/lib/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for s390-specific library files..
+#
+
+ifdef SMP
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+else
+.S.o:
+ $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+endif
+
+L_TARGET = lib.a
+
+obj-y = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o
+
+include $(TOPDIR)/Rules.make
+
diff --git a/arch/s390x/lib/checksum.c b/arch/s390x/lib/checksum.c
new file mode 100644
index 000000000..489299b3a
--- /dev/null
+++ b/arch/s390x/lib/checksum.c
@@ -0,0 +1,40 @@
+/*
+ * arch/s390/lib/checksum.c
+ * S390 fast network checksum routines
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Ulrich Hild (first version),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *
+ * This file contains network checksum routines
+ */
+
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <asm/checksum.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+unsigned int
+csum_partial (const unsigned char *buff, int len, unsigned int sum)
+{
+ /*
+ * Experiments with ethernet and slip connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary.
+ */
+ __asm__ __volatile__ (
+ " lgr 2,%1\n" /* address in gpr 2 */
+ " lgfr 3,%2\n" /* length in gpr 3 */
+ "0: cksm %0,2\n" /* do checksum on longs */
+ " jo 0b\n"
+ : "+&d" (sum)
+ : "d" (buff), "d" (len)
+ : "cc", "2", "3" );
+ return sum;
+}
+
diff --git a/arch/s390x/lib/delay.c b/arch/s390x/lib/delay.c
new file mode 100644
index 000000000..012a95308
--- /dev/null
+++ b/arch/s390x/lib/delay.c
@@ -0,0 +1,50 @@
+/*
+ * arch/s390/kernel/delay.c
+ * Precise Delay Loops for S390
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * Derived from "arch/i386/lib/delay.c"
+ * Copyright (C) 1993 Linus Torvalds
+ * Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_SMP
+#include <asm/smp.h>
+#endif
+
+void __delay(unsigned long loops)
+{
+ /*
+ * To end the bloody studid and useless discussion about the
+ * BogoMips number I took the liberty to define the __delay
+ * function in a way that that resulting BogoMips number will
+ * yield the megahertz number of the cpu. The important function
+ * is udelay and that is done using the tod clock. -- martin.
+ */
+ __asm__ __volatile__(
+ "0: brct %0,0b"
+ : /* no outputs */ : "r" (loops/2) );
+}
+
+/*
+ * Waits for 'usecs' microseconds using the tod clock
+ */
+void __udelay(unsigned long usecs)
+{
+ uint64_t start_cc, end_cc;
+
+ if (usecs == 0)
+ return;
+ asm volatile ("STCK %0" : "=m" (start_cc));
+ do {
+ asm volatile ("STCK %0" : "=m" (end_cc));
+ } while (((end_cc - start_cc)/4096) < usecs);
+}
+
diff --git a/arch/s390x/lib/memset.S b/arch/s390x/lib/memset.S
new file mode 100644
index 000000000..1e4b035d2
--- /dev/null
+++ b/arch/s390x/lib/memset.S
@@ -0,0 +1,30 @@
+/*
+ * arch/s390/lib/memset.S
+ * S390 fast memset routine
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+/*
+ * R2 = address to memory area
+ * R3 = byte to fill memory with
+ * R4 = number of bytes to fill
+ */
+ .globl memset
+memset:
+ LTGR 4,4
+ JZ memset_end
+ LGR 0,2 # save pointer to memory area
+ LGR 1,3 # move pad byte to R1
+ LGR 3,4
+ SGR 4,4 # no source for MVCLE, only a pad byte
+ SGR 5,5
+ MVCLE 2,4,0(1) # thats it, MVCLE is your friend
+ JO .-4
+ LGR 2,0 # return pointer to mem.
+memset_end:
+ BR 14
+
+
diff --git a/arch/s390x/lib/strcmp.S b/arch/s390x/lib/strcmp.S
new file mode 100644
index 000000000..124f3df26
--- /dev/null
+++ b/arch/s390x/lib/strcmp.S
@@ -0,0 +1,27 @@
+/*
+ * arch/s390/lib/strcmp.S
+ * S390 strcmp routine
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+/*
+ * R2 = address of compare string
+ * R3 = address of test string
+ */
+ .globl strcmp
+strcmp:
+ SGR 0,0
+ SGR 1,1
+ CLST 2,3
+ JO .-4
+ JE strcmp_equal
+ IC 0,0(3)
+ IC 1,0(2)
+ SGR 1,0
+strcmp_equal:
+ LGR 2,1
+ BR 14
+
diff --git a/arch/s390x/lib/strncpy.S b/arch/s390x/lib/strncpy.S
new file mode 100644
index 000000000..0360a38c3
--- /dev/null
+++ b/arch/s390x/lib/strncpy.S
@@ -0,0 +1,30 @@
+/*
+ * arch/s390/kernel/strncpy.S
+ * S390 strncpy routine
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+/*
+ * R2 = address of destination
+ * R3 = address of source string
+ * R4 = max number of bytes to copy
+ */
+ .globl strncpy
+strncpy:
+ LGR 1,2 # don't touch address in R2
+ LTR 4,4
+ JZ strncpy_exit # 0 bytes -> nothing to do
+ SGR 0,0
+strncpy_loop:
+ ICM 0,1,0(3) # ICM sets the cc, IC does not
+ LA 3,1(3)
+ STC 0,0(1)
+ LA 1,1(1)
+ JZ strncpy_exit # ICM inserted a 0x00
+ BRCTG 4,strncpy_loop # R4 -= 1, jump to strncpy_loop if > 0
+strncpy_exit:
+ BR 14
+
diff --git a/arch/s390x/lib/uaccess.S b/arch/s390x/lib/uaccess.S
new file mode 100644
index 000000000..2a5356c19
--- /dev/null
+++ b/arch/s390x/lib/uaccess.S
@@ -0,0 +1,45 @@
+/*
+ * arch/s390x/lib/uaccess.S
+ * fixup routines for copy_{from|to}_user functions.
+ *
+ * S390
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * These functions have a non-standard call interface
+ */
+
+#include <asm/lowcore.h>
+
+ .text
+ .align 4
+ .globl __copy_from_user_fixup
+__copy_from_user_fixup:
+ lg 1,__LC_PGM_OLD_PSW+8
+0: lghi 3,-4096
+ ng 3,__LC_TRANS_EXC_ADDR
+ sgr 3,4
+ bm 4(1)
+1: mvcle 2,4,0
+ b 4(1)
+ .section __ex_table,"a"
+ .align 8
+ .quad 1b,0b
+ .previous
+
+ .align 4
+ .text
+ .globl __copy_to_user_fixup
+__copy_to_user_fixup:
+ lg 1,__LC_PGM_OLD_PSW+8
+0: lghi 5,-4096
+ ng 5,__LC_TRANS_EXC_ADDR
+ sgr 5,4
+ bm 4(1)
+1: mvcle 4,2,0
+ b 4(1)
+ .section __ex_table,"a"
+ .align 8
+ .quad 1b,0b
+ .previous
+
diff --git a/arch/s390x/mm/Makefile b/arch/s390x/mm/Makefile
new file mode 100644
index 000000000..73e25bd30
--- /dev/null
+++ b/arch/s390x/mm/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the linux i386-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := mm.o
+
+obj-y := init.o fault.o ioremap.o extable.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/s390x/mm/extable.c b/arch/s390x/mm/extable.c
new file mode 100644
index 000000000..774e86854
--- /dev/null
+++ b/arch/s390x/mm/extable.c
@@ -0,0 +1,61 @@
+/*
+ * arch/s390/mm/extable.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com)
+ *
+ * Derived from "arch/i386/mm/extable.c"
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ long diff;
+
+ mid = (last - first) / 2 + first;
+ diff = mid->insn - value;
+ if (diff == 0)
+ return mid->fixup;
+ else if (diff < 0)
+ first = mid+1;
+ else
+ last = mid-1;
+ }
+ return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+ unsigned long ret;
+
+#ifndef CONFIG_MODULES
+ /* There is only the kernel to search. */
+ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+ if (ret) return FIX_PSW(ret);
+#else
+ /* The kernel is the last "module" -- no need to treat it special. */
+ struct module *mp;
+ for (mp = module_list; mp != NULL; mp = mp->next) {
+ if (mp->ex_table_start == NULL)
+ continue;
+ ret = search_one_table(mp->ex_table_start,
+ mp->ex_table_end - 1, addr);
+ if (ret) return FIX_PSW(ret);
+ }
+#endif
+
+ return 0;
+}
diff --git a/arch/s390x/mm/fault.c b/arch/s390x/mm/fault.c
new file mode 100644
index 000000000..4c324b690
--- /dev/null
+++ b/arch/s390x/mm/fault.c
@@ -0,0 +1,266 @@
+/*
+ * arch/s390/mm/fault.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com)
+ *
+ * Derived from "arch/i386/mm/fault.c"
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/hardirq.h>
+
+#ifdef CONFIG_SYSCTL
+extern int sysctl_userprocess_debug;
+#endif
+
+extern void die(const char *,struct pt_regs *,long);
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * error_code:
+ * ****0004 Protection -> Write-Protection (suprression)
+ * ****0010 Segment translation -> Not present (nullification)
+ * ****0011 Page translation -> Not present (nullification)
+ * ****003B Region third exception -> Not present (nullification)
+ */
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct * vma;
+ unsigned long address;
+ unsigned long fixup;
+ int write;
+ unsigned long psw_mask;
+ unsigned long psw_addr;
+ int si_code = SEGV_MAPERR;
+ int kernel_address = 0;
+
+ /*
+ * get psw mask of Program old psw to find out,
+ * if user or kernel mode
+ */
+
+ psw_mask = S390_lowcore.program_old_psw.mask;
+ psw_addr = S390_lowcore.program_old_psw.addr;
+
+ /*
+ * get the failing address
+ * more specific the segment and page table portion of
+ * the address
+ */
+
+ address = S390_lowcore.trans_exc_code&-4096L;
+
+ tsk = current;
+ mm = tsk->mm;
+
+ if (in_interrupt() || !mm)
+ goto no_context;
+
+ /*
+ * Check which address space the address belongs to
+ */
+ switch (S390_lowcore.trans_exc_code & 3)
+ {
+ case 0: /* Primary Segment Table Descriptor */
+ kernel_address = 1;
+ goto no_context;
+
+ case 1: /* STD determined via access register */
+ if (S390_lowcore.exc_access_id == 0)
+ {
+ kernel_address = 1;
+ goto no_context;
+ }
+ if (regs && S390_lowcore.exc_access_id < NUM_ACRS)
+ {
+ if (regs->acrs[S390_lowcore.exc_access_id] == 0)
+ {
+ kernel_address = 1;
+ goto no_context;
+ }
+ if (regs->acrs[S390_lowcore.exc_access_id] == 1)
+ {
+ /* user space address */
+ break;
+ }
+ }
+ die("page fault via unknown access register", regs, error_code);
+ break;
+
+ case 2: /* Secondary Segment Table Descriptor */
+ case 3: /* Home Segment Table Descriptor */
+ /* user space address */
+ break;
+ }
+
+
+ /*
+ * When we get here, the fault happened in the current
+ * task's user address space, so we search the VMAs
+ */
+
+ down(&mm->mmap_sem);
+
+ vma = find_vma(mm, address);
+ if (!vma) {
+ printk("no vma for address %lX\n",address);
+ goto bad_area;
+ }
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, address))
+ goto bad_area;
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ write = 0;
+ si_code = SEGV_ACCERR;
+
+ switch (error_code & 0xFF) {
+ case 0x04: /* write, present*/
+ write = 1;
+ break;
+ case 0x10: /* not present*/
+ case 0x11: /* not present*/
+ case 0x3B: /* not present*/
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+ goto bad_area;
+ break;
+ default:
+ printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF);
+ goto bad_area;
+ }
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ switch (handle_mm_fault(mm, vma, address, write)) {
+ case 1:
+ tsk->min_flt++;
+ break;
+ case 2:
+ tsk->maj_flt++;
+ break;
+ case 0:
+ goto do_sigbus;
+ default:
+ goto out_of_memory;
+ }
+
+ up(&mm->mmap_sem);
+ return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+ up(&mm->mmap_sem);
+
+ /* User mode accesses just cause a SIGSEGV */
+ if (psw_mask & PSW_PROBLEM_STATE) {
+ struct siginfo si;
+ tsk->thread.prot_addr = address;
+ tsk->thread.trap_no = error_code;
+#ifndef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
+ printk("User process fault: interruption code 0x%lX\n",error_code);
+ printk("failing address: %lX\n",address);
+ show_regs(regs);
+#endif
+#else
+ if (sysctl_userprocess_debug) {
+ printk("User process fault: interruption code 0x%lX\n",
+ error_code);
+ printk("failing address: %lX\n", address);
+ show_regs(regs);
+ }
+#endif
+ si.si_signo = SIGSEGV;
+ si.si_code = si_code;
+ si.si_addr = (void*) address;
+ force_sig_info(SIGSEGV, &si, tsk);
+ return;
+ }
+
+no_context:
+ /* Are we prepared to handle this kernel fault? */
+ if ((fixup = search_exception_table(regs->psw.addr)) != 0) {
+ regs->psw.addr = fixup;
+ return;
+ }
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ if (kernel_address)
+ printk(KERN_ALERT "Unable to handle kernel pointer dereference"
+ " at virtual kernel address %016lx\n", address);
+ else
+ printk(KERN_ALERT "Unable to handle kernel paging request"
+ " at virtual user address %016lx\n", address);
+
+/*
+ * need to define, which information is useful here
+ */
+
+ die("Oops", regs, error_code);
+ do_exit(SIGKILL);
+
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+*/
+out_of_memory:
+ up(&mm->mmap_sem);
+ printk("VM: killing process %s\n", tsk->comm);
+ if (psw_mask & PSW_PROBLEM_STATE)
+ do_exit(SIGKILL);
+ goto no_context;
+
+do_sigbus:
+ up(&mm->mmap_sem);
+
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->thread.prot_addr = address;
+ tsk->thread.trap_no = error_code;
+ force_sig(SIGBUS, tsk);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!(psw_mask & PSW_PROBLEM_STATE))
+ goto no_context;
+}
diff --git a/arch/s390x/mm/init.c b/arch/s390x/mm/init.c
new file mode 100644
index 000000000..91d66ccfe
--- /dev/null
+++ b/arch/s390x/mm/init.c
@@ -0,0 +1,405 @@
+/*
+ * arch/s390/mm/init.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hpenner@de.ibm.com)
+ *
+ * Derived from "arch/i386/mm/init.c"
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>
+#endif
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/dma.h>
+#include <asm/lowcore.h>
+
+static unsigned long totalram_pages;
+
+/*
+ * empty_bad_page is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving an inode
+ * unused etc..
+ *
+ * empty_bad_pte_table is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * empty_bad_pmd_table is the accompanying segment table: it is initialized
+ * to point to empty_bad_pte_table page tables.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
+char empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+pmd_t empty_bad_pmd_table[PTRS_PER_PMD] __attribute__((__aligned__(PAGE_SIZE)));
+pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE)));
+
+static int test_access(unsigned long loc)
+{
+ static const int ssm_mask = 0x07000000L;
+ int rc, i;
+
+ rc = 0;
+ for (i=0; i<2; i++) {
+ __asm__ __volatile__(
+ " slgr %0,%0\n"
+ " ssm %1\n"
+ " tprot 0(%2),0\n"
+ "0: jne 1f\n"
+ " lghi %0,1\n"
+ "1: ssm %3\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 8\n"
+ " .quad 0b,1b\n"
+ ".previous"
+ : "+&d" (rc) : "i" (0), "a" (loc), "m" (ssm_mask)
+ : "cc");
+ if (rc == 0)
+ break;
+ loc += 0x100000;
+ }
+ return rc;
+}
+
+static pmd_t *get_bad_pmd_table(void)
+{
+ pmd_t v;
+ int i;
+
+ pmd_set(&v, empty_bad_pte_table);
+
+ for (i = 0; i < PTRS_PER_PMD; i++)
+ empty_bad_pmd_table[i] = v;
+
+ return empty_bad_pmd_table;
+}
+
+static pte_t *get_bad_pte_table(void)
+{
+ pte_t v;
+ int i;
+
+ v = pte_mkdirty(mk_pte_phys(__pa(empty_bad_page), PAGE_SHARED));
+
+ for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++)
+ empty_bad_pte_table[i] = v;
+
+ return empty_bad_pte_table;
+}
+
+pmd_t *
+get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+ pmd_t *pmd;
+ int i;
+
+ pmd = (pmd_t *) __get_free_pages(GFP_KERNEL,2);
+ if (pgd_none(*pgd)) {
+ if (pmd) {
+ for (i = 0; i < PTRS_PER_PMD; i++)
+ pmd_clear(pmd+i);
+ pgd_set(pgd, pmd);
+ return pmd + offset;
+ }
+ pmd = (pmd_t *) get_bad_pmd_table();
+ pgd_set(pgd, pmd);
+ return NULL;
+ }
+ free_pages((unsigned long)pmd,2);
+ if (pgd_bad(*pgd))
+ BUG();
+ return (pmd_t *) pgd_page(*pgd) + offset;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+ pte_t *pte;
+ int i;
+
+ pte = (pte_t*) __get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (pte) {
+ for (i=0;i<PTRS_PER_PTE;i++)
+ pte_clear(pte+i);
+ pmd_set(pmd,pte);
+ return pte + offset;
+ }
+ pte = (pte_t*) get_bad_pte_table();
+ pmd_set(pmd,pte);
+ return NULL;
+ }
+ free_page(__pa(pte));
+ if (pmd_bad(*pmd))
+ BUG();
+ return (pte_t *) pmd_page(*pmd) + offset;
+}
+
+int do_check_pgt_cache(int low, int high)
+{
+ int freed = 0;
+ if(pgtable_cache_size > high) {
+ do {
+ if(pgd_quicklist)
+ free_pgd_slow(get_pgd_fast()), freed += 4;
+ if(pmd_quicklist)
+ free_pmd_slow(get_pmd_fast()), freed += 4;
+ if(pte_quicklist)
+ free_pte_slow(get_pte_fast()), freed++;
+ } while(pgtable_cache_size > low);
+ }
+ return freed;
+}
+
+void show_mem(void)
+{
+ int i, total = 0,reserved = 0;
+ int shared = 0, cached = 0;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+ i = max_mapnr;
+ while (i-- > 0) {
+ total++;
+ if (PageReserved(mem_map+i))
+ reserved++;
+ else if (PageSwapCache(mem_map+i))
+ cached++;
+ else if (page_count(mem_map+i))
+ shared += atomic_read(&mem_map[i].count) - 1;
+ }
+ printk("%d pages of RAM\n",total);
+ printk("%d reserved pages\n",reserved);
+ printk("%d pages shared\n",shared);
+ printk("%d pages swap cached\n",cached);
+ printk("%ld pages in page table cache\n",pgtable_cache_size);
+ show_buffers();
+}
+
+/* References to section boundaries */
+
+extern unsigned long _text;
+extern unsigned long _etext;
+extern unsigned long _edata;
+extern unsigned long __bss_start;
+extern unsigned long _end;
+
+extern unsigned long __init_begin;
+extern unsigned long __init_end;
+
+/*
+ * paging_init() sets up the page tables
+ */
+
+unsigned long last_valid_pfn;
+
+void __init paging_init(void)
+{
+ pgd_t * pg_dir;
+ pmd_t * pm_dir;
+ pte_t * pt_dir;
+ pte_t pte;
+ int i,j,k;
+ unsigned long address=0;
+ unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) |
+ _REGION_TABLE;
+ unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE);
+ static const int ssm_mask = 0x04000000L;
+
+ unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+ unsigned long dma_pfn, high_pfn;
+
+ dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
+ high_pfn = max_low_pfn;
+
+ if (dma_pfn > high_pfn)
+ zones_size[ZONE_DMA] = high_pfn;
+ else {
+ zones_size[ZONE_DMA] = dma_pfn;
+ zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
+ }
+
+ /* Initialize mem_map[]. */
+ free_area_init(zones_size);
+
+
+ /*
+ * map whole physical memory to virtual memory (identity mapping)
+ */
+
+ pg_dir = swapper_pg_dir;
+
+ for (i = 0 ; i < PTRS_PER_PGD ; i++,pg_dir++) {
+
+ if (address >= end_mem) {
+ pgd_clear(pg_dir);
+ continue;
+ }
+
+ pm_dir = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE*4);
+ pgd_set(pg_dir,pm_dir);
+
+ for (j = 0 ; j < PTRS_PER_PMD ; j++,pm_dir++) {
+ if (address >= end_mem) {
+ pmd_clear(pm_dir);
+ continue;
+ }
+
+ pt_dir = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+ pmd_set(pm_dir,pt_dir);
+
+ for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
+ pte = mk_pte_phys(address, PAGE_KERNEL);
+ if (address >= end_mem) {
+ pte_clear(&pte);
+ continue;
+ }
+ set_pte(pt_dir, pte);
+ address += PAGE_SIZE;
+ }
+ }
+ }
+
+ /* enable virtual mapping in kernel mode */
+ __asm__ __volatile__("lctlg 1,1,%0\n\t"
+ "lctlg 7,7,%0\n\t"
+ "lctlg 13,13,%0\n\t"
+ "ssm %1"
+ : :"m" (pgdir_k), "m" (ssm_mask));
+
+ local_flush_tlb();
+
+ return;
+}
+
+void __init mem_init(void)
+{
+ unsigned long codesize, reservedpages, datasize, initsize;
+ unsigned long tmp;
+
+ max_mapnr = num_physpages = max_low_pfn;
+ high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+
+ /* clear the zero-page */
+ memset(empty_zero_page, 0, PAGE_SIZE);
+
+ /* this will put all low memory onto the freelists */
+ totalram_pages += free_all_bootmem();
+
+ /* mark usable pages in the mem_map[] and count reserved pages */
+ reservedpages = 0;
+ tmp = 0;
+ do {
+ if (tmp && (tmp & 0x1ff) == 0 &&
+ test_access(tmp * PAGE_SIZE) == 0) {
+ printk("2M Segment 0x%016lX not available\n",
+ tmp * PAGE_SIZE);
+ do {
+ set_bit(PG_reserved, &mem_map[tmp].flags);
+ reservedpages++;
+ tmp++;
+ } while (tmp < max_low_pfn && (tmp & 0x1ff));
+ } else {
+ if (PageReserved(mem_map+tmp))
+ reservedpages++;
+ tmp++;
+ }
+ } while (tmp < max_low_pfn);
+
+ codesize = (unsigned long) &_etext - (unsigned long) &_text;
+ datasize = (unsigned long) &_edata - (unsigned long) &_etext;
+ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
+ printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
+ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+ max_mapnr << (PAGE_SHIFT-10),
+ codesize >> 10,
+ reservedpages << (PAGE_SHIFT-10),
+ datasize >>10,
+ initsize >> 10);
+}
+
+void free_initmem(void)
+{
+ unsigned long addr;
+
+ addr = (unsigned long)(&__init_begin);
+ for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(addr));
+ set_page_count(virt_to_page(addr), 1);
+ free_page(addr);
+ totalram_pages++;
+ }
+ printk ("Freeing unused kernel memory: %ldk freed\n",
+ (&__init_end - &__init_begin) >> 10);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ if (start < end)
+ printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(start));
+ set_page_count(virt_to_page(start), 1);
+ free_page(start);
+ totalram_pages++;
+ }
+}
+#endif
+
+void si_meminfo(struct sysinfo *val)
+{
+ val->totalram = totalram_pages;
+ val->sharedram = 0;
+ val->freeram = nr_free_pages();
+ val->bufferram = atomic_read(&buffermem_pages);
+ val->totalhigh = 0;
+ val->freehigh = 0;
+ val->mem_unit = PAGE_SIZE;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/arch/s390x/mm/ioremap.c b/arch/s390x/mm/ioremap.c
new file mode 100644
index 000000000..38acc4a22
--- /dev/null
+++ b/arch/s390x/mm/ioremap.c
@@ -0,0 +1,129 @@
+/*
+ * arch/s390/mm/ioremap.c
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com)
+ *
+ * Derived from "arch/i386/mm/extable.c"
+ * (C) Copyright 1995 1996 Linus Torvalds
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ * This is needed for high PCI addresses that aren't mapped in the
+ * 640k-1MB IO memory area on PC's
+ */
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+ unsigned long phys_addr, unsigned long flags)
+{
+ unsigned long end;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ if (address >= end)
+ BUG();
+ do {
+ if (!pte_none(*pte)) {
+ printk("remap_area_pte: page already exists\n");
+ BUG();
+ }
+ set_pte(pte, mk_pte_phys(phys_addr,
+ __pgprot(_PAGE_PRESENT | flags)));
+ address += PAGE_SIZE;
+ phys_addr += PAGE_SIZE;
+ pte++;
+ } while (address && (address < end));
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+ unsigned long phys_addr, unsigned long flags)
+{
+ unsigned long end;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ phys_addr -= address;
+ if (address >= end)
+ BUG();
+ do {
+ pte_t * pte = pte_alloc_kernel(pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ remap_area_pte(pte, address, end - address, address + phys_addr, flags);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address && (address < end));
+ return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+ unsigned long size, unsigned long flags)
+{
+ pgd_t * dir;
+ unsigned long end = address + size;
+
+ phys_addr -= address;
+ dir = pgd_offset(&init_mm, address);
+ flush_cache_all();
+ if (address >= end)
+ BUG();
+ do {
+ pmd_t *pmd = pmd_alloc_kernel(dir, address);
+ if (!pmd)
+ return -ENOMEM;
+ if (remap_area_pmd(pmd, address, end - address,
+ phys_addr + address, flags))
+ return -ENOMEM;
+ set_pgdir(address, *dir);
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (address && (address < end));
+ flush_tlb_all();
+ return 0;
+}
+
+/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ */
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+ void * addr;
+ struct vm_struct * area;
+
+ if (phys_addr < virt_to_phys(high_memory))
+ return phys_to_virt(phys_addr);
+ if (phys_addr & ~PAGE_MASK)
+ return NULL;
+ size = PAGE_ALIGN(size);
+ if (!size || size > phys_addr + size)
+ return NULL;
+ area = get_vm_area(size, VM_IOREMAP);
+ if (!area)
+ return NULL;
+ addr = area->addr;
+ if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+ vfree(addr);
+ return NULL;
+ }
+ return addr;
+}
+
+void iounmap(void *addr)
+{
+ if (addr > high_memory)
+ return vfree(addr);
+}
diff --git a/arch/s390x/tools/dasdfmt/Makefile b/arch/s390x/tools/dasdfmt/Makefile
new file mode 100644
index 000000000..b60641bbc
--- /dev/null
+++ b/arch/s390x/tools/dasdfmt/Makefile
@@ -0,0 +1,9 @@
+all: dasdfmt
+
+dasdfmt: dasdfmt.c
+ $(CC) -o $@ $^
+ $(STRIP) $@
+
+clean:
+ rm -f dasdfmt
+
diff --git a/arch/s390x/tools/dasdfmt/dasdfmt.8 b/arch/s390x/tools/dasdfmt/dasdfmt.8
new file mode 100644
index 000000000..9e6a4e89e
--- /dev/null
+++ b/arch/s390x/tools/dasdfmt/dasdfmt.8
@@ -0,0 +1,68 @@
+.TH DASDFMT 8 "Tue Jan 25 2000"
+.UC 4
+.SH NAME
+dasdfmt \- formatting of DSAD (ECKD) disk drives.
+.SH SYNOPSIS
+\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
+.SH DESCRIPTION
+\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
+for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
+\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
+
+.SH OPTIONS
+.TP
+\fB-t\fR
+Disables any modification of the disk drive. \fBdasdfmt\fR just prints
+out, what it \fBwould\fR do.
+
+.TP
+\fB-v\fR
+Increases verbosity.
+
+.TP
+\fB-y\fR
+Start formatting without further user-confirmation.
+
+.TP
+\fB-L\fR
+Omit the writing of a disk label after formatting.
+
+.TP
+\fB-V\fR
+Print version number and exit.
+
+.TP
+\fB-b\fR \fIblockSize\fR
+Specify blocksize to be used. \fIblocksize\fR must be a positive integer
+and always be a power of two. Due due some limitations in the driver,
+it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
+
+.TP
+\fB-l\fR \fIdiskLabel\fR
+Specify the label to be written to disk after formatting. If no label is
+specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
+ASCII string and is automatically converted to EBCDIC.
+
+.TP
+\fIdiskSpec\fR
+This parameter specified the device to be formatted. It also can be
+given in two variants:
+.sp
+ \fB-f\fR \fB/dev/dasd\fR\fIX\fR
+.br
+or
+.br
+ \fB-n\fR \fIdevnum\fR
+.sp
+The first form uses the commonly used
+.SM UNIX
+device notation where \fIX\fR is a single lowercase letter.
+The second form uses simply the device number.
+
+.SH BUGS
+None so far ;-)
+
+.SH AUTHOR
+.nf
+This man-page was written by Fritz Elfert <felfert@to.com>
+.fi
diff --git a/arch/s390x/tools/dasdfmt/dasdfmt.c b/arch/s390x/tools/dasdfmt/dasdfmt.c
new file mode 100644
index 000000000..2820fc91d
--- /dev/null
+++ b/arch/s390x/tools/dasdfmt/dasdfmt.c
@@ -0,0 +1,830 @@
+/*
+ *
+ * dasdfmt.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Corporation
+ * Author(s): Utz Bacher, <utz.bacher@de.ibm.com>
+ *
+ * Device-in-use-checks by Fritz Elfert, <felfert@to.com>
+ *
+ * Still to do:
+ * detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them
+ */
+
+/* #define _LINUX_BLKDEV_H */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <mntent.h>
+#define __KERNEL__ /* we want to use kdev_t and not have to define it */
+#include <linux/kdev_t.h>
+#undef __KERNEL__
+
+#include <linux/fs.h>
+#include <asm/dasd.h>
+#include <linux/hdreg.h>
+
+#define EXIT_MISUSE 1
+#define EXIT_BUSY 2
+#define TEMPFILENAME "/tmp/ddfXXXXXX"
+#define TEMPFILENAMECHARS 8 /* 8 characters are fixed in all temp filenames */
+#define SLASHDEV "/dev/"
+#define PROC_DASD_DEVICES "/proc/dasd/devices"
+/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */
+#define PROC_MOUNTS _PATH_MOUNTED
+#define PROC_SWAPS "/proc/swaps"
+#define DASD_DRIVER_NAME "dasd"
+#define LABEL_LENGTH 10
+#define PROC_LINE_LENGTH 80
+#define ERR_LENGTH 80
+
+#define MAX_FILELEN NAME_MAX+PATH_MAX
+
+#define GIVEN_DEVNO 1
+#define GIVEN_MAJOR 2
+#define GIVEN_MINOR 4
+
+#define CHECK_START 1
+#define CHECK_END 2
+#define CHECK_BLKSIZE 4
+#define CHECK_ALL ~0
+
+#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
+#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
+
+#define CHECK_SPEC_MAX_ONCE(i,str) \
+ {if (i>1) \
+ ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
+ "can only be specified once\n",prog_name);}
+
+#define PARSE_PARAM_INTO(x,param,base,str) \
+ {x=(int)strtol(param,&endptr,base); \
+ if (*endptr) \
+ ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
+ "is in invalid format\n",prog_name);}
+
+char *prog_name;/*="dasdfmt";*/
+char tempfilename[]=TEMPFILENAME;
+
+__u8 _ascebc[256] =
+{
+ /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ /* ->NL */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN EM SUB ESC FS GS RS US */
+ /* ->IGS ->IRS ->IUS */
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ /*80*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0 sz */
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+void convert_label(char *str)
+{
+ int i;
+ for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]];
+}
+
+void
+exit_usage(int exitcode)
+{
+#ifdef RANGE_FORMATTING
+ printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \
+ "<diskspec>\n\n",prog_name);
+#else /* RANGE_FORMATTING */
+ printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \
+ "<diskspec>\n\n",prog_name);
+#endif /* RANGE_FORMATTING */
+ printf(" -t means testmode\n");
+ printf(" -v means verbose mode\n");
+ printf(" -V means print version\n");
+ printf(" -L means don't write disk label\n");
+ printf(" <label> is a label which is converted to EBCDIC and " \
+ "written to disk\n");
+ printf(" <blocksize> has to be power of 2 and at least 512\n");
+#ifdef RANGE_FORMATTING
+ printf(" <range> is either\n");
+ printf(" -s <start_track> -e <end_track>\n");
+ printf(" or\n");
+ printf(" -r <start_track>-<end_track>\n");
+#endif /* RANGE_FORMATTING */
+ printf(" and <diskspec> is either\n");
+ printf(" -f /dev/dasdX\n");
+ printf(" or\n");
+ printf(" -n <s390-devnr>\n");
+ exit(exitcode);
+}
+
+void
+get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
+{
+ FILE *file;
+ int d,rc;
+ kdev_t mi,ma;
+ int mi_i,ma_i; /* for scanf :-( */
+ char line[PROC_LINE_LENGTH];
+
+ file=fopen(PROC_DASD_DEVICES,"r");
+ if (file==NULL)
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to open " \
+ PROC_DASD_DEVICES ": %s (do you have the /proc " \
+ "filesystem enabled?)\n",prog_name,strerror(errno));
+
+ /* fgets(line,sizeof(line),file); omit first line */
+ while (fgets(line,sizeof(line),file)!=NULL) {
+ rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i);
+ ma=ma_i;
+ mi=mi_i;
+ if ( (rc==3) &&
+ !((d!=*devno)&&(mode&GIVEN_DEVNO)) &&
+ !((ma!=*major_no)&&(mode&GIVEN_MAJOR)) &&
+ !((mi!=*minor_no)&&(mode&GIVEN_MINOR)) ) {
+ *devno=d;
+ *major_no=ma;
+ *minor_no=mi;
+ /* yes, this is a quick exit, but the easiest way */
+ fclose(file);
+ return;
+ }
+ }
+ fclose(file);
+
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
+ "filesystem (are you sure to have the right param line?)\n",
+ prog_name);
+}
+
+char *
+get_devname_from_devno(int devno,int verbosity)
+{
+ kdev_t major_no,minor_no;
+ kdev_t file_major,file_minor;
+ struct stat stat_buf;
+ int rc;
+ int found;
+ char *devname;
+ char tmpname[MAX_FILELEN];
+
+ DIR *dp;
+ struct dirent *direntp;
+
+ /**** get minor number ****/
+ get_xno_from_xno(&devno,&major_no,&minor_no,GIVEN_DEVNO);
+
+ /**** get device file ****/
+ if ((dp=opendir(SLASHDEV)) == NULL)
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: unable to read " SLASHDEV \
+ "\n",prog_name);
+ found=0;
+ while ((direntp=readdir(dp)) != NULL) {
+ strcpy(tmpname,SLASHDEV);
+ strcat(tmpname,direntp->d_name);
+ rc=stat(tmpname,&stat_buf);
+ if (!rc) {
+ file_major=MAJOR(stat_buf.st_rdev);
+ file_minor=MINOR(stat_buf.st_rdev);
+ if ((file_major==major_no) && (file_minor==minor_no)) {
+ found=1;
+ break;
+ }
+ }
+ }
+ if (found) {
+ devname=malloc(strlen(direntp->d_name));
+ strcpy(devname,tmpname);
+ }
+ rc=closedir(dp);
+ if (rc<0) ERRMSG("%s: unable to close directory " SLASHDEV \
+ "; continuing\n",prog_name);
+ if (found)
+ return devname;
+
+ if (verbosity>=1)
+ printf("I didn't find device node in " SLASHDEV \
+ "; trying to create a temporary node\n");
+
+ /**** get temp file and create device node *****/
+ rc=mkstemp(tempfilename);
+ if (rc==-1)
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to get temporary " \
+ "filename: %s\n",prog_name,strerror(errno));
+ close(rc);
+ rc=unlink(tempfilename);
+
+ rc=mknod(tempfilename,S_IFBLK|0600,MKDEV(major_no,minor_no));
+ if (rc)
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to create temporary " \
+ "device node %s: %s\n",prog_name,tempfilename,
+ strerror(errno));
+ return tempfilename;
+}
+
+char *
+check_param(int mode,format_data_t data)
+{
+ char *s;
+
+ if (NULL==(s=malloc(ERR_LENGTH)))
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: not enough memory.\n",prog_name);
+
+ if ((mode&CHECK_START)&&(data.start_unit<0)) {
+ strcpy(s,"start track must be greater than zero");
+ goto exit;
+ }
+ if ((mode&CHECK_END)&&(data.stop_unit<-1)) {
+ strcpy(s,"end track must be -1 or greater than zero");
+ goto exit;
+ }
+ if ((mode&CHECK_END)&&(data.start_unit>data.stop_unit)&&
+ (data.stop_unit!=-1)) {
+ strcpy(s,"end track must be higher than start track");
+ goto exit;
+ }
+
+ if ((mode&CHECK_BLKSIZE)&&(data.blksize<1)) {
+ strcpy(s,"blocksize must be a positive integer");
+ goto exit;
+ }
+ if (mode&CHECK_BLKSIZE) while (data.blksize>0) {
+ if ((data.blksize%2)&&(data.blksize!=1)) {
+ strcpy(s,"blocksize must be a power of 2");
+ goto exit;
+ }
+ data.blksize/=2;
+ }
+
+ free(s);
+ return NULL;
+exit:
+ return s;
+}
+
+#define ASK_PRINTOUT printf("Please enter %s",output)
+#define ASK_GETBUFFER fgets(buffer,sizeof(buffer),stdin)
+#define ASK_SCANFORNUMBER(var) rc=sscanf(buffer,"%d%c",&var,&c)
+#define ASK_COMPLAIN_FORMAT if ((rc==2)&&(c=='\n')) rc=1; \
+ if (rc==-1) rc=1; /* this happens, if enter is pressed */ \
+ if (rc!=1) printf(" -- wrong input, try again.\n")
+#define ASK_CHECK_PARAM(mode) str=check_param(mode,params); \
+ if (str!=NULL) { printf(" -- %s\n",str); rc=0; free(str); }
+
+format_data_t
+ask_user_for_data(format_data_t params)
+{
+ char buffer[20]; /* should be enough for inputing track numbers */
+ char c;
+ int i,rc;
+ char *str;
+ char output[60],o2[12];
+
+#ifdef RANGE_FORMATTING
+ i=params.start_unit;
+ do {
+ params.start_unit=i;
+ sprintf(output,"the start track of the range to format " \
+ "[%d]: ",i);
+ ASK_PRINTOUT;
+ ASK_GETBUFFER;
+ ASK_SCANFORNUMBER(params.start_unit);
+ ASK_COMPLAIN_FORMAT;
+ ASK_CHECK_PARAM(CHECK_START);
+ } while (rc!=1);
+
+ i=params.stop_unit;
+ do {
+ params.stop_unit=i;
+ sprintf(output,"the end track of the range to format [");
+ if (i==-1) sprintf(o2,"END]: "); else
+ sprintf(o2,"%d]: ",i);
+ strcat(output,o2);
+ ASK_PRINTOUT;
+ ASK_GETBUFFER;
+ if ( (!strcasecmp(buffer,"end")) ||
+ (!strcasecmp(buffer,"end\n")) ) {
+ rc=1;
+ params.stop_unit=-1;
+ } else {
+ ASK_SCANFORNUMBER(params.stop_unit);
+ ASK_COMPLAIN_FORMAT;
+ ASK_CHECK_PARAM(CHECK_END);
+ }
+ } while (rc!=1);
+#endif /* RANGE_FORMATTING */
+
+ i=params.blksize;
+ do {
+ params.blksize=i;
+ sprintf(output,"the blocksize of the formatting [%d]: ",i);
+ ASK_PRINTOUT;
+ ASK_GETBUFFER;
+ ASK_SCANFORNUMBER(params.blksize);
+ ASK_COMPLAIN_FORMAT;
+ ASK_CHECK_PARAM(CHECK_BLKSIZE);
+ } while (rc!=1);
+
+ return params;
+}
+
+/* Check if the device we are going to format is mounted.
+ * If true, complain and exit.
+ */
+void
+check_mounted(int major, int minor)
+{
+ FILE *f;
+ int ishift = 0;
+ struct mntent *ment;
+ struct stat stbuf;
+ char line[128];
+
+ /* If whole disk to be formatted ... */
+ if ((minor % (1U << DASD_PARTN_BITS)) == 0) {
+ /* ... ignore partition-selector */
+ minor >>= DASD_PARTN_BITS;
+ ishift = DASD_PARTN_BITS;
+ }
+ /*
+ * first, check filesystems
+ */
+ if (!(f = fopen(PROC_MOUNTS, "r")))
+ ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS,
+ strerror(errno));
+ while ((ment = getmntent(f))) {
+ if (stat(ment->mnt_fsname, &stbuf) == 0)
+ if ((major == MAJOR(stbuf.st_rdev)) &&
+ (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
+ ERRMSG("%s: device is mounted on %s!!\n",
+ prog_name,ment->mnt_dir);
+ ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
+ "format it, please unmount it.\n");
+ }
+ }
+ fclose(f);
+ /*
+ * second, check active swap spaces
+ */
+ if (!(f = fopen(PROC_SWAPS, "r")))
+ ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno));
+ /*
+ * skip header line
+ */
+ fgets(line, sizeof(line), f);
+ while (fgets(line, sizeof(line), f)) {
+ char *p;
+ for (p = line; *p && (!isspace(*p)); p++) ;
+ *p = '\0';
+ if (stat(line, &stbuf) == 0)
+ if ((major == MAJOR(stbuf.st_rdev)) &&
+ (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
+ ERRMSG("%s: the device is in use for "
+ "swapping!!\n",prog_name);
+ ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
+ "format it, please use swapoff %s.\n",
+ line);
+ }
+ }
+ fclose(f);
+}
+
+void
+do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
+ int verbosity,int writenolabel,int labelspec,
+ char *label,int withoutprompt,int devno)
+{
+ int fd,rc;
+ struct stat stat_buf;
+ kdev_t minor_no,major_no;
+ int new_blksize;
+ unsigned int label_position;
+ struct hd_geometry new_geometry;
+ char inp_buffer[5]; /* to contain yes */
+
+ fd=open(dev_name,O_RDWR);
+ if (fd==-1)
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: error opening device %s: " \
+ "%s\n",prog_name,dev_name,strerror(errno));
+
+ if (verbosity>=1) {
+ }
+
+ rc=stat(dev_name,&stat_buf);
+ if (rc) {
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: error occured during stat: " \
+ "%s\n",prog_name,strerror(errno));
+ } else {
+ if (!S_ISBLK(stat_buf.st_mode))
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: file is not a " \
+ "blockdevice.\n",prog_name);
+ major_no=MAJOR(stat_buf.st_rdev);
+ minor_no=MINOR(stat_buf.st_rdev);
+ }
+ check_mounted(major_no, minor_no);
+
+ if ((!writenolabel) && (!labelspec)) {
+ sprintf(label,"LNX1 x%04x",devno);
+ }
+
+ if ( ((withoutprompt)&&(verbosity>=1)) ||
+ (!withoutprompt) ) {
+ get_xno_from_xno(&devno,&major_no,&minor_no,
+ GIVEN_MAJOR|GIVEN_MINOR);
+ printf("\nI am going to format the device %s in the " \
+ "following way:\n",dev_name);
+ printf(" Device number of device : 0x%x\n",devno);
+ printf(" Major number of device : %u\n",major_no);
+ printf(" Minor number of device : %u\n",minor_no);
+ printf(" Labelling device : %s\n",(writenolabel)?
+ "no":"yes");
+ if (!writenolabel)
+ printf(" Disk label : %s\n",label);
+#ifdef RANGE_FORMATTING
+ printf(" Start track : %d\n" \
+ ,format_params.start_unit);
+ printf(" End track : ");
+ if (format_params.stop_unit==-1)
+ printf("last track of disk\n");
+ else
+ printf("%d\n",format_params.stop_unit);
+#endif /* RANGE_FORMATTING */
+ printf(" Blocksize : %d\n" \
+ ,format_params.blksize);
+ if (testmode) printf("Test mode active, omitting ioctl.\n");
+ }
+
+ while (!testmode) {
+ if (!withoutprompt) {
+ printf("\n--->> ATTENTION! <<---\n");
+ printf("All data in the specified range of that " \
+ "device will be lost.\nType \"yes\" to " \
+ "continue, no will leave the disk untouched: ");
+ fgets(inp_buffer,sizeof(inp_buffer),stdin);
+ if (strcasecmp(inp_buffer,"yes") &&
+ strcasecmp(inp_buffer,"yes\n")) {
+ printf("Omitting ioctl call (disk will " \
+ "NOT be formatted).\n");
+ break;
+ }
+ }
+
+ if ( !( (withoutprompt)&&(verbosity<1) ))
+ printf("Formatting the device. This may take a " \
+ "while (get yourself a coffee).\n");
+ rc=ioctl(fd,BIODASDFORMAT,format_params);
+ if (rc)
+ ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
+ "returned with the following error " \
+ "message:\n%s\n",prog_name,strerror(errno));
+ printf("Finished formatting the device.\n");
+
+ if (!writenolabel) {
+ if (verbosity>0)
+ printf("Retrieving disk geometry... ");
+
+ rc=ioctl(fd,HDIO_GETGEO,&new_geometry);
+ if (rc) {
+ ERRMSG("%s: the ioctl call to get geometry " \
+ "returned with the following error " \
+ "message:\n%s\n",prog_name,
+ strerror(errno));
+ goto reread;
+ }
+
+
+ rc=ioctl(fd,BLKGETSIZE,&new_blksize);
+ if (rc) {
+ ERRMSG("%s: the ioctl call to get blocksize " \
+ "returned with the following error " \
+ "message:\n%s\n",prog_name,
+ strerror(errno));
+ goto reread;
+ }
+
+ if (verbosity>0) printf("done\n");
+
+ label_position=new_geometry.start*new_blksize;
+
+ if (verbosity>0) printf("Writing label... ");
+ convert_label(label);
+ rc=lseek(fd,label_position,SEEK_SET);
+ if (rc!=label_position) {
+ ERRMSG("%s: lseek on the device to %i " \
+ "failed with the following error " \
+ "message:\n%s\n",prog_name,
+ label_position,strerror(errno));
+ goto reread;
+ }
+ rc=write(fd,label,LABEL_LENGTH);
+ if (rc!=LABEL_LENGTH) {
+ ERRMSG("%s: writing the label only wrote %d " \
+ "bytes.\n",prog_name,rc);
+ goto reread;
+ }
+
+ sync();
+ sync();
+
+ if (verbosity>0) printf("done\n");
+ }
+ reread:
+ printf("Rereading the partition table... ");
+ rc=ioctl(fd,BLKRRPART,NULL);
+ if (rc) {
+ ERRMSG("%s: error during rereading the partition " \
+ "table: %s.\n",prog_name,strerror(errno));
+ } else printf("done.\n");
+
+ break;
+ }
+
+ rc=close(fd);
+ if (rc)
+ ERRMSG("%s: error during close: " \
+ "%s; continuing.\n",prog_name,strerror(errno));
+}
+
+
+
+int main(int argc,char *argv[]) {
+ int verbosity;
+ int testmode;
+ int withoutprompt;
+ int writenolabel,labelspec;
+
+ char *dev_name;
+ int devno;
+ char *dev_filename,*devno_param_str,*range_param_str;
+ char *start_param_str,*end_param_str,*blksize_param_str;
+ char label[LABEL_LENGTH+1];
+
+ format_data_t format_params;
+
+ int rc;
+ int oc;
+ char *endptr;
+
+ char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
+ int i,i1,i2;
+ char *str;
+
+ int start_specified,end_specified,blksize_specified;
+ int devfile_specified,devno_specified,range_specified;
+
+ /******************* initialization ********************/
+ prog_name=argv[0];
+
+ endptr=NULL;
+
+ /* set default values */
+ format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
+ format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
+ format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
+ format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
+ testmode=0;
+ verbosity=0;
+ withoutprompt=0;
+ writenolabel=0;
+ labelspec=0;
+ for (i=0;i<LABEL_LENGTH;i++) label[i]=' ';
+ label[LABEL_LENGTH]=0;
+
+ start_specified=end_specified=blksize_specified=0;
+ devfile_specified=devno_specified=range_specified=0;
+
+ /*************** parse parameters **********************/
+
+ /* avoid error message generated by getopt */
+ opterr=0;
+
+#ifdef RANGE_FORMATTING
+ while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) {
+#endif /* RANGE_FORMATTING */
+ while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) {
+ switch (oc) {
+ case 'y':
+ withoutprompt=1;
+ break;
+
+ case 't':
+ testmode=1;
+ break;
+
+ case 'v':
+ verbosity++;
+ break;
+
+ case '?': /* fall-through */
+ case ':':
+ exit_usage(EXIT_MISUSE);
+
+ case 'h':
+ exit_usage(0);
+
+ case 'V':
+ printf("%s version 0.99\n",prog_name);
+ exit(0);
+
+ case 'l':
+ strncpy(label,optarg,LABEL_LENGTH);
+ if (strlen(optarg)<LABEL_LENGTH)
+ label[strlen(optarg)]=' ';
+ labelspec++;
+ break;
+
+ case 'L':
+ writenolabel++;
+ break;
+
+#ifdef RANGE_FORMATTING
+ case 's' :
+ start_param_str=optarg;
+ start_specified++;
+ break;
+
+ case 'e' :
+ end_param_str=optarg;
+ end_specified++;
+ break;
+
+ case 'r' :
+ range_param_str=optarg;
+ range_specified++;
+ break;
+#endif /* RANGE_FORMATTING */
+
+ case 'b' :
+ blksize_param_str=optarg;
+ blksize_specified++;
+ break;
+
+ case 'n' :
+ devno_param_str=optarg;
+ devno_specified++;
+ break;
+
+ case 'f' :
+ dev_filename=optarg;
+ devfile_specified++;
+ break;
+ }
+ }
+
+ /******************** checking of parameters **************/
+
+ /* convert range into -s and -e */
+ CHECK_SPEC_MAX_ONCE(range_specified,"formatting range");
+
+ while (range_specified) {
+ start_specified++;
+ end_specified++;
+
+ /* scan for 1 or 2 integers, separated by a dash */
+ rc=sscanf(range_param_str,"%d%c%d%c",&i1,&c1,&i2,&c2);
+ if ((rc==3)&&(c1=='-')) {
+ format_params.start_unit=i1;
+ format_params.stop_unit=i2;
+ break;
+ }
+ if (rc==1) {
+ format_params.start_unit=i1;
+ break;
+ }
+
+ /* scan for integer and -END */
+ rc=sscanf(range_param_str,"%d%s",&i1,cbuffer);
+ if ((rc==2)&&(!strcasecmp(cbuffer,"-END"))) {
+ format_params.start_unit=i1;
+ format_params.stop_unit=-1;
+ break;
+ }
+ ERRMSG_EXIT(EXIT_MISUSE,"%s: specified range " \
+ "is in invalid format\n",prog_name);
+ }
+
+ if ((!devfile_specified)&&(!devno_specified))
+ ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
+ "not specified\n",prog_name);
+
+ if ((devfile_specified+devno_specified)>1)
+ ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
+ "can only be specified once\n",prog_name);
+
+ if ((!start_specified)&&(!end_specified)&&(!range_specified)&&
+ (!blksize_specified)) {
+ format_params=ask_user_for_data(format_params);
+ }
+
+ CHECK_SPEC_MAX_ONCE(start_specified,"start track");
+ CHECK_SPEC_MAX_ONCE(end_specified,"end track");
+ CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
+ CHECK_SPEC_MAX_ONCE(labelspec,"label");
+ CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag");
+
+ if (devno_specified)
+ PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
+ if (start_specified&&!range_specified)
+ PARSE_PARAM_INTO(format_params.start_unit,start_param_str,10,
+ "start track");
+ if (end_specified&&!range_specified)
+ PARSE_PARAM_INTO(format_params.stop_unit,end_param_str,10,
+ "end track");
+ if (blksize_specified)
+ PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
+ "blocksize");
+
+ /***********get dev_name *********************/
+ dev_name=(devno_specified)?
+ get_devname_from_devno(devno,verbosity):
+ dev_filename;
+
+ /*** range checking *********/
+ str=check_param(CHECK_ALL,format_params);
+ if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
+
+ /******* issue the real command and reread part table *******/
+ do_format_dasd(dev_name,format_params,testmode,verbosity,
+ writenolabel,labelspec,label,withoutprompt,devno);
+
+ /*************** cleanup ********************************/
+ if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
+ rc=unlink(dev_name);
+ if ((rc)&&(verbosity>=1))
+ ERRMSG("%s: temporary device node %s could not be " \
+ "removed: %s\n",prog_name,dev_name,
+ strerror(errno));
+ } else {
+ if (devno_specified) {
+ /* so we have allocated space for the filename */
+ free(dev_name);
+ }
+ }
+
+ return 0;
+}
diff --git a/arch/s390x/tools/silo/Makefile b/arch/s390x/tools/silo/Makefile
new file mode 100644
index 000000000..62b11d7da
--- /dev/null
+++ b/arch/s390x/tools/silo/Makefile
@@ -0,0 +1,15 @@
+all: silo
+
+silo.o: silo.c
+ $(CC) -c -o silo.o -O2 silo.c
+
+cfg.o: cfg.c
+ $(CC) -c -o cfg.o -O2 cfg.c
+
+silo: silo.o cfg.o
+ $(CC) -o $@ $^
+ $(STRIP) $@
+
+clean:
+ rm -f *.o silo
+
diff --git a/arch/s390x/tools/silo/cfg.c b/arch/s390x/tools/silo/cfg.c
new file mode 100644
index 000000000..2b11d93b8
--- /dev/null
+++ b/arch/s390x/tools/silo/cfg.c
@@ -0,0 +1,373 @@
+/* cfg.c - Configuration file parser */
+
+/* Copyright 1992-1997 Werner Almesberger. See file COPYING for details. */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "cfg.h"
+
+#define MAX_TOKEN 200
+#define MAX_VAR_NAME MAX_TOKEN
+
+static FILE *file;
+static char flag_set;
+static char *last_token = NULL,*last_item = NULL,*last_value = NULL;
+static int line_num;
+static char *file_name = NULL;
+static int back = 0; /* can go back by one char */
+
+
+void pdie(char *msg)
+{
+ fflush(stdout);
+ perror(msg);
+ exit(1);
+}
+
+
+void die(char *fmt,...)
+{
+ va_list ap;
+
+ fflush(stdout);
+ va_start(ap,fmt);
+ vfprintf(stderr,fmt,ap);
+ va_end(ap);
+ fputc('\n',stderr);
+ exit(1);
+}
+
+char *pstrdup(const char *str)
+{
+ char *this;
+
+ if ((this = strdup(str)) == NULL) pdie("Out of memory");
+ return this;
+}
+
+int cfg_open(char *name)
+{
+ if (!strcmp(name,"-")) file = stdin;
+ else if (!(file = fopen(file_name = name,"r"))) pdie(name);
+ line_num = 1;
+ return fileno(file);
+}
+
+void cfg_error(char *msg,...)
+{
+ va_list ap;
+
+ fflush(stdout);
+ va_start(ap,msg);
+ vfprintf(stderr,msg,ap);
+ va_end(ap);
+ if (!file_name) fputc('\n',stderr);
+ else fprintf(stderr," near line %d in file %s\n",line_num,file_name);
+ exit(1);
+}
+
+
+static int next_raw(void)
+{
+ int ch;
+
+ if (!back) return getc(file);
+ ch = back;
+ back = 0;
+ return ch;
+}
+
+
+static int next(void)
+{
+ static char *var;
+ char buffer[MAX_VAR_NAME+1];
+ int ch,braced;
+ char *put;
+
+ if (back) {
+ ch = back;
+ back = 0;
+ return ch;
+ }
+ if (var && *var) return *var++;
+ ch = getc(file);
+ if (ch == '\\') {
+ ch = getc(file);
+ if (ch == '$') return ch;
+ ungetc(ch,file);
+ return '\\';
+ }
+ if (ch != '$') return ch;
+ ch = getc(file);
+ braced = ch == '{';
+ put = buffer;
+ if (!braced) *put++ = ch;
+ while (1) {
+ ch = getc(file);
+#if 0
+ if (!braced && ch < ' ') {
+ ungetc(ch,file);
+ break;
+ }
+#endif
+ if (ch == EOF) cfg_error("EOF in variable name");
+ if (ch < ' ') cfg_error("control character in variable name");
+ if (braced && ch == '}') break;
+ if (!braced && !isalpha(ch) && !isdigit(ch) && ch != '_') {
+ ungetc(ch,file);
+ break;
+ }
+ if (put-buffer == MAX_VAR_NAME) cfg_error("variable name too long");
+ *put++ = ch;
+ }
+ *put = 0;
+ if (!(var = getenv(buffer))) cfg_error("unknown variable \"%s\"",buffer);
+ return next();
+}
+
+
+static void again(int ch)
+{
+ if (back) die("internal error: again invoked twice");
+ back = ch;
+}
+
+
+static char *cfg_get_token(void)
+{
+ char buf[MAX_TOKEN+1];
+ char *here;
+ int ch,escaped;
+
+ if (last_token) {
+ here = last_token;
+ last_token = NULL;
+ return here;
+ }
+ while (1) {
+ while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n')
+ if (ch == '\n') line_num++;
+ if (ch == EOF) return NULL;
+ if (ch != '#') break;
+ while ((ch = next_raw()), ch != '\n')
+ if (ch == EOF) return NULL;
+ line_num++;
+ }
+ if (ch == '=') return pstrdup("=");
+ if (ch == '"') {
+ here = buf;
+ while (here-buf < MAX_TOKEN) {
+ if ((ch = next()) == EOF) cfg_error("EOF in quoted string");
+ if (ch == '"') {
+ *here = 0;
+ return pstrdup(buf);
+ }
+ if (ch == '\\') {
+ ch = next();
+ if (ch != '"' && ch != '\\' && ch != '\n')
+ cfg_error("Bad use of \\ in quoted string");
+ if (ch == '\n') {
+ while ((ch = next()), ch == ' ' || ch == '\t');
+ if (!ch) continue;
+ again(ch);
+ ch = ' ';
+ }
+ }
+ if (ch == '\n' || ch == '\t')
+ cfg_error("\\n and \\t are not allowed in quoted strings");
+ *here++ = ch;
+ }
+ cfg_error("Quoted string is too long");
+ return 0; /* not reached */
+ }
+ here = buf;
+ escaped = 0;
+ while (here-buf < MAX_TOKEN) {
+ if (escaped) {
+ if (ch == EOF) cfg_error("\\ precedes EOF");
+ if (ch == '\n') line_num++;
+ else *here++ = ch == '\t' ? ' ' : ch;
+ escaped = 0;
+ }
+ else {
+ if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
+ ch == '=' || ch == EOF) {
+ again(ch);
+ *here = 0;
+ return pstrdup(buf);
+ }
+ if (!(escaped = (ch == '\\'))) *here++ = ch;
+ }
+ ch = next();
+ }
+ cfg_error("Token is too long");
+ return 0; /* not reached */
+}
+
+
+static void cfg_return_token(char *token)
+{
+ last_token = token;
+}
+
+
+static int cfg_next(char **item,char **value)
+{
+ char *this;
+
+ if (last_item) {
+ *item = last_item;
+ *value = last_value;
+ last_item = NULL;
+ return 1;
+ }
+ *value = NULL;
+ if (!(*item = cfg_get_token())) return 0;
+ if (!strcmp(*item,"=")) cfg_error("Syntax error");
+ if (!(this = cfg_get_token())) return 1;
+ if (strcmp(this,"=")) {
+ cfg_return_token(this);
+ return 1;
+ }
+ if (!(*value = cfg_get_token())) cfg_error("Value expected at EOF");
+ if (!strcmp(*value,"=")) cfg_error("Syntax error after %s",*item);
+ return 1;
+}
+
+
+static void cfg_return(char *item,char *value)
+{
+ last_item = item;
+ last_value = value;
+}
+
+
+void cfg_init(CONFIG *table)
+{
+ while (table->type != cft_end) {
+ switch (table->type) {
+ case cft_strg:
+ if (table->data) free(table->data);
+ case cft_flag:
+ table->data = NULL;
+ break;
+ case cft_link:
+ table = ((CONFIG *) table->action)-1;
+ break;
+ default:
+ die("Unknown syntax code %d",table->type);
+ }
+ table++;
+ }
+}
+
+
+static int cfg_do_set(CONFIG *table,char *item,char *value,int copy,
+ void *context)
+{
+ CONFIG *walk;
+
+ for (walk = table; walk->type != cft_end; walk++) {
+ if (walk->name && !strcasecmp(walk->name,item)) {
+ if (value && walk->type != cft_strg)
+ cfg_error("'%s' doesn't have a value",walk->name);
+ if (!value && walk->type == cft_strg)
+ cfg_error("Value expected for '%s'",walk->name);
+ if (walk->data) {
+ if (walk->context == context)
+ cfg_error("Duplicate entry '%s'",walk->name);
+ else {
+ fprintf(stderr,"Ignoring entry '%s'\n",walk->name);
+ if (!copy) free(value);
+ return 1;
+ }
+ }
+ if (walk->type == cft_flag) walk->data = &flag_set;
+ else if (walk->type == cft_strg) {
+ if (copy) walk->data = pstrdup(value);
+ else walk->data = value;
+ }
+ walk->context = context;
+ if (walk->action) ((void (*)(void)) walk->action)();
+ break;
+ }
+ if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
+ }
+ if (walk->type != cft_end) return 1;
+ cfg_return(item,value);
+ return 0;
+}
+
+
+void cfg_set(CONFIG *table,char *item,char *value,void *context)
+{
+ if (!cfg_do_set(table,item,value,1,context))
+ cfg_error("cfg_set: Can't set %s",item);
+}
+
+
+void cfg_unset(CONFIG *table,char *item)
+{
+ CONFIG *walk;
+
+ for (walk = table; walk->type != cft_end; walk++)
+ if (walk->name && !strcasecmp(walk->name,item)) {
+ if (!walk->data) die("internal error (cfg_unset %s, unset)",item);
+ if (walk->type == cft_strg) free(walk->data);
+ walk->data = NULL;
+ return;
+ }
+ die("internal error (cfg_unset %s, unknown",item);
+}
+
+
+int cfg_parse(CONFIG *table)
+{
+ char *item,*value;
+
+ while (1) {
+ if (!cfg_next(&item,&value)) return 0;
+ if (!cfg_do_set(table,item,value,0,table)) return 1;
+ free(item);
+ }
+}
+
+
+int cfg_get_flag(CONFIG *table,char *item)
+{
+ CONFIG *walk;
+
+ for (walk = table; walk->type != cft_end; walk++) {
+ if (walk->name && !strcasecmp(walk->name,item)) {
+ if (walk->type != cft_flag)
+ die("cfg_get_flag: operating on non-flag %s",item);
+ return !!walk->data;
+ }
+ if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
+ }
+ die("cfg_get_flag: unknown item %s",item);
+ return 0; /* not reached */
+}
+
+
+char *cfg_get_strg(CONFIG *table,char *item)
+{
+ CONFIG *walk;
+
+ for (walk = table; walk->type != cft_end; walk++) {
+ if (walk->name && !strcasecmp(walk->name,item)) {
+ if (walk->type != cft_strg)
+ die("cfg_get_strg: operating on non-string %s",item);
+ return walk->data;
+ }
+ if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
+ }
+ die("cfg_get_strg: unknown item %s",item);
+ return 0; /* not reached */
+}
diff --git a/arch/s390x/tools/silo/cfg.h b/arch/s390x/tools/silo/cfg.h
new file mode 100644
index 000000000..97d10bf73
--- /dev/null
+++ b/arch/s390x/tools/silo/cfg.h
@@ -0,0 +1,58 @@
+/* cfg.h - Configuration file parser */
+
+/* Copyright 1992-1996 Werner Almesberger. See file COPYING for details. */
+
+
+#ifndef CFG_H
+#define CFG_H
+
+typedef enum { cft_strg, cft_flag, cft_link, cft_end } CFG_TYPE;
+
+typedef struct {
+ CFG_TYPE type;
+ char *name;
+ void *action;
+ void *data;
+ void *context;
+} CONFIG;
+
+extern int cfg_open(char *name);
+
+/* Opens the configuration file. Returns the file descriptor of the open
+ file. */
+
+extern void cfg_error(char *msg,...);
+
+/* Signals an error while parsing the configuration file and terminates the
+ program. */
+
+extern void cfg_init(CONFIG *table);
+
+/* Initializes the specified table. */
+
+extern void cfg_set(CONFIG *table,char *item,char *value,void *context);
+
+/* Sets the specified variable in table. If the variable has already been set
+ since the last call to cfg_init, a warning message is issued if the context
+ keys don't match or a fatal error is reported if they do. */
+
+extern void cfg_unset(CONFIG *table,char *item);
+
+/* Unsets the specified variable in table. It is a fatal error if the variable
+ was not set. */
+
+extern int cfg_parse(CONFIG *table);
+
+/* Parses the configuration file for variables contained in table. A non-zero
+ value is returned if a variable not found in table has been met. Zero is
+ returned if EOF has been reached. */
+
+extern int cfg_get_flag(CONFIG *table,char *item);
+
+/* Returns one if the specified variable is set, zero if it isn't. */
+
+extern char *cfg_get_strg(CONFIG *table,char *item);
+
+/* Returns the value of the specified variable if it is set, NULL otherwise. */
+
+#endif
diff --git a/arch/s390x/tools/silo/silo.c b/arch/s390x/tools/silo/silo.c
new file mode 100644
index 000000000..9ac04ac2b
--- /dev/null
+++ b/arch/s390x/tools/silo/silo.c
@@ -0,0 +1,573 @@
+/*
+ * arch/s390/boot/silo.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *
+ * Report bugs to: <linux390@de.ibm.com>
+ *
+ * Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Fritz Elfert <felfert@to.com> contributed support for
+ * /etc/silo.conf based on Intel's lilo
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <dirent.h>
+#include <linux/fs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <asm/ioctl.h>
+
+#include "cfg.h"
+
+CONFIG cf_options[] = {
+ { cft_strg, "append", NULL, NULL,NULL },
+ { cft_strg, "image", NULL, NULL,NULL },
+ { cft_strg, "ipldevice", NULL, NULL,NULL },
+ { cft_strg, "bootsect", NULL, NULL,NULL },
+ { cft_strg, "map", NULL, NULL,NULL },
+ { cft_strg, "parmfile", NULL, NULL,NULL },
+ { cft_strg, "ramdisk", NULL, NULL,NULL },
+ { cft_strg, "root", NULL, NULL,NULL },
+ { cft_flag, "readonly", NULL, NULL,NULL },
+ { cft_strg, "verbose", NULL, NULL,NULL },
+ { cft_strg, "testlevel", NULL, NULL,NULL },
+ { cft_end, NULL, NULL, NULL,NULL }
+};
+
+/* from dasd.h */
+#define DASD_PARTN_BITS 2
+#define BIODASDRWTB _IOWR('D',0,int)
+/* end */
+
+#define SILO_CFG "/etc/silo.conf"
+#define SILO_IMAGE "./image"
+#define SILO_BOOTMAP "./boot.map"
+#define SILO_PARMFILE "./parmfile"
+#define SILO_BOOTSECT "/boot/ipleckd.boot"
+
+#define PRINT_LEVEL(x,y...) if ( silo_options.verbosity >= x ) printf(y)
+#define ERROR_LEVEL(x,y...) if ( silo_options.verbosity >= x ) fprintf(stderr,y)
+#define TOGGLE(x) ((x)=((x)?(0):(1)))
+#define GETARG(x) {int len=strlen(optarg);x=malloc(len);strncpy(x,optarg,len);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
+
+#define ITRY(x) if ( (x) == -1 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
+#define NTRY(x) if ( (x) == 0 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
+
+#define MAX_CLUSTERS 256
+#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
+
+#define SILO_VERSION "1.1"
+
+struct silo_options
+ {
+ short int verbosity;
+ short int testlevel;
+ char *image;
+ char *ipldevice;
+ char *parmfile;
+ char *ramdisk;
+ char *bootsect;
+ char *conffile;
+ char *bootmap;
+ }
+silo_options =
+{
+ 1, /* verbosity */
+ 2, /* testlevel */
+ SILO_IMAGE, /* image */
+ NULL, /* ipldevice */
+ SILO_PARMFILE, /* parmfile */
+ NULL, /* initrd */
+ SILO_BOOTSECT, /* bootsector */
+ SILO_CFG, /* silo.conf file */
+ SILO_BOOTMAP, /* boot.map */
+};
+
+struct blockdesc
+ {
+ unsigned long off;
+ unsigned short ct;
+ unsigned long addr;
+ };
+
+struct blocklist
+ {
+ struct blockdesc blk[MAX_CLUSTERS];
+ unsigned short ix;
+ };
+
+void
+usage (void)
+{
+ printf ("Usage:\n");
+ printf ("silo -d ipldevice [additional options]\n");
+ printf ("-d /dev/node : set ipldevice to /dev/node\n");
+ printf ("-f image : set image to image\n");
+ printf ("-F conffile : specify configuration file (/etc/silo.conf)\n");
+ printf ("-p parmfile : set parameter file to parmfile\n");
+ printf ("-b bootsect : set bootsector to bootsect\n");
+ printf ("Additional options\n");
+ printf ("-B bootmap:\n");
+ printf ("-v: increase verbosity level\n");
+ printf ("-v#: set verbosity level to #\n");
+ printf ("-t: decrease testing level\n");
+ printf ("-h: print this message\n");
+ printf ("-?: print this message\n");
+ printf ("-V: print version\n");
+}
+
+int
+read_cfg(struct silo_options *o)
+{
+ char *tmp;
+ if (access(o->conffile, R_OK) && (errno == ENOENT))
+ return 0;
+ /* If errno != ENOENT, let cfg_open report an error */
+ cfg_open(o->conffile);
+ cfg_parse(cf_options);
+ tmp = cfg_get_strg(cf_options, "ipldevice");
+ if ( ! o->ipldevice && tmp )
+ o->ipldevice = tmp;
+ tmp = cfg_get_strg(cf_options, "image");
+ if ( ! strncmp(o-> image,SILO_IMAGE,strlen(SILO_IMAGE)) && tmp )
+ o->image = tmp;
+ tmp = cfg_get_strg(cf_options, "parmfile");
+ if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp)
+ o->parmfile = tmp;
+ if ( ! o -> ramdisk )
+ o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
+ tmp = cfg_get_strg(cf_options, "bootsect");
+ if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp)
+ o->bootsect = tmp;
+ tmp = cfg_get_strg(cf_options, "map") ;
+ if ( !strncmp(o -> bootmap,SILO_BOOTMAP,strlen(SILO_BOOTMAP)) && tmp)
+ o->bootmap = tmp;
+ tmp = cfg_get_strg(cf_options, "verbose");
+ if ( tmp ) {
+ unsigned short v;
+ sscanf (tmp, "%hu", &v);
+ o->verbosity = v;
+ }
+ tmp = cfg_get_strg(cf_options, "testlevel");
+ if ( tmp ) {
+ unsigned short t;
+ sscanf (tmp, "%hu", &t);
+ o->testlevel += t;
+ }
+ return 1;
+}
+
+char *
+gen_tmpparm( char *pfile )
+{
+ char *append = cfg_get_strg(cf_options, "append");
+ char *root = cfg_get_strg(cf_options, "root");
+ int ro = cfg_get_flag(cf_options, "readonly");
+ FILE *f,*of;
+ char *fn;
+ char c;
+ char *tmpdir=NULL,*save=NULL;
+
+ if (!append && !root && !ro)
+ return pfile;
+ of = fopen(pfile, "r");
+ if ( of ) {
+ NTRY( fn = tempnam(NULL,"parm."));
+ } else {
+ fn = pfile;
+ }
+ NTRY( f = fopen(fn, "a+"));
+ if ( of ) {
+ while ( ! feof (of) ) {
+ c=fgetc(of);
+ fputc(c,f);
+ }
+ }
+ if (root)
+ fprintf(f, " root=%s", root);
+ if (ro)
+ fprintf(f, " ro");
+ if (append)
+ fprintf(f, " %s", append);
+ fprintf(f, "\n");
+ fclose(f);
+ fclose(of);
+ printf ("tempfile is %s\n",fn);
+ return strdup(fn);
+}
+
+int
+parse_options (struct silo_options *o, int argc, char *argv[])
+{
+ int rc = 0;
+ int oc;
+
+ while ((oc = getopt (argc, argv, "Vf:F:d:p:r:b:B:h?v::t::")) != -1)
+ {
+ switch (oc)
+ {
+ case 'V':
+ printf("silo version: %s\n",SILO_VERSION);
+ exit(0);
+ case 'v':
+ {
+ unsigned short v;
+ if (optarg && sscanf (optarg, "%hu", &v))
+ o->verbosity = v;
+ else
+ o->verbosity++;
+ PRINT_LEVEL (1, "Verbosity value is now %hu\n", o->verbosity);
+ break;
+ }
+ case 't':
+ {
+ unsigned short t;
+ if (optarg && sscanf (optarg, "%hu", &t))
+ o->testlevel -= t;
+ else
+ o->testlevel--;
+ PRINT_LEVEL (1, "Testonly flag is now %d\n", o->testlevel);
+ break;
+ }
+ case 'h':
+ case '?':
+ usage ();
+ exit(0);
+ case 'd':
+ GETARG (o->ipldevice);
+ break;
+ case 'f':
+ GETARG (o->image);
+ break;
+ case 'F':
+ GETARG (o->conffile);
+ break;
+ case 'p':
+ GETARG (o->parmfile);
+ break;
+ case 'r':
+ GETARG (o->ramdisk);
+ break;
+ case 'b':
+ GETARG (o->bootsect);
+ break;
+ case 'B':
+ GETARG (o->bootmap);
+ default:
+ rc = EINVAL;
+ break;
+ }
+ }
+ read_cfg(o);
+ return rc;
+}
+
+int
+verify_device (char *name)
+{
+ int rc = 0;
+ struct stat dst;
+ struct stat st;
+ ITRY (stat (name, &dst));
+ if (S_ISBLK (dst.st_mode))
+ {
+ if (!(MINOR (dst.st_rdev) & PARTN_MASK))
+ {
+ rc = dst.st_rdev;
+ }
+ else
+ /* invalid MINOR & PARTN_MASK */
+ {
+ ERROR_LEVEL (1, "Cannot boot from partition %d %d %d",
+ (int) PARTN_MASK, (int) MINOR (dst.st_rdev), (int) (PARTN_MASK & MINOR (dst.st_rdev)));
+ rc = -1;
+ errno = EINVAL;
+ }
+ }
+ else
+ /* error S_ISBLK */
+ {
+ ERROR_LEVEL (1, "%s is no block device\n", name);
+ rc = -1;
+ errno = EINVAL;
+ }
+ return rc;
+}
+
+int
+verify_file (char *name, int dev)
+{
+ int rc = 0;
+ struct stat dst;
+ struct stat st;
+ int bs = 1024;
+ int l;
+
+ ITRY(stat ( name, &dst ));
+ if (S_ISREG (dst.st_mode))
+ {
+ if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
+ {
+ /* whatever to do if all is ok... */
+ }
+ else
+ /* devicenumber doesn't match */
+ {
+ ERROR_LEVEL (1, "%s is not on device (%d/%d) but on (%d/%d)\n", name, (unsigned) MAJOR (dev), (unsigned) MINOR (dev), (unsigned) MAJOR (dst.st_dev), (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK));
+ rc = -1;
+ errno = EINVAL;
+ }
+ }
+ else
+ /* error S_ISREG */
+ {
+ ERROR_LEVEL (1, "%s is neither regular file nor linkto one\n", name);
+ rc = -1;
+ errno = EINVAL;
+ }
+ return rc;
+}
+
+int
+verify_options (struct silo_options *o)
+{
+ int rc = 0;
+ int dev = 0;
+ int crc = 0;
+ if (!o->ipldevice || !o->image || !o->bootsect)
+ {
+ if (!o->ipldevice)
+ fprintf(stderr,"ipldevice\n");
+ if (!o->image)
+ fprintf(stderr,"image\n");
+ if (!o->bootsect)
+ fprintf(stderr,"bootsect\n");
+
+ usage ();
+ exit (1);
+ }
+ PRINT_LEVEL (1, "Testlevel is set to %d\n",o->testlevel);
+
+ PRINT_LEVEL (1, "IPL device is: '%s'", o->ipldevice);
+ ITRY (dev = verify_device (o->ipldevice));
+ PRINT_LEVEL (2, "...ok...(%d/%d)", (unsigned short) MAJOR (dev), (unsigned short) MINOR (dev));
+ PRINT_LEVEL (1, "\n");
+
+ PRINT_LEVEL (0, "bootsector is: '%s'", o->bootsect);
+ ITRY (verify_file (o->bootsect, dev));
+ PRINT_LEVEL (1, "...ok...");
+ PRINT_LEVEL (0, "\n");
+
+ if ( o -> testlevel > 0 &&
+ ! strncmp( o->bootmap, SILO_BOOTMAP,strlen(SILO_BOOTMAP) )) {
+ NTRY( o -> bootmap = tempnam(NULL,"boot."));
+ }
+ PRINT_LEVEL (0, "bootmap is set to: '%s'", o->bootmap);
+ if ( access ( o->bootmap, O_RDWR ) == -1 ) {
+ if ( errno == ENOENT ) {
+ ITRY (creat ( o-> bootmap, O_RDWR ));
+ } else {
+ PRINT_LEVEL(1,"Cannot acces bootmap file '%s': %s\n",o->bootmap,
+ strerror(errno));
+ }
+ }
+ ITRY (verify_file (o->bootmap, dev));
+ PRINT_LEVEL (1, "...ok...");
+ PRINT_LEVEL (0, "\n");
+
+ PRINT_LEVEL (0, "Kernel image is: '%s'", o->image);
+ ITRY (verify_file (o->image, dev));
+ PRINT_LEVEL (1, "...ok...");
+ PRINT_LEVEL (0, "\n");
+
+ PRINT_LEVEL (0, "original parameterfile is: '%s'", o->parmfile);
+ ITRY (verify_file (o->parmfile, dev));
+ PRINT_LEVEL (1, "...ok...");
+ o->parmfile = gen_tmpparm(o->parmfile);
+ PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile);
+ ITRY (verify_file (o->parmfile, dev));
+ PRINT_LEVEL (1, "...ok...");
+ PRINT_LEVEL (0, "\n");
+
+ if (o->ramdisk)
+ {
+ PRINT_LEVEL (0, "initialramdisk is: '%s'", o->ramdisk);
+ ITRY (verify_file (o->ramdisk, dev));
+ PRINT_LEVEL (1, "...ok...");
+ PRINT_LEVEL (0, "\n");
+ }
+
+ return crc;
+}
+
+
+int
+add_file_to_blocklist (char *name, struct blocklist *lst, long addr)
+{
+ int fd;
+ int devfd;
+ struct stat fst;
+ int i;
+ int blk;
+ int bs;
+ int blocks;
+
+ int rc = 0;
+
+ ITRY (fd = open (name, O_RDONLY));
+ ITRY (fstat (fd, &fst));
+ ITRY (mknod ("/tmp/silodev", S_IFBLK | S_IRUSR | S_IWUSR, fst.st_dev));
+ ITRY (devfd = open ("/tmp/silodev", O_RDONLY));
+ ITRY (ioctl (fd, FIGETBSZ, &bs));
+ blocks = (fst.st_size + bs - 1) / bs;
+ for (i = 0; i < blocks; i++)
+ {
+ blk = i;
+ ITRY (ioctl (fd, FIBMAP, &blk));
+ if (blk)
+ {
+ int oldblk = blk;
+ ITRY (ioctl (devfd, BIODASDRWTB, &blk));
+ if (blk <= 0)
+ {
+ ERROR_LEVEL (0, "BIODASDRWTB on blk %d returned %d\n", oldblk, blk);
+ break;
+ }
+ }
+ else
+ {
+ PRINT_LEVEL (1, "Filled hole on blk %d\n", i);
+ }
+ if (lst->ix == 0 || i == 0 ||
+ lst->blk[lst->ix - 1].ct >= 128 ||
+ (lst->blk[lst->ix - 1].off + lst->blk[lst->ix - 1].ct != blk &&
+ !(lst->blk[lst->ix - 1].off == 0 && blk == 0)))
+ {
+ if (lst->ix >= MAX_CLUSTERS)
+ {
+ rc = 1;
+ errno = ENOMEM;
+ break;
+ }
+ lst->blk[lst->ix].off = blk;
+ lst->blk[lst->ix].ct = 1;
+ lst->blk[lst->ix].addr = addr + i * bs;
+ lst->ix++;
+ }
+ else
+ {
+ lst->blk[lst->ix - 1].ct++;
+ }
+ }
+ ITRY(unlink("/tmp/silodev"));
+ return rc;
+}
+
+int
+write_bootsect (struct silo_options *o, struct blocklist *blklst)
+{
+ int i;
+ int s_fd, d_fd, b_fd, bd_fd;
+ struct stat s_st, d_st, b_st;
+ int rc=0;
+ int bs, boots;
+ char *tmpdev;
+ char buffer[4096]={0,};
+ ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC));
+ ITRY (fstat (d_fd, &d_st));
+ ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
+ ITRY (verify_file (o->bootsect, d_st.st_rdev));
+ for (i = 0; i < blklst->ix; i++)
+ {
+ int offset = blklst->blk[i].off;
+ int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
+ PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
+ if ( o->testlevel <= 1 ) {
+ NTRY (write (s_fd, &offset, sizeof (int)));
+ NTRY (write (s_fd, &addrct, sizeof (int)));
+ }
+ }
+ ITRY (ioctl (s_fd,FIGETBSZ, &bs));
+ ITRY (stat (o->bootmap, &s_st));
+ if (s_st.st_size > bs )
+ {
+ ERROR_LEVEL (0,"%s is larger than one block\n", o->bootmap);
+ rc = -1;
+ errno = EINVAL;
+ }
+ boots=0;
+ NTRY ( tmpdev = tmpnam(NULL) );
+ ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
+ ITRY (bd_fd = open (tmpdev, O_RDONLY));
+ ITRY (ioctl(s_fd,FIBMAP,&boots));
+ ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
+ PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
+ close (bd_fd);
+ close(s_fd);
+ ITRY (unlink(tmpdev));
+ /* Now patch the bootsector */
+ ITRY (b_fd = open (o->bootsect, O_RDONLY));
+ NTRY (read (b_fd, buffer, 4096));
+ memset (buffer + 0xe0, 0, 8);
+ *(int *) (buffer + 0xe0) = boots;
+ if ( o -> testlevel <= 0 ) {
+ NTRY (write (d_fd, buffer, 4096));
+ NTRY (write (d_fd, buffer, 4096));
+ }
+ close (b_fd);
+ close (d_fd);
+ return rc;
+}
+
+int
+do_silo (struct silo_options *o)
+{
+ int rc = 0;
+
+ int device_fd;
+ int image_fd;
+ struct blocklist blklist;
+ memset (&blklist, 0, sizeof (struct blocklist));
+ ITRY (add_file_to_blocklist (o->image, &blklist, 0x00000000));
+ if (o->parmfile)
+ {
+ ITRY (add_file_to_blocklist (o->parmfile, &blklist, 0x00008000));
+ }
+ if (o->ramdisk)
+ {
+ ITRY (add_file_to_blocklist (o->ramdisk, &blklist, 0x00800000));
+ }
+ ITRY (write_bootsect (o, &blklist));
+ return rc;
+}
+
+int
+main (int argct, char *argv[])
+{
+ int rc = 0;
+ char *save=NULL;
+ char *tmpdir=getenv("TMPDIR");
+ if (tmpdir) {
+ NTRY( save=(char*)malloc(strlen(tmpdir)));
+ NTRY( strncpy(save,tmpdir,strlen(tmpdir)));
+ }
+ ITRY( setenv("TMPDIR",".",1));
+ ITRY (parse_options (&silo_options, argct, argv));
+ ITRY (verify_options (&silo_options));
+ if ( silo_options.testlevel > 0 ) {
+ printf ("WARNING: silo does not modify your volume. Use -t2 to change IPL records\n");
+ }
+ ITRY (do_silo (&silo_options));
+ if ( save )
+ ITRY( setenv("TMPDIR",save,1));
+ return rc;
+}
diff --git a/arch/s390x/tools/silo/silo.conf b/arch/s390x/tools/silo/silo.conf
new file mode 100644
index 000000000..47d8a4551
--- /dev/null
+++ b/arch/s390x/tools/silo/silo.conf
@@ -0,0 +1,7 @@
+ipldevice = /dev/dasda
+image = /boot/image
+bootsect = /boot/ipleckd.boot
+map = /boot/boot.map
+root = /dev/dasd01
+readonly
+append = "dasd=200-20f noinitrd"
diff --git a/arch/s390x/vmlinux.lds b/arch/s390x/vmlinux.lds
new file mode 100644
index 000000000..8d8ea9fcf
--- /dev/null
+++ b/arch/s390x/vmlinux.lds
@@ -0,0 +1,78 @@
+/* ld script to make s390 Linux kernel
+ * Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
+OUTPUT_ARCH(s390)
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x00000000;
+ _text = .; /* Text and read-only data */
+ .text : {
+ *(.text)
+ *(.fixup)
+ *(.gnu.warning)
+ } = 0x0700
+ .text.lock : { *(.text.lock) } /* out-of-line lock text */
+ .rodata : { *(.rodata) }
+ .kstrtab : { *(.kstrtab) }
+
+ . = ALIGN(16); /* Exception table */
+ __start___ex_table = .;
+ __ex_table : { *(__ex_table) }
+ __stop___ex_table = .;
+
+ __start___ksymtab = .; /* Kernel symbol table */
+ __ksymtab : { *(__ksymtab) }
+ __stop___ksymtab = .;
+
+ _etext = .; /* End of text section */
+
+ .data : { /* Data */
+ *(.data)
+ CONSTRUCTORS
+ }
+
+ _edata = .; /* End of data section */
+
+ . = ALIGN(16384); /* init_task */
+ .data.init_task : { *(.data.init_task) }
+
+ . = ALIGN(4096); /* Init code and data */
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+
+ __setup_start = .;
+ .setup.init : { *(.setup.init) }
+ __setup_end = .;
+ __initcall_start = .;
+ .initcall.init : { *(.initcall.init) }
+ __initcall_end = .;
+ . = ALIGN(4096);
+ __init_end = .;
+
+ . = ALIGN(32);
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+ . = ALIGN(4096);
+ .data.page_aligned : { *(.data.idt) }
+
+
+ __bss_start = .; /* BSS */
+ .bss : {
+ *(.bss)
+ }
+ _end = . ;
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 200148320..615d46148 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -22,7 +22,7 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 1ce22f0fd..a7810c914 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -24,7 +24,7 @@
#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index b6fb1e9a8..7b5d77e90 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -17,7 +17,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
index cb27cf77b..434345d1b 100644
--- a/arch/sparc/config.in
+++ b/arch/sparc/config.in
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.107 2001/01/06 00:46:44 davem Exp $
+# $Id: config.in,v 1.108 2001/02/18 09:02:59 davem Exp $
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/config-language.txt.
#
@@ -183,8 +183,8 @@ if [ "$CONFIG_SCSI" != "n" ]; then
mainmenu_option next_comment
comment 'SCSI low-level drivers'
- tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
- tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
+ dep_tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
+ dep_tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
endmenu
fi
endmenu
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index 00c465b10..d8800b0f3 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.15 2000/11/08 05:06:21 davem Exp $
+/* $Id: ebus.c,v 1.16 2001/02/13 01:16:43 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -11,7 +11,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <asm/system.h>
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 41ef9737e..36ce64d83 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.42 2000/12/05 00:56:36 anton Exp $
+/* $Id: ioport.c,v 1.44 2001/02/13 04:07:38 davem Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -32,7 +32,7 @@
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/pci.h> /* struct pci_dev */
#include <linux/proc_fs.h>
@@ -225,7 +225,7 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz)
* XXX Playing with implementation details here.
* On sparc64 Ebus has resources with precise boundaries.
* We share drivers with sparc64. Too clever drivers use
- * start of a resource instead of a base adress.
+ * start of a resource instead of a base address.
*
* XXX-2 This may be not valid anymore, clean when
* interface to sbus_ioremap() is resolved.
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index eaa7fc4a3..56bea7a28 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.109 2000/08/31 10:00:39 anton Exp $
+/* $Id: irq.c,v 1.110 2001/02/13 01:16:43 davem Exp $
* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
* Sparc the IRQ's are basically 'cast in stone'
* and you are supposed to probe the prom's device
@@ -19,7 +19,7 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/smp.h>
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 9bc82a518..6ccc27153 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.21 2001/01/18 00:23:00 davem Exp $
+/* $Id: pcic.c,v 1.22 2001/02/13 01:16:43 davem Exp $
* pcic.c: Sparc/PCI controller support
*
* Copyright (C) 1998 V. Roganov and G. Raiko
@@ -15,7 +15,7 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/ebus.h>
#include <asm/sbus.h> /* for sanity check... */
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 878147763..1820eb12a 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.154 2000/10/05 06:12:57 anton Exp $
+/* $Id: process.c,v 1.155 2001/02/13 01:16:43 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -19,7 +19,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/config.h>
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
index baed3a125..cba111a71 100644
--- a/arch/sparc/kernel/ptrace.c
+++ b/arch/sparc/kernel/ptrace.c
@@ -5,7 +5,7 @@
* Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
* and David Mosberger.
*
- * Added Linux support -miguel (wierd, eh?, the orignal code was meant
+ * Added Linux support -miguel (weird, eh?, the orignal code was meant
* to emulate SunOS).
*/
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index aef0869e0..6cc594963 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.122 2001/01/01 01:46:15 davem Exp $
+/* $Id: setup.c,v 1.123 2001/02/13 01:16:43 davem Exp $
* linux/arch/sparc/kernel/setup.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -12,7 +12,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/smp.h>
#include <linux/user.h>
#include <linux/a.out.h>
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index 3f33ca265..90fbfd819 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -17,7 +17,7 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <asm/ptrace.h>
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 4ce99b06b..6981f4d10 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -1,4 +1,4 @@
-/* $Id: sun4d_irq.c,v 1.26 2000/07/26 01:04:03 davem Exp $
+/* $Id: sun4d_irq.c,v 1.27 2001/02/13 01:16:43 davem Exp $
* arch/sparc/kernel/sun4d_irq.c:
* SS1000/SC2000 interrupt handling.
*
@@ -14,7 +14,7 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/smp.h>
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index d14dbc2ac..098b2e58d 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -287,11 +287,11 @@ void __init smp4d_boot_cpus(void)
smp_highest_cpu = i;
}
}
- SMP_PRINTK(("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, (bogosum + 2500)/500000, ((bogosum + 2500)/5000)%100));
+ SMP_PRINTK(("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n", cpucount + 1, bogosum/(500000/HZ), (bogosum/(5000/HZ))%100));
printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
cpucount + 1,
- (bogosum + 2500)/500000,
- ((bogosum + 2500)/5000)%100);
+ bogosum/(500000/HZ),
+ (bogosum/(5000/HZ))%100);
smp_activated = 1;
smp_num_cpus = cpucount + 1;
}
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 2c79caf33..0d0477403 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -18,7 +18,7 @@
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/ioport.h>
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 230a95e6b..04e3d65fa 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -256,8 +256,8 @@ void __init smp4m_boot_cpus(void)
}
printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
cpucount + 1,
- (bogosum + 2500)/500000,
- ((bogosum + 2500)/5000)%100);
+ bogosum/(500000/HZ),
+ (bogosum/(5000/HZ))%100);
smp_activated = 1;
smp_num_cpus = cpucount + 1;
}
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 24ae3829d..adaae6062 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.131 2001/01/24 21:05:12 davem Exp $
+/* $Id: sys_sunos.c,v 1.132 2001/02/13 01:16:43 davem Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -28,7 +28,7 @@
#include <linux/utsname.h>
#include <linux/major.h>
#include <linux/stat.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/errno.h>
#include <linux/smp.h>
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c
index 1679384d6..be4522e1f 100644
--- a/arch/sparc/mm/io-unit.c
+++ b/arch/sparc/mm/io-unit.c
@@ -1,4 +1,4 @@
-/* $Id: io-unit.c,v 1.22 2000/08/09 00:00:15 davem Exp $
+/* $Id: io-unit.c,v 1.23 2001/02/13 01:16:43 davem Exp $
* io-unit.c: IO-UNIT specific routines for memory management.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -7,7 +7,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/scatterlist.h>
#include <asm/pgalloc.h>
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
index 058fdd0d1..3bd631f36 100644
--- a/arch/sparc/mm/iommu.c
+++ b/arch/sparc/mm/iommu.c
@@ -1,4 +1,4 @@
-/* $Id: iommu.c,v 1.20 2000/08/09 00:00:15 davem Exp $
+/* $Id: iommu.c,v 1.21 2001/02/13 01:16:43 davem Exp $
* iommu.c: IOMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -11,7 +11,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/scatterlist.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 0dba7d0a3..a5b2b117b 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.225 2000/11/30 08:37:31 anton Exp $
+/* $Id: srmmu.c,v 1.226 2001/02/13 01:16:44 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -11,7 +11,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/init.h>
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index 1b32dd8ef..ef5157b05 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -353,7 +353,7 @@ void __init sun4c_probe_vac(void)
break;
default:
- prom_printf("Cannot initialize VAC - wierd sun4 model idprom->id_machtype = %d", idprom->id_machtype);
+ prom_printf("Cannot initialize VAC - weird sun4 model idprom->id_machtype = %d", idprom->id_machtype);
prom_halt();
};
} else {
diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in
index 5c208915b..2d67b5e54 100644
--- a/arch/sparc64/config.in
+++ b/arch/sparc64/config.in
@@ -161,15 +161,15 @@ if [ "$CONFIG_SCSI" != "n" ]; then
mainmenu_option next_comment
comment 'SCSI low-level drivers'
- tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
- tristate 'PTI Qlogic, ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
+ dep_tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
+ dep_tristate 'PTI Qlogic, ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
if [ "$CONFIG_PCI" != "n" ]; then
dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
bool ' Enable tagged command queueing (TCQ) by default' CONFIG_AIC7XXX_TAGGED_QUEUEING
int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8
- bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
+ bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS
int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
fi
dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI
@@ -197,6 +197,8 @@ if [ "$CONFIG_SCSI" != "n" ]; then
fi
endmenu
+source drivers/message/fusion/Config.in
+
source drivers/fc4/Config.in
if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index b066b8b96..bda2fb6a5 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -23,7 +23,7 @@
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/user.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/binfmts.h>
#include <linux/personality.h>
#include <linux/init.h>
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index e175fac27..6dbe45a6c 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.53 2000/11/08 05:08:23 davem Exp $
+/* $Id: ebus.c,v 1.54 2001/02/13 01:16:44 davem Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <asm/system.h>
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index 67c1ec6d0..e2cdc3613 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.105 2001/01/18 04:47:44 davem Exp $
+/* $Id: ioctl32.c,v 1.107 2001/02/13 01:16:44 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
@@ -16,7 +16,7 @@
#include <linux/smp_lock.h>
#include <linux/ioctl.h>
#include <linux/if.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/hdreg.h>
#include <linux/raid/md.h>
#include <linux/kd.h>
@@ -3770,7 +3770,7 @@ IOCTL_TABLE_END
unsigned int ioctl32_hash_table[1024];
-extern inline unsigned long ioctl32_hash(unsigned long cmd)
+static inline unsigned long ioctl32_hash(unsigned long cmd)
{
return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff;
}
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 92bd3ed88..1bd29505b 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.94 2000/09/21 06:27:10 anton Exp $
+/* $Id: irq.c,v 1.95 2001/02/13 01:16:44 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,7 +13,7 @@
#include <linux/signal.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/random.h> /* XXX ADD add_foo_randomness() calls... -DaveM */
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 14473724f..ff7060c0a 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -1,11 +1,11 @@
-/* $Id: pci_common.c,v 1.12 2000/05/01 06:32:49 davem Exp $
+/* $Id: pci_common.c,v 1.13 2001/02/13 01:16:44 davem Exp $
* pci_common.c: PCI controller common support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
*/
#include <linux/string.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <asm/pbm.h>
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index fbd7832cd..7a671158e 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.18 2001/01/11 16:26:45 davem Exp $
+/* $Id: pci_psycho.c,v 1.19 2001/02/13 01:16:44 davem Exp $
* pci_psycho.c: PSYCHO/U2P specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -10,7 +10,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/pbm.h>
#include <asm/iommu.h>
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index ec74a3696..cce2e5467 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.22 2001/01/16 13:03:48 anton Exp $
+/* $Id: pci_sabre.c,v 1.23 2001/02/13 01:16:44 davem Exp $
* pci_sabre.c: Sabre specific PCI controller support.
*
* Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -10,7 +10,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/apb.h>
#include <asm/pbm.h>
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 9299c2531..daac0d783 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.2 2001/01/12 02:43:30 davem Exp $
+/* $Id: pci_schizo.c,v 1.3 2001/02/13 01:16:44 davem Exp $
* pci_schizo.c: SCHIZO specific PCI controller support.
*
* Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -8,7 +8,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/pbm.h>
#include <asm/iommu.h>
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 4534ad59b..3fc337d71 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.113 2000/11/08 08:14:58 davem Exp $
+/* $Id: process.c,v 1.114 2001/02/13 01:16:44 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -22,7 +22,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/config.h>
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 977d0f35a..7f791c4d0 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -6,7 +6,7 @@
* Based upon code written by Ross Biro, Linus Torvalds, Bob Manson,
* and David Mosberger.
*
- * Added Linux support -miguel (wierd, eh?, the orignal code was meant
+ * Added Linux support -miguel (weird, eh?, the orignal code was meant
* to emulate SunOS).
*/
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 7baebc89e..30cac5e00 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.12 2000/09/21 06:25:14 anton Exp $
+/* $Id: sbus.c,v 1.13 2001/02/13 01:16:44 davem Exp $
* sbus.c: UltraSparc SBUS controller support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -8,7 +8,7 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <asm/page.h>
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 11d29f21f..7817f4566 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.58 2001/01/01 01:46:15 davem Exp $
+/* $Id: setup.c,v 1.59 2001/02/13 01:16:44 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -12,7 +12,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/smp.h>
#include <linux/user.h>
#include <linux/a.out.h>
diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c
index 6899e7c4a..4d89be41e 100644
--- a/arch/sparc64/kernel/starfire.c
+++ b/arch/sparc64/kernel/starfire.c
@@ -1,4 +1,4 @@
-/* $Id: starfire.c,v 1.8 2000/10/27 18:36:47 anton Exp $
+/* $Id: starfire.c,v 1.9 2001/02/13 01:16:44 davem Exp $
* starfire.c: Starfire/E10000 support.
*
* Copyright (C) 1998 David S. Miller (davem@redhat.com)
@@ -6,7 +6,7 @@
*/
#include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/page.h>
#include <asm/oplib.h>
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 391979c87..e3cd81c97 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.47 2000/11/29 05:56:12 anton Exp $
+/* $Id: sys_sparc.c,v 1.48 2001/02/13 01:16:44 davem Exp $
* linux/arch/sparc64/kernel/sys_sparc.c
*
* This file contains various random system calls that
@@ -21,7 +21,7 @@
#include <linux/utsname.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/ipc.h>
#include <linux/personality.h>
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 184b4169d..d68b75cab 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.172 2001/01/24 21:05:13 davem Exp $
+/* $Id: sys_sparc32.c,v 1.173 2001/02/13 01:16:44 davem Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -25,7 +25,7 @@
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/uio.h>
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 58e4704c4..bfbd8841c 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.56 2001/01/04 05:35:48 davem Exp $
+/* $Id: sys_sunos32.c,v 1.57 2001/02/13 01:16:44 davem Exp $
* sys_sunos32.c: SunOS binary compatability layer on sparc64.
*
* Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -27,7 +27,7 @@
#include <linux/utsname.h>
#include <linux/major.h>
#include <linux/stat.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/errno.h>
#include <linux/smp.h>
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 2562df1f3..cc703d3bc 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.68 2000/11/22 06:50:37 davem Exp $
+/* $Id: traps.c,v 1.70 2001/02/09 05:46:44 davem Exp $
* arch/sparc64/kernel/traps.c
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -639,6 +639,30 @@ void user_instruction_dump (unsigned int *pc)
printk("\n");
}
+void show_trace_task(struct task_struct *tsk)
+{
+ unsigned long pc, fp;
+ unsigned long task_base = (unsigned long)tsk;
+ struct reg_window *rw;
+ int count = 0;
+
+ if (!tsk)
+ return;
+
+ fp = tsk->thread.ksp + STACK_BIAS;
+ do {
+ /* Bogus frame pointer? */
+ if (fp < (task_base + sizeof(struct task_struct)) ||
+ fp >= (task_base + (2 * PAGE_SIZE)))
+ break;
+ rw = (struct reg_window *)fp;
+ pc = rw->ins[7];
+ printk("[%016lx] ", pc);
+ fp = rw->ins[6] + STACK_BIAS;
+ } while (++count < 16);
+ printk("\n");
+}
+
void die_if_kernel(char *str, struct pt_regs *regs)
{
extern void __show_regs(struct pt_regs * regs);
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 289092756..15407f4f4 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.161 2000/12/09 20:16:58 davem Exp $
+/* $Id: init.c,v 1.162 2001/02/13 01:16:44 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/blk.h>
#include <linux/swap.h>
#include <linux/swapctl.h>
diff --git a/arch/sparc64/mm/modutil.c b/arch/sparc64/mm/modutil.c
index b8e2833f0..41bd1f077 100644
--- a/arch/sparc64/mm/modutil.c
+++ b/arch/sparc64/mm/modutil.c
@@ -1,11 +1,11 @@
-/* $Id: modutil.c,v 1.6 2000/06/26 23:20:24 davem Exp $
+/* $Id: modutil.c,v 1.7 2001/02/13 01:16:44 davem Exp $
* arch/sparc64/mm/modutil.c
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Based upon code written by Linus Torvalds and others.
*/
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index e80d6b13f..8ca96f5b2 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -1,4 +1,4 @@
-/* $Id: fs.c,v 1.23 2000/08/29 07:01:54 davem Exp $
+/* $Id: fs.c,v 1.24 2001/02/13 01:16:44 davem Exp $
* fs.c: fs related syscall emulation for Solaris
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -9,7 +9,7 @@
#include <linux/types.h>
#include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/file.h>
diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c
index e016e4b1a..e40b38092 100644
--- a/arch/sparc64/solaris/socket.c
+++ b/arch/sparc64/solaris/socket.c
@@ -1,4 +1,4 @@
-/* $Id: socket.c,v 1.4 2000/11/18 02:11:00 davem Exp $
+/* $Id: socket.c,v 1.5 2001/02/13 01:16:44 davem Exp $
* socket.c: Socket syscall emulation for Solaris 2.6+
*
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -10,7 +10,7 @@
#include <linux/types.h>
#include <linux/smp_lock.h>
#include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/socket.h>
#include <linux/file.h>
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
index bf2182381..a8e695c04 100644
--- a/arch/sparc64/solaris/socksys.c
+++ b/arch/sparc64/solaris/socksys.c
@@ -1,4 +1,4 @@
-/* $Id: socksys.c,v 1.17 2000/10/19 00:49:53 davem Exp $
+/* $Id: socksys.c,v 1.18 2001/02/13 01:16:44 davem Exp $
* socksys.c: /dev/inet/ stuff for Solaris emulation.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -16,7 +16,7 @@
#include <linux/file.h>
#include <linux/init.h>
#include <linux/poll.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/in.h>
#include <linux/devfs_fs_kernel.h>