]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
x86: Fix argument widths of hypercall ABI
authorJan Kiszka <jan.kiszka@siemens.com>
Tue, 8 Jul 2014 06:06:21 +0000 (08:06 +0200)
committerJan Kiszka <jan.kiszka@siemens.com>
Tue, 8 Jul 2014 06:06:21 +0000 (08:06 +0200)
The x86 hypercall ABI defined 64-bit arguments and return codes so far.
However, our interface header took and returned only 32 bits. This
slipped through unnoticed because usually no physical addresses beyond
4G are passed to the Cell Create hypercall, the only place where it
practically matters.

Fix the issue and extend the ABI to support also 32-bit callers. We
define hypercall code and return value to be 32 bits, argument width are
now corresponding the the callers mode: 64 bits in IA-32e mode, 32 bits
otherwise. While the root cell still has to be in 64-bit mode, non-root
cells in other modes are now fine to invoke the hypercalls as well.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Documentation/hypervisor-interfaces.txt
driver.c
hypervisor/arch/x86/include/asm/jailhouse_hypercall.h
hypervisor/arch/x86/vmx.c

index 6726e451ed76e7d1fbe2a8eac8a2ab82a0440780..03f44068e68ee4e10630cdd775b35b2375b72c9a 100644 (file)
@@ -20,14 +20,14 @@ a similar channel. Details of the hypercall ABI are architecture specific and
 will be defined in the following.
 
 
-Intel x86-64 (IA-32e) ABI
+Intel x86 (IA-32/32e) ABI
 - - - - - - - - - - - - -
 
 Instruction:    vmcall
-Hypercall code: RAX
-1. argument:    RDI
-2. argument:    RSI
-Return code:    RAX
+Hypercall code: EAX
+1. argument:    RDI (IA-32e) / EDI (IA-32)
+2. argument:    RSI (IA-32e) / ESI (IA-32)
+Return code:    EAX
 
 
 Hypercall "Disable" (code 0)
index e2afdb873cf67b0a18adb54b1be12a7fabb1f7f1..f0e68a17f2cc48d1960a3801da7995c18c0aafe1 100644 (file)
--- a/driver.c
+++ b/driver.c
 #include <jailhouse/header.h>
 #include <jailhouse/hypercall.h>
 
+#ifdef CONFIG_X86_32
+#error 64-bit kernel required!
+#endif
+
 /* For compatibility with older kernel versions */
 #include <linux/version.h>
 
index 54cd22873e787f51cf16eb9710c00ae83c39ab7f..04050251c1292f525daaf9c1150b1c8ad431cfad 100644 (file)
  * the COPYING file in the top-level directory.
  */
 
-#ifndef __x86_64__
-#error 64-bit kernel required!
-#endif
-
 #define JAILHOUSE_BASE         0xfffffffff0000000
 
 #define JAILHOUSE_CALL_INS     "vmcall"
@@ -50,7 +46,7 @@ static inline __u32 jailhouse_call(__u32 num)
        return result;
 }
 
-static inline __u32 jailhouse_call_arg1(__u32 num, __u32 arg1)
+static inline __u32 jailhouse_call_arg1(__u32 num, unsigned long arg1)
 {
        __u32 result;
 
@@ -61,7 +57,8 @@ static inline __u32 jailhouse_call_arg1(__u32 num, __u32 arg1)
        return result;
 }
 
-static inline __u32 jailhouse_call_arg2(__u32 num, __u32 arg1, __u32 arg2)
+static inline __u32 jailhouse_call_arg2(__u32 num, unsigned long arg1,
+                                       unsigned long arg2)
 {
        __u32 result;
 
index e6b97a76d9c2b38e392fc8503b466e39be09fbbe..ad65b2ad420ac72ec474736f8522c5a86b8c24a3 100644 (file)
@@ -869,19 +869,20 @@ static void update_efer(void)
 static void vmx_handle_hypercall(struct registers *guest_regs,
                                 struct per_cpu *cpu_data)
 {
+       bool ia32e_mode = !!(vmcs_read64(GUEST_IA32_EFER) & EFER_LMA);
+       unsigned long arg_mask = ia32e_mode ? (u64)-1 : (u32)-1;
        unsigned long code = guest_regs->rax;
 
        vmx_skip_emulated_instruction(X86_INST_LEN_VMCALL);
 
-       if ((!(vmcs_read64(GUEST_IA32_EFER) & EFER_LMA) &&
-            vmcs_read64(GUEST_RFLAGS) & X86_RFLAGS_VM) ||
+       if ((!ia32e_mode && vmcs_read64(GUEST_RFLAGS) & X86_RFLAGS_VM) ||
            (vmcs_read16(GUEST_CS_SELECTOR) & 3) != 0) {
                guest_regs->rax = -EPERM;
                return;
        }
 
-       guest_regs->rax = hypercall(cpu_data, code, guest_regs->rdi,
-                                   guest_regs->rsi);
+       guest_regs->rax = hypercall(cpu_data, code, guest_regs->rdi & arg_mask,
+                                   guest_regs->rsi & arg_mask);
        if (guest_regs->rax == -ENOSYS)
                printk("CPU %d: Unknown vmcall %d, RIP: %p\n",
                       cpu_data->cpu_id, code,