whiterose

linux unikernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/whiterose

commit 3591b19511ed88e2e82f64b7d7bf54a5f8d10363
parent 45f5532a2f65afeda9e8a02bf1aca15c2b4c9be8
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Tue,  5 Mar 2019 11:13:10 -0800

Merge tag 's390-5.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Martin Schwidefsky:

 - A copy of Arnds compat wrapper generation series

 - Pass information about the KVM guest to the host in form the control
   program code and the control program version code

 - Map IOV resources to support PCI physical functions on s390

 - Add vector load and store alignment hints to improve performance

 - Use the "jdd" constraint with gcc 9 to make jump labels working again

 - Remove amode workaround for old z/VM releases from the DCSS code

 - Add support for in-kernel performance measurements using the CPU
   measurement counter facility

 - Introduce a new PMU device cpum_cf_diag to capture counters and store
   thenn as event raw data.

 - Bug fixes and cleanups

* tag 's390-5.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (54 commits)
  Revert "s390/cpum_cf: Add kernel message exaplanations"
  s390/dasd: fix read device characteristic with CONFIG_VMAP_STACK=y
  s390/suspend: fix prefix register reset in swsusp_arch_resume
  s390: warn about clearing als implied facilities
  s390: allow overriding facilities via command line
  s390: clean up redundant facilities list setup
  s390/als: remove duplicated in-place implementation of stfle
  s390/cio: Use cpa range elsewhere within vfio-ccw
  s390/cio: Fix vfio-ccw handling of recursive TICs
  s390: vfio_ap: link the vfio_ap devices to the vfio_ap bus subsystem
  s390/cpum_cf: Handle EBUSY return code from CPU counter facility reservation
  s390/cpum_cf: Add kernel message exaplanations
  s390/cpum_cf_diag: Add support for s390 counter facility diagnostic trace
  s390/cpum_cf: add ctr_stcctm() function
  s390/cpum_cf: move common functions into a separate file
  s390/cpum_cf: introduce kernel_cpumcf_avail() function
  s390/cpu_mf: replace stcctm5() with the stcctm() function
  s390/cpu_mf: add store cpu counter multiple instruction support
  s390/cpum_cf: Add minimal in-kernel interface for counter measurements
  s390/cpum_cf: introduce kernel_cpumcf_alert() to obtain measurement alerts
  ...

Diffstat:
March/s390/Kconfig | 2++
March/s390/boot/als.c | 20++++----------------
March/s390/boot/boot.h | 2++
March/s390/boot/ipl_parm.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
March/s390/boot/startup.c | 1+
March/s390/boot/string.c | 1+
March/s390/hypfs/hypfs.h | 6+++---
March/s390/hypfs/hypfs_dbfs.c | 8++------
March/s390/hypfs/hypfs_diag.c | 9++++-----
March/s390/hypfs/hypfs_diag0c.c | 6+++---
March/s390/hypfs/hypfs_sprp.c | 6+++---
March/s390/hypfs/hypfs_vm.c | 3++-
March/s390/hypfs/inode.c | 11+++--------
Aarch/s390/include/asm/cpu_mcf.h | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aarch/s390/include/asm/cpu_mf-insn.h | 22++++++++++++++++++++++
March/s390/include/asm/cpu_mf.h | 18++++++++++++++----
March/s390/include/asm/diag.h | 12++++++++++++
March/s390/include/asm/ftrace.h | 25+++++++++++++++++++++++++
March/s390/include/asm/jump_label.h | 14++++++++++----
March/s390/include/asm/pci.h | 1-
March/s390/include/asm/perf_event.h | 2+-
March/s390/include/asm/qdio.h | 4++--
March/s390/include/asm/sclp.h | 1+
March/s390/include/asm/string.h | 28++++++++++++++++++++++------
Aarch/s390/include/asm/syscall_wrapper.h | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
March/s390/include/asm/vx-insn.h | 8++++----
March/s390/include/uapi/asm/posix_types.h | 6++++++
March/s390/kernel/Makefile | 6++++--
March/s390/kernel/compat_linux.c | 235+------------------------------------------------------------------------------
Darch/s390/kernel/compat_wrapper.c | 186-------------------------------------------------------------------------------
March/s390/kernel/debug.c | 6------
March/s390/kernel/diag.c | 1+
March/s390/kernel/early.c | 2--
March/s390/kernel/entry.S | 4++--
March/s390/kernel/head64.S | 2--
March/s390/kernel/kdebugfs.c | 2--
March/s390/kernel/perf_cpum_cf.c | 224++++++++++---------------------------------------------------------------------
Aarch/s390/kernel/perf_cpum_cf_common.c | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aarch/s390/kernel/perf_cpum_cf_diag.c | 693+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
March/s390/kernel/perf_cpum_cf_events.c | 1+
March/s390/kernel/setup.c | 60++++++++++++++++++++++++++++++++++++++++++------------------
March/s390/kernel/swsusp.S | 6+++---
March/s390/kernel/sys_s390.c | 16+++++++++++++---
March/s390/kernel/syscalls/syscall.tbl | 286++++++++++++++++++++++++++++++++++++++++----------------------------------------
March/s390/kernel/sysinfo.c | 2--
March/s390/kernel/vtime.c | 4++--
March/s390/lib/string.c | 28++++++++++++++++++++++++++++
March/s390/mm/extmem.c | 133+++++++++----------------------------------------------------------------------
March/s390/mm/kasan_init.c | 2--
March/s390/mm/mmap.c | 33+++++++++++++++++++--------------
March/s390/mm/pgtable.c | 2--
March/s390/pci/pci.c | 22+++++++++++++++++++++-
March/s390/pci/pci_debug.c | 15++++-----------
Mdrivers/s390/block/dasd.c | 19+++++--------------
Mdrivers/s390/char/sclp.h | 4+++-
Mdrivers/s390/char/sclp_early.c | 2++
Mdrivers/s390/cio/qdio_setup.c | 6+++---
Mdrivers/s390/cio/vfio_ccw_cp.c | 55++++++++++++++++++++++++++++++++++++++++++-------------
Mdrivers/s390/crypto/ap_bus.c | 19+++++++++++++++++--
Mdrivers/s390/crypto/ap_bus.h | 3++-
Mdrivers/s390/crypto/ap_queue.c | 7++++++-
Mdrivers/s390/crypto/pkey_api.c | 2+-
Mdrivers/s390/crypto/vfio_ap_drv.c | 44+++++++++++++++++++++++++++++++++++---------
Mdrivers/s390/crypto/vfio_ap_ops.c | 4++--
Mdrivers/s390/crypto/vfio_ap_private.h | 1+
Mdrivers/s390/net/ism_drv.c | 12+++++++++---
Mdrivers/s390/net/qeth_core_main.c | 4++--
Mdrivers/s390/scsi/zfcp_qdio.c | 4++--
Minclude/linux/syscalls.h | 4++++
Mipc/syscall.c | 20++++++++++++++++----
Mkernel/sys_ni.c | 1+
71 files changed, 1846 insertions(+), 1080 deletions(-)

diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig @@ -75,6 +75,7 @@ config S390 select ARCH_HAS_SET_MEMORY select ARCH_HAS_STRICT_KERNEL_RWX select ARCH_HAS_STRICT_MODULE_RWX + select ARCH_HAS_SYSCALL_WRAPPER select ARCH_HAS_UBSAN_SANITIZE_ALL select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_INLINE_READ_LOCK @@ -379,6 +380,7 @@ config COMPAT select COMPAT_BINFMT_ELF if BINFMT_ELF select ARCH_WANT_OLD_COMPAT_IPC select COMPAT_OLD_SIGACTION + select HAVE_UID16 depends on MULTIUSER help Select this option if you want to enable your system kernel to diff --git a/arch/s390/boot/als.c b/arch/s390/boot/als.c @@ -7,6 +7,7 @@ #include <asm/facility.h> #include <asm/lowcore.h> #include <asm/sclp.h> +#include "boot.h" /* * The code within this file will be called very early. It may _not_ @@ -58,7 +59,7 @@ static void u16_to_decimal(char *str, u16 val) *str = '\0'; } -static void print_missing_facilities(void) +void print_missing_facilities(void) { static char als_str[80] = "Missing facilities: "; unsigned long val; @@ -90,7 +91,6 @@ static void print_missing_facilities(void) } strcat(als_str, "\n"); sclp_early_printk(als_str); - sclp_early_printk("See Principles of Operations for facility bits\n"); } static void facility_mismatch(void) @@ -98,6 +98,7 @@ static void facility_mismatch(void) sclp_early_printk("The Linux kernel requires more recent processor hardware\n"); print_machine_type(); print_missing_facilities(); + sclp_early_printk("See Principles of Operations for facility bits\n"); disabled_wait(0x8badcccc); } @@ -105,20 +106,7 @@ void verify_facilities(void) { int i; - for (i = 0; i < ARRAY_SIZE(S390_lowcore.stfle_fac_list); i++) - S390_lowcore.stfle_fac_list[i] = 0; - asm volatile( - " stfl 0(0)\n" - : "=m" (S390_lowcore.stfl_fac_list)); - S390_lowcore.stfle_fac_list[0] = (u64)S390_lowcore.stfl_fac_list << 32; - if (S390_lowcore.stfl_fac_list & 0x01000000) { - register unsigned long reg0 asm("0") = ARRAY_SIZE(als) - 1; - - asm volatile(".insn s,0xb2b00000,0(%1)" /* stfle */ - : "+d" (reg0) - : "a" (&S390_lowcore.stfle_fac_list) - : "memory", "cc"); - } + __stfle(S390_lowcore.stfle_fac_list, ARRAY_SIZE(S390_lowcore.stfle_fac_list)); for (i = 0; i < ARRAY_SIZE(als); i++) { if ((S390_lowcore.stfle_fac_list[i] & als[i]) != als[i]) facility_mismatch(); diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h @@ -6,6 +6,8 @@ void startup_kernel(void); void detect_memory(void); void store_ipl_parmblock(void); void setup_boot_command_line(void); +void parse_boot_command_line(void); void setup_memory_end(void); +void print_missing_facilities(void); #endif /* BOOT_BOOT_H */ diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> #include <linux/init.h> #include <linux/ctype.h> #include <asm/ebcdic.h> #include <asm/sclp.h> #include <asm/sections.h> #include <asm/boot_data.h> +#include <asm/facility.h> #include "boot.h" char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; @@ -143,8 +145,66 @@ void setup_boot_command_line(void) append_ipl_block_parm(); } +static void modify_facility(unsigned long nr, bool clear) +{ + if (clear) + __clear_facility(nr, S390_lowcore.stfle_fac_list); + else + __set_facility(nr, S390_lowcore.stfle_fac_list); +} + +static void check_cleared_facilities(void) +{ + unsigned long als[] = { FACILITIES_ALS }; + int i; + + for (i = 0; i < ARRAY_SIZE(als); i++) { + if ((S390_lowcore.stfle_fac_list[i] & als[i]) != als[i]) { + sclp_early_printk("Warning: The Linux kernel requires facilities cleared via command line option\n"); + print_missing_facilities(); + break; + } + } +} + +static void modify_fac_list(char *str) +{ + unsigned long val, endval; + char *endp; + bool clear; + + while (*str) { + clear = false; + if (*str == '!') { + clear = true; + str++; + } + val = simple_strtoull(str, &endp, 0); + if (str == endp) + break; + str = endp; + if (*str == '-') { + str++; + endval = simple_strtoull(str, &endp, 0); + if (str == endp) + break; + str = endp; + while (val <= endval) { + modify_facility(val, clear); + val++; + } + } else { + modify_facility(val, clear); + } + if (*str != ',') + break; + str++; + } + check_cleared_facilities(); +} + static char command_line_buf[COMMAND_LINE_SIZE] __section(.data); -static void parse_mem_opt(void) +void parse_boot_command_line(void) { char *param, *val; bool enabled; @@ -165,12 +225,14 @@ static void parse_mem_opt(void) if (!rc && !enabled) noexec_disabled = 1; } + + if (!strcmp(param, "facilities")) + modify_fac_list(val); } } void setup_memory_end(void) { - parse_mem_opt(); #ifdef CONFIG_CRASH_DUMP if (!OLDMEM_BASE && early_ipl_block_valid && early_ipl_block.hdr.pbt == DIAG308_IPL_TYPE_FCP && diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c @@ -53,6 +53,7 @@ void startup_kernel(void) sclp_early_read_info(); store_ipl_parmblock(); setup_boot_command_line(); + parse_boot_command_line(); setup_memory_end(); detect_memory(); if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { diff --git a/arch/s390/boot/string.c b/arch/s390/boot/string.c @@ -2,6 +2,7 @@ #include <linux/ctype.h> #include <linux/kernel.h> #include <linux/errno.h> +#undef CONFIG_KASAN #include "../lib/string.c" int strncmp(const char *cs, const char *ct, size_t count) diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h @@ -43,7 +43,7 @@ int hypfs_diag0c_init(void); void hypfs_diag0c_exit(void); /* Set Partition-Resource Parameter */ -int hypfs_sprp_init(void); +void hypfs_sprp_init(void); void hypfs_sprp_exit(void); /* debugfs interface */ @@ -69,9 +69,9 @@ struct hypfs_dbfs_file { struct dentry *dentry; }; -extern int hypfs_dbfs_init(void); +extern void hypfs_dbfs_init(void); extern void hypfs_dbfs_exit(void); -extern int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df); +extern void hypfs_dbfs_create_file(struct hypfs_dbfs_file *df); extern void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df); #endif /* _HYPFS_H_ */ diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c @@ -78,14 +78,11 @@ static const struct file_operations dbfs_ops = { .unlocked_ioctl = dbfs_ioctl, }; -int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) +void hypfs_dbfs_create_file(struct hypfs_dbfs_file *df) { df->dentry = debugfs_create_file(df->name, 0400, dbfs_dir, df, &dbfs_ops); - if (IS_ERR(df->dentry)) - return PTR_ERR(df->dentry); mutex_init(&df->lock); - return 0; } void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df) @@ -93,10 +90,9 @@ void hypfs_dbfs_remove_file(struct hypfs_dbfs_file *df) debugfs_remove(df->dentry); } -int hypfs_dbfs_init(void) +void hypfs_dbfs_init(void) { dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); - return PTR_ERR_OR_ZERO(dbfs_dir); } void hypfs_dbfs_exit(void) diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c @@ -440,11 +440,10 @@ __init int hypfs_diag_init(void) pr_err("The hardware system does not support hypfs\n"); return -ENODATA; } - if (diag204_info_type == DIAG204_INFO_EXT) { - rc = hypfs_dbfs_create_file(&dbfs_file_d204); - if (rc) - return rc; - } + + if (diag204_info_type == DIAG204_INFO_EXT) + hypfs_dbfs_create_file(&dbfs_file_d204); + if (MACHINE_IS_LPAR) { rc = diag224_get_name_table(); if (rc) { diff --git a/arch/s390/hypfs/hypfs_diag0c.c b/arch/s390/hypfs/hypfs_diag0c.c @@ -54,8 +54,7 @@ static void *diag0c_store(unsigned int *count) if (!cpu_vec) goto fail_put_online_cpus; /* Note: Diag 0c needs 8 byte alignment and real storage */ - diag0c_data = kzalloc(sizeof(struct hypfs_diag0c_hdr) + - cpu_count * sizeof(struct hypfs_diag0c_entry), + diag0c_data = kzalloc(struct_size(diag0c_data, entry, cpu_count), GFP_KERNEL | GFP_DMA); if (!diag0c_data) goto fail_kfree_cpu_vec; @@ -125,7 +124,8 @@ int __init hypfs_diag0c_init(void) { if (!MACHINE_IS_VM) return 0; - return hypfs_dbfs_create_file(&dbfs_file_0c); + hypfs_dbfs_create_file(&dbfs_file_0c); + return 0; } /* diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c @@ -137,11 +137,11 @@ static struct hypfs_dbfs_file hypfs_sprp_file = { .unlocked_ioctl = hypfs_sprp_ioctl, }; -int hypfs_sprp_init(void) +void hypfs_sprp_init(void) { if (!sclp.has_sprp) - return 0; - return hypfs_dbfs_create_file(&hypfs_sprp_file); + return; + hypfs_dbfs_create_file(&hypfs_sprp_file); } void hypfs_sprp_exit(void) diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c @@ -279,7 +279,8 @@ int hypfs_vm_init(void) guest_query = local_guest; else return -EACCES; - return hypfs_dbfs_create_file(&dbfs_file_2fc); + hypfs_dbfs_create_file(&dbfs_file_2fc); + return 0; } void hypfs_vm_exit(void) diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c @@ -456,9 +456,8 @@ static int __init hypfs_init(void) { int rc; - rc = hypfs_dbfs_init(); - if (rc) - return rc; + hypfs_dbfs_init(); + if (hypfs_diag_init()) { rc = -ENODATA; goto fail_dbfs_exit; @@ -467,10 +466,7 @@ static int __init hypfs_init(void) rc = -ENODATA; goto fail_hypfs_diag_exit; } - if (hypfs_sprp_init()) { - rc = -ENODATA; - goto fail_hypfs_vm_exit; - } + hypfs_sprp_init(); if (hypfs_diag0c_init()) { rc = -ENODATA; goto fail_hypfs_sprp_exit; @@ -489,7 +485,6 @@ fail_hypfs_diag0c_exit: hypfs_diag0c_exit(); fail_hypfs_sprp_exit: hypfs_sprp_exit(); -fail_hypfs_vm_exit: hypfs_vm_exit(); fail_hypfs_diag_exit: hypfs_diag_exit(); diff --git a/arch/s390/include/asm/cpu_mcf.h b/arch/s390/include/asm/cpu_mcf.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Counter facility support definitions for the Linux perf + * + * Copyright IBM Corp. 2019 + * Author(s): Hendrik Brueckner <brueckner@linux.ibm.com> + */ +#ifndef _ASM_S390_CPU_MCF_H +#define _ASM_S390_CPU_MCF_H + +#include <linux/perf_event.h> +#include <asm/cpu_mf.h> + +enum cpumf_ctr_set { + CPUMF_CTR_SET_BASIC = 0, /* Basic Counter Set */ + CPUMF_CTR_SET_USER = 1, /* Problem-State Counter Set */ + CPUMF_CTR_SET_CRYPTO = 2, /* Crypto-Activity Counter Set */ + CPUMF_CTR_SET_EXT = 3, /* Extended Counter Set */ + CPUMF_CTR_SET_MT_DIAG = 4, /* MT-diagnostic Counter Set */ + + /* Maximum number of counter sets */ + CPUMF_CTR_SET_MAX, +}; + +#define CPUMF_LCCTL_ENABLE_SHIFT 16 +#define CPUMF_LCCTL_ACTCTL_SHIFT 0 +static const u64 cpumf_ctr_ctl[CPUMF_CTR_SET_MAX] = { + [CPUMF_CTR_SET_BASIC] = 0x02, + [CPUMF_CTR_SET_USER] = 0x04, + [CPUMF_CTR_SET_CRYPTO] = 0x08, + [CPUMF_CTR_SET_EXT] = 0x01, + [CPUMF_CTR_SET_MT_DIAG] = 0x20, +}; + +static inline void ctr_set_enable(u64 *state, int ctr_set) +{ + *state |= cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT; +} +static inline void ctr_set_disable(u64 *state, int ctr_set) +{ + *state &= ~(cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT); +} +static inline void ctr_set_start(u64 *state, int ctr_set) +{ + *state |= cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT; +} +static inline void ctr_set_stop(u64 *state, int ctr_set) +{ + *state &= ~(cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT); +} + +static inline void ctr_set_multiple_enable(u64 *state, u64 ctrsets) +{ + *state |= ctrsets << CPUMF_LCCTL_ENABLE_SHIFT; +} + +static inline void ctr_set_multiple_disable(u64 *state, u64 ctrsets) +{ + *state &= ~(ctrsets << CPUMF_LCCTL_ENABLE_SHIFT); +} + +static inline void ctr_set_multiple_start(u64 *state, u64 ctrsets) +{ + *state |= ctrsets << CPUMF_LCCTL_ACTCTL_SHIFT; +} + +static inline void ctr_set_multiple_stop(u64 *state, u64 ctrsets) +{ + *state &= ~(ctrsets << CPUMF_LCCTL_ACTCTL_SHIFT); +} + +static inline int ctr_stcctm(enum cpumf_ctr_set set, u64 range, u64 *dest) +{ + switch (set) { + case CPUMF_CTR_SET_BASIC: + return stcctm(BASIC, range, dest); + case CPUMF_CTR_SET_USER: + return stcctm(PROBLEM_STATE, range, dest); + case CPUMF_CTR_SET_CRYPTO: + return stcctm(CRYPTO_ACTIVITY, range, dest); + case CPUMF_CTR_SET_EXT: + return stcctm(EXTENDED, range, dest); + case CPUMF_CTR_SET_MT_DIAG: + return stcctm(MT_DIAG_CLEARING, range, dest); + case CPUMF_CTR_SET_MAX: + return 3; + } + return 3; +} + +struct cpu_cf_events { + struct cpumf_ctr_info info; + atomic_t ctr_set[CPUMF_CTR_SET_MAX]; + atomic64_t alert; + u64 state, tx_state; + unsigned int flags; + unsigned int txn_flags; +}; +DECLARE_PER_CPU(struct cpu_cf_events, cpu_cf_events); + +bool kernel_cpumcf_avail(void); +int __kernel_cpumcf_begin(void); +unsigned long kernel_cpumcf_alert(int clear); +void __kernel_cpumcf_end(void); + +static inline int kernel_cpumcf_begin(void) +{ + if (!cpum_cf_avail()) + return -ENODEV; + + preempt_disable(); + return __kernel_cpumcf_begin(); +} +static inline void kernel_cpumcf_end(void) +{ + __kernel_cpumcf_end(); + preempt_enable(); +} + +/* Return true if store counter set multiple instruction is available */ +static inline int stccm_avail(void) +{ + return test_facility(142); +} + +#endif /* _ASM_S390_CPU_MCF_H */ diff --git a/arch/s390/include/asm/cpu_mf-insn.h b/arch/s390/include/asm/cpu_mf-insn.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Support for CPU-MF instructions + * + * Copyright IBM Corp. 2019 + * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> + */ +#ifndef _ASM_S390_CPU_MF_INSN_H +#define _ASM_S390_CPU_MF_INSN_H + +#ifdef __ASSEMBLY__ + +/* Macro to generate the STCCTM instruction with a customized + * M3 field designating the counter set. + */ +.macro STCCTM r1 m3 db2 + .insn rsy,0xeb0000000017,\r1,\m3 & 0xf,\db2 +.endm + +#endif /* __ASSEMBLY__ */ + +#endif diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h @@ -12,6 +12,8 @@ #include <linux/errno.h> #include <asm/facility.h> +asm(".include \"asm/cpu_mf-insn.h\"\n"); + #define CPU_MF_INT_SF_IAE (1 << 31) /* invalid entry address */ #define CPU_MF_INT_SF_ISE (1 << 30) /* incorrect SDBT entry */ #define CPU_MF_INT_SF_PRA (1 << 29) /* program request alert */ @@ -209,17 +211,25 @@ static inline int ecctr(u64 ctr, u64 *val) return cc; } -/* Store CPU counter multiple for the MT utilization counter set */ -static inline int stcctm5(u64 num, u64 *val) +/* Store CPU counter multiple for a particular counter set */ +enum stcctm_ctr_set { + EXTENDED = 0, + BASIC = 1, + PROBLEM_STATE = 2, + CRYPTO_ACTIVITY = 3, + MT_DIAG = 5, + MT_DIAG_CLEARING = 9, /* clears loss-of-MT-ctr-data alert */ +}; +static inline int stcctm(enum stcctm_ctr_set set, u64 range, u64 *dest) { int cc; asm volatile ( - " .insn rsy,0xeb0000000017,%2,5,%1\n" + " STCCTM %2,%3,%1\n" " ipm %0\n" " srl %0,28\n" : "=d" (cc) - : "Q" (*val), "d" (num) + : "Q" (*dest), "d" (range), "i" (set) : "cc", "memory"); return cc; } diff --git a/arch/s390/include/asm/diag.h b/arch/s390/include/asm/diag.h @@ -32,6 +32,7 @@ enum diag_stat_enum { DIAG_STAT_X2FC, DIAG_STAT_X304, DIAG_STAT_X308, + DIAG_STAT_X318, DIAG_STAT_X500, NR_DIAG_STAT }; @@ -293,6 +294,17 @@ struct diag26c_mac_resp { u8 res[2]; } __aligned(8); +#define CPNC_LINUX 0x4 +union diag318_info { + unsigned long val; + struct { + unsigned int cpnc : 8; + unsigned int cpvc_linux : 24; + unsigned char cpvc_distro[3]; + unsigned char zero; + }; +}; + int diag204(unsigned long subcode, unsigned long size, void *addr); int diag224(void *ptr); int diag26c(void *req, void *resp, enum diag26c_sc subcode); diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h @@ -81,5 +81,30 @@ static inline void ftrace_generate_call_insn(struct ftrace_insn *insn, #endif } +/* + * Even though the system call numbers are identical for s390/s390x a + * different system call table is used for compat tasks. This may lead + * to e.g. incorrect or missing trace event sysfs files. + * Therefore simply do not trace compat system calls at all. + * See kernel/trace/trace_syscalls.c. + */ +#define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS +static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs) +{ + return is_compat_task(); +} + +#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME +static inline bool arch_syscall_match_sym_name(const char *sym, + const char *name) +{ + /* + * Skip __s390_ and __s390x_ prefix - due to compat wrappers + * and aliasing some symbols of 64 bit system call functions + * may get the __s390_ prefix instead of the __s390x_ prefix. + */ + return !strcmp(sym + 7, name) || !strcmp(sym + 8, name); +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_S390_FTRACE_H */ diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h @@ -10,6 +10,12 @@ #define JUMP_LABEL_NOP_SIZE 6 #define JUMP_LABEL_NOP_OFFSET 2 +#if __GNUC__ < 9 +#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "X" +#else +#define JUMP_LABEL_STATIC_KEY_CONSTRAINT "jdd" +#endif + /* * We use a brcl 0,2 instruction for jump labels at compile time so it * can be easily distinguished from a hotpatch generated instruction. @@ -20,9 +26,9 @@ static inline bool arch_static_branch(struct static_key *key, bool branch) ".pushsection __jump_table,\"aw\"\n" ".balign 8\n" ".long 0b-.,%l[label]-.\n" - ".quad %0-.\n" + ".quad %0+%1-.\n" ".popsection\n" - : : "X" (&((char *)key)[branch]) : : label); + : : JUMP_LABEL_STATIC_KEY_CONSTRAINT (key), "i" (branch) : : label); return false; label: return true; @@ -34,9 +40,9 @@ static inline bool arch_static_branch_jump(struct static_key *key, bool branch) ".pushsection __jump_table,\"aw\"\n" ".balign 8\n" ".long 0b-.,%l[label]-.\n" - ".quad %0-.\n" + ".quad %0+%1-.\n" ".popsection\n" - : : "X" (&((char *)key)[branch]) : : label); + : : JUMP_LABEL_STATIC_KEY_CONSTRAINT (key), "i" (branch) : : label); return false; label: return true; diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h @@ -148,7 +148,6 @@ struct zpci_dev { enum pci_bus_speed max_bus_speed; struct dentry *debugfs_dev; - struct dentry *debugfs_perf; struct s390_domain *s390_domain; /* s390 IOMMU domain data */ }; diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h @@ -12,7 +12,6 @@ #include <linux/perf_event.h> #include <linux/device.h> -#include <asm/cpu_mf.h> /* Per-CPU flags for PMU states */ #define PMU_F_RESERVED 0x1000 @@ -55,6 +54,7 @@ struct perf_sf_sde_regs { #define PERF_CPUM_SF_MAX_CTR 2 #define PERF_EVENT_CPUM_SF 0xB0000UL /* Event: Basic-sampling */ #define PERF_EVENT_CPUM_SF_DIAG 0xBD000UL /* Event: Combined-sampling */ +#define PERF_EVENT_CPUM_CF_DIAG 0xBC000UL /* Event: Counter sets */ #define PERF_CPUM_SF_BASIC_MODE 0x0001 /* Basic-sampling flag */ #define PERF_CPUM_SF_DIAG_MODE 0x0002 /* Diagnostic-sampling flag */ #define PERF_CPUM_SF_MODE_MASK (PERF_CPUM_SF_BASIC_MODE| \ diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h @@ -361,8 +361,8 @@ struct qdio_initialize { unsigned long); int scan_threshold; unsigned long int_parm; - void **input_sbal_addr_array; - void **output_sbal_addr_array; + struct qdio_buffer **input_sbal_addr_array; + struct qdio_buffer **output_sbal_addr_array; struct qdio_outbuf_state *output_sbal_state_array; }; diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h @@ -78,6 +78,7 @@ struct sclp_info { unsigned char has_skey : 1; unsigned char has_kss : 1; unsigned char has_gisaf : 1; + unsigned char has_diag318 : 1; unsigned int ibc; unsigned int mtid; unsigned int mtid_cp; diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h @@ -12,15 +12,21 @@ #include <linux/types.h> #endif -#define __HAVE_ARCH_MEMCHR /* inline & arch function */ -#define __HAVE_ARCH_MEMCMP /* arch function */ #define __HAVE_ARCH_MEMCPY /* gcc builtin & arch function */ #define __HAVE_ARCH_MEMMOVE /* gcc builtin & arch function */ -#define __HAVE_ARCH_MEMSCAN /* inline & arch function */ #define __HAVE_ARCH_MEMSET /* gcc builtin & arch function */ #define __HAVE_ARCH_MEMSET16 /* arch function */ #define __HAVE_ARCH_MEMSET32 /* arch function */ #define __HAVE_ARCH_MEMSET64 /* arch function */ + +void *memcpy(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); +void *memmove(void *dest, const void *src, size_t n); + +#ifndef CONFIG_KASAN +#define __HAVE_ARCH_MEMCHR /* inline & arch function */ +#define __HAVE_ARCH_MEMCMP /* arch function */ +#define __HAVE_ARCH_MEMSCAN /* inline & arch function */ #define __HAVE_ARCH_STRCAT /* inline & arch function */ #define __HAVE_ARCH_STRCMP /* arch function */ #define __HAVE_ARCH_STRCPY /* inline & arch function */ @@ -35,9 +41,6 @@ /* Prototypes for non-inlined arch strings functions. */ int memcmp(const void *s1, const void *s2, size_t n); -void *memcpy(void *dest, const void *src, size_t n); -void *memset(void *s, int c, size_t n); -void *memmove(void *dest, const void *src, size_t n); int strcmp(const char *s1, const char *s2); size_t strlcat(char *dest, const char *src, size_t n); size_t strlcpy(char *dest, const char *src, size_t size); @@ -45,6 +48,7 @@ char *strncat(char *dest, const char *src, size_t n); char *strncpy(char *dest, const char *src, size_t n); char *strrchr(const char *s, int c); char *strstr(const char *s1, const char *s2); +#endif /* !CONFIG_KASAN */ #undef __HAVE_ARCH_STRCHR #undef __HAVE_ARCH_STRNCHR @@ -95,6 +99,7 @@ static inline void *memset64(uint64_t *s, uint64_t v, size_t count) #if !defined(IN_ARCH_STRING_C) && (!defined(CONFIG_FORTIFY_SOURCE) || defined(__NO_FORTIFY)) +#ifdef __HAVE_ARCH_MEMCHR static inline void *memchr(const void * s, int c, size_t n) { register int r0 asm("0") = (char) c; @@ -109,7 +114,9 @@ static inline void *memchr(const void * s, int c, size_t n) : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory"); return (void *) ret; } +#endif +#ifdef __HAVE_ARCH_MEMSCAN static inline void *memscan(void *s, int c, size_t n) { register int r0 asm("0") = (char) c; @@ -121,7 +128,9 @@ static inline void *memscan(void *s, int c, size_t n) : "+a" (ret), "+&a" (s) : "d" (r0) : "cc", "memory"); return (void *) ret; } +#endif +#ifdef __HAVE_ARCH_STRCAT static inline char *strcat(char *dst, const char *src) { register int r0 asm("0") = 0; @@ -137,7 +146,9 @@ static inline char *strcat(char *dst, const char *src) : "d" (r0), "0" (0) : "cc", "memory" ); return ret; } +#endif +#ifdef __HAVE_ARCH_STRCPY static inline char *strcpy(char *dst, const char *src) { register int r0 asm("0") = 0; @@ -150,7 +161,9 @@ static inline char *strcpy(char *dst, const char *src) : "cc", "memory"); return ret; } +#endif +#ifdef __HAVE_ARCH_STRLEN static inline size_t strlen(const char *s) { register unsigned long r0 asm("0") = 0; @@ -162,7 +175,9 @@ static inline size_t strlen(const char *s) : "+d" (r0), "+a" (tmp) : : "cc", "memory"); return r0 - (unsigned long) s; } +#endif +#ifdef __HAVE_ARCH_STRNLEN static inline size_t strnlen(const char * s, size_t n) { register int r0 asm("0") = 0; @@ -175,6 +190,7 @@ static inline size_t strnlen(const char * s, size_t n) : "+a" (end), "+a" (tmp) : "d" (r0) : "cc", "memory"); return end - s; } +#endif #else /* IN_ARCH_STRING_C */ void *memchr(const void * s, int c, size_t n); void *memscan(void *s, int c, size_t n); diff --git a/arch/s390/include/asm/syscall_wrapper.h b/arch/s390/include/asm/syscall_wrapper.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * syscall_wrapper.h - s390 specific wrappers to syscall definitions + * + */ + +#ifndef _ASM_S390_SYSCALL_WRAPPER_H +#define _ASM_S390_SYSCALL_WRAPPER_H + +#ifdef CONFIG_COMPAT +#define __SC_COMPAT_TYPE(t, a) \ + __typeof(__builtin_choose_expr(sizeof(t) > 4, 0L, (t)0)) a + +#define __SC_COMPAT_CAST(t, a) \ +({ \ + long __ReS = a; \ + \ + BUILD_BUG_ON((sizeof(t) > 4) && !__TYPE_IS_L(t) && \ + !__TYPE_IS_UL(t) && !__TYPE_IS_PTR(t) && \ + !__TYPE_IS_LL(t)); \ + if (__TYPE_IS_L(t)) \ + __ReS = (s32)a; \ + if (__TYPE_IS_UL(t)) \ + __ReS = (u32)a; \ + if (__TYPE_IS_PTR(t)) \ + __ReS = a & 0x7fffffff; \ + if (__TYPE_IS_LL(t)) \ + return -ENOSYS; \ + (t)__ReS; \ +}) + +#define __S390_SYS_STUBx(x, name, ...) \ + asmlinkage long __s390_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))\ + ALLOW_ERROR_INJECTION(__s390_sys##name, ERRNO); \ + asmlinkage long __s390_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))\ + { \ + long ret = __s390x_sys##name(__MAP(x,__SC_COMPAT_CAST,__VA_ARGS__));\ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + return ret; \ + } + +/* + * To keep the naming coherent, re-define SYSCALL_DEFINE0 to create an alias + * named __s390x_sys_*() + */ +#define COMPAT_SYSCALL_DEFINE0(sname) \ + SYSCALL_METADATA(_##sname, 0); \ + asmlinkage long __s390_compat_sys_##sname(void); \ + ALLOW_ERROR_INJECTION(__s390_compat__sys_##sname, ERRNO); \ + asmlinkage long __s390_compat_sys_##sname(void) + +#define SYSCALL_DEFINE0(sname) \ + SYSCALL_METADATA(_##sname, 0); \ + asmlinkage long __s390x_sys_##sname(void); \ + ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO); \ + asmlinkage long __s390_sys_##sname(void) \ + __attribute__((alias(__stringify(__s390x_sys_##sname)))); \ + asmlinkage long __s390x_sys_##sname(void) + +#define COND_SYSCALL(name) \ + cond_syscall(__s390x_sys_##name); \ + cond_syscall(__s390_sys_##name) + +#define SYS_NI(name) \ + SYSCALL_ALIAS(__s390x_sys_##name, sys_ni_posix_timers); \ + SYSCALL_ALIAS(__s390_sys_##name, sys_ni_posix_timers) + +#define COMPAT_SYSCALL_DEFINEx(x, name, ...) \ + __diag_push(); \ + __diag_ignore(GCC, 8, "-Wattribute-alias", \ + "Type aliasing is used to sanitize syscall arguments");\ + asmlinkage long __s390_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ + asmlinkage long __s390_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ + __attribute__((alias(__stringify(__se_compat_sys##name)))); \ + ALLOW_ERROR_INJECTION(compat_sys##name, ERRNO); \ + static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + asmlinkage long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ + asmlinkage long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ + { \ + long ret = __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));\ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + return ret; \ + } \ + __diag_pop(); \ + static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) + +/* + * As some compat syscalls may not be implemented, we need to expand + * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in + * kernel/time/posix-stubs.c to cover this case as well. + */ +#define COND_SYSCALL_COMPAT(name) \ + cond_syscall(__s390_compat_sys_##name) + +#define COMPAT_SYS_NI(name) \ + SYSCALL_ALIAS(__s390_compat_sys_##name, sys_ni_posix_timers) + +#else /* CONFIG_COMPAT */ + +#define __S390_SYS_STUBx(x, fullname, name, ...) + +#define SYSCALL_DEFINE0(sname) \ + SYSCALL_METADATA(_##sname, 0); \ + asmlinkage long __s390x_sys_##sname(void); \ + ALLOW_ERROR_INJECTION(__s390x_sys_##sname, ERRNO); \ + asmlinkage long __s390x_sys_##sname(void) + +#define COND_SYSCALL(name) \ + cond_syscall(__s390x_sys_##name) + +#define SYS_NI(name) \ + SYSCALL_ALIAS(__s390x_sys_##name, sys_ni_posix_timers); + +#endif /* CONFIG_COMPAT */ + +#define __SYSCALL_DEFINEx(x, name, ...) \ + __diag_push(); \ + __diag_ignore(GCC, 8, "-Wattribute-alias", \ + "Type aliasing is used to sanitize syscall arguments");\ + asmlinkage long __s390x_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ + __attribute__((alias(__stringify(__se_sys##name)))); \ + ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO); \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ + static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ + __S390_SYS_STUBx(x, name, __VA_ARGS__) \ + asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ + { \ + long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + return ret; \ + } \ + __diag_pop(); \ + static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) + +#endif /* _ASM_X86_SYSCALL_WRAPPER_H */ diff --git a/arch/s390/include/asm/vx-insn.h b/arch/s390/include/asm/vx-insn.h @@ -363,23 +363,23 @@ .endm /* VECTOR LOAD MULTIPLE */ -.macro VLM vfrom, vto, disp, base +.macro VLM vfrom, vto, disp, base, hint=3 VX_NUM v1, \vfrom VX_NUM v3, \vto GR_NUM b2, \base /* Base register */ .word 0xE700 | ((v1&15) << 4) | (v3&15) .word (b2 << 12) | (\disp) - MRXBOPC 0, 0x36, v1, v3 + MRXBOPC \hint, 0x36, v1, v3 .endm /* VECTOR STORE MULTIPLE */ -.macro VSTM vfrom, vto, disp, base +.macro VSTM vfrom, vto, disp, base, hint=3 VX_NUM v1, \vfrom VX_NUM v3, \vto GR_NUM b2, \base /* Base register */ .word 0xE700 | ((v1&15) << 4) | (v3&15) .word (b2 << 12) | (\disp) - MRXBOPC 0, 0x3E, v1, v3 + MRXBOPC \hint, 0x3E, v1, v3 .endm /* VECTOR PERMUTE */ diff --git a/arch/s390/include/uapi/asm/posix_types.h b/arch/s390/include/uapi/asm/posix_types.h @@ -20,6 +20,12 @@ typedef long __kernel_ssize_t; typedef unsigned short __kernel_old_dev_t; #define __kernel_old_dev_t __kernel_old_dev_t +#ifdef __KERNEL__ +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +#define __kernel_old_uid_t __kernel_old_uid_t +#endif + #ifndef __s390x__ typedef unsigned long __kernel_ino_t; diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile @@ -65,7 +65,7 @@ obj-$(CONFIG_HIBERNATION) += suspend.o swsusp.o obj-$(CONFIG_AUDIT) += audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o -obj-$(CONFIG_COMPAT) += compat_wrapper.o $(compat-obj-y) +obj-$(CONFIG_COMPAT) += $(compat-obj-y) obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_KPROBES) += kprobes.o @@ -77,8 +77,10 @@ obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o kexec_image.o obj-$(CONFIG_KEXEC_FILE) += kexec_elf.o -obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf.o perf_cpum_sf.o +obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_cpum_cf_common.o +obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf.o perf_cpum_sf.o obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_events.o perf_regs.o +obj-$(CONFIG_PERF_EVENTS) += perf_cpum_cf_diag.o obj-$(CONFIG_TRACEPOINTS) += trace.o diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c @@ -34,7 +34,6 @@ #include <linux/stat.h> #include <linux/filter.h> #include <linux/highmem.h> -#include <linux/highuid.h> #include <linux/mman.h> #include <linux/ipv6.h> #include <linux/in.h> @@ -58,245 +57,13 @@ #include "compat_linux.h" -/* For this source file, we want overflow handling. */ - -#undef high2lowuid -#undef high2lowgid -#undef low2highuid -#undef low2highgid -#undef SET_UID16 -#undef SET_GID16 -#undef NEW_TO_OLD_UID -#undef NEW_TO_OLD_GID -#undef SET_OLDSTAT_UID -#undef SET_OLDSTAT_GID -#undef SET_STAT_UID -#undef SET_STAT_GID - -#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid) -#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) -#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid) -#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid) -#define SET_UID16(var, uid) var = high2lowuid(uid) -#define SET_GID16(var, gid) var = high2lowgid(gid) -#define NEW_TO_OLD_UID(uid) high2lowuid(uid) -#define NEW_TO_OLD_GID(gid) high2lowgid(gid) -#define SET_OLDSTAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid) -#define SET_OLDSTAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid) -#define SET_STAT_UID(stat, uid) (stat).st_uid = high2lowuid(uid) -#define SET_STAT_GID(stat, gid) (stat).st_gid = high2lowgid(gid) - -COMPAT_SYSCALL_DEFINE3(s390_chown16, const char __user *, filename, - u16, user, u16, group) -{ - return ksys_chown(filename, low2highuid(user), low2highgid(group)); -} - -COMPAT_SYSCALL_DEFINE3(s390_lchown16, const char __user *, - filename, u16, user, u16, group) -{ - return ksys_lchown(filename, low2highuid(user), low2highgid(group)); -} - -COMPAT_SYSCALL_DEFINE3(s390_fchown16, unsigned int, fd, u16, user, u16, group) -{ - return ksys_fchown(fd, low2highuid(user), low2highgid(group)); -} - -COMPAT_SYSCALL_DEFINE2(s390_setregid16, u16, rgid, u16, egid) -{ - return sys_setregid(low2highgid(rgid), low2highgid(egid)); -} - -COMPAT_SYSCALL_DEFINE1(s390_setgid16, u16, gid) -{ - return sys_setgid(low2highgid(gid)); -} - -COMPAT_SYSCALL_DEFINE2(s390_setreuid16, u16, ruid, u16, euid) -{ - return sys_setreuid(low2highuid(ruid), low2highuid(euid)); -} - -COMPAT_SYSCALL_DEFINE1(s390_setuid16, u16, uid) -{ - return sys_setuid(low2highuid(uid)); -} - -COMPAT_SYSCALL_DEFINE3(s390_setresuid16, u16, ruid, u16, euid, u16, suid) -{ - return sys_setresuid(low2highuid(ruid), low2highuid(euid), - low2highuid(suid)); -} - -COMPAT_SYSCALL_DEFINE3(s390_getresuid16, u16 __user *, ruidp, - u16 __user *, euidp, u16 __user *, suidp) -{ - const struct cred *cred = current_cred(); - int retval; - u16 ruid, euid, suid; - - ruid = high2lowuid(from_kuid_munged(cred->user_ns, cred->uid)); - euid = high2lowuid(from_kuid_munged(cred->user_ns, cred->euid)); - suid = high2lowuid(from_kuid_munged(cred->user_ns, cred->suid)); - - if (!(retval = put_user(ruid, ruidp)) && - !(retval = put_user(euid, euidp))) - retval = put_user(suid, suidp); - - return retval; -} - -COMPAT_SYSCALL_DEFINE3(s390_setresgid16, u16, rgid, u16, egid, u16, sgid) -{ - return sys_setresgid(low2highgid(rgid), low2highgid(egid), - low2highgid(sgid)); -} - -COMPAT_SYSCALL_DEFINE3(s390_getresgid16, u16 __user *, rgidp, - u16 __user *, egidp, u16 __user *, sgidp) -{ - const struct cred *cred = current_cred(); - int retval; - u16 rgid, egid, sgid; - - rgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->gid)); - egid = high2lowgid(from_kgid_munged(cred->user_ns, cred->egid)); - sgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->sgid)); - - if (!(retval = put_user(rgid, rgidp)) && - !(retval = put_user(egid, egidp))) - retval = put_user(sgid, sgidp); - - return retval; -} - -COMPAT_SYSCALL_DEFINE1(s390_setfsuid16, u16, uid) -{ - return sys_setfsuid(low2highuid(uid)); -} - -COMPAT_SYSCALL_DEFINE1(s390_setfsgid16, u16, gid) -{ - return sys_setfsgid(low2highgid(gid)); -} - -static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info) -{ - struct user_namespace *user_ns = current_user_ns(); - int i; - u16 group; - kgid_t kgid; - - for (i = 0; i < group_info->ngroups; i++) { - kgid = group_info->gid[i]; - group = (u16)from_kgid_munged(user_ns, kgid); - if (put_user(group, grouplist+i)) - return -EFAULT; - } - - return 0; -} - -static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist) -{ - struct user_namespace *user_ns = current_user_ns(); - int i; - u16 group; - kgid_t kgid; - - for (i = 0; i < group_info->ngroups; i++) { - if (get_user(group, grouplist+i)) - return -EFAULT; - - kgid = make_kgid(user_ns, (gid_t)group); - if (!gid_valid(kgid)) - return -EINVAL; - - group_info->gid[i] = kgid; - } - - return 0; -} - -COMPAT_SYSCALL_DEFINE2(s390_getgroups16, int, gidsetsize, u16 __user *, grouplist) -{ - const struct cred *cred = current_cred(); - int i; - - if (gidsetsize < 0) - return -EINVAL; - - get_group_info(cred->group_info); - i = cred->group_info->ngroups; - if (gidsetsize) { - if (i > gidsetsize) { - i = -EINVAL; - goto out; - } - if (groups16_to_user(grouplist, cred->group_info)) { - i = -EFAULT; - goto out; - } - } -out: - put_group_info(cred->group_info); - return i; -} - -COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplist) -{ - struct group_info *group_info; - int retval; - - if (!may_setgroups()) - return -EPERM; - if ((unsigned)gidsetsize > NGROUPS_MAX) - return -EINVAL; - - group_info = groups_alloc(gidsetsize); - if (!group_info) - return -ENOMEM; - retval = groups16_from_user(group_info, grouplist); - if (retval) { - put_group_info(group_info); - return retval; - } - - groups_sort(group_info); - retval = set_current_groups(group_info); - put_group_info(group_info); - - return retval; -} - -COMPAT_SYSCALL_DEFINE0(s390_getuid16) -{ - return high2lowuid(from_kuid_munged(current_user_ns(), current_uid())); -} - -COMPAT_SYSCALL_DEFINE0(s390_geteuid16) -{ - return high2lowuid(from_kuid_munged(current_user_ns(), current_euid())); -} - -COMPAT_SYSCALL_DEFINE0(s390_getgid16) -{ - return high2lowgid(from_kgid_munged(current_user_ns(), current_gid())); -} - -COMPAT_SYSCALL_DEFINE0(s390_getegid16) -{ - return high2lowgid(from_kgid_munged(current_user_ns(), current_egid())); -} - #ifdef CONFIG_SYSVIPC COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, compat_ulong_t, second, compat_ulong_t, third, compat_uptr_t, ptr) { if (call >> 16) /* hack for backward compatibility */ return -EINVAL; - return compat_sys_ipc(call, first, second, third, ptr, third); + return compat_ksys_ipc(call, first, second, third, ptr, third); } #endif diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c @@ -1,186 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Compat system call wrappers. - * - * Copyright IBM Corp. 2014 - */ - -#include <linux/syscalls.h> -#include <linux/compat.h> -#include "entry.h" - -#define COMPAT_SYSCALL_WRAP1(name, ...) \ - COMPAT_SYSCALL_WRAPx(1, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_WRAP2(name, ...) \ - COMPAT_SYSCALL_WRAPx(2, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_WRAP3(name, ...) \ - COMPAT_SYSCALL_WRAPx(3, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_WRAP4(name, ...) \ - COMPAT_SYSCALL_WRAPx(4, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_WRAP5(name, ...) \ - COMPAT_SYSCALL_WRAPx(5, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_WRAP6(name, ...) \ - COMPAT_SYSCALL_WRAPx(6, _##name, __VA_ARGS__) - -#define __SC_COMPAT_TYPE(t, a) \ - __typeof(__builtin_choose_expr(sizeof(t) > 4, 0L, (t)0)) a - -#define __SC_COMPAT_CAST(t, a) \ -({ \ - long __ReS = a; \ - \ - BUILD_BUG_ON((sizeof(t) > 4) && !__TYPE_IS_L(t) && \ - !__TYPE_IS_UL(t) && !__TYPE_IS_PTR(t)); \ - if (__TYPE_IS_L(t)) \ - __ReS = (s32)a; \ - if (__TYPE_IS_UL(t)) \ - __ReS = (u32)a; \ - if (__TYPE_IS_PTR(t)) \ - __ReS = a & 0x7fffffff; \ - (t)__ReS; \ -}) - -/* - * The COMPAT_SYSCALL_WRAP macro generates system call wrappers to be used by - * compat tasks. These wrappers will only be used for system calls where only - * the system call arguments need sign or zero extension or zeroing of the upper - * 33 bits of pointers. - * Note: since the wrapper function will afterwards call a system call which - * again performs zero and sign extension for all system call arguments with - * a size of less than eight bytes, these compat wrappers only touch those - * system call arguments with a size of eight bytes ((unsigned) long and - * pointers). Zero and sign extension for e.g. int parameters will be done by - * the regular system call wrappers. - */ -#define COMPAT_SYSCALL_WRAPx(x, name, ...) \ -asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ -asmlinkage long notrace compat_sys##name(__MAP(x,__SC_COMPAT_TYPE,__VA_ARGS__));\ -asmlinkage long notrace compat_sys##name(__MAP(x,__SC_COMPAT_TYPE,__VA_ARGS__)) \ -{ \ - return sys##name(__MAP(x,__SC_COMPAT_CAST,__VA_ARGS__)); \ -} - -COMPAT_SYSCALL_WRAP2(creat, const char __user *, pathname, umode_t, mode); -COMPAT_SYSCALL_WRAP2(link, const char __user *, oldname, const char __user *, newname); -COMPAT_SYSCALL_WRAP1(unlink, const char __user *, pathname); -COMPAT_SYSCALL_WRAP1(chdir, const char __user *, filename); -COMPAT_SYSCALL_WRAP3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev); -COMPAT_SYSCALL_WRAP2(chmod, const char __user *, filename, umode_t, mode); -COMPAT_SYSCALL_WRAP1(oldumount, char __user *, name); -COMPAT_SYSCALL_WRAP2(access, const char __user *, filename, int, mode); -COMPAT_SYSCALL_WRAP2(rename, const char __user *, oldname, const char __user *, newname); -COMPAT_SYSCALL_WRAP2(mkdir, const char __user *, pathname, umode_t, mode); -COMPAT_SYSCALL_WRAP1(rmdir, const char __user *, pathname); -COMPAT_SYSCALL_WRAP1(pipe, int __user *, fildes); -COMPAT_SYSCALL_WRAP1(brk, unsigned long, brk); -COMPAT_SYSCALL_WRAP2(signal, int, sig, __sighandler_t, handler); -COMPAT_SYSCALL_WRAP1(acct, const char __user *, name); -COMPAT_SYSCALL_WRAP2(umount, char __user *, name, int, flags); -COMPAT_SYSCALL_WRAP1(chroot, const char __user *, filename); -COMPAT_SYSCALL_WRAP3(sigsuspend, int, unused1, int, unused2, old_sigset_t, mask); -COMPAT_SYSCALL_WRAP2(sethostname, char __user *, name, int, len); -COMPAT_SYSCALL_WRAP2(symlink, const char __user *, old, const char __user *, new); -COMPAT_SYSCALL_WRAP3(readlink, const char __user *, path, char __user *, buf, int, bufsiz); -COMPAT_SYSCALL_WRAP1(uselib, const char __user *, library); -COMPAT_SYSCALL_WRAP2(swapon, const char __user *, specialfile, int, swap_flags); -COMPAT_SYSCALL_WRAP4(reboot, int, magic1, int, magic2, unsigned int, cmd, void __user *, arg); -COMPAT_SYSCALL_WRAP2(munmap, unsigned long, addr, size_t, len); -COMPAT_SYSCALL_WRAP3(syslog, int, type, char __user *, buf, int, len); -COMPAT_SYSCALL_WRAP1(swapoff, const char __user *, specialfile); -COMPAT_SYSCALL_WRAP2(setdomainname, char __user *, name, int, len); -COMPAT_SYSCALL_WRAP1(newuname, struct new_utsname __user *, name); -COMPAT_SYSCALL_WRAP3(mprotect, unsigned long, start, size_t, len, unsigned long, prot); -COMPAT_SYSCALL_WRAP3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs); -COMPAT_SYSCALL_WRAP2(delete_module, const char __user *, name_user, unsigned int, flags); -COMPAT_SYSCALL_WRAP4(quotactl, unsigned int, cmd, const char __user *, special, qid_t, id, void __user *, addr); -COMPAT_SYSCALL_WRAP2(bdflush, int, func, long, data); -COMPAT_SYSCALL_WRAP3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2); -COMPAT_SYSCALL_WRAP5(llseek, unsigned int, fd, unsigned long, high, unsigned long, low, loff_t __user *, result, unsigned int, whence); -COMPAT_SYSCALL_WRAP3(msync, unsigned long, start, size_t, len, int, flags); -COMPAT_SYSCALL_WRAP2(mlock, unsigned long, start, size_t, len); -COMPAT_SYSCALL_WRAP2(munlock, unsigned long, start, size_t, len); -COMPAT_SYSCALL_WRAP2(sched_setparam, pid_t, pid, struct sched_param __user *, param); -COMPAT_SYSCALL_WRAP2(sched_getparam, pid_t, pid, struct sched_param __user *, param); -COMPAT_SYSCALL_WRAP3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param); -COMPAT_SYSCALL_WRAP5(mremap, unsigned long, addr, unsigned long, old_len, unsigned long, new_len, unsigned long, flags, unsigned long, new_addr); -COMPAT_SYSCALL_WRAP3(poll, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout); -COMPAT_SYSCALL_WRAP5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, unsigned long, arg4, unsigned long, arg5); -COMPAT_SYSCALL_WRAP2(getcwd, char __user *, buf, unsigned long, size); -COMPAT_SYSCALL_WRAP2(capget, cap_user_header_t, header, cap_user_data_t, dataptr); -COMPAT_SYSCALL_WRAP2(capset, cap_user_header_t, header, const cap_user_data_t, data); -COMPAT_SYSCALL_WRAP3(lchown, const char __user *, filename, uid_t, user, gid_t, group); -COMPAT_SYSCALL_WRAP2(getgroups, int, gidsetsize, gid_t __user *, grouplist); -COMPAT_SYSCALL_WRAP2(setgroups, int, gidsetsize, gid_t __user *, grouplist); -COMPAT_SYSCALL_WRAP3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid); -COMPAT_SYSCALL_WRAP3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid); -COMPAT_SYSCALL_WRAP3(chown, const char __user *, filename, uid_t, user, gid_t, group); -COMPAT_SYSCALL_WRAP2(pivot_root, const char __user *, new_root, const char __user *, put_old); -COMPAT_SYSCALL_WRAP3(mincore, unsigned long, start, size_t, len, unsigned char __user *, vec); -COMPAT_SYSCALL_WRAP3(madvise, unsigned long, start, size_t, len, int, behavior); -COMPAT_SYSCALL_WRAP5(setxattr, const char __user *, path, const char __user *, name, const void __user *, value, size_t, size, int, flags); -COMPAT_SYSCALL_WRAP5(lsetxattr, const char __user *, path, const char __user *, name, const void __user *, value, size_t, size, int, flags); -COMPAT_SYSCALL_WRAP5(fsetxattr, int, fd, const char __user *, name, const void __user *, value, size_t, size, int, flags); -COMPAT_SYSCALL_WRAP3(getdents64, unsigned int, fd, struct linux_dirent64 __user *, dirent, unsigned int, count); -COMPAT_SYSCALL_WRAP4(getxattr, const char __user *, path, const char __user *, name, void __user *, value, size_t, size); -COMPAT_SYSCALL_WRAP4(lgetxattr, const char __user *, path, const char __user *, name, void __user *, value, size_t, size); -COMPAT_SYSCALL_WRAP4(fgetxattr, int, fd, const char __user *, name, void __user *, value, size_t, size); -COMPAT_SYSCALL_WRAP3(listxattr, const char __user *, path, char __user *, list, size_t, size); -COMPAT_SYSCALL_WRAP3(llistxattr, const char __user *, path, char __user *, list, size_t, size); -COMPAT_SYSCALL_WRAP3(flistxattr, int, fd, char __user *, list, size_t, size); -COMPAT_SYSCALL_WRAP2(removexattr, const char __user *, path, const char __user *, name); -COMPAT_SYSCALL_WRAP2(lremovexattr, const char __user *, path, const char __user *, name); -COMPAT_SYSCALL_WRAP2(fremovexattr, int, fd, const char __user *, name); -COMPAT_SYSCALL_WRAP1(set_tid_address, int __user *, tidptr); -COMPAT_SYSCALL_WRAP4(epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event __user *, event); -COMPAT_SYSCALL_WRAP4(epoll_wait, int, epfd, struct epoll_event __user *, events, int, maxevents, int, timeout); -COMPAT_SYSCALL_WRAP1(io_destroy, aio_context_t, ctx); -COMPAT_SYSCALL_WRAP3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, struct io_event __user *, result); -COMPAT_SYSCALL_WRAP1(mq_unlink, const char __user *, name); -COMPAT_SYSCALL_WRAP5(add_key, const char __user *, tp, const char __user *, dsc, const void __user *, pld, size_t, len, key_serial_t, id); -COMPAT_SYSCALL_WRAP4(request_key, const char __user *, tp, const char __user *, dsc, const char __user *, info, key_serial_t, id); -COMPAT_SYSCALL_WRAP5(remap_file_pages, unsigned long, start, unsigned long, size, unsigned long, prot, unsigned long, pgoff, unsigned long, flags); -COMPAT_SYSCALL_WRAP3(inotify_add_watch, int, fd, const char __user *, path, u32, mask); -COMPAT_SYSCALL_WRAP3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode); -COMPAT_SYSCALL_WRAP4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, unsigned, dev); -COMPAT_SYSCALL_WRAP5(fchownat, int, dfd, const char __user *, filename, uid_t, user, gid_t, group, int, flag); -COMPAT_SYSCALL_WRAP3(unlinkat, int, dfd, const char __user *, pathname, int, flag); -COMPAT_SYSCALL_WRAP4(renameat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname); -COMPAT_SYSCALL_WRAP5(linkat, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, int, flags); -COMPAT_SYSCALL_WRAP3(symlinkat, const char __user *, oldname, int, newdfd, const char __user *, newname); -COMPAT_SYSCALL_WRAP4(readlinkat, int, dfd, const char __user *, path, char __user *, buf, int, bufsiz); -COMPAT_SYSCALL_WRAP3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode); -COMPAT_SYSCALL_WRAP3(faccessat, int, dfd, const char __user *, filename, int, mode); -COMPAT_SYSCALL_WRAP1(unshare, unsigned long, unshare_flags); -COMPAT_SYSCALL_WRAP6(splice, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags); -COMPAT_SYSCALL_WRAP4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags); -COMPAT_SYSCALL_WRAP3(getcpu, unsigned __user *, cpu, unsigned __user *, node, struct getcpu_cache __user *, cache); -COMPAT_SYSCALL_WRAP2(pipe2, int __user *, fildes, int, flags); -COMPAT_SYSCALL_WRAP5(perf_event_open, struct perf_event_attr __user *, attr_uptr, pid_t, pid, int, cpu, int, group_fd, unsigned long, flags); -COMPAT_SYSCALL_WRAP5(clone, unsigned long, newsp, unsigned long, clone_flags, int __user *, parent_tidptr, int __user *, child_tidptr, unsigned long, tls); -COMPAT_SYSCALL_WRAP4(prlimit64, pid_t, pid, unsigned int, resource, const struct rlimit64 __user *, new_rlim, struct rlimit64 __user *, old_rlim); -COMPAT_SYSCALL_WRAP5(name_to_handle_at, int, dfd, const char __user *, name, struct file_handle __user *, handle, int __user *, mnt_id, int, flag); -COMPAT_SYSCALL_WRAP5(kcmp, pid_t, pid1, pid_t, pid2, int, type, unsigned long, idx1, unsigned long, idx2); -COMPAT_SYSCALL_WRAP3(finit_module, int, fd, const char __user *, uargs, int, flags); -COMPAT_SYSCALL_WRAP3(sched_setattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, flags); -COMPAT_SYSCALL_WRAP4(sched_getattr, pid_t, pid, struct sched_attr __user *, attr, unsigned int, size, unsigned int, flags); -COMPAT_SYSCALL_WRAP5(renameat2, int, olddfd, const char __user *, oldname, int, newdfd, const char __user *, newname, unsigned int, flags); -COMPAT_SYSCALL_WRAP3(seccomp, unsigned int, op, unsigned int, flags, void __user *, uargs) -COMPAT_SYSCALL_WRAP3(getrandom, char __user *, buf, size_t, count, unsigned int, flags) -COMPAT_SYSCALL_WRAP2(memfd_create, const char __user *, uname, unsigned int, flags) -COMPAT_SYSCALL_WRAP3(bpf, int, cmd, union bpf_attr *, attr, unsigned int, size); -COMPAT_SYSCALL_WRAP3(s390_pci_mmio_write, const unsigned long, mmio_addr, const void __user *, user_buffer, const size_t, length); -COMPAT_SYSCALL_WRAP3(s390_pci_mmio_read, const unsigned long, mmio_addr, void __user *, user_buffer, const size_t, length); -COMPAT_SYSCALL_WRAP4(socketpair, int, family, int, type, int, protocol, int __user *, usockvec); -COMPAT_SYSCALL_WRAP3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen); -COMPAT_SYSCALL_WRAP3(connect, int, fd, struct sockaddr __user *, uservaddr, int, addrlen); -COMPAT_SYSCALL_WRAP4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, int __user *, upeer_addrlen, int, flags); -COMPAT_SYSCALL_WRAP3(getsockname, int, fd, struct sockaddr __user *, usockaddr, int __user *, usockaddr_len); -COMPAT_SYSCALL_WRAP3(getpeername, int, fd, struct sockaddr __user *, usockaddr, int __user *, usockaddr_len); -COMPAT_SYSCALL_WRAP6(sendto, int, fd, void __user *, buff, size_t, len, unsigned int, flags, struct sockaddr __user *, addr, int, addr_len); -COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags); -COMPAT_SYSCALL_WRAP6(copy_file_range, int, fd_in, loff_t __user *, off_in, int, fd_out, loff_t __user *, off_out, size_t, len, unsigned int, flags); -COMPAT_SYSCALL_WRAP2(s390_guarded_storage, int, command, struct gs_cb *, gs_cb); -COMPAT_SYSCALL_WRAP5(statx, int, dfd, const char __user *, path, unsigned, flags, unsigned, mask, struct statx __user *, buffer); -COMPAT_SYSCALL_WRAP4(s390_sthyi, unsigned long, code, void __user *, info, u64 __user *, rc, unsigned long, flags); -COMPAT_SYSCALL_WRAP5(kexec_file_load, int, kernel_fd, int, initrd_fd, unsigned long, cmdline_len, const char __user *, cmdline_ptr, unsigned long, flags) -COMPAT_SYSCALL_WRAP4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32, sig) diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c @@ -1056,12 +1056,6 @@ int debug_register_view(debug_info_t *id, struct debug_view *view) mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry, id, &debug_file_ops); - if (!pde) { - pr_err("Registering view %s/%s failed due to out of " - "memory\n", id->name, view->name); - rc = -1; - goto out; - } spin_lock_irqsave(&id->lock, flags); for (i = 0; i < DEBUG_MAX_VIEWS; i++) { if (!id->views[i]) diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c @@ -45,6 +45,7 @@ static const struct diag_desc diag_map[NR_DIAG_STAT] = { [DIAG_STAT_X2FC] = { .code = 0x2fc, .name = "Guest Performance Data" }, [DIAG_STAT_X304] = { .code = 0x304, .name = "Partition-Resource Service" }, [DIAG_STAT_X308] = { .code = 0x308, .name = "List-Directed IPL" }, + [DIAG_STAT_X318] = { .code = 0x318, .name = "CP Name and Version Codes" }, [DIAG_STAT_X500] = { .code = 0x500, .name = "Virtio Service" }, }; diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c @@ -164,8 +164,6 @@ static noinline __init void setup_lowcore_early(void) static noinline __init void setup_facility_list(void) { - stfle(S390_lowcore.stfle_fac_list, - ARRAY_SIZE(S390_lowcore.stfle_fac_list)); memcpy(S390_lowcore.alt_stfle_fac_list, S390_lowcore.stfle_fac_list, sizeof(S390_lowcore.alt_stfle_fac_list)); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S @@ -1512,7 +1512,7 @@ cleanup_critical: .quad .Lsie_skip - .Lsie_entry #endif .section .rodata, "a" -#define SYSCALL(esame,emu) .long esame +#define SYSCALL(esame,emu) .long __s390x_ ## esame .globl sys_call_table sys_call_table: #include "asm/syscall_table.h" @@ -1520,7 +1520,7 @@ sys_call_table: #ifdef CONFIG_COMPAT -#define SYSCALL(esame,emu) .long emu +#define SYSCALL(esame,emu) .long __s390_ ## emu .globl sys_call_table_emu sys_call_table_emu: #include "asm/syscall_table.h" diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S @@ -27,8 +27,6 @@ ENTRY(startup_continue) mvc 0(16,%r1),__LC_BOOT_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 larl %r0,boot_vdso_data stg %r0,__LC_VDSO_PER_CPU # diff --git a/arch/s390/kernel/kdebugfs.c b/arch/s390/kernel/kdebugfs.c @@ -9,8 +9,6 @@ EXPORT_SYMBOL(arch_debugfs_dir); static int __init arch_kdebugfs_init(void) { arch_debugfs_dir = debugfs_create_dir("s390", NULL); - if (IS_ERR(arch_debugfs_dir)) - arch_debugfs_dir = NULL; return 0; } postcore_initcall(arch_kdebugfs_init); diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c @@ -10,73 +10,11 @@ #include <linux/kernel.h> #include <linux/kernel_stat.h> -#include <linux/perf_event.h> #include <linux/percpu.h> #include <linux/notifier.h> #include <linux/init.h> #include <linux/export.h> -#include <asm/ctl_reg.h> -#include <asm/irq.h> -#include <asm/cpu_mf.h> - -enum cpumf_ctr_set { - CPUMF_CTR_SET_BASIC = 0, /* Basic Counter Set */ - CPUMF_CTR_SET_USER = 1, /* Problem-State Counter Set */ - CPUMF_CTR_SET_CRYPTO = 2, /* Crypto-Activity Counter Set */ - CPUMF_CTR_SET_EXT = 3, /* Extended Counter Set */ - CPUMF_CTR_SET_MT_DIAG = 4, /* MT-diagnostic Counter Set */ - - /* Maximum number of counter sets */ - CPUMF_CTR_SET_MAX, -}; - -#define CPUMF_LCCTL_ENABLE_SHIFT 16 -#define CPUMF_LCCTL_ACTCTL_SHIFT 0 -static const u64 cpumf_state_ctl[CPUMF_CTR_SET_MAX] = { - [CPUMF_CTR_SET_BASIC] = 0x02, - [CPUMF_CTR_SET_USER] = 0x04, - [CPUMF_CTR_SET_CRYPTO] = 0x08, - [CPUMF_CTR_SET_EXT] = 0x01, - [CPUMF_CTR_SET_MT_DIAG] = 0x20, -}; - -static void ctr_set_enable(u64 *state, int ctr_set) -{ - *state |= cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT; -} -static void ctr_set_disable(u64 *state, int ctr_set) -{ - *state &= ~(cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ENABLE_SHIFT); -} -static void ctr_set_start(u64 *state, int ctr_set) -{ - *state |= cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT; -} -static void ctr_set_stop(u64 *state, int ctr_set) -{ - *state &= ~(cpumf_state_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT); -} - -/* Local CPUMF event structure */ -struct cpu_hw_events { - struct cpumf_ctr_info info; - atomic_t ctr_set[CPUMF_CTR_SET_MAX]; - u64 state, tx_state; - unsigned int flags; - unsigned int txn_flags; -}; -static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { - .ctr_set = { - [CPUMF_CTR_SET_BASIC] = ATOMIC_INIT(0), - [CPUMF_CTR_SET_USER] = ATOMIC_INIT(0), - [CPUMF_CTR_SET_CRYPTO] = ATOMIC_INIT(0), - [CPUMF_CTR_SET_EXT] = ATOMIC_INIT(0), - [CPUMF_CTR_SET_MT_DIAG] = ATOMIC_INIT(0), - }, - .state = 0, - .flags = 0, - .txn_flags = 0, -}; +#include <asm/cpu_mcf.h> static enum cpumf_ctr_set get_counter_set(u64 event) { @@ -98,11 +36,11 @@ static enum cpumf_ctr_set get_counter_set(u64 event) static int validate_ctr_version(const struct hw_perf_event *hwc) { - struct cpu_hw_events *cpuhw; + struct cpu_cf_events *cpuhw; int err = 0; u16 mtdiag_ctl; - cpuhw = &get_cpu_var(cpu_hw_events); + cpuhw = &get_cpu_var(cpu_cf_events); /* check required version for counter sets */ switch (hwc->config_base) { @@ -135,7 +73,7 @@ static int validate_ctr_version(const struct hw_perf_event *hwc) * Thus, the counters can only be used if SMT is on and the * counter set is enabled and active. */ - mtdiag_ctl = cpumf_state_ctl[CPUMF_CTR_SET_MT_DIAG]; + mtdiag_ctl = cpumf_ctr_ctl[CPUMF_CTR_SET_MT_DIAG]; if (!((cpuhw->info.auth_ctl & mtdiag_ctl) && (cpuhw->info.enable_ctl & mtdiag_ctl) && (cpuhw->info.act_ctl & mtdiag_ctl))) @@ -143,28 +81,28 @@ static int validate_ctr_version(const struct hw_perf_event *hwc) break; } - put_cpu_var(cpu_hw_events); + put_cpu_var(cpu_cf_events); return err; } static int validate_ctr_auth(const struct hw_perf_event *hwc) { - struct cpu_hw_events *cpuhw; + struct cpu_cf_events *cpuhw; u64 ctrs_state; int err = 0; - cpuhw = &get_cpu_var(cpu_hw_events); + cpuhw = &get_cpu_var(cpu_cf_events); /* Check authorization for cpu counter sets. * If the particular CPU counter set is not authorized, * return with -ENOENT in order to fall back to other * PMUs that might suffice the event request. */ - ctrs_state = cpumf_state_ctl[hwc->config_base]; + ctrs_state = cpumf_ctr_ctl[hwc->config_base]; if (!(ctrs_state & cpuhw->info.auth_ctl)) err = -ENOENT; - put_cpu_var(cpu_hw_events); + put_cpu_var(cpu_cf_events); return err; } @@ -175,7 +113,7 @@ static int validate_ctr_auth(const struct hw_perf_event *hwc) */ static void cpumf_pmu_enable(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); int err; if (cpuhw->flags & PMU_F_ENABLED) @@ -198,7 +136,7 @@ static void cpumf_pmu_enable(struct pmu *pmu) */ static void cpumf_pmu_disable(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); int err; u64 inactive; @@ -222,86 +160,13 @@ static atomic_t num_events = ATOMIC_INIT(0); /* Used to avoid races in calling reserve/release_cpumf_hardware */ static DEFINE_MUTEX(pmc_reserve_mutex); -/* CPU-measurement alerts for the counter facility */ -static void cpumf_measurement_alert(struct ext_code ext_code, - unsigned int alert, unsigned long unused) -{ - struct cpu_hw_events *cpuhw; - - if (!(alert & CPU_MF_INT_CF_MASK)) - return; - - inc_irq_stat(IRQEXT_CMC); - cpuhw = this_cpu_ptr(&cpu_hw_events); - - /* Measurement alerts are shared and might happen when the PMU - * is not reserved. Ignore these alerts in this case. */ - if (!(cpuhw->flags & PMU_F_RESERVED)) - return; - - /* counter authorization change alert */ - if (alert & CPU_MF_INT_CF_CACA) - qctri(&cpuhw->info); - - /* loss of counter data alert */ - if (alert & CPU_MF_INT_CF_LCDA) - pr_err("CPU[%i] Counter data was lost\n", smp_processor_id()); - - /* loss of MT counter data alert */ - if (alert & CPU_MF_INT_CF_MTDA) - pr_warn("CPU[%i] MT counter data was lost\n", - smp_processor_id()); -} - -#define PMC_INIT 0 -#define PMC_RELEASE 1 -static void setup_pmc_cpu(void *flags) -{ - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); - - switch (*((int *) flags)) { - case PMC_INIT: - memset(&cpuhw->info, 0, sizeof(cpuhw->info)); - qctri(&cpuhw->info); - cpuhw->flags |= PMU_F_RESERVED; - break; - - case PMC_RELEASE: - cpuhw->flags &= ~PMU_F_RESERVED; - break; - } - - /* Disable CPU counter sets */ - lcctl(0); -} - -/* Initialize the CPU-measurement facility */ -static int reserve_pmc_hardware(void) -{ - int flags = PMC_INIT; - - on_each_cpu(setup_pmc_cpu, &flags, 1); - irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT); - - return 0; -} - -/* Release the CPU-measurement facility */ -static void release_pmc_hardware(void) -{ - int flags = PMC_RELEASE; - - on_each_cpu(setup_pmc_cpu, &flags, 1); - irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT); -} - /* Release the PMU if event is the last perf event */ static void hw_perf_event_destroy(struct perf_event *event) { if (!atomic_add_unless(&num_events, -1, 1)) { mutex_lock(&pmc_reserve_mutex); if (atomic_dec_return(&num_events) == 0) - release_pmc_hardware(); + __kernel_cpumcf_end(); mutex_unlock(&pmc_reserve_mutex); } } @@ -332,7 +197,7 @@ static int __hw_perf_event_init(struct perf_event *event) struct perf_event_attr *attr = &event->attr; struct hw_perf_event *hwc = &event->hw; enum cpumf_ctr_set set; - int err; + int err = 0; u64 ev; switch (attr->type) { @@ -402,12 +267,14 @@ static int __hw_perf_event_init(struct perf_event *event) /* Initialize for using the CPU-measurement counter facility */ if (!atomic_inc_not_zero(&num_events)) { mutex_lock(&pmc_reserve_mutex); - if (atomic_read(&num_events) == 0 && reserve_pmc_hardware()) + if (atomic_read(&num_events) == 0 && __kernel_cpumcf_begin()) err = -EBUSY; else atomic_inc(&num_events); mutex_unlock(&pmc_reserve_mutex); } + if (err) + return err; event->destroy = hw_perf_event_destroy; /* Finally, validate version and authorization of the counter set */ @@ -488,7 +355,7 @@ static void cpumf_pmu_read(struct perf_event *event) static void cpumf_pmu_start(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); struct hw_perf_event *hwc = &event->hw; if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) @@ -519,7 +386,7 @@ static void cpumf_pmu_start(struct perf_event *event, int flags) static void cpumf_pmu_stop(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); struct hw_perf_event *hwc = &event->hw; if (!(hwc->state & PERF_HES_STOPPED)) { @@ -540,7 +407,7 @@ static void cpumf_pmu_stop(struct perf_event *event, int flags) static int cpumf_pmu_add(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); /* Check authorization for the counter set to which this * counter belongs. @@ -564,7 +431,7 @@ static int cpumf_pmu_add(struct perf_event *event, int flags) static void cpumf_pmu_del(struct perf_event *event, int flags) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); cpumf_pmu_stop(event, PERF_EF_UPDATE); @@ -592,7 +459,7 @@ static void cpumf_pmu_del(struct perf_event *event, int flags) */ static void cpumf_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); WARN_ON_ONCE(cpuhw->txn_flags); /* txn already in flight */ @@ -612,7 +479,7 @@ static void cpumf_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) static void cpumf_pmu_cancel_txn(struct pmu *pmu) { unsigned int txn_flags; - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ @@ -633,7 +500,7 @@ static void cpumf_pmu_cancel_txn(struct pmu *pmu) */ static int cpumf_pmu_commit_txn(struct pmu *pmu) { - struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); u64 state; WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ @@ -671,54 +538,17 @@ static struct pmu cpumf_pmu = { .cancel_txn = cpumf_pmu_cancel_txn, }; -static int cpumf_pmf_setup(unsigned int cpu, int flags) -{ - local_irq_disable(); - setup_pmc_cpu(&flags); - local_irq_enable(); - return 0; -} - -static int s390_pmu_online_cpu(unsigned int cpu) -{ - return cpumf_pmf_setup(cpu, PMC_INIT); -} - -static int s390_pmu_offline_cpu(unsigned int cpu) -{ - return cpumf_pmf_setup(cpu, PMC_RELEASE); -} - static int __init cpumf_pmu_init(void) { int rc; - if (!cpum_cf_avail()) + if (!kernel_cpumcf_avail()) return -ENODEV; - /* clear bit 15 of cr0 to unauthorize problem-state to - * extract measurement counters */ - ctl_clear_bit(0, 48); - - /* register handler for measurement-alert interruptions */ - rc = register_external_irq(EXT_IRQ_MEASURE_ALERT, - cpumf_measurement_alert); - if (rc) { - pr_err("Registering for CPU-measurement alerts " - "failed with rc=%i\n", rc); - return rc; - } - cpumf_pmu.attr_groups = cpumf_cf_event_group(); rc = perf_pmu_register(&cpumf_pmu, "cpum_cf", PERF_TYPE_RAW); - if (rc) { + if (rc) pr_err("Registering the cpum_cf PMU failed with rc=%i\n", rc); - unregister_external_irq(EXT_IRQ_MEASURE_ALERT, - cpumf_measurement_alert); - return rc; - } - return cpuhp_setup_state(CPUHP_AP_PERF_S390_CF_ONLINE, - "perf/s390/cf:online", - s390_pmu_online_cpu, s390_pmu_offline_cpu); + return rc; } -early_initcall(cpumf_pmu_init); +subsys_initcall(cpumf_pmu_init); diff --git a/arch/s390/kernel/perf_cpum_cf_common.c b/arch/s390/kernel/perf_cpum_cf_common.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CPU-Measurement Counter Facility Support - Common Layer + * + * Copyright IBM Corp. 2019 + * Author(s): Hendrik Brueckner <brueckner@linux.ibm.com> + */ +#define KMSG_COMPONENT "cpum_cf_common" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/kernel.h> +#include <linux/kernel_stat.h> +#include <linux/percpu.h> +#include <linux/notifier.h> +#include <linux/init.h> +#include <linux/export.h> +#include <asm/ctl_reg.h> +#include <asm/irq.h> +#include <asm/cpu_mcf.h> + +/* Per-CPU event structure for the counter facility */ +DEFINE_PER_CPU(struct cpu_cf_events, cpu_cf_events) = { + .ctr_set = { + [CPUMF_CTR_SET_BASIC] = ATOMIC_INIT(0), + [CPUMF_CTR_SET_USER] = ATOMIC_INIT(0), + [CPUMF_CTR_SET_CRYPTO] = ATOMIC_INIT(0), + [CPUMF_CTR_SET_EXT] = ATOMIC_INIT(0), + [CPUMF_CTR_SET_MT_DIAG] = ATOMIC_INIT(0), + }, + .alert = ATOMIC64_INIT(0), + .state = 0, + .flags = 0, + .txn_flags = 0, +}; +/* Indicator whether the CPU-Measurement Counter Facility Support is ready */ +static bool cpum_cf_initalized; + +/* CPU-measurement alerts for the counter facility */ +static void cpumf_measurement_alert(struct ext_code ext_code, + unsigned int alert, unsigned long unused) +{ + struct cpu_cf_events *cpuhw; + + if (!(alert & CPU_MF_INT_CF_MASK)) + return; + + inc_irq_stat(IRQEXT_CMC); + cpuhw = this_cpu_ptr(&cpu_cf_events); + + /* Measurement alerts are shared and might happen when the PMU + * is not reserved. Ignore these alerts in this case. */ + if (!(cpuhw->flags & PMU_F_RESERVED)) + return; + + /* counter authorization change alert */ + if (alert & CPU_MF_INT_CF_CACA) + qctri(&cpuhw->info); + + /* loss of counter data alert */ + if (alert & CPU_MF_INT_CF_LCDA) + pr_err("CPU[%i] Counter data was lost\n", smp_processor_id()); + + /* loss of MT counter data alert */ + if (alert & CPU_MF_INT_CF_MTDA) + pr_warn("CPU[%i] MT counter data was lost\n", + smp_processor_id()); + + /* store alert for special handling by in-kernel users */ + atomic64_or(alert, &cpuhw->alert); +} + +#define PMC_INIT 0 +#define PMC_RELEASE 1 +static void cpum_cf_setup_cpu(void *flags) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + + switch (*((int *) flags)) { + case PMC_INIT: + memset(&cpuhw->info, 0, sizeof(cpuhw->info)); + qctri(&cpuhw->info); + cpuhw->flags |= PMU_F_RESERVED; + break; + + case PMC_RELEASE: + cpuhw->flags &= ~PMU_F_RESERVED; + break; + } + + /* Disable CPU counter sets */ + lcctl(0); +} + +bool kernel_cpumcf_avail(void) +{ + return cpum_cf_initalized; +} +EXPORT_SYMBOL(kernel_cpumcf_avail); + + +/* Reserve/release functions for sharing perf hardware */ +static DEFINE_SPINLOCK(cpumcf_owner_lock); +static void *cpumcf_owner; + +/* Initialize the CPU-measurement counter facility */ +int __kernel_cpumcf_begin(void) +{ + int flags = PMC_INIT; + int err = 0; + + spin_lock(&cpumcf_owner_lock); + if (cpumcf_owner) + err = -EBUSY; + else + cpumcf_owner = __builtin_return_address(0); + spin_unlock(&cpumcf_owner_lock); + if (err) + return err; + + on_each_cpu(cpum_cf_setup_cpu, &flags, 1); + irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT); + + return 0; +} +EXPORT_SYMBOL(__kernel_cpumcf_begin); + +/* Obtain the CPU-measurement alerts for the counter facility */ +unsigned long kernel_cpumcf_alert(int clear) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + unsigned long alert; + + alert = atomic64_read(&cpuhw->alert); + if (clear) + atomic64_set(&cpuhw->alert, 0); + + return alert; +} +EXPORT_SYMBOL(kernel_cpumcf_alert); + +/* Release the CPU-measurement counter facility */ +void __kernel_cpumcf_end(void) +{ + int flags = PMC_RELEASE; + + on_each_cpu(cpum_cf_setup_cpu, &flags, 1); + irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT); + + spin_lock(&cpumcf_owner_lock); + cpumcf_owner = NULL; + spin_unlock(&cpumcf_owner_lock); +} +EXPORT_SYMBOL(__kernel_cpumcf_end); + +static int cpum_cf_setup(unsigned int cpu, int flags) +{ + local_irq_disable(); + cpum_cf_setup_cpu(&flags); + local_irq_enable(); + return 0; +} + +static int cpum_cf_online_cpu(unsigned int cpu) +{ + return cpum_cf_setup(cpu, PMC_INIT); +} + +static int cpum_cf_offline_cpu(unsigned int cpu) +{ + return cpum_cf_setup(cpu, PMC_RELEASE); +} + +static int __init cpum_cf_init(void) +{ + int rc; + + if (!cpum_cf_avail()) + return -ENODEV; + + /* clear bit 15 of cr0 to unauthorize problem-state to + * extract measurement counters */ + ctl_clear_bit(0, 48); + + /* register handler for measurement-alert interruptions */ + rc = register_external_irq(EXT_IRQ_MEASURE_ALERT, + cpumf_measurement_alert); + if (rc) { + pr_err("Registering for CPU-measurement alerts " + "failed with rc=%i\n", rc); + return rc; + } + + rc = cpuhp_setup_state(CPUHP_AP_PERF_S390_CF_ONLINE, + "perf/s390/cf:online", + cpum_cf_online_cpu, cpum_cf_offline_cpu); + if (!rc) + cpum_cf_initalized = true; + + return rc; +} +early_initcall(cpum_cf_init); diff --git a/arch/s390/kernel/perf_cpum_cf_diag.c b/arch/s390/kernel/perf_cpum_cf_diag.c @@ -0,0 +1,693 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Performance event support for s390x - CPU-measurement Counter Sets + * + * Copyright IBM Corp. 2019 + * Author(s): Hendrik Brueckner <brueckner@linux.ibm.com> + * Thomas Richer <tmricht@linux.ibm.com> + */ +#define KMSG_COMPONENT "cpum_cf_diag" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include <linux/kernel.h> +#include <linux/kernel_stat.h> +#include <linux/percpu.h> +#include <linux/notifier.h> +#include <linux/init.h> +#include <linux/export.h> +#include <linux/slab.h> +#include <linux/processor.h> + +#include <asm/ctl_reg.h> +#include <asm/irq.h> +#include <asm/cpu_mcf.h> +#include <asm/timex.h> +#include <asm/debug.h> + +#define CF_DIAG_CTRSET_DEF 0xfeef /* Counter set header mark */ + +static unsigned int cf_diag_cpu_speed; +static debug_info_t *cf_diag_dbg; + +struct cf_diag_csd { /* Counter set data per CPU */ + size_t used; /* Bytes used in data/start */ + unsigned char start[PAGE_SIZE]; /* Counter set at event start */ + unsigned char data[PAGE_SIZE]; /* Counter set at event delete */ +}; +DEFINE_PER_CPU(struct cf_diag_csd, cf_diag_csd); + +/* Counter sets are stored as data stream in a page sized memory buffer and + * exported to user space via raw data attached to the event sample data. + * Each counter set starts with an eight byte header consisting of: + * - a two byte eye catcher (0xfeef) + * - a one byte counter set number + * - a two byte counter set size (indicates the number of counters in this set) + * - a three byte reserved value (must be zero) to make the header the same + * size as a counter value. + * All counter values are eight byte in size. + * + * All counter sets are followed by a 64 byte trailer. + * The trailer consists of a: + * - flag field indicating valid fields when corresponding bit set + * - the counter facility first and second version number + * - the CPU speed if nonzero + * - the time stamp the counter sets have been collected + * - the time of day (TOD) base value + * - the machine type. + * + * The counter sets are saved when the process is prepared to be executed on a + * CPU and saved again when the process is going to be removed from a CPU. + * The difference of both counter sets are calculated and stored in the event + * sample data area. + */ + +struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */ + unsigned int def:16; /* 0-15 Data Entry Format */ + unsigned int set:16; /* 16-31 Counter set identifier */ + unsigned int ctr:16; /* 32-47 Number of stored counters */ + unsigned int res1:16; /* 48-63 Reserved */ +}; + +struct cf_trailer_entry { /* CPU-M CF_DIAG trailer (64 byte) */ + /* 0 - 7 */ + union { + struct { + unsigned int clock_base:1; /* TOD clock base set */ + unsigned int speed:1; /* CPU speed set */ + /* Measurement alerts */ + unsigned int mtda:1; /* Loss of MT ctr. data alert */ + unsigned int caca:1; /* Counter auth. change alert */ + unsigned int lcda:1; /* Loss of counter data alert */ + }; + unsigned long flags; /* 0-63 All indicators */ + }; + /* 8 - 15 */ + unsigned int cfvn:16; /* 64-79 Ctr First Version */ + unsigned int csvn:16; /* 80-95 Ctr Second Version */ + unsigned int cpu_speed:32; /* 96-127 CPU speed */ + /* 16 - 23 */ + unsigned long timestamp; /* 128-191 Timestamp (TOD) */ + /* 24 - 55 */ + union { + struct { + unsigned long progusage1; + unsigned long progusage2; + unsigned long progusage3; + unsigned long tod_base; + }; + unsigned long progusage[4]; + }; + /* 56 - 63 */ + unsigned int mach_type:16; /* Machine type */ + unsigned int res1:16; /* Reserved */ + unsigned int res2:32; /* Reserved */ +}; + +/* Create the trailer data at the end of a page. */ +static void cf_diag_trailer(struct cf_trailer_entry *te) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + struct cpuid cpuid; + + te->cfvn = cpuhw->info.cfvn; /* Counter version numbers */ + te->csvn = cpuhw->info.csvn; + + get_cpu_id(&cpuid); /* Machine type */ + te->mach_type = cpuid.machine; + te->cpu_speed = cf_diag_cpu_speed; + if (te->cpu_speed) + te->speed = 1; + te->clock_base = 1; /* Save clock base */ + memcpy(&te->tod_base, &tod_clock_base[1], 8); + store_tod_clock((__u64 *)&te->timestamp); +} + +/* + * Change the CPUMF state to active. + * Enable and activate the CPU-counter sets according + * to the per-cpu control state. + */ +static void cf_diag_enable(struct pmu *pmu) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + int err; + + debug_sprintf_event(cf_diag_dbg, 5, + "%s pmu %p cpu %d flags %#x state %#llx\n", + __func__, pmu, smp_processor_id(), cpuhw->flags, + cpuhw->state); + if (cpuhw->flags & PMU_F_ENABLED) + return; + + err = lcctl(cpuhw->state); + if (err) { + pr_err("Enabling the performance measuring unit " + "failed with rc=%x\n", err); + return; + } + cpuhw->flags |= PMU_F_ENABLED; +} + +/* + * Change the CPUMF state to inactive. + * Disable and enable (inactive) the CPU-counter sets according + * to the per-cpu control state. + */ +static void cf_diag_disable(struct pmu *pmu) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + u64 inactive; + int err; + + debug_sprintf_event(cf_diag_dbg, 5, + "%s pmu %p cpu %d flags %#x state %#llx\n", + __func__, pmu, smp_processor_id(), cpuhw->flags, + cpuhw->state); + if (!(cpuhw->flags & PMU_F_ENABLED)) + return; + + inactive = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1); + err = lcctl(inactive); + if (err) { + pr_err("Disabling the performance measuring unit " + "failed with rc=%x\n", err); + return; + } + cpuhw->flags &= ~PMU_F_ENABLED; +} + +/* Number of perf events counting hardware events */ +static atomic_t cf_diag_events = ATOMIC_INIT(0); + +/* Release the PMU if event is the last perf event */ +static void cf_diag_perf_event_destroy(struct perf_event *event) +{ + debug_sprintf_event(cf_diag_dbg, 5, + "%s event %p cpu %d cf_diag_events %d\n", + __func__, event, event->cpu, + atomic_read(&cf_diag_events)); + if (atomic_dec_return(&cf_diag_events) == 0) + __kernel_cpumcf_end(); +} + +/* Setup the event. Test for authorized counter sets and only include counter + * sets which are authorized at the time of the setup. Including unauthorized + * counter sets result in specification exception (and panic). + */ +static int __hw_perf_event_init(struct perf_event *event) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + struct perf_event_attr *attr = &event->attr; + enum cpumf_ctr_set i; + int err = 0; + + debug_sprintf_event(cf_diag_dbg, 5, + "%s event %p cpu %d authorized %#x\n", __func__, + event, event->cpu, cpuhw->info.auth_ctl); + + event->hw.config = attr->config; + event->hw.config_base = 0; + local64_set(&event->count, 0); + + /* Add all authorized counter sets to config_base */ + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) + if (cpuhw->info.auth_ctl & cpumf_ctr_ctl[i]) + event->hw.config_base |= cpumf_ctr_ctl[i]; + + /* No authorized counter sets, nothing to count/sample */ + if (!event->hw.config_base) { + err = -EINVAL; + goto out; + } + + /* Set sample_period to indicate sampling */ + event->hw.sample_period = attr->sample_period; + local64_set(&event->hw.period_left, event->hw.sample_period); + event->hw.last_period = event->hw.sample_period; +out: + debug_sprintf_event(cf_diag_dbg, 5, "%s err %d config_base %#lx\n", + __func__, err, event->hw.config_base); + return err; +} + +static int cf_diag_event_init(struct perf_event *event) +{ + struct perf_event_attr *attr = &event->attr; + int err = -ENOENT; + + debug_sprintf_event(cf_diag_dbg, 5, + "%s event %p cpu %d config %#llx " + "sample_type %#llx cf_diag_events %d\n", __func__, + event, event->cpu, attr->config, attr->sample_type, + atomic_read(&cf_diag_events)); + + if (event->attr.config != PERF_EVENT_CPUM_CF_DIAG || + event->attr.type != PERF_TYPE_RAW) + goto out; + + /* Raw events are used to access counters directly, + * hence do not permit excludes. + * This event is usesless without PERF_SAMPLE_RAW to return counter set + * values as raw data. + */ + if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv || + !(attr->sample_type & (PERF_SAMPLE_CPU | PERF_SAMPLE_RAW))) { + err = -EOPNOTSUPP; + goto out; + } + + /* Initialize for using the CPU-measurement counter facility */ + if (atomic_inc_return(&cf_diag_events) == 1) { + if (__kernel_cpumcf_begin()) { + atomic_dec(&cf_diag_events); + err = -EBUSY; + goto out; + } + } + event->destroy = cf_diag_perf_event_destroy; + + err = __hw_perf_event_init(event); + if (unlikely(err)) + event->destroy(event); +out: + debug_sprintf_event(cf_diag_dbg, 5, "%s err %d\n", __func__, err); + return err; +} + +static void cf_diag_read(struct perf_event *event) +{ + debug_sprintf_event(cf_diag_dbg, 5, "%s event %p\n", __func__, event); +} + +/* Return the maximum possible counter set size (in number of 8 byte counters) + * depending on type and model number. + */ +static size_t cf_diag_ctrset_size(enum cpumf_ctr_set ctrset, + struct cpumf_ctr_info *info) +{ + size_t ctrset_size = 0; + + switch (ctrset) { + case CPUMF_CTR_SET_BASIC: + if (info->cfvn >= 1) + ctrset_size = 6; + break; + case CPUMF_CTR_SET_USER: + if (info->cfvn == 1) + ctrset_size = 6; + else if (info->cfvn >= 3) + ctrset_size = 2; + break; + case CPUMF_CTR_SET_CRYPTO: + ctrset_size = 16; + break; + case CPUMF_CTR_SET_EXT: + if (info->csvn == 1) + ctrset_size = 32; + else if (info->csvn == 2) + ctrset_size = 48; + else if (info->csvn >= 3) + ctrset_size = 128; + break; + case CPUMF_CTR_SET_MT_DIAG: + if (info->csvn > 3) + ctrset_size = 48; + break; + case CPUMF_CTR_SET_MAX: + break; + } + + return ctrset_size; +} + +/* Calculate memory needed to store all counter sets together with header and + * trailer data. This is independend of the counter set authorization which + * can vary depending on the configuration. + */ +static size_t cf_diag_ctrset_maxsize(struct cpumf_ctr_info *info) +{ + size_t max_size = sizeof(struct cf_trailer_entry); + enum cpumf_ctr_set i; + + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { + size_t size = cf_diag_ctrset_size(i, info); + + if (size) + max_size += size * sizeof(u64) + + sizeof(struct cf_ctrset_entry); + } + debug_sprintf_event(cf_diag_dbg, 5, "%s max_size %zu\n", __func__, + max_size); + + return max_size; +} + +/* Read a counter set. The counter set number determines which counter set and + * the CPUM-CF first and second version number determine the number of + * available counters in this counter set. + * Each counter set starts with header containing the counter set number and + * the number of 8 byte counters. + * + * The functions returns the number of bytes occupied by this counter set + * including the header. + * If there is no counter in the counter set, this counter set is useless and + * zero is returned on this case. + */ +static size_t cf_diag_getctrset(struct cf_ctrset_entry *ctrdata, int ctrset, + size_t room) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + size_t ctrset_size, need = 0; + int rc = 3; /* Assume write failure */ + + ctrdata->def = CF_DIAG_CTRSET_DEF; + ctrdata->set = ctrset; + ctrdata->res1 = 0; + ctrset_size = cf_diag_ctrset_size(ctrset, &cpuhw->info); + + if (ctrset_size) { /* Save data */ + need = ctrset_size * sizeof(u64) + sizeof(*ctrdata); + if (need <= room) + rc = ctr_stcctm(ctrset, ctrset_size, + (u64 *)(ctrdata + 1)); + if (rc != 3) + ctrdata->ctr = ctrset_size; + else + need = 0; + } + + debug_sprintf_event(cf_diag_dbg, 6, + "%s ctrset %d ctrset_size %zu cfvn %d csvn %d" + " need %zd rc:%d\n", + __func__, ctrset, ctrset_size, cpuhw->info.cfvn, + cpuhw->info.csvn, need, rc); + return need; +} + +/* Read out all counter sets and save them in the provided data buffer. + * The last 64 byte host an artificial trailer entry. + */ +static size_t cf_diag_getctr(void *data, size_t sz, unsigned long auth) +{ + struct cf_trailer_entry *trailer; + size_t offset = 0, done; + int i; + + memset(data, 0, sz); + sz -= sizeof(*trailer); /* Always room for trailer */ + for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) { + struct cf_ctrset_entry *ctrdata = data + offset; + + if (!(auth & cpumf_ctr_ctl[i])) + continue; /* Counter set not authorized */ + + done = cf_diag_getctrset(ctrdata, i, sz - offset); + offset += done; + debug_sprintf_event(cf_diag_dbg, 6, + "%s ctrset %d offset %zu done %zu\n", + __func__, i, offset, done); + } + trailer = data + offset; + cf_diag_trailer(trailer); + return offset + sizeof(*trailer); +} + +/* Calculate the difference for each counter in a counter set. */ +static void cf_diag_diffctrset(u64 *pstart, u64 *pstop, int counters) +{ + for (; --counters >= 0; ++pstart, ++pstop) + if (*pstop >= *pstart) + *pstop -= *pstart; + else + *pstop = *pstart - *pstop; +} + +/* Scan the counter sets and calculate the difference of each counter + * in each set. The result is the increment of each counter during the + * period the counter set has been activated. + * + * Return true on success. + */ +static int cf_diag_diffctr(struct cf_diag_csd *csd, unsigned long auth) +{ + struct cf_trailer_entry *trailer_start, *trailer_stop; + struct cf_ctrset_entry *ctrstart, *ctrstop; + size_t offset = 0; + + auth &= (1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1; + do { + ctrstart = (struct cf_ctrset_entry *)(csd->start + offset); + ctrstop = (struct cf_ctrset_entry *)(csd->data + offset); + + if (memcmp(ctrstop, ctrstart, sizeof(*ctrstop))) { + pr_err("cpum_cf_diag counter set compare error " + "in set %i\n", ctrstart->set); + return 0; + } + auth &= ~cpumf_ctr_ctl[ctrstart->set]; + if (ctrstart->def == CF_DIAG_CTRSET_DEF) { + cf_diag_diffctrset((u64 *)(ctrstart + 1), + (u64 *)(ctrstop + 1), ctrstart->ctr); + offset += ctrstart->ctr * sizeof(u64) + + sizeof(*ctrstart); + } + debug_sprintf_event(cf_diag_dbg, 6, + "%s set %d ctr %d offset %zu auth %lx\n", + __func__, ctrstart->set, ctrstart->ctr, + offset, auth); + } while (ctrstart->def && auth); + + /* Save time_stamp from start of event in stop's trailer */ + trailer_start = (struct cf_trailer_entry *)(csd->start + offset); + trailer_stop = (struct cf_trailer_entry *)(csd->data + offset); + trailer_stop->progusage[0] = trailer_start->timestamp; + + return 1; +} + +/* Create perf event sample with the counter sets as raw data. The sample + * is then pushed to the event subsystem and the function checks for + * possible event overflows. If an event overflow occurs, the PMU is + * stopped. + * + * Return non-zero if an event overflow occurred. + */ +static int cf_diag_push_sample(struct perf_event *event, + struct cf_diag_csd *csd) +{ + struct perf_sample_data data; + struct perf_raw_record raw; + struct pt_regs regs; + int overflow; + + /* Setup perf sample */ + perf_sample_data_init(&data, 0, event->hw.last_period); + memset(&regs, 0, sizeof(regs)); + memset(&raw, 0, sizeof(raw)); + + if (event->attr.sample_type & PERF_SAMPLE_CPU) + data.cpu_entry.cpu = event->cpu; + if (event->attr.sample_type & PERF_SAMPLE_RAW) { + raw.frag.size = csd->used; + raw.frag.data = csd->data; + raw.size = csd->used; + data.raw = &raw; + } + + overflow = perf_event_overflow(event, &data, &regs); + debug_sprintf_event(cf_diag_dbg, 6, + "%s event %p cpu %d sample_type %#llx raw %d " + "ov %d\n", __func__, event, event->cpu, + event->attr.sample_type, raw.size, overflow); + if (overflow) + event->pmu->stop(event, 0); + + perf_event_update_userpage(event); + return overflow; +} + +static void cf_diag_start(struct perf_event *event, int flags) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + struct cf_diag_csd *csd = this_cpu_ptr(&cf_diag_csd); + struct hw_perf_event *hwc = &event->hw; + + debug_sprintf_event(cf_diag_dbg, 5, + "%s event %p cpu %d flags %#x hwc-state %#x\n", + __func__, event, event->cpu, flags, hwc->state); + if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED))) + return; + + /* (Re-)enable and activate all counter sets */ + lcctl(0); /* Reset counter sets */ + hwc->state = 0; + ctr_set_multiple_enable(&cpuhw->state, hwc->config_base); + lcctl(cpuhw->state); /* Enable counter sets */ + csd->used = cf_diag_getctr(csd->start, sizeof(csd->start), + event->hw.config_base); + ctr_set_multiple_start(&cpuhw->state, hwc->config_base); + /* Function cf_diag_enable() starts the counter sets. */ +} + +static void cf_diag_stop(struct perf_event *event, int flags) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + struct cf_diag_csd *csd = this_cpu_ptr(&cf_diag_csd); + struct hw_perf_event *hwc = &event->hw; + + debug_sprintf_event(cf_diag_dbg, 5, + "%s event %p cpu %d flags %#x hwc-state %#x\n", + __func__, event, event->cpu, flags, hwc->state); + + /* Deactivate all counter sets */ + ctr_set_multiple_stop(&cpuhw->state, hwc->config_base); + local64_inc(&event->count); + csd->used = cf_diag_getctr(csd->data, sizeof(csd->data), + event->hw.config_base); + if (cf_diag_diffctr(csd, event->hw.config_base)) + cf_diag_push_sample(event, csd); + hwc->state |= PERF_HES_STOPPED; +} + +static int cf_diag_add(struct perf_event *event, int flags) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + int err = 0; + + debug_sprintf_event(cf_diag_dbg, 5, + "%s event %p cpu %d flags %#x cpuhw:%p\n", + __func__, event, event->cpu, flags, cpuhw); + + if (cpuhw->flags & PMU_F_IN_USE) { + err = -EAGAIN; + goto out; + } + + event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED; + + cpuhw->flags |= PMU_F_IN_USE; + if (flags & PERF_EF_START) + cf_diag_start(event, PERF_EF_RELOAD); +out: + debug_sprintf_event(cf_diag_dbg, 5, "%s err %d\n", __func__, err); + return err; +} + +static void cf_diag_del(struct perf_event *event, int flags) +{ + struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events); + + debug_sprintf_event(cf_diag_dbg, 5, + "%s event %p cpu %d flags %#x\n", + __func__, event, event->cpu, flags); + + cf_diag_stop(event, PERF_EF_UPDATE); + ctr_set_multiple_stop(&cpuhw->state, event->hw.config_base); + ctr_set_multiple_disable(&cpuhw->state, event->hw.config_base); + cpuhw->flags &= ~PMU_F_IN_USE; +} + +CPUMF_EVENT_ATTR(CF_DIAG, CF_DIAG, PERF_EVENT_CPUM_CF_DIAG); + +static struct attribute *cf_diag_events_attr[] = { + CPUMF_EVENT_PTR(CF_DIAG, CF_DIAG), + NULL, +}; + +PMU_FORMAT_ATTR(event, "config:0-63"); + +static struct attribute *cf_diag_format_attr[] = { + &format_attr_event.attr, + NULL, +}; + +static struct attribute_group cf_diag_events_group = { + .name = "events", + .attrs = cf_diag_events_attr, +}; +static struct attribute_group cf_diag_format_group = { + .name = "format", + .attrs = cf_diag_format_attr, +}; +static const struct attribute_group *cf_diag_attr_groups[] = { + &cf_diag_events_group, + &cf_diag_format_group, + NULL, +}; + +/* Performance monitoring unit for s390x */ +static struct pmu cf_diag = { + .task_ctx_nr = perf_sw_context, + .pmu_enable = cf_diag_enable, + .pmu_disable = cf_diag_disable, + .event_init = cf_diag_event_init, + .add = cf_diag_add, + .del = cf_diag_del, + .start = cf_diag_start, + .stop = cf_diag_stop, + .read = cf_diag_read, + + .attr_groups = cf_diag_attr_groups +}; + +/* Get the CPU speed, try sampling facility first and CPU attributes second. */ +static void cf_diag_get_cpu_speed(void) +{ + if (cpum_sf_avail()) { /* Sampling facility first */ + struct hws_qsi_info_block si; + + memset(&si, 0, sizeof(si)); + if (!qsi(&si)) { + cf_diag_cpu_speed = si.cpu_speed; + return; + } + } + + if (test_facility(34)) { /* CPU speed extract static part */ + unsigned long mhz = __ecag(ECAG_CPU_ATTRIBUTE, 0); + + if (mhz != -1UL) + cf_diag_cpu_speed = mhz & 0xffffffff; + } +} + +/* Initialize the counter set PMU to generate complete counter set data as + * event raw data. This relies on the CPU Measurement Counter Facility device + * already being loaded and initialized. + */ +static int __init cf_diag_init(void) +{ + struct cpumf_ctr_info info; + size_t need; + int rc; + + if (!kernel_cpumcf_avail() || !stccm_avail() || qctri(&info)) + return -ENODEV; + cf_diag_get_cpu_speed(); + + /* Make sure the counter set data fits into predefined buffer. */ + need = cf_diag_ctrset_maxsize(&info); + if (need > sizeof(((struct cf_diag_csd *)0)->start)) { + pr_err("Insufficient memory for PMU(cpum_cf_diag) need=%zu\n", + need); + return -ENOMEM; + } + + /* Setup s390dbf facility */ + cf_diag_dbg = debug_register(KMSG_COMPONENT, 2, 1, 128); + if (!cf_diag_dbg) { + pr_err("Registration of s390dbf(cpum_cf_diag) failed\n"); + return -ENOMEM; + } + debug_register_view(cf_diag_dbg, &debug_sprintf_view); + + rc = perf_pmu_register(&cf_diag, "cpum_cf_diag", PERF_TYPE_RAW); + if (rc) { + debug_unregister_view(cf_diag_dbg, &debug_sprintf_view); + debug_unregister(cf_diag_dbg); + pr_err("Registration of PMU(cpum_cf_diag) failed with rc=%i\n", + rc); + } + return rc; +} +arch_initcall(cf_diag_init); diff --git a/arch/s390/kernel/perf_cpum_cf_events.c b/arch/s390/kernel/perf_cpum_cf_events.c @@ -6,6 +6,7 @@ #include <linux/slab.h> #include <linux/perf_event.h> +#include <asm/cpu_mf.h> /* BEGIN: CPUM_CF COUNTER DEFINITIONS =================================== */ diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c @@ -369,7 +369,7 @@ void __init arch_call_rest_init(void) : : [_frame] "a" (frame)); } -static void __init setup_lowcore(void) +static void __init setup_lowcore_dat_off(void) { struct lowcore *lc; @@ -380,19 +380,16 @@ static void __init setup_lowcore(void) lc = memblock_alloc_low(sizeof(*lc), sizeof(*lc)); lc->restart_psw.mask = PSW_KERNEL_BITS; lc->restart_psw.addr = (unsigned long) restart_int_handler; - lc->external_new_psw.mask = PSW_KERNEL_BITS | - PSW_MASK_DAT | PSW_MASK_MCHECK; + lc->external_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; lc->external_new_psw.addr = (unsigned long) ext_int_handler; lc->svc_new_psw.mask = PSW_KERNEL_BITS | - PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK; + PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK; lc->svc_new_psw.addr = (unsigned long) system_call; - lc->program_new_psw.mask = PSW_KERNEL_BITS | - PSW_MASK_DAT | PSW_MASK_MCHECK; + lc->program_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; lc->program_new_psw.addr = (unsigned long) pgm_check_handler; lc->mcck_new_psw.mask = PSW_KERNEL_BITS; lc->mcck_new_psw.addr = (unsigned long) mcck_int_handler; - lc->io_new_psw.mask = PSW_KERNEL_BITS | - PSW_MASK_DAT | PSW_MASK_MCHECK; + lc->io_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; lc->io_new_psw.addr = (unsigned long) io_int_handler; lc->clock_comparator = clock_comparator_max; lc->nodat_stack = ((unsigned long) &init_thread_union) @@ -452,6 +449,16 @@ static void __init setup_lowcore(void) lowcore_ptr[0] = lc; } +static void __init setup_lowcore_dat_on(void) +{ + __ctl_clear_bit(0, 28); + S390_lowcore.external_new_psw.mask |= PSW_MASK_DAT; + S390_lowcore.svc_new_psw.mask |= PSW_MASK_DAT; + S390_lowcore.program_new_psw.mask |= PSW_MASK_DAT; + S390_lowcore.io_new_psw.mask |= PSW_MASK_DAT; + __ctl_set_bit(0, 28); +} + static struct resource code_resource = { .name = "Kernel code", .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM, @@ -794,18 +801,9 @@ static void __init reserve_kernel(void) { unsigned long start_pfn = PFN_UP(__pa(_end)); -#ifdef CONFIG_DMA_API_DEBUG - /* - * DMA_API_DEBUG code stumbles over addresses from the - * range [PARMAREA_END, _stext]. Mark the memory as reserved - * so it is not used for CONFIG_DMA_API_DEBUG=y. - */ - memblock_reserve(0, PFN_PHYS(start_pfn)); -#else memblock_reserve(0, PARMAREA_END); memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn) - (unsigned long)_stext); -#endif } static void __init setup_memory(void) @@ -990,6 +988,25 @@ static void __init setup_task_size(void) } /* + * Issue diagnose 318 to set the control program name and + * version codes. + */ +static void __init setup_control_program_code(void) +{ + union diag318_info diag318_info = { + .cpnc = CPNC_LINUX, + .cpvc_linux = 0, + .cpvc_distro = {0}, + }; + + if (!sclp.has_diag318) + return; + + diag_stat_inc(DIAG_STAT_X318); + asm volatile("diag %0,0,0x318\n" : : "d" (diag318_info.val)); +} + +/* * Setup function called from init/main.c just after the banner * was printed. */ @@ -1033,6 +1050,7 @@ void __init setup_arch(char **cmdline_p) os_info_init(); setup_ipl(); setup_task_size(); + setup_control_program_code(); /* Do some memory reservations *before* memory is added to memblock */ reserve_memory_end(); @@ -1072,7 +1090,7 @@ void __init setup_arch(char **cmdline_p) #endif setup_resources(); - setup_lowcore(); + setup_lowcore_dat_off(); smp_fill_possible_mask(); cpu_detect_mhz_feature(); cpu_init(); @@ -1085,6 +1103,12 @@ void __init setup_arch(char **cmdline_p) */ paging_init(); + /* + * After paging_init created the kernel page table, the new PSWs + * in lowcore can now run with DAT enabled. + */ + setup_lowcore_dat_on(); + /* Setup default console */ conmode_default(); set_preferred_console(); diff --git a/arch/s390/kernel/swsusp.S b/arch/s390/kernel/swsusp.S @@ -124,13 +124,13 @@ ENTRY(swsusp_arch_resume) lghi %r2,1 brasl %r14,arch_set_page_states - /* Deactivate DAT */ - stnsm __SF_EMPTY(%r15),0xfb - /* Set prefix page to zero */ xc __SF_EMPTY(4,%r15),__SF_EMPTY(%r15) spx __SF_EMPTY(%r15) + /* Deactivate DAT */ + stnsm __SF_EMPTY(%r15),0xfb + /* Restore saved image */ larl %r1,restore_pblist lg %r1,0(%r1) diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c @@ -58,6 +58,7 @@ out: return error; } +#ifdef CONFIG_SYSVIPC /* * sys_ipc() is the de-multiplexer for the SysV IPC calls. */ @@ -74,19 +75,28 @@ SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second, * Therefore we can call the generic variant by simply passing the * third parameter also as fifth parameter. */ - return sys_ipc(call, first, second, third, ptr, third); + return ksys_ipc(call, first, second, third, ptr, third); } +#endif /* CONFIG_SYSVIPC */ SYSCALL_DEFINE1(s390_personality, unsigned int, personality) { - unsigned int ret; + unsigned int ret = current->personality; if (personality(current->personality) == PER_LINUX32 && personality(personality) == PER_LINUX) personality |= PER_LINUX32; - ret = sys_personality(personality); + + if (personality != 0xffffffff) + set_personality(personality); + if (personality(ret) == PER_LINUX32) ret &= ~PER_LINUX32; return ret; } + +SYSCALL_DEFINE0(ni_syscall) +{ + return -ENOSYS; +} diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl @@ -15,86 +15,86 @@ 5 common open sys_open compat_sys_open 6 common close sys_close sys_close 7 common restart_syscall sys_restart_syscall sys_restart_syscall -8 common creat sys_creat compat_sys_creat -9 common link sys_link compat_sys_link -10 common unlink sys_unlink compat_sys_unlink +8 common creat sys_creat sys_creat +9 common link sys_link sys_link +10 common unlink sys_unlink sys_unlink 11 common execve sys_execve compat_sys_execve -12 common chdir sys_chdir compat_sys_chdir +12 common chdir sys_chdir sys_chdir 13 32 time - compat_sys_time -14 common mknod sys_mknod compat_sys_mknod -15 common chmod sys_chmod compat_sys_chmod -16 32 lchown - compat_sys_s390_lchown16 +14 common mknod sys_mknod sys_mknod +15 common chmod sys_chmod sys_chmod +16 32 lchown - sys_lchown16 19 common lseek sys_lseek compat_sys_lseek 20 common getpid sys_getpid sys_getpid 21 common mount sys_mount compat_sys_mount -22 common umount sys_oldumount compat_sys_oldumount -23 32 setuid - compat_sys_s390_setuid16 -24 32 getuid - compat_sys_s390_getuid16 +22 common umount sys_oldumount sys_oldumount +23 32 setuid - sys_setuid16 +24 32 getuid - sys_getuid16 25 32 stime - compat_sys_stime 26 common ptrace sys_ptrace compat_sys_ptrace 27 common alarm sys_alarm sys_alarm 29 common pause sys_pause sys_pause 30 common utime sys_utime compat_sys_utime -33 common access sys_access compat_sys_access +33 common access sys_access sys_access 34 common nice sys_nice sys_nice 36 common sync sys_sync sys_sync 37 common kill sys_kill sys_kill -38 common rename sys_rename compat_sys_rename -39 common mkdir sys_mkdir compat_sys_mkdir -40 common rmdir sys_rmdir compat_sys_rmdir +38 common rename sys_rename sys_rename +39 common mkdir sys_mkdir sys_mkdir +40 common rmdir sys_rmdir sys_rmdir 41 common dup sys_dup sys_dup -42 common pipe sys_pipe compat_sys_pipe +42 common pipe sys_pipe sys_pipe 43 common times sys_times compat_sys_times -45 common brk sys_brk compat_sys_brk -46 32 setgid - compat_sys_s390_setgid16 -47 32 getgid - compat_sys_s390_getgid16 -48 common signal sys_signal compat_sys_signal -49 32 geteuid - compat_sys_s390_geteuid16 -50 32 getegid - compat_sys_s390_getegid16 -51 common acct sys_acct compat_sys_acct -52 common umount2 sys_umount compat_sys_umount +45 common brk sys_brk sys_brk +46 32 setgid - sys_setgid16 +47 32 getgid - sys_getgid16 +48 common signal sys_signal sys_signal +49 32 geteuid - sys_geteuid16 +50 32 getegid - sys_getegid16 +51 common acct sys_acct sys_acct +52 common umount2 sys_umount sys_umount 54 common ioctl sys_ioctl compat_sys_ioctl 55 common fcntl sys_fcntl compat_sys_fcntl 57 common setpgid sys_setpgid sys_setpgid 60 common umask sys_umask sys_umask -61 common chroot sys_chroot compat_sys_chroot +61 common chroot sys_chroot sys_chroot 62 common ustat sys_ustat compat_sys_ustat 63 common dup2 sys_dup2 sys_dup2 64 common getppid sys_getppid sys_getppid 65 common getpgrp sys_getpgrp sys_getpgrp 66 common setsid sys_setsid sys_setsid 67 common sigaction sys_sigaction compat_sys_sigaction -70 32 setreuid - compat_sys_s390_setreuid16 -71 32 setregid - compat_sys_s390_setregid16 -72 common sigsuspend sys_sigsuspend compat_sys_sigsuspend +70 32 setreuid - sys_setreuid16 +71 32 setregid - sys_setregid16 +72 common sigsuspend sys_sigsuspend sys_sigsuspend 73 common sigpending sys_sigpending compat_sys_sigpending -74 common sethostname sys_sethostname compat_sys_sethostname +74 common sethostname sys_sethostname sys_sethostname 75 common setrlimit sys_setrlimit compat_sys_setrlimit 76 32 getrlimit - compat_sys_old_getrlimit 77 common getrusage sys_getrusage compat_sys_getrusage 78 common gettimeofday sys_gettimeofday compat_sys_gettimeofday 79 common settimeofday sys_settimeofday compat_sys_settimeofday -80 32 getgroups - compat_sys_s390_getgroups16 -81 32 setgroups - compat_sys_s390_setgroups16 -83 common symlink sys_symlink compat_sys_symlink -85 common readlink sys_readlink compat_sys_readlink -86 common uselib sys_uselib compat_sys_uselib -87 common swapon sys_swapon compat_sys_swapon -88 common reboot sys_reboot compat_sys_reboot +80 32 getgroups - sys_getgroups16 +81 32 setgroups - sys_setgroups16 +83 common symlink sys_symlink sys_symlink +85 common readlink sys_readlink sys_readlink +86 common uselib sys_uselib sys_uselib +87 common swapon sys_swapon sys_swapon +88 common reboot sys_reboot sys_reboot 89 common readdir - compat_sys_old_readdir 90 common mmap sys_old_mmap compat_sys_s390_old_mmap -91 common munmap sys_munmap compat_sys_munmap +91 common munmap sys_munmap sys_munmap 92 common truncate sys_truncate compat_sys_truncate 93 common ftruncate sys_ftruncate compat_sys_ftruncate 94 common fchmod sys_fchmod sys_fchmod -95 32 fchown - compat_sys_s390_fchown16 +95 32 fchown - sys_fchown16 96 common getpriority sys_getpriority sys_getpriority 97 common setpriority sys_setpriority sys_setpriority 99 common statfs sys_statfs compat_sys_statfs 100 common fstatfs sys_fstatfs compat_sys_fstatfs 101 32 ioperm - - 102 common socketcall sys_socketcall compat_sys_socketcall -103 common syslog sys_syslog compat_sys_syslog +103 common syslog sys_syslog sys_syslog 104 common setitimer sys_setitimer compat_sys_setitimer 105 common getitimer sys_getitimer compat_sys_getitimer 106 common stat sys_newstat compat_sys_newstat @@ -104,63 +104,63 @@ 111 common vhangup sys_vhangup sys_vhangup 112 common idle - - 114 common wait4 sys_wait4 compat_sys_wait4 -115 common swapoff sys_swapoff compat_sys_swapoff +115 common swapoff sys_swapoff sys_swapoff 116 common sysinfo sys_sysinfo compat_sys_sysinfo 117 common ipc sys_s390_ipc compat_sys_s390_ipc 118 common fsync sys_fsync sys_fsync 119 common sigreturn sys_sigreturn compat_sys_sigreturn -120 common clone sys_clone compat_sys_clone -121 common setdomainname sys_setdomainname compat_sys_setdomainname -122 common uname sys_newuname compat_sys_newuname +120 common clone sys_clone sys_clone +121 common setdomainname sys_setdomainname sys_setdomainname +122 common uname sys_newuname sys_newuname 124 common adjtimex sys_adjtimex compat_sys_adjtimex -125 common mprotect sys_mprotect compat_sys_mprotect +125 common mprotect sys_mprotect sys_mprotect 126 common sigprocmask sys_sigprocmask compat_sys_sigprocmask 127 common create_module - - -128 common init_module sys_init_module compat_sys_init_module -129 common delete_module sys_delete_module compat_sys_delete_module +128 common init_module sys_init_module sys_init_module +129 common delete_module sys_delete_module sys_delete_module 130 common get_kernel_syms - - -131 common quotactl sys_quotactl compat_sys_quotactl +131 common quotactl sys_quotactl sys_quotactl 132 common getpgid sys_getpgid sys_getpgid 133 common fchdir sys_fchdir sys_fchdir -134 common bdflush sys_bdflush compat_sys_bdflush -135 common sysfs sys_sysfs compat_sys_sysfs +134 common bdflush sys_bdflush sys_bdflush +135 common sysfs sys_sysfs sys_sysfs 136 common personality sys_s390_personality sys_s390_personality 137 common afs_syscall - - -138 32 setfsuid - compat_sys_s390_setfsuid16 -139 32 setfsgid - compat_sys_s390_setfsgid16 -140 32 _llseek - compat_sys_llseek +138 32 setfsuid - sys_setfsuid16 +139 32 setfsgid - sys_setfsgid16 +140 32 _llseek - sys_llseek 141 common getdents sys_getdents compat_sys_getdents 142 32 _newselect - compat_sys_select 142 64 select sys_select - 143 common flock sys_flock sys_flock -144 common msync sys_msync compat_sys_msync +144 common msync sys_msync sys_msync 145 common readv sys_readv compat_sys_readv 146 common writev sys_writev compat_sys_writev 147 common getsid sys_getsid sys_getsid 148 common fdatasync sys_fdatasync sys_fdatasync 149 common _sysctl sys_sysctl compat_sys_sysctl -150 common mlock sys_mlock compat_sys_mlock -151 common munlock sys_munlock compat_sys_munlock +150 common mlock sys_mlock sys_mlock +151 common munlock sys_munlock sys_munlock 152 common mlockall sys_mlockall sys_mlockall 153 common munlockall sys_munlockall sys_munlockall -154 common sched_setparam sys_sched_setparam compat_sys_sched_setparam -155 common sched_getparam sys_sched_getparam compat_sys_sched_getparam -156 common sched_setscheduler sys_sched_setscheduler compat_sys_sched_setscheduler +154 common sched_setparam sys_sched_setparam sys_sched_setparam +155 common sched_getparam sys_sched_getparam sys_sched_getparam +156 common sched_setscheduler sys_sched_setscheduler sys_sched_setscheduler 157 common sched_getscheduler sys_sched_getscheduler sys_sched_getscheduler 158 common sched_yield sys_sched_yield sys_sched_yield 159 common sched_get_priority_max sys_sched_get_priority_max sys_sched_get_priority_max 160 common sched_get_priority_min sys_sched_get_priority_min sys_sched_get_priority_min 161 common sched_rr_get_interval sys_sched_rr_get_interval compat_sys_sched_rr_get_interval 162 common nanosleep sys_nanosleep compat_sys_nanosleep -163 common mremap sys_mremap compat_sys_mremap -164 32 setresuid - compat_sys_s390_setresuid16 -165 32 getresuid - compat_sys_s390_getresuid16 +163 common mremap sys_mremap sys_mremap +164 32 setresuid - sys_setresuid16 +165 32 getresuid - sys_getresuid16 167 common query_module - - -168 common poll sys_poll compat_sys_poll +168 common poll sys_poll sys_poll 169 common nfsservctl - - -170 32 setresgid - compat_sys_s390_setresgid16 -171 32 getresgid - compat_sys_s390_getresgid16 -172 common prctl sys_prctl compat_sys_prctl +170 32 setresgid - sys_setresgid16 +171 32 getresgid - sys_getresgid16 +172 common prctl sys_prctl sys_prctl 173 common rt_sigreturn sys_rt_sigreturn compat_sys_rt_sigreturn 174 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction 175 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask @@ -170,10 +170,10 @@ 179 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend 180 common pread64 sys_pread64 compat_sys_s390_pread64 181 common pwrite64 sys_pwrite64 compat_sys_s390_pwrite64 -182 32 chown - compat_sys_s390_chown16 -183 common getcwd sys_getcwd compat_sys_getcwd -184 common capget sys_capget compat_sys_capget -185 common capset sys_capset compat_sys_capset +182 32 chown - sys_chown16 +183 common getcwd sys_getcwd sys_getcwd +184 common capget sys_capget sys_capget +185 common capset sys_capset sys_capset 186 common sigaltstack sys_sigaltstack compat_sys_sigaltstack 187 common sendfile sys_sendfile64 compat_sys_sendfile 188 common getpmsg - - @@ -187,7 +187,7 @@ 195 32 stat64 - compat_sys_s390_stat64 196 32 lstat64 - compat_sys_s390_lstat64 197 32 fstat64 - compat_sys_s390_fstat64 -198 32 lchown32 - compat_sys_lchown +198 32 lchown32 - sys_lchown 198 64 lchown sys_lchown - 199 32 getuid32 - sys_getuid 199 64 getuid sys_getuid - @@ -201,21 +201,21 @@ 203 64 setreuid sys_setreuid - 204 32 setregid32 - sys_setregid 204 64 setregid sys_setregid - -205 32 getgroups32 - compat_sys_getgroups +205 32 getgroups32 - sys_getgroups 205 64 getgroups sys_getgroups - -206 32 setgroups32 - compat_sys_setgroups +206 32 setgroups32 - sys_setgroups 206 64 setgroups sys_setgroups - 207 32 fchown32 - sys_fchown 207 64 fchown sys_fchown - 208 32 setresuid32 - sys_setresuid 208 64 setresuid sys_setresuid - -209 32 getresuid32 - compat_sys_getresuid +209 32 getresuid32 - sys_getresuid 209 64 getresuid sys_getresuid - 210 32 setresgid32 - sys_setresgid 210 64 setresgid sys_setresgid - -211 32 getresgid32 - compat_sys_getresgid +211 32 getresgid32 - sys_getresgid 211 64 getresgid sys_getresgid - -212 32 chown32 - compat_sys_chown +212 32 chown32 - sys_chown 212 64 chown sys_chown - 213 32 setuid32 - sys_setuid 213 64 setuid sys_setuid - @@ -225,25 +225,25 @@ 215 64 setfsuid sys_setfsuid - 216 32 setfsgid32 - sys_setfsgid 216 64 setfsgid sys_setfsgid - -217 common pivot_root sys_pivot_root compat_sys_pivot_root -218 common mincore sys_mincore compat_sys_mincore -219 common madvise sys_madvise compat_sys_madvise -220 common getdents64 sys_getdents64 compat_sys_getdents64 +217 common pivot_root sys_pivot_root sys_pivot_root +218 common mincore sys_mincore sys_mincore +219 common madvise sys_madvise sys_madvise +220 common getdents64 sys_getdents64 sys_getdents64 221 32 fcntl64 - compat_sys_fcntl64 222 common readahead sys_readahead compat_sys_s390_readahead 223 32 sendfile64 - compat_sys_sendfile64 -224 common setxattr sys_setxattr compat_sys_setxattr -225 common lsetxattr sys_lsetxattr compat_sys_lsetxattr -226 common fsetxattr sys_fsetxattr compat_sys_fsetxattr -227 common getxattr sys_getxattr compat_sys_getxattr -228 common lgetxattr sys_lgetxattr compat_sys_lgetxattr -229 common fgetxattr sys_fgetxattr compat_sys_fgetxattr -230 common listxattr sys_listxattr compat_sys_listxattr -231 common llistxattr sys_llistxattr compat_sys_llistxattr -232 common flistxattr sys_flistxattr compat_sys_flistxattr -233 common removexattr sys_removexattr compat_sys_removexattr -234 common lremovexattr sys_lremovexattr compat_sys_lremovexattr -235 common fremovexattr sys_fremovexattr compat_sys_fremovexattr +224 common setxattr sys_setxattr sys_setxattr +225 common lsetxattr sys_lsetxattr sys_lsetxattr +226 common fsetxattr sys_fsetxattr sys_fsetxattr +227 common getxattr sys_getxattr sys_getxattr +228 common lgetxattr sys_lgetxattr sys_lgetxattr +229 common fgetxattr sys_fgetxattr sys_fgetxattr +230 common listxattr sys_listxattr sys_listxattr +231 common llistxattr sys_llistxattr sys_llistxattr +232 common flistxattr sys_flistxattr sys_flistxattr +233 common removexattr sys_removexattr sys_removexattr +234 common lremovexattr sys_lremovexattr sys_lremovexattr +235 common fremovexattr sys_fremovexattr sys_fremovexattr 236 common gettid sys_gettid sys_gettid 237 common tkill sys_tkill sys_tkill 238 common futex sys_futex compat_sys_futex @@ -251,15 +251,15 @@ 240 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity 241 common tgkill sys_tgkill sys_tgkill 243 common io_setup sys_io_setup compat_sys_io_setup -244 common io_destroy sys_io_destroy compat_sys_io_destroy +244 common io_destroy sys_io_destroy sys_io_destroy 245 common io_getevents sys_io_getevents compat_sys_io_getevents 246 common io_submit sys_io_submit compat_sys_io_submit -247 common io_cancel sys_io_cancel compat_sys_io_cancel +247 common io_cancel sys_io_cancel sys_io_cancel 248 common exit_group sys_exit_group sys_exit_group 249 common epoll_create sys_epoll_create sys_epoll_create -250 common epoll_ctl sys_epoll_ctl compat_sys_epoll_ctl -251 common epoll_wait sys_epoll_wait compat_sys_epoll_wait -252 common set_tid_address sys_set_tid_address compat_sys_set_tid_address +250 common epoll_ctl sys_epoll_ctl sys_epoll_ctl +251 common epoll_wait sys_epoll_wait sys_epoll_wait +252 common set_tid_address sys_set_tid_address sys_set_tid_address 253 common fadvise64 sys_fadvise64_64 compat_sys_s390_fadvise64 254 common timer_create sys_timer_create compat_sys_timer_create 255 common timer_settime sys_timer_settime compat_sys_timer_settime @@ -273,52 +273,52 @@ 264 32 fadvise64_64 - compat_sys_s390_fadvise64_64 265 common statfs64 sys_statfs64 compat_sys_statfs64 266 common fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 -267 common remap_file_pages sys_remap_file_pages compat_sys_remap_file_pages +267 common remap_file_pages sys_remap_file_pages sys_remap_file_pages 268 common mbind sys_mbind compat_sys_mbind 269 common get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy 270 common set_mempolicy sys_set_mempolicy compat_sys_set_mempolicy 271 common mq_open sys_mq_open compat_sys_mq_open -272 common mq_unlink sys_mq_unlink compat_sys_mq_unlink +272 common mq_unlink sys_mq_unlink sys_mq_unlink 273 common mq_timedsend sys_mq_timedsend compat_sys_mq_timedsend 274 common mq_timedreceive sys_mq_timedreceive compat_sys_mq_timedreceive 275 common mq_notify sys_mq_notify compat_sys_mq_notify 276 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr 277 common kexec_load sys_kexec_load compat_sys_kexec_load -278 common add_key sys_add_key compat_sys_add_key -279 common request_key sys_request_key compat_sys_request_key +278 common add_key sys_add_key sys_add_key +279 common request_key sys_request_key sys_request_key 280 common keyctl sys_keyctl compat_sys_keyctl 281 common waitid sys_waitid compat_sys_waitid 282 common ioprio_set sys_ioprio_set sys_ioprio_set 283 common ioprio_get sys_ioprio_get sys_ioprio_get 284 common inotify_init sys_inotify_init sys_inotify_init -285 common inotify_add_watch sys_inotify_add_watch compat_sys_inotify_add_watch +285 common inotify_add_watch sys_inotify_add_watch sys_inotify_add_watch 286 common inotify_rm_watch sys_inotify_rm_watch sys_inotify_rm_watch 287 common migrate_pages sys_migrate_pages compat_sys_migrate_pages 288 common openat sys_openat compat_sys_openat -289 common mkdirat sys_mkdirat compat_sys_mkdirat -290 common mknodat sys_mknodat compat_sys_mknodat -291 common fchownat sys_fchownat compat_sys_fchownat +289 common mkdirat sys_mkdirat sys_mkdirat +290 common mknodat sys_mknodat sys_mknodat +291 common fchownat sys_fchownat sys_fchownat 292 common futimesat sys_futimesat compat_sys_futimesat 293 32 fstatat64 - compat_sys_s390_fstatat64 293 64 newfstatat sys_newfstatat - -294 common unlinkat sys_unlinkat compat_sys_unlinkat -295 common renameat sys_renameat compat_sys_renameat -296 common linkat sys_linkat compat_sys_linkat -297 common symlinkat sys_symlinkat compat_sys_symlinkat -298 common readlinkat sys_readlinkat compat_sys_readlinkat -299 common fchmodat sys_fchmodat compat_sys_fchmodat -300 common faccessat sys_faccessat compat_sys_faccessat +294 common unlinkat sys_unlinkat sys_unlinkat +295 common renameat sys_renameat sys_renameat +296 common linkat sys_linkat sys_linkat +297 common symlinkat sys_symlinkat sys_symlinkat +298 common readlinkat sys_readlinkat sys_readlinkat +299 common fchmodat sys_fchmodat sys_fchmodat +300 common faccessat sys_faccessat sys_faccessat 301 common pselect6 sys_pselect6 compat_sys_pselect6 302 common ppoll sys_ppoll compat_sys_ppoll -303 common unshare sys_unshare compat_sys_unshare +303 common unshare sys_unshare sys_unshare 304 common set_robust_list sys_set_robust_list compat_sys_set_robust_list 305 common get_robust_list sys_get_robust_list compat_sys_get_robust_list -306 common splice sys_splice compat_sys_splice +306 common splice sys_splice sys_splice 307 common sync_file_range sys_sync_file_range compat_sys_s390_sync_file_range -308 common tee sys_tee compat_sys_tee +308 common tee sys_tee sys_tee 309 common vmsplice sys_vmsplice compat_sys_vmsplice 310 common move_pages sys_move_pages compat_sys_move_pages -311 common getcpu sys_getcpu compat_sys_getcpu +311 common getcpu sys_getcpu sys_getcpu 312 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait 313 common utimes sys_utimes compat_sys_utimes 314 common fallocate sys_fallocate compat_sys_s390_fallocate @@ -332,17 +332,17 @@ 322 common signalfd4 sys_signalfd4 compat_sys_signalfd4 323 common eventfd2 sys_eventfd2 sys_eventfd2 324 common inotify_init1 sys_inotify_init1 sys_inotify_init1 -325 common pipe2 sys_pipe2 compat_sys_pipe2 +325 common pipe2 sys_pipe2 sys_pipe2 326 common dup3 sys_dup3 sys_dup3 327 common epoll_create1 sys_epoll_create1 sys_epoll_create1 328 common preadv sys_preadv compat_sys_preadv 329 common pwritev sys_pwritev compat_sys_pwritev 330 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo -331 common perf_event_open sys_perf_event_open compat_sys_perf_event_open +331 common perf_event_open sys_perf_event_open sys_perf_event_open 332 common fanotify_init sys_fanotify_init sys_fanotify_init 333 common fanotify_mark sys_fanotify_mark compat_sys_fanotify_mark -334 common prlimit64 sys_prlimit64 compat_sys_prlimit64 -335 common name_to_handle_at sys_name_to_handle_at compat_sys_name_to_handle_at +334 common prlimit64 sys_prlimit64 sys_prlimit64 +335 common name_to_handle_at sys_name_to_handle_at sys_name_to_handle_at 336 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at 337 common clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime 338 common syncfs sys_syncfs sys_syncfs @@ -350,44 +350,44 @@ 340 common process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv 341 common process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev 342 common s390_runtime_instr sys_s390_runtime_instr sys_s390_runtime_instr -343 common kcmp sys_kcmp compat_sys_kcmp -344 common finit_module sys_finit_module compat_sys_finit_module -345 common sched_setattr sys_sched_setattr compat_sys_sched_setattr -346 common sched_getattr sys_sched_getattr compat_sys_sched_getattr -347 common renameat2 sys_renameat2 compat_sys_renameat2 -348 common seccomp sys_seccomp compat_sys_seccomp -349 common getrandom sys_getrandom compat_sys_getrandom -350 common memfd_create sys_memfd_create compat_sys_memfd_create -351 common bpf sys_bpf compat_sys_bpf -352 common s390_pci_mmio_write sys_s390_pci_mmio_write compat_sys_s390_pci_mmio_write -353 common s390_pci_mmio_read sys_s390_pci_mmio_read compat_sys_s390_pci_mmio_read +343 common kcmp sys_kcmp sys_kcmp +344 common finit_module sys_finit_module sys_finit_module +345 common sched_setattr sys_sched_setattr sys_sched_setattr +346 common sched_getattr sys_sched_getattr sys_sched_getattr +347 common renameat2 sys_renameat2 sys_renameat2 +348 common seccomp sys_seccomp sys_seccomp +349 common getrandom sys_getrandom sys_getrandom +350 common memfd_create sys_memfd_create sys_memfd_create +351 common bpf sys_bpf sys_bpf +352 common s390_pci_mmio_write sys_s390_pci_mmio_write sys_s390_pci_mmio_write +353 common s390_pci_mmio_read sys_s390_pci_mmio_read sys_s390_pci_mmio_read 354 common execveat sys_execveat compat_sys_execveat 355 common userfaultfd sys_userfaultfd sys_userfaultfd 356 common membarrier sys_membarrier sys_membarrier 357 common recvmmsg sys_recvmmsg compat_sys_recvmmsg 358 common sendmmsg sys_sendmmsg compat_sys_sendmmsg 359 common socket sys_socket sys_socket -360 common socketpair sys_socketpair compat_sys_socketpair -361 common bind sys_bind compat_sys_bind -362 common connect sys_connect compat_sys_connect +360 common socketpair sys_socketpair sys_socketpair +361 common bind sys_bind sys_bind +362 common connect sys_connect sys_connect 363 common listen sys_listen sys_listen -364 common accept4 sys_accept4 compat_sys_accept4 +364 common accept4 sys_accept4 sys_accept4 365 common getsockopt sys_getsockopt compat_sys_getsockopt 366 common setsockopt sys_setsockopt compat_sys_setsockopt -367 common getsockname sys_getsockname compat_sys_getsockname -368 common getpeername sys_getpeername compat_sys_getpeername -369 common sendto sys_sendto compat_sys_sendto +367 common getsockname sys_getsockname sys_getsockname +368 common getpeername sys_getpeername sys_getpeername +369 common sendto sys_sendto sys_sendto 370 common sendmsg sys_sendmsg compat_sys_sendmsg 371 common recvfrom sys_recvfrom compat_sys_recvfrom 372 common recvmsg sys_recvmsg compat_sys_recvmsg 373 common shutdown sys_shutdown sys_shutdown -374 common mlock2 sys_mlock2 compat_sys_mlock2 -375 common copy_file_range sys_copy_file_range compat_sys_copy_file_range +374 common mlock2 sys_mlock2 sys_mlock2 +375 common copy_file_range sys_copy_file_range sys_copy_file_range 376 common preadv2 sys_preadv2 compat_sys_preadv2 377 common pwritev2 sys_pwritev2 compat_sys_pwritev2 -378 common s390_guarded_storage sys_s390_guarded_storage compat_sys_s390_guarded_storage -379 common statx sys_statx compat_sys_statx -380 common s390_sthyi sys_s390_sthyi compat_sys_s390_sthyi -381 common kexec_file_load sys_kexec_file_load compat_sys_kexec_file_load +378 common s390_guarded_storage sys_s390_guarded_storage sys_s390_guarded_storage +379 common statx sys_statx sys_statx +380 common s390_sthyi sys_s390_sthyi sys_s390_sthyi +381 common kexec_file_load sys_kexec_file_load sys_kexec_file_load 382 common io_pgetevents sys_io_pgetevents compat_sys_io_pgetevents -383 common rseq sys_rseq compat_sys_rseq +383 common rseq sys_rseq sys_rseq diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c @@ -545,8 +545,6 @@ static __init int stsi_init_debugfs(void) int lvl, i; stsi_root = debugfs_create_dir("stsi", arch_debugfs_dir); - if (IS_ERR_OR_NULL(stsi_root)) - return 0; lvl = stsi(NULL, 0, 0, 0); if (lvl > 0) stsi_0_0_0 = lvl; diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c @@ -69,7 +69,7 @@ static void update_mt_scaling(void) u64 delta, fac, mult, div; int i; - stcctm5(smp_cpu_mtid + 1, cycles_new); + stcctm(MT_DIAG, smp_cpu_mtid + 1, cycles_new); cycles_old = this_cpu_ptr(mt_cycles); fac = 1; mult = div = 0; @@ -432,6 +432,6 @@ void vtime_init(void) __this_cpu_write(mt_scaling_jiffies, jiffies); __this_cpu_write(mt_scaling_mult, 1); __this_cpu_write(mt_scaling_div, 1); - stcctm5(smp_cpu_mtid + 1, this_cpu_ptr(mt_cycles)); + stcctm(MT_DIAG, smp_cpu_mtid + 1, this_cpu_ptr(mt_cycles)); } } diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c @@ -43,11 +43,13 @@ static inline char *__strnend(const char *s, size_t n) * * returns the length of @s */ +#ifdef __HAVE_ARCH_STRLEN size_t strlen(const char *s) { return __strend(s) - s; } EXPORT_SYMBOL(strlen); +#endif /** * strnlen - Find the length of a length-limited string @@ -56,11 +58,13 @@ EXPORT_SYMBOL(strlen); * * returns the minimum of the length of @s and @n */ +#ifdef __HAVE_ARCH_STRNLEN size_t strnlen(const char *s, size_t n) { return __strnend(s, n) - s; } EXPORT_SYMBOL(strnlen); +#endif /** * strcpy - Copy a %NUL terminated string @@ -69,6 +73,7 @@ EXPORT_SYMBOL(strnlen); * * returns a pointer to @dest */ +#ifdef __HAVE_ARCH_STRCPY char *strcpy(char *dest, const char *src) { register int r0 asm("0") = 0; @@ -81,6 +86,7 @@ char *strcpy(char *dest, const char *src) return ret; } EXPORT_SYMBOL(strcpy); +#endif /** * strlcpy - Copy a %NUL terminated string into a sized buffer @@ -93,6 +99,7 @@ EXPORT_SYMBOL(strcpy); * of course, the buffer size is zero). It does not pad * out the result like strncpy() does. */ +#ifdef __HAVE_ARCH_STRLCPY size_t strlcpy(char *dest, const char *src, size_t size) { size_t ret = __strend(src) - src; @@ -105,6 +112,7 @@ size_t strlcpy(char *dest, const char *src, size_t size) return ret; } EXPORT_SYMBOL(strlcpy); +#endif /** * strncpy - Copy a length-limited, %NUL-terminated string @@ -115,6 +123,7 @@ EXPORT_SYMBOL(strlcpy); * The result is not %NUL-terminated if the source exceeds * @n bytes. */ +#ifdef __HAVE_ARCH_STRNCPY char *strncpy(char *dest, const char *src, size_t n) { size_t len = __strnend(src, n) - src; @@ -123,6 +132,7 @@ char *strncpy(char *dest, const char *src, size_t n) return dest; } EXPORT_SYMBOL(strncpy); +#endif /** * strcat - Append one %NUL-terminated string to another @@ -131,6 +141,7 @@ EXPORT_SYMBOL(strncpy); * * returns a pointer to @dest */ +#ifdef __HAVE_ARCH_STRCAT char *strcat(char *dest, const char *src) { register int r0 asm("0") = 0; @@ -146,6 +157,7 @@ char *strcat(char *dest, const char *src) return ret; } EXPORT_SYMBOL(strcat); +#endif /** * strlcat - Append a length-limited, %NUL-terminated string to another @@ -153,6 +165,7 @@ EXPORT_SYMBOL(strcat); * @src: The string to append to it * @n: The size of the destination buffer. */ +#ifdef __HAVE_ARCH_STRLCAT size_t strlcat(char *dest, const char *src, size_t n) { size_t dsize = __strend(dest) - dest; @@ -170,6 +183,7 @@ size_t strlcat(char *dest, const char *src, size_t n) return res; } EXPORT_SYMBOL(strlcat); +#endif /** * strncat - Append a length-limited, %NUL-terminated string to another @@ -182,6 +196,7 @@ EXPORT_SYMBOL(strlcat); * Note that in contrast to strncpy, strncat ensures the result is * terminated. */ +#ifdef __HAVE_ARCH_STRNCAT char *strncat(char *dest, const char *src, size_t n) { size_t len = __strnend(src, n) - src; @@ -192,6 +207,7 @@ char *strncat(char *dest, const char *src, size_t n) return dest; } EXPORT_SYMBOL(strncat); +#endif /** * strcmp - Compare two strings @@ -202,6 +218,7 @@ EXPORT_SYMBOL(strncat); * < 0 if @s1 is less than @s2 * > 0 if @s1 is greater than @s2 */ +#ifdef __HAVE_ARCH_STRCMP int strcmp(const char *s1, const char *s2) { register int r0 asm("0") = 0; @@ -219,12 +236,14 @@ int strcmp(const char *s1, const char *s2) return ret; } EXPORT_SYMBOL(strcmp); +#endif /** * strrchr - Find the last occurrence of a character in a string * @s: The string to be searched * @c: The character to search for */ +#ifdef __HAVE_ARCH_STRRCHR char *strrchr(const char *s, int c) { size_t len = __strend(s) - s; @@ -237,6 +256,7 @@ char *strrchr(const char *s, int c) return NULL; } EXPORT_SYMBOL(strrchr); +#endif static inline int clcle(const char *s1, unsigned long l1, const char *s2, unsigned long l2) @@ -261,6 +281,7 @@ static inline int clcle(const char *s1, unsigned long l1, * @s1: The string to be searched * @s2: The string to search for */ +#ifdef __HAVE_ARCH_STRSTR char *strstr(const char *s1, const char *s2) { int l1, l2; @@ -280,6 +301,7 @@ char *strstr(const char *s1, const char *s2) return NULL; } EXPORT_SYMBOL(strstr); +#endif /** * memchr - Find a character in an area of memory. @@ -290,6 +312,7 @@ EXPORT_SYMBOL(strstr); * returns the address of the first occurrence of @c, or %NULL * if @c is not found */ +#ifdef __HAVE_ARCH_MEMCHR void *memchr(const void *s, int c, size_t n) { register int r0 asm("0") = (char) c; @@ -304,6 +327,7 @@ void *memchr(const void *s, int c, size_t n) return (void *) ret; } EXPORT_SYMBOL(memchr); +#endif /** * memcmp - Compare two areas of memory @@ -311,6 +335,7 @@ EXPORT_SYMBOL(memchr); * @s2: Another area of memory * @count: The size of the area. */ +#ifdef __HAVE_ARCH_MEMCMP int memcmp(const void *s1, const void *s2, size_t n) { int ret; @@ -321,6 +346,7 @@ int memcmp(const void *s1, const void *s2, size_t n) return ret; } EXPORT_SYMBOL(memcmp); +#endif /** * memscan - Find a character in an area of memory. @@ -331,6 +357,7 @@ EXPORT_SYMBOL(memcmp); * returns the address of the first occurrence of @c, or 1 byte past * the area if @c is not found */ +#ifdef __HAVE_ARCH_MEMSCAN void *memscan(void *s, int c, size_t n) { register int r0 asm("0") = (char) c; @@ -342,3 +369,4 @@ void *memscan(void *s, int c, size_t n) return (void *) ret; } EXPORT_SYMBOL(memscan); +#endif diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c @@ -28,12 +28,7 @@ #include <asm/cpcmd.h> #include <asm/setup.h> -#define DCSS_LOADSHR 0x00 -#define DCSS_LOADNSR 0x04 #define DCSS_PURGESEG 0x08 -#define DCSS_FINDSEG 0x0c -#define DCSS_LOADNOLY 0x10 -#define DCSS_SEGEXT 0x18 #define DCSS_LOADSHRX 0x20 #define DCSS_LOADNSRX 0x24 #define DCSS_FINDSEGX 0x2c @@ -53,20 +48,6 @@ struct qout64 { struct qrange range[6]; }; -struct qrange_old { - unsigned int start; /* last byte type */ - unsigned int end; /* last byte reserved */ -}; - -/* output area format for the Diag x'64' old subcode x'18' */ -struct qout64_old { - int segstart; - int segend; - int segcnt; - int segrcnt; - struct qrange_old range[6]; -}; - struct qin64 { char qopcode; char rsrv1[3]; @@ -95,52 +76,10 @@ static DEFINE_MUTEX(dcss_lock); static LIST_HEAD(dcss_list); static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", "EW/EN-MIXED" }; -static int loadshr_scode, loadnsr_scode; -static int segext_scode, purgeseg_scode; -static int scode_set; - -/* set correct Diag x'64' subcodes. */ -static int -dcss_set_subcodes(void) -{ - char *name = kmalloc(8, GFP_KERNEL | GFP_DMA); - unsigned long rx, ry; - int rc; - - if (name == NULL) - return -ENOMEM; - - rx = (unsigned long) name; - ry = DCSS_FINDSEGX; - - strcpy(name, "dummy"); - diag_stat_inc(DIAG_STAT_X064); - asm volatile( - " diag %0,%1,0x64\n" - "0: ipm %2\n" - " srl %2,28\n" - " j 2f\n" - "1: la %2,3\n" - "2:\n" - EX_TABLE(0b, 1b) - : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc", "memory"); - - kfree(name); - /* Diag x'64' new subcodes are supported, set to new subcodes */ - if (rc != 3) { - loadshr_scode = DCSS_LOADSHRX; - loadnsr_scode = DCSS_LOADNSRX; - purgeseg_scode = DCSS_PURGESEG; - segext_scode = DCSS_SEGEXTX; - return 0; - } - /* Diag x'64' new subcodes are not supported, set to old subcodes */ - loadshr_scode = DCSS_LOADNOLY; - loadnsr_scode = DCSS_LOADNSR; - purgeseg_scode = DCSS_PURGESEG; - segext_scode = DCSS_SEGEXT; - return 0; -} +static int loadshr_scode = DCSS_LOADSHRX; +static int loadnsr_scode = DCSS_LOADNSRX; +static int purgeseg_scode = DCSS_PURGESEG; +static int segext_scode = DCSS_SEGEXTX; /* * Create the 8 bytes, ebcdic VM segment name from @@ -196,32 +135,15 @@ dcss_diag(int *func, void *parameter, unsigned long rx, ry; int rc; - if (scode_set == 0) { - rc = dcss_set_subcodes(); - if (rc < 0) - return rc; - scode_set = 1; - } rx = (unsigned long) parameter; ry = (unsigned long) *func; - /* 64-bit Diag x'64' new subcode, keep in 64-bit addressing mode */ diag_stat_inc(DIAG_STAT_X064); - if (*func > DCSS_SEGEXT) - asm volatile( - " diag %0,%1,0x64\n" - " ipm %2\n" - " srl %2,28\n" - : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); - /* 31-bit Diag x'64' old subcode, switch to 31-bit addressing mode */ - else - asm volatile( - " sam31\n" - " diag %0,%1,0x64\n" - " sam64\n" - " ipm %2\n" - " srl %2,28\n" - : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); + asm volatile( + " diag %0,%1,0x64\n" + " ipm %2\n" + " srl %2,28\n" + : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); *ret1 = rx; *ret2 = ry; return rc; @@ -271,31 +193,6 @@ query_segment_type (struct dcss_segment *seg) goto out_free; } - /* Only old format of output area of Diagnose x'64' is supported, - copy data for the new format. */ - if (segext_scode == DCSS_SEGEXT) { - struct qout64_old *qout_old; - qout_old = kzalloc(sizeof(*qout_old), GFP_KERNEL | GFP_DMA); - if (qout_old == NULL) { - rc = -ENOMEM; - goto out_free; - } - memcpy(qout_old, qout, sizeof(struct qout64_old)); - qout->segstart = (unsigned long) qout_old->segstart; - qout->segend = (unsigned long) qout_old->segend; - qout->segcnt = qout_old->segcnt; - qout->segrcnt = qout_old->segrcnt; - - if (qout->segcnt > 6) - qout->segrcnt = 6; - for (i = 0; i < qout->segrcnt; i++) { - qout->range[i].start = - (unsigned long) qout_old->range[i].start; - qout->range[i].end = - (unsigned long) qout_old->range[i].end; - } - kfree(qout_old); - } if (qout->segcnt > 6) { rc = -EOPNOTSUPP; goto out_free; @@ -410,11 +307,9 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long if (rc < 0) goto out_free; - if (loadshr_scode == DCSS_LOADSHRX) { - if (segment_overlaps_others(seg)) { - rc = -EBUSY; - goto out_free; - } + if (segment_overlaps_others(seg)) { + rc = -EBUSY; + goto out_free; } rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1); @@ -472,11 +367,11 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *addr = seg->start_addr; *end = seg->end; if (do_nonshared) - pr_info("DCSS %s of range %p to %p and type %s loaded as " + pr_info("DCSS %s of range %px to %px and type %s loaded as " "exclusive-writable\n", name, (void*) seg->start_addr, (void*) seg->end, segtype_string[seg->vm_segtype]); else { - pr_info("DCSS %s of range %p to %p and type %s loaded in " + pr_info("DCSS %s of range %px to %px and type %s loaded in " "shared access mode\n", name, (void*) seg->start_addr, (void*) seg->end, segtype_string[seg->vm_segtype]); } diff --git a/arch/s390/mm/kasan_init.c b/arch/s390/mm/kasan_init.c @@ -226,8 +226,6 @@ static void __init kasan_enable_dat(void) static void __init kasan_early_detect_facilities(void) { - __stfle(S390_lowcore.stfle_fac_list, - ARRAY_SIZE(S390_lowcore.stfle_fac_list)); if (test_facility(8)) { has_edat = true; __ctl_set_bit(0, 23); diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c @@ -29,14 +29,6 @@ static unsigned long stack_maxrandom_size(void) return STACK_RND_MASK << PAGE_SHIFT; } -/* - * Top of mmap area (just below the process stack). - * - * Leave at least a ~32 MB hole. - */ -#define MIN_GAP (32*1024*1024) -#define MAX_GAP (STACK_TOP/6*5) - static inline int mmap_is_legacy(struct rlimit *rlim_stack) { if (current->personality & ADDR_COMPAT_LAYOUT) @@ -60,13 +52,26 @@ static inline unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack) { unsigned long gap = rlim_stack->rlim_cur; + unsigned long pad = stack_maxrandom_size() + stack_guard_gap; + unsigned long gap_min, gap_max; + + /* Values close to RLIM_INFINITY can overflow. */ + if (gap + pad > gap) + gap += pad; + + /* + * Top of mmap area (just below the process stack). + * Leave at least a ~32 MB hole. + */ + gap_min = 32 * 1024 * 1024UL; + gap_max = (STACK_TOP / 6) * 5; + + if (gap < gap_min) + gap = gap_min; + else if (gap > gap_max) + gap = gap_max; - if (gap < MIN_GAP) - gap = MIN_GAP; - else if (gap > MAX_GAP) - gap = MAX_GAP; - gap &= PAGE_MASK; - return STACK_TOP - stack_maxrandom_size() - rnd - gap; + return PAGE_ALIGN(STACK_TOP - gap - rnd); } unsigned long diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c @@ -318,7 +318,6 @@ pte_t ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, } return old; } -EXPORT_SYMBOL(ptep_modify_prot_start); void ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) @@ -337,7 +336,6 @@ void ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr, } preempt_enable(); } -EXPORT_SYMBOL(ptep_modify_prot_commit); static inline void pmdp_idte_local(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp) diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c @@ -285,7 +285,7 @@ void __iomem *pci_iomap_range(struct pci_dev *pdev, struct zpci_dev *zdev = to_zpci(pdev); int idx; - if (!pci_resource_len(pdev, bar)) + if (!pci_resource_len(pdev, bar) || bar >= PCI_BAR_COUNT) return NULL; idx = zdev->bars[bar].map_idx; @@ -484,6 +484,15 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev) } } +#ifdef CONFIG_PCI_IOV +static struct resource iov_res = { + .name = "PCI IOV res", + .start = 0, + .end = -1, + .flags = IORESOURCE_MEM, +}; +#endif + static void zpci_map_resources(struct pci_dev *pdev) { resource_size_t len; @@ -497,6 +506,17 @@ static void zpci_map_resources(struct pci_dev *pdev) (resource_size_t __force) pci_iomap(pdev, i, 0); pdev->resource[i].end = pdev->resource[i].start + len - 1; } + +#ifdef CONFIG_PCI_IOV + i = PCI_IOV_RESOURCES; + + for (; i < PCI_SRIOV_NUM_BARS + PCI_IOV_RESOURCES; i++) { + len = pci_resource_len(pdev, i); + if (!len) + continue; + pdev->resource[i].parent = &iov_res; + } +#endif } static void zpci_unmap_resources(struct pci_dev *pdev) diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c @@ -172,21 +172,14 @@ static const struct file_operations debugfs_pci_perf_fops = { void zpci_debug_init_device(struct zpci_dev *zdev, const char *name) { zdev->debugfs_dev = debugfs_create_dir(name, debugfs_root); - if (IS_ERR(zdev->debugfs_dev)) - zdev->debugfs_dev = NULL; - - zdev->debugfs_perf = debugfs_create_file("statistics", - S_IFREG | S_IRUGO | S_IWUSR, - zdev->debugfs_dev, zdev, - &debugfs_pci_perf_fops); - if (IS_ERR(zdev->debugfs_perf)) - zdev->debugfs_perf = NULL; + + debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR, + zdev->debugfs_dev, zdev, &debugfs_pci_perf_fops); } void zpci_debug_exit_device(struct zpci_dev *zdev) { - debugfs_remove(zdev->debugfs_perf); - debugfs_remove(zdev->debugfs_dev); + debugfs_remove_recursive(zdev->debugfs_dev); } int __init zpci_debug_init(void) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c @@ -3965,13 +3965,11 @@ int dasd_generic_restore_device(struct ccw_device *cdev) EXPORT_SYMBOL_GPL(dasd_generic_restore_device); static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, - void *rdc_buffer, int rdc_buffer_size, int magic) { struct dasd_ccw_req *cqr; struct ccw1 *ccw; - unsigned long *idaw; cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device, NULL); @@ -3986,16 +3984,8 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, ccw = cqr->cpaddr; ccw->cmd_code = CCW_CMD_RDC; - if (idal_is_needed(rdc_buffer, rdc_buffer_size)) { - idaw = (unsigned long *) (cqr->data); - ccw->cda = (__u32)(addr_t) idaw; - ccw->flags = CCW_FLAG_IDA; - idaw = idal_create_words(idaw, rdc_buffer, rdc_buffer_size); - } else { - ccw->cda = (__u32)(addr_t) rdc_buffer; - ccw->flags = 0; - } - + ccw->cda = (__u32)(addr_t) cqr->data; + ccw->flags = 0; ccw->count = rdc_buffer_size; cqr->startdev = device; cqr->memdev = device; @@ -4013,12 +4003,13 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, int magic, int ret; struct dasd_ccw_req *cqr; - cqr = dasd_generic_build_rdc(device, rdc_buffer, rdc_buffer_size, - magic); + cqr = dasd_generic_build_rdc(device, rdc_buffer_size, magic); if (IS_ERR(cqr)) return PTR_ERR(cqr); ret = dasd_sleep_on(cqr); + if (ret == 0) + memcpy(rdc_buffer, cqr->data, rdc_buffer_size); dasd_sfree_request(cqr, cqr->memdev); return ret; } diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h @@ -195,7 +195,9 @@ struct read_info_sccb { u16 hcpua; /* 120-121 */ u8 _pad_122[124 - 122]; /* 122-123 */ u32 hmfai; /* 124-127 */ - u8 _pad_128[4096 - 128]; /* 128-4095 */ + u8 _pad_128[134 - 128]; /* 128-133 */ + u8 byte_134; /* 134 */ + u8 _pad_135[4096 - 135]; /* 135-4095 */ } __packed __aligned(PAGE_SIZE); struct read_storage_sccb { diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c @@ -44,6 +44,8 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; if (sccb->fac91 & 0x40) S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_GUEST; + if (sccb->cpuoff > 134) + sclp.has_diag318 = !!(sccb->byte_134 & 0x80); sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; sclp.rzm <<= 20; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c @@ -181,7 +181,7 @@ static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, } static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, - void **sbals_array, int i) + struct qdio_buffer **sbals_array, int i) { struct qdio_q *prev; int j; @@ -212,8 +212,8 @@ static void setup_queues(struct qdio_irq *irq_ptr, struct qdio_initialize *qdio_init) { struct qdio_q *q; - void **input_sbal_array = qdio_init->input_sbal_addr_array; - void **output_sbal_array = qdio_init->output_sbal_addr_array; + struct qdio_buffer **input_sbal_array = qdio_init->input_sbal_addr_array; + struct qdio_buffer **output_sbal_array = qdio_init->output_sbal_addr_array; struct qdio_outbuf_state *output_sbal_state_array = qdio_init->output_sbal_state_array; int i; diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c @@ -283,6 +283,33 @@ static long copy_ccw_from_iova(struct channel_program *cp, #define ccw_is_chain(_ccw) ((_ccw)->flags & (CCW_FLAG_CC | CCW_FLAG_DC)) +/* + * is_cpa_within_range() + * + * @cpa: channel program address being questioned + * @head: address of the beginning of a CCW chain + * @len: number of CCWs within the chain + * + * Determine whether the address of a CCW (whether a new chain, + * or the target of a TIC) falls within a range (including the end points). + * + * Returns 1 if yes, 0 if no. + */ +static inline int is_cpa_within_range(u32 cpa, u32 head, int len) +{ + u32 tail = head + (len - 1) * sizeof(struct ccw1); + + return (head <= cpa && cpa <= tail); +} + +static inline int is_tic_within_range(struct ccw1 *ccw, u32 head, int len) +{ + if (!ccw_is_tic(ccw)) + return 0; + + return is_cpa_within_range(ccw->cda, head, len); +} + static struct ccwchain *ccwchain_alloc(struct channel_program *cp, int len) { struct ccwchain *chain; @@ -392,7 +419,15 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp) return -EOPNOTSUPP; } - if ((!ccw_is_chain(ccw)) && (!ccw_is_tic(ccw))) + /* + * We want to keep counting if the current CCW has the + * command-chaining flag enabled, or if it is a TIC CCW + * that loops back into the current chain. The latter + * is used for device orientation, where the CCW PRIOR to + * the TIC can either jump to the TIC or a CCW immediately + * after the TIC, depending on the results of its operation. + */ + if (!ccw_is_chain(ccw) && !is_tic_within_range(ccw, iova, cnt)) break; ccw++; @@ -408,13 +443,11 @@ static int ccwchain_calc_length(u64 iova, struct channel_program *cp) static int tic_target_chain_exists(struct ccw1 *tic, struct channel_program *cp) { struct ccwchain *chain; - u32 ccw_head, ccw_tail; + u32 ccw_head; list_for_each_entry(chain, &cp->ccwchain_list, next) { ccw_head = chain->ch_iova; - ccw_tail = ccw_head + (chain->ch_len - 1) * sizeof(struct ccw1); - - if ((ccw_head <= tic->cda) && (tic->cda <= ccw_tail)) + if (is_cpa_within_range(tic->cda, ccw_head, chain->ch_len)) return 1; } @@ -481,13 +514,11 @@ static int ccwchain_fetch_tic(struct ccwchain *chain, { struct ccw1 *ccw = chain->ch_ccw + idx; struct ccwchain *iter; - u32 ccw_head, ccw_tail; + u32 ccw_head; list_for_each_entry(iter, &cp->ccwchain_list, next) { ccw_head = iter->ch_iova; - ccw_tail = ccw_head + (iter->ch_len - 1) * sizeof(struct ccw1); - - if ((ccw_head <= ccw->cda) && (ccw->cda <= ccw_tail)) { + if (is_cpa_within_range(ccw->cda, ccw_head, iter->ch_len)) { ccw->cda = (__u32) (addr_t) (((char *)iter->ch_ccw) + (ccw->cda - ccw_head)); return 0; @@ -829,7 +860,7 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw) { struct ccwchain *chain; u32 cpa = scsw->cmd.cpa; - u32 ccw_head, ccw_tail; + u32 ccw_head; /* * LATER: @@ -839,9 +870,7 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw) */ list_for_each_entry(chain, &cp->ccwchain_list, next) { ccw_head = (u32)(u64)chain->ch_ccw; - ccw_tail = (u32)(u64)(chain->ch_ccw + chain->ch_len - 1); - - if ((ccw_head <= cpa) && (cpa <= ccw_tail)) { + if (is_cpa_within_range(cpa, ccw_head, chain->ch_len)) { /* * (cpa - ccw_head) is the offset value of the host * physical ccw to its chain head. diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c @@ -1336,6 +1336,16 @@ static int __match_queue_device_with_qid(struct device *dev, void *data) } /* + * Helper function to be used with bus_find_dev + * matches any queue device with given queue id + */ +static int __match_queue_device_with_queue_id(struct device *dev, void *data) +{ + return is_queue_dev(dev) + && AP_QID_QUEUE(to_ap_queue(dev)->qid) == (int)(long) data; +} + +/* * Helper function for ap_scan_bus(). * Does the scan bus job for the given adapter id. */ @@ -1435,8 +1445,13 @@ static void _ap_scan_bus_adapter(int id) borked = aq->state == AP_STATE_BORKED; spin_unlock_bh(&aq->lock); } - if (borked) /* Remove broken device */ + if (borked) { + /* Remove broken device */ + AP_DBF(DBF_DEBUG, + "removing broken queue=%02x.%04x\n", + id, dom); device_unregister(dev); + } put_device(dev); continue; } @@ -1506,7 +1521,7 @@ static void ap_scan_bus(struct work_struct *unused) struct device *dev = bus_find_device(&ap_bus_type, NULL, (void *)(long) ap_domain_index, - __match_queue_device_with_qid); + __match_queue_device_with_queue_id); if (dev) put_device(dev); else diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h @@ -91,7 +91,8 @@ enum ap_state { AP_STATE_WORKING, AP_STATE_QUEUE_FULL, AP_STATE_SUSPEND_WAIT, - AP_STATE_BORKED, + AP_STATE_UNBOUND, /* momentary not bound to a driver */ + AP_STATE_BORKED, /* broken */ NR_AP_STATES }; diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c @@ -420,6 +420,10 @@ static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = { [AP_EVENT_POLL] = ap_sm_suspend_read, [AP_EVENT_TIMEOUT] = ap_sm_nop, }, + [AP_STATE_UNBOUND] = { + [AP_EVENT_POLL] = ap_sm_nop, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, [AP_STATE_BORKED] = { [AP_EVENT_POLL] = ap_sm_nop, [AP_EVENT_TIMEOUT] = ap_sm_nop, @@ -725,6 +729,7 @@ static void __ap_flush_queue(struct ap_queue *aq) ap_msg->rc = -EAGAIN; ap_msg->receive(aq, ap_msg, NULL); } + aq->queue_count = 0; } void ap_flush_queue(struct ap_queue *aq) @@ -743,7 +748,7 @@ void ap_queue_remove(struct ap_queue *aq) /* reset with zero, also clears irq registration */ spin_lock_bh(&aq->lock); ap_zapq(aq->qid); - aq->state = AP_STATE_BORKED; + aq->state = AP_STATE_UNBOUND; spin_unlock_bh(&aq->lock); } EXPORT_SYMBOL(ap_queue_remove); diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c @@ -1079,7 +1079,7 @@ int pkey_verifykey(const struct pkey_seckey *seckey, rc = mkvp_cache_fetch(cardnr, domain, mkvp); if (rc) goto out; - if (t->mkvp == mkvp[1]) { + if (t->mkvp == mkvp[1] && t->mkvp != mkvp[0]) { DEBUG_DBG("%s secure key has old mkvp\n", __func__); if (pattributes) *pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP; diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c @@ -15,7 +15,6 @@ #include "vfio_ap_private.h" #define VFIO_AP_ROOT_NAME "vfio_ap" -#define VFIO_AP_DEV_TYPE_NAME "ap_matrix" #define VFIO_AP_DEV_NAME "matrix" MODULE_AUTHOR("IBM Corporation"); @@ -24,10 +23,6 @@ MODULE_LICENSE("GPL v2"); static struct ap_driver vfio_ap_drv; -static struct device_type vfio_ap_dev_type = { - .name = VFIO_AP_DEV_TYPE_NAME, -}; - struct ap_matrix_dev *matrix_dev; /* Only type 10 adapters (CEX4 and later) are supported @@ -62,6 +57,22 @@ static void vfio_ap_matrix_dev_release(struct device *dev) kfree(matrix_dev); } +static int matrix_bus_match(struct device *dev, struct device_driver *drv) +{ + return 1; +} + +static struct bus_type matrix_bus = { + .name = "matrix", + .match = &matrix_bus_match, +}; + +static struct device_driver matrix_driver = { + .name = "vfio_ap", + .bus = &matrix_bus, + .suppress_bind_attrs = true, +}; + static int vfio_ap_matrix_dev_create(void) { int ret; @@ -71,6 +82,10 @@ static int vfio_ap_matrix_dev_create(void) if (IS_ERR(root_device)) return PTR_ERR(root_device); + ret = bus_register(&matrix_bus); + if (ret) + goto bus_register_err; + matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL); if (!matrix_dev) { ret = -ENOMEM; @@ -87,30 +102,41 @@ static int vfio_ap_matrix_dev_create(void) mutex_init(&matrix_dev->lock); INIT_LIST_HEAD(&matrix_dev->mdev_list); - matrix_dev->device.type = &vfio_ap_dev_type; dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME); matrix_dev->device.parent = root_device; + matrix_dev->device.bus = &matrix_bus; matrix_dev->device.release = vfio_ap_matrix_dev_release; - matrix_dev->device.driver = &vfio_ap_drv.driver; + matrix_dev->vfio_ap_drv = &vfio_ap_drv; ret = device_register(&matrix_dev->device); if (ret) goto matrix_reg_err; + ret = driver_register(&matrix_driver); + if (ret) + goto matrix_drv_err; + return 0; +matrix_drv_err: + device_unregister(&matrix_dev->device); matrix_reg_err: put_device(&matrix_dev->device); matrix_alloc_err: + bus_unregister(&matrix_bus); +bus_register_err: root_device_unregister(root_device); - return ret; } static void vfio_ap_matrix_dev_destroy(void) { + struct device *root_device = matrix_dev->device.parent; + + driver_unregister(&matrix_driver); device_unregister(&matrix_dev->device); - root_device_unregister(matrix_dev->device.parent); + bus_unregister(&matrix_bus); + root_device_unregister(root_device); } static int __init vfio_ap_init(void) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c @@ -198,8 +198,8 @@ static int vfio_ap_verify_queue_reserved(unsigned long *apid, qres.apqi = apqi; qres.reserved = false; - ret = driver_for_each_device(matrix_dev->device.driver, NULL, &qres, - vfio_ap_has_queue); + ret = driver_for_each_device(&matrix_dev->vfio_ap_drv->driver, NULL, + &qres, vfio_ap_has_queue); if (ret) return ret; diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h @@ -40,6 +40,7 @@ struct ap_matrix_dev { struct ap_config_info info; struct list_head mdev_list; struct mutex lock; + struct ap_driver *vfio_ap_drv; }; extern struct ap_matrix_dev *matrix_dev; diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c @@ -141,10 +141,13 @@ static int register_ieq(struct ism_dev *ism) static int unregister_sba(struct ism_dev *ism) { + int ret; + if (!ism->sba) return 0; - if (ism_cmd_simple(ism, ISM_UNREG_SBA)) + ret = ism_cmd_simple(ism, ISM_UNREG_SBA); + if (ret && ret != ISM_ERROR) return -EIO; dma_free_coherent(&ism->pdev->dev, PAGE_SIZE, @@ -158,10 +161,13 @@ static int unregister_sba(struct ism_dev *ism) static int unregister_ieq(struct ism_dev *ism) { + int ret; + if (!ism->ieq) return 0; - if (ism_cmd_simple(ism, ISM_UNREG_IEQ)) + ret = ism_cmd_simple(ism, ISM_UNREG_IEQ); + if (ret && ret != ISM_ERROR) return -EIO; dma_free_coherent(&ism->pdev->dev, PAGE_SIZE, @@ -287,7 +293,7 @@ static int ism_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb) cmd.request.dmb_tok = dmb->dmb_tok; ret = ism_cmd(ism, &cmd); - if (ret) + if (ret && ret != ISM_ERROR) goto out; ism_free_dmb(ism, dmb); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c @@ -4884,8 +4884,8 @@ static int qeth_qdio_establish(struct qeth_card *card) init_data.output_handler = qeth_qdio_output_handler; init_data.queue_start_poll_array = queue_start_poll; init_data.int_parm = (unsigned long) card; - init_data.input_sbal_addr_array = (void **) in_sbal_ptrs; - init_data.output_sbal_addr_array = (void **) out_sbal_ptrs; + init_data.input_sbal_addr_array = in_sbal_ptrs; + init_data.output_sbal_addr_array = out_sbal_ptrs; init_data.output_sbal_state_array = card->qdio.out_bufstates; init_data.scan_threshold = (card->info.type == QETH_CARD_TYPE_IQD) ? 1 : 32; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c @@ -294,8 +294,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, id->input_handler = zfcp_qdio_int_resp; id->output_handler = zfcp_qdio_int_req; id->int_parm = (unsigned long) qdio; - id->input_sbal_addr_array = (void **) (qdio->res_q); - id->output_sbal_addr_array = (void **) (qdio->req_q); + id->input_sbal_addr_array = qdio->res_q; + id->output_sbal_addr_array = qdio->req_q; id->scan_threshold = QDIO_MAX_BUFFERS_PER_Q - ZFCP_QDIO_MAX_SBALS_PER_REQ * 2; } diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h @@ -1185,6 +1185,10 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff); ssize_t ksys_readahead(int fd, loff_t offset, size_t count); +int ksys_ipc(unsigned int call, int first, unsigned long second, + unsigned long third, void __user * ptr, long fifth); +int compat_ksys_ipc(u32 call, int first, int second, + u32 third, u32 ptr, u32 fifth); /* * The following kernel syscall equivalents are just wrappers to fs-internal diff --git a/ipc/syscall.c b/ipc/syscall.c @@ -17,8 +17,8 @@ #include <linux/shm.h> #include <linux/uaccess.h> -SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, - unsigned long, third, void __user *, ptr, long, fifth) +int ksys_ipc(unsigned int call, int first, unsigned long second, + unsigned long third, void __user * ptr, long fifth) { int version, ret; @@ -106,6 +106,12 @@ SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, return -ENOSYS; } } + +SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second, + unsigned long, third, void __user *, ptr, long, fifth) +{ + return ksys_ipc(call, first, second, third, ptr, fifth); +} #endif #ifdef CONFIG_COMPAT @@ -121,8 +127,8 @@ struct compat_ipc_kludge { }; #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC -COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, - u32, third, compat_uptr_t, ptr, u32, fifth) +int compat_ksys_ipc(u32 call, int first, int second, + u32 third, compat_uptr_t ptr, u32 fifth) { int version; u32 pad; @@ -195,5 +201,11 @@ COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, return -ENOSYS; } + +COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, + u32, third, compat_uptr_t, ptr, u32, fifth) +{ + return compat_ksys_ipc(call, first, second, third, ptr, fifth); +} #endif #endif diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c @@ -366,6 +366,7 @@ COND_SYSCALL(kexec_file_load); /* s390 */ COND_SYSCALL(s390_pci_mmio_read); COND_SYSCALL(s390_pci_mmio_write); +COND_SYSCALL(s390_ipc); COND_SYSCALL_COMPAT(s390_ipc); /* powerpc */