]>
Commit | Line | Data |
---|---|---|
8ef39ecf CF |
1 | /* |
2 | * QEMU Windows Hypervisor Platform accelerator (WHPX) | |
3 | * | |
4 | * Copyright Microsoft Corp. 2017 | |
5 | * | |
6 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
7 | * See the COPYING file in the top-level directory. | |
8 | * | |
9 | */ | |
10 | ||
11 | #include "qemu/osdep.h" | |
12 | #include "sysemu/kvm_int.h" | |
13 | #include "qemu/main-loop.h" | |
14 | #include "sysemu/cpus.h" | |
15 | #include "qemu/guest-random.h" | |
16 | ||
17 | #include "sysemu/whpx.h" | |
9102c968 | 18 | #include "whpx-internal.h" |
b86f59c7 | 19 | #include "whpx-accel-ops.h" |
8ef39ecf | 20 | |
8ef39ecf CF |
21 | static void *whpx_cpu_thread_fn(void *arg) |
22 | { | |
23 | CPUState *cpu = arg; | |
24 | int r; | |
25 | ||
26 | rcu_register_thread(); | |
27 | ||
195801d7 | 28 | bql_lock(); |
8ef39ecf CF |
29 | qemu_thread_get_self(cpu->thread); |
30 | cpu->thread_id = qemu_get_thread_id(); | |
31 | current_cpu = cpu; | |
32 | ||
33 | r = whpx_init_vcpu(cpu); | |
34 | if (r < 0) { | |
35 | fprintf(stderr, "whpx_init_vcpu failed: %s\n", strerror(-r)); | |
36 | exit(1); | |
37 | } | |
38 | ||
39 | /* signal CPU creation */ | |
40 | cpu_thread_signal_created(cpu); | |
41 | qemu_guest_random_seed_thread_part2(cpu->random_seed); | |
42 | ||
43 | do { | |
44 | if (cpu_can_run(cpu)) { | |
45 | r = whpx_vcpu_exec(cpu); | |
46 | if (r == EXCP_DEBUG) { | |
47 | cpu_handle_guest_debug(cpu); | |
48 | } | |
49 | } | |
50 | while (cpu_thread_is_idle(cpu)) { | |
7c754c78 | 51 | qemu_cond_wait_bql(cpu->halt_cond); |
8ef39ecf CF |
52 | } |
53 | qemu_wait_io_event_common(cpu); | |
54 | } while (!cpu->unplug || cpu_can_run(cpu)); | |
55 | ||
56 | whpx_destroy_vcpu(cpu); | |
57 | cpu_thread_signal_destroyed(cpu); | |
195801d7 | 58 | bql_unlock(); |
8ef39ecf CF |
59 | rcu_unregister_thread(); |
60 | return NULL; | |
61 | } | |
62 | ||
63 | static void whpx_start_vcpu_thread(CPUState *cpu) | |
64 | { | |
65 | char thread_name[VCPU_THREAD_NAME_SIZE]; | |
66 | ||
b21e2380 MA |
67 | cpu->thread = g_new0(QemuThread, 1); |
68 | cpu->halt_cond = g_new0(QemuCond, 1); | |
8ef39ecf CF |
69 | qemu_cond_init(cpu->halt_cond); |
70 | snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/WHPX", | |
71 | cpu->cpu_index); | |
72 | qemu_thread_create(cpu->thread, thread_name, whpx_cpu_thread_fn, | |
73 | cpu, QEMU_THREAD_JOINABLE); | |
8ef39ecf CF |
74 | } |
75 | ||
76 | static void whpx_kick_vcpu_thread(CPUState *cpu) | |
77 | { | |
78 | if (!qemu_cpu_is_self(cpu)) { | |
79 | whpx_vcpu_kick(cpu); | |
80 | } | |
81 | } | |
82 | ||
ad7d684d PMD |
83 | static bool whpx_vcpu_thread_is_idle(CPUState *cpu) |
84 | { | |
85 | return !whpx_apic_in_platform(); | |
86 | } | |
87 | ||
b86f59c7 CF |
88 | static void whpx_accel_ops_class_init(ObjectClass *oc, void *data) |
89 | { | |
90 | AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); | |
91 | ||
92 | ops->create_vcpu_thread = whpx_start_vcpu_thread; | |
93 | ops->kick_vcpu_thread = whpx_kick_vcpu_thread; | |
ad7d684d | 94 | ops->cpu_thread_is_idle = whpx_vcpu_thread_is_idle; |
b86f59c7 CF |
95 | |
96 | ops->synchronize_post_reset = whpx_cpu_synchronize_post_reset; | |
97 | ops->synchronize_post_init = whpx_cpu_synchronize_post_init; | |
98 | ops->synchronize_state = whpx_cpu_synchronize_state; | |
99 | ops->synchronize_pre_loadvm = whpx_cpu_synchronize_pre_loadvm; | |
d7482ffe | 100 | ops->synchronize_pre_resume = whpx_cpu_synchronize_pre_resume; |
b86f59c7 | 101 | } |
8ef39ecf | 102 | |
b86f59c7 CF |
103 | static const TypeInfo whpx_accel_ops_type = { |
104 | .name = ACCEL_OPS_NAME("whpx"), | |
105 | ||
106 | .parent = TYPE_ACCEL_OPS, | |
107 | .class_init = whpx_accel_ops_class_init, | |
108 | .abstract = true, | |
8ef39ecf | 109 | }; |
b86f59c7 CF |
110 | |
111 | static void whpx_accel_ops_register_types(void) | |
112 | { | |
113 | type_register_static(&whpx_accel_ops_type); | |
114 | } | |
115 | type_init(whpx_accel_ops_register_types); |