Commit dff839f2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Heiko Carstens:
 "The main thing in this merge is the defense for the Spectre
  vulnerabilities. But there are other updates as well, the changes in
  more detail:

   - An s390 specific implementation of the array_index_mask_nospec
     function to the defense against spectre v1

   - Two patches to utilize the new PPA-12/PPA-13 instructions to run
     the kernel and/or user space with reduced branch predicton.

   - The s390 variant of the 'retpoline' spectre v2 defense called
     'expoline'. There is no return instruction for s390, instead an
     indirect branch is used for function return

     The s390 defense mechanism for indirect branches works by using an
     execute-type instruction with the indirect branch as the target of
     the execute. In effect that turns off the prediction for the
     indirect branch.

   - Scrub registers in entry.S that contain user controlled values to
     prevent the speculative use of these values.

   - Re-add the second parameter for the s390 specific runtime
     instrumentation system call and move the header file to uapi. The
     second parameter will continue to do nothing but older kernel
     versions only accepted valid real-time signal numbers. The details
     will be documented in the man-page for the system call.

   - Corrections and improvements for the s390 specific documentation

   - Add a line to /proc/sysinfo to display the CPU model dependent
     license-internal-code identifier

   - A header file include fix for eadm.

   - An error message fix in the kprobes code.

   - The removal of an outdated ARCH_xxx select statement"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/kconfig: Remove ARCH_WANTS_PROT_NUMA_PROT_NONE select
  s390: introduce execute-trampolines for branches
  s390: run user space and KVM guests with modified branch prediction
  s390: add options to change branch prediction behaviour for the kernel
  s390/alternative: use a copy of the facility bit mask
  s390: add optimized array_index_mask_nospec
  s390: scrub registers on kernel entry and KVM exit
  s390/cio: fix kernel-doc usage
  s390/runtime_instrumentation: re-add signum system call parameter
  s390/cpum_cf: correct counter number of LAST_HOST_TRANSLATIONS
  s390/kprobes: Fix %p uses in error messages
  s390/runtime instrumentation: provide uapi header file
  s390/sysinfo: add and display licensed internal code identifier
  s390/docs: reword airq section
  s390/docs: mention subchannel types
  s390/cmf: fix kerneldoc
  s390/eadm: fix CONFIG_BLOCK include dependency
parents 54ce685c 48973df8
......@@ -22,9 +22,28 @@ While most I/O devices on a s390 system are typically driven through the
channel I/O mechanism described here, there are various other methods
(like the diag interface). These are out of the scope of this document.
The s390 common I/O layer also provides access to some devices that are
not strictly considered I/O devices. They are considered here as well,
although they are not the focus of this document.
Some additional information can also be found in the kernel source under
Documentation/s390/driver-model.txt.
The css bus
===========
The css bus contains the subchannels available on the system. They fall
into several categories:
* Standard I/O subchannels, for use by the system. They have a child
device on the ccw bus and are described below.
* I/O subchannels bound to the vfio-ccw driver. See
Documentation/s390/vfio-ccw.txt.
* Message subchannels. No Linux driver currently exists.
* CHSC subchannels (at most one). The chsc subchannel driver can be used
to send asynchronous chsc commands.
* eADM subchannels. Used for talking to storage class memory.
The ccw bus
===========
......@@ -102,10 +121,15 @@ ccw group devices
Generic interfaces
==================
Some interfaces are available to other drivers that do not necessarily
have anything to do with the busses described above, but still are
indirectly using basic infrastructure in the common I/O layer. One
example is the support for adapter interrupts.
The following section contains interfaces in use not only by drivers
dealing with ccw devices, but drivers for various other s390 hardware
as well.
Adapter interrupts
------------------
The common I/O layer provides helper functions for dealing with adapter
interrupts and interrupt vectors.
.. kernel-doc:: drivers/s390/cio/airq.c
:export:
......@@ -112,7 +112,6 @@ config S390
select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_WANTS_DYNAMIC_TASK_STRUCT
select ARCH_WANTS_PROT_NUMA_PROT_NONE
select ARCH_WANTS_UBSAN_NO_NULL
select ARCH_WANT_IPC_PARSE_VERSION
select BUILDTIME_EXTABLE_SORT
......@@ -540,6 +539,51 @@ config ARCH_RANDOM
If unsure, say Y.
config KERNEL_NOBP
def_bool n
prompt "Enable modified branch prediction for the kernel by default"
help
If this option is selected the kernel will switch to a modified
branch prediction mode if the firmware interface is available.
The modified branch prediction mode improves the behaviour in
regard to speculative execution.
With the option enabled the kernel parameter "nobp=0" or "nospec"
can be used to run the kernel in the normal branch prediction mode.
With the option disabled the modified branch prediction mode is
enabled with the "nobp=1" kernel parameter.
If unsure, say N.
config EXPOLINE
def_bool n
prompt "Avoid speculative indirect branches in the kernel"
help
Compile the kernel with the expoline compiler options to guard
against kernel-to-user data leaks by avoiding speculative indirect
branches.
Requires a compiler with -mindirect-branch=thunk support for full
protection. The kernel may run slower.
If unsure, say N.
choice
prompt "Expoline default"
depends on EXPOLINE
default EXPOLINE_FULL
config EXPOLINE_OFF
bool "spectre_v2=off"
config EXPOLINE_MEDIUM
bool "spectre_v2=auto"
config EXPOLINE_FULL
bool "spectre_v2=on"
endchoice
endmenu
menu "Memory setup"
......
......@@ -78,6 +78,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
endif
ifdef CONFIG_EXPOLINE
ifeq ($(call cc-option-yn,$(CC_FLAGS_MARCH) -mindirect-branch=thunk),y)
CC_FLAGS_EXPOLINE := -mindirect-branch=thunk
CC_FLAGS_EXPOLINE += -mfunction-return=thunk
CC_FLAGS_EXPOLINE += -mindirect-branch-table
export CC_FLAGS_EXPOLINE
cflags-y += $(CC_FLAGS_EXPOLINE)
endif
endif
ifdef CONFIG_FUNCTION_TRACER
# make use of hotpatch feature if the compiler supports it
cc_hotpatch := -mhotpatch=0,3
......
......@@ -49,6 +49,30 @@ do { \
#define __smp_mb__before_atomic() barrier()
#define __smp_mb__after_atomic() barrier()
/**
* array_index_mask_nospec - generate a mask for array_idx() that is
* ~0UL when the bounds check succeeds and 0 otherwise
* @index: array element index
* @size: number of elements in array
*/
#define array_index_mask_nospec array_index_mask_nospec
static inline unsigned long array_index_mask_nospec(unsigned long index,
unsigned long size)
{
unsigned long mask;
if (__builtin_constant_p(size) && size > 0) {
asm(" clgr %2,%1\n"
" slbgr %0,%0\n"
:"=d" (mask) : "d" (size-1), "d" (index) :"cc");
return mask;
}
asm(" clgr %1,%2\n"
" slbgr %0,%0\n"
:"=d" (mask) : "d" (size), "d" (index) :"cc");
return ~mask;
}
#include <asm-generic/barrier.h>
#endif /* __ASM_BARRIER_H */
......@@ -4,7 +4,7 @@
#include <linux/types.h>
#include <linux/device.h>
#include <linux/blkdev.h>
#include <linux/blk_types.h>
struct arqb {
u64 data;
......
......@@ -15,6 +15,24 @@
#define MAX_FACILITY_BIT (sizeof(((struct lowcore *)0)->stfle_fac_list) * 8)
static inline void __set_facility(unsigned long nr, void *facilities)
{
unsigned char *ptr = (unsigned char *) facilities;
if (nr >= MAX_FACILITY_BIT)
return;
ptr[nr >> 3] |= 0x80 >> (nr & 7);
}
static inline void __clear_facility(unsigned long nr, void *facilities)
{
unsigned char *ptr = (unsigned char *) facilities;
if (nr >= MAX_FACILITY_BIT)
return;
ptr[nr >> 3] &= ~(0x80 >> (nr & 7));
}
static inline int __test_facility(unsigned long nr, void *facilities)
{
unsigned char *ptr;
......
......@@ -136,7 +136,11 @@ struct lowcore {
__u64 vdso_per_cpu_data; /* 0x03b8 */
__u64 machine_flags; /* 0x03c0 */
__u64 gmap; /* 0x03c8 */
__u8 pad_0x03d0[0x0e00-0x03d0]; /* 0x03d0 */
__u8 pad_0x03d0[0x0400-0x03d0]; /* 0x03d0 */
/* br %r1 trampoline */
__u16 br_r1_trampoline; /* 0x0400 */
__u8 pad_0x0402[0x0e00-0x0402]; /* 0x0402 */
/*
* 0xe00 contains the address of the IPL Parameter Information
......@@ -151,7 +155,8 @@ struct lowcore {
__u8 pad_0x0e20[0x0f00-0x0e20]; /* 0x0e20 */
/* Extended facility list */
__u64 stfle_fac_list[32]; /* 0x0f00 */
__u64 stfle_fac_list[16]; /* 0x0f00 */
__u64 alt_stfle_fac_list[16]; /* 0x0f80 */
__u8 pad_0x1000[0x11b0-0x1000]; /* 0x1000 */
/* Pointer to the machine check extended save area */
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_EXPOLINE_H
#define _ASM_S390_EXPOLINE_H
#ifndef __ASSEMBLY__
#include <linux/types.h>
extern int nospec_call_disable;
extern int nospec_return_disable;
void nospec_init_branches(void);
void nospec_call_revert(s32 *start, s32 *end);
void nospec_return_revert(s32 *start, s32 *end);
#endif /* __ASSEMBLY__ */
#endif /* _ASM_S390_EXPOLINE_H */
......@@ -91,6 +91,7 @@ void cpu_detect_mhz_feature(void);
extern const struct seq_operations cpuinfo_op;
extern int sysctl_ieee_emulation_warnings;
extern void execve_tail(void);
extern void __bpon(void);
/*
* User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit.
......@@ -377,6 +378,9 @@ extern void memcpy_absolute(void *, void *, size_t);
memcpy_absolute(&(dest), &__tmp, sizeof(__tmp)); \
} while (0)
extern int s390_isolate_bp(void);
extern int s390_isolate_bp_guest(void);
#endif /* __ASSEMBLY__ */
#endif /* __ASM_S390_PROCESSOR_H */
......@@ -2,75 +2,10 @@
#ifndef _RUNTIME_INSTR_H
#define _RUNTIME_INSTR_H
#define S390_RUNTIME_INSTR_START 0x1
#define S390_RUNTIME_INSTR_STOP 0x2
struct runtime_instr_cb {
__u64 rca;
__u64 roa;
__u64 rla;
__u32 v : 1;
__u32 s : 1;
__u32 k : 1;
__u32 h : 1;
__u32 a : 1;
__u32 reserved1 : 3;
__u32 ps : 1;
__u32 qs : 1;
__u32 pc : 1;
__u32 qc : 1;
__u32 reserved2 : 1;
__u32 g : 1;
__u32 u : 1;
__u32 l : 1;
__u32 key : 4;
__u32 reserved3 : 8;
__u32 t : 1;
__u32 rgs : 3;
__u32 m : 4;
__u32 n : 1;
__u32 mae : 1;
__u32 reserved4 : 2;
__u32 c : 1;
__u32 r : 1;
__u32 b : 1;
__u32 j : 1;
__u32 e : 1;
__u32 x : 1;
__u32 reserved5 : 2;
__u32 bpxn : 1;
__u32 bpxt : 1;
__u32 bpti : 1;
__u32 bpni : 1;
__u32 reserved6 : 2;
__u32 d : 1;
__u32 f : 1;
__u32 ic : 4;
__u32 dc : 4;
__u64 reserved7;
__u64 sf;
__u64 rsic;
__u64 reserved8;
} __packed __aligned(8);
#include <uapi/asm/runtime_instr.h>
extern struct runtime_instr_cb runtime_instr_empty_cb;
static inline void load_runtime_instr_cb(struct runtime_instr_cb *cb)
{
asm volatile(".insn rsy,0xeb0000000060,0,0,%0" /* LRIC */
: : "Q" (*cb));
}
static inline void store_runtime_instr_cb(struct runtime_instr_cb *cb)
{
asm volatile(".insn rsy,0xeb0000000061,0,0,%0" /* STRIC */
: "=Q" (*cb) : : "cc");
}
static inline void save_ri_cb(struct runtime_instr_cb *cb_prev)
{
if (cb_prev)
......
......@@ -21,7 +21,8 @@ struct sysinfo_1_1_1 {
unsigned char :8;
unsigned char ccr;
unsigned char cai;
char reserved_0[28];
char reserved_0[20];
unsigned long lic;
char manufacturer[16];
char type[4];
char reserved_1[12];
......
......@@ -58,6 +58,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
#define TIF_GUARDED_STORAGE 4 /* load guarded storage control block */
#define TIF_PATCH_PENDING 5 /* pending live patching update */
#define TIF_PGSTE 6 /* New mm's will use 4K page tables */
#define TIF_ISOLATE_BP 8 /* Run process with isolated BP */
#define TIF_ISOLATE_BP_GUEST 9 /* Run KVM guests with isolated BP */
#define TIF_31BIT 16 /* 32bit process */
#define TIF_MEMDIE 17 /* is terminating due to OOM killer */
......@@ -78,6 +80,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
#define _TIF_UPROBE _BITUL(TIF_UPROBE)
#define _TIF_GUARDED_STORAGE _BITUL(TIF_GUARDED_STORAGE)
#define _TIF_PATCH_PENDING _BITUL(TIF_PATCH_PENDING)
#define _TIF_ISOLATE_BP _BITUL(TIF_ISOLATE_BP)
#define _TIF_ISOLATE_BP_GUEST _BITUL(TIF_ISOLATE_BP_GUEST)
#define _TIF_31BIT _BITUL(TIF_31BIT)
#define _TIF_SINGLE_STEP _BITUL(TIF_SINGLE_STEP)
......
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _S390_UAPI_RUNTIME_INSTR_H
#define _S390_UAPI_RUNTIME_INSTR_H
#include <linux/types.h>
#define S390_RUNTIME_INSTR_START 0x1
#define S390_RUNTIME_INSTR_STOP 0x2
struct runtime_instr_cb {
__u64 rca;
__u64 roa;
__u64 rla;
__u32 v : 1;
__u32 s : 1;
__u32 k : 1;
__u32 h : 1;
__u32 a : 1;
__u32 reserved1 : 3;
__u32 ps : 1;
__u32 qs : 1;
__u32 pc : 1;
__u32 qc : 1;
__u32 reserved2 : 1;
__u32 g : 1;
__u32 u : 1;
__u32 l : 1;
__u32 key : 4;
__u32 reserved3 : 8;
__u32 t : 1;
__u32 rgs : 3;
__u32 m : 4;
__u32 n : 1;
__u32 mae : 1;
__u32 reserved4 : 2;
__u32 c : 1;
__u32 r : 1;
__u32 b : 1;
__u32 j : 1;
__u32 e : 1;
__u32 x : 1;
__u32 reserved5 : 2;
__u32 bpxn : 1;
__u32 bpxt : 1;
__u32 bpti : 1;
__u32 bpni : 1;
__u32 reserved6 : 2;
__u32 d : 1;
__u32 f : 1;
__u32 ic : 4;
__u32 dc : 4;
__u64 reserved7;
__u64 sf;
__u64 rsic;
__u64 reserved8;
} __packed __aligned(8);
static inline void load_runtime_instr_cb(struct runtime_instr_cb *cb)
{
asm volatile(".insn rsy,0xeb0000000060,0,0,%0" /* LRIC */
: : "Q" (*cb));
}
static inline void store_runtime_instr_cb(struct runtime_instr_cb *cb)
{
asm volatile(".insn rsy,0xeb0000000061,0,0,%0" /* STRIC */
: "=Q" (*cb) : : "cc");
}
#endif /* _S390_UAPI_RUNTIME_INSTR_H */
......@@ -29,6 +29,7 @@ UBSAN_SANITIZE_early.o := n
#
ifneq ($(CC_FLAGS_MARCH),-march=z900)
CFLAGS_REMOVE_als.o += $(CC_FLAGS_MARCH)
CFLAGS_REMOVE_als.o += $(CC_FLAGS_EXPOLINE)
CFLAGS_als.o += -march=z900
AFLAGS_REMOVE_head.o += $(CC_FLAGS_MARCH)
AFLAGS_head.o += -march=z900
......@@ -63,6 +64,9 @@ obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o
extra-y += head.o head64.o vmlinux.lds
obj-$(CONFIG_EXPOLINE) += nospec-branch.o
CFLAGS_REMOVE_expoline.o += $(CC_FLAGS_EXPOLINE)
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SCHED_TOPOLOGY) += topology.o
......
......@@ -15,6 +15,29 @@ static int __init disable_alternative_instructions(char *str)
early_param("noaltinstr", disable_alternative_instructions);
static int __init nobp_setup_early(char *str)
{
bool enabled;
int rc;
rc = kstrtobool(str, &enabled);
if (rc)
return rc;
if (enabled && test_facility(82))
__set_facility(82, S390_lowcore.alt_stfle_fac_list);
else
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
return 0;
}
early_param("nobp", nobp_setup_early);
static int __init nospec_setup_early(char *str)
{
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
return 0;
}
early_param("nospec", nospec_setup_early);
struct brcl_insn {
u16 opc;
s32 disp;
......@@ -75,7 +98,8 @@ static void __init_or_module __apply_alternatives(struct alt_instr *start,
instr = (u8 *)&a->instr_offset + a->instr_offset;
replacement = (u8 *)&a->repl_offset + a->repl_offset;
if (!test_facility(a->facility))
if (!__test_facility(a->facility,
S390_lowcore.alt_stfle_fac_list))
continue;
if (unlikely(a->instrlen % 2 || a->replacementlen % 2)) {
......
......@@ -193,6 +193,11 @@ 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));
if (!IS_ENABLED(CONFIG_KERNEL_NOBP))
__clear_facility(82, S390_lowcore.alt_stfle_fac_list);
}
static __init void detect_diag9c(void)
......
This diff is collapsed.
......@@ -543,6 +543,7 @@ static struct kset *ipl_kset;
static void __ipl_run(void *unused)
{
__bpon();
diag308(DIAG308_LOAD_CLEAR, NULL);
if (MACHINE_IS_VM)
__cpcmd("IPL", NULL, 0, NULL);
......
......@@ -281,7 +281,7 @@ static void kprobe_reenter_check(struct kprobe_ctlblk *kcb, struct kprobe *p)
* is a BUG. The code path resides in the .kprobes.text
* section and is executed with interrupts disabled.
*/
printk(KERN_EMERG "Invalid kprobe detected at %p.\n", p->addr);
pr_err("Invalid kprobe detected.\n");
dump_kprobe(p);
BUG();
}
......
......@@ -19,6 +19,8 @@
#include <linux/moduleloader.h>
#include <linux/bug.h>
#include <asm/alternative.h>
#include <asm/nospec-branch.h>
#include <asm/facility.h>
#if 0
#define DEBUGP printk
......@@ -156,7 +158,11 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
me->arch.got_offset = me->core_layout.size;
me->core_layout.size += me->arch.got_size;
me->arch.plt_offset = me->core_layout.size;
me->core_layout.size += me->arch.plt_size;
if (me->arch.plt_size) {
if (IS_ENABLED(CONFIG_EXPOLINE) && !nospec_call_disable)
me->arch.plt_size += PLT_ENTRY_SIZE;
me->core_layout.size += me->arch.plt_size;
}
return 0;
}
......@@ -310,9 +316,21 @@ static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
unsigned int *ip;
ip = me->core_layout.base + me->arch.plt_offset +
info->plt_offset;
ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */
ip[1] = 0x100a0004;
ip[2] = 0x07f10000;
ip[0] = 0x0d10e310; /* basr 1,0 */
ip[1] = 0x100a0004; /* lg 1,10(1) */
if (IS_ENABLED(CONFIG_EXPOLINE) &&
!nospec_call_disable) {
unsigned int *ij;
ij = me->core_layout.base +
me->arch.plt_offset +
me->arch.plt_size - PLT_ENTRY_SIZE;
ip[2] = 0xa7f40000 + /* j __jump_r1 */
(unsigned int)(u16)
(((unsigned long) ij - 8 -
(unsigned long) ip) / 2);
} else {
ip[2] = 0x07f10000; /* br %r1 */
}
ip[3] = (unsigned int) (val >> 32);
ip[4] = (unsigned int) val;
info->plt_initialized = 1;
......@@ -418,16 +436,42 @@ int module_finalize(const Elf_Ehdr *hdr,
struct module *me)
{
const Elf_Shdr *s;
char *secstrings;
char *secstrings, *secname;
void *aseg;
if (IS_ENABLED(CONFIG_EXPOLINE) &&
!nospec_call_disable && me->arch.plt_size) {
unsigned int *ij;
ij = me->core_layout.base + me->arch.plt_offset +
me->arch.plt_size - PLT_ENTRY_SIZE;
if (test_facility(35)) {
ij[0] = 0xc6000000; /* exrl %r0,.+10 */
ij[1] = 0x0005a7f4; /* j . */
ij[2] = 0x000007f1; /* br %r1 */
} else {
ij[0] = 0x44000000 | (unsigned int)
offsetof(struct lowcore, br_r1_trampoline);
ij[1] = 0xa7f40000; /* j . */
}
}
secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
if (!strcmp(".altinstructions", secstrings + s->sh_name)) {
/* patch .altinstructions */
void *aseg = (void *)s->sh_addr;
aseg = (void *) s->sh_addr;
secname = secstrings + s->sh_name;
if (!strcmp(".altinstructions", secname))
/* patch .altinstructions */
apply_alternatives(aseg, aseg + s->sh_size);
}
if (IS_ENABLED(CONFIG_EXPOLINE) &&
(!strcmp(".nospec_call_table", secname)))
nospec_call_revert(aseg, aseg + s->sh_size);
if (IS_ENABLED(CONFIG_EXPOLINE) &&
(!strcmp(".nospec_return_table", secname)))
nospec_return_revert(aseg, aseg + s->sh_size);
}
jump_label_apply_nops(me);
......
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <asm/nospec-branch.h>
int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF);
int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL);
static int __init nospectre_v2_setup_early(char *str)
{
nospec_call_disable = 1;
nospec_return_disable = 1;
return 0;
}
early_param("nospectre_v2", nospectre_v2_setup_early);
static int __init spectre_v2_setup_early(char *str)
{
if (str && !strncmp(str, "on", 2)) {
nospec_call_disable = 0;
nospec_return_disable = 0;
}
if (str && !strncmp(str, "off", 3)) {
nospec_call_disable = 1;
nospec_return_disable = 1;
}
if (str && !strncmp(str, "auto", 4)) {
nospec_call_disable = 0;
nospec_return_disable = 1;
}
return 0;
}
early_param("spectre_v2", spectre_v2_setup_early);
static void __init_or_module __nospec_revert(s32 *start, s32 *end)
{
enum { BRCL_EXPOLINE, BRASL_EXPOLINE } type;
u8 *instr, *thunk, *br;
u8 insnbuf[6];
s32 *epo;
/* Second part of the instruction replace is always a nop */
memcpy(insnbuf + 2, (char[]) { 0x47, 0x00, 0x00, 0x00 }, 4);
for (epo = start; epo < end; epo++) {
instr = (u8 *) epo + *epo;
if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x04)
type = BRCL_EXPOLINE; /* brcl instruction */
else if (instr[0] == 0xc0 && (instr[1] & 0x0f) == 0x05)
type = BRASL_EXPOLINE; /* brasl instruction */
else
continue;
thunk = instr + (*(int *)(instr + 2)) * 2;
if (thunk[0] == 0xc6 && thunk[1] == 0x00)
/* exrl %r0,<target-br> */
br = thunk + (*(int *)(thunk + 2)) * 2;
else if (thunk[0] == 0xc0 && (thunk[1] & 0x0f) == 0x00 &&
thunk[6] == 0x44 && thunk[7] == 0x00 &&
(thunk[8] & 0x0f) == 0x00 && thunk[9] == 0x00 &&
(thunk[1] & 0xf0) == (thunk[8] & 0xf0))
/* larl %rx,<target br> + ex %r0,0(%rx) */
br = thunk + (*(int *)(thunk + 2)) * 2;
else
continue;
if (br[0] != 0x07 || (br[1] & 0xf0) != 0xf0)
continue;
switch (type) {
case BRCL_EXPOLINE:
/* brcl to thunk, replace with br + nop */
insnbuf[0] = br[0];
insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
break;
case BRASL_EXPOLINE:
/* brasl to thunk, replace with basr + nop */
insnbuf[0] = 0x0d;
insnbuf[1] = (instr[1] & 0xf0) | (br[1] & 0x0f);
break;
}
s390_kernel_write(instr, insnbuf, 6);
}
}
void __init_or_module nospec_call_revert(s32 *start, s32 *end)
{
if (nospec_call_disable)
__nospec_revert(start, end);
}
void __init_or_module nospec_return_revert(s32 *start, s32 *end)
{
if (nospec_return_disable)
__nospec_revert(start, end);
}
extern s32 __nospec_call_start[], __nospec_call_end[];
extern s32 __nospec_return_start[], __nospec_return_end[];
void __init nospec_init_branches(void)
{
nospec_call_revert(__nospec_call_start, __nospec_call_end);
nospec_return_revert(__nospec_return_start, __nospec_return_end);
}
......@@ -226,7 +226,7 @@ CPUMF_EVENT_ATTR(cf_z14, L1I_OFFDRAWER_L4_SOURCED_WRITES, 0x00af);
CPUMF_EVENT_ATTR(cf_z14, BCD_DFP_EXECUTION_SLOTS, 0x00e0);
CPUMF_EVENT_ATTR(cf_z14, VX_BCD_EXECUTION_SLOTS, 0x00e1);
CPUMF_EVENT_ATTR(cf_z14, DECIMAL_INSTRUCTIONS, 0x00e2);
CPUMF_EVENT_ATTR(cf_z14, LAST_HOST_TRANSLATIONS, 0x00e9);
CPUMF_EVENT_ATTR(cf_z14, LAST_HOST_TRANSLATIONS, 0x00e8);
CPUMF_EVENT_ATTR(cf_z14, TX_NC_TABORT, 0x00f3);
CPUMF_EVENT_ATTR(cf_z14, TX_C_TABORT_NO_SPECIAL, 0x00f4);
CPUMF_EVENT_ATTR(cf_z14, TX_C_TABORT_SPECIAL, 0x00f5);
......
......@@ -197,3 +197,21 @@ const struct seq_operations cpuinfo_op = {
.stop = c_stop,
.show = show_cpuinfo,
};
int s390_isolate_bp(void)
{
if (!test_facility(82))
return -EOPNOTSUPP;
set_thread_flag(TIF_ISOLATE_BP);
return 0;
}
EXPORT_SYMBOL(s390_isolate_bp);
int s390_isolate_bp_guest(void)
{
if (!test_facility(82))
return -EOPNOTSUPP;
set_thread_flag(TIF_ISOLATE_BP_GUEST);
return 0;
}
EXPORT_SYMBOL(s390_isolate_bp_guest);
......@@ -18,6 +18,8 @@
#include <asm/cpu_mf.h>
#include <asm/irq.h>
#include "entry.h"
/* empty control block to disable RI by loading it */
struct runtime_instr_cb runtime_instr_empty_cb;
......@@ -59,7 +61,13 @@ static void init_runtime_instr_cb(struct runtime_instr_cb *cb)
cb->v = 1;
}
SYSCALL_DEFINE1(s390_runtime_instr, int, command)
/*
* The signum argument is unused. In older kernels it was used to
* specify a real-time signal. For backwards compatibility user space
* should pass a valid real-time signal number (the signum argument
* was checked in older kernels).
*/
SYSCALL_DEFINE2(s390_runtime_instr, int, command, int, signum)
{
struct runtime_instr_cb *cb;
......
......@@ -68,6 +68,7 @@
#include <asm/sysinfo.h>
#include <asm/numa.h>
#include <asm/alternative.h>
#include <asm/nospec-branch.h>
#include "entry.h"
/*
......@@ -340,7 +341,9 @@ static void __init setup_lowcore(void)
lc->preempt_count = S390_lowcore.preempt_count;
lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
MAX_FACILITY_BIT/8);
sizeof(lc->stfle_fac_list));
memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
sizeof(lc->alt_stfle_fac_list));
nmi_alloc_boot_cpu(lc);
vdso_alloc_boot_cpu(lc);
lc->sync_enter_timer = S390_lowcore.sync_enter_timer;
......@@ -377,6 +380,7 @@ static void __init setup_lowcore(void)
lc->spinlock_index = 0;
arch_spin_lock_setup(0);
#endif
lc->br_r1_trampoline = 0x07f1; /* br %r1 */
set_prefix((u32)(unsigned long) lc);
lowcore_ptr[0] = lc;
......@@ -952,6 +956,8 @@ void __init setup_arch(char **cmdline_p)
set_preferred_console();
apply_alternative_instructions();
if (IS_ENABLED(CONFIG_EXPOLINE))
nospec_init_branches();
/* Setup zfcpdump support */
setup_zfcpdump();
......
......@@ -214,6 +214,7 @@ static int pcpu_alloc_lowcore(struct pcpu *pcpu, int cpu)
lc->cpu_nr = cpu;
lc->spinlock_lockval = arch_spin_lockval(cpu);
lc->spinlock_index = 0;
lc->br_r1_trampoline = 0x07f1; /* br %r1 */
if (nmi_alloc_per_cpu(lc))
goto out;
if (vdso_alloc_per_cpu(lc))
......@@ -266,7 +267,9 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
__ctl_store(lc->cregs_save_area, 0, 15);
save_access_regs((unsigned int *) lc->access_regs_save_area);
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
MAX_FACILITY_BIT/8);
sizeof(lc->stfle_fac_list));
memcpy(lc->alt_stfle_fac_list, S390_lowcore.alt_stfle_fac_list,
sizeof(lc->alt_stfle_fac_list));
arch_spin_lock_setup(cpu);
}
......@@ -317,6 +320,7 @@ static void pcpu_delegate(struct pcpu *pcpu, void (*func)(void *),
mem_assign_absolute(lc->restart_fn, (unsigned long) func);
mem_assign_absolute(lc->restart_data, (unsigned long) data);
mem_assign_absolute(lc->restart_source, source_cpu);
__bpon();
asm volatile(
"0: sigp 0,%0,%2 # sigp restart to target cpu\n"
" brc 2,0b # busy, try again\n"
......@@ -901,6 +905,7 @@ void __cpu_die(unsigned int cpu)
void __noreturn cpu_die(void)
{
idle_task_exit();
__bpon();
pcpu_sigp_retry(pcpu_devices + smp_processor_id(), SIGP_STOP, 0);
for (;;) ;
}
......
......@@ -89,6 +89,8 @@ static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info)
EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap));
seq_printf(m, "Manufacturer: %-16.16s\n", info->manufacturer);
seq_printf(m, "Type: %-4.4s\n", info->type);
if (info->lic)
seq_printf(m, "LIC Identifier: %016lx\n", info->lic);
/*
* Sigh: the model field has been renamed with System z9
* to model_capacity and a new model field has been added
......
......@@ -123,6 +123,20 @@ SECTIONS
*(.altinstr_replacement)
}
/*
* Table with the patch locations to undo expolines
*/
.nospec_call_table : {
__nospec_call_start = . ;
*(.s390_indirect*)
__nospec_call_end = . ;
}
.nospec_return_table : {
__nospec_return_start = . ;
*(.s390_return*)
__nospec_return_end = . ;
}
/* early.c uses stsi, which requires page aligned data. */
. = ALIGN(PAGE_SIZE);
INIT_DATA_SECTION(0x100)
......
......@@ -19,6 +19,8 @@ endif
CFLAGS_sclp_early_core.o += -D__NO_FORTIFY
CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_EXPOLINE)
obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
sclp_early.o sclp_early_core.o
......
......@@ -412,7 +412,7 @@ static void chp_release(struct device *dev)
/**
* chp_update_desc - update channel-path description
* @chp - channel-path
* @chp: channel-path
*
* Update the channel-path description of the specified channel-path
* including channel measurement related information.
......@@ -438,7 +438,7 @@ int chp_update_desc(struct channel_path *chp)
/**
* chp_new - register a new channel-path
* @chpid - channel-path ID
* @chpid: channel-path ID
*
* Create and register data structure representing new channel-path. Return
* zero on success, non-zero otherwise.
......@@ -730,8 +730,8 @@ static void cfg_func(struct work_struct *work)
/**
* chp_cfg_schedule - schedule chpid configuration request
* @chpid - channel-path ID
* @configure - Non-zero for configure, zero for deconfigure
* @chpid: channel-path ID
* @configure: Non-zero for configure, zero for deconfigure
*
* Schedule a channel-path configuration/deconfiguration request.
*/
......@@ -747,7 +747,7 @@ void chp_cfg_schedule(struct chp_id chpid, int configure)
/**
* chp_cfg_cancel_deconfigure - cancel chpid deconfiguration request
* @chpid - channel-path ID
* @chpid: channel-path ID
*
* Cancel an active channel-path deconfiguration request if it has not yet
* been performed.
......
......@@ -1059,7 +1059,7 @@ EXPORT_SYMBOL_GPL(cio_tm_start_key);
/**
* cio_tm_intrg - perform interrogate function
* @sch - subchannel on which to perform the interrogate function
* @sch: subchannel on which to perform the interrogate function
*
* If the specified subchannel is running in transport-mode, perform the
* interrogate function. Return zero on success, non-zero otherwie.
......
......@@ -1118,9 +1118,10 @@ int ccw_set_cmf(struct ccw_device *cdev, int enable)
* enable_cmf() - switch on the channel measurement for a specific device
* @cdev: The ccw device to be enabled
*
* Returns %0 for success or a negative error value.
* Note: If this is called on a device for which channel measurement is already
* enabled a reset of the measurement data is triggered.
* Enable channel measurements for @cdev. If this is called on a device
* for which channel measurement is already enabled a reset of the
* measurement data is triggered.
* Returns: %0 for success or a negative error value.
* Context:
* non-atomic
*/
......@@ -1160,7 +1161,7 @@ int enable_cmf(struct ccw_device *cdev)
* __disable_cmf() - switch off the channel measurement for a specific device
* @cdev: The ccw device to be disabled
*
* Returns %0 for success or a negative error value.
* Returns: %0 for success or a negative error value.
*
* Context:
* non-atomic, device_lock() held.
......@@ -1184,7 +1185,7 @@ int __disable_cmf(struct ccw_device *cdev)
* disable_cmf() - switch off the channel measurement for a specific device
* @cdev: The ccw device to be disabled
*
* Returns %0 for success or a negative error value.
* Returns: %0 for success or a negative error value.
*
* Context:
* non-atomic
......@@ -1205,7 +1206,7 @@ int disable_cmf(struct ccw_device *cdev)
* @cdev: the channel to be read
* @index: the index of the value to be read
*
* Returns the value read or %0 if the value cannot be read.
* Returns: The value read or %0 if the value cannot be read.
*
* Context:
* any
......@@ -1220,7 +1221,7 @@ u64 cmf_read(struct ccw_device *cdev, int index)
* @cdev: the channel to be read
* @data: a pointer to a data block that will be filled
*
* Returns %0 on success, a negative error value otherwise.
* Returns: %0 on success, a negative error value otherwise.
*
* Context:
* any
......
......@@ -15,7 +15,7 @@
#include <asm/fcx.h>
#include <asm/itcw.h>
/**
/*
* struct itcw - incremental tcw helper data type
*
* This structure serves as a handle for the incremental construction of a
......
......@@ -72,6 +72,7 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask,
* @mask: which output queues to process
* @bb: busy bit indicator, set only if SIGA-w/wt could not access a buffer
* @fc: function code to perform
* @aob: asynchronous operation block
*
* Returns condition code.
* Note: For IQDC unicast queues only the highest priority queue is processed.
......@@ -1761,9 +1762,6 @@ EXPORT_SYMBOL(qdio_stop_irq);
* @response: Response code will be stored at this address
* @cb: Callback function will be executed for each element
* of the address list
* @priv: Pointer passed from the caller to qdio_pnso_brinfo()
* @type: Type of the address entry passed to the callback
* @entry: Entry containg the address of the specified type
* @priv: Pointer to pass to the callback function.
*
* Performs "Store-network-bridging-information list" operation and calls
......
......@@ -835,7 +835,7 @@ void cp_update_scsw(struct channel_program *cp, union scsw *scsw)
/**
* cp_iova_pinned() - check if an iova is pinned for a ccw chain.
* @cmd: ccwchain command on which to perform the operation
* @cp: channel_program on which to perform the operation
* @iova: the iova to check
*
* If the @iova is currently pinned for the ccw chain, return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment