MAINTAINERS: add maintainer to virtio-9p
[qemu/ar7.git] / target-s390x / helper.c
blobd88700695e89b45f7550573c07e47d3099036f26
1 /*
2 * S/390 helpers
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2011 Alexander Graf
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.
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.
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/>.
21 #include "cpu.h"
22 #include "exec/gdbstub.h"
23 #include "qemu/timer.h"
24 #include "exec/cpu_ldst.h"
25 #ifndef CONFIG_USER_ONLY
26 #include "sysemu/sysemu.h"
27 #endif
29 //#define DEBUG_S390
30 //#define DEBUG_S390_STDOUT
32 #ifdef DEBUG_S390
33 #ifdef DEBUG_S390_STDOUT
34 #define DPRINTF(fmt, ...) \
35 do { fprintf(stderr, fmt, ## __VA_ARGS__); \
36 qemu_log(fmt, ##__VA_ARGS__); } while (0)
37 #else
38 #define DPRINTF(fmt, ...) \
39 do { qemu_log(fmt, ## __VA_ARGS__); } while (0)
40 #endif
41 #else
42 #define DPRINTF(fmt, ...) \
43 do { } while (0)
44 #endif
47 #ifndef CONFIG_USER_ONLY
48 void s390x_tod_timer(void *opaque)
50 S390CPU *cpu = opaque;
51 CPUS390XState *env = &cpu->env;
53 env->pending_int |= INTERRUPT_TOD;
54 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
57 void s390x_cpu_timer(void *opaque)
59 S390CPU *cpu = opaque;
60 CPUS390XState *env = &cpu->env;
62 env->pending_int |= INTERRUPT_CPUTIMER;
63 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
65 #endif
67 S390CPU *cpu_s390x_init(const char *cpu_model)
69 S390CPU *cpu;
71 cpu = S390_CPU(object_new(TYPE_S390_CPU));
73 object_property_set_bool(OBJECT(cpu), true, "realized", NULL);
75 return cpu;
78 #if defined(CONFIG_USER_ONLY)
80 void s390_cpu_do_interrupt(CPUState *cs)
82 cs->exception_index = -1;
85 int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
86 int rw, int mmu_idx)
88 S390CPU *cpu = S390_CPU(cs);
90 cs->exception_index = EXCP_PGM;
91 cpu->env.int_pgm_code = PGM_ADDRESSING;
92 /* On real machines this value is dropped into LowMem. Since this
93 is userland, simply put this someplace that cpu_loop can find it. */
94 cpu->env.__excp_addr = address;
95 return 1;
98 #else /* !CONFIG_USER_ONLY */
100 /* Ensure to exit the TB after this call! */
101 void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen)
103 CPUState *cs = CPU(s390_env_get_cpu(env));
105 cs->exception_index = EXCP_PGM;
106 env->int_pgm_code = code;
107 env->int_pgm_ilen = ilen;
110 int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr,
111 int rw, int mmu_idx)
113 S390CPU *cpu = S390_CPU(cs);
114 CPUS390XState *env = &cpu->env;
115 uint64_t asc = cpu_mmu_idx_to_asc(mmu_idx);
116 target_ulong vaddr, raddr;
117 int prot;
119 DPRINTF("%s: address 0x%" VADDR_PRIx " rw %d mmu_idx %d\n",
120 __func__, orig_vaddr, rw, mmu_idx);
122 orig_vaddr &= TARGET_PAGE_MASK;
123 vaddr = orig_vaddr;
125 /* 31-Bit mode */
126 if (!(env->psw.mask & PSW_MASK_64)) {
127 vaddr &= 0x7fffffff;
130 if (mmu_translate(env, vaddr, rw, asc, &raddr, &prot, true)) {
131 /* Translation ended in exception */
132 return 1;
135 /* check out of RAM access */
136 if (raddr > (ram_size + virtio_size)) {
137 DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
138 (uint64_t)raddr, (uint64_t)ram_size);
139 trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER);
140 return 1;
143 qemu_log_mask(CPU_LOG_MMU, "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n",
144 __func__, (uint64_t)vaddr, (uint64_t)raddr, prot);
146 tlb_set_page(cs, orig_vaddr, raddr, prot,
147 mmu_idx, TARGET_PAGE_SIZE);
149 return 0;
152 hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
154 S390CPU *cpu = S390_CPU(cs);
155 CPUS390XState *env = &cpu->env;
156 target_ulong raddr;
157 int prot;
158 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
160 /* 31-Bit mode */
161 if (!(env->psw.mask & PSW_MASK_64)) {
162 vaddr &= 0x7fffffff;
165 mmu_translate(env, vaddr, MMU_INST_FETCH, asc, &raddr, &prot, false);
167 return raddr;
170 hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
172 hwaddr phys_addr;
173 target_ulong page;
175 page = vaddr & TARGET_PAGE_MASK;
176 phys_addr = cpu_get_phys_page_debug(cs, page);
177 phys_addr += (vaddr & ~TARGET_PAGE_MASK);
179 return phys_addr;
182 void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
184 uint64_t old_mask = env->psw.mask;
186 env->psw.addr = addr;
187 env->psw.mask = mask;
188 if (tcg_enabled()) {
189 env->cc_op = (mask >> 44) & 3;
192 if ((old_mask ^ mask) & PSW_MASK_PER) {
193 s390_cpu_recompute_watchpoints(CPU(s390_env_get_cpu(env)));
196 if (mask & PSW_MASK_WAIT) {
197 S390CPU *cpu = s390_env_get_cpu(env);
198 if (s390_cpu_halt(cpu) == 0) {
199 #ifndef CONFIG_USER_ONLY
200 qemu_system_shutdown_request();
201 #endif
206 static uint64_t get_psw_mask(CPUS390XState *env)
208 uint64_t r = env->psw.mask;
210 if (tcg_enabled()) {
211 env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
212 env->cc_vr);
214 r &= ~PSW_MASK_CC;
215 assert(!(env->cc_op & ~3));
216 r |= (uint64_t)env->cc_op << 44;
219 return r;
222 static LowCore *cpu_map_lowcore(CPUS390XState *env)
224 S390CPU *cpu = s390_env_get_cpu(env);
225 LowCore *lowcore;
226 hwaddr len = sizeof(LowCore);
228 lowcore = cpu_physical_memory_map(env->psa, &len, 1);
230 if (len < sizeof(LowCore)) {
231 cpu_abort(CPU(cpu), "Could not map lowcore\n");
234 return lowcore;
237 static void cpu_unmap_lowcore(LowCore *lowcore)
239 cpu_physical_memory_unmap(lowcore, sizeof(LowCore), 1, sizeof(LowCore));
242 void do_restart_interrupt(CPUS390XState *env)
244 uint64_t mask, addr;
245 LowCore *lowcore;
247 lowcore = cpu_map_lowcore(env);
249 lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env));
250 lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr);
251 mask = be64_to_cpu(lowcore->restart_new_psw.mask);
252 addr = be64_to_cpu(lowcore->restart_new_psw.addr);
254 cpu_unmap_lowcore(lowcore);
256 load_psw(env, mask, addr);
259 static void do_program_interrupt(CPUS390XState *env)
261 uint64_t mask, addr;
262 LowCore *lowcore;
263 int ilen = env->int_pgm_ilen;
265 switch (ilen) {
266 case ILEN_LATER:
267 ilen = get_ilen(cpu_ldub_code(env, env->psw.addr));
268 break;
269 case ILEN_LATER_INC:
270 ilen = get_ilen(cpu_ldub_code(env, env->psw.addr));
271 env->psw.addr += ilen;
272 break;
273 default:
274 assert(ilen == 2 || ilen == 4 || ilen == 6);
277 qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n",
278 __func__, env->int_pgm_code, ilen);
280 lowcore = cpu_map_lowcore(env);
282 /* Signal PER events with the exception. */
283 if (env->per_perc_atmid) {
284 env->int_pgm_code |= PGM_PER;
285 lowcore->per_address = cpu_to_be64(env->per_address);
286 lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid);
287 env->per_perc_atmid = 0;
290 lowcore->pgm_ilen = cpu_to_be16(ilen);
291 lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
292 lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env));
293 lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
294 mask = be64_to_cpu(lowcore->program_new_psw.mask);
295 addr = be64_to_cpu(lowcore->program_new_psw.addr);
296 lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
298 cpu_unmap_lowcore(lowcore);
300 DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__,
301 env->int_pgm_code, ilen, env->psw.mask,
302 env->psw.addr);
304 load_psw(env, mask, addr);
307 static void do_svc_interrupt(CPUS390XState *env)
309 uint64_t mask, addr;
310 LowCore *lowcore;
312 lowcore = cpu_map_lowcore(env);
314 lowcore->svc_code = cpu_to_be16(env->int_svc_code);
315 lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
316 lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env));
317 lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
318 mask = be64_to_cpu(lowcore->svc_new_psw.mask);
319 addr = be64_to_cpu(lowcore->svc_new_psw.addr);
321 cpu_unmap_lowcore(lowcore);
323 load_psw(env, mask, addr);
325 /* When a PER event is pending, the PER exception has to happen
326 immediately after the SERVICE CALL one. */
327 if (env->per_perc_atmid) {
328 env->int_pgm_code = PGM_PER;
329 env->int_pgm_ilen = env->int_svc_ilen;
330 do_program_interrupt(env);
334 #define VIRTIO_SUBCODE_64 0x0D00
336 static void do_ext_interrupt(CPUS390XState *env)
338 S390CPU *cpu = s390_env_get_cpu(env);
339 uint64_t mask, addr;
340 LowCore *lowcore;
341 ExtQueue *q;
343 if (!(env->psw.mask & PSW_MASK_EXT)) {
344 cpu_abort(CPU(cpu), "Ext int w/o ext mask\n");
347 if (env->ext_index < 0 || env->ext_index >= MAX_EXT_QUEUE) {
348 cpu_abort(CPU(cpu), "Ext queue overrun: %d\n", env->ext_index);
351 q = &env->ext_queue[env->ext_index];
352 lowcore = cpu_map_lowcore(env);
354 lowcore->ext_int_code = cpu_to_be16(q->code);
355 lowcore->ext_params = cpu_to_be32(q->param);
356 lowcore->ext_params2 = cpu_to_be64(q->param64);
357 lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env));
358 lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
359 lowcore->cpu_addr = cpu_to_be16(env->cpu_num | VIRTIO_SUBCODE_64);
360 mask = be64_to_cpu(lowcore->external_new_psw.mask);
361 addr = be64_to_cpu(lowcore->external_new_psw.addr);
363 cpu_unmap_lowcore(lowcore);
365 env->ext_index--;
366 if (env->ext_index == -1) {
367 env->pending_int &= ~INTERRUPT_EXT;
370 DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__,
371 env->psw.mask, env->psw.addr);
373 load_psw(env, mask, addr);
376 static void do_io_interrupt(CPUS390XState *env)
378 S390CPU *cpu = s390_env_get_cpu(env);
379 LowCore *lowcore;
380 IOIntQueue *q;
381 uint8_t isc;
382 int disable = 1;
383 int found = 0;
385 if (!(env->psw.mask & PSW_MASK_IO)) {
386 cpu_abort(CPU(cpu), "I/O int w/o I/O mask\n");
389 for (isc = 0; isc < ARRAY_SIZE(env->io_index); isc++) {
390 uint64_t isc_bits;
392 if (env->io_index[isc] < 0) {
393 continue;
395 if (env->io_index[isc] >= MAX_IO_QUEUE) {
396 cpu_abort(CPU(cpu), "I/O queue overrun for isc %d: %d\n",
397 isc, env->io_index[isc]);
400 q = &env->io_queue[env->io_index[isc]][isc];
401 isc_bits = ISC_TO_ISC_BITS(IO_INT_WORD_ISC(q->word));
402 if (!(env->cregs[6] & isc_bits)) {
403 disable = 0;
404 continue;
406 if (!found) {
407 uint64_t mask, addr;
409 found = 1;
410 lowcore = cpu_map_lowcore(env);
412 lowcore->subchannel_id = cpu_to_be16(q->id);
413 lowcore->subchannel_nr = cpu_to_be16(q->nr);
414 lowcore->io_int_parm = cpu_to_be32(q->parm);
415 lowcore->io_int_word = cpu_to_be32(q->word);
416 lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env));
417 lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr);
418 mask = be64_to_cpu(lowcore->io_new_psw.mask);
419 addr = be64_to_cpu(lowcore->io_new_psw.addr);
421 cpu_unmap_lowcore(lowcore);
423 env->io_index[isc]--;
425 DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__,
426 env->psw.mask, env->psw.addr);
427 load_psw(env, mask, addr);
429 if (env->io_index[isc] >= 0) {
430 disable = 0;
432 continue;
435 if (disable) {
436 env->pending_int &= ~INTERRUPT_IO;
441 static void do_mchk_interrupt(CPUS390XState *env)
443 S390CPU *cpu = s390_env_get_cpu(env);
444 uint64_t mask, addr;
445 LowCore *lowcore;
446 MchkQueue *q;
447 int i;
449 if (!(env->psw.mask & PSW_MASK_MCHECK)) {
450 cpu_abort(CPU(cpu), "Machine check w/o mchk mask\n");
453 if (env->mchk_index < 0 || env->mchk_index >= MAX_MCHK_QUEUE) {
454 cpu_abort(CPU(cpu), "Mchk queue overrun: %d\n", env->mchk_index);
457 q = &env->mchk_queue[env->mchk_index];
459 if (q->type != 1) {
460 /* Don't know how to handle this... */
461 cpu_abort(CPU(cpu), "Unknown machine check type %d\n", q->type);
463 if (!(env->cregs[14] & (1 << 28))) {
464 /* CRW machine checks disabled */
465 return;
468 lowcore = cpu_map_lowcore(env);
470 for (i = 0; i < 16; i++) {
471 lowcore->floating_pt_save_area[i] = cpu_to_be64(get_freg(env, i)->ll);
472 lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]);
473 lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]);
474 lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]);
476 lowcore->prefixreg_save_area = cpu_to_be32(env->psa);
477 lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc);
478 lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr);
479 lowcore->cpu_timer_save_area[0] = cpu_to_be32(env->cputm >> 32);
480 lowcore->cpu_timer_save_area[1] = cpu_to_be32((uint32_t)env->cputm);
481 lowcore->clock_comp_save_area[0] = cpu_to_be32(env->ckc >> 32);
482 lowcore->clock_comp_save_area[1] = cpu_to_be32((uint32_t)env->ckc);
484 lowcore->mcck_interruption_code[0] = cpu_to_be32(0x00400f1d);
485 lowcore->mcck_interruption_code[1] = cpu_to_be32(0x40330000);
486 lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env));
487 lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
488 mask = be64_to_cpu(lowcore->mcck_new_psw.mask);
489 addr = be64_to_cpu(lowcore->mcck_new_psw.addr);
491 cpu_unmap_lowcore(lowcore);
493 env->mchk_index--;
494 if (env->mchk_index == -1) {
495 env->pending_int &= ~INTERRUPT_MCHK;
498 DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__,
499 env->psw.mask, env->psw.addr);
501 load_psw(env, mask, addr);
504 void s390_cpu_do_interrupt(CPUState *cs)
506 S390CPU *cpu = S390_CPU(cs);
507 CPUS390XState *env = &cpu->env;
509 qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n",
510 __func__, cs->exception_index, env->psw.addr);
512 s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
513 /* handle machine checks */
514 if ((env->psw.mask & PSW_MASK_MCHECK) &&
515 (cs->exception_index == -1)) {
516 if (env->pending_int & INTERRUPT_MCHK) {
517 cs->exception_index = EXCP_MCHK;
520 /* handle external interrupts */
521 if ((env->psw.mask & PSW_MASK_EXT) &&
522 cs->exception_index == -1) {
523 if (env->pending_int & INTERRUPT_EXT) {
524 /* code is already in env */
525 cs->exception_index = EXCP_EXT;
526 } else if (env->pending_int & INTERRUPT_TOD) {
527 cpu_inject_ext(cpu, 0x1004, 0, 0);
528 cs->exception_index = EXCP_EXT;
529 env->pending_int &= ~INTERRUPT_EXT;
530 env->pending_int &= ~INTERRUPT_TOD;
531 } else if (env->pending_int & INTERRUPT_CPUTIMER) {
532 cpu_inject_ext(cpu, 0x1005, 0, 0);
533 cs->exception_index = EXCP_EXT;
534 env->pending_int &= ~INTERRUPT_EXT;
535 env->pending_int &= ~INTERRUPT_TOD;
538 /* handle I/O interrupts */
539 if ((env->psw.mask & PSW_MASK_IO) &&
540 (cs->exception_index == -1)) {
541 if (env->pending_int & INTERRUPT_IO) {
542 cs->exception_index = EXCP_IO;
546 switch (cs->exception_index) {
547 case EXCP_PGM:
548 do_program_interrupt(env);
549 break;
550 case EXCP_SVC:
551 do_svc_interrupt(env);
552 break;
553 case EXCP_EXT:
554 do_ext_interrupt(env);
555 break;
556 case EXCP_IO:
557 do_io_interrupt(env);
558 break;
559 case EXCP_MCHK:
560 do_mchk_interrupt(env);
561 break;
563 cs->exception_index = -1;
565 if (!env->pending_int) {
566 cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
570 bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
572 if (interrupt_request & CPU_INTERRUPT_HARD) {
573 S390CPU *cpu = S390_CPU(cs);
574 CPUS390XState *env = &cpu->env;
576 if (env->psw.mask & PSW_MASK_EXT) {
577 s390_cpu_do_interrupt(cs);
578 return true;
581 return false;
584 void s390_cpu_recompute_watchpoints(CPUState *cs)
586 const int wp_flags = BP_CPU | BP_MEM_WRITE | BP_STOP_BEFORE_ACCESS;
587 S390CPU *cpu = S390_CPU(cs);
588 CPUS390XState *env = &cpu->env;
590 /* We are called when the watchpoints have changed. First
591 remove them all. */
592 cpu_watchpoint_remove_all(cs, BP_CPU);
594 /* Return if PER is not enabled */
595 if (!(env->psw.mask & PSW_MASK_PER)) {
596 return;
599 /* Return if storage-alteration event is not enabled. */
600 if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) {
601 return;
604 if (env->cregs[10] == 0 && env->cregs[11] == -1LL) {
605 /* We can't create a watchoint spanning the whole memory range, so
606 split it in two parts. */
607 cpu_watchpoint_insert(cs, 0, 1ULL << 63, wp_flags, NULL);
608 cpu_watchpoint_insert(cs, 1ULL << 63, 1ULL << 63, wp_flags, NULL);
609 } else if (env->cregs[10] > env->cregs[11]) {
610 /* The address range loops, create two watchpoints. */
611 cpu_watchpoint_insert(cs, env->cregs[10], -env->cregs[10],
612 wp_flags, NULL);
613 cpu_watchpoint_insert(cs, 0, env->cregs[11] + 1, wp_flags, NULL);
615 } else {
616 /* Default case, create a single watchpoint. */
617 cpu_watchpoint_insert(cs, env->cregs[10],
618 env->cregs[11] - env->cregs[10] + 1,
619 wp_flags, NULL);
623 void s390x_cpu_debug_excp_handler(CPUState *cs)
625 S390CPU *cpu = S390_CPU(cs);
626 CPUS390XState *env = &cpu->env;
627 CPUWatchpoint *wp_hit = cs->watchpoint_hit;
629 if (wp_hit && wp_hit->flags & BP_CPU) {
630 /* FIXME: When the storage-alteration-space control bit is set,
631 the exception should only be triggered if the memory access
632 is done using an address space with the storage-alteration-event
633 bit set. We have no way to detect that with the current
634 watchpoint code. */
635 cs->watchpoint_hit = NULL;
637 env->per_address = env->psw.addr;
638 env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
639 /* FIXME: We currently no way to detect the address space used
640 to trigger the watchpoint. For now just consider it is the
641 current default ASC. This turn to be true except when MVCP
642 and MVCS instrutions are not used. */
643 env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
645 /* Remove all watchpoints to re-execute the code. A PER exception
646 will be triggered, it will call load_psw which will recompute
647 the watchpoints. */
648 cpu_watchpoint_remove_all(cs, BP_CPU);
649 cpu_resume_from_signal(cs, NULL);
652 #endif /* CONFIG_USER_ONLY */