diff --git a/usr.sbin/bhyvectl/amd64/bhyvectl_machdep.c b/usr.sbin/bhyvectl/amd64/bhyvectl_machdep.c --- a/usr.sbin/bhyvectl/amd64/bhyvectl_machdep.c +++ b/usr.sbin/bhyvectl/amd64/bhyvectl_machdep.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -41,6 +42,7 @@ #include #include #include +#include #include #include "amd/vmcb.h" @@ -93,6 +95,7 @@ static vm_paddr_t gpa_pmap; static int inject_nmi, assert_lapic_lvt = -1; static int get_intinfo; +static int get_cpuid_cfg; static int set_cr0, get_cr0, set_cr2, get_cr2, set_cr3, get_cr3; static int set_cr4, get_cr4; static uint64_t set_cr0_val, set_cr2_val, set_cr3_val, set_cr4_val; @@ -278,6 +281,38 @@ printf("\n"); } +static void +print_cpuid_cfg(struct vm_vcpu_cpuid_config *vvcc) +{ + printf("CPUID configuration for vcpu %d: flags = 0x%x, nent = %d\n", + vvcc->vvcc_vcpuid, vvcc->vvcc_flags, vvcc->vvcc_nent); + + if (vvcc->vvcc_nent == 0) + return; + + printf("%10s,%5s %10s %10s %10s %10s %16s\n", + "Function", "Index", "EAX", "EBX", "ECX", "EDX", "ASCII"); + + for (uint32_t i = 0; i != vvcc->vvcc_nent; i++) { + struct vcpu_cpuid_entry *vce = + &((struct vcpu_cpuid_entry *)vvcc->vvcc_entries)[i]; + char *regs = (char *)&vce->vce_eax; + + printf("0x%.8x", vce->vce_function); + if ((vce->vce_flags & VCE_FLAG_MATCH_INDEX) != 0) + printf(",0x%.3x: ", vce->vce_index); + else + printf(": "); + printf("0x%.8x,0x%.8x,0x%.8x,0x%.8x ", + vce->vce_eax, vce->vce_ebx, vce->vce_ecx, vce->vce_edx); + + for (int j = 0; j != 16; j++) + printf("%c", isprint(regs[j]) ? regs[j] : '.'); + + printf("\n"); + } +} + /* AMD 6th generation and Intel compatible MSRs */ #define MSR_AMD6TH_START 0xC0000000 #define MSR_AMD6TH_END 0xC0001FFF @@ -1217,6 +1252,7 @@ { "get-x2apic-state", NO_ARG, &get_x2apic_state, 1 }, { "inject-nmi", NO_ARG, &inject_nmi, 1 }, { "get-intinfo", NO_ARG, &get_intinfo, 1 }, + { "get-cpuid-cfg", NO_ARG, &get_cpuid_cfg, 1 }, }; const struct option intel_opts[] = { { "get-vmcs-pinbased-ctls", @@ -1885,4 +1921,39 @@ print_intinfo("current", info[1]); } } + + if (!error && (get_cpuid_cfg || get_all)) { + struct vm_vcpu_cpuid_config vvcc = { + .vvcc_vcpuid = 0, /* filled in by the ioctl code */ + .vvcc_flags = 0, + .vvcc_nent = 0, + .vvcc_entries = NULL + }; + size_t entries_sz; + + /* + * Get the flags and the number of configured CPUID entries, + * and allocate a buffer for the entries if necessary. + */ + error = vm_get_cpuid(vcpu, &vvcc); + if (error == 0 && vvcc.vvcc_nent != 0) { + entries_sz = vvcc.vvcc_nent * + sizeof (struct vcpu_cpuid_entry); + vvcc.vvcc_entries = malloc(entries_sz); + } + + /* + * If there are CPUID entries, call vm_get_cpuid() again + * to get them. + */ + if (error == 0 && vvcc.vvcc_entries != NULL) { + bzero(vvcc.vvcc_entries, entries_sz); + + error = vm_get_cpuid(vcpu, &vvcc); + } + + if (error == 0) { + print_cpuid_cfg(&vvcc); + } + } }