Commit 4ab6cfc4 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 's390-5.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull more s390 updates from Heiko Carstens:
 "Just a couple of small improvements, bug fixes and cleanups:

   - Add Eric Farman as maintainer for s390 virtio drivers.

   - Improve machine check handling, and avoid incorrectly injecting a
     machine check into a kvm guest.

   - Add cond_resched() call to gmap page table walker in order to avoid
     possible huge latencies. Also use non-quiesing sske instruction to
     speed up storage key handling.

   - Add __GFP_NORETRY to KEXEC_CONTROL_MEMORY_GFP so s390 behaves
     similar like common code.

   - Get sie control block address from correct stack slot in perf event
     code. This fixes potential random memory accesses.

   - Change uaccess code so that the exception handler sets the result
     of get_user() and __get_kernel_nofault() to zero in case of a
     fault. Until now this was done via input parameters for inline
     assemblies. Doing it via fault handling is what most or even all
     other architectures are doing.

   - Couple of other small cleanups and fixes"

* tag 's390-5.19-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
  s390/stack: add union to reflect kvm stack slot usages
  s390/stack: merge empty stack frame slots
  s390/uaccess: whitespace cleanup
  s390/uaccess: use __noreturn instead of __attribute__((noreturn))
  s390/uaccess: use exception handler to zero result on get_user() failure
  s390/uaccess: use symbolic names for inline assembler operands
  s390/mcck: isolate SIE instruction when setting CIF_MCCK_GUEST flag
  s390/mm: use non-quiescing sske for KVM switch to keyed guest
  s390/gmap: voluntarily schedule during key setting
  MAINTAINERS: Update s390 virtio-ccw
  s390/kexec: add __GFP_NORETRY to KEXEC_CONTROL_MEMORY_GFP
  s390/Kconfig.debug: fix indentation
  s390/Kconfig: fix indentation
  s390/perf: obtain sie_block from the right address
  s390: generate register offsets into pt_regs automatically
  s390: simplify early program check handler
  s390/crypto: fix scatterwalk_unmap() callers in AES-GCM
parents 93ce7948 e0ffcf3f
...@@ -21057,6 +21057,7 @@ F: include/uapi/linux/virtio_crypto.h ...@@ -21057,6 +21057,7 @@ F: include/uapi/linux/virtio_crypto.h
VIRTIO DRIVERS FOR S390 VIRTIO DRIVERS FOR S390
M: Cornelia Huck <cohuck@redhat.com> M: Cornelia Huck <cohuck@redhat.com>
M: Halil Pasic <pasic@linux.ibm.com> M: Halil Pasic <pasic@linux.ibm.com>
M: Eric Farman <farman@linux.ibm.com>
L: linux-s390@vger.kernel.org L: linux-s390@vger.kernel.org
L: virtualization@lists.linux-foundation.org L: virtualization@lists.linux-foundation.org
L: kvm@vger.kernel.org L: kvm@vger.kernel.org
......
...@@ -701,7 +701,7 @@ static inline void _gcm_sg_unmap_and_advance(struct gcm_sg_walk *gw, ...@@ -701,7 +701,7 @@ static inline void _gcm_sg_unmap_and_advance(struct gcm_sg_walk *gw,
unsigned int nbytes) unsigned int nbytes)
{ {
gw->walk_bytes_remain -= nbytes; gw->walk_bytes_remain -= nbytes;
scatterwalk_unmap(&gw->walk); scatterwalk_unmap(gw->walk_ptr);
scatterwalk_advance(&gw->walk, nbytes); scatterwalk_advance(&gw->walk, nbytes);
scatterwalk_done(&gw->walk, 0, gw->walk_bytes_remain); scatterwalk_done(&gw->walk, 0, gw->walk_bytes_remain);
gw->walk_ptr = NULL; gw->walk_ptr = NULL;
...@@ -776,7 +776,7 @@ static int gcm_out_walk_go(struct gcm_sg_walk *gw, unsigned int minbytesneeded) ...@@ -776,7 +776,7 @@ static int gcm_out_walk_go(struct gcm_sg_walk *gw, unsigned int minbytesneeded)
goto out; goto out;
} }
scatterwalk_unmap(&gw->walk); scatterwalk_unmap(gw->walk_ptr);
gw->walk_ptr = NULL; gw->walk_ptr = NULL;
gw->ptr = gw->buf; gw->ptr = gw->buf;
......
...@@ -3,12 +3,24 @@ ...@@ -3,12 +3,24 @@
#define __ASM_EXTABLE_H #define __ASM_EXTABLE_H
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/bits.h>
#include <asm/asm-const.h> #include <asm/asm-const.h>
#define EX_TYPE_NONE 0 #define EX_TYPE_NONE 0
#define EX_TYPE_FIXUP 1 #define EX_TYPE_FIXUP 1
#define EX_TYPE_BPF 2 #define EX_TYPE_BPF 2
#define EX_TYPE_UACCESS 3 #define EX_TYPE_UA_STORE 3
#define EX_TYPE_UA_LOAD_MEM 4
#define EX_TYPE_UA_LOAD_REG 5
#define EX_DATA_REG_ERR_SHIFT 0
#define EX_DATA_REG_ERR GENMASK(3, 0)
#define EX_DATA_REG_ADDR_SHIFT 4
#define EX_DATA_REG_ADDR GENMASK(7, 4)
#define EX_DATA_LEN_SHIFT 8
#define EX_DATA_LEN GENMASK(11, 8)
#define __EX_TABLE(_section, _fault, _target, _type) \ #define __EX_TABLE(_section, _fault, _target, _type) \
stringify_in_c(.section _section,"a";) \ stringify_in_c(.section _section,"a";) \
...@@ -19,35 +31,58 @@ ...@@ -19,35 +31,58 @@
stringify_in_c(.short 0;) \ stringify_in_c(.short 0;) \
stringify_in_c(.previous) stringify_in_c(.previous)
#define __EX_TABLE_UA(_section, _fault, _target, _type, _reg) \ #define __EX_TABLE_UA(_section, _fault, _target, _type, _regerr, _regaddr, _len)\
stringify_in_c(.section _section,"a";) \ stringify_in_c(.section _section,"a";) \
stringify_in_c(.align 4;) \ stringify_in_c(.align 4;) \
stringify_in_c(.long (_fault) - .;) \ stringify_in_c(.long (_fault) - .;) \
stringify_in_c(.long (_target) - .;) \ stringify_in_c(.long (_target) - .;) \
stringify_in_c(.short (_type);) \ stringify_in_c(.short (_type);) \
stringify_in_c(.macro extable_reg reg;) \ stringify_in_c(.macro extable_reg regerr, regaddr;) \
stringify_in_c(.set .Lfound, 0;) \ stringify_in_c(.set .Lfound, 0;) \
stringify_in_c(.set .Lregnr, 0;) \ stringify_in_c(.set .Lcurr, 0;) \
stringify_in_c(.irp rs,r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15;) \ stringify_in_c(.irp rs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15;) \
stringify_in_c(.ifc "\reg", "%%\rs";) \ stringify_in_c( .ifc "\regerr", "%%r\rs";) \
stringify_in_c(.set .Lfound, 1;) \ stringify_in_c( .set .Lfound, 1;) \
stringify_in_c(.short .Lregnr;) \ stringify_in_c( .set .Lregerr, .Lcurr;) \
stringify_in_c( .endif;) \
stringify_in_c( .set .Lcurr, .Lcurr+1;) \
stringify_in_c(.endr;) \
stringify_in_c(.ifne (.Lfound != 1);) \
stringify_in_c( .error "extable_reg: bad register argument1";) \
stringify_in_c(.endif;) \ stringify_in_c(.endif;) \
stringify_in_c(.set .Lregnr, .Lregnr+1;) \ stringify_in_c(.set .Lfound, 0;) \
stringify_in_c(.set .Lcurr, 0;) \
stringify_in_c(.irp rs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15;) \
stringify_in_c( .ifc "\regaddr", "%%r\rs";) \
stringify_in_c( .set .Lfound, 1;) \
stringify_in_c( .set .Lregaddr, .Lcurr;) \
stringify_in_c( .endif;) \
stringify_in_c( .set .Lcurr, .Lcurr+1;) \
stringify_in_c(.endr;) \ stringify_in_c(.endr;) \
stringify_in_c(.ifne (.Lfound != 1);) \ stringify_in_c(.ifne (.Lfound != 1);) \
stringify_in_c(.error "extable_reg: bad register argument";) \ stringify_in_c( .error "extable_reg: bad register argument2";) \
stringify_in_c(.endif;) \ stringify_in_c(.endif;) \
stringify_in_c(.short .Lregerr << EX_DATA_REG_ERR_SHIFT | \
.Lregaddr << EX_DATA_REG_ADDR_SHIFT | \
_len << EX_DATA_LEN_SHIFT;) \
stringify_in_c(.endm;) \ stringify_in_c(.endm;) \
stringify_in_c(extable_reg _reg;) \ stringify_in_c(extable_reg _regerr,_regaddr;) \
stringify_in_c(.purgem extable_reg;) \ stringify_in_c(.purgem extable_reg;) \
stringify_in_c(.previous) stringify_in_c(.previous)
#define EX_TABLE(_fault, _target) \ #define EX_TABLE(_fault, _target) \
__EX_TABLE(__ex_table, _fault, _target, EX_TYPE_FIXUP) __EX_TABLE(__ex_table, _fault, _target, EX_TYPE_FIXUP)
#define EX_TABLE_AMODE31(_fault, _target) \ #define EX_TABLE_AMODE31(_fault, _target) \
__EX_TABLE(.amode31.ex_table, _fault, _target, EX_TYPE_FIXUP) __EX_TABLE(.amode31.ex_table, _fault, _target, EX_TYPE_FIXUP)
#define EX_TABLE_UA(_fault, _target, _reg) \
__EX_TABLE_UA(__ex_table, _fault, _target, EX_TYPE_UACCESS, _reg) #define EX_TABLE_UA_STORE(_fault, _target, _regerr) \
__EX_TABLE_UA(__ex_table, _fault, _target, EX_TYPE_UA_STORE, _regerr, _regerr, 0)
#define EX_TABLE_UA_LOAD_MEM(_fault, _target, _regerr, _regmem, _len) \
__EX_TABLE_UA(__ex_table, _fault, _target, EX_TYPE_UA_LOAD_MEM, _regerr, _regmem, _len)
#define EX_TABLE_UA_LOAD_REG(_fault, _target, _regerr, _regzero) \
__EX_TABLE_UA(__ex_table, _fault, _target, EX_TYPE_UA_LOAD_REG, _regerr, _regzero, 0)
#endif /* __ASM_EXTABLE_H */ #endif /* __ASM_EXTABLE_H */
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31) #define KEXEC_CONTROL_MEMORY_LIMIT (1UL<<31)
/* Allocate control page with GFP_DMA */ /* Allocate control page with GFP_DMA */
#define KEXEC_CONTROL_MEMORY_GFP GFP_DMA #define KEXEC_CONTROL_MEMORY_GFP (GFP_DMA | __GFP_NORETRY)
/* Maximum address we can use for the crash control pages */ /* Maximum address we can use for the crash control pages */
#define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL) #define KEXEC_CRASH_CONTROL_MEMORY_LIMIT (-1UL)
......
...@@ -304,12 +304,6 @@ static __always_inline void __noreturn disabled_wait(void) ...@@ -304,12 +304,6 @@ static __always_inline void __noreturn disabled_wait(void)
while (1); while (1);
} }
/*
* Basic Program Check Handler.
*/
extern void s390_base_pgm_handler(void);
extern void (*s390_base_pgm_handler_fn)(struct pt_regs *regs);
#define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL
extern int memcpy_real(void *, unsigned long, size_t); extern int memcpy_real(void *, unsigned long, size_t);
......
...@@ -39,8 +39,15 @@ static inline bool on_stack(struct stack_info *info, ...@@ -39,8 +39,15 @@ static inline bool on_stack(struct stack_info *info,
* Kernel uses the packed stack layout (-mpacked-stack). * Kernel uses the packed stack layout (-mpacked-stack).
*/ */
struct stack_frame { struct stack_frame {
unsigned long empty1[5]; union {
unsigned int empty2[8]; unsigned long empty[9];
struct {
unsigned long sie_control_block;
unsigned long sie_savearea;
unsigned long sie_reason;
unsigned long sie_flags;
};
};
unsigned long gprs[10]; unsigned long gprs[10];
unsigned long back_chain; unsigned long back_chain;
}; };
......
...@@ -55,9 +55,6 @@ copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned lo ...@@ -55,9 +55,6 @@ copy_to_user_key(void __user *to, const void *from, unsigned long n, unsigned lo
return n; return n;
} }
int __put_user_bad(void) __attribute__((noreturn));
int __get_user_bad(void) __attribute__((noreturn));
union oac { union oac {
unsigned int val; unsigned int val;
struct { struct {
...@@ -80,8 +77,14 @@ union oac { ...@@ -80,8 +77,14 @@ union oac {
}; };
}; };
#define __put_get_user_asm(to, from, size, oac_spec) \ int __noreturn __put_user_bad(void);
#define __put_user_asm(to, from, size) \
({ \ ({ \
union oac __oac_spec = { \
.oac1.as = PSW_BITS_AS_SECONDARY, \
.oac1.a = 1, \
}; \
int __rc; \ int __rc; \
\ \
asm volatile( \ asm volatile( \
...@@ -89,26 +92,15 @@ union oac { ...@@ -89,26 +92,15 @@ union oac {
"0: mvcos %[_to],%[_from],%[_size]\n" \ "0: mvcos %[_to],%[_from],%[_size]\n" \
"1: xr %[rc],%[rc]\n" \ "1: xr %[rc],%[rc]\n" \
"2:\n" \ "2:\n" \
EX_TABLE_UA(0b,2b,%[rc]) EX_TABLE_UA(1b,2b,%[rc]) \ EX_TABLE_UA_STORE(0b, 2b, %[rc]) \
EX_TABLE_UA_STORE(1b, 2b, %[rc]) \
: [rc] "=&d" (__rc), [_to] "+Q" (*(to)) \ : [rc] "=&d" (__rc), [_to] "+Q" (*(to)) \
: [_size] "d" (size), [_from] "Q" (*(from)), \ : [_size] "d" (size), [_from] "Q" (*(from)), \
[spec] "d" (oac_spec.val) \ [spec] "d" (__oac_spec.val) \
: "cc", "0"); \ : "cc", "0"); \
__rc; \ __rc; \
}) })
#define __put_user_asm(to, from, size) \
__put_get_user_asm(to, from, size, ((union oac) { \
.oac1.as = PSW_BITS_AS_SECONDARY, \
.oac1.a = 1 \
}))
#define __get_user_asm(to, from, size) \
__put_get_user_asm(to, from, size, ((union oac) { \
.oac2.as = PSW_BITS_AS_SECONDARY, \
.oac2.a = 1 \
})) \
static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned long size) static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned long size)
{ {
int rc; int rc;
...@@ -141,6 +133,31 @@ static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned lon ...@@ -141,6 +133,31 @@ static __always_inline int __put_user_fn(void *x, void __user *ptr, unsigned lon
return rc; return rc;
} }
int __noreturn __get_user_bad(void);
#define __get_user_asm(to, from, size) \
({ \
union oac __oac_spec = { \
.oac2.as = PSW_BITS_AS_SECONDARY, \
.oac2.a = 1, \
}; \
int __rc; \
\
asm volatile( \
" lr 0,%[spec]\n" \
"0: mvcos 0(%[_to]),%[_from],%[_size]\n" \
"1: xr %[rc],%[rc]\n" \
"2:\n" \
EX_TABLE_UA_LOAD_MEM(0b, 2b, %[rc], %[_to], %[_ksize]) \
EX_TABLE_UA_LOAD_MEM(1b, 2b, %[rc], %[_to], %[_ksize]) \
: [rc] "=&d" (__rc), "=Q" (*(to)) \
: [_size] "d" (size), [_from] "Q" (*(from)), \
[spec] "d" (__oac_spec.val), [_to] "a" (to), \
[_ksize] "K" (size) \
: "cc", "0"); \
__rc; \
})
static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size) static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsigned long size)
{ {
int rc; int rc;
...@@ -181,14 +198,14 @@ static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsign ...@@ -181,14 +198,14 @@ static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsign
({ \ ({ \
__typeof__(*(ptr)) __x = (x); \ __typeof__(*(ptr)) __x = (x); \
int __pu_err = -EFAULT; \ int __pu_err = -EFAULT; \
\
__chk_user_ptr(ptr); \ __chk_user_ptr(ptr); \
switch (sizeof (*(ptr))) { \ switch (sizeof(*(ptr))) { \
case 1: \ case 1: \
case 2: \ case 2: \
case 4: \ case 4: \
case 8: \ case 8: \
__pu_err = __put_user_fn(&__x, ptr, \ __pu_err = __put_user_fn(&__x, ptr, sizeof(*(ptr))); \
sizeof(*(ptr))); \
break; \ break; \
default: \ default: \
__put_user_bad(); \ __put_user_bad(); \
...@@ -203,38 +220,38 @@ static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsign ...@@ -203,38 +220,38 @@ static __always_inline int __get_user_fn(void *x, const void __user *ptr, unsign
__put_user(x, ptr); \ __put_user(x, ptr); \
}) })
#define __get_user(x, ptr) \ #define __get_user(x, ptr) \
({ \ ({ \
int __gu_err = -EFAULT; \ int __gu_err = -EFAULT; \
\
__chk_user_ptr(ptr); \ __chk_user_ptr(ptr); \
switch (sizeof(*(ptr))) { \ switch (sizeof(*(ptr))) { \
case 1: { \ case 1: { \
unsigned char __x = 0; \ unsigned char __x; \
__gu_err = __get_user_fn(&__x, ptr, \ \
sizeof(*(ptr))); \ __gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \ (x) = *(__force __typeof__(*(ptr)) *)&__x; \
break; \ break; \
}; \ }; \
case 2: { \ case 2: { \
unsigned short __x = 0; \ unsigned short __x; \
__gu_err = __get_user_fn(&__x, ptr, \ \
sizeof(*(ptr))); \ __gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \ (x) = *(__force __typeof__(*(ptr)) *)&__x; \
break; \ break; \
}; \ }; \
case 4: { \ case 4: { \
unsigned int __x = 0; \ unsigned int __x; \
__gu_err = __get_user_fn(&__x, ptr, \ \
sizeof(*(ptr))); \ __gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \ (x) = *(__force __typeof__(*(ptr)) *)&__x; \
break; \ break; \
}; \ }; \
case 8: { \ case 8: { \
unsigned long long __x = 0; \ unsigned long __x; \
__gu_err = __get_user_fn(&__x, ptr, \ \
sizeof(*(ptr))); \ __gu_err = __get_user_fn(&__x, ptr, sizeof(*(ptr))); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \ (x) = *(__force __typeof__(*(ptr)) *)&__x; \
break; \ break; \
}; \ }; \
default: \ default: \
...@@ -278,19 +295,20 @@ int __noreturn __put_kernel_bad(void); ...@@ -278,19 +295,20 @@ int __noreturn __put_kernel_bad(void);
int __rc; \ int __rc; \
\ \
asm volatile( \ asm volatile( \
"0: " insn " %2,%1\n" \ "0: " insn " %[_val],%[_to]\n" \
"1: xr %0,%0\n" \ "1: xr %[rc],%[rc]\n" \
"2:\n" \ "2:\n" \
EX_TABLE_UA(0b,2b,%0) EX_TABLE_UA(1b,2b,%0) \ EX_TABLE_UA_STORE(0b, 2b, %[rc]) \
: "=d" (__rc), "+Q" (*(to)) \ EX_TABLE_UA_STORE(1b, 2b, %[rc]) \
: "d" (val) \ : [rc] "=d" (__rc), [_to] "+Q" (*(to)) \
: [_val] "d" (val) \
: "cc"); \ : "cc"); \
__rc; \ __rc; \
}) })
#define __put_kernel_nofault(dst, src, type, err_label) \ #define __put_kernel_nofault(dst, src, type, err_label) \
do { \ do { \
u64 __x = (u64)(*((type *)(src))); \ unsigned long __x = (unsigned long)(*((type *)(src))); \
int __pk_err; \ int __pk_err; \
\ \
switch (sizeof(type)) { \ switch (sizeof(type)) { \
...@@ -321,12 +339,13 @@ int __noreturn __get_kernel_bad(void); ...@@ -321,12 +339,13 @@ int __noreturn __get_kernel_bad(void);
int __rc; \ int __rc; \
\ \
asm volatile( \ asm volatile( \
"0: " insn " %1,%2\n" \ "0: " insn " %[_val],%[_from]\n" \
"1: xr %0,%0\n" \ "1: xr %[rc],%[rc]\n" \
"2:\n" \ "2:\n" \
EX_TABLE_UA(0b,2b,%0) EX_TABLE_UA(1b,2b,%0) \ EX_TABLE_UA_LOAD_REG(0b, 2b, %[rc], %[_val]) \
: "=d" (__rc), "+d" (val) \ EX_TABLE_UA_LOAD_REG(1b, 2b, %[rc], %[_val]) \
: "Q" (*(from)) \ : [rc] "=d" (__rc), [_val] "=d" (val) \
: [_from] "Q" (*(from)) \
: "cc"); \ : "cc"); \
__rc; \ __rc; \
}) })
...@@ -337,28 +356,28 @@ do { \ ...@@ -337,28 +356,28 @@ do { \
\ \
switch (sizeof(type)) { \ switch (sizeof(type)) { \
case 1: { \ case 1: { \
u8 __x = 0; \ unsigned char __x; \
\ \
__gk_err = __get_kernel_asm(__x, (type *)(src), "ic"); \ __gk_err = __get_kernel_asm(__x, (type *)(src), "ic"); \
*((type *)(dst)) = (type)__x; \ *((type *)(dst)) = (type)__x; \
break; \ break; \
}; \ }; \
case 2: { \ case 2: { \
u16 __x = 0; \ unsigned short __x; \
\ \
__gk_err = __get_kernel_asm(__x, (type *)(src), "lh"); \ __gk_err = __get_kernel_asm(__x, (type *)(src), "lh"); \
*((type *)(dst)) = (type)__x; \ *((type *)(dst)) = (type)__x; \
break; \ break; \
}; \ }; \
case 4: { \ case 4: { \
u32 __x = 0; \ unsigned int __x; \
\ \
__gk_err = __get_kernel_asm(__x, (type *)(src), "l"); \ __gk_err = __get_kernel_asm(__x, (type *)(src), "l"); \
*((type *)(dst)) = (type)__x; \ *((type *)(dst)) = (type)__x; \
break; \ break; \
}; \ }; \
case 8: { \ case 8: { \
u64 __x = 0; \ unsigned long __x; \
\ \
__gk_err = __get_kernel_asm(__x, (type *)(src), "lg"); \ __gk_err = __get_kernel_asm(__x, (type *)(src), "lg"); \
*((type *)(dst)) = (type)__x; \ *((type *)(dst)) = (type)__x; \
......
...@@ -33,7 +33,7 @@ CFLAGS_stacktrace.o += -fno-optimize-sibling-calls ...@@ -33,7 +33,7 @@ CFLAGS_stacktrace.o += -fno-optimize-sibling-calls
CFLAGS_dumpstack.o += -fno-optimize-sibling-calls CFLAGS_dumpstack.o += -fno-optimize-sibling-calls
CFLAGS_unwind_bc.o += -fno-optimize-sibling-calls CFLAGS_unwind_bc.o += -fno-optimize-sibling-calls
obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o obj-y := traps.o time.o process.o earlypgm.o early.o setup.o idle.o vtime.o
obj-y += processor.o syscall.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o obj-y += processor.o syscall.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o
obj-y += sysinfo.o lgr.o os_info.o machine_kexec.o obj-y += sysinfo.o lgr.o os_info.o machine_kexec.o
......
...@@ -32,6 +32,22 @@ int main(void) ...@@ -32,6 +32,22 @@ int main(void)
/* pt_regs offsets */ /* pt_regs offsets */
OFFSET(__PT_PSW, pt_regs, psw); OFFSET(__PT_PSW, pt_regs, psw);
OFFSET(__PT_GPRS, pt_regs, gprs); OFFSET(__PT_GPRS, pt_regs, gprs);
OFFSET(__PT_R0, pt_regs, gprs[0]);
OFFSET(__PT_R1, pt_regs, gprs[1]);
OFFSET(__PT_R2, pt_regs, gprs[2]);
OFFSET(__PT_R3, pt_regs, gprs[3]);
OFFSET(__PT_R4, pt_regs, gprs[4]);
OFFSET(__PT_R5, pt_regs, gprs[5]);
OFFSET(__PT_R6, pt_regs, gprs[6]);
OFFSET(__PT_R7, pt_regs, gprs[7]);
OFFSET(__PT_R8, pt_regs, gprs[8]);
OFFSET(__PT_R9, pt_regs, gprs[9]);
OFFSET(__PT_R10, pt_regs, gprs[10]);
OFFSET(__PT_R11, pt_regs, gprs[11]);
OFFSET(__PT_R12, pt_regs, gprs[12]);
OFFSET(__PT_R13, pt_regs, gprs[13]);
OFFSET(__PT_R14, pt_regs, gprs[14]);
OFFSET(__PT_R15, pt_regs, gprs[15]);
OFFSET(__PT_ORIG_GPR2, pt_regs, orig_gpr2); OFFSET(__PT_ORIG_GPR2, pt_regs, orig_gpr2);
OFFSET(__PT_FLAGS, pt_regs, flags); OFFSET(__PT_FLAGS, pt_regs, flags);
OFFSET(__PT_CR1, pt_regs, cr1); OFFSET(__PT_CR1, pt_regs, cr1);
...@@ -41,11 +57,11 @@ int main(void) ...@@ -41,11 +57,11 @@ int main(void)
/* stack_frame offsets */ /* stack_frame offsets */
OFFSET(__SF_BACKCHAIN, stack_frame, back_chain); OFFSET(__SF_BACKCHAIN, stack_frame, back_chain);
OFFSET(__SF_GPRS, stack_frame, gprs); OFFSET(__SF_GPRS, stack_frame, gprs);
OFFSET(__SF_EMPTY, stack_frame, empty1[0]); OFFSET(__SF_EMPTY, stack_frame, empty[0]);
OFFSET(__SF_SIE_CONTROL, stack_frame, empty1[1]); OFFSET(__SF_SIE_CONTROL, stack_frame, sie_control_block);
OFFSET(__SF_SIE_SAVEAREA, stack_frame, empty1[2]); OFFSET(__SF_SIE_SAVEAREA, stack_frame, sie_savearea);
OFFSET(__SF_SIE_REASON, stack_frame, empty1[3]); OFFSET(__SF_SIE_REASON, stack_frame, sie_reason);
OFFSET(__SF_SIE_FLAGS, stack_frame, empty1[4]); OFFSET(__SF_SIE_FLAGS, stack_frame, sie_flags);
DEFINE(STACK_FRAME_OVERHEAD, sizeof(struct stack_frame)); DEFINE(STACK_FRAME_OVERHEAD, sizeof(struct stack_frame));
BLANK(); BLANK();
/* idle data offsets */ /* idle data offsets */
......
...@@ -149,7 +149,7 @@ static __init void setup_topology(void) ...@@ -149,7 +149,7 @@ static __init void setup_topology(void)
topology_max_mnest = max_mnest; topology_max_mnest = max_mnest;
} }
static void early_pgm_check_handler(struct pt_regs *regs) void __do_early_pgm_check(struct pt_regs *regs)
{ {
if (!fixup_exception(regs)) if (!fixup_exception(regs))
disabled_wait(); disabled_wait();
...@@ -159,12 +159,11 @@ static noinline __init void setup_lowcore_early(void) ...@@ -159,12 +159,11 @@ static noinline __init void setup_lowcore_early(void)
{ {
psw_t psw; psw_t psw;
psw.addr = (unsigned long)s390_base_pgm_handler; psw.addr = (unsigned long)early_pgm_check_handler;
psw.mask = PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA; psw.mask = PSW_MASK_BASE | PSW_DEFAULT_KEY | PSW_MASK_EA | PSW_MASK_BA;
if (IS_ENABLED(CONFIG_KASAN)) if (IS_ENABLED(CONFIG_KASAN))
psw.mask |= PSW_MASK_DAT; psw.mask |= PSW_MASK_DAT;
S390_lowcore.program_new_psw = psw; S390_lowcore.program_new_psw = psw;
s390_base_pgm_handler_fn = early_pgm_check_handler;
S390_lowcore.preempt_count = INIT_PREEMPT_COUNT; S390_lowcore.preempt_count = INIT_PREEMPT_COUNT;
} }
......
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
/* /*
* arch/s390/kernel/base.S
*
* Copyright IBM Corp. 2006, 2007 * Copyright IBM Corp. 2006, 2007
* Author(s): Michael Holzheu <holzheu@de.ibm.com> * Author(s): Michael Holzheu <holzheu@de.ibm.com>
*/ */
#include <linux/linkage.h> #include <linux/linkage.h>
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/nospec-insn.h>
#include <asm/ptrace.h>
GEN_BR_THUNK %r9 ENTRY(early_pgm_check_handler)
GEN_BR_THUNK %r14
__PT_R0 = __PT_GPRS
__PT_R8 = __PT_GPRS + 64
ENTRY(s390_base_pgm_handler)
stmg %r8,%r15,__LC_SAVE_AREA_SYNC stmg %r8,%r15,__LC_SAVE_AREA_SYNC
aghi %r15,-(STACK_FRAME_OVERHEAD+__PT_SIZE) aghi %r15,-(STACK_FRAME_OVERHEAD+__PT_SIZE)
la %r11,STACK_FRAME_OVERHEAD(%r15) la %r11,STACK_FRAME_OVERHEAD(%r15)
...@@ -26,25 +16,8 @@ ENTRY(s390_base_pgm_handler) ...@@ -26,25 +16,8 @@ ENTRY(s390_base_pgm_handler)
mvc __PT_PSW(16,%r11),__LC_PGM_OLD_PSW mvc __PT_PSW(16,%r11),__LC_PGM_OLD_PSW
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC mvc __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
lgr %r2,%r11 lgr %r2,%r11
larl %r1,s390_base_pgm_handler_fn brasl %r14,__do_early_pgm_check
lg %r9,0(%r1)
ltgr %r9,%r9
jz 1f
BASR_EX %r14,%r9
mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15) mvc __LC_RETURN_PSW(16),STACK_FRAME_OVERHEAD+__PT_PSW(%r15)
lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15) lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15)
lpswe __LC_RETURN_PSW lpswe __LC_RETURN_PSW
1: larl %r13,disabled_wait_psw ENDPROC(early_pgm_check_handler)
lpswe 0(%r13)
ENDPROC(s390_base_pgm_handler)
.align 8
disabled_wait_psw:
.quad 0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler
.section .bss
.align 8
.globl s390_base_pgm_handler_fn
s390_base_pgm_handler_fn:
.quad 0
.previous
...@@ -29,23 +29,6 @@ ...@@ -29,23 +29,6 @@
#include <asm/export.h> #include <asm/export.h>
#include <asm/nospec-insn.h> #include <asm/nospec-insn.h>
__PT_R0 = __PT_GPRS
__PT_R1 = __PT_GPRS + 8
__PT_R2 = __PT_GPRS + 16
__PT_R3 = __PT_GPRS + 24
__PT_R4 = __PT_GPRS + 32
__PT_R5 = __PT_GPRS + 40
__PT_R6 = __PT_GPRS + 48
__PT_R7 = __PT_GPRS + 56
__PT_R8 = __PT_GPRS + 64
__PT_R9 = __PT_GPRS + 72
__PT_R10 = __PT_GPRS + 80
__PT_R11 = __PT_GPRS + 88
__PT_R12 = __PT_GPRS + 96
__PT_R13 = __PT_GPRS + 104
__PT_R14 = __PT_GPRS + 112
__PT_R15 = __PT_GPRS + 120
STACK_SHIFT = PAGE_SHIFT + THREAD_SIZE_ORDER STACK_SHIFT = PAGE_SHIFT + THREAD_SIZE_ORDER
STACK_SIZE = 1 << STACK_SHIFT STACK_SIZE = 1 << STACK_SHIFT
STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
...@@ -268,6 +251,10 @@ ENTRY(sie64a) ...@@ -268,6 +251,10 @@ ENTRY(sie64a)
BPEXIT __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) BPEXIT __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
.Lsie_entry: .Lsie_entry:
sie 0(%r14) sie 0(%r14)
# Let the next instruction be NOP to avoid triggering a machine check
# and handling it in a guest as result of the instruction execution.
nopr 7
.Lsie_leave:
BPOFF BPOFF
BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST) BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
.Lsie_skip: .Lsie_skip:
...@@ -564,7 +551,7 @@ ENTRY(mcck_int_handler) ...@@ -564,7 +551,7 @@ ENTRY(mcck_int_handler)
jno .Lmcck_panic jno .Lmcck_panic
#if IS_ENABLED(CONFIG_KVM) #if IS_ENABLED(CONFIG_KVM)
OUTSIDE %r9,.Lsie_gmap,.Lsie_done,6f OUTSIDE %r9,.Lsie_gmap,.Lsie_done,6f
OUTSIDE %r9,.Lsie_entry,.Lsie_skip,4f OUTSIDE %r9,.Lsie_entry,.Lsie_leave,4f
oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
j 5f j 5f
4: CHKSTG .Lmcck_panic 4: CHKSTG .Lmcck_panic
......
...@@ -17,10 +17,12 @@ void ext_int_handler(void); ...@@ -17,10 +17,12 @@ void ext_int_handler(void);
void io_int_handler(void); void io_int_handler(void);
void mcck_int_handler(void); void mcck_int_handler(void);
void restart_int_handler(void); void restart_int_handler(void);
void early_pgm_check_handler(void);
void __ret_from_fork(struct task_struct *prev, struct pt_regs *regs); void __ret_from_fork(struct task_struct *prev, struct pt_regs *regs);
void __do_pgm_check(struct pt_regs *regs); void __do_pgm_check(struct pt_regs *regs);
void __do_syscall(struct pt_regs *regs, int per_trap); void __do_syscall(struct pt_regs *regs, int per_trap);
void __do_early_pgm_check(struct pt_regs *regs);
void do_protection_exception(struct pt_regs *regs); void do_protection_exception(struct pt_regs *regs);
void do_dat_exception(struct pt_regs *regs); void do_dat_exception(struct pt_regs *regs);
......
...@@ -30,7 +30,7 @@ static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs) ...@@ -30,7 +30,7 @@ static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs)
if (!stack) if (!stack)
return NULL; return NULL;
return (struct kvm_s390_sie_block *) stack->empty1[0]; return (struct kvm_s390_sie_block *)stack->sie_control_block;
} }
static bool is_in_guest(struct pt_regs *regs) static bool is_in_guest(struct pt_regs *regs)
......
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <linux/bitfield.h>
#include <linux/extable.h> #include <linux/extable.h>
#include <linux/string.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/panic.h> #include <linux/panic.h>
#include <asm/asm-extable.h> #include <asm/asm-extable.h>
...@@ -24,9 +26,34 @@ static bool ex_handler_fixup(const struct exception_table_entry *ex, struct pt_r ...@@ -24,9 +26,34 @@ static bool ex_handler_fixup(const struct exception_table_entry *ex, struct pt_r
return true; return true;
} }
static bool ex_handler_uaccess(const struct exception_table_entry *ex, struct pt_regs *regs) static bool ex_handler_ua_store(const struct exception_table_entry *ex, struct pt_regs *regs)
{ {
regs->gprs[ex->data] = -EFAULT; unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
regs->gprs[reg_err] = -EFAULT;
regs->psw.addr = extable_fixup(ex);
return true;
}
static bool ex_handler_ua_load_mem(const struct exception_table_entry *ex, struct pt_regs *regs)
{
unsigned int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
size_t len = FIELD_GET(EX_DATA_LEN, ex->data);
regs->gprs[reg_err] = -EFAULT;
memset((void *)regs->gprs[reg_addr], 0, len);
regs->psw.addr = extable_fixup(ex);
return true;
}
static bool ex_handler_ua_load_reg(const struct exception_table_entry *ex, struct pt_regs *regs)
{
unsigned int reg_zero = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
unsigned int reg_err = FIELD_GET(EX_DATA_REG_ERR, ex->data);
regs->gprs[reg_err] = -EFAULT;
regs->gprs[reg_zero] = 0;
regs->psw.addr = extable_fixup(ex); regs->psw.addr = extable_fixup(ex);
return true; return true;
} }
...@@ -43,8 +70,12 @@ bool fixup_exception(struct pt_regs *regs) ...@@ -43,8 +70,12 @@ bool fixup_exception(struct pt_regs *regs)
return ex_handler_fixup(ex, regs); return ex_handler_fixup(ex, regs);
case EX_TYPE_BPF: case EX_TYPE_BPF:
return ex_handler_bpf(ex, regs); return ex_handler_bpf(ex, regs);
case EX_TYPE_UACCESS: case EX_TYPE_UA_STORE:
return ex_handler_uaccess(ex, regs); return ex_handler_ua_store(ex, regs);
case EX_TYPE_UA_LOAD_MEM:
return ex_handler_ua_load_mem(ex, regs);
case EX_TYPE_UA_LOAD_REG:
return ex_handler_ua_load_reg(ex, regs);
} }
panic("invalid exception table entry"); panic("invalid exception table entry");
} }
...@@ -2608,6 +2608,18 @@ static int __s390_enable_skey_pte(pte_t *pte, unsigned long addr, ...@@ -2608,6 +2608,18 @@ static int __s390_enable_skey_pte(pte_t *pte, unsigned long addr,
return 0; return 0;
} }
/*
* Give a chance to schedule after setting a key to 256 pages.
* We only hold the mm lock, which is a rwsem and the kvm srcu.
* Both can sleep.
*/
static int __s390_enable_skey_pmd(pmd_t *pmd, unsigned long addr,
unsigned long next, struct mm_walk *walk)
{
cond_resched();
return 0;
}
static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr, static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr,
unsigned long hmask, unsigned long next, unsigned long hmask, unsigned long next,
struct mm_walk *walk) struct mm_walk *walk)
...@@ -2630,12 +2642,14 @@ static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr, ...@@ -2630,12 +2642,14 @@ static int __s390_enable_skey_hugetlb(pte_t *pte, unsigned long addr,
end = start + HPAGE_SIZE - 1; end = start + HPAGE_SIZE - 1;
__storage_key_init_range(start, end); __storage_key_init_range(start, end);
set_bit(PG_arch_1, &page->flags); set_bit(PG_arch_1, &page->flags);
cond_resched();
return 0; return 0;
} }
static const struct mm_walk_ops enable_skey_walk_ops = { static const struct mm_walk_ops enable_skey_walk_ops = {
.hugetlb_entry = __s390_enable_skey_hugetlb, .hugetlb_entry = __s390_enable_skey_hugetlb,
.pte_entry = __s390_enable_skey_pte, .pte_entry = __s390_enable_skey_pte,
.pmd_entry = __s390_enable_skey_pmd,
}; };
int s390_enable_skey(void) int s390_enable_skey(void)
......
...@@ -748,7 +748,7 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ...@@ -748,7 +748,7 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
pgste_val(pgste) |= PGSTE_GR_BIT | PGSTE_GC_BIT; pgste_val(pgste) |= PGSTE_GR_BIT | PGSTE_GC_BIT;
ptev = pte_val(*ptep); ptev = pte_val(*ptep);
if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE)) if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE))
page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 1); page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 0);
pgste_set_unlock(ptep, pgste); pgste_set_unlock(ptep, pgste);
preempt_enable(); preempt_enable();
} }
......
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