mirror of https://github.com/xemu-project/xemu.git
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>
This commit is contained in:
parent
ccbdf5e81b
commit
73d2407407
|
@ -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 .
|
||||
When 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
|
||||
=========================
|
||||
|
||||
|
|
|
@ -704,3 +704,246 @@ 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;
|
||||
}
|
||||
|
|
|
@ -81,4 +81,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
|
||||
|
|
|
@ -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),
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue