Skip to content
This repository was archived by the owner on Jan 28, 2023. It is now read-only.

Commit b178462

Browse files
authored
Merge pull request #383 from intel/get-cpuid
Enable getting CPUID features for guest VCPUs
2 parents 83e6ee6 + 24f0fb9 commit b178462

File tree

12 files changed

+151
-25
lines changed

12 files changed

+151
-25
lines changed

core/cpuid.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,10 @@ void cpuid_init_supported_features(void)
322322

323323
uint32_t cpuid_guest_get_size(void)
324324
{
325-
return sizeof(uint32_t) + CPUID_TOTAL_LEAVES * sizeof(hax_cpuid_entry);
325+
// Both the external type 'hax_cpuid' and the internal type 'hax_cpuid_t'
326+
// have the same size, so the size of either type can be calculated by this
327+
// function.
328+
return sizeof(hax_cpuid_t) + CPUID_TOTAL_LEAVES * sizeof(hax_cpuid_entry);
326329
}
327330

328331
void cpuid_guest_init(hax_cpuid_t *cpuid)
@@ -406,27 +409,35 @@ void cpuid_set_features_mask(hax_cpuid_t *cpuid, uint64_t features_mask)
406409
cpuid->features_mask = features_mask;
407410
}
408411

409-
void cpuid_get_guest_features(hax_cpuid_t *cpuid, hax_cpuid_entry *features)
412+
int cpuid_get_guest_features(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info)
410413
{
411-
hax_cpuid_entry *entry;
414+
size_t size;
412415

413-
if (cpuid == NULL || features == NULL)
414-
return;
416+
if (cpuid == NULL || cpuid_info == NULL)
417+
return -EINVAL;
415418

416-
entry = find_cpuid_entry(cpuid->features, CPUID_TOTAL_LEAVES,
417-
features->function, 0);
418-
if (entry == NULL)
419-
return;
419+
if (cpuid_info->total < CPUID_TOTAL_LEAVES) {
420+
cpuid_info->total = CPUID_TOTAL_LEAVES;
421+
hax_log(HAX_LOGI, "%s: The buffer passed in is not enough to hold %lu "
422+
"CPUID leaves.\n", __func__, cpuid_info->total);
423+
return -ENOMEM;
424+
}
420425

421-
*features = *entry;
426+
size = CPUID_TOTAL_LEAVES * sizeof(hax_cpuid_entry);
427+
428+
cpuid_info->total = CPUID_TOTAL_LEAVES;
429+
cpuid_info->pad = 0;
430+
memcpy_s(cpuid_info->entries, size, cpuid->features, size);
431+
432+
return 0;
422433
}
423434

424-
void cpuid_set_guest_features(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info)
435+
int cpuid_set_guest_features(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info)
425436
{
426437
int i;
427438

428439
if (cpuid == NULL || cpuid_info == NULL)
429-
return;
440+
return -EINVAL;
430441

431442
hax_log(HAX_LOGI, "%s: user setting:\n", __func__);
432443
dump_features(cpuid_info->entries, cpuid_info->total);
@@ -440,6 +451,8 @@ void cpuid_set_guest_features(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info)
440451

441452
hax_log(HAX_LOGI, "%s: after:\n", __func__);
442453
dump_features(cpuid->features, CPUID_TOTAL_LEAVES);
454+
455+
return 0;
443456
}
444457

445458
static hax_cpuid_entry * find_cpuid_entry(hax_cpuid_entry *features,

core/include/cpuid.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ void cpuid_guest_init(hax_cpuid_t *cpuid);
263263
void cpuid_execute(hax_cpuid_t *cpuid, cpuid_args_t *args);
264264
void cpuid_get_features_mask(hax_cpuid_t *cpuid, uint64_t *features_mask);
265265
void cpuid_set_features_mask(hax_cpuid_t *cpuid, uint64_t features_mask);
266-
void cpuid_get_guest_features(hax_cpuid_t *cpuid, hax_cpuid_entry *features);
267-
void cpuid_set_guest_features(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info);
266+
int cpuid_get_guest_features(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info);
267+
int cpuid_set_guest_features(hax_cpuid_t *cpuid, hax_cpuid *cpuid_info);
268268

269269
#endif /* HAX_CORE_CPUID_H_ */

core/include/hax_core_interface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ int vcpu_get_fpu(struct vcpu_t *vcpu, struct fx_layout *fl);
4646
int vcpu_set_regs(struct vcpu_t *vcpu, struct vcpu_state_t *vs);
4747
int vcpu_get_regs(struct vcpu_t *vcpu, struct vcpu_state_t *vs);
4848
int vcpu_set_cpuid(struct vcpu_t *vcpu, hax_cpuid *cpuid_info);
49+
int vcpu_get_cpuid(struct vcpu_t *vcpu, hax_cpuid *cpuid_info);
4950
void vcpu_debug(struct vcpu_t *vcpu, struct hax_debug_t *debug);
5051

5152
void * get_vcpu_host(struct vcpu_t *vcpu);

core/include/vcpu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ int vcpu_put_fpu(struct vcpu_t *vcpu, struct fx_layout *fl);
276276
int vcpu_get_msr(struct vcpu_t *vcpu, uint64_t entry, uint64_t *val);
277277
int vcpu_put_msr(struct vcpu_t *vcpu, uint64_t entry, uint64_t val);
278278
int vcpu_set_cpuid(struct vcpu_t *vcpu, hax_cpuid *cpuid_info);
279+
int vcpu_get_cpuid(struct vcpu_t *vcpu, hax_cpuid *cpuid_info);
279280
void vcpu_debug(struct vcpu_t *vcpu, struct hax_debug_t *debug);
280281

281282
/* The declaration for OS wrapper code */

core/vcpu.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3977,9 +3977,15 @@ int vcpu_set_cpuid(struct vcpu_t *vcpu, hax_cpuid *cpuid_info)
39773977
return -EFAULT;
39783978
}
39793979

3980-
cpuid_set_guest_features(vcpu->guest_cpuid, cpuid_info);
3980+
return cpuid_set_guest_features(vcpu->guest_cpuid, cpuid_info);
3981+
}
39813982

3982-
return 0;
3983+
int vcpu_get_cpuid(struct vcpu_t *vcpu, hax_cpuid *cpuid_info)
3984+
{
3985+
hax_log(HAX_LOGI, "%s: vCPU #%u is getting guest CPUID.\n", __func__,
3986+
vcpu->vcpu_id);
3987+
3988+
return cpuid_get_guest_features(vcpu->guest_cpuid, cpuid_info);
39833989
}
39843990

39853991
void vcpu_debug(struct vcpu_t *vcpu, struct hax_debug_t *debug)

docs/api.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,3 +763,60 @@ caller is smaller than the size of `struct hax_cpuid`.
763763
`HAX_MAX_CPUID_ENTRIES`.
764764
* `-EFAULT` (macOS): Failed to copy contents in `entries` to the memory in
765765
kernel space.
766+
767+
#### HAX\_VCPU\_IOCTL\_GET\_CPUID
768+
Retrieves the VCPU responses to the CPU identification (CPUID) instructions.
769+
770+
HAXM initializes a minimal feature set for guest VCPUs in kernel space. Only the
771+
CPUID instructions supported by HAXM will be emulated and cached during the
772+
initialization phase. When the guest VCPU executes these CPUID instructions,
773+
these cached values ​​will be returned as the execution result.
774+
775+
This IOCTL is used to retrieve all supported CPUID features set and cached
776+
values ​​of each instruction register. When the VCPUs are initialized, invoking
777+
this IOCTL will return the default CPUID features set of HAXM; after having
778+
invoked the IOCTL `HAX_VCPU_IOCTL_SET_CPUID`, invoking this IOCTL will return
779+
the most recently set CPUID features set.
780+
781+
The parameter `struct hax_cpuid` of this IOCTL is a variable-length type, so it
782+
is required to allocate sufficient buffer before retrieving the CPUID features
783+
set. Usually, the CPUID features set is retrieved by invoking this IOCTL twice
784+
consecutively. The first time, directly pass in the variable address of
785+
`hax_cpuid` and specify the member `total` as 0 to retrieve the total number of
786+
supported CPUIDs; the second time, first allocate an extra buffer of
787+
`total * sizeof(hax_cpuid_entry)` bytes for the variable-length array `entries`,
788+
and specify `total` as the number of array elements, then the whole CPUID
789+
features set can be retrived.
790+
791+
Since All VCPUs share the same feature set in a VM, send this IOCTL to any VCPU
792+
to retrieve CPUID features set, the results are all the same.
793+
794+
* Since: Capability `HAX_CAP_CPUID`
795+
* Parameter: `struct hax_cpuid cpuid`, (q.v. `HAX_VCPU_IOCTL_SET_CPUID`)
796+
* (Input/Output) `total`: Number of CPUIDs in `entries`. The valid value
797+
should be in the range [0, `HAX_MAX_CPUID_ENTRIES`]. If this parameter is set to
798+
0, it outputs the total number of CPUID features supported by HAXM and the IOCTL
799+
makes no use of the output parameter `entries`.
800+
* (Output) `pad`: Ignored.
801+
* (Output) `entries`: Array of `struct hax_cpuid_entry`. The array requires to
802+
allocate sufficient buffer to receive the CPUID features set supported by HAXM.
803+
The actual size of the array is indicated by `total`. If `total` is 0, it is not
804+
necessary to allocate any extra buffer for the array.
805+
806+
For each entry in `struct hax_cpuid_entry`
807+
* (Output) `function`: CPUID function code, i.e., initial EAX value.
808+
* (Output) `index`: Sub-leaf index.
809+
* (Output) `flags`: Feature flags.
810+
* (Output) `eax`: EAX register value.
811+
* (Output) `ebx`: EBX register value.
812+
* (Output) `ecx`: ECX register value.
813+
* (Output) `edx`: EDX register value.
814+
* (Output) `pad`: Ignored.
815+
* Error codes:
816+
* `STATUS_INVALID_PARAMETER` (Windows): The input buffer provided by the
817+
caller is smaller than the size of `struct hax_cpuid`.
818+
* `STATUS_UNSUCCESSFUL` (Windows): Failed to get CPUID features.
819+
* `-E2BIG` (macOS): The input value of `total` is greater than
820+
`HAX_MAX_CPUID_ENTRIES`.
821+
* `-EFAULT` (macOS): Failed to copy contents in `entries` to the memory in
822+
kernel space.

include/darwin/hax_interface_mac.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
// a variable-length type. When ioctl() is invoked, the argument of user data
7575
// should pass the address of the pointer to `hax_cpuid`.
7676
#define HAX_VCPU_IOCTL_SET_CPUID _IOW(0, 0xca, struct hax_cpuid *)
77+
#define HAX_VCPU_IOCTL_GET_CPUID _IOW(0, 0xcb, struct hax_cpuid *)
7778

7879
#define HAX_KERNEL64_CS 0x80
7980
#define HAX_KERNEL32_CS 0x08

include/linux/hax_interface_linux.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171

7272
#define HAX_IOCTL_VCPU_DEBUG _IOW(0, 0xc9, struct hax_debug_t)
7373
#define HAX_VCPU_IOCTL_SET_CPUID _IOW(0, 0xca, struct hax_cpuid *)
74+
#define HAX_VCPU_IOCTL_GET_CPUID _IOW(0, 0xcb, struct hax_cpuid *)
7475

7576
#define HAX_KERNEL64_CS 0x80
7677
#define HAX_KERNEL32_CS 0x08

platforms/darwin/com_intel_hax_ui.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,17 @@ static int hax_vcpu_major = 0;
104104
} \
105105
if (copyin(uaddr, (dest), size)) { \
106106
hax_log(HAX_LOGE, "%s: argument read error.\n", __func__); \
107-
unload_user_data(dest); \
107+
unload_user_data(dest, false); \
108108
ret = -EFAULT; \
109109
break; \
110110
}
111111

112-
#define unload_user_data(dest) \
113-
if ((dest) != NULL) \
112+
#define unload_user_data(dest, overwrite) \
113+
if ((overwrite) && copyout((dest), uaddr, size)) { \
114+
hax_log(HAX_LOGE, "%s: failed to write data back.\n", __func__); \
115+
ret = -EFAULT; \
116+
} \
117+
if ((dest) != NULL) \
114118
hax_vfree((dest), size);
115119

116120
static void handle_unknown_ioctl(dev_t dev, ulong cmd, struct proc *p);
@@ -282,7 +286,15 @@ static int hax_vcpu_ioctl(dev_t dev, ulong cmd, caddr_t data, int flag,
282286
load_user_data(cpuid, data, total, HAX_MAX_CPUID_ENTRIES, hax_cpuid,
283287
hax_cpuid_entry);
284288
ret = vcpu_set_cpuid(cvcpu, cpuid);
285-
unload_user_data(cpuid);
289+
unload_user_data(cpuid, false);
290+
break;
291+
}
292+
case HAX_VCPU_IOCTL_GET_CPUID: {
293+
struct hax_cpuid *cpuid;
294+
load_user_data(cpuid, data, total, HAX_MAX_CPUID_ENTRIES, hax_cpuid,
295+
hax_cpuid_entry);
296+
ret = vcpu_get_cpuid(cvcpu, cpuid);
297+
unload_user_data(cpuid, true);
286298
break;
287299
}
288300
default: {

platforms/linux/components.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,17 @@
6767
} \
6868
if (copy_from_user((dest), from, size)) { \
6969
hax_log(HAX_LOGE, "%s: argument read error.\n", __func__); \
70-
unload_user_data(dest); \
70+
unload_user_data(dest, false); \
7171
ret = -EFAULT; \
7272
break; \
7373
}
7474

75-
#define unload_user_data(dest) \
76-
if ((dest) != NULL) \
75+
#define unload_user_data(dest, overwrite) \
76+
if ((overwrite) && copy_to_user(from, (dest), size)) { \
77+
hax_log(HAX_LOGE, "%s: failed to write data back.\n", __func__); \
78+
ret = -EFAULT; \
79+
} \
80+
if ((dest) != NULL) \
7781
hax_vfree((dest), size);
7882

7983
typedef struct hax_vm_linux_t {
@@ -484,7 +488,15 @@ static long hax_vcpu_ioctl(struct file *filp, unsigned int cmd,
484488
load_user_data(cpuid, argp, total, HAX_MAX_CPUID_ENTRIES, hax_cpuid,
485489
hax_cpuid_entry);
486490
ret = vcpu_set_cpuid(cvcpu, cpuid);
487-
unload_user_data(cpuid);
491+
unload_user_data(cpuid, false);
492+
break;
493+
}
494+
case HAX_VCPU_IOCTL_GET_CPUID: {
495+
struct hax_cpuid *cpuid;
496+
load_user_data(cpuid, argp, total, HAX_MAX_CPUID_ENTRIES, hax_cpuid,
497+
hax_cpuid_entry);
498+
ret = vcpu_get_cpuid(cvcpu, cpuid);
499+
unload_user_data(cpuid, true);
488500
break;
489501
}
490502
default:

platforms/windows/hax_entry.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ NTSTATUS HaxVcpuControl(PDEVICE_OBJECT DeviceObject,
258258
PCHAR inBuf, outBuf; // pointer to Input and output buffer
259259
uint32_t vcpu_id, vm_id;
260260
struct vcpu_t *cvcpu;
261-
int infret = 0;
261+
int infret = 0, err;
262262
struct hax_vcpu_windows *vcpu = ext;
263263
PIO_STACK_LOCATION irpSp;// Pointer to current stack location
264264

@@ -444,6 +444,26 @@ NTSTATUS HaxVcpuControl(PDEVICE_OBJECT DeviceObject,
444444
}
445445
break;
446446
}
447+
case HAX_VCPU_IOCTL_GET_CPUID: {
448+
hax_cpuid *cpuid = (hax_cpuid *)outBuf;
449+
if (outBufLength < sizeof(hax_cpuid) || outBufLength <
450+
sizeof(hax_cpuid) + cpuid->total *
451+
sizeof(hax_cpuid_entry)) {
452+
ret = STATUS_INVALID_PARAMETER;
453+
goto done;
454+
}
455+
err = vcpu_get_cpuid(cvcpu, cpuid);
456+
if (err == -EINVAL) {
457+
ret = STATUS_UNSUCCESSFUL;
458+
break;
459+
}
460+
if (err == -ENOMEM) {
461+
infret = sizeof(hax_cpuid);
462+
break;
463+
}
464+
infret = sizeof(hax_cpuid) + cpuid->total * sizeof(hax_cpuid_entry);
465+
break;
466+
}
447467
default:
448468
hax_log(HAX_LOGE, "Unknow vcpu ioctl %lx\n",
449469
irpSp->Parameters.DeviceIoControl.IoControlCode);

platforms/windows/hax_entry.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,5 +167,7 @@ extern PDRIVER_OBJECT HaxDriverObject;
167167
CTL_CODE(HAX_DEVICE_TYPE, 0x916, METHOD_BUFFERED, FILE_ANY_ACCESS)
168168
#define HAX_VCPU_IOCTL_SET_CPUID \
169169
CTL_CODE(HAX_DEVICE_TYPE, 0x917, METHOD_BUFFERED, FILE_ANY_ACCESS)
170+
#define HAX_VCPU_IOCTL_GET_CPUID \
171+
CTL_CODE(HAX_DEVICE_TYPE, 0x918, METHOD_BUFFERED, FILE_ANY_ACCESS)
170172

171173
#endif // HAX_WINDOWS_HAX_ENTRY_H_

0 commit comments

Comments
 (0)