]> Git Repo - qemu.git/blob - target-s390x/misc_helper.c
target-s390: Convert SACF
[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, uint32_t r1, uint64_t r2)
92 {
93     int r;
94
95     r = sclp_service_call(r1, r2);
96     if (r < 0) {
97         program_interrupt(env, -r, 4);
98         return 0;
99     }
100     return r;
101 }
102
103 /* DIAG */
104 uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
105                       uint64_t code)
106 {
107     uint64_t r;
108
109     switch (num) {
110     case 0x500:
111         /* KVM hypercall */
112         r = s390_virtio_hypercall(env, mem, code);
113         break;
114     case 0x44:
115         /* yield */
116         r = 0;
117         break;
118     case 0x308:
119         /* ipl */
120         r = 0;
121         break;
122     default:
123         r = -1;
124         break;
125     }
126
127     if (r) {
128         program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
129     }
130
131     return r;
132 }
133
134 /* Set Prefix */
135 void HELPER(spx)(CPUS390XState *env, uint64_t a1)
136 {
137     uint32_t prefix = a1 & 0x7fffe000;
138     env->psa = prefix;
139     qemu_log("prefix: %#x\n", prefix);
140     tlb_flush_page(env, 0);
141     tlb_flush_page(env, TARGET_PAGE_SIZE);
142 }
143
144 static inline uint64_t clock_value(CPUS390XState *env)
145 {
146     uint64_t time;
147
148     time = env->tod_offset +
149         time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
150
151     return time;
152 }
153
154 /* Store Clock */
155 uint64_t HELPER(stck)(CPUS390XState *env)
156 {
157     return clock_value(env);
158 }
159
160 /* Set Clock Comparator */
161 void HELPER(sckc)(CPUS390XState *env, uint64_t time)
162 {
163     if (time == -1ULL) {
164         return;
165     }
166
167     /* difference between now and then */
168     time -= clock_value(env);
169     /* nanoseconds */
170     time = (time * 125) >> 9;
171
172     qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
173 }
174
175 /* Store Clock Comparator */
176 uint64_t HELPER(stckc)(CPUS390XState *env)
177 {
178     /* XXX implement */
179     return 0;
180 }
181
182 /* Set CPU Timer */
183 void HELPER(spt)(CPUS390XState *env, uint64_t time)
184 {
185     if (time == -1ULL) {
186         return;
187     }
188
189     /* nanoseconds */
190     time = (time * 125) >> 9;
191
192     qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
193 }
194
195 /* Store CPU Timer */
196 uint64_t HELPER(stpt)(CPUS390XState *env)
197 {
198     /* XXX implement */
199     return 0;
200 }
201
202 /* Store System Information */
203 uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0,
204                       uint32_t r1)
205 {
206     int cc = 0;
207     int sel1, sel2;
208
209     if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
210         ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
211         /* valid function code, invalid reserved bits */
212         program_interrupt(env, PGM_SPECIFICATION, 2);
213     }
214
215     sel1 = r0 & STSI_R0_SEL1_MASK;
216     sel2 = r1 & STSI_R1_SEL2_MASK;
217
218     /* XXX: spec exception if sysib is not 4k-aligned */
219
220     switch (r0 & STSI_LEVEL_MASK) {
221     case STSI_LEVEL_1:
222         if ((sel1 == 1) && (sel2 == 1)) {
223             /* Basic Machine Configuration */
224             struct sysib_111 sysib;
225
226             memset(&sysib, 0, sizeof(sysib));
227             ebcdic_put(sysib.manuf, "QEMU            ", 16);
228             /* same as machine type number in STORE CPU ID */
229             ebcdic_put(sysib.type, "QEMU", 4);
230             /* same as model number in STORE CPU ID */
231             ebcdic_put(sysib.model, "QEMU            ", 16);
232             ebcdic_put(sysib.sequence, "QEMU            ", 16);
233             ebcdic_put(sysib.plant, "QEMU", 4);
234             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
235         } else if ((sel1 == 2) && (sel2 == 1)) {
236             /* Basic Machine CPU */
237             struct sysib_121 sysib;
238
239             memset(&sysib, 0, sizeof(sysib));
240             /* XXX make different for different CPUs? */
241             ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
242             ebcdic_put(sysib.plant, "QEMU", 4);
243             stw_p(&sysib.cpu_addr, env->cpu_num);
244             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
245         } else if ((sel1 == 2) && (sel2 == 2)) {
246             /* Basic Machine CPUs */
247             struct sysib_122 sysib;
248
249             memset(&sysib, 0, sizeof(sysib));
250             stl_p(&sysib.capability, 0x443afc29);
251             /* XXX change when SMP comes */
252             stw_p(&sysib.total_cpus, 1);
253             stw_p(&sysib.active_cpus, 1);
254             stw_p(&sysib.standby_cpus, 0);
255             stw_p(&sysib.reserved_cpus, 0);
256             cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
257         } else {
258             cc = 3;
259         }
260         break;
261     case STSI_LEVEL_2:
262         {
263             if ((sel1 == 2) && (sel2 == 1)) {
264                 /* LPAR CPU */
265                 struct sysib_221 sysib;
266
267                 memset(&sysib, 0, sizeof(sysib));
268                 /* XXX make different for different CPUs? */
269                 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
270                 ebcdic_put(sysib.plant, "QEMU", 4);
271                 stw_p(&sysib.cpu_addr, env->cpu_num);
272                 stw_p(&sysib.cpu_id, 0);
273                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
274             } else if ((sel1 == 2) && (sel2 == 2)) {
275                 /* LPAR CPUs */
276                 struct sysib_222 sysib;
277
278                 memset(&sysib, 0, sizeof(sysib));
279                 stw_p(&sysib.lpar_num, 0);
280                 sysib.lcpuc = 0;
281                 /* XXX change when SMP comes */
282                 stw_p(&sysib.total_cpus, 1);
283                 stw_p(&sysib.conf_cpus, 1);
284                 stw_p(&sysib.standby_cpus, 0);
285                 stw_p(&sysib.reserved_cpus, 0);
286                 ebcdic_put(sysib.name, "QEMU    ", 8);
287                 stl_p(&sysib.caf, 1000);
288                 stw_p(&sysib.dedicated_cpus, 0);
289                 stw_p(&sysib.shared_cpus, 0);
290                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
291             } else {
292                 cc = 3;
293             }
294             break;
295         }
296     case STSI_LEVEL_3:
297         {
298             if ((sel1 == 2) && (sel2 == 2)) {
299                 /* VM CPUs */
300                 struct sysib_322 sysib;
301
302                 memset(&sysib, 0, sizeof(sysib));
303                 sysib.count = 1;
304                 /* XXX change when SMP comes */
305                 stw_p(&sysib.vm[0].total_cpus, 1);
306                 stw_p(&sysib.vm[0].conf_cpus, 1);
307                 stw_p(&sysib.vm[0].standby_cpus, 0);
308                 stw_p(&sysib.vm[0].reserved_cpus, 0);
309                 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
310                 stl_p(&sysib.vm[0].caf, 1000);
311                 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
312                 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
313             } else {
314                 cc = 3;
315             }
316             break;
317         }
318     case STSI_LEVEL_CURRENT:
319         env->regs[0] = STSI_LEVEL_3;
320         break;
321     default:
322         cc = 3;
323         break;
324     }
325
326     return cc;
327 }
328
329 uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
330                       uint64_t cpu_addr)
331 {
332     int cc = 0;
333
334     HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
335                __func__, order_code, r1, cpu_addr);
336
337     /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
338        as parameter (input). Status (output) is always R1. */
339
340     switch (order_code) {
341     case SIGP_SET_ARCH:
342         /* switch arch */
343         break;
344     case SIGP_SENSE:
345         /* enumerate CPU status */
346         if (cpu_addr) {
347             /* XXX implement when SMP comes */
348             return 3;
349         }
350         env->regs[r1] &= 0xffffffff00000000ULL;
351         cc = 1;
352         break;
353 #if !defined(CONFIG_USER_ONLY)
354     case SIGP_RESTART:
355         qemu_system_reset_request();
356         cpu_loop_exit(env);
357         break;
358     case SIGP_STOP:
359         qemu_system_shutdown_request();
360         cpu_loop_exit(env);
361         break;
362 #endif
363     default:
364         /* unknown sigp */
365         fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
366         cc = 3;
367     }
368
369     return cc;
370 }
371 #endif
This page took 0.042215 seconds and 4 git commands to generate.