Skip to content

Commit

Permalink
Merge tag 'kvm-s390-next-4.15-1' of git://git.kernel.org/pub/scm/linu…
Browse files Browse the repository at this point in the history
…x/kernel/git/kvms390/linux

KVM: s390: fixes and improvements for 4.15

- Some initial preparation patches for exitless interrupts and crypto
- New capability for AIS migration
- Fixes
- merge of the sthyi tree from the base s390 team, which moves the sthyi
out of KVM into a shared function also for non-KVM
  • Loading branch information
rkrcmar committed Nov 16, 2017
2 parents 61d7507 + da9a144 commit a6014f1
Show file tree
Hide file tree
Showing 20 changed files with 262 additions and 113 deletions.
9 changes: 9 additions & 0 deletions Documentation/virtual/kvm/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4351,3 +4351,12 @@ This capability indicates that userspace can load HV_X64_MSR_VP_INDEX msr. Its
value is used to denote the target vcpu for a SynIC interrupt. For
compatibilty, KVM initializes this msr to KVM's internal vcpu index. When this
capability is absent, userspace can still query this msr's value.

8.13 KVM_CAP_S390_AIS_MIGRATION

Architectures: s390
Parameters: none

This capability indicates if the flic device will be able to get/set the
AIS states for migration via the KVM_DEV_FLIC_AISM_ALL attribute and allows
to discover this without having to create a flic device.
5 changes: 5 additions & 0 deletions Documentation/virtual/kvm/devices/s390_flic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,13 @@ struct kvm_s390_ais_all {
to an ISC (MSB0 bit 0 to ISC 0 and so on). The combination of simm bit and
nimm bit presents AIS mode for a ISC.

KVM_DEV_FLIC_AISM_ALL is indicated by KVM_CAP_S390_AIS_MIGRATION.

Note: The KVM_SET_DEVICE_ATTR/KVM_GET_DEVICE_ATTR device ioctls executed on
FLIC with an unknown group or attribute gives the error code EINVAL (instead of
ENXIO, as specified in the API documentation). It is not possible to conclude
that a FLIC operation is unavailable based on the error code resulting from a
usage attempt.

Note: The KVM_DEV_FLIC_CLEAR_IO_IRQ ioctl will return EINVAL in case a zero
schid is specified.
26 changes: 21 additions & 5 deletions arch/s390/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -685,11 +685,28 @@ struct kvm_s390_crypto {
__u8 dea_kw;
};

#define APCB0_MASK_SIZE 1
struct kvm_s390_apcb0 {
__u64 apm[APCB0_MASK_SIZE]; /* 0x0000 */
__u64 aqm[APCB0_MASK_SIZE]; /* 0x0008 */
__u64 adm[APCB0_MASK_SIZE]; /* 0x0010 */
__u64 reserved18; /* 0x0018 */
};

#define APCB1_MASK_SIZE 4
struct kvm_s390_apcb1 {
__u64 apm[APCB1_MASK_SIZE]; /* 0x0000 */
__u64 aqm[APCB1_MASK_SIZE]; /* 0x0020 */
__u64 adm[APCB1_MASK_SIZE]; /* 0x0040 */
__u64 reserved60[4]; /* 0x0060 */
};

struct kvm_s390_crypto_cb {
__u8 reserved00[72]; /* 0x0000 */
__u8 dea_wrapping_key_mask[24]; /* 0x0048 */
__u8 aes_wrapping_key_mask[32]; /* 0x0060 */
__u8 reserved80[128]; /* 0x0080 */
struct kvm_s390_apcb0 apcb0; /* 0x0000 */
__u8 reserved20[0x0048 - 0x0020]; /* 0x0020 */
__u8 dea_wrapping_key_mask[24]; /* 0x0048 */
__u8 aes_wrapping_key_mask[32]; /* 0x0060 */
struct kvm_s390_apcb1 apcb1; /* 0x0080 */
};

/*
Expand Down Expand Up @@ -736,7 +753,6 @@ struct kvm_arch{
wait_queue_head_t ipte_wq;
int ipte_lock_count;
struct mutex ipte_mutex;
struct ratelimit_state sthyi_limit;
spinlock_t start_stop_lock;
struct sie_page2 *sie_page2;
struct kvm_s390_cpu_model model;
Expand Down
1 change: 1 addition & 0 deletions arch/s390/include/asm/sysinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,5 @@ struct service_level {
int register_service_level(struct service_level *);
int unregister_service_level(struct service_level *);

int sthyi_fill(void *dst, u64 *rc);
#endif /* __ASM_S390_SYSINFO_H */
6 changes: 6 additions & 0 deletions arch/s390/include/uapi/asm/sthyi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef _UAPI_ASM_STHYI_H
#define _UAPI_ASM_STHYI_H

#define STHYI_FC_CP_IFL_CAP 0

#endif /* _UAPI_ASM_STHYI_H */
3 changes: 2 additions & 1 deletion arch/s390/include/uapi/asm/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,8 @@
#define __NR_pwritev2 377
#define __NR_s390_guarded_storage 378
#define __NR_statx 379
#define NR_syscalls 380
#define __NR_s390_sthyi 380
#define NR_syscalls 381

/*
* There are some system calls that are not present on 64 bit, some
Expand Down
2 changes: 1 addition & 1 deletion arch/s390/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
obj-y += processor.o sys_s390.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 als.o
obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o
obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o
obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o

extra-y += head.o head64.o vmlinux.lds
Expand Down
1 change: 1 addition & 0 deletions arch/s390/kernel/compat_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,4 @@ 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);
1 change: 1 addition & 0 deletions arch/s390/kernel/entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ long sys_s390_runtime_instr(int command, int signum);
long sys_s390_guarded_storage(int command, struct gs_cb __user *);
long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t);
long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
long sys_s390_sthyi(unsigned long function_code, void __user *buffer, u64 __user *return_code, unsigned long flags);

DECLARE_PER_CPU(u64, mt_cycles[8]);

Expand Down
172 changes: 110 additions & 62 deletions arch/s390/kvm/sthyi.c → arch/s390/kernel/sthyi.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,19 @@
* Copyright IBM Corp. 2016
* Author(s): Janosch Frank <[email protected]>
*/
#include <linux/kvm_host.h>
#include <linux/errno.h>
#include <linux/pagemap.h>
#include <linux/vmalloc.h>
#include <linux/ratelimit.h>

#include <asm/kvm_host.h>
#include <linux/syscalls.h>
#include <linux/mutex.h>
#include <asm/asm-offsets.h>
#include <asm/sclp.h>
#include <asm/diag.h>
#include <asm/sysinfo.h>
#include <asm/ebcdic.h>

#include "kvm-s390.h"
#include "gaccess.h"
#include "trace.h"
#include <asm/facility.h>
#include <asm/sthyi.h>
#include "entry.h"

#define DED_WEIGHT 0xffff
/*
Expand Down Expand Up @@ -144,6 +141,21 @@ struct lpar_cpu_inf {
struct cpu_inf ifl;
};

/*
* STHYI requires extensive locking in the higher hypervisors
* and is very computational/memory expensive. Therefore we
* cache the retrieved data whose valid period is 1s.
*/
#define CACHE_VALID_JIFFIES HZ

struct sthyi_info {
void *info;
unsigned long end;
};

static DEFINE_MUTEX(sthyi_mutex);
static struct sthyi_info sthyi_cache;

static inline u64 cpu_id(u8 ctidx, void *diag224_buf)
{
return *((u64 *)(diag224_buf + (ctidx + 1) * DIAG204_CPU_NAME_LEN));
Expand Down Expand Up @@ -382,88 +394,124 @@ static void fill_diag(struct sthyi_sctns *sctns)
vfree(diag204_buf);
}

static int sthyi(u64 vaddr)
static int sthyi(u64 vaddr, u64 *rc)
{
register u64 code asm("0") = 0;
register u64 addr asm("2") = vaddr;
register u64 rcode asm("3");
int cc;

asm volatile(
".insn rre,0xB2560000,%[code],%[addr]\n"
"ipm %[cc]\n"
"srl %[cc],28\n"
: [cc] "=d" (cc)
: [cc] "=d" (cc), "=d" (rcode)
: [code] "d" (code), [addr] "a" (addr)
: "3", "memory", "cc");
: "memory", "cc");
*rc = rcode;
return cc;
}

int handle_sthyi(struct kvm_vcpu *vcpu)
static int fill_dst(void *dst, u64 *rc)
{
int reg1, reg2, r = 0;
u64 code, addr, cc = 0;
struct sthyi_sctns *sctns = NULL;

if (!test_kvm_facility(vcpu->kvm, 74))
return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
struct sthyi_sctns *sctns = (struct sthyi_sctns *)dst;

/*
* STHYI requires extensive locking in the higher hypervisors
* and is very computational/memory expensive. Therefore we
* ratelimit the executions per VM.
* If the facility is on, we don't want to emulate the instruction.
* We ask the hypervisor to provide the data.
*/
if (!__ratelimit(&vcpu->kvm->arch.sthyi_limit)) {
kvm_s390_retry_instr(vcpu);
if (test_facility(74))
return sthyi((u64)dst, rc);

fill_hdr(sctns);
fill_stsi(sctns);
fill_diag(sctns);
*rc = 0;
return 0;
}

static int sthyi_init_cache(void)
{
if (sthyi_cache.info)
return 0;
}
sthyi_cache.info = (void *)get_zeroed_page(GFP_KERNEL);
if (!sthyi_cache.info)
return -ENOMEM;
sthyi_cache.end = jiffies - 1; /* expired */
return 0;
}

kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
code = vcpu->run->s.regs.gprs[reg1];
addr = vcpu->run->s.regs.gprs[reg2];
static int sthyi_update_cache(u64 *rc)
{
int r;

vcpu->stat.instruction_sthyi++;
VCPU_EVENT(vcpu, 3, "STHYI: fc: %llu addr: 0x%016llx", code, addr);
trace_kvm_s390_handle_sthyi(vcpu, code, addr);
memset(sthyi_cache.info, 0, PAGE_SIZE);
r = fill_dst(sthyi_cache.info, rc);
if (r)
return r;
sthyi_cache.end = jiffies + CACHE_VALID_JIFFIES;
return r;
}

if (reg1 == reg2 || reg1 & 1 || reg2 & 1)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
/*
* sthyi_fill - Fill page with data returned by the STHYI instruction
*
* @dst: Pointer to zeroed page
* @rc: Pointer for storing the return code of the instruction
*
* Fills the destination with system information returned by the STHYI
* instruction. The data is generated by emulation or execution of STHYI,
* if available. The return value is the condition code that would be
* returned, the rc parameter is the return code which is passed in
* register R2 + 1.
*/
int sthyi_fill(void *dst, u64 *rc)
{
int r;

if (code & 0xffff) {
cc = 3;
mutex_lock(&sthyi_mutex);
r = sthyi_init_cache();
if (r)
goto out;
}

if (addr & ~PAGE_MASK)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
if (time_is_before_jiffies(sthyi_cache.end)) {
/* cache expired */
r = sthyi_update_cache(rc);
if (r)
goto out;
}
*rc = 0;
memcpy(dst, sthyi_cache.info, PAGE_SIZE);
out:
mutex_unlock(&sthyi_mutex);
return r;
}
EXPORT_SYMBOL_GPL(sthyi_fill);

sctns = (void *)get_zeroed_page(GFP_KERNEL);
if (!sctns)
SYSCALL_DEFINE4(s390_sthyi, unsigned long, function_code, void __user *, buffer,
u64 __user *, return_code, unsigned long, flags)
{
u64 sthyi_rc;
void *info;
int r;

if (flags)
return -EINVAL;
if (function_code != STHYI_FC_CP_IFL_CAP)
return -EOPNOTSUPP;
info = (void *)get_zeroed_page(GFP_KERNEL);
if (!info)
return -ENOMEM;

/*
* If we are a guest, we don't want to emulate an emulated
* instruction. We ask the hypervisor to provide the data.
*/
if (test_facility(74)) {
cc = sthyi((u64)sctns);
r = sthyi_fill(info, &sthyi_rc);
if (r < 0)
goto out;
if (return_code && put_user(sthyi_rc, return_code)) {
r = -EFAULT;
goto out;
}

fill_hdr(sctns);
fill_stsi(sctns);
fill_diag(sctns);

if (copy_to_user(buffer, info, PAGE_SIZE))
r = -EFAULT;
out:
if (!cc) {
r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
if (r) {
free_page((unsigned long)sctns);
return kvm_s390_inject_prog_cond(vcpu, r);
}
}

free_page((unsigned long)sctns);
vcpu->run->s.regs.gprs[reg2 + 1] = cc ? 4 : 0;
kvm_s390_set_psw_cc(vcpu, cc);
free_page((unsigned long)info);
return r;
}
1 change: 1 addition & 0 deletions arch/s390/kernel/syscalls.S
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,4 @@ SYSCALL(sys_preadv2,compat_sys_preadv2)
SYSCALL(sys_pwritev2,compat_sys_pwritev2)
SYSCALL(sys_s390_guarded_storage,compat_sys_s390_guarded_storage) /* 378 */
SYSCALL(sys_statx,compat_sys_statx)
SYSCALL(sys_s390_sthyi,compat_sys_s390_sthyi)
2 changes: 1 addition & 1 deletion arch/s390/kvm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/async_pf.o $(KVM)/irqch
ccflags-y := -Ivirt/kvm -Iarch/s390/kvm

kvm-objs := $(common-objs) kvm-s390.o intercept.o interrupt.o priv.o sigp.o
kvm-objs += diag.o gaccess.o guestdbg.o sthyi.o vsie.o
kvm-objs += diag.o gaccess.o guestdbg.o vsie.o

obj-$(CONFIG_KVM) += kvm.o
Loading

0 comments on commit a6014f1

Please sign in to comment.