From c0fae8df86bdba78925c88cebf3c5d74c8693eb0 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 1 May 2015 13:00:09 +0200 Subject: [PATCH] x86: Implement standard hypervisor detection protocol This provides cpuid-based Jailhouse detection conforming to the protocol also used by other major hypervisors: set bit 31 of ecx for function 0x01, provide a signature via function 0x40000000 and a so far empty feature set via function 0x40000001. Signed-off-by: Jan Kiszka --- Documentation/hypervisor-interfaces.txt | 55 +++++++++++++++++-- .../x86/include/asm/jailhouse_hypercall.h | 4 ++ hypervisor/arch/x86/include/asm/processor.h | 1 + hypervisor/arch/x86/vcpu.c | 36 +++++++++--- 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/Documentation/hypervisor-interfaces.txt b/Documentation/hypervisor-interfaces.txt index 517c30c..e9f0ae0 100644 --- a/Documentation/hypervisor-interfaces.txt +++ b/Documentation/hypervisor-interfaces.txt @@ -1,12 +1,55 @@ 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 diff --git a/hypervisor/arch/x86/include/asm/jailhouse_hypercall.h b/hypervisor/arch/x86/include/asm/jailhouse_hypercall.h index db3ed59..b128447 100644 --- a/hypervisor/arch/x86/include/asm/jailhouse_hypercall.h +++ b/hypervisor/arch/x86/include/asm/jailhouse_hypercall.h @@ -65,6 +65,10 @@ #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 diff --git a/hypervisor/arch/x86/include/asm/processor.h b/hypervisor/arch/x86/include/asm/processor.h index 74673ed..7dfc846 100644 --- a/hypervisor/arch/x86/include/asm/processor.h +++ b/hypervisor/arch/x86/include/asm/processor.h @@ -25,6 +25,7 @@ /* 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) diff --git a/hypervisor/arch/x86/vcpu.c b/hypervisor/arch/x86/vcpu.c index 16b5db2..c72ccd9 100644 --- a/hypervisor/arch/x86/vcpu.c +++ b/hypervisor/arch/x86/vcpu.c @@ -313,18 +313,38 @@ bool vcpu_handle_msr_write(void) 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); } -- 2.39.2