master
c 391 lines 10.8 KB
Raw
1 /*
2 * Copyright 2008 IBM Corporation
3 * 2008 Red Hat, Inc.
4 * Copyright 2011 Intel Corporation
5 * Copyright 2016 Veertu, Inc.
6 * Copyright 2017 The Android Open Source Project
7 *
8 * QEMU Hypervisor.framework support
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General Public
12 * License as published by the Free Software Foundation.
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 * This file contain code under public domain from the hvdos project:
23 * https://github.com/mist64/hvdos
24 *
25 * Parts Copyright (c) 2011 NetApp, Inc.
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 *
37 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 */
49
50 #include "qemu/osdep.h"
51 #include "qemu/guest-random.h"
52 #include "qemu/main-loop.h"
53 #include "qemu/queue.h"
54 #include "gdbstub/enums.h"
55 #include "exec/cpu-common.h"
56 #include "hw/core/cpu.h"
57 #include "accel/accel-cpu-ops.h"
58 #include "system/cpus.h"
59 #include "system/hvf.h"
60 #include "system/hvf_int.h"
61 #include <mach/mach_time.h>
62
63 HVFState *hvf_state;
64
65 static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
66 {
67 if (!cpu->vcpu_dirty) {
68 hvf_arch_get_registers(cpu);
69 cpu->vcpu_dirty = true;
70 }
71 }
72
73 static void hvf_cpu_synchronize_state(CPUState *cpu)
74 {
75 if (!cpu->vcpu_dirty) {
76 run_on_cpu(cpu, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL);
77 }
78 }
79
80 static void do_hvf_cpu_synchronize_set_dirty(CPUState *cpu,
81 run_on_cpu_data arg)
82 {
83 /* QEMU state is the reference, push it to HVF now and on next entry */
84 cpu->vcpu_dirty = true;
85 }
86
87 static void hvf_cpu_synchronize_post_reset(CPUState *cpu)
88 {
89 run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
90 }
91
92 static void hvf_cpu_synchronize_post_init(CPUState *cpu)
93 {
94 run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
95 }
96
97 static void hvf_cpu_synchronize_pre_loadvm(CPUState *cpu)
98 {
99 run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
100 }
101
102 static void dummy_signal(int sig)
103 {
104 }
105
106 static void do_hvf_get_vcpu_exec_time(CPUState *cpu, run_on_cpu_data arg)
107 {
108 int r = hv_vcpu_get_exec_time(cpu->accel->fd, arg.host_ptr);
109 assert_hvf_ok(r);
110 }
111
112 static void hvf_vcpu_destroy(CPUState *cpu)
113 {
114 hv_return_t ret = hv_vcpu_destroy(cpu->accel->fd);
115 assert_hvf_ok(ret);
116
117 hvf_arch_vcpu_destroy(cpu);
118 g_free(cpu->accel);
119 cpu->accel = NULL;
120 }
121
122 static int hvf_init_vcpu(CPUState *cpu)
123 {
124 int r;
125
126 cpu->accel = g_new0(AccelCPUState, 1);
127
128 /* init cpu signals */
129 struct sigaction sigact;
130
131 memset(&sigact, 0, sizeof(sigact));
132 sigact.sa_handler = dummy_signal;
133 sigaction(SIG_IPI, &sigact, NULL);
134
135 #ifdef __aarch64__
136 cpu->accel->guest_debug_enabled = false;
137
138 r = hv_vcpu_create(&cpu->accel->fd,
139 (hv_vcpu_exit_t **)&cpu->accel->exit, NULL);
140 #else
141 r = hv_vcpu_create(&cpu->accel->fd, HV_VCPU_DEFAULT);
142 #endif
143 assert_hvf_ok(r);
144 cpu->vcpu_dirty = true;
145
146 return hvf_arch_init_vcpu(cpu);
147 }
148
149 /*
150 * The HVF-specific vCPU thread function. This one should only run when the host
151 * CPU supports the VMX "unrestricted guest" feature.
152 */
153 static void *hvf_cpu_thread_fn(void *arg)
154 {
155 CPUState *cpu = arg;
156
157 int r;
158
159 assert(hvf_enabled());
160
161 rcu_register_thread();
162
163 bql_lock();
164 qemu_thread_get_self(cpu->thread);
165
166 cpu->thread_id = qemu_get_thread_id();
167 current_cpu = cpu;
168
169 hvf_init_vcpu(cpu);
170
171 /* signal CPU creation */
172 cpu_thread_signal_created(cpu);
173 qemu_guest_random_seed_thread_part2(cpu->random_seed);
174
175 do {
176 qemu_process_cpu_events(cpu);
177 if (cpu_can_run(cpu)) {
178 r = hvf_arch_vcpu_exec(cpu);
179 if (r == EXCP_DEBUG) {
180 cpu_handle_guest_debug(cpu);
181 }
182 }
183 } while (!cpu->unplug || cpu_can_run(cpu));
184
185 hvf_vcpu_destroy(cpu);
186 cpu_thread_signal_destroyed(cpu);
187 bql_unlock();
188 rcu_unregister_thread();
189 return NULL;
190 }
191
192 static void hvf_start_vcpu_thread(CPUState *cpu)
193 {
194 char thread_name[VCPU_THREAD_NAME_SIZE];
195
196 /*
197 * HVF currently does not support TCG, and only runs in
198 * unrestricted-guest mode.
199 */
200 assert(hvf_enabled());
201
202 snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/HVF",
203 cpu->cpu_index);
204 qemu_thread_create(cpu->thread, thread_name, hvf_cpu_thread_fn,
205 cpu, QEMU_THREAD_JOINABLE);
206 }
207
208 struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu, vaddr pc)
209 {
210 struct hvf_sw_breakpoint *bp;
211
212 QTAILQ_FOREACH(bp, &hvf_state->hvf_sw_breakpoints, entry) {
213 if (bp->pc == pc) {
214 return bp;
215 }
216 }
217 return NULL;
218 }
219
220 int hvf_sw_breakpoints_active(CPUState *cpu)
221 {
222 return !QTAILQ_EMPTY(&hvf_state->hvf_sw_breakpoints);
223 }
224
225 static void do_hvf_update_guest_debug(CPUState *cpu, run_on_cpu_data arg)
226 {
227 hvf_arch_update_guest_debug(cpu);
228 }
229
230 int hvf_update_guest_debug(CPUState *cpu)
231 {
232 run_on_cpu(cpu, do_hvf_update_guest_debug, RUN_ON_CPU_NULL);
233 return 0;
234 }
235
236 static int hvf_insert_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type,
237 vaddr addr, vaddr len)
238 {
239 struct hvf_sw_breakpoint *bp;
240 int err;
241
242 if (type == GDB_BREAKPOINT_SW) {
243 bp = hvf_find_sw_breakpoint(cpu, addr);
244 if (bp) {
245 bp->use_count++;
246 return 0;
247 }
248
249 bp = g_new(struct hvf_sw_breakpoint, 1);
250 bp->pc = addr;
251 bp->use_count = 1;
252 err = hvf_arch_insert_sw_breakpoint(cpu, bp);
253 if (err) {
254 g_free(bp);
255 return err;
256 }
257
258 QTAILQ_INSERT_HEAD(&hvf_state->hvf_sw_breakpoints, bp, entry);
259 } else {
260 err = hvf_arch_insert_gdbstub_hw_breakpoint(addr, len, type);
261 if (err) {
262 return err;
263 }
264 }
265
266 CPU_FOREACH(cpu) {
267 err = hvf_update_guest_debug(cpu);
268 if (err) {
269 return err;
270 }
271 }
272 return 0;
273 }
274
275 static int hvf_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type,
276 vaddr addr, vaddr len)
277 {
278 struct hvf_sw_breakpoint *bp;
279 int err;
280
281 if (type == GDB_BREAKPOINT_SW) {
282 bp = hvf_find_sw_breakpoint(cpu, addr);
283 if (!bp) {
284 return -ENOENT;
285 }
286
287 if (bp->use_count > 1) {
288 bp->use_count--;
289 return 0;
290 }
291
292 err = hvf_arch_remove_sw_breakpoint(cpu, bp);
293 if (err) {
294 return err;
295 }
296
297 QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry);
298 g_free(bp);
299 } else {
300 err = hvf_arch_remove_gdbstub_hw_breakpoint(addr, len, type);
301 if (err) {
302 return err;
303 }
304 }
305
306 CPU_FOREACH(cpu) {
307 err = hvf_update_guest_debug(cpu);
308 if (err) {
309 return err;
310 }
311 }
312 return 0;
313 }
314
315 static void hvf_remove_all_gdbstub_breakpoints(CPUState *cpu)
316 {
317 struct hvf_sw_breakpoint *bp, *next;
318 CPUState *tmpcpu;
319
320 QTAILQ_FOREACH_SAFE(bp, &hvf_state->hvf_sw_breakpoints, entry, next) {
321 if (hvf_arch_remove_sw_breakpoint(cpu, bp) != 0) {
322 /* Try harder to find a CPU that currently sees the breakpoint. */
323 CPU_FOREACH(tmpcpu)
324 {
325 if (hvf_arch_remove_sw_breakpoint(tmpcpu, bp) == 0) {
326 break;
327 }
328 }
329 }
330 QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry);
331 g_free(bp);
332 }
333 hvf_arch_remove_all_gdbstub_hw_breakpoints();
334
335 CPU_FOREACH(cpu) {
336 hvf_update_guest_debug(cpu);
337 }
338 }
339
340 static void hvf_get_vcpu_stats(CPUState *cpu, GString *buf)
341 {
342 uint64_t time_mach; /* units of mach_absolute_time() */
343
344 run_on_cpu(cpu, do_hvf_get_vcpu_exec_time, RUN_ON_CPU_HOST_PTR(&time_mach));
345
346 mach_timebase_info_data_t timebase;
347 mach_timebase_info(&timebase);
348 uint64_t time_ns = time_mach * timebase.numer / timebase.denom;
349
350 g_string_append_printf(buf, "HVF cumulative execution time: %llu.%.3llus\n",
351 time_ns / 1000000000,
352 (time_ns % 1000000000) / 1000000);
353 }
354
355 static void hvf_accel_ops_class_init(ObjectClass *oc, const void *data)
356 {
357 AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
358
359 ops->cpu_target_realize = hvf_arch_cpu_realize;
360
361 ops->create_vcpu_thread = hvf_start_vcpu_thread;
362 ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
363 ops->handle_interrupt = generic_handle_interrupt;
364
365 ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
366 ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
367 ops->synchronize_state = hvf_cpu_synchronize_state;
368 ops->synchronize_pre_loadvm = hvf_cpu_synchronize_pre_loadvm;
369
370 ops->insert_gdbstub_breakpoint = hvf_insert_gdbstub_breakpoint;
371 ops->remove_gdbstub_breakpoint = hvf_remove_gdbstub_breakpoint;
372 ops->remove_all_gdbstub_breakpoints = hvf_remove_all_gdbstub_breakpoints;
373 ops->update_guest_debug = hvf_update_guest_debug;
374
375 ops->get_vcpu_stats = hvf_get_vcpu_stats;
376 };
377
378 static const TypeInfo hvf_accel_ops_type = {
379 .name = ACCEL_OPS_NAME("hvf"),
380
381 .parent = TYPE_ACCEL_OPS,
382 .class_init = hvf_accel_ops_class_init,
383 .abstract = true,
384 };
385
386 static void hvf_accel_ops_register_types(void)
387 {
388 type_register_static(&hvf_accel_ops_type);
389 }
390
391 type_init(hvf_accel_ops_register_types);