xref: /qemu/accel/hvf/hvf-accel-ops.c (revision cc3d262aa93a42e19c38f6acb6d0f6012a71eb4b)
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/error-report.h"
52 #include "qemu/main-loop.h"
53 #include "exec/address-spaces.h"
54 #include "exec/exec-all.h"
55 #include "gdbstub/enums.h"
56 #include "hw/boards.h"
57 #include "system/accel-ops.h"
58 #include "system/cpus.h"
59 #include "system/hvf.h"
60 #include "system/hvf_int.h"
61 #include "system/runstate.h"
62 #include "qemu/guest-random.h"
63 
64 HVFState *hvf_state;
65 
66 /* Memory slots */
67 
68 hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
69 {
70     hvf_slot *slot;
71     int x;
72     for (x = 0; x < hvf_state->num_slots; ++x) {
73         slot = &hvf_state->slots[x];
74         if (slot->size && start < (slot->start + slot->size) &&
75             (start + size) > slot->start) {
76             return slot;
77         }
78     }
79     return NULL;
80 }
81 
82 struct mac_slot {
83     int present;
84     uint64_t size;
85     uint64_t gpa_start;
86     uint64_t gva;
87 };
88 
89 struct mac_slot mac_slots[32];
90 
91 static int do_hvf_set_memory(hvf_slot *slot, hv_memory_flags_t flags)
92 {
93     struct mac_slot *macslot;
94     hv_return_t ret;
95 
96     macslot = &mac_slots[slot->slot_id];
97 
98     if (macslot->present) {
99         if (macslot->size != slot->size) {
100             macslot->present = 0;
101             ret = hv_vm_unmap(macslot->gpa_start, macslot->size);
102             assert_hvf_ok(ret);
103         }
104     }
105 
106     if (!slot->size) {
107         return 0;
108     }
109 
110     macslot->present = 1;
111     macslot->gpa_start = slot->start;
112     macslot->size = slot->size;
113     ret = hv_vm_map(slot->mem, slot->start, slot->size, flags);
114     assert_hvf_ok(ret);
115     return 0;
116 }
117 
118 static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
119 {
120     hvf_slot *mem;
121     MemoryRegion *area = section->mr;
122     bool writable = !area->readonly && !area->rom_device;
123     hv_memory_flags_t flags;
124     uint64_t page_size = qemu_real_host_page_size();
125 
126     if (!memory_region_is_ram(area)) {
127         if (writable) {
128             return;
129         } else if (!memory_region_is_romd(area)) {
130             /*
131              * If the memory device is not in romd_mode, then we actually want
132              * to remove the hvf memory slot so all accesses will trap.
133              */
134              add = false;
135         }
136     }
137 
138     if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) ||
139         !QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) {
140         /* Not page aligned, so we can not map as RAM */
141         add = false;
142     }
143 
144     mem = hvf_find_overlap_slot(
145             section->offset_within_address_space,
146             int128_get64(section->size));
147 
148     if (mem && add) {
149         if (mem->size == int128_get64(section->size) &&
150             mem->start == section->offset_within_address_space &&
151             mem->mem == (memory_region_get_ram_ptr(area) +
152             section->offset_within_region)) {
153             return; /* Same region was attempted to register, go away. */
154         }
155     }
156 
157     /* Region needs to be reset. set the size to 0 and remap it. */
158     if (mem) {
159         mem->size = 0;
160         if (do_hvf_set_memory(mem, 0)) {
161             error_report("Failed to reset overlapping slot");
162             abort();
163         }
164     }
165 
166     if (!add) {
167         return;
168     }
169 
170     if (area->readonly ||
171         (!memory_region_is_ram(area) && memory_region_is_romd(area))) {
172         flags = HV_MEMORY_READ | HV_MEMORY_EXEC;
173     } else {
174         flags = HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC;
175     }
176 
177     /* Now make a new slot. */
178     int x;
179 
180     for (x = 0; x < hvf_state->num_slots; ++x) {
181         mem = &hvf_state->slots[x];
182         if (!mem->size) {
183             break;
184         }
185     }
186 
187     if (x == hvf_state->num_slots) {
188         error_report("No free slots");
189         abort();
190     }
191 
192     mem->size = int128_get64(section->size);
193     mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
194     mem->start = section->offset_within_address_space;
195     mem->region = area;
196 
197     if (do_hvf_set_memory(mem, flags)) {
198         error_report("Error registering new memory slot");
199         abort();
200     }
201 }
202 
203 static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
204 {
205     if (!cpu->accel->dirty) {
206         hvf_get_registers(cpu);
207         cpu->accel->dirty = true;
208     }
209 }
210 
211 static void hvf_cpu_synchronize_state(CPUState *cpu)
212 {
213     if (!cpu->accel->dirty) {
214         run_on_cpu(cpu, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL);
215     }
216 }
217 
218 static void do_hvf_cpu_synchronize_set_dirty(CPUState *cpu,
219                                              run_on_cpu_data arg)
220 {
221     /* QEMU state is the reference, push it to HVF now and on next entry */
222     cpu->accel->dirty = true;
223 }
224 
225 static void hvf_cpu_synchronize_post_reset(CPUState *cpu)
226 {
227     run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
228 }
229 
230 static void hvf_cpu_synchronize_post_init(CPUState *cpu)
231 {
232     run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
233 }
234 
235 static void hvf_cpu_synchronize_pre_loadvm(CPUState *cpu)
236 {
237     run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
238 }
239 
240 static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
241 {
242     hvf_slot *slot;
243 
244     slot = hvf_find_overlap_slot(
245             section->offset_within_address_space,
246             int128_get64(section->size));
247 
248     /* protect region against writes; begin tracking it */
249     if (on) {
250         slot->flags |= HVF_SLOT_LOG;
251         hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
252                       HV_MEMORY_READ | HV_MEMORY_EXEC);
253     /* stop tracking region*/
254     } else {
255         slot->flags &= ~HVF_SLOT_LOG;
256         hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
257                       HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC);
258     }
259 }
260 
261 static void hvf_log_start(MemoryListener *listener,
262                           MemoryRegionSection *section, int old, int new)
263 {
264     if (old != 0) {
265         return;
266     }
267 
268     hvf_set_dirty_tracking(section, 1);
269 }
270 
271 static void hvf_log_stop(MemoryListener *listener,
272                          MemoryRegionSection *section, int old, int new)
273 {
274     if (new != 0) {
275         return;
276     }
277 
278     hvf_set_dirty_tracking(section, 0);
279 }
280 
281 static void hvf_log_sync(MemoryListener *listener,
282                          MemoryRegionSection *section)
283 {
284     /*
285      * sync of dirty pages is handled elsewhere; just make sure we keep
286      * tracking the region.
287      */
288     hvf_set_dirty_tracking(section, 1);
289 }
290 
291 static void hvf_region_add(MemoryListener *listener,
292                            MemoryRegionSection *section)
293 {
294     hvf_set_phys_mem(section, true);
295 }
296 
297 static void hvf_region_del(MemoryListener *listener,
298                            MemoryRegionSection *section)
299 {
300     hvf_set_phys_mem(section, false);
301 }
302 
303 static MemoryListener hvf_memory_listener = {
304     .name = "hvf",
305     .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
306     .region_add = hvf_region_add,
307     .region_del = hvf_region_del,
308     .log_start = hvf_log_start,
309     .log_stop = hvf_log_stop,
310     .log_sync = hvf_log_sync,
311 };
312 
313 static void dummy_signal(int sig)
314 {
315 }
316 
317 bool hvf_allowed;
318 
319 static int hvf_accel_init(MachineState *ms)
320 {
321     int x;
322     hv_return_t ret;
323     HVFState *s;
324     int pa_range = 36;
325     MachineClass *mc = MACHINE_GET_CLASS(ms);
326 
327     if (mc->hvf_get_physical_address_range) {
328         pa_range = mc->hvf_get_physical_address_range(ms);
329         if (pa_range < 0) {
330             return -EINVAL;
331         }
332     }
333 
334     ret = hvf_arch_vm_create(ms, (uint32_t)pa_range);
335     assert_hvf_ok(ret);
336 
337     s = g_new0(HVFState, 1);
338 
339     s->num_slots = ARRAY_SIZE(s->slots);
340     for (x = 0; x < s->num_slots; ++x) {
341         s->slots[x].size = 0;
342         s->slots[x].slot_id = x;
343     }
344 
345     QTAILQ_INIT(&s->hvf_sw_breakpoints);
346 
347     hvf_state = s;
348     memory_listener_register(&hvf_memory_listener, &address_space_memory);
349 
350     return hvf_arch_init();
351 }
352 
353 static inline int hvf_gdbstub_sstep_flags(void)
354 {
355     return SSTEP_ENABLE | SSTEP_NOIRQ;
356 }
357 
358 static void hvf_accel_class_init(ObjectClass *oc, void *data)
359 {
360     AccelClass *ac = ACCEL_CLASS(oc);
361     ac->name = "HVF";
362     ac->init_machine = hvf_accel_init;
363     ac->allowed = &hvf_allowed;
364     ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags;
365 }
366 
367 static const TypeInfo hvf_accel_type = {
368     .name = TYPE_HVF_ACCEL,
369     .parent = TYPE_ACCEL,
370     .class_init = hvf_accel_class_init,
371 };
372 
373 static void hvf_type_init(void)
374 {
375     type_register_static(&hvf_accel_type);
376 }
377 
378 type_init(hvf_type_init);
379 
380 static void hvf_vcpu_destroy(CPUState *cpu)
381 {
382     hv_return_t ret = hv_vcpu_destroy(cpu->accel->fd);
383     assert_hvf_ok(ret);
384 
385     hvf_arch_vcpu_destroy(cpu);
386     g_free(cpu->accel);
387     cpu->accel = NULL;
388 }
389 
390 static int hvf_init_vcpu(CPUState *cpu)
391 {
392     int r;
393 
394     cpu->accel = g_new0(AccelCPUState, 1);
395 
396     /* init cpu signals */
397     struct sigaction sigact;
398 
399     memset(&sigact, 0, sizeof(sigact));
400     sigact.sa_handler = dummy_signal;
401     sigaction(SIG_IPI, &sigact, NULL);
402 
403     pthread_sigmask(SIG_BLOCK, NULL, &cpu->accel->unblock_ipi_mask);
404     sigdelset(&cpu->accel->unblock_ipi_mask, SIG_IPI);
405 
406 #ifdef __aarch64__
407     r = hv_vcpu_create(&cpu->accel->fd,
408                        (hv_vcpu_exit_t **)&cpu->accel->exit, NULL);
409 #else
410     r = hv_vcpu_create(&cpu->accel->fd, HV_VCPU_DEFAULT);
411 #endif
412     cpu->accel->dirty = true;
413     assert_hvf_ok(r);
414 
415     cpu->accel->guest_debug_enabled = false;
416 
417     return hvf_arch_init_vcpu(cpu);
418 }
419 
420 /*
421  * The HVF-specific vCPU thread function. This one should only run when the host
422  * CPU supports the VMX "unrestricted guest" feature.
423  */
424 static void *hvf_cpu_thread_fn(void *arg)
425 {
426     CPUState *cpu = arg;
427 
428     int r;
429 
430     assert(hvf_enabled());
431 
432     rcu_register_thread();
433 
434     bql_lock();
435     qemu_thread_get_self(cpu->thread);
436 
437     cpu->thread_id = qemu_get_thread_id();
438     current_cpu = cpu;
439 
440     hvf_init_vcpu(cpu);
441 
442     /* signal CPU creation */
443     cpu_thread_signal_created(cpu);
444     qemu_guest_random_seed_thread_part2(cpu->random_seed);
445 
446     do {
447         if (cpu_can_run(cpu)) {
448             r = hvf_vcpu_exec(cpu);
449             if (r == EXCP_DEBUG) {
450                 cpu_handle_guest_debug(cpu);
451             }
452         }
453         qemu_wait_io_event(cpu);
454     } while (!cpu->unplug || cpu_can_run(cpu));
455 
456     hvf_vcpu_destroy(cpu);
457     cpu_thread_signal_destroyed(cpu);
458     bql_unlock();
459     rcu_unregister_thread();
460     return NULL;
461 }
462 
463 static void hvf_start_vcpu_thread(CPUState *cpu)
464 {
465     char thread_name[VCPU_THREAD_NAME_SIZE];
466 
467     /*
468      * HVF currently does not support TCG, and only runs in
469      * unrestricted-guest mode.
470      */
471     assert(hvf_enabled());
472 
473     snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/HVF",
474              cpu->cpu_index);
475     qemu_thread_create(cpu->thread, thread_name, hvf_cpu_thread_fn,
476                        cpu, QEMU_THREAD_JOINABLE);
477 }
478 
479 static int hvf_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len)
480 {
481     struct hvf_sw_breakpoint *bp;
482     int err;
483 
484     if (type == GDB_BREAKPOINT_SW) {
485         bp = hvf_find_sw_breakpoint(cpu, addr);
486         if (bp) {
487             bp->use_count++;
488             return 0;
489         }
490 
491         bp = g_new(struct hvf_sw_breakpoint, 1);
492         bp->pc = addr;
493         bp->use_count = 1;
494         err = hvf_arch_insert_sw_breakpoint(cpu, bp);
495         if (err) {
496             g_free(bp);
497             return err;
498         }
499 
500         QTAILQ_INSERT_HEAD(&hvf_state->hvf_sw_breakpoints, bp, entry);
501     } else {
502         err = hvf_arch_insert_hw_breakpoint(addr, len, type);
503         if (err) {
504             return err;
505         }
506     }
507 
508     CPU_FOREACH(cpu) {
509         err = hvf_update_guest_debug(cpu);
510         if (err) {
511             return err;
512         }
513     }
514     return 0;
515 }
516 
517 static int hvf_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len)
518 {
519     struct hvf_sw_breakpoint *bp;
520     int err;
521 
522     if (type == GDB_BREAKPOINT_SW) {
523         bp = hvf_find_sw_breakpoint(cpu, addr);
524         if (!bp) {
525             return -ENOENT;
526         }
527 
528         if (bp->use_count > 1) {
529             bp->use_count--;
530             return 0;
531         }
532 
533         err = hvf_arch_remove_sw_breakpoint(cpu, bp);
534         if (err) {
535             return err;
536         }
537 
538         QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry);
539         g_free(bp);
540     } else {
541         err = hvf_arch_remove_hw_breakpoint(addr, len, type);
542         if (err) {
543             return err;
544         }
545     }
546 
547     CPU_FOREACH(cpu) {
548         err = hvf_update_guest_debug(cpu);
549         if (err) {
550             return err;
551         }
552     }
553     return 0;
554 }
555 
556 static void hvf_remove_all_breakpoints(CPUState *cpu)
557 {
558     struct hvf_sw_breakpoint *bp, *next;
559     CPUState *tmpcpu;
560 
561     QTAILQ_FOREACH_SAFE(bp, &hvf_state->hvf_sw_breakpoints, entry, next) {
562         if (hvf_arch_remove_sw_breakpoint(cpu, bp) != 0) {
563             /* Try harder to find a CPU that currently sees the breakpoint. */
564             CPU_FOREACH(tmpcpu)
565             {
566                 if (hvf_arch_remove_sw_breakpoint(tmpcpu, bp) == 0) {
567                     break;
568                 }
569             }
570         }
571         QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry);
572         g_free(bp);
573     }
574     hvf_arch_remove_all_hw_breakpoints();
575 
576     CPU_FOREACH(cpu) {
577         hvf_update_guest_debug(cpu);
578     }
579 }
580 
581 static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
582 {
583     AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
584 
585     ops->create_vcpu_thread = hvf_start_vcpu_thread;
586     ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
587 
588     ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
589     ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
590     ops->synchronize_state = hvf_cpu_synchronize_state;
591     ops->synchronize_pre_loadvm = hvf_cpu_synchronize_pre_loadvm;
592 
593     ops->insert_breakpoint = hvf_insert_breakpoint;
594     ops->remove_breakpoint = hvf_remove_breakpoint;
595     ops->remove_all_breakpoints = hvf_remove_all_breakpoints;
596     ops->update_guest_debug = hvf_update_guest_debug;
597     ops->supports_guest_debug = hvf_arch_supports_guest_debug;
598 };
599 static const TypeInfo hvf_accel_ops_type = {
600     .name = ACCEL_OPS_NAME("hvf"),
601 
602     .parent = TYPE_ACCEL_OPS,
603     .class_init = hvf_accel_ops_class_init,
604     .abstract = true,
605 };
606 static void hvf_accel_ops_register_types(void)
607 {
608     type_register_static(&hvf_accel_ops_type);
609 }
610 type_init(hvf_accel_ops_register_types);
611