Page MenuHomeFreeBSD

D44528.id137621.diff
No OneTemporary

D44528.id137621.diff

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

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)

Event Timeline