aboutsummaryrefslogtreecommitdiff
path: root/target/s390x/kvm.c
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2017-09-28 22:36:54 +0200
committerCornelia Huck <cohuck@redhat.com>2017-10-20 13:32:10 +0200
commit74b4c74d5efb0a489bdf0acc5b5d0197167e7649 (patch)
tree45b71699d0352d8d70bc5dfc109a6e09abe806f4 /target/s390x/kvm.c
parenta7a2b8e3d57582df2f176069d57c1ddae667387d (diff)
s390x/kvm: factor out SIGP code into sigp.c
We want to use the same code base for TCG, so let's cleanly factor it out. The sigp mutex is currently not really needed, as everything is protected by the iothread mutex. But this could change later, so leave it in place and initialize it properly from common code. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: David Hildenbrand <david@redhat.com> Message-Id: <20170928203708.9376-17-david@redhat.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
Diffstat (limited to 'target/s390x/kvm.c')
-rw-r--r--target/s390x/kvm.c349
1 files changed, 6 insertions, 343 deletions
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 1950291f95..b2e36559c8 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -135,8 +135,6 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO
};
-static QemuMutex qemu_sigp_mutex;
-
static int cap_sync_regs;
static int cap_async_pf;
static int cap_mem_op;
@@ -322,8 +320,6 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
*/
/* kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0); */
- qemu_mutex_init(&qemu_sigp_mutex);
-
return 0;
}
@@ -1508,355 +1504,22 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
return r;
}
-typedef struct SigpInfo {
- uint64_t param;
- int cc;
- uint64_t *status_reg;
-} SigpInfo;
-
-static void set_sigp_status(SigpInfo *si, uint64_t status)
-{
- *si->status_reg &= 0xffffffff00000000ULL;
- *si->status_reg |= status;
- si->cc = SIGP_CC_STATUS_STORED;
-}
-
-static void sigp_start(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
-
- if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
- return;
- }
-
- s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
-
- if (s390_cpu_get_state(cpu) != CPU_STATE_OPERATING) {
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
- return;
- }
-
- /* disabled wait - sleeping in user space */
- if (cs->halted) {
- s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
- } else {
- /* execute the stop function */
- cpu->env.sigp_order = SIGP_STOP;
- cpu_inject_stop(cpu);
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
-
- /* disabled wait - sleeping in user space */
- if (s390_cpu_get_state(cpu) == CPU_STATE_OPERATING && cs->halted) {
- s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
- }
-
- switch (s390_cpu_get_state(cpu)) {
- case CPU_STATE_OPERATING:
- cpu->env.sigp_order = SIGP_STOP_STORE_STATUS;
- cpu_inject_stop(cpu);
- /* store will be performed when handling the stop intercept */
- break;
- case CPU_STATE_STOPPED:
- /* already stopped, just store the status */
- cpu_synchronize_state(cs);
- s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
- break;
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
- uint32_t address = si->param & 0x7ffffe00u;
-
- /* cpu has to be stopped */
- if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
- set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
- return;
- }
-
- cpu_synchronize_state(cs);
-
- if (s390_store_status(cpu, address, false)) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-#define ADTL_SAVE_LC_MASK 0xfUL
-static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
- uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
- hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
- hwaddr len = 1UL << (lc ? lc : 10);
-
- if (!s390_has_feat(S390_FEAT_VECTOR) &&
- !s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
- set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
- return;
- }
-
- /* cpu has to be stopped */
- if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
- set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
- return;
- }
-
- /* address must be aligned to length */
- if (addr & (len - 1)) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
-
- /* no GS: only lc == 0 is valid */
- if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
- lc != 0) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
-
- /* GS: 0, 10, 11, 12 are valid */
- if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
- lc != 0 &&
- lc != 10 &&
- lc != 11 &&
- lc != 12) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
-
- cpu_synchronize_state(cs);
-
- if (s390_store_adtl_status(cpu, addr, len)) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
-
- switch (s390_cpu_get_state(cpu)) {
- case CPU_STATE_STOPPED:
- /* the restart irq has to be delivered prior to any other pending irq */
- cpu_synchronize_state(cs);
- do_restart_interrupt(&cpu->env);
- s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
- break;
- case CPU_STATE_OPERATING:
- cpu_inject_restart(cpu);
- break;
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-int kvm_s390_cpu_restart(S390CPU *cpu)
-{
- SigpInfo si = {};
-
- run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
- return 0;
-}
-
-static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
- SigpInfo *si = arg.host_ptr;
-
- cpu_synchronize_state(cs);
- scc->initial_cpu_reset(cs);
- cpu_synchronize_post_reset(cs);
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
- SigpInfo *si = arg.host_ptr;
-
- cpu_synchronize_state(cs);
- scc->cpu_reset(cs);
- cpu_synchronize_post_reset(cs);
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
- uint32_t addr = si->param & 0x7fffe000u;
-
- cpu_synchronize_state(cs);
-
- if (!address_space_access_valid(&address_space_memory, addr,
- sizeof(struct LowCore), false)) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
-
- /* cpu has to be stopped */
- if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
- set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
- return;
- }
-
- cpu->env.psa = addr;
- cpu_synchronize_post_init(cs);
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static int handle_sigp_single_dst(S390CPU *dst_cpu, uint8_t order,
- uint64_t param, uint64_t *status_reg)
-{
- SigpInfo si = {
- .param = param,
- .status_reg = status_reg,
- };
-
- /* cpu available? */
- if (dst_cpu == NULL) {
- return SIGP_CC_NOT_OPERATIONAL;
- }
-
- /* only resets can break pending orders */
- if (dst_cpu->env.sigp_order != 0 &&
- order != SIGP_CPU_RESET &&
- order != SIGP_INITIAL_CPU_RESET) {
- return SIGP_CC_BUSY;
- }
-
- switch (order) {
- case SIGP_START:
- run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_STOP:
- run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_RESTART:
- run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_STOP_STORE_STATUS:
- run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_STORE_STATUS_ADDR:
- run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_STORE_ADTL_STATUS:
- run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_SET_PREFIX:
- run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_INITIAL_CPU_RESET:
- run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_CPU_RESET:
- run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
- break;
- default:
- set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
- }
-
- return si.cc;
-}
-
-static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
- uint64_t *status_reg)
-{
- CPUState *cur_cs;
- S390CPU *cur_cpu;
- bool all_stopped = true;
-
- CPU_FOREACH(cur_cs) {
- cur_cpu = S390_CPU(cur_cs);
-
- if (cur_cpu == cpu) {
- continue;
- }
- if (s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
- all_stopped = false;
- }
- }
-
- *status_reg &= 0xffffffff00000000ULL;
-
- /* Reject set arch order, with czam we're always in z/Arch mode. */
- *status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
- SIGP_STAT_INCORRECT_STATE);
- return SIGP_CC_STATUS_STORED;
-}
-
-static int handle_sigp(S390CPU *cpu, uint8_t ipa1, uint32_t ipb)
+static int kvm_s390_handle_sigp(S390CPU *cpu, uint8_t ipa1, uint32_t ipb)
{
CPUS390XState *env = &cpu->env;
const uint8_t r1 = ipa1 >> 4;
const uint8_t r3 = ipa1 & 0x0f;
int ret;
uint8_t order;
- uint64_t *status_reg;
- uint64_t param;
- S390CPU *dst_cpu = NULL;
cpu_synchronize_state(CPU(cpu));
/* get order code */
- order = decode_basedisp_rs(env, ipb, NULL)
- & SIGP_ORDER_MASK;
- status_reg = &env->regs[r1];
- param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
+ order = decode_basedisp_rs(env, ipb, NULL) & SIGP_ORDER_MASK;
- if (qemu_mutex_trylock(&qemu_sigp_mutex)) {
- ret = SIGP_CC_BUSY;
- goto out;
- }
-
- switch (order) {
- case SIGP_SET_ARCH:
- ret = sigp_set_architecture(cpu, param, status_reg);
- break;
- default:
- /* all other sigp orders target a single vcpu */
- dst_cpu = s390_cpu_addr2state(env->regs[r3]);
- ret = handle_sigp_single_dst(dst_cpu, order, param, status_reg);
- }
- qemu_mutex_unlock(&qemu_sigp_mutex);
-
-out:
- trace_kvm_sigp_finished(order, CPU(cpu)->cpu_index,
- dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
-
- if (ret >= 0) {
- setcc(cpu, ret);
- return 0;
- }
-
- return ret;
+ ret = handle_sigp(env, order, r1, r3);
+ setcc(cpu, ret);
+ return 0;
}
static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
@@ -1884,7 +1547,7 @@ static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
r = handle_diag(cpu, run, run->s390_sieic.ipb);
break;
case IPA0_SIGP:
- r = handle_sigp(cpu, ipa1, run->s390_sieic.ipb);
+ r = kvm_s390_handle_sigp(cpu, ipa1, run->s390_sieic.ipb);
break;
}