qxl: call qemu_spice_display_init_common for secondary devices
[qemu/ar7.git] / target / s390x / diag.c
blob10ac845bcda24d9f9a06fef4f9bcfce081c4fde7
1 /*
2 * S390x DIAG instruction helper functions
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include "qemu/osdep.h"
16 #include "cpu.h"
17 #include "exec/address-spaces.h"
18 #include "exec/exec-all.h"
19 #include "hw/watchdog/wdt_diag288.h"
20 #include "sysemu/cpus.h"
21 #include "hw/s390x/ipl.h"
23 static int modified_clear_reset(S390CPU *cpu)
25 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
26 CPUState *t;
28 pause_all_vcpus();
29 cpu_synchronize_all_states();
30 CPU_FOREACH(t) {
31 run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
33 s390_cmma_reset();
34 subsystem_reset();
35 s390_crypto_reset();
36 scc->load_normal(CPU(cpu));
37 cpu_synchronize_all_post_reset();
38 resume_all_vcpus();
39 return 0;
42 static int load_normal_reset(S390CPU *cpu)
44 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
45 CPUState *t;
47 pause_all_vcpus();
48 cpu_synchronize_all_states();
49 CPU_FOREACH(t) {
50 run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL);
52 s390_cmma_reset();
53 subsystem_reset();
54 scc->initial_cpu_reset(CPU(cpu));
55 scc->load_normal(CPU(cpu));
56 cpu_synchronize_all_post_reset();
57 resume_all_vcpus();
58 return 0;
61 int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
63 uint64_t func = env->regs[r1];
64 uint64_t timeout = env->regs[r1 + 1];
65 uint64_t action = env->regs[r3];
66 Object *obj;
67 DIAG288State *diag288;
68 DIAG288Class *diag288_class;
70 if (r1 % 2 || action != 0) {
71 return -1;
74 /* Timeout must be more than 15 seconds except for timer deletion */
75 if (func != WDT_DIAG288_CANCEL && timeout < 15) {
76 return -1;
79 obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL);
80 if (!obj) {
81 return -1;
84 diag288 = DIAG288(obj);
85 diag288_class = DIAG288_GET_CLASS(diag288);
86 return diag288_class->handle_timer(diag288, func, timeout);
89 #define DIAG_308_RC_OK 0x0001
90 #define DIAG_308_RC_NO_CONF 0x0102
91 #define DIAG_308_RC_INVALID 0x0402
93 void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
95 uint64_t addr = env->regs[r1];
96 uint64_t subcode = env->regs[r3];
97 IplParameterBlock *iplb;
99 if (env->psw.mask & PSW_MASK_PSTATE) {
100 program_interrupt(env, PGM_PRIVILEGED, ILEN_AUTO);
101 return;
104 if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
105 program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
106 return;
109 switch (subcode) {
110 case 0:
111 modified_clear_reset(s390_env_get_cpu(env));
112 if (tcg_enabled()) {
113 cpu_loop_exit(CPU(s390_env_get_cpu(env)));
115 break;
116 case 1:
117 load_normal_reset(s390_env_get_cpu(env));
118 if (tcg_enabled()) {
119 cpu_loop_exit(CPU(s390_env_get_cpu(env)));
121 break;
122 case 3:
123 s390_reipl_request();
124 if (tcg_enabled()) {
125 cpu_loop_exit(CPU(s390_env_get_cpu(env)));
127 break;
128 case 5:
129 if ((r1 & 1) || (addr & 0x0fffULL)) {
130 program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
131 return;
133 if (!address_space_access_valid(&address_space_memory, addr,
134 sizeof(IplParameterBlock), false)) {
135 program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO);
136 return;
138 iplb = g_malloc0(sizeof(IplParameterBlock));
139 cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
140 if (!iplb_valid_len(iplb)) {
141 env->regs[r1 + 1] = DIAG_308_RC_INVALID;
142 goto out;
145 cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
147 if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) {
148 env->regs[r1 + 1] = DIAG_308_RC_INVALID;
149 goto out;
152 s390_ipl_update_diag308(iplb);
153 env->regs[r1 + 1] = DIAG_308_RC_OK;
154 out:
155 g_free(iplb);
156 return;
157 case 6:
158 if ((r1 & 1) || (addr & 0x0fffULL)) {
159 program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
160 return;
162 if (!address_space_access_valid(&address_space_memory, addr,
163 sizeof(IplParameterBlock), true)) {
164 program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO);
165 return;
167 iplb = s390_ipl_get_iplb();
168 if (iplb) {
169 cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
170 env->regs[r1 + 1] = DIAG_308_RC_OK;
171 } else {
172 env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
174 return;
175 default:
176 hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
177 break;