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

Commit

Permalink
Add set_cpuid ioctl that enables setting cpuid values to be returned …
Browse files Browse the repository at this point in the history
…by haxm

Signed-off-by: Alexey Romko <[email protected]>
  • Loading branch information
nevilad committed Mar 8, 2020
1 parent 7f3aaab commit 3c3af3b
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 9 deletions.
1 change: 1 addition & 0 deletions core/include/hax_core_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ int hax_vm_core_open(struct vm_t *vm);
/* Corresponding hax_get_vm with refer == 1 */
int hax_put_vm(struct vm_t *vm);
int hax_vm_set_qemuversion(struct vm_t *vm, struct hax_qemu_version *ver);
int hax_vm_set_cpuid(struct vm_t *vm, struct hax_cpuid *cpuid_data);

struct vm_t * hax_create_vm(int *vm_id);
int hax_teardown_vm(struct vm_t *vm);
Expand Down
1 change: 1 addition & 0 deletions core/include/vcpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,5 +288,6 @@ static inline bool valid_vcpu_id(int vcpu_id)

bool vcpu_is_panic(struct vcpu_t *vcpu);
void vcpu_set_panic(struct vcpu_t *vcpu);
bool is_cpuid_supported(struct hax_cpuid *cpuid_data);

#endif // HAX_CORE_VCPU_H_
2 changes: 2 additions & 0 deletions core/include/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct vm_t {
uint64_t spare_ramsize;
uint ram_entry_num;
struct hax_vcpu_mem *ram_entry;
struct hax_cpuid *cpuid_data;
};

struct hva_entry {
Expand Down Expand Up @@ -128,6 +129,7 @@ int _hax_teardown_vm(struct vm_t *vm);
void hax_teardown_vcpus(struct vm_t *vm);
int hax_destroy_host_interface(void);
int hax_vm_set_qemuversion(struct vm_t *vm, struct hax_qemu_version *ver);
//int hax_vm_set_cpuid(struct vm_t *vm, struct hax_cpuid *cpuid_data);

uint64_t vm_get_eptp(struct vm_t *vm);

Expand Down
87 changes: 78 additions & 9 deletions core/vcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2506,22 +2506,91 @@ static int exit_cpuid(struct vcpu_t *vcpu, struct hax_tunnel *htun)
return HAX_RESUME;
}

bool is_cpuid_supported(struct hax_cpuid *cpuid_data)
{
uint32_t cpuid_i;
for (cpuid_i = 0; cpuid_i < cpuid_data->nent; cpuid_i++) {
switch (cpuid_data->entries[cpuid_i].function) {
case 0: {
if (cpuid_data->entries[cpuid_i].eax > 0xa) {
hax_log(HAX_LOGE, "Unsupported cpuid level %d\n",
cpuid_data->entries[cpuid_i].eax);
return false;
}
break;
}
case 0x80000000: {
if (cpuid_data->entries[cpuid_i].eax > 0x80000008) {
hax_log(HAX_LOGE, "Unsupported cpuid xlevel %d\n",
cpuid_data->entries[cpuid_i].eax);
return false;
}
break;
}
case 1: {
// Disallow to clear these feature bits, since MSR handling
// code is written as if these are supported.
uint32_t nonDisabledFlags = FEATURE(MCE) | FEATURE(APIC) |
FEATURE(MTRR) | FEATURE(PAT);
if ((cpuid_data->entries[cpuid_i].edx & nonDisabledFlags) !=
nonDisabledFlags) {
hax_log(HAX_LOGE, "MCE/APIC/MTRR/PAT disabling in cpuid "
"not supported\n");
return false;
}
break;
}
}
}
return true;
}

static int get_vm_cpuid(struct vcpu_t *vcpu, uint32_t a, uint32_t c)
{
struct hax_cpuid_entry *cpuid_entry;
struct vcpu_state_t *state = vcpu->state;

cpuid_entry = &vcpu->vm->cpuid_data->entries[0];
for (uint32_t cpuid_i = 0; cpuid_i < vcpu->vm->cpuid_data->nent;
cpuid_i++) {
if (cpuid_entry[cpuid_i].function == a &&
(!(cpuid_entry[cpuid_i].flags & HAX_CPUID_FLAG_SIGNIFCANT_INDEX) ||
cpuid_entry[cpuid_i].index == c)) {

state->_eax = cpuid_entry[cpuid_i].eax;
state->_ecx = cpuid_entry[cpuid_i].ecx;
state->_edx = cpuid_entry[cpuid_i].edx;
state->_ebx = cpuid_entry[cpuid_i].ebx;
return 1;
}
}

state->_eax = 0;
state->_ecx = 0;
state->_edx = 0;
state->_ebx = 0;
return 0;
}

static void handle_cpuid(struct vcpu_t *vcpu, struct hax_tunnel *htun)
{
struct vcpu_state_t *state = vcpu->state;
uint32_t a = state->_eax, c = state->_ecx;
cpuid_args_t args;

args.eax = state->_eax;
args.ecx = state->_ecx;
asm_cpuid(&args);
state->_eax = args.eax;
state->_ecx = args.ecx;
state->_edx = args.edx;
state->_ebx = args.ebx;

handle_cpuid_virtual(vcpu, a, c);
if(vcpu->vm->cpuid_data) {
get_vm_cpuid(vcpu, a, c);
} else {
args.eax = state->_eax;
args.ecx = state->_ecx;
asm_cpuid(&args);
state->_eax = args.eax;
state->_ecx = args.ecx;
state->_edx = args.edx;
state->_ebx = args.ebx;

handle_cpuid_virtual(vcpu, a, c);
}
hax_log(HAX_LOGD, "CPUID %08x %08x: %08x %08x %08x %08x\n", a, c,
state->_eax, state->_ebx, state->_ecx, state->_edx);
htun->_exit_reason = vmx(vcpu, exit_reason).basic_reason;
Expand Down
29 changes: 29 additions & 0 deletions core/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,35 @@ int hax_vm_set_qemuversion(struct vm_t *vm, struct hax_qemu_version *ver)
return 0;
}

int hax_vm_set_cpuid(struct vm_t *vm, struct hax_cpuid *cpuid_data)
{
uint32_t dSize, cpuid_i;

if (vm->cpuid_data) {
dSize = sizeof(struct hax_cpuid) +
sizeof(struct hax_cpuid_entry) * vm->cpuid_data->nent;

hax_vfree(vm->cpuid_data, dSize);
vm->cpuid_data = 0;
}

if (!is_cpuid_supported(cpuid_data)) {
hax_log(HAX_LOGE, "%s: is_cpuid_supported failed\n", __func__);
return -EINVAL;
}
dSize = sizeof(struct hax_cpuid) +
sizeof(struct hax_cpuid_entry) * cpuid_data->nent;

vm->cpuid_data = hax_vmalloc(dSize, HAX_MEM_NONPAGE);
if (!vm->cpuid_data) {
hax_log(HAX_LOGE, "%s: Not enough memory for cpuid_data\n", __func__);
return -ENOMEM;
}

memcpy(vm->cpuid_data, cpuid_data, dSize);
return 0;
}

uint64_t vm_get_eptp(struct vm_t *vm)
{
return vm->ept_tree.eptp.value;
Expand Down
1 change: 1 addition & 0 deletions include/darwin/hax_interface_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@

/* API 2.0 */
#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION _IOW(0, 0x84, struct hax_qemu_version)
#define HAX_VM_IOCTL_SET_CPUID _IOW(0, 0x88, struct hax_cpuid_data)

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

Expand Down
28 changes: 28 additions & 0 deletions include/hax_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,32 @@ struct hax_debug_t {
uint64_t dr[8];
} PACKED;

#define HAX_CPUID_FLAG_SIGNIFCANT_INDEX (1 << 0)

struct hax_cpuid_entry {
uint32_t function;
uint32_t index;
uint32_t flags;
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t padding[3];
} PACKED;

struct hax_cpuid {
uint32_t nent;
uint32_t padding;
struct hax_cpuid_entry entries[0];
} PACKED;

#ifndef HAX_PLATFORM_WINDOWS
#define HAX_MAX_CPUID_ENTRIES 32

struct hax_cpuid_data {
struct hax_cpuid cpuid;
struct hax_cpuid_entry entries[HAX_MAX_CPUID_ENTRIES];
} PACKED;
#endif

#endif // HAX_INTERFACE_H_
1 change: 1 addition & 0 deletions include/linux/hax_interface_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@

/* API 2.0 */
#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION _IOW(0, 0x84, struct hax_qemu_version)
#define HAX_VM_IOCTL_SET_CPUID _IOW(0, 0x88, struct hax_cpuid)

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

Expand Down
1 change: 1 addition & 0 deletions include/netbsd/hax_interface_netbsd.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@

/* API 2.0 */
#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION _IOW(0, 0x84, struct hax_qemu_version)
#define HAX_VM_IOCTL_SET_CPUID _IOW(0, 0x88, struct hax_cpuid_data)

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

Expand Down
9 changes: 9 additions & 0 deletions platforms/darwin/com_intel_hax_ui.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,15 @@ static int hax_vm_ioctl(dev_t dev, ulong cmd, caddr_t data, int flag,
ret = hax_vm_set_qemuversion(cvm, info);
break;
}
case HAX_VM_IOCTL_SET_CPUID: {
struct hax_cpuid_data *info;

info = (struct hax_cpuid_data *)inBuf;
if (hax_vm_set_cpuid(cvm, info->cpuid)) {
ret = -EINVAL;
}
break;
}
default: {
handle_unknown_ioctl(dev, cmd, p);
ret = -ENOSYS;
Expand Down
28 changes: 28 additions & 0 deletions platforms/linux/components.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,34 @@ static long hax_vm_ioctl(struct file *filp, unsigned int cmd,
ret = hax_vm_set_qemuversion(cvm, &info);
break;
}
case HAX_VM_IOCTL_SET_CPUID: {
struct hax_cpuid_data *info;
uint32_t size;

info = (struct hax_cpuid_data *)inBuf;
if (copy_from_user(&info, argp, sizeof(struct hax_cpuid))) {
ret = -EFAULT;
break;
}

if (info->nent > HAX_MAX_CPUID_ENTRIES) {
ret = -E2BIG;
break;
}

size = sizeof(struct hax_cpuid) +
sizeof(struct hax_cpuid_entry) * info->nent;

if (copy_from_user(&info, argp, size)) {
ret = -EFAULT;
break;
}

if (hax_vm_set_cpuid(cvm, info)) {
ret = EFAULT;
}
break;
}
default:
// TODO: Print information about the process that sent the ioctl.
hax_log(HAX_LOGE, "Unknown VM IOCTL 0x%lx\n", cmd);
Expand Down
9 changes: 9 additions & 0 deletions platforms/netbsd/hax_entry_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,15 @@ int hax_vm_ioctl(dev_t self __unused, u_long cmd, void *data, int flag,
ret = hax_vm_set_qemuversion(cvm, info);
break;
}
case HAX_VM_IOCTL_SET_CPUID: {
struct hax_cpuid_data *info;

info = (struct hax_cpuid_data *)inBuf;
if (hax_vm_set_cpuid(cvm, info->cpuid)) {
ret = -EINVAL;
}
break;
}
default:
// TODO: Print information about the process that sent the ioctl.
hax_log(HAX_LOGE, "Unknown VM IOCTL %#lx, pid=%d ('%s')\n", cmd,
Expand Down
25 changes: 25 additions & 0 deletions platforms/windows/hax_entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,31 @@ NTSTATUS HaxVmControl(PDEVICE_OBJECT DeviceObject, struct hax_vm_windows *ext,
hax_vm_set_qemuversion(cvm, info);
break;
}
case HAX_VM_IOCTL_SET_CPUID: {
struct hax_cpuid *info;
uint32_t size;

if (inBufLength < sizeof(struct hax_cpuid)) {
ret = STATUS_INVALID_PARAMETER;
goto done;
}

info = (struct hax_cpuid *)inBuf;
size = sizeof(struct hax_cpuid) +
sizeof(struct hax_cpuid_entry) * info->nent;

// Check buffer is of reasonable size (0x2000 should be enough)
if (inBufLength < size || 0x2000 < size) {
ret = STATUS_INVALID_PARAMETER;
goto done;
}

if (hax_vm_set_cpuid(cvm, info)) {
ret = STATUS_UNSUCCESSFUL;
goto done;
}
break;
}
default:
ret = STATUS_INVALID_PARAMETER;
break;
Expand Down
2 changes: 2 additions & 0 deletions platforms/windows/hax_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ extern PDRIVER_OBJECT HaxDriverObject;
/* API version 2.0 */
#define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION \
CTL_CODE(HAX_DEVICE_TYPE, 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_SET_CPUID \
CTL_CODE(HAX_DEVICE_TYPE, 0x917, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define HAX_IOCTL_VCPU_DEBUG \
CTL_CODE(HAX_DEVICE_TYPE, 0x916, METHOD_BUFFERED, FILE_ANY_ACCESS)
Expand Down

0 comments on commit 3c3af3b

Please sign in to comment.