Add ioctls to control the X2APIC capability exposed by the virtual machine to

the guest.

At the moment this simply sets the state in the 'vcpu' instance but there is
no code that acts upon these settings.
This commit is contained in:
Neel Natu 2012-09-25 19:08:51 +00:00
parent edf89256dd
commit e90273829b
7 changed files with 114 additions and 0 deletions

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -185,6 +185,8 @@ usage(void)
" [--get-vmcs-interruptibility]\n"
" [--set-pinning=<host_cpuid>]\n"
" [--get-pinning]\n"
" [--set-x2apic-state=<state>]\n"
" [--get-x2apic-state]\n"
" [--set-lowmem=<memory below 4GB in units of MB>]\n"
" [--get-lowmem]\n"
" [--set-highmem=<memory above 4GB in units of MB>]\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)