1
2
3
4
5
6
7
8
9
10#include "qemu/osdep.h"
11#include "qemu/log.h"
12#include "cpu.h"
13#include "exec/exec-all.h"
14#include "sysemu/kvm.h"
15#include "hw/s390x/ioinst.h"
16
17
18void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen)
19{
20 CPUState *cs = CPU(s390_env_get_cpu(env));
21
22 cs->exception_index = EXCP_PGM;
23 env->int_pgm_code = code;
24 env->int_pgm_ilen = ilen;
25}
26
27static void tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code,
28 int ilen)
29{
30#ifdef CONFIG_TCG
31 trigger_pgm_exception(env, code, ilen);
32 cpu_loop_exit(CPU(s390_env_get_cpu(env)));
33#else
34 g_assert_not_reached();
35#endif
36}
37
38void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
39{
40 S390CPU *cpu = s390_env_get_cpu(env);
41
42 qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
43 env->psw.addr);
44
45 if (kvm_enabled()) {
46 kvm_s390_program_interrupt(cpu, code);
47 } else if (tcg_enabled()) {
48 tcg_s390_program_interrupt(env, code, ilen);
49 } else {
50 g_assert_not_reached();
51 }
52}
53
54#if !defined(CONFIG_USER_ONLY)
55void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param,
56 uint64_t param64)
57{
58 CPUS390XState *env = &cpu->env;
59
60 if (env->ext_index == MAX_EXT_QUEUE - 1) {
61
62 return;
63 }
64
65 env->ext_index++;
66 assert(env->ext_index < MAX_EXT_QUEUE);
67
68 env->ext_queue[env->ext_index].code = code;
69 env->ext_queue[env->ext_index].param = param;
70 env->ext_queue[env->ext_index].param64 = param64;
71
72 env->pending_int |= INTERRUPT_EXT;
73 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
74}
75
76static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id,
77 uint16_t subchannel_number,
78 uint32_t io_int_parm, uint32_t io_int_word)
79{
80 CPUS390XState *env = &cpu->env;
81 int isc = IO_INT_WORD_ISC(io_int_word);
82
83 if (env->io_index[isc] == MAX_IO_QUEUE - 1) {
84
85 return;
86 }
87
88 env->io_index[isc]++;
89 assert(env->io_index[isc] < MAX_IO_QUEUE);
90
91 env->io_queue[env->io_index[isc]][isc].id = subchannel_id;
92 env->io_queue[env->io_index[isc]][isc].nr = subchannel_number;
93 env->io_queue[env->io_index[isc]][isc].parm = io_int_parm;
94 env->io_queue[env->io_index[isc]][isc].word = io_int_word;
95
96 env->pending_int |= INTERRUPT_IO;
97 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
98}
99
100static void cpu_inject_crw_mchk(S390CPU *cpu)
101{
102 CPUS390XState *env = &cpu->env;
103
104 if (env->mchk_index == MAX_MCHK_QUEUE - 1) {
105
106 return;
107 }
108
109 env->mchk_index++;
110 assert(env->mchk_index < MAX_MCHK_QUEUE);
111
112 env->mchk_queue[env->mchk_index].type = 1;
113
114 env->pending_int |= INTERRUPT_MCHK;
115 cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
116}
117
118
119
120
121
122
123void s390_sclp_extint(uint32_t parm)
124{
125 if (kvm_enabled()) {
126 kvm_s390_service_interrupt(parm);
127 } else {
128 S390CPU *dummy_cpu = s390_cpu_addr2state(0);
129
130 cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0);
131 }
132}
133
134void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr,
135 uint32_t io_int_parm, uint32_t io_int_word)
136{
137 if (kvm_enabled()) {
138 kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm,
139 io_int_word);
140 } else {
141 S390CPU *dummy_cpu = s390_cpu_addr2state(0);
142
143 cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm,
144 io_int_word);
145 }
146}
147
148void s390_crw_mchk(void)
149{
150 if (kvm_enabled()) {
151 kvm_s390_crw_mchk();
152 } else {
153 S390CPU *dummy_cpu = s390_cpu_addr2state(0);
154
155 cpu_inject_crw_mchk(dummy_cpu);
156 }
157}
158
159#endif
160