diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c index d7e6143c124..78ed3686f8e 100644 --- a/lib/libvmmapi/vmmapi.c +++ b/lib/libvmmapi/vmmapi.c @@ -537,6 +537,35 @@ vm_get_stat_desc(struct vmctx *ctx, int index) return (NULL); } +int +vm_get_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state *state) +{ + int error; + struct vm_x2apic x2apic; + + bzero(&x2apic, sizeof(x2apic)); + x2apic.cpuid = vcpu; + + error = ioctl(ctx->fd, VM_GET_X2APIC_STATE, &x2apic); + *state = x2apic.state; + return (error); +} + +int +vm_set_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state state) +{ + int error; + struct vm_x2apic x2apic; + + bzero(&x2apic, sizeof(x2apic)); + x2apic.cpuid = vcpu; + x2apic.state = state; + + error = ioctl(ctx->fd, VM_SET_X2APIC_STATE, &x2apic); + + return (error); +} + /* * From Intel Vol 3a: * Table 9-1. IA-32 Processor States Following Power-up, Reset or INIT diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h index 516bbc34eaf..b9184097478 100644 --- a/lib/libvmmapi/vmmapi.h +++ b/lib/libvmmapi/vmmapi.h @@ -30,6 +30,7 @@ #define _VMMAPI_H_ struct vmctx; +enum x2apic_state; int vm_create(const char *name); struct vmctx *vm_open(const char *name); @@ -90,6 +91,9 @@ uint64_t *vm_get_stats(struct vmctx *ctx, int vcpu, struct timeval *ret_tv, int *ret_entries); const char *vm_get_stat_desc(struct vmctx *ctx, int index); +int vm_get_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state *s); +int vm_set_x2apic_state(struct vmctx *ctx, int vcpu, enum x2apic_state s); + /* Reset vcpu register state */ int vcpu_reset(struct vmctx *ctx, int vcpu); diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h index e8419639be7..0b3a29c818b 100644 --- a/sys/amd64/include/vmm.h +++ b/sys/amd64/include/vmm.h @@ -40,6 +40,8 @@ struct vm_exit; struct vm_run; struct vlapic; +enum x2apic_state; + typedef int (*vmm_init_func_t)(void); typedef int (*vmm_cleanup_func_t)(void); typedef void * (*vmi_init_func_t)(struct vm *vm); /* instance specific apis */ @@ -109,6 +111,8 @@ uint64_t *vm_guest_msrs(struct vm *vm, int cpu); struct vlapic *vm_lapic(struct vm *vm, int cpu); int vm_get_capability(struct vm *vm, int vcpu, int type, int *val); int vm_set_capability(struct vm *vm, int vcpu, int type, int val); +int vm_get_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state *state); +int vm_set_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state state); void vm_activate_cpu(struct vm *vm, int vcpu); cpuset_t vm_active_cpus(struct vm *vm); struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid); @@ -205,6 +209,13 @@ enum vm_cap_type { VM_CAP_MAX }; +enum x2apic_state { + X2APIC_ENABLED, + X2APIC_AVAILABLE, + X2APIC_DISABLED, + X2APIC_STATE_LAST +}; + /* * The 'access' field has the format specified in Table 21-2 of the Intel * Architecture Manual vol 3b. diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h index d1a50d64ab1..fc64fd8afe7 100644 --- a/sys/amd64/include/vmm_dev.h +++ b/sys/amd64/include/vmm_dev.h @@ -136,6 +136,11 @@ struct vm_stat_desc { char desc[128]; /* out */ }; +struct vm_x2apic { + int cpuid; + enum x2apic_state state; +}; + enum { IOCNUM_RUN, IOCNUM_SET_PINNING, @@ -158,6 +163,8 @@ enum { IOCNUM_INJECT_NMI, IOCNUM_VM_STATS, IOCNUM_VM_STAT_DESC, + IOCNUM_SET_X2APIC_STATE, + IOCNUM_GET_X2APIC_STATE, }; #define VM_RUN \ @@ -202,4 +209,8 @@ enum { _IOWR('v', IOCNUM_VM_STATS, struct vm_stats) #define VM_STAT_DESC \ _IOWR('v', IOCNUM_VM_STAT_DESC, struct vm_stat_desc) +#define VM_SET_X2APIC_STATE \ + _IOW('v', IOCNUM_SET_X2APIC_STATE, struct vm_x2apic) +#define VM_GET_X2APIC_STATE \ + _IOWR('v', IOCNUM_GET_X2APIC_STATE, struct vm_x2apic) #endif diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c index d896f6db062..29dbe675ea6 100644 --- a/sys/amd64/vmm/vmm.c +++ b/sys/amd64/vmm/vmm.c @@ -73,6 +73,7 @@ struct vcpu { struct savefpu *guestfpu; /* guest fpu state */ void *stats; struct vm_exit exitinfo; + enum x2apic_state x2apic_state; }; #define VCPU_F_PINNED 0x0001 #define VCPU_F_RUNNING 0x0002 @@ -163,6 +164,7 @@ vcpu_init(struct vm *vm, uint32_t vcpu_id) vcpu->guestfpu = fpu_save_area_alloc(); fpu_save_area_reset(vcpu->guestfpu); vcpu->stats = vmm_stat_alloc(); + vcpu->x2apic_state = X2APIC_ENABLED; } struct vm_exit * @@ -745,3 +747,28 @@ vcpu_stats(struct vm *vm, int vcpuid) return (vm->vcpu[vcpuid].stats); } + +int +vm_get_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state *state) +{ + if (vcpuid < 0 || vcpuid >= VM_MAXCPU) + return (EINVAL); + + *state = vm->vcpu[vcpuid].x2apic_state; + + return (0); +} + +int +vm_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state) +{ + if (vcpuid < 0 || vcpuid >= VM_MAXCPU) + return (EINVAL); + + if (state < 0 || state >= X2APIC_STATE_LAST) + return (EINVAL); + + vm->vcpu[vcpuid].x2apic_state = state; + + return (0); +} diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c index 116b5f12b7e..686ddec0860 100644 --- a/sys/amd64/vmm/vmm_dev.c +++ b/sys/amd64/vmm/vmm_dev.c @@ -163,6 +163,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, struct vm_nmi *vmnmi; struct vm_stats *vmstats; struct vm_stat_desc *statdesc; + struct vm_x2apic *x2apic; mtx_lock(&vmmdev_mtx); sc = vmmdev_lookup2(cdev); @@ -185,6 +186,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, case VM_GET_CAPABILITY: case VM_SET_CAPABILITY: case VM_PPTDEV_MSI: + case VM_SET_X2APIC_STATE: /* * XXX fragile, handle with care * Assumes that the first field of the ioctl data is the vcpu. @@ -335,6 +337,16 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag, vmcap->captype, vmcap->capval); break; + case VM_SET_X2APIC_STATE: + x2apic = (struct vm_x2apic *)data; + error = vm_set_x2apic_state(sc->vm, + x2apic->cpuid, x2apic->state); + break; + case VM_GET_X2APIC_STATE: + x2apic = (struct vm_x2apic *)data; + error = vm_get_x2apic_state(sc->vm, + x2apic->cpuid, &x2apic->state); + break; default: error = ENOTTY; break; diff --git a/usr.sbin/vmmctl/vmmctl.c b/usr.sbin/vmmctl/vmmctl.c index c0e04024a17..b205c7b87cb 100644 --- a/usr.sbin/vmmctl/vmmctl.c +++ b/usr.sbin/vmmctl/vmmctl.c @@ -185,6 +185,8 @@ usage(void) " [--get-vmcs-interruptibility]\n" " [--set-pinning=]\n" " [--get-pinning]\n" + " [--set-x2apic-state=]\n" + " [--get-x2apic-state]\n" " [--set-lowmem=]\n" " [--get-lowmem]\n" " [--set-highmem=]\n" @@ -217,6 +219,8 @@ static int set_desc_ldtr, get_desc_ldtr; static int set_cs, set_ds, set_es, set_fs, set_gs, set_ss, set_tr, set_ldtr; static int get_cs, get_ds, get_es, get_fs, get_gs, get_ss, get_tr, get_ldtr; static int set_pinning, get_pinning, pincpu; +static int set_x2apic_state, get_x2apic_state; +enum x2apic_state x2apic_state; static int run; /* @@ -371,6 +375,7 @@ enum { SET_TR, SET_LDTR, SET_PINNING, + SET_X2APIC_STATE, SET_VMCS_EXCEPTION_BITMAP, SET_VMCS_ENTRY_INTERRUPTION_INFO, SET_CAP, @@ -419,6 +424,7 @@ main(int argc, char *argv[]) { "set-tr", REQ_ARG, 0, SET_TR }, { "set-ldtr", REQ_ARG, 0, SET_LDTR }, { "set-pinning",REQ_ARG, 0, SET_PINNING }, + { "set-x2apic-state",REQ_ARG, 0, SET_X2APIC_STATE }, { "set-vmcs-exception-bitmap", REQ_ARG, 0, SET_VMCS_EXCEPTION_BITMAP }, { "set-vmcs-entry-interruption-info", @@ -547,6 +553,7 @@ main(int argc, char *argv[]) { "get-vmcs-interruptibility", NO_ARG, &get_vmcs_interruptibility, 1 }, { "get-pinning",NO_ARG, &get_pinning, 1 }, + { "get-x2apic-state",NO_ARG, &get_x2apic_state, 1 }, { "get-all", NO_ARG, &get_all, 1 }, { "run", NO_ARG, &run, 1 }, { "create", NO_ARG, &create, 1 }, @@ -656,6 +663,10 @@ main(int argc, char *argv[]) pincpu = strtol(optarg, NULL, 0); set_pinning = 1; break; + case SET_X2APIC_STATE: + x2apic_state = strtol(optarg, NULL, 0); + set_x2apic_state = 1; + break; case SET_VMCS_EXCEPTION_BITMAP: exception_bitmap = strtoul(optarg, NULL, 0); set_exception_bitmap = 1; @@ -804,6 +815,9 @@ main(int argc, char *argv[]) if (!error && set_pinning) error = vm_set_pinning(ctx, vcpu, pincpu); + if (!error && set_x2apic_state) + error = vm_set_x2apic_state(ctx, vcpu, x2apic_state); + if (!error && set_exception_bitmap) { error = vm_set_vmcs_field(ctx, vcpu, VMCS_EXCEPTION_BITMAP, exception_bitmap); @@ -1129,6 +1143,12 @@ main(int argc, char *argv[]) } } + if (!error && (get_x2apic_state || get_all)) { + error = vm_get_x2apic_state(ctx, vcpu, &x2apic_state); + if (error == 0) + printf("x2apic_state[%d]\t%d\n", vcpu, x2apic_state); + } + if (!error && (get_pinbased_ctls || get_all)) { error = vm_get_vmcs_field(ctx, vcpu, VMCS_PIN_BASED_CTLS, &ctl); if (error == 0)