aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hax.h1
-rw-r--r--target-i386/hax-all.c50
-rw-r--r--target-i386/hax-darwin.c14
-rw-r--r--target-i386/hax-darwin.h2
-rw-r--r--target-i386/hax-i386.h2
-rw-r--r--target-i386/hax-interface.h35
-rw-r--r--target-i386/hax-windows.c30
-rw-r--r--target-i386/hax-windows.h1
-rw-r--r--vl-android.c1
9 files changed, 135 insertions, 1 deletions
diff --git a/hax.h b/hax.h
index 9af61ce..a29e45e 100644
--- a/hax.h
+++ b/hax.h
@@ -11,6 +11,7 @@ struct hax_vcpu_state;
#ifdef CONFIG_HAX
int hax_enabled(void);
+int hax_set_ramsize(uint64_t ramsize);
int hax_init(int smp_cpus);
int hax_init_vcpu(CPUState *env);
/* Execute vcpu in non-root mode */
diff --git a/target-i386/hax-all.c b/target-i386/hax-all.c
index c8f4cec..0c3b589 100644
--- a/target-i386/hax-all.c
+++ b/target-i386/hax-all.c
@@ -124,6 +124,37 @@ uint32_t hax_cur_version = 0x1;
/* Least HAX kernel version */
uint32_t hax_lest_version = 0x1;
+static int hax_get_capability(struct hax_state *hax)
+{
+ int ret;
+ struct hax_capabilityinfo capinfo, *cap = &capinfo;
+
+ ret = hax_capability(hax, cap);
+ if (ret)
+ return -ENOSYS;
+
+ if ( ((cap->wstatus & HAX_CAP_WORKSTATUS_MASK) ==
+ HAX_CAP_STATUS_NOTWORKING ))
+ {
+ if (cap->winfo & HAX_CAP_FAILREASON_VT)
+ dprint("VT feature is not enabled, HAXM not working.\n");
+ else if (cap->winfo & HAX_CAP_FAILREASON_NX)
+ dprint("NX feature is not enabled, HAXM not working.\n");
+ return -ENXIO;
+ }
+
+ if (cap->wstatus & HAX_CAP_MEMQUOTA)
+ {
+ if (cap->mem_quota < hax->mem_quota)
+ {
+ dprint("The memory needed by this VM exceeds the driver limit.\n");
+ return -ENOSPC;
+ }
+ }
+
+ return 0;
+}
+
static int hax_version_support(struct hax_state *hax)
{
int ret;
@@ -296,6 +327,16 @@ int hax_vm_destroy(struct hax_vm *vm)
return 0;
}
+int hax_set_ramsize(uint64_t ramsize)
+{
+ struct hax_state *hax = &hax_global;
+
+ memset(hax, 0, sizeof(struct hax_state));
+ hax->mem_quota = ram_size;
+
+ return 0;
+}
+
int hax_init(int smp_cpus)
{
struct hax_state *hax = NULL;
@@ -304,7 +345,6 @@ int hax_init(int smp_cpus)
hax_support = 0;
hax = &hax_global;
- memset(hax, 0, sizeof(struct hax_state));
hax->fd = hax_mod_open();
if (hax_invalid_fd(hax->fd))
@@ -314,6 +354,14 @@ int hax_init(int smp_cpus)
goto error;
}
+ ret = hax_get_capability(hax);
+ /* In case HAXM have no such capability support */
+ if (ret && (ret != -ENOSYS))
+ {
+ ret = -EINVAL;
+ goto error;
+ }
+
if (!hax_version_support(hax))
{
dprint("Incompatible HAX version. Qemu current version %x ", hax_cur_version );
diff --git a/target-i386/hax-darwin.c b/target-i386/hax-darwin.c
index 45c781b..1522d39 100644
--- a/target-i386/hax-darwin.c
+++ b/target-i386/hax-darwin.c
@@ -85,6 +85,20 @@ int hax_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, ram_addr_t
return ret;
}
+int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap)
+{
+ int ret;
+
+ ret = ioctl(hax->fd, HAX_IOCTL_CAPABILITY, cap);
+ if (ret == -1)
+ {
+ dprint("Failed to get HAX capability\n");
+ return -errno;
+ }
+
+ return 0;
+}
+
int hax_mod_version(struct hax_state *hax, struct hax_module_version *version)
{
int ret;
diff --git a/target-i386/hax-darwin.h b/target-i386/hax-darwin.h
index 261cfd3..2c6129b 100644
--- a/target-i386/hax-darwin.h
+++ b/target-i386/hax-darwin.h
@@ -40,6 +40,8 @@ static inline void hax_close_fd(hax_fd fd)
#define HAX_IOCTL_VERSION _IOWR(0, 0x20, struct hax_module_version)
/* Create VM instance and return the vm_id */
#define HAX_IOCTL_CREATE_VM _IOWR(0, 0x21, int)
+/* Get HAXM capability information */
+#define HAX_IOCTL_CAPABILITY _IOR(0, 0x23, struct hax_capabilityinfo)
/* Pass down a VM_ID, create a VCPU instance for it */
#define HAX_VM_IOCTL_VCPU_CREATE _IOR(0, 0x80, int)
diff --git a/target-i386/hax-i386.h b/target-i386/hax-i386.h
index 5ad22ad..a5a7e1d 100644
--- a/target-i386/hax-i386.h
+++ b/target-i386/hax-i386.h
@@ -40,6 +40,7 @@ struct hax_state
hax_fd fd; /* the global hax device interface */
uint32_t version;
struct hax_vm *vm;
+ uint64_t mem_quota;
};
#define HAX_MAX_VCPU 0x10
@@ -67,6 +68,7 @@ int hax_sync_vcpu_state(CPUState *env, struct vcpu_state_t *state, int set);
int hax_sync_msr(CPUState *env, struct hax_msr_data *msrs, int set);
int hax_sync_fpu(CPUState *env, struct fx_layout *fl, int set);
int hax_vm_destroy(struct hax_vm *vm);
+int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap);
/* Common host function */
int hax_host_create_vm(struct hax_state *hax, int *vm_id);
diff --git a/target-i386/hax-interface.h b/target-i386/hax-interface.h
index 5a9ed31..569eeba 100644
--- a/target-i386/hax-interface.h
+++ b/target-i386/hax-interface.h
@@ -347,4 +347,39 @@ struct hax_set_ram_info
uint64_t va;
};
+/*
+ * We need to load the HAXM (HAX Manager) to tell if the host system has the
+ * required capabilities to operate, and we use hax_capabilityinfo to get such
+ * info from HAXM.
+ *
+ * To prevent HAXM from over-consuming RAM, we set the maximum amount of RAM
+ * that can be used for guests at HAX installation time. Once the quota is
+ * reached, HAXM will no longer attempt to allocate memory for guests.
+ * Detect that HAXM is out of quota can take the emulator to non-HAXM model
+ */
+struct hax_capabilityinfo
+{
+ /* bit 0: 1 - HAXM is working
+ * 0 - HAXM is not working possibly because VT/NX is disabled
+ NX means Non-eXecution, aks. XD (eXecution Disable)
+ * bit 1: 1 - HAXM has hard limit on how many RAM can be used as guest RAM
+ * 0 - HAXM has no memory limitation
+ */
+#define HAX_CAP_STATUS_WORKING 0x1
+#define HAX_CAP_STATUS_NOTWORKING 0x0
+#define HAX_CAP_WORKSTATUS_MASK 0x1
+#define HAX_CAP_MEMQUOTA 0x2
+ uint16_t wstatus;
+ /*
+ * valid when HAXM is not working
+ * bit 0: HAXM is not working because VT is not enabeld
+ * bit 1: HAXM is not working because NX not enabled
+ */
+#define HAX_CAP_FAILREASON_VT 0x1
+#define HAX_CAP_FAILREASON_NX 0x2
+ uint16_t winfo;
+ uint32_t pad;
+ uint64_t mem_quota;
+};
+
#endif
diff --git a/target-i386/hax-windows.c b/target-i386/hax-windows.c
index d66ec4a..0035d21 100644
--- a/target-i386/hax-windows.c
+++ b/target-i386/hax-windows.c
@@ -133,6 +133,36 @@ int hax_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size, ram_addr_t
return 0;
}
+int hax_capability(struct hax_state *hax, struct hax_capabilityinfo *cap)
+{
+ int ret;
+ HANDLE hDevice = hax->fd; //handle to hax module
+ DWORD dSize = 0;
+ DWORD err = 0;
+
+ if (hax_invalid_fd(hDevice)) {
+ dprint("Invalid fd for hax device!\n");
+ return -ENODEV;
+ }
+
+ ret = DeviceIoControl(hDevice,
+ HAX_IOCTL_CAPABILITY,
+ NULL, 0,
+ cap, sizeof(*cap),
+ &dSize,
+ (LPOVERLAPPED) NULL);
+
+ if (!ret) {
+ err = GetLastError();
+ if (err == ERROR_INSUFFICIENT_BUFFER ||
+ err == ERROR_MORE_DATA)
+ dprint("hax capability is too long to hold.\n");
+ dprint("Failed to get Hax capability:%d\n", err);
+ return -EFAULT;
+ } else
+ return 0;
+}
+
int hax_mod_version(struct hax_state *hax, struct hax_module_version *version)
{
int ret;
diff --git a/target-i386/hax-windows.h b/target-i386/hax-windows.h
index b6d60b7..9e596d3 100644
--- a/target-i386/hax-windows.h
+++ b/target-i386/hax-windows.h
@@ -45,6 +45,7 @@ static inline int hax_invalid_fd(hax_fd fd)
/* See comments for the ioctl in hax-darwin.h */
#define HAX_IOCTL_VERSION CTL_CODE(HAX_DEVICE_TYPE, 0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_IOCTL_CREATE_VM CTL_CODE(HAX_DEVICE_TYPE, 0x901, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define HAX_IOCTL_CAPABILITY CTL_CODE(HAX_DEVICE_TYPE, 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_VCPU_CREATE CTL_CODE(HAX_DEVICE_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define HAX_VM_IOCTL_ALLOC_RAM CTL_CODE(HAX_DEVICE_TYPE, 0x903, METHOD_BUFFERED, FILE_ANY_ACCESS)
diff --git a/vl-android.c b/vl-android.c
index 8071052..46f869a 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -4143,6 +4143,7 @@ int main(int argc, char **argv, char **envp)
{
int ret;
+ hax_set_ramsize(ram_size);
ret = hax_init(smp_cpus);
fprintf(stderr, "HAX is %s and emulator runs in %s mode\n",
!ret ? "working" :"not working", !ret ? "fast virt" : "emulation");