Merge remote-tracking branch 'qmp/queue/qmp' into staging
[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 "helper.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
32 #if !defined(CONFIG_USER_ONLY)
33 #include "exec/softmmu_exec.h"
34 #include "sysemu/sysemu.h"
35 #endif
36
37 /* #define DEBUG_HELPER */
38 #ifdef DEBUG_HELPER
39 #define HELPER_LOG(x...) qemu_log(x)
40 #else
41 #define HELPER_LOG(x...)
42 #endif
43
44 /* Raise an exception dynamically from a helper function.  */
45 void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
46                                      uintptr_t retaddr)
47 {
48     int t;
49
50     env->exception_index = EXCP_PGM;
51     env->int_pgm_code = excp;
52
53     /* Use the (ultimate) callers address to find the insn that trapped.  */
54     cpu_restore_state(env, retaddr);
55
56     /* Advance past the insn.  */
57     t = cpu_ldub_code(env, env->psw.addr);
58     env->int_pgm_ilen = t = get_ilen(t);
59     env->psw.addr += 2 * t;
60
61     cpu_loop_exit(env);
62 }
63
64 /* Raise an exception statically from a TB.  */
65 void HELPER(exception)(CPUS390XState *env, uint32_t excp)
66 {
67     HELPER_LOG("%s: exception %d\n", __func__, excp);
68     env->exception_index = excp;
69     cpu_loop_exit(env);
70 }
71
72 #ifndef CONFIG_USER_ONLY
73 void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
74 {
75     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
76                   env->psw.addr);
77
78     if (kvm_enabled()) {
79 #ifdef CONFIG_KVM
80         kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code);
81 #endif
82     } else {
83         env->int_pgm_code = code;
84         env->int_pgm_ilen = ilen;
85         env->exception_index = EXCP_PGM;
86         cpu_loop_exit(env);
87     }
88 }
89
90 /* SCLP service call */
91 uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
92 {
93     int r = sclp_service_call(r1, r2);
94     if (r < 0) {
95         program_interrupt(env, -r, 4);
96         return 0;
97     }
98     return r;
99 }
100
101 /* DIAG */
102 uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
103                       uint64_t code)
104 {
105     uint64_t r;
106
107     switch (num) {
108     case 0x500:
109         /* KVM hypercall */
110         r = s390_virtio_hypercall(env, mem, code);
111         break;
112     case 0x44:
113         /* yield */
114         r = 0;
115         break;
116     case 0x308:
117         /* ipl */
118         r = 0;
119         break;
120     default:
121         r = -1;
122         break;
123     }
124
125     if (r) {
126         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
127     }
128
129     return r;
130 }
131
132 /* Set Prefix */
133 void HELPER(spx)(CPUS390XState *env, uint64_t a1)
134 {
135     uint32_t prefix = a1 & 0x7fffe000;
136     env->psa = prefix;
137     qemu_log("prefix: %#x\n", prefix);
138     tlb_flush_page(env, 0);
139     tlb_flush_page(env, TARGET_PAGE_SIZE);
140 }
141
142 static inline uint64_t clock_value(CPUS390XState *env)
143 {
144     uint64_t time;
145
146     time = env->tod_offset +
147         time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
148
149     return time;
150 }
151
152 /* Store Clock */
153 uint64_t HELPER(stck)(CPUS390XState *env)
154 {
155     return clock_value(env);
156 }
157
158 /* Set Clock Comparator */
159 void HELPER(sckc)(CPUS390XState *env, uint64_t time)
160 {
161     if (time == -1ULL) {
162         return;
163     }
164
165     /* difference between now and then */
166     time -= clock_value(env);
167     /* nanoseconds */
168     time = (time * 125) >> 9;
169
170     qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
171 }
172
173 /* Store Clock Comparator */
174 uint64_t HELPER(stckc)(CPUS390XState *env)
175 {
176     /* XXX implement */
177     return 0;
178 }
179
180 /* Set CPU Timer */
181 void HELPER(spt)(CPUS390XState *env, uint64_t time)
182 {
183     if (time == -1ULL) {
184         return;
185     }
186
187     /* nanoseconds */
188     time = (time * 125) >> 9;
189
190     qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
191 }
192
193 /* Store CPU Timer */
194 uint64_t HELPER(stpt)(CPUS390XState *env)
195 {
196     /* XXX implement */
197     return 0;
198 }
199
200 /* Store System Information */
201 uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
202                       uint64_t r0, uint64_t r1)
203 {
204     int cc = 0;
205     int sel1, sel2;
206
207     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
208         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
209         /* valid function code, invalid reserved bits */
210         program_interrupt(env, PGM_SPECIFICATION, 2);
211     }
212
213     sel1 = r0 & STSI_R0_SEL1_MASK;
214     sel2 = r1 & STSI_R1_SEL2_MASK;
215
216     /* XXX: spec exception if sysib is not 4k-aligned */
217
218     switch (r0 & STSI_LEVEL_MASK) {
219     case STSI_LEVEL_1:
220         if ((sel1 == 1) && (sel2 == 1)) {
221             /* Basic Machine Configuration */
222             struct sysib_111 sysib;
223
224             memset(&sysib, 0, sizeof(sysib));
225             ebcdic_put(sysib.manuf, "QEMU            ", 16);
226             /* same as machine type number in STORE CPU ID */
227             ebcdic_put(sysib.type, "QEMU", 4);
228             /* same as model number in STORE CPU ID */
229             ebcdic_put(sysib.model, "QEMU            ", 16);
230             ebcdic_put(sysib.sequence, "QEMU            ", 16);
231             ebcdic_put(sysib.plant, "QEMU", 4);
232             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
233         } else if ((sel1 == 2) && (sel2 == 1)) {
234             /* Basic Machine CPU */
235             struct sysib_121 sysib;
236
237             memset(&sysib, 0, sizeof(sysib));
238             /* XXX make different for different CPUs? */
239             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
240             ebcdic_put(sysib.plant, "QEMU", 4);
241             stw_p(&sysib.cpu_addr, env->cpu_num);
242             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
243         } else if ((sel1 == 2) && (sel2 == 2)) {
244             /* Basic Machine CPUs */
245             struct sysib_122 sysib;
246
247             memset(&sysib, 0, sizeof(sysib));
248             stl_p(&sysib.capability, 0x443afc29);
249             /* XXX change when SMP comes */
250             stw_p(&sysib.total_cpus, 1);
251             stw_p(&sysib.active_cpus, 1);
252             stw_p(&sysib.standby_cpus, 0);
253             stw_p(&sysib.reserved_cpus, 0);
254             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
255         } else {
256             cc = 3;
257         }
258         break;
259     case STSI_LEVEL_2:
260         {
261             if ((sel1 == 2) && (sel2 == 1)) {
262                 /* LPAR CPU */
263                 struct sysib_221 sysib;
264
265                 memset(&sysib, 0, sizeof(sysib));
266                 /* XXX make different for different CPUs? */
267                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
268                 ebcdic_put(sysib.plant, "QEMU", 4);
269                 stw_p(&sysib.cpu_addr, env->cpu_num);
270                 stw_p(&sysib.cpu_id, 0);
271                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
272             } else if ((sel1 == 2) && (sel2 == 2)) {
273                 /* LPAR CPUs */
274                 struct sysib_222 sysib;
275
276                 memset(&sysib, 0, sizeof(sysib));
277                 stw_p(&sysib.lpar_num, 0);
278                 sysib.lcpuc = 0;
279                 /* XXX change when SMP comes */
280                 stw_p(&sysib.total_cpus, 1);
281                 stw_p(&sysib.conf_cpus, 1);
282                 stw_p(&sysib.standby_cpus, 0);
283                 stw_p(&sysib.reserved_cpus, 0);
284                 ebcdic_put(sysib.name, "QEMU    ", 8);
285                 stl_p(&sysib.caf, 1000);
286                 stw_p(&sysib.dedicated_cpus, 0);
287                 stw_p(&sysib.shared_cpus, 0);
288                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
289             } else {
290                 cc = 3;
291             }
292             break;
293         }
294     case STSI_LEVEL_3:
295         {
296             if ((sel1 == 2) && (sel2 == 2)) {
297                 /* VM CPUs */
298                 struct sysib_322 sysib;
299
300                 memset(&sysib, 0, sizeof(sysib));
301                 sysib.count = 1;
302                 /* XXX change when SMP comes */
303                 stw_p(&sysib.vm[0].total_cpus, 1);
304                 stw_p(&sysib.vm[0].conf_cpus, 1);
305                 stw_p(&sysib.vm[0].standby_cpus, 0);
306                 stw_p(&sysib.vm[0].reserved_cpus, 0);
307                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
308                 stl_p(&sysib.vm[0].caf, 1000);
309                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
310                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
311             } else {
312                 cc = 3;
313             }
314             break;
315         }
316     case STSI_LEVEL_CURRENT:
317         env->regs[0] = STSI_LEVEL_3;
318         break;
319     default:
320         cc = 3;
321         break;
322     }
323
324     return cc;
325 }
326
327 uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
328                       uint64_t cpu_addr)
329 {
330     int cc = 0;
331
332     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
333                __func__, order_code, r1, cpu_addr);
334
335     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
336        as parameter (input). Status (output) is always R1. */
337
338     switch (order_code) {
339     case SIGP_SET_ARCH:
340         /* switch arch */
341         break;
342     case SIGP_SENSE:
343         /* enumerate CPU status */
344         if (cpu_addr) {
345             /* XXX implement when SMP comes */
346             return 3;
347         }
348         env->regs[r1] &= 0xffffffff00000000ULL;
349         cc = 1;
350         break;
351 #if !defined(CONFIG_USER_ONLY)
352     case SIGP_RESTART:
353         qemu_system_reset_request();
354         cpu_loop_exit(env);
355         break;
356     case SIGP_STOP:
357         qemu_system_shutdown_request();
358         cpu_loop_exit(env);
359         break;
360 #endif
361     default:
362         /* unknown sigp */
363         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
364         cc = 3;
365     }
366
367     return cc;
368 }
369 #endif