Commit f62c95fd authored by Paolo Bonzini's avatar Paolo Bonzini

Merge tag 'kvm-s390-next-20141028' of...

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)
parents 41e7ed64 a6cc3108
...@@ -226,10 +226,17 @@ struct kvm_vcpu_stat { ...@@ -226,10 +226,17 @@ struct kvm_vcpu_stat {
u32 instruction_sigp_sense_running; u32 instruction_sigp_sense_running;
u32 instruction_sigp_external_call; u32 instruction_sigp_external_call;
u32 instruction_sigp_emergency; u32 instruction_sigp_emergency;
u32 instruction_sigp_cond_emergency;
u32 instruction_sigp_start;
u32 instruction_sigp_stop; u32 instruction_sigp_stop;
u32 instruction_sigp_stop_store_status;
u32 instruction_sigp_store_status;
u32 instruction_sigp_arch; u32 instruction_sigp_arch;
u32 instruction_sigp_prefix; u32 instruction_sigp_prefix;
u32 instruction_sigp_restart; u32 instruction_sigp_restart;
u32 instruction_sigp_init_cpu_reset;
u32 instruction_sigp_cpu_reset;
u32 instruction_sigp_unknown;
u32 diagnose_10; u32 diagnose_10;
u32 diagnose_44; u32 diagnose_44;
u32 diagnose_9c; u32 diagnose_9c;
...@@ -434,6 +441,8 @@ struct kvm_arch{ ...@@ -434,6 +441,8 @@ struct kvm_arch{
int user_cpu_state_ctrl; int user_cpu_state_ctrl;
struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS]; struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
wait_queue_head_t ipte_wq; wait_queue_head_t ipte_wq;
int ipte_lock_count;
struct mutex ipte_mutex;
spinlock_t start_stop_lock; spinlock_t start_stop_lock;
struct kvm_s390_crypto crypto; struct kvm_s390_crypto crypto;
}; };
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#define SIGP_RESTART 6 #define SIGP_RESTART 6
#define SIGP_STOP_AND_STORE_STATUS 9 #define SIGP_STOP_AND_STORE_STATUS 9
#define SIGP_INITIAL_CPU_RESET 11 #define SIGP_INITIAL_CPU_RESET 11
#define SIGP_CPU_RESET 12
#define SIGP_SET_PREFIX 13 #define SIGP_SET_PREFIX 13
#define SIGP_STORE_STATUS_AT_ADDRESS 14 #define SIGP_STORE_STATUS_AT_ADDRESS 14
#define SIGP_SET_ARCHITECTURE 18 #define SIGP_SET_ARCHITECTURE 18
......
...@@ -207,8 +207,6 @@ union raddress { ...@@ -207,8 +207,6 @@ union raddress {
unsigned long pfra : 52; /* Page-Frame Real Address */ 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) int ipte_lock_held(struct kvm_vcpu *vcpu)
{ {
...@@ -216,16 +214,16 @@ 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) if (vcpu->arch.sie_block->eca & 1)
return ic->kh != 0; 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) static void ipte_lock_simple(struct kvm_vcpu *vcpu)
{ {
union ipte_control old, new, *ic; union ipte_control old, new, *ic;
mutex_lock(&ipte_mutex); mutex_lock(&vcpu->kvm->arch.ipte_mutex);
ipte_lock_count++; vcpu->kvm->arch.ipte_lock_count++;
if (ipte_lock_count > 1) if (vcpu->kvm->arch.ipte_lock_count > 1)
goto out; goto out;
ic = &vcpu->kvm->arch.sca->ipte_control; ic = &vcpu->kvm->arch.sca->ipte_control;
do { do {
...@@ -238,16 +236,16 @@ static void ipte_lock_simple(struct kvm_vcpu *vcpu) ...@@ -238,16 +236,16 @@ static void ipte_lock_simple(struct kvm_vcpu *vcpu)
new.k = 1; new.k = 1;
} while (cmpxchg(&ic->val, old.val, new.val) != old.val); } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
out: out:
mutex_unlock(&ipte_mutex); mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
} }
static void ipte_unlock_simple(struct kvm_vcpu *vcpu) static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
{ {
union ipte_control old, new, *ic; union ipte_control old, new, *ic;
mutex_lock(&ipte_mutex); mutex_lock(&vcpu->kvm->arch.ipte_mutex);
ipte_lock_count--; vcpu->kvm->arch.ipte_lock_count--;
if (ipte_lock_count) if (vcpu->kvm->arch.ipte_lock_count)
goto out; goto out;
ic = &vcpu->kvm->arch.sca->ipte_control; ic = &vcpu->kvm->arch.sca->ipte_control;
do { do {
...@@ -256,7 +254,7 @@ static void ipte_unlock_simple(struct kvm_vcpu *vcpu) ...@@ -256,7 +254,7 @@ static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
} while (cmpxchg(&ic->val, old.val, new.val) != old.val); } while (cmpxchg(&ic->val, old.val, new.val) != old.val);
wake_up(&vcpu->kvm->arch.ipte_wq); wake_up(&vcpu->kvm->arch.ipte_wq);
out: out:
mutex_unlock(&ipte_mutex); mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
} }
static void ipte_lock_siif(struct kvm_vcpu *vcpu) static void ipte_lock_siif(struct kvm_vcpu *vcpu)
......
...@@ -270,7 +270,7 @@ static int __must_check __deliver_prog_irq(struct kvm_vcpu *vcpu, ...@@ -270,7 +270,7 @@ static int __must_check __deliver_prog_irq(struct kvm_vcpu *vcpu,
break; break;
case PGM_MONITOR: case PGM_MONITOR:
rc = put_guest_lc(vcpu, pgm_info->mon_class_nr, 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, rc |= put_guest_lc(vcpu, pgm_info->mon_code,
(u64 *)__LC_MON_CODE); (u64 *)__LC_MON_CODE);
break; break;
......
...@@ -81,10 +81,17 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { ...@@ -81,10 +81,17 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "instruction_sigp_sense_running", VCPU_STAT(instruction_sigp_sense_running) }, { "instruction_sigp_sense_running", VCPU_STAT(instruction_sigp_sense_running) },
{ "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) }, { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) },
{ "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, { "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", 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_arch", VCPU_STAT(instruction_sigp_arch) },
{ "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) }, { "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) },
{ "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) }, { "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_10", VCPU_STAT(diagnose_10) },
{ "diagnose_44", VCPU_STAT(diagnose_44) }, { "diagnose_44", VCPU_STAT(diagnose_44) },
{ "diagnose_9c", VCPU_STAT(diagnose_9c) }, { "diagnose_9c", VCPU_STAT(diagnose_9c) },
...@@ -453,6 +460,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) ...@@ -453,6 +460,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
spin_lock_init(&kvm->arch.float_int.lock); spin_lock_init(&kvm->arch.float_int.lock);
INIT_LIST_HEAD(&kvm->arch.float_int.list); INIT_LIST_HEAD(&kvm->arch.float_int.list);
init_waitqueue_head(&kvm->arch.ipte_wq); init_waitqueue_head(&kvm->arch.ipte_wq);
mutex_init(&kvm->arch.ipte_mutex);
debug_register_view(kvm->arch.dbf, &debug_sprintf_view); debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
VM_EVENT(kvm, 3, "%s", "vm created"); VM_EVENT(kvm, 3, "%s", "vm created");
......
...@@ -20,20 +20,13 @@ ...@@ -20,20 +20,13 @@
#include "kvm-s390.h" #include "kvm-s390.h"
#include "trace.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) u64 *reg)
{ {
struct kvm_s390_local_interrupt *li; struct kvm_s390_local_interrupt *li;
struct kvm_vcpu *dst_vcpu = NULL;
int cpuflags; int cpuflags;
int rc; 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; li = &dst_vcpu->arch.local_int;
cpuflags = atomic_read(li->cpuflags); cpuflags = atomic_read(li->cpuflags);
...@@ -48,55 +41,53 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr, ...@@ -48,55 +41,53 @@ static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
rc = SIGP_CC_STATUS_STORED; 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; 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 = { struct kvm_s390_interrupt s390int = {
.type = KVM_S390_INT_EMERGENCY, .type = KVM_S390_INT_EMERGENCY,
.parm = vcpu->vcpu_id, .parm = vcpu->vcpu_id,
}; };
struct kvm_vcpu *dst_vcpu = NULL;
int rc = 0; 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); rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
if (!rc) 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; 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) u16 asn, u64 *reg)
{ {
struct kvm_vcpu *dst_vcpu = NULL;
const u64 psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT; const u64 psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
u16 p_asn, s_asn; u16 p_asn, s_asn;
psw_t *psw; psw_t *psw;
u32 flags; 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); flags = atomic_read(&dst_vcpu->arch.sie_block->cpuflags);
psw = &dst_vcpu->arch.sie_block->gpsw; psw = &dst_vcpu->arch.sie_block->gpsw;
p_asn = dst_vcpu->arch.sie_block->gcr[4] & 0xffff; /* Primary ASN */ p_asn = dst_vcpu->arch.sie_block->gcr[4] & 0xffff; /* Primary ASN */
s_asn = dst_vcpu->arch.sie_block->gcr[3] & 0xffff; /* Secondary 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) if (!(flags & CPUSTAT_STOPPED)
|| (psw->mask & psw_int_mask) != psw_int_mask || (psw->mask & psw_int_mask) != psw_int_mask
|| ((flags & CPUSTAT_WAIT) && psw->addr != 0) || ((flags & CPUSTAT_WAIT) && psw->addr != 0)
|| (!(flags & CPUSTAT_WAIT) && (asn == p_asn || asn == s_asn))) { || (!(flags & CPUSTAT_WAIT) && (asn == p_asn || asn == s_asn))) {
return __sigp_emergency(vcpu, cpu_addr); return __inject_sigp_emergency(vcpu, dst_vcpu);
} else { } else {
*reg &= 0xffffffff00000000UL; *reg &= 0xffffffff00000000UL;
*reg |= SIGP_STATUS_INCORRECT_STATE; *reg |= SIGP_STATUS_INCORRECT_STATE;
...@@ -104,23 +95,19 @@ static int __sigp_conditional_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr, ...@@ -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 = { struct kvm_s390_interrupt s390int = {
.type = KVM_S390_INT_EXTERNAL_CALL, .type = KVM_S390_INT_EXTERNAL_CALL,
.parm = vcpu->vcpu_id, .parm = vcpu->vcpu_id,
}; };
struct kvm_vcpu *dst_vcpu = NULL;
int rc; 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); rc = kvm_s390_inject_vcpu(dst_vcpu, &s390int);
if (!rc) 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; return rc ? rc : SIGP_CC_ORDER_CODE_ACCEPTED;
} }
...@@ -160,23 +147,27 @@ static int __inject_sigp_stop(struct kvm_vcpu *dst_vcpu, int action) ...@@ -160,23 +147,27 @@ static int __inject_sigp_stop(struct kvm_vcpu *dst_vcpu, int action)
return rc; 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; int rc;
if (cpu_addr >= KVM_MAX_VCPUS) rc = __inject_sigp_stop(dst_vcpu, ACTION_STOP_ON_STOP);
return SIGP_CC_NOT_OPERATIONAL; VCPU_EVENT(vcpu, 4, "sent sigp stop to cpu %x", dst_vcpu->vcpu_id);
dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr); return rc;
if (!dst_vcpu) }
return SIGP_CC_NOT_OPERATIONAL;
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 /* If the CPU has already been stopped, we still have
* to save the status when doing stop-and-store. This * to save the status when doing stop-and-store. This
* has to be done after unlocking all spinlocks. */ * has to be done after unlocking all spinlocks. */
...@@ -212,18 +203,13 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) ...@@ -212,18 +203,13 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter)
return rc; return rc;
} }
static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, static int __sigp_set_prefix(struct kvm_vcpu *vcpu, struct kvm_vcpu *dst_vcpu,
u64 *reg) u32 address, u64 *reg)
{ {
struct kvm_s390_local_interrupt *li; struct kvm_s390_local_interrupt *li;
struct kvm_vcpu *dst_vcpu = NULL;
struct kvm_s390_interrupt_info *inti; struct kvm_s390_interrupt_info *inti;
int rc; 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; li = &dst_vcpu->arch.local_int;
/* /*
...@@ -260,24 +246,20 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, ...@@ -260,24 +246,20 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
kvm_s390_vcpu_wakeup(dst_vcpu); kvm_s390_vcpu_wakeup(dst_vcpu);
rc = SIGP_CC_ORDER_CODE_ACCEPTED; 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: out_li:
spin_unlock(&li->lock); spin_unlock(&li->lock);
return rc; return rc;
} }
static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu, u16 cpu_id, static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu,
struct kvm_vcpu *dst_vcpu,
u32 addr, u64 *reg) u32 addr, u64 *reg)
{ {
struct kvm_vcpu *dst_vcpu = NULL;
int flags; int flags;
int rc; 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); spin_lock(&dst_vcpu->arch.local_int.lock);
flags = atomic_read(dst_vcpu->arch.local_int.cpuflags); flags = atomic_read(dst_vcpu->arch.local_int.cpuflags);
spin_unlock(&dst_vcpu->arch.local_int.lock); 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, ...@@ -297,19 +279,12 @@ static int __sigp_store_status_at_addr(struct kvm_vcpu *vcpu, u16 cpu_id,
return rc; return rc;
} }
static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr, static int __sigp_sense_running(struct kvm_vcpu *vcpu,
u64 *reg) struct kvm_vcpu *dst_vcpu, u64 *reg)
{ {
struct kvm_s390_local_interrupt *li; struct kvm_s390_local_interrupt *li;
struct kvm_vcpu *dst_vcpu = NULL;
int rc; 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; li = &dst_vcpu->arch.local_int;
if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) { if (atomic_read(li->cpuflags) & CPUSTAT_RUNNING) {
/* running */ /* running */
...@@ -321,26 +296,19 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr, ...@@ -321,26 +296,19 @@ static int __sigp_sense_running(struct kvm_vcpu *vcpu, u16 cpu_addr,
rc = SIGP_CC_STATUS_STORED; rc = SIGP_CC_STATUS_STORED;
} }
VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x", cpu_addr, VCPU_EVENT(vcpu, 4, "sensed running status of cpu %x rc %x",
rc); dst_vcpu->vcpu_id, rc);
return rc; return rc;
} }
/* Test whether the destination CPU is available and not busy */ static int __prepare_sigp_re_start(struct kvm_vcpu *vcpu,
static int sigp_check_callable(struct kvm_vcpu *vcpu, u16 cpu_addr) struct kvm_vcpu *dst_vcpu, u8 order_code)
{ {
struct kvm_s390_local_interrupt *li; struct kvm_s390_local_interrupt *li = &dst_vcpu->arch.local_int;
int rc = SIGP_CC_ORDER_CODE_ACCEPTED; /* handle (RE)START in user space */
struct kvm_vcpu *dst_vcpu = NULL; int rc = -EOPNOTSUPP;
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;
spin_lock(&li->lock); spin_lock(&li->lock);
if (li->action_bits & ACTION_STOP_ON_STOP) if (li->action_bits & ACTION_STOP_ON_STOP)
rc = SIGP_CC_BUSY; rc = SIGP_CC_BUSY;
...@@ -349,90 +317,131 @@ static int sigp_check_callable(struct kvm_vcpu *vcpu, u16 cpu_addr) ...@@ -349,90 +317,131 @@ static int sigp_check_callable(struct kvm_vcpu *vcpu, u16 cpu_addr)
return rc; return rc;
} }
int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) static int __prepare_sigp_cpu_reset(struct kvm_vcpu *vcpu,
struct kvm_vcpu *dst_vcpu, u8 order_code)
{ {
int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; /* handle (INITIAL) CPU RESET in user space */
int r3 = vcpu->arch.sie_block->ipa & 0x000f; return -EOPNOTSUPP;
u32 parameter; }
u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
u8 order_code;
int rc;
/* sigp in userspace can exit */ static int __prepare_sigp_unknown(struct kvm_vcpu *vcpu,
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) struct kvm_vcpu *dst_vcpu)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); {
/* handle unknown orders in user space */
return -EOPNOTSUPP;
}
order_code = kvm_s390_get_base_disp_rs(vcpu); 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 (r1 % 2) if (cpu_addr >= KVM_MAX_VCPUS)
parameter = vcpu->run->s.regs.gprs[r1]; return SIGP_CC_NOT_OPERATIONAL;
else
parameter = vcpu->run->s.regs.gprs[r1 + 1]; dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
if (!dst_vcpu)
return SIGP_CC_NOT_OPERATIONAL;
trace_kvm_s390_handle_sigp(vcpu, order_code, cpu_addr, parameter);
switch (order_code) { switch (order_code) {
case SIGP_SENSE: case SIGP_SENSE:
vcpu->stat.instruction_sigp_sense++; vcpu->stat.instruction_sigp_sense++;
rc = __sigp_sense(vcpu, cpu_addr, rc = __sigp_sense(vcpu, dst_vcpu, status_reg);
&vcpu->run->s.regs.gprs[r1]);
break; break;
case SIGP_EXTERNAL_CALL: case SIGP_EXTERNAL_CALL:
vcpu->stat.instruction_sigp_external_call++; vcpu->stat.instruction_sigp_external_call++;
rc = __sigp_external_call(vcpu, cpu_addr); rc = __sigp_external_call(vcpu, dst_vcpu);
break; break;
case SIGP_EMERGENCY_SIGNAL: case SIGP_EMERGENCY_SIGNAL:
vcpu->stat.instruction_sigp_emergency++; vcpu->stat.instruction_sigp_emergency++;
rc = __sigp_emergency(vcpu, cpu_addr); rc = __sigp_emergency(vcpu, dst_vcpu);
break; break;
case SIGP_STOP: case SIGP_STOP:
vcpu->stat.instruction_sigp_stop++; vcpu->stat.instruction_sigp_stop++;
rc = __sigp_stop(vcpu, cpu_addr, ACTION_STOP_ON_STOP); rc = __sigp_stop(vcpu, dst_vcpu);
break; break;
case SIGP_STOP_AND_STORE_STATUS: case SIGP_STOP_AND_STORE_STATUS:
vcpu->stat.instruction_sigp_stop++; vcpu->stat.instruction_sigp_stop_store_status++;
rc = __sigp_stop(vcpu, cpu_addr, ACTION_STORE_ON_STOP | rc = __sigp_stop_and_store_status(vcpu, dst_vcpu, status_reg);
ACTION_STOP_ON_STOP);
break; break;
case SIGP_STORE_STATUS_AT_ADDRESS: case SIGP_STORE_STATUS_AT_ADDRESS:
rc = __sigp_store_status_at_addr(vcpu, cpu_addr, parameter, vcpu->stat.instruction_sigp_store_status++;
&vcpu->run->s.regs.gprs[r1]); rc = __sigp_store_status_at_addr(vcpu, dst_vcpu, parameter,
break; status_reg);
case SIGP_SET_ARCHITECTURE:
vcpu->stat.instruction_sigp_arch++;
rc = __sigp_set_arch(vcpu, parameter);
break; break;
case SIGP_SET_PREFIX: case SIGP_SET_PREFIX:
vcpu->stat.instruction_sigp_prefix++; vcpu->stat.instruction_sigp_prefix++;
rc = __sigp_set_prefix(vcpu, cpu_addr, parameter, rc = __sigp_set_prefix(vcpu, dst_vcpu, parameter, status_reg);
&vcpu->run->s.regs.gprs[r1]);
break; break;
case SIGP_COND_EMERGENCY_SIGNAL: case SIGP_COND_EMERGENCY_SIGNAL:
rc = __sigp_conditional_emergency(vcpu, cpu_addr, parameter, vcpu->stat.instruction_sigp_cond_emergency++;
&vcpu->run->s.regs.gprs[r1]); rc = __sigp_conditional_emergency(vcpu, dst_vcpu, parameter,
status_reg);
break; break;
case SIGP_SENSE_RUNNING: case SIGP_SENSE_RUNNING:
vcpu->stat.instruction_sigp_sense_running++; vcpu->stat.instruction_sigp_sense_running++;
rc = __sigp_sense_running(vcpu, cpu_addr, rc = __sigp_sense_running(vcpu, dst_vcpu, status_reg);
&vcpu->run->s.regs.gprs[r1]);
break; break;
case SIGP_START: case SIGP_START:
rc = sigp_check_callable(vcpu, cpu_addr); vcpu->stat.instruction_sigp_start++;
if (rc == SIGP_CC_ORDER_CODE_ACCEPTED) rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
rc = -EOPNOTSUPP; /* Handle START in user space */
break; break;
case SIGP_RESTART: case SIGP_RESTART:
vcpu->stat.instruction_sigp_restart++; vcpu->stat.instruction_sigp_restart++;
rc = sigp_check_callable(vcpu, cpu_addr); rc = __prepare_sigp_re_start(vcpu, dst_vcpu, order_code);
if (rc == SIGP_CC_ORDER_CODE_ACCEPTED) { break;
VCPU_EVENT(vcpu, 4, case SIGP_INITIAL_CPU_RESET:
"sigp restart %x to handle userspace", vcpu->stat.instruction_sigp_init_cpu_reset++;
cpu_addr); rc = __prepare_sigp_cpu_reset(vcpu, dst_vcpu, order_code);
/* user space must know about restart */ break;
rc = -EOPNOTSUPP; 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;
}
int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
{
int r1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
int r3 = vcpu->arch.sie_block->ipa & 0x000f;
u32 parameter;
u16 cpu_addr = vcpu->run->s.regs.gprs[r3];
u8 order_code;
int rc;
/* sigp in userspace can exit */
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
order_code = kvm_s390_get_base_disp_rs(vcpu);
if (r1 % 2)
parameter = vcpu->run->s.regs.gprs[r1];
else
parameter = vcpu->run->s.regs.gprs[r1 + 1];
trace_kvm_s390_handle_sigp(vcpu, order_code, cpu_addr, parameter);
switch (order_code) {
case SIGP_SET_ARCHITECTURE:
vcpu->stat.instruction_sigp_arch++;
rc = __sigp_set_arch(vcpu, parameter);
break; break;
default: default:
return -EOPNOTSUPP; rc = handle_sigp_dst(vcpu, order_code, cpu_addr,
parameter,
&vcpu->run->s.regs.gprs[r1]);
} }
if (rc < 0) if (rc < 0)
......
...@@ -936,7 +936,7 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, ...@@ -936,7 +936,7 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
down_read(&mm->mmap_sem); down_read(&mm->mmap_sem);
retry: retry:
ptep = get_locked_pte(current->mm, addr, &ptl); ptep = get_locked_pte(mm, addr, &ptl);
if (unlikely(!ptep)) { if (unlikely(!ptep)) {
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
return -EFAULT; return -EFAULT;
......
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