#if !defined(CONFIG_USER_ONLY)
#include "exec/softmmu_exec.h"
+#include "sysemu/cpus.h"
#include "sysemu/sysemu.h"
+#include "hw/s390x/ebcdic.h"
#endif
/* #define DEBUG_HELPER */
}
#ifndef CONFIG_USER_ONLY
+
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
{
qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
}
/* SCLP service call */
-uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2)
+uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
{
- int r;
-
- r = sclp_service_call(r1, r2);
+ int r = sclp_service_call(r1, r2);
if (r < 0) {
program_interrupt(env, -r, 4);
return 0;
return r;
}
+#ifndef CONFIG_USER_ONLY
+static void cpu_reset_all(void)
+{
+ CPUState *cs;
+ S390CPUClass *scc;
+
+ CPU_FOREACH(cs) {
+ scc = S390_CPU_GET_CLASS(cs);
+ scc->cpu_reset(cs);
+ }
+}
+
+static void cpu_full_reset_all(void)
+{
+ CPUState *cpu;
+
+ CPU_FOREACH(cpu) {
+ cpu_reset(cpu);
+ }
+}
+
+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;
+}
+
+static int load_normal_reset(S390CPU *cpu)
+{
+ 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;
+}
+
+#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;
+ }
+}
+#endif
+
/* DIAG */
uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
uint64_t code)
switch (num) {
case 0x500:
/* KVM hypercall */
- r = s390_virtio_hypercall(env, mem, code);
+ r = s390_virtio_hypercall(env);
break;
case 0x44:
/* yield */
return r;
}
-/* Store CPU ID */
-void HELPER(stidp)(CPUS390XState *env, uint64_t a1)
-{
- cpu_stq_data(env, a1, env->cpu_num);
-}
-
/* Set Prefix */
void HELPER(spx)(CPUS390XState *env, uint64_t a1)
{
- uint32_t prefix;
-
- prefix = cpu_ldl_data(env, 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)(CPUS390XState *env, uint64_t a1)
+uint64_t HELPER(stck)(CPUS390XState *env)
{
- cpu_stq_data(env, a1, clock_value(env));
-
- return 0;
-}
-
-/* Store Clock Extended */
-uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1)
-{
- cpu_stb_data(env, a1, 0);
- /* basically the same value as stck */
- cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num);
- /* more fine grained than stck */
- cpu_stq_data(env, a1 + 9, 0);
- /* XXX programmable fields */
- cpu_stw_data(env, a1 + 17, 0);
-
- return 0;
+ return clock_value(env);
}
/* Set Clock Comparator */
-void HELPER(sckc)(CPUS390XState *env, uint64_t a1)
+void HELPER(sckc)(CPUS390XState *env, uint64_t time)
{
- uint64_t time = cpu_ldq_data(env, a1);
-
if (time == -1ULL) {
return;
}
/* 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)(CPUS390XState *env, uint64_t a1)
+uint64_t HELPER(stckc)(CPUS390XState *env)
{
/* XXX implement */
- cpu_stq_data(env, a1, 0);
+ return 0;
}
/* Set CPU Timer */
-void HELPER(spt)(CPUS390XState *env, uint64_t a1)
+void HELPER(spt)(CPUS390XState *env, uint64_t time)
{
- uint64_t time = cpu_ldq_data(env, a1);
-
if (time == -1ULL) {
return;
}
/* 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)(CPUS390XState *env, uint64_t a1)
+uint64_t HELPER(stpt)(CPUS390XState *env)
{
/* XXX implement */
- cpu_stq_data(env, a1, 0);
+ return 0;
}
/* Store System Information */
-uint32_t HELPER(stsi)(CPUS390XState *env, 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;