]>
Commit | Line | Data |
---|---|---|
000a1a38 CB |
1 | /* |
2 | * QEMU S/390 Interrupt support | |
3 | * | |
79afc36d | 4 | * Copyright IBM Corp. 2012, 2014 |
000a1a38 CB |
5 | * |
6 | * This work is licensed under the terms of the GNU GPL, version 2 or (at your | |
7 | * option) any later version. See the COPYING file in the top-level directory. | |
8 | */ | |
9 | ||
9615495a | 10 | #include "qemu/osdep.h" |
e3cfd926 | 11 | #include "qemu/log.h" |
000a1a38 | 12 | #include "cpu.h" |
4e58b838 | 13 | #include "internal.h" |
e3cfd926 | 14 | #include "exec/exec-all.h" |
9c17d615 | 15 | #include "sysemu/kvm.h" |
bd3f16ac PB |
16 | #include "hw/s390x/ioinst.h" |
17 | ||
e3cfd926 TH |
18 | /* Ensure to exit the TB after this call! */ |
19 | void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen) | |
20 | { | |
21 | CPUState *cs = CPU(s390_env_get_cpu(env)); | |
22 | ||
23 | cs->exception_index = EXCP_PGM; | |
24 | env->int_pgm_code = code; | |
25 | env->int_pgm_ilen = ilen; | |
26 | } | |
27 | ||
28 | static void tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code, | |
29 | int ilen) | |
30 | { | |
31 | #ifdef CONFIG_TCG | |
32 | trigger_pgm_exception(env, code, ilen); | |
33 | cpu_loop_exit(CPU(s390_env_get_cpu(env))); | |
34 | #else | |
35 | g_assert_not_reached(); | |
36 | #endif | |
37 | } | |
38 | ||
39 | void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) | |
40 | { | |
41 | S390CPU *cpu = s390_env_get_cpu(env); | |
42 | ||
43 | qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", | |
44 | env->psw.addr); | |
45 | ||
46 | if (kvm_enabled()) { | |
47 | kvm_s390_program_interrupt(cpu, code); | |
48 | } else if (tcg_enabled()) { | |
49 | tcg_s390_program_interrupt(env, code, ilen); | |
50 | } else { | |
51 | g_assert_not_reached(); | |
52 | } | |
53 | } | |
54 | ||
bd3f16ac PB |
55 | #if !defined(CONFIG_USER_ONLY) |
56 | void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, | |
57 | uint64_t param64) | |
58 | { | |
59 | CPUS390XState *env = &cpu->env; | |
60 | ||
61 | if (env->ext_index == MAX_EXT_QUEUE - 1) { | |
62 | /* ugh - can't queue anymore. Let's drop. */ | |
63 | return; | |
64 | } | |
65 | ||
66 | env->ext_index++; | |
67 | assert(env->ext_index < MAX_EXT_QUEUE); | |
68 | ||
69 | env->ext_queue[env->ext_index].code = code; | |
70 | env->ext_queue[env->ext_index].param = param; | |
71 | env->ext_queue[env->ext_index].param64 = param64; | |
72 | ||
73 | env->pending_int |= INTERRUPT_EXT; | |
74 | cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); | |
75 | } | |
76 | ||
77 | static void cpu_inject_io(S390CPU *cpu, uint16_t subchannel_id, | |
78 | uint16_t subchannel_number, | |
79 | uint32_t io_int_parm, uint32_t io_int_word) | |
80 | { | |
81 | CPUS390XState *env = &cpu->env; | |
82 | int isc = IO_INT_WORD_ISC(io_int_word); | |
83 | ||
84 | if (env->io_index[isc] == MAX_IO_QUEUE - 1) { | |
85 | /* ugh - can't queue anymore. Let's drop. */ | |
86 | return; | |
87 | } | |
88 | ||
89 | env->io_index[isc]++; | |
90 | assert(env->io_index[isc] < MAX_IO_QUEUE); | |
91 | ||
92 | env->io_queue[env->io_index[isc]][isc].id = subchannel_id; | |
93 | env->io_queue[env->io_index[isc]][isc].nr = subchannel_number; | |
94 | env->io_queue[env->io_index[isc]][isc].parm = io_int_parm; | |
95 | env->io_queue[env->io_index[isc]][isc].word = io_int_word; | |
96 | ||
97 | env->pending_int |= INTERRUPT_IO; | |
98 | cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); | |
99 | } | |
100 | ||
101 | static void cpu_inject_crw_mchk(S390CPU *cpu) | |
102 | { | |
103 | CPUS390XState *env = &cpu->env; | |
104 | ||
105 | if (env->mchk_index == MAX_MCHK_QUEUE - 1) { | |
106 | /* ugh - can't queue anymore. Let's drop. */ | |
107 | return; | |
108 | } | |
109 | ||
110 | env->mchk_index++; | |
111 | assert(env->mchk_index < MAX_MCHK_QUEUE); | |
112 | ||
113 | env->mchk_queue[env->mchk_index].type = 1; | |
114 | ||
115 | env->pending_int |= INTERRUPT_MCHK; | |
116 | cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); | |
117 | } | |
000a1a38 | 118 | |
79afc36d CH |
119 | /* |
120 | * All of the following interrupts are floating, i.e. not per-vcpu. | |
de13d216 CH |
121 | * We just need a dummy cpustate in order to be able to inject in the |
122 | * non-kvm case. | |
79afc36d | 123 | */ |
000a1a38 CB |
124 | void s390_sclp_extint(uint32_t parm) |
125 | { | |
000a1a38 | 126 | if (kvm_enabled()) { |
de13d216 | 127 | kvm_s390_service_interrupt(parm); |
000a1a38 | 128 | } else { |
de13d216 | 129 | S390CPU *dummy_cpu = s390_cpu_addr2state(0); |
de13d216 | 130 | |
f9466733 | 131 | cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0); |
000a1a38 CB |
132 | } |
133 | } | |
79afc36d | 134 | |
de13d216 CH |
135 | void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, |
136 | uint32_t io_int_parm, uint32_t io_int_word) | |
79afc36d CH |
137 | { |
138 | if (kvm_enabled()) { | |
de13d216 | 139 | kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm, |
79afc36d CH |
140 | io_int_word); |
141 | } else { | |
de13d216 CH |
142 | S390CPU *dummy_cpu = s390_cpu_addr2state(0); |
143 | ||
144 | cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm, | |
79afc36d CH |
145 | io_int_word); |
146 | } | |
147 | } | |
148 | ||
de13d216 | 149 | void s390_crw_mchk(void) |
79afc36d CH |
150 | { |
151 | if (kvm_enabled()) { | |
de13d216 | 152 | kvm_s390_crw_mchk(); |
79afc36d | 153 | } else { |
de13d216 CH |
154 | S390CPU *dummy_cpu = s390_cpu_addr2state(0); |
155 | ||
156 | cpu_inject_crw_mchk(dummy_cpu); | |
79afc36d CH |
157 | } |
158 | } | |
159 | ||
000a1a38 | 160 | #endif |