visor/include/x86/vmx.h

157 lines
4 KiB
C
Raw Normal View History

2025-03-10 19:19:53 +01:00
#ifndef _VISOR_VMX_H_
#define _VISOR_VMX_H_
#include <stdint.h>
2025-03-11 20:59:39 +01:00
#define VM_ENTRY_CONTROLS 0x4012
2025-03-11 17:16:03 +01:00
#define VMCS_INSTRUCTION_ERROR 0x4400
2025-03-10 20:24:32 +01:00
struct VMXON {
2025-03-10 19:19:53 +01:00
uint32_t revisionID;
uint32_t abortIndicator;
2025-03-10 20:24:32 +01:00
char vmcsData[];
};
struct VMCS {
2025-03-10 20:41:09 +01:00
uint32_t revisionID;
2025-03-10 19:19:53 +01:00
/* Guest-state area */
/* Host-state area */
/* VM-execution control fields */
/* VM-exit control fields */
/* VM-entry control fields */
/* VM-exit information fields */
};
2025-03-10 20:24:32 +01:00
static inline uint64_t
2025-03-10 19:19:53 +01:00
vmxon(void *region)
{
2025-03-10 20:24:32 +01:00
uint64_t regionpa = (uint64_t)region;
uint64_t flags;
__asm__ volatile (
2025-03-10 20:41:09 +01:00
"vmxon %1\n\t"
"pushf \n\t"
"pop %0\n\t"
2025-03-10 20:24:32 +01:00
: "=r"(flags) : "m"(regionpa));
return flags;
2025-03-10 19:19:53 +01:00
}
static inline void
vmxoff(void)
{
__asm__ volatile ("vmxoff\n\t" ::);
}
2025-03-10 20:41:09 +01:00
static inline uint64_t
2025-03-10 19:19:53 +01:00
vmptrld(void *region)
{
2025-03-10 20:41:09 +01:00
uint64_t regionpa = (uint64_t)region;
uint64_t flags;
__asm__ volatile (
"vmptrld %1\n\t"
"pushf \n\t"
"pop %0\n\t"
: "=r"(flags) : "m"(regionpa));
return flags;
2025-03-10 19:19:53 +01:00
}
static inline void
vmptrst(void *arg)
{
__asm__ volatile ("vmptrst\n\t" ::);
}
2025-03-10 20:41:09 +01:00
static inline uint64_t
2025-03-10 19:19:53 +01:00
vmclear(void *region)
{
2025-03-10 20:41:09 +01:00
uint64_t regionpa = (uint64_t)region;
uint64_t flags;
__asm__ volatile (
"vmclear %1\n\t"
"pushf \n\t"
"pop %0\n\t"
: "=r"(flags) : "m"(regionpa));
return flags;
2025-03-10 19:19:53 +01:00
}
2025-03-11 17:16:03 +01:00
static inline uint64_t
2025-03-10 19:19:53 +01:00
vmlaunch(void)
{
2025-03-11 17:16:03 +01:00
uint64_t flags;
__asm__ volatile (
"vmlaunch \n\t"
"pushf \n\t"
"pop %0\n\t"
: "=r"(flags));
return flags;
2025-03-10 19:19:53 +01:00
}
static inline void
vmresume(void)
{
__asm__ volatile ("vmresume\n\t" ::);
}
2025-03-11 17:16:03 +01:00
static inline uint64_t
vmread(uint64_t field)
2025-03-10 19:19:53 +01:00
{
2025-03-11 17:16:03 +01:00
uint64_t value;
__asm__ volatile ("vmread %0, %1\n\t" : "=rm"(value) : "r"(field));
return value;
2025-03-10 19:19:53 +01:00
}
static inline void
2025-03-11 01:40:28 +01:00
vmwrite(uint64_t field, uint64_t value)
2025-03-10 19:19:53 +01:00
{
2025-03-11 17:16:03 +01:00
__asm__ volatile ("vmwrite %0, %1\n\t" :: "rm"(value), "r"(field));
2025-03-10 19:19:53 +01:00
}
static inline void
vmcall()
{
__asm__ volatile ("vmcall\n\t" ::);
}
2025-03-11 17:16:03 +01:00
static inline const char *
vmx_describe_error(uint32_t error)
{
switch (error) {
default: return "Unknown VMX Error";
case 0: return NULL;
case 1: return "VMCALL executed in VMX root operation";
case 2: return "VMCLEAR with invalid physical address";
case 3: return "VMCLEAR with VMXON pointer";
case 4: return "VMLAUNCH with non-clear VMCS";
case 5: return "VMRESUME with non-launched VMCS";
case 6: return "VMRESUME after VMXOFF (VMXOFF and VMXON between VMLAUNCH and VMRESUME)";
case 7: return "VM entry with invalid control field(s)";
case 8: return "VM entry with invalid host-state field(s)";
case 9: return "VMPTRLD with invalid physical address";
case 10: return "VMPTRLD with VMXON pointer";
case 11: return "VMPTRLD with incorrect VMCS revision identifier";
case 12: return "VMREAD/VMWRITE from/to unsupported VMCS component";
case 13: return "VMWRITE to read-only VMCS component";
case 15: return "VMXON executed in VMX root operation";
case 16: return "VM entry with invalid executive-VMCS pointer";
case 17: return "VM entry with non-launched executive VMCS";
case 18: return "VM entry with executive-VMCS pointer not VMXON pointer (when attempting to deactivate the dual-monitor treatment of SMIs and SMM)";
case 19: return "VMCALL with non-clear VMCS (when attempting to activate the dual-monitor treatment of SMIs and SMM)";
case 20: return "VMCALL with invalid VM-exit control fields";
case 22: return "VMCALL with incorrect MSEG revision identifier (when attempting to activate the dual-monitor treatment of SMIs and SMM)";
case 23: return "VMXOFF under dual-monitor treatment of SMIs and SMM";
case 24: return "VMCALL with invalid SMM-monitor features (when attempting to activate the dual-monitor treatment of SMIs and SMM)";
case 25: return "VM entry with invalid VM-execution control fields in executive VMCS (when attempting to return from SMM)";
case 26: return "VM entry with events blocked by MOV SS";
case 28: return "Invalid operand to INVEPT/INVVPID";
}
}
static inline const char *
vmcs_describe_error(void)
{
uint32_t error = vmread(VMCS_INSTRUCTION_ERROR) & 0xffffffff;
return vmx_describe_error(error);
}
2025-03-10 19:19:53 +01:00
#endif