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