s390x: cleanup interrupt injection
[sdk/emulator/qemu.git] / target-s390x / misc_helper.c
1 /*
2  *  S/390 misc helper routines
3  *
4  *  Copyright (c) 2009 Ulrich Hecht
5  *  Copyright (c) 2009 Alexander Graf
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "cpu.h"
22 #include "exec/memory.h"
23 #include "qemu/host-utils.h"
24 #include "exec/helper-proto.h"
25 #include <string.h>
26 #include "sysemu/kvm.h"
27 #include "qemu/timer.h"
28 #ifdef CONFIG_KVM
29 #include <linux/kvm.h>
30 #endif
31 #include "exec/cpu_ldst.h"
32
33 #if !defined(CONFIG_USER_ONLY)
34 #include "sysemu/cpus.h"
35 #include "sysemu/sysemu.h"
36 #include "hw/s390x/ebcdic.h"
37 #endif
38
39 /* #define DEBUG_HELPER */
40 #ifdef DEBUG_HELPER
41 #define HELPER_LOG(x...) qemu_log(x)
42 #else
43 #define HELPER_LOG(x...)
44 #endif
45
46 /* Raise an exception dynamically from a helper function.  */
47 void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
48                                      uintptr_t retaddr)
49 {
50     CPUState *cs = CPU(s390_env_get_cpu(env));
51     int t;
52
53     cs->exception_index = EXCP_PGM;
54     env->int_pgm_code = excp;
55
56     /* Use the (ultimate) callers address to find the insn that trapped.  */
57     cpu_restore_state(cs, retaddr);
58
59     /* Advance past the insn.  */
60     t = cpu_ldub_code(env, env->psw.addr);
61     env->int_pgm_ilen = t = get_ilen(t);
62     env->psw.addr += 2 * t;
63
64     cpu_loop_exit(cs);
65 }
66
67 /* Raise an exception statically from a TB.  */
68 void HELPER(exception)(CPUS390XState *env, uint32_t excp)
69 {
70     CPUState *cs = CPU(s390_env_get_cpu(env));
71
72     HELPER_LOG("%s: exception %d\n", __func__, excp);
73     cs->exception_index = excp;
74     cpu_loop_exit(cs);
75 }
76
77 #ifndef CONFIG_USER_ONLY
78
79 void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
80 {
81     S390CPU *cpu = s390_env_get_cpu(env);
82
83     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
84                   env->psw.addr);
85
86     if (kvm_enabled()) {
87 #ifdef CONFIG_KVM
88         struct kvm_s390_irq irq = {
89             .type = KVM_S390_PROGRAM_INT,
90             .u.pgm.code = code,
91         };
92
93         kvm_s390_vcpu_interrupt(cpu, &irq);
94 #endif
95     } else {
96         CPUState *cs = CPU(cpu);
97
98         env->int_pgm_code = code;
99         env->int_pgm_ilen = ilen;
100         cs->exception_index = EXCP_PGM;
101         cpu_loop_exit(cs);
102     }
103 }
104
105 /* SCLP service call */
106 uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
107 {
108     int r = sclp_service_call(env, r1, r2);
109     if (r < 0) {
110         program_interrupt(env, -r, 4);
111         return 0;
112     }
113     return r;
114 }
115
116 #ifndef CONFIG_USER_ONLY
117 static void cpu_reset_all(void)
118 {
119     CPUState *cs;
120     S390CPUClass *scc;
121
122     CPU_FOREACH(cs) {
123         scc = S390_CPU_GET_CLASS(cs);
124         scc->cpu_reset(cs);
125     }
126 }
127
128 static void cpu_full_reset_all(void)
129 {
130     CPUState *cpu;
131
132     CPU_FOREACH(cpu) {
133         cpu_reset(cpu);
134     }
135 }
136
137 static int modified_clear_reset(S390CPU *cpu)
138 {
139     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
140
141     pause_all_vcpus();
142     cpu_synchronize_all_states();
143     cpu_full_reset_all();
144     cmma_reset(cpu);
145     io_subsystem_reset();
146     scc->load_normal(CPU(cpu));
147     cpu_synchronize_all_post_reset();
148     resume_all_vcpus();
149     return 0;
150 }
151
152 static int load_normal_reset(S390CPU *cpu)
153 {
154     S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
155
156     pause_all_vcpus();
157     cpu_synchronize_all_states();
158     cpu_reset_all();
159     cmma_reset(cpu);
160     io_subsystem_reset();
161     scc->initial_cpu_reset(CPU(cpu));
162     scc->load_normal(CPU(cpu));
163     cpu_synchronize_all_post_reset();
164     resume_all_vcpus();
165     return 0;
166 }
167
168 #define DIAG_308_RC_NO_CONF         0x0102
169 #define DIAG_308_RC_INVALID         0x0402
170 void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
171 {
172     uint64_t addr =  env->regs[r1];
173     uint64_t subcode = env->regs[r3];
174
175     if (env->psw.mask & PSW_MASK_PSTATE) {
176         program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
177         return;
178     }
179
180     if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
181         program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
182         return;
183     }
184
185     switch (subcode) {
186     case 0:
187         modified_clear_reset(s390_env_get_cpu(env));
188         break;
189     case 1:
190         load_normal_reset(s390_env_get_cpu(env));
191         break;
192     case 5:
193         if ((r1 & 1) || (addr & 0x0fffULL)) {
194             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
195             return;
196         }
197         env->regs[r1+1] = DIAG_308_RC_INVALID;
198         return;
199     case 6:
200         if ((r1 & 1) || (addr & 0x0fffULL)) {
201             program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
202             return;
203         }
204         env->regs[r1+1] = DIAG_308_RC_NO_CONF;
205         return;
206     default:
207         hw_error("Unhandled diag308 subcode %" PRIx64, subcode);
208         break;
209     }
210 }
211 #endif
212
213 /* DIAG */
214 uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
215                       uint64_t code)
216 {
217     uint64_t r;
218
219     switch (num) {
220     case 0x500:
221         /* KVM hypercall */
222         r = s390_virtio_hypercall(env);
223         break;
224     case 0x44:
225         /* yield */
226         r = 0;
227         break;
228     case 0x308:
229         /* ipl */
230         r = 0;
231         break;
232     default:
233         r = -1;
234         break;
235     }
236
237     if (r) {
238         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
239     }
240
241     return r;
242 }
243
244 /* Set Prefix */
245 void HELPER(spx)(CPUS390XState *env, uint64_t a1)
246 {
247     CPUState *cs = CPU(s390_env_get_cpu(env));
248     uint32_t prefix = a1 & 0x7fffe000;
249
250     env->psa = prefix;
251     qemu_log("prefix: %#x\n", prefix);
252     tlb_flush_page(cs, 0);
253     tlb_flush_page(cs, TARGET_PAGE_SIZE);
254 }
255
256 static inline uint64_t clock_value(CPUS390XState *env)
257 {
258     uint64_t time;
259
260     time = env->tod_offset +
261         time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
262
263     return time;
264 }
265
266 /* Store Clock */
267 uint64_t HELPER(stck)(CPUS390XState *env)
268 {
269     return clock_value(env);
270 }
271
272 /* Set Clock Comparator */
273 void HELPER(sckc)(CPUS390XState *env, uint64_t time)
274 {
275     if (time == -1ULL) {
276         return;
277     }
278
279     /* difference between now and then */
280     time -= clock_value(env);
281     /* nanoseconds */
282     time = (time * 125) >> 9;
283
284     timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
285 }
286
287 /* Store Clock Comparator */
288 uint64_t HELPER(stckc)(CPUS390XState *env)
289 {
290     /* XXX implement */
291     return 0;
292 }
293
294 /* Set CPU Timer */
295 void HELPER(spt)(CPUS390XState *env, uint64_t time)
296 {
297     if (time == -1ULL) {
298         return;
299     }
300
301     /* nanoseconds */
302     time = (time * 125) >> 9;
303
304     timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
305 }
306
307 /* Store CPU Timer */
308 uint64_t HELPER(stpt)(CPUS390XState *env)
309 {
310     /* XXX implement */
311     return 0;
312 }
313
314 /* Store System Information */
315 uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
316                       uint64_t r0, uint64_t r1)
317 {
318     int cc = 0;
319     int sel1, sel2;
320
321     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
322         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
323         /* valid function code, invalid reserved bits */
324         program_interrupt(env, PGM_SPECIFICATION, 2);
325     }
326
327     sel1 = r0 & STSI_R0_SEL1_MASK;
328     sel2 = r1 & STSI_R1_SEL2_MASK;
329
330     /* XXX: spec exception if sysib is not 4k-aligned */
331
332     switch (r0 & STSI_LEVEL_MASK) {
333     case STSI_LEVEL_1:
334         if ((sel1 == 1) && (sel2 == 1)) {
335             /* Basic Machine Configuration */
336             struct sysib_111 sysib;
337
338             memset(&sysib, 0, sizeof(sysib));
339             ebcdic_put(sysib.manuf, "QEMU            ", 16);
340             /* same as machine type number in STORE CPU ID */
341             ebcdic_put(sysib.type, "QEMU", 4);
342             /* same as model number in STORE CPU ID */
343             ebcdic_put(sysib.model, "QEMU            ", 16);
344             ebcdic_put(sysib.sequence, "QEMU            ", 16);
345             ebcdic_put(sysib.plant, "QEMU", 4);
346             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
347         } else if ((sel1 == 2) && (sel2 == 1)) {
348             /* Basic Machine CPU */
349             struct sysib_121 sysib;
350
351             memset(&sysib, 0, sizeof(sysib));
352             /* XXX make different for different CPUs? */
353             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
354             ebcdic_put(sysib.plant, "QEMU", 4);
355             stw_p(&sysib.cpu_addr, env->cpu_num);
356             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
357         } else if ((sel1 == 2) && (sel2 == 2)) {
358             /* Basic Machine CPUs */
359             struct sysib_122 sysib;
360
361             memset(&sysib, 0, sizeof(sysib));
362             stl_p(&sysib.capability, 0x443afc29);
363             /* XXX change when SMP comes */
364             stw_p(&sysib.total_cpus, 1);
365             stw_p(&sysib.active_cpus, 1);
366             stw_p(&sysib.standby_cpus, 0);
367             stw_p(&sysib.reserved_cpus, 0);
368             cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
369         } else {
370             cc = 3;
371         }
372         break;
373     case STSI_LEVEL_2:
374         {
375             if ((sel1 == 2) && (sel2 == 1)) {
376                 /* LPAR CPU */
377                 struct sysib_221 sysib;
378
379                 memset(&sysib, 0, sizeof(sysib));
380                 /* XXX make different for different CPUs? */
381                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
382                 ebcdic_put(sysib.plant, "QEMU", 4);
383                 stw_p(&sysib.cpu_addr, env->cpu_num);
384                 stw_p(&sysib.cpu_id, 0);
385                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
386             } else if ((sel1 == 2) && (sel2 == 2)) {
387                 /* LPAR CPUs */
388                 struct sysib_222 sysib;
389
390                 memset(&sysib, 0, sizeof(sysib));
391                 stw_p(&sysib.lpar_num, 0);
392                 sysib.lcpuc = 0;
393                 /* XXX change when SMP comes */
394                 stw_p(&sysib.total_cpus, 1);
395                 stw_p(&sysib.conf_cpus, 1);
396                 stw_p(&sysib.standby_cpus, 0);
397                 stw_p(&sysib.reserved_cpus, 0);
398                 ebcdic_put(sysib.name, "QEMU    ", 8);
399                 stl_p(&sysib.caf, 1000);
400                 stw_p(&sysib.dedicated_cpus, 0);
401                 stw_p(&sysib.shared_cpus, 0);
402                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
403             } else {
404                 cc = 3;
405             }
406             break;
407         }
408     case STSI_LEVEL_3:
409         {
410             if ((sel1 == 2) && (sel2 == 2)) {
411                 /* VM CPUs */
412                 struct sysib_322 sysib;
413
414                 memset(&sysib, 0, sizeof(sysib));
415                 sysib.count = 1;
416                 /* XXX change when SMP comes */
417                 stw_p(&sysib.vm[0].total_cpus, 1);
418                 stw_p(&sysib.vm[0].conf_cpus, 1);
419                 stw_p(&sysib.vm[0].standby_cpus, 0);
420                 stw_p(&sysib.vm[0].reserved_cpus, 0);
421                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
422                 stl_p(&sysib.vm[0].caf, 1000);
423                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
424                 cpu_physical_memory_write(a0, &sysib, sizeof(sysib));
425             } else {
426                 cc = 3;
427             }
428             break;
429         }
430     case STSI_LEVEL_CURRENT:
431         env->regs[0] = STSI_LEVEL_3;
432         break;
433     default:
434         cc = 3;
435         break;
436     }
437
438     return cc;
439 }
440
441 uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
442                       uint64_t cpu_addr)
443 {
444     int cc = 0;
445
446     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
447                __func__, order_code, r1, cpu_addr);
448
449     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
450        as parameter (input). Status (output) is always R1. */
451
452     switch (order_code) {
453     case SIGP_SET_ARCH:
454         /* switch arch */
455         break;
456     case SIGP_SENSE:
457         /* enumerate CPU status */
458         if (cpu_addr) {
459             /* XXX implement when SMP comes */
460             return 3;
461         }
462         env->regs[r1] &= 0xffffffff00000000ULL;
463         cc = 1;
464         break;
465 #if !defined(CONFIG_USER_ONLY)
466     case SIGP_RESTART:
467         qemu_system_reset_request();
468         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
469         break;
470     case SIGP_STOP:
471         qemu_system_shutdown_request();
472         cpu_loop_exit(CPU(s390_env_get_cpu(env)));
473         break;
474 #endif
475     default:
476         /* unknown sigp */
477         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
478         cc = 3;
479     }
480
481     return cc;
482 }
483 #endif