xref: /openbmc/qemu/accel/hvf/hvf-accel-ops.c (revision 6fdc5bc1)
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 "sysemu/cpus.h"
58 #include "sysemu/hvf.h"
59 #include "sysemu/hvf_int.h"
60 #include "sysemu/runstate.h"
61 #include "qemu/guest-random.h"
62 
63 HVFState *hvf_state;
64 
65 /* Memory slots */
66 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
290 static void hvf_region_add(MemoryListener *listener,
291                            MemoryRegionSection *section)
292 {
293     hvf_set_phys_mem(section, true);
294 }
295 
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 
312 static void dummy_signal(int sig)
313 {
314 }
315 
316 bool hvf_allowed;
317 
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 
352 static inline int hvf_gdbstub_sstep_flags(void)
353 {
354     return SSTEP_ENABLE | SSTEP_NOIRQ;
355 }
356 
357 static void hvf_accel_class_init(ObjectClass *oc, 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     .class_init = hvf_accel_class_init,
370 };
371 
372 static void hvf_type_init(void)
373 {
374     type_register_static(&hvf_accel_type);
375 }
376 
377 type_init(hvf_type_init);
378 
379 static void hvf_vcpu_destroy(CPUState *cpu)
380 {
381     hv_return_t ret = hv_vcpu_destroy(cpu->accel->fd);
382     assert_hvf_ok(ret);
383 
384     hvf_arch_vcpu_destroy(cpu);
385     g_free(cpu->accel);
386     cpu->accel = NULL;
387 }
388 
389 static int hvf_init_vcpu(CPUState *cpu)
390 {
391     int r;
392 
393     cpu->accel = g_new0(AccelCPUState, 1);
394 
395     /* init cpu signals */
396     struct sigaction sigact;
397 
398     memset(&sigact, 0, sizeof(sigact));
399     sigact.sa_handler = dummy_signal;
400     sigaction(SIG_IPI, &sigact, NULL);
401 
402     pthread_sigmask(SIG_BLOCK, NULL, &cpu->accel->unblock_ipi_mask);
403     sigdelset(&cpu->accel->unblock_ipi_mask, SIG_IPI);
404 
405 #ifdef __aarch64__
406     r = hv_vcpu_create(&cpu->accel->fd,
407                        (hv_vcpu_exit_t **)&cpu->accel->exit, NULL);
408 #else
409     r = hv_vcpu_create(&cpu->accel->fd, HV_VCPU_DEFAULT);
410 #endif
411     cpu->accel->dirty = true;
412     assert_hvf_ok(r);
413 
414     cpu->accel->guest_debug_enabled = false;
415 
416     return hvf_arch_init_vcpu(cpu);
417 }
418 
419 /*
420  * The HVF-specific vCPU thread function. This one should only run when the host
421  * CPU supports the VMX "unrestricted guest" feature.
422  */
423 static void *hvf_cpu_thread_fn(void *arg)
424 {
425     CPUState *cpu = arg;
426 
427     int r;
428 
429     assert(hvf_enabled());
430 
431     rcu_register_thread();
432 
433     bql_lock();
434     qemu_thread_get_self(cpu->thread);
435 
436     cpu->thread_id = qemu_get_thread_id();
437     current_cpu = cpu;
438 
439     hvf_init_vcpu(cpu);
440 
441     /* signal CPU creation */
442     cpu_thread_signal_created(cpu);
443     qemu_guest_random_seed_thread_part2(cpu->random_seed);
444 
445     do {
446         if (cpu_can_run(cpu)) {
447             r = hvf_vcpu_exec(cpu);
448             if (r == EXCP_DEBUG) {
449                 cpu_handle_guest_debug(cpu);
450             }
451         }
452         qemu_wait_io_event(cpu);
453     } while (!cpu->unplug || cpu_can_run(cpu));
454 
455     hvf_vcpu_destroy(cpu);
456     cpu_thread_signal_destroyed(cpu);
457     bql_unlock();
458     rcu_unregister_thread();
459     return NULL;
460 }
461 
462 static void hvf_start_vcpu_thread(CPUState *cpu)
463 {
464     char thread_name[VCPU_THREAD_NAME_SIZE];
465 
466     /*
467      * HVF currently does not support TCG, and only runs in
468      * unrestricted-guest mode.
469      */
470     assert(hvf_enabled());
471 
472     snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/HVF",
473              cpu->cpu_index);
474     qemu_thread_create(cpu->thread, thread_name, hvf_cpu_thread_fn,
475                        cpu, QEMU_THREAD_JOINABLE);
476 }
477 
478 static int hvf_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len)
479 {
480     struct hvf_sw_breakpoint *bp;
481     int err;
482 
483     if (type == GDB_BREAKPOINT_SW) {
484         bp = hvf_find_sw_breakpoint(cpu, addr);
485         if (bp) {
486             bp->use_count++;
487             return 0;
488         }
489 
490         bp = g_new(struct hvf_sw_breakpoint, 1);
491         bp->pc = addr;
492         bp->use_count = 1;
493         err = hvf_arch_insert_sw_breakpoint(cpu, bp);
494         if (err) {
495             g_free(bp);
496             return err;
497         }
498 
499         QTAILQ_INSERT_HEAD(&hvf_state->hvf_sw_breakpoints, bp, entry);
500     } else {
501         err = hvf_arch_insert_hw_breakpoint(addr, len, type);
502         if (err) {
503             return err;
504         }
505     }
506 
507     CPU_FOREACH(cpu) {
508         err = hvf_update_guest_debug(cpu);
509         if (err) {
510             return err;
511         }
512     }
513     return 0;
514 }
515 
516 static int hvf_remove_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len)
517 {
518     struct hvf_sw_breakpoint *bp;
519     int err;
520 
521     if (type == GDB_BREAKPOINT_SW) {
522         bp = hvf_find_sw_breakpoint(cpu, addr);
523         if (!bp) {
524             return -ENOENT;
525         }
526 
527         if (bp->use_count > 1) {
528             bp->use_count--;
529             return 0;
530         }
531 
532         err = hvf_arch_remove_sw_breakpoint(cpu, bp);
533         if (err) {
534             return err;
535         }
536 
537         QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry);
538         g_free(bp);
539     } else {
540         err = hvf_arch_remove_hw_breakpoint(addr, len, type);
541         if (err) {
542             return err;
543         }
544     }
545 
546     CPU_FOREACH(cpu) {
547         err = hvf_update_guest_debug(cpu);
548         if (err) {
549             return err;
550         }
551     }
552     return 0;
553 }
554 
555 static void hvf_remove_all_breakpoints(CPUState *cpu)
556 {
557     struct hvf_sw_breakpoint *bp, *next;
558     CPUState *tmpcpu;
559 
560     QTAILQ_FOREACH_SAFE(bp, &hvf_state->hvf_sw_breakpoints, entry, next) {
561         if (hvf_arch_remove_sw_breakpoint(cpu, bp) != 0) {
562             /* Try harder to find a CPU that currently sees the breakpoint. */
563             CPU_FOREACH(tmpcpu)
564             {
565                 if (hvf_arch_remove_sw_breakpoint(tmpcpu, bp) == 0) {
566                     break;
567                 }
568             }
569         }
570         QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry);
571         g_free(bp);
572     }
573     hvf_arch_remove_all_hw_breakpoints();
574 
575     CPU_FOREACH(cpu) {
576         hvf_update_guest_debug(cpu);
577     }
578 }
579 
580 static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
581 {
582     AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
583 
584     ops->create_vcpu_thread = hvf_start_vcpu_thread;
585     ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
586 
587     ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
588     ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
589     ops->synchronize_state = hvf_cpu_synchronize_state;
590     ops->synchronize_pre_loadvm = hvf_cpu_synchronize_pre_loadvm;
591 
592     ops->insert_breakpoint = hvf_insert_breakpoint;
593     ops->remove_breakpoint = hvf_remove_breakpoint;
594     ops->remove_all_breakpoints = hvf_remove_all_breakpoints;
595     ops->update_guest_debug = hvf_update_guest_debug;
596     ops->supports_guest_debug = hvf_arch_supports_guest_debug;
597 };
598 static const TypeInfo hvf_accel_ops_type = {
599     .name = ACCEL_OPS_NAME("hvf"),
600 
601     .parent = TYPE_ACCEL_OPS,
602     .class_init = hvf_accel_ops_class_init,
603     .abstract = true,
604 };
605 static void hvf_accel_ops_register_types(void)
606 {
607     type_register_static(&hvf_accel_ops_type);
608 }
609 type_init(hvf_accel_ops_register_types);
610