From 466fc7bdc4516c0c39ae20a19ff0828333c121e9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 8 Mar 2020 12:35:16 +0400 Subject: [PATCH] Set cpuid values to hax through set_cpuid ioctl when run with nondefault cpu Signed-off-by: Alexey Romko --- target/i386/hax-all.c | 105 ++++++++++++++++++++++++++++++++++++++++++++ target/i386/hax-i386.h | 1 + target/i386/hax-interface.h | 21 ++++++++- target/i386/hax-posix.c | 19 +++++++- target/i386/hax-posix.h | 1 + target/i386/hax-windows.c | 26 +++++++++++ target/i386/hax-windows.h | 2 + 7 files changed, 173 insertions(+), 2 deletions(-) diff --git a/target/i386/hax-all.c b/target/i386/hax-all.c index 0bdd309665..e04f34d3b8 100644 --- a/target/i386/hax-all.c +++ b/target/i386/hax-all.c @@ -216,6 +216,107 @@ int hax_vcpu_destroy(CPUState *cpu) return 0; } +#define HAX_MAX_CPUID_ENTRIES 50 + +static int hax_arch_init(CPUState *cs) +{ + struct hax_cpuid_data { + struct hax_cpuid cpuid; + struct hax_cpuid_entry entries[HAX_MAX_CPUID_ENTRIES]; + } __attribute__ ((__packed__)) cpuid_data; + + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + uint32_t limit, i, j, cpuid_i; + uint32_t unused; + struct hax_cpuid_entry *c; + int r; + MachineClass *machine_class = find_default_machine(); + + if( current_machine->cpu_type == machine_class->default_cpu_type ) + return 0; + + if (env->cpuid_xlevel2 > 0) { + fprintf(stderr, "xlevel2 unsupported\n"); + abort(); + } + + cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused); + + /* HAX CPU features are between Nehalem and Penryn. Don't allow to set + more recent CPUs, as HAX doesn't support them */ + if (limit > 0x0a) { + fprintf(stderr, "unsupported level value: 0x%x (max 0xa)\n", limit); + abort(); + } + + memset(&cpuid_data, 0, sizeof(cpuid_data)); + + cpuid_i = 0; + + for (i = 0; i <= limit; i++) { + if (cpuid_i == HAX_MAX_CPUID_ENTRIES) { + fprintf(stderr, "unsupported level value: 0x%x\n", limit); + abort(); + } + c = &cpuid_data.entries[cpuid_i++]; + + if (i == 4) { + for (j = 0; ; j++) { + c->function = i; + c->flags = HAX_CPUID_FLAG_SIGNIFCANT_INDEX; + c->index = j; + cpu_x86_cpuid(env, i, j, &c->eax, &c->ebx, &c->ecx, &c->edx); + + if (c->eax == 0) { + break; + } + if (cpuid_i == HAX_MAX_CPUID_ENTRIES) { + fprintf(stderr, "cpuid_data is full, no space for " + "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); + abort(); + } + c = &cpuid_data.entries[cpuid_i++]; + } + } + else { + c->function = i; + c->flags = 0; + cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); + } + } + + cpu_x86_cpuid(env, 0x80000000, 0, &limit, &unused, &unused, &unused); + + if (limit > 0x80000008) { + fprintf(stderr, "unsupported level value: 0x%x\n", limit); + abort(); + } + + for (i = 0x80000000; i <= limit; i++) { + if (cpuid_i == HAX_MAX_CPUID_ENTRIES) { + fprintf(stderr, "unsupported xlevel value: 0x%x\n", limit); + abort(); + } + c = &cpuid_data.entries[cpuid_i++]; + + c->function = i; + c->flags = 0; + cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); + } + + cpuid_data.cpuid.nent = cpuid_i; + cpuid_data.cpuid.padding = 0; + + r = hax_set_cpuid(&cpuid_data.cpuid); + if (r < 0) { + fprintf(stderr, "Failed to set cpuid info to HAX\n"); + abort(); + } + + return r; +} + int hax_init_vcpu(CPUState *cpu) { int ret; @@ -226,6 +327,10 @@ int hax_init_vcpu(CPUState *cpu) exit(-1); } + /* Ignore errors */ + if( !cpu->cpu_index ) + hax_arch_init(cpu); + cpu->hax_vcpu = hax_global.vm->vcpus[cpu->cpu_index]; cpu->vcpu_dirty = true; qemu_register_reset(hax_reset_vcpu_state, (CPUArchState *) (cpu->env_ptr)); diff --git a/target/i386/hax-i386.h b/target/i386/hax-i386.h index 9515803184..593f035a6c 100644 --- a/target/i386/hax-i386.h +++ b/target/i386/hax-i386.h @@ -65,6 +65,7 @@ int hax_sync_vcpu_state(CPUArchState *env, struct vcpu_state_t *state, int set); int hax_sync_msr(CPUArchState *env, struct hax_msr_data *msrs, int set); int hax_sync_fpu(CPUArchState *env, struct fx_layout *fl, int set); +int hax_set_cpuid(struct hax_cpuid *cpuid); #endif int hax_vm_destroy(struct hax_vm *vm); diff --git a/target/i386/hax-interface.h b/target/i386/hax-interface.h index c87aedbc2e..efa55518eb 100644 --- a/target/i386/hax-interface.h +++ b/target/i386/hax-interface.h @@ -218,7 +218,6 @@ struct vcpu_state_t { uint32_t _activity_state; uint32_t pad; interruptibility_state_t _interruptibility_state; - uint64_t _cr8; }; @@ -368,4 +367,24 @@ struct hax_fastmmio { uint64_t _cr3; uint64_t _cr4; } __attribute__ ((__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]; +}; + +struct hax_cpuid { + uint32_t nent; + uint32_t padding; + struct hax_cpuid_entry entries[0]; +}; + #endif diff --git a/target/i386/hax-posix.c b/target/i386/hax-posix.c index a5426a6dac..9a0c1324cc 100644 --- a/target/i386/hax-posix.c +++ b/target/i386/hax-posix.c @@ -10,7 +10,7 @@ * */ -/* HAX module interface - darwin version */ +/* HAX module interface - posix version */ #include "qemu/osdep.h" #include @@ -321,3 +321,20 @@ int hax_inject_interrupt(CPUArchState *env, int vector) return ioctl(fd, HAX_VCPU_IOCTL_INTERRUPT, &vector); } + +int hax_set_cpuid(struct hax_cpuid *cpuid) +{ + int ret; + + if (!hax_global.vm || !hax_global.vm->fd) { + return -EINVAL; + } + + ret = ioctl(hax_global.vm->fd, HAX_VM_IOCTL_SET_CPUID, cpuid); + + if (!ret) { + return -EFAULT; + } + + return 0; +} diff --git a/target/i386/hax-posix.h b/target/i386/hax-posix.h index fb7c64426d..44ca357157 100644 --- a/target/i386/hax-posix.h +++ b/target/i386/hax-posix.h @@ -45,6 +45,7 @@ static inline void hax_close_fd(hax_fd fd) #define HAX_VM_IOCTL_VCPU_DESTROY _IOW(0, 0x83, uint32_t) #define HAX_VM_IOCTL_NOTIFY_QEMU_VERSION _IOW(0, 0x84, struct hax_qemu_version) #define HAX_VM_IOCTL_ADD_RAMBLOCK _IOW(0, 0x85, struct hax_ramblock_info) +#define HAX_VM_IOCTL_SET_CPUID _IOW(0, 0x88, struct hax_cpuid) #define HAX_VCPU_IOCTL_RUN _IO(0, 0xc0) #define HAX_VCPU_IOCTL_SET_MSRS _IOWR(0, 0xc1, struct hax_msr_data) diff --git a/target/i386/hax-windows.c b/target/i386/hax-windows.c index 5729ad9b48..e960e5aace 100644 --- a/target/i386/hax-windows.c +++ b/target/i386/hax-windows.c @@ -492,3 +492,29 @@ int hax_inject_interrupt(CPUArchState *env, int vector) return 0; } } + +int hax_set_cpuid(struct hax_cpuid *cpuid) +{ + int ret; + HANDLE hDeviceVM; + DWORD size = 0; + + if (!hax_global.vm || !hax_global.vm->fd) { + return -EINVAL; + } + + hDeviceVM = hax_global.vm->fd; + size = sizeof( struct hax_cpuid ) + + sizeof( struct hax_cpuid_entry ) * cpuid->nent; + + ret = DeviceIoControl(hDeviceVM, + HAX_VM_IOCTL_SET_CPUID, + cpuid, size, + NULL, 0, &dSize, (LPOVERLAPPED) NULL); + + if (!ret) { + return -EFAULT; + } + + return 0; +} diff --git a/target/i386/hax-windows.h b/target/i386/hax-windows.h index 12cbd813dc..de0cb8fb06 100644 --- a/target/i386/hax-windows.h +++ b/target/i386/hax-windows.h @@ -59,6 +59,8 @@ static inline int hax_invalid_fd(hax_fd fd) METHOD_BUFFERED, FILE_ANY_ACCESS) #define HAX_VM_IOCTL_ADD_RAMBLOCK CTL_CODE(HAX_DEVICE_TYPE, 0x913, \ METHOD_BUFFERED, FILE_ANY_ACCESS) +#define HAX_VM_IOCTL_SET_CPUID CTL_CODE(HAX_DEVICE_TYPE, 0x917, \ + METHOD_BUFFERED, FILE_ANY_ACCESS) #define HAX_VCPU_IOCTL_RUN CTL_CODE(HAX_DEVICE_TYPE, 0x906, \ METHOD_BUFFERED, FILE_ANY_ACCESS) -- 2.15.0.windows.1