If VMware ESX finds itself virtualized (read: inside VMware), it reads the TSC
speed
from its backdoor, because measuring the TSC inside a VM is not exact.
This patch implements a hacky way to detect the TSC speed and passes that
through to
the VM. I am open to suggestions on how to improve the behavior.
It also adds a magic return value of 2 on the version return, which is required
by
VMware ESX.
WARNING: This implementation breaks on non-x86 hosts!
Signed-off-by: Alexander Graf <address@hidden>
---
hw/vmport.c | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/hw/vmport.c b/hw/vmport.c
index 884af3f..825fd92 100644
--- a/hw/vmport.c
+++ b/hw/vmport.c
@@ -28,6 +28,7 @@
//#define VMPORT_DEBUG
+#define VMPORT_CMD_GETPROCSPEED 0x01
#define VMPORT_CMD_GETVERSION 0x0a
#define VMPORT_CMD_GETRAMSIZE 0x14
@@ -87,6 +88,7 @@ static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr)
{
CPUState *env = cpu_single_env;
env->regs[R_EBX] = VMPORT_MAGIC;
+ env->regs[R_ECX] = 2;
return 6;
}
@@ -97,6 +99,25 @@ static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr)
return ram_size;
}
+
+static inline int64_t rdtsc(void)
+{
+ int64_t val;
+ asm volatile ("rdtsc" : "=A" (val));
+ return val;
+}
+
+static uint32_t vmport_cmd_proc_speed(void *opaque, uint32_t addr)
+{
+ static uint64_t tsc = 0;
+ if ( tsc == 0 ) {
+ tsc = rdtsc();
+ usleep(100000);
+ tsc = (rdtsc() - tsc) / 100000;
+ }
+ return (tsc / 66) * 66;
+}
+
void vmport_init(void)
{
register_ioport_read(0x5658, 1, 4, vmport_ioport_read, &port_state);
@@ -105,4 +126,5 @@ void vmport_init(void)
/* Register some generic port commands */
vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL);
vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL);
+ vmport_register(VMPORT_CMD_GETPROCSPEED, vmport_cmd_proc_speed, NULL);
}