master
c 134 lines 3.58 KB
Raw
1 /*
2 * S/390 helpers - system only
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.1 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 "cpu.h"
23 #include "s390x-internal.h"
24 #include "qemu/timer.h"
25 #include "hw/s390x/ioinst.h"
26 #include "system/hw_accel.h"
27 #include "system/memory.h"
28 #include "system/runstate.h"
29 #include "exec/target_page.h"
30 #include "exec/watchpoint.h"
31
32 void s390x_tod_timer(void *opaque)
33 {
34 cpu_inject_clock_comparator((S390CPU *) opaque);
35 }
36
37 void s390x_cpu_timer(void *opaque)
38 {
39 cpu_inject_cpu_timer((S390CPU *) opaque);
40 }
41
42 hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr addr)
43 {
44 S390CPU *cpu = S390_CPU(cs);
45 CPUS390XState *env = &cpu->env;
46 hwaddr raddr;
47 int prot;
48 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
49 uint64_t tec;
50 vaddr page = addr & TARGET_PAGE_MASK;
51
52 /* 31-Bit mode */
53 if (!(env->psw.mask & PSW_MASK_64)) {
54 page &= 0x7fffffff;
55 }
56
57 /* We want to read the code (e.g., see what we are single-stepping).*/
58 if (asc != PSW_ASC_HOME) {
59 asc = PSW_ASC_PRIMARY;
60 }
61
62 /*
63 * We want to read code even if IEP is active. Use MMU_DATA_LOAD instead
64 * of MMU_INST_FETCH.
65 */
66 if (mmu_translate(env, page, MMU_DATA_LOAD, asc, &raddr, &prot, &tec)) {
67 return -1;
68 }
69 raddr += (addr & ~TARGET_PAGE_MASK);
70 return raddr;
71 }
72
73 static inline bool is_special_wait_psw(uint64_t psw_addr)
74 {
75 /* signal quiesce */
76 return (psw_addr & 0xfffUL) == 0xfffUL;
77 }
78
79 void s390_handle_wait(S390CPU *cpu)
80 {
81 CPUState *cs = CPU(cpu);
82
83 s390_cpu_halt(cpu);
84
85 if (s390_count_running_cpus() == 0) {
86 if (is_special_wait_psw(cpu->env.psw.addr)) {
87 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
88 } else {
89 cpu->env.crash_reason = S390_CRASH_REASON_DISABLED_WAIT;
90 qemu_system_guest_panicked(cpu_get_crash_info(cs));
91 }
92 }
93 }
94
95 LowCore *cpu_map_lowcore(CPUS390XState *env)
96 {
97 LowCore *lowcore;
98 hwaddr len = sizeof(LowCore);
99 CPUState *cs = env_cpu(env);
100 const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
101
102 lowcore = address_space_map(cs->as, env->psa, &len, true, attrs);
103
104 if (len < sizeof(LowCore)) {
105 cpu_abort(cs, "Could not map lowcore\n");
106 }
107
108 return lowcore;
109 }
110
111 void cpu_unmap_lowcore(CPUS390XState *env, LowCore *lowcore)
112 {
113 AddressSpace *as = env_cpu(env)->as;
114
115 address_space_unmap(as, lowcore, sizeof(LowCore), true, sizeof(LowCore));
116 }
117
118 void do_restart_interrupt(CPUS390XState *env)
119 {
120 uint64_t mask, addr;
121 LowCore *lowcore;
122
123 lowcore = cpu_map_lowcore(env);
124
125 lowcore->restart_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
126 lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr);
127 mask = be64_to_cpu(lowcore->restart_new_psw.mask);
128 addr = be64_to_cpu(lowcore->restart_new_psw.addr);
129
130 cpu_unmap_lowcore(env, lowcore);
131 env->pending_int &= ~INTERRUPT_RESTART;
132
133 s390_cpu_set_psw(env, mask, addr);
134 }