mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
Nested VMX: Define structure and access APIs for virtual VMCS.
Signed-off-by: Qing He <qing.he@intel.com> Signed-off-by: Eddie Dong <eddie.dong@intel.com> Acked-by: Tim Deegan <Tim.Deegan@citrix.com> Committed-by: Tim Deegan <Tim.Deegan@citrix.com>
This commit is contained in:
1 parent
09fce80165
commit
45c152f107
2 files changed
+134
No files matched your search
@@ -119,6 +119,84 @@ enum vmx_ops_result {
|
||||
#define CASE_GET_REG(REG, reg) \
|
||||
case VMX_REG_ ## REG: value = regs->reg; break
|
||||
|
||||
static int vvmcs_offset(u32 width, u32 type, u32 index)
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = (index & 0x1f) | type << 5 | width << 7;
|
||||
|
||||
if ( offset == 0 ) /* vpid */
|
||||
offset = 0x3f;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
u64 __get_vvmcs(void *vvmcs, u32 vmcs_encoding)
|
||||
{
|
||||
union vmcs_encoding enc;
|
||||
u64 *content = (u64 *) vvmcs;
|
||||
int offset;
|
||||
u64 res;
|
||||
|
||||
enc.word = vmcs_encoding;
|
||||
offset = vvmcs_offset(enc.width, enc.type, enc.index);
|
||||
res = content[offset];
|
||||
|
||||
switch ( enc.width ) {
|
||||
case VVMCS_WIDTH_16:
|
||||
res &= 0xffff;
|
||||
break;
|
||||
case VVMCS_WIDTH_64:
|
||||
if ( enc.access_type )
|
||||
res >>= 32;
|
||||
break;
|
||||
case VVMCS_WIDTH_32:
|
||||
res &= 0xffffffff;
|
||||
break;
|
||||
case VVMCS_WIDTH_NATURAL:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void __set_vvmcs(void *vvmcs, u32 vmcs_encoding, u64 val)
|
||||
{
|
||||
union vmcs_encoding enc;
|
||||
u64 *content = (u64 *) vvmcs;
|
||||
int offset;
|
||||
u64 res;
|
||||
|
||||
enc.word = vmcs_encoding;
|
||||
offset = vvmcs_offset(enc.width, enc.type, enc.index);
|
||||
res = content[offset];
|
||||
|
||||
switch ( enc.width ) {
|
||||
case VVMCS_WIDTH_16:
|
||||
res = val & 0xffff;
|
||||
break;
|
||||
case VVMCS_WIDTH_64:
|
||||
if ( enc.access_type )
|
||||
{
|
||||
res &= 0xffffffff;
|
||||
res |= val << 32;
|
||||
}
|
||||
else
|
||||
res = val;
|
||||
break;
|
||||
case VVMCS_WIDTH_32:
|
||||
res = val & 0xffffffff;
|
||||
break;
|
||||
case VVMCS_WIDTH_NATURAL:
|
||||
default:
|
||||
res = val;
|
||||
break;
|
||||
}
|
||||
|
||||
content[offset] = res;
|
||||
}
|
||||
|
||||
static unsigned long reg_read(struct cpu_user_regs *regs,
|
||||
enum vmx_regs_enc index)
|
||||
{
|
||||
|
||||
@@ -96,5 +96,61 @@ uint32_t nvmx_vcpu_asid(struct vcpu *v);
|
||||
|
||||
int nvmx_handle_vmxon(struct cpu_user_regs *regs);
|
||||
int nvmx_handle_vmxoff(struct cpu_user_regs *regs);
|
||||
/*
|
||||
* Virtual VMCS layout
|
||||
*
|
||||
* Since physical VMCS layout is unknown, a custom layout is used
|
||||
* for virtual VMCS seen by guest. It occupies a 4k page, and the
|
||||
* field is offset by an 9-bit offset into u64[], The offset is as
|
||||
* follow, which means every <width, type> pair has a max of 32
|
||||
* fields available.
|
||||
*
|
||||
* 9 7 5 0
|
||||
* --------------------------------
|
||||
* offset: | width | type | index |
|
||||
* --------------------------------
|
||||
*
|
||||
* Also, since the lower range <width=0, type={0,1}> has only one
|
||||
* field: VPID, it is moved to a higher offset (63), and leaves the
|
||||
* lower range to non-indexed field like VMCS revision.
|
||||
*
|
||||
*/
|
||||
|
||||
#define VVMCS_REVISION 0x40000001u
|
||||
|
||||
struct vvmcs_header {
|
||||
u32 revision;
|
||||
u32 abort;
|
||||
};
|
||||
|
||||
union vmcs_encoding {
|
||||
struct {
|
||||
u32 access_type : 1;
|
||||
u32 index : 9;
|
||||
u32 type : 2;
|
||||
u32 rsv1 : 1;
|
||||
u32 width : 2;
|
||||
u32 rsv2 : 17;
|
||||
};
|
||||
u32 word;
|
||||
};
|
||||
|
||||
enum vvmcs_encoding_width {
|
||||
VVMCS_WIDTH_16 = 0,
|
||||
VVMCS_WIDTH_64,
|
||||
VVMCS_WIDTH_32,
|
||||
VVMCS_WIDTH_NATURAL,
|
||||
};
|
||||
|
||||
enum vvmcs_encoding_type {
|
||||
VVMCS_TYPE_CONTROL = 0,
|
||||
VVMCS_TYPE_RO,
|
||||
VVMCS_TYPE_GSTATE,
|
||||
VVMCS_TYPE_HSTATE,
|
||||
};
|
||||
|
||||
u64 __get_vvmcs(void *vvmcs, u32 vmcs_encoding);
|
||||
void __set_vvmcs(void *vvmcs, u32 vmcs_encoding, u64 val);
|
||||
|
||||
#endif /* __ASM_X86_HVM_VVMX_H__ */
|
||||
|
||||