diff options
author | Michal Marek <mmarek@suse.cz> | 2010-08-04 13:59:13 +0200 |
---|---|---|
committer | Michal Marek <mmarek@suse.cz> | 2010-08-04 13:59:13 +0200 |
commit | 772320e84588dcbe1600ffb83e5f328f2209ac2a (patch) | |
tree | a7de21b79340aeaa17c58126f6b801b82c77b53a /arch/s390 | |
parent | 1ce53adf13a54375d2a5c7cdbe341b2558389615 (diff) | |
parent | 9fe6206f400646a2322096b56c59891d530e8d51 (diff) | |
download | linux-772320e84588dcbe1600ffb83e5f328f2209ac2a.tar.gz linux-772320e84588dcbe1600ffb83e5f328f2209ac2a.tar.bz2 linux-772320e84588dcbe1600ffb83e5f328f2209ac2a.zip |
Merge commit 'v2.6.35' into kbuild/kbuild
Conflicts:
arch/powerpc/Makefile
Diffstat (limited to 'arch/s390')
118 files changed, 3052 insertions, 2058 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index c80235206c01..bee1c0f794cf 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -54,6 +54,9 @@ config GENERIC_BUG depends on BUG default y +config GENERIC_BUG_RELATIVE_POINTERS + def_bool y + config NO_IOMEM def_bool y @@ -87,6 +90,7 @@ config S390 select HAVE_SYSCALL_TRACEPOINTS select HAVE_DYNAMIC_FTRACE select HAVE_FUNCTION_GRAPH_TRACER + select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_DEFAULT_NO_SPIN_MUTEXES select HAVE_OPROFILE select HAVE_KPROBES @@ -95,6 +99,10 @@ config S390 select HAVE_ARCH_TRACEHOOK select INIT_ALL_POSSIBLE select HAVE_PERF_EVENTS + select HAVE_KERNEL_GZIP + select HAVE_KERNEL_BZIP2 + select HAVE_KERNEL_LZMA + select HAVE_KERNEL_LZO select ARCH_INLINE_SPIN_TRYLOCK select ARCH_INLINE_SPIN_TRYLOCK_BH select ARCH_INLINE_SPIN_LOCK @@ -437,13 +445,6 @@ config FORCE_MAX_ZONEORDER int default "9" -config PROCESS_DEBUG - bool "Show crashed user process info" - help - Say Y to print all process fault locations to the console. This is - a debugging option; you probably do not want to set it unless you - are an S390 port maintainer. - config PFAULT bool "Pseudo page fault support" help @@ -479,13 +480,6 @@ config CMM Everybody who wants to run Linux under VM should select this option. -config CMM_PROC - bool "/proc interface to cooperative memory management" - depends on CMM - help - Select this option to enable the /proc interface to the - cooperative memory management. - config CMM_IUCV bool "IUCV special message interface to cooperative memory management" depends on CMM && (SMSGIUCV=y || CMM=SMSGIUCV) diff --git a/arch/s390/Kconfig.debug b/arch/s390/Kconfig.debug index 2283933a9a93..45e0c6199f36 100644 --- a/arch/s390/Kconfig.debug +++ b/arch/s390/Kconfig.debug @@ -6,4 +6,17 @@ config TRACE_IRQFLAGS_SUPPORT source "lib/Kconfig.debug" +config DEBUG_STRICT_USER_COPY_CHECKS + bool "Strict user copy size checks" + ---help--- + Enabling this option turns a certain set of sanity checks for user + copy operations into compile time warnings. + + The copy_from_user() etc checks are there to help test if there + are sufficient security checks on the length argument of + the copy operation, by having gcc prove that the argument is + within bounds. + + If unsure, or if you run an older (pre 4.4) gcc, say N. + endmenu diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 83ef8724c833..0c9e6c6d2a64 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -14,6 +14,7 @@ # ifndef CONFIG_64BIT +LD_BFD := elf32-s390 LDFLAGS := -m elf_s390 KBUILD_CFLAGS += -m31 KBUILD_AFLAGS += -m31 @@ -21,6 +22,7 @@ UTS_MACHINE := s390 STACK_SIZE := 8192 CHECKFLAGS += -D__s390__ -msize-long else +LD_BFD := elf64-s390 LDFLAGS := -m elf64_s390 KBUILD_AFLAGS_MODULE += -fpic -D__PIC__ KBUILD_CFLAGS_MODULE += -fpic -D__PIC__ @@ -31,6 +33,8 @@ STACK_SIZE := 16384 CHECKFLAGS += -D__s390__ -D__s390x__ endif +export LD_BFD + cflags-$(CONFIG_MARCH_G5) += $(call cc-option,-march=g5) cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900) cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) @@ -86,7 +90,9 @@ KBUILD_AFLAGS += $(aflags-y) OBJCOPYFLAGS := -O binary LDFLAGS_vmlinux := -e start -head-y := arch/s390/kernel/head.o arch/s390/kernel/init_task.o +head-y := arch/s390/kernel/head.o +head-y += arch/s390/kernel/$(if $(CONFIG_64BIT),head64.o,head31.o) +head-y += arch/s390/kernel/init_task.o core-y += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \ arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ @@ -100,21 +106,28 @@ drivers-$(CONFIG_OPROFILE) += arch/s390/oprofile/ boot := arch/s390/boot -all: image +all: image bzImage install: vmlinux $(Q)$(MAKE) $(build)=$(boot) $@ -image: vmlinux +image bzImage: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ zfcpdump: $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ +vdso_install: +ifeq ($(CONFIG_64BIT),y) + $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@ +endif + $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso32 $@ + archclean: $(Q)$(MAKE) $(clean)=$(boot) # Don't use tabs in echo arguments define archhelp echo '* image - Kernel image for IPL ($(boot)/image)' + echo '* bzImage - Compressed kernel image for IPL ($(boot)/bzImage)' endef diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index 4188cbe63a54..e43fe7537031 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/init.h> -#include <linux/slab.h> #include <linux/errno.h> #include <linux/kernel_stat.h> #include <linux/pagemap.h> diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index 4ce7fa95880f..9a9586f4103f 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/init.h> -#include <linux/slab.h> #include <linux/errno.h> #include <linux/kernel_stat.h> #include <linux/netdevice.h> diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c index 55c80ffd42b9..92f1cb745d69 100644 --- a/arch/s390/appldata/appldata_os.c +++ b/arch/s390/appldata/appldata_os.c @@ -181,7 +181,7 @@ static int __init appldata_os_init(void) goto out; } - appldata_os_data = kzalloc(max_size, GFP_DMA); + appldata_os_data = kzalloc(max_size, GFP_KERNEL | GFP_DMA); if (appldata_os_data == NULL) { rc = -ENOMEM; goto out; diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile index 4d97eef36b8d..8800cf090694 100644 --- a/arch/s390/boot/Makefile +++ b/arch/s390/boot/Makefile @@ -9,10 +9,18 @@ COMPILE_VERSION := __linux_compile_version_id__`hostname | \ EXTRA_CFLAGS := -DCOMPILE_VERSION=$(COMPILE_VERSION) -gstabs -I. targets := image +targets += bzImage +subdir- := compressed $(obj)/image: vmlinux FORCE $(call if_changed,objcopy) +$(obj)/bzImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/compressed/vmlinux: FORCE + $(Q)$(MAKE) $(build)=$(obj)/compressed $@ + install: $(CONFIGURE) $(obj)/image sh -x $(srctree)/$(obj)/install.sh $(KERNELRELEASE) $(obj)/image \ System.map Kerntypes "$(INSTALL_PATH)" diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile new file mode 100644 index 000000000000..1c999f726a58 --- /dev/null +++ b/arch/s390/boot/compressed/Makefile @@ -0,0 +1,63 @@ +# +# linux/arch/s390/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +BITS := $(if $(CONFIG_64BIT),64,31) + +targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \ + vmlinux.bin.lzma vmlinux.bin.lzo misc.o piggy.o sizes.h head$(BITS).o + +KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 +KBUILD_CFLAGS += $(cflags-y) +KBUILD_CFLAGS += $(call cc-option,-mpacked-stack) +KBUILD_CFLAGS += $(call cc-option,-ffreestanding) + +GCOV_PROFILE := n + +OBJECTS := $(addprefix $(objtree)/arch/s390/kernel/, head.o sclp.o ebcdic.o) +OBJECTS += $(obj)/head$(BITS).o $(obj)/misc.o $(obj)/piggy.o + +LDFLAGS_vmlinux := --oformat $(LD_BFD) -e startup -T +$(obj)/vmlinux: $(obj)/vmlinux.lds $(OBJECTS) + $(call if_changed,ld) + @: + +sed-sizes := -e 's/^\([0-9a-fA-F]*\) . \(__bss_start\|_end\)$$/\#define SZ\2 0x\1/p' + +quiet_cmd_sizes = GEN $@ + cmd_sizes = $(NM) $< | sed -n $(sed-sizes) > $@ + +$(obj)/sizes.h: vmlinux + $(call if_changed,sizes) + +AFLAGS_head$(BITS).o += -I$(obj) +$(obj)/head$(BITS).o: $(obj)/sizes.h + +CFLAGS_misc.o += -I$(obj) +$(obj)/misc.o: $(obj)/sizes.h + +OBJCOPYFLAGS_vmlinux.bin := -R .comment -S +$(obj)/vmlinux.bin: vmlinux + $(call if_changed,objcopy) + +vmlinux.bin.all-y := $(obj)/vmlinux.bin + +suffix-$(CONFIG_KERNEL_GZIP) := gz +suffix-$(CONFIG_KERNEL_BZIP2) := bz2 +suffix-$(CONFIG_KERNEL_LZMA) := lzma +suffix-$(CONFIG_KERNEL_LZO) := lzo + +$(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y) + $(call if_changed,gzip) +$(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y) + $(call if_changed,bzip2) +$(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y) + $(call if_changed,lzma) +$(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) + $(call if_changed,lzo) + +LDFLAGS_piggy.o := -r --format binary --oformat $(LD_BFD) -T +$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) + $(call if_changed,ld) diff --git a/arch/s390/boot/compressed/head31.S b/arch/s390/boot/compressed/head31.S new file mode 100644 index 000000000000..2a5523a32bcc --- /dev/null +++ b/arch/s390/boot/compressed/head31.S @@ -0,0 +1,51 @@ +/* + * Startup glue code to uncompress the kernel + * + * Copyright IBM Corp. 2010 + * + * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> + */ + +#include <linux/init.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> +#include <asm/page.h> +#include "sizes.h" + +__HEAD + .globl startup_continue +startup_continue: + basr %r13,0 # get base +.LPG1: + # setup stack + l %r15,.Lstack-.LPG1(%r13) + ahi %r15,-96 + l %r1,.Ldecompress-.LPG1(%r13) + basr %r14,%r1 + # setup registers for memory mover & branch to target + lr %r4,%r2 + l %r2,.Loffset-.LPG1(%r13) + la %r4,0(%r2,%r4) + l %r3,.Lmvsize-.LPG1(%r13) + lr %r5,%r3 + # move the memory mover someplace safe + la %r1,0x200 + mvc 0(mover_end-mover,%r1),mover-.LPG1(%r13) + # decompress image is started at 0x11000 + lr %r6,%r2 + br %r1 +mover: + mvcle %r2,%r4,0 + jo mover + br %r6 +mover_end: + + .align 8 +.Lstack: + .long 0x8000 + (1<<(PAGE_SHIFT+THREAD_ORDER)) +.Ldecompress: + .long decompress_kernel +.Loffset: + .long 0x11000 +.Lmvsize: + .long SZ__bss_start diff --git a/arch/s390/boot/compressed/head64.S b/arch/s390/boot/compressed/head64.S new file mode 100644 index 000000000000..2982cb140550 --- /dev/null +++ b/arch/s390/boot/compressed/head64.S @@ -0,0 +1,48 @@ +/* + * Startup glue code to uncompress the kernel + * + * Copyright IBM Corp. 2010 + * + * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> + */ + +#include <linux/init.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> +#include <asm/page.h> +#include "sizes.h" + +__HEAD + .globl startup_continue +startup_continue: + basr %r13,0 # get base +.LPG1: + # setup stack + lg %r15,.Lstack-.LPG1(%r13) + aghi %r15,-160 + brasl %r14,decompress_kernel + # setup registers for memory mover & branch to target + lgr %r4,%r2 + lg %r2,.Loffset-.LPG1(%r13) + la %r4,0(%r2,%r4) + lg %r3,.Lmvsize-.LPG1(%r13) + lgr %r5,%r3 + # move the memory mover someplace safe + la %r1,0x200 + mvc 0(mover_end-mover,%r1),mover-.LPG1(%r13) + # decompress image is started at 0x11000 + lgr %r6,%r2 + br %r1 +mover: + mvcle %r2,%r4,0 + jo mover + br %r6 +mover_end: + + .align 8 +.Lstack: + .quad 0x8000 + (1<<(PAGE_SHIFT+THREAD_ORDER)) +.Loffset: + .quad 0x11000 +.Lmvsize: + .quad SZ__bss_start diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c new file mode 100644 index 000000000000..0851eb1e919e --- /dev/null +++ b/arch/s390/boot/compressed/misc.c @@ -0,0 +1,162 @@ +/* + * Definitions and wrapper functions for kernel decompressor + * + * Copyright IBM Corp. 2010 + * + * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> + */ + +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/ipl.h> +#include "sizes.h" + +/* + * gzip declarations + */ +#define STATIC static + +#undef memset +#undef memcpy +#undef memmove +#define memzero(s, n) memset((s), 0, (n)) + +/* Symbols defined by linker scripts */ +extern char input_data[]; +extern int input_len; +extern char _text, _end; +extern char _bss, _ebss; + +static void error(char *m); + +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; + +#ifdef CONFIG_HAVE_KERNEL_BZIP2 +#define HEAP_SIZE 0x400000 +#else +#define HEAP_SIZE 0x10000 +#endif + +#ifdef CONFIG_KERNEL_GZIP +#include "../../../../lib/decompress_inflate.c" +#endif + +#ifdef CONFIG_KERNEL_BZIP2 +#include "../../../../lib/decompress_bunzip2.c" +#endif + +#ifdef CONFIG_KERNEL_LZMA +#include "../../../../lib/decompress_unlzma.c" +#endif + +#ifdef CONFIG_KERNEL_LZO +#include "../../../../lib/decompress_unlzo.c" +#endif + +extern _sclp_print_early(const char *); + +int puts(const char *s) +{ + _sclp_print_early(s); + return 0; +} + +void *memset(void *s, int c, size_t n) +{ + char *xs; + + if (c == 0) + return __builtin_memset(s, 0, n); + + xs = (char *) s; + if (n > 0) + do { + *xs++ = c; + } while (--n > 0); + return s; +} + +void *memcpy(void *__dest, __const void *__src, size_t __n) +{ + return __builtin_memcpy(__dest, __src, __n); +} + +void *memmove(void *__dest, __const void *__src, size_t __n) +{ + char *d; + const char *s; + + if (__dest <= __src) + return __builtin_memcpy(__dest, __src, __n); + d = __dest + __n; + s = __src + __n; + while (__n--) + *--d = *--s; + return __dest; +} + +static void error(char *x) +{ + unsigned long long psw = 0x000a0000deadbeefULL; + + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + asm volatile("lpsw %0" : : "Q" (psw)); +} + +/* + * Safe guard the ipl parameter block against a memory area that will be + * overwritten. The validity check for the ipl parameter block is complex + * (see cio_get_iplinfo and ipl_save_parameters) but if the pointer to + * the ipl parameter block intersects with the passed memory area we can + * safely assume that we can read from that memory. In that case just copy + * the memory to IPL_PARMBLOCK_ORIGIN even if there is no ipl parameter + * block. + */ +static void check_ipl_parmblock(void *start, unsigned long size) +{ + void *src, *dst; + + src = (void *)(unsigned long) S390_lowcore.ipl_parmblock_ptr; + if (src + PAGE_SIZE <= start || src >= start + size) + return; + dst = (void *) IPL_PARMBLOCK_ORIGIN; + memmove(dst, src, PAGE_SIZE); + S390_lowcore.ipl_parmblock_ptr = IPL_PARMBLOCK_ORIGIN; +} + +unsigned long decompress_kernel(void) +{ + unsigned long output_addr; + unsigned char *output; + + check_ipl_parmblock((void *) 0, (unsigned long) output + SZ__bss_start); + memset(&_bss, 0, &_ebss - &_bss); + free_mem_ptr = (unsigned long)&_end; + free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; + output = (unsigned char *) ((free_mem_end_ptr + 4095UL) & -4096UL); + +#ifdef CONFIG_BLK_DEV_INITRD + /* + * Move the initrd right behind the end of the decompressed + * kernel image. + */ + if (INITRD_START && INITRD_SIZE && + INITRD_START < (unsigned long) output + SZ__bss_start) { + check_ipl_parmblock(output + SZ__bss_start, + INITRD_START + INITRD_SIZE); + memmove(output + SZ__bss_start, + (void *) INITRD_START, INITRD_SIZE); + INITRD_START = (unsigned long) output + SZ__bss_start; + } +#endif + + puts("Uncompressing Linux... "); + decompress(input_data, input_len, NULL, NULL, output, NULL, error); + puts("Ok, booting the kernel.\n"); + return (unsigned long) output; +} + diff --git a/arch/s390/boot/compressed/vmlinux.lds.S b/arch/s390/boot/compressed/vmlinux.lds.S new file mode 100644 index 000000000000..d80f79d8dd9c --- /dev/null +++ b/arch/s390/boot/compressed/vmlinux.lds.S @@ -0,0 +1,55 @@ +#include <asm-generic/vmlinux.lds.h> + +#ifdef CONFIG_64BIT +OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390") +OUTPUT_ARCH(s390:64-bit) +#else +OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390") +OUTPUT_ARCH(s390) +#endif + +ENTRY(startup) + +SECTIONS +{ + /* Be careful parts of head_64.S assume startup_32 is at + * address 0. + */ + . = 0; + .head.text : { + _head = . ; + HEAD_TEXT + _ehead = . ; + } + .rodata.compressed : { + *(.rodata.compressed) + } + .text : { + _text = .; /* Text */ + *(.text) + *(.text.*) + _etext = . ; + } + .rodata : { + _rodata = . ; + *(.rodata) /* read-only data */ + *(.rodata.*) + _erodata = . ; + } + .data : { + _data = . ; + *(.data) + *(.data.*) + _edata = . ; + } + . = ALIGN(256); + .bss : { + _bss = . ; + *(.bss) + *(.bss.*) + *(COMMON) + . = ALIGN(8); /* For convenience during zeroing */ + _ebss = .; + } + _end = .; +} diff --git a/arch/s390/boot/compressed/vmlinux.scr b/arch/s390/boot/compressed/vmlinux.scr new file mode 100644 index 000000000000..f02382ae5c48 --- /dev/null +++ b/arch/s390/boot/compressed/vmlinux.scr @@ -0,0 +1,10 @@ +SECTIONS +{ + .rodata.compressed : { + input_len = .; + LONG(input_data_end - input_data) input_data = .; + *(.data) + output_len = . - 4; + input_data_end = .; + } +} diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 6be4503201ac..58f46734465f 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -78,14 +78,14 @@ static int setkey_fallback_cip(struct crypto_tfm *tfm, const u8 *in_key, struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); int ret; - sctx->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; - sctx->fallback.blk->base.crt_flags |= (tfm->crt_flags & + sctx->fallback.cip->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + sctx->fallback.cip->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); ret = crypto_cipher_setkey(sctx->fallback.cip, in_key, key_len); if (ret) { tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; - tfm->crt_flags |= (sctx->fallback.blk->base.crt_flags & + tfm->crt_flags |= (sctx->fallback.cip->base.crt_flags & CRYPTO_TFM_RES_MASK); } return ret; diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index a3209906739e..aa819dac2360 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/random.h> +#include <linux/slab.h> #include <asm/debug.h> #include <asm/uaccess.h> diff --git a/arch/s390/crypto/sha_common.c b/arch/s390/crypto/sha_common.c index 7903ec47e6b9..f42dbabc0d30 100644 --- a/arch/s390/crypto/sha_common.c +++ b/arch/s390/crypto/sha_common.c @@ -79,7 +79,7 @@ int s390_sha_final(struct shash_desc *desc, u8 *out) memset(ctx->buf + index, 0x00, end - index - 8); /* - * Append message length. Well, SHA-512 wants a 128 bit lenght value, + * Append message length. Well, SHA-512 wants a 128 bit length value, * nevertheless we use u64, should be enough for now... */ bits = ctx->count * 8; diff --git a/arch/s390/defconfig b/arch/s390/defconfig index b416aa11b91e..253f158db668 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.33-rc2 -# Mon Jan 4 09:03:07 2010 +# Linux kernel version: 2.6.35-rc1 +# Fri Jun 4 11:32:40 2010 # CONFIG_SCHED_MC=y CONFIG_MMU=y @@ -17,6 +17,7 @@ CONFIG_GENERIC_TIME=y CONFIG_GENERIC_TIME_VSYSCALL=y CONFIG_GENERIC_CLOCKEVENTS=y CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y CONFIG_NO_IOMEM=y CONFIG_NO_DMA=y CONFIG_GENERIC_LOCKBREAK=y @@ -34,8 +35,17 @@ CONFIG_CONSTRUCTORS=y CONFIG_EXPERIMENTAL=y CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_SYSVIPC_SYSCTL=y @@ -55,15 +65,11 @@ CONFIG_TREE_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=64 # CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set # CONFIG_TREE_RCU_TRACE is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=17 -CONFIG_GROUP_SCHED=y -CONFIG_FAIR_GROUP_SCHED=y -# CONFIG_RT_GROUP_SCHED is not set -CONFIG_USER_SCHED=y -# CONFIG_CGROUP_SCHED is not set CONFIG_CGROUPS=y # CONFIG_CGROUP_DEBUG is not set CONFIG_CGROUP_NS=y @@ -72,6 +78,8 @@ CONFIG_CGROUP_NS=y # CONFIG_CPUSETS is not set # CONFIG_CGROUP_CPUACCT is not set # CONFIG_RESOURCE_COUNTERS is not set +# CONFIG_CGROUP_SCHED is not set +# CONFIG_BLK_CGROUP is not set CONFIG_SYSFS_DEPRECATED=y CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_RELAY is not set @@ -86,6 +94,7 @@ CONFIG_INITRAMFS_SOURCE="" CONFIG_RD_GZIP=y CONFIG_RD_BZIP2=y CONFIG_RD_LZMA=y +CONFIG_RD_LZO=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SYSCTL=y CONFIG_ANON_INODES=y @@ -119,6 +128,7 @@ CONFIG_SLAB=y # CONFIG_SLUB is not set # CONFIG_SLOB is not set # CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y CONFIG_HAVE_OPROFILE=y CONFIG_KPROBES=y CONFIG_HAVE_SYSCALL_WRAPPERS=y @@ -127,6 +137,7 @@ CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y CONFIG_HAVE_ARCH_TRACEHOOK=y CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y CONFIG_HAVE_DEFAULT_NO_SPIN_MUTEXES=y # @@ -149,7 +160,6 @@ CONFIG_STOP_MACHINE=y CONFIG_BLOCK=y CONFIG_BLK_DEV_BSG=y # CONFIG_BLK_DEV_INTEGRITY is not set -# CONFIG_BLK_CGROUP is not set CONFIG_BLOCK_COMPAT=y # @@ -158,7 +168,6 @@ CONFIG_BLOCK_COMPAT=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_DEADLINE=y CONFIG_IOSCHED_CFQ=y -# CONFIG_CFQ_GROUP_IOSCHED is not set CONFIG_DEFAULT_DEADLINE=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set @@ -311,7 +320,6 @@ CONFIG_COMPAT_BINFMT_ELF=y # CONFIG_HAVE_AOUT is not set CONFIG_BINFMT_MISC=m CONFIG_FORCE_MAX_ZONEORDER=9 -# CONFIG_PROCESS_DEBUG is not set CONFIG_PFAULT=y # CONFIG_SHARED_KERNEL is not set # CONFIG_CMM is not set @@ -338,13 +346,13 @@ CONFIG_PM_SLEEP=y CONFIG_HIBERNATION=y CONFIG_PM_STD_PARTITION="" # CONFIG_PM_RUNTIME is not set +CONFIG_PM_OPS=y CONFIG_NET=y # # Networking options # CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y CONFIG_XFRM=y # CONFIG_XFRM_USER is not set @@ -448,6 +456,7 @@ CONFIG_NF_CONNTRACK=m # CONFIG_IP6_NF_IPTABLES is not set # CONFIG_IP_DCCP is not set CONFIG_IP_SCTP=m +# CONFIG_NET_SCTPPROBE is not set # CONFIG_SCTP_DBG_MSG is not set # CONFIG_SCTP_DBG_OBJCNT is not set # CONFIG_SCTP_HMAC_NONE is not set @@ -456,6 +465,7 @@ CONFIG_SCTP_HMAC_MD5=y # CONFIG_RDS is not set # CONFIG_TIPC is not set # CONFIG_ATM is not set +# CONFIG_L2TP is not set # CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set # CONFIG_DECNET is not set @@ -516,12 +526,14 @@ CONFIG_NET_ACT_NAT=m # CONFIG_NET_CLS_IND is not set CONFIG_NET_SCH_FIFO=y # CONFIG_DCB is not set +CONFIG_RPS=y # # Network testing # # CONFIG_NET_PKTGEN is not set # CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_DROP_MONITOR is not set CONFIG_CAN=m CONFIG_CAN_RAW=m CONFIG_CAN_BCM=m @@ -536,6 +548,7 @@ CONFIG_CAN_VCAN=m # CONFIG_WIMAX is not set # CONFIG_RFKILL is not set # CONFIG_NET_9P is not set +# CONFIG_CAIF is not set # CONFIG_PCMCIA is not set CONFIG_CCW=y @@ -598,6 +611,7 @@ CONFIG_MISC_DEVICES=y # # SCSI device support # +CONFIG_SCSI_MOD=y # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y # CONFIG_SCSI_DMA is not set @@ -717,6 +731,7 @@ CONFIG_VIRTIO_NET=m # Character devices # CONFIG_DEVKMEM=y +# CONFIG_N_GSM is not set CONFIG_UNIX98_PTYS=y # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set CONFIG_LEGACY_PTYS=y @@ -764,6 +779,7 @@ CONFIG_S390_TAPE_34XX=m # CONFIG_MONREADER is not set CONFIG_MONWRITER=m CONFIG_S390_VMUR=m +# CONFIG_RAMOOPS is not set # # PPS support @@ -777,10 +793,6 @@ CONFIG_S390_VMUR=m # CONFIG_NEW_LEDS is not set CONFIG_ACCESSIBILITY=y # CONFIG_AUXDISPLAY is not set - -# -# TI VLYNQ -# # CONFIG_STAGING is not set # @@ -856,6 +868,7 @@ CONFIG_MISC_FILESYSTEMS=y # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set # CONFIG_CRAMFS is not set # CONFIG_SQUASHFS is not set # CONFIG_VXFS_FS is not set @@ -884,6 +897,7 @@ CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set +# CONFIG_CEPH_FS is not set # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set @@ -945,6 +959,7 @@ CONFIG_DEBUG_MUTEXES=y # CONFIG_LOCK_STAT is not set CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y # CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y # CONFIG_DEBUG_INFO is not set @@ -962,16 +977,22 @@ CONFIG_DEBUG_MEMORY_INIT=y # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y # CONFIG_LKDTM is not set +# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_LATENCYTOP is not set CONFIG_SYSCTL_SYSCALL_CHECK=y # CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y CONFIG_TRACING_SUPPORT=y CONFIG_FTRACE=y # CONFIG_FUNCTION_TRACER is not set @@ -988,10 +1009,16 @@ CONFIG_BRANCH_PROFILE_NONE=y # CONFIG_KMEMTRACE is not set # CONFIG_WORKQUEUE_TRACER is not set # CONFIG_BLK_DEV_IO_TRACE is not set +CONFIG_KPROBE_EVENT=y +# CONFIG_RING_BUFFER_BENCHMARK is not set # CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set CONFIG_SAMPLES=y +# CONFIG_SAMPLE_TRACEPOINTS is not set +# CONFIG_SAMPLE_TRACE_EVENTS is not set # CONFIG_SAMPLE_KOBJECT is not set # CONFIG_SAMPLE_KPROBES is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set # # Security options @@ -1025,6 +1052,7 @@ CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_MANAGER2=y CONFIG_CRYPTO_GF128MUL=m # CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_PCRYPT is not set CONFIG_CRYPTO_WORKQUEUE=y # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_AUTHENC=m @@ -1112,7 +1140,7 @@ CONFIG_CRYPTO_SHA512_S390=m # CONFIG_CRYPTO_DES_S390 is not set # CONFIG_CRYPTO_AES_S390 is not set CONFIG_S390_PRNG=m -# CONFIG_BINARY_PRINTF is not set +CONFIG_BINARY_PRINTF=y # # Library routines @@ -1129,14 +1157,16 @@ CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=m CONFIG_LZO_COMPRESS=m -CONFIG_LZO_DECOMPRESS=m +CONFIG_LZO_DECOMPRESS=y CONFIG_DECOMPRESS_GZIP=y CONFIG_DECOMPRESS_BZIP2=y CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZO=y CONFIG_NLATTR=y CONFIG_HAVE_KVM=y CONFIG_VIRTUALIZATION=y CONFIG_KVM=m +# CONFIG_VHOST_NET is not set CONFIG_VIRTIO=y CONFIG_VIRTIO_RING=y CONFIG_VIRTIO_BALLOON=m diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index aea572009d60..fa487d4cc08b 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h @@ -11,6 +11,7 @@ #include <linux/fs.h> #include <linux/types.h> +#include <linux/debugfs.h> #define REG_FILE_MODE 0440 #define UPDATE_FILE_MODE 0220 @@ -34,6 +35,9 @@ extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); /* VM Hypervisor */ extern int hypfs_vm_init(void); +extern void hypfs_vm_exit(void); extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); +/* Directory for debugfs files */ +extern struct dentry *hypfs_dbfs_dir; #endif /* _HYPFS_H_ */ diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c index 2b92d501425f..1211bb1d2f24 100644 --- a/arch/s390/hypfs/hypfs_diag.c +++ b/arch/s390/hypfs/hypfs_diag.c @@ -12,10 +12,10 @@ #include <linux/types.h> #include <linux/errno.h> -#include <linux/gfp.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/vmalloc.h> +#include <linux/mm.h> #include <asm/ebcdic.h> #include "hypfs.h" @@ -23,6 +23,8 @@ #define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */ #define TMP_SIZE 64 /* size of temporary buffers */ +#define DBFS_D204_HDR_VERSION 0 + /* diag 204 subcodes */ enum diag204_sc { SUBC_STIB4 = 4, @@ -48,6 +50,8 @@ static void *diag204_buf; /* 4K aligned buffer for diag204 data */ static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */ static int diag204_buf_pages; /* number of pages for diag204 data */ +static struct dentry *dbfs_d204_file; + /* * DIAG 204 data structures and member access functions. * @@ -365,18 +369,21 @@ static void diag204_free_buffer(void) } else { free_pages((unsigned long) diag204_buf, 0); } - diag204_buf_pages = 0; diag204_buf = NULL; } +static void *page_align_ptr(void *ptr) +{ + return (void *) PAGE_ALIGN((unsigned long) ptr); +} + static void *diag204_alloc_vbuf(int pages) { /* The buffer has to be page aligned! */ diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1)); if (!diag204_buf_vmalloc) return ERR_PTR(-ENOMEM); - diag204_buf = (void*)((unsigned long)diag204_buf_vmalloc - & ~0xfffUL) + 0x1000; + diag204_buf = page_align_ptr(diag204_buf_vmalloc); diag204_buf_pages = pages; return diag204_buf; } @@ -469,17 +476,26 @@ fail_alloc: return rc; } +static int diag204_do_store(void *buf, int pages) +{ + int rc; + + rc = diag204((unsigned long) diag204_store_sc | + (unsigned long) diag204_info_type, pages, buf); + return rc < 0 ? -ENOSYS : 0; +} + static void *diag204_store(void) { void *buf; - int pages; + int pages, rc; buf = diag204_get_buffer(diag204_info_type, &pages); if (IS_ERR(buf)) goto out; - if (diag204((unsigned long)diag204_store_sc | - (unsigned long)diag204_info_type, pages, buf) < 0) - return ERR_PTR(-ENOSYS); + rc = diag204_do_store(buf, pages); + if (rc) + return ERR_PTR(rc); out: return buf; } @@ -488,7 +504,7 @@ out: static int diag224(void *ptr) { - int rc = -ENOTSUPP; + int rc = -EOPNOTSUPP; asm volatile( " diag %1,%2,0x224\n" @@ -507,7 +523,7 @@ static int diag224_get_name_table(void) return -ENOMEM; if (diag224(diag224_cpu_names)) { kfree(diag224_cpu_names); - return -ENOTSUPP; + return -EOPNOTSUPP; } EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16); return 0; @@ -527,6 +543,92 @@ static int diag224_idx2name(int index, char *name) return 0; } +struct dbfs_d204_hdr { + u64 len; /* Length of d204 buffer without header */ + u16 version; /* Version of header */ + u8 sc; /* Used subcode */ + char reserved[53]; +} __attribute__ ((packed)); + +struct dbfs_d204 { + struct dbfs_d204_hdr hdr; /* 64 byte header */ + char buf[]; /* d204 buffer */ +} __attribute__ ((packed)); + +struct dbfs_d204_private { + struct dbfs_d204 *d204; /* Aligned d204 data with header */ + void *base; /* Base pointer (needed for vfree) */ +}; + +static int dbfs_d204_open(struct inode *inode, struct file *file) +{ + struct dbfs_d204_private *data; + struct dbfs_d204 *d204; + int rc, buf_size; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr); + data->base = vmalloc(buf_size); + if (!data->base) { + rc = -ENOMEM; + goto fail_kfree_data; + } + memset(data->base, 0, buf_size); + d204 = page_align_ptr(data->base + sizeof(d204->hdr)) + - sizeof(d204->hdr); + rc = diag204_do_store(&d204->buf, diag204_buf_pages); + if (rc) + goto fail_vfree_base; + d204->hdr.version = DBFS_D204_HDR_VERSION; + d204->hdr.len = PAGE_SIZE * diag204_buf_pages; + d204->hdr.sc = diag204_store_sc; + data->d204 = d204; + file->private_data = data; + return nonseekable_open(inode, file); + +fail_vfree_base: + vfree(data->base); +fail_kfree_data: + kfree(data); + return rc; +} + +static int dbfs_d204_release(struct inode *inode, struct file *file) +{ + struct dbfs_d204_private *data = file->private_data; + + vfree(data->base); + kfree(data); + return 0; +} + +static ssize_t dbfs_d204_read(struct file *file, char __user *buf, + size_t size, loff_t *ppos) +{ + struct dbfs_d204_private *data = file->private_data; + + return simple_read_from_buffer(buf, size, ppos, data->d204, + data->d204->hdr.len + + sizeof(data->d204->hdr)); +} + +static const struct file_operations dbfs_d204_ops = { + .open = dbfs_d204_open, + .read = dbfs_d204_read, + .release = dbfs_d204_release, +}; + +static int hypfs_dbfs_init(void) +{ + dbfs_d204_file = debugfs_create_file("diag_204", 0400, hypfs_dbfs_dir, + NULL, &dbfs_d204_ops); + if (IS_ERR(dbfs_d204_file)) + return PTR_ERR(dbfs_d204_file); + return 0; +} + __init int hypfs_diag_init(void) { int rc; @@ -541,11 +643,17 @@ __init int hypfs_diag_init(void) pr_err("The hardware system does not provide all " "functions required by hypfs\n"); } + if (diag204_info_type == INFO_EXT) { + rc = hypfs_dbfs_init(); + if (rc) + diag204_free_buffer(); + } return rc; } void hypfs_diag_exit(void) { + debugfs_remove(dbfs_d204_file); diag224_delete_name_table(); diag204_free_buffer(); } diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c index f0b0d31f0b48..ee5ab1a578e7 100644 --- a/arch/s390/hypfs/hypfs_vm.c +++ b/arch/s390/hypfs/hypfs_vm.c @@ -10,14 +10,18 @@ #include <linux/string.h> #include <linux/vmalloc.h> #include <asm/ebcdic.h> +#include <asm/timex.h> #include "hypfs.h" #define NAME_LEN 8 +#define DBFS_D2FC_HDR_VERSION 0 static char local_guest[] = " "; static char all_guests[] = "* "; static char *guest_query; +static struct dentry *dbfs_d2fc_file; + struct diag2fc_data { __u32 version; __u32 flags; @@ -76,23 +80,26 @@ static int diag2fc(int size, char* query, void *addr) return -residual_cnt; } -static struct diag2fc_data *diag2fc_store(char *query, int *count) +/* + * Allocate buffer for "query" and store diag 2fc at "offset" + */ +static void *diag2fc_store(char *query, unsigned int *count, int offset) { + void *data; int size; - struct diag2fc_data *data; do { size = diag2fc(0, query, NULL); if (size < 0) return ERR_PTR(-EACCES); - data = vmalloc(size); + data = vmalloc(size + offset); if (!data) return ERR_PTR(-ENOMEM); - if (diag2fc(size, query, data) == 0) + if (diag2fc(size, query, data + offset) == 0) break; vfree(data); } while (1); - *count = (size / sizeof(*data)); + *count = (size / sizeof(struct diag2fc_data)); return data; } @@ -168,9 +175,10 @@ int hypfs_vm_create_files(struct super_block *sb, struct dentry *root) { struct dentry *dir, *file; struct diag2fc_data *data; - int rc, i, count = 0; + unsigned int count = 0; + int rc, i; - data = diag2fc_store(guest_query, &count); + data = diag2fc_store(guest_query, &count, 0); if (IS_ERR(data)) return PTR_ERR(data); @@ -218,8 +226,61 @@ failed: return rc; } +struct dbfs_d2fc_hdr { + u64 len; /* Length of d2fc buffer without header */ + u16 version; /* Version of header */ + char tod_ext[16]; /* TOD clock for d2fc */ + u64 count; /* Number of VM guests in d2fc buffer */ + char reserved[30]; +} __attribute__ ((packed)); + +struct dbfs_d2fc { + struct dbfs_d2fc_hdr hdr; /* 64 byte header */ + char buf[]; /* d2fc buffer */ +} __attribute__ ((packed)); + +static int dbfs_d2fc_open(struct inode *inode, struct file *file) +{ + struct dbfs_d2fc *data; + unsigned int count; + + data = diag2fc_store(guest_query, &count, sizeof(data->hdr)); + if (IS_ERR(data)) + return PTR_ERR(data); + get_clock_ext(data->hdr.tod_ext); + data->hdr.len = count * sizeof(struct diag2fc_data); + data->hdr.version = DBFS_D2FC_HDR_VERSION; + data->hdr.count = count; + memset(&data->hdr.reserved, 0, sizeof(data->hdr.reserved)); + file->private_data = data; + return nonseekable_open(inode, file); +} + +static int dbfs_d2fc_release(struct inode *inode, struct file *file) +{ + diag2fc_free(file->private_data); + return 0; +} + +static ssize_t dbfs_d2fc_read(struct file *file, char __user *buf, + size_t size, loff_t *ppos) +{ + struct dbfs_d2fc *data = file->private_data; + + return simple_read_from_buffer(buf, size, ppos, data, data->hdr.len + + sizeof(struct dbfs_d2fc_hdr)); +} + +static const struct file_operations dbfs_d2fc_ops = { + .open = dbfs_d2fc_open, + .read = dbfs_d2fc_read, + .release = dbfs_d2fc_release, +}; + int hypfs_vm_init(void) { + if (!MACHINE_IS_VM) + return 0; if (diag2fc(0, all_guests, NULL) > 0) guest_query = all_guests; else if (diag2fc(0, local_guest, NULL) > 0) @@ -227,5 +288,17 @@ int hypfs_vm_init(void) else return -EACCES; + dbfs_d2fc_file = debugfs_create_file("diag_2fc", 0400, hypfs_dbfs_dir, + NULL, &dbfs_d2fc_ops); + if (IS_ERR(dbfs_d2fc_file)) + return PTR_ERR(dbfs_d2fc_file); + return 0; } + +void hypfs_vm_exit(void) +{ + if (!MACHINE_IS_VM) + return; + debugfs_remove(dbfs_d2fc_file); +} diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 341aff2687a5..6b120f073043 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -14,8 +14,8 @@ #include <linux/fs.h> #include <linux/namei.h> #include <linux/vfs.h> +#include <linux/slab.h> #include <linux/pagemap.h> -#include <linux/gfp.h> #include <linux/time.h> #include <linux/parser.h> #include <linux/sysfs.h> @@ -46,6 +46,8 @@ static const struct super_operations hypfs_s_ops; /* start of list of all dentries, which have to be deleted on update */ static struct dentry *hypfs_last_dentry; +struct dentry *hypfs_dbfs_dir; + static void hypfs_update_update(struct super_block *sb) { struct hypfs_sb_info *sb_info = sb->s_fs_info; @@ -145,7 +147,7 @@ static int hypfs_open(struct inode *inode, struct file *filp) } mutex_unlock(&fs_info->lock); } - return 0; + return nonseekable_open(inode, filp); } static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov, @@ -288,46 +290,30 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = HYPFS_MAGIC; sb->s_op = &hypfs_s_ops; - if (hypfs_parse_options(data, sb)) { - rc = -EINVAL; - goto err_alloc; - } + if (hypfs_parse_options(data, sb)) + return -EINVAL; root_inode = hypfs_make_inode(sb, S_IFDIR | 0755); - if (!root_inode) { - rc = -ENOMEM; - goto err_alloc; - } + if (!root_inode) + return -ENOMEM; root_inode->i_op = &simple_dir_inode_operations; root_inode->i_fop = &simple_dir_operations; - root_dentry = d_alloc_root(root_inode); + sb->s_root = root_dentry = d_alloc_root(root_inode); if (!root_dentry) { iput(root_inode); - rc = -ENOMEM; - goto err_alloc; + return -ENOMEM; } if (MACHINE_IS_VM) rc = hypfs_vm_create_files(sb, root_dentry); else rc = hypfs_diag_create_files(sb, root_dentry); if (rc) - goto err_tree; + return rc; sbi->update_file = hypfs_create_update_file(sb, root_dentry); - if (IS_ERR(sbi->update_file)) { - rc = PTR_ERR(sbi->update_file); - goto err_tree; - } + if (IS_ERR(sbi->update_file)) + return PTR_ERR(sbi->update_file); hypfs_update_update(sb); - sb->s_root = root_dentry; pr_info("Hypervisor filesystem mounted\n"); return 0; - -err_tree: - hypfs_delete_tree(root_dentry); - d_genocide(root_dentry); - dput(root_dentry); -err_alloc: - kfree(sbi); - return rc; } static int hypfs_get_super(struct file_system_type *fst, int flags, @@ -340,12 +326,12 @@ static void hypfs_kill_super(struct super_block *sb) { struct hypfs_sb_info *sb_info = sb->s_fs_info; - if (sb->s_root) { + if (sb->s_root) hypfs_delete_tree(sb->s_root); + if (sb_info->update_file) hypfs_remove(sb_info->update_file); - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; - } + kfree(sb->s_fs_info); + sb->s_fs_info = NULL; kill_litter_super(sb); } @@ -484,20 +470,22 @@ static int __init hypfs_init(void) { int rc; - if (MACHINE_IS_VM) { - if (hypfs_vm_init()) - /* no diag 2fc, just exit */ - return -ENODATA; - } else { - if (hypfs_diag_init()) { - rc = -ENODATA; - goto fail_diag; - } + hypfs_dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); + if (IS_ERR(hypfs_dbfs_dir)) + return PTR_ERR(hypfs_dbfs_dir); + + if (hypfs_diag_init()) { + rc = -ENODATA; + goto fail_debugfs_remove; + } + if (hypfs_vm_init()) { + rc = -ENODATA; + goto fail_hypfs_diag_exit; } s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); if (!s390_kobj) { rc = -ENOMEM; - goto fail_sysfs; + goto fail_hypfs_vm_exit; } rc = register_filesystem(&hypfs_type); if (rc) @@ -506,18 +494,22 @@ static int __init hypfs_init(void) fail_filesystem: kobject_put(s390_kobj); -fail_sysfs: - if (!MACHINE_IS_VM) - hypfs_diag_exit(); -fail_diag: +fail_hypfs_vm_exit: + hypfs_vm_exit(); +fail_hypfs_diag_exit: + hypfs_diag_exit(); +fail_debugfs_remove: + debugfs_remove(hypfs_dbfs_dir); + pr_err("Initialization of hypfs failed with rc=%i\n", rc); return rc; } static void __exit hypfs_exit(void) { - if (!MACHINE_IS_VM) - hypfs_diag_exit(); + hypfs_diag_exit(); + hypfs_vm_exit(); + debugfs_remove(hypfs_dbfs_dir); unregister_filesystem(&hypfs_type); kobject_put(s390_kobj); } diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index 2a113d6a7dfd..76daea117181 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -15,11 +15,10 @@ #include <linux/compiler.h> #include <linux/types.h> +#include <asm/system.h> #define ATOMIC_INIT(i) { (i) } -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) - #define __CS_LOOP(ptr, op_val, op_string) ({ \ int old_val, new_val; \ asm volatile( \ @@ -35,26 +34,6 @@ new_val; \ }) -#else /* __GNUC__ */ - -#define __CS_LOOP(ptr, op_val, op_string) ({ \ - int old_val, new_val; \ - asm volatile( \ - " l %0,0(%3)\n" \ - "0: lr %1,%0\n" \ - op_string " %1,%4\n" \ - " cs %0,%1,0(%3)\n" \ - " jl 0b" \ - : "=&d" (old_val), "=&d" (new_val), \ - "=m" (((atomic_t *)(ptr))->counter) \ - : "a" (ptr), "d" (op_val), \ - "m" (((atomic_t *)(ptr))->counter) \ - : "cc", "memory"); \ - new_val; \ -}) - -#endif /* __GNUC__ */ - static inline int atomic_read(const atomic_t *v) { barrier(); @@ -101,19 +80,11 @@ static inline void atomic_set_mask(unsigned long mask, atomic_t *v) static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) asm volatile( " cs %0,%2,%1" : "+d" (old), "=Q" (v->counter) : "d" (new), "Q" (v->counter) : "cc", "memory"); -#else /* __GNUC__ */ - asm volatile( - " cs %0,%3,0(%2)" - : "+d" (old), "=m" (v->counter) - : "a" (v), "d" (new), "m" (v->counter) - : "cc", "memory"); -#endif /* __GNUC__ */ return old; } @@ -140,8 +111,6 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) #ifdef CONFIG_64BIT -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) - #define __CSG_LOOP(ptr, op_val, op_string) ({ \ long long old_val, new_val; \ asm volatile( \ @@ -157,26 +126,6 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) new_val; \ }) -#else /* __GNUC__ */ - -#define __CSG_LOOP(ptr, op_val, op_string) ({ \ - long long old_val, new_val; \ - asm volatile( \ - " lg %0,0(%3)\n" \ - "0: lgr %1,%0\n" \ - op_string " %1,%4\n" \ - " csg %0,%1,0(%3)\n" \ - " jl 0b" \ - : "=&d" (old_val), "=&d" (new_val), \ - "=m" (((atomic_t *)(ptr))->counter) \ - : "a" (ptr), "d" (op_val), \ - "m" (((atomic_t *)(ptr))->counter) \ - : "cc", "memory"); \ - new_val; \ -}) - -#endif /* __GNUC__ */ - static inline long long atomic64_read(const atomic64_t *v) { barrier(); @@ -214,19 +163,11 @@ static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v) static inline long long atomic64_cmpxchg(atomic64_t *v, long long old, long long new) { -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) asm volatile( " csg %0,%2,%1" : "+d" (old), "=Q" (v->counter) : "d" (new), "Q" (v->counter) : "cc", "memory"); -#else /* __GNUC__ */ - asm volatile( - " csg %0,%3,0(%2)" - : "+d" (old), "=m" (v->counter) - : "a" (v), "d" (new), "m" (v->counter) - : "cc", "memory"); -#endif /* __GNUC__ */ return old; } @@ -243,10 +184,8 @@ static inline long long atomic64_read(const atomic64_t *v) register_pair rp; asm volatile( - " lm %0,%N0,0(%1)" - : "=&d" (rp) - : "a" (&v->counter), "m" (v->counter) - ); + " lm %0,%N0,%1" + : "=&d" (rp) : "Q" (v->counter) ); return rp.pair; } @@ -255,10 +194,8 @@ static inline void atomic64_set(atomic64_t *v, long long i) register_pair rp = {.pair = i}; asm volatile( - " stm %1,%N1,0(%2)" - : "=m" (v->counter) - : "d" (rp), "a" (&v->counter) - ); + " stm %1,%N1,%0" + : "=Q" (v->counter) : "d" (rp) ); } static inline long long atomic64_xchg(atomic64_t *v, long long new) @@ -267,11 +204,11 @@ static inline long long atomic64_xchg(atomic64_t *v, long long new) register_pair rp_old; asm volatile( - " lm %0,%N0,0(%2)\n" - "0: cds %0,%3,0(%2)\n" + " lm %0,%N0,%1\n" + "0: cds %0,%2,%1\n" " jl 0b\n" - : "=&d" (rp_old), "+m" (v->counter) - : "a" (&v->counter), "d" (rp_new) + : "=&d" (rp_old), "=Q" (v->counter) + : "d" (rp_new), "Q" (v->counter) : "cc"); return rp_old.pair; } @@ -283,9 +220,9 @@ static inline long long atomic64_cmpxchg(atomic64_t *v, register_pair rp_new = {.pair = new}; asm volatile( - " cds %0,%3,0(%2)" - : "+&d" (rp_old), "+m" (v->counter) - : "a" (&v->counter), "d" (rp_new) + " cds %0,%2,%1" + : "+&d" (rp_old), "=Q" (v->counter) + : "d" (rp_new), "Q" (v->counter) : "cc"); return rp_old.pair; } @@ -338,6 +275,7 @@ static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v) static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) { long long c, old; + c = atomic64_read(v); for (;;) { if (unlikely(c == u)) @@ -350,6 +288,23 @@ static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u) return c != u; } +static inline long long atomic64_dec_if_positive(atomic64_t *v) +{ + long long c, old, dec; + + c = atomic64_read(v); + for (;;) { + dec = c - 1; + if (unlikely(dec < 0)) + break; + old = atomic64_cmpxchg((v), c, dec); + if (likely(old == c)) + break; + c = old; + } + return dec; +} + #define atomic64_add(_i, _v) atomic64_add_return(_i, _v) #define atomic64_add_negative(_i, _v) (atomic64_add_return(_i, _v) < 0) #define atomic64_inc(_v) atomic64_add_return(1, _v) diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h index b30606f6d523..2e05972c5085 100644 --- a/arch/s390/include/asm/bitops.h +++ b/arch/s390/include/asm/bitops.h @@ -71,8 +71,6 @@ extern const char _sb_findmap[]; #define __BITOPS_AND "nr" #define __BITOPS_XOR "xr" -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) - #define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ asm volatile( \ " l %0,%2\n" \ @@ -85,22 +83,6 @@ extern const char _sb_findmap[]; : "d" (__val), "Q" (*(unsigned long *) __addr) \ : "cc"); -#else /* __GNUC__ */ - -#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ - asm volatile( \ - " l %0,0(%4)\n" \ - "0: lr %1,%0\n" \ - __op_string " %1,%3\n" \ - " cs %0,%1,0(%4)\n" \ - " jl 0b" \ - : "=&d" (__old), "=&d" (__new), \ - "=m" (*(unsigned long *) __addr) \ - : "d" (__val), "a" (__addr), \ - "m" (*(unsigned long *) __addr) : "cc"); - -#endif /* __GNUC__ */ - #else /* __s390x__ */ #define __BITOPS_ALIGN 7 @@ -109,8 +91,6 @@ extern const char _sb_findmap[]; #define __BITOPS_AND "ngr" #define __BITOPS_XOR "xgr" -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) - #define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ asm volatile( \ " lg %0,%2\n" \ @@ -123,23 +103,6 @@ extern const char _sb_findmap[]; : "d" (__val), "Q" (*(unsigned long *) __addr) \ : "cc"); -#else /* __GNUC__ */ - -#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \ - asm volatile( \ - " lg %0,0(%4)\n" \ - "0: lgr %1,%0\n" \ - __op_string " %1,%3\n" \ - " csg %0,%1,0(%4)\n" \ - " jl 0b" \ - : "=&d" (__old), "=&d" (__new), \ - "=m" (*(unsigned long *) __addr) \ - : "d" (__val), "a" (__addr), \ - "m" (*(unsigned long *) __addr) : "cc"); - - -#endif /* __GNUC__ */ - #endif /* __s390x__ */ #define __BITOPS_WORDS(bits) (((bits)+__BITOPS_WORDSIZE-1)/__BITOPS_WORDSIZE) @@ -261,9 +224,8 @@ static inline void __set_bit(unsigned long nr, volatile unsigned long *ptr) addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); asm volatile( - " oc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) : "a" (addr), - "a" (_oi_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc" ); + " oc %O0(1,%R0),%1" + : "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc" ); } static inline void @@ -290,9 +252,8 @@ __clear_bit(unsigned long nr, volatile unsigned long *ptr) addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); asm volatile( - " nc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) : "a" (addr), - "a" (_ni_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc"); + " nc %O0(1,%R0),%1" + : "=Q" (*(char *) addr) : "Q" (_ni_bitmap[nr & 7]) : "cc" ); } static inline void @@ -318,9 +279,8 @@ static inline void __change_bit(unsigned long nr, volatile unsigned long *ptr) addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); asm volatile( - " xc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) : "a" (addr), - "a" (_oi_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc" ); + " xc %O0(1,%R0),%1" + : "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc" ); } static inline void @@ -349,10 +309,9 @@ test_and_set_bit_simple(unsigned long nr, volatile unsigned long *ptr) addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); ch = *(unsigned char *) addr; asm volatile( - " oc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) - : "a" (addr), "a" (_oi_bitmap + (nr & 7)), - "m" (*(char *) addr) : "cc", "memory"); + " oc %O0(1,%R0),%1" + : "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) + : "cc", "memory"); return (ch >> (nr & 7)) & 1; } #define __test_and_set_bit(X,Y) test_and_set_bit_simple(X,Y) @@ -369,10 +328,9 @@ test_and_clear_bit_simple(unsigned long nr, volatile unsigned long *ptr) addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); ch = *(unsigned char *) addr; asm volatile( - " nc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) - : "a" (addr), "a" (_ni_bitmap + (nr & 7)), - "m" (*(char *) addr) : "cc", "memory"); + " nc %O0(1,%R0),%1" + : "=Q" (*(char *) addr) : "Q" (_ni_bitmap[nr & 7]) + : "cc", "memory"); return (ch >> (nr & 7)) & 1; } #define __test_and_clear_bit(X,Y) test_and_clear_bit_simple(X,Y) @@ -389,10 +347,9 @@ test_and_change_bit_simple(unsigned long nr, volatile unsigned long *ptr) addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3); ch = *(unsigned char *) addr; asm volatile( - " xc 0(1,%1),0(%2)" - : "=m" (*(char *) addr) - : "a" (addr), "a" (_oi_bitmap + (nr & 7)), - "m" (*(char *) addr) : "cc", "memory"); + " xc %O0(1,%R0),%1" + : "=Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) + : "cc", "memory"); return (ch >> (nr & 7)) & 1; } #define __test_and_change_bit(X,Y) test_and_change_bit_simple(X,Y) @@ -591,11 +548,11 @@ static inline unsigned long __load_ulong_le(const unsigned long *p, p = (unsigned long *)((unsigned long) p + offset); #ifndef __s390x__ asm volatile( - " ic %0,0(%1)\n" - " icm %0,2,1(%1)\n" - " icm %0,4,2(%1)\n" - " icm %0,8,3(%1)" - : "=&d" (word) : "a" (p), "m" (*p) : "cc"); + " ic %0,%O1(%R1)\n" + " icm %0,2,%O1+1(%R1)\n" + " icm %0,4,%O1+2(%R1)\n" + " icm %0,8,%O1+3(%R1)" + : "=&d" (word) : "Q" (*p) : "cc"); #else asm volatile( " lrvg %0,%1" diff --git a/arch/s390/include/asm/bug.h b/arch/s390/include/asm/bug.h index b1066b9fb5f8..bf90d1fd97a5 100644 --- a/arch/s390/include/asm/bug.h +++ b/arch/s390/include/asm/bug.h @@ -5,12 +5,6 @@ #ifdef CONFIG_BUG -#ifdef CONFIG_64BIT -#define S390_LONG ".quad" -#else -#define S390_LONG ".long" -#endif - #ifdef CONFIG_DEBUG_BUGVERBOSE #define __EMIT_BUG(x) do { \ @@ -21,7 +15,7 @@ "2: .asciz \""__FILE__"\"\n" \ ".previous\n" \ ".section __bug_table,\"a\"\n" \ - "3:\t" S390_LONG "\t1b,2b\n" \ + "3: .long 1b-3b,2b-3b\n" \ " .short %0,%1\n" \ " .org 3b+%2\n" \ ".previous\n" \ @@ -37,7 +31,7 @@ "0: j 0b+2\n" \ "1:\n" \ ".section __bug_table,\"a\"\n" \ - "2:\t" S390_LONG "\t1b\n" \ + "2: .long 1b-2b\n" \ " .short %0\n" \ " .org 2b+%1\n" \ ".previous\n" \ @@ -52,18 +46,18 @@ unreachable(); \ } while (0) -#define __WARN() do { \ - __EMIT_BUG(BUGFLAG_WARNING); \ +#define __WARN_TAINT(taint) do { \ + __EMIT_BUG(BUGFLAG_TAINT(taint)); \ } while (0) #define WARN_ON(x) ({ \ int __ret_warn_on = !!(x); \ if (__builtin_constant_p(__ret_warn_on)) { \ if (__ret_warn_on) \ - __EMIT_BUG(BUGFLAG_WARNING); \ + __WARN(); \ } else { \ if (unlikely(__ret_warn_on)) \ - __EMIT_BUG(BUGFLAG_WARNING); \ + __WARN(); \ } \ unlikely(__ret_warn_on); \ }) diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index f4bd346a52d3..1c0030f9b890 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h @@ -91,6 +91,14 @@ struct ccw_device { void (*handler) (struct ccw_device *, unsigned long, struct irb *); }; +/* + * Possible CIO actions triggered by the unit check handler. + */ +enum uc_todo { + UC_TODO_RETRY, + UC_TODO_RETRY_ON_NEW_PATH, + UC_TODO_STOP +}; /** * struct ccw driver - device driver for channel attached devices @@ -107,6 +115,7 @@ struct ccw_device { * @freeze: callback for freezing during hibernation snapshotting * @thaw: undo work done in @freeze * @restore: callback for restoring after hibernation + * @uc_handler: callback for unit check handler * @driver: embedded device driver structure * @name: device driver name */ @@ -124,6 +133,7 @@ struct ccw_driver { int (*freeze)(struct ccw_device *); int (*thaw) (struct ccw_device *); int (*restore)(struct ccw_device *); + enum uc_todo (*uc_handler) (struct ccw_device *, struct irb *); struct device_driver driver; char *name; }; diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h index e85679af54dd..e34347d567a6 100644 --- a/arch/s390/include/asm/cio.h +++ b/arch/s390/include/asm/cio.h @@ -20,7 +20,7 @@ /** * struct ccw1 - channel command word * @cmd_code: command code - * @flags: flags, like IDA adressing, etc. + * @flags: flags, like IDA addressing, etc. * @count: byte count * @cda: data address * diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index 01a08020bc0e..104f2007f097 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -35,7 +35,8 @@ extern long psw32_user_bits; -#define COMPAT_USER_HZ 100 +#define COMPAT_USER_HZ 100 +#define COMPAT_UTS_MACHINE "s390\0\0\0\0" typedef u32 compat_size_t; typedef s32 compat_ssize_t; diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index 258ba88b7b50..8b1a52a137c5 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h @@ -188,15 +188,16 @@ struct s390_idle_data { DECLARE_PER_CPU(struct s390_idle_data, s390_idle); -void vtime_start_cpu(void); +void vtime_start_cpu(__u64 int_clock, __u64 enter_timer); cputime64_t s390_get_idle_time(int cpu); #define arch_idle_time(cpu) s390_get_idle_time(cpu) -static inline void s390_idle_check(void) +static inline void s390_idle_check(struct pt_regs *regs, __u64 int_clock, + __u64 enter_timer) { - if ((&__get_cpu_var(s390_idle))->idle_enter != 0ULL) - vtime_start_cpu(); + if (regs->psw.mask & PSW_MASK_WAIT) + vtime_start_cpu(int_clock, enter_timer); } static inline int s390_nohz_delay(int cpu) diff --git a/arch/s390/include/asm/crw.h b/arch/s390/include/asm/crw.h index 2185a6d619d3..749a97e61bea 100644 --- a/arch/s390/include/asm/crw.h +++ b/arch/s390/include/asm/crw.h @@ -32,6 +32,7 @@ typedef void (*crw_handler_t)(struct crw *, struct crw *, int); extern int crw_register_handler(int rsc, crw_handler_t handler); extern void crw_unregister_handler(int rsc); extern void crw_handle_channel_report(void); +void crw_wait_for_channel_report(void); #define NR_RSCS 16 diff --git a/arch/s390/include/asm/etr.h b/arch/s390/include/asm/etr.h index 80ef58c61970..538e1b36a726 100644 --- a/arch/s390/include/asm/etr.h +++ b/arch/s390/include/asm/etr.h @@ -145,11 +145,11 @@ static inline int etr_setr(struct etr_eacr *ctrl) int rc = -ENOSYS; asm volatile( - " .insn s,0xb2160000,0(%2)\n" + " .insn s,0xb2160000,%1\n" "0: la %0,0\n" "1:\n" EX_TABLE(0b,1b) - : "+d" (rc) : "m" (*ctrl), "a" (ctrl)); + : "+d" (rc) : "Q" (*ctrl)); return rc; } @@ -159,11 +159,11 @@ static inline int etr_stetr(struct etr_aib *aib) int rc = -ENOSYS; asm volatile( - " .insn s,0xb2170000,0(%2)\n" + " .insn s,0xb2170000,%1\n" "0: la %0,0\n" "1:\n" EX_TABLE(0b,1b) - : "+d" (rc) : "m" (*aib), "a" (aib)); + : "+d" (rc) : "Q" (*aib)); return rc; } @@ -174,11 +174,11 @@ static inline int etr_steai(struct etr_aib *aib, unsigned int func) int rc = -ENOSYS; asm volatile( - " .insn s,0xb2b30000,0(%2)\n" + " .insn s,0xb2b30000,%1\n" "0: la %0,0\n" "1:\n" EX_TABLE(0b,1b) - : "+d" (rc) : "m" (*aib), "a" (aib), "d" (reg0)); + : "+d" (rc) : "Q" (*aib), "d" (reg0)); return rc; } diff --git a/arch/s390/include/asm/irqflags.h b/arch/s390/include/asm/irqflags.h index c2fb432f576a..15b3ac253898 100644 --- a/arch/s390/include/asm/irqflags.h +++ b/arch/s390/include/asm/irqflags.h @@ -8,8 +8,6 @@ #include <linux/types.h> -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) - /* store then or system mask. */ #define __raw_local_irq_stosm(__or) \ ({ \ @@ -36,40 +34,6 @@ asm volatile("ssm %0" : : "Q" (__mask) : "memory"); \ }) -#else /* __GNUC__ */ - -/* store then or system mask. */ -#define __raw_local_irq_stosm(__or) \ -({ \ - unsigned long __mask; \ - asm volatile( \ - " stosm 0(%1),%2" \ - : "=m" (__mask) \ - : "a" (&__mask), "i" (__or) : "memory"); \ - __mask; \ -}) - -/* store then and system mask. */ -#define __raw_local_irq_stnsm(__and) \ -({ \ - unsigned long __mask; \ - asm volatile( \ - " stnsm 0(%1),%2" \ - : "=m" (__mask) \ - : "a" (&__mask), "i" (__and) : "memory"); \ - __mask; \ -}) - -/* set system mask. */ -#define __raw_local_irq_ssm(__mask) \ -({ \ - asm volatile( \ - " ssm 0(%0)" \ - : : "a" (&__mask), "m" (__mask) : "memory"); \ -}) - -#endif /* __GNUC__ */ - /* interrupt control.. */ static inline unsigned long raw_local_irq_enable(void) { diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index f2ef4b619ce1..0f97ef2d92ac 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h @@ -1,141 +1,16 @@ /* - * include/asm-s390/lowcore.h - * - * 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), - * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + * Copyright IBM Corp. 1999,2010 + * Author(s): Hartmut Penner <hp@de.ibm.com>, + * Martin Schwidefsky <schwidefsky@de.ibm.com>, + * Denis Joseph Barrow, */ #ifndef _ASM_S390_LOWCORE_H #define _ASM_S390_LOWCORE_H -#define __LC_IPL_PARMBLOCK_PTR 0x0014 -#define __LC_EXT_PARAMS 0x0080 -#define __LC_CPU_ADDRESS 0x0084 -#define __LC_EXT_INT_CODE 0x0086 - -#define __LC_SVC_ILC 0x0088 -#define __LC_SVC_INT_CODE 0x008a -#define __LC_PGM_ILC 0x008c -#define __LC_PGM_INT_CODE 0x008e - -#define __LC_PER_ATMID 0x0096 -#define __LC_PER_ADDRESS 0x0098 -#define __LC_PER_ACCESS_ID 0x00a1 -#define __LC_AR_MODE_ID 0x00a3 - -#define __LC_SUBCHANNEL_ID 0x00b8 -#define __LC_SUBCHANNEL_NR 0x00ba -#define __LC_IO_INT_PARM 0x00bc -#define __LC_IO_INT_WORD 0x00c0 -#define __LC_STFL_FAC_LIST 0x00c8 -#define __LC_MCCK_CODE 0x00e8 - -#define __LC_DUMP_REIPL 0x0e00 - -#ifndef __s390x__ -#define __LC_EXT_OLD_PSW 0x0018 -#define __LC_SVC_OLD_PSW 0x0020 -#define __LC_PGM_OLD_PSW 0x0028 -#define __LC_MCK_OLD_PSW 0x0030 -#define __LC_IO_OLD_PSW 0x0038 -#define __LC_EXT_NEW_PSW 0x0058 -#define __LC_SVC_NEW_PSW 0x0060 -#define __LC_PGM_NEW_PSW 0x0068 -#define __LC_MCK_NEW_PSW 0x0070 -#define __LC_IO_NEW_PSW 0x0078 -#define __LC_SAVE_AREA 0x0200 -#define __LC_RETURN_PSW 0x0240 -#define __LC_RETURN_MCCK_PSW 0x0248 -#define __LC_SYNC_ENTER_TIMER 0x0250 -#define __LC_ASYNC_ENTER_TIMER 0x0258 -#define __LC_EXIT_TIMER 0x0260 -#define __LC_USER_TIMER 0x0268 -#define __LC_SYSTEM_TIMER 0x0270 -#define __LC_STEAL_TIMER 0x0278 -#define __LC_LAST_UPDATE_TIMER 0x0280 -#define __LC_LAST_UPDATE_CLOCK 0x0288 -#define __LC_CURRENT 0x0290 -#define __LC_THREAD_INFO 0x0294 -#define __LC_KERNEL_STACK 0x0298 -#define __LC_ASYNC_STACK 0x029c -#define __LC_PANIC_STACK 0x02a0 -#define __LC_KERNEL_ASCE 0x02a4 -#define __LC_USER_ASCE 0x02a8 -#define __LC_USER_EXEC_ASCE 0x02ac -#define __LC_CPUID 0x02b0 -#define __LC_INT_CLOCK 0x02c8 -#define __LC_MACHINE_FLAGS 0x02d8 -#define __LC_FTRACE_FUNC 0x02dc -#define __LC_IRB 0x0300 -#define __LC_PFAULT_INTPARM 0x0080 -#define __LC_CPU_TIMER_SAVE_AREA 0x00d8 -#define __LC_CLOCK_COMP_SAVE_AREA 0x00e0 -#define __LC_PSW_SAVE_AREA 0x0100 -#define __LC_PREFIX_SAVE_AREA 0x0108 -#define __LC_AREGS_SAVE_AREA 0x0120 -#define __LC_FPREGS_SAVE_AREA 0x0160 -#define __LC_GPREGS_SAVE_AREA 0x0180 -#define __LC_CREGS_SAVE_AREA 0x01c0 -#else /* __s390x__ */ -#define __LC_LAST_BREAK 0x0110 -#define __LC_EXT_OLD_PSW 0x0130 -#define __LC_SVC_OLD_PSW 0x0140 -#define __LC_PGM_OLD_PSW 0x0150 -#define __LC_MCK_OLD_PSW 0x0160 -#define __LC_IO_OLD_PSW 0x0170 -#define __LC_RESTART_PSW 0x01a0 -#define __LC_EXT_NEW_PSW 0x01b0 -#define __LC_SVC_NEW_PSW 0x01c0 -#define __LC_PGM_NEW_PSW 0x01d0 -#define __LC_MCK_NEW_PSW 0x01e0 -#define __LC_IO_NEW_PSW 0x01f0 -#define __LC_SAVE_AREA 0x0200 -#define __LC_RETURN_PSW 0x0280 -#define __LC_RETURN_MCCK_PSW 0x0290 -#define __LC_SYNC_ENTER_TIMER 0x02a0 -#define __LC_ASYNC_ENTER_TIMER 0x02a8 -#define __LC_EXIT_TIMER 0x02b0 -#define __LC_USER_TIMER 0x02b8 -#define __LC_SYSTEM_TIMER 0x02c0 -#define __LC_STEAL_TIMER 0x02c8 -#define __LC_LAST_UPDATE_TIMER 0x02d0 -#define __LC_LAST_UPDATE_CLOCK 0x02d8 -#define __LC_CURRENT 0x02e0 -#define __LC_THREAD_INFO 0x02e8 -#define __LC_KERNEL_STACK 0x02f0 -#define __LC_ASYNC_STACK 0x02f8 -#define __LC_PANIC_STACK 0x0300 -#define __LC_KERNEL_ASCE 0x0308 -#define __LC_USER_ASCE 0x0310 -#define __LC_USER_EXEC_ASCE 0x0318 -#define __LC_CPUID 0x0320 -#define __LC_INT_CLOCK 0x0340 -#define __LC_VDSO_PER_CPU 0x0350 -#define __LC_MACHINE_FLAGS 0x0358 -#define __LC_FTRACE_FUNC 0x0360 -#define __LC_IRB 0x0380 -#define __LC_PASTE 0x03c0 -#define __LC_PFAULT_INTPARM 0x11b8 -#define __LC_FPREGS_SAVE_AREA 0x1200 -#define __LC_GPREGS_SAVE_AREA 0x1280 -#define __LC_PSW_SAVE_AREA 0x1300 -#define __LC_PREFIX_SAVE_AREA 0x1318 -#define __LC_FP_CREG_SAVE_AREA 0x131c -#define __LC_TODREG_SAVE_AREA 0x1324 -#define __LC_CPU_TIMER_SAVE_AREA 0x1328 -#define __LC_CLOCK_COMP_SAVE_AREA 0x1331 -#define __LC_AREGS_SAVE_AREA 0x1340 -#define __LC_CREGS_SAVE_AREA 0x1380 -#endif /* __s390x__ */ - -#ifndef __ASSEMBLY__ - -#include <asm/cpu.h> -#include <asm/ptrace.h> #include <linux/types.h> +#include <asm/ptrace.h> +#include <asm/cpu.h> void restart_int_handler(void); void ext_int_handler(void); @@ -144,7 +19,12 @@ void pgm_check_handler(void); void mcck_int_handler(void); void io_int_handler(void); -struct save_area_s390 { +#ifdef CONFIG_32BIT + +#define LC_ORDER 0 +#define LC_PAGES 1 + +struct save_area { u32 ext_save; u64 timer; u64 clk_cmp; @@ -156,54 +36,13 @@ struct save_area_s390 { u64 fp_regs[4]; u32 gp_regs[16]; u32 ctrl_regs[16]; -} __attribute__((packed)); - -struct save_area_s390x { - u64 fp_regs[16]; - u64 gp_regs[16]; - u8 psw[16]; - u8 pad1[8]; - u32 pref_reg; - u32 fp_ctrl_reg; - u8 pad2[4]; - u32 tod_reg; - u64 timer; - u64 clk_cmp; - u8 pad3[8]; - u32 acc_regs[16]; - u64 ctrl_regs[16]; -} __attribute__((packed)); - -union save_area { - struct save_area_s390 s390; - struct save_area_s390x s390x; -}; - -#define SAVE_AREA_BASE_S390 0xd4 -#define SAVE_AREA_BASE_S390X 0x1200 - -#ifndef __s390x__ -#define SAVE_AREA_SIZE sizeof(struct save_area_s390) -#define SAVE_AREA_BASE SAVE_AREA_BASE_S390 -#else -#define SAVE_AREA_SIZE sizeof(struct save_area_s390x) -#define SAVE_AREA_BASE SAVE_AREA_BASE_S390X -#endif - -#ifndef __s390x__ -#define LC_ORDER 0 -#else -#define LC_ORDER 1 -#endif - -#define LC_PAGES (1UL << LC_ORDER) +} __packed; -struct _lowcore -{ -#ifndef __s390x__ - /* 0x0000 - 0x01ff: defined by architecture */ +struct _lowcore { psw_t restart_psw; /* 0x0000 */ - __u32 ccw2[4]; /* 0x0008 */ + psw_t restart_old_psw; /* 0x0008 */ + __u8 pad_0x0010[0x0014-0x0010]; /* 0x0010 */ + __u32 ipl_parmblock_ptr; /* 0x0014 */ psw_t external_old_psw; /* 0x0018 */ psw_t svc_old_psw; /* 0x0020 */ psw_t program_old_psw; /* 0x0028 */ @@ -229,7 +68,9 @@ struct _lowcore __u32 monitor_code; /* 0x009c */ __u8 exc_access_id; /* 0x00a0 */ __u8 per_access_id; /* 0x00a1 */ - __u8 pad_0x00a2[0x00b8-0x00a2]; /* 0x00a2 */ + __u8 op_access_id; /* 0x00a2 */ + __u8 ar_access_id; /* 0x00a3 */ + __u8 pad_0x00a4[0x00b8-0x00a4]; /* 0x00a4 */ __u16 subchannel_id; /* 0x00b8 */ __u16 subchannel_nr; /* 0x00ba */ __u32 io_int_parm; /* 0x00bc */ @@ -245,8 +86,9 @@ struct _lowcore __u32 external_damage_code; /* 0x00f4 */ __u32 failing_storage_address; /* 0x00f8 */ __u8 pad_0x00fc[0x0100-0x00fc]; /* 0x00fc */ - __u32 st_status_fixed_logout[4]; /* 0x0100 */ - __u8 pad_0x0110[0x0120-0x0110]; /* 0x0110 */ + psw_t psw_save_area; /* 0x0100 */ + __u32 prefixreg_save_area; /* 0x0108 */ + __u8 pad_0x010c[0x0120-0x010c]; /* 0x010c */ /* CPU register save area: defined by architecture */ __u32 access_regs_save_area[16]; /* 0x0120 */ @@ -262,43 +104,44 @@ struct _lowcore /* CPU time accounting values */ __u64 sync_enter_timer; /* 0x0250 */ __u64 async_enter_timer; /* 0x0258 */ - __u64 exit_timer; /* 0x0260 */ - __u64 user_timer; /* 0x0268 */ - __u64 system_timer; /* 0x0270 */ - __u64 steal_timer; /* 0x0278 */ - __u64 last_update_timer; /* 0x0280 */ - __u64 last_update_clock; /* 0x0288 */ + __u64 mcck_enter_timer; /* 0x0260 */ + __u64 exit_timer; /* 0x0268 */ + __u64 user_timer; /* 0x0270 */ + __u64 system_timer; /* 0x0278 */ + __u64 steal_timer; /* 0x0280 */ + __u64 last_update_timer; /* 0x0288 */ + __u64 last_update_clock; /* 0x0290 */ /* Current process. */ - __u32 current_task; /* 0x0290 */ - __u32 thread_info; /* 0x0294 */ - __u32 kernel_stack; /* 0x0298 */ + __u32 current_task; /* 0x0298 */ + __u32 thread_info; /* 0x029c */ + __u32 kernel_stack; /* 0x02a0 */ /* Interrupt and panic stack. */ - __u32 async_stack; /* 0x029c */ - __u32 panic_stack; /* 0x02a0 */ + __u32 async_stack; /* 0x02a4 */ + __u32 panic_stack; /* 0x02a8 */ /* Address space pointer. */ - __u32 kernel_asce; /* 0x02a4 */ - __u32 user_asce; /* 0x02a8 */ - __u32 user_exec_asce; /* 0x02ac */ + __u32 kernel_asce; /* 0x02ac */ + __u32 user_asce; /* 0x02b0 */ + __u32 user_exec_asce; /* 0x02b4 */ /* SMP info area */ - struct cpuid cpu_id; /* 0x02b0 */ __u32 cpu_nr; /* 0x02b8 */ __u32 softirq_pending; /* 0x02bc */ __u32 percpu_offset; /* 0x02c0 */ __u32 ext_call_fast; /* 0x02c4 */ __u64 int_clock; /* 0x02c8 */ - __u64 clock_comparator; /* 0x02d0 */ - __u32 machine_flags; /* 0x02d8 */ - __u32 ftrace_func; /* 0x02dc */ - __u8 pad_0x02f0[0x0300-0x02f0]; /* 0x02f0 */ + __u64 mcck_clock; /* 0x02d0 */ + __u64 clock_comparator; /* 0x02d8 */ + __u32 machine_flags; /* 0x02e0 */ + __u32 ftrace_func; /* 0x02e4 */ + __u8 pad_0x02e8[0x0300-0x02e8]; /* 0x02e8 */ /* Interrupt response block */ __u8 irb[64]; /* 0x0300 */ - __u8 pad_0x0400[0x0e00-0x0400]; /* 0x0400 */ + __u8 pad_0x0340[0x0e00-0x0340]; /* 0x0340 */ /* * 0xe00 contains the address of the IPL Parameter Information @@ -310,10 +153,32 @@ struct _lowcore /* Align to the top 1k of prefix area */ __u8 pad_0x0e08[0x1000-0x0e08]; /* 0x0e08 */ -#else /* !__s390x__ */ - /* 0x0000 - 0x01ff: defined by architecture */ - __u32 ccw1[2]; /* 0x0000 */ - __u32 ccw2[4]; /* 0x0008 */ +} __packed; + +#else /* CONFIG_32BIT */ + +#define LC_ORDER 1 +#define LC_PAGES 2 + +struct save_area { + u64 fp_regs[16]; + u64 gp_regs[16]; + u8 psw[16]; + u8 pad1[8]; + u32 pref_reg; + u32 fp_ctrl_reg; + u8 pad2[4]; + u32 tod_reg; + u64 timer; + u64 clk_cmp; + u8 pad3[8]; + u32 acc_regs[16]; + u64 ctrl_regs[16]; +} __packed; + +struct _lowcore { + __u8 pad_0x0000[0x0014-0x0000]; /* 0x0000 */ + __u32 ipl_parmblock_ptr; /* 0x0014 */ __u8 pad_0x0018[0x0080-0x0018]; /* 0x0018 */ __u32 ext_params; /* 0x0080 */ __u16 cpu_addr; /* 0x0084 */ @@ -325,14 +190,14 @@ struct _lowcore __u32 data_exc_code; /* 0x0090 */ __u16 mon_class_num; /* 0x0094 */ __u16 per_perc_atmid; /* 0x0096 */ - addr_t per_address; /* 0x0098 */ + __u64 per_address; /* 0x0098 */ __u8 exc_access_id; /* 0x00a0 */ __u8 per_access_id; /* 0x00a1 */ __u8 op_access_id; /* 0x00a2 */ __u8 ar_access_id; /* 0x00a3 */ __u8 pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */ - addr_t trans_exc_code; /* 0x00a8 */ - addr_t monitor_code; /* 0x00b0 */ + __u64 trans_exc_code; /* 0x00a8 */ + __u64 monitor_code; /* 0x00b0 */ __u16 subchannel_id; /* 0x00b8 */ __u16 subchannel_nr; /* 0x00ba */ __u32 io_int_parm; /* 0x00bc */ @@ -343,8 +208,10 @@ struct _lowcore __u32 mcck_interruption_code[2]; /* 0x00e8 */ __u8 pad_0x00f0[0x00f4-0x00f0]; /* 0x00f0 */ __u32 external_damage_code; /* 0x00f4 */ - addr_t failing_storage_address; /* 0x00f8 */ - __u8 pad_0x0100[0x0120-0x0100]; /* 0x0100 */ + __u64 failing_storage_address; /* 0x00f8 */ + __u8 pad_0x0100[0x0110-0x0100]; /* 0x0100 */ + __u64 breaking_event_addr; /* 0x0110 */ + __u8 pad_0x0118[0x0120-0x0118]; /* 0x0118 */ psw_t restart_old_psw; /* 0x0120 */ psw_t external_old_psw; /* 0x0130 */ psw_t svc_old_psw; /* 0x0140 */ @@ -367,39 +234,41 @@ struct _lowcore /* CPU accounting and timing values. */ __u64 sync_enter_timer; /* 0x02a0 */ __u64 async_enter_timer; /* 0x02a8 */ - __u64 exit_timer; /* 0x02b0 */ - __u64 user_timer; /* 0x02b8 */ - __u64 system_timer; /* 0x02c0 */ - __u64 steal_timer; /* 0x02c8 */ - __u64 last_update_timer; /* 0x02d0 */ - __u64 last_update_clock; /* 0x02d8 */ + __u64 mcck_enter_timer; /* 0x02b0 */ + __u64 exit_timer; /* 0x02b8 */ + __u64 user_timer; /* 0x02c0 */ + __u64 system_timer; /* 0x02c8 */ + __u64 steal_timer; /* 0x02d0 */ + __u64 last_update_timer; /* 0x02d8 */ + __u64 last_update_clock; /* 0x02e0 */ /* Current process. */ - __u64 current_task; /* 0x02e0 */ - __u64 thread_info; /* 0x02e8 */ - __u64 kernel_stack; /* 0x02f0 */ + __u64 current_task; /* 0x02e8 */ + __u64 thread_info; /* 0x02f0 */ + __u64 kernel_stack; /* 0x02f8 */ /* Interrupt and panic stack. */ - __u64 async_stack; /* 0x02f8 */ - __u64 panic_stack; /* 0x0300 */ + __u64 async_stack; /* 0x0300 */ + __u64 panic_stack; /* 0x0308 */ /* Address space pointer. */ - __u64 kernel_asce; /* 0x0308 */ - __u64 user_asce; /* 0x0310 */ - __u64 user_exec_asce; /* 0x0318 */ + __u64 kernel_asce; /* 0x0310 */ + __u64 user_asce; /* 0x0318 */ + __u64 user_exec_asce; /* 0x0320 */ /* SMP info area */ - struct cpuid cpu_id; /* 0x0320 */ __u32 cpu_nr; /* 0x0328 */ __u32 softirq_pending; /* 0x032c */ __u64 percpu_offset; /* 0x0330 */ __u64 ext_call_fast; /* 0x0338 */ __u64 int_clock; /* 0x0340 */ - __u64 clock_comparator; /* 0x0348 */ - __u64 vdso_per_cpu_data; /* 0x0350 */ - __u64 machine_flags; /* 0x0358 */ - __u64 ftrace_func; /* 0x0360 */ - __u8 pad_0x0368[0x0380-0x0368]; /* 0x0368 */ + __u64 mcck_clock; /* 0x0348 */ + __u64 clock_comparator; /* 0x0350 */ + __u64 vdso_per_cpu_data; /* 0x0358 */ + __u64 machine_flags; /* 0x0360 */ + __u64 ftrace_func; /* 0x0368 */ + __u64 sie_hook; /* 0x0370 */ + __u64 cmf_hpp; /* 0x0378 */ /* Interrupt response block. */ __u8 irb[64]; /* 0x0380 */ @@ -425,7 +294,7 @@ struct _lowcore /* CPU register save area: defined by architecture */ __u64 floating_pt_save_area[16]; /* 0x1200 */ __u64 gpregs_save_area[16]; /* 0x1280 */ - __u32 st_status_fixed_logout[4]; /* 0x1300 */ + psw_t psw_save_area; /* 0x1300 */ __u8 pad_0x1310[0x1318-0x1310]; /* 0x1310 */ __u32 prefixreg_save_area; /* 0x1318 */ __u32 fpt_creg_save_area; /* 0x131c */ @@ -439,10 +308,12 @@ struct _lowcore /* align to the top of the prefix area */ __u8 pad_0x1400[0x2000-0x1400]; /* 0x1400 */ -#endif /* !__s390x__ */ -} __attribute__((packed)); /* End structure*/ +} __packed; + +#endif /* CONFIG_32BIT */ #define S390_lowcore (*((struct _lowcore *) 0)) + extern struct _lowcore *lowcore_ptr[]; static inline void set_prefix(__u32 address) @@ -458,6 +329,4 @@ static inline __u32 store_prefix(void) return address; } -#endif - -#endif +#endif /* _ASM_S390_LOWCORE_H */ diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h index 5e9daf5d7f22..af650fb47206 100644 --- a/arch/s390/include/asm/page.h +++ b/arch/s390/include/asm/page.h @@ -107,9 +107,6 @@ typedef pte_t *pgtable_t; #define __pgd(x) ((pgd_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } ) -/* default storage key used for all pages */ -extern unsigned int default_storage_key; - static inline void page_set_storage_key(unsigned long addr, unsigned int skey) { diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index e2fa79cf0614..89a504c3f12e 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -43,7 +43,7 @@ extern void vmem_map_init(void); * The S390 doesn't have any external MMU info: the kernel page * tables contain all the necessary information. */ -#define update_mmu_cache(vma, address, pte) do { } while (0) +#define update_mmu_cache(vma, address, ptep) do { } while (0) /* * ZERO_PAGE is a global shared page that is always zero: used @@ -105,7 +105,7 @@ extern char empty_zero_page[PAGE_SIZE]; #ifndef __ASSEMBLY__ /* * The vmalloc area will always be on the topmost area of the kernel - * mapping. We reserve 96MB (31bit) / 1GB (64bit) for vmalloc, + * mapping. We reserve 96MB (31bit) / 128GB (64bit) for vmalloc, * which should be enough for any sane case. * By putting vmalloc at the top, we maximise the gap between physical * memory and vmalloc to catch misplaced memory accesses. As a side @@ -120,8 +120,8 @@ extern unsigned long VMALLOC_START; #define VMALLOC_END 0x7e000000UL #define VMEM_MAP_END 0x80000000UL #else /* __s390x__ */ -#define VMALLOC_SIZE (1UL << 30) -#define VMALLOC_END 0x3e040000000UL +#define VMALLOC_SIZE (128UL << 30) +#define VMALLOC_END 0x3e000000000UL #define VMEM_MAP_END 0x40000000000UL #endif /* __s390x__ */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index b42715458312..73e259834e10 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -28,7 +28,7 @@ static inline void get_cpu_id(struct cpuid *ptr) { - asm volatile("stidp 0(%1)" : "=m" (*ptr) : "a" (ptr)); + asm volatile("stidp %0" : "=Q" (*ptr)); } extern void s390_adjust_jiffies(void); @@ -184,9 +184,9 @@ static inline void psw_set_key(unsigned int key) static inline void __load_psw(psw_t psw) { #ifndef __s390x__ - asm volatile("lpsw 0(%0)" : : "a" (&psw), "m" (psw) : "cc"); + asm volatile("lpsw %0" : : "Q" (psw) : "cc"); #else - asm volatile("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc"); + asm volatile("lpswe %0" : : "Q" (psw) : "cc"); #endif } @@ -206,17 +206,17 @@ static inline void __load_psw_mask (unsigned long mask) asm volatile( " basr %0,0\n" "0: ahi %0,1f-0b\n" - " st %0,4(%1)\n" - " lpsw 0(%1)\n" + " st %0,%O1+4(%R1)\n" + " lpsw %1\n" "1:" - : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc"); + : "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc"); #else /* __s390x__ */ asm volatile( " larl %0,1f\n" - " stg %0,8(%1)\n" - " lpswe 0(%1)\n" + " stg %0,%O1+8(%R1)\n" + " lpswe %1\n" "1:" - : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc"); + : "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc"); #endif /* __s390x__ */ } diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 95dcf183a28d..e2c218dc68a6 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h @@ -328,8 +328,8 @@ struct pt_regs psw_t psw; unsigned long gprs[NUM_GPRS]; unsigned long orig_gpr2; - unsigned short svcnr; unsigned short ilc; + unsigned short svcnr; }; #endif @@ -436,6 +436,7 @@ typedef struct #define PTRACE_PEEKDATA_AREA 0x5003 #define PTRACE_POKETEXT_AREA 0x5004 #define PTRACE_POKEDATA_AREA 0x5005 +#define PTRACE_GET_LAST_BREAK 0x5006 /* * PT_PROT definition is loosely based on hppa bsd definition in @@ -489,16 +490,24 @@ struct user_regs_struct * These are defined as per linux/ptrace.h, which see. */ #define arch_has_single_step() (1) -struct task_struct; -extern void user_enable_single_step(struct task_struct *); -extern void user_disable_single_step(struct task_struct *); +extern void show_regs(struct pt_regs * regs); #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) #define user_stack_pointer(regs)((regs)->gprs[15]) #define regs_return_value(regs)((regs)->gprs[2]) #define profile_pc(regs) instruction_pointer(regs) -extern void show_regs(struct pt_regs * regs); + +int regs_query_register_offset(const char *name); +const char *regs_query_register_name(unsigned int offset); +unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset); +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n); + +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ + return regs->gprs[15] & PSW_ADDR_INSN; +} + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 79d849f014f0..0eaae6260274 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -13,7 +13,8 @@ #include <asm/cio.h> #include <asm/ccwdev.h> -#define QDIO_MAX_QUEUES_PER_IRQ 32 +/* only use 4 queues to save some cachelines */ +#define QDIO_MAX_QUEUES_PER_IRQ 4 #define QDIO_MAX_BUFFERS_PER_Q 128 #define QDIO_MAX_BUFFERS_MASK (QDIO_MAX_BUFFERS_PER_Q - 1) #define QDIO_MAX_ELEMENTS_PER_BUFFER 16 @@ -320,11 +321,6 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, #define QDIO_ERROR_ACTIVATE_CHECK_CONDITION 0x40 #define QDIO_ERROR_SLSB_STATE 0x80 -/* for qdio_initialize */ -#define QDIO_INBOUND_0COPY_SBALS 0x01 -#define QDIO_OUTBOUND_0COPY_SBALS 0x02 -#define QDIO_USE_OUTBOUND_PCIS 0x04 - /* for qdio_cleanup */ #define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01 #define QDIO_FLAG_CLEANUP_USING_HALT 0x02 @@ -343,7 +339,6 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, * @input_handler: handler to be called for input queues * @output_handler: handler to be called for output queues * @int_parm: interruption parameter - * @flags: initialization flags * @input_sbal_addr_array: address of no_input_qs * 128 pointers * @output_sbal_addr_array: address of no_output_qs * 128 pointers */ @@ -360,7 +355,6 @@ struct qdio_initialize { qdio_handler_t *input_handler; qdio_handler_t *output_handler; unsigned long int_parm; - unsigned long flags; void **input_sbal_addr_array; void **output_sbal_addr_array; }; @@ -374,14 +368,12 @@ struct qdio_initialize { #define QDIO_FLAG_SYNC_OUTPUT 0x02 #define QDIO_FLAG_PCI_OUT 0x10 -extern int qdio_initialize(struct qdio_initialize *); extern int qdio_allocate(struct qdio_initialize *); extern int qdio_establish(struct qdio_initialize *); extern int qdio_activate(struct ccw_device *); extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, int q_nr, unsigned int bufnr, unsigned int count); -extern int qdio_cleanup(struct ccw_device*, int); extern int qdio_shutdown(struct ccw_device*, int); extern int qdio_free(struct ccw_device *); extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*); diff --git a/arch/s390/include/asm/rwsem.h b/arch/s390/include/asm/rwsem.h index 9d2a17971805..423fdda2322d 100644 --- a/arch/s390/include/asm/rwsem.h +++ b/arch/s390/include/asm/rwsem.h @@ -124,21 +124,21 @@ static inline void __down_read(struct rw_semaphore *sem) asm volatile( #ifndef __s390x__ - " l %0,0(%3)\n" + " l %0,%2\n" "0: lr %1,%0\n" - " ahi %1,%5\n" - " cs %0,%1,0(%3)\n" + " ahi %1,%4\n" + " cs %0,%1,%2\n" " jl 0b" #else /* __s390x__ */ - " lg %0,0(%3)\n" + " lg %0,%2\n" "0: lgr %1,%0\n" - " aghi %1,%5\n" - " csg %0,%1,0(%3)\n" + " aghi %1,%4\n" + " csg %0,%1,%2\n" " jl 0b" #endif /* __s390x__ */ - : "=&d" (old), "=&d" (new), "=m" (sem->count) - : "a" (&sem->count), "m" (sem->count), - "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory"); + : "=&d" (old), "=&d" (new), "=Q" (sem->count) + : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS) + : "cc", "memory"); if (old < 0) rwsem_down_read_failed(sem); } @@ -152,25 +152,25 @@ static inline int __down_read_trylock(struct rw_semaphore *sem) asm volatile( #ifndef __s390x__ - " l %0,0(%3)\n" + " l %0,%2\n" "0: ltr %1,%0\n" " jm 1f\n" - " ahi %1,%5\n" - " cs %0,%1,0(%3)\n" + " ahi %1,%4\n" + " cs %0,%1,%2\n" " jl 0b\n" "1:" #else /* __s390x__ */ - " lg %0,0(%3)\n" + " lg %0,%2\n" "0: ltgr %1,%0\n" " jm 1f\n" - " aghi %1,%5\n" - " csg %0,%1,0(%3)\n" + " aghi %1,%4\n" + " csg %0,%1,%2\n" " jl 0b\n" "1:" #endif /* __s390x__ */ - : "=&d" (old), "=&d" (new), "=m" (sem->count) - : "a" (&sem->count), "m" (sem->count), - "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory"); + : "=&d" (old), "=&d" (new), "=Q" (sem->count) + : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS) + : "cc", "memory"); return old >= 0 ? 1 : 0; } @@ -184,20 +184,20 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) tmp = RWSEM_ACTIVE_WRITE_BIAS; asm volatile( #ifndef __s390x__ - " l %0,0(%3)\n" + " l %0,%2\n" "0: lr %1,%0\n" - " a %1,%5\n" - " cs %0,%1,0(%3)\n" + " a %1,%4\n" + " cs %0,%1,%2\n" " jl 0b" #else /* __s390x__ */ - " lg %0,0(%3)\n" + " lg %0,%2\n" "0: lgr %1,%0\n" - " ag %1,%5\n" - " csg %0,%1,0(%3)\n" + " ag %1,%4\n" + " csg %0,%1,%2\n" " jl 0b" #endif /* __s390x__ */ - : "=&d" (old), "=&d" (new), "=m" (sem->count) - : "a" (&sem->count), "m" (sem->count), "m" (tmp) + : "=&d" (old), "=&d" (new), "=Q" (sem->count) + : "Q" (sem->count), "m" (tmp) : "cc", "memory"); if (old != 0) rwsem_down_write_failed(sem); @@ -217,22 +217,22 @@ static inline int __down_write_trylock(struct rw_semaphore *sem) asm volatile( #ifndef __s390x__ - " l %0,0(%2)\n" + " l %0,%1\n" "0: ltr %0,%0\n" " jnz 1f\n" - " cs %0,%4,0(%2)\n" + " cs %0,%3,%1\n" " jl 0b\n" #else /* __s390x__ */ - " lg %0,0(%2)\n" + " lg %0,%1\n" "0: ltgr %0,%0\n" " jnz 1f\n" - " csg %0,%4,0(%2)\n" + " csg %0,%3,%1\n" " jl 0b\n" #endif /* __s390x__ */ "1:" - : "=&d" (old), "=m" (sem->count) - : "a" (&sem->count), "m" (sem->count), - "d" (RWSEM_ACTIVE_WRITE_BIAS) : "cc", "memory"); + : "=&d" (old), "=Q" (sem->count) + : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS) + : "cc", "memory"); return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0; } @@ -245,21 +245,20 @@ static inline void __up_read(struct rw_semaphore *sem) asm volatile( #ifndef __s390x__ - " l %0,0(%3)\n" + " l %0,%2\n" "0: lr %1,%0\n" - " ahi %1,%5\n" - " cs %0,%1,0(%3)\n" + " ahi %1,%4\n" + " cs %0,%1,%2\n" " jl 0b" #else /* __s390x__ */ - " lg %0,0(%3)\n" + " lg %0,%2\n" "0: lgr %1,%0\n" - " aghi %1,%5\n" - " csg %0,%1,0(%3)\n" + " aghi %1,%4\n" + " csg %0,%1,%2\n" " jl 0b" #endif /* __s390x__ */ - : "=&d" (old), "=&d" (new), "=m" (sem->count) - : "a" (&sem->count), "m" (sem->count), - "i" (-RWSEM_ACTIVE_READ_BIAS) + : "=&d" (old), "=&d" (new), "=Q" (sem->count) + : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS) : "cc", "memory"); if (new < 0) if ((new & RWSEM_ACTIVE_MASK) == 0) @@ -276,20 +275,20 @@ static inline void __up_write(struct rw_semaphore *sem) tmp = -RWSEM_ACTIVE_WRITE_BIAS; asm volatile( #ifndef __s390x__ - " l %0,0(%3)\n" + " l %0,%2\n" "0: lr %1,%0\n" - " a %1,%5\n" - " cs %0,%1,0(%3)\n" + " a %1,%4\n" + " cs %0,%1,%2\n" " jl 0b" #else /* __s390x__ */ - " lg %0,0(%3)\n" + " lg %0,%2\n" "0: lgr %1,%0\n" - " ag %1,%5\n" - " csg %0,%1,0(%3)\n" + " ag %1,%4\n" + " csg %0,%1,%2\n" " jl 0b" #endif /* __s390x__ */ - : "=&d" (old), "=&d" (new), "=m" (sem->count) - : "a" (&sem->count), "m" (sem->count), "m" (tmp) + : "=&d" (old), "=&d" (new), "=Q" (sem->count) + : "Q" (sem->count), "m" (tmp) : "cc", "memory"); if (new < 0) if ((new & RWSEM_ACTIVE_MASK) == 0) @@ -306,20 +305,20 @@ static inline void __downgrade_write(struct rw_semaphore *sem) tmp = -RWSEM_WAITING_BIAS; asm volatile( #ifndef __s390x__ - " l %0,0(%3)\n" + " l %0,%2\n" "0: lr %1,%0\n" - " a %1,%5\n" - " cs %0,%1,0(%3)\n" + " a %1,%4\n" + " cs %0,%1,%2\n" " jl 0b" #else /* __s390x__ */ - " lg %0,0(%3)\n" + " lg %0,%2\n" "0: lgr %1,%0\n" - " ag %1,%5\n" - " csg %0,%1,0(%3)\n" + " ag %1,%4\n" + " csg %0,%1,%2\n" " jl 0b" #endif /* __s390x__ */ - : "=&d" (old), "=&d" (new), "=m" (sem->count) - : "a" (&sem->count), "m" (sem->count), "m" (tmp) + : "=&d" (old), "=&d" (new), "=Q" (sem->count) + : "Q" (sem->count), "m" (tmp) : "cc", "memory"); if (new > 1) rwsem_downgrade_wake(sem); @@ -334,20 +333,20 @@ static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) asm volatile( #ifndef __s390x__ - " l %0,0(%3)\n" + " l %0,%2\n" "0: lr %1,%0\n" - " ar %1,%5\n" - " cs %0,%1,0(%3)\n" + " ar %1,%4\n" + " cs %0,%1,%2\n" " jl 0b" #else /* __s390x__ */ - " lg %0,0(%3)\n" + " lg %0,%2\n" "0: lgr %1,%0\n" - " agr %1,%5\n" - " csg %0,%1,0(%3)\n" + " agr %1,%4\n" + " csg %0,%1,%2\n" " jl 0b" #endif /* __s390x__ */ - : "=&d" (old), "=&d" (new), "=m" (sem->count) - : "a" (&sem->count), "m" (sem->count), "d" (delta) + : "=&d" (old), "=&d" (new), "=Q" (sem->count) + : "Q" (sem->count), "d" (delta) : "cc", "memory"); } @@ -360,20 +359,20 @@ static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) asm volatile( #ifndef __s390x__ - " l %0,0(%3)\n" + " l %0,%2\n" "0: lr %1,%0\n" - " ar %1,%5\n" - " cs %0,%1,0(%3)\n" + " ar %1,%4\n" + " cs %0,%1,%2\n" " jl 0b" #else /* __s390x__ */ - " lg %0,0(%3)\n" + " lg %0,%2\n" "0: lgr %1,%0\n" - " agr %1,%5\n" - " csg %0,%1,0(%3)\n" + " agr %1,%4\n" + " csg %0,%1,%2\n" " jl 0b" #endif /* __s390x__ */ - : "=&d" (old), "=&d" (new), "=m" (sem->count) - : "a" (&sem->count), "m" (sem->count), "d" (delta) + : "=&d" (old), "=&d" (new), "=Q" (sem->count) + : "Q" (sem->count), "d" (delta) : "cc", "memory"); return new; } diff --git a/arch/s390/include/asm/scatterlist.h b/arch/s390/include/asm/scatterlist.h index 35d786fe93ae..be44d94cba54 100644 --- a/arch/s390/include/asm/scatterlist.h +++ b/arch/s390/include/asm/scatterlist.h @@ -1 +1,3 @@ +#define ISA_DMA_THRESHOLD (~0UL) + #include <asm-generic/scatterlist.h> diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 52a779c337e8..25e831d58e1e 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -2,7 +2,7 @@ * include/asm-s390/setup.h * * S390 version - * Copyright IBM Corp. 1999,2006 + * Copyright IBM Corp. 1999,2010 */ #ifndef _ASM_S390_SETUP_H @@ -14,14 +14,14 @@ #ifdef __KERNEL__ -#include <asm/lowcore.h> -#include <asm/types.h> - #define PARMAREA 0x10400 #define MEMORY_CHUNKS 256 #ifndef __ASSEMBLY__ +#include <asm/lowcore.h> +#include <asm/types.h> + #ifndef __s390x__ #define IPL_DEVICE (*(unsigned long *) (0x10404)) #define INITRD_START (*(unsigned long *) (0x1040C)) @@ -71,9 +71,13 @@ extern unsigned int user_mode; #define MACHINE_FLAG_KVM (1UL << 9) #define MACHINE_FLAG_HPAGE (1UL << 10) #define MACHINE_FLAG_PFMF (1UL << 11) +#define MACHINE_FLAG_LPAR (1UL << 12) +#define MACHINE_FLAG_SPP (1UL << 13) #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) +#define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR) + #define MACHINE_HAS_DIAG9C (S390_lowcore.machine_flags & MACHINE_FLAG_DIAG9C) #ifndef __s390x__ @@ -85,6 +89,7 @@ extern unsigned int user_mode; #define MACHINE_HAS_MVCOS (0) #define MACHINE_HAS_HPAGE (0) #define MACHINE_HAS_PFMF (0) +#define MACHINE_HAS_SPP (0) #else /* __s390x__ */ #define MACHINE_HAS_IEEE (1) #define MACHINE_HAS_CSP (1) @@ -94,6 +99,7 @@ extern unsigned int user_mode; #define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS) #define MACHINE_HAS_HPAGE (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE) #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) +#define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) #endif /* __s390x__ */ #define ZFCPDUMP_HSA_SIZE (32UL<<20) diff --git a/arch/s390/include/asm/sigp.h b/arch/s390/include/asm/sigp.h index f72d611f7e13..e3bffd4e2d66 100644 --- a/arch/s390/include/asm/sigp.h +++ b/arch/s390/include/asm/sigp.h @@ -1,24 +1,19 @@ /* - * include/asm-s390/sigp.h + * Routines and structures for signalling other processors. * - * S390 version - * Copyright (C) 1999 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) - * Heiko Carstens (heiko.carstens@de.ibm.com) - * - * sigp.h by D.J. Barrow (c) IBM 1999 - * contains routines / structures for signalling other S/390 processors in an - * SMP configuration. + * Copyright IBM Corp. 1999,2010 + * Author(s): Denis Joseph Barrow, + * Martin Schwidefsky <schwidefsky@de.ibm.com>, + * Heiko Carstens <heiko.carstens@de.ibm.com>, */ -#ifndef __SIGP__ -#define __SIGP__ +#ifndef __ASM_SIGP_H +#define __ASM_SIGP_H #include <asm/system.h> -/* get real cpu address from logical cpu number */ -extern int __cpu_logical_map[]; +/* Get real cpu address from logical cpu number. */ +extern unsigned short __cpu_logical_map[]; static inline int cpu_logical_map(int cpu) { @@ -29,107 +24,108 @@ static inline int cpu_logical_map(int cpu) #endif } -typedef enum -{ - sigp_unassigned=0x0, - sigp_sense, - sigp_external_call, - sigp_emergency_signal, - sigp_start, - sigp_stop, - sigp_restart, - sigp_unassigned1, - sigp_unassigned2, - sigp_stop_and_store_status, - sigp_unassigned3, - sigp_initial_cpu_reset, - sigp_cpu_reset, - sigp_set_prefix, - sigp_store_status_at_address, - sigp_store_extended_status_at_address -} sigp_order_code; - -typedef __u32 sigp_status_word; - -typedef enum -{ - sigp_order_code_accepted=0, - sigp_status_stored, - sigp_busy, - sigp_not_operational -} sigp_ccode; - +enum { + sigp_sense = 1, + sigp_external_call = 2, + sigp_emergency_signal = 3, + sigp_start = 4, + sigp_stop = 5, + sigp_restart = 6, + sigp_stop_and_store_status = 9, + sigp_initial_cpu_reset = 11, + sigp_cpu_reset = 12, + sigp_set_prefix = 13, + sigp_store_status_at_address = 14, + sigp_store_extended_status_at_address = 15, + sigp_set_architecture = 18, + sigp_conditional_emergency_signal = 19, + sigp_sense_running = 21, +}; + +enum { + sigp_order_code_accepted = 0, + sigp_status_stored = 1, + sigp_busy = 2, + sigp_not_operational = 3, +}; /* - * Definitions for the external call + * Definitions for external call. */ - -/* 'Bit' signals, asynchronous */ -typedef enum -{ - ec_schedule=0, +enum { + ec_schedule = 0, ec_call_function, ec_call_function_single, - ec_bit_last -} ec_bit_sig; +}; /* - * Signal processor + * Signal processor. */ -static inline sigp_ccode -signal_processor(__u16 cpu_addr, sigp_order_code order_code) +static inline int raw_sigp(u16 cpu, int order) { register unsigned long reg1 asm ("1") = 0; - sigp_ccode ccode; + int ccode; asm volatile( " sigp %1,%2,0(%3)\n" " ipm %0\n" " srl %0,28\n" : "=d" (ccode) - : "d" (reg1), "d" (cpu_logical_map(cpu_addr)), - "a" (order_code) : "cc" , "memory"); + : "d" (reg1), "d" (cpu), + "a" (order) : "cc" , "memory"); return ccode; } /* - * Signal processor with parameter + * Signal processor with parameter. */ -static inline sigp_ccode -signal_processor_p(__u32 parameter, __u16 cpu_addr, sigp_order_code order_code) +static inline int raw_sigp_p(u32 parameter, u16 cpu, int order) { register unsigned int reg1 asm ("1") = parameter; - sigp_ccode ccode; + int ccode; asm volatile( " sigp %1,%2,0(%3)\n" " ipm %0\n" " srl %0,28\n" : "=d" (ccode) - : "d" (reg1), "d" (cpu_logical_map(cpu_addr)), - "a" (order_code) : "cc" , "memory"); + : "d" (reg1), "d" (cpu), + "a" (order) : "cc" , "memory"); return ccode; } /* - * Signal processor with parameter and return status + * Signal processor with parameter and return status. */ -static inline sigp_ccode -signal_processor_ps(__u32 *statusptr, __u32 parameter, __u16 cpu_addr, - sigp_order_code order_code) +static inline int raw_sigp_ps(u32 *status, u32 parm, u16 cpu, int order) { - register unsigned int reg1 asm ("1") = parameter; - sigp_ccode ccode; + register unsigned int reg1 asm ("1") = parm; + int ccode; asm volatile( " sigp %1,%2,0(%3)\n" " ipm %0\n" " srl %0,28\n" : "=d" (ccode), "+d" (reg1) - : "d" (cpu_logical_map(cpu_addr)), "a" (order_code) + : "d" (cpu), "a" (order) : "cc" , "memory"); - *statusptr = reg1; + *status = reg1; return ccode; } -#endif /* __SIGP__ */ +static inline int sigp(int cpu, int order) +{ + return raw_sigp(cpu_logical_map(cpu), order); +} + +static inline int sigp_p(u32 parameter, int cpu, int order) +{ + return raw_sigp_p(parameter, cpu_logical_map(cpu), order); +} + +static inline int sigp_ps(u32 *status, u32 parm, int cpu, int order) +{ + return raw_sigp_ps(status, parm, cpu_logical_map(cpu), order); +} + +#endif /* __ASM_SIGP_H */ diff --git a/arch/s390/include/asm/smp.h b/arch/s390/include/asm/smp.h index 2ab1141eeb50..edc03cb9cd79 100644 --- a/arch/s390/include/asm/smp.h +++ b/arch/s390/include/asm/smp.h @@ -29,7 +29,43 @@ extern int smp_cpu_polarization[]; extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); -extern union save_area *zfcpdump_save_areas[NR_CPUS + 1]; +extern struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; + +extern void smp_switch_to_ipl_cpu(void (*func)(void *), void *); +extern void smp_switch_to_cpu(void (*)(void *), void *, unsigned long sp, + int from, int to); +extern void smp_restart_cpu(void); + +/* + * returns 1 if (virtual) cpu is scheduled + * returns 0 otherwise + */ +static inline int smp_vcpu_scheduled(int cpu) +{ + u32 status; + + switch (sigp_ps(&status, 0, cpu, sigp_sense_running)) { + case sigp_status_stored: + /* Check for running status */ + if (status & 0x400) + return 0; + break; + case sigp_not_operational: + return 0; + default: + break; + } + return 1; +} + +#else /* CONFIG_SMP */ + +static inline void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) +{ + func(data); +} + +#define smp_vcpu_scheduled (1) #endif /* CONFIG_SMP */ diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index a587907d77f3..56612fc8186e 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h @@ -13,8 +13,6 @@ #include <linux/smp.h> -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) - static inline int _raw_compare_and_swap(volatile unsigned int *lock, unsigned int old, unsigned int new) @@ -27,22 +25,6 @@ _raw_compare_and_swap(volatile unsigned int *lock, return old; } -#else /* __GNUC__ */ - -static inline int -_raw_compare_and_swap(volatile unsigned int *lock, - unsigned int old, unsigned int new) -{ - asm volatile( - " cs %0,%3,0(%4)" - : "=d" (old), "=m" (*lock) - : "0" (old), "d" (new), "a" (lock), "m" (*lock) - : "cc", "memory" ); - return old; -} - -#endif /* __GNUC__ */ - /* * Simple spin lock operations. There are two variants, one clears IRQ's * on the local processor, one does not. diff --git a/arch/s390/include/asm/swab.h b/arch/s390/include/asm/swab.h index eb18dc1f327b..6bdee21c077e 100644 --- a/arch/s390/include/asm/swab.h +++ b/arch/s390/include/asm/swab.h @@ -47,11 +47,11 @@ static inline __u32 __arch_swab32p(const __u32 *x) asm volatile( #ifndef __s390x__ - " icm %0,8,3(%1)\n" - " icm %0,4,2(%1)\n" - " icm %0,2,1(%1)\n" - " ic %0,0(%1)" - : "=&d" (result) : "a" (x), "m" (*x) : "cc"); + " icm %0,8,%O1+3(%R1)\n" + " icm %0,4,%O1+2(%R1)\n" + " icm %0,2,%O1+1(%R1)\n" + " ic %0,%1" + : "=&d" (result) : "Q" (*x) : "cc"); #else /* __s390x__ */ " lrv %0,%1" : "=d" (result) : "m" (*x)); @@ -77,9 +77,9 @@ static inline __u16 __arch_swab16p(const __u16 *x) asm volatile( #ifndef __s390x__ - " icm %0,2,1(%1)\n" - " ic %0,0(%1)\n" - : "=&d" (result) : "a" (x), "m" (*x) : "cc"); + " icm %0,2,%O+1(%R1)\n" + " ic %0,%1\n" + : "=&d" (result) : "Q" (*x) : "cc"); #else /* __s390x__ */ " lrvh %0,%1" : "=d" (result) : "m" (*x)); diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index e0a73d3eb837..8429686951f9 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h @@ -15,6 +15,13 @@ #include <linux/sched.h> #include <asm/ptrace.h> +/* + * The syscall table always contains 32 bit pointers since we know that the + * address of the function to be called is (way) below 4GB. So the "int" + * type here is what we want [need] for both 32 bit and 64 bit systems. + */ +extern const unsigned int sys_call_table[]; + static inline long syscall_get_nr(struct task_struct *task, struct pt_regs *regs) { diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h index 9d70057d828c..22bdb2a0ee5f 100644 --- a/arch/s390/include/asm/sysinfo.h +++ b/arch/s390/include/asm/sysinfo.h @@ -87,7 +87,8 @@ struct sysinfo_2_2_2 { struct sysinfo_3_2_2 { char reserved_0[31]; - unsigned char count; + unsigned char :4; + unsigned char count:4; struct { char reserved_0[4]; unsigned short cpus_total; diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 379661d2f81a..cef66210c846 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h @@ -24,65 +24,65 @@ extern struct task_struct *__switch_to(void *, void *); static inline void save_fp_regs(s390_fp_regs *fpregs) { asm volatile( - " std 0,8(%1)\n" - " std 2,24(%1)\n" - " std 4,40(%1)\n" - " std 6,56(%1)" - : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory"); + " std 0,%O0+8(%R0)\n" + " std 2,%O0+24(%R0)\n" + " std 4,%O0+40(%R0)\n" + " std 6,%O0+56(%R0)" + : "=Q" (*fpregs) : "Q" (*fpregs)); if (!MACHINE_HAS_IEEE) return; asm volatile( - " stfpc 0(%1)\n" - " std 1,16(%1)\n" - " std 3,32(%1)\n" - " std 5,48(%1)\n" - " std 7,64(%1)\n" - " std 8,72(%1)\n" - " std 9,80(%1)\n" - " std 10,88(%1)\n" - " std 11,96(%1)\n" - " std 12,104(%1)\n" - " std 13,112(%1)\n" - " std 14,120(%1)\n" - " std 15,128(%1)\n" - : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory"); + " stfpc %0\n" + " std 1,%O0+16(%R0)\n" + " std 3,%O0+32(%R0)\n" + " std 5,%O0+48(%R0)\n" + " std 7,%O0+64(%R0)\n" + " std 8,%O0+72(%R0)\n" + " std 9,%O0+80(%R0)\n" + " std 10,%O0+88(%R0)\n" + " std 11,%O0+96(%R0)\n" + " std 12,%O0+104(%R0)\n" + " std 13,%O0+112(%R0)\n" + " std 14,%O0+120(%R0)\n" + " std 15,%O0+128(%R0)\n" + : "=Q" (*fpregs) : "Q" (*fpregs)); } static inline void restore_fp_regs(s390_fp_regs *fpregs) { asm volatile( - " ld 0,8(%0)\n" - " ld 2,24(%0)\n" - " ld 4,40(%0)\n" - " ld 6,56(%0)" - : : "a" (fpregs), "m" (*fpregs)); + " ld 0,%O0+8(%R0)\n" + " ld 2,%O0+24(%R0)\n" + " ld 4,%O0+40(%R0)\n" + " ld 6,%O0+56(%R0)" + : : "Q" (*fpregs)); if (!MACHINE_HAS_IEEE) return; asm volatile( - " lfpc 0(%0)\n" - " ld 1,16(%0)\n" - " ld 3,32(%0)\n" - " ld 5,48(%0)\n" - " ld 7,64(%0)\n" - " ld 8,72(%0)\n" - " ld 9,80(%0)\n" - " ld 10,88(%0)\n" - " ld 11,96(%0)\n" - " ld 12,104(%0)\n" - " ld 13,112(%0)\n" - " ld 14,120(%0)\n" - " ld 15,128(%0)\n" - : : "a" (fpregs), "m" (*fpregs)); + " lfpc %0\n" + " ld 1,%O0+16(%R0)\n" + " ld 3,%O0+32(%R0)\n" + " ld 5,%O0+48(%R0)\n" + " ld 7,%O0+64(%R0)\n" + " ld 8,%O0+72(%R0)\n" + " ld 9,%O0+80(%R0)\n" + " ld 10,%O0+88(%R0)\n" + " ld 11,%O0+96(%R0)\n" + " ld 12,%O0+104(%R0)\n" + " ld 13,%O0+112(%R0)\n" + " ld 14,%O0+120(%R0)\n" + " ld 15,%O0+128(%R0)\n" + : : "Q" (*fpregs)); } static inline void save_access_regs(unsigned int *acrs) { - asm volatile("stam 0,15,0(%0)" : : "a" (acrs) : "memory"); + asm volatile("stam 0,15,%0" : "=Q" (*acrs)); } static inline void restore_access_regs(unsigned int *acrs) { - asm volatile("lam 0,15,0(%0)" : : "a" (acrs)); + asm volatile("lam 0,15,%0" : : "Q" (*acrs)); } #define switch_to(prev,next,last) do { \ @@ -110,6 +110,7 @@ extern void pfault_fini(void); #endif /* CONFIG_PFAULT */ extern void cmma_init(void); +extern int memcpy_real(void *, void *, size_t); #define finish_arch_switch(prev) do { \ set_fs(current->thread.mm_segment); \ @@ -139,48 +140,48 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) shift = (3 ^ (addr & 3)) << 3; addr ^= addr & 3; asm volatile( - " l %0,0(%4)\n" + " l %0,%4\n" "0: lr 0,%0\n" " nr 0,%3\n" " or 0,%2\n" - " cs %0,0,0(%4)\n" + " cs %0,0,%4\n" " jl 0b\n" - : "=&d" (old), "=m" (*(int *) addr) - : "d" (x << shift), "d" (~(255 << shift)), "a" (addr), - "m" (*(int *) addr) : "memory", "cc", "0"); + : "=&d" (old), "=Q" (*(int *) addr) + : "d" (x << shift), "d" (~(255 << shift)), + "Q" (*(int *) addr) : "memory", "cc", "0"); return old >> shift; case 2: addr = (unsigned long) ptr; shift = (2 ^ (addr & 2)) << 3; addr ^= addr & 2; asm volatile( - " l %0,0(%4)\n" + " l %0,%4\n" "0: lr 0,%0\n" " nr 0,%3\n" " or 0,%2\n" - " cs %0,0,0(%4)\n" + " cs %0,0,%4\n" " jl 0b\n" - : "=&d" (old), "=m" (*(int *) addr) - : "d" (x << shift), "d" (~(65535 << shift)), "a" (addr), - "m" (*(int *) addr) : "memory", "cc", "0"); + : "=&d" (old), "=Q" (*(int *) addr) + : "d" (x << shift), "d" (~(65535 << shift)), + "Q" (*(int *) addr) : "memory", "cc", "0"); return old >> shift; case 4: asm volatile( - " l %0,0(%3)\n" - "0: cs %0,%2,0(%3)\n" + " l %0,%3\n" + "0: cs %0,%2,%3\n" " jl 0b\n" - : "=&d" (old), "=m" (*(int *) ptr) - : "d" (x), "a" (ptr), "m" (*(int *) ptr) + : "=&d" (old), "=Q" (*(int *) ptr) + : "d" (x), "Q" (*(int *) ptr) : "memory", "cc"); return old; #ifdef __s390x__ case 8: asm volatile( - " lg %0,0(%3)\n" - "0: csg %0,%2,0(%3)\n" + " lg %0,%3\n" + "0: csg %0,%2,%3\n" " jl 0b\n" : "=&d" (old), "=m" (*(long *) ptr) - : "d" (x), "a" (ptr), "m" (*(long *) ptr) + : "d" (x), "Q" (*(long *) ptr) : "memory", "cc"); return old; #endif /* __s390x__ */ @@ -215,20 +216,20 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) shift = (3 ^ (addr & 3)) << 3; addr ^= addr & 3; asm volatile( - " l %0,0(%4)\n" + " l %0,%2\n" "0: nr %0,%5\n" " lr %1,%0\n" - " or %0,%2\n" - " or %1,%3\n" - " cs %0,%1,0(%4)\n" + " or %0,%3\n" + " or %1,%4\n" + " cs %0,%1,%2\n" " jnl 1f\n" " xr %1,%0\n" " nr %1,%5\n" " jnz 0b\n" "1:" - : "=&d" (prev), "=&d" (tmp) - : "d" (old << shift), "d" (new << shift), "a" (ptr), - "d" (~(255 << shift)) + : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr) + : "d" (old << shift), "d" (new << shift), + "d" (~(255 << shift)), "Q" (*(int *) ptr) : "memory", "cc"); return prev >> shift; case 2: @@ -236,33 +237,35 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) shift = (2 ^ (addr & 2)) << 3; addr ^= addr & 2; asm volatile( - " l %0,0(%4)\n" + " l %0,%2\n" "0: nr %0,%5\n" " lr %1,%0\n" - " or %0,%2\n" - " or %1,%3\n" - " cs %0,%1,0(%4)\n" + " or %0,%3\n" + " or %1,%4\n" + " cs %0,%1,%2\n" " jnl 1f\n" " xr %1,%0\n" " nr %1,%5\n" " jnz 0b\n" "1:" - : "=&d" (prev), "=&d" (tmp) - : "d" (old << shift), "d" (new << shift), "a" (ptr), - "d" (~(65535 << shift)) + : "=&d" (prev), "=&d" (tmp), "=Q" (*(int *) ptr) + : "d" (old << shift), "d" (new << shift), + "d" (~(65535 << shift)), "Q" (*(int *) ptr) : "memory", "cc"); return prev >> shift; case 4: asm volatile( - " cs %0,%2,0(%3)\n" - : "=&d" (prev) : "0" (old), "d" (new), "a" (ptr) + " cs %0,%3,%1\n" + : "=&d" (prev), "=Q" (*(int *) ptr) + : "0" (old), "d" (new), "Q" (*(int *) ptr) : "memory", "cc"); return prev; #ifdef __s390x__ case 8: asm volatile( - " csg %0,%2,0(%3)\n" - : "=&d" (prev) : "0" (old), "d" (new), "a" (ptr) + " csg %0,%3,%1\n" + : "=&d" (prev), "=Q" (*(long *) ptr) + : "0" (old), "d" (new), "Q" (*(long *) ptr) : "memory", "cc"); return prev; #endif /* __s390x__ */ @@ -302,17 +305,17 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) #define __ctl_load(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ asm volatile( \ - " lctlg %1,%2,0(%0)\n" \ - : : "a" (&array), "i" (low), "i" (high), \ - "m" (*(addrtype *)(&array))); \ + " lctlg %1,%2,%0\n" \ + : : "Q" (*(addrtype *)(&array)), \ + "i" (low), "i" (high)); \ }) #define __ctl_store(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ asm volatile( \ - " stctg %2,%3,0(%1)\n" \ - : "=m" (*(addrtype *)(&array)) \ - : "a" (&array), "i" (low), "i" (high)); \ + " stctg %1,%2,%0\n" \ + : "=Q" (*(addrtype *)(&array)) \ + : "i" (low), "i" (high)); \ }) #else /* __s390x__ */ @@ -320,17 +323,17 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) #define __ctl_load(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ asm volatile( \ - " lctl %1,%2,0(%0)\n" \ - : : "a" (&array), "i" (low), "i" (high), \ - "m" (*(addrtype *)(&array))); \ + " lctl %1,%2,%0\n" \ + : : "Q" (*(addrtype *)(&array)), \ + "i" (low), "i" (high)); \ }) #define __ctl_store(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ asm volatile( \ - " stctl %2,%3,0(%1)\n" \ - : "=m" (*(addrtype *)(&array)) \ - : "a" (&array), "i" (low), "i" (high)); \ + " stctl %1,%2,%0\n" \ + : "=Q" (*(addrtype *)(&array)) \ + : "i" (low), "i" (high)); \ }) #endif /* __s390x__ */ @@ -456,11 +459,6 @@ extern void (*_machine_power_off)(void); #define arch_align_stack(x) (x) -#ifdef CONFIG_TRACE_IRQFLAGS -extern psw_t sysc_restore_trace_psw; -extern psw_t io_restore_trace_psw; -#endif - static inline int tprot(unsigned long addr) { int rc = -EFAULT; diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index 66069e736842..5baf0230b29b 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h @@ -50,6 +50,7 @@ struct thread_info { struct restart_block restart_block; __u64 user_timer; __u64 system_timer; + unsigned long last_break; /* last breaking-event-address. */ }; /* @@ -73,7 +74,7 @@ struct thread_info { /* how to get the thread information struct from C */ static inline struct thread_info *current_thread_info(void) { - return (struct thread_info *)((*(unsigned long *) __LC_KERNEL_STACK)-THREAD_SIZE); + return (struct thread_info *)(S390_lowcore.kernel_stack - THREAD_SIZE); } #define THREAD_SIZE_ORDER THREAD_ORDER @@ -96,7 +97,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ #define TIF_31BIT 17 /* 32bit process */ -#define TIF_MEMDIE 18 +#define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 19 /* restore signal mask in do_signal() */ #define TIF_FREEZE 20 /* thread is freezing for suspend */ diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index 68d9fea34b4b..09d345a701dc 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h @@ -20,10 +20,10 @@ static inline int set_clock(__u64 time) int cc; asm volatile( - " sck 0(%2)\n" + " sck %1\n" " ipm %0\n" " srl %0,28\n" - : "=d" (cc) : "m" (time), "a" (&time) : "cc"); + : "=d" (cc) : "Q" (time) : "cc"); return cc; } @@ -32,21 +32,21 @@ static inline int store_clock(__u64 *time) int cc; asm volatile( - " stck 0(%2)\n" + " stck %1\n" " ipm %0\n" " srl %0,28\n" - : "=d" (cc), "=m" (*time) : "a" (time) : "cc"); + : "=d" (cc), "=Q" (*time) : : "cc"); return cc; } static inline void set_clock_comparator(__u64 time) { - asm volatile("sckc 0(%1)" : : "m" (time), "a" (&time)); + asm volatile("sckc %0" : : "Q" (time)); } static inline void store_clock_comparator(__u64 *time) { - asm volatile("stckc 0(%1)" : "=m" (*time) : "a" (time)); + asm volatile("stckc %0" : "=Q" (*time)); } #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ @@ -57,25 +57,19 @@ static inline unsigned long long get_clock (void) { unsigned long long clk; -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) asm volatile("stck %0" : "=Q" (clk) : : "cc"); -#else /* __GNUC__ */ - asm volatile("stck 0(%1)" : "=m" (clk) : "a" (&clk) : "cc"); -#endif /* __GNUC__ */ return clk; } +static inline void get_clock_ext(char *clk) +{ + asm volatile("stcke %0" : "=Q" (*clk) : : "cc"); +} + static inline unsigned long long get_clock_xt(void) { unsigned char clk[16]; - -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) - asm volatile("stcke %0" : "=Q" (clk) : : "cc"); -#else /* __GNUC__ */ - asm volatile("stcke 0(%1)" : "=m" (clk) - : "a" (clk) : "cc"); -#endif /* __GNUC__ */ - + get_clock_ext(clk); return *((unsigned long long *)&clk[1]); } diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index 6e7211abd950..dc8a67297d0f 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h @@ -7,8 +7,10 @@ const struct cpumask *cpu_coregroup_mask(unsigned int cpu); +extern unsigned char cpu_core_id[NR_CPUS]; extern cpumask_t cpu_core_map[NR_CPUS]; +#define topology_core_id(cpu) (cpu_core_id[cpu]) #define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) int topology_set_cpu_management(int fc); diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h index cbf0a8745bf4..d6b1ed0ec52b 100644 --- a/arch/s390/include/asm/uaccess.h +++ b/arch/s390/include/asm/uaccess.h @@ -265,6 +265,12 @@ __copy_from_user(void *to, const void __user *from, unsigned long n) return uaccess.copy_from_user(n, from, to); } +extern void copy_from_user_overflow(void) +#ifdef CONFIG_DEBUG_STRICT_USER_COPY_CHECKS +__compiletime_warning("copy_from_user() buffer size is not provably correct") +#endif +; + /** * copy_from_user: - Copy a block of data from user space. * @to: Destination address, in kernel space. @@ -284,7 +290,13 @@ __copy_from_user(void *to, const void __user *from, unsigned long n) static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) { + unsigned int sz = __compiletime_object_size(to); + might_fault(); + if (unlikely(sz != -1 && sz < n)) { + copy_from_user_overflow(); + return n; + } if (access_ok(VERIFY_READ, from, n)) n = __copy_from_user(to, from, n); else diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h index 6e9f049fa823..5f0075150a65 100644 --- a/arch/s390/include/asm/unistd.h +++ b/arch/s390/include/asm/unistd.h @@ -392,6 +392,7 @@ #define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_NICE #define __ARCH_WANT_SYS_OLD_GETRLIMIT +#define __ARCH_WANT_SYS_OLD_MMAP #define __ARCH_WANT_SYS_OLDUMOUNT #define __ARCH_WANT_SYS_SIGPENDING #define __ARCH_WANT_SYS_SIGPROCMASK diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h index 7bdd7c8ebc91..533f35751aeb 100644 --- a/arch/s390/include/asm/vdso.h +++ b/arch/s390/include/asm/vdso.h @@ -7,7 +7,7 @@ #define VDSO32_LBASE 0 #define VDSO64_LBASE 0 -#define VDSO_VERSION_STRING LINUX_2.6.26 +#define VDSO_VERSION_STRING LINUX_2.6.29 #ifndef __ASSEMBLY__ @@ -29,6 +29,7 @@ struct vdso_data { __u32 tz_minuteswest; /* Minutes west of Greenwich 0x30 */ __u32 tz_dsttime; /* Type of dst correction 0x34 */ __u32 ectg_available; + __u32 ntp_mult; /* NTP adjusted multiplier 0x3C */ }; struct vdso_per_cpu_data { diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 683f6381cc59..64230bc392fa 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -29,9 +29,12 @@ obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) extra-y += head.o init_task.o vmlinux.lds +extra-y += $(if $(CONFIG_64BIT),head64.o,head31.o) obj-$(CONFIG_MODULES) += s390_ksyms.o module.o obj-$(CONFIG_SMP) += smp.o topology.o +obj-$(CONFIG_SMP) += $(if $(CONFIG_64BIT),switch_cpu64.o, \ + switch_cpu.o) obj-$(CONFIG_HIBERNATION) += suspend.o swsusp_asm64.o obj-$(CONFIG_AUDIT) += audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 63e46433e81d..5232278d79ad 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -4,18 +4,27 @@ * and format the required data. */ -#include <linux/sched.h> +#define ASM_OFFSETS_C + #include <linux/kbuild.h> +#include <linux/sched.h> #include <asm/vdso.h> #include <asm/sigp.h> +/* + * Make sure that the compiler is new enough. We want a compiler that + * is known to work with the "Q" assembler constraint. + */ +#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3) +#error Your compiler is too old; please use version 3.3.3 or newer +#endif + int main(void) { DEFINE(__THREAD_info, offsetof(struct task_struct, stack)); DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp)); DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info)); - DEFINE(__THREAD_mm_segment, - offsetof(struct task_struct, thread.mm_segment)); + DEFINE(__THREAD_mm_segment, offsetof(struct task_struct, thread.mm_segment)); BLANK(); DEFINE(__TASK_pid, offsetof(struct task_struct, pid)); BLANK(); @@ -30,6 +39,7 @@ int main(void) DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count)); DEFINE(__TI_user_timer, offsetof(struct thread_info, user_timer)); DEFINE(__TI_system_timer, offsetof(struct thread_info, system_timer)); + DEFINE(__TI_last_break, offsetof(struct thread_info, last_break)); BLANK(); DEFINE(__PT_ARGS, offsetof(struct pt_regs, args)); DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); @@ -52,18 +62,98 @@ int main(void) DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest)); DEFINE(__VDSO_ECTG_OK, offsetof(struct vdso_data, ectg_available)); - DEFINE(__VDSO_ECTG_BASE, - offsetof(struct vdso_per_cpu_data, ectg_timer_base)); - DEFINE(__VDSO_ECTG_USER, - offsetof(struct vdso_per_cpu_data, ectg_user_time)); + DEFINE(__VDSO_NTP_MULT, offsetof(struct vdso_data, ntp_mult)); + DEFINE(__VDSO_ECTG_BASE, offsetof(struct vdso_per_cpu_data, ectg_timer_base)); + DEFINE(__VDSO_ECTG_USER, offsetof(struct vdso_per_cpu_data, ectg_user_time)); /* constants used by the vdso */ DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); DEFINE(CLOCK_REALTIME_RES, MONOTONIC_RES_NSEC); + BLANK(); /* constants for SIGP */ DEFINE(__SIGP_STOP, sigp_stop); DEFINE(__SIGP_RESTART, sigp_restart); DEFINE(__SIGP_SENSE, sigp_sense); DEFINE(__SIGP_INITIAL_CPU_RESET, sigp_initial_cpu_reset); + BLANK(); + /* lowcore offsets */ + DEFINE(__LC_EXT_PARAMS, offsetof(struct _lowcore, ext_params)); + DEFINE(__LC_CPU_ADDRESS, offsetof(struct _lowcore, cpu_addr)); + DEFINE(__LC_EXT_INT_CODE, offsetof(struct _lowcore, ext_int_code)); + DEFINE(__LC_SVC_ILC, offsetof(struct _lowcore, svc_ilc)); + DEFINE(__LC_SVC_INT_CODE, offsetof(struct _lowcore, svc_code)); + DEFINE(__LC_PGM_ILC, offsetof(struct _lowcore, pgm_ilc)); + DEFINE(__LC_PGM_INT_CODE, offsetof(struct _lowcore, pgm_code)); + DEFINE(__LC_PER_ATMID, offsetof(struct _lowcore, per_perc_atmid)); + DEFINE(__LC_PER_ADDRESS, offsetof(struct _lowcore, per_address)); + DEFINE(__LC_PER_ACCESS_ID, offsetof(struct _lowcore, per_access_id)); + DEFINE(__LC_AR_MODE_ID, offsetof(struct _lowcore, ar_access_id)); + DEFINE(__LC_SUBCHANNEL_ID, offsetof(struct _lowcore, subchannel_id)); + DEFINE(__LC_SUBCHANNEL_NR, offsetof(struct _lowcore, subchannel_nr)); + DEFINE(__LC_IO_INT_PARM, offsetof(struct _lowcore, io_int_parm)); + DEFINE(__LC_IO_INT_WORD, offsetof(struct _lowcore, io_int_word)); + DEFINE(__LC_STFL_FAC_LIST, offsetof(struct _lowcore, stfl_fac_list)); + DEFINE(__LC_MCCK_CODE, offsetof(struct _lowcore, mcck_interruption_code)); + DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib)); + BLANK(); + DEFINE(__LC_RST_NEW_PSW, offsetof(struct _lowcore, restart_psw)); + DEFINE(__LC_RST_OLD_PSW, offsetof(struct _lowcore, restart_old_psw)); + DEFINE(__LC_EXT_OLD_PSW, offsetof(struct _lowcore, external_old_psw)); + DEFINE(__LC_SVC_OLD_PSW, offsetof(struct _lowcore, svc_old_psw)); + DEFINE(__LC_PGM_OLD_PSW, offsetof(struct _lowcore, program_old_psw)); + DEFINE(__LC_MCK_OLD_PSW, offsetof(struct _lowcore, mcck_old_psw)); + DEFINE(__LC_IO_OLD_PSW, offsetof(struct _lowcore, io_old_psw)); + DEFINE(__LC_EXT_NEW_PSW, offsetof(struct _lowcore, external_new_psw)); + DEFINE(__LC_SVC_NEW_PSW, offsetof(struct _lowcore, svc_new_psw)); + DEFINE(__LC_PGM_NEW_PSW, offsetof(struct _lowcore, program_new_psw)); + DEFINE(__LC_MCK_NEW_PSW, offsetof(struct _lowcore, mcck_new_psw)); + DEFINE(__LC_IO_NEW_PSW, offsetof(struct _lowcore, io_new_psw)); + DEFINE(__LC_SAVE_AREA, offsetof(struct _lowcore, save_area)); + DEFINE(__LC_RETURN_PSW, offsetof(struct _lowcore, return_psw)); + DEFINE(__LC_RETURN_MCCK_PSW, offsetof(struct _lowcore, return_mcck_psw)); + DEFINE(__LC_SYNC_ENTER_TIMER, offsetof(struct _lowcore, sync_enter_timer)); + DEFINE(__LC_ASYNC_ENTER_TIMER, offsetof(struct _lowcore, async_enter_timer)); + DEFINE(__LC_MCCK_ENTER_TIMER, offsetof(struct _lowcore, mcck_enter_timer)); + DEFINE(__LC_EXIT_TIMER, offsetof(struct _lowcore, exit_timer)); + DEFINE(__LC_USER_TIMER, offsetof(struct _lowcore, user_timer)); + DEFINE(__LC_SYSTEM_TIMER, offsetof(struct _lowcore, system_timer)); + DEFINE(__LC_STEAL_TIMER, offsetof(struct _lowcore, steal_timer)); + DEFINE(__LC_LAST_UPDATE_TIMER, offsetof(struct _lowcore, last_update_timer)); + DEFINE(__LC_LAST_UPDATE_CLOCK, offsetof(struct _lowcore, last_update_clock)); + DEFINE(__LC_CURRENT, offsetof(struct _lowcore, current_task)); + DEFINE(__LC_THREAD_INFO, offsetof(struct _lowcore, thread_info)); + DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack)); + DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack)); + DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack)); + DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce)); + DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); + DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce)); + DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); + DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); + DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); + DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); + DEFINE(__LC_IRB, offsetof(struct _lowcore, irb)); + DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); + DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area)); + DEFINE(__LC_PSW_SAVE_AREA, offsetof(struct _lowcore, psw_save_area)); + DEFINE(__LC_PREFIX_SAVE_AREA, offsetof(struct _lowcore, prefixreg_save_area)); + DEFINE(__LC_AREGS_SAVE_AREA, offsetof(struct _lowcore, access_regs_save_area)); + DEFINE(__LC_FPREGS_SAVE_AREA, offsetof(struct _lowcore, floating_pt_save_area)); + DEFINE(__LC_GPREGS_SAVE_AREA, offsetof(struct _lowcore, gpregs_save_area)); + DEFINE(__LC_CREGS_SAVE_AREA, offsetof(struct _lowcore, cregs_save_area)); +#ifdef CONFIG_32BIT + DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params)); + DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, extended_save_area_addr)); +#else /* CONFIG_32BIT */ + DEFINE(__LC_PFAULT_INTPARM, offsetof(struct _lowcore, ext_params2)); + DEFINE(__LC_EXT_PARAMS2, offsetof(struct _lowcore, ext_params2)); + DEFINE(SAVE_AREA_BASE, offsetof(struct _lowcore, floating_pt_save_area)); + DEFINE(__LC_PASTE, offsetof(struct _lowcore, paste)); + DEFINE(__LC_FP_CREG_SAVE_AREA, offsetof(struct _lowcore, fpt_creg_save_area)); + DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr)); + DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data)); + DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook)); + DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp)); +#endif /* CONFIG_32BIT */ return 0; } diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S index dc7e5259770f..15e46ca94335 100644 --- a/arch/s390/kernel/base.S +++ b/arch/s390/kernel/base.S @@ -6,8 +6,8 @@ * Michael Holzheu <holzheu@de.ibm.com> */ +#include <asm/asm-offsets.h> #include <asm/ptrace.h> -#include <asm/lowcore.h> #ifdef CONFIG_64BIT diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 11c3aba664ea..73b624ed9cd8 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -29,7 +29,6 @@ #include <linux/sem.h> #include <linux/msg.h> #include <linux/shm.h> -#include <linux/slab.h> #include <linux/uio.h> #include <linux/quota.h> #include <linux/module.h> @@ -52,6 +51,7 @@ #include <linux/ptrace.h> #include <linux/fadvise.h> #include <linux/ipc.h> +#include <linux/slab.h> #include <asm/types.h> #include <asm/uaccess.h> diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 30de2d0e52bb..672ce52341b4 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -547,7 +547,7 @@ sys32_setdomainname_wrapper: .globl sys32_newuname_wrapper sys32_newuname_wrapper: llgtr %r2,%r2 # struct new_utsname * - jg sys_s390_newuname # branch to system call + jg sys_newuname # branch to system call .globl compat_sys_adjtimex_wrapper compat_sys_adjtimex_wrapper: diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 0168472b2fdf..98192261491d 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -655,6 +655,7 @@ found: p_info->act_entry_offset = 0; file->private_data = p_info; debug_info_get(debug_info); + nonseekable_open(inode, file); out: mutex_unlock(&debug_mutex); return rc; diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index db943a7ec513..b39b27d68b45 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -86,10 +86,17 @@ enum { U4_12, /* 4 bit unsigned value starting at 12 */ U4_16, /* 4 bit unsigned value starting at 16 */ U4_20, /* 4 bit unsigned value starting at 20 */ + U4_32, /* 4 bit unsigned value starting at 32 */ U8_8, /* 8 bit unsigned value starting at 8 */ U8_16, /* 8 bit unsigned value starting at 16 */ + U8_24, /* 8 bit unsigned value starting at 24 */ + U8_32, /* 8 bit unsigned value starting at 32 */ + I8_8, /* 8 bit signed value starting at 8 */ + I8_32, /* 8 bit signed value starting at 32 */ I16_16, /* 16 bit signed value starting at 16 */ + I16_32, /* 32 bit signed value starting at 16 */ U16_16, /* 16 bit unsigned value starting at 16 */ + U16_32, /* 32 bit unsigned value starting at 16 */ J16_16, /* PC relative jump offset at 16 */ J32_16, /* PC relative long offset at 16 */ I32_16, /* 32 bit signed value starting at 16 */ @@ -104,21 +111,37 @@ enum { */ enum { INSTR_INVALID, - INSTR_E, INSTR_RIE_RRP, INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, - INSTR_RIL_UP, INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP, + INSTR_E, + INSTR_RIE_R0IU, INSTR_RIE_R0UU, INSTR_RIE_RRP, INSTR_RIE_RRPU, + INSTR_RIE_RRUUU, INSTR_RIE_RUPI, INSTR_RIE_RUPU, + INSTR_RIL_RI, INSTR_RIL_RP, INSTR_RIL_RU, INSTR_RIL_UP, + INSTR_RIS_R0RDU, INSTR_RIS_R0UU, INSTR_RIS_RURDI, INSTR_RIS_RURDU, + INSTR_RI_RI, INSTR_RI_RP, INSTR_RI_RU, INSTR_RI_UP, INSTR_RRE_00, INSTR_RRE_0R, INSTR_RRE_AA, INSTR_RRE_AR, INSTR_RRE_F0, - INSTR_RRE_FF, INSTR_RRE_R0, INSTR_RRE_RA, INSTR_RRE_RF, INSTR_RRE_RR, - INSTR_RRE_RR_OPT, INSTR_RRF_F0FF, INSTR_RRF_FUFF, INSTR_RRF_M0RR, - INSTR_RRF_R0RR, INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF, + INSTR_RRE_FF, INSTR_RRE_FR, INSTR_RRE_R0, INSTR_RRE_RA, INSTR_RRE_RF, + INSTR_RRE_RR, INSTR_RRE_RR_OPT, + INSTR_RRF_0UFF, INSTR_RRF_F0FF, INSTR_RRF_F0FF2, INSTR_RRF_F0FR, + INSTR_RRF_FFRU, INSTR_RRF_FUFF, INSTR_RRF_M0RR, INSTR_RRF_R0RR, + INSTR_RRF_RURR, INSTR_RRF_U0FF, INSTR_RRF_U0RF, INSTR_RRF_U0RR, + INSTR_RRF_UUFF, INSTR_RRR_F0FF, INSTR_RRS_RRRDU, INSTR_RR_FF, INSTR_RR_R0, INSTR_RR_RR, INSTR_RR_U0, INSTR_RR_UR, - INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD, INSTR_RSI_RRP, - INSTR_RSL_R0RD, INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, - INSTR_RSY_RURD, INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, - INSTR_RS_RRRD, INSTR_RS_RURD, INSTR_RXE_FRRD, INSTR_RXE_RRRD, - INSTR_RXF_FRRDF, INSTR_RXY_FRRD, INSTR_RXY_RRRD, INSTR_RX_FRRD, - INSTR_RX_RRRD, INSTR_RX_URRD, INSTR_SIY_URD, INSTR_SI_URD, - INSTR_SSE_RDRD, INSTR_SSF_RRDRD, INSTR_SS_L0RDRD, INSTR_SS_LIRDRD, - INSTR_SS_LLRDRD, INSTR_SS_RRRDRD, INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3, + INSTR_RSE_CCRD, INSTR_RSE_RRRD, INSTR_RSE_RURD, + INSTR_RSI_RRP, + INSTR_RSL_R0RD, + INSTR_RSY_AARD, INSTR_RSY_CCRD, INSTR_RSY_RRRD, INSTR_RSY_RURD, + INSTR_RS_AARD, INSTR_RS_CCRD, INSTR_RS_R0RD, INSTR_RS_RRRD, + INSTR_RS_RURD, + INSTR_RXE_FRRD, INSTR_RXE_RRRD, + INSTR_RXF_FRRDF, + INSTR_RXY_FRRD, INSTR_RXY_RRRD, INSTR_RXY_URRD, + INSTR_RX_FRRD, INSTR_RX_RRRD, INSTR_RX_URRD, + INSTR_SIL_RDI, INSTR_SIL_RDU, + INSTR_SIY_IRD, INSTR_SIY_URD, + INSTR_SI_URD, + INSTR_SSE_RDRD, + INSTR_SSF_RRDRD, + INSTR_SS_L0RDRD, INSTR_SS_LIRDRD, INSTR_SS_LLRDRD, INSTR_SS_RRRDRD, + INSTR_SS_RRRDRD2, INSTR_SS_RRRDRD3, INSTR_S_00, INSTR_S_RD, }; @@ -129,7 +152,7 @@ struct operand { }; struct insn { - const char name[5]; + const char name[6]; unsigned char opfrag; unsigned char format; }; @@ -170,11 +193,16 @@ static const struct operand operands[] = [U4_12] = { 4, 12, 0 }, [U4_16] = { 4, 16, 0 }, [U4_20] = { 4, 20, 0 }, + [U4_32] = { 4, 32, 0 }, [U8_8] = { 8, 8, 0 }, [U8_16] = { 8, 16, 0 }, + [U8_24] = { 8, 24, 0 }, + [U8_32] = { 8, 32, 0 }, [I16_16] = { 16, 16, OPERAND_SIGNED }, [U16_16] = { 16, 16, 0 }, + [U16_32] = { 16, 32, 0 }, [J16_16] = { 16, 16, OPERAND_PCREL }, + [I16_32] = { 16, 32, OPERAND_SIGNED }, [J32_16] = { 32, 16, OPERAND_PCREL }, [I32_16] = { 32, 16, OPERAND_SIGNED }, [U32_16] = { 32, 16, 0 }, @@ -183,82 +211,93 @@ static const struct operand operands[] = }; static const unsigned char formats[][7] = { - [INSTR_E] = { 0xff, 0,0,0,0,0,0 }, /* e.g. pr */ - [INSTR_RIE_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, /* e.g. brxhg */ - [INSTR_RIL_RP] = { 0x0f, R_8,J32_16,0,0,0,0 }, /* e.g. brasl */ - [INSTR_RIL_UP] = { 0x0f, U4_8,J32_16,0,0,0,0 }, /* e.g. brcl */ - [INSTR_RIL_RI] = { 0x0f, R_8,I32_16,0,0,0,0 }, /* e.g. afi */ - [INSTR_RIL_RU] = { 0x0f, R_8,U32_16,0,0,0,0 }, /* e.g. alfi */ - [INSTR_RI_RI] = { 0x0f, R_8,I16_16,0,0,0,0 }, /* e.g. ahi */ - [INSTR_RI_RP] = { 0x0f, R_8,J16_16,0,0,0,0 }, /* e.g. brct */ - [INSTR_RI_RU] = { 0x0f, R_8,U16_16,0,0,0,0 }, /* e.g. tml */ - [INSTR_RI_UP] = { 0x0f, U4_8,J16_16,0,0,0,0 }, /* e.g. brc */ - [INSTR_RRE_00] = { 0xff, 0,0,0,0,0,0 }, /* e.g. palb */ - [INSTR_RRE_0R] = { 0xff, R_28,0,0,0,0,0 }, /* e.g. tb */ - [INSTR_RRE_AA] = { 0xff, A_24,A_28,0,0,0,0 }, /* e.g. cpya */ - [INSTR_RRE_AR] = { 0xff, A_24,R_28,0,0,0,0 }, /* e.g. sar */ - [INSTR_RRE_F0] = { 0xff, F_24,0,0,0,0,0 }, /* e.g. sqer */ - [INSTR_RRE_FF] = { 0xff, F_24,F_28,0,0,0,0 }, /* e.g. debr */ - [INSTR_RRE_R0] = { 0xff, R_24,0,0,0,0,0 }, /* e.g. ipm */ - [INSTR_RRE_RA] = { 0xff, R_24,A_28,0,0,0,0 }, /* e.g. ear */ - [INSTR_RRE_RF] = { 0xff, R_24,F_28,0,0,0,0 }, /* e.g. cefbr */ - [INSTR_RRE_RR] = { 0xff, R_24,R_28,0,0,0,0 }, /* e.g. lura */ - [INSTR_RRE_RR_OPT]= { 0xff, R_24,RO_28,0,0,0,0 }, /* efpc, sfpc */ - [INSTR_RRF_F0FF] = { 0xff, F_16,F_24,F_28,0,0,0 }, /* e.g. madbr */ - [INSTR_RRF_FUFF] = { 0xff, F_24,F_16,F_28,U4_20,0,0 },/* e.g. didbr */ - [INSTR_RRF_RURR] = { 0xff, R_24,R_28,R_16,U4_20,0,0 },/* e.g. .insn */ - [INSTR_RRF_R0RR] = { 0xff, R_24,R_16,R_28,0,0,0 }, /* e.g. idte */ - [INSTR_RRF_U0FF] = { 0xff, F_24,U4_16,F_28,0,0,0 }, /* e.g. fixr */ - [INSTR_RRF_U0RF] = { 0xff, R_24,U4_16,F_28,0,0,0 }, /* e.g. cfebr */ - [INSTR_RRF_M0RR] = { 0xff, R_24,R_28,M_16,0,0,0 }, /* e.g. sske */ - [INSTR_RR_FF] = { 0xff, F_8,F_12,0,0,0,0 }, /* e.g. adr */ - [INSTR_RR_R0] = { 0xff, R_8, 0,0,0,0,0 }, /* e.g. spm */ - [INSTR_RR_RR] = { 0xff, R_8,R_12,0,0,0,0 }, /* e.g. lr */ - [INSTR_RR_U0] = { 0xff, U8_8, 0,0,0,0,0 }, /* e.g. svc */ - [INSTR_RR_UR] = { 0xff, U4_8,R_12,0,0,0,0 }, /* e.g. bcr */ - [INSTR_RSE_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, /* e.g. lmh */ - [INSTR_RSE_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, /* e.g. lmh */ - [INSTR_RSE_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icmh */ - [INSTR_RSL_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, /* e.g. tp */ - [INSTR_RSI_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, /* e.g. brxh */ - [INSTR_RSY_RRRD] = { 0xff, R_8,R_12,D20_20,B_16,0,0 },/* e.g. stmy */ + [INSTR_E] = { 0xff, 0,0,0,0,0,0 }, + [INSTR_RIE_R0UU] = { 0xff, R_8,U16_16,U4_32,0,0,0 }, + [INSTR_RIE_RRPU] = { 0xff, R_8,R_12,U4_32,J16_16,0,0 }, + [INSTR_RIE_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, + [INSTR_RIE_RRUUU] = { 0xff, R_8,R_12,U8_16,U8_24,U8_32,0 }, + [INSTR_RIE_RUPI] = { 0xff, R_8,I8_32,U4_12,J16_16,0,0 }, + [INSTR_RIL_RI] = { 0x0f, R_8,I32_16,0,0,0,0 }, + [INSTR_RIL_RP] = { 0x0f, R_8,J32_16,0,0,0,0 }, + [INSTR_RIL_RU] = { 0x0f, R_8,U32_16,0,0,0,0 }, + [INSTR_RIL_UP] = { 0x0f, U4_8,J32_16,0,0,0,0 }, + [INSTR_RIS_R0RDU] = { 0xff, R_8,U8_32,D_20,B_16,0,0 }, + [INSTR_RIS_RURDI] = { 0xff, R_8,I8_32,U4_12,D_20,B_16,0 }, + [INSTR_RIS_RURDU] = { 0xff, R_8,U8_32,U4_12,D_20,B_16,0 }, + [INSTR_RI_RI] = { 0x0f, R_8,I16_16,0,0,0,0 }, + [INSTR_RI_RP] = { 0x0f, R_8,J16_16,0,0,0,0 }, + [INSTR_RI_RU] = { 0x0f, R_8,U16_16,0,0,0,0 }, + [INSTR_RI_UP] = { 0x0f, U4_8,J16_16,0,0,0,0 }, + [INSTR_RRE_00] = { 0xff, 0,0,0,0,0,0 }, + [INSTR_RRE_0R] = { 0xff, R_28,0,0,0,0,0 }, + [INSTR_RRE_AA] = { 0xff, A_24,A_28,0,0,0,0 }, + [INSTR_RRE_AR] = { 0xff, A_24,R_28,0,0,0,0 }, + [INSTR_RRE_F0] = { 0xff, F_24,0,0,0,0,0 }, + [INSTR_RRE_FF] = { 0xff, F_24,F_28,0,0,0,0 }, + [INSTR_RRE_FR] = { 0xff, F_24,R_28,0,0,0,0 }, + [INSTR_RRE_R0] = { 0xff, R_24,0,0,0,0,0 }, + [INSTR_RRE_RA] = { 0xff, R_24,A_28,0,0,0,0 }, + [INSTR_RRE_RF] = { 0xff, R_24,F_28,0,0,0,0 }, + [INSTR_RRE_RR] = { 0xff, R_24,R_28,0,0,0,0 }, + [INSTR_RRE_RR_OPT]= { 0xff, R_24,RO_28,0,0,0,0 }, + [INSTR_RRF_0UFF] = { 0xff, F_24,F_28,U4_20,0,0,0 }, + [INSTR_RRF_F0FF2] = { 0xff, F_24,F_16,F_28,0,0,0 }, + [INSTR_RRF_F0FF] = { 0xff, F_16,F_24,F_28,0,0,0 }, + [INSTR_RRF_F0FR] = { 0xff, F_24,F_16,R_28,0,0,0 }, + [INSTR_RRF_FFRU] = { 0xff, F_24,F_16,R_28,U4_20,0,0 }, + [INSTR_RRF_FUFF] = { 0xff, F_24,F_16,F_28,U4_20,0,0 }, + [INSTR_RRF_M0RR] = { 0xff, R_24,R_28,M_16,0,0,0 }, + [INSTR_RRF_R0RR] = { 0xff, R_24,R_16,R_28,0,0,0 }, + [INSTR_RRF_RURR] = { 0xff, R_24,R_28,R_16,U4_20,0,0 }, + [INSTR_RRF_U0FF] = { 0xff, F_24,U4_16,F_28,0,0,0 }, + [INSTR_RRF_U0RF] = { 0xff, R_24,U4_16,F_28,0,0,0 }, + [INSTR_RRF_U0RR] = { 0xff, R_24,R_28,U4_16,0,0,0 }, + [INSTR_RRF_UUFF] = { 0xff, F_24,U4_16,F_28,U4_20,0,0 }, + [INSTR_RRR_F0FF] = { 0xff, F_24,F_28,F_16,0,0,0 }, + [INSTR_RRS_RRRDU] = { 0xff, R_8,R_12,U4_32,D_20,B_16,0 }, + [INSTR_RR_FF] = { 0xff, F_8,F_12,0,0,0,0 }, + [INSTR_RR_R0] = { 0xff, R_8, 0,0,0,0,0 }, + [INSTR_RR_RR] = { 0xff, R_8,R_12,0,0,0,0 }, + [INSTR_RR_U0] = { 0xff, U8_8, 0,0,0,0,0 }, + [INSTR_RR_UR] = { 0xff, U4_8,R_12,0,0,0,0 }, + [INSTR_RSE_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, + [INSTR_RSE_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, + [INSTR_RSE_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, + [INSTR_RSI_RRP] = { 0xff, R_8,R_12,J16_16,0,0,0 }, + [INSTR_RSL_R0RD] = { 0xff, D_20,L4_8,B_16,0,0,0 }, + [INSTR_RSY_AARD] = { 0xff, A_8,A_12,D20_20,B_16,0,0 }, + [INSTR_RSY_CCRD] = { 0xff, C_8,C_12,D20_20,B_16,0,0 }, + [INSTR_RSY_RRRD] = { 0xff, R_8,R_12,D20_20,B_16,0,0 }, [INSTR_RSY_RURD] = { 0xff, R_8,U4_12,D20_20,B_16,0,0 }, - /* e.g. icmh */ - [INSTR_RSY_AARD] = { 0xff, A_8,A_12,D20_20,B_16,0,0 },/* e.g. lamy */ - [INSTR_RSY_CCRD] = { 0xff, C_8,C_12,D20_20,B_16,0,0 },/* e.g. lamy */ - [INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 }, /* e.g. lam */ - [INSTR_RS_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, /* e.g. lctl */ - [INSTR_RS_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, /* e.g. sll */ - [INSTR_RS_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, /* e.g. cs */ - [INSTR_RS_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, /* e.g. icm */ - [INSTR_RXE_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, /* e.g. axbr */ - [INSTR_RXE_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, /* e.g. lg */ + [INSTR_RS_AARD] = { 0xff, A_8,A_12,D_20,B_16,0,0 }, + [INSTR_RS_CCRD] = { 0xff, C_8,C_12,D_20,B_16,0,0 }, + [INSTR_RS_R0RD] = { 0xff, R_8,D_20,B_16,0,0,0 }, + [INSTR_RS_RRRD] = { 0xff, R_8,R_12,D_20,B_16,0,0 }, + [INSTR_RS_RURD] = { 0xff, R_8,U4_12,D_20,B_16,0,0 }, + [INSTR_RXE_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, + [INSTR_RXE_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, [INSTR_RXF_FRRDF] = { 0xff, F_32,F_8,D_20,X_12,B_16,0 }, - /* e.g. madb */ - [INSTR_RXY_RRRD] = { 0xff, R_8,D20_20,X_12,B_16,0,0 },/* e.g. ly */ - [INSTR_RXY_FRRD] = { 0xff, F_8,D20_20,X_12,B_16,0,0 },/* e.g. ley */ - [INSTR_RX_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, /* e.g. ae */ - [INSTR_RX_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, /* e.g. l */ - [INSTR_RX_URRD] = { 0xff, U4_8,D_20,X_12,B_16,0,0 }, /* e.g. bc */ - [INSTR_SI_URD] = { 0xff, D_20,B_16,U8_8,0,0,0 }, /* e.g. cli */ - [INSTR_SIY_URD] = { 0xff, D20_20,B_16,U8_8,0,0,0 }, /* e.g. tmy */ - [INSTR_SSE_RDRD] = { 0xff, D_20,B_16,D_36,B_32,0,0 }, /* e.g. mvsdk */ + [INSTR_RXY_FRRD] = { 0xff, F_8,D20_20,X_12,B_16,0,0 }, + [INSTR_RXY_RRRD] = { 0xff, R_8,D20_20,X_12,B_16,0,0 }, + [INSTR_RXY_URRD] = { 0xff, U4_8,D20_20,X_12,B_16,0,0 }, + [INSTR_RX_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, + [INSTR_RX_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, + [INSTR_RX_URRD] = { 0xff, U4_8,D_20,X_12,B_16,0,0 }, + [INSTR_SIL_RDI] = { 0xff, D_20,B_16,I16_32,0,0,0 }, + [INSTR_SIL_RDU] = { 0xff, D_20,B_16,U16_32,0,0,0 }, + [INSTR_SIY_IRD] = { 0xff, D20_20,B_16,I8_8,0,0,0 }, + [INSTR_SIY_URD] = { 0xff, D20_20,B_16,U8_8,0,0,0 }, + [INSTR_SI_URD] = { 0xff, D_20,B_16,U8_8,0,0,0 }, + [INSTR_SSE_RDRD] = { 0xff, D_20,B_16,D_36,B_32,0,0 }, + [INSTR_SSF_RRDRD] = { 0x00, D_20,B_16,D_36,B_32,R_8,0 }, [INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 }, - /* e.g. mvc */ [INSTR_SS_LIRDRD] = { 0xff, D_20,L4_8,B_16,D_36,B_32,U4_12 }, - /* e.g. srp */ [INSTR_SS_LLRDRD] = { 0xff, D_20,L4_8,B_16,D_36,L4_12,B_32 }, - /* e.g. pack */ - [INSTR_SS_RRRDRD] = { 0xff, D_20,R_8,B_16,D_36,B_32,R_12 }, - /* e.g. mvck */ [INSTR_SS_RRRDRD2]= { 0xff, R_8,D_20,B_16,R_12,D_36,B_32 }, - /* e.g. plo */ [INSTR_SS_RRRDRD3]= { 0xff, R_8,R_12,D_20,B_16,D_36,B_32 }, - /* e.g. lmd */ - [INSTR_S_00] = { 0xff, 0,0,0,0,0,0 }, /* e.g. hsch */ - [INSTR_S_RD] = { 0xff, D_20,B_16,0,0,0,0 }, /* e.g. lpsw */ - [INSTR_SSF_RRDRD] = { 0x00, D_20,B_16,D_36,B_32,R_8,0 }, - /* e.g. mvcos */ + [INSTR_SS_RRRDRD] = { 0xff, D_20,R_8,B_16,D_36,B_32,R_12 }, + [INSTR_S_00] = { 0xff, 0,0,0,0,0,0 }, + [INSTR_S_RD] = { 0xff, D_20,B_16,0,0,0,0 }, }; static struct insn opcode[] = { @@ -454,6 +493,8 @@ static struct insn opcode[] = { static struct insn opcode_01[] = { #ifdef CONFIG_64BIT { "sam64", 0x0e, INSTR_E }, + { "pfpo", 0x0a, INSTR_E }, + { "ptff", 0x04, INSTR_E }, #endif { "pr", 0x01, INSTR_E }, { "upt", 0x02, INSTR_E }, @@ -519,6 +560,8 @@ static struct insn opcode_b2[] = { { "cutfu", 0xa7, INSTR_RRF_M0RR }, { "stfle", 0xb0, INSTR_S_RD }, { "lpswe", 0xb2, INSTR_S_RD }, + { "srnmt", 0xb9, INSTR_S_RD }, + { "lfas", 0xbd, INSTR_S_RD }, #endif { "stidp", 0x02, INSTR_S_RD }, { "sck", 0x04, INSTR_S_RD }, @@ -589,7 +632,6 @@ static struct insn opcode_b2[] = { { "clst", 0x5d, INSTR_RRE_RR }, { "srst", 0x5e, INSTR_RRE_RR }, { "cmpsc", 0x63, INSTR_RRE_RR }, - { "cmpsc", 0x63, INSTR_RRE_RR }, { "siga", 0x74, INSTR_S_RD }, { "xsch", 0x76, INSTR_S_00 }, { "rp", 0x77, INSTR_S_RD }, @@ -630,6 +672,57 @@ static struct insn opcode_b3[] = { { "cger", 0xc8, INSTR_RRF_U0RF }, { "cgdr", 0xc9, INSTR_RRF_U0RF }, { "cgxr", 0xca, INSTR_RRF_U0RF }, + { "lpdfr", 0x70, INSTR_RRE_FF }, + { "lndfr", 0x71, INSTR_RRE_FF }, + { "cpsdr", 0x72, INSTR_RRF_F0FF2 }, + { "lcdfr", 0x73, INSTR_RRE_FF }, + { "ldgr", 0xc1, INSTR_RRE_FR }, + { "lgdr", 0xcd, INSTR_RRE_RF }, + { "adtr", 0xd2, INSTR_RRR_F0FF }, + { "axtr", 0xda, INSTR_RRR_F0FF }, + { "cdtr", 0xe4, INSTR_RRE_FF }, + { "cxtr", 0xec, INSTR_RRE_FF }, + { "kdtr", 0xe0, INSTR_RRE_FF }, + { "kxtr", 0xe8, INSTR_RRE_FF }, + { "cedtr", 0xf4, INSTR_RRE_FF }, + { "cextr", 0xfc, INSTR_RRE_FF }, + { "cdgtr", 0xf1, INSTR_RRE_FR }, + { "cxgtr", 0xf9, INSTR_RRE_FR }, + { "cdstr", 0xf3, INSTR_RRE_FR }, + { "cxstr", 0xfb, INSTR_RRE_FR }, + { "cdutr", 0xf2, INSTR_RRE_FR }, + { "cxutr", 0xfa, INSTR_RRE_FR }, + { "cgdtr", 0xe1, INSTR_RRF_U0RF }, + { "cgxtr", 0xe9, INSTR_RRF_U0RF }, + { "csdtr", 0xe3, INSTR_RRE_RF }, + { "csxtr", 0xeb, INSTR_RRE_RF }, + { "cudtr", 0xe2, INSTR_RRE_RF }, + { "cuxtr", 0xea, INSTR_RRE_RF }, + { "ddtr", 0xd1, INSTR_RRR_F0FF }, + { "dxtr", 0xd9, INSTR_RRR_F0FF }, + { "eedtr", 0xe5, INSTR_RRE_RF }, + { "eextr", 0xed, INSTR_RRE_RF }, + { "esdtr", 0xe7, INSTR_RRE_RF }, + { "esxtr", 0xef, INSTR_RRE_RF }, + { "iedtr", 0xf6, INSTR_RRF_F0FR }, + { "iextr", 0xfe, INSTR_RRF_F0FR }, + { "ltdtr", 0xd6, INSTR_RRE_FF }, + { "ltxtr", 0xde, INSTR_RRE_FF }, + { "fidtr", 0xd7, INSTR_RRF_UUFF }, + { "fixtr", 0xdf, INSTR_RRF_UUFF }, + { "ldetr", 0xd4, INSTR_RRF_0UFF }, + { "lxdtr", 0xdc, INSTR_RRF_0UFF }, + { "ledtr", 0xd5, INSTR_RRF_UUFF }, + { "ldxtr", 0xdd, INSTR_RRF_UUFF }, + { "mdtr", 0xd0, INSTR_RRR_F0FF }, + { "mxtr", 0xd8, INSTR_RRR_F0FF }, + { "qadtr", 0xf5, INSTR_RRF_FUFF }, + { "qaxtr", 0xfd, INSTR_RRF_FUFF }, + { "rrdtr", 0xf7, INSTR_RRF_FFRU }, + { "rrxtr", 0xff, INSTR_RRF_FFRU }, + { "sfasr", 0x85, INSTR_RRE_R0 }, + { "sdtr", 0xd3, INSTR_RRR_F0FF }, + { "sxtr", 0xdb, INSTR_RRR_F0FF }, #endif { "lpebr", 0x00, INSTR_RRE_FF }, { "lnebr", 0x01, INSTR_RRE_FF }, @@ -780,6 +873,14 @@ static struct insn opcode_b9[] = { { "cu24", 0xb1, INSTR_RRF_M0RR }, { "cu41", 0xb2, INSTR_RRF_M0RR }, { "cu42", 0xb3, INSTR_RRF_M0RR }, + { "crt", 0x72, INSTR_RRF_U0RR }, + { "cgrt", 0x60, INSTR_RRF_U0RR }, + { "clrt", 0x73, INSTR_RRF_U0RR }, + { "clgrt", 0x61, INSTR_RRF_U0RR }, + { "ptf", 0xa2, INSTR_RRE_R0 }, + { "pfmf", 0xaf, INSTR_RRE_RR }, + { "trte", 0xbf, INSTR_RRF_M0RR }, + { "trtre", 0xbd, INSTR_RRF_M0RR }, #endif { "kmac", 0x1e, INSTR_RRE_RR }, { "lrvr", 0x1f, INSTR_RRE_RR }, @@ -835,6 +936,43 @@ static struct insn opcode_c2[] = { { "cfi", 0x0d, INSTR_RIL_RI }, { "clgfi", 0x0e, INSTR_RIL_RU }, { "clfi", 0x0f, INSTR_RIL_RU }, + { "msfi", 0x01, INSTR_RIL_RI }, + { "msgfi", 0x00, INSTR_RIL_RI }, +#endif + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_c4[] = { +#ifdef CONFIG_64BIT + { "lrl", 0x0d, INSTR_RIL_RP }, + { "lgrl", 0x08, INSTR_RIL_RP }, + { "lgfrl", 0x0c, INSTR_RIL_RP }, + { "lhrl", 0x05, INSTR_RIL_RP }, + { "lghrl", 0x04, INSTR_RIL_RP }, + { "llgfrl", 0x0e, INSTR_RIL_RP }, + { "llhrl", 0x02, INSTR_RIL_RP }, + { "llghrl", 0x06, INSTR_RIL_RP }, + { "strl", 0x0f, INSTR_RIL_RP }, + { "stgrl", 0x0b, INSTR_RIL_RP }, + { "sthrl", 0x07, INSTR_RIL_RP }, +#endif + { "", 0, INSTR_INVALID } +}; + +static struct insn opcode_c6[] = { +#ifdef CONFIG_64BIT + { "crl", 0x0d, INSTR_RIL_RP }, + { "cgrl", 0x08, INSTR_RIL_RP }, + { "cgfrl", 0x0c, INSTR_RIL_RP }, + { "chrl", 0x05, INSTR_RIL_RP }, + { "cghrl", 0x04, INSTR_RIL_RP }, + { "clrl", 0x0f, INSTR_RIL_RP }, + { "clgrl", 0x0a, INSTR_RIL_RP }, + { "clgfrl", 0x0e, INSTR_RIL_RP }, + { "clhrl", 0x07, INSTR_RIL_RP }, + { "clghrl", 0x06, INSTR_RIL_RP }, + { "pfdrl", 0x02, INSTR_RIL_UP }, + { "exrl", 0x00, INSTR_RIL_RP }, #endif { "", 0, INSTR_INVALID } }; @@ -842,6 +980,8 @@ static struct insn opcode_c2[] = { static struct insn opcode_c8[] = { #ifdef CONFIG_64BIT { "mvcos", 0x00, INSTR_SSF_RRDRD }, + { "ectg", 0x01, INSTR_SSF_RRDRD }, + { "csst", 0x02, INSTR_SSF_RRDRD }, #endif { "", 0, INSTR_INVALID } }; @@ -917,6 +1057,12 @@ static struct insn opcode_e3[] = { { "llgh", 0x91, INSTR_RXY_RRRD }, { "llc", 0x94, INSTR_RXY_RRRD }, { "llh", 0x95, INSTR_RXY_RRRD }, + { "cgh", 0x34, INSTR_RXY_RRRD }, + { "laey", 0x75, INSTR_RXY_RRRD }, + { "ltgf", 0x32, INSTR_RXY_RRRD }, + { "mfy", 0x5c, INSTR_RXY_RRRD }, + { "mhy", 0x7c, INSTR_RXY_RRRD }, + { "pfd", 0x36, INSTR_RXY_URRD }, #endif { "lrv", 0x1e, INSTR_RXY_RRRD }, { "lrvh", 0x1f, INSTR_RXY_RRRD }, @@ -931,6 +1077,15 @@ static struct insn opcode_e3[] = { static struct insn opcode_e5[] = { #ifdef CONFIG_64BIT { "strag", 0x02, INSTR_SSE_RDRD }, + { "chhsi", 0x54, INSTR_SIL_RDI }, + { "chsi", 0x5c, INSTR_SIL_RDI }, + { "cghsi", 0x58, INSTR_SIL_RDI }, + { "clhhsi", 0x55, INSTR_SIL_RDU }, + { "clfhsi", 0x5d, INSTR_SIL_RDU }, + { "clghsi", 0x59, INSTR_SIL_RDU }, + { "mvhhi", 0x44, INSTR_SIL_RDI }, + { "mvhi", 0x4c, INSTR_SIL_RDI }, + { "mvghi", 0x48, INSTR_SIL_RDI }, #endif { "lasp", 0x00, INSTR_SSE_RDRD }, { "tprot", 0x01, INSTR_SSE_RDRD }, @@ -977,6 +1132,11 @@ static struct insn opcode_eb[] = { { "lmy", 0x98, INSTR_RSY_RRRD }, { "lamy", 0x9a, INSTR_RSY_AARD }, { "stamy", 0x9b, INSTR_RSY_AARD }, + { "asi", 0x6a, INSTR_SIY_IRD }, + { "agsi", 0x7a, INSTR_SIY_IRD }, + { "alsi", 0x6e, INSTR_SIY_IRD }, + { "algsi", 0x7e, INSTR_SIY_IRD }, + { "ecag", 0x4c, INSTR_RSY_RRRD }, #endif { "rll", 0x1d, INSTR_RSY_RRRD }, { "mvclu", 0x8e, INSTR_RSY_RRRD }, @@ -988,6 +1148,30 @@ static struct insn opcode_ec[] = { #ifdef CONFIG_64BIT { "brxhg", 0x44, INSTR_RIE_RRP }, { "brxlg", 0x45, INSTR_RIE_RRP }, + { "crb", 0xf6, INSTR_RRS_RRRDU }, + { "cgrb", 0xe4, INSTR_RRS_RRRDU }, + { "crj", 0x76, INSTR_RIE_RRPU }, + { "cgrj", 0x64, INSTR_RIE_RRPU }, + { "cib", 0xfe, INSTR_RIS_RURDI }, + { "cgib", 0xfc, INSTR_RIS_RURDI }, + { "cij", 0x7e, INSTR_RIE_RUPI }, + { "cgij", 0x7c, INSTR_RIE_RUPI }, + { "cit", 0x72, INSTR_RIE_R0IU }, + { "cgit", 0x70, INSTR_RIE_R0IU }, + { "clrb", 0xf7, INSTR_RRS_RRRDU }, + { "clgrb", 0xe5, INSTR_RRS_RRRDU }, + { "clrj", 0x77, INSTR_RIE_RRPU }, + { "clgrj", 0x65, INSTR_RIE_RRPU }, + { "clib", 0xff, INSTR_RIS_RURDU }, + { "clgib", 0xfd, INSTR_RIS_RURDU }, + { "clij", 0x7f, INSTR_RIE_RUPU }, + { "clgij", 0x7d, INSTR_RIE_RUPU }, + { "clfit", 0x73, INSTR_RIE_R0UU }, + { "clgit", 0x71, INSTR_RIE_R0UU }, + { "rnsbg", 0x54, INSTR_RIE_RRUUU }, + { "rxsbg", 0x57, INSTR_RIE_RRUUU }, + { "rosbg", 0x56, INSTR_RIE_RRUUU }, + { "risbg", 0x55, INSTR_RIE_RRUUU }, #endif { "", 0, INSTR_INVALID } }; @@ -1004,6 +1188,16 @@ static struct insn opcode_ed[] = { { "ldy", 0x65, INSTR_RXY_FRRD }, { "stey", 0x66, INSTR_RXY_FRRD }, { "stdy", 0x67, INSTR_RXY_FRRD }, + { "sldt", 0x40, INSTR_RXF_FRRDF }, + { "slxt", 0x48, INSTR_RXF_FRRDF }, + { "srdt", 0x41, INSTR_RXF_FRRDF }, + { "srxt", 0x49, INSTR_RXF_FRRDF }, + { "tdcet", 0x50, INSTR_RXE_FRRD }, + { "tdcdt", 0x54, INSTR_RXE_FRRD }, + { "tdcxt", 0x58, INSTR_RXE_FRRD }, + { "tdget", 0x51, INSTR_RXE_FRRD }, + { "tdgdt", 0x55, INSTR_RXE_FRRD }, + { "tdgxt", 0x59, INSTR_RXE_FRRD }, #endif { "ldeb", 0x04, INSTR_RXE_FRRD }, { "lxdb", 0x05, INSTR_RXE_FRRD }, @@ -1037,6 +1231,7 @@ static struct insn opcode_ed[] = { { "mae", 0x2e, INSTR_RXF_FRRDF }, { "mse", 0x2f, INSTR_RXF_FRRDF }, { "sqe", 0x34, INSTR_RXE_FRRD }, + { "sqd", 0x35, INSTR_RXE_FRRD }, { "mee", 0x37, INSTR_RXE_FRRD }, { "mad", 0x3e, INSTR_RXF_FRRDF }, { "msd", 0x3f, INSTR_RXF_FRRDF }, @@ -1117,6 +1312,12 @@ static struct insn *find_insn(unsigned char *code) case 0xc2: table = opcode_c2; break; + case 0xc4: + table = opcode_c4; + break; + case 0xc6: + table = opcode_c6; + break; case 0xc8: table = opcode_c8; break; diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index e49e9e0c69fd..c00856ad4e5a 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -82,7 +82,8 @@ asm( " lm 6,15,24(15)\n" #endif " br 14\n" - " .size savesys_ipl_nss, .-savesys_ipl_nss\n"); + " .size savesys_ipl_nss, .-savesys_ipl_nss\n" + " .previous\n"); static __initdata char upper_command_line[COMMAND_LINE_SIZE]; @@ -214,10 +215,13 @@ static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE); static noinline __init void detect_machine_type(void) { - /* No VM information? Looks like LPAR */ - if (stsi(&vmms, 3, 2, 2) == -ENOSYS) + /* Check current-configuration-level */ + if ((stsi(NULL, 0, 0, 0) >> 28) <= 2) { + S390_lowcore.machine_flags |= MACHINE_FLAG_LPAR; return; - if (!vmms.count) + } + /* Get virtual-machine cpu information. */ + if (stsi(&vmms, 3, 2, 2) == -ENOSYS || !vmms.count) return; /* Running under KVM? If not we assume z/VM */ @@ -352,6 +356,7 @@ static __init void detect_machine_facilities(void) { #ifdef CONFIG_64BIT unsigned int facilities; + unsigned long long facility_bits; facilities = stfl(); if (facilities & (1 << 28)) @@ -360,6 +365,9 @@ static __init void detect_machine_facilities(void) S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF; if (facilities & (1 << 4)) S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; + if ((stfle(&facility_bits, 1) > 0) && + (facility_bits & (1ULL << (63 - 40)))) + S390_lowcore.machine_flags |= MACHINE_FLAG_SPP; #endif } @@ -402,8 +410,19 @@ static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t)) static void __init setup_boot_command_line(void) { + int i; + + /* convert arch command line to ascii */ + for (i = 0; i < ARCH_COMMAND_LINE_SIZE; i++) + if (COMMAND_LINE[i] & 0x80) + break; + if (i < ARCH_COMMAND_LINE_SIZE) + EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); + COMMAND_LINE[ARCH_COMMAND_LINE_SIZE-1] = 0; + /* copy arch command line */ - strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); + strlcpy(boot_command_line, strstrip(COMMAND_LINE), + ARCH_COMMAND_LINE_SIZE); /* append IPL PARM data to the boot command line */ if (MACHINE_IS_VM) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index e8ef21c51bbe..bea9ee37ac9d 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -13,7 +13,6 @@ #include <linux/linkage.h> #include <linux/init.h> #include <asm/cache.h> -#include <asm/lowcore.h> #include <asm/errno.h> #include <asm/ptrace.h> #include <asm/thread_info.h> @@ -74,21 +73,24 @@ STACK_SIZE = 1 << STACK_SHIFT basr %r14,%r1 .endm - .macro TRACE_IRQS_CHECK - basr %r2,%r0 + .macro TRACE_IRQS_CHECK_ON tm SP_PSW(%r15),0x03 # irqs enabled? - jz 0f - l %r1,BASED(.Ltrace_irq_on_caller) - basr %r14,%r1 - j 1f -0: l %r1,BASED(.Ltrace_irq_off_caller) - basr %r14,%r1 -1: + bz BASED(0f) + TRACE_IRQS_ON +0: + .endm + + .macro TRACE_IRQS_CHECK_OFF + tm SP_PSW(%r15),0x03 # irqs enabled? + bz BASED(0f) + TRACE_IRQS_OFF +0: .endm #else #define TRACE_IRQS_ON #define TRACE_IRQS_OFF -#define TRACE_IRQS_CHECK +#define TRACE_IRQS_CHECK_ON +#define TRACE_IRQS_CHECK_OFF #endif #ifdef CONFIG_LOCKDEP @@ -178,9 +180,9 @@ STACK_SIZE = 1 << STACK_SHIFT s %r15,BASED(.Lc_spsize) # make room for registers & psw mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - icm %r12,3,__LC_SVC_ILC + icm %r12,12,__LC_SVC_ILC stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack - st %r12,SP_SVCNR(%r15) + st %r12,SP_ILC(%r15) mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack la %r12,0 st %r12,__SF_BACKCHAIN(%r15) # clear back chain @@ -274,66 +276,45 @@ sysc_do_restart: st %r2,SP_R2(%r15) # store return value (change R2 on stack) sysc_return: + LOCKDEP_SYS_EXIT +sysc_tif: tm __TI_flags+3(%r9),_TIF_WORK_SVC bnz BASED(sysc_work) # there is work to do (signals etc.) sysc_restore: -#ifdef CONFIG_TRACE_IRQFLAGS - la %r1,BASED(sysc_restore_trace_psw_addr) - l %r1,0(%r1) - lpsw 0(%r1) -sysc_restore_trace: - TRACE_IRQS_CHECK - LOCKDEP_SYS_EXIT -#endif -sysc_leave: RESTORE_ALL __LC_RETURN_PSW,1 sysc_done: -#ifdef CONFIG_TRACE_IRQFLAGS -sysc_restore_trace_psw_addr: - .long sysc_restore_trace_psw - - .section .data,"aw",@progbits - .align 8 - .globl sysc_restore_trace_psw -sysc_restore_trace_psw: - .long 0, sysc_restore_trace + 0x80000000 - .previous -#endif - # -# recheck if there is more work to do -# -sysc_work_loop: - tm __TI_flags+3(%r9),_TIF_WORK_SVC - bz BASED(sysc_restore) # there is no work to do -# -# One of the work bits is on. Find out which one. +# There is work to do, but first we need to check if we return to userspace. # sysc_work: tm SP_PSW+1(%r15),0x01 # returning to user ? bno BASED(sysc_restore) + +# +# One of the work bits is on. Find out which one. +# +sysc_work_tif: tm __TI_flags+3(%r9),_TIF_MCCK_PENDING bo BASED(sysc_mcck_pending) tm __TI_flags+3(%r9),_TIF_NEED_RESCHED bo BASED(sysc_reschedule) tm __TI_flags+3(%r9),_TIF_SIGPENDING - bnz BASED(sysc_sigpending) + bo BASED(sysc_sigpending) tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME - bnz BASED(sysc_notify_resume) + bo BASED(sysc_notify_resume) tm __TI_flags+3(%r9),_TIF_RESTART_SVC bo BASED(sysc_restart) tm __TI_flags+3(%r9),_TIF_SINGLE_STEP bo BASED(sysc_singlestep) - b BASED(sysc_restore) -sysc_work_done: + b BASED(sysc_return) # beware of critical section cleanup # # _TIF_NEED_RESCHED is set, call schedule # sysc_reschedule: l %r1,BASED(.Lschedule) - la %r14,BASED(sysc_work_loop) + la %r14,BASED(sysc_return) br %r1 # call scheduler # @@ -341,7 +322,7 @@ sysc_reschedule: # sysc_mcck_pending: l %r1,BASED(.Ls390_handle_mcck) - la %r14,BASED(sysc_work_loop) + la %r14,BASED(sysc_return) br %r1 # TIF bit will be cleared by handler # @@ -356,7 +337,7 @@ sysc_sigpending: bo BASED(sysc_restart) tm __TI_flags+3(%r9),_TIF_SINGLE_STEP bo BASED(sysc_singlestep) - b BASED(sysc_work_loop) + b BASED(sysc_return) # # _TIF_NOTIFY_RESUME is set, call do_notify_resume @@ -364,7 +345,7 @@ sysc_sigpending: sysc_notify_resume: la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Ldo_notify_resume) - la %r14,BASED(sysc_work_loop) + la %r14,BASED(sysc_return) br %r1 # call do_notify_resume @@ -459,11 +440,13 @@ kernel_execve: br %r14 # execve succeeded. 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts + TRACE_IRQS_OFF l %r15,__LC_KERNEL_STACK # load ksp s %r15,BASED(.Lc_spsize) # make room for registers & psw l %r9,__LC_THREAD_INFO mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) + TRACE_IRQS_ON stosm __SF_EMPTY(%r15),0x03 # reenable interrupts l %r1,BASED(.Lexecve_tail) basr %r14,%r1 @@ -500,8 +483,8 @@ pgm_check_handler: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER pgm_no_vtime: + TRACE_IRQS_CHECK_OFF l %r9,__LC_THREAD_INFO # load pointer to thread_info struct - TRACE_IRQS_OFF l %r3,__LC_PGM_ILC # load program interruption code la %r8,0x7f nr %r8,%r3 @@ -510,8 +493,10 @@ pgm_do_call: sll %r8,2 l %r7,0(%r8,%r7) # load address of handler routine la %r2,SP_PTREGS(%r15) # address of register-save area - la %r14,BASED(sysc_return) - br %r7 # branch to interrupt-handler + basr %r14,%r7 # branch to interrupt-handler +pgm_exit: + TRACE_IRQS_CHECK_ON + b BASED(sysc_return) # # handle per exception @@ -538,20 +523,28 @@ pgm_per_std: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER pgm_no_vtime2: + TRACE_IRQS_CHECK_OFF l %r9,__LC_THREAD_INFO # load pointer to thread_info struct - TRACE_IRQS_OFF l %r1,__TI_task(%r9) + tm SP_PSW+1(%r15),0x01 # kernel per event ? + bz BASED(kernel_per) mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - tm SP_PSW+1(%r15),0x01 # kernel per event ? - bz BASED(kernel_per) l %r3,__LC_PGM_ILC # load program interruption code la %r8,0x7f nr %r8,%r3 # clear per-event-bit and ilc - be BASED(sysc_return) # only per or per+check ? - b BASED(pgm_do_call) + be BASED(pgm_exit2) # only per or per+check ? + l %r7,BASED(.Ljump_table) + sll %r8,2 + l %r7,0(%r8,%r7) # load address of handler routine + la %r2,SP_PTREGS(%r15) # address of register-save area + basr %r14,%r7 # branch to interrupt-handler +pgm_exit2: + TRACE_IRQS_ON + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + b BASED(sysc_return) # # it was a single stepped SVC that is causing all the trouble @@ -571,8 +564,8 @@ pgm_svcper: mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP TRACE_IRQS_ON - lm %r2,%r6,SP_R2(%r15) # load svc arguments stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + lm %r2,%r6,SP_R2(%r15) # load svc arguments b BASED(sysc_do_svc) # @@ -583,8 +576,8 @@ kernel_per: mvi SP_SVCNR+1(%r15),0xff la %r2,SP_PTREGS(%r15) # address of register-save area l %r1,BASED(.Lhandle_per) # load adr. of per handler - la %r14,BASED(sysc_restore)# load adr. of system return - br %r1 # branch to do_single_step + basr %r14,%r1 # branch to do_single_step + b BASED(pgm_exit) /* * IO interrupt handler routine @@ -603,134 +596,126 @@ io_int_handler: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER io_no_vtime: - l %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF + l %r9,__LC_THREAD_INFO # load pointer to thread_info struct l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ la %r2,SP_PTREGS(%r15) # address of register-save area basr %r14,%r1 # branch to standard irq handler io_return: + LOCKDEP_SYS_EXIT + TRACE_IRQS_ON +io_tif: tm __TI_flags+3(%r9),_TIF_WORK_INT bnz BASED(io_work) # there is work to do (signals etc.) io_restore: -#ifdef CONFIG_TRACE_IRQFLAGS - la %r1,BASED(io_restore_trace_psw_addr) - l %r1,0(%r1) - lpsw 0(%r1) -io_restore_trace: - TRACE_IRQS_CHECK - LOCKDEP_SYS_EXIT -#endif -io_leave: RESTORE_ALL __LC_RETURN_PSW,0 io_done: -#ifdef CONFIG_TRACE_IRQFLAGS -io_restore_trace_psw_addr: - .long io_restore_trace_psw - - .section .data,"aw",@progbits - .align 8 - .globl io_restore_trace_psw -io_restore_trace_psw: - .long 0, io_restore_trace + 0x80000000 - .previous -#endif - # -# switch to kernel stack, then check the TIF bits +# There is work todo, find out in which context we have been interrupted: +# 1) if we return to user space we can do all _TIF_WORK_INT work +# 2) if we return to kernel code and preemptive scheduling is enabled check +# the preemption counter and if it is zero call preempt_schedule_irq +# Before any work can be done, a switch to the kernel stack is required. # io_work: tm SP_PSW+1(%r15),0x01 # returning to user ? -#ifndef CONFIG_PREEMPT - bno BASED(io_restore) # no-> skip resched & signal -#else - bnz BASED(io_work_user) # no -> check for preemptive scheduling + bo BASED(io_work_user) # yes -> do resched & signal +#ifdef CONFIG_PREEMPT # check for preemptive scheduling icm %r0,15,__TI_precount(%r9) bnz BASED(io_restore) # preemption disabled + tm __TI_flags+3(%r9),_TIF_NEED_RESCHED + bno BASED(io_restore) + # switch to kernel stack l %r1,SP_R15(%r15) s %r1,BASED(.Lc_spsize) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain lr %r15,%r1 -io_resume_loop: - tm __TI_flags+3(%r9),_TIF_NEED_RESCHED - bno BASED(io_restore) + # TRACE_IRQS_ON already done at io_return, call + # TRACE_IRQS_OFF to keep things symmetrical + TRACE_IRQS_OFF l %r1,BASED(.Lpreempt_schedule_irq) - la %r14,BASED(io_resume_loop) - br %r1 # call schedule + basr %r14,%r1 # call preempt_schedule_irq + b BASED(io_return) +#else + b BASED(io_restore) #endif +# +# Need to do work before returning to userspace, switch to kernel stack +# io_work_user: l %r1,__LC_KERNEL_STACK s %r1,BASED(.Lc_spsize) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain lr %r15,%r1 + # # One of the work bits is on. Find out which one. -# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED +# Checked are: _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_NEED_RESCHED # and _TIF_MCCK_PENDING # -io_work_loop: +io_work_tif: tm __TI_flags+3(%r9),_TIF_MCCK_PENDING bo BASED(io_mcck_pending) tm __TI_flags+3(%r9),_TIF_NEED_RESCHED bo BASED(io_reschedule) tm __TI_flags+3(%r9),_TIF_SIGPENDING - bnz BASED(io_sigpending) + bo BASED(io_sigpending) tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME - bnz BASED(io_notify_resume) - b BASED(io_restore) -io_work_done: + bo BASED(io_notify_resume) + b BASED(io_return) # beware of critical section cleanup # # _TIF_MCCK_PENDING is set, call handler # io_mcck_pending: + # TRACE_IRQS_ON already done at io_return l %r1,BASED(.Ls390_handle_mcck) basr %r14,%r1 # TIF bit will be cleared by handler - b BASED(io_work_loop) + TRACE_IRQS_OFF + b BASED(io_return) # # _TIF_NEED_RESCHED is set, call schedule # io_reschedule: - TRACE_IRQS_ON + # TRACE_IRQS_ON already done at io_return l %r1,BASED(.Lschedule) stosm __SF_EMPTY(%r15),0x03 # reenable interrupts basr %r14,%r1 # call scheduler stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts TRACE_IRQS_OFF - tm __TI_flags+3(%r9),_TIF_WORK_INT - bz BASED(io_restore) # there is no work to do - b BASED(io_work_loop) + b BASED(io_return) # # _TIF_SIGPENDING is set, call do_signal # io_sigpending: - TRACE_IRQS_ON + # TRACE_IRQS_ON already done at io_return stosm __SF_EMPTY(%r15),0x03 # reenable interrupts la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Ldo_signal) basr %r14,%r1 # call do_signal stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts TRACE_IRQS_OFF - b BASED(io_work_loop) + b BASED(io_return) # # _TIF_SIGPENDING is set, call do_signal # io_notify_resume: - TRACE_IRQS_ON + # TRACE_IRQS_ON already done at io_return stosm __SF_EMPTY(%r15),0x03 # reenable interrupts la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Ldo_notify_resume) basr %r14,%r1 # call do_signal stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts TRACE_IRQS_OFF - b BASED(io_work_loop) + b BASED(io_return) /* * External interrupt handler routine @@ -765,15 +750,14 @@ __critical_end: .globl mcck_int_handler mcck_int_handler: - stck __LC_INT_CLOCK + stck __LC_MCCK_CLOCK spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs SAVE_ALL_BASE __LC_SAVE_AREA+32 la %r12,__LC_MCK_OLD_PSW tm __LC_MCCK_CODE,0x80 # system damage? bo BASED(mcck_int_main) # yes -> rest of mcck code invalid - mvc __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER - mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA + mvc __LC_MCCK_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? bo BASED(1f) la %r14,__LC_SYNC_ENTER_TIMER @@ -787,7 +771,7 @@ mcck_int_handler: bl BASED(0f) la %r14,__LC_LAST_UPDATE_TIMER 0: spt 0(%r14) - mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) + mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? bno BASED(mcck_int_main) # no -> skip cleanup critical tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit @@ -809,9 +793,9 @@ mcck_int_main: bno BASED(mcck_no_vtime) # no -> skip cleanup critical tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(mcck_no_vtime) - UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER - mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_MCCK_ENTER_TIMER mcck_no_vtime: l %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # load pt_regs @@ -834,7 +818,6 @@ mcck_no_vtime: mcck_return: mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit - mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+52 tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? bno BASED(0f) lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 @@ -918,18 +901,14 @@ stack_overflow: cleanup_table_system_call: .long system_call + 0x80000000, sysc_do_svc + 0x80000000 -cleanup_table_sysc_return: - .long sysc_return + 0x80000000, sysc_leave + 0x80000000 -cleanup_table_sysc_leave: - .long sysc_leave + 0x80000000, sysc_done + 0x80000000 -cleanup_table_sysc_work_loop: - .long sysc_work_loop + 0x80000000, sysc_work_done + 0x80000000 -cleanup_table_io_return: - .long io_return + 0x80000000, io_leave + 0x80000000 -cleanup_table_io_leave: - .long io_leave + 0x80000000, io_done + 0x80000000 -cleanup_table_io_work_loop: - .long io_work_loop + 0x80000000, io_work_done + 0x80000000 +cleanup_table_sysc_tif: + .long sysc_tif + 0x80000000, sysc_restore + 0x80000000 +cleanup_table_sysc_restore: + .long sysc_restore + 0x80000000, sysc_done + 0x80000000 +cleanup_table_io_tif: + .long io_tif + 0x80000000, io_restore + 0x80000000 +cleanup_table_io_restore: + .long io_restore + 0x80000000, io_done + 0x80000000 cleanup_critical: clc 4(4,%r12),BASED(cleanup_table_system_call) @@ -937,49 +916,40 @@ cleanup_critical: clc 4(4,%r12),BASED(cleanup_table_system_call+4) bl BASED(cleanup_system_call) 0: - clc 4(4,%r12),BASED(cleanup_table_sysc_return) - bl BASED(0f) - clc 4(4,%r12),BASED(cleanup_table_sysc_return+4) - bl BASED(cleanup_sysc_return) -0: - clc 4(4,%r12),BASED(cleanup_table_sysc_leave) + clc 4(4,%r12),BASED(cleanup_table_sysc_tif) bl BASED(0f) - clc 4(4,%r12),BASED(cleanup_table_sysc_leave+4) - bl BASED(cleanup_sysc_leave) + clc 4(4,%r12),BASED(cleanup_table_sysc_tif+4) + bl BASED(cleanup_sysc_tif) 0: - clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop) + clc 4(4,%r12),BASED(cleanup_table_sysc_restore) bl BASED(0f) - clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4) - bl BASED(cleanup_sysc_return) + clc 4(4,%r12),BASED(cleanup_table_sysc_restore+4) + bl BASED(cleanup_sysc_restore) 0: - clc 4(4,%r12),BASED(cleanup_table_io_return) + clc 4(4,%r12),BASED(cleanup_table_io_tif) bl BASED(0f) - clc 4(4,%r12),BASED(cleanup_table_io_return+4) - bl BASED(cleanup_io_return) + clc 4(4,%r12),BASED(cleanup_table_io_tif+4) + bl BASED(cleanup_io_tif) 0: - clc 4(4,%r12),BASED(cleanup_table_io_leave) + clc 4(4,%r12),BASED(cleanup_table_io_restore) bl BASED(0f) - clc 4(4,%r12),BASED(cleanup_table_io_leave+4) - bl BASED(cleanup_io_leave) -0: - clc 4(4,%r12),BASED(cleanup_table_io_work_loop) - bl BASED(0f) - clc 4(4,%r12),BASED(cleanup_table_io_work_loop+4) - bl BASED(cleanup_io_return) + clc 4(4,%r12),BASED(cleanup_table_io_restore+4) + bl BASED(cleanup_io_restore) 0: br %r14 cleanup_system_call: mvc __LC_RETURN_PSW(8),0(%r12) - c %r12,BASED(.Lmck_old_psw) - be BASED(0f) - la %r12,__LC_SAVE_AREA+16 - b BASED(1f) -0: la %r12,__LC_SAVE_AREA+32 -1: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4) bh BASED(0f) + mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER + c %r12,BASED(.Lmck_old_psw) + be BASED(0f) mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER +0: c %r12,BASED(.Lmck_old_psw) + la %r12,__LC_SAVE_AREA+32 + be BASED(0f) + la %r12,__LC_SAVE_AREA+16 0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) bhe BASED(cleanup_vtime) clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn) @@ -1012,55 +982,54 @@ cleanup_system_call_insn: .long sysc_stime + 0x80000000 .long sysc_update + 0x80000000 -cleanup_sysc_return: +cleanup_sysc_tif: mvc __LC_RETURN_PSW(4),0(%r12) - mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_sysc_return) + mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_sysc_tif) la %r12,__LC_RETURN_PSW br %r14 -cleanup_sysc_leave: - clc 4(4,%r12),BASED(cleanup_sysc_leave_insn) +cleanup_sysc_restore: + clc 4(4,%r12),BASED(cleanup_sysc_restore_insn) be BASED(2f) + mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER + c %r12,BASED(.Lmck_old_psw) + be BASED(0f) mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER - clc 4(4,%r12),BASED(cleanup_sysc_leave_insn+4) +0: clc 4(4,%r12),BASED(cleanup_sysc_restore_insn+4) be BASED(2f) mvc __LC_RETURN_PSW(8),SP_PSW(%r15) c %r12,BASED(.Lmck_old_psw) - bne BASED(0f) - mvc __LC_SAVE_AREA+32(16),SP_R12(%r15) - b BASED(1f) -0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15) -1: lm %r0,%r11,SP_R0(%r15) + la %r12,__LC_SAVE_AREA+32 + be BASED(1f) + la %r12,__LC_SAVE_AREA+16 +1: mvc 0(16,%r12),SP_R12(%r15) + lm %r0,%r11,SP_R0(%r15) l %r15,SP_R15(%r15) 2: la %r12,__LC_RETURN_PSW br %r14 -cleanup_sysc_leave_insn: +cleanup_sysc_restore_insn: .long sysc_done - 4 + 0x80000000 .long sysc_done - 8 + 0x80000000 -cleanup_io_return: +cleanup_io_tif: mvc __LC_RETURN_PSW(4),0(%r12) - mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_io_work_loop) + mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_io_tif) la %r12,__LC_RETURN_PSW br %r14 -cleanup_io_leave: - clc 4(4,%r12),BASED(cleanup_io_leave_insn) - be BASED(2f) - mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER - clc 4(4,%r12),BASED(cleanup_io_leave_insn+4) - be BASED(2f) +cleanup_io_restore: + clc 4(4,%r12),BASED(cleanup_io_restore_insn) + be BASED(1f) + mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER + clc 4(4,%r12),BASED(cleanup_io_restore_insn+4) + be BASED(1f) mvc __LC_RETURN_PSW(8),SP_PSW(%r15) - c %r12,BASED(.Lmck_old_psw) - bne BASED(0f) mvc __LC_SAVE_AREA+32(16),SP_R12(%r15) - b BASED(1f) -0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15) -1: lm %r0,%r11,SP_R0(%r15) + lm %r0,%r11,SP_R0(%r15) l %r15,SP_R15(%r15) -2: la %r12,__LC_RETURN_PSW +1: la %r12,__LC_RETURN_PSW br %r14 -cleanup_io_leave_insn: +cleanup_io_restore_insn: .long io_done - 4 + 0x80000000 .long io_done - 8 + 0x80000000 diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index e1e5e767ab56..eb15c12ec158 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h @@ -24,17 +24,13 @@ int __cpuinit start_secondary(void *cpuvoid); void __init startup_init(void); void die(const char * str, struct pt_regs * regs, long err); -struct new_utsname; -struct mmap_arg_struct; +struct s390_mmap_arg_struct; struct fadvise64_64_args; struct old_sigaction; -struct sel_arg_struct; -long sys_mmap2(struct mmap_arg_struct __user *arg); -long sys_s390_old_mmap(struct mmap_arg_struct __user *arg); -long sys_ipc(uint call, int first, unsigned long second, +long sys_mmap2(struct s390_mmap_arg_struct __user *arg); +long sys_s390_ipc(uint call, int first, unsigned long second, unsigned long third, void __user *ptr); -long sys_s390_newuname(struct new_utsname __user *name); long sys_s390_personality(unsigned long personality); long sys_s390_fadvise64(int fd, u32 offset_high, u32 offset_low, size_t len, int advice); diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index f33658f09dd7..8bccec15ea90 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -2,18 +2,16 @@ * arch/s390/kernel/entry64.S * S390 low-level entry points. * - * Copyright (C) IBM Corp. 1999,2006 + * Copyright (C) IBM Corp. 1999,2010 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * Hartmut Penner (hp@de.ibm.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), * Heiko Carstens <heiko.carstens@de.ibm.com> */ -#include <linux/sys.h> #include <linux/linkage.h> #include <linux/init.h> #include <asm/cache.h> -#include <asm/lowcore.h> #include <asm/errno.h> #include <asm/ptrace.h> #include <asm/thread_info.h> @@ -61,30 +59,45 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ #define BASED(name) name-system_call(%r13) + .macro HANDLE_SIE_INTERCEPT +#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) + lg %r3,__LC_SIE_HOOK + ltgr %r3,%r3 + jz 0f + basr %r14,%r3 +0: +#endif + .endm + #ifdef CONFIG_TRACE_IRQFLAGS .macro TRACE_IRQS_ON - basr %r2,%r0 - brasl %r14,trace_hardirqs_on_caller + basr %r2,%r0 + brasl %r14,trace_hardirqs_on_caller .endm .macro TRACE_IRQS_OFF - basr %r2,%r0 - brasl %r14,trace_hardirqs_off_caller + basr %r2,%r0 + brasl %r14,trace_hardirqs_off_caller .endm - .macro TRACE_IRQS_CHECK - basr %r2,%r0 + .macro TRACE_IRQS_CHECK_ON tm SP_PSW(%r15),0x03 # irqs enabled? jz 0f - brasl %r14,trace_hardirqs_on_caller - j 1f -0: brasl %r14,trace_hardirqs_off_caller -1: + TRACE_IRQS_ON +0: + .endm + + .macro TRACE_IRQS_CHECK_OFF + tm SP_PSW(%r15),0x03 # irqs enabled? + jz 0f + TRACE_IRQS_OFF +0: .endm #else #define TRACE_IRQS_ON #define TRACE_IRQS_OFF -#define TRACE_IRQS_CHECK +#define TRACE_IRQS_CHECK_ON +#define TRACE_IRQS_CHECK_OFF #endif #ifdef CONFIG_LOCKDEP @@ -113,31 +126,35 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ * R15 - kernel stack pointer */ - .macro SAVE_ALL_BASE savearea - stmg %r12,%r15,\savearea - larl %r13,system_call - .endm - .macro SAVE_ALL_SVC psworg,savearea - la %r12,\psworg + stmg %r11,%r15,\savearea lg %r15,__LC_KERNEL_STACK # problem state -> load ksp + aghi %r15,-SP_SIZE # make room for registers & psw + lg %r11,__LC_LAST_BREAK .endm - .macro SAVE_ALL_SYNC psworg,savearea - la %r12,\psworg + .macro SAVE_ALL_PGM psworg,savearea + stmg %r11,%r15,\savearea tm \psworg+1,0x01 # test problem state bit - jz 2f # skip stack setup save - lg %r15,__LC_KERNEL_STACK # problem state -> load ksp #ifdef CONFIG_CHECK_STACK - j 3f -2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD - jz stack_overflow -3: + jnz 1f + tml %r15,STACK_SIZE - CONFIG_STACK_GUARD + jnz 2f + la %r12,\psworg + j stack_overflow +#else + jz 2f #endif -2: +1: lg %r15,__LC_KERNEL_STACK # problem state -> load ksp +2: aghi %r15,-SP_SIZE # make room for registers & psw + larl %r13,system_call + lg %r11,__LC_LAST_BREAK .endm .macro SAVE_ALL_ASYNC psworg,savearea + stmg %r11,%r15,\savearea + larl %r13,system_call + lg %r11,__LC_LAST_BREAK la %r12,\psworg tm \psworg+1,0x01 # test problem state bit jnz 1f # from user -> load kernel stack @@ -151,27 +168,23 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ 0: lg %r14,__LC_ASYNC_STACK # are we already on the async. stack ? slgr %r14,%r15 srag %r14,%r14,STACK_SHIFT - jz 2f -1: lg %r15,__LC_ASYNC_STACK # load async stack #ifdef CONFIG_CHECK_STACK - j 3f -2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD - jz stack_overflow -3: + jnz 1f + tml %r15,STACK_SIZE - CONFIG_STACK_GUARD + jnz 2f + j stack_overflow +#else + jz 2f #endif -2: +1: lg %r15,__LC_ASYNC_STACK # load async stack +2: aghi %r15,-SP_SIZE # make room for registers & psw .endm - .macro CREATE_STACK_FRAME psworg,savearea - aghi %r15,-SP_SIZE # make room for registers & psw - mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack + .macro CREATE_STACK_FRAME savearea + xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 - icm %r12,3,__LC_SVC_ILC - stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack - st %r12,SP_SVCNR(%r15) - mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack - la %r12,0 - stg %r12,__SF_BACKCHAIN(%r15) + mvc SP_R11(40,%r15),\savearea # move %r11-%r15 to stack + stmg %r0,%r10,SP_R0(%r15) # store gprs %r0-%r10 to kernel stack .endm .macro RESTORE_ALL psworg,sync @@ -187,6 +200,13 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ lpswe \psworg # back to caller .endm + .macro LAST_BREAK + srag %r10,%r11,23 + jz 0f + stg %r11,__TI_last_break(%r12) +0: + .endm + /* * Scheduler resume function, called by switch_to * gpr2 = (task_struct *) prev @@ -232,143 +252,129 @@ __critical_start: system_call: stpt __LC_SYNC_ENTER_TIMER sysc_saveall: - SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA - CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA - llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore + CREATE_STACK_FRAME __LC_SAVE_AREA + mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW + mvc SP_ILC(4,%r15),__LC_SVC_ILC + stg %r7,SP_ARGS(%r15) + lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct sysc_vtime: UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER sysc_stime: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER sysc_update: mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER + LAST_BREAK sysc_do_svc: - lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct - ltgr %r7,%r7 # test for svc 0 + llgh %r7,SP_SVCNR(%r15) + slag %r7,%r7,2 # shift and test for svc 0 jnz sysc_nr_ok # svc 0: system call number in %r1 - cl %r1,BASED(.Lnr_syscalls) + llgfr %r1,%r1 # clear high word in r1 + cghi %r1,NR_syscalls jnl sysc_nr_ok - lgfr %r7,%r1 # clear high word in r1 + sth %r1,SP_SVCNR(%r15) + slag %r7,%r1,2 # shift and test for svc 0 sysc_nr_ok: - mvc SP_ARGS(8,%r15),SP_R7(%r15) -sysc_do_restart: - sth %r7,SP_SVCNR(%r15) - sllg %r7,%r7,2 # svc number * 4 larl %r10,sys_call_table #ifdef CONFIG_COMPAT - tm __TI_flags+5(%r9),(_TIF_31BIT>>16) # running in 31 bit mode ? + tm __TI_flags+5(%r12),(_TIF_31BIT>>16) # running in 31 bit mode ? jno sysc_noemu larl %r10,sys_call_table_emu # use 31 bit emulation system calls sysc_noemu: #endif - tm __TI_flags+6(%r9),_TIF_SYSCALL + tm __TI_flags+6(%r12),_TIF_SYSCALL lgf %r8,0(%r7,%r10) # load address of system call routine jnz sysc_tracesys basr %r14,%r8 # call sys_xxxx stg %r2,SP_R2(%r15) # store return value (change R2 on stack) sysc_return: - tm __TI_flags+7(%r9),_TIF_WORK_SVC + LOCKDEP_SYS_EXIT +sysc_tif: + tm __TI_flags+7(%r12),_TIF_WORK_SVC jnz sysc_work # there is work to do (signals etc.) sysc_restore: -#ifdef CONFIG_TRACE_IRQFLAGS - larl %r1,sysc_restore_trace_psw - lpswe 0(%r1) -sysc_restore_trace: - TRACE_IRQS_CHECK - LOCKDEP_SYS_EXIT -#endif -sysc_leave: RESTORE_ALL __LC_RETURN_PSW,1 sysc_done: -#ifdef CONFIG_TRACE_IRQFLAGS - .section .data,"aw",@progbits - .align 8 - .globl sysc_restore_trace_psw -sysc_restore_trace_psw: - .quad 0, sysc_restore_trace - .previous -#endif - -# -# recheck if there is more work to do # -sysc_work_loop: - tm __TI_flags+7(%r9),_TIF_WORK_SVC - jz sysc_restore # there is no work to do -# -# One of the work bits is on. Find out which one. +# There is work to do, but first we need to check if we return to userspace. # sysc_work: tm SP_PSW+1(%r15),0x01 # returning to user ? jno sysc_restore - tm __TI_flags+7(%r9),_TIF_MCCK_PENDING + +# +# One of the work bits is on. Find out which one. +# +sysc_work_tif: + tm __TI_flags+7(%r12),_TIF_MCCK_PENDING jo sysc_mcck_pending - tm __TI_flags+7(%r9),_TIF_NEED_RESCHED + tm __TI_flags+7(%r12),_TIF_NEED_RESCHED jo sysc_reschedule - tm __TI_flags+7(%r9),_TIF_SIGPENDING - jnz sysc_sigpending - tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME - jnz sysc_notify_resume - tm __TI_flags+7(%r9),_TIF_RESTART_SVC + tm __TI_flags+7(%r12),_TIF_SIGPENDING + jo sysc_sigpending + tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME + jo sysc_notify_resume + tm __TI_flags+7(%r12),_TIF_RESTART_SVC jo sysc_restart - tm __TI_flags+7(%r9),_TIF_SINGLE_STEP + tm __TI_flags+7(%r12),_TIF_SINGLE_STEP jo sysc_singlestep - j sysc_restore -sysc_work_done: + j sysc_return # beware of critical section cleanup # # _TIF_NEED_RESCHED is set, call schedule # sysc_reschedule: - larl %r14,sysc_work_loop - jg schedule # return point is sysc_return + larl %r14,sysc_return + jg schedule # return point is sysc_return # # _TIF_MCCK_PENDING is set, call handler # sysc_mcck_pending: - larl %r14,sysc_work_loop + larl %r14,sysc_return jg s390_handle_mcck # TIF bit will be cleared by handler # # _TIF_SIGPENDING is set, call do_signal # sysc_sigpending: - ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP + ni __TI_flags+7(%r12),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP la %r2,SP_PTREGS(%r15) # load pt_regs brasl %r14,do_signal # call do_signal - tm __TI_flags+7(%r9),_TIF_RESTART_SVC + tm __TI_flags+7(%r12),_TIF_RESTART_SVC jo sysc_restart - tm __TI_flags+7(%r9),_TIF_SINGLE_STEP + tm __TI_flags+7(%r12),_TIF_SINGLE_STEP jo sysc_singlestep - j sysc_work_loop + j sysc_return # # _TIF_NOTIFY_RESUME is set, call do_notify_resume # sysc_notify_resume: la %r2,SP_PTREGS(%r15) # load pt_regs - larl %r14,sysc_work_loop + larl %r14,sysc_return jg do_notify_resume # call do_notify_resume # # _TIF_RESTART_SVC is set, set up registers and restart svc # sysc_restart: - ni __TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC + ni __TI_flags+7(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC lg %r7,SP_R2(%r15) # load new svc number mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument lmg %r2,%r6,SP_R2(%r15) # load svc arguments - j sysc_do_restart # restart svc + sth %r7,SP_SVCNR(%r15) + slag %r7,%r7,2 + j sysc_nr_ok # restart svc # # _TIF_SINGLE_STEP is set, call do_single_step # sysc_singlestep: - ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP + ni __TI_flags+7(%r12),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number la %r2,SP_PTREGS(%r15) # address of register-save area larl %r14,sysc_return # load adr. of system return @@ -381,8 +387,8 @@ sysc_singlestep: sysc_tracesys: la %r2,SP_PTREGS(%r15) # load pt_regs la %r3,0 - srl %r7,2 - stg %r7,SP_R2(%r15) + llgh %r0,SP_SVCNR(%r15) + stg %r0,SP_R2(%r15) brasl %r14,do_syscall_trace_enter lghi %r0,NR_syscalls clgr %r0,%r2 @@ -395,7 +401,7 @@ sysc_tracego: basr %r14,%r8 # call sys_xxx stg %r2,SP_R2(%r15) # store return value sysc_tracenogo: - tm __TI_flags+6(%r9),_TIF_SYSCALL + tm __TI_flags+6(%r12),_TIF_SYSCALL jz sysc_return la %r2,SP_PTREGS(%r15) # load pt_regs larl %r14,sysc_return # return point is sysc_return @@ -407,7 +413,7 @@ sysc_tracenogo: .globl ret_from_fork ret_from_fork: lg %r13,__LC_SVC_NEW_PSW+8 - lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct + lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? jo 0f stg %r15,SP_R15(%r15) # store stack pointer for new kthread @@ -437,12 +443,14 @@ kernel_execve: br %r14 # execve succeeded. 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts +# TRACE_IRQS_OFF lg %r15,__LC_KERNEL_STACK # load ksp aghi %r15,-SP_SIZE # make room for registers & psw lg %r13,__LC_SVC_NEW_PSW+8 - lg %r9,__LC_THREAD_INFO mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs + lg %r12,__LC_THREAD_INFO xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) +# TRACE_IRQS_ON stosm __SF_EMPTY(%r15),0x03 # reenable interrupts brasl %r14,execve_tail j sysc_return @@ -467,20 +475,23 @@ pgm_check_handler: * for LPSW?). */ stpt __LC_SYNC_ENTER_TIMER - SAVE_ALL_BASE __LC_SAVE_AREA tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception jnz pgm_per # got per exception -> special case - SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA - CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA + SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA + CREATE_STACK_FRAME __LC_SAVE_AREA + xc SP_ILC(4,%r15),SP_ILC(%r15) + mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW + lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER + LAST_BREAK pgm_no_vtime: - lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct - mvc SP_ARGS(8,%r15),__LC_LAST_BREAK - TRACE_IRQS_OFF + HANDLE_SIE_INTERCEPT + TRACE_IRQS_CHECK_OFF + stg %r11,SP_ARGS(%r15) lgf %r3,__LC_PGM_ILC # load program interruption code lghi %r8,0x7f ngr %r8,%r3 @@ -489,8 +500,10 @@ pgm_do_call: larl %r1,pgm_check_table lg %r1,0(%r8,%r1) # load address of handler routine la %r2,SP_PTREGS(%r15) # address of register-save area - larl %r14,sysc_return - br %r1 # branch to interrupt-handler + basr %r14,%r1 # branch to interrupt-handler +pgm_exit: + TRACE_IRQS_CHECK_ON + j sysc_return # # handle per exception @@ -502,55 +515,68 @@ pgm_per: clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW je pgm_svcper # no interesting special case, ignore PER event - lmg %r12,%r15,__LC_SAVE_AREA lpswe __LC_PGM_OLD_PSW # # Normal per exception # pgm_per_std: - SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA - CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA + SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA + CREATE_STACK_FRAME __LC_SAVE_AREA + mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW + lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz pgm_no_vtime2 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER + LAST_BREAK pgm_no_vtime2: - lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct - TRACE_IRQS_OFF - lg %r1,__TI_task(%r9) + HANDLE_SIE_INTERCEPT + TRACE_IRQS_CHECK_OFF + lg %r1,__TI_task(%r12) tm SP_PSW+1(%r15),0x01 # kernel per event ? jz kernel_per mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID - oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP + oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP lgf %r3,__LC_PGM_ILC # load program interruption code lghi %r8,0x7f ngr %r8,%r3 # clear per-event-bit and ilc - je sysc_return - j pgm_do_call + je pgm_exit2 + sll %r8,3 + larl %r1,pgm_check_table + lg %r1,0(%r8,%r1) # load address of handler routine + la %r2,SP_PTREGS(%r15) # address of register-save area + basr %r14,%r1 # branch to interrupt-handler +pgm_exit2: + TRACE_IRQS_ON + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + j sysc_return # # it was a single stepped SVC that is causing all the trouble # pgm_svcper: - SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA - CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA + SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA + CREATE_STACK_FRAME __LC_SAVE_AREA + mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW + mvc SP_ILC(4,%r15),__LC_SVC_ILC + lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER - llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore - lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct - lg %r8,__TI_task(%r9) + LAST_BREAK + TRACE_IRQS_OFF + lg %r8,__TI_task(%r12) mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID mvc __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID - oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP + oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP TRACE_IRQS_ON - lmg %r2,%r6,SP_R2(%r15) # load svc arguments stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + lmg %r2,%r6,SP_R2(%r15) # load svc arguments j sysc_do_svc # @@ -559,8 +585,8 @@ pgm_svcper: kernel_per: xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number la %r2,SP_PTREGS(%r15) # address of register-save area - larl %r14,sysc_restore # load adr. of system ret, no work - jg do_single_step # branch to do_single_step + brasl %r14,do_single_step + j pgm_exit /* * IO interrupt handler routine @@ -569,162 +595,133 @@ kernel_per: io_int_handler: stck __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER - SAVE_ALL_BASE __LC_SAVE_AREA+32 - SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+32 - CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32 + SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+40 + CREATE_STACK_FRAME __LC_SAVE_AREA+40 + mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack + lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz io_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER + LAST_BREAK io_no_vtime: - lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct + HANDLE_SIE_INTERCEPT TRACE_IRQS_OFF la %r2,SP_PTREGS(%r15) # address of register-save area brasl %r14,do_IRQ # call standard irq handler io_return: - tm __TI_flags+7(%r9),_TIF_WORK_INT + LOCKDEP_SYS_EXIT + TRACE_IRQS_ON +io_tif: + tm __TI_flags+7(%r12),_TIF_WORK_INT jnz io_work # there is work to do (signals etc.) io_restore: -#ifdef CONFIG_TRACE_IRQFLAGS - larl %r1,io_restore_trace_psw - lpswe 0(%r1) -io_restore_trace: - TRACE_IRQS_CHECK - LOCKDEP_SYS_EXIT -#endif -io_leave: RESTORE_ALL __LC_RETURN_PSW,0 io_done: -#ifdef CONFIG_TRACE_IRQFLAGS - .section .data,"aw",@progbits - .align 8 - .globl io_restore_trace_psw -io_restore_trace_psw: - .quad 0, io_restore_trace - .previous -#endif - # -# There is work todo, we need to check if we return to userspace, then -# check, if we are in SIE, if yes leave it +# There is work todo, find out in which context we have been interrupted: +# 1) if we return to user space we can do all _TIF_WORK_INT work +# 2) if we return to kernel code and kvm is enabled check if we need to +# modify the psw to leave SIE +# 3) if we return to kernel code and preemptive scheduling is enabled check +# the preemption counter and if it is zero call preempt_schedule_irq +# Before any work can be done, a switch to the kernel stack is required. # io_work: tm SP_PSW+1(%r15),0x01 # returning to user ? -#ifndef CONFIG_PREEMPT -#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) - jnz io_work_user # yes -> no need to check for SIE - la %r1, BASED(sie_opcode) # we return to kernel here - lg %r2, SP_PSW+8(%r15) - clc 0(2,%r1), 0(%r2) # is current instruction = SIE? - jne io_restore # no-> return to kernel - lg %r1, SP_PSW+8(%r15) # yes-> add 4 bytes to leave SIE - aghi %r1, 4 - stg %r1, SP_PSW+8(%r15) - j io_restore # return to kernel -#else - jno io_restore # no-> skip resched & signal -#endif -#else - jnz io_work_user # yes -> do resched & signal -#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) - la %r1, BASED(sie_opcode) - lg %r2, SP_PSW+8(%r15) - clc 0(2,%r1), 0(%r2) # is current instruction = SIE? - jne 0f # no -> leave PSW alone - lg %r1, SP_PSW+8(%r15) # yes-> add 4 bytes to leave SIE - aghi %r1, 4 - stg %r1, SP_PSW+8(%r15) -0: -#endif + jo io_work_user # yes -> do resched & signal +#ifdef CONFIG_PREEMPT # check for preemptive scheduling - icm %r0,15,__TI_precount(%r9) + icm %r0,15,__TI_precount(%r12) jnz io_restore # preemption is disabled + tm __TI_flags+7(%r12),_TIF_NEED_RESCHED + jno io_restore # switch to kernel stack lg %r1,SP_R15(%r15) aghi %r1,-SP_SIZE mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain lgr %r15,%r1 -io_resume_loop: - tm __TI_flags+7(%r9),_TIF_NEED_RESCHED - jno io_restore - larl %r14,io_resume_loop - jg preempt_schedule_irq + # TRACE_IRQS_ON already done at io_return, call + # TRACE_IRQS_OFF to keep things symmetrical + TRACE_IRQS_OFF + brasl %r14,preempt_schedule_irq + j io_return +#else + j io_restore #endif +# +# Need to do work before returning to userspace, switch to kernel stack +# io_work_user: lg %r1,__LC_KERNEL_STACK aghi %r1,-SP_SIZE mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain lgr %r15,%r1 + # # One of the work bits is on. Find out which one. -# Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGPENDING, _TIF_NEED_RESCHED +# Checked are: _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_NEED_RESCHED # and _TIF_MCCK_PENDING # -io_work_loop: - tm __TI_flags+7(%r9),_TIF_MCCK_PENDING +io_work_tif: + tm __TI_flags+7(%r12),_TIF_MCCK_PENDING jo io_mcck_pending - tm __TI_flags+7(%r9),_TIF_NEED_RESCHED + tm __TI_flags+7(%r12),_TIF_NEED_RESCHED jo io_reschedule - tm __TI_flags+7(%r9),_TIF_SIGPENDING - jnz io_sigpending - tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME - jnz io_notify_resume - j io_restore -io_work_done: - -#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) -sie_opcode: - .long 0xb2140000 -#endif + tm __TI_flags+7(%r12),_TIF_SIGPENDING + jo io_sigpending + tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME + jo io_notify_resume + j io_return # beware of critical section cleanup # # _TIF_MCCK_PENDING is set, call handler # io_mcck_pending: + # TRACE_IRQS_ON already done at io_return brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler - j io_work_loop + TRACE_IRQS_OFF + j io_return # # _TIF_NEED_RESCHED is set, call schedule # io_reschedule: - TRACE_IRQS_ON + # TRACE_IRQS_ON already done at io_return stosm __SF_EMPTY(%r15),0x03 # reenable interrupts brasl %r14,schedule # call scheduler stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts TRACE_IRQS_OFF - tm __TI_flags+7(%r9),_TIF_WORK_INT - jz io_restore # there is no work to do - j io_work_loop + j io_return # # _TIF_SIGPENDING or is set, call do_signal # io_sigpending: - TRACE_IRQS_ON + # TRACE_IRQS_ON already done at io_return stosm __SF_EMPTY(%r15),0x03 # reenable interrupts la %r2,SP_PTREGS(%r15) # load pt_regs brasl %r14,do_signal # call do_signal stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts TRACE_IRQS_OFF - j io_work_loop + j io_return # # _TIF_NOTIFY_RESUME or is set, call do_notify_resume # io_notify_resume: - TRACE_IRQS_ON + # TRACE_IRQS_ON already done at io_return stosm __SF_EMPTY(%r15),0x03 # reenable interrupts la %r2,SP_PTREGS(%r15) # load pt_regs brasl %r14,do_notify_resume # call do_notify_resume stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts TRACE_IRQS_OFF - j io_work_loop + j io_return /* * External interrupt handler routine @@ -733,16 +730,18 @@ io_notify_resume: ext_int_handler: stck __LC_INT_CLOCK stpt __LC_ASYNC_ENTER_TIMER - SAVE_ALL_BASE __LC_SAVE_AREA+32 - SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32 - CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32 + SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+40 + CREATE_STACK_FRAME __LC_SAVE_AREA+40 + mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack + lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz ext_no_vtime UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER + LAST_BREAK ext_no_vtime: - lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct + HANDLE_SIE_INTERCEPT TRACE_IRQS_OFF la %r2,SP_PTREGS(%r15) # address of register-save area llgh %r3,__LC_EXT_INT_CODE # get interruption code @@ -756,17 +755,18 @@ __critical_end: */ .globl mcck_int_handler mcck_int_handler: - stck __LC_INT_CLOCK + stck __LC_MCCK_CLOCK la %r1,4095 # revalidate r1 spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs - SAVE_ALL_BASE __LC_SAVE_AREA+64 + stmg %r11,%r15,__LC_SAVE_AREA+80 + larl %r13,system_call + lg %r11,__LC_LAST_BREAK la %r12,__LC_MCK_OLD_PSW tm __LC_MCCK_CODE,0x80 # system damage? jo mcck_int_main # yes -> rest of mcck code invalid la %r14,4095 - mvc __LC_SAVE_AREA+104(8),__LC_ASYNC_ENTER_TIMER - mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14) + mvc __LC_MCCK_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14) tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? jo 1f la %r14,__LC_SYNC_ENTER_TIMER @@ -780,7 +780,7 @@ mcck_int_handler: jl 0f la %r14,__LC_LAST_UPDATE_TIMER 0: spt 0(%r14) - mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) + mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? jno mcck_int_main # no -> skip cleanup critical tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit @@ -796,16 +796,19 @@ mcck_int_main: srag %r14,%r14,PAGE_SHIFT jz 0f lg %r15,__LC_PANIC_STACK # load panic stack -0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64 +0: aghi %r15,-SP_SIZE # make room for registers & psw + CREATE_STACK_FRAME __LC_SAVE_AREA+80 + mvc SP_PSW(16,%r15),0(%r12) + lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? jno mcck_no_vtime # no -> no timer update tm SP_PSW+1(%r15),0x01 # interrupting from user ? jz mcck_no_vtime - UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER + UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER - mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER + mvc __LC_LAST_UPDATE_TIMER(8),__LC_MCCK_ENTER_TIMER + LAST_BREAK mcck_no_vtime: - lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # load pt_regs brasl %r14,s390_do_machine_check tm SP_PSW+1(%r15),0x01 # returning to user ? @@ -816,8 +819,9 @@ mcck_no_vtime: xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain lgr %r15,%r1 stosm __SF_EMPTY(%r15),0x04 # turn dat on - tm __TI_flags+7(%r9),_TIF_MCCK_PENDING + tm __TI_flags+7(%r12),_TIF_MCCK_PENDING jno mcck_return + HANDLE_SIE_INTERCEPT TRACE_IRQS_OFF brasl %r14,s390_handle_mcck TRACE_IRQS_ON @@ -825,11 +829,11 @@ mcck_return: mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 - mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+104 tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? jno 0f stpt __LC_EXIT_TIMER 0: lpswe __LC_RETURN_MCCK_PSW # back to caller +mcck_done: /* * Restart interruption handler, kick starter for additional CPUs @@ -885,14 +889,14 @@ stack_overflow: lg %r15,__LC_PANIC_STACK # change to panic stack aghi %r15,-SP_SIZE mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack - stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack + stmg %r0,%r10,SP_R0(%r15) # store gprs %r0-%r10 to kernel stack la %r1,__LC_SAVE_AREA chi %r12,__LC_SVC_OLD_PSW je 0f chi %r12,__LC_PGM_OLD_PSW je 0f - la %r1,__LC_SAVE_AREA+32 -0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack + la %r1,__LC_SAVE_AREA+40 +0: mvc SP_R11(40,%r15),0(%r1) # move %r11-%r15 to stack mvc SP_ARGS(8,%r15),__LC_LAST_BREAK xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain la %r2,SP_PTREGS(%r15) # load pt_regs @@ -901,18 +905,14 @@ stack_overflow: cleanup_table_system_call: .quad system_call, sysc_do_svc -cleanup_table_sysc_return: - .quad sysc_return, sysc_leave -cleanup_table_sysc_leave: - .quad sysc_leave, sysc_done -cleanup_table_sysc_work_loop: - .quad sysc_work_loop, sysc_work_done -cleanup_table_io_return: - .quad io_return, io_leave -cleanup_table_io_leave: - .quad io_leave, io_done -cleanup_table_io_work_loop: - .quad io_work_loop, io_work_done +cleanup_table_sysc_tif: + .quad sysc_tif, sysc_restore +cleanup_table_sysc_restore: + .quad sysc_restore, sysc_done +cleanup_table_io_tif: + .quad io_tif, io_restore +cleanup_table_io_restore: + .quad io_restore, io_done cleanup_critical: clc 8(8,%r12),BASED(cleanup_table_system_call) @@ -920,61 +920,54 @@ cleanup_critical: clc 8(8,%r12),BASED(cleanup_table_system_call+8) jl cleanup_system_call 0: - clc 8(8,%r12),BASED(cleanup_table_sysc_return) + clc 8(8,%r12),BASED(cleanup_table_sysc_tif) jl 0f - clc 8(8,%r12),BASED(cleanup_table_sysc_return+8) - jl cleanup_sysc_return + clc 8(8,%r12),BASED(cleanup_table_sysc_tif+8) + jl cleanup_sysc_tif 0: - clc 8(8,%r12),BASED(cleanup_table_sysc_leave) + clc 8(8,%r12),BASED(cleanup_table_sysc_restore) jl 0f - clc 8(8,%r12),BASED(cleanup_table_sysc_leave+8) - jl cleanup_sysc_leave + clc 8(8,%r12),BASED(cleanup_table_sysc_restore+8) + jl cleanup_sysc_restore 0: - clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop) + clc 8(8,%r12),BASED(cleanup_table_io_tif) jl 0f - clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8) - jl cleanup_sysc_return + clc 8(8,%r12),BASED(cleanup_table_io_tif+8) + jl cleanup_io_tif 0: - clc 8(8,%r12),BASED(cleanup_table_io_return) + clc 8(8,%r12),BASED(cleanup_table_io_restore) jl 0f - clc 8(8,%r12),BASED(cleanup_table_io_return+8) - jl cleanup_io_return -0: - clc 8(8,%r12),BASED(cleanup_table_io_leave) - jl 0f - clc 8(8,%r12),BASED(cleanup_table_io_leave+8) - jl cleanup_io_leave -0: - clc 8(8,%r12),BASED(cleanup_table_io_work_loop) - jl 0f - clc 8(8,%r12),BASED(cleanup_table_io_work_loop+8) - jl cleanup_io_return + clc 8(8,%r12),BASED(cleanup_table_io_restore+8) + jl cleanup_io_restore 0: br %r14 cleanup_system_call: mvc __LC_RETURN_PSW(16),0(%r12) - cghi %r12,__LC_MCK_OLD_PSW - je 0f - la %r12,__LC_SAVE_AREA+32 - j 1f -0: la %r12,__LC_SAVE_AREA+64 -1: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8) jh 0f + mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER + cghi %r12,__LC_MCK_OLD_PSW + je 0f mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER +0: cghi %r12,__LC_MCK_OLD_PSW + la %r12,__LC_SAVE_AREA+80 + je 0f + la %r12,__LC_SAVE_AREA+40 0: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16) jhe cleanup_vtime clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn) jh 0f - mvc __LC_SAVE_AREA(32),0(%r12) -0: stg %r13,8(%r12) - stg %r12,__LC_SAVE_AREA+96 # argh - SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA - CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA - lg %r12,__LC_SAVE_AREA+96 # argh - stg %r15,24(%r12) - llgh %r7,__LC_SVC_INT_CODE + mvc __LC_SAVE_AREA(40),0(%r12) +0: lg %r15,__LC_KERNEL_STACK # problem state -> load ksp + aghi %r15,-SP_SIZE # make room for registers & psw + stg %r15,32(%r12) + stg %r11,0(%r12) + CREATE_STACK_FRAME __LC_SAVE_AREA + mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW + mvc SP_ILC(4,%r15),__LC_SVC_ILC + stg %r7,SP_ARGS(%r15) + mvc 8(8,%r12),__LC_THREAD_INFO cleanup_vtime: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) jhe cleanup_stime @@ -985,7 +978,11 @@ cleanup_stime: UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER cleanup_update: mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER - mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8) + srag %r12,%r11,23 + lg %r12,__LC_THREAD_INFO + jz 0f + stg %r11,__TI_last_break(%r12) +0: mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8) la %r12,__LC_RETURN_PSW br %r14 cleanup_system_call_insn: @@ -995,55 +992,54 @@ cleanup_system_call_insn: .quad sysc_stime .quad sysc_update -cleanup_sysc_return: +cleanup_sysc_tif: mvc __LC_RETURN_PSW(8),0(%r12) - mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_sysc_return) + mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_sysc_tif) la %r12,__LC_RETURN_PSW br %r14 -cleanup_sysc_leave: - clc 8(8,%r12),BASED(cleanup_sysc_leave_insn) - je 3f - clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8) +cleanup_sysc_restore: + clc 8(8,%r12),BASED(cleanup_sysc_restore_insn) + je 2f + clc 8(8,%r12),BASED(cleanup_sysc_restore_insn+8) jhe 0f + mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER + cghi %r12,__LC_MCK_OLD_PSW + je 0f mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) cghi %r12,__LC_MCK_OLD_PSW - jne 1f - mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) - j 2f -1: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) -2: lmg %r0,%r11,SP_R0(%r15) + la %r12,__LC_SAVE_AREA+80 + je 1f + la %r12,__LC_SAVE_AREA+40 +1: mvc 0(40,%r12),SP_R11(%r15) + lmg %r0,%r10,SP_R0(%r15) lg %r15,SP_R15(%r15) -3: la %r12,__LC_RETURN_PSW +2: la %r12,__LC_RETURN_PSW br %r14 -cleanup_sysc_leave_insn: +cleanup_sysc_restore_insn: .quad sysc_done - 4 .quad sysc_done - 16 -cleanup_io_return: +cleanup_io_tif: mvc __LC_RETURN_PSW(8),0(%r12) - mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_io_work_loop) + mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_io_tif) la %r12,__LC_RETURN_PSW br %r14 -cleanup_io_leave: - clc 8(8,%r12),BASED(cleanup_io_leave_insn) - je 3f - clc 8(8,%r12),BASED(cleanup_io_leave_insn+8) +cleanup_io_restore: + clc 8(8,%r12),BASED(cleanup_io_restore_insn) + je 1f + clc 8(8,%r12),BASED(cleanup_io_restore_insn+8) jhe 0f - mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER + mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) - cghi %r12,__LC_MCK_OLD_PSW - jne 1f - mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) - j 2f -1: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) -2: lmg %r0,%r11,SP_R0(%r15) + mvc __LC_SAVE_AREA+80(40),SP_R11(%r15) + lmg %r0,%r10,SP_R0(%r15) lg %r15,SP_R15(%r15) -3: la %r12,__LC_RETURN_PSW +1: la %r12,__LC_RETURN_PSW br %r14 -cleanup_io_leave_insn: +cleanup_io_restore_insn: .quad io_done - 4 .quad io_done - 16 @@ -1051,13 +1047,6 @@ cleanup_io_leave_insn: * Integer constants */ .align 4 -.Lconst: -.Lnr_syscalls: .long NR_syscalls -.L0x0130: .short 0x130 -.L0x0140: .short 0x140 -.L0x0150: .short 0x150 -.L0x0160: .short 0x160 -.L0x0170: .short 0x170 .Lcritical_start: .quad __critical_start .Lcritical_end: diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index 5a82bc68193e..6a83d0581317 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c @@ -13,7 +13,7 @@ #include <linux/kernel.h> #include <linux/types.h> #include <trace/syscall.h> -#include <asm/lowcore.h> +#include <asm/asm-offsets.h> #ifdef CONFIG_DYNAMIC_FTRACE @@ -200,13 +200,3 @@ out: return parent; } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ - -#ifdef CONFIG_FTRACE_SYSCALLS - -extern unsigned int sys_call_table[]; - -unsigned long __init arch_syscall_addr(int nr) -{ - return (unsigned long)sys_call_table[nr]; -} -#endif diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index c52b4f7742fa..51838ad42d56 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -1,5 +1,5 @@ /* - * Copyright IBM Corp. 1999,2009 + * Copyright IBM Corp. 1999,2010 * * Author(s): Hartmut Penner <hp@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com> @@ -22,12 +22,9 @@ */ #include <linux/init.h> -#include <asm/setup.h> -#include <asm/lowcore.h> #include <asm/asm-offsets.h> #include <asm/thread_info.h> #include <asm/page.h> -#include <asm/cpu.h> #ifdef CONFIG_64BIT #define ARCH_OFFSET 4 @@ -288,19 +285,7 @@ iplstart: 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 + 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) @@ -343,8 +328,8 @@ iplstart: # # reset files in VM reader # - stidp __LC_CPUID # store cpuid - tm __LC_CPUID,0xff # running VM ? + stidp __LC_SAVE_AREA # store cpuid + tm __LC_SAVE_AREA,0xff # running VM ? bno .Lnoreset la %r2,.Lreset lhi %r3,26 @@ -384,7 +369,6 @@ iplstart: .Linitrd:.long _end + 0x400000 # default address of initrd .Lparm: .long PARMAREA .Lstartup: .long startup -.Lcvtab:.long _ebcasc # ebcdic to ascii table .Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6 .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" @@ -417,13 +401,10 @@ start: .sk8x8: mvc 0(240,%r8),0(%r9) # copy iplparms into buffer .gotr: - l %r10,.tbl # EBCDIC to ASCII table - tr 0(240,%r8),0(%r10) slr %r0,%r0 st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11) st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11) j startup # continue with startup -.tbl: .long _ebcasc # translate table .cmd: .long COMMAND_LINE # address of command line buffer .parm: .long PARMAREA .lowcase: @@ -467,16 +448,15 @@ start: # or linload or SALIPL # .org 0x10000 -startup:basr %r13,0 # get base + .globl startup +startup: + basr %r13,0 # get base .LPG0: xc 0x200(256),0x200 # partially clear lowcore xc 0x300(256),0x300 - l %r1,5f-.LPG0(%r13) - stck 0(%r1) - spt 6f-.LPG0(%r13) - mvc __LC_LAST_UPDATE_CLOCK(8),0(%r1) - mvc __LC_LAST_UPDATE_TIMER(8),6f-.LPG0(%r13) - mvc __LC_EXIT_TIMER(8),5f-.LPG0(%r13) + stck __LC_LAST_UPDATE_CLOCK + spt 5f-.LPG0(%r13) + mvc __LC_LAST_UPDATE_TIMER(8),5f-.LPG0(%r13) #ifndef CONFIG_MARCH_G5 # check capabilities against MARCH_{G5,Z900,Z990,Z9_109,Z10} xc __LC_STFL_FAC_LIST(8),__LC_STFL_FAC_LIST @@ -494,7 +474,6 @@ startup:basr %r13,0 # get base cl %r0,2f+12-.LPG0(%r13) je 3f 1: l %r15,.Lstack-.LPG0(%r13) - ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE ahi %r15,-96 la %r2,.Lals_string-.LPG0(%r13) l %r3,.Lsclp_print-.LPG0(%r13) @@ -505,7 +484,7 @@ startup:basr %r13,0 # get base .Lsclp_print: .long _sclp_print_early .Lstack: - .long init_thread_union + .long 0x8000 + (1<<(PAGE_SHIFT+THREAD_ORDER)) .align 16 2: .long 0x000a0000,0x8badcccc #if defined(CONFIG_64BIT) @@ -532,13 +511,25 @@ startup:basr %r13,0 # get base 3: #endif +#ifdef CONFIG_64BIT + mvi __LC_AR_MODE_ID,1 # set esame flag + slr %r0,%r0 # set cpuid to zero + lhi %r1,2 # mode 2 = esame (dump) + sigp %r1,%r0,0x12 # switch to esame mode + sam64 # switch to 64 bit mode + larl %r13,4f + lmh %r0,%r15,0(%r13) # clear high-order half + jg startup_continue +4: .fill 16,4,0x0 +#else + mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) l %r13,4f-.LPG0(%r13) b 0(%r13) - .align 4 + .align 8 4: .long startup_continue -5: .long sched_clock_base_cc +#endif .align 8 -6: .long 0x7fffffff,0xffffffff +5: .long 0x7fffffff,0xffffffff # # params at 10400 (setup.h) @@ -552,8 +543,4 @@ startup:basr %r13,0 # get base .byte "root=/dev/ram0 ro" .byte 0 -#ifdef CONFIG_64BIT -#include "head64.S" -#else -#include "head31.S" -#endif + .org 0x11000 diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index 602b508cd4c4..b8f8dc126102 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -1,7 +1,7 @@ /* * arch/s390/kernel/head31.S * - * Copyright (C) IBM Corp. 2005,2006 + * Copyright (C) IBM Corp. 2005,2010 * * Author(s): Hartmut Penner <hp@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com> @@ -10,13 +10,19 @@ * */ - .org 0x11000 +#include <linux/init.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> +#include <asm/page.h> +__HEAD + .globl startup_continue startup_continue: basr %r13,0 # get base .LPG1: - mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) + l %r1,.Lbase_cc-.LPG1(%r13) + mvc 0(8,%r1),__LC_LAST_UPDATE_CLOCK lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers l %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area # move IPL device to lowcore @@ -69,12 +75,14 @@ startup_continue: .Lduald:.rept 8 .long 0x80000000,0,0,0 # invalid access-list entries .endr +.Lbase_cc: + .long sched_clock_base_cc - .org 0x12000 .globl _ehead _ehead: + #ifdef CONFIG_SHARED_KERNEL - .org 0x100000 + .org 0x100000 - 0x11000 # head.o ends at 0x11000 #endif # diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index d984a2a380c3..cdef68717416 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -1,7 +1,7 @@ /* * arch/s390/kernel/head64.S * - * Copyright (C) IBM Corp. 1999,2006 + * Copyright (C) IBM Corp. 1999,2010 * * Author(s): Hartmut Penner <hp@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com> @@ -10,81 +10,17 @@ * */ - .org 0x11000 +#include <linux/init.h> +#include <asm/asm-offsets.h> +#include <asm/thread_info.h> +#include <asm/page.h> +__HEAD + .globl startup_continue startup_continue: - basr %r13,0 # get base -.LPG1: sll %r13,1 # remove high order bit - srl %r13,1 - -#ifdef CONFIG_ZFCPDUMP - - # check if we have been ipled using zfcp dump: - - tm 0xb9,0x01 # test if subchannel is enabled - jno .nodump # subchannel disabled - l %r1,0xb8 - la %r5,.Lipl_schib-.LPG1(%r13) - stsch 0(%r5) # get schib of subchannel - jne .nodump # schib not available - tm 5(%r5),0x01 # devno valid? - jno .nodump - tm 4(%r5),0x80 # qdio capable device? - jno .nodump - l %r2,20(%r0) # address of ipl parameter block - lhi %r3,0 - ic %r3,0x148(%r2) # get opt field - chi %r3,0x20 # load with dump? - jne .nodump - - # store all prefix registers in case of load with dump: - - la %r7,0 # base register for 0 page - la %r8,0 # first cpu - l %r11,.Lpref_arr_ptr-.LPG1(%r13) # address of prefix array - ahi %r11,4 # skip boot cpu - lr %r12,%r11 - ahi %r12,(CONFIG_NR_CPUS*4) # end of prefix array - stap .Lcurrent_cpu+2-.LPG1(%r13) # store current cpu addr -1: - cl %r8,.Lcurrent_cpu-.LPG1(%r13) # is ipl cpu ? - je 4f # if yes get next cpu -2: - lr %r9,%r7 - sigp %r9,%r8,0x9 # stop & store status of cpu - brc 8,3f # accepted - brc 4,4f # status stored: next cpu - brc 2,2b # busy: try again - brc 1,4f # not op: next cpu -3: - mvc 0(4,%r11),264(%r7) # copy prefix register to prefix array - ahi %r11,4 # next element in prefix array - clr %r11,%r12 - je 5f # no more space in prefix array -4: - ahi %r8,1 # next cpu (r8 += 1) - chi %r8,MAX_CPU_ADDRESS # is last possible cpu ? - jle 1b # jump if not last cpu -5: - lhi %r1,2 # mode 2 = esame (dump) - j 6f - .align 4 -.Lipl_schib: - .rept 13 - .long 0 - .endr -.nodump: - lhi %r1,1 # mode 1 = esame (normal ipl) -6: -#else - lhi %r1,1 # mode 1 = esame (normal ipl) -#endif /* CONFIG_ZFCPDUMP */ - mvi __LC_AR_MODE_ID,1 # set esame flag - slr %r0,%r0 # set cpuid to zero - sigp %r1,%r0,0x12 # switch to esame mode - sam64 # switch to 64 bit mode - llgfr %r13,%r13 # clear high-order half of base reg - lmh %r0,%r15,.Lzero64-.LPG1(%r13) # clear high-order half + larl %r1,sched_clock_base_cc + mvc 0(8,%r1),__LC_LAST_UPDATE_CLOCK + larl %r13,.LPG1 # get base lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area # move IPL device to lowcore @@ -108,6 +44,7 @@ startup_continue: lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 16 +.LPG1: .Lentry:.quad 0x0000000180000000,_stext .Lctl: .quad 0x04350002 # cr0: various things .quad 0 # cr1: primary space segment table @@ -129,13 +66,6 @@ startup_continue: .L4malign:.quad 0xffffffffffc00000 .Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 .Lnop: .long 0x07000700 -.Lzero64:.fill 16,4,0x0 -#ifdef CONFIG_ZFCPDUMP -.Lcurrent_cpu: - .long 0x0 -.Lpref_arr_ptr: - .long zfcpdump_prefix_array -#endif /* CONFIG_ZFCPDUMP */ .Lparmaddr: .quad PARMAREA .align 64 @@ -146,11 +76,11 @@ startup_continue: .long 0x80000000,0,0,0 # invalid access-list entries .endr - .org 0x12000 .globl _ehead _ehead: + #ifdef CONFIG_SHARED_KERNEL - .org 0x100000 + .org 0x100000 - 0x11000 # head.o ends at 0x11000 #endif # diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 4d73296fed74..a689070be287 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -15,6 +15,7 @@ #include <linux/reboot.h> #include <linux/ctype.h> #include <linux/fs.h> +#include <linux/gfp.h> #include <asm/ipl.h> #include <asm/smp.h> #include <asm/setup.h> @@ -402,8 +403,9 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj, static struct kobj_attribute sys_ipl_device_attr = __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL); -static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr, - char *buf, loff_t off, size_t count) +static ssize_t ipl_parameter_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) { return memory_read_from_buffer(buf, count, &off, IPL_PARMBLOCK_START, IPL_PARMBLOCK_SIZE); @@ -418,8 +420,9 @@ static struct bin_attribute ipl_parameter_attr = { .read = &ipl_parameter_read, }; -static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *attr, - char *buf, loff_t off, size_t count) +static ssize_t ipl_scp_data_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) { unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len; void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data; @@ -553,7 +556,7 @@ out: return rc; } -static void ipl_run(struct shutdown_trigger *trigger) +static void __ipl_run(void *unused) { diag308(DIAG308_IPL, NULL); if (MACHINE_IS_VM) @@ -562,6 +565,11 @@ static void ipl_run(struct shutdown_trigger *trigger) reipl_ccw_dev(&ipl_info.data.ccw.dev_id); } +static void ipl_run(struct shutdown_trigger *trigger) +{ + smp_switch_to_ipl_cpu(__ipl_run, NULL); +} + static int __init ipl_init(void) { int rc; @@ -688,7 +696,7 @@ static struct kobj_attribute sys_reipl_ccw_vmparm_attr = /* FCP reipl device attributes */ -static ssize_t reipl_fcp_scpdata_read(struct kobject *kobj, +static ssize_t reipl_fcp_scpdata_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { @@ -698,7 +706,7 @@ static ssize_t reipl_fcp_scpdata_read(struct kobject *kobj, return memory_read_from_buffer(buf, count, &off, scp_data, size); } -static ssize_t reipl_fcp_scpdata_write(struct kobject *kobj, +static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { @@ -1039,7 +1047,7 @@ static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb, sprintf(dst + pos, " PARM %s", vmparm); } -static void reipl_run(struct shutdown_trigger *trigger) +static void __reipl_run(void *unused) { struct ccw_dev_id devid; static char buf[128]; @@ -1087,6 +1095,11 @@ static void reipl_run(struct shutdown_trigger *trigger) disabled_wait((unsigned long) __builtin_return_address(0)); } +static void reipl_run(struct shutdown_trigger *trigger) +{ + smp_switch_to_ipl_cpu(__reipl_run, NULL); +} + static void reipl_block_ccw_init(struct ipl_parameter_block *ipb) { ipb->hdr.len = IPL_PARM_BLK_CCW_LEN; @@ -1369,20 +1382,18 @@ static struct kobj_attribute dump_type_attr = static struct kset *dump_kset; -static void dump_run(struct shutdown_trigger *trigger) +static void __dump_run(void *unused) { struct ccw_dev_id devid; static char buf[100]; switch (dump_method) { case DUMP_METHOD_CCW_CIO: - smp_send_stop(); devid.devno = dump_block_ccw->ipl_info.ccw.devno; devid.ssid = 0; reipl_ccw_dev(&devid); break; case DUMP_METHOD_CCW_VM: - smp_send_stop(); sprintf(buf, "STORE STATUS"); __cpcmd(buf, NULL, 0, NULL); sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); @@ -1396,10 +1407,17 @@ static void dump_run(struct shutdown_trigger *trigger) diag308(DIAG308_SET, dump_block_fcp); diag308(DIAG308_DUMP, NULL); break; - case DUMP_METHOD_NONE: - return; + default: + break; } - printk(KERN_EMERG "Dump failed!\n"); +} + +static void dump_run(struct shutdown_trigger *trigger) +{ + if (dump_method == DUMP_METHOD_NONE) + return; + smp_send_stop(); + smp_switch_to_ipl_cpu(__dump_run, NULL); } static int __init dump_ccw_init(void) @@ -1577,7 +1595,7 @@ static void vmcmd_run(struct shutdown_trigger *trigger) static int vmcmd_init(void) { if (!MACHINE_IS_VM) - return -ENOTSUPP; + return -EOPNOTSUPP; vmcmd_kset = kset_create_and_add("vmcmd", NULL, firmware_kobj); if (!vmcmd_kset) return -ENOMEM; @@ -1595,7 +1613,7 @@ static void stop_run(struct shutdown_trigger *trigger) { if (strcmp(trigger->name, ON_PANIC_STR) == 0) disabled_wait((unsigned long) __builtin_return_address(0)); - while (signal_processor(smp_processor_id(), sigp_stop) == sigp_busy) + while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) cpu_relax(); for (;;); } @@ -1902,7 +1920,6 @@ void __init ipl_update_parameters(void) void __init ipl_save_parameters(void) { struct cio_iplinfo iplinfo; - unsigned int *ipl_ptr; void *src, *dst; if (cio_get_iplinfo(&iplinfo)) @@ -1913,11 +1930,10 @@ void __init ipl_save_parameters(void) if (!iplinfo.is_qdio) return; ipl_flags |= IPL_PARMBLOCK_VALID; - ipl_ptr = (unsigned int *)__LC_IPL_PARMBLOCK_PTR; - src = (void *)(unsigned long)*ipl_ptr; + src = (void *)(unsigned long)S390_lowcore.ipl_parmblock_ptr; dst = (void *)IPL_PARMBLOCK_ORIGIN; memmove(dst, src, PAGE_SIZE); - *ipl_ptr = IPL_PARMBLOCK_ORIGIN; + S390_lowcore.ipl_parmblock_ptr = IPL_PARMBLOCK_ORIGIN; } static LIST_HEAD(rcall); diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 86783efa24ee..2a3d2bf6f083 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -29,6 +29,7 @@ #include <asm/cacheflush.h> #include <asm/sections.h> #include <linux/module.h> +#include <linux/slab.h> DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); @@ -62,6 +63,8 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction) case 0x0b: /* bsm */ case 0x83: /* diag */ case 0x44: /* ex */ + case 0xac: /* stnsm */ + case 0xad: /* stosm */ return -EINVAL; } switch (*(__u16 *) instruction) { @@ -71,6 +74,7 @@ int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction) case 0xb258: /* bsg */ case 0xb218: /* pc */ case 0xb228: /* pt */ + case 0xb98d: /* epsw */ return -EINVAL; } return 0; diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 131d7ee8b416..a922d51df6bf 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -54,11 +54,11 @@ void machine_shutdown(void) { } -void machine_kexec(struct kimage *image) +static void __machine_kexec(void *data) { relocate_kernel_t data_mover; + struct kimage *image = data; - smp_send_stop(); pfault_fini(); s390_reset_system(); @@ -68,3 +68,9 @@ void machine_kexec(struct kimage *image) (*data_mover)(&image->head, image->start); for (;;); } + +void machine_kexec(struct kimage *image) +{ + smp_send_stop(); + smp_switch_to_ipl_cpu(__machine_kexec, image); +} diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 639380a0c45c..22cfd634c355 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -55,8 +55,10 @@ void *module_alloc(unsigned long size) /* Free memory returned from module_alloc */ void module_free(struct module *mod, void *module_region) { - vfree(mod->arch.syminfo); - mod->arch.syminfo = NULL; + if (mod) { + vfree(mod->arch.syminfo); + mod->arch.syminfo = NULL; + } vfree(module_region); } diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 015e27da40eb..ac151399ef34 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -255,7 +255,8 @@ void notrace s390_do_machine_check(struct pt_regs *regs) int umode; nmi_enter(); - s390_idle_check(); + s390_idle_check(regs, S390_lowcore.mcck_clock, + S390_lowcore.mcck_enter_timer); mci = (struct mci *) &S390_lowcore.mcck_interruption_code; mcck = &__get_cpu_var(cpu_mcck); diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 00b6d1d292f2..1039fdea15b5 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -16,9 +16,9 @@ #include <linux/fs.h> #include <linux/smp.h> #include <linux/stddef.h> +#include <linux/slab.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/user.h> #include <linux/interrupt.h> diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 0729f36c2fe3..ecb2d02b02e4 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -18,24 +18,42 @@ #include <asm/lowcore.h> #include <asm/param.h> +static DEFINE_PER_CPU(struct cpuid, cpu_id); + +/* + * cpu_init - initializes state that is per-CPU. + */ +void __cpuinit cpu_init(void) +{ + struct cpuid *id = &per_cpu(cpu_id, smp_processor_id()); + + get_cpu_id(id); + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + BUG_ON(current->mm); + enter_lazy_tlb(&init_mm, current); +} + +/* + * print_cpu_info - print basic information about a cpu + */ void __cpuinit print_cpu_info(void) { + struct cpuid *id = &per_cpu(cpu_id, smp_processor_id()); + pr_info("Processor %d started, address %d, identification %06X\n", - S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, - S390_lowcore.cpu_id.ident); + S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, id->ident); } /* * show_cpuinfo - Get information on one CPU for use by procfs. */ - static int show_cpuinfo(struct seq_file *m, void *v) { static const char *hwcap_str[10] = { "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", "highgprs" }; - struct _lowcore *lc; unsigned long n = (unsigned long) v - 1; int i; @@ -55,19 +73,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) } if (cpu_online(n)) { -#ifdef CONFIG_SMP - lc = (smp_processor_id() == n) ? - &S390_lowcore : lowcore_ptr[n]; -#else - lc = &S390_lowcore; -#endif + struct cpuid *id = &per_cpu(cpu_id, n); seq_printf(m, "processor %li: " "version = %02X, " "identification = %06X, " "machine = %04X\n", - n, lc->cpu_id.version, - lc->cpu_id.ident, - lc->cpu_id.machine); + n, id->version, id->ident, id->machine); } preempt_enable(); return 0; diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 7cf464234419..83339d33c4b1 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -57,6 +57,7 @@ enum s390_regset { REGSET_GENERAL, REGSET_FP, + REGSET_LAST_BREAK, REGSET_GENERAL_EXTENDED, }; @@ -381,6 +382,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) copied += sizeof(unsigned long); } return 0; + case PTRACE_GET_LAST_BREAK: + put_user(task_thread_info(child)->last_break, + (unsigned long __user *) data); + return 0; default: /* Removing high order bit from addr (only for 31 bit). */ addr &= PSW_ADDR_INSN; @@ -633,6 +638,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, copied += sizeof(unsigned int); } return 0; + case PTRACE_GET_LAST_BREAK: + put_user(task_thread_info(child)->last_break, + (unsigned int __user *) data); + return 0; } return compat_ptrace_request(child, request, addr, data); } @@ -640,7 +649,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) { - long ret; + long ret = 0; /* Do the secure computing check first. */ secure_computing(regs->gprs[2]); @@ -649,7 +658,6 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) * The sysc_tracesys code in entry.S stored the system * call number to gprs[2]. */ - ret = regs->gprs[2]; if (test_thread_flag(TIF_SYSCALL_TRACE) && (tracehook_report_syscall_entry(regs) || regs->gprs[2] >= NR_syscalls)) { @@ -671,7 +679,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) regs->gprs[2], regs->orig_gpr2, regs->gprs[3], regs->gprs[4], regs->gprs[5]); - return ret; + return ret ?: regs->gprs[2]; } asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) @@ -798,6 +806,28 @@ static int s390_fpregs_set(struct task_struct *target, return rc; } +#ifdef CONFIG_64BIT + +static int s390_last_break_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + if (count > 0) { + if (kbuf) { + unsigned long *k = kbuf; + *k = task_thread_info(target)->last_break; + } else { + unsigned long __user *u = ubuf; + if (__put_user(task_thread_info(target)->last_break, u)) + return -EFAULT; + } + } + return 0; +} + +#endif + static const struct user_regset s390_regsets[] = { [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, @@ -815,6 +845,15 @@ static const struct user_regset s390_regsets[] = { .get = s390_fpregs_get, .set = s390_fpregs_set, }, +#ifdef CONFIG_64BIT + [REGSET_LAST_BREAK] = { + .core_note_type = NT_S390_LAST_BREAK, + .n = 1, + .size = sizeof(long), + .align = sizeof(long), + .get = s390_last_break_get, + }, +#endif }; static const struct user_regset_view user_s390_view = { @@ -949,6 +988,27 @@ static int s390_compat_regs_high_set(struct task_struct *target, return rc; } +static int s390_compat_last_break_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + compat_ulong_t last_break; + + if (count > 0) { + last_break = task_thread_info(target)->last_break; + if (kbuf) { + unsigned long *k = kbuf; + *k = last_break; + } else { + unsigned long __user *u = ubuf; + if (__put_user(last_break, u)) + return -EFAULT; + } + } + return 0; +} + static const struct user_regset s390_compat_regsets[] = { [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, @@ -966,6 +1026,13 @@ static const struct user_regset s390_compat_regsets[] = { .get = s390_fpregs_get, .set = s390_fpregs_set, }, + [REGSET_LAST_BREAK] = { + .core_note_type = NT_S390_LAST_BREAK, + .n = 1, + .size = sizeof(long), + .align = sizeof(long), + .get = s390_compat_last_break_get, + }, [REGSET_GENERAL_EXTENDED] = { .core_note_type = NT_S390_HIGH_GPRS, .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), @@ -992,3 +1059,61 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) #endif return &user_s390_view; } + +static const char *gpr_names[NUM_GPRS] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", +}; + +unsigned long regs_get_register(struct pt_regs *regs, unsigned int offset) +{ + if (offset >= NUM_GPRS) + return 0; + return regs->gprs[offset]; +} + +int regs_query_register_offset(const char *name) +{ + unsigned long offset; + + if (!name || *name != 'r') + return -EINVAL; + if (strict_strtoul(name + 1, 10, &offset)) + return -EINVAL; + if (offset >= NUM_GPRS) + return -EINVAL; + return offset; +} + +const char *regs_query_register_name(unsigned int offset) +{ + if (offset >= NUM_GPRS) + return NULL; + return gpr_names[offset]; +} + +static int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr) +{ + unsigned long ksp = kernel_stack_pointer(regs); + + return (addr & ~(THREAD_SIZE - 1)) == (ksp & ~(THREAD_SIZE - 1)); +} + +/** + * regs_get_kernel_stack_nth() - get Nth entry of the stack + * @regs:pt_regs which contains kernel stack pointer. + * @n:stack entry number. + * + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which + * is specifined by @regs. If the @n th entry is NOT in the kernel stack, + * this returns 0. + */ +unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) +{ + unsigned long addr; + + addr = kernel_stack_pointer(regs) + n * sizeof(long); + if (!regs_within_kernel_stack(regs, addr)) + return 0; + return *(unsigned long *)addr; +} diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index 2f481cc3d1c9..cb899d9f8505 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S @@ -6,7 +6,7 @@ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com) */ -#include <asm/lowcore.h> +#include <asm/asm-offsets.h> # # do_reipl_asm diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S index 774147824c3d..5e73dee63baa 100644 --- a/arch/s390/kernel/reipl64.S +++ b/arch/s390/kernel/reipl64.S @@ -4,7 +4,7 @@ * Denis Joseph Barrow, */ -#include <asm/lowcore.h> +#include <asm/asm-offsets.h> # # do_reipl_asm diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index 59618bcd99b7..9ce641b5291f 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -120,7 +120,8 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code) struct pt_regs *old_regs; old_regs = set_irq_regs(regs); - s390_idle_check(); + s390_idle_check(regs, S390_lowcore.int_clock, + S390_lowcore.async_enter_timer); irq_enter(); if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) /* Serve timer interrupts first. */ diff --git a/arch/s390/kernel/sclp.S b/arch/s390/kernel/sclp.S index e27ca63076d1..2e82fdd89320 100644 --- a/arch/s390/kernel/sclp.S +++ b/arch/s390/kernel/sclp.S @@ -9,8 +9,10 @@ */ LC_EXT_NEW_PSW = 0x58 # addr of ext int handler +LC_EXT_NEW_PSW_64 = 0x1b0 # addr of ext int handler 64 bit LC_EXT_INT_PARAM = 0x80 # addr of ext int parameter LC_EXT_INT_CODE = 0x86 # addr of ext int code +LC_AR_MODE_ID = 0xa3 # # Subroutine which waits synchronously until either an external interruption @@ -30,8 +32,16 @@ _sclp_wait_int: .LbaseS1: ahi %r15,-96 # create stack frame la %r8,LC_EXT_NEW_PSW # register int handler - mvc .LoldpswS1-.LbaseS1(8,%r13),0(%r8) - mvc 0(8,%r8),.LextpswS1-.LbaseS1(%r13) + la %r9,.LextpswS1-.LbaseS1(%r13) +#ifdef CONFIG_64BIT + tm LC_AR_MODE_ID,1 + jno .Lesa1 + la %r8,LC_EXT_NEW_PSW_64 # register int handler 64 bit + la %r9,.LextpswS1_64-.LbaseS1(%r13) +.Lesa1: +#endif + mvc .LoldpswS1-.LbaseS1(16,%r13),0(%r8) + mvc 0(16,%r8),0(%r9) lhi %r6,0x0200 # cr mask for ext int (cr0.54) ltr %r2,%r2 jz .LsetctS1 @@ -64,15 +74,19 @@ _sclp_wait_int: .LtimeoutS1: lctl %c0,%c0,.LctlS1-.LbaseS1(%r13) # restore interrupt setting # restore old handler - mvc 0(8,%r8),.LoldpswS1-.LbaseS1(%r13) + mvc 0(16,%r8),.LoldpswS1-.LbaseS1(%r13) lm %r6,%r15,120(%r15) # restore registers br %r14 # return to caller .align 8 .LoldpswS1: - .long 0, 0 # old ext int PSW + .long 0, 0, 0, 0 # old ext int PSW .LextpswS1: .long 0x00080000, 0x80000000+.LwaitS1 # PSW to handle ext int +#ifdef CONFIG_64BIT +.LextpswS1_64: + .quad 0x0000000180000000, .LwaitS1 # PSW to handle ext int, 64 bit +#endif .LwaitpswS1: .long 0x010a0000, 0x00000000+.LloopS1 # PSW to wait for ext int .LtimeS1: @@ -221,7 +235,7 @@ _sclp_print: lh %r9,0(%r8) # update sccb length ar %r9,%r6 sth %r9,0(%r8) - ar %r7,%r6 # update current mto adress + ar %r7,%r6 # update current mto address ltr %r0,%r0 # more characters? jnz .LinitmtoS4 l %r2,.LwritedataS4-.LbaseS4(%r13)# write data @@ -250,6 +264,13 @@ _sclp_print: _sclp_print_early: stm %r6,%r15,24(%r15) # save registers ahi %r15,-96 # create stack frame +#ifdef CONFIG_64BIT + tm LC_AR_MODE_ID,1 + jno .Lesa2 + ahi %r15,-80 + stmh %r6,%r15,96(%r15) # store upper register halves +.Lesa2: +#endif lr %r10,%r2 # save string pointer lhi %r2,0 bras %r14,_sclp_setup # enable console @@ -262,6 +283,13 @@ _sclp_print_early: lhi %r2,1 bras %r14,_sclp_setup # disable console .LendS5: +#ifdef CONFIG_64BIT + tm LC_AR_MODE_ID,1 + jno .Lesa3 + lmh %r6,%r15,96(%r15) # store upper register halves + ahi %r15,80 +.Lesa3: +#endif lm %r6,%r15,120(%r15) # restore registers br %r14 diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 8d8957b38ab3..c8e8e1354e1d 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -2,7 +2,7 @@ * arch/s390/kernel/setup.c * * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) IBM Corp. 1999,2010 * Author(s): Hartmut Penner (hp@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com) * @@ -25,7 +25,6 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/slab.h> #include <linux/user.h> #include <linux/tty.h> #include <linux/ioport.h> @@ -114,22 +113,6 @@ static struct resource data_resource = { }; /* - * cpu_init() initializes state that is per-CPU. - */ -void __cpuinit cpu_init(void) -{ - /* - * Store processor id in lowcore (used e.g. in timer_interrupt) - */ - get_cpu_id(&S390_lowcore.cpu_id); - - atomic_inc(&init_mm.mm_count); - current->active_mm = &init_mm; - BUG_ON(current->mm); - enter_lazy_tlb(&init_mm, current); -} - -/* * condev= and conmode= setup parameter. */ @@ -386,25 +369,18 @@ static void setup_addressing_mode(void) pr_info("Address spaces switched, " "mvcos not available\n"); } -#ifdef CONFIG_TRACE_IRQFLAGS - sysc_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; - io_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; -#endif } static void __init setup_lowcore(void) { struct _lowcore *lc; - int lc_pages; /* * Setup lowcore for boot cpu */ - lc_pages = sizeof(void *) == 8 ? 2 : 1; - lc = (struct _lowcore *) - __alloc_bootmem(lc_pages * PAGE_SIZE, lc_pages * PAGE_SIZE, 0); - memset(lc, 0, lc_pages * PAGE_SIZE); + BUILD_BUG_ON(sizeof(struct _lowcore) != LC_PAGES * 4096); + lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0); lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) restart_int_handler; @@ -436,11 +412,12 @@ setup_lowcore(void) #ifndef CONFIG_64BIT if (MACHINE_HAS_IEEE) { lc->extended_save_area_addr = (__u32) - __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0); + __alloc_bootmem_low(PAGE_SIZE, PAGE_SIZE, 0); /* enable extended save area */ __ctl_set_bit(14, 29); } #else + lc->cmf_hpp = -1ULL; lc->vdso_per_cpu_data = (unsigned long) &lc->paste[0]; #endif lc->sync_enter_timer = S390_lowcore.sync_enter_timer; @@ -699,6 +676,7 @@ static void __init setup_hwcaps(void) static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; unsigned long long facility_list_extended; unsigned int facility_list; + struct cpuid cpu_id; int i; facility_list = stfl(); @@ -760,7 +738,8 @@ static void __init setup_hwcaps(void) */ elf_hwcap |= HWCAP_S390_HIGH_GPRS; - switch (S390_lowcore.cpu_id.machine) { + get_cpu_id(&cpu_id); + switch (cpu_id.machine) { case 0x9672: #if !defined(CONFIG_64BIT) default: /* Use "g5" as default for 31 bit kernels. */ @@ -804,7 +783,7 @@ setup_arch(char **cmdline_p) if (MACHINE_IS_VM) pr_info("Linux is running as a z/VM " "guest operating system in 31-bit mode\n"); - else + else if (MACHINE_IS_LPAR) pr_info("Linux is running natively in 31-bit mode\n"); if (MACHINE_HAS_IEEE) pr_info("The hardware system has IEEE compatible " @@ -818,7 +797,7 @@ setup_arch(char **cmdline_p) "guest operating system in 64-bit mode\n"); else if (MACHINE_IS_KVM) pr_info("Linux is running under KVM in 64-bit mode\n"); - else + else if (MACHINE_IS_LPAR) pr_info("Linux is running natively in 64-bit mode\n"); #endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 6289945562b0..ee7ac8b11782 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -313,6 +313,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, To avoid breaking binary compatibility, they are passed as args. */ regs->gprs[4] = current->thread.trap_no; regs->gprs[5] = current->thread.prot_addr; + regs->gprs[6] = task_thread_info(current)->last_break; /* Place signal number on stack to allow backtrace from handler. */ if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) @@ -376,6 +377,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, regs->gprs[2] = map_signal(sig); regs->gprs[3] = (unsigned long) &frame->info; regs->gprs[4] = (unsigned long) &frame->uc; + regs->gprs[5] = task_thread_info(current)->last_break; return 0; give_sigsegv: diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 76a6fdd46c45..541053ed234e 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -36,6 +36,8 @@ #include <linux/cpu.h> #include <linux/timex.h> #include <linux/bootmem.h> +#include <linux/slab.h> +#include <asm/asm-offsets.h> #include <asm/ipl.h> #include <asm/setup.h> #include <asm/sigp.h> @@ -53,7 +55,7 @@ #include "entry.h" /* logical cpu to cpu address */ -int __cpu_logical_map[NR_CPUS]; +unsigned short __cpu_logical_map[NR_CPUS]; static struct task_struct *current_set[NR_CPUS]; @@ -72,13 +74,13 @@ static int cpu_management; static DEFINE_PER_CPU(struct cpu, cpu_devices); -static void smp_ext_bitcall(int, ec_bit_sig); +static void smp_ext_bitcall(int, int); -static int cpu_stopped(int cpu) +static int raw_cpu_stopped(int cpu) { - __u32 status; + u32 status; - switch (signal_processor_ps(&status, 0, cpu, sigp_sense)) { + switch (raw_sigp_ps(&status, 0, cpu, sigp_sense)) { case sigp_status_stored: /* Check for stopped and check stop state */ if (status & 0x50) @@ -90,6 +92,44 @@ static int cpu_stopped(int cpu) return 0; } +static inline int cpu_stopped(int cpu) +{ + return raw_cpu_stopped(cpu_logical_map(cpu)); +} + +void smp_switch_to_ipl_cpu(void (*func)(void *), void *data) +{ + struct _lowcore *lc, *current_lc; + struct stack_frame *sf; + struct pt_regs *regs; + unsigned long sp; + + if (smp_processor_id() == 0) + func(data); + __load_psw_mask(PSW_BASE_BITS | PSW_DEFAULT_KEY); + /* Disable lowcore protection */ + __ctl_clear_bit(0, 28); + current_lc = lowcore_ptr[smp_processor_id()]; + lc = lowcore_ptr[0]; + if (!lc) + lc = current_lc; + lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; + lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) smp_restart_cpu; + if (!cpu_online(0)) + smp_switch_to_cpu(func, data, 0, stap(), __cpu_logical_map[0]); + while (sigp(0, sigp_stop_and_store_status) == sigp_busy) + cpu_relax(); + sp = lc->panic_stack; + sp -= sizeof(struct pt_regs); + regs = (struct pt_regs *) sp; + memcpy(®s->gprs, ¤t_lc->gpregs_save_area, sizeof(regs->gprs)); + regs->psw = lc->psw_save_area; + sp -= STACK_FRAME_OVERHEAD; + sf = (struct stack_frame *) sp; + sf->back_chain = regs->gprs[15]; + smp_switch_to_cpu(func, data, sp, stap(), __cpu_logical_map[0]); +} + void smp_send_stop(void) { int cpu, rc; @@ -103,7 +143,7 @@ void smp_send_stop(void) if (cpu == smp_processor_id()) continue; do { - rc = signal_processor(cpu, sigp_stop); + rc = sigp(cpu, sigp_stop); } while (rc == sigp_busy); while (!cpu_stopped(cpu)) @@ -139,13 +179,13 @@ static void do_ext_call_interrupt(__u16 code) * Send an external call sigp to another cpu and return without waiting * for its completion. */ -static void smp_ext_bitcall(int cpu, ec_bit_sig sig) +static void smp_ext_bitcall(int cpu, int sig) { /* * Set signaling bit in lowcore of target cpu and kick it */ set_bit(sig, (unsigned long *) &lowcore_ptr[cpu]->ext_call_fast); - while (signal_processor(cpu, sigp_emergency_signal) == sigp_busy) + while (sigp(cpu, sigp_emergency_signal) == sigp_busy) udelay(10); } @@ -239,24 +279,8 @@ void smp_ctl_clear_bit(int cr, int bit) } EXPORT_SYMBOL(smp_ctl_clear_bit); -/* - * In early ipl state a temp. logically cpu number is needed, so the sigp - * functions can be used to sense other cpus. Since NR_CPUS is >= 2 on - * CONFIG_SMP and the ipl cpu is logical cpu 0, it must be 1. - */ -#define CPU_INIT_NO 1 - #ifdef CONFIG_ZFCPDUMP -/* - * zfcpdump_prefix_array holds prefix registers for the following scenario: - * 64 bit zfcpdump kernel and 31 bit kernel which is to be dumped. We have to - * save its prefix registers, since they get lost, when switching from 31 bit - * to 64 bit. - */ -unsigned int zfcpdump_prefix_array[NR_CPUS + 1] \ - __attribute__((__section__(".data"))); - static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) { if (ipl_info.type != IPL_TYPE_FCP_DUMP) @@ -266,21 +290,15 @@ static void __init smp_get_save_area(unsigned int cpu, unsigned int phy_cpu) "the dump\n", cpu, NR_CPUS - 1); return; } - zfcpdump_save_areas[cpu] = kmalloc(sizeof(union save_area), GFP_KERNEL); - __cpu_logical_map[CPU_INIT_NO] = (__u16) phy_cpu; - while (signal_processor(CPU_INIT_NO, sigp_stop_and_store_status) == - sigp_busy) + zfcpdump_save_areas[cpu] = kmalloc(sizeof(struct save_area), GFP_KERNEL); + while (raw_sigp(phy_cpu, sigp_stop_and_store_status) == sigp_busy) cpu_relax(); - memcpy(zfcpdump_save_areas[cpu], - (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE, - SAVE_AREA_SIZE); -#ifdef CONFIG_64BIT - /* copy original prefix register */ - zfcpdump_save_areas[cpu]->s390x.pref_reg = zfcpdump_prefix_array[cpu]; -#endif + memcpy_real(zfcpdump_save_areas[cpu], + (void *)(unsigned long) store_prefix() + SAVE_AREA_BASE, + sizeof(struct save_area)); } -union save_area *zfcpdump_save_areas[NR_CPUS + 1]; +struct save_area *zfcpdump_save_areas[NR_CPUS + 1]; EXPORT_SYMBOL_GPL(zfcpdump_save_areas); #else @@ -389,8 +407,7 @@ static void __init smp_detect_cpus(void) for (cpu = 0; cpu <= MAX_CPU_ADDRESS; cpu++) { if (cpu == boot_cpu_addr) continue; - __cpu_logical_map[CPU_INIT_NO] = cpu; - if (!cpu_stopped(CPU_INIT_NO)) + if (!raw_cpu_stopped(cpu)) continue; smp_get_save_area(c_cpus, cpu); c_cpus++; @@ -413,8 +430,7 @@ static void __init smp_detect_cpus(void) cpu_addr = info->cpu[cpu].address; if (cpu_addr == boot_cpu_addr) continue; - __cpu_logical_map[CPU_INIT_NO] = cpu_addr; - if (!cpu_stopped(CPU_INIT_NO)) { + if (!raw_cpu_stopped(cpu_addr)) { s_cpus++; continue; } @@ -533,18 +549,18 @@ static void smp_free_lowcore(int cpu) /* Upping and downing of CPUs */ int __cpuinit __cpu_up(unsigned int cpu) { - struct task_struct *idle; struct _lowcore *cpu_lowcore; + struct task_struct *idle; struct stack_frame *sf; - sigp_ccode ccode; u32 lowcore; + int ccode; if (smp_cpu_state[cpu] != CPU_STATE_CONFIGURED) return -EIO; if (smp_alloc_lowcore(cpu)) return -ENOMEM; do { - ccode = signal_processor(cpu, sigp_initial_cpu_reset); + ccode = sigp(cpu, sigp_initial_cpu_reset); if (ccode == sigp_busy) udelay(10); if (ccode == sigp_not_operational) @@ -552,7 +568,7 @@ int __cpuinit __cpu_up(unsigned int cpu) } while (ccode == sigp_busy); lowcore = (u32)(unsigned long)lowcore_ptr[cpu]; - while (signal_processor_p(lowcore, cpu, sigp_set_prefix) == sigp_busy) + while (sigp_p(lowcore, cpu, sigp_set_prefix) == sigp_busy) udelay(10); idle = current_set[cpu]; @@ -578,7 +594,7 @@ int __cpuinit __cpu_up(unsigned int cpu) cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func; eieio(); - while (signal_processor(cpu, sigp_restart) == sigp_busy) + while (sigp(cpu, sigp_restart) == sigp_busy) udelay(10); while (!cpu_online(cpu)) @@ -640,7 +656,7 @@ void __cpu_die(unsigned int cpu) /* Wait until target cpu is down */ while (!cpu_stopped(cpu)) cpu_relax(); - while (signal_processor_p(0, cpu, sigp_set_prefix) == sigp_busy) + while (sigp_p(0, cpu, sigp_set_prefix) == sigp_busy) udelay(10); smp_free_lowcore(cpu); pr_info("Processor %d stopped\n", cpu); @@ -649,7 +665,7 @@ void __cpu_die(unsigned int cpu) void cpu_die(void) { idle_task_exit(); - while (signal_processor(smp_processor_id(), sigp_stop) == sigp_busy) + while (sigp(smp_processor_id(), sigp_stop) == sigp_busy) cpu_relax(); for (;;); } @@ -765,7 +781,8 @@ static ssize_t cpu_configure_store(struct sys_device *dev, get_online_cpus(); mutex_lock(&smp_cpu_state_mutex); rc = -EBUSY; - if (cpu_online(cpu)) + /* disallow configuration changes of online cpus and cpu 0 */ + if (cpu_online(cpu) || cpu == 0) goto out; rc = 0; switch (val) { @@ -927,21 +944,21 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self, struct cpu *c = &per_cpu(cpu_devices, cpu); struct sys_device *s = &c->sysdev; struct s390_idle_data *idle; + int err = 0; switch (action) { case CPU_ONLINE: case CPU_ONLINE_FROZEN: idle = &per_cpu(s390_idle, cpu); memset(idle, 0, sizeof(struct s390_idle_data)); - if (sysfs_create_group(&s->kobj, &cpu_online_attr_group)) - return NOTIFY_BAD; + err = sysfs_create_group(&s->kobj, &cpu_online_attr_group); break; case CPU_DEAD: case CPU_DEAD_FROZEN: sysfs_remove_group(&s->kobj, &cpu_online_attr_group); break; } - return NOTIFY_OK; + return notifier_from_errno(err); } static struct notifier_block __cpuinitdata smp_cpu_nb = { @@ -1004,7 +1021,9 @@ out: return rc; } -static ssize_t __ref rescan_store(struct sysdev_class *class, const char *buf, +static ssize_t __ref rescan_store(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + const char *buf, size_t count) { int rc; @@ -1015,7 +1034,9 @@ static ssize_t __ref rescan_store(struct sysdev_class *class, const char *buf, static SYSDEV_CLASS_ATTR(rescan, 0200, NULL, rescan_store); #endif /* CONFIG_HOTPLUG_CPU */ -static ssize_t dispatching_show(struct sysdev_class *class, char *buf) +static ssize_t dispatching_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { ssize_t count; @@ -1025,7 +1046,9 @@ static ssize_t dispatching_show(struct sysdev_class *class, char *buf) return count; } -static ssize_t dispatching_store(struct sysdev_class *dev, const char *buf, +static ssize_t dispatching_store(struct sysdev_class *dev, + struct sysdev_class_attribute *attr, + const char *buf, size_t count) { int val, rc; diff --git a/arch/s390/kernel/switch_cpu.S b/arch/s390/kernel/switch_cpu.S new file mode 100644 index 000000000000..469f11b574fa --- /dev/null +++ b/arch/s390/kernel/switch_cpu.S @@ -0,0 +1,58 @@ +/* + * 31-bit switch cpu code + * + * Copyright IBM Corp. 2009 + * + */ + +#include <asm/asm-offsets.h> +#include <asm/ptrace.h> + +# smp_switch_to_cpu switches to destination cpu and executes the passed function +# Parameter: %r2 - function to call +# %r3 - function parameter +# %r4 - stack poiner +# %r5 - current cpu +# %r6 - destination cpu + + .section .text + .align 4 + .globl smp_switch_to_cpu +smp_switch_to_cpu: + stm %r6,%r15,__SF_GPRS(%r15) + lr %r1,%r15 + ahi %r15,-STACK_FRAME_OVERHEAD + st %r1,__SF_BACKCHAIN(%r15) + basr %r13,0 +0: la %r1,.gprregs_addr-0b(%r13) + l %r1,0(%r1) + stm %r0,%r15,0(%r1) +1: sigp %r0,%r6,__SIGP_RESTART /* start destination CPU */ + brc 2,1b /* busy, try again */ +2: sigp %r0,%r5,__SIGP_STOP /* stop current CPU */ + brc 2,2b /* busy, try again */ +3: j 3b + + .globl smp_restart_cpu +smp_restart_cpu: + basr %r13,0 +0: la %r1,.gprregs_addr-0b(%r13) + l %r1,0(%r1) + lm %r0,%r15,0(%r1) +1: sigp %r0,%r5,__SIGP_SENSE /* Wait for calling CPU */ + brc 10,1b /* busy, accepted (status 0), running */ + tmll %r0,0x40 /* Test if calling CPU is stopped */ + jz 1b + ltr %r4,%r4 /* New stack ? */ + jz 1f + lr %r15,%r4 +1: basr %r14,%r2 + +.gprregs_addr: + .long .gprregs + + .section .data,"aw",@progbits +.gprregs: + .rept 16 + .long 0 + .endr diff --git a/arch/s390/kernel/switch_cpu64.S b/arch/s390/kernel/switch_cpu64.S new file mode 100644 index 000000000000..d94aacc898cb --- /dev/null +++ b/arch/s390/kernel/switch_cpu64.S @@ -0,0 +1,51 @@ +/* + * 64-bit switch cpu code + * + * Copyright IBM Corp. 2009 + * + */ + +#include <asm/asm-offsets.h> +#include <asm/ptrace.h> + +# smp_switch_to_cpu switches to destination cpu and executes the passed function +# Parameter: %r2 - function to call +# %r3 - function parameter +# %r4 - stack poiner +# %r5 - current cpu +# %r6 - destination cpu + + .section .text + .align 4 + .globl smp_switch_to_cpu +smp_switch_to_cpu: + stmg %r6,%r15,__SF_GPRS(%r15) + lgr %r1,%r15 + aghi %r15,-STACK_FRAME_OVERHEAD + stg %r1,__SF_BACKCHAIN(%r15) + larl %r1,.gprregs + stmg %r0,%r15,0(%r1) +1: sigp %r0,%r6,__SIGP_RESTART /* start destination CPU */ + brc 2,1b /* busy, try again */ +2: sigp %r0,%r5,__SIGP_STOP /* stop current CPU */ + brc 2,2b /* busy, try again */ +3: j 3b + + .globl smp_restart_cpu +smp_restart_cpu: + larl %r1,.gprregs + lmg %r0,%r15,0(%r1) +1: sigp %r0,%r5,__SIGP_SENSE /* Wait for calling CPU */ + brc 10,1b /* busy, accepted (status 0), running */ + tmll %r0,0x40 /* Test if calling CPU is stopped */ + jz 1b + ltgr %r4,%r4 /* New stack ? */ + jz 1f + lgr %r15,%r4 +1: basr %r14,%r2 + + .section .data,"aw",@progbits +.gprregs: + .rept 16 + .quad 0 + .endr diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index e5cd623cb025..1f066e46e83e 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S @@ -176,7 +176,7 @@ pgm_check_entry: cgr %r1,%r2 je restore_registers /* r1 = r2 -> nothing to do */ larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */ - mvc __LC_RESTART_PSW(16,%r0),0(%r4) + mvc __LC_RST_NEW_PSW(16,%r0),0(%r4) 3: sigp %r9,%r1,__SIGP_INITIAL_CPU_RESET brc 8,4f /* accepted */ @@ -256,6 +256,9 @@ restore_registers: lghi %r2,0 brasl %r14,arch_set_page_states + /* Reinitialize the channel subsystem */ + brasl %r14,channel_subsystem_reinit + /* Return 0 */ lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) lghi %r2,0 diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c index 86a74c9c9e63..7b6b0f81a283 100644 --- a/arch/s390/kernel/sys_s390.c +++ b/arch/s390/kernel/sys_s390.c @@ -33,13 +33,12 @@ #include "entry.h" /* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux for S/390 isn't able to handle more than 5 - * system call parameters, so these system calls used a memory - * block for parameter passing.. + * Perform the mmap() system call. Linux for S/390 isn't able to handle more + * than 5 system call parameters, so this system call uses a memory block + * for parameter passing. */ -struct mmap_arg_struct { +struct s390_mmap_arg_struct { unsigned long addr; unsigned long len; unsigned long prot; @@ -48,9 +47,9 @@ struct mmap_arg_struct { unsigned long offset; }; -SYSCALL_DEFINE1(mmap2, struct mmap_arg_struct __user *, arg) +SYSCALL_DEFINE1(mmap2, struct s390_mmap_arg_struct __user *, arg) { - struct mmap_arg_struct a; + struct s390_mmap_arg_struct a; int error = -EFAULT; if (copy_from_user(&a, arg, sizeof(a))) @@ -60,29 +59,12 @@ out: return error; } -SYSCALL_DEFINE1(s390_old_mmap, struct mmap_arg_struct __user *, arg) -{ - struct mmap_arg_struct a; - long error = -EFAULT; - - if (copy_from_user(&a, arg, sizeof(a))) - goto out; - - error = -EINVAL; - if (a.offset & ~PAGE_MASK) - goto out; - - error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); -out: - return error; -} - /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * * This is really horribly ugly. */ -SYSCALL_DEFINE5(ipc, uint, call, int, first, unsigned long, second, +SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second, unsigned long, third, void __user *, ptr) { struct ipc_kludge tmp; @@ -149,17 +131,6 @@ SYSCALL_DEFINE5(ipc, uint, call, int, first, unsigned long, second, } #ifdef CONFIG_64BIT -SYSCALL_DEFINE1(s390_newuname, struct new_utsname __user *, name) -{ - int ret = sys_newuname(name); - - if (personality(current->personality) == PER_LINUX32 && !ret) { - ret = copy_to_user(name->machine, "s390\0\0\0\0", 8); - if (ret) ret = -EFAULT; - } - return ret; -} - SYSCALL_DEFINE1(s390_personality, unsigned long, personality) { int ret; diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 30eca070d426..201ce6bed34e 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -98,7 +98,7 @@ SYSCALL(sys_uselib,sys_uselib,sys32_uselib_wrapper) SYSCALL(sys_swapon,sys_swapon,sys32_swapon_wrapper) SYSCALL(sys_reboot,sys_reboot,sys32_reboot_wrapper) SYSCALL(sys_ni_syscall,sys_ni_syscall,old32_readdir_wrapper) /* old readdir syscall */ -SYSCALL(sys_s390_old_mmap,sys_s390_old_mmap,old32_mmap_wrapper) /* 90 */ +SYSCALL(sys_old_mmap,sys_old_mmap,old32_mmap_wrapper) /* 90 */ SYSCALL(sys_munmap,sys_munmap,sys32_munmap_wrapper) SYSCALL(sys_truncate,sys_truncate,sys32_truncate_wrapper) SYSCALL(sys_ftruncate,sys_ftruncate,sys32_ftruncate_wrapper) @@ -125,12 +125,12 @@ NI_SYSCALL /* vm86old for i386 */ SYSCALL(sys_wait4,sys_wait4,compat_sys_wait4_wrapper) SYSCALL(sys_swapoff,sys_swapoff,sys32_swapoff_wrapper) /* 115 */ SYSCALL(sys_sysinfo,sys_sysinfo,compat_sys_sysinfo_wrapper) -SYSCALL(sys_ipc,sys_ipc,sys32_ipc_wrapper) +SYSCALL(sys_s390_ipc,sys_s390_ipc,sys32_ipc_wrapper) SYSCALL(sys_fsync,sys_fsync,sys32_fsync_wrapper) SYSCALL(sys_sigreturn,sys_sigreturn,sys32_sigreturn) SYSCALL(sys_clone,sys_clone,sys_clone_wrapper) /* 120 */ SYSCALL(sys_setdomainname,sys_setdomainname,sys32_setdomainname_wrapper) -SYSCALL(sys_newuname,sys_s390_newuname,sys32_newuname_wrapper) +SYSCALL(sys_newuname,sys_newuname,sys32_newuname_wrapper) NI_SYSCALL /* modify_ldt for i386 */ SYSCALL(sys_adjtimex,sys_adjtimex,compat_sys_adjtimex_wrapper) SYSCALL(sys_mprotect,sys_mprotect,sys32_mprotect_wrapper) /* 125 */ diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index b5e75e1061c8..a0ffc7717ed6 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/module.h> +#include <linux/slab.h> #include <asm/ebcdic.h> #include <asm/sysinfo.h> #include <asm/cpcmd.h> diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 65065ac48ed3..15a7536452d5 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -36,6 +36,7 @@ #include <linux/notifier.h> #include <linux/clocksource.h> #include <linux/clockchips.h> +#include <linux/gfp.h> #include <asm/uaccess.h> #include <asm/delay.h> #include <asm/s390_ext.h> @@ -51,14 +52,6 @@ #define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) -/* - * Create a small time difference between the timer interrupts - * on the different cpus to avoid lock contention. - */ -#define CPU_DEVIATION (smp_processor_id() << 12) - -#define TICK_SIZE tick - u64 sched_clock_base_cc = -1; /* Force to data section. */ EXPORT_SYMBOL_GPL(sched_clock_base_cc); @@ -81,15 +74,15 @@ unsigned long long monotonic_clock(void) } EXPORT_SYMBOL(monotonic_clock); -void tod_to_timeval(__u64 todval, struct timespec *xtime) +void tod_to_timeval(__u64 todval, struct timespec *xt) { unsigned long long sec; sec = todval >> 12; do_div(sec, 1000000); - xtime->tv_sec = sec; + xt->tv_sec = sec; todval -= (sec * 1000000) << 12; - xtime->tv_nsec = ((todval * 1000) >> 12); + xt->tv_nsec = ((todval * 1000) >> 12); } EXPORT_SYMBOL(tod_to_timeval); @@ -224,10 +217,11 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock, ++vdso_data->tb_update_count; smp_wmb(); vdso_data->xtime_tod_stamp = clock->cycle_last; - vdso_data->xtime_clock_sec = xtime.tv_sec; - vdso_data->xtime_clock_nsec = xtime.tv_nsec; + vdso_data->xtime_clock_sec = wall_time->tv_sec; + vdso_data->xtime_clock_nsec = wall_time->tv_nsec; vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; + vdso_data->ntp_mult = mult; smp_wmb(); ++vdso_data->tb_update_count; } @@ -397,7 +391,6 @@ static void __init time_init_wq(void) if (time_sync_wq) return; time_sync_wq = create_singlethread_workqueue("timesync"); - stop_machine_create(); } /* @@ -531,8 +524,11 @@ void etr_switch_to_local(void) if (!etr_eacr.sl) return; disable_sync_clock(NULL); - set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); - queue_work(time_sync_wq, &etr_work); + if (!test_and_set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events)) { + etr_eacr.es = etr_eacr.sl = 0; + etr_setr(&etr_eacr); + queue_work(time_sync_wq, &etr_work); + } } /* @@ -546,8 +542,11 @@ void etr_sync_check(void) if (!etr_eacr.es) return; disable_sync_clock(NULL); - set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); - queue_work(time_sync_wq, &etr_work); + if (!test_and_set_bit(ETR_EVENT_SYNC_CHECK, &etr_events)) { + etr_eacr.es = 0; + etr_setr(&etr_eacr); + queue_work(time_sync_wq, &etr_work); + } } /* @@ -909,7 +908,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib, * Do not try to get the alternate port aib if the clock * is not in sync yet. */ - if (!check_sync_clock()) + if (!eacr.es || !check_sync_clock()) return eacr; /* @@ -1071,7 +1070,7 @@ static void etr_work_fn(struct work_struct *work) * If the clock is in sync just update the eacr and return. * If there is no valid sync port wait for a port update. */ - if (check_sync_clock() || sync_port < 0) { + if ((eacr.es && check_sync_clock()) || sync_port < 0) { etr_update_eacr(eacr); etr_set_tolec_timeout(now); goto out_unlock; @@ -1124,14 +1123,18 @@ static struct sys_device etr_port1_dev = { /* * ETR class attributes */ -static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf) +static ssize_t etr_stepping_port_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { return sprintf(buf, "%i\n", etr_port0.esw.p); } static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL); -static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf) +static ssize_t etr_stepping_mode_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { char *mode_str; @@ -1592,7 +1595,9 @@ static struct sysdev_class stp_sysclass = { .name = "stp", }; -static ssize_t stp_ctn_id_show(struct sysdev_class *class, char *buf) +static ssize_t stp_ctn_id_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { if (!stp_online) return -ENODATA; @@ -1602,7 +1607,9 @@ static ssize_t stp_ctn_id_show(struct sysdev_class *class, char *buf) static SYSDEV_CLASS_ATTR(ctn_id, 0400, stp_ctn_id_show, NULL); -static ssize_t stp_ctn_type_show(struct sysdev_class *class, char *buf) +static ssize_t stp_ctn_type_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { if (!stp_online) return -ENODATA; @@ -1611,7 +1618,9 @@ static ssize_t stp_ctn_type_show(struct sysdev_class *class, char *buf) static SYSDEV_CLASS_ATTR(ctn_type, 0400, stp_ctn_type_show, NULL); -static ssize_t stp_dst_offset_show(struct sysdev_class *class, char *buf) +static ssize_t stp_dst_offset_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { if (!stp_online || !(stp_info.vbits & 0x2000)) return -ENODATA; @@ -1620,7 +1629,9 @@ static ssize_t stp_dst_offset_show(struct sysdev_class *class, char *buf) static SYSDEV_CLASS_ATTR(dst_offset, 0400, stp_dst_offset_show, NULL); -static ssize_t stp_leap_seconds_show(struct sysdev_class *class, char *buf) +static ssize_t stp_leap_seconds_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { if (!stp_online || !(stp_info.vbits & 0x8000)) return -ENODATA; @@ -1629,7 +1640,9 @@ static ssize_t stp_leap_seconds_show(struct sysdev_class *class, char *buf) static SYSDEV_CLASS_ATTR(leap_seconds, 0400, stp_leap_seconds_show, NULL); -static ssize_t stp_stratum_show(struct sysdev_class *class, char *buf) +static ssize_t stp_stratum_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { if (!stp_online) return -ENODATA; @@ -1638,7 +1651,9 @@ static ssize_t stp_stratum_show(struct sysdev_class *class, char *buf) static SYSDEV_CLASS_ATTR(stratum, 0400, stp_stratum_show, NULL); -static ssize_t stp_time_offset_show(struct sysdev_class *class, char *buf) +static ssize_t stp_time_offset_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { if (!stp_online || !(stp_info.vbits & 0x0800)) return -ENODATA; @@ -1647,7 +1662,9 @@ static ssize_t stp_time_offset_show(struct sysdev_class *class, char *buf) static SYSDEV_CLASS_ATTR(time_offset, 0400, stp_time_offset_show, NULL); -static ssize_t stp_time_zone_offset_show(struct sysdev_class *class, char *buf) +static ssize_t stp_time_zone_offset_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { if (!stp_online || !(stp_info.vbits & 0x4000)) return -ENODATA; @@ -1657,7 +1674,9 @@ static ssize_t stp_time_zone_offset_show(struct sysdev_class *class, char *buf) static SYSDEV_CLASS_ATTR(time_zone_offset, 0400, stp_time_zone_offset_show, NULL); -static ssize_t stp_timing_mode_show(struct sysdev_class *class, char *buf) +static ssize_t stp_timing_mode_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { if (!stp_online) return -ENODATA; @@ -1666,7 +1685,9 @@ static ssize_t stp_timing_mode_show(struct sysdev_class *class, char *buf) static SYSDEV_CLASS_ATTR(timing_mode, 0400, stp_timing_mode_show, NULL); -static ssize_t stp_timing_state_show(struct sysdev_class *class, char *buf) +static ssize_t stp_timing_state_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { if (!stp_online) return -ENODATA; @@ -1675,12 +1696,15 @@ static ssize_t stp_timing_state_show(struct sysdev_class *class, char *buf) static SYSDEV_CLASS_ATTR(timing_state, 0400, stp_timing_state_show, NULL); -static ssize_t stp_online_show(struct sysdev_class *class, char *buf) +static ssize_t stp_online_show(struct sysdev_class *class, + struct sysdev_class_attribute *attr, + char *buf) { return sprintf(buf, "%i\n", stp_online); } static ssize_t stp_online_store(struct sysdev_class *class, + struct sysdev_class_attribute *attr, const char *buf, size_t count) { unsigned int value; diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 14ef6f05e432..bcef00766a64 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -37,7 +37,8 @@ struct tl_cpu { }; struct tl_container { - unsigned char reserved[8]; + unsigned char reserved[7]; + unsigned char id; }; union tl_entry { @@ -58,6 +59,7 @@ struct tl_info { struct core_info { struct core_info *next; + unsigned char id; cpumask_t mask; }; @@ -73,6 +75,7 @@ static DECLARE_WORK(topology_work, topology_work_fn); static DEFINE_SPINLOCK(topology_lock); cpumask_t cpu_core_map[NR_CPUS]; +unsigned char cpu_core_id[NR_CPUS]; static cpumask_t cpu_coregroup_map(unsigned int cpu) { @@ -116,6 +119,7 @@ static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core) for_each_present_cpu(lcpu) { if (cpu_logical_map(lcpu) == rcpu) { cpu_set(lcpu, core->mask); + cpu_core_id[lcpu] = core->id; smp_cpu_polarization[lcpu] = tl_cpu->pp; } } @@ -158,6 +162,7 @@ static void tl_to_cores(struct tl_info *info) break; case 1: core = core->next; + core->id = tle->container.id; break; case 0: add_cpus_to_core(&tle->cpu, core); @@ -165,10 +170,11 @@ static void tl_to_cores(struct tl_info *info) default: clear_cores(); machine_has_topology = 0; - return; + goto out; } tle = next_tle(tle); } +out: spin_unlock_irq(&topology_lock); } diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 6e7ad63854c0..5d8f0f3d0250 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -46,13 +46,7 @@ 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 +int show_unhandled_signals; extern pgm_check_handler_t do_protection_exception; extern pgm_check_handler_t do_dat_exception; @@ -315,18 +309,19 @@ void die(const char * str, struct pt_regs * regs, long err) do_exit(SIGSEGV); } -static void inline -report_user_fault(long interruption_code, struct pt_regs *regs) +static void inline report_user_fault(struct pt_regs *regs, long int_code, + int signr) { -#if defined(CONFIG_SYSCTL) - if (!sysctl_userprocess_debug) + if ((task_pid_nr(current) > 1) && !show_unhandled_signals) return; -#endif -#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG) - printk("User process fault: interruption code 0x%lX\n", - interruption_code); + if (!unhandled_signal(current, signr)) + return; + if (!printk_ratelimit()) + return; + printk("User process fault: interruption code 0x%lX ", int_code); + print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); + printk("\n"); show_regs(regs); -#endif } int is_valid_bugaddr(unsigned long addr) @@ -354,7 +349,7 @@ static void __kprobes inline do_trap(long interruption_code, int signr, tsk->thread.trap_no = interruption_code & 0xffff; force_sig_info(signr, info, tsk); - report_user_fault(interruption_code, regs); + report_user_fault(regs, interruption_code, signr); } else { const struct exception_table_entry *fixup; fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); @@ -390,8 +385,8 @@ static void default_trap_handler(struct pt_regs * regs, long interruption_code) { if (regs->psw.mask & PSW_MASK_PSTATE) { local_irq_enable(); + report_user_fault(regs, interruption_code, SIGSEGV); do_exit(SIGSEGV); - report_user_fault(interruption_code, regs); } else die("Unknown program exception", regs, interruption_code); } diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 5f99e66c51c3..6b83870507d5 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -23,6 +23,7 @@ #include <linux/security.h> #include <linux/bootmem.h> #include <linux/compat.h> +#include <asm/asm-offsets.h> #include <asm/pgtable.h> #include <asm/system.h> #include <asm/processor.h> @@ -101,11 +102,7 @@ static void vdso_init_per_cpu_data(int cpu, struct vdso_per_cpu_data *vpcd) /* * Allocate/free per cpu vdso data. */ -#ifdef CONFIG_64BIT #define SEGMENT_ORDER 2 -#else -#define SEGMENT_ORDER 1 -#endif int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore) { diff --git a/arch/s390/kernel/vdso32/clock_gettime.S b/arch/s390/kernel/vdso32/clock_gettime.S index 4a98909a8310..969643954273 100644 --- a/arch/s390/kernel/vdso32/clock_gettime.S +++ b/arch/s390/kernel/vdso32/clock_gettime.S @@ -38,13 +38,13 @@ __kernel_clock_gettime: sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,2f ahi %r0,-1 -2: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */ +2: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */ lr %r2,%r0 - lhi %r0,1000 + l %r0,__VDSO_NTP_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 3f - ahi %r0,1000 + a %r0,__VDSO_NTP_MULT(%r5) 3: alr %r0,%r2 srdl %r0,12 al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ @@ -86,13 +86,13 @@ __kernel_clock_gettime: sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,12f ahi %r0,-1 -12: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */ +12: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */ lr %r2,%r0 - lhi %r0,1000 + l %r0,__VDSO_NTP_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 13f - ahi %r0,1000 + a %r0,__VDSO_NTP_MULT(%r5) 13: alr %r0,%r2 srdl %r0,12 al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ diff --git a/arch/s390/kernel/vdso32/gettimeofday.S b/arch/s390/kernel/vdso32/gettimeofday.S index ad8acfc949fb..2d3633175e3b 100644 --- a/arch/s390/kernel/vdso32/gettimeofday.S +++ b/arch/s390/kernel/vdso32/gettimeofday.S @@ -35,13 +35,13 @@ __kernel_gettimeofday: sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,3f ahi %r0,-1 -3: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */ +3: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */ st %r0,24(%r15) - lhi %r0,1000 + l %r0,__VDSO_NTP_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 4f - ahi %r0,1000 + a %r0,__VDSO_NTP_MULT(%r5) 4: al %r0,24(%r15) srdl %r0,12 al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S index 49106c6e6f88..f40467884a03 100644 --- a/arch/s390/kernel/vdso64/clock_gettime.S +++ b/arch/s390/kernel/vdso64/clock_gettime.S @@ -36,7 +36,7 @@ __kernel_clock_gettime: stck 48(%r15) /* Store TOD clock */ lg %r1,48(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ - mghi %r1,1000 + msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */ srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */ lg %r0,__VDSO_XTIME_SEC(%r5) @@ -64,7 +64,7 @@ __kernel_clock_gettime: stck 48(%r15) /* Store TOD clock */ lg %r1,48(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ - mghi %r1,1000 + msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */ srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */ lg %r0,__VDSO_XTIME_SEC(%r5) diff --git a/arch/s390/kernel/vdso64/gettimeofday.S b/arch/s390/kernel/vdso64/gettimeofday.S index f873e75634e1..36ee674722ec 100644 --- a/arch/s390/kernel/vdso64/gettimeofday.S +++ b/arch/s390/kernel/vdso64/gettimeofday.S @@ -31,7 +31,7 @@ __kernel_gettimeofday: stck 48(%r15) /* Store TOD clock */ lg %r1,48(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ - mghi %r1,1000 + msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */ srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime.tv_nsec */ lg %r0,__VDSO_XTIME_SEC(%r5) /* xtime.tv_sec */ diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index b59a812a010e..3479f1b0d4e0 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -121,32 +121,35 @@ void account_system_vtime(struct task_struct *tsk) } EXPORT_SYMBOL_GPL(account_system_vtime); -void vtime_start_cpu(void) +void vtime_start_cpu(__u64 int_clock, __u64 enter_timer) { struct s390_idle_data *idle = &__get_cpu_var(s390_idle); struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer); __u64 idle_time, expires; + if (idle->idle_enter == 0ULL) + return; + /* Account time spent with enabled wait psw loaded as idle time. */ - idle_time = S390_lowcore.int_clock - idle->idle_enter; + idle_time = int_clock - idle->idle_enter; account_idle_time(idle_time); S390_lowcore.steal_timer += idle->idle_enter - S390_lowcore.last_update_clock; - S390_lowcore.last_update_clock = S390_lowcore.int_clock; + S390_lowcore.last_update_clock = int_clock; /* Account system time spent going idle. */ S390_lowcore.system_timer += S390_lowcore.last_update_timer - vq->idle; - S390_lowcore.last_update_timer = S390_lowcore.async_enter_timer; + S390_lowcore.last_update_timer = enter_timer; /* Restart vtime CPU timer */ if (vq->do_spt) { /* Program old expire value but first save progress. */ - expires = vq->idle - S390_lowcore.async_enter_timer; + expires = vq->idle - enter_timer; expires += get_vtimer(); set_vtimer(expires); } else { /* Don't account the CPU timer delta while the cpu was idle. */ - vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer; + vq->elapsed -= vq->idle - enter_timer; } idle->sequence++; diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 6ee55ae84ce2..a7251580891c 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -35,6 +35,7 @@ config KVM # OK, it's a little counter-intuitive to do this, but it puts it neatly under # the virtualization menu. +source drivers/vhost/Kconfig source drivers/virtio/Kconfig endif # VIRTUALIZATION diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index 8300309698fa..9e4c84187cf5 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c @@ -39,7 +39,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) vcpu->run->s390_reset_flags = 0; break; default: - return -ENOTSUPP; + return -EOPNOTSUPP; } atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); @@ -62,6 +62,6 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu) case 0x308: return __diag_ipl_functions(vcpu); default: - return -ENOTSUPP; + return -EOPNOTSUPP; } } diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index b40096494e46..3ddc30895e31 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -32,7 +32,7 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) vcpu->stat.instruction_lctlg++; if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f) - return -ENOTSUPP; + return -EOPNOTSUPP; useraddr = disp2; if (base2) @@ -138,7 +138,7 @@ static int handle_stop(struct kvm_vcpu *vcpu) rc = __kvm_s390_vcpu_store_status(vcpu, KVM_S390_STORE_STATUS_NOADDR); if (rc >= 0) - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; } if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) { @@ -150,7 +150,7 @@ static int handle_stop(struct kvm_vcpu *vcpu) if (vcpu->arch.local_int.action_bits & ACTION_STOP_ON_STOP) { vcpu->arch.local_int.action_bits &= ~ACTION_STOP_ON_STOP; VCPU_EVENT(vcpu, 3, "%s", "cpu stopped"); - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; } spin_unlock_bh(&vcpu->arch.local_int.lock); @@ -171,9 +171,9 @@ static int handle_validity(struct kvm_vcpu *vcpu) 2*PAGE_SIZE); if (rc) /* user will receive sigsegv, exit to user */ - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; } else - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; if (rc) VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d", @@ -189,7 +189,7 @@ static int handle_instruction(struct kvm_vcpu *vcpu) handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; if (handler) return handler(vcpu); - return -ENOTSUPP; + return -EOPNOTSUPP; } static int handle_prog(struct kvm_vcpu *vcpu) @@ -206,7 +206,7 @@ static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) rc = handle_instruction(vcpu); rc2 = handle_prog(vcpu); - if (rc == -ENOTSUPP) + if (rc == -EOPNOTSUPP) vcpu->arch.sie_block->icptcode = 0x04; if (rc) return rc; @@ -231,9 +231,9 @@ int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu) u8 code = vcpu->arch.sie_block->icptcode; if (code & 3 || (code >> 2) >= ARRAY_SIZE(intercept_funcs)) - return -ENOTSUPP; + return -EOPNOTSUPP; func = intercept_funcs[code >> 2]; if (func) return func(vcpu); - return -ENOTSUPP; + return -EOPNOTSUPP; } diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 43486c2408e1..35c21bf910c5 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -10,12 +10,13 @@ * Author(s): Carsten Otte <cotte@de.ibm.com> */ -#include <asm/lowcore.h> -#include <asm/uaccess.h> -#include <linux/hrtimer.h> #include <linux/interrupt.h> #include <linux/kvm_host.h> +#include <linux/hrtimer.h> #include <linux/signal.h> +#include <linux/slab.h> +#include <asm/asm-offsets.h> +#include <asm/uaccess.h> #include "kvm-s390.h" #include "gaccess.h" @@ -187,8 +188,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, if (rc == -EFAULT) exception = 1; - rc = put_guest_u64(vcpu, __LC_PFAULT_INTPARM, - inti->ext.ext_params2); + rc = put_guest_u64(vcpu, __LC_EXT_PARAMS2, + inti->ext.ext_params2); if (rc == -EFAULT) exception = 1; break; @@ -342,7 +343,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) if (psw_interrupts_disabled(vcpu)) { VCPU_EVENT(vcpu, 3, "%s", "disabled wait"); __unset_cpu_idle(vcpu); - return -ENOTSUPP; /* disabled wait */ + return -EOPNOTSUPP; /* disabled wait */ } if (psw_extint_disabled(vcpu) || diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index f8bcaefd7d34..ae3705816878 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -23,6 +23,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/timer.h> +#include <asm/asm-offsets.h> #include <asm/lowcore.h> #include <asm/pgtable.h> #include <asm/nmi.h> @@ -241,6 +242,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm_free_physmem(kvm); free_page((unsigned long)(kvm->arch.sca)); debug_unregister(kvm->arch.dbf); + cleanup_srcu_struct(&kvm->srcu); kfree(kvm); } @@ -339,11 +341,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, rc = kvm_vcpu_init(vcpu, kvm, id); if (rc) - goto out_free_cpu; + goto out_free_sie_block; VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu, vcpu->arch.sie_block); return vcpu; +out_free_sie_block: + free_page((unsigned long)(vcpu->arch.sie_block)); out_free_cpu: kfree(vcpu); out_nomem: @@ -543,7 +547,7 @@ rerun_vcpu: rc = -EINTR; } - if (rc == -ENOTSUPP) { + if (rc == -EOPNOTSUPP) { /* intercept cannot be handled in-kernel, prepare kvm-run */ kvm_run->exit_reason = KVM_EXIT_S390_SIEIC; kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode; @@ -603,45 +607,45 @@ int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) } else prefix = 0; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, fp_regs), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, fp_regs), vcpu->arch.guest_fpregs.fprs, 128, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, gp_regs), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, gp_regs), vcpu->arch.guest_gprs, 128, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, psw), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, psw), &vcpu->arch.sie_block->gpsw, 16, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, pref_reg), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, pref_reg), &vcpu->arch.sie_block->prefix, 4, prefix)) return -EFAULT; if (__guestcopy(vcpu, - addr + offsetof(struct save_area_s390x, fp_ctrl_reg), + addr + offsetof(struct save_area, fp_ctrl_reg), &vcpu->arch.guest_fpregs.fpc, 4, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, tod_reg), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, tod_reg), &vcpu->arch.sie_block->todpr, 4, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, timer), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, timer), &vcpu->arch.sie_block->cputm, 8, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, clk_cmp), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, clk_cmp), &vcpu->arch.sie_block->ckc, 8, prefix)) return -EFAULT; - if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, acc_regs), + if (__guestcopy(vcpu, addr + offsetof(struct save_area, acc_regs), &vcpu->arch.guest_acrs, 64, prefix)) return -EFAULT; if (__guestcopy(vcpu, - addr + offsetof(struct save_area_s390x, ctrl_regs), + addr + offsetof(struct save_area, ctrl_regs), &vcpu->arch.sie_block->gcr, 128, prefix)) return -EFAULT; return 0; @@ -689,14 +693,12 @@ long kvm_arch_vcpu_ioctl(struct file *filp, } /* Section: memory related */ -int kvm_arch_set_memory_region(struct kvm *kvm, - struct kvm_userspace_memory_region *mem, - struct kvm_memory_slot old, - int user_alloc) +int kvm_arch_prepare_memory_region(struct kvm *kvm, + struct kvm_memory_slot *memslot, + struct kvm_memory_slot old, + struct kvm_userspace_memory_region *mem, + int user_alloc) { - int i; - struct kvm_vcpu *vcpu; - /* A few sanity checks. We can have exactly one memory slot which has to start at guest virtual zero and which has to be located at a page boundary in userland and which has to end at a page boundary. @@ -719,14 +721,23 @@ int kvm_arch_set_memory_region(struct kvm *kvm, if (!user_alloc) return -EINVAL; + return 0; +} + +void kvm_arch_commit_memory_region(struct kvm *kvm, + struct kvm_userspace_memory_region *mem, + struct kvm_memory_slot old, + int user_alloc) +{ + int i; + struct kvm_vcpu *vcpu; + /* request update of sie control block for all available vcpus */ kvm_for_each_vcpu(i, vcpu, kvm) { if (test_and_set_bit(KVM_REQ_MMU_RELOAD, &vcpu->requests)) continue; kvm_s390_inject_sigp_stop(vcpu, ACTION_RELOADVCPU_ON_STOP); } - - return 0; } void kvm_arch_flush_shadow(struct kvm *kvm) @@ -741,7 +752,7 @@ gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) static int __init kvm_s390_init(void) { int ret; - ret = kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE); + ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); if (ret) return ret; @@ -750,7 +761,7 @@ static int __init kvm_s390_init(void) * to hold the maximum amount of facilites. On the other hand, we * only set facilities that are known to work in KVM. */ - facilities = (unsigned long long *) get_zeroed_page(GFP_DMA); + facilities = (unsigned long long *) get_zeroed_page(GFP_KERNEL|GFP_DMA); if (!facilities) { kvm_exit(); return -ENOMEM; diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 06cce8285ba0..cfa9d1777457 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -67,10 +67,14 @@ static inline long kvm_s390_vcpu_get_memsize(struct kvm_vcpu *vcpu) static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu) { + int idx; struct kvm_memory_slot *mem; + struct kvm_memslots *memslots; - down_read(&vcpu->kvm->slots_lock); - mem = &vcpu->kvm->memslots[0]; + idx = srcu_read_lock(&vcpu->kvm->srcu); + memslots = kvm_memslots(vcpu->kvm); + + mem = &memslots->memslots[0]; vcpu->arch.sie_block->gmsor = mem->userspace_addr; vcpu->arch.sie_block->gmslm = @@ -78,7 +82,7 @@ static inline void kvm_s390_vcpu_set_mem(struct kvm_vcpu *vcpu) (mem->npages << PAGE_SHIFT) + VIRTIODESCSPACE - 1ul; - up_read(&vcpu->kvm->slots_lock); + srcu_read_unlock(&vcpu->kvm->srcu, idx); } /* implemented in priv.c */ diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index d426aac8095d..44205507717c 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -12,6 +12,7 @@ */ #include <linux/kvm.h> +#include <linux/gfp.h> #include <linux/errno.h> #include <asm/current.h> #include <asm/debug.h> @@ -323,5 +324,5 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) else return handler(vcpu); } - return -ENOTSUPP; + return -EOPNOTSUPP; } diff --git a/arch/s390/kvm/sie64a.S b/arch/s390/kvm/sie64a.S index 934fd6a885f6..7e9d30d567b0 100644 --- a/arch/s390/kvm/sie64a.S +++ b/arch/s390/kvm/sie64a.S @@ -1,20 +1,58 @@ /* * sie64a.S - low level sie call * - * Copyright IBM Corp. 2008 + * Copyright IBM Corp. 2008,2010 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License (version 2 only) * as published by the Free Software Foundation. * * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> + * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> */ #include <linux/errno.h> #include <asm/asm-offsets.h> +#include <asm/setup.h> +#include <asm/asm-offsets.h> +#include <asm/ptrace.h> +#include <asm/thread_info.h> + +_TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) + +/* + * offsets into stackframe + * SP_ = offsets into stack sie64 is called with + * SPI_ = offsets into irq stack + */ +SP_GREGS = __SF_EMPTY +SP_HOOK = __SF_EMPTY+8 +SP_GPP = __SF_EMPTY+16 +SPI_PSW = STACK_FRAME_OVERHEAD + __PT_PSW + -SP_R5 = 5 * 8 # offset into stackframe -SP_R6 = 6 * 8 + .macro SPP newpp + tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP + jz 0f + .insn s,0xb2800000,\newpp +0: + .endm + +sie_irq_handler: + SPP __LC_CMF_HPP # set host id + larl %r2,sie_inst + clg %r2,SPI_PSW+8(0,%r15) # intercepted sie + jne 1f + xc __LC_SIE_HOOK(8),__LC_SIE_HOOK + lg %r2,__LC_THREAD_INFO # pointer thread_info struct + tm __TI_flags+7(%r2),_TIF_EXIT_SIE + jz 0f + larl %r2,sie_exit # work pending, leave sie + stg %r2,__LC_RETURN_PSW+8 + br %r14 +0: larl %r2,sie_reenter # re-enter with guest id + stg %r2,__LC_RETURN_PSW+8 +1: br %r14 /* * sie64a calling convention: @@ -23,23 +61,34 @@ SP_R6 = 6 * 8 */ .globl sie64a sie64a: - lgr %r5,%r3 - stmg %r5,%r14,SP_R5(%r15) # save register on entry - lgr %r14,%r2 # pointer to sie control block - lmg %r0,%r13,0(%r3) # load guest gprs 0-13 + stg %r3,SP_GREGS(%r15) # save guest register save area + stmg %r6,%r14,__SF_GPRS(%r15) # save registers on entry + lgr %r14,%r2 # pointer to sie control block + larl %r5,sie_irq_handler + stg %r2,SP_GPP(%r15) + stg %r5,SP_HOOK(%r15) # save hook target + lmg %r0,%r13,0(%r3) # load guest gprs 0-13 +sie_reenter: + mvc __LC_SIE_HOOK(8),SP_HOOK(%r15) + SPP SP_GPP(%r15) # set guest id sie_inst: sie 0(%r14) - lg %r14,SP_R5(%r15) - stmg %r0,%r13,0(%r14) # save guest gprs 0-13 + xc __LC_SIE_HOOK(8),__LC_SIE_HOOK + SPP __LC_CMF_HPP # set host id +sie_exit: + lg %r14,SP_GREGS(%r15) + stmg %r0,%r13,0(%r14) # save guest gprs 0-13 lghi %r2,0 - lmg %r6,%r14,SP_R6(%r15) + lmg %r6,%r14,__SF_GPRS(%r15) br %r14 sie_err: - lg %r14,SP_R5(%r15) - stmg %r0,%r13,0(%r14) # save guest gprs 0-13 + xc __LC_SIE_HOOK(8),__LC_SIE_HOOK + SPP __LC_CMF_HPP # set host id + lg %r14,SP_GREGS(%r15) + stmg %r0,%r13,0(%r14) # save guest gprs 0-13 lghi %r2,-EFAULT - lmg %r6,%r14,SP_R6(%r15) + lmg %r6,%r14,__SF_GPRS(%r15) br %r14 .section __ex_table,"a" diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 15ee1111de58..702276f5e2fa 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -14,6 +14,7 @@ #include <linux/kvm.h> #include <linux/kvm_host.h> +#include <linux/slab.h> #include "gaccess.h" #include "kvm-s390.h" @@ -112,7 +113,7 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action) { struct kvm_s390_interrupt_info *inti; - inti = kzalloc(sizeof(*inti), GFP_KERNEL); + inti = kzalloc(sizeof(*inti), GFP_ATOMIC); if (!inti) return -ENOMEM; inti->type = KVM_S390_SIGP_STOP; @@ -172,7 +173,7 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) rc = 0; /* order accepted */ break; default: - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; } return rc; } @@ -293,7 +294,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) vcpu->stat.instruction_sigp_restart++; /* user space must know about restart */ default: - return -ENOTSUPP; + return -EOPNOTSUPP; } if (rc < 0) diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index 97975ec7a274..761ab8b56afc 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -3,6 +3,7 @@ # lib-y += delay.o string.o uaccess_std.o uaccess_pt.o +obj-y += usercopy.o obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o lib-$(CONFIG_64BIT) += uaccess_mvcos.o lib-$(CONFIG_SMP) += spinlock.o diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index cff327f109a8..91754ffb9203 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -43,16 +43,24 @@ void arch_spin_lock_wait(arch_spinlock_t *lp) { int count = spin_retry; unsigned int cpu = ~smp_processor_id(); + unsigned int owner; while (1) { - if (count-- <= 0) { - unsigned int owner = lp->owner_cpu; - if (owner != 0) - _raw_yield_cpu(~owner); - count = spin_retry; + owner = lp->owner_cpu; + if (!owner || smp_vcpu_scheduled(~owner)) { + for (count = spin_retry; count > 0; count--) { + if (arch_spin_is_locked(lp)) + continue; + if (_raw_compare_and_swap(&lp->owner_cpu, 0, + cpu) == 0) + return; + } + if (MACHINE_IS_LPAR) + continue; } - if (arch_spin_is_locked(lp)) - continue; + owner = lp->owner_cpu; + if (owner) + _raw_yield_cpu(~owner); if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) return; } @@ -63,17 +71,27 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags) { int count = spin_retry; unsigned int cpu = ~smp_processor_id(); + unsigned int owner; local_irq_restore(flags); while (1) { - if (count-- <= 0) { - unsigned int owner = lp->owner_cpu; - if (owner != 0) - _raw_yield_cpu(~owner); - count = spin_retry; + owner = lp->owner_cpu; + if (!owner || smp_vcpu_scheduled(~owner)) { + for (count = spin_retry; count > 0; count--) { + if (arch_spin_is_locked(lp)) + continue; + local_irq_disable(); + if (_raw_compare_and_swap(&lp->owner_cpu, 0, + cpu) == 0) + return; + local_irq_restore(flags); + } + if (MACHINE_IS_LPAR) + continue; } - if (arch_spin_is_locked(lp)) - continue; + owner = lp->owner_cpu; + if (owner) + _raw_yield_cpu(~owner); local_irq_disable(); if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) return; @@ -100,8 +118,11 @@ EXPORT_SYMBOL(arch_spin_trylock_retry); void arch_spin_relax(arch_spinlock_t *lock) { unsigned int cpu = lock->owner_cpu; - if (cpu != 0) - _raw_yield_cpu(~cpu); + if (cpu != 0) { + if (MACHINE_IS_VM || MACHINE_IS_KVM || + !smp_vcpu_scheduled(~cpu)) + _raw_yield_cpu(~cpu); + } } EXPORT_SYMBOL(arch_spin_relax); diff --git a/arch/s390/lib/usercopy.c b/arch/s390/lib/usercopy.c new file mode 100644 index 000000000000..14b363fec8a2 --- /dev/null +++ b/arch/s390/lib/usercopy.c @@ -0,0 +1,8 @@ +#include <linux/module.h> +#include <linux/bug.h> + +void copy_from_user_overflow(void) +{ + WARN(1, "Buffer overflow detected!\n"); +} +EXPORT_SYMBOL(copy_from_user_overflow); diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index 76a3637b88e0..eb6a2ef5f82e 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -1,17 +1,16 @@ /* - * arch/s390/mm/cmm.c + * Collaborative memory management interface. * - * S390 version - * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * Copyright IBM Corp 2003,2010 + * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, * - * Collaborative memory management interface. */ #include <linux/errno.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/gfp.h> #include <linux/sched.h> #include <linux/sysctl.h> #include <linux/ctype.h> @@ -19,9 +18,9 @@ #include <linux/kthread.h> #include <linux/oom.h> #include <linux/suspend.h> +#include <linux/uaccess.h> #include <asm/pgalloc.h> -#include <asm/uaccess.h> #include <asm/diag.h> static char *sender = "VMRMSVM"; @@ -52,14 +51,14 @@ static struct cmm_page_array *cmm_timed_page_list; static DEFINE_SPINLOCK(cmm_lock); static struct task_struct *cmm_thread_ptr; -static wait_queue_head_t cmm_thread_wait; -static struct timer_list cmm_timer; +static DECLARE_WAIT_QUEUE_HEAD(cmm_thread_wait); +static DEFINE_TIMER(cmm_timer, NULL, 0, 0); static void cmm_timer_fn(unsigned long); static void cmm_set_timer(void); -static long -cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list) +static long cmm_alloc_pages(long nr, long *counter, + struct cmm_page_array **list) { struct cmm_page_array *pa, *npa; unsigned long addr; @@ -98,8 +97,7 @@ cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list) return nr; } -static long -cmm_free_pages(long nr, long *counter, struct cmm_page_array **list) +static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list) { struct cmm_page_array *pa; unsigned long addr; @@ -139,11 +137,10 @@ static int cmm_oom_notify(struct notifier_block *self, } static struct notifier_block cmm_oom_nb = { - .notifier_call = cmm_oom_notify + .notifier_call = cmm_oom_notify, }; -static int -cmm_thread(void *dummy) +static int cmm_thread(void *dummy) { int rc; @@ -169,7 +166,7 @@ cmm_thread(void *dummy) cmm_timed_pages_target = cmm_timed_pages; } else if (cmm_timed_pages_target < cmm_timed_pages) { cmm_free_pages(1, &cmm_timed_pages, - &cmm_timed_page_list); + &cmm_timed_page_list); } if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer)) cmm_set_timer(); @@ -177,14 +174,12 @@ cmm_thread(void *dummy) return 0; } -static void -cmm_kick_thread(void) +static void cmm_kick_thread(void) { wake_up(&cmm_thread_wait); } -static void -cmm_set_timer(void) +static void cmm_set_timer(void) { if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) { if (timer_pending(&cmm_timer)) @@ -201,8 +196,7 @@ cmm_set_timer(void) add_timer(&cmm_timer); } -static void -cmm_timer_fn(unsigned long ignored) +static void cmm_timer_fn(unsigned long ignored) { long nr; @@ -215,57 +209,49 @@ cmm_timer_fn(unsigned long ignored) cmm_set_timer(); } -void -cmm_set_pages(long nr) +static void cmm_set_pages(long nr) { cmm_pages_target = nr; cmm_kick_thread(); } -long -cmm_get_pages(void) +static long cmm_get_pages(void) { return cmm_pages; } -void -cmm_add_timed_pages(long nr) +static void cmm_add_timed_pages(long nr) { cmm_timed_pages_target += nr; cmm_kick_thread(); } -long -cmm_get_timed_pages(void) +static long cmm_get_timed_pages(void) { return cmm_timed_pages; } -void -cmm_set_timeout(long nr, long seconds) +static void cmm_set_timeout(long nr, long seconds) { cmm_timeout_pages = nr; cmm_timeout_seconds = seconds; cmm_set_timer(); } -static int -cmm_skip_blanks(char *cp, char **endp) +static int cmm_skip_blanks(char *cp, char **endp) { char *str; - for (str = cp; *str == ' ' || *str == '\t'; str++); + for (str = cp; *str == ' ' || *str == '\t'; str++) + ; *endp = str; return str != cp; } -#ifdef CONFIG_CMM_PROC - static struct ctl_table cmm_table[]; -static int -cmm_pages_handler(ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) +static int cmm_pages_handler(ctl_table *ctl, int write, void __user *buffer, + size_t *lenp, loff_t *ppos) { char buf[16], *p; long nr; @@ -304,9 +290,8 @@ cmm_pages_handler(ctl_table *ctl, int write, return 0; } -static int -cmm_timeout_handler(ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) +static int cmm_timeout_handler(ctl_table *ctl, int write, void __user *buffer, + size_t *lenp, loff_t *ppos) { char buf[64], *p; long nr, seconds; @@ -369,12 +354,10 @@ static struct ctl_table cmm_dir_table[] = { }, { } }; -#endif #ifdef CONFIG_CMM_IUCV #define SMSG_PREFIX "CMM" -static void -cmm_smsg_target(char *from, char *msg) +static void cmm_smsg_target(const char *from, char *msg) { long nr, seconds; @@ -444,16 +427,13 @@ static struct notifier_block cmm_power_notifier = { .notifier_call = cmm_power_event, }; -static int -cmm_init (void) +static int cmm_init(void) { int rc = -ENOMEM; -#ifdef CONFIG_CMM_PROC cmm_sysctl_header = register_sysctl_table(cmm_dir_table); if (!cmm_sysctl_header) goto out_sysctl; -#endif #ifdef CONFIG_CMM_IUCV rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); if (rc < 0) @@ -465,8 +445,6 @@ cmm_init (void) rc = register_pm_notifier(&cmm_power_notifier); if (rc) goto out_pm; - init_waitqueue_head(&cmm_thread_wait); - init_timer(&cmm_timer); cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0; if (rc) @@ -482,36 +460,26 @@ out_oom_notify: smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); out_smsg: #endif -#ifdef CONFIG_CMM_PROC unregister_sysctl_table(cmm_sysctl_header); out_sysctl: -#endif + del_timer_sync(&cmm_timer); return rc; } +module_init(cmm_init); -static void -cmm_exit(void) +static void cmm_exit(void) { - kthread_stop(cmm_thread_ptr); - unregister_pm_notifier(&cmm_power_notifier); - unregister_oom_notifier(&cmm_oom_nb); - cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); - cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); -#ifdef CONFIG_CMM_PROC unregister_sysctl_table(cmm_sysctl_header); -#endif #ifdef CONFIG_CMM_IUCV smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); #endif + unregister_pm_notifier(&cmm_power_notifier); + unregister_oom_notifier(&cmm_oom_nb); + kthread_stop(cmm_thread_ptr); + del_timer_sync(&cmm_timer); + cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); + cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); } - -module_init(cmm_init); module_exit(cmm_exit); -EXPORT_SYMBOL(cmm_set_pages); -EXPORT_SYMBOL(cmm_get_pages); -EXPORT_SYMBOL(cmm_add_timed_pages); -EXPORT_SYMBOL(cmm_get_timed_pages); -EXPORT_SYMBOL(cmm_set_timeout); - MODULE_LICENSE("GPL"); diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 5c8457129603..3cc95dd0a3a6 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -105,7 +105,7 @@ static int dcss_set_subcodes(void) { #ifdef CONFIG_64BIT - char *name = kmalloc(8 * sizeof(char), GFP_DMA); + char *name = kmalloc(8 * sizeof(char), GFP_KERNEL | GFP_DMA); unsigned long rx, ry; int rc; @@ -252,12 +252,13 @@ dcss_diag_translate_rc (int vm_rc) { static int query_segment_type (struct dcss_segment *seg) { - struct qin64 *qin = kmalloc (sizeof(struct qin64), GFP_DMA); - struct qout64 *qout = kmalloc (sizeof(struct qout64), GFP_DMA); - - int diag_cc, rc, i; unsigned long dummy, vmrc; + int diag_cc, rc, i; + struct qout64 *qout; + struct qin64 *qin; + qin = kmalloc(sizeof(*qin), GFP_KERNEL | GFP_DMA); + qout = kmalloc(sizeof(*qout), GFP_KERNEL | GFP_DMA); if ((qin == NULL) || (qout == NULL)) { rc = -ENOMEM; goto out_free; @@ -286,7 +287,7 @@ query_segment_type (struct dcss_segment *seg) copy data for the new format. */ if (segext_scode == DCSS_SEGEXT) { struct qout64_old *qout_old; - qout_old = kzalloc(sizeof(struct qout64_old), GFP_DMA); + qout_old = kzalloc(sizeof(*qout_old), GFP_KERNEL | GFP_DMA); if (qout_old == NULL) { rc = -ENOMEM; goto out_free; @@ -309,7 +310,7 @@ query_segment_type (struct dcss_segment *seg) } #endif if (qout->segcnt > 6) { - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; goto out_free; } @@ -324,11 +325,11 @@ query_segment_type (struct dcss_segment *seg) for (i=0; i<qout->segcnt; i++) { if (((qout->range[i].start & 0xff) != SEG_TYPE_EW) && ((qout->range[i].start & 0xff) != SEG_TYPE_EN)) { - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; goto out_free; } if (start != qout->range[i].start >> PAGE_SHIFT) { - rc = -ENOTSUPP; + rc = -EOPNOTSUPP; goto out_free; } start = (qout->range[i].end >> PAGE_SHIFT) + 1; @@ -357,7 +358,7 @@ query_segment_type (struct dcss_segment *seg) * -ENOSYS : we are not running on VM * -EIO : could not perform query diagnose * -ENOENT : no such segment - * -ENOTSUPP: multi-part segment cannot be used with linux + * -EOPNOTSUPP: multi-part segment cannot be used with linux * -ENOMEM : out of memory * 0 .. 6 : type of segment as defined in include/asm-s390/extmem.h */ @@ -407,11 +408,11 @@ segment_overlaps_others (struct dcss_segment *seg) static int __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end) { - struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment), - GFP_DMA); - int rc, diag_cc; unsigned long start_addr, end_addr, dummy; + struct dcss_segment *seg; + int rc, diag_cc; + seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA); if (seg == NULL) { rc = -ENOMEM; goto out; @@ -515,7 +516,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long * -ENOSYS : we are not running on VM * -EIO : could not perform query or load diagnose * -ENOENT : no such segment - * -ENOTSUPP: multi-part segment cannot be used with linux + * -EOPNOTSUPP: multi-part segment cannot be used with linux * -ENOSPC : segment cannot be used (overlaps with storage) * -EBUSY : segment can temporarily not be used (overlaps with dcss) * -ERANGE : segment cannot be used (exceeds kernel mapping range) @@ -742,7 +743,7 @@ void segment_warning(int rc, char *seg_name) pr_err("Loading or querying DCSS %s resulted in a " "hardware error\n", seg_name); break; - case -ENOTSUPP: + case -EOPNOTSUPP: pr_err("DCSS %s has multiple page ranges and cannot be " "loaded or queried\n", seg_name); break; diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index fc102e70d9c2..2505b2ea0ef1 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -30,6 +30,7 @@ #include <linux/kprobes.h> #include <linux/uaccess.h> #include <linux/hugetlb.h> +#include <asm/asm-offsets.h> #include <asm/system.h> #include <asm/pgtable.h> #include <asm/s390_ext.h> @@ -47,10 +48,6 @@ #define __PF_RES_FIELD 0x8000000000000000ULL #endif /* CONFIG_64BIT */ -#ifdef CONFIG_SYSCTL -extern int sysctl_userprocess_debug; -#endif - #define VM_FAULT_BADCONTEXT 0x010000 #define VM_FAULT_BADMAP 0x020000 #define VM_FAULT_BADACCESS 0x040000 @@ -59,15 +56,13 @@ static inline int notify_page_fault(struct pt_regs *regs) { int ret = 0; -#ifdef CONFIG_KPROBES /* kprobe_running() needs smp_processor_id() */ - if (!user_mode(regs)) { + if (kprobes_built_in() && !user_mode(regs)) { preempt_disable(); if (kprobe_running() && kprobe_fault_handler(regs, 14)) ret = 1; preempt_enable(); } -#endif return ret; } @@ -121,6 +116,22 @@ static inline int user_space_fault(unsigned long trans_exc_code) return trans_exc_code != 3; } +static inline void report_user_fault(struct pt_regs *regs, long int_code, + int signr, unsigned long address) +{ + if ((task_pid_nr(current) > 1) && !show_unhandled_signals) + return; + if (!unhandled_signal(current, signr)) + return; + if (!printk_ratelimit()) + return; + printk("User process fault: interruption code 0x%lX ", int_code); + print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); + printk("\n"); + printk("failing address: %lX\n", address); + show_regs(regs); +} + /* * Send SIGSEGV to task. This is an external routine * to keep the stack usage of do_page_fault small. @@ -134,17 +145,7 @@ static noinline void do_sigsegv(struct pt_regs *regs, long int_code, address = trans_exc_code & __FAIL_ADDR_MASK; current->thread.prot_addr = address; current->thread.trap_no = int_code; -#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG) -#if defined(CONFIG_SYSCTL) - if (sysctl_userprocess_debug) -#endif - { - printk("User process fault: interruption code 0x%lX\n", - int_code); - printk("failing address: %lX\n", address); - show_regs(regs); - } -#endif + report_user_fault(regs, int_code, SIGSEGV, address); si.si_signo = SIGSEGV; si.si_code = si_code; si.si_addr = (void __user *) address; diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 765647952221..acc91c75bc94 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -26,6 +26,7 @@ #include <linux/pfn.h> #include <linux/poison.h> #include <linux/initrd.h> +#include <linux/gfp.h> #include <asm/processor.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -143,33 +144,34 @@ void kernel_map_pages(struct page *page, int numpages, int enable) } #endif -void free_initmem(void) +void free_init_pages(char *what, unsigned long begin, unsigned long end) { - unsigned long addr; + unsigned long addr = begin; - addr = (unsigned long)(&__init_begin); - for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { + if (begin >= end) + return; + for (; addr < end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); - memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); + memset((void *)(addr & PAGE_MASK), POISON_FREE_INITMEM, + PAGE_SIZE); free_page(addr); totalram_pages++; - } - printk ("Freeing unused kernel memory: %ldk freed\n", - ((unsigned long)&__init_end - (unsigned long)&__init_begin) >> 10); + } + printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10); +} + +void free_initmem(void) +{ + free_init_pages("unused kernel memory", + (unsigned long)&__init_begin, + (unsigned long)&__init_end); } #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { - if (start < end) - printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); - for (; start < end; start += PAGE_SIZE) { - ClearPageReserved(virt_to_page(start)); - init_page_count(virt_to_page(start)); - free_page(start); - totalram_pages++; - } + free_init_pages("initrd memory", start, end); } #endif diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c index 81756271dc44..a8c2af8c650f 100644 --- a/arch/s390/mm/maccess.c +++ b/arch/s390/mm/maccess.c @@ -59,3 +59,29 @@ long probe_kernel_write(void *dst, void *src, size_t size) } return copied < 0 ? -EFAULT : 0; } + +int memcpy_real(void *dest, void *src, size_t count) +{ + register unsigned long _dest asm("2") = (unsigned long) dest; + register unsigned long _len1 asm("3") = (unsigned long) count; + register unsigned long _src asm("4") = (unsigned long) src; + register unsigned long _len2 asm("5") = (unsigned long) count; + unsigned long flags; + int rc = -EFAULT; + + if (!count) + return 0; + flags = __raw_local_irq_stnsm(0xf8UL); + asm volatile ( + "0: mvcle %1,%2,0x0\n" + "1: jo 0b\n" + " lhi %0,0x0\n" + "2:\n" + EX_TABLE(1b,2b) + : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1), + "+d" (_len2), "=m" (*((long *) dest)) + : "m" (*((long *) src)) + : "cc", "memory"); + __raw_local_irq_ssm(flags); + return rc; +} diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index 098923ae458f..a90d45e9dfb0 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -10,6 +10,7 @@ #include <linux/errno.h> #include <linux/types.h> #include <linux/mm.h> +#include <linux/gfp.h> #include <linux/init.h> #define ESSA_SET_STABLE 1 diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index ad621e06ada3..8d999249d357 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -6,11 +6,11 @@ #include <linux/sched.h> #include <linux/kernel.h> #include <linux/errno.h> +#include <linux/gfp.h> #include <linux/mm.h> #include <linux/swap.h> #include <linux/smp.h> #include <linux/highmem.h> -#include <linux/slab.h> #include <linux/pagemap.h> #include <linux/spinlock.h> #include <linux/module.h> diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index 300ab012b0fd..90165e7ca04e 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/list.h> #include <linux/hugetlb.h> +#include <linux/slab.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> #include <asm/setup.h> @@ -70,12 +71,8 @@ static pte_t __ref *vmem_pte_alloc(void) pte = alloc_bootmem(PTRS_PER_PTE * sizeof(pte_t)); if (!pte) return NULL; - if (MACHINE_HAS_HPAGE) - clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY | _PAGE_CO, - PTRS_PER_PTE * sizeof(pte_t)); - else - clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY, - PTRS_PER_PTE * sizeof(pte_t)); + clear_table((unsigned long *) pte, _PAGE_TYPE_EMPTY, + PTRS_PER_PTE * sizeof(pte_t)); return pte; } @@ -116,8 +113,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro) if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) && (address + HPAGE_SIZE <= start + size) && (address >= HPAGE_SIZE)) { - pte_val(pte) |= _SEGMENT_ENTRY_LARGE | - _SEGMENT_ENTRY_CO; + pte_val(pte) |= _SEGMENT_ENTRY_LARGE; pmd_val(*pm_dir) = pte_val(pte); address += HPAGE_SIZE - PAGE_SIZE; continue; |