From: Jon Doron <arilou@gmail.com>
To: Emanuele Giuseppe Esposito <eesposit@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>,
Vitaly Kuznetsov <vkuznets@redhat.com>,
qemu-devel@nongnu.org
Subject: Re: [PATCH v1 3/4] hyperv: Add support to process syndbg commands
Date: Wed, 16 Feb 2022 12:28:12 +0200 [thread overview]
Message-ID: <YgzRvOjUmb+GFx//@jondnuc> (raw)
In-Reply-To: <463ce2ca-232f-c68f-5deb-c66bd067b81d@redhat.com>
On 16/02/2022, Emanuele Giuseppe Esposito wrote:
>
>
>On 04/02/2022 11:07, Jon Doron wrote:
>> 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
>
>When
>
Done
>> +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;
>
>Add a line here between field and function definition.
>
Done
>> +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;
>>
>
next prev parent reply other threads:[~2022-02-16 10:40 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 ` [PATCH v1 3/4] hyperv: Add support to process syndbg commands Jon Doron
2022-02-16 9:10 ` Emanuele Giuseppe Esposito
2022-02-16 10:28 ` Jon Doron [this message]
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=YgzRvOjUmb+GFx//@jondnuc \
--to=arilou@gmail.com \
--cc=eesposit@redhat.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).