]> Git Repo - qemu.git/blobdiff - target-s390x/misc_helper.c
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
[qemu.git] / target-s390x / misc_helper.c
index 1d5137f984701675f677ce7eb1a1e3597e459a46..728456f2954f64cb66d2a81c92bdb560a239e7fd 100644 (file)
  */
 
 #include "cpu.h"
-#include "memory.h"
-#include "cputlb.h"
-#include "dyngen-exec.h"
-#include "host-utils.h"
+#include "exec/memory.h"
+#include "qemu/host-utils.h"
 #include "helper.h"
 #include <string.h>
-#include "kvm.h"
-#include "qemu-timer.h"
+#include "sysemu/kvm.h"
+#include "qemu/timer.h"
 #ifdef CONFIG_KVM
 #include <linux/kvm.h>
 #endif
 
 #if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#include "sysemu.h"
+#include "exec/softmmu_exec.h"
+#include "sysemu/cpus.h"
+#include "sysemu/sysemu.h"
+#include "hw/s390x/ebcdic.h"
 #endif
 
 /* #define DEBUG_HELPER */
 #define HELPER_LOG(x...)
 #endif
 
-/* raise an exception */
-void HELPER(exception)(uint32_t excp)
+/* Raise an exception dynamically from a helper function.  */
+void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
+                                     uintptr_t retaddr)
+{
+    int t;
+
+    env->exception_index = EXCP_PGM;
+    env->int_pgm_code = excp;
+
+    /* Use the (ultimate) callers address to find the insn that trapped.  */
+    cpu_restore_state(env, retaddr);
+
+    /* Advance past the insn.  */
+    t = cpu_ldub_code(env, env->psw.addr);
+    env->int_pgm_ilen = t = get_ilen(t);
+    env->psw.addr += 2 * t;
+
+    cpu_loop_exit(env);
+}
+
+/* Raise an exception statically from a TB.  */
+void HELPER(exception)(CPUS390XState *env, uint32_t excp)
 {
     HELPER_LOG("%s: exception %d\n", __func__, excp);
     env->exception_index = excp;
@@ -52,87 +72,140 @@ void HELPER(exception)(uint32_t excp)
 }
 
 #ifndef CONFIG_USER_ONLY
-void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
+
+void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
 {
-    qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
+    qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
+                  env->psw.addr);
 
     if (kvm_enabled()) {
 #ifdef CONFIG_KVM
-        kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
+        kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code);
 #endif
     } else {
         env->int_pgm_code = code;
-        env->int_pgm_ilc = ilc;
+        env->int_pgm_ilen = ilen;
         env->exception_index = EXCP_PGM;
         cpu_loop_exit(env);
     }
 }
 
-/*
- * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc
- */
-int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
+/* SCLP service call */
+uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
 {
-    int r = 0;
-    int shift = 0;
+    int r = sclp_service_call(env, r1, r2);
+    if (r < 0) {
+        program_interrupt(env, -r, 4);
+        return 0;
+    }
+    return r;
+}
 
-#ifdef DEBUG_HELPER
-    printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
-#endif
+#ifndef CONFIG_USER_ONLY
+static void cpu_reset_all(void)
+{
+    CPUState *cs;
+    S390CPUClass *scc;
 
-    /* basic checks */
-    if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) {
-        return -PGM_ADDRESSING;
-    }
-    if (sccb & ~0x7ffffff8ul) {
-        return -PGM_SPECIFICATION;
+    CPU_FOREACH(cs) {
+        scc = S390_CPU_GET_CLASS(cs);
+        scc->cpu_reset(cs);
     }
+}
 
-    switch (code) {
-    case SCLP_CMDW_READ_SCP_INFO:
-    case SCLP_CMDW_READ_SCP_INFO_FORCED:
-        while ((ram_size >> (20 + shift)) > 65535) {
-            shift++;
-        }
-        stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
-        stb_phys(sccb + SCP_INCREMENT, 1 << shift);
-        stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
+static void cpu_full_reset_all(void)
+{
+    CPUState *cpu;
 
-        s390_sclp_extint(sccb & ~3);
-        break;
-    default:
-#ifdef DEBUG_HELPER
-        printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
-#endif
-        r = 3;
-        break;
+    CPU_FOREACH(cpu) {
+        cpu_reset(cpu);
     }
+}
 
-    return r;
+static int modified_clear_reset(S390CPU *cpu)
+{
+    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
+
+    pause_all_vcpus();
+    cpu_synchronize_all_states();
+    cpu_full_reset_all();
+    io_subsystem_reset();
+    scc->load_normal(CPU(cpu));
+    cpu_synchronize_all_post_reset();
+    resume_all_vcpus();
+    return 0;
 }
 
-/* SCLP service call */
-uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
+static int load_normal_reset(S390CPU *cpu)
 {
-    int r;
+    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
+
+    pause_all_vcpus();
+    cpu_synchronize_all_states();
+    cpu_reset_all();
+    io_subsystem_reset();
+    scc->initial_cpu_reset(CPU(cpu));
+    scc->load_normal(CPU(cpu));
+    cpu_synchronize_all_post_reset();
+    resume_all_vcpus();
+    return 0;
+}
 
-    r = sclp_service_call(env, r1, r2);
-    if (r < 0) {
-        program_interrupt(env, -r, 4);
-        return 0;
+#define DIAG_308_RC_NO_CONF         0x0102
+#define DIAG_308_RC_INVALID         0x0402
+void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
+{
+    uint64_t addr =  env->regs[r1];
+    uint64_t subcode = env->regs[r3];
+
+    if (env->psw.mask & PSW_MASK_PSTATE) {
+        program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
+        return;
+    }
+
+    if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
+        program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
+        return;
+    }
+
+    switch (subcode) {
+    case 0:
+        modified_clear_reset(s390_env_get_cpu(env));
+        break;
+    case 1:
+        load_normal_reset(s390_env_get_cpu(env));
+        break;
+    case 5:
+        if ((r1 & 1) || (addr & 0x0fffULL)) {
+            program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
+            return;
+        }
+        env->regs[r1+1] = DIAG_308_RC_INVALID;
+        return;
+    case 6:
+        if ((r1 & 1) || (addr & 0x0fffULL)) {
+            program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
+            return;
+        }
+        env->regs[r1+1] = DIAG_308_RC_NO_CONF;
+        return;
+    default:
+        hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
+        break;
     }
-    return r;
 }
+#endif
 
 /* DIAG */
-uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code)
+uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
+                      uint64_t code)
 {
     uint64_t r;
 
     switch (num) {
     case 0x500:
         /* KVM hypercall */
-        r = s390_virtio_hypercall(env, mem, code);
+        r = s390_virtio_hypercall(env);
         break;
     case 0x44:
         /* yield */
@@ -148,75 +221,41 @@ uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code)
     }
 
     if (r) {
-        program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
+        program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
     }
 
     return r;
 }
 
-/* Store CPU ID */
-void HELPER(stidp)(uint64_t a1)
-{
-    stq(a1, env->cpu_num);
-}
-
 /* Set Prefix */
-void HELPER(spx)(uint64_t a1)
+void HELPER(spx)(CPUS390XState *env, uint64_t a1)
 {
-    uint32_t prefix;
-
-    prefix = ldl(a1);
-    env->psa = prefix & 0xfffff000;
+    uint32_t prefix = a1 & 0x7fffe000;
+    env->psa = prefix;
     qemu_log("prefix: %#x\n", prefix);
     tlb_flush_page(env, 0);
     tlb_flush_page(env, TARGET_PAGE_SIZE);
 }
 
-/* Set Clock */
-uint32_t HELPER(sck)(uint64_t a1)
-{
-    /* XXX not implemented - is it necessary? */
-
-    return 0;
-}
-
 static inline uint64_t clock_value(CPUS390XState *env)
 {
     uint64_t time;
 
     time = env->tod_offset +
-        time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
+        time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
 
     return time;
 }
 
 /* Store Clock */
-uint32_t HELPER(stck)(uint64_t a1)
+uint64_t HELPER(stck)(CPUS390XState *env)
 {
-    stq(a1, clock_value(env));
-
-    return 0;
-}
-
-/* Store Clock Extended */
-uint32_t HELPER(stcke)(uint64_t a1)
-{
-    stb(a1, 0);
-    /* basically the same value as stck */
-    stq(a1 + 1, clock_value(env) | env->cpu_num);
-    /* more fine grained than stck */
-    stq(a1 + 9, 0);
-    /* XXX programmable fields */
-    stw(a1 + 17, 0);
-
-    return 0;
+    return clock_value(env);
 }
 
 /* Set Clock Comparator */
-void HELPER(sckc)(uint64_t a1)
+void HELPER(sckc)(CPUS390XState *env, uint64_t time)
 {
-    uint64_t time = ldq(a1);
-
     if (time == -1ULL) {
         return;
     }
@@ -226,21 +265,19 @@ void HELPER(sckc)(uint64_t a1)
     /* nanoseconds */
     time = (time * 125) >> 9;
 
-    qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
+    timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
 }
 
 /* Store Clock Comparator */
-void HELPER(stckc)(uint64_t a1)
+uint64_t HELPER(stckc)(CPUS390XState *env)
 {
     /* XXX implement */
-    stq(a1, 0);
+    return 0;
 }
 
 /* Set CPU Timer */
-void HELPER(spt)(uint64_t a1)
+void HELPER(spt)(CPUS390XState *env, uint64_t time)
 {
-    uint64_t time = ldq(a1);
-
     if (time == -1ULL) {
         return;
     }
@@ -248,18 +285,19 @@ void HELPER(spt)(uint64_t a1)
     /* nanoseconds */
     time = (time * 125) >> 9;
 
-    qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
+    timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
 }
 
 /* Store CPU Timer */
-void HELPER(stpt)(uint64_t a1)
+uint64_t HELPER(stpt)(CPUS390XState *env)
 {
     /* XXX implement */
-    stq(a1, 0);
+    return 0;
 }
 
 /* Store System Information */
-uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
+uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
+                      uint64_t r0, uint64_t r1)
 {
     int cc = 0;
     int sel1, sel2;
@@ -384,7 +422,8 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
     return cc;
 }
 
-uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
+uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
+                      uint64_t cpu_addr)
 {
     int cc = 0;
 
This page took 0.038881 seconds and 4 git commands to generate.