blob: 23fe51f0f42f7dc1339b6c2b5859b809f07804d5 [file] [log] [blame]
Andreas Färber29e4bcb2012-04-02 11:39:23 +02001/*
2 * QEMU S/390 CPU
3 *
Andreas Färber1ac1a742012-04-02 13:31:59 +02004 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2011 Alexander Graf
Andreas Färber29e4bcb2012-04-02 11:39:23 +02006 * Copyright (c) 2012 SUSE LINUX Products GmbH
Jens Freimann70bada02013-01-07 05:27:14 +00007 * Copyright (c) 2012 IBM Corp.
Andreas Färber29e4bcb2012-04-02 11:39:23 +02008 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library 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 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, see
21 * <http://www.gnu.org/licenses/lgpl-2.1.html>
Jens Freimann70bada02013-01-07 05:27:14 +000022 * Contributions after 2012-12-11 are licensed under the terms of the
23 * GNU GPL, version 2 or (at your option) any later version.
Andreas Färber29e4bcb2012-04-02 11:39:23 +020024 */
25
Andreas Färber564b8632012-05-03 04:13:04 +020026#include "cpu.h"
Andreas Färber29e4bcb2012-04-02 11:39:23 +020027#include "qemu-common.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010028#include "qemu/timer.h"
Jens Freimann70bada02013-01-07 05:27:14 +000029#include "hw/hw.h"
Andreas Färberc7396bb2013-01-20 19:41:06 +010030#ifndef CONFIG_USER_ONLY
Viktor Mihajlovski904e5fd2012-12-18 07:50:59 +000031#include "sysemu/arch_init.h"
32#endif
Andreas Färber29e4bcb2012-04-02 11:39:23 +020033
Jens Freimann70bada02013-01-07 05:27:14 +000034#define CR0_RESET 0xE0UL
35#define CR14_RESET 0xC2000000UL;
36
Viktor Mihajlovski904e5fd2012-12-18 07:50:59 +000037/* generate CPU information for cpu -? */
38void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf)
39{
40#ifdef CONFIG_KVM
41 (*cpu_fprintf)(f, "s390 %16s\n", "host");
42#endif
43}
44
45#ifndef CONFIG_USER_ONLY
46CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
47{
48 CpuDefinitionInfoList *entry;
49 CpuDefinitionInfo *info;
50
51 info = g_malloc0(sizeof(*info));
52 info->name = g_strdup("host");
53
54 entry = g_malloc0(sizeof(*entry));
55 entry->value = info;
56
57 return entry;
58}
59#endif
Andreas Färber29e4bcb2012-04-02 11:39:23 +020060
Andreas Färber1ac1a742012-04-02 13:31:59 +020061/* CPUClass::reset() */
Andreas Färber29e4bcb2012-04-02 11:39:23 +020062static void s390_cpu_reset(CPUState *s)
63{
64 S390CPU *cpu = S390_CPU(s);
65 S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
66 CPUS390XState *env = &cpu->env;
67
Andreas Färber1ac1a742012-04-02 13:31:59 +020068 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
Andreas Färber55e5c282012-12-17 06:18:02 +010069 qemu_log("CPU Reset (CPU %d)\n", s->cpu_index);
Andreas Färber1ac1a742012-04-02 13:31:59 +020070 log_cpu_state(env, 0);
71 }
72
Andreas Färber49e15872013-01-30 12:48:25 +000073 s390_del_running_cpu(cpu);
Jens Freimann70bada02013-01-07 05:27:14 +000074
Andreas Färber29e4bcb2012-04-02 11:39:23 +020075 scc->parent_reset(s);
76
Andreas Färber1ac1a742012-04-02 13:31:59 +020077 memset(env, 0, offsetof(CPUS390XState, breakpoints));
Jens Freimann70bada02013-01-07 05:27:14 +000078
79 /* architectured initial values for CR 0 and 14 */
80 env->cregs[0] = CR0_RESET;
81 env->cregs[14] = CR14_RESET;
82 /* set halted to 1 to make sure we can add the cpu in
Andreas Färber259186a2013-01-17 18:51:17 +010083 * s390_ipl_cpu code, where CPUState::halted is set back to 0
Jens Freimann70bada02013-01-07 05:27:14 +000084 * after incrementing the cpu counter */
85#if !defined(CONFIG_USER_ONLY)
Andreas Färber259186a2013-01-17 18:51:17 +010086 s->halted = 1;
Jens Freimann70bada02013-01-07 05:27:14 +000087#endif
Andreas Färber1ac1a742012-04-02 13:31:59 +020088 tlb_flush(env, 1);
Andreas Färber29e4bcb2012-04-02 11:39:23 +020089}
90
Jens Freimann70bada02013-01-07 05:27:14 +000091#if !defined(CONFIG_USER_ONLY)
92static void s390_cpu_machine_reset_cb(void *opaque)
93{
94 S390CPU *cpu = opaque;
95
96 cpu_reset(CPU(cpu));
97}
98#endif
99
Andreas Färber1f136632013-01-16 04:00:41 +0100100static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
101{
102 S390CPU *cpu = S390_CPU(dev);
103 S390CPUClass *scc = S390_CPU_GET_CLASS(dev);
104
105 qemu_init_vcpu(&cpu->env);
106 cpu_reset(CPU(cpu));
107
108 scc->parent_realize(dev, errp);
109}
110
Andreas Färber8f22e0d2012-04-02 13:56:29 +0200111static void s390_cpu_initfn(Object *obj)
112{
Andreas Färberc05efcb2013-01-17 12:13:41 +0100113 CPUState *cs = CPU(obj);
Andreas Färber8f22e0d2012-04-02 13:56:29 +0200114 S390CPU *cpu = S390_CPU(obj);
115 CPUS390XState *env = &cpu->env;
Andreas Färber2b7ac762013-01-19 22:43:32 +0100116 static bool inited;
Andreas Färber8f22e0d2012-04-02 13:56:29 +0200117 static int cpu_num = 0;
118#if !defined(CONFIG_USER_ONLY)
119 struct tm tm;
120#endif
121
Andreas Färberc05efcb2013-01-17 12:13:41 +0100122 cs->env_ptr = env;
Andreas Färber8f22e0d2012-04-02 13:56:29 +0200123 cpu_exec_init(env);
124#if !defined(CONFIG_USER_ONLY)
Jens Freimann70bada02013-01-07 05:27:14 +0000125 qemu_register_reset(s390_cpu_machine_reset_cb, cpu);
Andreas Färber8f22e0d2012-04-02 13:56:29 +0200126 qemu_get_timedate(&tm, 0);
127 env->tod_offset = TOD_UNIX_EPOCH +
128 (time2tod(mktimegm(&tm)) * 1000000000ULL);
129 env->tod_basetime = 0;
Andreas Färberb8ba6792012-04-02 14:00:43 +0200130 env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, cpu);
131 env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, cpu);
Andreas Färber259186a2013-01-17 18:51:17 +0100132 /* set CPUState::halted state to 1 to avoid decrementing the running
Jens Freimann70bada02013-01-07 05:27:14 +0000133 * cpu counter in s390_cpu_reset to a negative number at
134 * initial ipl */
Andreas Färber259186a2013-01-17 18:51:17 +0100135 cs->halted = 1;
Andreas Färber8f22e0d2012-04-02 13:56:29 +0200136#endif
137 env->cpu_num = cpu_num++;
138 env->ext_index = -1;
Andreas Färber2b7ac762013-01-19 22:43:32 +0100139
140 if (tcg_enabled() && !inited) {
141 inited = true;
142 s390x_translate_init();
143 }
Andreas Färber8f22e0d2012-04-02 13:56:29 +0200144}
145
Andreas Färberd5627ce2013-01-07 06:14:16 +0000146static void s390_cpu_finalize(Object *obj)
147{
148#if !defined(CONFIG_USER_ONLY)
149 S390CPU *cpu = S390_CPU(obj);
150
151 qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
152#endif
153}
154
Andreas Färberc7396bb2013-01-20 19:41:06 +0100155static const VMStateDescription vmstate_s390_cpu = {
156 .name = "cpu",
157 .unmigratable = 1,
158};
159
Andreas Färber29e4bcb2012-04-02 11:39:23 +0200160static void s390_cpu_class_init(ObjectClass *oc, void *data)
161{
162 S390CPUClass *scc = S390_CPU_CLASS(oc);
163 CPUClass *cc = CPU_CLASS(scc);
Andreas Färberc7396bb2013-01-20 19:41:06 +0100164 DeviceClass *dc = DEVICE_CLASS(oc);
Andreas Färber29e4bcb2012-04-02 11:39:23 +0200165
Andreas Färber1f136632013-01-16 04:00:41 +0100166 scc->parent_realize = dc->realize;
167 dc->realize = s390_cpu_realizefn;
168
Andreas Färber29e4bcb2012-04-02 11:39:23 +0200169 scc->parent_reset = cc->reset;
170 cc->reset = s390_cpu_reset;
Andreas Färberc7396bb2013-01-20 19:41:06 +0100171
Andreas Färber97a8ea52013-02-02 10:57:51 +0100172 cc->do_interrupt = s390_cpu_do_interrupt;
Andreas Färberc7396bb2013-01-20 19:41:06 +0100173 dc->vmsd = &vmstate_s390_cpu;
Andreas Färber29e4bcb2012-04-02 11:39:23 +0200174}
175
176static const TypeInfo s390_cpu_type_info = {
177 .name = TYPE_S390_CPU,
178 .parent = TYPE_CPU,
179 .instance_size = sizeof(S390CPU),
Andreas Färber8f22e0d2012-04-02 13:56:29 +0200180 .instance_init = s390_cpu_initfn,
Andreas Färberd5627ce2013-01-07 06:14:16 +0000181 .instance_finalize = s390_cpu_finalize,
Andreas Färber29e4bcb2012-04-02 11:39:23 +0200182 .abstract = false,
183 .class_size = sizeof(S390CPUClass),
184 .class_init = s390_cpu_class_init,
185};
186
187static void s390_cpu_register_types(void)
188{
189 type_register_static(&s390_cpu_type_info);
190}
191
192type_init(s390_cpu_register_types)