mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-12-11 16:00:50 -07:00
Accelerators patches
- Generic API consolidation, cleanups (dead code removal, documentation added) - Remove monitor TCG 'info opcount' and @x-query-opcount - Have HVF / NVMM / WHPX use generic CPUState::vcpu_dirty field - Expose nvmm_enabled() and whpx_enabled() to common code - Have hmp_info_registers() dump vector registers -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmhnql4ACgkQ4+MsLN6t wN6Lfg//R4h6dyAg02hyopwb/DSI97hAsD9kap15ro1qszYrIOkJcEPoE37HDi6d O0Ls+8NPpJcnMwdghHvVaRGoIH2OY5ogXKo6UK1BbOn8iAGxRrT/IPVCyFbPmQoe Bk78Z/wne/YgCXiW4HGHSJO5sL04AQqcFYnwjisHHf3Ox8RR85LbhWqthZluta4i a/Y8W5UO7jfwhAl1/Zb2cU+Rv75I6xcaLQAfmbt4j+wHP52I2cjLpIYo4sCn+ULJ AVX4q4MKrkDrr6CYPXxdGJzYEzVn9evynVcQoRzL6bLZFMpa284AzVd3kQg9NWAb p1hvKJTA57q4XDoD50qVGLhP207VVSUcdm0r2ZJA2jag5ddoT+x2talz8/f6In1b 7BrSM/pla8x9KvTne/ko0wSL0o2dOWyig8mBxARLZWPxk+LBVs1PBZfvn+3j1pYA rWV25Ht4QJlUYMbe3NvEIomsVThKg8Fh3b4mEuyPM+LZ1brgmhrzJG1SF+G4fH8A aig/RVqgNHtajSnG4A723k2/QzlvnAiT7E3dKB5FogjTcVzFRaWFKsUb4ORqsCAz c/AheCJY4PP3pAnb0ODISSVviXwAXqCLbtZhDGhHNYl3C69EyGPPMiVxCaIxKDxU bF7AIYhRTTMyNSbnkcRS3UDO/gZS7x5/K+/YAM9akQEYADIodYM= =Vb39 -----END PGP SIGNATURE----- Merge tag 'accel-20250704' of https://github.com/philmd/qemu into staging Accelerators patches - Generic API consolidation, cleanups (dead code removal, documentation added) - Remove monitor TCG 'info opcount' and @x-query-opcount - Have HVF / NVMM / WHPX use generic CPUState::vcpu_dirty field - Expose nvmm_enabled() and whpx_enabled() to common code - Have hmp_info_registers() dump vector registers # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmhnql4ACgkQ4+MsLN6t # wN6Lfg//R4h6dyAg02hyopwb/DSI97hAsD9kap15ro1qszYrIOkJcEPoE37HDi6d # O0Ls+8NPpJcnMwdghHvVaRGoIH2OY5ogXKo6UK1BbOn8iAGxRrT/IPVCyFbPmQoe # Bk78Z/wne/YgCXiW4HGHSJO5sL04AQqcFYnwjisHHf3Ox8RR85LbhWqthZluta4i # a/Y8W5UO7jfwhAl1/Zb2cU+Rv75I6xcaLQAfmbt4j+wHP52I2cjLpIYo4sCn+ULJ # AVX4q4MKrkDrr6CYPXxdGJzYEzVn9evynVcQoRzL6bLZFMpa284AzVd3kQg9NWAb # p1hvKJTA57q4XDoD50qVGLhP207VVSUcdm0r2ZJA2jag5ddoT+x2talz8/f6In1b # 7BrSM/pla8x9KvTne/ko0wSL0o2dOWyig8mBxARLZWPxk+LBVs1PBZfvn+3j1pYA # rWV25Ht4QJlUYMbe3NvEIomsVThKg8Fh3b4mEuyPM+LZ1brgmhrzJG1SF+G4fH8A # aig/RVqgNHtajSnG4A723k2/QzlvnAiT7E3dKB5FogjTcVzFRaWFKsUb4ORqsCAz # c/AheCJY4PP3pAnb0ODISSVviXwAXqCLbtZhDGhHNYl3C69EyGPPMiVxCaIxKDxU # bF7AIYhRTTMyNSbnkcRS3UDO/gZS7x5/K+/YAM9akQEYADIodYM= # =Vb39 # -----END PGP SIGNATURE----- # gpg: Signature made Fri 04 Jul 2025 06:18:06 EDT # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * tag 'accel-20250704' of https://github.com/philmd/qemu: (31 commits) MAINTAINERS: Add me as reviewer of overall accelerators section monitor/hmp-cmds-target: add CPU_DUMP_VPU in hmp_info_registers() accel: Pass AccelState argument to gdbstub_supported_sstep_flags() accel: Remove unused MachineState argument of AccelClass::setup_post() accel: Directly pass AccelState argument to AccelClass::has_memory() accel/kvm: Directly pass KVMState argument to do_kvm_create_vm() accel/kvm: Prefer local AccelState over global MachineState::accel accel/tcg: Prefer local AccelState over global current_accel() accel: Propagate AccelState to AccelClass::init_machine() accel: Keep reference to AccelOpsClass in AccelClass accel: Expose and register generic_handle_interrupt() accel/dummy: Extract 'dummy-cpus.h' header from 'system/cpus.h' accel/whpx: Expose whpx_enabled() to common code accel/nvmm: Expose nvmm_enabled() to common code accel/system: Document cpu_synchronize_state_post_init/reset() accel/system: Document cpu_synchronize_state() accel/kvm: Remove kvm_cpu_synchronize_state() stub accel/whpx: Replace @dirty field by generic CPUState::vcpu_dirty field accel/nvmm: Replace @dirty field by generic CPUState::vcpu_dirty field accel/hvf: Replace @dirty field by generic CPUState::vcpu_dirty field ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
989dd906ed
44 changed files with 551 additions and 535 deletions
|
|
@ -495,6 +495,7 @@ Guest CPU Cores (other accelerators)
|
||||||
Overall
|
Overall
|
||||||
M: Richard Henderson <richard.henderson@linaro.org>
|
M: Richard Henderson <richard.henderson@linaro.org>
|
||||||
R: Paolo Bonzini <pbonzini@redhat.com>
|
R: Paolo Bonzini <pbonzini@redhat.com>
|
||||||
|
R: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: include/exec/cpu*.h
|
F: include/exec/cpu*.h
|
||||||
F: include/exec/target_long.h
|
F: include/exec/target_long.h
|
||||||
|
|
@ -503,6 +504,7 @@ F: include/system/accel-*.h
|
||||||
F: include/system/cpus.h
|
F: include/system/cpus.h
|
||||||
F: include/accel/accel-cpu*.h
|
F: include/accel/accel-cpu*.h
|
||||||
F: accel/accel-*.?
|
F: accel/accel-*.?
|
||||||
|
F: accel/dummy-cpus.?
|
||||||
F: accel/Makefile.objs
|
F: accel/Makefile.objs
|
||||||
F: accel/stubs/Makefile.objs
|
F: accel/stubs/Makefile.objs
|
||||||
F: cpu-common.c
|
F: cpu-common.c
|
||||||
|
|
@ -540,6 +542,7 @@ WHPX CPUs
|
||||||
M: Sunil Muthuswamy <sunilmut@microsoft.com>
|
M: Sunil Muthuswamy <sunilmut@microsoft.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: target/i386/whpx/
|
F: target/i386/whpx/
|
||||||
|
F: accel/stubs/whpx-stub.c
|
||||||
F: include/system/whpx.h
|
F: include/system/whpx.h
|
||||||
|
|
||||||
X86 Instruction Emulator
|
X86 Instruction Emulator
|
||||||
|
|
@ -586,6 +589,7 @@ NetBSD Virtual Machine Monitor (NVMM) CPU support
|
||||||
M: Reinoud Zandijk <reinoud@netbsd.org>
|
M: Reinoud Zandijk <reinoud@netbsd.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: include/system/nvmm.h
|
F: include/system/nvmm.h
|
||||||
|
F: accel/stubs/nvmm-stub.c
|
||||||
F: target/i386/nvmm/
|
F: target/i386/nvmm/
|
||||||
|
|
||||||
Hosts
|
Hosts
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ int accel_supported_gdbstub_sstep_flags(void)
|
||||||
AccelState *accel = current_accel();
|
AccelState *accel = current_accel();
|
||||||
AccelClass *acc = ACCEL_GET_CLASS(accel);
|
AccelClass *acc = ACCEL_GET_CLASS(accel);
|
||||||
if (acc->gdbstub_supported_sstep_flags) {
|
if (acc->gdbstub_supported_sstep_flags) {
|
||||||
return acc->gdbstub_supported_sstep_flags();
|
return acc->gdbstub_supported_sstep_flags(accel);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ int accel_init_machine(AccelState *accel, MachineState *ms)
|
||||||
int ret;
|
int ret;
|
||||||
ms->accelerator = accel;
|
ms->accelerator = accel;
|
||||||
*(acc->allowed) = true;
|
*(acc->allowed) = true;
|
||||||
ret = acc->init_machine(ms);
|
ret = acc->init_machine(accel, ms);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
ms->accelerator = NULL;
|
ms->accelerator = NULL;
|
||||||
*(acc->allowed) = false;
|
*(acc->allowed) = false;
|
||||||
|
|
@ -58,7 +58,7 @@ void accel_setup_post(MachineState *ms)
|
||||||
AccelState *accel = ms->accelerator;
|
AccelState *accel = ms->accelerator;
|
||||||
AccelClass *acc = ACCEL_GET_CLASS(accel);
|
AccelClass *acc = ACCEL_GET_CLASS(accel);
|
||||||
if (acc->setup_post) {
|
if (acc->setup_post) {
|
||||||
acc->setup_post(ms, accel);
|
acc->setup_post(accel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,8 +85,9 @@ void accel_init_ops_interfaces(AccelClass *ac)
|
||||||
* non-NULL create_vcpu_thread operation.
|
* non-NULL create_vcpu_thread operation.
|
||||||
*/
|
*/
|
||||||
ops = ACCEL_OPS_CLASS(oc);
|
ops = ACCEL_OPS_CLASS(oc);
|
||||||
|
ac->ops = ops;
|
||||||
if (ops->ops_init) {
|
if (ops->ops_init) {
|
||||||
ops->ops_init(ops);
|
ops->ops_init(ac);
|
||||||
}
|
}
|
||||||
cpus_register_accel(ops);
|
cpus_register_accel(ops);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
|
#include "accel/dummy-cpus.h"
|
||||||
|
|
||||||
static void *dummy_cpu_thread_fn(void *arg)
|
static void *dummy_cpu_thread_fn(void *arg)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
14
accel/dummy-cpus.h
Normal file
14
accel/dummy-cpus.h
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* Dummy cpu thread code
|
||||||
|
*
|
||||||
|
* Copyright IBM, Corp. 2011
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ACCEL_DUMMY_CPUS_H
|
||||||
|
#define ACCEL_DUMMY_CPUS_H
|
||||||
|
|
||||||
|
void dummy_start_vcpu_thread(CPUState *cpu);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -48,18 +48,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "system/address-spaces.h"
|
#include "qemu/queue.h"
|
||||||
#include "gdbstub/enums.h"
|
#include "gdbstub/enums.h"
|
||||||
#include "hw/boards.h"
|
#include "exec/cpu-common.h"
|
||||||
|
#include "hw/core/cpu.h"
|
||||||
#include "system/accel-ops.h"
|
#include "system/accel-ops.h"
|
||||||
#include "system/cpus.h"
|
#include "system/cpus.h"
|
||||||
#include "system/hvf.h"
|
#include "system/hvf.h"
|
||||||
#include "system/hvf_int.h"
|
#include "system/hvf_int.h"
|
||||||
#include "system/runstate.h"
|
|
||||||
#include "qemu/guest-random.h"
|
|
||||||
#include "trace.h"
|
|
||||||
|
|
||||||
HVFState *hvf_state;
|
HVFState *hvf_state;
|
||||||
|
|
||||||
|
|
@ -79,143 +77,17 @@ hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mac_slot {
|
|
||||||
int present;
|
|
||||||
uint64_t size;
|
|
||||||
uint64_t gpa_start;
|
|
||||||
uint64_t gva;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mac_slot mac_slots[32];
|
|
||||||
|
|
||||||
static int do_hvf_set_memory(hvf_slot *slot, hv_memory_flags_t flags)
|
|
||||||
{
|
|
||||||
struct mac_slot *macslot;
|
|
||||||
hv_return_t ret;
|
|
||||||
|
|
||||||
macslot = &mac_slots[slot->slot_id];
|
|
||||||
|
|
||||||
if (macslot->present) {
|
|
||||||
if (macslot->size != slot->size) {
|
|
||||||
macslot->present = 0;
|
|
||||||
trace_hvf_vm_unmap(macslot->gpa_start, macslot->size);
|
|
||||||
ret = hv_vm_unmap(macslot->gpa_start, macslot->size);
|
|
||||||
assert_hvf_ok(ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!slot->size) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
macslot->present = 1;
|
|
||||||
macslot->gpa_start = slot->start;
|
|
||||||
macslot->size = slot->size;
|
|
||||||
trace_hvf_vm_map(slot->start, slot->size, slot->mem, flags,
|
|
||||||
flags & HV_MEMORY_READ ? 'R' : '-',
|
|
||||||
flags & HV_MEMORY_WRITE ? 'W' : '-',
|
|
||||||
flags & HV_MEMORY_EXEC ? 'E' : '-');
|
|
||||||
ret = hv_vm_map(slot->mem, slot->start, slot->size, flags);
|
|
||||||
assert_hvf_ok(ret);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
|
||||||
{
|
|
||||||
hvf_slot *mem;
|
|
||||||
MemoryRegion *area = section->mr;
|
|
||||||
bool writable = !area->readonly && !area->rom_device;
|
|
||||||
hv_memory_flags_t flags;
|
|
||||||
uint64_t page_size = qemu_real_host_page_size();
|
|
||||||
|
|
||||||
if (!memory_region_is_ram(area)) {
|
|
||||||
if (writable) {
|
|
||||||
return;
|
|
||||||
} else if (!memory_region_is_romd(area)) {
|
|
||||||
/*
|
|
||||||
* If the memory device is not in romd_mode, then we actually want
|
|
||||||
* to remove the hvf memory slot so all accesses will trap.
|
|
||||||
*/
|
|
||||||
add = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) ||
|
|
||||||
!QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) {
|
|
||||||
/* Not page aligned, so we can not map as RAM */
|
|
||||||
add = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem = hvf_find_overlap_slot(
|
|
||||||
section->offset_within_address_space,
|
|
||||||
int128_get64(section->size));
|
|
||||||
|
|
||||||
if (mem && add) {
|
|
||||||
if (mem->size == int128_get64(section->size) &&
|
|
||||||
mem->start == section->offset_within_address_space &&
|
|
||||||
mem->mem == (memory_region_get_ram_ptr(area) +
|
|
||||||
section->offset_within_region)) {
|
|
||||||
return; /* Same region was attempted to register, go away. */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Region needs to be reset. set the size to 0 and remap it. */
|
|
||||||
if (mem) {
|
|
||||||
mem->size = 0;
|
|
||||||
if (do_hvf_set_memory(mem, 0)) {
|
|
||||||
error_report("Failed to reset overlapping slot");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!add) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (area->readonly ||
|
|
||||||
(!memory_region_is_ram(area) && memory_region_is_romd(area))) {
|
|
||||||
flags = HV_MEMORY_READ | HV_MEMORY_EXEC;
|
|
||||||
} else {
|
|
||||||
flags = HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now make a new slot. */
|
|
||||||
int x;
|
|
||||||
|
|
||||||
for (x = 0; x < hvf_state->num_slots; ++x) {
|
|
||||||
mem = &hvf_state->slots[x];
|
|
||||||
if (!mem->size) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x == hvf_state->num_slots) {
|
|
||||||
error_report("No free slots");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
mem->size = int128_get64(section->size);
|
|
||||||
mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
|
|
||||||
mem->start = section->offset_within_address_space;
|
|
||||||
mem->region = area;
|
|
||||||
|
|
||||||
if (do_hvf_set_memory(mem, flags)) {
|
|
||||||
error_report("Error registering new memory slot");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
static void do_hvf_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
if (!cpu->accel->dirty) {
|
if (!cpu->vcpu_dirty) {
|
||||||
hvf_get_registers(cpu);
|
hvf_get_registers(cpu);
|
||||||
cpu->accel->dirty = true;
|
cpu->vcpu_dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hvf_cpu_synchronize_state(CPUState *cpu)
|
static void hvf_cpu_synchronize_state(CPUState *cpu)
|
||||||
{
|
{
|
||||||
if (!cpu->accel->dirty) {
|
if (!cpu->vcpu_dirty) {
|
||||||
run_on_cpu(cpu, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL);
|
run_on_cpu(cpu, do_hvf_cpu_synchronize_state, RUN_ON_CPU_NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +96,7 @@ static void do_hvf_cpu_synchronize_set_dirty(CPUState *cpu,
|
||||||
run_on_cpu_data arg)
|
run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
/* QEMU state is the reference, push it to HVF now and on next entry */
|
/* QEMU state is the reference, push it to HVF now and on next entry */
|
||||||
cpu->accel->dirty = true;
|
cpu->vcpu_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hvf_cpu_synchronize_post_reset(CPUState *cpu)
|
static void hvf_cpu_synchronize_post_reset(CPUState *cpu)
|
||||||
|
|
@ -242,147 +114,10 @@ static void hvf_cpu_synchronize_pre_loadvm(CPUState *cpu)
|
||||||
run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
|
run_on_cpu(cpu, do_hvf_cpu_synchronize_set_dirty, RUN_ON_CPU_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
|
|
||||||
{
|
|
||||||
hvf_slot *slot;
|
|
||||||
|
|
||||||
slot = hvf_find_overlap_slot(
|
|
||||||
section->offset_within_address_space,
|
|
||||||
int128_get64(section->size));
|
|
||||||
|
|
||||||
/* protect region against writes; begin tracking it */
|
|
||||||
if (on) {
|
|
||||||
slot->flags |= HVF_SLOT_LOG;
|
|
||||||
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
|
||||||
HV_MEMORY_READ | HV_MEMORY_EXEC);
|
|
||||||
/* stop tracking region*/
|
|
||||||
} else {
|
|
||||||
slot->flags &= ~HVF_SLOT_LOG;
|
|
||||||
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
|
||||||
HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hvf_log_start(MemoryListener *listener,
|
|
||||||
MemoryRegionSection *section, int old, int new)
|
|
||||||
{
|
|
||||||
if (old != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hvf_set_dirty_tracking(section, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hvf_log_stop(MemoryListener *listener,
|
|
||||||
MemoryRegionSection *section, int old, int new)
|
|
||||||
{
|
|
||||||
if (new != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
hvf_set_dirty_tracking(section, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hvf_log_sync(MemoryListener *listener,
|
|
||||||
MemoryRegionSection *section)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* sync of dirty pages is handled elsewhere; just make sure we keep
|
|
||||||
* tracking the region.
|
|
||||||
*/
|
|
||||||
hvf_set_dirty_tracking(section, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hvf_region_add(MemoryListener *listener,
|
|
||||||
MemoryRegionSection *section)
|
|
||||||
{
|
|
||||||
hvf_set_phys_mem(section, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hvf_region_del(MemoryListener *listener,
|
|
||||||
MemoryRegionSection *section)
|
|
||||||
{
|
|
||||||
hvf_set_phys_mem(section, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static MemoryListener hvf_memory_listener = {
|
|
||||||
.name = "hvf",
|
|
||||||
.priority = MEMORY_LISTENER_PRIORITY_ACCEL,
|
|
||||||
.region_add = hvf_region_add,
|
|
||||||
.region_del = hvf_region_del,
|
|
||||||
.log_start = hvf_log_start,
|
|
||||||
.log_stop = hvf_log_stop,
|
|
||||||
.log_sync = hvf_log_sync,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void dummy_signal(int sig)
|
static void dummy_signal(int sig)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hvf_allowed;
|
|
||||||
|
|
||||||
static int hvf_accel_init(MachineState *ms)
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
hv_return_t ret;
|
|
||||||
HVFState *s;
|
|
||||||
int pa_range = 36;
|
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
|
||||||
|
|
||||||
if (mc->hvf_get_physical_address_range) {
|
|
||||||
pa_range = mc->hvf_get_physical_address_range(ms);
|
|
||||||
if (pa_range < 0) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = hvf_arch_vm_create(ms, (uint32_t)pa_range);
|
|
||||||
assert_hvf_ok(ret);
|
|
||||||
|
|
||||||
s = g_new0(HVFState, 1);
|
|
||||||
|
|
||||||
s->num_slots = ARRAY_SIZE(s->slots);
|
|
||||||
for (x = 0; x < s->num_slots; ++x) {
|
|
||||||
s->slots[x].size = 0;
|
|
||||||
s->slots[x].slot_id = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTAILQ_INIT(&s->hvf_sw_breakpoints);
|
|
||||||
|
|
||||||
hvf_state = s;
|
|
||||||
memory_listener_register(&hvf_memory_listener, &address_space_memory);
|
|
||||||
|
|
||||||
return hvf_arch_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int hvf_gdbstub_sstep_flags(void)
|
|
||||||
{
|
|
||||||
return SSTEP_ENABLE | SSTEP_NOIRQ;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hvf_accel_class_init(ObjectClass *oc, const void *data)
|
|
||||||
{
|
|
||||||
AccelClass *ac = ACCEL_CLASS(oc);
|
|
||||||
ac->name = "HVF";
|
|
||||||
ac->init_machine = hvf_accel_init;
|
|
||||||
ac->allowed = &hvf_allowed;
|
|
||||||
ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const TypeInfo hvf_accel_type = {
|
|
||||||
.name = TYPE_HVF_ACCEL,
|
|
||||||
.parent = TYPE_ACCEL,
|
|
||||||
.instance_size = sizeof(HVFState),
|
|
||||||
.class_init = hvf_accel_class_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void hvf_type_init(void)
|
|
||||||
{
|
|
||||||
type_register_static(&hvf_accel_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
type_init(hvf_type_init);
|
|
||||||
|
|
||||||
static void hvf_vcpu_destroy(CPUState *cpu)
|
static void hvf_vcpu_destroy(CPUState *cpu)
|
||||||
{
|
{
|
||||||
hv_return_t ret = hv_vcpu_destroy(cpu->accel->fd);
|
hv_return_t ret = hv_vcpu_destroy(cpu->accel->fd);
|
||||||
|
|
@ -415,8 +150,8 @@ static int hvf_init_vcpu(CPUState *cpu)
|
||||||
#else
|
#else
|
||||||
r = hv_vcpu_create(&cpu->accel->fd, HV_VCPU_DEFAULT);
|
r = hv_vcpu_create(&cpu->accel->fd, HV_VCPU_DEFAULT);
|
||||||
#endif
|
#endif
|
||||||
cpu->accel->dirty = true;
|
|
||||||
assert_hvf_ok(r);
|
assert_hvf_ok(r);
|
||||||
|
cpu->vcpu_dirty = true;
|
||||||
|
|
||||||
cpu->accel->guest_debug_enabled = false;
|
cpu->accel->guest_debug_enabled = false;
|
||||||
|
|
||||||
|
|
@ -482,6 +217,34 @@ static void hvf_start_vcpu_thread(CPUState *cpu)
|
||||||
cpu, QEMU_THREAD_JOINABLE);
|
cpu, QEMU_THREAD_JOINABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu, vaddr pc)
|
||||||
|
{
|
||||||
|
struct hvf_sw_breakpoint *bp;
|
||||||
|
|
||||||
|
QTAILQ_FOREACH(bp, &hvf_state->hvf_sw_breakpoints, entry) {
|
||||||
|
if (bp->pc == pc) {
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hvf_sw_breakpoints_active(CPUState *cpu)
|
||||||
|
{
|
||||||
|
return !QTAILQ_EMPTY(&hvf_state->hvf_sw_breakpoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_hvf_update_guest_debug(CPUState *cpu, run_on_cpu_data arg)
|
||||||
|
{
|
||||||
|
hvf_arch_update_guest_debug(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hvf_update_guest_debug(CPUState *cpu)
|
||||||
|
{
|
||||||
|
run_on_cpu(cpu, do_hvf_update_guest_debug, RUN_ON_CPU_NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int hvf_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len)
|
static int hvf_insert_breakpoint(CPUState *cpu, int type, vaddr addr, vaddr len)
|
||||||
{
|
{
|
||||||
struct hvf_sw_breakpoint *bp;
|
struct hvf_sw_breakpoint *bp;
|
||||||
|
|
@ -590,6 +353,7 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, const void *data)
|
||||||
|
|
||||||
ops->create_vcpu_thread = hvf_start_vcpu_thread;
|
ops->create_vcpu_thread = hvf_start_vcpu_thread;
|
||||||
ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
|
ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
|
||||||
|
ops->handle_interrupt = generic_handle_interrupt;
|
||||||
|
|
||||||
ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
|
ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
|
||||||
ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
|
ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
|
||||||
|
|
@ -609,8 +373,10 @@ static const TypeInfo hvf_accel_ops_type = {
|
||||||
.class_init = hvf_accel_ops_class_init,
|
.class_init = hvf_accel_ops_class_init,
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void hvf_accel_ops_register_types(void)
|
static void hvf_accel_ops_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&hvf_accel_ops_type);
|
type_register_static(&hvf_accel_ops_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(hvf_accel_ops_register_types);
|
type_init(hvf_accel_ops_register_types);
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,24 @@
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
#include "system/address-spaces.h"
|
||||||
|
#include "system/memory.h"
|
||||||
#include "system/hvf.h"
|
#include "system/hvf.h"
|
||||||
#include "system/hvf_int.h"
|
#include "system/hvf_int.h"
|
||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
|
#include "hw/boards.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
bool hvf_allowed;
|
||||||
|
|
||||||
|
struct mac_slot {
|
||||||
|
int present;
|
||||||
|
uint64_t size;
|
||||||
|
uint64_t gpa_start;
|
||||||
|
uint64_t gva;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mac_slot mac_slots[32];
|
||||||
|
|
||||||
const char *hvf_return_string(hv_return_t ret)
|
const char *hvf_return_string(hv_return_t ret)
|
||||||
{
|
{
|
||||||
|
|
@ -42,30 +57,254 @@ void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu, vaddr pc)
|
static int do_hvf_set_memory(hvf_slot *slot, hv_memory_flags_t flags)
|
||||||
{
|
{
|
||||||
struct hvf_sw_breakpoint *bp;
|
struct mac_slot *macslot;
|
||||||
|
hv_return_t ret;
|
||||||
|
|
||||||
QTAILQ_FOREACH(bp, &hvf_state->hvf_sw_breakpoints, entry) {
|
macslot = &mac_slots[slot->slot_id];
|
||||||
if (bp->pc == pc) {
|
|
||||||
return bp;
|
if (macslot->present) {
|
||||||
|
if (macslot->size != slot->size) {
|
||||||
|
macslot->present = 0;
|
||||||
|
trace_hvf_vm_unmap(macslot->gpa_start, macslot->size);
|
||||||
|
ret = hv_vm_unmap(macslot->gpa_start, macslot->size);
|
||||||
|
assert_hvf_ok(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int hvf_sw_breakpoints_active(CPUState *cpu)
|
if (!slot->size) {
|
||||||
{
|
return 0;
|
||||||
return !QTAILQ_EMPTY(&hvf_state->hvf_sw_breakpoints);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void do_hvf_update_guest_debug(CPUState *cpu, run_on_cpu_data arg)
|
macslot->present = 1;
|
||||||
{
|
macslot->gpa_start = slot->start;
|
||||||
hvf_arch_update_guest_debug(cpu);
|
macslot->size = slot->size;
|
||||||
}
|
trace_hvf_vm_map(slot->start, slot->size, slot->mem, flags,
|
||||||
|
flags & HV_MEMORY_READ ? 'R' : '-',
|
||||||
int hvf_update_guest_debug(CPUState *cpu)
|
flags & HV_MEMORY_WRITE ? 'W' : '-',
|
||||||
{
|
flags & HV_MEMORY_EXEC ? 'E' : '-');
|
||||||
run_on_cpu(cpu, do_hvf_update_guest_debug, RUN_ON_CPU_NULL);
|
ret = hv_vm_map(slot->mem, slot->start, slot->size, flags);
|
||||||
|
assert_hvf_ok(ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
|
||||||
|
{
|
||||||
|
hvf_slot *mem;
|
||||||
|
MemoryRegion *area = section->mr;
|
||||||
|
bool writable = !area->readonly && !area->rom_device;
|
||||||
|
hv_memory_flags_t flags;
|
||||||
|
uint64_t page_size = qemu_real_host_page_size();
|
||||||
|
|
||||||
|
if (!memory_region_is_ram(area)) {
|
||||||
|
if (writable) {
|
||||||
|
return;
|
||||||
|
} else if (!memory_region_is_romd(area)) {
|
||||||
|
/*
|
||||||
|
* If the memory device is not in romd_mode, then we actually want
|
||||||
|
* to remove the hvf memory slot so all accesses will trap.
|
||||||
|
*/
|
||||||
|
add = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) ||
|
||||||
|
!QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) {
|
||||||
|
/* Not page aligned, so we can not map as RAM */
|
||||||
|
add = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem = hvf_find_overlap_slot(
|
||||||
|
section->offset_within_address_space,
|
||||||
|
int128_get64(section->size));
|
||||||
|
|
||||||
|
if (mem && add) {
|
||||||
|
if (mem->size == int128_get64(section->size) &&
|
||||||
|
mem->start == section->offset_within_address_space &&
|
||||||
|
mem->mem == (memory_region_get_ram_ptr(area) +
|
||||||
|
section->offset_within_region)) {
|
||||||
|
return; /* Same region was attempted to register, go away. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Region needs to be reset. set the size to 0 and remap it. */
|
||||||
|
if (mem) {
|
||||||
|
mem->size = 0;
|
||||||
|
if (do_hvf_set_memory(mem, 0)) {
|
||||||
|
error_report("Failed to reset overlapping slot");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!add) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (area->readonly ||
|
||||||
|
(!memory_region_is_ram(area) && memory_region_is_romd(area))) {
|
||||||
|
flags = HV_MEMORY_READ | HV_MEMORY_EXEC;
|
||||||
|
} else {
|
||||||
|
flags = HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now make a new slot. */
|
||||||
|
int x;
|
||||||
|
|
||||||
|
for (x = 0; x < hvf_state->num_slots; ++x) {
|
||||||
|
mem = &hvf_state->slots[x];
|
||||||
|
if (!mem->size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x == hvf_state->num_slots) {
|
||||||
|
error_report("No free slots");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
mem->size = int128_get64(section->size);
|
||||||
|
mem->mem = memory_region_get_ram_ptr(area) + section->offset_within_region;
|
||||||
|
mem->start = section->offset_within_address_space;
|
||||||
|
mem->region = area;
|
||||||
|
|
||||||
|
if (do_hvf_set_memory(mem, flags)) {
|
||||||
|
error_report("Error registering new memory slot");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
|
||||||
|
{
|
||||||
|
hvf_slot *slot;
|
||||||
|
|
||||||
|
slot = hvf_find_overlap_slot(
|
||||||
|
section->offset_within_address_space,
|
||||||
|
int128_get64(section->size));
|
||||||
|
|
||||||
|
/* protect region against writes; begin tracking it */
|
||||||
|
if (on) {
|
||||||
|
slot->flags |= HVF_SLOT_LOG;
|
||||||
|
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
||||||
|
HV_MEMORY_READ | HV_MEMORY_EXEC);
|
||||||
|
/* stop tracking region*/
|
||||||
|
} else {
|
||||||
|
slot->flags &= ~HVF_SLOT_LOG;
|
||||||
|
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
|
||||||
|
HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_log_start(MemoryListener *listener,
|
||||||
|
MemoryRegionSection *section, int old, int new)
|
||||||
|
{
|
||||||
|
if (old != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hvf_set_dirty_tracking(section, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_log_stop(MemoryListener *listener,
|
||||||
|
MemoryRegionSection *section, int old, int new)
|
||||||
|
{
|
||||||
|
if (new != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hvf_set_dirty_tracking(section, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_log_sync(MemoryListener *listener,
|
||||||
|
MemoryRegionSection *section)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* sync of dirty pages is handled elsewhere; just make sure we keep
|
||||||
|
* tracking the region.
|
||||||
|
*/
|
||||||
|
hvf_set_dirty_tracking(section, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_region_add(MemoryListener *listener,
|
||||||
|
MemoryRegionSection *section)
|
||||||
|
{
|
||||||
|
hvf_set_phys_mem(section, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_region_del(MemoryListener *listener,
|
||||||
|
MemoryRegionSection *section)
|
||||||
|
{
|
||||||
|
hvf_set_phys_mem(section, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryListener hvf_memory_listener = {
|
||||||
|
.name = "hvf",
|
||||||
|
.priority = MEMORY_LISTENER_PRIORITY_ACCEL,
|
||||||
|
.region_add = hvf_region_add,
|
||||||
|
.region_del = hvf_region_del,
|
||||||
|
.log_start = hvf_log_start,
|
||||||
|
.log_stop = hvf_log_stop,
|
||||||
|
.log_sync = hvf_log_sync,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int hvf_accel_init(AccelState *as, MachineState *ms)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
hv_return_t ret;
|
||||||
|
HVFState *s;
|
||||||
|
int pa_range = 36;
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||||
|
|
||||||
|
if (mc->hvf_get_physical_address_range) {
|
||||||
|
pa_range = mc->hvf_get_physical_address_range(ms);
|
||||||
|
if (pa_range < 0) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hvf_arch_vm_create(ms, (uint32_t)pa_range);
|
||||||
|
assert_hvf_ok(ret);
|
||||||
|
|
||||||
|
s = g_new0(HVFState, 1);
|
||||||
|
|
||||||
|
s->num_slots = ARRAY_SIZE(s->slots);
|
||||||
|
for (x = 0; x < s->num_slots; ++x) {
|
||||||
|
s->slots[x].size = 0;
|
||||||
|
s->slots[x].slot_id = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTAILQ_INIT(&s->hvf_sw_breakpoints);
|
||||||
|
|
||||||
|
hvf_state = s;
|
||||||
|
memory_listener_register(&hvf_memory_listener, &address_space_memory);
|
||||||
|
|
||||||
|
return hvf_arch_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hvf_gdbstub_sstep_flags(AccelState *as)
|
||||||
|
{
|
||||||
|
return SSTEP_ENABLE | SSTEP_NOIRQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hvf_accel_class_init(ObjectClass *oc, const void *data)
|
||||||
|
{
|
||||||
|
AccelClass *ac = ACCEL_CLASS(oc);
|
||||||
|
ac->name = "HVF";
|
||||||
|
ac->init_machine = hvf_accel_init;
|
||||||
|
ac->allowed = &hvf_allowed;
|
||||||
|
ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo hvf_accel_type = {
|
||||||
|
.name = TYPE_HVF_ACCEL,
|
||||||
|
.parent = TYPE_ACCEL,
|
||||||
|
.instance_size = sizeof(HVFState),
|
||||||
|
.class_init = hvf_accel_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void hvf_type_init(void)
|
||||||
|
{
|
||||||
|
type_register_static(&hvf_accel_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(hvf_type_init);
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, const void *data)
|
||||||
ops->synchronize_post_init = kvm_cpu_synchronize_post_init;
|
ops->synchronize_post_init = kvm_cpu_synchronize_post_init;
|
||||||
ops->synchronize_state = kvm_cpu_synchronize_state;
|
ops->synchronize_state = kvm_cpu_synchronize_state;
|
||||||
ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
|
ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
|
||||||
|
ops->handle_interrupt = generic_handle_interrupt;
|
||||||
|
|
||||||
#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
|
#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
|
||||||
ops->update_guest_debug = kvm_update_guest_debug_ops;
|
ops->update_guest_debug = kvm_update_guest_debug_ops;
|
||||||
|
|
|
||||||
|
|
@ -453,7 +453,13 @@ static void kvm_reset_parked_vcpus(KVMState *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_create_vcpu(CPUState *cpu)
|
/**
|
||||||
|
* kvm_create_vcpu - Gets a parked KVM vCPU or creates a KVM vCPU
|
||||||
|
* @cpu: QOM CPUState object for which KVM vCPU has to be fetched/created.
|
||||||
|
*
|
||||||
|
* @returns: 0 when success, errno (<0) when failed.
|
||||||
|
*/
|
||||||
|
static int kvm_create_vcpu(CPUState *cpu)
|
||||||
{
|
{
|
||||||
unsigned long vcpu_id = kvm_arch_vcpu_id(cpu);
|
unsigned long vcpu_id = kvm_arch_vcpu_id(cpu);
|
||||||
KVMState *s = kvm_state;
|
KVMState *s = kvm_state;
|
||||||
|
|
@ -2496,13 +2502,10 @@ uint32_t kvm_dirty_ring_size(void)
|
||||||
return kvm_state->kvm_dirty_ring_size;
|
return kvm_state->kvm_dirty_ring_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_kvm_create_vm(MachineState *ms, int type)
|
static int do_kvm_create_vm(KVMState *s, int type)
|
||||||
{
|
{
|
||||||
KVMState *s;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
s = KVM_STATE(ms->accelerator);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = kvm_ioctl(s, KVM_CREATE_VM, type);
|
ret = kvm_ioctl(s, KVM_CREATE_VM, type);
|
||||||
} while (ret == -EINTR);
|
} while (ret == -EINTR);
|
||||||
|
|
@ -2599,7 +2602,7 @@ static int kvm_setup_dirty_ring(KVMState *s)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvm_init(MachineState *ms)
|
static int kvm_init(AccelState *as, MachineState *ms)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||||
static const char upgrade_note[] =
|
static const char upgrade_note[] =
|
||||||
|
|
@ -2614,15 +2617,13 @@ static int kvm_init(MachineState *ms)
|
||||||
{ /* end of list */ }
|
{ /* end of list */ }
|
||||||
}, *nc = num_cpus;
|
}, *nc = num_cpus;
|
||||||
int soft_vcpus_limit, hard_vcpus_limit;
|
int soft_vcpus_limit, hard_vcpus_limit;
|
||||||
KVMState *s;
|
KVMState *s = KVM_STATE(as);
|
||||||
const KVMCapabilityInfo *missing_cap;
|
const KVMCapabilityInfo *missing_cap;
|
||||||
int ret;
|
int ret;
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
qemu_mutex_init(&kml_slots_lock);
|
qemu_mutex_init(&kml_slots_lock);
|
||||||
|
|
||||||
s = KVM_STATE(ms->accelerator);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On systems where the kernel can support different base page
|
* On systems where the kernel can support different base page
|
||||||
* sizes, host page size may be different from TARGET_PAGE_SIZE,
|
* sizes, host page size may be different from TARGET_PAGE_SIZE,
|
||||||
|
|
@ -2674,7 +2675,7 @@ static int kvm_init(MachineState *ms)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = do_kvm_create_vm(ms, type);
|
ret = do_kvm_create_vm(s, type);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
@ -3817,10 +3818,10 @@ int kvm_get_one_reg(CPUState *cs, uint64_t id, void *target)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool kvm_accel_has_memory(MachineState *ms, AddressSpace *as,
|
static bool kvm_accel_has_memory(AccelState *accel, AddressSpace *as,
|
||||||
hwaddr start_addr, hwaddr size)
|
hwaddr start_addr, hwaddr size)
|
||||||
{
|
{
|
||||||
KVMState *kvm = KVM_STATE(ms->accelerator);
|
KVMState *kvm = KVM_STATE(accel);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < kvm->nr_as; ++i) {
|
for (i = 0; i < kvm->nr_as; ++i) {
|
||||||
|
|
@ -4011,7 +4012,7 @@ static void kvm_accel_instance_init(Object *obj)
|
||||||
* Returns: SSTEP_* flags that KVM supports for guest debug. The
|
* Returns: SSTEP_* flags that KVM supports for guest debug. The
|
||||||
* support is probed during kvm_init()
|
* support is probed during kvm_init()
|
||||||
*/
|
*/
|
||||||
static int kvm_gdbstub_sstep_flags(void)
|
static int kvm_gdbstub_sstep_flags(AccelState *as)
|
||||||
{
|
{
|
||||||
return kvm_sstep_flags;
|
return kvm_sstep_flags;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include "qemu/guest-random.h"
|
#include "qemu/guest-random.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "hw/core/cpu.h"
|
#include "hw/core/cpu.h"
|
||||||
|
#include "accel/dummy-cpus.h"
|
||||||
|
|
||||||
static int64_t qtest_clock_counter;
|
static int64_t qtest_clock_counter;
|
||||||
|
|
||||||
|
|
@ -37,7 +38,7 @@ static void qtest_set_virtual_clock(int64_t count)
|
||||||
qatomic_set_i64(&qtest_clock_counter, count);
|
qatomic_set_i64(&qtest_clock_counter, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qtest_init_accel(MachineState *ms)
|
static int qtest_init_accel(AccelState *as, MachineState *ms)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -66,6 +67,7 @@ static void qtest_accel_ops_class_init(ObjectClass *oc, const void *data)
|
||||||
ops->create_vcpu_thread = dummy_start_vcpu_thread;
|
ops->create_vcpu_thread = dummy_start_vcpu_thread;
|
||||||
ops->get_virtual_clock = qtest_get_virtual_clock;
|
ops->get_virtual_clock = qtest_get_virtual_clock;
|
||||||
ops->set_virtual_clock = qtest_set_virtual_clock;
|
ops->set_virtual_clock = qtest_set_virtual_clock;
|
||||||
|
ops->handle_interrupt = generic_handle_interrupt;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const TypeInfo qtest_accel_ops_type = {
|
static const TypeInfo qtest_accel_ops_type = {
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,6 @@ void kvm_flush_coalesced_mmio_buffer(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_cpu_synchronize_state(CPUState *cpu)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool kvm_has_sync_mmu(void)
|
bool kvm_has_sync_mmu(void)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -105,11 +101,6 @@ unsigned int kvm_get_free_memslots(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_init_cpu_signals(CPUState *cpu)
|
|
||||||
{
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool kvm_arm_supports_user_irq(void)
|
bool kvm_arm_supports_user_irq(void)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,7 @@ system_stubs_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c'))
|
||||||
system_stubs_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
|
system_stubs_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
|
||||||
system_stubs_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c'))
|
system_stubs_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c'))
|
||||||
system_stubs_ss.add(when: 'CONFIG_HVF', if_false: files('hvf-stub.c'))
|
system_stubs_ss.add(when: 'CONFIG_HVF', if_false: files('hvf-stub.c'))
|
||||||
|
system_stubs_ss.add(when: 'CONFIG_NVMM', if_false: files('nvmm-stub.c'))
|
||||||
|
system_stubs_ss.add(when: 'CONFIG_WHPX', if_false: files('whpx-stub.c'))
|
||||||
|
|
||||||
specific_ss.add_all(when: ['CONFIG_SYSTEM_ONLY'], if_true: system_stubs_ss)
|
specific_ss.add_all(when: ['CONFIG_SYSTEM_ONLY'], if_true: system_stubs_ss)
|
||||||
|
|
|
||||||
12
accel/stubs/nvmm-stub.c
Normal file
12
accel/stubs/nvmm-stub.c
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* NVMM stubs for QEMU
|
||||||
|
*
|
||||||
|
* Copyright (c) Linaro
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "system/nvmm.h"
|
||||||
|
|
||||||
|
bool nvmm_allowed;
|
||||||
12
accel/stubs/whpx-stub.c
Normal file
12
accel/stubs/whpx-stub.c
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* WHPX stubs for QEMU
|
||||||
|
*
|
||||||
|
* Copyright (c) Linaro
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "system/whpx.h"
|
||||||
|
|
||||||
|
bool whpx_allowed;
|
||||||
|
|
@ -139,4 +139,6 @@ G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr);
|
||||||
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
|
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
|
||||||
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr);
|
void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr);
|
||||||
|
|
||||||
|
void tcg_dump_stats(GString *buf);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -141,16 +141,26 @@ static void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
|
||||||
*pelide = elide;
|
*pelide = elide;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcg_dump_info(GString *buf)
|
static void tcg_dump_flush_info(GString *buf)
|
||||||
{
|
{
|
||||||
g_string_append_printf(buf, "[TCG profiler not compiled]\n");
|
size_t flush_full, flush_part, flush_elide;
|
||||||
|
|
||||||
|
g_string_append_printf(buf, "TB flush count %u\n",
|
||||||
|
qatomic_read(&tb_ctx.tb_flush_count));
|
||||||
|
g_string_append_printf(buf, "TB invalidate count %u\n",
|
||||||
|
qatomic_read(&tb_ctx.tb_phys_invalidate_count));
|
||||||
|
|
||||||
|
tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
|
||||||
|
g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full);
|
||||||
|
g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
|
||||||
|
g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_exec_info(GString *buf)
|
static void dump_exec_info(GString *buf)
|
||||||
{
|
{
|
||||||
struct tb_tree_stats tst = {};
|
struct tb_tree_stats tst = {};
|
||||||
struct qht_stats hst;
|
struct qht_stats hst;
|
||||||
size_t nb_tbs, flush_full, flush_part, flush_elide;
|
size_t nb_tbs;
|
||||||
|
|
||||||
tcg_tb_foreach(tb_tree_stats_iter, &tst);
|
tcg_tb_foreach(tb_tree_stats_iter, &tst);
|
||||||
nb_tbs = tst.nb_tbs;
|
nb_tbs = tst.nb_tbs;
|
||||||
|
|
@ -187,16 +197,14 @@ static void dump_exec_info(GString *buf)
|
||||||
qht_statistics_destroy(&hst);
|
qht_statistics_destroy(&hst);
|
||||||
|
|
||||||
g_string_append_printf(buf, "\nStatistics:\n");
|
g_string_append_printf(buf, "\nStatistics:\n");
|
||||||
g_string_append_printf(buf, "TB flush count %u\n",
|
tcg_dump_flush_info(buf);
|
||||||
qatomic_read(&tb_ctx.tb_flush_count));
|
}
|
||||||
g_string_append_printf(buf, "TB invalidate count %u\n",
|
|
||||||
qatomic_read(&tb_ctx.tb_phys_invalidate_count));
|
|
||||||
|
|
||||||
tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
|
void tcg_dump_stats(GString *buf)
|
||||||
g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full);
|
{
|
||||||
g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
|
dump_accel_info(buf);
|
||||||
g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide);
|
dump_exec_info(buf);
|
||||||
tcg_dump_info(buf);
|
dump_drift_info(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
HumanReadableText *qmp_x_query_jit(Error **errp)
|
HumanReadableText *qmp_x_query_jit(Error **errp)
|
||||||
|
|
@ -208,29 +216,7 @@ HumanReadableText *qmp_x_query_jit(Error **errp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dump_accel_info(buf);
|
tcg_dump_stats(buf);
|
||||||
dump_exec_info(buf);
|
|
||||||
dump_drift_info(buf);
|
|
||||||
|
|
||||||
return human_readable_text_from_str(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tcg_dump_op_count(GString *buf)
|
|
||||||
{
|
|
||||||
g_string_append_printf(buf, "[TCG profiler not compiled]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
HumanReadableText *qmp_x_query_opcount(Error **errp)
|
|
||||||
{
|
|
||||||
g_autoptr(GString) buf = g_string_new("");
|
|
||||||
|
|
||||||
if (!tcg_enabled()) {
|
|
||||||
error_setg(errp,
|
|
||||||
"Opcode count information is only available with accel=tcg");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
tcg_dump_op_count(buf);
|
|
||||||
|
|
||||||
return human_readable_text_from_str(buf);
|
return human_readable_text_from_str(buf);
|
||||||
}
|
}
|
||||||
|
|
@ -238,7 +224,6 @@ HumanReadableText *qmp_x_query_opcount(Error **errp)
|
||||||
static void hmp_tcg_register(void)
|
static void hmp_tcg_register(void)
|
||||||
{
|
{
|
||||||
monitor_register_hmp_info_hrt("jit", qmp_x_query_jit);
|
monitor_register_hmp_info_hrt("jit", qmp_x_query_jit);
|
||||||
monitor_register_hmp_info_hrt("opcount", qmp_x_query_opcount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(hmp_tcg_register);
|
type_init(hmp_tcg_register);
|
||||||
|
|
|
||||||
|
|
@ -93,8 +93,6 @@ static void tcg_cpu_reset_hold(CPUState *cpu)
|
||||||
/* mask must never be zero, except for A20 change call */
|
/* mask must never be zero, except for A20 change call */
|
||||||
void tcg_handle_interrupt(CPUState *cpu, int mask)
|
void tcg_handle_interrupt(CPUState *cpu, int mask)
|
||||||
{
|
{
|
||||||
g_assert(bql_locked());
|
|
||||||
|
|
||||||
cpu->interrupt_request |= mask;
|
cpu->interrupt_request |= mask;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -198,8 +196,10 @@ static inline void tcg_remove_all_breakpoints(CPUState *cpu)
|
||||||
cpu_watchpoint_remove_all(cpu, BP_GDB);
|
cpu_watchpoint_remove_all(cpu, BP_GDB);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tcg_accel_ops_init(AccelOpsClass *ops)
|
static void tcg_accel_ops_init(AccelClass *ac)
|
||||||
{
|
{
|
||||||
|
AccelOpsClass *ops = ac->ops;
|
||||||
|
|
||||||
if (qemu_tcg_mttcg_enabled()) {
|
if (qemu_tcg_mttcg_enabled()) {
|
||||||
ops->create_vcpu_thread = mttcg_start_vcpu_thread;
|
ops->create_vcpu_thread = mttcg_start_vcpu_thread;
|
||||||
ops->kick_vcpu_thread = mttcg_kick_vcpu_thread;
|
ops->kick_vcpu_thread = mttcg_kick_vcpu_thread;
|
||||||
|
|
|
||||||
|
|
@ -80,9 +80,9 @@ static void tcg_accel_instance_init(Object *obj)
|
||||||
|
|
||||||
bool one_insn_per_tb;
|
bool one_insn_per_tb;
|
||||||
|
|
||||||
static int tcg_init_machine(MachineState *ms)
|
static int tcg_init_machine(AccelState *as, MachineState *ms)
|
||||||
{
|
{
|
||||||
TCGState *s = TCG_STATE(current_accel());
|
TCGState *s = TCG_STATE(as);
|
||||||
unsigned max_threads = 1;
|
unsigned max_threads = 1;
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
|
@ -219,7 +219,7 @@ static void tcg_set_one_insn_per_tb(Object *obj, bool value, Error **errp)
|
||||||
qatomic_set(&one_insn_per_tb, value);
|
qatomic_set(&one_insn_per_tb, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tcg_gdbstub_supported_sstep_flags(void)
|
static int tcg_gdbstub_supported_sstep_flags(AccelState *as)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* In replay mode all events will come from the log and can't be
|
* In replay mode all events will come from the log and can't be
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include "hw/xen/xen_igd.h"
|
#include "hw/xen/xen_igd.h"
|
||||||
#include "chardev/char.h"
|
#include "chardev/char.h"
|
||||||
#include "qemu/accel.h"
|
#include "qemu/accel.h"
|
||||||
|
#include "accel/dummy-cpus.h"
|
||||||
#include "system/accel-ops.h"
|
#include "system/accel-ops.h"
|
||||||
#include "system/cpus.h"
|
#include "system/cpus.h"
|
||||||
#include "system/xen.h"
|
#include "system/xen.h"
|
||||||
|
|
@ -63,7 +64,7 @@ static void xen_set_igd_gfx_passthru(Object *obj, bool value, Error **errp)
|
||||||
xen_igd_gfx_pt_set(value, errp);
|
xen_igd_gfx_pt_set(value, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xen_setup_post(MachineState *ms, AccelState *accel)
|
static void xen_setup_post(AccelState *as)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
|
@ -76,7 +77,7 @@ static void xen_setup_post(MachineState *ms, AccelState *accel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xen_init(MachineState *ms)
|
static int xen_init(AccelState *as, MachineState *ms)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||||
|
|
||||||
|
|
@ -152,6 +153,7 @@ static void xen_accel_ops_class_init(ObjectClass *oc, const void *data)
|
||||||
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
|
||||||
|
|
||||||
ops->create_vcpu_thread = dummy_start_vcpu_thread;
|
ops->create_vcpu_thread = dummy_start_vcpu_thread;
|
||||||
|
ops->handle_interrupt = generic_handle_interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo xen_accel_ops_type = {
|
static const TypeInfo xen_accel_ops_type = {
|
||||||
|
|
|
||||||
|
|
@ -474,7 +474,7 @@ int main(int argc, char **argv)
|
||||||
opt_one_insn_per_tb, &error_abort);
|
opt_one_insn_per_tb, &error_abort);
|
||||||
object_property_set_int(OBJECT(accel), "tb-size",
|
object_property_set_int(OBJECT(accel), "tb-size",
|
||||||
opt_tb_size, &error_abort);
|
opt_tb_size, &error_abort);
|
||||||
ac->init_machine(NULL);
|
ac->init_machine(accel, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -256,20 +256,6 @@ SRST
|
||||||
Show dynamic compiler info.
|
Show dynamic compiler info.
|
||||||
ERST
|
ERST
|
||||||
|
|
||||||
#if defined(CONFIG_TCG)
|
|
||||||
{
|
|
||||||
.name = "opcount",
|
|
||||||
.args_type = "",
|
|
||||||
.params = "",
|
|
||||||
.help = "show dynamic compiler opcode counters",
|
|
||||||
},
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SRST
|
|
||||||
``info opcount``
|
|
||||||
Show dynamic compiler opcode counters
|
|
||||||
ERST
|
|
||||||
|
|
||||||
{
|
{
|
||||||
.name = "sync-profile",
|
.name = "sync-profile",
|
||||||
.args_type = "mean:-m,no_coalesce:-n,max:i?",
|
.args_type = "mean:-m,no_coalesce:-n,max:i?",
|
||||||
|
|
|
||||||
|
|
@ -442,6 +442,7 @@ struct qemu_work_item;
|
||||||
* @opaque: User data.
|
* @opaque: User data.
|
||||||
* @mem_io_pc: Host Program Counter at which the memory was accessed.
|
* @mem_io_pc: Host Program Counter at which the memory was accessed.
|
||||||
* @accel: Pointer to accelerator specific state.
|
* @accel: Pointer to accelerator specific state.
|
||||||
|
* @vcpu_dirty: Hardware accelerator is not synchronized with QEMU state
|
||||||
* @kvm_fd: vCPU file descriptor for KVM.
|
* @kvm_fd: vCPU file descriptor for KVM.
|
||||||
* @work_mutex: Lock to prevent multiple access to @work_list.
|
* @work_mutex: Lock to prevent multiple access to @work_list.
|
||||||
* @work_list: List of pending asynchronous work.
|
* @work_list: List of pending asynchronous work.
|
||||||
|
|
@ -538,7 +539,6 @@ struct CPUState {
|
||||||
uint32_t kvm_fetch_index;
|
uint32_t kvm_fetch_index;
|
||||||
uint64_t dirty_pages;
|
uint64_t dirty_pages;
|
||||||
int kvm_vcpu_stats_fd;
|
int kvm_vcpu_stats_fd;
|
||||||
bool vcpu_dirty;
|
|
||||||
|
|
||||||
/* Use by accel-block: CPU is executing an ioctl() */
|
/* Use by accel-block: CPU is executing an ioctl() */
|
||||||
QemuLockCnt in_ioctl_lock;
|
QemuLockCnt in_ioctl_lock;
|
||||||
|
|
@ -554,6 +554,7 @@ struct CPUState {
|
||||||
uint32_t halted;
|
uint32_t halted;
|
||||||
int32_t exception_index;
|
int32_t exception_index;
|
||||||
|
|
||||||
|
bool vcpu_dirty;
|
||||||
AccelCPUState *accel;
|
AccelCPUState *accel;
|
||||||
|
|
||||||
/* Used to keep track of an outstanding cpu throttle thread for migration
|
/* Used to keep track of an outstanding cpu throttle thread for migration
|
||||||
|
|
|
||||||
|
|
@ -37,17 +37,20 @@ typedef struct AccelClass {
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
const char *name;
|
const char *name;
|
||||||
int (*init_machine)(MachineState *ms);
|
/* Cached by accel_init_ops_interfaces() when created */
|
||||||
|
AccelOpsClass *ops;
|
||||||
|
|
||||||
|
int (*init_machine)(AccelState *as, MachineState *ms);
|
||||||
bool (*cpu_common_realize)(CPUState *cpu, Error **errp);
|
bool (*cpu_common_realize)(CPUState *cpu, Error **errp);
|
||||||
void (*cpu_common_unrealize)(CPUState *cpu);
|
void (*cpu_common_unrealize)(CPUState *cpu);
|
||||||
|
|
||||||
/* system related hooks */
|
/* system related hooks */
|
||||||
void (*setup_post)(MachineState *ms, AccelState *accel);
|
void (*setup_post)(AccelState *as);
|
||||||
bool (*has_memory)(MachineState *ms, AddressSpace *as,
|
bool (*has_memory)(AccelState *accel, AddressSpace *as,
|
||||||
hwaddr start_addr, hwaddr size);
|
hwaddr start_addr, hwaddr size);
|
||||||
|
|
||||||
/* gdbstub related hooks */
|
/* gdbstub related hooks */
|
||||||
int (*gdbstub_supported_sstep_flags)(void);
|
int (*gdbstub_supported_sstep_flags)(AccelState *as);
|
||||||
|
|
||||||
bool *allowed;
|
bool *allowed;
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#ifndef ACCEL_OPS_H
|
#ifndef ACCEL_OPS_H
|
||||||
#define ACCEL_OPS_H
|
#define ACCEL_OPS_H
|
||||||
|
|
||||||
|
#include "qemu/accel.h"
|
||||||
#include "exec/vaddr.h"
|
#include "exec/vaddr.h"
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ struct AccelOpsClass {
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
|
|
||||||
/* initialization function called when accel is chosen */
|
/* initialization function called when accel is chosen */
|
||||||
void (*ops_init)(AccelOpsClass *ops);
|
void (*ops_init)(AccelClass *ac);
|
||||||
|
|
||||||
bool (*cpus_are_resettable)(void);
|
bool (*cpus_are_resettable)(void);
|
||||||
void (*cpu_reset_hold)(CPUState *cpu);
|
void (*cpu_reset_hold)(CPUState *cpu);
|
||||||
|
|
@ -40,12 +41,29 @@ struct AccelOpsClass {
|
||||||
void (*kick_vcpu_thread)(CPUState *cpu);
|
void (*kick_vcpu_thread)(CPUState *cpu);
|
||||||
bool (*cpu_thread_is_idle)(CPUState *cpu);
|
bool (*cpu_thread_is_idle)(CPUState *cpu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* synchronize_post_reset:
|
||||||
|
* synchronize_post_init:
|
||||||
|
* @cpu: The vCPU to synchronize.
|
||||||
|
*
|
||||||
|
* Request to synchronize QEMU vCPU registers to the hardware accelerator
|
||||||
|
* (QEMU is the reference).
|
||||||
|
*/
|
||||||
void (*synchronize_post_reset)(CPUState *cpu);
|
void (*synchronize_post_reset)(CPUState *cpu);
|
||||||
void (*synchronize_post_init)(CPUState *cpu);
|
void (*synchronize_post_init)(CPUState *cpu);
|
||||||
|
/**
|
||||||
|
* synchronize_state:
|
||||||
|
* synchronize_pre_loadvm:
|
||||||
|
* @cpu: The vCPU to synchronize.
|
||||||
|
*
|
||||||
|
* Request to synchronize QEMU vCPU registers from the hardware accelerator
|
||||||
|
* (the hardware accelerator is the reference).
|
||||||
|
*/
|
||||||
void (*synchronize_state)(CPUState *cpu);
|
void (*synchronize_state)(CPUState *cpu);
|
||||||
void (*synchronize_pre_loadvm)(CPUState *cpu);
|
void (*synchronize_pre_loadvm)(CPUState *cpu);
|
||||||
void (*synchronize_pre_resume)(bool step_pending);
|
void (*synchronize_pre_resume)(bool step_pending);
|
||||||
|
|
||||||
|
/* handle_interrupt is mandatory. */
|
||||||
void (*handle_interrupt)(CPUState *cpu, int mask);
|
void (*handle_interrupt)(CPUState *cpu, int mask);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -70,4 +88,6 @@ struct AccelOpsClass {
|
||||||
void (*remove_all_breakpoints)(CPUState *cpu);
|
void (*remove_all_breakpoints)(CPUState *cpu);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void generic_handle_interrupt(CPUState *cpu, int mask);
|
||||||
|
|
||||||
#endif /* ACCEL_OPS_H */
|
#endif /* ACCEL_OPS_H */
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,6 @@ void cpus_register_accel(const AccelOpsClass *i);
|
||||||
/* return registers ops */
|
/* return registers ops */
|
||||||
const AccelOpsClass *cpus_get_accel(void);
|
const AccelOpsClass *cpus_get_accel(void);
|
||||||
|
|
||||||
/* accel/dummy-cpus.c */
|
|
||||||
|
|
||||||
/* Create a dummy vcpu for AccelOpsClass->create_vcpu_thread */
|
|
||||||
void dummy_start_vcpu_thread(CPUState *);
|
|
||||||
|
|
||||||
/* interface available for cpus accelerator threads */
|
/* interface available for cpus accelerator threads */
|
||||||
|
|
||||||
/* For temporary buffers for forming a name */
|
/* For temporary buffers for forming a name */
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,6 @@
|
||||||
#define HVF_H
|
#define HVF_H
|
||||||
|
|
||||||
#include "qemu/accel.h"
|
#include "qemu/accel.h"
|
||||||
#include "qemu/queue.h"
|
|
||||||
#include "exec/vaddr.h"
|
|
||||||
#include "qom/object.h"
|
|
||||||
#include "exec/vaddr.h"
|
|
||||||
|
|
||||||
#ifdef COMPILING_PER_TARGET
|
#ifdef COMPILING_PER_TARGET
|
||||||
# ifdef CONFIG_HVF
|
# ifdef CONFIG_HVF
|
||||||
|
|
@ -40,38 +36,4 @@ typedef struct HVFState HVFState;
|
||||||
DECLARE_INSTANCE_CHECKER(HVFState, HVF_STATE,
|
DECLARE_INSTANCE_CHECKER(HVFState, HVF_STATE,
|
||||||
TYPE_HVF_ACCEL)
|
TYPE_HVF_ACCEL)
|
||||||
|
|
||||||
#ifdef COMPILING_PER_TARGET
|
|
||||||
struct hvf_sw_breakpoint {
|
|
||||||
vaddr pc;
|
|
||||||
vaddr saved_insn;
|
|
||||||
int use_count;
|
|
||||||
QTAILQ_ENTRY(hvf_sw_breakpoint) entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu,
|
|
||||||
vaddr pc);
|
|
||||||
int hvf_sw_breakpoints_active(CPUState *cpu);
|
|
||||||
|
|
||||||
int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp);
|
|
||||||
int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp);
|
|
||||||
int hvf_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type);
|
|
||||||
int hvf_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type);
|
|
||||||
void hvf_arch_remove_all_hw_breakpoints(void);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* hvf_update_guest_debug:
|
|
||||||
* @cs: CPUState for the CPU to update
|
|
||||||
*
|
|
||||||
* Update guest to enable or disable debugging. Per-arch specifics will be
|
|
||||||
* handled by calling down to hvf_arch_update_guest_debug.
|
|
||||||
*/
|
|
||||||
int hvf_update_guest_debug(CPUState *cpu);
|
|
||||||
void hvf_arch_update_guest_debug(CPUState *cpu);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return whether the guest supports debugging.
|
|
||||||
*/
|
|
||||||
bool hvf_arch_supports_guest_debug(void);
|
|
||||||
#endif /* COMPILING_PER_TARGET */
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
#define HVF_INT_H
|
#define HVF_INT_H
|
||||||
|
|
||||||
#include "qemu/queue.h"
|
#include "qemu/queue.h"
|
||||||
|
#include "exec/vaddr.h"
|
||||||
|
#include "qom/object.h"
|
||||||
|
|
||||||
#ifdef __aarch64__
|
#ifdef __aarch64__
|
||||||
#include <Hypervisor/Hypervisor.h>
|
#include <Hypervisor/Hypervisor.h>
|
||||||
|
|
@ -60,7 +62,6 @@ struct AccelCPUState {
|
||||||
bool vtimer_masked;
|
bool vtimer_masked;
|
||||||
sigset_t unblock_ipi_mask;
|
sigset_t unblock_ipi_mask;
|
||||||
bool guest_debug_enabled;
|
bool guest_debug_enabled;
|
||||||
bool dirty;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
|
void assert_hvf_ok_impl(hv_return_t ret, const char *file, unsigned int line,
|
||||||
|
|
@ -77,4 +78,36 @@ int hvf_put_registers(CPUState *);
|
||||||
int hvf_get_registers(CPUState *);
|
int hvf_get_registers(CPUState *);
|
||||||
void hvf_kick_vcpu_thread(CPUState *cpu);
|
void hvf_kick_vcpu_thread(CPUState *cpu);
|
||||||
|
|
||||||
|
struct hvf_sw_breakpoint {
|
||||||
|
vaddr pc;
|
||||||
|
vaddr saved_insn;
|
||||||
|
int use_count;
|
||||||
|
QTAILQ_ENTRY(hvf_sw_breakpoint) entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu,
|
||||||
|
vaddr pc);
|
||||||
|
int hvf_sw_breakpoints_active(CPUState *cpu);
|
||||||
|
|
||||||
|
int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp);
|
||||||
|
int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp);
|
||||||
|
int hvf_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type);
|
||||||
|
int hvf_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type);
|
||||||
|
void hvf_arch_remove_all_hw_breakpoints(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hvf_update_guest_debug:
|
||||||
|
* @cs: CPUState for the CPU to update
|
||||||
|
*
|
||||||
|
* Update guest to enable or disable debugging. Per-arch specifics will be
|
||||||
|
* handled by calling down to hvf_arch_update_guest_debug.
|
||||||
|
*/
|
||||||
|
int hvf_update_guest_debug(CPUState *cpu);
|
||||||
|
void hvf_arch_update_guest_debug(CPUState *cpu);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return whether the guest supports debugging.
|
||||||
|
*/
|
||||||
|
bool hvf_arch_supports_guest_debug(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,26 @@
|
||||||
#include "system/whpx.h"
|
#include "system/whpx.h"
|
||||||
#include "system/nvmm.h"
|
#include "system/nvmm.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_synchronize_state:
|
||||||
|
* cpu_synchronize_pre_loadvm:
|
||||||
|
* @cpu: The vCPU to synchronize.
|
||||||
|
*
|
||||||
|
* Request to synchronize QEMU vCPU registers from the hardware accelerator
|
||||||
|
* (the hardware accelerator is the reference).
|
||||||
|
*/
|
||||||
void cpu_synchronize_state(CPUState *cpu);
|
void cpu_synchronize_state(CPUState *cpu);
|
||||||
void cpu_synchronize_post_reset(CPUState *cpu);
|
|
||||||
void cpu_synchronize_post_init(CPUState *cpu);
|
|
||||||
void cpu_synchronize_pre_loadvm(CPUState *cpu);
|
void cpu_synchronize_pre_loadvm(CPUState *cpu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cpu_synchronize_post_reset:
|
||||||
|
* cpu_synchronize_post_init:
|
||||||
|
* @cpu: The vCPU to synchronize.
|
||||||
|
*
|
||||||
|
* Request to synchronize QEMU vCPU registers to the hardware accelerator
|
||||||
|
* (QEMU is the reference).
|
||||||
|
*/
|
||||||
|
void cpu_synchronize_post_reset(CPUState *cpu);
|
||||||
|
void cpu_synchronize_post_init(CPUState *cpu);
|
||||||
|
|
||||||
#endif /* QEMU_HW_ACCEL_H */
|
#endif /* QEMU_HW_ACCEL_H */
|
||||||
|
|
|
||||||
|
|
@ -317,14 +317,6 @@ int kvm_create_device(KVMState *s, uint64_t type, bool test);
|
||||||
*/
|
*/
|
||||||
bool kvm_device_supported(int vmfd, uint64_t type);
|
bool kvm_device_supported(int vmfd, uint64_t type);
|
||||||
|
|
||||||
/**
|
|
||||||
* kvm_create_vcpu - Gets a parked KVM vCPU or creates a KVM vCPU
|
|
||||||
* @cpu: QOM CPUState object for which KVM vCPU has to be fetched/created.
|
|
||||||
*
|
|
||||||
* @returns: 0 when success, errno (<0) when failed.
|
|
||||||
*/
|
|
||||||
int kvm_create_vcpu(CPUState *cpu);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kvm_park_vcpu - Park QEMU KVM vCPU context
|
* kvm_park_vcpu - Park QEMU KVM vCPU context
|
||||||
* @cpu: QOM CPUState object for which QEMU KVM vCPU context has to be parked.
|
* @cpu: QOM CPUState object for which QEMU KVM vCPU context has to be parked.
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,18 @@
|
||||||
#define QEMU_NVMM_H
|
#define QEMU_NVMM_H
|
||||||
|
|
||||||
#ifdef COMPILING_PER_TARGET
|
#ifdef COMPILING_PER_TARGET
|
||||||
|
# ifdef CONFIG_NVMM
|
||||||
#ifdef CONFIG_NVMM
|
# define CONFIG_NVMM_IS_POSSIBLE
|
||||||
|
# endif /* !CONFIG_NVMM */
|
||||||
int nvmm_enabled(void);
|
#else
|
||||||
|
# define CONFIG_NVMM_IS_POSSIBLE
|
||||||
#else /* CONFIG_NVMM */
|
|
||||||
|
|
||||||
#define nvmm_enabled() (0)
|
|
||||||
|
|
||||||
#endif /* CONFIG_NVMM */
|
|
||||||
|
|
||||||
#endif /* COMPILING_PER_TARGET */
|
#endif /* COMPILING_PER_TARGET */
|
||||||
|
|
||||||
|
#ifdef CONFIG_NVMM_IS_POSSIBLE
|
||||||
|
extern bool nvmm_allowed;
|
||||||
|
#define nvmm_enabled() (nvmm_allowed)
|
||||||
|
#else /* !CONFIG_NVMM_IS_POSSIBLE */
|
||||||
|
#define nvmm_enabled() 0
|
||||||
|
#endif /* !CONFIG_NVMM_IS_POSSIBLE */
|
||||||
|
|
||||||
#endif /* QEMU_NVMM_H */
|
#endif /* QEMU_NVMM_H */
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,20 @@
|
||||||
#define QEMU_WHPX_H
|
#define QEMU_WHPX_H
|
||||||
|
|
||||||
#ifdef COMPILING_PER_TARGET
|
#ifdef COMPILING_PER_TARGET
|
||||||
|
# ifdef CONFIG_WHPX
|
||||||
#ifdef CONFIG_WHPX
|
# define CONFIG_WHPX_IS_POSSIBLE
|
||||||
|
# endif /* !CONFIG_WHPX */
|
||||||
int whpx_enabled(void);
|
#else
|
||||||
bool whpx_apic_in_platform(void);
|
# define CONFIG_WHPX_IS_POSSIBLE
|
||||||
|
|
||||||
#else /* CONFIG_WHPX */
|
|
||||||
|
|
||||||
#define whpx_enabled() (0)
|
|
||||||
#define whpx_apic_in_platform() (0)
|
|
||||||
|
|
||||||
#endif /* CONFIG_WHPX */
|
|
||||||
|
|
||||||
#endif /* COMPILING_PER_TARGET */
|
#endif /* COMPILING_PER_TARGET */
|
||||||
|
|
||||||
|
#ifdef CONFIG_WHPX_IS_POSSIBLE
|
||||||
|
extern bool whpx_allowed;
|
||||||
|
#define whpx_enabled() (whpx_allowed)
|
||||||
|
bool whpx_apic_in_platform(void);
|
||||||
|
#else /* !CONFIG_WHPX_IS_POSSIBLE */
|
||||||
|
#define whpx_enabled() 0
|
||||||
|
#define whpx_apic_in_platform() (0)
|
||||||
|
#endif /* !CONFIG_WHPX_IS_POSSIBLE */
|
||||||
|
|
||||||
#endif /* QEMU_WHPX_H */
|
#endif /* QEMU_WHPX_H */
|
||||||
|
|
|
||||||
|
|
@ -820,7 +820,7 @@ int main(int argc, char **argv, char **envp)
|
||||||
opt_one_insn_per_tb, &error_abort);
|
opt_one_insn_per_tb, &error_abort);
|
||||||
object_property_set_int(OBJECT(accel), "tb-size",
|
object_property_set_int(OBJECT(accel), "tb-size",
|
||||||
opt_tb_size, &error_abort);
|
opt_tb_size, &error_abort);
|
||||||
ac->init_machine(NULL);
|
ac->init_machine(accel, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ void hmp_info_registers(Monitor *mon, const QDict *qdict)
|
||||||
if (all_cpus) {
|
if (all_cpus) {
|
||||||
CPU_FOREACH(cs) {
|
CPU_FOREACH(cs) {
|
||||||
monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index);
|
monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index);
|
||||||
cpu_dump_state(cs, NULL, CPU_DUMP_FPU);
|
cpu_dump_state(cs, NULL, CPU_DUMP_FPU | CPU_DUMP_VPU);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cs = vcpu >= 0 ? qemu_get_cpu(vcpu) : mon_get_cpu(mon);
|
cs = vcpu >= 0 ? qemu_get_cpu(vcpu) : mon_get_cpu(mon);
|
||||||
|
|
@ -117,7 +117,7 @@ void hmp_info_registers(Monitor *mon, const QDict *qdict)
|
||||||
}
|
}
|
||||||
|
|
||||||
monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index);
|
monitor_printf(mon, "\nCPU#%d\n", cs->cpu_index);
|
||||||
cpu_dump_state(cs, NULL, CPU_DUMP_FPU);
|
cpu_dump_state(cs, NULL, CPU_DUMP_FPU | CPU_DUMP_VPU);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1761,24 +1761,6 @@
|
||||||
'returns': 'HumanReadableText',
|
'returns': 'HumanReadableText',
|
||||||
'features': [ 'unstable' ] }
|
'features': [ 'unstable' ] }
|
||||||
|
|
||||||
##
|
|
||||||
# @x-query-opcount:
|
|
||||||
#
|
|
||||||
# Query TCG opcode counters
|
|
||||||
#
|
|
||||||
# Features:
|
|
||||||
#
|
|
||||||
# @unstable: This command is meant for debugging.
|
|
||||||
#
|
|
||||||
# Returns: TCG opcode counters
|
|
||||||
#
|
|
||||||
# Since: 6.2
|
|
||||||
##
|
|
||||||
{ 'command': 'x-query-opcount',
|
|
||||||
'returns': 'HumanReadableText',
|
|
||||||
'if': 'CONFIG_TCG',
|
|
||||||
'features': [ 'unstable' ] }
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# @x-query-ramblock:
|
# @x-query-ramblock:
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ int64_t cpus_get_elapsed_ticks(void)
|
||||||
return cpu_get_ticks();
|
return cpu_get_ticks();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generic_handle_interrupt(CPUState *cpu, int mask)
|
void generic_handle_interrupt(CPUState *cpu, int mask)
|
||||||
{
|
{
|
||||||
cpu->interrupt_request |= mask;
|
cpu->interrupt_request |= mask;
|
||||||
|
|
||||||
|
|
@ -265,11 +265,9 @@ static void generic_handle_interrupt(CPUState *cpu, int mask)
|
||||||
|
|
||||||
void cpu_interrupt(CPUState *cpu, int mask)
|
void cpu_interrupt(CPUState *cpu, int mask)
|
||||||
{
|
{
|
||||||
if (cpus_accel->handle_interrupt) {
|
g_assert(bql_locked());
|
||||||
|
|
||||||
cpus_accel->handle_interrupt(cpu, mask);
|
cpus_accel->handle_interrupt(cpu, mask);
|
||||||
} else {
|
|
||||||
generic_handle_interrupt(cpu, mask);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -678,6 +676,8 @@ void cpus_register_accel(const AccelOpsClass *ops)
|
||||||
{
|
{
|
||||||
assert(ops != NULL);
|
assert(ops != NULL);
|
||||||
assert(ops->create_vcpu_thread != NULL); /* mandatory */
|
assert(ops->create_vcpu_thread != NULL); /* mandatory */
|
||||||
|
assert(ops->handle_interrupt);
|
||||||
|
|
||||||
cpus_accel = ops;
|
cpus_accel = ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3501,7 +3501,7 @@ static void mtree_print_flatview(gpointer key, gpointer value,
|
||||||
if (fvi->ac) {
|
if (fvi->ac) {
|
||||||
for (i = 0; i < fv_address_spaces->len; ++i) {
|
for (i = 0; i < fv_address_spaces->len; ++i) {
|
||||||
as = g_array_index(fv_address_spaces, AddressSpace*, i);
|
as = g_array_index(fv_address_spaces, AddressSpace*, i);
|
||||||
if (fvi->ac->has_memory(current_machine, as,
|
if (fvi->ac->has_memory(current_machine->accelerator, as,
|
||||||
int128_get64(range->addr.start),
|
int128_get64(range->addr.start),
|
||||||
MR_SIZE(range->addr.size) + 1)) {
|
MR_SIZE(range->addr.size) + 1)) {
|
||||||
qemu_printf(" %s", fvi->ac->name);
|
qemu_printf(" %s", fvi->ac->name);
|
||||||
|
|
|
||||||
|
|
@ -813,9 +813,9 @@ int hvf_put_registers(CPUState *cpu)
|
||||||
|
|
||||||
static void flush_cpu_state(CPUState *cpu)
|
static void flush_cpu_state(CPUState *cpu)
|
||||||
{
|
{
|
||||||
if (cpu->accel->dirty) {
|
if (cpu->vcpu_dirty) {
|
||||||
hvf_put_registers(cpu);
|
hvf_put_registers(cpu);
|
||||||
cpu->accel->dirty = false;
|
cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -733,9 +733,9 @@ int hvf_vcpu_exec(CPUState *cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (cpu->accel->dirty) {
|
if (cpu->vcpu_dirty) {
|
||||||
hvf_put_registers(cpu);
|
hvf_put_registers(cpu);
|
||||||
cpu->accel->dirty = false;
|
cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hvf_inject_interrupts(cpu)) {
|
if (hvf_inject_interrupts(cpu)) {
|
||||||
|
|
|
||||||
|
|
@ -427,7 +427,7 @@ int hvf_process_events(CPUState *cs)
|
||||||
X86CPU *cpu = X86_CPU(cs);
|
X86CPU *cpu = X86_CPU(cs);
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
|
|
||||||
if (!cs->accel->dirty) {
|
if (!cs->vcpu_dirty) {
|
||||||
/* light weight sync for CPU_INTERRUPT_HARD and IF_MASK */
|
/* light weight sync for CPU_INTERRUPT_HARD and IF_MASK */
|
||||||
env->eflags = rreg(cs->accel->fd, HV_X86_RFLAGS);
|
env->eflags = rreg(cs->accel->fd, HV_X86_RFLAGS);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ static void nvmm_accel_ops_class_init(ObjectClass *oc, const void *data)
|
||||||
|
|
||||||
ops->create_vcpu_thread = nvmm_start_vcpu_thread;
|
ops->create_vcpu_thread = nvmm_start_vcpu_thread;
|
||||||
ops->kick_vcpu_thread = nvmm_kick_vcpu_thread;
|
ops->kick_vcpu_thread = nvmm_kick_vcpu_thread;
|
||||||
|
ops->handle_interrupt = generic_handle_interrupt;
|
||||||
|
|
||||||
ops->synchronize_post_reset = nvmm_cpu_synchronize_post_reset;
|
ops->synchronize_post_reset = nvmm_cpu_synchronize_post_reset;
|
||||||
ops->synchronize_post_init = nvmm_cpu_synchronize_post_init;
|
ops->synchronize_post_init = nvmm_cpu_synchronize_post_init;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ struct AccelCPUState {
|
||||||
struct nvmm_vcpu vcpu;
|
struct nvmm_vcpu vcpu;
|
||||||
uint8_t tpr;
|
uint8_t tpr;
|
||||||
bool stop;
|
bool stop;
|
||||||
bool dirty;
|
|
||||||
|
|
||||||
/* Window-exiting for INTs/NMIs. */
|
/* Window-exiting for INTs/NMIs. */
|
||||||
bool int_window_exit;
|
bool int_window_exit;
|
||||||
|
|
@ -47,7 +46,7 @@ struct qemu_machine {
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static bool nvmm_allowed;
|
bool nvmm_allowed;
|
||||||
static struct qemu_machine qemu_mach;
|
static struct qemu_machine qemu_mach;
|
||||||
|
|
||||||
static struct nvmm_machine *
|
static struct nvmm_machine *
|
||||||
|
|
@ -508,7 +507,7 @@ nvmm_io_callback(struct nvmm_io *io)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Needed, otherwise infinite loop. */
|
/* Needed, otherwise infinite loop. */
|
||||||
current_cpu->accel->dirty = false;
|
current_cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -517,7 +516,7 @@ nvmm_mem_callback(struct nvmm_mem *mem)
|
||||||
cpu_physical_memory_rw(mem->gpa, mem->data, mem->size, mem->write);
|
cpu_physical_memory_rw(mem->gpa, mem->data, mem->size, mem->write);
|
||||||
|
|
||||||
/* Needed, otherwise infinite loop. */
|
/* Needed, otherwise infinite loop. */
|
||||||
current_cpu->accel->dirty = false;
|
current_cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nvmm_assist_callbacks nvmm_callbacks = {
|
static struct nvmm_assist_callbacks nvmm_callbacks = {
|
||||||
|
|
@ -727,9 +726,9 @@ nvmm_vcpu_loop(CPUState *cpu)
|
||||||
* Inner VCPU loop.
|
* Inner VCPU loop.
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
if (cpu->accel->dirty) {
|
if (cpu->vcpu_dirty) {
|
||||||
nvmm_set_registers(cpu);
|
nvmm_set_registers(cpu);
|
||||||
cpu->accel->dirty = false;
|
cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcpu->stop) {
|
if (qcpu->stop) {
|
||||||
|
|
@ -827,32 +826,32 @@ static void
|
||||||
do_nvmm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
do_nvmm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
nvmm_get_registers(cpu);
|
nvmm_get_registers(cpu);
|
||||||
cpu->accel->dirty = true;
|
cpu->vcpu_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_nvmm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg)
|
do_nvmm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
nvmm_set_registers(cpu);
|
nvmm_set_registers(cpu);
|
||||||
cpu->accel->dirty = false;
|
cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_nvmm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
|
do_nvmm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
nvmm_set_registers(cpu);
|
nvmm_set_registers(cpu);
|
||||||
cpu->accel->dirty = false;
|
cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_nvmm_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg)
|
do_nvmm_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
cpu->accel->dirty = true;
|
cpu->vcpu_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvmm_cpu_synchronize_state(CPUState *cpu)
|
void nvmm_cpu_synchronize_state(CPUState *cpu)
|
||||||
{
|
{
|
||||||
if (!cpu->accel->dirty) {
|
if (!cpu->vcpu_dirty) {
|
||||||
run_on_cpu(cpu, do_nvmm_cpu_synchronize_state, RUN_ON_CPU_NULL);
|
run_on_cpu(cpu, do_nvmm_cpu_synchronize_state, RUN_ON_CPU_NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -982,7 +981,7 @@ nvmm_init_vcpu(CPUState *cpu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qcpu->dirty = true;
|
qcpu->vcpu_dirty = true;
|
||||||
cpu->accel = qcpu;
|
cpu->accel = qcpu;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1153,7 +1152,7 @@ static struct RAMBlockNotifier nvmm_ram_notifier = {
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
nvmm_accel_init(MachineState *ms)
|
nvmm_accel_init(AccelState *as, MachineState *ms)
|
||||||
{
|
{
|
||||||
int ret, err;
|
int ret, err;
|
||||||
|
|
||||||
|
|
@ -1193,12 +1192,6 @@ nvmm_accel_init(MachineState *ms)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
nvmm_enabled(void)
|
|
||||||
{
|
|
||||||
return nvmm_allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nvmm_accel_class_init(ObjectClass *oc, const void *data)
|
nvmm_accel_class_init(ObjectClass *oc, const void *data)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ static void whpx_accel_ops_class_init(ObjectClass *oc, const void *data)
|
||||||
ops->create_vcpu_thread = whpx_start_vcpu_thread;
|
ops->create_vcpu_thread = whpx_start_vcpu_thread;
|
||||||
ops->kick_vcpu_thread = whpx_kick_vcpu_thread;
|
ops->kick_vcpu_thread = whpx_kick_vcpu_thread;
|
||||||
ops->cpu_thread_is_idle = whpx_vcpu_thread_is_idle;
|
ops->cpu_thread_is_idle = whpx_vcpu_thread_is_idle;
|
||||||
|
ops->handle_interrupt = generic_handle_interrupt;
|
||||||
|
|
||||||
ops->synchronize_post_reset = whpx_cpu_synchronize_post_reset;
|
ops->synchronize_post_reset = whpx_cpu_synchronize_post_reset;
|
||||||
ops->synchronize_post_init = whpx_cpu_synchronize_post_init;
|
ops->synchronize_post_init = whpx_cpu_synchronize_post_init;
|
||||||
|
|
|
||||||
|
|
@ -237,13 +237,12 @@ struct AccelCPUState {
|
||||||
uint64_t tpr;
|
uint64_t tpr;
|
||||||
uint64_t apic_base;
|
uint64_t apic_base;
|
||||||
bool interruption_pending;
|
bool interruption_pending;
|
||||||
bool dirty;
|
|
||||||
|
|
||||||
/* Must be the last field as it may have a tail */
|
/* Must be the last field as it may have a tail */
|
||||||
WHV_RUN_VP_EXIT_CONTEXT exit_ctx;
|
WHV_RUN_VP_EXIT_CONTEXT exit_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool whpx_allowed;
|
bool whpx_allowed;
|
||||||
static bool whp_dispatch_initialized;
|
static bool whp_dispatch_initialized;
|
||||||
static HMODULE hWinHvPlatform, hWinHvEmulation;
|
static HMODULE hWinHvPlatform, hWinHvEmulation;
|
||||||
static uint32_t max_vcpu_index;
|
static uint32_t max_vcpu_index;
|
||||||
|
|
@ -836,7 +835,7 @@ static HRESULT CALLBACK whpx_emu_setreg_callback(
|
||||||
* The emulator just successfully wrote the register state. We clear the
|
* The emulator just successfully wrote the register state. We clear the
|
||||||
* dirty state so we avoid the double write on resume of the VP.
|
* dirty state so we avoid the double write on resume of the VP.
|
||||||
*/
|
*/
|
||||||
cpu->accel->dirty = false;
|
cpu->vcpu_dirty = false;
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
@ -1391,7 +1390,7 @@ static int whpx_last_vcpu_stopping(CPUState *cpu)
|
||||||
/* Returns the address of the next instruction that is about to be executed. */
|
/* Returns the address of the next instruction that is about to be executed. */
|
||||||
static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid)
|
static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid)
|
||||||
{
|
{
|
||||||
if (cpu->accel->dirty) {
|
if (cpu->vcpu_dirty) {
|
||||||
/* The CPU registers have been modified by other parts of QEMU. */
|
/* The CPU registers have been modified by other parts of QEMU. */
|
||||||
return cpu_env(cpu)->eip;
|
return cpu_env(cpu)->eip;
|
||||||
} else if (exit_context_valid) {
|
} else if (exit_context_valid) {
|
||||||
|
|
@ -1704,9 +1703,9 @@ static int whpx_vcpu_run(CPUState *cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (cpu->accel->dirty) {
|
if (cpu->vcpu_dirty) {
|
||||||
whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);
|
whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);
|
||||||
cpu->accel->dirty = false;
|
cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exclusive_step_mode == WHPX_STEP_NONE) {
|
if (exclusive_step_mode == WHPX_STEP_NONE) {
|
||||||
|
|
@ -2054,9 +2053,9 @@ static int whpx_vcpu_run(CPUState *cpu)
|
||||||
|
|
||||||
static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
if (!cpu->accel->dirty) {
|
if (!cpu->vcpu_dirty) {
|
||||||
whpx_get_registers(cpu);
|
whpx_get_registers(cpu);
|
||||||
cpu->accel->dirty = true;
|
cpu->vcpu_dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2064,20 +2063,20 @@ static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,
|
||||||
run_on_cpu_data arg)
|
run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
whpx_set_registers(cpu, WHPX_SET_RESET_STATE);
|
whpx_set_registers(cpu, WHPX_SET_RESET_STATE);
|
||||||
cpu->accel->dirty = false;
|
cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,
|
static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,
|
||||||
run_on_cpu_data arg)
|
run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
whpx_set_registers(cpu, WHPX_SET_FULL_STATE);
|
whpx_set_registers(cpu, WHPX_SET_FULL_STATE);
|
||||||
cpu->accel->dirty = false;
|
cpu->vcpu_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,
|
static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,
|
||||||
run_on_cpu_data arg)
|
run_on_cpu_data arg)
|
||||||
{
|
{
|
||||||
cpu->accel->dirty = true;
|
cpu->vcpu_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -2086,7 +2085,7 @@ static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,
|
||||||
|
|
||||||
void whpx_cpu_synchronize_state(CPUState *cpu)
|
void whpx_cpu_synchronize_state(CPUState *cpu)
|
||||||
{
|
{
|
||||||
if (!cpu->accel->dirty) {
|
if (!cpu->vcpu_dirty) {
|
||||||
run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL);
|
run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2226,7 +2225,7 @@ int whpx_init_vcpu(CPUState *cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
vcpu->interruptable = true;
|
vcpu->interruptable = true;
|
||||||
vcpu->dirty = true;
|
cpu->vcpu_dirty = true;
|
||||||
cpu->accel = vcpu;
|
cpu->accel = vcpu;
|
||||||
max_vcpu_index = max(max_vcpu_index, cpu->cpu_index);
|
max_vcpu_index = max(max_vcpu_index, cpu->cpu_index);
|
||||||
qemu_add_vm_change_state_handler(whpx_cpu_update_state, env);
|
qemu_add_vm_change_state_handler(whpx_cpu_update_state, env);
|
||||||
|
|
@ -2505,7 +2504,7 @@ static void whpx_set_kernel_irqchip(Object *obj, Visitor *v,
|
||||||
* Partition support
|
* Partition support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int whpx_accel_init(MachineState *ms)
|
static int whpx_accel_init(AccelState *as, MachineState *ms)
|
||||||
{
|
{
|
||||||
struct whpx_state *whpx;
|
struct whpx_state *whpx;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -2689,11 +2688,6 @@ error:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int whpx_enabled(void)
|
|
||||||
{
|
|
||||||
return whpx_allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool whpx_apic_in_platform(void) {
|
bool whpx_apic_in_platform(void) {
|
||||||
return whpx_global.apic_in_platform;
|
return whpx_global.apic_in_platform;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ static int query_error_class(const char *cmd)
|
||||||
{ "x-query-usb", ERROR_CLASS_GENERIC_ERROR },
|
{ "x-query-usb", ERROR_CLASS_GENERIC_ERROR },
|
||||||
/* Only valid with accel=tcg */
|
/* Only valid with accel=tcg */
|
||||||
{ "x-query-jit", ERROR_CLASS_GENERIC_ERROR },
|
{ "x-query-jit", ERROR_CLASS_GENERIC_ERROR },
|
||||||
{ "x-query-opcount", ERROR_CLASS_GENERIC_ERROR },
|
|
||||||
{ "xen-event-list", ERROR_CLASS_GENERIC_ERROR },
|
{ "xen-event-list", ERROR_CLASS_GENERIC_ERROR },
|
||||||
{ NULL, -1 }
|
{ NULL, -1 }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue