xref: /qemu/accel/hvf/hvf-accel-ops.c (revision a8b5c10c7147ebc992de12fdc3f25a219f5c742f)
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 "system/address-spaces.h"
54 #include "gdbstub/enums.h"
55 #include "hw/boards.h"
56 #include "system/accel-ops.h"
57 #include "system/cpus.h"
58 #include "system/hvf.h"
59 #include "system/hvf_int.h"
60 #include "system/runstate.h"
61 #include "qemu/guest-random.h"
62 
63 HVFState *hvf_state;
64 
65 /* Memory slots */
66 
hvf_find_overlap_slot(uint64_t start,uint64_t size)67 hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
68 {
69     hvf_slot *slot;
70     int x;
71     for (x = 0; x < hvf_state->num_slots; ++x) {
72         slot = &hvf_state->slots[x];
73         if (slot->size && start < (slot->start + slot->size) &&
74             (start + size) > slot->start) {
75             return slot;
76         }
77     }
78     return NULL;
79 }
80 
81 struct mac_slot {
82     int present;
83     uint64_t size;
84     uint64_t gpa_start;
85     uint64_t gva;
86 };
87 
88 struct mac_slot mac_slots[32];
89 
do_hvf_set_memory(hvf_slot * slot,hv_memory_flags_t flags)90 static int do_hvf_set_memory(hvf_slot *slot, hv_memory_flags_t flags)
91 {
92     struct mac_slot *macslot;
93     hv_return_t ret;
94 
95     macslot = &mac_slots[slot->slot_id];
96 
97     if (macslot->present) {
98         if (macslot->size != slot->size) {
99             macslot->present = 0;
100             ret = hv_vm_unmap(macslot->gpa_start, macslot->size);
101             assert_hvf_ok(ret);
102         }
103     }
104 
105     if (!slot->size) {
106         return 0;
107     }
108 
109     macslot->present = 1;
110     macslot->gpa_start = slot->start;
111     macslot->size = slot->size;
112     ret = hv_vm_map(slot->mem, slot->start, slot->size, flags);
113     assert_hvf_ok(ret);
114     return 0;
115 }
116 
hvf_set_phys_mem(MemoryRegionSection * section,bool add)117 static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
118 {
119     hvf_slot *mem;
120     MemoryRegion *area = section->mr;
121     bool writable = !area->readonly && !area->rom_device;
122     hv_memory_flags_t flags;
123     uint64_t page_size = qemu_real_host_page_size();
124 
125     if (!memory_region_is_ram(area)) {
126         if (writable) {
127             return;
128         } else if (!memory_region_is_romd(area)) {
129             /*
130              * If the memory device is not in romd_mode, then we actually want
131              * to remove the hvf memory slot so all accesses will trap.
132              */
133              add = false;
134         }
135     }
136 
137     if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) ||
138         !QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) {
139         /* Not page aligned, so we can not map as RAM */
140         add = false;
141     }
142 
143     mem = hvf_find_overlap_slot(
144             section->offset_within_address_space,
145             int128_get64(section->size));
146 
147     if (mem && add) {
148         if (mem->size == int128_get64(section->size) &&
149             mem->start == section->offset_within_address_space &&
150             mem->mem == (memory_region_get_ram_ptr(area) +
151             section->offset_within_region)) {
152             return; /* Same region was attempted to register, go away. */
153         }
154     }
155 
156     /* Region needs to be reset. set the size to 0 and remap it. */
157     if (mem) {
158         mem->size = 0;
159         if (do_hvf_set_memory(mem, 0)) {
160             error_report("Failed to reset overlapping slot");
161             abort();
162         }
163     }
164 
165     if (!add) {
166         return;
167     }
168 
169     if (area->readonly ||
170         (!memory_region_is_ram(area) && memory_region_is_romd(area))) {
171         flags = HV_MEMORY_READ | HV_MEMORY_EXEC;
172     } else {
173         flags = HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC;
174     }
175 
176     /* Now make a new slot. */
177     int x;
178 
179     for (x = 0; x < hvf_state->num_slots; ++x) {
180         mem = &hvf_state->slots[x];
181         if (!mem->size) {
182             break;
183         }
184     }
185 
186     if (x == hvf_state->num_slots) {
187         error_report("No free slots");
188         abort();
189     }
190 
191     mem->size = int128_get64(section->size);
192     mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
193     mem->start = section->offset_within_address_space;
194     mem->region = area;
195 
196     if (do_hvf_set_memory(mem, flags)) {
197         error_report("Error registering new memory slot");
198         abort();
199     }
200 }
201 
do_hvf_cpu_synchronize_state(CPUState * cpu,run_on_cpu_data arg)202 static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
203 {
204     if (!cpu->accel->dirty) {
205         hvf_get_registers(cpu);
206         cpu->accel->dirty = true;
207     }
208 }
209 
hvf_cpu_synchronize_state(CPUState * cpu)210 static void hvf_cpu_synchronize_state(CPUState *cpu)
211 {
212     if (!cpu->accel->dirty) {
213         run_on_cpu(cpu, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL);
214     }
215 }
216 
do_hvf_cpu_synchronize_set_dirty(CPUState * cpu,run_on_cpu_data arg)217 static void do_hvf_cpu_synchronize_set_dirty(CPUState *cpu,
218                                              run_on_cpu_data arg)
219 {
220     /* QEMU state is the reference, push it to HVF now and on next entry */
221     cpu->accel->dirty = true;
222 }
223 
hvf_cpu_synchronize_post_reset(CPUState * cpu)224 static void hvf_cpu_synchronize_post_reset(CPUState *cpu)
225 {
226     run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
227 }
228 
hvf_cpu_synchronize_post_init(CPUState * cpu)229 static void hvf_cpu_synchronize_post_init(CPUState *cpu)
230 {
231     run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
232 }
233 
hvf_cpu_synchronize_pre_loadvm(CPUState * cpu)234 static void hvf_cpu_synchronize_pre_loadvm(CPUState *cpu)
235 {
236     run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
237 }
238 
hvf_set_dirty_tracking(MemoryRegionSection * section,bool on)239 static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
240 {
241     hvf_slot *slot;
242 
243     slot = hvf_find_overlap_slot(
244             section->offset_within_address_space,
245             int128_get64(section->size));
246 
247     /* protect region against writes; begin tracking it */
248     if (on) {
249         slot->flags |= HVF_SLOT_LOG;
250         hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
251                       HV_MEMORY_READ | HV_MEMORY_EXEC);
252     /* stop tracking region*/
253     } else {
254         slot->flags &= ~HVF_SLOT_LOG;
255         hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
256                       HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC);
257     }
258 }
259 
hvf_log_start(MemoryListener * listener,MemoryRegionSection * section,int old,int new)260 static void hvf_log_start(MemoryListener *listener,
261                           MemoryRegionSection *section, int old, int new)
262 {
263     if (old != 0) {
264         return;
265     }
266 
267     hvf_set_dirty_tracking(section, 1);
268 }
269 
hvf_log_stop(MemoryListener * listener,MemoryRegionSection * section,int old,int new)270 static void hvf_log_stop(MemoryListener *listener,
271                          MemoryRegionSection *section, int old, int new)
272 {
273     if (new != 0) {
274         return;
275     }
276 
277     hvf_set_dirty_tracking(section, 0);
278 }
279 
hvf_log_sync(MemoryListener * listener,MemoryRegionSection * section)280 static void hvf_log_sync(MemoryListener *listener,
281                          MemoryRegionSection *section)
282 {
283     /*
284      * sync of dirty pages is handled elsewhere; just make sure we keep
285      * tracking the region.
286      */
287     hvf_set_dirty_tracking(section, 1);
288 }
289 
hvf_region_add(MemoryListener * listener,MemoryRegionSection * section)290 static void hvf_region_add(MemoryListener *listener,
291                            MemoryRegionSection *section)
292 {
293     hvf_set_phys_mem(section, true);
294 }
295 
hvf_region_del(MemoryListener * listener,MemoryRegionSection * section)296 static void hvf_region_del(MemoryListener *listener,
297                            MemoryRegionSection *section)
298 {
299     hvf_set_phys_mem(section, false);
300 }
301 
302 static MemoryListener hvf_memory_listener = {
303     .name = "hvf",
304     .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
305     .region_add = hvf_region_add,
306     .region_del = hvf_region_del,
307     .log_start = hvf_log_start,
308     .log_stop = hvf_log_stop,
309     .log_sync = hvf_log_sync,
310 };
311 
dummy_signal(int sig)312 static void dummy_signal(int sig)
313 {
314 }
315 
316 bool hvf_allowed;
317 
hvf_accel_init(MachineState * ms)318 static int hvf_accel_init(MachineState *ms)
319 {
320     int x;
321     hv_return_t ret;
322     HVFState *s;
323     int pa_range = 36;
324     MachineClass *mc = MACHINE_GET_CLASS(ms);
325 
326     if (mc->hvf_get_physical_address_range) {
327         pa_range = mc->hvf_get_physical_address_range(ms);
328         if (pa_range < 0) {
329             return -EINVAL;
330         }
331     }
332 
333     ret = hvf_arch_vm_create(ms, (uint32_t)pa_range);
334     assert_hvf_ok(ret);
335 
336     s = g_new0(HVFState, 1);
337 
338     s->num_slots = ARRAY_SIZE(s->slots);
339     for (x = 0; x < s->num_slots; ++x) {
340         s->slots[x].size = 0;
341         s->slots[x].slot_id = x;
342     }
343 
344     QTAILQ_INIT(&s->hvf_sw_breakpoints);
345 
346     hvf_state = s;
347     memory_listener_register(&hvf_memory_listener, &address_space_memory);
348 
349     return hvf_arch_init();
350 }
351 
hvf_gdbstub_sstep_flags(void)352 static inline int hvf_gdbstub_sstep_flags(void)
353 {
354     return SSTEP_ENABLE | SSTEP_NOIRQ;
355 }
356 
hvf_accel_class_init(ObjectClass * oc,const void * data)357 static void hvf_accel_class_init(ObjectClass *oc, const void *data)
358 {
359     AccelClass *ac = ACCEL_CLASS(oc);
360     ac->name = "HVF";
361     ac->init_machine = hvf_accel_init;
362     ac->allowed = &hvf_allowed;
363     ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags;
364 }
365 
366 static const TypeInfo hvf_accel_type = {
367     .name = TYPE_HVF_ACCEL,
368     .parent = TYPE_ACCEL,
369     .instance_size = sizeof(HVFState),
370     .class_init = hvf_accel_class_init,
371 };
372 
hvf_type_init(void)373 static void hvf_type_init(void)
374 {
375     type_register_static(&hvf_accel_type);
376 }
377 
378 type_init(hvf_type_init);
379 
hvf_vcpu_destroy(CPUState * cpu)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 
hvf_init_vcpu(CPUState * cpu)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  */
hvf_cpu_thread_fn(void * arg)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 
hvf_start_vcpu_thread(CPUState * cpu)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 
hvf_insert_breakpoint(CPUState * cpu,int type,vaddr addr,vaddr len)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 
hvf_remove_breakpoint(CPUState * cpu,int type,vaddr addr,vaddr len)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 
hvf_remove_all_breakpoints(CPUState * cpu)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 
hvf_accel_ops_class_init(ObjectClass * oc,const void * data)581 static void hvf_accel_ops_class_init(ObjectClass *oc, const 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 };
hvf_accel_ops_register_types(void)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