xref: /openbmc/qemu/target/s390x/helper.c (revision 8908eb1a)
1 /*
2  *  S/390 helpers
3  *
4  *  Copyright (c) 2009 Ulrich Hecht
5  *  Copyright (c) 2011 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 "qemu/osdep.h"
22 #include "qapi/error.h"
23 #include "cpu.h"
24 #include "exec/gdbstub.h"
25 #include "qemu/timer.h"
26 #include "exec/exec-all.h"
27 #include "hw/s390x/ioinst.h"
28 #ifndef CONFIG_USER_ONLY
29 #include "sysemu/sysemu.h"
30 #endif
31 
32 //#define DEBUG_S390
33 //#define DEBUG_S390_STDOUT
34 
35 #ifdef DEBUG_S390
36 #ifdef DEBUG_S390_STDOUT
37 #define DPRINTF(fmt, ...) \
38     do { fprintf(stderr, fmt, ## __VA_ARGS__); \
39          if (qemu_log_separate()) qemu_log(fmt, ##__VA_ARGS__); } while (0)
40 #else
41 #define DPRINTF(fmt, ...) \
42     do { qemu_log(fmt, ## __VA_ARGS__); } while (0)
43 #endif
44 #else
45 #define DPRINTF(fmt, ...) \
46     do { } while (0)
47 #endif
48 
49 
50 #ifndef CONFIG_USER_ONLY
51 void s390x_tod_timer(void *opaque)
52 {
53     S390CPU *cpu = opaque;
54     CPUS390XState *env = &cpu->env;
55 
56     env->pending_int |= INTERRUPT_TOD;
57     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
58 }
59 
60 void s390x_cpu_timer(void *opaque)
61 {
62     S390CPU *cpu = opaque;
63     CPUS390XState *env = &cpu->env;
64 
65     env->pending_int |= INTERRUPT_CPUTIMER;
66     cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
67 }
68 #endif
69 
70 S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp)
71 {
72     static bool features_parsed;
73     char *name, *features;
74     const char *typename;
75     ObjectClass *oc;
76     CPUClass *cc;
77 
78     name = g_strdup(cpu_model);
79     features = strchr(name, ',');
80     if (features) {
81         features[0] = 0;
82         features++;
83     }
84 
85     oc = cpu_class_by_name(TYPE_S390_CPU, name);
86     if (!oc) {
87         error_setg(errp, "Unknown CPU definition \'%s\'", name);
88         g_free(name);
89         return NULL;
90     }
91     typename = object_class_get_name(oc);
92 
93     if (!features_parsed) {
94         features_parsed = true;
95         cc = CPU_CLASS(oc);
96         cc->parse_features(typename, features, errp);
97     }
98     g_free(name);
99 
100     if (*errp) {
101         return NULL;
102     }
103     return S390_CPU(CPU(object_new(typename)));
104 }
105 
106 S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp)
107 {
108     S390CPU *cpu;
109     Error *err = NULL;
110 
111     cpu = cpu_s390x_create(cpu_model, &err);
112     if (err != NULL) {
113         goto out;
114     }
115 
116     object_property_set_int(OBJECT(cpu), id, "id", &err);
117     if (err != NULL) {
118         goto out;
119     }
120     object_property_set_bool(OBJECT(cpu), true, "realized", &err);
121 
122 out:
123     if (err) {
124         error_propagate(errp, err);
125         object_unref(OBJECT(cpu));
126         cpu = NULL;
127     }
128     return cpu;
129 }
130 
131 S390CPU *cpu_s390x_init(const char *cpu_model)
132 {
133     Error *err = NULL;
134     S390CPU *cpu;
135     /* Use to track CPU ID for linux-user only */
136     static int64_t next_cpu_id;
137 
138     cpu = s390x_new_cpu(cpu_model, next_cpu_id++, &err);
139     if (err) {
140         error_report_err(err);
141     }
142     return cpu;
143 }
144 
145 #ifndef CONFIG_USER_ONLY
146 
147 hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
148 {
149     S390CPU *cpu = S390_CPU(cs);
150     CPUS390XState *env = &cpu->env;
151     target_ulong raddr;
152     int prot;
153     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
154 
155     /* 31-Bit mode */
156     if (!(env->psw.mask & PSW_MASK_64)) {
157         vaddr &= 0x7fffffff;
158     }
159 
160     if (mmu_translate(env, vaddr, MMU_INST_FETCH, asc, &raddr, &prot, false)) {
161         return -1;
162     }
163     return raddr;
164 }
165 
166 hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
167 {
168     hwaddr phys_addr;
169     target_ulong page;
170 
171     page = vaddr & TARGET_PAGE_MASK;
172     phys_addr = cpu_get_phys_page_debug(cs, page);
173     phys_addr += (vaddr & ~TARGET_PAGE_MASK);
174 
175     return phys_addr;
176 }
177 
178 void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
179 {
180     uint64_t old_mask = env->psw.mask;
181 
182     env->psw.addr = addr;
183     env->psw.mask = mask;
184     if (tcg_enabled()) {
185         env->cc_op = (mask >> 44) & 3;
186     }
187 
188     if ((old_mask ^ mask) & PSW_MASK_PER) {
189         s390_cpu_recompute_watchpoints(CPU(s390_env_get_cpu(env)));
190     }
191 
192     if (mask & PSW_MASK_WAIT) {
193         S390CPU *cpu = s390_env_get_cpu(env);
194         if (s390_cpu_halt(cpu) == 0) {
195 #ifndef CONFIG_USER_ONLY
196             qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
197 #endif
198         }
199     }
200 }
201 
202 uint64_t get_psw_mask(CPUS390XState *env)
203 {
204     uint64_t r = env->psw.mask;
205 
206     if (tcg_enabled()) {
207         env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
208                              env->cc_vr);
209 
210         r &= ~PSW_MASK_CC;
211         assert(!(env->cc_op & ~3));
212         r |= (uint64_t)env->cc_op << 44;
213     }
214 
215     return r;
216 }
217 
218 LowCore *cpu_map_lowcore(CPUS390XState *env)
219 {
220     S390CPU *cpu = s390_env_get_cpu(env);
221     LowCore *lowcore;
222     hwaddr len = sizeof(LowCore);
223 
224     lowcore = cpu_physical_memory_map(env->psa, &len, 1);
225 
226     if (len < sizeof(LowCore)) {
227         cpu_abort(CPU(cpu), "Could not map lowcore\n");
228     }
229 
230     return lowcore;
231 }
232 
233 void cpu_unmap_lowcore(LowCore *lowcore)
234 {
235     cpu_physical_memory_unmap(lowcore, sizeof(LowCore), 1, sizeof(LowCore));
236 }
237 
238 void do_restart_interrupt(CPUS390XState *env)
239 {
240     uint64_t mask, addr;
241     LowCore *lowcore;
242 
243     lowcore = cpu_map_lowcore(env);
244 
245     lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env));
246     lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr);
247     mask = be64_to_cpu(lowcore->restart_new_psw.mask);
248     addr = be64_to_cpu(lowcore->restart_new_psw.addr);
249 
250     cpu_unmap_lowcore(lowcore);
251 
252     load_psw(env, mask, addr);
253 }
254 
255 void s390_cpu_recompute_watchpoints(CPUState *cs)
256 {
257     const int wp_flags = BP_CPU | BP_MEM_WRITE | BP_STOP_BEFORE_ACCESS;
258     S390CPU *cpu = S390_CPU(cs);
259     CPUS390XState *env = &cpu->env;
260 
261     /* We are called when the watchpoints have changed. First
262        remove them all.  */
263     cpu_watchpoint_remove_all(cs, BP_CPU);
264 
265     /* Return if PER is not enabled */
266     if (!(env->psw.mask & PSW_MASK_PER)) {
267         return;
268     }
269 
270     /* Return if storage-alteration event is not enabled.  */
271     if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) {
272         return;
273     }
274 
275     if (env->cregs[10] == 0 && env->cregs[11] == -1LL) {
276         /* We can't create a watchoint spanning the whole memory range, so
277            split it in two parts.   */
278         cpu_watchpoint_insert(cs, 0, 1ULL << 63, wp_flags, NULL);
279         cpu_watchpoint_insert(cs, 1ULL << 63, 1ULL << 63, wp_flags, NULL);
280     } else if (env->cregs[10] > env->cregs[11]) {
281         /* The address range loops, create two watchpoints.  */
282         cpu_watchpoint_insert(cs, env->cregs[10], -env->cregs[10],
283                               wp_flags, NULL);
284         cpu_watchpoint_insert(cs, 0, env->cregs[11] + 1, wp_flags, NULL);
285 
286     } else {
287         /* Default case, create a single watchpoint.  */
288         cpu_watchpoint_insert(cs, env->cregs[10],
289                               env->cregs[11] - env->cregs[10] + 1,
290                               wp_flags, NULL);
291     }
292 }
293 
294 #endif /* CONFIG_USER_ONLY */
295 
296 void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
297                          int flags)
298 {
299     S390CPU *cpu = S390_CPU(cs);
300     CPUS390XState *env = &cpu->env;
301     int i;
302 
303     if (env->cc_op > 3) {
304         cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %15s\n",
305                     env->psw.mask, env->psw.addr, cc_name(env->cc_op));
306     } else {
307         cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %02x\n",
308                     env->psw.mask, env->psw.addr, env->cc_op);
309     }
310 
311     for (i = 0; i < 16; i++) {
312         cpu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]);
313         if ((i % 4) == 3) {
314             cpu_fprintf(f, "\n");
315         } else {
316             cpu_fprintf(f, " ");
317         }
318     }
319 
320     for (i = 0; i < 16; i++) {
321         cpu_fprintf(f, "F%02d=%016" PRIx64, i, get_freg(env, i)->ll);
322         if ((i % 4) == 3) {
323             cpu_fprintf(f, "\n");
324         } else {
325             cpu_fprintf(f, " ");
326         }
327     }
328 
329     for (i = 0; i < 32; i++) {
330         cpu_fprintf(f, "V%02d=%016" PRIx64 "%016" PRIx64, i,
331                     env->vregs[i][0].ll, env->vregs[i][1].ll);
332         cpu_fprintf(f, (i % 2) ? "\n" : " ");
333     }
334 
335 #ifndef CONFIG_USER_ONLY
336     for (i = 0; i < 16; i++) {
337         cpu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]);
338         if ((i % 4) == 3) {
339             cpu_fprintf(f, "\n");
340         } else {
341             cpu_fprintf(f, " ");
342         }
343     }
344 #endif
345 
346 #ifdef DEBUG_INLINE_BRANCHES
347     for (i = 0; i < CC_OP_MAX; i++) {
348         cpu_fprintf(f, "  %15s = %10ld\t%10ld\n", cc_name(i),
349                     inline_branch_miss[i], inline_branch_hit[i]);
350     }
351 #endif
352 
353     cpu_fprintf(f, "\n");
354 }
355