From nobody Wed May 01 19:46:02 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4VV6xk4LHHz5JxGF; Wed, 1 May 2024 19:46:02 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4VV6xk2hBcz4gtd; Wed, 1 May 2024 19:46:02 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1714592762; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nE4wzB+jWJur6J31EGeDGPH0Tg+s2hxOrHN3T3QMRRc=; b=mQ9vClhWG4q0ou2NG78CKULwts1gPPDeIC9iOMCabZG5NZ5Rgfwj/lJ4u85KG7zmCvMG3l FrhMdU4UwPd3AoXwd2r4Uq/YikXhxdbLdx3Oct3ddLo2C7sxGpfp1caD4IhMaccJp2AoQF mwZmN36e/oF6Fi+nllsyoKM7JF6got0Lz7FF1jCQxiwBDoMIpmcvc2IEmbt6nBxGsykHD9 7U4JVWeyUaS3DcyOfIJ8Ed2itGkg/QG43+flyKCiDJDUeSM1vN/6+bFkYuMpBmXPV/pwWW njBN6YI0xh5WzGuqTrB3lYFsZ27DEt3u7IT5Ay3B3h6ObIkxTlMnJuYJem6tHQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1714592762; a=rsa-sha256; cv=none; b=qJQM160Zd3aB2yT8X+JRVldNGbCSoqvfIReDsKt7pEvmGwdptGBcLSdDCPLFQg4rdoHzwW p27dhm8IMRqOhf10BfxI8UFuFMe7sMzCW4g7llNu3+uUR20JRUluUpSfyayD9adu49V5CO fL3Nwq+qsYfH0fHLzydV3c97WB0AljXV9bUkigp3qbdJwOR/aXBYx5vC4ELib8S5sp4pZN OkjM3KEnQnUlUFQ9Ha1wDAJGZfhde8difsVoJ+fA7oHgcr87uyq8cFPfJWWfqv6PlOX6fG jXw8duWoZJuHxiISXAnWxhIIEXww1E/N/b613YRko7CrSuff+uVa2gVuGr7BjA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1714592762; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nE4wzB+jWJur6J31EGeDGPH0Tg+s2hxOrHN3T3QMRRc=; b=pzoK8Ii6nlx9xCmrVPm3HsneAljFnH8lKcVItJ1nJDGky6Kiy3Sabp4WA6Fv0YO6IctNmg EFfRC7A3Y+gvFJEfsUu8w7BL2VmLaZ4CEnyjpo2Qt9bj4AMWRH5RFY95U4hOaouKqscsv2 tjVjfrj9nPE0DF/7Lyde2/jojDsAn44t5nsZOb8bGQNYX9dMFoE77aPxsVUWGh1p1EjVJN XRk/dCmM/bkonWNXjhh5Jw1KvSVTUJqmlbwJROPaS0bpDxwr3qXPTRNBL5wqx31IQZlNIa DhEBQ4LL/Q2n5Vk02EJTx+ZE9yyvl/LPD4+75bQ0M9M7S743J7jNqwXTO8R0yA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4VV6xk20Q2zXwm; Wed, 1 May 2024 19:46:02 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 441Jk240083014; Wed, 1 May 2024 19:46:02 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 441Jk2fF083011; Wed, 1 May 2024 19:46:02 GMT (envelope-from git) Date: Wed, 1 May 2024 19:46:02 GMT Message-Id: <202405011946.441Jk2fF083011@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Stephen J. Kiernan" Subject: git: ecaab0fb5da4 - main - guestrpc module to handle VMware backdoor port GuestRPC functionality List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: stevek X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: ecaab0fb5da4cd7340c62b77bcb19efcfa1b69df Auto-Submitted: auto-generated The branch main has been updated by stevek: URL: https://cgit.FreeBSD.org/src/commit/?id=ecaab0fb5da4cd7340c62b77bcb19efcfa1b69df commit ecaab0fb5da4cd7340c62b77bcb19efcfa1b69df Author: Stephen J. Kiernan AuthorDate: 2024-05-01 19:45:45 +0000 Commit: Stephen J. Kiernan CommitDate: 2024-05-01 19:45:45 +0000 guestrpc module to handle VMware backdoor port GuestRPC functionality Convert existing FreeBSD vmware_hvcall function to take a channel and parameter arguments. Added vmware_guestrpc_cmd() to send GuestRPC commands to the VMware hypervisor. The sbuf argument is used for both the command to send and to store the data to return to the caller. The following KPIs can be used to get and set FreeBSD-specific guest information in key/value pairs: * vmware_guestrpc_set_guestinfo - set a value into the guestinfo.fbsd. key * vmware_guestrpc_get_guestinfo - get the value stored in the guestinfo.fbsd. key Add VMware devices to x86 NOTES Reviewed by: jhb Obtained from: Juniper Networks, Inc. Differential Revision: https://reviews.freebsd.org/D44528 --- sys/conf/files.x86 | 1 + sys/x86/acpica/madt.c | 3 +- sys/x86/conf/NOTES | 5 + sys/x86/include/vmware.h | 8 +- sys/x86/include/vmware_guestrpc.h | 37 +++++ sys/x86/x86/identcpu.c | 3 +- sys/x86/x86/tsc.c | 2 +- sys/x86/x86/vmware_guestrpc.c | 337 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 391 insertions(+), 5 deletions(-) diff --git a/sys/conf/files.x86 b/sys/conf/files.x86 index ce31c42215be..9439a46ce347 100644 --- a/sys/conf/files.x86 +++ b/sys/conf/files.x86 @@ -380,6 +380,7 @@ x86/x86/stack_machdep.c optional ddb | stack x86/x86/tsc.c standard x86/x86/ucode.c standard x86/x86/ucode_subr.c standard +x86/x86/vmware_guestrpc.c optional vmware_guestrpc x86/x86/delay.c standard x86/xen/hvm.c optional xenhvm x86/xen/xen_apic.c optional xenhvm smp diff --git a/sys/x86/acpica/madt.c b/sys/x86/acpica/madt.c index adfeed70c5c6..c6358ad7e847 100644 --- a/sys/x86/acpica/madt.c +++ b/sys/x86/acpica/madt.c @@ -159,7 +159,8 @@ madt_x2apic_disable_reason(void) } if (vm_guest == VM_GUEST_VMWARE) { - vmware_hvcall(VMW_HVCMD_GETVCPU_INFO, p); + vmware_hvcall(0, VMW_HVCMD_GETVCPU_INFO, + VMW_HVCMD_DEFAULT_PARAM, 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 index 5042585da310..87a8f8924d12 100644 --- a/sys/x86/conf/NOTES +++ b/sys/x86/conf/NOTES @@ -550,6 +550,11 @@ device kvm_clock # KVM paravirtual clock driver 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 index 38bca8c146a7..5ab6462b862d 100644 --- 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_guestrpc.h b/sys/x86/include/vmware_guestrpc.h new file mode 100644 index 000000000000..24055b6c249e --- /dev/null +++ b/sys/x86/include/vmware_guestrpc.h @@ -0,0 +1,37 @@ +/*- + * 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 + * 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. + */ + +#ifndef _X86_VMWARE_GUESTRPC_H_ +#define _X86_VMWARE_GUESTRPC_H_ + +struct sbuf; + +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_GUESTRPC_H_ */ diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c index 919dda722d71..953736d6b25c 100644 --- a/sys/x86/x86/identcpu.c +++ b/sys/x86/x86/identcpu.c @@ -1470,7 +1470,8 @@ identify_hypervisor(void) 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 index 7c11a1f5f300..4edaa37d9b54 100644 --- a/sys/x86/x86/tsc.c +++ b/sys/x86/x86/tsc.c @@ -139,7 +139,7 @@ tsc_freq_vmware(void) { 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 index 000000000000..b62f40c5a9ef --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* 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 " 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);