Hypervisor Interface for Cells
==============================
-The Jailhouse hypervisor provides two kinds of interfaces to interact with its
-cells during runtime. One is a set of hypercalls which cells can be invoked
-synchronously by executing architecture specific instructions that switch to
-hypervisor mode. The other interface consists of variables located in a
-per-cell memory region that is shared between hypervisor and that particular
-cell.
+The Jailhouse hypervisor provides three kinds of interfaces to interact with
+its cells during runtime. The first is a read-only detection interface. The
+second is a set of hypercalls which cells can invoke synchronously by executing
+architecture specific instructions that switch to hypervisor mode. The third
+interface consists of variables located in a per-cell memory region that is
+shared between hypervisor and that particular cell.
+
+
+Detection
+---------
+
+This interface is useful for cell code that should work not only inside a
+Jailhouse cell. The ABI is architecture specific.
+
+
+x86 ABI
+- - - -
+
+On x86, Jailhouse modifies the register values returned when executing the
+cpuid instruction as follows:
+
+
+Function (EAX): 0x01
+Result in EAX: passed unmodified
+ EBX: passed unmodified
+ ECX: bit 31 ("hypervisor") set, all other bits passed unmodified
+ EDX: passed unmodified
+
+Note: A cell should first check if bit 31 is set in ECX before querying the
+signature function 0x40000000.
+
+
+Function (EAX): 0x40000000 (signature)
+Result in EAX: highest supported hypervisor function, currently 0x40000001
+ EBX: 0x6c69614a ("Jail")
+ ECX: 0x73756f68 ("hous")
+ EDX: 0x00000065 ("e")
+
+Note: A cell should first validate the presence of Jailhouse via both checking
+the hypervisor feature bit (function 31) and then the signature (function
+0x40000000) before evaluating the returned values of the feature function
+0x40000001.
+
+
+Function (EAX): 0x40000001 (features)
+Result in EAX: 0
+ EBX: 0
+ ECX: 0
+ EDX: 0
Hypercalls
#define JAILHOUSE_CPU_STAT_VMEXITS_XSETBV JAILHOUSE_GENERIC_CPU_STATS + 5
#define JAILHOUSE_NUM_CPU_STATS JAILHOUSE_GENERIC_CPU_STATS + 6
+/* CPUID interface */
+#define JAILHOUSE_CPUID_SIGNATURE 0x40000000
+#define JAILHOUSE_CPUID_FEATURES 0x40000001
+
#ifdef __ASSEMBLY__
#define __MAKE_UL(x) x
/* leaf 0x01, ECX */
#define X86_FEATURE_VMX (1 << 5)
#define X86_FEATURE_XSAVE (1 << 26)
+#define X86_FEATURE_HYPERVISOR (1 << 31)
/* leaf 0x80000001, ECX */
#define X86_FEATURE_SVM (1 << 2)
void vcpu_handle_cpuid(void)
{
+ static const char signature[12] = "Jailhouse";
union registers *guest_regs = &this_cpu_data()->guest_regs;
+ u32 function = guest_regs->rax;
this_cpu_data()->stats[JAILHOUSE_CPU_STAT_VMEXITS_CPUID]++;
- /* clear upper 32 bits of the involved registers */
- guest_regs->rax &= 0xffffffff;
- guest_regs->rbx &= 0xffffffff;
- guest_regs->rcx &= 0xffffffff;
- guest_regs->rdx &= 0xffffffff;
-
- cpuid((u32 *)&guest_regs->rax, (u32 *)&guest_regs->rbx,
- (u32 *)&guest_regs->rcx, (u32 *)&guest_regs->rdx);
+ switch (function) {
+ case JAILHOUSE_CPUID_SIGNATURE:
+ guest_regs->rax = JAILHOUSE_CPUID_FEATURES;
+ guest_regs->rbx = *(u32 *)signature;
+ guest_regs->rcx = *(u32 *)(signature + 4);
+ guest_regs->rdx = *(u32 *)(signature + 8);
+ break;
+ case JAILHOUSE_CPUID_FEATURES:
+ guest_regs->rax = 0;
+ guest_regs->rbx = 0;
+ guest_regs->rcx = 0;
+ guest_regs->rdx = 0;
+ break;
+ default:
+ /* clear upper 32 bits of the involved registers */
+ guest_regs->rax &= 0xffffffff;
+ guest_regs->rbx &= 0xffffffff;
+ guest_regs->rcx &= 0xffffffff;
+ guest_regs->rdx &= 0xffffffff;
+
+ cpuid((u32 *)&guest_regs->rax, (u32 *)&guest_regs->rbx,
+ (u32 *)&guest_regs->rcx, (u32 *)&guest_regs->rdx);
+ if (function == 0x01)
+ guest_regs->rcx |= X86_FEATURE_HYPERVISOR;
+ break;
+ }
vcpu_skip_emulated_instruction(X86_INST_LEN_CPUID);
}