]>
Commit | Line | Data |
---|---|---|
45e077d7 CF |
1 | /* |
2 | * QEMU TCG Single Threaded vCPUs implementation using instruction counting | |
3 | * | |
4 | * Copyright (c) 2003-2008 Fabrice Bellard | |
5 | * Copyright (c) 2014 Red Hat Inc. | |
6 | * | |
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | * of this software and associated documentation files (the "Software"), to deal | |
9 | * in the Software without restriction, including without limitation the rights | |
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | * copies of the Software, and to permit persons to whom the Software is | |
12 | * furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice shall be included in | |
15 | * all copies or substantial portions of the Software. | |
16 | * | |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | * THE SOFTWARE. | |
24 | */ | |
25 | ||
26 | #include "qemu/osdep.h" | |
27 | #include "qemu-common.h" | |
28 | #include "sysemu/tcg.h" | |
29 | #include "sysemu/replay.h" | |
30 | #include "qemu/main-loop.h" | |
31 | #include "qemu/guest-random.h" | |
32 | #include "exec/exec-all.h" | |
45e077d7 | 33 | |
b86f59c7 CF |
34 | #include "tcg-accel-ops.h" |
35 | #include "tcg-accel-ops-icount.h" | |
36 | #include "tcg-accel-ops-rr.h" | |
45e077d7 | 37 | |
9e2658d6 | 38 | static int64_t icount_get_limit(void) |
45e077d7 CF |
39 | { |
40 | int64_t deadline; | |
41 | ||
42 | if (replay_mode != REPLAY_MODE_PLAY) { | |
43 | /* | |
44 | * Include all the timers, because they may need an attention. | |
45 | * Too long CPU execution may create unnecessary delay in UI. | |
46 | */ | |
47 | deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, | |
48 | QEMU_TIMER_ATTR_ALL); | |
49 | /* Check realtime timers, because they help with input processing */ | |
50 | deadline = qemu_soonest_timeout(deadline, | |
51 | qemu_clock_deadline_ns_all(QEMU_CLOCK_REALTIME, | |
52 | QEMU_TIMER_ATTR_ALL)); | |
53 | ||
54 | /* | |
55 | * Maintain prior (possibly buggy) behaviour where if no deadline | |
56 | * was set (as there is no QEMU_CLOCK_VIRTUAL timer) or it is more than | |
57 | * INT32_MAX nanoseconds ahead, we still use INT32_MAX | |
58 | * nanoseconds. | |
59 | */ | |
60 | if ((deadline < 0) || (deadline > INT32_MAX)) { | |
61 | deadline = INT32_MAX; | |
62 | } | |
63 | ||
64 | return icount_round(deadline); | |
65 | } else { | |
66 | return replay_get_instructions(); | |
67 | } | |
68 | } | |
69 | ||
9e2658d6 | 70 | static void icount_notify_aio_contexts(void) |
45e077d7 CF |
71 | { |
72 | /* Wake up other AioContexts. */ | |
73 | qemu_clock_notify(QEMU_CLOCK_VIRTUAL); | |
74 | qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL); | |
75 | } | |
76 | ||
9e2658d6 | 77 | void icount_handle_deadline(void) |
45e077d7 CF |
78 | { |
79 | assert(qemu_in_vcpu_thread()); | |
80 | int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL, | |
81 | QEMU_TIMER_ATTR_ALL); | |
82 | ||
189012fc PD |
83 | /* |
84 | * Instructions, interrupts, and exceptions are processed in cpu-exec. | |
85 | * Don't interrupt cpu thread, when these events are waiting | |
86 | * (i.e., there is no checkpoint) | |
87 | */ | |
88 | if (deadline == 0 | |
89 | && (replay_mode != REPLAY_MODE_PLAY || replay_has_checkpoint())) { | |
9e2658d6 | 90 | icount_notify_aio_contexts(); |
45e077d7 CF |
91 | } |
92 | } | |
93 | ||
9e2658d6 | 94 | void icount_prepare_for_run(CPUState *cpu) |
45e077d7 CF |
95 | { |
96 | int insns_left; | |
97 | ||
98 | /* | |
9e2658d6 | 99 | * These should always be cleared by icount_process_data after |
45e077d7 | 100 | * each vCPU execution. However u16.high can be raised |
b86f59c7 | 101 | * asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt |
45e077d7 CF |
102 | */ |
103 | g_assert(cpu_neg(cpu)->icount_decr.u16.low == 0); | |
104 | g_assert(cpu->icount_extra == 0); | |
105 | ||
9e2658d6 | 106 | cpu->icount_budget = icount_get_limit(); |
45e077d7 CF |
107 | insns_left = MIN(0xffff, cpu->icount_budget); |
108 | cpu_neg(cpu)->icount_decr.u16.low = insns_left; | |
109 | cpu->icount_extra = cpu->icount_budget - insns_left; | |
110 | ||
111 | replay_mutex_lock(); | |
112 | ||
113 | if (cpu->icount_budget == 0 && replay_has_checkpoint()) { | |
9e2658d6 | 114 | icount_notify_aio_contexts(); |
45e077d7 CF |
115 | } |
116 | } | |
117 | ||
9e2658d6 | 118 | void icount_process_data(CPUState *cpu) |
45e077d7 CF |
119 | { |
120 | /* Account for executed instructions */ | |
121 | icount_update(cpu); | |
122 | ||
123 | /* Reset the counters */ | |
124 | cpu_neg(cpu)->icount_decr.u16.low = 0; | |
125 | cpu->icount_extra = 0; | |
126 | cpu->icount_budget = 0; | |
127 | ||
128 | replay_account_executed_instructions(); | |
129 | ||
130 | replay_mutex_unlock(); | |
131 | } | |
132 | ||
b86f59c7 | 133 | void icount_handle_interrupt(CPUState *cpu, int mask) |
45e077d7 CF |
134 | { |
135 | int old_mask = cpu->interrupt_request; | |
136 | ||
b86f59c7 | 137 | tcg_handle_interrupt(cpu, mask); |
45e077d7 CF |
138 | if (qemu_cpu_is_self(cpu) && |
139 | !cpu->can_do_io | |
140 | && (mask & ~old_mask) != 0) { | |
141 | cpu_abort(cpu, "Raised interrupt while not in I/O function"); | |
142 | } | |
143 | } |