Merge branch 'x86-vmware-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 vmware updates from Ingo Molnar: "This updates the VMWARE guest driver with support for VMCALL/VMMCALL based hypercalls" * 'x86-vmware-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: input/vmmouse: Update the backdoor call with support for new instructions drm/vmwgfx: Update the backdoor call with support for new instructions x86/vmware: Add a header file for hypercall definitions x86/vmware: Update platform detection code for VMCALL/VMMCALL hypercalls
This commit is contained in:
commit
7ac63f6ba5
|
@ -17193,6 +17193,7 @@ M: "VMware, Inc." <pv-drivers@vmware.com>
|
|||
L: virtualization@lists.linux-foundation.org
|
||||
S: Supported
|
||||
F: arch/x86/kernel/cpu/vmware.c
|
||||
F: arch/x86/include/asm/vmware.h
|
||||
|
||||
VMWARE PVRDMA DRIVER
|
||||
M: Adit Ranadive <aditr@vmware.com>
|
||||
|
|
|
@ -231,6 +231,8 @@
|
|||
#define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */
|
||||
#define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */
|
||||
#define X86_FEATURE_EPT_AD ( 8*32+17) /* Intel Extended Page Table access-dirty bit */
|
||||
#define X86_FEATURE_VMCALL ( 8*32+18) /* "" Hypervisor supports the VMCALL instruction */
|
||||
#define X86_FEATURE_VMW_VMMCALL ( 8*32+19) /* "" VMware prefers VMMCALL hypercall instruction */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */
|
||||
#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 or MIT */
|
||||
#ifndef _ASM_X86_VMWARE_H
|
||||
#define _ASM_X86_VMWARE_H
|
||||
|
||||
#include <asm/cpufeatures.h>
|
||||
#include <asm/alternative.h>
|
||||
|
||||
/*
|
||||
* The hypercall definitions differ in the low word of the %edx argument
|
||||
* in the following way: the old port base interface uses the port
|
||||
* number to distinguish between high- and low bandwidth versions.
|
||||
*
|
||||
* The new vmcall interface instead uses a set of flags to select
|
||||
* bandwidth mode and transfer direction. The flags should be loaded
|
||||
* into %dx by any user and are automatically replaced by the port
|
||||
* number if the VMWARE_HYPERVISOR_PORT method is used.
|
||||
*
|
||||
* In short, new driver code should strictly use the new definition of
|
||||
* %dx content.
|
||||
*/
|
||||
|
||||
/* Old port-based version */
|
||||
#define VMWARE_HYPERVISOR_PORT "0x5658"
|
||||
#define VMWARE_HYPERVISOR_PORT_HB "0x5659"
|
||||
|
||||
/* Current vmcall / vmmcall version */
|
||||
#define VMWARE_HYPERVISOR_HB BIT(0)
|
||||
#define VMWARE_HYPERVISOR_OUT BIT(1)
|
||||
|
||||
/* The low bandwidth call. The low word of edx is presumed clear. */
|
||||
#define VMWARE_HYPERCALL \
|
||||
ALTERNATIVE_2("movw $" VMWARE_HYPERVISOR_PORT ", %%dx; inl (%%dx)", \
|
||||
"vmcall", X86_FEATURE_VMCALL, \
|
||||
"vmmcall", X86_FEATURE_VMW_VMMCALL)
|
||||
|
||||
/*
|
||||
* The high bandwidth out call. The low word of edx is presumed to have the
|
||||
* HB and OUT bits set.
|
||||
*/
|
||||
#define VMWARE_HYPERCALL_HB_OUT \
|
||||
ALTERNATIVE_2("movw $" VMWARE_HYPERVISOR_PORT_HB ", %%dx; rep outsb", \
|
||||
"vmcall", X86_FEATURE_VMCALL, \
|
||||
"vmmcall", X86_FEATURE_VMW_VMMCALL)
|
||||
|
||||
/*
|
||||
* The high bandwidth in call. The low word of edx is presumed to have the
|
||||
* HB bit set.
|
||||
*/
|
||||
#define VMWARE_HYPERCALL_HB_IN \
|
||||
ALTERNATIVE_2("movw $" VMWARE_HYPERVISOR_PORT_HB ", %%dx; rep insb", \
|
||||
"vmcall", X86_FEATURE_VMCALL, \
|
||||
"vmmcall", X86_FEATURE_VMW_VMMCALL)
|
||||
#endif
|
|
@ -30,34 +30,69 @@
|
|||
#include <asm/hypervisor.h>
|
||||
#include <asm/timer.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/vmware.h>
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "vmware: " fmt
|
||||
|
||||
#define CPUID_VMWARE_INFO_LEAF 0x40000000
|
||||
#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
|
||||
#define VMWARE_HYPERVISOR_PORT 0x5658
|
||||
#define CPUID_VMWARE_INFO_LEAF 0x40000000
|
||||
#define CPUID_VMWARE_FEATURES_LEAF 0x40000010
|
||||
#define CPUID_VMWARE_FEATURES_ECX_VMMCALL BIT(0)
|
||||
#define CPUID_VMWARE_FEATURES_ECX_VMCALL BIT(1)
|
||||
|
||||
#define VMWARE_PORT_CMD_GETVERSION 10
|
||||
#define VMWARE_PORT_CMD_GETHZ 45
|
||||
#define VMWARE_PORT_CMD_GETVCPU_INFO 68
|
||||
#define VMWARE_PORT_CMD_LEGACY_X2APIC 3
|
||||
#define VMWARE_PORT_CMD_VCPU_RESERVED 31
|
||||
#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
|
||||
|
||||
#define VMWARE_CMD_GETVERSION 10
|
||||
#define VMWARE_CMD_GETHZ 45
|
||||
#define VMWARE_CMD_GETVCPU_INFO 68
|
||||
#define VMWARE_CMD_LEGACY_X2APIC 3
|
||||
#define VMWARE_CMD_VCPU_RESERVED 31
|
||||
|
||||
#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \
|
||||
__asm__("inl (%%dx)" : \
|
||||
"=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
|
||||
"0"(VMWARE_HYPERVISOR_MAGIC), \
|
||||
"1"(VMWARE_PORT_CMD_##cmd), \
|
||||
"2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \
|
||||
"memory");
|
||||
"=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
|
||||
"a"(VMWARE_HYPERVISOR_MAGIC), \
|
||||
"c"(VMWARE_CMD_##cmd), \
|
||||
"d"(VMWARE_HYPERVISOR_PORT), "b"(UINT_MAX) : \
|
||||
"memory")
|
||||
|
||||
#define VMWARE_VMCALL(cmd, eax, ebx, ecx, edx) \
|
||||
__asm__("vmcall" : \
|
||||
"=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
|
||||
"a"(VMWARE_HYPERVISOR_MAGIC), \
|
||||
"c"(VMWARE_CMD_##cmd), \
|
||||
"d"(0), "b"(UINT_MAX) : \
|
||||
"memory")
|
||||
|
||||
#define VMWARE_VMMCALL(cmd, eax, ebx, ecx, edx) \
|
||||
__asm__("vmmcall" : \
|
||||
"=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
|
||||
"a"(VMWARE_HYPERVISOR_MAGIC), \
|
||||
"c"(VMWARE_CMD_##cmd), \
|
||||
"d"(0), "b"(UINT_MAX) : \
|
||||
"memory")
|
||||
|
||||
#define VMWARE_CMD(cmd, eax, ebx, ecx, edx) do { \
|
||||
switch (vmware_hypercall_mode) { \
|
||||
case CPUID_VMWARE_FEATURES_ECX_VMCALL: \
|
||||
VMWARE_VMCALL(cmd, eax, ebx, ecx, edx); \
|
||||
break; \
|
||||
case CPUID_VMWARE_FEATURES_ECX_VMMCALL: \
|
||||
VMWARE_VMMCALL(cmd, eax, ebx, ecx, edx); \
|
||||
break; \
|
||||
default: \
|
||||
VMWARE_PORT(cmd, eax, ebx, ecx, edx); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static unsigned long vmware_tsc_khz __ro_after_init;
|
||||
static u8 vmware_hypercall_mode __ro_after_init;
|
||||
|
||||
static inline int __vmware_platform(void)
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx);
|
||||
VMWARE_CMD(GETVERSION, eax, ebx, ecx, edx);
|
||||
return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC;
|
||||
}
|
||||
|
||||
|
@ -129,6 +164,10 @@ static void __init vmware_set_capabilities(void)
|
|||
{
|
||||
setup_force_cpu_cap(X86_FEATURE_CONSTANT_TSC);
|
||||
setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
|
||||
if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMCALL)
|
||||
setup_force_cpu_cap(X86_FEATURE_VMCALL);
|
||||
else if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMMCALL)
|
||||
setup_force_cpu_cap(X86_FEATURE_VMW_VMMCALL);
|
||||
}
|
||||
|
||||
static void __init vmware_platform_setup(void)
|
||||
|
@ -136,7 +175,7 @@ static void __init vmware_platform_setup(void)
|
|||
uint32_t eax, ebx, ecx, edx;
|
||||
uint64_t lpj, tsc_khz;
|
||||
|
||||
VMWARE_PORT(GETHZ, eax, ebx, ecx, edx);
|
||||
VMWARE_CMD(GETHZ, eax, ebx, ecx, edx);
|
||||
|
||||
if (ebx != UINT_MAX) {
|
||||
lpj = tsc_khz = eax | (((uint64_t)ebx) << 32);
|
||||
|
@ -174,10 +213,21 @@ static void __init vmware_platform_setup(void)
|
|||
vmware_set_capabilities();
|
||||
}
|
||||
|
||||
static u8 vmware_select_hypercall(void)
|
||||
{
|
||||
int eax, ebx, ecx, edx;
|
||||
|
||||
cpuid(CPUID_VMWARE_FEATURES_LEAF, &eax, &ebx, &ecx, &edx);
|
||||
return (ecx & (CPUID_VMWARE_FEATURES_ECX_VMMCALL |
|
||||
CPUID_VMWARE_FEATURES_ECX_VMCALL));
|
||||
}
|
||||
|
||||
/*
|
||||
* While checking the dmi string information, just checking the product
|
||||
* serial key should be enough, as this will always have a VMware
|
||||
* specific string when running under VMware hypervisor.
|
||||
* If !boot_cpu_has(X86_FEATURE_HYPERVISOR), vmware_hypercall_mode
|
||||
* intentionally defaults to 0.
|
||||
*/
|
||||
static uint32_t __init vmware_platform(void)
|
||||
{
|
||||
|
@ -187,8 +237,16 @@ static uint32_t __init vmware_platform(void)
|
|||
|
||||
cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0],
|
||||
&hyper_vendor_id[1], &hyper_vendor_id[2]);
|
||||
if (!memcmp(hyper_vendor_id, "VMwareVMware", 12))
|
||||
if (!memcmp(hyper_vendor_id, "VMwareVMware", 12)) {
|
||||
if (eax >= CPUID_VMWARE_FEATURES_LEAF)
|
||||
vmware_hypercall_mode =
|
||||
vmware_select_hypercall();
|
||||
|
||||
pr_info("hypercall mode: 0x%02x\n",
|
||||
(unsigned int) vmware_hypercall_mode);
|
||||
|
||||
return CPUID_VMWARE_INFO_LEAF;
|
||||
}
|
||||
} else if (dmi_available && dmi_name_in_serial("VMware") &&
|
||||
__vmware_platform())
|
||||
return 1;
|
||||
|
@ -200,9 +258,9 @@ static uint32_t __init vmware_platform(void)
|
|||
static bool __init vmware_legacy_x2apic_available(void)
|
||||
{
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
VMWARE_PORT(GETVCPU_INFO, eax, ebx, ecx, edx);
|
||||
return (eax & (1 << VMWARE_PORT_CMD_VCPU_RESERVED)) == 0 &&
|
||||
(eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0;
|
||||
VMWARE_CMD(GETVCPU_INFO, eax, ebx, ecx, edx);
|
||||
return (eax & (1 << VMWARE_CMD_VCPU_RESERVED)) == 0 &&
|
||||
(eax & (1 << VMWARE_CMD_LEGACY_X2APIC)) != 0;
|
||||
}
|
||||
|
||||
const __initconst struct hypervisor_x86 x86_hyper_vmware = {
|
||||
|
|
|
@ -46,8 +46,6 @@
|
|||
#define RETRIES 3
|
||||
|
||||
#define VMW_HYPERVISOR_MAGIC 0x564D5868
|
||||
#define VMW_HYPERVISOR_PORT 0x5658
|
||||
#define VMW_HYPERVISOR_HB_PORT 0x5659
|
||||
|
||||
#define VMW_PORT_CMD_MSG 30
|
||||
#define VMW_PORT_CMD_HB_MSG 0
|
||||
|
@ -93,7 +91,7 @@ static int vmw_open_channel(struct rpc_channel *channel, unsigned int protocol)
|
|||
|
||||
VMW_PORT(VMW_PORT_CMD_OPEN_CHANNEL,
|
||||
(protocol | GUESTMSG_FLAG_COOKIE), si, di,
|
||||
VMW_HYPERVISOR_PORT,
|
||||
0,
|
||||
VMW_HYPERVISOR_MAGIC,
|
||||
eax, ebx, ecx, edx, si, di);
|
||||
|
||||
|
@ -126,7 +124,7 @@ static int vmw_close_channel(struct rpc_channel *channel)
|
|||
|
||||
VMW_PORT(VMW_PORT_CMD_CLOSE_CHANNEL,
|
||||
0, si, di,
|
||||
(VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
|
||||
channel->channel_id << 16,
|
||||
VMW_HYPERVISOR_MAGIC,
|
||||
eax, ebx, ecx, edx, si, di);
|
||||
|
||||
|
@ -160,7 +158,8 @@ static unsigned long vmw_port_hb_out(struct rpc_channel *channel,
|
|||
VMW_PORT_HB_OUT(
|
||||
(MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
|
||||
msg_len, si, di,
|
||||
VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
|
||||
VMWARE_HYPERVISOR_HB | (channel->channel_id << 16) |
|
||||
VMWARE_HYPERVISOR_OUT,
|
||||
VMW_HYPERVISOR_MAGIC, bp,
|
||||
eax, ebx, ecx, edx, si, di);
|
||||
|
||||
|
@ -181,7 +180,7 @@ static unsigned long vmw_port_hb_out(struct rpc_channel *channel,
|
|||
|
||||
VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16),
|
||||
word, si, di,
|
||||
VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
|
||||
channel->channel_id << 16,
|
||||
VMW_HYPERVISOR_MAGIC,
|
||||
eax, ebx, ecx, edx, si, di);
|
||||
}
|
||||
|
@ -213,7 +212,7 @@ static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply,
|
|||
VMW_PORT_HB_IN(
|
||||
(MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
|
||||
reply_len, si, di,
|
||||
VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
|
||||
VMWARE_HYPERVISOR_HB | (channel->channel_id << 16),
|
||||
VMW_HYPERVISOR_MAGIC, bp,
|
||||
eax, ebx, ecx, edx, si, di);
|
||||
|
||||
|
@ -230,7 +229,7 @@ static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply,
|
|||
|
||||
VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16),
|
||||
MESSAGE_STATUS_SUCCESS, si, di,
|
||||
VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
|
||||
channel->channel_id << 16,
|
||||
VMW_HYPERVISOR_MAGIC,
|
||||
eax, ebx, ecx, edx, si, di);
|
||||
|
||||
|
@ -269,7 +268,7 @@ static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
|
|||
|
||||
VMW_PORT(VMW_PORT_CMD_SENDSIZE,
|
||||
msg_len, si, di,
|
||||
VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
|
||||
channel->channel_id << 16,
|
||||
VMW_HYPERVISOR_MAGIC,
|
||||
eax, ebx, ecx, edx, si, di);
|
||||
|
||||
|
@ -327,7 +326,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
|
|||
|
||||
VMW_PORT(VMW_PORT_CMD_RECVSIZE,
|
||||
0, si, di,
|
||||
(VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
|
||||
channel->channel_id << 16,
|
||||
VMW_HYPERVISOR_MAGIC,
|
||||
eax, ebx, ecx, edx, si, di);
|
||||
|
||||
|
@ -371,7 +370,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
|
|||
|
||||
VMW_PORT(VMW_PORT_CMD_RECVSTATUS,
|
||||
MESSAGE_STATUS_SUCCESS, si, di,
|
||||
(VMW_HYPERVISOR_PORT | (channel->channel_id << 16)),
|
||||
channel->channel_id << 16,
|
||||
VMW_HYPERVISOR_MAGIC,
|
||||
eax, ebx, ecx, edx, si, di);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#ifndef _VMWGFX_MSG_H
|
||||
#define _VMWGFX_MSG_H
|
||||
|
||||
#include <asm/vmware.h>
|
||||
|
||||
/**
|
||||
* Hypervisor-specific bi-directional communication channel. Should never
|
||||
|
@ -44,7 +45,7 @@
|
|||
* @in_ebx: [IN] Message Len, through EBX
|
||||
* @in_si: [IN] Input argument through SI, set to 0 if not used
|
||||
* @in_di: [IN] Input argument through DI, set ot 0 if not used
|
||||
* @port_num: [IN] port number + [channel id]
|
||||
* @flags: [IN] hypercall flags + [channel id]
|
||||
* @magic: [IN] hypervisor magic value
|
||||
* @eax: [OUT] value of EAX register
|
||||
* @ebx: [OUT] e.g. status from an HB message status command
|
||||
|
@ -54,10 +55,10 @@
|
|||
* @di: [OUT]
|
||||
*/
|
||||
#define VMW_PORT(cmd, in_ebx, in_si, in_di, \
|
||||
port_num, magic, \
|
||||
flags, magic, \
|
||||
eax, ebx, ecx, edx, si, di) \
|
||||
({ \
|
||||
asm volatile ("inl %%dx, %%eax;" : \
|
||||
asm volatile (VMWARE_HYPERCALL : \
|
||||
"=a"(eax), \
|
||||
"=b"(ebx), \
|
||||
"=c"(ecx), \
|
||||
|
@ -67,7 +68,7 @@
|
|||
"a"(magic), \
|
||||
"b"(in_ebx), \
|
||||
"c"(cmd), \
|
||||
"d"(port_num), \
|
||||
"d"(flags), \
|
||||
"S"(in_si), \
|
||||
"D"(in_di) : \
|
||||
"memory"); \
|
||||
|
@ -85,7 +86,7 @@
|
|||
* @in_ecx: [IN] Message Len, through ECX
|
||||
* @in_si: [IN] Input argument through SI, set to 0 if not used
|
||||
* @in_di: [IN] Input argument through DI, set to 0 if not used
|
||||
* @port_num: [IN] port number + [channel id]
|
||||
* @flags: [IN] hypercall flags + [channel id]
|
||||
* @magic: [IN] hypervisor magic value
|
||||
* @bp: [IN]
|
||||
* @eax: [OUT] value of EAX register
|
||||
|
@ -98,12 +99,12 @@
|
|||
#ifdef __x86_64__
|
||||
|
||||
#define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \
|
||||
port_num, magic, bp, \
|
||||
flags, magic, bp, \
|
||||
eax, ebx, ecx, edx, si, di) \
|
||||
({ \
|
||||
asm volatile ("push %%rbp;" \
|
||||
"mov %12, %%rbp;" \
|
||||
"rep outsb;" \
|
||||
VMWARE_HYPERCALL_HB_OUT \
|
||||
"pop %%rbp;" : \
|
||||
"=a"(eax), \
|
||||
"=b"(ebx), \
|
||||
|
@ -114,7 +115,7 @@
|
|||
"a"(magic), \
|
||||
"b"(cmd), \
|
||||
"c"(in_ecx), \
|
||||
"d"(port_num), \
|
||||
"d"(flags), \
|
||||
"S"(in_si), \
|
||||
"D"(in_di), \
|
||||
"r"(bp) : \
|
||||
|
@ -123,12 +124,12 @@
|
|||
|
||||
|
||||
#define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \
|
||||
port_num, magic, bp, \
|
||||
flags, magic, bp, \
|
||||
eax, ebx, ecx, edx, si, di) \
|
||||
({ \
|
||||
asm volatile ("push %%rbp;" \
|
||||
"mov %12, %%rbp;" \
|
||||
"rep insb;" \
|
||||
VMWARE_HYPERCALL_HB_IN \
|
||||
"pop %%rbp" : \
|
||||
"=a"(eax), \
|
||||
"=b"(ebx), \
|
||||
|
@ -139,7 +140,7 @@
|
|||
"a"(magic), \
|
||||
"b"(cmd), \
|
||||
"c"(in_ecx), \
|
||||
"d"(port_num), \
|
||||
"d"(flags), \
|
||||
"S"(in_si), \
|
||||
"D"(in_di), \
|
||||
"r"(bp) : \
|
||||
|
@ -157,13 +158,13 @@
|
|||
* just pushed it.
|
||||
*/
|
||||
#define VMW_PORT_HB_OUT(cmd, in_ecx, in_si, in_di, \
|
||||
port_num, magic, bp, \
|
||||
flags, magic, bp, \
|
||||
eax, ebx, ecx, edx, si, di) \
|
||||
({ \
|
||||
asm volatile ("push %12;" \
|
||||
"push %%ebp;" \
|
||||
"mov 0x04(%%esp), %%ebp;" \
|
||||
"rep outsb;" \
|
||||
VMWARE_HYPERCALL_HB_OUT \
|
||||
"pop %%ebp;" \
|
||||
"add $0x04, %%esp;" : \
|
||||
"=a"(eax), \
|
||||
|
@ -175,7 +176,7 @@
|
|||
"a"(magic), \
|
||||
"b"(cmd), \
|
||||
"c"(in_ecx), \
|
||||
"d"(port_num), \
|
||||
"d"(flags), \
|
||||
"S"(in_si), \
|
||||
"D"(in_di), \
|
||||
"m"(bp) : \
|
||||
|
@ -184,13 +185,13 @@
|
|||
|
||||
|
||||
#define VMW_PORT_HB_IN(cmd, in_ecx, in_si, in_di, \
|
||||
port_num, magic, bp, \
|
||||
flags, magic, bp, \
|
||||
eax, ebx, ecx, edx, si, di) \
|
||||
({ \
|
||||
asm volatile ("push %12;" \
|
||||
"push %%ebp;" \
|
||||
"mov 0x04(%%esp), %%ebp;" \
|
||||
"rep insb;" \
|
||||
VMWARE_HYPERCALL_HB_IN \
|
||||
"pop %%ebp;" \
|
||||
"add $0x04, %%esp;" : \
|
||||
"=a"(eax), \
|
||||
|
@ -202,7 +203,7 @@
|
|||
"a"(magic), \
|
||||
"b"(cmd), \
|
||||
"c"(in_ecx), \
|
||||
"d"(port_num), \
|
||||
"d"(flags), \
|
||||
"S"(in_si), \
|
||||
"D"(in_di), \
|
||||
"m"(bp) : \
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/hypervisor.h>
|
||||
#include <asm/vmware.h>
|
||||
|
||||
#include "psmouse.h"
|
||||
#include "vmmouse.h"
|
||||
|
||||
#define VMMOUSE_PROTO_MAGIC 0x564D5868U
|
||||
#define VMMOUSE_PROTO_PORT 0x5658
|
||||
|
||||
/*
|
||||
* Main commands supported by the vmmouse hypervisor port.
|
||||
|
@ -84,7 +84,7 @@ struct vmmouse_data {
|
|||
#define VMMOUSE_CMD(cmd, in1, out1, out2, out3, out4) \
|
||||
({ \
|
||||
unsigned long __dummy1, __dummy2; \
|
||||
__asm__ __volatile__ ("inl %%dx" : \
|
||||
__asm__ __volatile__ (VMWARE_HYPERCALL : \
|
||||
"=a"(out1), \
|
||||
"=b"(out2), \
|
||||
"=c"(out3), \
|
||||
|
@ -94,7 +94,7 @@ struct vmmouse_data {
|
|||
"a"(VMMOUSE_PROTO_MAGIC), \
|
||||
"b"(in1), \
|
||||
"c"(VMMOUSE_PROTO_CMD_##cmd), \
|
||||
"d"(VMMOUSE_PROTO_PORT) : \
|
||||
"d"(0) : \
|
||||
"memory"); \
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue