xref: /openbmc/qemu/target/s390x/tcg/excp_helper.c (revision 3b2fe44bb7f605f179e5e7feb2c13c2eb3abbb80)
1c9274b6bSCho, Yu-Chen /*
2c9274b6bSCho, Yu-Chen  * s390x exception / interrupt helpers
3c9274b6bSCho, Yu-Chen  *
4c9274b6bSCho, Yu-Chen  *  Copyright (c) 2009 Ulrich Hecht
5c9274b6bSCho, Yu-Chen  *  Copyright (c) 2011 Alexander Graf
6c9274b6bSCho, Yu-Chen  *
7c9274b6bSCho, Yu-Chen  * This library is free software; you can redistribute it and/or
8c9274b6bSCho, Yu-Chen  * modify it under the terms of the GNU Lesser General Public
9c9274b6bSCho, Yu-Chen  * License as published by the Free Software Foundation; either
10c9274b6bSCho, Yu-Chen  * version 2.1 of the License, or (at your option) any later version.
11c9274b6bSCho, Yu-Chen  *
12c9274b6bSCho, Yu-Chen  * This library is distributed in the hope that it will be useful,
13c9274b6bSCho, Yu-Chen  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14c9274b6bSCho, Yu-Chen  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15c9274b6bSCho, Yu-Chen  * Lesser General Public License for more details.
16c9274b6bSCho, Yu-Chen  *
17c9274b6bSCho, Yu-Chen  * You should have received a copy of the GNU Lesser General Public
18c9274b6bSCho, Yu-Chen  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19c9274b6bSCho, Yu-Chen  */
20c9274b6bSCho, Yu-Chen 
21c9274b6bSCho, Yu-Chen #include "qemu/osdep.h"
22cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
23c9274b6bSCho, Yu-Chen #include "cpu.h"
24c9274b6bSCho, Yu-Chen #include "exec/helper-proto.h"
25c9274b6bSCho, Yu-Chen #include "exec/exec-all.h"
26e4272df0SPhilippe Mathieu-Daudé #include "s390x-internal.h"
27c9274b6bSCho, Yu-Chen #include "tcg_s390x.h"
28c9274b6bSCho, Yu-Chen #ifndef CONFIG_USER_ONLY
29e4272df0SPhilippe Mathieu-Daudé #include "qemu/timer.h"
30e4272df0SPhilippe Mathieu-Daudé #include "exec/address-spaces.h"
31e4272df0SPhilippe Mathieu-Daudé #include "hw/s390x/ioinst.h"
32c9274b6bSCho, Yu-Chen #include "hw/s390x/s390_flic.h"
33c9274b6bSCho, Yu-Chen #include "hw/boards.h"
34c9274b6bSCho, Yu-Chen #endif
35c9274b6bSCho, Yu-Chen 
tcg_s390_program_interrupt(CPUS390XState * env,uint32_t code,uintptr_t ra)368905770bSMarc-André Lureau G_NORETURN void tcg_s390_program_interrupt(CPUS390XState *env,
37c9274b6bSCho, Yu-Chen                                            uint32_t code, uintptr_t ra)
38c9274b6bSCho, Yu-Chen {
39c9274b6bSCho, Yu-Chen     CPUState *cs = env_cpu(env);
40c9274b6bSCho, Yu-Chen 
413d419a4dSRichard Henderson     cpu_restore_state(cs, ra);
42c9274b6bSCho, Yu-Chen     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
43c9274b6bSCho, Yu-Chen                   env->psw.addr);
44c9274b6bSCho, Yu-Chen     trigger_pgm_exception(env, code);
45c9274b6bSCho, Yu-Chen     cpu_loop_exit(cs);
46c9274b6bSCho, Yu-Chen }
47c9274b6bSCho, Yu-Chen 
tcg_s390_data_exception(CPUS390XState * env,uint32_t dxc,uintptr_t ra)488905770bSMarc-André Lureau G_NORETURN void tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
49c9274b6bSCho, Yu-Chen                                         uintptr_t ra)
50c9274b6bSCho, Yu-Chen {
51c9274b6bSCho, Yu-Chen     g_assert(dxc <= 0xff);
52c9274b6bSCho, Yu-Chen #if !defined(CONFIG_USER_ONLY)
53c9274b6bSCho, Yu-Chen     /* Store the DXC into the lowcore */
54c9274b6bSCho, Yu-Chen     stl_phys(env_cpu(env)->as,
55c9274b6bSCho, Yu-Chen              env->psa + offsetof(LowCore, data_exc_code), dxc);
56c9274b6bSCho, Yu-Chen #endif
57c9274b6bSCho, Yu-Chen 
58c9274b6bSCho, Yu-Chen     /* Store the DXC into the FPC if AFP is enabled */
59c9274b6bSCho, Yu-Chen     if (env->cregs[0] & CR0_AFP) {
60c9274b6bSCho, Yu-Chen         env->fpc = deposit32(env->fpc, 8, 8, dxc);
61c9274b6bSCho, Yu-Chen     }
62c9274b6bSCho, Yu-Chen     tcg_s390_program_interrupt(env, PGM_DATA, ra);
63c9274b6bSCho, Yu-Chen }
64c9274b6bSCho, Yu-Chen 
tcg_s390_vector_exception(CPUS390XState * env,uint32_t vxc,uintptr_t ra)658905770bSMarc-André Lureau G_NORETURN void tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
66c9274b6bSCho, Yu-Chen                                           uintptr_t ra)
67c9274b6bSCho, Yu-Chen {
68c9274b6bSCho, Yu-Chen     g_assert(vxc <= 0xff);
69c9274b6bSCho, Yu-Chen #if !defined(CONFIG_USER_ONLY)
70c9274b6bSCho, Yu-Chen     /* Always store the VXC into the lowcore, without AFP it is undefined */
71c9274b6bSCho, Yu-Chen     stl_phys(env_cpu(env)->as,
72c9274b6bSCho, Yu-Chen              env->psa + offsetof(LowCore, data_exc_code), vxc);
73c9274b6bSCho, Yu-Chen #endif
74c9274b6bSCho, Yu-Chen 
75c9274b6bSCho, Yu-Chen     /* Always store the VXC into the FPC, without AFP it is undefined */
76c9274b6bSCho, Yu-Chen     env->fpc = deposit32(env->fpc, 8, 8, vxc);
77c9274b6bSCho, Yu-Chen     tcg_s390_program_interrupt(env, PGM_VECTOR_PROCESSING, ra);
78c9274b6bSCho, Yu-Chen }
79c9274b6bSCho, Yu-Chen 
HELPER(data_exception)80c9274b6bSCho, Yu-Chen void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
81c9274b6bSCho, Yu-Chen {
82c9274b6bSCho, Yu-Chen     tcg_s390_data_exception(env, dxc, GETPC());
83c9274b6bSCho, Yu-Chen }
84c9274b6bSCho, Yu-Chen 
855bcbf356SRichard Henderson /*
865bcbf356SRichard Henderson  * Unaligned accesses are only diagnosed with MO_ALIGN.  At the moment,
87ba1ef833SIlya Leoshkevich  * this is only for the atomic and relative long operations, for which we want
88ba1ef833SIlya Leoshkevich  * to raise a specification exception.
895bcbf356SRichard Henderson  */
908905770bSMarc-André Lureau static G_NORETURN
do_unaligned_access(CPUState * cs,uintptr_t retaddr)918905770bSMarc-André Lureau void do_unaligned_access(CPUState *cs, uintptr_t retaddr)
925bcbf356SRichard Henderson {
93d0143fa9SPhilippe Mathieu-Daudé     tcg_s390_program_interrupt(cpu_env(cs), PGM_SPECIFICATION, retaddr);
945bcbf356SRichard Henderson }
955bcbf356SRichard Henderson 
96c9274b6bSCho, Yu-Chen #if defined(CONFIG_USER_ONLY)
97c9274b6bSCho, Yu-Chen 
s390_cpu_do_interrupt(CPUState * cs)98c9274b6bSCho, Yu-Chen void s390_cpu_do_interrupt(CPUState *cs)
99c9274b6bSCho, Yu-Chen {
100c9274b6bSCho, Yu-Chen     cs->exception_index = -1;
101c9274b6bSCho, Yu-Chen }
102c9274b6bSCho, Yu-Chen 
s390_cpu_record_sigsegv(CPUState * cs,vaddr address,MMUAccessType access_type,bool maperr,uintptr_t retaddr)103c8e7fef1SRichard Henderson void s390_cpu_record_sigsegv(CPUState *cs, vaddr address,
104c8e7fef1SRichard Henderson                              MMUAccessType access_type,
105c8e7fef1SRichard Henderson                              bool maperr, uintptr_t retaddr)
106c9274b6bSCho, Yu-Chen {
107c9274b6bSCho, Yu-Chen     S390CPU *cpu = S390_CPU(cs);
108c9274b6bSCho, Yu-Chen 
109c8e7fef1SRichard Henderson     trigger_pgm_exception(&cpu->env, maperr ? PGM_ADDRESSING : PGM_PROTECTION);
110c8e7fef1SRichard Henderson     /*
111c8e7fef1SRichard Henderson      * On real machines this value is dropped into LowMem. Since this
112c8e7fef1SRichard Henderson      * is userland, simply put this someplace that cpu_loop can find it.
113c8e7fef1SRichard Henderson      * S390 only gives the page of the fault, not the exact address.
114c8e7fef1SRichard Henderson      * C.f. the construction of TEC in mmu_translate().
115c8e7fef1SRichard Henderson      */
116c8e7fef1SRichard Henderson     cpu->env.__excp_addr = address & TARGET_PAGE_MASK;
117c9274b6bSCho, Yu-Chen     cpu_loop_exit_restore(cs, retaddr);
118c9274b6bSCho, Yu-Chen }
119c9274b6bSCho, Yu-Chen 
s390_cpu_record_sigbus(CPUState * cs,vaddr address,MMUAccessType access_type,uintptr_t retaddr)1205bcbf356SRichard Henderson void s390_cpu_record_sigbus(CPUState *cs, vaddr address,
1215bcbf356SRichard Henderson                             MMUAccessType access_type, uintptr_t retaddr)
1225bcbf356SRichard Henderson {
1235bcbf356SRichard Henderson     do_unaligned_access(cs, retaddr);
1245bcbf356SRichard Henderson }
1255bcbf356SRichard Henderson 
126c9274b6bSCho, Yu-Chen #else /* !CONFIG_USER_ONLY */
127c9274b6bSCho, Yu-Chen 
cpu_mmu_idx_to_asc(int mmu_idx)128c9274b6bSCho, Yu-Chen static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx)
129c9274b6bSCho, Yu-Chen {
130c9274b6bSCho, Yu-Chen     switch (mmu_idx) {
131c9274b6bSCho, Yu-Chen     case MMU_PRIMARY_IDX:
132c9274b6bSCho, Yu-Chen         return PSW_ASC_PRIMARY;
133c9274b6bSCho, Yu-Chen     case MMU_SECONDARY_IDX:
134c9274b6bSCho, Yu-Chen         return PSW_ASC_SECONDARY;
135c9274b6bSCho, Yu-Chen     case MMU_HOME_IDX:
136c9274b6bSCho, Yu-Chen         return PSW_ASC_HOME;
137c9274b6bSCho, Yu-Chen     default:
138c9274b6bSCho, Yu-Chen         abort();
139c9274b6bSCho, Yu-Chen     }
140c9274b6bSCho, Yu-Chen }
141c9274b6bSCho, Yu-Chen 
s390_cpu_tlb_fill(CPUState * cs,vaddr address,int size,MMUAccessType access_type,int mmu_idx,bool probe,uintptr_t retaddr)142c9274b6bSCho, Yu-Chen bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
143c9274b6bSCho, Yu-Chen                        MMUAccessType access_type, int mmu_idx,
144c9274b6bSCho, Yu-Chen                        bool probe, uintptr_t retaddr)
145c9274b6bSCho, Yu-Chen {
146d0143fa9SPhilippe Mathieu-Daudé     CPUS390XState *env = cpu_env(cs);
147c9274b6bSCho, Yu-Chen     target_ulong vaddr, raddr;
148c9274b6bSCho, Yu-Chen     uint64_t asc, tec;
149c9274b6bSCho, Yu-Chen     int prot, excp;
150c9274b6bSCho, Yu-Chen 
151c9274b6bSCho, Yu-Chen     qemu_log_mask(CPU_LOG_MMU, "%s: addr 0x%" VADDR_PRIx " rw %d mmu_idx %d\n",
152c9274b6bSCho, Yu-Chen                   __func__, address, access_type, mmu_idx);
153c9274b6bSCho, Yu-Chen 
154c9274b6bSCho, Yu-Chen     vaddr = address;
155c9274b6bSCho, Yu-Chen 
156c9274b6bSCho, Yu-Chen     if (mmu_idx < MMU_REAL_IDX) {
157c9274b6bSCho, Yu-Chen         asc = cpu_mmu_idx_to_asc(mmu_idx);
158c9274b6bSCho, Yu-Chen         /* 31-Bit mode */
159c9274b6bSCho, Yu-Chen         if (!(env->psw.mask & PSW_MASK_64)) {
160c9274b6bSCho, Yu-Chen             vaddr &= 0x7fffffff;
161c9274b6bSCho, Yu-Chen         }
162c9274b6bSCho, Yu-Chen         excp = mmu_translate(env, vaddr, access_type, asc, &raddr, &prot, &tec);
163c9274b6bSCho, Yu-Chen     } else if (mmu_idx == MMU_REAL_IDX) {
164c9274b6bSCho, Yu-Chen         /* 31-Bit mode */
165c9274b6bSCho, Yu-Chen         if (!(env->psw.mask & PSW_MASK_64)) {
166c9274b6bSCho, Yu-Chen             vaddr &= 0x7fffffff;
167c9274b6bSCho, Yu-Chen         }
168c9274b6bSCho, Yu-Chen         excp = mmu_translate_real(env, vaddr, access_type, &raddr, &prot, &tec);
169c9274b6bSCho, Yu-Chen     } else {
170c9274b6bSCho, Yu-Chen         g_assert_not_reached();
171c9274b6bSCho, Yu-Chen     }
172c9274b6bSCho, Yu-Chen 
173c9274b6bSCho, Yu-Chen     env->tlb_fill_exc = excp;
174c9274b6bSCho, Yu-Chen     env->tlb_fill_tec = tec;
175c9274b6bSCho, Yu-Chen 
176c9274b6bSCho, Yu-Chen     if (!excp) {
177c9274b6bSCho, Yu-Chen         qemu_log_mask(CPU_LOG_MMU,
178c9274b6bSCho, Yu-Chen                       "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n",
179c9274b6bSCho, Yu-Chen                       __func__, (uint64_t)vaddr, (uint64_t)raddr, prot);
180c9274b6bSCho, Yu-Chen         tlb_set_page(cs, address & TARGET_PAGE_MASK, raddr, prot,
181c9274b6bSCho, Yu-Chen                      mmu_idx, TARGET_PAGE_SIZE);
182c9274b6bSCho, Yu-Chen         return true;
183c9274b6bSCho, Yu-Chen     }
184c9274b6bSCho, Yu-Chen     if (probe) {
185c9274b6bSCho, Yu-Chen         return false;
186c9274b6bSCho, Yu-Chen     }
187c9274b6bSCho, Yu-Chen 
188c9274b6bSCho, Yu-Chen     /*
189c9274b6bSCho, Yu-Chen      * For data accesses, ILEN will be filled in from the unwind info,
190c9274b6bSCho, Yu-Chen      * within cpu_loop_exit_restore.  For code accesses, retaddr == 0,
191c9274b6bSCho, Yu-Chen      * and so unwinding will not occur.  However, ILEN is also undefined
192c9274b6bSCho, Yu-Chen      * for that case -- we choose to set ILEN = 2.
193c9274b6bSCho, Yu-Chen      */
194c9274b6bSCho, Yu-Chen     env->int_pgm_ilen = 2;
195c9274b6bSCho, Yu-Chen     trigger_pgm_exception(env, excp);
196c9274b6bSCho, Yu-Chen     cpu_loop_exit_restore(cs, retaddr);
197c9274b6bSCho, Yu-Chen }
198c9274b6bSCho, Yu-Chen 
do_program_interrupt(CPUS390XState * env)199c9274b6bSCho, Yu-Chen static void do_program_interrupt(CPUS390XState *env)
200c9274b6bSCho, Yu-Chen {
201c9274b6bSCho, Yu-Chen     uint64_t mask, addr;
202c9274b6bSCho, Yu-Chen     LowCore *lowcore;
203c9274b6bSCho, Yu-Chen     int ilen = env->int_pgm_ilen;
2048b94ec53SRichard Henderson     bool set_trans_exc_code = false;
2058b94ec53SRichard Henderson     bool advance = false;
206c9274b6bSCho, Yu-Chen 
207199c42a6SIlya Leoshkevich     assert((env->int_pgm_code == PGM_SPECIFICATION && ilen == 0) ||
208199c42a6SIlya Leoshkevich            ilen == 2 || ilen == 4 || ilen == 6);
209c9274b6bSCho, Yu-Chen 
210c9274b6bSCho, Yu-Chen     switch (env->int_pgm_code) {
211c9274b6bSCho, Yu-Chen     case PGM_PER:
212*a6a33760SRichard Henderson         /* advance already handled */
213c9274b6bSCho, Yu-Chen         break;
2148b94ec53SRichard Henderson     case PGM_ASCE_TYPE:
2158b94ec53SRichard Henderson     case PGM_REG_FIRST_TRANS:
2168b94ec53SRichard Henderson     case PGM_REG_SEC_TRANS:
2178b94ec53SRichard Henderson     case PGM_REG_THIRD_TRANS:
2188b94ec53SRichard Henderson     case PGM_SEGMENT_TRANS:
2198b94ec53SRichard Henderson     case PGM_PAGE_TRANS:
2208b94ec53SRichard Henderson         assert(env->int_pgm_code == env->tlb_fill_exc);
2218b94ec53SRichard Henderson         set_trans_exc_code = true;
2228b94ec53SRichard Henderson         break;
2238b94ec53SRichard Henderson     case PGM_PROTECTION:
2248b94ec53SRichard Henderson         assert(env->int_pgm_code == env->tlb_fill_exc);
2258b94ec53SRichard Henderson         set_trans_exc_code = true;
2268b94ec53SRichard Henderson         advance = true;
2278b94ec53SRichard Henderson         break;
228c9274b6bSCho, Yu-Chen     case PGM_OPERATION:
229c9274b6bSCho, Yu-Chen     case PGM_PRIVILEGED:
230c9274b6bSCho, Yu-Chen     case PGM_EXECUTE:
231c9274b6bSCho, Yu-Chen     case PGM_ADDRESSING:
232c9274b6bSCho, Yu-Chen     case PGM_SPECIFICATION:
233c9274b6bSCho, Yu-Chen     case PGM_DATA:
234c9274b6bSCho, Yu-Chen     case PGM_FIXPT_OVERFLOW:
235c9274b6bSCho, Yu-Chen     case PGM_FIXPT_DIVIDE:
236c9274b6bSCho, Yu-Chen     case PGM_DEC_OVERFLOW:
237c9274b6bSCho, Yu-Chen     case PGM_DEC_DIVIDE:
238c9274b6bSCho, Yu-Chen     case PGM_HFP_EXP_OVERFLOW:
239c9274b6bSCho, Yu-Chen     case PGM_HFP_EXP_UNDERFLOW:
240c9274b6bSCho, Yu-Chen     case PGM_HFP_SIGNIFICANCE:
241c9274b6bSCho, Yu-Chen     case PGM_HFP_DIVIDE:
242c9274b6bSCho, Yu-Chen     case PGM_TRANS_SPEC:
243c9274b6bSCho, Yu-Chen     case PGM_SPECIAL_OP:
244c9274b6bSCho, Yu-Chen     case PGM_OPERAND:
245c9274b6bSCho, Yu-Chen     case PGM_HFP_SQRT:
246c9274b6bSCho, Yu-Chen     case PGM_PC_TRANS_SPEC:
247c9274b6bSCho, Yu-Chen     case PGM_ALET_SPEC:
248c9274b6bSCho, Yu-Chen     case PGM_MONITOR:
2498b94ec53SRichard Henderson         advance = true;
250c9274b6bSCho, Yu-Chen         break;
251c9274b6bSCho, Yu-Chen     }
252c9274b6bSCho, Yu-Chen 
2538b94ec53SRichard Henderson     /* advance the PSW if our exception is not nullifying */
2548b94ec53SRichard Henderson     if (advance) {
2558b94ec53SRichard Henderson         env->psw.addr += ilen;
2568b94ec53SRichard Henderson     }
2578b94ec53SRichard Henderson 
258c9274b6bSCho, Yu-Chen     qemu_log_mask(CPU_LOG_INT,
259c9274b6bSCho, Yu-Chen                   "%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
260c9274b6bSCho, Yu-Chen                   __func__, env->int_pgm_code, ilen, env->psw.mask,
261c9274b6bSCho, Yu-Chen                   env->psw.addr);
262c9274b6bSCho, Yu-Chen 
263c9274b6bSCho, Yu-Chen     lowcore = cpu_map_lowcore(env);
264c9274b6bSCho, Yu-Chen 
265c9274b6bSCho, Yu-Chen     /* Signal PER events with the exception.  */
266c9274b6bSCho, Yu-Chen     if (env->per_perc_atmid) {
267c9274b6bSCho, Yu-Chen         env->int_pgm_code |= PGM_PER;
268c9274b6bSCho, Yu-Chen         lowcore->per_address = cpu_to_be64(env->per_address);
269c9274b6bSCho, Yu-Chen         lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid);
270c9274b6bSCho, Yu-Chen         env->per_perc_atmid = 0;
271c9274b6bSCho, Yu-Chen     }
272c9274b6bSCho, Yu-Chen 
2738b94ec53SRichard Henderson     if (set_trans_exc_code) {
2748b94ec53SRichard Henderson         lowcore->trans_exc_code = cpu_to_be64(env->tlb_fill_tec);
2758b94ec53SRichard Henderson     }
2768b94ec53SRichard Henderson 
277c9274b6bSCho, Yu-Chen     lowcore->pgm_ilen = cpu_to_be16(ilen);
278c9274b6bSCho, Yu-Chen     lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
279c9274b6bSCho, Yu-Chen     lowcore->program_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
280c9274b6bSCho, Yu-Chen     lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
281c9274b6bSCho, Yu-Chen     mask = be64_to_cpu(lowcore->program_new_psw.mask);
282c9274b6bSCho, Yu-Chen     addr = be64_to_cpu(lowcore->program_new_psw.addr);
283c9274b6bSCho, Yu-Chen     lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
284c9274b6bSCho, Yu-Chen 
285c9274b6bSCho, Yu-Chen     cpu_unmap_lowcore(lowcore);
286c9274b6bSCho, Yu-Chen 
287c9274b6bSCho, Yu-Chen     s390_cpu_set_psw(env, mask, addr);
288c9274b6bSCho, Yu-Chen }
289c9274b6bSCho, Yu-Chen 
do_svc_interrupt(CPUS390XState * env)290c9274b6bSCho, Yu-Chen static void do_svc_interrupt(CPUS390XState *env)
291c9274b6bSCho, Yu-Chen {
292c9274b6bSCho, Yu-Chen     uint64_t mask, addr;
293c9274b6bSCho, Yu-Chen     LowCore *lowcore;
294c9274b6bSCho, Yu-Chen 
295c9274b6bSCho, Yu-Chen     lowcore = cpu_map_lowcore(env);
296c9274b6bSCho, Yu-Chen 
297c9274b6bSCho, Yu-Chen     lowcore->svc_code = cpu_to_be16(env->int_svc_code);
298c9274b6bSCho, Yu-Chen     lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
299c9274b6bSCho, Yu-Chen     lowcore->svc_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
300c9274b6bSCho, Yu-Chen     lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
301c9274b6bSCho, Yu-Chen     mask = be64_to_cpu(lowcore->svc_new_psw.mask);
302c9274b6bSCho, Yu-Chen     addr = be64_to_cpu(lowcore->svc_new_psw.addr);
303c9274b6bSCho, Yu-Chen 
304c9274b6bSCho, Yu-Chen     cpu_unmap_lowcore(lowcore);
305c9274b6bSCho, Yu-Chen 
306c9274b6bSCho, Yu-Chen     s390_cpu_set_psw(env, mask, addr);
307c9274b6bSCho, Yu-Chen 
308c9274b6bSCho, Yu-Chen     /* When a PER event is pending, the PER exception has to happen
309c9274b6bSCho, Yu-Chen        immediately after the SERVICE CALL one.  */
310c9274b6bSCho, Yu-Chen     if (env->per_perc_atmid) {
311c9274b6bSCho, Yu-Chen         env->int_pgm_code = PGM_PER;
312c9274b6bSCho, Yu-Chen         env->int_pgm_ilen = env->int_svc_ilen;
313c9274b6bSCho, Yu-Chen         do_program_interrupt(env);
314c9274b6bSCho, Yu-Chen     }
315c9274b6bSCho, Yu-Chen }
316c9274b6bSCho, Yu-Chen 
317c9274b6bSCho, Yu-Chen #define VIRTIO_SUBCODE_64 0x0D00
318c9274b6bSCho, Yu-Chen 
do_ext_interrupt(CPUS390XState * env)319c9274b6bSCho, Yu-Chen static void do_ext_interrupt(CPUS390XState *env)
320c9274b6bSCho, Yu-Chen {
321c9274b6bSCho, Yu-Chen     QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
322c9274b6bSCho, Yu-Chen     S390CPU *cpu = env_archcpu(env);
323c9274b6bSCho, Yu-Chen     uint64_t mask, addr;
324c9274b6bSCho, Yu-Chen     uint16_t cpu_addr;
325c9274b6bSCho, Yu-Chen     LowCore *lowcore;
326c9274b6bSCho, Yu-Chen 
327c9274b6bSCho, Yu-Chen     if (!(env->psw.mask & PSW_MASK_EXT)) {
328c9274b6bSCho, Yu-Chen         cpu_abort(CPU(cpu), "Ext int w/o ext mask\n");
329c9274b6bSCho, Yu-Chen     }
330c9274b6bSCho, Yu-Chen 
331c9274b6bSCho, Yu-Chen     lowcore = cpu_map_lowcore(env);
332c9274b6bSCho, Yu-Chen 
333c9274b6bSCho, Yu-Chen     if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
334c9274b6bSCho, Yu-Chen         (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
335c9274b6bSCho, Yu-Chen         MachineState *ms = MACHINE(qdev_get_machine());
336c9274b6bSCho, Yu-Chen         unsigned int max_cpus = ms->smp.max_cpus;
337c9274b6bSCho, Yu-Chen 
338c9274b6bSCho, Yu-Chen         lowcore->ext_int_code = cpu_to_be16(EXT_EMERGENCY);
339c9274b6bSCho, Yu-Chen         cpu_addr = find_first_bit(env->emergency_signals, S390_MAX_CPUS);
340c9274b6bSCho, Yu-Chen         g_assert(cpu_addr < S390_MAX_CPUS);
341c9274b6bSCho, Yu-Chen         lowcore->cpu_addr = cpu_to_be16(cpu_addr);
342c9274b6bSCho, Yu-Chen         clear_bit(cpu_addr, env->emergency_signals);
343c9274b6bSCho, Yu-Chen         if (bitmap_empty(env->emergency_signals, max_cpus)) {
344c9274b6bSCho, Yu-Chen             env->pending_int &= ~INTERRUPT_EMERGENCY_SIGNAL;
345c9274b6bSCho, Yu-Chen         }
346c9274b6bSCho, Yu-Chen     } else if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
347c9274b6bSCho, Yu-Chen                (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
348c9274b6bSCho, Yu-Chen         lowcore->ext_int_code = cpu_to_be16(EXT_EXTERNAL_CALL);
349c9274b6bSCho, Yu-Chen         lowcore->cpu_addr = cpu_to_be16(env->external_call_addr);
350c9274b6bSCho, Yu-Chen         env->pending_int &= ~INTERRUPT_EXTERNAL_CALL;
351c9274b6bSCho, Yu-Chen     } else if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
352c9274b6bSCho, Yu-Chen                (env->cregs[0] & CR0_CKC_SC)) {
353c9274b6bSCho, Yu-Chen         lowcore->ext_int_code = cpu_to_be16(EXT_CLOCK_COMP);
354c9274b6bSCho, Yu-Chen         lowcore->cpu_addr = 0;
355c9274b6bSCho, Yu-Chen         env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;
356c9274b6bSCho, Yu-Chen     } else if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
357c9274b6bSCho, Yu-Chen                (env->cregs[0] & CR0_CPU_TIMER_SC)) {
358c9274b6bSCho, Yu-Chen         lowcore->ext_int_code = cpu_to_be16(EXT_CPU_TIMER);
359c9274b6bSCho, Yu-Chen         lowcore->cpu_addr = 0;
360c9274b6bSCho, Yu-Chen         env->pending_int &= ~INTERRUPT_EXT_CPU_TIMER;
361c9274b6bSCho, Yu-Chen     } else if (qemu_s390_flic_has_service(flic) &&
362c9274b6bSCho, Yu-Chen                (env->cregs[0] & CR0_SERVICE_SC)) {
363c9274b6bSCho, Yu-Chen         uint32_t param;
364c9274b6bSCho, Yu-Chen 
365c9274b6bSCho, Yu-Chen         param = qemu_s390_flic_dequeue_service(flic);
366c9274b6bSCho, Yu-Chen         lowcore->ext_int_code = cpu_to_be16(EXT_SERVICE);
367c9274b6bSCho, Yu-Chen         lowcore->ext_params = cpu_to_be32(param);
368c9274b6bSCho, Yu-Chen         lowcore->cpu_addr = 0;
369c9274b6bSCho, Yu-Chen     } else {
370c9274b6bSCho, Yu-Chen         g_assert_not_reached();
371c9274b6bSCho, Yu-Chen     }
372c9274b6bSCho, Yu-Chen 
373c9274b6bSCho, Yu-Chen     mask = be64_to_cpu(lowcore->external_new_psw.mask);
374c9274b6bSCho, Yu-Chen     addr = be64_to_cpu(lowcore->external_new_psw.addr);
375c9274b6bSCho, Yu-Chen     lowcore->external_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
376c9274b6bSCho, Yu-Chen     lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
377c9274b6bSCho, Yu-Chen 
378c9274b6bSCho, Yu-Chen     cpu_unmap_lowcore(lowcore);
379c9274b6bSCho, Yu-Chen 
380c9274b6bSCho, Yu-Chen     s390_cpu_set_psw(env, mask, addr);
381c9274b6bSCho, Yu-Chen }
382c9274b6bSCho, Yu-Chen 
do_io_interrupt(CPUS390XState * env)383c9274b6bSCho, Yu-Chen static void do_io_interrupt(CPUS390XState *env)
384c9274b6bSCho, Yu-Chen {
385c9274b6bSCho, Yu-Chen     QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
386c9274b6bSCho, Yu-Chen     uint64_t mask, addr;
387c9274b6bSCho, Yu-Chen     QEMUS390FlicIO *io;
388c9274b6bSCho, Yu-Chen     LowCore *lowcore;
389c9274b6bSCho, Yu-Chen 
390c9274b6bSCho, Yu-Chen     g_assert(env->psw.mask & PSW_MASK_IO);
391c9274b6bSCho, Yu-Chen     io = qemu_s390_flic_dequeue_io(flic, env->cregs[6]);
392c9274b6bSCho, Yu-Chen     g_assert(io);
393c9274b6bSCho, Yu-Chen 
394c9274b6bSCho, Yu-Chen     lowcore = cpu_map_lowcore(env);
395c9274b6bSCho, Yu-Chen 
396c9274b6bSCho, Yu-Chen     lowcore->subchannel_id = cpu_to_be16(io->id);
397c9274b6bSCho, Yu-Chen     lowcore->subchannel_nr = cpu_to_be16(io->nr);
398c9274b6bSCho, Yu-Chen     lowcore->io_int_parm = cpu_to_be32(io->parm);
399c9274b6bSCho, Yu-Chen     lowcore->io_int_word = cpu_to_be32(io->word);
400c9274b6bSCho, Yu-Chen     lowcore->io_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
401c9274b6bSCho, Yu-Chen     lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr);
402c9274b6bSCho, Yu-Chen     mask = be64_to_cpu(lowcore->io_new_psw.mask);
403c9274b6bSCho, Yu-Chen     addr = be64_to_cpu(lowcore->io_new_psw.addr);
404c9274b6bSCho, Yu-Chen 
405c9274b6bSCho, Yu-Chen     cpu_unmap_lowcore(lowcore);
406c9274b6bSCho, Yu-Chen     g_free(io);
407c9274b6bSCho, Yu-Chen 
408c9274b6bSCho, Yu-Chen     s390_cpu_set_psw(env, mask, addr);
409c9274b6bSCho, Yu-Chen }
410c9274b6bSCho, Yu-Chen 
411c9274b6bSCho, Yu-Chen typedef struct MchkExtSaveArea {
412c9274b6bSCho, Yu-Chen     uint64_t    vregs[32][2];                     /* 0x0000 */
413c9274b6bSCho, Yu-Chen     uint8_t     pad_0x0200[0x0400 - 0x0200];      /* 0x0200 */
414c9274b6bSCho, Yu-Chen } MchkExtSaveArea;
415c9274b6bSCho, Yu-Chen QEMU_BUILD_BUG_ON(sizeof(MchkExtSaveArea) != 1024);
416c9274b6bSCho, Yu-Chen 
mchk_store_vregs(CPUS390XState * env,uint64_t mcesao)417c9274b6bSCho, Yu-Chen static int mchk_store_vregs(CPUS390XState *env, uint64_t mcesao)
418c9274b6bSCho, Yu-Chen {
419c9274b6bSCho, Yu-Chen     hwaddr len = sizeof(MchkExtSaveArea);
420c9274b6bSCho, Yu-Chen     MchkExtSaveArea *sa;
421c9274b6bSCho, Yu-Chen     int i;
422c9274b6bSCho, Yu-Chen 
423c9274b6bSCho, Yu-Chen     sa = cpu_physical_memory_map(mcesao, &len, true);
424c9274b6bSCho, Yu-Chen     if (!sa) {
425c9274b6bSCho, Yu-Chen         return -EFAULT;
426c9274b6bSCho, Yu-Chen     }
427c9274b6bSCho, Yu-Chen     if (len != sizeof(MchkExtSaveArea)) {
428c9274b6bSCho, Yu-Chen         cpu_physical_memory_unmap(sa, len, 1, 0);
429c9274b6bSCho, Yu-Chen         return -EFAULT;
430c9274b6bSCho, Yu-Chen     }
431c9274b6bSCho, Yu-Chen 
432c9274b6bSCho, Yu-Chen     for (i = 0; i < 32; i++) {
433c9274b6bSCho, Yu-Chen         sa->vregs[i][0] = cpu_to_be64(env->vregs[i][0]);
434c9274b6bSCho, Yu-Chen         sa->vregs[i][1] = cpu_to_be64(env->vregs[i][1]);
435c9274b6bSCho, Yu-Chen     }
436c9274b6bSCho, Yu-Chen 
437c9274b6bSCho, Yu-Chen     cpu_physical_memory_unmap(sa, len, 1, len);
438c9274b6bSCho, Yu-Chen     return 0;
439c9274b6bSCho, Yu-Chen }
440c9274b6bSCho, Yu-Chen 
do_mchk_interrupt(CPUS390XState * env)441c9274b6bSCho, Yu-Chen static void do_mchk_interrupt(CPUS390XState *env)
442c9274b6bSCho, Yu-Chen {
443c9274b6bSCho, Yu-Chen     QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
444c9274b6bSCho, Yu-Chen     uint64_t mcic = s390_build_validity_mcic() | MCIC_SC_CP;
445c9274b6bSCho, Yu-Chen     uint64_t mask, addr, mcesao = 0;
446c9274b6bSCho, Yu-Chen     LowCore *lowcore;
447c9274b6bSCho, Yu-Chen     int i;
448c9274b6bSCho, Yu-Chen 
449c9274b6bSCho, Yu-Chen     /* for now we only support channel report machine checks (floating) */
450c9274b6bSCho, Yu-Chen     g_assert(env->psw.mask & PSW_MASK_MCHECK);
451c9274b6bSCho, Yu-Chen     g_assert(env->cregs[14] & CR14_CHANNEL_REPORT_SC);
452c9274b6bSCho, Yu-Chen 
453c9274b6bSCho, Yu-Chen     qemu_s390_flic_dequeue_crw_mchk(flic);
454c9274b6bSCho, Yu-Chen 
455c9274b6bSCho, Yu-Chen     lowcore = cpu_map_lowcore(env);
456c9274b6bSCho, Yu-Chen 
457c9274b6bSCho, Yu-Chen     /* extended save area */
458c9274b6bSCho, Yu-Chen     if (mcic & MCIC_VB_VR) {
459c9274b6bSCho, Yu-Chen         /* length and alignment is 1024 bytes */
460c9274b6bSCho, Yu-Chen         mcesao = be64_to_cpu(lowcore->mcesad) & ~0x3ffull;
461c9274b6bSCho, Yu-Chen     }
462c9274b6bSCho, Yu-Chen 
463c9274b6bSCho, Yu-Chen     /* try to store vector registers */
464c9274b6bSCho, Yu-Chen     if (!mcesao || mchk_store_vregs(env, mcesao)) {
465c9274b6bSCho, Yu-Chen         mcic &= ~MCIC_VB_VR;
466c9274b6bSCho, Yu-Chen     }
467c9274b6bSCho, Yu-Chen 
468c9274b6bSCho, Yu-Chen     /* we are always in z/Architecture mode */
469c9274b6bSCho, Yu-Chen     lowcore->ar_access_id = 1;
470c9274b6bSCho, Yu-Chen 
471c9274b6bSCho, Yu-Chen     for (i = 0; i < 16; i++) {
472c9274b6bSCho, Yu-Chen         lowcore->floating_pt_save_area[i] = cpu_to_be64(*get_freg(env, i));
473c9274b6bSCho, Yu-Chen         lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]);
474c9274b6bSCho, Yu-Chen         lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]);
475c9274b6bSCho, Yu-Chen         lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]);
476c9274b6bSCho, Yu-Chen     }
477c9274b6bSCho, Yu-Chen     lowcore->prefixreg_save_area = cpu_to_be32(env->psa);
478c9274b6bSCho, Yu-Chen     lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc);
479c9274b6bSCho, Yu-Chen     lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr);
480c9274b6bSCho, Yu-Chen     lowcore->cpu_timer_save_area = cpu_to_be64(env->cputm);
481c9274b6bSCho, Yu-Chen     lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8);
482c9274b6bSCho, Yu-Chen 
483c9274b6bSCho, Yu-Chen     lowcore->mcic = cpu_to_be64(mcic);
484c9274b6bSCho, Yu-Chen     lowcore->mcck_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
485c9274b6bSCho, Yu-Chen     lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
486c9274b6bSCho, Yu-Chen     mask = be64_to_cpu(lowcore->mcck_new_psw.mask);
487c9274b6bSCho, Yu-Chen     addr = be64_to_cpu(lowcore->mcck_new_psw.addr);
488c9274b6bSCho, Yu-Chen 
489c9274b6bSCho, Yu-Chen     cpu_unmap_lowcore(lowcore);
490c9274b6bSCho, Yu-Chen 
491c9274b6bSCho, Yu-Chen     s390_cpu_set_psw(env, mask, addr);
492c9274b6bSCho, Yu-Chen }
493c9274b6bSCho, Yu-Chen 
s390_cpu_do_interrupt(CPUState * cs)494c9274b6bSCho, Yu-Chen void s390_cpu_do_interrupt(CPUState *cs)
495c9274b6bSCho, Yu-Chen {
496c9274b6bSCho, Yu-Chen     QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
497c9274b6bSCho, Yu-Chen     S390CPU *cpu = S390_CPU(cs);
498c9274b6bSCho, Yu-Chen     CPUS390XState *env = &cpu->env;
499c9274b6bSCho, Yu-Chen     bool stopped = false;
500c9274b6bSCho, Yu-Chen 
501c9274b6bSCho, Yu-Chen     qemu_log_mask(CPU_LOG_INT, "%s: %d at psw=%" PRIx64 ":%" PRIx64 "\n",
502c9274b6bSCho, Yu-Chen                   __func__, cs->exception_index, env->psw.mask, env->psw.addr);
503c9274b6bSCho, Yu-Chen 
504c9274b6bSCho, Yu-Chen try_deliver:
505c9274b6bSCho, Yu-Chen     /* handle machine checks */
506c9274b6bSCho, Yu-Chen     if (cs->exception_index == -1 && s390_cpu_has_mcck_int(cpu)) {
507c9274b6bSCho, Yu-Chen         cs->exception_index = EXCP_MCHK;
508c9274b6bSCho, Yu-Chen     }
509c9274b6bSCho, Yu-Chen     /* handle external interrupts */
510c9274b6bSCho, Yu-Chen     if (cs->exception_index == -1 && s390_cpu_has_ext_int(cpu)) {
511c9274b6bSCho, Yu-Chen         cs->exception_index = EXCP_EXT;
512c9274b6bSCho, Yu-Chen     }
513c9274b6bSCho, Yu-Chen     /* handle I/O interrupts */
514c9274b6bSCho, Yu-Chen     if (cs->exception_index == -1 && s390_cpu_has_io_int(cpu)) {
515c9274b6bSCho, Yu-Chen         cs->exception_index = EXCP_IO;
516c9274b6bSCho, Yu-Chen     }
517c9274b6bSCho, Yu-Chen     /* RESTART interrupt */
518c9274b6bSCho, Yu-Chen     if (cs->exception_index == -1 && s390_cpu_has_restart_int(cpu)) {
519c9274b6bSCho, Yu-Chen         cs->exception_index = EXCP_RESTART;
520c9274b6bSCho, Yu-Chen     }
521c9274b6bSCho, Yu-Chen     /* STOP interrupt has least priority */
522c9274b6bSCho, Yu-Chen     if (cs->exception_index == -1 && s390_cpu_has_stop_int(cpu)) {
523c9274b6bSCho, Yu-Chen         cs->exception_index = EXCP_STOP;
524c9274b6bSCho, Yu-Chen     }
525c9274b6bSCho, Yu-Chen 
526c9274b6bSCho, Yu-Chen     switch (cs->exception_index) {
527c9274b6bSCho, Yu-Chen     case EXCP_PGM:
528c9274b6bSCho, Yu-Chen         do_program_interrupt(env);
529c9274b6bSCho, Yu-Chen         break;
530c9274b6bSCho, Yu-Chen     case EXCP_SVC:
531c9274b6bSCho, Yu-Chen         do_svc_interrupt(env);
532c9274b6bSCho, Yu-Chen         break;
533c9274b6bSCho, Yu-Chen     case EXCP_EXT:
534c9274b6bSCho, Yu-Chen         do_ext_interrupt(env);
535c9274b6bSCho, Yu-Chen         break;
536c9274b6bSCho, Yu-Chen     case EXCP_IO:
537c9274b6bSCho, Yu-Chen         do_io_interrupt(env);
538c9274b6bSCho, Yu-Chen         break;
539c9274b6bSCho, Yu-Chen     case EXCP_MCHK:
540c9274b6bSCho, Yu-Chen         do_mchk_interrupt(env);
541c9274b6bSCho, Yu-Chen         break;
542c9274b6bSCho, Yu-Chen     case EXCP_RESTART:
543c9274b6bSCho, Yu-Chen         do_restart_interrupt(env);
544c9274b6bSCho, Yu-Chen         break;
545c9274b6bSCho, Yu-Chen     case EXCP_STOP:
546c9274b6bSCho, Yu-Chen         do_stop_interrupt(env);
547c9274b6bSCho, Yu-Chen         stopped = true;
548c9274b6bSCho, Yu-Chen         break;
549c9274b6bSCho, Yu-Chen     }
550c9274b6bSCho, Yu-Chen 
551c9274b6bSCho, Yu-Chen     if (cs->exception_index != -1 && !stopped) {
552c9274b6bSCho, Yu-Chen         /* check if there are more pending interrupts to deliver */
553c9274b6bSCho, Yu-Chen         cs->exception_index = -1;
554c9274b6bSCho, Yu-Chen         goto try_deliver;
555c9274b6bSCho, Yu-Chen     }
556c9274b6bSCho, Yu-Chen     cs->exception_index = -1;
557c9274b6bSCho, Yu-Chen 
558c9274b6bSCho, Yu-Chen     /* we might still have pending interrupts, but not deliverable */
559c9274b6bSCho, Yu-Chen     if (!env->pending_int && !qemu_s390_flic_has_any(flic)) {
560c9274b6bSCho, Yu-Chen         cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
561c9274b6bSCho, Yu-Chen     }
562c9274b6bSCho, Yu-Chen 
563c9274b6bSCho, Yu-Chen     /* WAIT PSW during interrupt injection or STOP interrupt */
564c9274b6bSCho, Yu-Chen     if ((env->psw.mask & PSW_MASK_WAIT) || stopped) {
565c9274b6bSCho, Yu-Chen         /* don't trigger a cpu_loop_exit(), use an interrupt instead */
566c9274b6bSCho, Yu-Chen         cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
567c9274b6bSCho, Yu-Chen     } else if (cs->halted) {
56844ee69eaSThomas Huth         /* unhalt if we had a WAIT PSW somewhere in our injection chain */
569c9274b6bSCho, Yu-Chen         s390_cpu_unhalt(cpu);
570c9274b6bSCho, Yu-Chen     }
571c9274b6bSCho, Yu-Chen }
572c9274b6bSCho, Yu-Chen 
s390_cpu_exec_interrupt(CPUState * cs,int interrupt_request)573c9274b6bSCho, Yu-Chen bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
574c9274b6bSCho, Yu-Chen {
575c9274b6bSCho, Yu-Chen     if (interrupt_request & CPU_INTERRUPT_HARD) {
576c9274b6bSCho, Yu-Chen         S390CPU *cpu = S390_CPU(cs);
577c9274b6bSCho, Yu-Chen         CPUS390XState *env = &cpu->env;
578c9274b6bSCho, Yu-Chen 
579c9274b6bSCho, Yu-Chen         if (env->ex_value) {
580c9274b6bSCho, Yu-Chen             /* Execution of the target insn is indivisible from
581c9274b6bSCho, Yu-Chen                the parent EXECUTE insn.  */
582c9274b6bSCho, Yu-Chen             return false;
583c9274b6bSCho, Yu-Chen         }
584c9274b6bSCho, Yu-Chen         if (s390_cpu_has_int(cpu)) {
585c9274b6bSCho, Yu-Chen             s390_cpu_do_interrupt(cs);
586c9274b6bSCho, Yu-Chen             return true;
587c9274b6bSCho, Yu-Chen         }
588c9274b6bSCho, Yu-Chen         if (env->psw.mask & PSW_MASK_WAIT) {
589c9274b6bSCho, Yu-Chen             /* Woken up because of a floating interrupt but it has already
590c9274b6bSCho, Yu-Chen              * been delivered. Go back to sleep. */
591c9274b6bSCho, Yu-Chen             cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
592c9274b6bSCho, Yu-Chen         }
593c9274b6bSCho, Yu-Chen     }
594c9274b6bSCho, Yu-Chen     return false;
595c9274b6bSCho, Yu-Chen }
596c9274b6bSCho, Yu-Chen 
s390x_cpu_debug_excp_handler(CPUState * cs)597c9274b6bSCho, Yu-Chen void s390x_cpu_debug_excp_handler(CPUState *cs)
598c9274b6bSCho, Yu-Chen {
599d0143fa9SPhilippe Mathieu-Daudé     CPUS390XState *env = cpu_env(cs);
600c9274b6bSCho, Yu-Chen     CPUWatchpoint *wp_hit = cs->watchpoint_hit;
601c9274b6bSCho, Yu-Chen 
602c9274b6bSCho, Yu-Chen     if (wp_hit && wp_hit->flags & BP_CPU) {
603c9274b6bSCho, Yu-Chen         /* FIXME: When the storage-alteration-space control bit is set,
604c9274b6bSCho, Yu-Chen            the exception should only be triggered if the memory access
605c9274b6bSCho, Yu-Chen            is done using an address space with the storage-alteration-event
606c9274b6bSCho, Yu-Chen            bit set.  We have no way to detect that with the current
607c9274b6bSCho, Yu-Chen            watchpoint code.  */
608c9274b6bSCho, Yu-Chen         cs->watchpoint_hit = NULL;
609c9274b6bSCho, Yu-Chen 
610c9274b6bSCho, Yu-Chen         env->per_address = env->psw.addr;
611c9274b6bSCho, Yu-Chen         env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
612c9274b6bSCho, Yu-Chen         /* FIXME: We currently no way to detect the address space used
613c9274b6bSCho, Yu-Chen            to trigger the watchpoint.  For now just consider it is the
614c9274b6bSCho, Yu-Chen            current default ASC. This turn to be true except when MVCP
615c9274b6bSCho, Yu-Chen            and MVCS instrutions are not used.  */
616c9274b6bSCho, Yu-Chen         env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
617c9274b6bSCho, Yu-Chen 
618c9274b6bSCho, Yu-Chen         /*
619c9274b6bSCho, Yu-Chen          * Remove all watchpoints to re-execute the code.  A PER exception
620c9274b6bSCho, Yu-Chen          * will be triggered, it will call s390_cpu_set_psw which will
621c9274b6bSCho, Yu-Chen          * recompute the watchpoints.
622c9274b6bSCho, Yu-Chen          */
623c9274b6bSCho, Yu-Chen         cpu_watchpoint_remove_all(cs, BP_CPU);
624c9274b6bSCho, Yu-Chen         cpu_loop_exit_noexc(cs);
625c9274b6bSCho, Yu-Chen     }
626c9274b6bSCho, Yu-Chen }
627c9274b6bSCho, Yu-Chen 
s390x_cpu_do_unaligned_access(CPUState * cs,vaddr addr,MMUAccessType access_type,int mmu_idx,uintptr_t retaddr)628c9274b6bSCho, Yu-Chen void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
629c9274b6bSCho, Yu-Chen                                    MMUAccessType access_type,
630c9274b6bSCho, Yu-Chen                                    int mmu_idx, uintptr_t retaddr)
631c9274b6bSCho, Yu-Chen {
6325bcbf356SRichard Henderson     do_unaligned_access(cs, retaddr);
633c9274b6bSCho, Yu-Chen }
634c9274b6bSCho, Yu-Chen 
6358905770bSMarc-André Lureau static G_NORETURN
monitor_event(CPUS390XState * env,uint64_t monitor_code,uint8_t monitor_class,uintptr_t ra)6368905770bSMarc-André Lureau void monitor_event(CPUS390XState *env,
637c9274b6bSCho, Yu-Chen                    uint64_t monitor_code,
638c9274b6bSCho, Yu-Chen                    uint8_t monitor_class, uintptr_t ra)
639c9274b6bSCho, Yu-Chen {
640c9274b6bSCho, Yu-Chen     /* Store the Monitor Code and the Monitor Class Number into the lowcore */
641c9274b6bSCho, Yu-Chen     stq_phys(env_cpu(env)->as,
642c9274b6bSCho, Yu-Chen              env->psa + offsetof(LowCore, monitor_code), monitor_code);
643c9274b6bSCho, Yu-Chen     stw_phys(env_cpu(env)->as,
644c9274b6bSCho, Yu-Chen              env->psa + offsetof(LowCore, mon_class_num), monitor_class);
645c9274b6bSCho, Yu-Chen 
646c9274b6bSCho, Yu-Chen     tcg_s390_program_interrupt(env, PGM_MONITOR, ra);
647c9274b6bSCho, Yu-Chen }
648c9274b6bSCho, Yu-Chen 
HELPER(monitor_call)649c9274b6bSCho, Yu-Chen void HELPER(monitor_call)(CPUS390XState *env, uint64_t monitor_code,
650c9274b6bSCho, Yu-Chen                           uint32_t monitor_class)
651c9274b6bSCho, Yu-Chen {
6529c028c05SIlya Leoshkevich     g_assert(monitor_class <= 0xf);
653c9274b6bSCho, Yu-Chen 
654c9274b6bSCho, Yu-Chen     if (env->cregs[8] & (0x8000 >> monitor_class)) {
655c9274b6bSCho, Yu-Chen         monitor_event(env, monitor_code, monitor_class, GETPC());
656c9274b6bSCho, Yu-Chen     }
657c9274b6bSCho, Yu-Chen }
658c9274b6bSCho, Yu-Chen 
659c9274b6bSCho, Yu-Chen #endif /* !CONFIG_USER_ONLY */
660