blob: 9c56d05f6bb5ddde202eefac3507640b10ca0c83 [file] [log] [blame]
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +02001/*
2 * QEMU System Emulator
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24#include "config-host.h"
25
David 'Digit' Turner9b3a4b02014-01-23 00:52:54 +010026#include "cpu.h"
David 'Digit' Turner6af67652013-12-14 23:49:32 +010027#include "monitor/monitor.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010028#include "sysemu/sysemu.h"
David 'Digit' Turnera889d352014-03-20 12:35:32 +010029#include "cpu.h"
David 'Digit' Turner0e051542014-01-23 02:41:42 +010030#include "exec/exec-all.h"
David 'Digit' Turner852088c2013-12-14 23:04:12 +010031#include "exec/gdbstub.h"
David 'Digit' Turner34c48ff2013-12-15 00:25:03 +010032#include "sysemu/dma.h"
33#include "sysemu/kvm.h"
David 'Digit' Turnera2c14f92014-02-04 01:02:30 +010034#include "exec/exec-all.h"
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010035#include "exec/hax.h"
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020036
David 'Digit' Turner11822842013-12-17 09:16:47 +010037#include "sysemu/cpus.h"
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020038
David 'Digit' Turner66576782014-03-24 16:57:57 +010039static CPUState *cur_cpu;
40static CPUState *next_cpu;
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020041
42/***********************************************************/
43void hw_error(const char *fmt, ...)
44{
45 va_list ap;
David 'Digit' Turner66576782014-03-24 16:57:57 +010046 CPUState *cpu;
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020047
48 va_start(ap, fmt);
49 fprintf(stderr, "qemu: hardware error: ");
50 vfprintf(stderr, fmt, ap);
51 fprintf(stderr, "\n");
David 'Digit' Turner66576782014-03-24 16:57:57 +010052 CPU_FOREACH(cpu) {
53 fprintf(stderr, "CPU #%d:\n", cpu->cpu_index);
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020054#ifdef TARGET_I386
David 'Digit' Turner66576782014-03-24 16:57:57 +010055 cpu_dump_state(cpu->env_ptr, stderr, fprintf, X86_DUMP_FPU);
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020056#else
David 'Digit' Turner66576782014-03-24 16:57:57 +010057 cpu_dump_state(cpu->env_ptr, stderr, fprintf, 0);
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020058#endif
59 }
60 va_end(ap);
61 abort();
62}
63
64static void do_vm_stop(int reason)
65{
66 if (vm_running) {
67 cpu_disable_ticks();
68 vm_running = 0;
69 pause_all_vcpus();
70 vm_state_notify(0, reason);
71 }
72}
73
David 'Digit' Turner66576782014-03-24 16:57:57 +010074static int cpu_can_run(CPUArchState *env)
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020075{
David 'Digit' Turner66576782014-03-24 16:57:57 +010076 CPUState *cpu = ENV_GET_CPU(env);
77 if (cpu->stop)
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020078 return 0;
David 'Digit' Turner66576782014-03-24 16:57:57 +010079 if (cpu->stopped)
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020080 return 0;
81 return 1;
82}
83
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020084int tcg_has_work(void)
85{
David 'Digit' Turner66576782014-03-24 16:57:57 +010086 CPUState *cpu;
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020087
David 'Digit' Turner66576782014-03-24 16:57:57 +010088 CPU_FOREACH(cpu) {
89 if (cpu->stop)
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020090 return 1;
David 'Digit' Turner66576782014-03-24 16:57:57 +010091 if (cpu->stopped)
David 'Digit' Turner4ab12252014-03-24 11:29:53 +010092 return 0;
David 'Digit' Turner66576782014-03-24 16:57:57 +010093 if (!cpu->halted)
David 'Digit' Turner4ab12252014-03-24 11:29:53 +010094 return 1;
David 'Digit' Turner66576782014-03-24 16:57:57 +010095 if (cpu_has_work(cpu))
David 'Digit' Turner4ab12252014-03-24 11:29:53 +010096 return 1;
97 return 0;
98 }
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +020099 return 0;
100}
101
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100102void qemu_init_vcpu(CPUState *cpu)
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200103{
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100104 CPUArchState *env = cpu->env_ptr;
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200105
106 if (kvm_enabled())
107 kvm_init_vcpu(env);
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800108#ifdef CONFIG_HAX
109 if (hax_enabled())
110 hax_init_vcpu(env);
111#endif
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200112 return;
113}
114
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100115bool qemu_cpu_is_self(CPUState *cpu)
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200116{
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100117 return true;
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200118}
119
120void resume_all_vcpus(void)
121{
122}
123
124void pause_all_vcpus(void)
125{
126}
127
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100128void qemu_cpu_kick(CPUState *cpu)
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200129{
130 return;
131}
132
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100133// In main-loop.c
134#ifdef _WIN32
135extern HANDLE qemu_event_handle;
136#endif
137
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200138void qemu_notify_event(void)
139{
David 'Digit' Turner66576782014-03-24 16:57:57 +0100140 CPUState *cpu = current_cpu;
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200141
David 'Digit' Turner66576782014-03-24 16:57:57 +0100142 if (cpu) {
David 'Digit' Turnerbf7a22f2014-03-25 16:36:03 +0100143 cpu_exit(cpu);
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800144 /*
145 * This is mainly for the Windows host, where the timer may be in
146 * a different thread with vcpu. Thus the timer function needs to
147 * notify the vcpu thread of more than simply cpu_exit. If env is
148 * not NULL, it means that the vcpu is in execute state, we need
149 * only to set the flags. If the guest is in execute state, the
150 * HAX kernel module will exit to qemu. If env is NULL, vcpu is
151 * in main_loop_wait, and we need a event to notify it.
152 */
153#ifdef CONFIG_HAX
154 if (hax_enabled())
155 hax_raise_event(env);
156 } else {
157#ifdef _WIN32
158 if(hax_enabled())
159 SetEvent(qemu_event_handle);
160#endif
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200161 }
Jun Nakajimaa381ef02011-12-17 19:13:25 -0800162#else
163 }
164#endif
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200165}
166
167void qemu_mutex_lock_iothread(void)
168{
169}
170
171void qemu_mutex_unlock_iothread(void)
172{
173}
174
175void vm_stop(int reason)
176{
177 do_vm_stop(reason);
178}
179
David 'Digit' Turnere2678e12014-01-16 15:56:43 +0100180static int qemu_cpu_exec(CPUOldState *env)
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200181{
182 int ret;
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200183
184#ifdef CONFIG_PROFILER
David 'Digit' Turnerf9077a82014-02-10 23:10:47 +0100185 int64_t ti = profile_getclock();
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200186#endif
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100187#ifndef CONFIG_ANDROID
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200188 if (use_icount) {
189 int64_t count;
190 int decr;
191 qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
192 env->icount_decr.u16.low = 0;
193 env->icount_extra = 0;
194 count = qemu_next_icount_deadline();
195 count = (count + (1 << icount_time_shift) - 1)
196 >> icount_time_shift;
197 qemu_icount += count;
198 decr = (count > 0xffff) ? 0xffff : count;
199 count -= decr;
200 env->icount_decr.u16.low = decr;
201 env->icount_extra = count;
202 }
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100203#endif
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200204 ret = cpu_exec(env);
205#ifdef CONFIG_PROFILER
206 qemu_time += profile_getclock() - ti;
207#endif
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100208#ifndef CONFIG_ANDROID
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200209 if (use_icount) {
210 /* Fold pending instructions back into the
211 instruction counter, and clear the interrupt flag. */
212 qemu_icount -= (env->icount_decr.u16.low
213 + env->icount_extra);
214 env->icount_decr.u32 = 0;
215 env->icount_extra = 0;
216 }
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100217#endif
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200218 return ret;
219}
220
221void tcg_cpu_exec(void)
222{
223 int ret = 0;
224
225 if (next_cpu == NULL)
David 'Digit' Turner4ab12252014-03-24 11:29:53 +0100226 next_cpu = QTAILQ_FIRST(&cpus);
David 'Digit' Turner66576782014-03-24 16:57:57 +0100227 for (; next_cpu != NULL; next_cpu = QTAILQ_NEXT(next_cpu, node)) {\
228 cur_cpu = next_cpu;
229 CPUOldState *env = cur_cpu->env_ptr;
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200230
231 if (!vm_running)
232 break;
233 if (qemu_timer_alarm_pending()) {
234 break;
235 }
236 if (cpu_can_run(env))
237 ret = qemu_cpu_exec(env);
238 if (ret == EXCP_DEBUG) {
David 'Digit' Turner0b1a8452014-03-25 17:37:52 +0100239 gdb_set_stop_cpu(cur_cpu);
David 'Digit' Turner23ca2ae2011-06-01 16:14:53 +0200240 debug_requested = 1;
241 break;
242 }
243 }
244}
245
David 'Digit' Turnerf0183552014-02-16 14:20:45 +0100246/***********************************************************/
247/* guest cycle counter */
248
249typedef struct TimersState {
250 int64_t cpu_ticks_prev;
251 int64_t cpu_ticks_offset;
252 int64_t cpu_clock_offset;
253 int32_t cpu_ticks_enabled;
254 int64_t dummy;
255} TimersState;
256
257static void timer_save(QEMUFile *f, void *opaque)
258{
259 TimersState *s = opaque;
260
261 if (s->cpu_ticks_enabled) {
262 hw_error("cannot save state if virtual timers are running");
263 }
264 qemu_put_be64(f, s->cpu_ticks_prev);
265 qemu_put_be64(f, s->cpu_ticks_offset);
266 qemu_put_be64(f, s->cpu_clock_offset);
267 }
268
269static int timer_load(QEMUFile *f, void *opaque, int version_id)
270{
271 TimersState *s = opaque;
272
273 if (version_id != 1 && version_id != 2)
274 return -EINVAL;
275 if (s->cpu_ticks_enabled) {
276 return -EINVAL;
277 }
278 s->cpu_ticks_prev = qemu_get_sbe64(f);
279 s->cpu_ticks_offset = qemu_get_sbe64(f);
280 if (version_id == 2) {
281 s->cpu_clock_offset = qemu_get_sbe64(f);
282 }
283 return 0;
284}
285
286
287TimersState timers_state;
288
289void qemu_timer_register_savevm(void) {
David 'Digit' Turner5cb5c0b2014-02-17 16:04:03 +0100290 register_savevm(NULL,
291 "timer",
292 0,
293 2,
294 timer_save,
295 timer_load,
296 &timers_state);
David 'Digit' Turnerf0183552014-02-16 14:20:45 +0100297}
298
David 'Digit' Turner9b3a4b02014-01-23 00:52:54 +0100299/* Return the virtual CPU time, based on the instruction counter. */
300int64_t cpu_get_icount(void)
301{
302 int64_t icount;
303 CPUOldState *env = cpu_single_env;;
304
305 icount = qemu_icount;
306 if (env) {
307 if (!can_do_io(env)) {
308 fprintf(stderr, "Bad clock read\n");
309 }
310 icount -= (env->icount_decr.u16.low + env->icount_extra);
311 }
312 return qemu_icount_bias + (icount << icount_time_shift);
313}
David 'Digit' Turnerf0183552014-02-16 14:20:45 +0100314
315/* return the host CPU cycle counter and handle stop/restart */
316int64_t cpu_get_ticks(void)
317{
318 if (use_icount) {
319 return cpu_get_icount();
320 }
321 if (!timers_state.cpu_ticks_enabled) {
322 return timers_state.cpu_ticks_offset;
323 } else {
324 int64_t ticks;
325 ticks = cpu_get_real_ticks();
326 if (timers_state.cpu_ticks_prev > ticks) {
327 /* Note: non increasing ticks may happen if the host uses
328 software suspend */
329 timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
330 }
331 timers_state.cpu_ticks_prev = ticks;
332 return ticks + timers_state.cpu_ticks_offset;
333 }
334}
335
336/* return the host CPU monotonic timer and handle stop/restart */
337int64_t cpu_get_clock(void)
338{
339 int64_t ti;
340 if (!timers_state.cpu_ticks_enabled) {
341 return timers_state.cpu_clock_offset;
342 } else {
343 ti = get_clock();
344 return ti + timers_state.cpu_clock_offset;
345 }
346}
347
348/* enable cpu_get_ticks() */
349void cpu_enable_ticks(void)
350{
351 if (!timers_state.cpu_ticks_enabled) {
352 timers_state.cpu_ticks_offset -= cpu_get_real_ticks();
353 timers_state.cpu_clock_offset -= get_clock();
354 timers_state.cpu_ticks_enabled = 1;
355 }
356}
357
358/* disable cpu_get_ticks() : the clock is stopped. You must not call
359 cpu_get_ticks() after that. */
360void cpu_disable_ticks(void)
361{
362 if (timers_state.cpu_ticks_enabled) {
363 timers_state.cpu_ticks_offset = cpu_get_ticks();
364 timers_state.cpu_clock_offset = cpu_get_clock();
365 timers_state.cpu_ticks_enabled = 0;
366 }
367}
David 'Digit' Turnerdcda9492014-02-16 15:13:55 +0100368
369void qemu_clock_warp(QEMUClockType clock) {
370}