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

Commit 3c3af3b

Browse files
committed
Add set_cpuid ioctl that enables setting cpuid values to be returned by haxm
Signed-off-by: Alexey Romko <[email protected]>
1 parent 7f3aaab commit 3c3af3b

File tree

14 files changed

+215
-9
lines changed

14 files changed

+215
-9
lines changed

core/include/hax_core_interface.h

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ int hax_vm_core_open(struct vm_t *vm);
8888
/* Corresponding hax_get_vm with refer == 1 */
8989
int hax_put_vm(struct vm_t *vm);
9090
int hax_vm_set_qemuversion(struct vm_t *vm, struct hax_qemu_version *ver);
91+
int hax_vm_set_cpuid(struct vm_t *vm, struct hax_cpuid *cpuid_data);
9192

9293
struct vm_t * hax_create_vm(int *vm_id);
9394
int hax_teardown_vm(struct vm_t *vm);

core/include/vcpu.h

+1
Original file line numberDiff line numberDiff line change
@@ -288,5 +288,6 @@ static inline bool valid_vcpu_id(int vcpu_id)
288288

289289
bool vcpu_is_panic(struct vcpu_t *vcpu);
290290
void vcpu_set_panic(struct vcpu_t *vcpu);
291+
bool is_cpuid_supported(struct hax_cpuid *cpuid_data);
291292

292293
#endif // HAX_CORE_VCPU_H_

core/include/vm.h

+2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ struct vm_t {
8484
uint64_t spare_ramsize;
8585
uint ram_entry_num;
8686
struct hax_vcpu_mem *ram_entry;
87+
struct hax_cpuid *cpuid_data;
8788
};
8889

8990
struct hva_entry {
@@ -128,6 +129,7 @@ int _hax_teardown_vm(struct vm_t *vm);
128129
void hax_teardown_vcpus(struct vm_t *vm);
129130
int hax_destroy_host_interface(void);
130131
int hax_vm_set_qemuversion(struct vm_t *vm, struct hax_qemu_version *ver);
132+
//int hax_vm_set_cpuid(struct vm_t *vm, struct hax_cpuid *cpuid_data);
131133

132134
uint64_t vm_get_eptp(struct vm_t *vm);
133135

core/vcpu.c

+78-9
Original file line numberDiff line numberDiff line change
@@ -2506,22 +2506,91 @@ static int exit_cpuid(struct vcpu_t *vcpu, struct hax_tunnel *htun)
25062506
return HAX_RESUME;
25072507
}
25082508

2509+
bool is_cpuid_supported(struct hax_cpuid *cpuid_data)
2510+
{
2511+
uint32_t cpuid_i;
2512+
for (cpuid_i = 0; cpuid_i < cpuid_data->nent; cpuid_i++) {
2513+
switch (cpuid_data->entries[cpuid_i].function) {
2514+
case 0: {
2515+
if (cpuid_data->entries[cpuid_i].eax > 0xa) {
2516+
hax_log(HAX_LOGE, "Unsupported cpuid level %d\n",
2517+
cpuid_data->entries[cpuid_i].eax);
2518+
return false;
2519+
}
2520+
break;
2521+
}
2522+
case 0x80000000: {
2523+
if (cpuid_data->entries[cpuid_i].eax > 0x80000008) {
2524+
hax_log(HAX_LOGE, "Unsupported cpuid xlevel %d\n",
2525+
cpuid_data->entries[cpuid_i].eax);
2526+
return false;
2527+
}
2528+
break;
2529+
}
2530+
case 1: {
2531+
// Disallow to clear these feature bits, since MSR handling
2532+
// code is written as if these are supported.
2533+
uint32_t nonDisabledFlags = FEATURE(MCE) | FEATURE(APIC) |
2534+
FEATURE(MTRR) | FEATURE(PAT);
2535+
if ((cpuid_data->entries[cpuid_i].edx & nonDisabledFlags) !=
2536+
nonDisabledFlags) {
2537+
hax_log(HAX_LOGE, "MCE/APIC/MTRR/PAT disabling in cpuid "
2538+
"not supported\n");
2539+
return false;
2540+
}
2541+
break;
2542+
}
2543+
}
2544+
}
2545+
return true;
2546+
}
2547+
2548+
static int get_vm_cpuid(struct vcpu_t *vcpu, uint32_t a, uint32_t c)
2549+
{
2550+
struct hax_cpuid_entry *cpuid_entry;
2551+
struct vcpu_state_t *state = vcpu->state;
2552+
2553+
cpuid_entry = &vcpu->vm->cpuid_data->entries[0];
2554+
for (uint32_t cpuid_i = 0; cpuid_i < vcpu->vm->cpuid_data->nent;
2555+
cpuid_i++) {
2556+
if (cpuid_entry[cpuid_i].function == a &&
2557+
(!(cpuid_entry[cpuid_i].flags & HAX_CPUID_FLAG_SIGNIFCANT_INDEX) ||
2558+
cpuid_entry[cpuid_i].index == c)) {
2559+
2560+
state->_eax = cpuid_entry[cpuid_i].eax;
2561+
state->_ecx = cpuid_entry[cpuid_i].ecx;
2562+
state->_edx = cpuid_entry[cpuid_i].edx;
2563+
state->_ebx = cpuid_entry[cpuid_i].ebx;
2564+
return 1;
2565+
}
2566+
}
2567+
2568+
state->_eax = 0;
2569+
state->_ecx = 0;
2570+
state->_edx = 0;
2571+
state->_ebx = 0;
2572+
return 0;
2573+
}
2574+
25092575
static void handle_cpuid(struct vcpu_t *vcpu, struct hax_tunnel *htun)
25102576
{
25112577
struct vcpu_state_t *state = vcpu->state;
25122578
uint32_t a = state->_eax, c = state->_ecx;
25132579
cpuid_args_t args;
25142580

2515-
args.eax = state->_eax;
2516-
args.ecx = state->_ecx;
2517-
asm_cpuid(&args);
2518-
state->_eax = args.eax;
2519-
state->_ecx = args.ecx;
2520-
state->_edx = args.edx;
2521-
state->_ebx = args.ebx;
2522-
2523-
handle_cpuid_virtual(vcpu, a, c);
2581+
if(vcpu->vm->cpuid_data) {
2582+
get_vm_cpuid(vcpu, a, c);
2583+
} else {
2584+
args.eax = state->_eax;
2585+
args.ecx = state->_ecx;
2586+
asm_cpuid(&args);
2587+
state->_eax = args.eax;
2588+
state->_ecx = args.ecx;
2589+
state->_edx = args.edx;
2590+
state->_ebx = args.ebx;
25242591

2592+
handle_cpuid_virtual(vcpu, a, c);
2593+
}
25252594
hax_log(HAX_LOGD, "CPUID %08x %08x: %08x %08x %08x %08x\n", a, c,
25262595
state->_eax, state->_ebx, state->_ecx, state->_edx);
25272596
htun->_exit_reason = vmx(vcpu, exit_reason).basic_reason;

core/vm.c

+29
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,35 @@ int hax_vm_set_qemuversion(struct vm_t *vm, struct hax_qemu_version *ver)
8181
return 0;
8282
}
8383

84+
int hax_vm_set_cpuid(struct vm_t *vm, struct hax_cpuid *cpuid_data)
85+
{
86+
uint32_t dSize, cpuid_i;
87+
88+
if (vm->cpuid_data) {
89+
dSize = sizeof(struct hax_cpuid) +
90+
sizeof(struct hax_cpuid_entry) * vm->cpuid_data->nent;
91+
92+
hax_vfree(vm->cpuid_data, dSize);
93+
vm->cpuid_data = 0;
94+
}
95+
96+
if (!is_cpuid_supported(cpuid_data)) {
97+
hax_log(HAX_LOGE, "%s: is_cpuid_supported failed\n", __func__);
98+
return -EINVAL;
99+
}
100+
dSize = sizeof(struct hax_cpuid) +
101+
sizeof(struct hax_cpuid_entry) * cpuid_data->nent;
102+
103+
vm->cpuid_data = hax_vmalloc(dSize, HAX_MEM_NONPAGE);
104+
if (!vm->cpuid_data) {
105+
hax_log(HAX_LOGE, "%s: Not enough memory for cpuid_data\n", __func__);
106+
return -ENOMEM;
107+
}
108+
109+
memcpy(vm->cpuid_data, cpuid_data, dSize);
110+
return 0;
111+
}
112+
84113
uint64_t vm_get_eptp(struct vm_t *vm)
85114
{
86115
return vm->ept_tree.eptp.value;

include/darwin/hax_interface_mac.h

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767

6868
/* API 2.0 */
6969
#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION _IOW(0, 0x84, struct hax_qemu_version)
70+
#define HAX_VM_IOCTL_SET_CPUID _IOW(0, 0x88, struct hax_cpuid_data)
7071

7172
#define HAX_IOCTL_VCPU_DEBUG _IOW(0, 0xc9, struct hax_debug_t)
7273

include/hax_interface.h

+28
Original file line numberDiff line numberDiff line change
@@ -297,4 +297,32 @@ struct hax_debug_t {
297297
uint64_t dr[8];
298298
} PACKED;
299299

300+
#define HAX_CPUID_FLAG_SIGNIFCANT_INDEX (1 << 0)
301+
302+
struct hax_cpuid_entry {
303+
uint32_t function;
304+
uint32_t index;
305+
uint32_t flags;
306+
uint32_t eax;
307+
uint32_t ebx;
308+
uint32_t ecx;
309+
uint32_t edx;
310+
uint32_t padding[3];
311+
} PACKED;
312+
313+
struct hax_cpuid {
314+
uint32_t nent;
315+
uint32_t padding;
316+
struct hax_cpuid_entry entries[0];
317+
} PACKED;
318+
319+
#ifndef HAX_PLATFORM_WINDOWS
320+
#define HAX_MAX_CPUID_ENTRIES 32
321+
322+
struct hax_cpuid_data {
323+
struct hax_cpuid cpuid;
324+
struct hax_cpuid_entry entries[HAX_MAX_CPUID_ENTRIES];
325+
} PACKED;
326+
#endif
327+
300328
#endif // HAX_INTERFACE_H_

include/linux/hax_interface_linux.h

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868

6969
/* API 2.0 */
7070
#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION _IOW(0, 0x84, struct hax_qemu_version)
71+
#define HAX_VM_IOCTL_SET_CPUID _IOW(0, 0x88, struct hax_cpuid)
7172

7273
#define HAX_IOCTL_VCPU_DEBUG _IOW(0, 0xc9, struct hax_debug_t)
7374

include/netbsd/hax_interface_netbsd.h

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171

7272
/* API 2.0 */
7373
#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION _IOW(0, 0x84, struct hax_qemu_version)
74+
#define HAX_VM_IOCTL_SET_CPUID _IOW(0, 0x88, struct hax_cpuid_data)
7475

7576
#define HAX_IOCTL_VCPU_DEBUG _IOW(0, 0xc9, struct hax_debug_t)
7677

platforms/darwin/com_intel_hax_ui.c

+9
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,15 @@ static int hax_vm_ioctl(dev_t dev, ulong cmd, caddr_t data, int flag,
455455
ret = hax_vm_set_qemuversion(cvm, info);
456456
break;
457457
}
458+
case HAX_VM_IOCTL_SET_CPUID: {
459+
struct hax_cpuid_data *info;
460+
461+
info = (struct hax_cpuid_data *)inBuf;
462+
if (hax_vm_set_cpuid(cvm, info->cpuid)) {
463+
ret = -EINVAL;
464+
}
465+
break;
466+
}
458467
default: {
459468
handle_unknown_ioctl(dev, cmd, p);
460469
ret = -ENOSYS;

platforms/linux/components.c

+28
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,34 @@ static long hax_vm_ioctl(struct file *filp, unsigned int cmd,
610610
ret = hax_vm_set_qemuversion(cvm, &info);
611611
break;
612612
}
613+
case HAX_VM_IOCTL_SET_CPUID: {
614+
struct hax_cpuid_data *info;
615+
uint32_t size;
616+
617+
info = (struct hax_cpuid_data *)inBuf;
618+
if (copy_from_user(&info, argp, sizeof(struct hax_cpuid))) {
619+
ret = -EFAULT;
620+
break;
621+
}
622+
623+
if (info->nent > HAX_MAX_CPUID_ENTRIES) {
624+
ret = -E2BIG;
625+
break;
626+
}
627+
628+
size = sizeof(struct hax_cpuid) +
629+
sizeof(struct hax_cpuid_entry) * info->nent;
630+
631+
if (copy_from_user(&info, argp, size)) {
632+
ret = -EFAULT;
633+
break;
634+
}
635+
636+
if (hax_vm_set_cpuid(cvm, info)) {
637+
ret = EFAULT;
638+
}
639+
break;
640+
}
613641
default:
614642
// TODO: Print information about the process that sent the ioctl.
615643
hax_log(HAX_LOGE, "Unknown VM IOCTL 0x%lx\n", cmd);

platforms/netbsd/hax_entry_vm.c

+9
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,15 @@ int hax_vm_ioctl(dev_t self __unused, u_long cmd, void *data, int flag,
214214
ret = hax_vm_set_qemuversion(cvm, info);
215215
break;
216216
}
217+
case HAX_VM_IOCTL_SET_CPUID: {
218+
struct hax_cpuid_data *info;
219+
220+
info = (struct hax_cpuid_data *)inBuf;
221+
if (hax_vm_set_cpuid(cvm, info->cpuid)) {
222+
ret = -EINVAL;
223+
}
224+
break;
225+
}
217226
default:
218227
// TODO: Print information about the process that sent the ioctl.
219228
hax_log(HAX_LOGE, "Unknown VM IOCTL %#lx, pid=%d ('%s')\n", cmd,

platforms/windows/hax_entry.c

+25
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,31 @@ NTSTATUS HaxVmControl(PDEVICE_OBJECT DeviceObject, struct hax_vm_windows *ext,
613613
hax_vm_set_qemuversion(cvm, info);
614614
break;
615615
}
616+
case HAX_VM_IOCTL_SET_CPUID: {
617+
struct hax_cpuid *info;
618+
uint32_t size;
619+
620+
if (inBufLength < sizeof(struct hax_cpuid)) {
621+
ret = STATUS_INVALID_PARAMETER;
622+
goto done;
623+
}
624+
625+
info = (struct hax_cpuid *)inBuf;
626+
size = sizeof(struct hax_cpuid) +
627+
sizeof(struct hax_cpuid_entry) * info->nent;
628+
629+
// Check buffer is of reasonable size (0x2000 should be enough)
630+
if (inBufLength < size || 0x2000 < size) {
631+
ret = STATUS_INVALID_PARAMETER;
632+
goto done;
633+
}
634+
635+
if (hax_vm_set_cpuid(cvm, info)) {
636+
ret = STATUS_UNSUCCESSFUL;
637+
goto done;
638+
}
639+
break;
640+
}
616641
default:
617642
ret = STATUS_INVALID_PARAMETER;
618643
break;

platforms/windows/hax_entry.h

+2
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ extern PDRIVER_OBJECT HaxDriverObject;
162162
/* API version 2.0 */
163163
#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION \
164164
CTL_CODE(HAX_DEVICE_TYPE, 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS)
165+
#define HAX_VM_IOCTL_SET_CPUID \
166+
CTL_CODE(HAX_DEVICE_TYPE, 0x917, METHOD_BUFFERED, FILE_ANY_ACCESS)
165167

166168
#define HAX_IOCTL_VCPU_DEBUG \
167169
CTL_CODE(HAX_DEVICE_TYPE, 0x916, METHOD_BUFFERED, FILE_ANY_ACCESS)

0 commit comments

Comments
 (0)