Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Heiko Carstens: "Since Martin is on vacation you get the s390 pull request for the v4.15 merge window this time from me. Besides a lot of cleanups and bug fixes these are the most important changes: - a new regset for runtime instrumentation registers - hardware accelerated AES-GCM support for the aes_s390 module - support for the new CEX6S crypto cards - support for FORTIFY_SOURCE - addition of missing z13 and new z14 instructions to the in-kernel disassembler - generate opcode tables for the in-kernel disassembler out of a simple text file instead of having to manually maintain those tables - fast memset16, memset32 and memset64 implementations - removal of named saved segment support - hardware counter support for z14 - queued spinlocks and queued rwlocks implementations for s390 - use the stack_depth tracking feature for s390 BPF JIT - a new s390_sthyi system call which emulates the sthyi (store hypervisor information) instruction - removal of the old KVM virtio transport - an s390 specific CPU alternatives implementation which is used in the new spinlock code" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (88 commits) MAINTAINERS: add virtio-ccw.h to virtio/s390 section s390/noexec: execute kexec datamover without DAT s390: fix transactional execution control register handling s390/bpf: take advantage of stack_depth tracking s390: simplify transactional execution elf hwcap handling s390/zcrypt: Rework struct ap_qact_ap_info. s390/virtio: remove unused header file kvm_virtio.h s390: avoid undefined behaviour s390/disassembler: generate opcode tables from text file s390/disassembler: remove insn_to_mnemonic() s390/dasd: avoid calling do_gettimeofday() s390: vfio-ccw: Do not attempt to free no-op, test and tic cda. s390: remove named saved segment support s390/archrandom: Reconsider s390 arch random implementation s390/pci: do not require AIS facility s390/qdio: sanitize put_indicator s390/qdio: use atomic_cmpxchg s390/nmi: avoid using long-displacement facility s390: pass endianness info to sparse s390/decompressor: remove informational messages ...
This commit is contained in:
@@ -31,6 +31,9 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/switch_to.h>
|
||||
#include <asm/runtime_instr.h>
|
||||
#include <asm/facility.h>
|
||||
|
||||
#include "entry.h"
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
@@ -45,42 +48,42 @@ void update_cr_regs(struct task_struct *task)
|
||||
struct pt_regs *regs = task_pt_regs(task);
|
||||
struct thread_struct *thread = &task->thread;
|
||||
struct per_regs old, new;
|
||||
unsigned long cr0_old, cr0_new;
|
||||
unsigned long cr2_old, cr2_new;
|
||||
union ctlreg0 cr0_old, cr0_new;
|
||||
union ctlreg2 cr2_old, cr2_new;
|
||||
int cr0_changed, cr2_changed;
|
||||
|
||||
__ctl_store(cr0_old, 0, 0);
|
||||
__ctl_store(cr2_old, 2, 2);
|
||||
__ctl_store(cr0_old.val, 0, 0);
|
||||
__ctl_store(cr2_old.val, 2, 2);
|
||||
cr0_new = cr0_old;
|
||||
cr2_new = cr2_old;
|
||||
/* Take care of the enable/disable of transactional execution. */
|
||||
if (MACHINE_HAS_TE) {
|
||||
/* Set or clear transaction execution TXC bit 8. */
|
||||
cr0_new |= (1UL << 55);
|
||||
cr0_new.tcx = 1;
|
||||
if (task->thread.per_flags & PER_FLAG_NO_TE)
|
||||
cr0_new &= ~(1UL << 55);
|
||||
cr0_new.tcx = 0;
|
||||
/* Set or clear transaction execution TDC bits 62 and 63. */
|
||||
cr2_new &= ~3UL;
|
||||
cr2_new.tdc = 0;
|
||||
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND) {
|
||||
if (task->thread.per_flags & PER_FLAG_TE_ABORT_RAND_TEND)
|
||||
cr2_new |= 1UL;
|
||||
cr2_new.tdc = 1;
|
||||
else
|
||||
cr2_new |= 2UL;
|
||||
cr2_new.tdc = 2;
|
||||
}
|
||||
}
|
||||
/* Take care of enable/disable of guarded storage. */
|
||||
if (MACHINE_HAS_GS) {
|
||||
cr2_new &= ~(1UL << 4);
|
||||
cr2_new.gse = 0;
|
||||
if (task->thread.gs_cb)
|
||||
cr2_new |= (1UL << 4);
|
||||
cr2_new.gse = 1;
|
||||
}
|
||||
/* Load control register 0/2 iff changed */
|
||||
cr0_changed = cr0_new != cr0_old;
|
||||
cr2_changed = cr2_new != cr2_old;
|
||||
cr0_changed = cr0_new.val != cr0_old.val;
|
||||
cr2_changed = cr2_new.val != cr2_old.val;
|
||||
if (cr0_changed)
|
||||
__ctl_load(cr0_new, 0, 0);
|
||||
__ctl_load(cr0_new.val, 0, 0);
|
||||
if (cr2_changed)
|
||||
__ctl_load(cr2_new, 2, 2);
|
||||
__ctl_load(cr2_new.val, 2, 2);
|
||||
/* Copy user specified PER registers */
|
||||
new.control = thread->per_user.control;
|
||||
new.start = thread->per_user.start;
|
||||
@@ -1172,26 +1175,37 @@ static int s390_gs_cb_set(struct task_struct *target,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct gs_cb *data = target->thread.gs_cb;
|
||||
struct gs_cb gs_cb = { }, *data = NULL;
|
||||
int rc;
|
||||
|
||||
if (!MACHINE_HAS_GS)
|
||||
return -ENODEV;
|
||||
if (!data) {
|
||||
if (!target->thread.gs_cb) {
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
data->gsd = 25;
|
||||
target->thread.gs_cb = data;
|
||||
if (target == current)
|
||||
__ctl_set_bit(2, 4);
|
||||
} else if (target == current) {
|
||||
save_gs_cb(data);
|
||||
}
|
||||
if (!target->thread.gs_cb)
|
||||
gs_cb.gsd = 25;
|
||||
else if (target == current)
|
||||
save_gs_cb(&gs_cb);
|
||||
else
|
||||
gs_cb = *target->thread.gs_cb;
|
||||
rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
data, 0, sizeof(struct gs_cb));
|
||||
if (target == current)
|
||||
restore_gs_cb(data);
|
||||
&gs_cb, 0, sizeof(gs_cb));
|
||||
if (rc) {
|
||||
kfree(data);
|
||||
return -EFAULT;
|
||||
}
|
||||
preempt_disable();
|
||||
if (!target->thread.gs_cb)
|
||||
target->thread.gs_cb = data;
|
||||
*target->thread.gs_cb = gs_cb;
|
||||
if (target == current) {
|
||||
__ctl_set_bit(2, 4);
|
||||
restore_gs_cb(target->thread.gs_cb);
|
||||
}
|
||||
preempt_enable();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1229,6 +1243,96 @@ static int s390_gs_bc_set(struct task_struct *target,
|
||||
data, 0, sizeof(struct gs_cb));
|
||||
}
|
||||
|
||||
static bool is_ri_cb_valid(struct runtime_instr_cb *cb)
|
||||
{
|
||||
return (cb->rca & 0x1f) == 0 &&
|
||||
(cb->roa & 0xfff) == 0 &&
|
||||
(cb->rla & 0xfff) == 0xfff &&
|
||||
cb->s == 1 &&
|
||||
cb->k == 1 &&
|
||||
cb->h == 0 &&
|
||||
cb->reserved1 == 0 &&
|
||||
cb->ps == 1 &&
|
||||
cb->qs == 0 &&
|
||||
cb->pc == 1 &&
|
||||
cb->qc == 0 &&
|
||||
cb->reserved2 == 0 &&
|
||||
cb->key == PAGE_DEFAULT_KEY &&
|
||||
cb->reserved3 == 0 &&
|
||||
cb->reserved4 == 0 &&
|
||||
cb->reserved5 == 0 &&
|
||||
cb->reserved6 == 0 &&
|
||||
cb->reserved7 == 0 &&
|
||||
cb->reserved8 == 0 &&
|
||||
cb->rla >= cb->roa &&
|
||||
cb->rca >= cb->roa &&
|
||||
cb->rca <= cb->rla+1 &&
|
||||
cb->m < 3;
|
||||
}
|
||||
|
||||
static int s390_runtime_instr_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
struct runtime_instr_cb *data = target->thread.ri_cb;
|
||||
|
||||
if (!test_facility(64))
|
||||
return -ENODEV;
|
||||
if (!data)
|
||||
return -ENODATA;
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
data, 0, sizeof(struct runtime_instr_cb));
|
||||
}
|
||||
|
||||
static int s390_runtime_instr_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
struct runtime_instr_cb ri_cb = { }, *data = NULL;
|
||||
int rc;
|
||||
|
||||
if (!test_facility(64))
|
||||
return -ENODEV;
|
||||
|
||||
if (!target->thread.ri_cb) {
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (target->thread.ri_cb) {
|
||||
if (target == current)
|
||||
store_runtime_instr_cb(&ri_cb);
|
||||
else
|
||||
ri_cb = *target->thread.ri_cb;
|
||||
}
|
||||
|
||||
rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&ri_cb, 0, sizeof(struct runtime_instr_cb));
|
||||
if (rc) {
|
||||
kfree(data);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!is_ri_cb_valid(&ri_cb)) {
|
||||
kfree(data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
preempt_disable();
|
||||
if (!target->thread.ri_cb)
|
||||
target->thread.ri_cb = data;
|
||||
*target->thread.ri_cb = ri_cb;
|
||||
if (target == current)
|
||||
load_runtime_instr_cb(target->thread.ri_cb);
|
||||
preempt_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct user_regset s390_regsets[] = {
|
||||
{
|
||||
.core_note_type = NT_PRSTATUS,
|
||||
@@ -1302,6 +1406,14 @@ static const struct user_regset s390_regsets[] = {
|
||||
.get = s390_gs_bc_get,
|
||||
.set = s390_gs_bc_set,
|
||||
},
|
||||
{
|
||||
.core_note_type = NT_S390_RI_CB,
|
||||
.n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_runtime_instr_get,
|
||||
.set = s390_runtime_instr_set,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_s390_view = {
|
||||
@@ -1538,6 +1650,14 @@ static const struct user_regset s390_compat_regsets[] = {
|
||||
.get = s390_gs_cb_get,
|
||||
.set = s390_gs_cb_set,
|
||||
},
|
||||
{
|
||||
.core_note_type = NT_S390_RI_CB,
|
||||
.n = sizeof(struct runtime_instr_cb) / sizeof(__u64),
|
||||
.size = sizeof(__u64),
|
||||
.align = sizeof(__u64),
|
||||
.get = s390_runtime_instr_get,
|
||||
.set = s390_runtime_instr_set,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_s390_compat_view = {
|
||||
|
Reference in New Issue
Block a user