summaryrefslogtreecommitdiffstats
path: root/target/i386
diff options
context:
space:
mode:
authorJon Doron2022-02-16 11:24:59 +0100
committerPaolo Bonzini2022-04-06 14:31:56 +0200
commit73d24074078a2cefb5305047e3bf50b73daa3f98 (patch)
tree79af4dadb4de590faf3baf6b689d9d682038f5b3 /target/i386
parenthyperv: Add definitions for syndbg (diff)
downloadqemu-73d24074078a2cefb5305047e3bf50b73daa3f98.tar.gz
qemu-73d24074078a2cefb5305047e3bf50b73daa3f98.tar.xz
qemu-73d24074078a2cefb5305047e3bf50b73daa3f98.zip
hyperv: Add support to process syndbg commands
SynDbg commands can come from two different flows: 1. Hypercalls, in this mode the data being sent is fully encapsulated network packets. 2. SynDbg specific MSRs, in this mode only the data that needs to be transfered is passed. Signed-off-by: Jon Doron <arilou@gmail.com> Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> Message-Id: <20220216102500.692781-4-arilou@gmail.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target/i386')
-rw-r--r--target/i386/cpu.c2
-rw-r--r--target/i386/cpu.h7
-rw-r--r--target/i386/kvm/hyperv-stub.c6
-rw-r--r--target/i386/kvm/hyperv.c52
-rw-r--r--target/i386/kvm/kvm.c76
5 files changed, 135 insertions, 8 deletions
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index cb6b5467d0..99343be926 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6927,6 +6927,8 @@ static Property x86_cpu_properties[] = {
HYPERV_FEAT_AVIC, 0),
DEFINE_PROP_ON_OFF_AUTO("hv-no-nonarch-coresharing", X86CPU,
hyperv_no_nonarch_cs, ON_OFF_AUTO_OFF),
+ DEFINE_PROP_BIT64("hv-syndbg", X86CPU, hyperv_features,
+ HYPERV_FEAT_SYNDBG, 0),
DEFINE_PROP_BOOL("hv-passthrough", X86CPU, hyperv_passthrough, false),
DEFINE_PROP_BOOL("hv-enforce-cpuid", X86CPU, hyperv_enforce_cpuid, false),
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 8422f6c18e..6b61124887 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1085,6 +1085,7 @@ uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
#define HYPERV_FEAT_IPI 13
#define HYPERV_FEAT_STIMER_DIRECT 14
#define HYPERV_FEAT_AVIC 15
+#define HYPERV_FEAT_SYNDBG 16
#ifndef HYPERV_SPINLOCK_NEVER_NOTIFY
#define HYPERV_SPINLOCK_NEVER_NOTIFY 0xFFFFFFFF
@@ -1601,6 +1602,12 @@ typedef struct CPUArchState {
uint64_t msr_hv_hypercall;
uint64_t msr_hv_guest_os_id;
uint64_t msr_hv_tsc;
+ uint64_t msr_hv_syndbg_control;
+ uint64_t msr_hv_syndbg_status;
+ uint64_t msr_hv_syndbg_send_page;
+ uint64_t msr_hv_syndbg_recv_page;
+ uint64_t msr_hv_syndbg_pending_page;
+ uint64_t msr_hv_syndbg_options;
/* Per-VCPU HV MSRs */
uint64_t msr_hv_vapic;
diff --git a/target/i386/kvm/hyperv-stub.c b/target/i386/kvm/hyperv-stub.c
index 0028527e79..778ed782e6 100644
--- a/target/i386/kvm/hyperv-stub.c
+++ b/target/i386/kvm/hyperv-stub.c
@@ -28,6 +28,12 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
case KVM_EXIT_HYPERV_HCALL:
exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE;
return 0;
+ case KVM_EXIT_HYPERV_SYNDBG:
+ if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) {
+ return -1;
+ }
+
+ return 0;
default:
return -1;
}
diff --git a/target/i386/kvm/hyperv.c b/target/i386/kvm/hyperv.c
index 26efc1e0e6..9026ef3a81 100644
--- a/target/i386/kvm/hyperv.c
+++ b/target/i386/kvm/hyperv.c
@@ -81,20 +81,66 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
case KVM_EXIT_HYPERV_HCALL: {
uint16_t code = exit->u.hcall.input & 0xffff;
bool fast = exit->u.hcall.input & HV_HYPERCALL_FAST;
- uint64_t param = exit->u.hcall.params[0];
+ uint64_t in_param = exit->u.hcall.params[0];
+ uint64_t out_param = exit->u.hcall.params[1];
switch (code) {
case HV_POST_MESSAGE:
- exit->u.hcall.result = hyperv_hcall_post_message(param, fast);
+ exit->u.hcall.result = hyperv_hcall_post_message(in_param, fast);
break;
case HV_SIGNAL_EVENT:
- exit->u.hcall.result = hyperv_hcall_signal_event(param, fast);
+ exit->u.hcall.result = hyperv_hcall_signal_event(in_param, fast);
+ break;
+ case HV_POST_DEBUG_DATA:
+ exit->u.hcall.result =
+ hyperv_hcall_post_dbg_data(in_param, out_param, fast);
+ break;
+ case HV_RETRIEVE_DEBUG_DATA:
+ exit->u.hcall.result =
+ hyperv_hcall_retreive_dbg_data(in_param, out_param, fast);
+ break;
+ case HV_RESET_DEBUG_SESSION:
+ exit->u.hcall.result =
+ hyperv_hcall_reset_dbg_session(out_param);
break;
default:
exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE;
}
return 0;
}
+
+ case KVM_EXIT_HYPERV_SYNDBG:
+ if (!hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) {
+ return -1;
+ }
+
+ switch (exit->u.syndbg.msr) {
+ case HV_X64_MSR_SYNDBG_CONTROL: {
+ uint64_t control = exit->u.syndbg.control;
+ env->msr_hv_syndbg_control = control;
+ env->msr_hv_syndbg_send_page = exit->u.syndbg.send_page;
+ env->msr_hv_syndbg_recv_page = exit->u.syndbg.recv_page;
+ exit->u.syndbg.status = HV_STATUS_SUCCESS;
+ if (control & HV_SYNDBG_CONTROL_SEND) {
+ exit->u.syndbg.status =
+ hyperv_syndbg_send(env->msr_hv_syndbg_send_page,
+ HV_SYNDBG_CONTROL_SEND_SIZE(control));
+ } else if (control & HV_SYNDBG_CONTROL_RECV) {
+ exit->u.syndbg.status =
+ hyperv_syndbg_recv(env->msr_hv_syndbg_recv_page,
+ TARGET_PAGE_SIZE);
+ }
+ break;
+ }
+ case HV_X64_MSR_SYNDBG_PENDING_BUFFER:
+ env->msr_hv_syndbg_pending_page = exit->u.syndbg.pending_page;
+ hyperv_syndbg_set_pending_page(env->msr_hv_syndbg_pending_page);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
default:
return -1;
}
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 9cf8e03669..0bb3176edc 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -104,6 +104,7 @@ static bool has_msr_hv_synic;
static bool has_msr_hv_stimer;
static bool has_msr_hv_frequencies;
static bool has_msr_hv_reenlightenment;
+static bool has_msr_hv_syndbg_options;
static bool has_msr_xss;
static bool has_msr_umwait;
static bool has_msr_spec_ctrl;
@@ -964,6 +965,14 @@ static struct {
.bits = HV_DEPRECATING_AEOI_RECOMMENDED}
}
},
+ [HYPERV_FEAT_SYNDBG] = {
+ .desc = "Enable synthetic kernel debugger channel (hv-syndbg)",
+ .flags = {
+ {.func = HV_CPUID_FEATURES, .reg = R_EDX,
+ .bits = HV_FEATURE_DEBUG_MSRS_AVAILABLE}
+ },
+ .dependencies = BIT(HYPERV_FEAT_SYNIC) | BIT(HYPERV_FEAT_RELAXED)
+ },
};
static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max,
@@ -1004,8 +1013,8 @@ static struct kvm_cpuid2 *try_get_hv_cpuid(CPUState *cs, int max,
static struct kvm_cpuid2 *get_supported_hv_cpuid(CPUState *cs)
{
struct kvm_cpuid2 *cpuid;
- /* 0x40000000..0x40000005, 0x4000000A, 0x40000080..0x40000080 leaves */
- int max = 10;
+ /* 0x40000000..0x40000005, 0x4000000A, 0x40000080..0x40000082 leaves */
+ int max = 11;
int i;
bool do_sys_ioctl;
@@ -1118,6 +1127,12 @@ static struct kvm_cpuid2 *get_supported_hv_cpuid_legacy(CPUState *cs)
entry_feat->eax |= HV_SYNTIMERS_AVAILABLE;
}
+ if (has_msr_hv_syndbg_options) {
+ entry_feat->edx |= HV_GUEST_DEBUGGING_AVAILABLE;
+ entry_feat->edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE;
+ entry_feat->ebx |= HV_PARTITION_DEBUGGING_ALLOWED;
+ }
+
if (kvm_check_extension(cs->kvm_state,
KVM_CAP_HYPERV_TLBFLUSH) > 0) {
entry_recomm->eax |= HV_REMOTE_TLB_FLUSH_RECOMMENDED;
@@ -1369,12 +1384,22 @@ static int hyperv_fill_cpuids(CPUState *cs,
{
X86CPU *cpu = X86_CPU(cs);
struct kvm_cpuid_entry2 *c;
- uint32_t cpuid_i = 0;
+ uint32_t signature[3];
+ uint32_t cpuid_i = 0, max_cpuid_leaf = 0;
+
+ max_cpuid_leaf = HV_CPUID_IMPLEMENT_LIMITS;
+ if (hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS)) {
+ max_cpuid_leaf = MAX(max_cpuid_leaf, HV_CPUID_NESTED_FEATURES);
+ }
+
+ if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) {
+ max_cpuid_leaf =
+ MAX(max_cpuid_leaf, HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES);
+ }
c = &cpuid_ent[cpuid_i++];
c->function = HV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
- c->eax = hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) ?
- HV_CPUID_NESTED_FEATURES : HV_CPUID_IMPLEMENT_LIMITS;
+ c->eax = max_cpuid_leaf;
c->ebx = cpu->hyperv_vendor_id[0];
c->ecx = cpu->hyperv_vendor_id[1];
c->edx = cpu->hyperv_vendor_id[2];
@@ -1453,6 +1478,33 @@ static int hyperv_fill_cpuids(CPUState *cs,
c->eax = cpu->hyperv_nested[0];
}
+ if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG)) {
+ c = &cpuid_ent[cpuid_i++];
+ c->function = HV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS;
+ c->eax = hyperv_feat_enabled(cpu, HYPERV_FEAT_EVMCS) ?
+ HV_CPUID_NESTED_FEATURES : HV_CPUID_IMPLEMENT_LIMITS;
+ memcpy(signature, "Microsoft VS", 12);
+ c->eax = 0;
+ c->ebx = signature[0];
+ c->ecx = signature[1];
+ c->edx = signature[2];
+
+ c = &cpuid_ent[cpuid_i++];
+ c->function = HV_CPUID_SYNDBG_INTERFACE;
+ memcpy(signature, "VS#1\0\0\0\0\0\0\0\0", 12);
+ c->eax = signature[0];
+ c->ebx = 0;
+ c->ecx = 0;
+ c->edx = 0;
+
+ c = &cpuid_ent[cpuid_i++];
+ c->function = HV_CPUID_SYNDBG_PLATFORM_CAPABILITIES;
+ c->eax = HV_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
+ c->ebx = 0;
+ c->ecx = 0;
+ c->edx = 0;
+ }
+
return cpuid_i;
}
@@ -2261,6 +2313,9 @@ static int kvm_get_supported_msrs(KVMState *s)
case HV_X64_MSR_REENLIGHTENMENT_CONTROL:
has_msr_hv_reenlightenment = true;
break;
+ case HV_X64_MSR_SYNDBG_OPTIONS:
+ has_msr_hv_syndbg_options = true;
+ break;
case MSR_IA32_SPEC_CTRL:
has_msr_spec_ctrl = true;
break;
@@ -3178,6 +3233,11 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_STATUS,
env->msr_hv_tsc_emulation_status);
}
+ if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNDBG) &&
+ has_msr_hv_syndbg_options) {
+ kvm_msr_entry_add(cpu, HV_X64_MSR_SYNDBG_OPTIONS,
+ hyperv_syndbg_query_options());
+ }
}
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_VAPIC)) {
kvm_msr_entry_add(cpu, HV_X64_MSR_APIC_ASSIST_PAGE,
@@ -3619,6 +3679,9 @@ static int kvm_get_msrs(X86CPU *cpu)
kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_CONTROL, 0);
kvm_msr_entry_add(cpu, HV_X64_MSR_TSC_EMULATION_STATUS, 0);
}
+ if (has_msr_hv_syndbg_options) {
+ kvm_msr_entry_add(cpu, HV_X64_MSR_SYNDBG_OPTIONS, 0);
+ }
if (has_msr_hv_crash) {
int j;
@@ -3910,6 +3973,9 @@ static int kvm_get_msrs(X86CPU *cpu)
case HV_X64_MSR_TSC_EMULATION_STATUS:
env->msr_hv_tsc_emulation_status = msrs[i].data;
break;
+ case HV_X64_MSR_SYNDBG_OPTIONS:
+ env->msr_hv_syndbg_options = msrs[i].data;
+ break;
case MSR_MTRRdefType:
env->mtrr_deftype = msrs[i].data;
break;