Skip to content

Commit f97f5a5

Browse files
ariloubonzini
authored andcommitted
x86/kvm/hyper-v: Add support for synthetic debugger interface
Add support for Hyper-V synthetic debugger (syndbg) interface. The syndbg interface is using MSRs to emulate a way to send/recv packets data. The debug transport dll (kdvm/kdnet) will identify if Hyper-V is enabled and if it supports the synthetic debugger interface it will attempt to use it, instead of trying to initialize a network adapter. Reviewed-by: Vitaly Kuznetsov <[email protected]> Signed-off-by: Jon Doron <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 22ad002 commit f97f5a5

File tree

7 files changed

+258
-3
lines changed

7 files changed

+258
-3
lines changed

Documentation/virt/kvm/api.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5070,6 +5070,7 @@ EOI was received.
50705070
struct kvm_hyperv_exit {
50715071
#define KVM_EXIT_HYPERV_SYNIC 1
50725072
#define KVM_EXIT_HYPERV_HCALL 2
5073+
#define KVM_EXIT_HYPERV_SYNDBG 3
50735074
__u32 type;
50745075
__u32 pad1;
50755076
union {
@@ -5085,6 +5086,15 @@ EOI was received.
50855086
__u64 result;
50865087
__u64 params[2];
50875088
} hcall;
5089+
struct {
5090+
__u32 msr;
5091+
__u32 pad2;
5092+
__u64 control;
5093+
__u64 status;
5094+
__u64 send_page;
5095+
__u64 recv_page;
5096+
__u64 pending_page;
5097+
} syndbg;
50885098
} u;
50895099
};
50905100
/* KVM_EXIT_HYPERV */
@@ -5101,6 +5111,12 @@ Hyper-V SynIC state change. Notification is used to remap SynIC
51015111
event/message pages and to enable/disable SynIC messages/events processing
51025112
in userspace.
51035113

5114+
- KVM_EXIT_HYPERV_SYNDBG -- synchronously notify user-space about
5115+
5116+
Hyper-V Synthetic debugger state change. Notification is used to either update
5117+
the pending_page location or to send a control command (send the buffer located
5118+
in send_page or recv a buffer to recv_page).
5119+
51045120
::
51055121

51065122
/* KVM_EXIT_ARM_NISV */

arch/x86/include/asm/kvm_host.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,18 @@ struct kvm_apic_map {
863863
struct kvm_lapic *phys_map[];
864864
};
865865

866+
/* Hyper-V synthetic debugger (SynDbg)*/
867+
struct kvm_hv_syndbg {
868+
struct {
869+
u64 control;
870+
u64 status;
871+
u64 send_page;
872+
u64 recv_page;
873+
u64 pending_page;
874+
} control;
875+
u64 options;
876+
};
877+
866878
/* Hyper-V emulation context */
867879
struct kvm_hv {
868880
struct mutex hv_lock;
@@ -886,6 +898,7 @@ struct kvm_hv {
886898
atomic_t num_mismatched_vp_indexes;
887899

888900
struct hv_partition_assist_pg *hv_pa_pg;
901+
struct kvm_hv_syndbg hv_syndbg;
889902
};
890903

891904
enum kvm_irqchip_mode {

arch/x86/kvm/hyperv.c

Lines changed: 155 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "x86.h"
2222
#include "lapic.h"
2323
#include "ioapic.h"
24+
#include "cpuid.h"
2425
#include "hyperv.h"
2526

2627
#include <linux/cpu.h>
@@ -266,6 +267,123 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
266267
return ret;
267268
}
268269

270+
static bool kvm_hv_is_syndbg_enabled(struct kvm_vcpu *vcpu)
271+
{
272+
struct kvm_cpuid_entry2 *entry;
273+
274+
entry = kvm_find_cpuid_entry(vcpu,
275+
HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES,
276+
0);
277+
if (!entry)
278+
return false;
279+
280+
return entry->eax & HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
281+
}
282+
283+
static int kvm_hv_syndbg_complete_userspace(struct kvm_vcpu *vcpu)
284+
{
285+
struct kvm *kvm = vcpu->kvm;
286+
struct kvm_hv *hv = &kvm->arch.hyperv;
287+
288+
if (vcpu->run->hyperv.u.syndbg.msr == HV_X64_MSR_SYNDBG_CONTROL)
289+
hv->hv_syndbg.control.status =
290+
vcpu->run->hyperv.u.syndbg.status;
291+
return 1;
292+
}
293+
294+
static void syndbg_exit(struct kvm_vcpu *vcpu, u32 msr)
295+
{
296+
struct kvm_hv_syndbg *syndbg = vcpu_to_hv_syndbg(vcpu);
297+
struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv;
298+
299+
hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNDBG;
300+
hv_vcpu->exit.u.syndbg.msr = msr;
301+
hv_vcpu->exit.u.syndbg.control = syndbg->control.control;
302+
hv_vcpu->exit.u.syndbg.send_page = syndbg->control.send_page;
303+
hv_vcpu->exit.u.syndbg.recv_page = syndbg->control.recv_page;
304+
hv_vcpu->exit.u.syndbg.pending_page = syndbg->control.pending_page;
305+
vcpu->arch.complete_userspace_io =
306+
kvm_hv_syndbg_complete_userspace;
307+
308+
kvm_make_request(KVM_REQ_HV_EXIT, vcpu);
309+
}
310+
311+
static int syndbg_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
312+
{
313+
struct kvm_hv_syndbg *syndbg = vcpu_to_hv_syndbg(vcpu);
314+
315+
if (!kvm_hv_is_syndbg_enabled(vcpu) && !host)
316+
return 1;
317+
318+
trace_kvm_hv_syndbg_set_msr(vcpu->vcpu_id,
319+
vcpu_to_hv_vcpu(vcpu)->vp_index, msr, data);
320+
switch (msr) {
321+
case HV_X64_MSR_SYNDBG_CONTROL:
322+
syndbg->control.control = data;
323+
if (!host)
324+
syndbg_exit(vcpu, msr);
325+
break;
326+
case HV_X64_MSR_SYNDBG_STATUS:
327+
syndbg->control.status = data;
328+
break;
329+
case HV_X64_MSR_SYNDBG_SEND_BUFFER:
330+
syndbg->control.send_page = data;
331+
break;
332+
case HV_X64_MSR_SYNDBG_RECV_BUFFER:
333+
syndbg->control.recv_page = data;
334+
break;
335+
case HV_X64_MSR_SYNDBG_PENDING_BUFFER:
336+
syndbg->control.pending_page = data;
337+
if (!host)
338+
syndbg_exit(vcpu, msr);
339+
break;
340+
case HV_X64_MSR_SYNDBG_OPTIONS:
341+
syndbg->options = data;
342+
break;
343+
default:
344+
break;
345+
}
346+
347+
return 0;
348+
}
349+
350+
static int syndbg_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host)
351+
{
352+
struct kvm_hv_syndbg *syndbg = vcpu_to_hv_syndbg(vcpu);
353+
354+
if (!kvm_hv_is_syndbg_enabled(vcpu) && !host)
355+
return 1;
356+
357+
switch (msr) {
358+
case HV_X64_MSR_SYNDBG_CONTROL:
359+
*pdata = syndbg->control.control;
360+
break;
361+
case HV_X64_MSR_SYNDBG_STATUS:
362+
*pdata = syndbg->control.status;
363+
break;
364+
case HV_X64_MSR_SYNDBG_SEND_BUFFER:
365+
*pdata = syndbg->control.send_page;
366+
break;
367+
case HV_X64_MSR_SYNDBG_RECV_BUFFER:
368+
*pdata = syndbg->control.recv_page;
369+
break;
370+
case HV_X64_MSR_SYNDBG_PENDING_BUFFER:
371+
*pdata = syndbg->control.pending_page;
372+
break;
373+
case HV_X64_MSR_SYNDBG_OPTIONS:
374+
*pdata = syndbg->options;
375+
break;
376+
default:
377+
break;
378+
}
379+
380+
trace_kvm_hv_syndbg_get_msr(vcpu->vcpu_id,
381+
vcpu_to_hv_vcpu(vcpu)->vp_index, msr,
382+
*pdata);
383+
384+
return 0;
385+
}
386+
269387
static int synic_get_msr(struct kvm_vcpu_hv_synic *synic, u32 msr, u64 *pdata,
270388
bool host)
271389
{
@@ -800,6 +918,8 @@ static bool kvm_hv_msr_partition_wide(u32 msr)
800918
case HV_X64_MSR_REENLIGHTENMENT_CONTROL:
801919
case HV_X64_MSR_TSC_EMULATION_CONTROL:
802920
case HV_X64_MSR_TSC_EMULATION_STATUS:
921+
case HV_X64_MSR_SYNDBG_OPTIONS:
922+
case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
803923
r = true;
804924
break;
805925
}
@@ -1061,6 +1181,9 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
10611181
if (!host)
10621182
return 1;
10631183
break;
1184+
case HV_X64_MSR_SYNDBG_OPTIONS:
1185+
case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
1186+
return syndbg_set_msr(vcpu, msr, data, host);
10641187
default:
10651188
vcpu_unimpl(vcpu, "Hyper-V unhandled wrmsr: 0x%x data 0x%llx\n",
10661189
msr, data);
@@ -1190,7 +1313,8 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
11901313
return 0;
11911314
}
11921315

1193-
static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
1316+
static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata,
1317+
bool host)
11941318
{
11951319
u64 data = 0;
11961320
struct kvm *kvm = vcpu->kvm;
@@ -1227,6 +1351,9 @@ static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
12271351
case HV_X64_MSR_TSC_EMULATION_STATUS:
12281352
data = hv->hv_tsc_emulation_status;
12291353
break;
1354+
case HV_X64_MSR_SYNDBG_OPTIONS:
1355+
case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
1356+
return syndbg_get_msr(vcpu, msr, pdata, host);
12301357
default:
12311358
vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
12321359
return 1;
@@ -1316,7 +1443,7 @@ int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host)
13161443
int r;
13171444

13181445
mutex_lock(&vcpu->kvm->arch.hyperv.hv_lock);
1319-
r = kvm_hv_get_msr_pw(vcpu, msr, pdata);
1446+
r = kvm_hv_get_msr_pw(vcpu, msr, pdata, host);
13201447
mutex_unlock(&vcpu->kvm->arch.hyperv.hv_lock);
13211448
return r;
13221449
} else
@@ -1795,6 +1922,9 @@ int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
17951922
{ .function = HYPERV_CPUID_FEATURES },
17961923
{ .function = HYPERV_CPUID_ENLIGHTMENT_INFO },
17971924
{ .function = HYPERV_CPUID_IMPLEMENT_LIMITS },
1925+
{ .function = HYPERV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS },
1926+
{ .function = HYPERV_CPUID_SYNDBG_INTERFACE },
1927+
{ .function = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES },
17981928
{ .function = HYPERV_CPUID_NESTED_FEATURES },
17991929
};
18001930
int i, nent = ARRAY_SIZE(cpuid_entries);
@@ -1820,7 +1950,7 @@ int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
18201950
case HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS:
18211951
memcpy(signature, "Linux KVM Hv", 12);
18221952

1823-
ent->eax = HYPERV_CPUID_NESTED_FEATURES;
1953+
ent->eax = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES;
18241954
ent->ebx = signature[0];
18251955
ent->ecx = signature[1];
18261956
ent->edx = signature[2];
@@ -1859,6 +1989,10 @@ int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
18591989
ent->edx |= HV_FEATURE_FREQUENCY_MSRS_AVAILABLE;
18601990
ent->edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE;
18611991

1992+
ent->ebx |= HV_X64_DEBUGGING;
1993+
ent->edx |= HV_X64_GUEST_DEBUGGING_AVAILABLE;
1994+
ent->edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE;
1995+
18621996
/*
18631997
* Direct Synthetic timers only make sense with in-kernel
18641998
* LAPIC
@@ -1902,6 +2036,24 @@ int kvm_vcpu_ioctl_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
19022036

19032037
break;
19042038

2039+
case HYPERV_CPUID_SYNDBG_VENDOR_AND_MAX_FUNCTIONS:
2040+
memcpy(signature, "Linux KVM Hv", 12);
2041+
2042+
ent->eax = 0;
2043+
ent->ebx = signature[0];
2044+
ent->ecx = signature[1];
2045+
ent->edx = signature[2];
2046+
break;
2047+
2048+
case HYPERV_CPUID_SYNDBG_INTERFACE:
2049+
memcpy(signature, "VS#1\0\0\0\0\0\0\0\0", 12);
2050+
ent->eax = signature[0];
2051+
break;
2052+
2053+
case HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES:
2054+
ent->eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING;
2055+
break;
2056+
19052057
default:
19062058
break;
19072059
}

arch/x86/kvm/hyperv.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic)
7373
return hv_vcpu_to_vcpu(container_of(synic, struct kvm_vcpu_hv, synic));
7474
}
7575

76+
static inline struct kvm_hv_syndbg *vcpu_to_hv_syndbg(struct kvm_vcpu *vcpu)
77+
{
78+
return &vcpu->kvm->arch.hyperv.hv_syndbg;
79+
}
80+
7681
int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host);
7782
int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host);
7883

arch/x86/kvm/trace.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,57 @@ TRACE_EVENT(kvm_nested_vmenter_failed,
15411541
__print_symbolic(__entry->err, VMX_VMENTER_INSTRUCTION_ERRORS))
15421542
);
15431543

1544+
/*
1545+
* Tracepoint for syndbg_set_msr.
1546+
*/
1547+
TRACE_EVENT(kvm_hv_syndbg_set_msr,
1548+
TP_PROTO(int vcpu_id, u32 vp_index, u32 msr, u64 data),
1549+
TP_ARGS(vcpu_id, vp_index, msr, data),
1550+
1551+
TP_STRUCT__entry(
1552+
__field(int, vcpu_id)
1553+
__field(u32, vp_index)
1554+
__field(u32, msr)
1555+
__field(u64, data)
1556+
),
1557+
1558+
TP_fast_assign(
1559+
__entry->vcpu_id = vcpu_id;
1560+
__entry->vp_index = vp_index;
1561+
__entry->msr = msr;
1562+
__entry->data = data;
1563+
),
1564+
1565+
TP_printk("vcpu_id %d vp_index %u msr 0x%x data 0x%llx",
1566+
__entry->vcpu_id, __entry->vp_index, __entry->msr,
1567+
__entry->data)
1568+
);
1569+
1570+
/*
1571+
* Tracepoint for syndbg_get_msr.
1572+
*/
1573+
TRACE_EVENT(kvm_hv_syndbg_get_msr,
1574+
TP_PROTO(int vcpu_id, u32 vp_index, u32 msr, u64 data),
1575+
TP_ARGS(vcpu_id, vp_index, msr, data),
1576+
1577+
TP_STRUCT__entry(
1578+
__field(int, vcpu_id)
1579+
__field(u32, vp_index)
1580+
__field(u32, msr)
1581+
__field(u64, data)
1582+
),
1583+
1584+
TP_fast_assign(
1585+
__entry->vcpu_id = vcpu_id;
1586+
__entry->vp_index = vp_index;
1587+
__entry->msr = msr;
1588+
__entry->data = data;
1589+
),
1590+
1591+
TP_printk("vcpu_id %d vp_index %u msr 0x%x data 0x%llx",
1592+
__entry->vcpu_id, __entry->vp_index, __entry->msr,
1593+
__entry->data)
1594+
);
15441595
#endif /* _TRACE_KVM_H */
15451596

15461597
#undef TRACE_INCLUDE_PATH

arch/x86/kvm/x86.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,10 @@ static const u32 emulated_msrs_all[] = {
12461246
HV_X64_MSR_VP_ASSIST_PAGE,
12471247
HV_X64_MSR_REENLIGHTENMENT_CONTROL, HV_X64_MSR_TSC_EMULATION_CONTROL,
12481248
HV_X64_MSR_TSC_EMULATION_STATUS,
1249+
HV_X64_MSR_SYNDBG_OPTIONS,
1250+
HV_X64_MSR_SYNDBG_CONTROL, HV_X64_MSR_SYNDBG_STATUS,
1251+
HV_X64_MSR_SYNDBG_SEND_BUFFER, HV_X64_MSR_SYNDBG_RECV_BUFFER,
1252+
HV_X64_MSR_SYNDBG_PENDING_BUFFER,
12491253

12501254
MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
12511255
MSR_KVM_PV_EOI_EN, MSR_KVM_ASYNC_PF_INT, MSR_KVM_ASYNC_PF_ACK,
@@ -3011,6 +3015,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
30113015
*/
30123016
break;
30133017
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
3018+
case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
3019+
case HV_X64_MSR_SYNDBG_OPTIONS:
30143020
case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
30153021
case HV_X64_MSR_CRASH_CTL:
30163022
case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:
@@ -3272,6 +3278,8 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
32723278
msr_info->data = 0x20000000;
32733279
break;
32743280
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
3281+
case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
3282+
case HV_X64_MSR_SYNDBG_OPTIONS:
32753283
case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
32763284
case HV_X64_MSR_CRASH_CTL:
32773285
case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:

0 commit comments

Comments
 (0)