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:
Jon Doron 2022-02-16 12:24:59 +02:00 committed by Paolo Bonzini
parent ccbdf5e81b
commit 73d2407407
8 changed files with 451 additions and 8 deletions

View file

@ -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;