xref: /openbmc/qemu/target/s390x/cpu-sysemu.c (revision efee71c8)
1 /*
2  * QEMU S/390 CPU - System Emulation-only code
3  *
4  * Copyright (c) 2009 Ulrich Hecht
5  * Copyright (c) 2011 Alexander Graf
6  * Copyright (c) 2012 SUSE LINUX Products GmbH
7  * Copyright (c) 2012 IBM Corp.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "qemu/osdep.h"
24 #include "qapi/error.h"
25 #include "cpu.h"
26 #include "s390x-internal.h"
27 #include "kvm/kvm_s390x.h"
28 #include "sysemu/kvm.h"
29 #include "sysemu/reset.h"
30 #include "qemu/timer.h"
31 #include "trace.h"
32 #include "qapi/qapi-visit-run-state.h"
33 #include "sysemu/hw_accel.h"
34 
35 #include "hw/s390x/pv.h"
36 #include "hw/boards.h"
37 #include "sysemu/sysemu.h"
38 #include "sysemu/tcg.h"
39 #include "hw/core/sysemu-cpu-ops.h"
40 
41 /* S390CPUClass::load_normal() */
42 static void s390_cpu_load_normal(CPUState *s)
43 {
44     S390CPU *cpu = S390_CPU(s);
45     uint64_t spsw;
46 
47     if (!s390_is_pv()) {
48         spsw = ldq_phys(s->as, 0);
49         cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
50         /*
51          * Invert short psw indication, so SIE will report a specification
52          * exception if it was not set.
53          */
54         cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
55         cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
56     } else {
57         /*
58          * Firmware requires us to set the load state before we set
59          * the cpu to operating on protected guests.
60          */
61         s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
62     }
63     s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
64 }
65 
66 void s390_cpu_machine_reset_cb(void *opaque)
67 {
68     S390CPU *cpu = opaque;
69 
70     run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
71 }
72 
73 static GuestPanicInformation *s390_cpu_get_crash_info(CPUState *cs)
74 {
75     GuestPanicInformation *panic_info;
76     S390CPU *cpu = S390_CPU(cs);
77 
78     cpu_synchronize_state(cs);
79     panic_info = g_malloc0(sizeof(GuestPanicInformation));
80 
81     panic_info->type = GUEST_PANIC_INFORMATION_TYPE_S390;
82     panic_info->u.s390.core = cpu->env.core_id;
83     panic_info->u.s390.psw_mask = cpu->env.psw.mask;
84     panic_info->u.s390.psw_addr = cpu->env.psw.addr;
85     panic_info->u.s390.reason = cpu->env.crash_reason;
86 
87     return panic_info;
88 }
89 
90 static void s390_cpu_get_crash_info_qom(Object *obj, Visitor *v,
91                                         const char *name, void *opaque,
92                                         Error **errp)
93 {
94     CPUState *cs = CPU(obj);
95     GuestPanicInformation *panic_info;
96 
97     if (!cs->crash_occurred) {
98         error_setg(errp, "No crash occurred");
99         return;
100     }
101 
102     panic_info = s390_cpu_get_crash_info(cs);
103 
104     visit_type_GuestPanicInformation(v, "crash-information", &panic_info,
105                                      errp);
106     qapi_free_GuestPanicInformation(panic_info);
107 }
108 
109 void s390_cpu_init_sysemu(Object *obj)
110 {
111     CPUState *cs = CPU(obj);
112     S390CPU *cpu = S390_CPU(obj);
113 
114     cs->start_powered_off = true;
115     object_property_add(obj, "crash-information", "GuestPanicInformation",
116                         s390_cpu_get_crash_info_qom, NULL, NULL, NULL);
117     cpu->env.tod_timer =
118         timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
119     cpu->env.cpu_timer =
120         timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
121     s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
122 }
123 
124 bool s390_cpu_realize_sysemu(DeviceState *dev, Error **errp)
125 {
126     S390CPU *cpu = S390_CPU(dev);
127     MachineState *ms = MACHINE(qdev_get_machine());
128     unsigned int max_cpus = ms->smp.max_cpus;
129 
130     if (cpu->env.core_id >= max_cpus) {
131         error_setg(errp, "Unable to add CPU with core-id: %" PRIu32
132                    ", maximum core-id: %d", cpu->env.core_id,
133                    max_cpus - 1);
134         return false;
135     }
136 
137     if (cpu_exists(cpu->env.core_id)) {
138         error_setg(errp, "Unable to add CPU with core-id: %" PRIu32
139                    ", it already exists", cpu->env.core_id);
140         return false;
141     }
142 
143     /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
144     CPU(cpu)->cpu_index = cpu->env.core_id;
145     return true;
146 }
147 
148 void s390_cpu_finalize(Object *obj)
149 {
150     S390CPU *cpu = S390_CPU(obj);
151 
152     timer_free(cpu->env.tod_timer);
153     timer_free(cpu->env.cpu_timer);
154 
155     qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
156     g_free(cpu->irqstate);
157 }
158 
159 static const struct SysemuCPUOps s390_sysemu_ops = {
160     .get_phys_page_debug = s390_cpu_get_phys_page_debug,
161     .get_crash_info = s390_cpu_get_crash_info,
162     .write_elf64_note = s390_cpu_write_elf64_note,
163     .legacy_vmsd = &vmstate_s390_cpu,
164 };
165 
166 void s390_cpu_class_init_sysemu(CPUClass *cc)
167 {
168     S390CPUClass *scc = S390_CPU_CLASS(cc);
169 
170     scc->load_normal = s390_cpu_load_normal;
171     cc->sysemu_ops = &s390_sysemu_ops;
172 }
173 
174 static bool disabled_wait(CPUState *cpu)
175 {
176     return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
177                             (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
178 }
179 
180 static unsigned s390_count_running_cpus(void)
181 {
182     CPUState *cpu;
183     int nr_running = 0;
184 
185     CPU_FOREACH(cpu) {
186         uint8_t state = S390_CPU(cpu)->env.cpu_state;
187         if (state == S390_CPU_STATE_OPERATING ||
188             state == S390_CPU_STATE_LOAD) {
189             if (!disabled_wait(cpu)) {
190                 nr_running++;
191             }
192         }
193     }
194 
195     return nr_running;
196 }
197 
198 unsigned int s390_cpu_halt(S390CPU *cpu)
199 {
200     CPUState *cs = CPU(cpu);
201     trace_cpu_halt(cs->cpu_index);
202 
203     if (!cs->halted) {
204         cs->halted = 1;
205         cs->exception_index = EXCP_HLT;
206     }
207 
208     return s390_count_running_cpus();
209 }
210 
211 void s390_cpu_unhalt(S390CPU *cpu)
212 {
213     CPUState *cs = CPU(cpu);
214     trace_cpu_unhalt(cs->cpu_index);
215 
216     if (cs->halted) {
217         cs->halted = 0;
218         cs->exception_index = -1;
219     }
220 }
221 
222 unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
223  {
224     trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
225 
226     switch (cpu_state) {
227     case S390_CPU_STATE_STOPPED:
228     case S390_CPU_STATE_CHECK_STOP:
229         /* halt the cpu for common infrastructure */
230         s390_cpu_halt(cpu);
231         break;
232     case S390_CPU_STATE_OPERATING:
233     case S390_CPU_STATE_LOAD:
234         /*
235          * Starting a CPU with a PSW WAIT bit set:
236          * KVM: handles this internally and triggers another WAIT exit.
237          * TCG: will actually try to continue to run. Don't unhalt, will
238          *      be done when the CPU actually has work (an interrupt).
239          */
240         if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) {
241             s390_cpu_unhalt(cpu);
242         }
243         break;
244     default:
245         error_report("Requested CPU state is not a valid S390 CPU state: %u",
246                      cpu_state);
247         exit(1);
248     }
249     if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
250         kvm_s390_set_cpu_state(cpu, cpu_state);
251     }
252     cpu->env.cpu_state = cpu_state;
253 
254     return s390_count_running_cpus();
255 }
256 
257 int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
258 {
259     if (kvm_enabled()) {
260         return kvm_s390_set_mem_limit(new_limit, hw_limit);
261     }
262     return 0;
263 }
264 
265 void s390_set_max_pagesize(uint64_t pagesize, Error **errp)
266 {
267     if (kvm_enabled()) {
268         kvm_s390_set_max_pagesize(pagesize, errp);
269     }
270 }
271 
272 void s390_cmma_reset(void)
273 {
274     if (kvm_enabled()) {
275         kvm_s390_cmma_reset();
276     }
277 }
278 
279 int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
280                                 int vq, bool assign)
281 {
282     if (kvm_enabled()) {
283         return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign);
284     } else {
285         return 0;
286     }
287 }
288 
289 void s390_crypto_reset(void)
290 {
291     if (kvm_enabled()) {
292         kvm_s390_crypto_reset();
293     }
294 }
295 
296 void s390_enable_css_support(S390CPU *cpu)
297 {
298     if (kvm_enabled()) {
299         kvm_s390_enable_css_support(cpu);
300     }
301 }
302 
303 void s390_do_cpu_set_diag318(CPUState *cs, run_on_cpu_data arg)
304 {
305     if (kvm_enabled()) {
306         kvm_s390_set_diag318(cs, arg.host_ulong);
307     }
308 }
309