Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F110667784
D44528.id137621.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D44528.id137621.diff
View Options
diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -378,6 +378,7 @@
x86/x86/pvclock.c optional kvm_clock | xenhvm
x86/x86/stack_machdep.c optional ddb | stack
x86/x86/tsc.c standard
+x86/x86/vmware_guestrpc.c optional vmware_guestrpc
x86/x86/ucode.c standard
x86/x86/ucode_subr.c standard
x86/x86/delay.c standard
diff --git a/sys/x86/acpica/madt.c b/sys/x86/acpica/madt.c
--- a/sys/x86/acpica/madt.c
+++ b/sys/x86/acpica/madt.c
@@ -159,7 +159,7 @@
}
if (vm_guest == VM_GUEST_VMWARE) {
- vmware_hvcall(VMW_HVCMD_GETVCPU_INFO, p);
+ vmware_hvcall(0, VMW_HVCMD_GETVCPU_INFO, UINT_MAX, p);
if ((p[0] & VMW_VCPUINFO_VCPU_RESERVED) != 0 ||
(p[0] & VMW_VCPUINFO_LEGACY_X2APIC) == 0)
return ("inside VMWare without intr redirection");
diff --git a/sys/x86/conf/NOTES b/sys/x86/conf/NOTES
--- a/sys/x86/conf/NOTES
+++ b/sys/x86/conf/NOTES
@@ -550,6 +550,11 @@
device hyperv # HyperV drivers
device hvhid # HyperV HID device
+# VMware hypervisor support
+device pvscsi # Paravirtual SCSI driver
+device vmci # Virtual Machine Communication Interface (VMCI)
+device vmware_guestrpc # GuestRPC interface
+
#
# Laptop/Notebook options:
#
diff --git a/sys/x86/include/vmware.h b/sys/x86/include/vmware.h
--- a/sys/x86/include/vmware.h
+++ b/sys/x86/include/vmware.h
@@ -31,19 +31,23 @@
#define VMW_HVPORT 0x5658
#define VMW_HVCMD_GETVERSION 10
+#define VMW_HVCMD_GUESTRPC 30
#define VMW_HVCMD_GETHZ 45
#define VMW_HVCMD_GETVCPU_INFO 68
+#define VMW_HVCMD_DEFAULT_PARAM UINT_MAX
+
#define VMW_VCPUINFO_LEGACY_X2APIC (1 << 3)
#define VMW_VCPUINFO_VCPU_RESERVED (1 << 31)
static __inline void
-vmware_hvcall(u_int cmd, u_int *p)
+vmware_hvcall(int chan, u_int cmd, u_int param, u_int *p)
{
__asm __volatile("inl %w3, %0"
: "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
- : "0" (VMW_HVMAGIC), "1" (UINT_MAX), "2" (cmd), "3" (VMW_HVPORT)
+ : "0" (VMW_HVMAGIC), "1" (param), "2" (cmd),
+ "3" (VMW_HVPORT | (chan << 16))
: "memory");
}
diff --git a/sys/x86/include/vmware.h b/sys/x86/include/vmware_guestrpc.h
copy from sys/x86/include/vmware.h
copy to sys/x86/include/vmware_guestrpc.h
--- a/sys/x86/include/vmware.h
+++ b/sys/x86/include/vmware_guestrpc.h
@@ -1,6 +1,7 @@
/*-
- * Copyright (c) 2011-2014 Jung-uk Kim <jkim@FreeBSD.org>
- * All rights reserved.
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2015-2024, Juniper Networks, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,27 +25,13 @@
* SUCH DAMAGE.
*/
-#ifndef _X86_VMWARE_H_
-#define _X86_VMWARE_H_
-
-#define VMW_HVMAGIC 0x564d5868
-#define VMW_HVPORT 0x5658
-
-#define VMW_HVCMD_GETVERSION 10
-#define VMW_HVCMD_GETHZ 45
-#define VMW_HVCMD_GETVCPU_INFO 68
-
-#define VMW_VCPUINFO_LEGACY_X2APIC (1 << 3)
-#define VMW_VCPUINFO_VCPU_RESERVED (1 << 31)
+#ifndef _X86_VMWARE_GUESTRPC_H_
+#define _X86_VMWARE_GUESTRPC_H_
-static __inline void
-vmware_hvcall(u_int cmd, u_int *p)
-{
+struct sbuf;
- __asm __volatile("inl %w3, %0"
- : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
- : "0" (VMW_HVMAGIC), "1" (UINT_MAX), "2" (cmd), "3" (VMW_HVPORT)
- : "memory");
-}
+int vmware_guestrpc_cmd(struct sbuf *sbufp);
+int vmware_guestrpc_set_guestinfo(const char *keyword, const char *val);
+int vmware_guestrpc_get_guestinfo(const char *keyword, struct sbuf *sbufp);
-#endif /* !_X86_VMWARE_H_ */
+#endif /* _X86_VMWARE_GUESTRPC_H_ */
diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c
--- a/sys/x86/x86/identcpu.c
+++ b/sys/x86/x86/identcpu.c
@@ -1470,7 +1470,8 @@
p = kern_getenv("smbios.system.serial");
if (p != NULL) {
if (strncmp(p, "VMware-", 7) == 0 || strncmp(p, "VMW", 3) == 0) {
- vmware_hvcall(VMW_HVCMD_GETVERSION, regs);
+ vmware_hvcall(0, VMW_HVCMD_GETVERSION,
+ VMW_HVCMD_DEFAULT_PARAM, regs);
if (regs[1] == VMW_HVMAGIC) {
vm_guest = VM_GUEST_VMWARE;
freeenv(p);
diff --git a/sys/x86/x86/tsc.c b/sys/x86/x86/tsc.c
--- a/sys/x86/x86/tsc.c
+++ b/sys/x86/x86/tsc.c
@@ -139,7 +139,7 @@
{
u_int regs[4];
- vmware_hvcall(VMW_HVCMD_GETHZ, regs);
+ vmware_hvcall(0, VMW_HVCMD_GETHZ, VMW_HVCMD_DEFAULT_PARAM, regs);
if (regs[1] != UINT_MAX)
tsc_freq = regs[0] | ((uint64_t)regs[1] << 32);
tsc_early_calib_exact = 1;
diff --git a/sys/x86/x86/vmware_guestrpc.c b/sys/x86/x86/vmware_guestrpc.c
new file mode 100644
--- /dev/null
+++ b/sys/x86/x86/vmware_guestrpc.c
@@ -0,0 +1,337 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2013-2024, Juniper Networks, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/bus.h>
+#include <sys/sbuf.h>
+#include <sys/errno.h>
+#include <sys/module.h>
+
+#include <x86/vmware.h>
+#include <x86/vmware_guestrpc.h>
+
+/* GuestRPC Subcommands */
+#define VMW_HVGUESTRPC_OPEN 0x00
+#define VMW_HVGUESTRPC_SEND_LEN 0x01
+#define VMW_HVGUESTRPC_SEND_DATA 0x02
+#define VMW_HVGUESTRPC_RECV_LEN 0x03
+#define VMW_HVGUESTRPC_RECV_DATA 0x04
+#define VMW_HVGUESTRPC_FINISH_RECV 0x05
+#define VMW_HVGUESTRPC_CLOSE 0x06
+/* GuestRPC Parameters */
+#define VMW_HVGUESTRPC_OPEN_MAGIC 0x49435052
+/* GuestRPC Status */
+#define VMW_HVGUESTRPC_FAILURE 0x00000000
+#define VMW_HVGUESTRPC_OPEN_SUCCESS 0x00010000
+#define VMW_HVGUESTRPC_SEND_LEN_SUCCESS 0x00810000
+#define VMW_HVGUESTRPC_SEND_DATA_SUCCESS 0x00010000
+#define VMW_HVGUESTRPC_RECV_LEN_SUCCESS 0x00830000
+#define VMW_HVGUESTRPC_RECV_DATA_SUCCESS 0x00010000
+#define VMW_HVGUESTRPC_FINISH_RECV_SUCCESS 0x00010000
+#define VMW_HVGUESTRPC_CLOSE_SUCCESS 0x00010000
+
+#define VMW_GUESTRPC_EBX(_p) ((_p)[1])
+#define VMW_GUESTRPC_EDXHI(_p) ((_p)[3] >> 16)
+#define VMW_GUESTRPC_STATUS(_p) ((_p)[2])
+
+static __inline void
+vmware_guestrpc(int chan, uint16_t subcmd, uint32_t param, u_int *p)
+{
+
+#ifdef DEBUG_VMGUESTRPC
+ printf("%s(%d, %#x, %#x, %p)\n", __func__, chan, subcmd, param, p);
+#endif
+ vmware_hvcall(chan, VMW_HVCMD_GUESTRPC | (subcmd << 16), param, p);
+#ifdef DEBUG_VMGUESTRPC
+ printf("p[0] = %#x\n", p[0]);
+ printf("p[1] = %#x\n", p[1]);
+ printf("p[2] = %#x\n", p[2]);
+ printf("p[3] = %#x\n", p[3]);
+#endif
+}
+
+/*
+ * Start a GuestRPC request
+ *
+ * Channel number is returned in the EDXHI parameter.
+ *
+ * This channel number must be used in successive GuestRPC requests for
+ * sending and receiving RPC data.
+ */
+static int
+vmware_guestrpc_open(void)
+{
+ u_int p[4];
+
+ vmware_guestrpc(0, VMW_HVGUESTRPC_OPEN, VMW_HVGUESTRPC_OPEN_MAGIC,
+ p);
+ if (VMW_GUESTRPC_STATUS(p) != VMW_HVGUESTRPC_OPEN_SUCCESS)
+ return (-1);
+
+ return (VMW_GUESTRPC_EDXHI(p));
+}
+
+/*
+ * Send the length of the GuestRPC request
+ *
+ * In a GuestRPC request, the total length of the request must be sent
+ * before any data can be sent.
+ */
+static int
+vmware_guestrpc_send_len(int channel, size_t len)
+{
+ u_int p[4];
+
+ vmware_guestrpc(channel, VMW_HVGUESTRPC_SEND_LEN, len, p);
+ if (VMW_GUESTRPC_STATUS(p) != VMW_HVGUESTRPC_SEND_LEN_SUCCESS)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Send the data for the GuestRPC request
+ *
+ * The total length of the GuestRPC request must be sent before any data.
+ * Data is sent 32-bit values at a time and therefore may require multiple
+ * calls to send all the data.
+ */
+static int
+vmware_guestrpc_send_data(int channel, uint32_t data)
+{
+ u_int p[4];
+
+ vmware_guestrpc(channel, VMW_HVGUESTRPC_SEND_DATA, data, p);
+ if (VMW_GUESTRPC_STATUS(p) != VMW_HVGUESTRPC_SEND_DATA_SUCCESS)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Receive the length of the GuestRPC reply.
+ *
+ * Length of the reply data is returned in the EBX parameter.
+ * The reply identifier is returned in the EDXHI parameter.
+ *
+ * The reply identifier must be used as the GuestRPC parameter in calls
+ * to vmware_guestrpc_recv_data()
+ */
+static int
+vmware_guestrpc_recv_len(int channel, size_t *lenp)
+{
+ u_int p[4];
+
+ vmware_guestrpc(channel, VMW_HVGUESTRPC_RECV_LEN, 0, p);
+ if (VMW_GUESTRPC_STATUS(p) != VMW_HVGUESTRPC_RECV_LEN_SUCCESS)
+ return (-1);
+
+ *lenp = VMW_GUESTRPC_EBX(p);
+ return (VMW_GUESTRPC_EDXHI(p));
+}
+
+/*
+ * Receive the GuestRPC reply data.
+ *
+ * Data is received in 32-bit values at a time and therefore may
+ * require multiple requests to get all the data.
+ */
+static int
+vmware_guestrpc_recv_data(int channel, int id, uint32_t *datap)
+{
+ u_int p[4];
+
+ vmware_guestrpc(channel, VMW_HVGUESTRPC_RECV_DATA, id, p);
+ if (VMW_GUESTRPC_STATUS(p) != VMW_HVGUESTRPC_RECV_DATA_SUCCESS)
+ return (-1);
+
+ *datap = VMW_GUESTRPC_EBX(p);
+ return (0);
+}
+
+/*
+ * Close the GuestRPC channel.
+ */
+static int
+vmware_guestrpc_close(int channel)
+{
+ u_int p[4];
+
+ vmware_guestrpc(channel, VMW_HVGUESTRPC_CLOSE, 0, p);
+ if (VMW_GUESTRPC_STATUS(p) != VMW_HVGUESTRPC_CLOSE_SUCCESS)
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * Send a GuestRPC command.
+ */
+int
+vmware_guestrpc_cmd(struct sbuf *sbufp)
+{
+ char *buf;
+ size_t cnt, len;
+ int chan, id, status;
+ uint32_t data;
+
+ /* Make sure we are running under VMware hypervisor */
+ if (vm_guest != VM_GUEST_VMWARE)
+ return (ENXIO);
+
+ /* Open the GuestRPC channel */
+ chan = vmware_guestrpc_open();
+ if (chan == -1)
+ return (EIO);
+
+ /* Send the length */
+ buf = sbuf_data(sbufp);
+ len = sbuf_len(sbufp);
+ status = vmware_guestrpc_send_len(chan, len);
+ if (status == -1)
+ goto done;
+
+ /* Send the data */
+ while (len > 0) {
+ data = 0;
+ cnt = min(4, len);
+ memcpy(&data, buf, cnt);
+ status = vmware_guestrpc_send_data(chan, data);
+ if (status == -1)
+ goto done;
+ buf += cnt;
+ len -= cnt;
+ }
+
+ /* Receive the length of the reply data */
+ id = vmware_guestrpc_recv_len(chan, &len);
+ if (id == -1)
+ goto done;
+
+ /* Receive the reply data */
+ sbuf_clear(sbufp);
+ while (len > 0) {
+ status = vmware_guestrpc_recv_data(chan, id, &data);
+ if (status == -1)
+ goto done;
+ sbuf_bcat(sbufp, &data, 4);
+ len -= min(4, len);
+ }
+
+done:
+ /* Close the GuestRPC channel */
+ vmware_guestrpc_close(chan);
+ return (status == -1 ? EIO : 0);
+}
+
+/*
+ * Set guest information key/value pair
+ */
+int
+vmware_guestrpc_set_guestinfo(const char *keyword, const char *val)
+{
+ struct sbuf sb;
+ char *buf;
+ int error;
+
+#ifdef DEBUG_VMGUESTRPC
+ printf("%s: %s=%s\n", __func__, keyword, val);
+#endif
+
+ /* Send "info-set" GuestRPC command */
+ sbuf_new(&sb, NULL, 256, SBUF_AUTOEXTEND);
+ sbuf_printf(&sb, "info-set guestinfo.fbsd.%s %s", keyword, val);
+ sbuf_trim(&sb);
+ sbuf_finish(&sb);
+
+ error = vmware_guestrpc_cmd(&sb);
+ if (error)
+ return (error);
+
+ sbuf_finish(&sb);
+ buf = sbuf_data(&sb);
+
+#ifdef DEBUG_VMGUESTRPC
+ printf("%s: result: %s\n", __func__, buf);
+#endif
+
+ /* Buffer will contain 1 on sucess or 0 on failure */
+ return ((buf[0] == '0') ? EINVAL : 0);
+}
+
+/*
+ * Get guest information key/value pair.
+ */
+int
+vmware_guestrpc_get_guestinfo(const char *keyword, struct sbuf *sbufp)
+{
+ struct sbuf sb;
+ char *buf;
+ int error;
+
+#ifdef DEBUG_VMGUESTRPC
+ printf("%s: %s\n", __func__, keyword);
+#endif
+
+ /* Send "info-get" GuestRPC command */
+ sbuf_new(&sb, NULL, 256, SBUF_AUTOEXTEND);
+ sbuf_printf(&sb, "info-get guestinfo.fbsd.%s", keyword);
+ sbuf_trim(&sb);
+ sbuf_finish(&sb);
+
+ error = vmware_guestrpc_cmd(&sb);
+ if (error)
+ return (error);
+
+ sbuf_finish(&sb);
+ buf = sbuf_data(&sb);
+
+#ifdef DEBUG_VMGUESTRPC
+ printf("%s: result: %s\n", __func__, buf);
+#endif
+
+ /*
+ * Buffer will contain "1 <value>" on success or
+ * "0 No value found" on failure
+ */
+ if (buf[0] == '0')
+ return (ENOENT);
+
+ /*
+ * Add value from buffer to the sbuf
+ */
+ sbuf_cat(sbufp, buf + 2);
+ return (0);
+}
+
+MODULE_VERSION(vmware_guestrpc, 1);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Feb 22, 4:43 PM (2 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16775116
Default Alt Text
D44528.id137621.diff (12 KB)
Attached To
Mode
D44528: guestrpc module to handle VMware backdoor port GuestRPC functionality
Attached
Detach File
Event Timeline
Log In to Comment