qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
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;
>>
>


  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).