Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F173990500
D60123.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D60123.diff
View Options
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
@@ -38,6 +38,7 @@
#include <fcntl.h>
#include <getopt.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -85,6 +86,7 @@
SET_RTC_TIME,
SET_RTC_NVRAM,
RTC_NVRAM_OFFSET,
+ GET_CPUID,
};
static int get_rtc_time, set_rtc_time;
@@ -97,6 +99,12 @@
static int inject_nmi, assert_lapic_lvt = -1;
static int get_intinfo;
static int get_cpuid_cfg;
+static int get_cpuid;
+static int get_cpuid_all;
+static int get_cpuid_parsable;
+static int get_cpuid_sparse;
+static uint32_t get_cpuid_leaf;
+static uint32_t get_cpuid_index;
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;
@@ -285,28 +293,49 @@
static void
print_cpuid_header(void)
{
+ if (get_cpuid_parsable != 0)
+ return;
+
printf("%10s, %5s %10s %10s %10s %10s %16s\n",
"Function", "Index", "EAX", "EBX", "ECX", "EDX", "ASCII");
}
static void
-print_cpuid_entry(uint32_t leaf, uint32_t index, uint32_t flags,
+print_cpuid_entry(int vcpuid, uint32_t leaf, uint32_t index, uint32_t max_index,
const uint32_t *regs)
{
const char *regbytes = (const char *)regs;
+ if (get_cpuid_parsable != 0) {
+ if (regs[0] == 0 && regs[1] == 0 && regs[2] == 0 && regs[3] == 0)
+ return;
+
+ if (vcpuid != 0 || get_cpuid_sparse == 0)
+ printf("vcpu.%d.", vcpuid);
+
+ printf("cpuid.");
+ }
+
printf("0x%.8x", leaf);
+ if (max_index > 0)
+ printf(",0x%.3x", index);
- if ((flags & VCE_FLAG_MATCH_INDEX) != 0)
- printf(",0x%.3x: ", index);
- else
- printf(": ");
+ if (get_cpuid_parsable != 0) {
+ printf("=");
+ } else {
+ if (max_index > 0)
+ printf(": ");
+ else
+ printf(": ");
+ }
printf("0x%.8x,0x%.8x,0x%.8x,0x%.8x ",
regs[0], regs[1], regs[2], regs[3]);
- for (int j = 0; j != 16; j++)
- printf("%c", isprint(regbytes[j]) ? regbytes[j] : '.');
+ if (get_cpuid_parsable == 0) {
+ for (int j = 0; j != 16; j++)
+ printf("%c", isprint(regbytes[j]) ? regbytes[j] : '.');
+ }
printf("\n");
}
@@ -326,11 +355,209 @@
struct vcpu_cpuid_entry *vce =
&((struct vcpu_cpuid_entry *)vvcc->vvcc_entries)[i];
- print_cpuid_entry(vce->vce_function,
+ print_cpuid_entry(vvcc->vvcc_vcpuid, vce->vce_function,
vce->vce_index, vce->vce_flags, &vce->vce_eax);
}
}
+static bool
+cpuid_0x0000000d_index_valid(struct vcpu *vcpu, uint32_t leaf, uint32_t index)
+{
+ /*
+ * Leaf 0x0000000d is quite special.
+ *
+ * Indices 0 and 1 are always valid.
+ *
+ * For indices 2-31, the index is valid if the corresponding
+ * bits of either EAX of index 0 or ECX of index 1 are set.
+ *
+ * For indices 32-64, the index is valid if the corresponding
+ * bits of EDX of either index 0 or index 1 are valid. The
+ * corresponding bits are index - 32.
+ */
+ struct vm_legacy_cpuid vlc;
+ uint32_t *regs;
+ int error;
+ int reg = 0;
+
+ if (index == 0 || index == 1)
+ return (true);
+
+ if (index >= 32) {
+ reg = 3;
+ index -= 32;
+ }
+
+ bzero(&vlc, sizeof(vlc));
+ vlc.vlc_eax = leaf;
+ vlc.vlc_ecx = 0;
+ error = vm_legacy_cpuid(vcpu, &vlc);
+ if (error != 0)
+ return (false);
+
+ regs = &vlc.vlc_eax;
+ if ((regs[reg] & (1 << index)) != 0)
+ return (true);
+
+ bzero(&vlc, sizeof(vlc));
+ vlc.vlc_eax = leaf;
+ vlc.vlc_ecx = 1;
+ error = vm_legacy_cpuid(vcpu, &vlc);
+ if (error != 0)
+ return (false);
+
+ regs = &vlc.vlc_eax;
+ if (reg != 3)
+ reg = 2;
+
+ return ((regs[reg] & (1 << index)) != 0);
+}
+
+static bool
+cpuid_index_valid(struct vcpu *vcpu, uint32_t leaf, uint32_t index,
+ const uint32_t *regs)
+{
+ struct {
+ uint32_t leaf;
+ int reg;
+ uint32_t mask;
+ } leaves[] = {
+ { 0x00000004, 0, 0x1f },
+ { 0x0000000b, 2, 0xff00 },
+ { 0x00000012, 0, 0xf },
+ { 0x0000001b, 0, 0xfff },
+ { 0x0000001f, 2, 0xff00 },
+ { 0x8000001d, 0, 0x1f },
+ { 0x80000026, 1, 0xffff },
+ };
+
+ if (leaf == 0x0000000d) {
+ return (cpuid_0x0000000d_index_valid(vcpu, leaf, index));
+ }
+
+ if (leaf == 0x00000010) {
+ /* valid if corresponding bit in EBX of index 0 is set */
+ return ((regs[1] & (1 << index)) != 0);
+ }
+
+ for (int i = 0; i != nitems(leaves); i++) {
+ if (leaves[i].leaf == leaf) {
+ return ((regs[leaves[i].reg] & leaves[i].mask) != 0);
+ }
+ }
+
+ return (true);
+}
+
+static uint32_t
+cpuid_max_index(uint32_t leaf, const uint32_t *regs)
+{
+ int i;
+
+ struct {
+ uint32_t leaf;
+ uint32_t static_max_index;
+ } leaves[] = {
+ { 0x00000004, 0x01f },
+ { 0x0000000b, 0x001 },
+ { 0x0000000d, 0x03f },
+ { 0x00000010, 0x003 },
+ { 0x00000012, 0x01f },
+ { 0x0000001b, 0x01f },
+ { 0x0000001f, 0x005 },
+ { 0x8000001d, 0x01f },
+ { 0x80000026, 0x003 },
+ };
+
+ if (leaf == 0x00000017 || leaf == 0x00000018) {
+ /* max. index is in EAX of index 0 */
+ return (regs[0]);
+ }
+
+ for (i = 0; i != nitems(leaves); i++) {
+ if (leaves[i].leaf == leaf) {
+ return (leaves[i].static_max_index);
+ }
+ }
+
+ return (0);
+}
+
+static int
+print_cpuid_all(struct vmctx *ctx, struct vcpu *vcpu, int vcpuid, uint32_t leaf)
+{
+ struct vcpu *vcpu0 = NULL;
+ bool match = false;
+ uint32_t high = 0;
+ struct vm_legacy_cpuid vlc0, vlc_vcpu0;
+ int error;
+
+ bzero(&vlc0, sizeof(vlc0));
+ vlc0.vlc_eax = leaf;
+ error = vm_legacy_cpuid(vcpu, &vlc0);
+ if (error != 0)
+ return (error);
+
+ if (get_cpuid_sparse == 1 && vcpuid != 0) {
+ vcpu0 = vm_vcpu_open(ctx, 0);
+ if (vcpu0 == NULL)
+ return (-1);
+
+ bzero(&vlc_vcpu0, sizeof(vlc_vcpu0));
+ vlc_vcpu0.vlc_eax = leaf;
+ error = vm_legacy_cpuid(vcpu0, &vlc_vcpu0);
+ if (error != 0)
+ return (error);
+ match = (0 == memcmp(&vlc0.vlc_eax, &vlc_vcpu0.vlc_eax,
+ sizeof(uint32_t) * 4));
+ } else {
+ match = false;
+ }
+
+ if (!match)
+ print_cpuid_entry(vcpuid, leaf, 0, 0, &vlc0.vlc_eax);
+
+ high = vlc0.vlc_eax;
+ for (leaf += 1; leaf <= high; leaf++) {
+ uint32_t max_index = cpuid_max_index(leaf, &vlc0.vlc_eax);
+ uint32_t index;
+
+ for (index = 0; index <= max_index; index++) {
+ struct vm_legacy_cpuid vlc;
+
+ bzero(&vlc, sizeof(vlc));
+ vlc.vlc_eax = leaf;
+ vlc.vlc_ecx = index;
+
+ error = vm_legacy_cpuid(vcpu, &vlc);
+ if (error != 0)
+ return (error);
+
+ if (!cpuid_index_valid(vcpu, leaf, index, &vlc.vlc_eax))
+ continue;
+
+ if (get_cpuid_sparse == 1 && vcpuid != 0) {
+ bzero(&vlc_vcpu0, sizeof(vlc_vcpu0));
+ vlc_vcpu0.vlc_eax = leaf;
+ vlc_vcpu0.vlc_ecx = index;
+ error = vm_legacy_cpuid(vcpu0, &vlc_vcpu0);
+ if (error != 0)
+ return (error);
+ match = (0 == memcmp(&vlc.vlc_eax,
+ &vlc_vcpu0.vlc_eax, sizeof(uint32_t) * 4));
+ } else {
+ match = false;
+ }
+
+ if (!match) {
+ print_cpuid_entry(vcpuid, leaf, index,
+ max_index, &vlc.vlc_eax);
+ }
+ }
+ }
+ return (0);
+}
+
/* AMD 6th generation and Intel compatible MSRs */
#define MSR_AMD6TH_START 0xC0000000
#define MSR_AMD6TH_END 0xC0001FFF
@@ -1271,6 +1498,7 @@
{ "inject-nmi", NO_ARG, &inject_nmi, 1 },
{ "get-intinfo", NO_ARG, &get_intinfo, 1 },
{ "get-cpuid-cfg", NO_ARG, &get_cpuid_cfg, 1 },
+ { "get-cpuid", OPT_ARG, 0, GET_CPUID },
};
const struct option intel_opts[] = {
{ "get-vmcs-pinbased-ctls",
@@ -1518,6 +1746,50 @@
case ASSERT_LAPIC_LVT:
assert_lapic_lvt = atoi(optarg);
break;
+ case GET_CPUID:
+ get_cpuid_all = 1;
+
+ if (optarg != NULL) {
+ const char *errstr;
+ char *leaf, *idx;
+
+ idx = optarg;
+ leaf = strsep(&idx, ",");
+
+ if (strcmp(leaf, "all") == 0) {
+ if (idx != NULL) {
+ if (strcmp(idx, "p") == 0) {
+ get_cpuid_parsable = 1;
+ }
+
+ if (strcmp(idx, "s") == 0) {
+ get_cpuid_parsable = 1;
+ get_cpuid_sparse = 1;
+ }
+
+ if (get_cpuid_parsable != 1) {
+ usage(opts);
+ }
+ }
+ break;
+ }
+
+ get_cpuid_leaf =
+ strtonumx(leaf, 0, UINT32_MAX, &errstr, 16);
+ if (errstr != NULL)
+ usage(opts);
+
+ if (idx != NULL) {
+ get_cpuid_index = strtonumx(idx, 0,
+ UINT32_MAX, &errstr, 16);
+ if (errstr != NULL)
+ usage(opts);
+ }
+
+ get_cpuid_all = 0;
+ get_cpuid = 1;
+ }
+ break;
}
}
@@ -1591,6 +1863,8 @@
return ("val");
case RTC_NVRAM_OFFSET:
return ("offset");
+ case GET_CPUID:
+ return ("{<function>[,<index>]|all[,{p|s}]}");
default:
return ("???");
}
@@ -1967,4 +2241,54 @@
}
}
}
+
+ if (!error && get_cpuid) {
+ struct vm_legacy_cpuid vlc;
+
+ bzero(&vlc, sizeof(vlc));
+ vlc.vlc_eax = get_cpuid_leaf;
+
+ error = vm_legacy_cpuid(vcpu, &vlc);
+ if (error == 0) {
+ uint32_t max_index = cpuid_max_index(get_cpuid_leaf,
+ &vlc.vlc_eax);
+
+ if (get_cpuid_index == 0) {
+ print_cpuid_header();
+ print_cpuid_entry(vcpuid, get_cpuid_leaf,
+ get_cpuid_index, max_index, &vlc.vlc_eax);
+ } else if (get_cpuid_index <= max_index &&
+ cpuid_index_valid(vcpu, get_cpuid_leaf,
+ get_cpuid_index, &vlc.vlc_eax)) {
+ bzero(&vlc, sizeof(vlc));
+ vlc.vlc_eax = get_cpuid_leaf;
+ vlc.vlc_ecx = get_cpuid_index;
+
+ error = vm_legacy_cpuid(vcpu, &vlc);
+ if (error == 0) {
+ print_cpuid_header();
+ print_cpuid_entry(vcpuid,
+ get_cpuid_leaf, get_cpuid_index,
+ max_index, &vlc.vlc_eax);
+ }
+ }
+ }
+ }
+
+ if (!error && (get_cpuid_all || get_all)) {
+ print_cpuid_header();
+
+ error = print_cpuid_all(ctx, vcpu, vcpuid, 0x00000000);
+ if (error == 0) {
+ error = print_cpuid_all(ctx, vcpu, vcpuid, 0x40000000);
+ if (error == 0) {
+ error = print_cpuid_all(ctx, vcpu, vcpuid,
+ 0x40000100);
+ if (error == 0) {
+ error = print_cpuid_all(ctx, vcpu,
+ vcpuid, 0x80000000);
+ }
+ }
+ }
+ }
}
diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c
--- a/usr.sbin/bhyvectl/bhyvectl.c
+++ b/usr.sbin/bhyvectl/bhyvectl.c
@@ -171,6 +171,10 @@
(void)fprintf(stderr, " [--%s=<%s>]\n", o->name,
o->val >= OPT_START_MD ? bhyvectl_opt_desc(o->val) :
set_desc[o->val]);
+ } else if (o->has_arg == OPT_ARG) {
+ (void)fprintf(stderr, " [--%s[=%s]\n", o->name,
+ o->val >= OPT_START_MD ? bhyvectl_opt_desc(o->val) :
+ set_desc[o->val]);
} else {
(void)fprintf(stderr, " [--%s]\n", o->name);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Sep 30, 7:50 PM (1 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39950448
Default Alt Text
D60123.diff (10 KB)
Attached To
Mode
D60123: bhyvectl/amd64: Add --get-cpuid[=all[,{p|s}]
Attached
Detach File
Event Timeline
Log In to Comment