1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
33
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
51void 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
60void 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
70S390CPU *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
106S390CPU *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
122out:
123 if (err) {
124 error_propagate(errp, err);
125 object_unref(OBJECT(cpu));
126 cpu = NULL;
127 }
128 return cpu;
129}
130
131S390CPU *cpu_s390x_init(const char *cpu_model)
132{
133 Error *err = NULL;
134 S390CPU *cpu;
135
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
147hwaddr 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
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
166hwaddr 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
178void 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
202uint64_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
218LowCore *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
233void cpu_unmap_lowcore(LowCore *lowcore)
234{
235 cpu_physical_memory_unmap(lowcore, sizeof(LowCore), 1, sizeof(LowCore));
236}
237
238void 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
255void 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
262
263 cpu_watchpoint_remove_all(cs, BP_CPU);
264
265
266 if (!(env->psw.mask & PSW_MASK_PER)) {
267 return;
268 }
269
270
271 if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) {
272 return;
273 }
274
275 if (env->cregs[10] == 0 && env->cregs[11] == -1LL) {
276
277
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
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
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
295
296void 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