From: Jon Doron <arilou@gmail.com>
To: qemu-devel@nongnu.org
Cc: pbonzini@redhat.com, vkuznets@redhat.com, Jon Doron <arilou@gmail.com>
Subject: [PATCH v1 3/4] hyperv: Add support to process syndbg commands
Date: Fri, 4 Feb 2022 12:07:22 +0200 [thread overview]
Message-ID: <20220204100723.406121-4-arilou@gmail.com> (raw)
In-Reply-To: <20220204100723.406121-1-arilou@gmail.com>
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>
---
docs/hyperv.txt | 15 +++
hw/hyperv/hyperv.c | 242 ++++++++++++++++++++++++++++++++++
include/hw/hyperv/hyperv.h | 58 ++++++++
target/i386/cpu.c | 2 +
target/i386/cpu.h | 7 +
target/i386/kvm/hyperv-stub.c | 6 +
target/i386/kvm/hyperv.c | 52 +++++++-
target/i386/kvm/kvm.c | 76 ++++++++++-
8 files changed, 450 insertions(+), 8 deletions(-)
diff --git a/docs/hyperv.txt b/docs/hyperv.txt
index 0417c183a3..7abc1b2d89 100644
--- a/docs/hyperv.txt
+++ b/docs/hyperv.txt
@@ -225,6 +225,21 @@ default (WS2016).
Note: hv-version-id-* are not enlightenments and thus don't enable Hyper-V
identification when specified without any other enlightenments.
+3.21. hv-syndbg
+===============
+Enables Hyper-V synthetic debugger interface, this is a special interface used
+by Windows Kernel debugger to send the packets through, rather than sending
+them via serial/network .
+Whe enabled, this enlightenment provides additional communication facilities
+to the guest: SynDbg messages.
+This new communication is used by Windows Kernel debugger rather than sending
+packets via serial/network, adding significant performance boost over the other
+comm channels.
+This enlightenment requires a VMBus device (-device vmbus-bridge,irq=15)
+and the follow enlightenments to work:
+hv-relaxed,hv_time,hv-vapic,hv-vpindex,hv-synic,hv-runtime,hv-stimer
+
+
4. Supplementary features
=========================
diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 88c9cc1334..c86e2aa02e 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -730,3 +730,245 @@ uint16_t hyperv_hcall_signal_event(uint64_t param, bool fast)
}
return HV_STATUS_INVALID_CONNECTION_ID;
}
+
+static HvSynDbgHandler hv_syndbg_handler;
+static void *hv_syndbg_context;
+void hyperv_set_syndbg_handler(HvSynDbgHandler handler, void *context)
+{
+ assert(!hv_syndbg_handler);
+ hv_syndbg_handler = handler;
+ hv_syndbg_context = context;
+}
+
+uint16_t hyperv_hcall_reset_dbg_session(uint64_t outgpa)
+{
+ uint16_t ret;
+ HvSynDbgMsg msg;
+ struct hyperv_reset_debug_session_output *reset_dbg_session = NULL;
+ hwaddr len;
+
+ if (!hv_syndbg_handler) {
+ ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+ goto cleanup;
+ }
+
+ len = sizeof(*reset_dbg_session);
+ reset_dbg_session = cpu_physical_memory_map(outgpa, &len, 1);
+ if (!reset_dbg_session || len < sizeof(*reset_dbg_session)) {
+ ret = HV_STATUS_INSUFFICIENT_MEMORY;
+ goto cleanup;
+ }
+
+ msg.type = HV_SYNDBG_MSG_CONNECTION_INFO;
+ ret = hv_syndbg_handler(hv_syndbg_context, &msg);
+ if (ret) {
+ goto cleanup;
+ }
+
+ reset_dbg_session->host_ip = msg.u.connection_info.host_ip;
+ reset_dbg_session->host_port = msg.u.connection_info.host_port;
+ /* The following fields are only used as validation for KDVM */
+ memset(&reset_dbg_session->host_mac, 0,
+ sizeof(reset_dbg_session->host_mac));
+ reset_dbg_session->target_ip = msg.u.connection_info.host_ip;
+ reset_dbg_session->target_port = msg.u.connection_info.host_port;
+ memset(&reset_dbg_session->target_mac, 0,
+ sizeof(reset_dbg_session->target_mac));
+cleanup:
+ if (reset_dbg_session) {
+ cpu_physical_memory_unmap(reset_dbg_session,
+ sizeof(*reset_dbg_session), 1, len);
+ }
+
+ return ret;
+}
+
+uint16_t hyperv_hcall_retreive_dbg_data(uint64_t ingpa, uint64_t outgpa,
+ bool fast)
+{
+ uint16_t ret;
+ struct hyperv_retrieve_debug_data_input *debug_data_in = NULL;
+ struct hyperv_retrieve_debug_data_output *debug_data_out = NULL;
+ hwaddr in_len, out_len;
+ HvSynDbgMsg msg;
+
+ if (fast || !hv_syndbg_handler) {
+ ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+ goto cleanup;
+ }
+
+ in_len = sizeof(*debug_data_in);
+ debug_data_in = cpu_physical_memory_map(ingpa, &in_len, 0);
+ if (!debug_data_in || in_len < sizeof(*debug_data_in)) {
+ ret = HV_STATUS_INSUFFICIENT_MEMORY;
+ goto cleanup;
+ }
+
+ out_len = sizeof(*debug_data_out);
+ debug_data_out = cpu_physical_memory_map(outgpa, &out_len, 1);
+ if (!debug_data_out || out_len < sizeof(*debug_data_out)) {
+ ret = HV_STATUS_INSUFFICIENT_MEMORY;
+ goto cleanup;
+ }
+
+ msg.type = HV_SYNDBG_MSG_RECV;
+ msg.u.recv.buf_gpa = outgpa + sizeof(*debug_data_out);
+ msg.u.recv.count = TARGET_PAGE_SIZE - sizeof(*debug_data_out);
+ msg.u.recv.options = debug_data_in->options;
+ msg.u.recv.timeout = debug_data_in->timeout;
+ msg.u.recv.is_raw = true;
+ ret = hv_syndbg_handler(hv_syndbg_context, &msg);
+ if (ret == HV_STATUS_NO_DATA) {
+ debug_data_out->retrieved_count = 0;
+ debug_data_out->remaining_count = debug_data_in->count;
+ goto cleanup;
+ } else if (ret != HV_STATUS_SUCCESS) {
+ goto cleanup;
+ }
+
+ debug_data_out->retrieved_count = msg.u.recv.retrieved_count;
+ debug_data_out->remaining_count =
+ debug_data_in->count - msg.u.recv.retrieved_count;
+cleanup:
+ if (debug_data_out) {
+ cpu_physical_memory_unmap(debug_data_out, sizeof(*debug_data_out), 1,
+ out_len);
+ }
+
+ if (debug_data_in) {
+ cpu_physical_memory_unmap(debug_data_in, sizeof(*debug_data_in), 0,
+ in_len);
+ }
+
+ return ret;
+}
+
+uint16_t hyperv_hcall_post_dbg_data(uint64_t ingpa, uint64_t outgpa, bool fast)
+{
+ uint16_t ret;
+ struct hyperv_post_debug_data_input *post_data_in = NULL;
+ struct hyperv_post_debug_data_output *post_data_out = NULL;
+ hwaddr in_len, out_len;
+ HvSynDbgMsg msg;
+
+ if (fast || !hv_syndbg_handler) {
+ ret = HV_STATUS_INVALID_HYPERCALL_CODE;
+ goto cleanup;
+ }
+
+ in_len = sizeof(*post_data_in);
+ post_data_in = cpu_physical_memory_map(ingpa, &in_len, 0);
+ if (!post_data_in || in_len < sizeof(*post_data_in)) {
+ ret = HV_STATUS_INSUFFICIENT_MEMORY;
+ goto cleanup;
+ }
+
+ if (post_data_in->count > TARGET_PAGE_SIZE - sizeof(*post_data_in)) {
+ ret = HV_STATUS_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ out_len = sizeof(*post_data_out);
+ post_data_out = cpu_physical_memory_map(outgpa, &out_len, 1);
+ if (!post_data_out || out_len < sizeof(*post_data_out)) {
+ ret = HV_STATUS_INSUFFICIENT_MEMORY;
+ goto cleanup;
+ }
+
+ msg.type = HV_SYNDBG_MSG_SEND;
+ msg.u.send.buf_gpa = ingpa + sizeof(*post_data_in);
+ msg.u.send.count = post_data_in->count;
+ msg.u.send.is_raw = true;
+ ret = hv_syndbg_handler(hv_syndbg_context, &msg);
+ if (ret != HV_STATUS_SUCCESS) {
+ goto cleanup;
+ }
+
+ post_data_out->pending_count = msg.u.send.pending_count;
+ ret = post_data_out->pending_count ? HV_STATUS_INSUFFICIENT_BUFFERS :
+ HV_STATUS_SUCCESS;
+cleanup:
+ if (post_data_out) {
+ cpu_physical_memory_unmap(post_data_out,
+ sizeof(*post_data_out), 1, out_len);
+ }
+
+ if (post_data_in) {
+ cpu_physical_memory_unmap(post_data_in,
+ sizeof(*post_data_in), 0, in_len);
+ }
+
+ return ret;
+}
+
+uint32_t hyperv_syndbg_send(uint64_t ingpa, uint32_t count)
+{
+ HvSynDbgMsg msg;
+
+ if (!hv_syndbg_handler) {
+ return HV_SYNDBG_STATUS_INVALID;
+ }
+
+ msg.type = HV_SYNDBG_MSG_SEND;
+ msg.u.send.buf_gpa = ingpa;
+ msg.u.send.count = count;
+ msg.u.send.is_raw = false;
+ if (hv_syndbg_handler(hv_syndbg_context, &msg)) {
+ return HV_SYNDBG_STATUS_INVALID;
+ }
+
+ return HV_SYNDBG_STATUS_SEND_SUCCESS;
+}
+
+uint32_t hyperv_syndbg_recv(uint64_t ingpa, uint32_t count)
+{
+ uint16_t ret;
+ HvSynDbgMsg msg;
+
+ if (!hv_syndbg_handler) {
+ return HV_SYNDBG_STATUS_INVALID;
+ }
+
+ msg.type = HV_SYNDBG_MSG_RECV;
+ msg.u.recv.buf_gpa = ingpa;
+ msg.u.recv.count = count;
+ msg.u.recv.options = 0;
+ msg.u.recv.timeout = 0;
+ msg.u.recv.is_raw = false;
+ ret = hv_syndbg_handler(hv_syndbg_context, &msg);
+ if (ret != HV_STATUS_SUCCESS) {
+ return 0;
+ }
+
+ return HV_SYNDBG_STATUS_SET_SIZE(HV_SYNDBG_STATUS_RECV_SUCCESS,
+ msg.u.recv.retrieved_count);
+}
+
+void hyperv_syndbg_set_pending_page(uint64_t ingpa)
+{
+ HvSynDbgMsg msg;
+
+ if (!hv_syndbg_handler) {
+ return;
+ }
+
+ msg.type = HV_SYNDBG_MSG_SET_PENDING_PAGE;
+ msg.u.pending_page.buf_gpa = ingpa;
+ hv_syndbg_handler(hv_syndbg_context, &msg);
+}
+
+uint64_t hyperv_syndbg_query_options(void)
+{
+ HvSynDbgMsg msg;
+
+ if (!hv_syndbg_handler) {
+ return 0;
+ }
+
+ msg.type = HV_SYNDBG_MSG_QUERY_OPTIONS;
+ if (hv_syndbg_handler(hv_syndbg_context, &msg) != HV_STATUS_SUCCESS) {
+ return 0;
+ }
+
+ return msg.u.query_options.options;
+}
diff --git a/include/hw/hyperv/hyperv.h b/include/hw/hyperv/hyperv.h
index ef9f6b6c09..e7a85156b0 100644
--- a/include/hw/hyperv/hyperv.h
+++ b/include/hw/hyperv/hyperv.h
@@ -83,4 +83,62 @@ void hyperv_synic_update(CPUState *cs, bool enable,
hwaddr msg_page_addr, hwaddr event_page_addr);
bool hyperv_is_synic_enabled(void);
+/*
+ * Process HVCALL_RESET_DEBUG_SESSION hypercall.
+ */
+uint16_t hyperv_hcall_reset_dbg_session(uint64_t outgpa);
+/*
+ * Process HVCALL_RETREIVE_DEBUG_DATA hypercall.
+ */
+uint16_t hyperv_hcall_retreive_dbg_data(uint64_t ingpa, uint64_t outgpa,
+ bool fast);
+/*
+ * Process HVCALL_POST_DEBUG_DATA hypercall.
+ */
+uint16_t hyperv_hcall_post_dbg_data(uint64_t ingpa, uint64_t outgpa, bool fast);
+
+uint32_t hyperv_syndbg_send(uint64_t ingpa, uint32_t count);
+uint32_t hyperv_syndbg_recv(uint64_t ingpa, uint32_t count);
+void hyperv_syndbg_set_pending_page(uint64_t ingpa);
+uint64_t hyperv_syndbg_query_options(void);
+
+typedef enum HvSynthDbgMsgType {
+ HV_SYNDBG_MSG_CONNECTION_INFO,
+ HV_SYNDBG_MSG_SEND,
+ HV_SYNDBG_MSG_RECV,
+ HV_SYNDBG_MSG_SET_PENDING_PAGE,
+ HV_SYNDBG_MSG_QUERY_OPTIONS
+} HvDbgSynthMsgType;
+
+typedef struct HvSynDbgMsg {
+ HvDbgSynthMsgType type;
+ union {
+ struct {
+ uint32_t host_ip;
+ uint16_t host_port;
+ } connection_info;
+ struct {
+ uint64_t buf_gpa;
+ uint32_t count;
+ uint32_t pending_count;
+ bool is_raw;
+ } send;
+ struct {
+ uint64_t buf_gpa;
+ uint32_t count;
+ uint32_t options;
+ uint64_t timeout;
+ uint32_t retrieved_count;
+ bool is_raw;
+ } recv;
+ struct {
+ uint64_t buf_gpa;
+ } pending_page;
+ struct {
+ uint64_t options;
+ } query_options;
+ } u;
+} HvSynDbgMsg;
+typedef uint16_t (*HvSynDbgHandler)(void *context, HvSynDbgMsg *msg);
+void hyperv_set_syndbg_handler(HvSynDbgHandler handler, void *context);
#endif
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index aa9e636800..9529a6389a 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -6841,6 +6841,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 9911d7c871..56e0317924 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1060,6 +1060,7 @@ typedef uint64_t FeatureWordArray[FEATURE_WORDS];
#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
@@ -1560,6 +1561,12 @@ typedef struct CPUX86State {
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
@@ -27,6 +27,12 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
return 0;
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..a70f695205 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_RETREIVE_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 2c8feb4a6f..ecabb332d7 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -102,6 +102,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;
@@ -932,6 +933,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,
@@ -972,8 +981,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;
@@ -1086,6 +1095,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_DEUBGGING_ALLOWED;
+ }
+
if (kvm_check_extension(cs->kvm_state,
KVM_CAP_HYPERV_TLBFLUSH) > 0) {
entry_recomm->eax |= HV_REMOTE_TLB_FLUSH_RECOMMENDED;
@@ -1337,12 +1352,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];
@@ -1421,6 +1446,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;
}
@@ -2215,6 +2267,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;
@@ -3132,6 +3187,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,
@@ -3565,6 +3625,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;
@@ -3851,6 +3914,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;
--
2.34.1
next prev parent reply other threads:[~2022-02-04 10:12 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-04 10:07 [PATCH v1 0/4] HyperV: Synthetic Debugging device Jon Doron
2022-02-04 10:07 ` [PATCH v1 1/4] hyperv: SControl is optional to enable SynIc Jon Doron
2022-02-16 9:10 ` Emanuele Giuseppe Esposito
2022-02-16 10:27 ` Jon Doron
2022-02-04 10:07 ` [PATCH v1 2/4] hyperv: Add definitions for syndbg Jon Doron
2022-02-16 9:10 ` Emanuele Giuseppe Esposito
2022-02-16 10:27 ` Jon Doron
2022-02-04 10:07 ` Jon Doron [this message]
2022-02-16 9:10 ` [PATCH v1 3/4] hyperv: Add support to process syndbg commands Emanuele Giuseppe Esposito
2022-02-16 10:28 ` Jon Doron
2022-02-04 10:07 ` [PATCH v1 4/4] hw: hyperv: Initial commit for Synthetic Debugging device Jon Doron
2022-02-16 9:11 ` Emanuele Giuseppe Esposito
2022-02-16 10:28 ` Jon Doron
2022-02-13 7:49 ` [PATCH v1 0/4] HyperV: " Jon Doron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220204100723.406121-4-arilou@gmail.com \
--to=arilou@gmail.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=vkuznets@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.