mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
KVM: s390: Fixes and cleanups
1. A small fix regarding program check handling (cc stable as it overwrites the wrong guest memory) 2. Improve the ipte interlock scalability for older hardware 3. current->mm to mm cleanup (currently a no-op) 4. several SIGP rework patches (more to come) -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJUT48bAAoJEBF7vIC1phx8P4EP/2QO6ZGHMKFXzvOex9mhesGt VUxmqJBwZe3xJqEr6LM7Fr7yHE4+UMg+LjV6ZeXL1KHFGZJ8mo8AOlQcx86r05+9 KARmX1K0RIBHUsGhWCAwjD9I5xWoIO56mH0jQetIuInjAMPU0TnQ4Ufh6WXTARG8 O1HRdqO91yikXRIkWw/9JN07MGaavdWbjyk+FhT39yIDqZckdzYkOmLyws9CskNS r3g9vl5kV251c28dVVr9+1j3Kd/OD06k3aGNUVenUGmbEjszl6/uoQn8swVri/eZ eLOCTYMaUBF3lbbl3H6g237x1/V49bwyfczDE1DxJ1y1fOcJlG8XQRf6g1p6jfSG j2yjl00YvsRnwuDTeW9OVmDwLK+r6IYP2QqDplW/XNS9BegTBTO3pqc/XDPqGZT7 a88vuFvD94coaqVJabXDVebzHfbskSEPkBI13QmbhxA9/a7nPpuNhws595dadn77 w9C7QKpSPtnBibDvN3atmKoekseY/3Iap/9KS3WT4mJPjHRTmt30ttZukDIcfaG7 oSi1sysXHFBmr20ZZhhqcIP2RFdlX3Efh++dZBYnAODzKIIZgjtdRutXagyXDlM/ w6Pb75/Jep19zlxVKcLNMudgxn67Ezf3f0jSbppPc16A53xkqK5f6wyTiNS1bv+q TL3JD2JA0O90ARd1AbEE =npsV -----END PGP SIGNATURE----- Merge tag 'kvm-s390-next-20141028' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD KVM: s390: Fixes and cleanups 1. A small fix regarding program check handling (cc stable as it overwrites the wrong guest memory) 2. Improve the ipte interlock scalability for older hardware 3. current->mm to mm cleanup (currently a no-op) 4. several SIGP rework patches (more to come)
This commit is contained in:
commit
f62c95fd40
@ -226,10 +226,17 @@ struct kvm_vcpu_stat {
|
||||
u32 instruction_sigp_sense_running;
|
||||
u32 instruction_sigp_external_call;
|
||||
u32 instruction_sigp_emergency;
|
||||
u32 instruction_sigp_cond_emergency;
|
||||
u32 instruction_sigp_start;
|
||||
u32 instruction_sigp_stop;
|
||||
u32 instruction_sigp_stop_store_status;
|
||||
u32 instruction_sigp_store_status;
|
||||
u32 instruction_sigp_arch;
|
||||
u32 instruction_sigp_prefix;
|
||||
u32 instruction_sigp_restart;
|
||||
u32 instruction_sigp_init_cpu_reset;
|
||||
u32 instruction_sigp_cpu_reset;
|
||||
u32 instruction_sigp_unknown;
|
||||
u32 diagnose_10;
|
||||
u32 diagnose_44;
|
||||
u32 diagnose_9c;
|
||||
@ -434,6 +441,8 @@ struct kvm_arch{
|
||||
int user_cpu_state_ctrl;
|
||||
struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
|
||||
wait_queue_head_t ipte_wq;
|
||||
int ipte_lock_count;
|
||||
struct mutex ipte_mutex;
|
||||
spinlock_t start_stop_lock;
|
||||
struct kvm_s390_crypto crypto;
|
||||
};
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define SIGP_RESTART 6
|
||||
#define SIGP_STOP_AND_STORE_STATUS 9
|
||||
#define SIGP_INITIAL_CPU_RESET 11
|
||||
#define SIGP_CPU_RESET 12
|
||||
#define SIGP_SET_PREFIX 13
|
||||
#define SIGP_STORE_STATUS_AT_ADDRESS 14
|
||||
#define SIGP_SET_ARCHITECTURE 18
|
||||
|
@ -207,8 +207,6 @@ union raddress {
|
||||
unsigned long pfra : 52; /* Page-Frame Real Address */
|
||||
};
|
||||
|
||||
static int ipte_lock_count;
|
||||
static DEFINE_MUTEX(ipte_mutex);
|
||||
|
||||
int ipte_lock_held(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
@ -216,16 +214,16 @@ int ipte_lock_held(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (vcpu->arch.sie_block->eca & 1)
|
||||
return ic->kh != 0;
|
||||
return ipte_lock_count != 0;
|
||||
return vcpu->kvm->arch.ipte_lock_count != 0;
|
||||
}
|
||||
|
||||
static void ipte_lock_simple(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
union ipte_control old, new, *ic;
|
||||
|
||||
mutex_lock(&ipte_mutex);
|
||||
ipte_lock_count++;
|
||||
if (ipte_lock_count > 1)
|
||||
mutex_lock(&vcpu->kvm->arch.ipte_mutex);
|
||||
vcpu->kvm->arch.ipte_lock_count++;
|
||||
if (vcpu->kvm->arch.ipte_lock_count > 1)
|
||||
goto out;
|
||||
ic = &vcpu->kvm->arch.sca->ipte_control;
|
||||
do {
|
||||
@ -238,16 +236,16 @@ static void ipte_lock_simple(struct kvm_vcpu *vcpu)
|
||||
new.k = 1;
|
||||
} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
|
||||
out:
|
||||
mutex_unlock(&ipte_mutex);
|
||||
mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
|
||||
}
|
||||
|
||||
static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
union ipte_control old, new, *ic;
|
||||
|
||||
mutex_lock(&ipte_mutex);
|
||||
ipte_lock_count--;
|
||||
if (ipte_lock_count)
|
||||
mutex_lock(&vcpu->kvm->arch.ipte_mutex);
|
||||
vcpu->kvm->arch.ipte_lock_count--;
|
||||
if (vcpu->kvm->arch.ipte_lock_count)
|
||||
goto out;
|
||||
ic = &vcpu->kvm->arch.sca->ipte_control;
|
||||
do {
|
||||
@ -256,7 +254,7 @@ static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
|
||||
} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
|
||||
wake_up(&vcpu->kvm->arch.ipte_wq);
|
||||
out:
|
||||
mutex_unlock(&ipte_mutex);
|
||||
mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
|
||||
}
|
||||
|
||||
static void ipte_lock_siif(struct kvm_vcpu *vcpu)
|
||||
|
@ -270,7 +270,7 @@ static int __must_check __deliver_prog_irq(struct kvm_vcpu *vcpu,
|
||||
break;
|
||||
case PGM_MONITOR:
|
||||
rc = put_guest_lc(vcpu, pgm_info->mon_class_nr,
|
||||
(u64 *)__LC_MON_CLASS_NR);
|
||||
(u16 *)__LC_MON_CLASS_NR);
|
||||
rc |= put_guest_lc(vcpu, pgm_info->mon_code,
|
||||
(u64 *)__LC_MON_CODE);
|
||||
break;
|
||||
|
@ -81,10 +81,17 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
|
||||
{ "instruction_sigp_sense_running", VCPU_STAT(instruction_sigp_sense_running) },
|
||||
{ "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) },
|
||||
{ "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) },
|
||||
{ "instruction_sigp_cond_emergency", VCPU_STAT(instruction_sigp_cond_emergency) },
|
||||
{ "instruction_sigp_start", VCPU_STAT(instruction_sigp_start) },
|
||||
{ "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) },
|
||||
{ "instruction_sigp_stop_store_status", VCPU_STAT(instruction_sigp_stop_store_status) },
|
||||
{ "instruction_sigp_store_status", VCPU_STAT(instruction_sigp_store_status) },
|
||||
{ "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) },
|
||||
{ "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) },
|
||||
{ "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) },
|
||||
{ "instruction_sigp_cpu_reset", VCPU_STAT(instruction_sigp_cpu_reset) },
|
||||
{ "instruction_sigp_init_cpu_reset", VCPU_STAT(instruction_sigp_init_cpu_reset) },
|
||||
{ "instruction_sigp_unknown", VCPU_STAT(instruction_sigp_unknown) },
|
||||
{ "diagnose_10", VCPU_STAT(diagnose_10) },
|
||||
{ "diagnose_44", VCPU_STAT(diagnose_44) },
|
||||
{ "diagnose_9c", VCPU_STAT(diagnose_9c) },
|
||||
@ -453,6 +460,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
|
||||
spin_lock_init(&kvm->arch.float_int.lock);
|
||||
INIT_LIST_HEAD(&kvm->arch.float_int.list);
|
||||
init_waitqueue_head(&kvm->arch.ipte_wq);
|
||||
mutex_init(&kvm->arch.ipte_mutex);
|
||||
|
||||
debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
|
||||
VM_EVENT(kvm, 3, "%s", "vm created");
|
||||
|
@ -20,20 +20,13 @@
|
||||
#include "kvm-s390.h"
|
||||
#include "trace.h"
|
||||
|
||||
static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
|
||||
static int __sigp_sense(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
|
||||
u64 *reg)
|
||||
{
|
||||
struct kvm_s390_local_interrupt *li;
|
||||
struct kvm_vcpu *dst_vcpu = NULL;
|
||||
int cpuflags;
|
||||
int rc;
|
||||
|
||||
if (cpu_addr >= KVM_MAX_VCPUS)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
|
||||
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
|
||||
if (!dst_vcpu)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
li = &dst_vcpu->arch.local_int;
|
||||
|
||||
cpuflags = atomic_read(li->cpuflags);
|
||||
@ -48,55 +41,53 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
|
||||
rc = SIGP_CC_STATUS_STORED;
|
||||
}
|
||||
|
||||
VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", cpu_addr, rc);
|
||||
VCPU_EVENT(vcpu, 4, "sensed status of cpu %x rc %x", dst_vcpu->vcpu_id,
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
|
||||
static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu *dst_vcpu)
|
||||
{
|
||||
struct kvm_s390_interrupt s390int = {
|
||||
.type = KVM_S390_INT_EMERGENCY,
|
||||
.parm = vcpu->vcpu_id,
|
||||
};
|
||||
struct kvm_vcpu *dst_vcpu = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (cpu_addr < KVM_MAX_VCPUS)
|
||||
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
|
||||
if (!dst_vcpu)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
|
||||
rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
|
||||
if (!rc)
|
||||
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
|
||||
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x",
|
||||
dst_vcpu->vcpu_id);
|
||||
|
||||
return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr,
|
||||
static int __sigp_emergency(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu)
|
||||
{
|
||||
return __inject_sigp_emergency(vcpu, dst_vcpu);
|
||||
}
|
||||
|
||||
static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu *dst_vcpu,
|
||||
u16 asn, u64 *reg)
|
||||
{
|
||||
struct kvm_vcpu *dst_vcpu = NULL;
|
||||
const u64 psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
|
||||
u16 p_asn, s_asn;
|
||||
psw_t *psw;
|
||||
u32 flags;
|
||||
|
||||
if (cpu_addr < KVM_MAX_VCPUS)
|
||||
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
|
||||
if (!dst_vcpu)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
flags = atomic_read(&dst_vcpu->arch.sie_block->cpuflags);
|
||||
psw = &dst_vcpu->arch.sie_block->gpsw;
|
||||
p_asn = dst_vcpu->arch.sie_block->gcr[4] & 0xffff; /* Primary ASN */
|
||||
s_asn = dst_vcpu->arch.sie_block->gcr[3] & 0xffff; /* Secondary ASN */
|
||||
|
||||
/* Deliver the emergency signal? */
|
||||
/* Inject the emergency signal? */
|
||||
if (!(flags & CPUSTAT_STOPPED)
|
||||
|| (psw->mask & psw_int_mask) != psw_int_mask
|
||||
|| ((flags & CPUSTAT_WAIT) && psw->addr != 0)
|
||||
|| (!(flags & CPUSTAT_WAIT) && (asn == p_asn || asn == s_asn))) {
|
||||
return __sigp_emergency(vcpu, cpu_addr);
|
||||
return __inject_sigp_emergency(vcpu, dst_vcpu);
|
||||
} else {
|
||||
*reg &= 0xffffffff00000000UL;
|
||||
*reg |= SIGP_STATUS_INCORRECT_STATE;
|
||||
@ -104,23 +95,19 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr,
|
||||
}
|
||||
}
|
||||
|
||||
static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
|
||||
static int __sigp_external_call(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu *dst_vcpu)
|
||||
{
|
||||
struct kvm_s390_interrupt s390int = {
|
||||
.type = KVM_S390_INT_EXTERNAL_CALL,
|
||||
.parm = vcpu->vcpu_id,
|
||||
};
|
||||
struct kvm_vcpu *dst_vcpu = NULL;
|
||||
int rc;
|
||||
|
||||
if (cpu_addr < KVM_MAX_VCPUS)
|
||||
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
|
||||
if (!dst_vcpu)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
|
||||
rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
|
||||
if (!rc)
|
||||
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr);
|
||||
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x",
|
||||
dst_vcpu->vcpu_id);
|
||||
|
||||
return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
}
|
||||
@ -160,23 +147,27 @@ static int __inject_sigp_stop(struct kvm_vcpu *dst_vcpu, int action)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __sigp_stop(struct kvm_vcpu *vcpu, u16 cpu_addr, int action)
|
||||
static int __sigp_stop(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu)
|
||||
{
|
||||
struct kvm_vcpu *dst_vcpu = NULL;
|
||||
int rc;
|
||||
|
||||
if (cpu_addr >= KVM_MAX_VCPUS)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
rc = __inject_sigp_stop(dst_vcpu, ACTION_STOP_ON_STOP);
|
||||
VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", dst_vcpu->vcpu_id);
|
||||
|
||||
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
|
||||
if (!dst_vcpu)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = __inject_sigp_stop(dst_vcpu, action);
|
||||
static int __sigp_stop_and_store_status(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu *dst_vcpu, u64 *reg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", cpu_addr);
|
||||
rc = __inject_sigp_stop(dst_vcpu, ACTION_STOP_ON_STOP |
|
||||
ACTION_STORE_ON_STOP);
|
||||
VCPU_EVENT(vcpu, 4, "sent sigp stop and store status to cpu %x",
|
||||
dst_vcpu->vcpu_id);
|
||||
|
||||
if ((action & ACTION_STORE_ON_STOP) != 0 && rc == -ESHUTDOWN) {
|
||||
if (rc == -ESHUTDOWN) {
|
||||
/* If the CPU has already been stopped, we still have
|
||||
* to save the status when doing stop-and-store. This
|
||||
* has to be done after unlocking all spinlocks. */
|
||||
@ -212,18 +203,13 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
|
||||
u64 *reg)
|
||||
static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
|
||||
u32 address, u64 *reg)
|
||||
{
|
||||
struct kvm_s390_local_interrupt *li;
|
||||
struct kvm_vcpu *dst_vcpu = NULL;
|
||||
struct kvm_s390_interrupt_info *inti;
|
||||
int rc;
|
||||
|
||||
if (cpu_addr < KVM_MAX_VCPUS)
|
||||
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
|
||||
if (!dst_vcpu)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
li = &dst_vcpu->arch.local_int;
|
||||
|
||||
/*
|
||||
@ -260,24 +246,20 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
|
||||
kvm_s390_vcpu_wakeup(dst_vcpu);
|
||||
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
|
||||
VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address);
|
||||
VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", dst_vcpu->vcpu_id,
|
||||
address);
|
||||
out_li:
|
||||
spin_unlock(&li->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu, u16 cpu_id,
|
||||
u32 addr, u64 *reg)
|
||||
static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu *dst_vcpu,
|
||||
u32 addr, u64 *reg)
|
||||
{
|
||||
struct kvm_vcpu *dst_vcpu = NULL;
|
||||
int flags;
|
||||
int rc;
|
||||
|
||||
if (cpu_id < KVM_MAX_VCPUS)
|
||||
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_id);
|
||||
if (!dst_vcpu)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
|
||||
spin_lock(&dst_vcpu->arch.local_int.lock);
|
||||
flags = atomic_read(dst_vcpu->arch.local_int.cpuflags);
|
||||
spin_unlock(&dst_vcpu->arch.local_int.lock);
|
||||
@ -297,19 +279,12 @@ static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu, u16 cpu_id,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
|
||||
u64 *reg)
|
||||
static int __sigp_sense_running(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu *dst_vcpu, u64 *reg)
|
||||
{
|
||||
struct kvm_s390_local_interrupt *li;
|
||||
struct kvm_vcpu *dst_vcpu = NULL;
|
||||
int rc;
|
||||
|
||||
if (cpu_addr >= KVM_MAX_VCPUS)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
|
||||
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
|
||||
if (!dst_vcpu)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
li = &dst_vcpu->arch.local_int;
|
||||
if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) {
|
||||
/* running */
|
||||
@ -321,18 +296,46 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
|
||||
rc = SIGP_CC_STATUS_STORED;
|
||||
}
|
||||
|
||||
VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x", cpu_addr,
|
||||
rc);
|
||||
VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x",
|
||||
dst_vcpu->vcpu_id, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Test whether the destination CPU is available and not busy */
|
||||
static int sigp_check_callable(struct kvm_vcpu *vcpu, u16 cpu_addr)
|
||||
static int __prepare_sigp_re_start(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu *dst_vcpu, u8 order_code)
|
||||
{
|
||||
struct kvm_s390_local_interrupt *li;
|
||||
int rc = SIGP_CC_ORDER_CODE_ACCEPTED;
|
||||
struct kvm_vcpu *dst_vcpu = NULL;
|
||||
struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int;
|
||||
/* handle (RE)START in user space */
|
||||
int rc = -EOPNOTSUPP;
|
||||
|
||||
spin_lock(&li->lock);
|
||||
if (li->action_bits & ACTION_STOP_ON_STOP)
|
||||
rc = SIGP_CC_BUSY;
|
||||
spin_unlock(&li->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __prepare_sigp_cpu_reset(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu *dst_vcpu, u8 order_code)
|
||||
{
|
||||
/* handle (INITIAL) CPU RESET in user space */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int __prepare_sigp_unknown(struct kvm_vcpu *vcpu,
|
||||
struct kvm_vcpu *dst_vcpu)
|
||||
{
|
||||
/* handle unknown orders in user space */
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int handle_sigp_dst(struct kvm_vcpu *vcpu, u8 order_code,
|
||||
u16 cpu_addr, u32 parameter, u64 *status_reg)
|
||||
{
|
||||
int rc;
|
||||
struct kvm_vcpu *dst_vcpu;
|
||||
|
||||
if (cpu_addr >= KVM_MAX_VCPUS)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
@ -340,11 +343,71 @@ static int sigp_check_callable(struct kvm_vcpu *vcpu, u16 cpu_addr)
|
||||
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
|
||||
if (!dst_vcpu)
|
||||
return SIGP_CC_NOT_OPERATIONAL;
|
||||
li = &dst_vcpu->arch.local_int;
|
||||
spin_lock(&li->lock);
|
||||
if (li->action_bits & ACTION_STOP_ON_STOP)
|
||||
rc = SIGP_CC_BUSY;
|
||||
spin_unlock(&li->lock);
|
||||
|
||||
switch (order_code) {
|
||||
case SIGP_SENSE:
|
||||
vcpu->stat.instruction_sigp_sense++;
|
||||
rc = __sigp_sense(vcpu, dst_vcpu, status_reg);
|
||||
break;
|
||||
case SIGP_EXTERNAL_CALL:
|
||||
vcpu->stat.instruction_sigp_external_call++;
|
||||
rc = __sigp_external_call(vcpu, dst_vcpu);
|
||||
break;
|
||||
case SIGP_EMERGENCY_SIGNAL:
|
||||
vcpu->stat.instruction_sigp_emergency++;
|
||||
rc = __sigp_emergency(vcpu, dst_vcpu);
|
||||
break;
|
||||
case SIGP_STOP:
|
||||
vcpu->stat.instruction_sigp_stop++;
|
||||
rc = __sigp_stop(vcpu, dst_vcpu);
|
||||
break;
|
||||
case SIGP_STOP_AND_STORE_STATUS:
|
||||
vcpu->stat.instruction_sigp_stop_store_status++;
|
||||
rc = __sigp_stop_and_store_status(vcpu, dst_vcpu, status_reg);
|
||||
break;
|
||||
case SIGP_STORE_STATUS_AT_ADDRESS:
|
||||
vcpu->stat.instruction_sigp_store_status++;
|
||||
rc = __sigp_store_status_at_addr(vcpu, dst_vcpu, parameter,
|
||||
status_reg);
|
||||
break;
|
||||
case SIGP_SET_PREFIX:
|
||||
vcpu->stat.instruction_sigp_prefix++;
|
||||
rc = __sigp_set_prefix(vcpu, dst_vcpu, parameter, status_reg);
|
||||
break;
|
||||
case SIGP_COND_EMERGENCY_SIGNAL:
|
||||
vcpu->stat.instruction_sigp_cond_emergency++;
|
||||
rc = __sigp_conditional_emergency(vcpu, dst_vcpu, parameter,
|
||||
status_reg);
|
||||
break;
|
||||
case SIGP_SENSE_RUNNING:
|
||||
vcpu->stat.instruction_sigp_sense_running++;
|
||||
rc = __sigp_sense_running(vcpu, dst_vcpu, status_reg);
|
||||
break;
|
||||
case SIGP_START:
|
||||
vcpu->stat.instruction_sigp_start++;
|
||||
rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
|
||||
break;
|
||||
case SIGP_RESTART:
|
||||
vcpu->stat.instruction_sigp_restart++;
|
||||
rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
|
||||
break;
|
||||
case SIGP_INITIAL_CPU_RESET:
|
||||
vcpu->stat.instruction_sigp_init_cpu_reset++;
|
||||
rc = __prepare_sigp_cpu_reset(vcpu, dst_vcpu, order_code);
|
||||
break;
|
||||
case SIGP_CPU_RESET:
|
||||
vcpu->stat.instruction_sigp_cpu_reset++;
|
||||
rc = __prepare_sigp_cpu_reset(vcpu, dst_vcpu, order_code);
|
||||
break;
|
||||
default:
|
||||
vcpu->stat.instruction_sigp_unknown++;
|
||||
rc = __prepare_sigp_unknown(vcpu, dst_vcpu);
|
||||
}
|
||||
|
||||
if (rc == -EOPNOTSUPP)
|
||||
VCPU_EVENT(vcpu, 4,
|
||||
"sigp order %u -> cpu %x: handled in user space",
|
||||
order_code, dst_vcpu->vcpu_id);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -371,68 +434,14 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
|
||||
|
||||
trace_kvm_s390_handle_sigp(vcpu, order_code, cpu_addr, parameter);
|
||||
switch (order_code) {
|
||||
case SIGP_SENSE:
|
||||
vcpu->stat.instruction_sigp_sense++;
|
||||
rc = __sigp_sense(vcpu, cpu_addr,
|
||||
&vcpu->run->s.regs.gprs[r1]);
|
||||
break;
|
||||
case SIGP_EXTERNAL_CALL:
|
||||
vcpu->stat.instruction_sigp_external_call++;
|
||||
rc = __sigp_external_call(vcpu, cpu_addr);
|
||||
break;
|
||||
case SIGP_EMERGENCY_SIGNAL:
|
||||
vcpu->stat.instruction_sigp_emergency++;
|
||||
rc = __sigp_emergency(vcpu, cpu_addr);
|
||||
break;
|
||||
case SIGP_STOP:
|
||||
vcpu->stat.instruction_sigp_stop++;
|
||||
rc = __sigp_stop(vcpu, cpu_addr, ACTION_STOP_ON_STOP);
|
||||
break;
|
||||
case SIGP_STOP_AND_STORE_STATUS:
|
||||
vcpu->stat.instruction_sigp_stop++;
|
||||
rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP |
|
||||
ACTION_STOP_ON_STOP);
|
||||
break;
|
||||
case SIGP_STORE_STATUS_AT_ADDRESS:
|
||||
rc = __sigp_store_status_at_addr(vcpu, cpu_addr, parameter,
|
||||
&vcpu->run->s.regs.gprs[r1]);
|
||||
break;
|
||||
case SIGP_SET_ARCHITECTURE:
|
||||
vcpu->stat.instruction_sigp_arch++;
|
||||
rc = __sigp_set_arch(vcpu, parameter);
|
||||
break;
|
||||
case SIGP_SET_PREFIX:
|
||||
vcpu->stat.instruction_sigp_prefix++;
|
||||
rc = __sigp_set_prefix(vcpu, cpu_addr, parameter,
|
||||
&vcpu->run->s.regs.gprs[r1]);
|
||||
break;
|
||||
case SIGP_COND_EMERGENCY_SIGNAL:
|
||||
rc = __sigp_conditional_emergency(vcpu, cpu_addr, parameter,
|
||||
&vcpu->run->s.regs.gprs[r1]);
|
||||
break;
|
||||
case SIGP_SENSE_RUNNING:
|
||||
vcpu->stat.instruction_sigp_sense_running++;
|
||||
rc = __sigp_sense_running(vcpu, cpu_addr,
|
||||
&vcpu->run->s.regs.gprs[r1]);
|
||||
break;
|
||||
case SIGP_START:
|
||||
rc = sigp_check_callable(vcpu, cpu_addr);
|
||||
if (rc == SIGP_CC_ORDER_CODE_ACCEPTED)
|
||||
rc = -EOPNOTSUPP; /* Handle START in user space */
|
||||
break;
|
||||
case SIGP_RESTART:
|
||||
vcpu->stat.instruction_sigp_restart++;
|
||||
rc = sigp_check_callable(vcpu, cpu_addr);
|
||||
if (rc == SIGP_CC_ORDER_CODE_ACCEPTED) {
|
||||
VCPU_EVENT(vcpu, 4,
|
||||
"sigp restart %x to handle userspace",
|
||||
cpu_addr);
|
||||
/* user space must know about restart */
|
||||
rc = -EOPNOTSUPP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
rc = handle_sigp_dst(vcpu, order_code, cpu_addr,
|
||||
parameter,
|
||||
&vcpu->run->s.regs.gprs[r1]);
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
|
@ -936,7 +936,7 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
retry:
|
||||
ptep = get_locked_pte(current->mm, addr, &ptl);
|
||||
ptep = get_locked_pte(mm, addr, &ptl);
|
||||
if (unlikely(!ptep)) {
|
||||
up_read(&mm->mmap_sem);
|
||||
return -EFAULT;
|
||||
|
Loading…
Reference in New Issue
Block a user