Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys add a port of the VMware Tools driver vmt(4) from OpenBSD



details:   https://anonhg.NetBSD.org/src/rev/fc961de57692
branches:  trunk
changeset: 770455:fc961de57692
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Mon Oct 17 22:39:22 2011 +0000

description:
add a port of the VMware Tools driver vmt(4) from OpenBSD

diffstat:

 sys/arch/x86/conf/files.x86 |     6 +-
 sys/arch/x86/x86/vmt.c      |  1195 +++++++++++++++++++++++++++++++++++++++++++
 sys/modules/vmt/Makefile    |    14 +
 sys/modules/vmt/vmt.ioconf  |    10 +
 4 files changed, 1224 insertions(+), 1 deletions(-)

diffs (truncated from 1251 to 300 lines):

diff -r 495f306310b5 -r fc961de57692 sys/arch/x86/conf/files.x86
--- a/sys/arch/x86/conf/files.x86       Mon Oct 17 22:38:01 2011 +0000
+++ b/sys/arch/x86/conf/files.x86       Mon Oct 17 22:39:22 2011 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.x86,v 1.72 2011/08/29 22:46:56 dyoung Exp $
+#      $NetBSD: files.x86,v 1.73 2011/10/17 22:39:22 jmcneill Exp $
 
 # options for MP configuration through the MP spec
 defflag opt_mpbios.h MPBIOS MPVERBOSE MPDEBUG MPBIOS_SCANPCI
@@ -61,6 +61,10 @@
 attach viac7temp at cpufeaturebus
 file   arch/x86/x86/viac7temp.c        viac7temp
 
+device vmt: sysmon_power
+attach vmt at cpufeaturebus
+file   arch/x86/x86/vmt.c              vmt
+
 file   arch/x86/x86/apic.c             ioapic | lapic
 file   arch/x86/x86/bus_dma.c
 file   arch/x86/x86/bus_space.c
diff -r 495f306310b5 -r fc961de57692 sys/arch/x86/x86/vmt.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/x86/x86/vmt.c    Mon Oct 17 22:39:22 2011 +0000
@@ -0,0 +1,1195 @@
+/* $NetBSD: vmt.c,v 1.1 2011/10/17 22:39:23 jmcneill Exp $ */
+/* $OpenBSD: vmt.c,v 1.11 2011/01/27 21:29:25 dtucker Exp $ */
+
+/*
+ * Copyright (c) 2007 David Crawshaw <david%zentus.com@localhost>
+ * Copyright (c) 2008 David Gwynne <dlg%openbsd.org@localhost>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Protocol reverse engineered by Ken Kato:
+ * http://chitchat.at.infoseek.co.jp/vmware/backdoor.html
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/types.h>
+#include <sys/kmem.h>
+#include <sys/callout.h>
+#include <sys/reboot.h>
+#include <sys/syslog.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/module.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <machine/cpuvar.h>
+
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/sysmon/sysmon_taskq.h>
+
+/* #define VMT_DEBUG */
+
+/* "The" magic number, always occupies the EAX register. */
+#define VM_MAGIC                       0x564D5868
+
+/* Port numbers, passed on EDX.LOW . */
+#define VM_PORT_CMD                    0x5658
+#define VM_PORT_RPC                    0x5659
+
+/* Commands, passed on ECX.LOW. */
+#define VM_CMD_GET_SPEED               0x01
+#define VM_CMD_APM                     0x02
+#define VM_CMD_GET_MOUSEPOS            0x04
+#define VM_CMD_SET_MOUSEPOS            0x05
+#define VM_CMD_GET_CLIPBOARD_LEN       0x06
+#define VM_CMD_GET_CLIPBOARD           0x07
+#define VM_CMD_SET_CLIPBOARD_LEN       0x08
+#define VM_CMD_SET_CLIPBOARD           0x09
+#define VM_CMD_GET_VERSION             0x0a
+#define  VM_VERSION_UNMANAGED                  0x7fffffff
+#define VM_CMD_GET_DEVINFO             0x0b
+#define VM_CMD_DEV_ADDREMOVE           0x0c
+#define VM_CMD_GET_GUI_OPTIONS         0x0d
+#define VM_CMD_SET_GUI_OPTIONS         0x0e
+#define VM_CMD_GET_SCREEN_SIZE         0x0f
+#define VM_CMD_GET_HWVER               0x11
+#define VM_CMD_POPUP_OSNOTFOUND                0x12
+#define VM_CMD_GET_BIOS_UUID           0x13
+#define VM_CMD_GET_MEM_SIZE            0x14
+/*#define VM_CMD_GET_TIME              0x17 */ /* deprecated */
+#define VM_CMD_RPC                     0x1e
+#define VM_CMD_GET_TIME_FULL           0x2e
+
+/* RPC sub-commands, passed on ECX.HIGH. */
+#define VM_RPC_OPEN                    0x00
+#define VM_RPC_SET_LENGTH              0x01
+#define VM_RPC_SET_DATA                        0x02
+#define VM_RPC_GET_LENGTH              0x03
+#define VM_RPC_GET_DATA                        0x04
+#define VM_RPC_GET_END                 0x05
+#define VM_RPC_CLOSE                   0x06
+
+/* RPC magic numbers, passed on EBX. */
+#define VM_RPC_OPEN_RPCI       0x49435052UL /* with VM_RPC_OPEN. */
+#define VM_RPC_OPEN_TCLO       0x4F4C4354UL /* with VP_RPC_OPEN. */
+#define VM_RPC_ENH_DATA                0x00010000UL /* with enhanced RPC data calls. */
+
+#define VM_RPC_FLAG_COOKIE     0x80000000UL
+
+/* RPC reply flags */
+#define VM_RPC_REPLY_SUCCESS   0x0001
+#define VM_RPC_REPLY_DORECV    0x0002          /* incoming message available */
+#define VM_RPC_REPLY_CLOSED    0x0004          /* RPC channel is closed */
+#define VM_RPC_REPLY_UNSENT    0x0008          /* incoming message was removed? */
+#define VM_RPC_REPLY_CHECKPOINT        0x0010          /* checkpoint occurred -> retry */
+#define VM_RPC_REPLY_POWEROFF  0x0020          /* underlying device is powering off */
+#define VM_RPC_REPLY_TIMEOUT   0x0040
+#define VM_RPC_REPLY_HB                0x0080          /* high-bandwidth tx/rx available */
+
+/* VM state change IDs */
+#define VM_STATE_CHANGE_HALT   1
+#define VM_STATE_CHANGE_REBOOT 2
+#define VM_STATE_CHANGE_POWERON 3
+#define VM_STATE_CHANGE_RESUME  4
+#define VM_STATE_CHANGE_SUSPEND 5
+
+/* VM guest info keys */
+#define VM_GUEST_INFO_DNS_NAME         1
+#define VM_GUEST_INFO_IP_ADDRESS       2
+#define VM_GUEST_INFO_DISK_FREE_SPACE  3
+#define VM_GUEST_INFO_BUILD_NUMBER     4
+#define VM_GUEST_INFO_OS_NAME_FULL     5
+#define VM_GUEST_INFO_OS_NAME          6
+#define VM_GUEST_INFO_UPTIME           7
+#define VM_GUEST_INFO_MEMORY           8
+#define VM_GUEST_INFO_IP_ADDRESS_V2    9
+
+/* RPC responses */
+#define VM_RPC_REPLY_OK                        "OK "
+#define VM_RPC_RESET_REPLY             "OK ATR toolbox"
+#define VM_RPC_REPLY_ERROR             "ERROR Unknown command"
+#define VM_RPC_REPLY_ERROR_IP_ADDR     "ERROR Unable to find guest IP address"
+
+/* A register. */
+union vm_reg {
+       struct {
+               uint16_t low;
+               uint16_t high;
+       } part;
+       uint32_t word;
+#ifdef __amd64__
+       struct {
+               uint32_t low;
+               uint32_t high;
+       } words;
+       uint64_t quad;
+#endif
+} __packed;
+
+/* A register frame. */
+struct vm_backdoor {
+       union vm_reg eax;
+       union vm_reg ebx;
+       union vm_reg ecx;
+       union vm_reg edx;
+       union vm_reg esi;
+       union vm_reg edi;
+       union vm_reg ebp;
+} __packed;
+
+/* RPC context. */
+struct vm_rpc {
+       uint16_t channel;
+       uint32_t cookie1;
+       uint32_t cookie2;
+};
+
+static int     vmt_match(device_t, cfdata_t, void *);
+static void    vmt_attach(device_t, device_t, void *);
+static int     vmt_detach(device_t, int);
+
+struct vmt_softc {
+       device_t                sc_dev;
+
+       struct vm_rpc           sc_tclo_rpc;
+       bool                    sc_tclo_rpc_open;
+       char                    *sc_rpc_buf;
+       int                     sc_rpc_error;
+       int                     sc_tclo_ping;
+       int                     sc_set_guest_os;
+#define VMT_RPC_BUFLEN                 256
+
+       struct callout          sc_tick;
+       struct callout          sc_tclo_tick;
+#if notyet
+       struct ksensordev       sc_sensordev;
+       struct ksensor          sc_sensor;
+#endif
+
+       struct sysmon_pswitch   sc_smpsw_power;
+       struct sysmon_pswitch   sc_smpsw_reset;
+       bool                    sc_smpsw_valid;
+
+       char                    sc_hostname[MAXHOSTNAMELEN];
+};
+
+CFATTACH_DECL_NEW(vmt, sizeof(struct vmt_softc),
+       vmt_match, vmt_attach, vmt_detach, NULL);
+
+static void vm_cmd(struct vm_backdoor *);
+static void vm_ins(struct vm_backdoor *);
+static void vm_outs(struct vm_backdoor *);
+
+/* Functions for communicating with the VM Host. */
+static int vm_rpc_open(struct vm_rpc *, uint32_t);
+static int vm_rpc_close(struct vm_rpc *);
+static int vm_rpc_send(const struct vm_rpc *, const uint8_t *, uint32_t);
+static int vm_rpc_send_str(const struct vm_rpc *, const uint8_t *);
+static int vm_rpc_get_length(const struct vm_rpc *, uint32_t *, uint16_t *);
+static int vm_rpc_get_data(const struct vm_rpc *, char *, uint32_t, uint16_t);
+static int vm_rpc_send_rpci_tx_buf(struct vmt_softc *, const uint8_t *, uint32_t);
+static int vm_rpc_send_rpci_tx(struct vmt_softc *, const char *, ...)
+    __printflike(2, 3);
+static int vm_rpci_response_successful(struct vmt_softc *);
+
+static void vmt_tclo_state_change_success(struct vmt_softc *, int, char);
+static void vmt_do_reboot(struct vmt_softc *);
+static void vmt_do_shutdown(struct vmt_softc *);
+
+static void vmt_update_guest_info(struct vmt_softc *);
+static void vmt_update_guest_uptime(struct vmt_softc *);
+
+static void vmt_tick(void *);
+static void vmt_tclo_tick(void *);
+static bool vmt_shutdown(device_t, int);
+static void vmt_pswitch_event(void *);
+
+extern char hostname[MAXHOSTNAMELEN];
+
+static bool
+vmt_probe(uint32_t *type)
+{
+       struct vm_backdoor frame;
+
+       memset(&frame, 0, sizeof(frame));
+
+       frame.eax.word = VM_MAGIC;
+       frame.ebx.word = ~VM_MAGIC;
+       frame.ecx.part.low = VM_CMD_GET_VERSION;
+       frame.ecx.part.high = 0xffff;
+       frame.edx.part.low  = VM_PORT_CMD;
+       frame.edx.part.high = 0;
+
+       vm_cmd(&frame);
+
+       if (frame.eax.word == 0xffffffff ||
+           frame.ebx.word != VM_MAGIC)
+               return false;
+
+       if (type)
+               *type = frame.ecx.word;
+
+       return true;
+}
+
+static int
+vmt_match(device_t parent, cfdata_t match, void *aux)
+{
+       struct cpufeature_attach_args *cfaa = aux;
+       struct cpu_info *ci = cfaa->ci;
+
+       if (strcmp(cfaa->name, "vm") != 0)
+               return 0;
+       if ((ci->ci_flags & (CPUF_BSP|CPUF_SP|CPUF_PRIMARY)) == 0)
+               return 0;
+
+       return vmt_probe(NULL);
+}
+
+static const char *
+vmt_type(void)
+{
+       uint32_t vmwaretype = 0;
+
+       vmt_probe(&vmwaretype);
+
+       switch (vmwaretype) {
+       case 1: return "Express";
+       case 2: return "ESX Server";
+       case 3: return "VMware Server";



Home | Main Index | Thread Index | Old Index