LCOV - code coverage report
Current view: top level - dev/pv - vmt.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 540 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 44 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: vmt.c,v 1.15 2018/04/28 15:44:59 jasper Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2007 David Crawshaw <david@zentus.com>
       5             :  * Copyright (c) 2008 David Gwynne <dlg@openbsd.org>
       6             :  *
       7             :  * Permission to use, copy, modify, and distribute this software for any
       8             :  * purpose with or without fee is hereby granted, provided that the above
       9             :  * copyright notice and this permission notice appear in all copies.
      10             :  *
      11             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      12             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      13             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      14             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      15             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      16             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      17             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      18             :  */
      19             : 
      20             : #if !defined(__i386__) && !defined(__amd64__)
      21             : #error vmt(4) is only supported on i386 and amd64
      22             : #endif
      23             : 
      24             : /*
      25             :  * Protocol reverse engineered by Ken Kato:
      26             :  * https://sites.google.com/site/chitchatvmback/backdoor
      27             :  */
      28             : 
      29             : #include <sys/param.h>
      30             : #include <sys/systm.h>
      31             : #include <sys/kernel.h>
      32             : #include <sys/malloc.h>
      33             : #include <sys/timeout.h>
      34             : #include <sys/signalvar.h>
      35             : #include <sys/syslog.h>
      36             : #include <sys/proc.h>
      37             : #include <sys/socket.h>
      38             : #include <sys/ioctl.h>
      39             : #include <sys/mount.h>
      40             : #include <sys/task.h>
      41             : 
      42             : #include <net/if.h>
      43             : #include <net/if_var.h>
      44             : #include <netinet/in.h>
      45             : 
      46             : #include <dev/pv/pvvar.h>
      47             : #include <dev/rndvar.h>
      48             : 
      49             : /* "The" magic number, always occupies the EAX register. */
      50             : #define VM_MAGIC                        0x564D5868
      51             : 
      52             : /* Port numbers, passed on EDX.LOW . */
      53             : #define VM_PORT_CMD                     0x5658
      54             : #define VM_PORT_RPC                     0x5659
      55             : 
      56             : /* Commands, passed on ECX.LOW. */
      57             : #define VM_CMD_GET_SPEED                0x01
      58             : #define VM_CMD_APM                      0x02
      59             : #define VM_CMD_GET_MOUSEPOS             0x04
      60             : #define VM_CMD_SET_MOUSEPOS             0x05
      61             : #define VM_CMD_GET_CLIPBOARD_LEN        0x06
      62             : #define VM_CMD_GET_CLIPBOARD            0x07
      63             : #define VM_CMD_SET_CLIPBOARD_LEN        0x08
      64             : #define VM_CMD_SET_CLIPBOARD            0x09
      65             : #define VM_CMD_GET_VERSION              0x0a
      66             : #define  VM_VERSION_UNMANAGED                   0x7fffffff
      67             : #define VM_CMD_GET_DEVINFO              0x0b
      68             : #define VM_CMD_DEV_ADDREMOVE            0x0c
      69             : #define VM_CMD_GET_GUI_OPTIONS          0x0d
      70             : #define VM_CMD_SET_GUI_OPTIONS          0x0e
      71             : #define VM_CMD_GET_SCREEN_SIZE          0x0f
      72             : #define VM_CMD_GET_HWVER                0x11
      73             : #define VM_CMD_POPUP_OSNOTFOUND         0x12
      74             : #define VM_CMD_GET_BIOS_UUID            0x13
      75             : #define VM_CMD_GET_MEM_SIZE             0x14
      76             : /*#define VM_CMD_GET_TIME               0x17 */ /* deprecated */
      77             : #define VM_CMD_RPC                      0x1e
      78             : #define VM_CMD_GET_TIME_FULL            0x2e
      79             : 
      80             : /* RPC sub-commands, passed on ECX.HIGH. */
      81             : #define VM_RPC_OPEN                     0x00
      82             : #define VM_RPC_SET_LENGTH               0x01
      83             : #define VM_RPC_SET_DATA                 0x02
      84             : #define VM_RPC_GET_LENGTH               0x03
      85             : #define VM_RPC_GET_DATA                 0x04
      86             : #define VM_RPC_GET_END                  0x05
      87             : #define VM_RPC_CLOSE                    0x06
      88             : 
      89             : /* RPC magic numbers, passed on EBX. */
      90             : #define VM_RPC_OPEN_RPCI        0x49435052UL /* with VM_RPC_OPEN. */
      91             : #define VM_RPC_OPEN_TCLO        0x4F4C4354UL /* with VP_RPC_OPEN. */
      92             : #define VM_RPC_ENH_DATA         0x00010000UL /* with enhanced RPC data calls. */
      93             : 
      94             : #define VM_RPC_FLAG_COOKIE      0x80000000UL
      95             : 
      96             : /* RPC reply flags */
      97             : #define VM_RPC_REPLY_SUCCESS    0x0001
      98             : #define VM_RPC_REPLY_DORECV     0x0002          /* incoming message available */
      99             : #define VM_RPC_REPLY_CLOSED     0x0004          /* RPC channel is closed */
     100             : #define VM_RPC_REPLY_UNSENT     0x0008          /* incoming message was removed? */
     101             : #define VM_RPC_REPLY_CHECKPOINT 0x0010          /* checkpoint occurred -> retry */
     102             : #define VM_RPC_REPLY_POWEROFF   0x0020          /* underlying device is powering off */
     103             : #define VM_RPC_REPLY_TIMEOUT    0x0040
     104             : #define VM_RPC_REPLY_HB         0x0080          /* high-bandwidth tx/rx available */
     105             : 
     106             : /* VM state change IDs */
     107             : #define VM_STATE_CHANGE_HALT    1
     108             : #define VM_STATE_CHANGE_REBOOT  2
     109             : #define VM_STATE_CHANGE_POWERON 3
     110             : #define VM_STATE_CHANGE_RESUME  4
     111             : #define VM_STATE_CHANGE_SUSPEND 5
     112             : 
     113             : /* VM guest info keys */
     114             : #define VM_GUEST_INFO_DNS_NAME          1
     115             : #define VM_GUEST_INFO_IP_ADDRESS        2
     116             : #define VM_GUEST_INFO_DISK_FREE_SPACE   3
     117             : #define VM_GUEST_INFO_BUILD_NUMBER      4
     118             : #define VM_GUEST_INFO_OS_NAME_FULL      5
     119             : #define VM_GUEST_INFO_OS_NAME           6
     120             : #define VM_GUEST_INFO_UPTIME            7
     121             : #define VM_GUEST_INFO_MEMORY            8
     122             : #define VM_GUEST_INFO_IP_ADDRESS_V2     9
     123             : 
     124             : /* RPC responses */
     125             : #define VM_RPC_REPLY_OK                 "OK "
     126             : #define VM_RPC_RESET_REPLY              "OK ATR toolbox"
     127             : #define VM_RPC_REPLY_ERROR              "ERROR Unknown command"
     128             : #define VM_RPC_REPLY_ERROR_IP_ADDR      "ERROR Unable to find guest IP address"
     129             : 
     130             : /* VM backup error codes */
     131             : #define VM_BACKUP_SUCCESS               0
     132             : #define VM_BACKUP_SYNC_ERROR            3
     133             : #define VM_BACKUP_REMOTE_ABORT          4
     134             : 
     135             : #define VM_BACKUP_TIMEOUT               30 /* seconds */
     136             : 
     137             : /* A register. */
     138             : union vm_reg {
     139             :         struct {
     140             :                 uint16_t low;
     141             :                 uint16_t high;
     142             :         } part;
     143             :         uint32_t word;
     144             : #ifdef __amd64__
     145             :         struct {
     146             :                 uint32_t low;
     147             :                 uint32_t high;
     148             :         } words;
     149             :         uint64_t quad;
     150             : #endif
     151             : } __packed;
     152             : 
     153             : /* A register frame. */
     154             : struct vm_backdoor {
     155             :         union vm_reg eax;
     156             :         union vm_reg ebx;
     157             :         union vm_reg ecx;
     158             :         union vm_reg edx;
     159             :         union vm_reg esi;
     160             :         union vm_reg edi;
     161             :         union vm_reg ebp;
     162             : } __packed;
     163             : 
     164             : /* RPC context. */
     165             : struct vm_rpc {
     166             :         uint16_t channel;
     167             :         uint32_t cookie1;
     168             :         uint32_t cookie2;
     169             : };
     170             : 
     171             : struct vmt_softc {
     172             :         struct device           sc_dev;
     173             : 
     174             :         struct vm_rpc           sc_tclo_rpc;
     175             :         char                    *sc_rpc_buf;
     176             :         int                     sc_rpc_error;
     177             :         int                     sc_tclo_ping;
     178             :         int                     sc_set_guest_os;
     179             :         int                     sc_quiesce;
     180             :         struct task             sc_quiesce_task;
     181             : #define VMT_RPC_BUFLEN          4096
     182             : 
     183             :         struct timeout          sc_tick;
     184             :         struct timeout          sc_tclo_tick;
     185             :         struct ksensordev       sc_sensordev;
     186             :         struct ksensor          sc_sensor;
     187             : 
     188             :         char                    sc_hostname[MAXHOSTNAMELEN];
     189             : };
     190             : 
     191             : #ifdef VMT_DEBUG
     192             : #define DPRINTF(_arg...)        printf(_arg)
     193             : #else
     194             : #define DPRINTF(_arg...)        do {} while(0)
     195             : #endif
     196             : #define DEVNAME(_s)             ((_s)->sc_dev.dv_xname)
     197             : 
     198             : void     vm_cmd(struct vm_backdoor *);
     199             : void     vm_ins(struct vm_backdoor *);
     200             : void     vm_outs(struct vm_backdoor *);
     201             : 
     202             : /* Functions for communicating with the VM Host. */
     203             : int      vm_rpc_open(struct vm_rpc *, uint32_t);
     204             : int      vm_rpc_close(struct vm_rpc *);
     205             : int      vm_rpc_send(const struct vm_rpc *, const uint8_t *, uint32_t);
     206             : int      vm_rpc_send_str(const struct vm_rpc *, const uint8_t *);
     207             : int      vm_rpc_get_length(const struct vm_rpc *, uint32_t *, uint16_t *);
     208             : int      vm_rpc_get_data(const struct vm_rpc *, char *, uint32_t, uint16_t);
     209             : int      vm_rpc_send_rpci_tx_buf(struct vmt_softc *, const uint8_t *, uint32_t);
     210             : int      vm_rpc_send_rpci_tx(struct vmt_softc *, const char *, ...)
     211             :             __attribute__((__format__(__kprintf__,2,3)));
     212             : int      vm_rpci_response_successful(struct vmt_softc *);
     213             : 
     214             : int      vmt_kvop(void *, int, char *, char *, size_t);
     215             : 
     216             : void     vmt_probe_cmd(struct vm_backdoor *, uint16_t);
     217             : void     vmt_tclo_state_change_success(struct vmt_softc *, int, char);
     218             : void     vmt_do_reboot(struct vmt_softc *);
     219             : void     vmt_do_shutdown(struct vmt_softc *);
     220             : void     vmt_shutdown(void *);
     221             : 
     222             : void     vmt_update_guest_info(struct vmt_softc *);
     223             : void     vmt_update_guest_uptime(struct vmt_softc *);
     224             : 
     225             : void     vmt_tick_hook(struct device *self);
     226             : void     vmt_tick(void *);
     227             : void     vmt_resume(void);
     228             : 
     229             : int      vmt_match(struct device *, void *, void *);
     230             : void     vmt_attach(struct device *, struct device *, void *);
     231             : int      vmt_activate(struct device *, int);
     232             : 
     233             : void     vmt_tclo_tick(void *);
     234             : int      vmt_tclo_process(struct vmt_softc *, const char *);
     235             : void     vmt_tclo_reset(struct vmt_softc *);
     236             : void     vmt_tclo_ping(struct vmt_softc *);
     237             : void     vmt_tclo_halt(struct vmt_softc *);
     238             : void     vmt_tclo_reboot(struct vmt_softc *);
     239             : void     vmt_tclo_poweron(struct vmt_softc *);
     240             : void     vmt_tclo_suspend(struct vmt_softc *);
     241             : void     vmt_tclo_resume(struct vmt_softc *);
     242             : void     vmt_tclo_capreg(struct vmt_softc *);
     243             : void     vmt_tclo_broadcastip(struct vmt_softc *);
     244             : 
     245             : void     vmt_set_backup_status(struct vmt_softc *, const char *, int,
     246             :             const char *);
     247             : void     vmt_quiesce_task(void *);
     248             : void     vmt_quiesce_done_task(void *);
     249             : void     vmt_tclo_abortbackup(struct vmt_softc *);
     250             : void     vmt_tclo_startbackup(struct vmt_softc *);
     251             : void     vmt_tclo_backupdone(struct vmt_softc *);
     252             : 
     253             : int      vmt_probe(void);
     254             : 
     255             : struct vmt_tclo_rpc {
     256             :         const char      *name;
     257             :         void            (*cb)(struct vmt_softc *);
     258             : } vmt_tclo_rpc[] = {
     259             :         /* Keep sorted by name (case-sensitive) */
     260             :         { "Capabilities_Register",      vmt_tclo_capreg },
     261             :         { "OS_Halt",                    vmt_tclo_halt },
     262             :         { "OS_PowerOn",                 vmt_tclo_poweron },
     263             :         { "OS_Reboot",                  vmt_tclo_reboot },
     264             :         { "OS_Resume",                  vmt_tclo_resume },
     265             :         { "OS_Suspend",                 vmt_tclo_suspend },
     266             :         { "Set_Option broadcastIP 1",   vmt_tclo_broadcastip },
     267             :         { "ping",                       vmt_tclo_ping },
     268             :         { "reset",                      vmt_tclo_reset },
     269             :         { "vmbackup.abort",           vmt_tclo_abortbackup },
     270             :         { "vmbackup.snapshotDone",    vmt_tclo_backupdone },
     271             :         { "vmbackup.start 1",         vmt_tclo_startbackup },
     272             :         { NULL },
     273             : #if 0
     274             :         /* Various unsupported commands */
     275             :         { "Set_Option autohide 0" },
     276             :         { "Set_Option copypaste 1" },
     277             :         { "Set_Option enableDnD 1" },
     278             :         { "Set_Option enableMessageBusTunnel 0" },
     279             :         { "Set_Option linkRootHgfsShare 0" },
     280             :         { "Set_Option mapRootHgfsShare 0" },
     281             :         { "Set_Option synctime 1" },
     282             :         { "Set_Option synctime.period 0" },
     283             :         { "Set_Option time.synchronize.tools.enable 1" },
     284             :         { "Set_Option time.synchronize.tools.percentCorrection 0" },
     285             :         { "Set_Option time.synchronize.tools.slewCorrection 1" },
     286             :         { "Set_Option time.synchronize.tools.startup 1" },
     287             :         { "Set_Option toolScripts.afterPowerOn 1" },
     288             :         { "Set_Option toolScripts.afterResume 1" },
     289             :         { "Set_Option toolScripts.beforePowerOff 1" },
     290             :         { "Set_Option toolScripts.beforeSuspend 1" },
     291             :         { "Time_Synchronize 0" },
     292             :         { "Vix_1_Relayed_Command \"38cdcae40e075d66\"" },
     293             : #endif
     294             : };
     295             : 
     296             : struct cfattach vmt_ca = {
     297             :         sizeof(struct vmt_softc),
     298             :         vmt_match,
     299             :         vmt_attach,
     300             :         NULL,
     301             :         vmt_activate
     302             : };
     303             : 
     304             : struct cfdriver vmt_cd = {
     305             :         NULL,
     306             :         "vmt",
     307             :         DV_DULL
     308             : };
     309             : 
     310             : extern char hostname[MAXHOSTNAMELEN];
     311             : 
     312             : void
     313           0 : vmt_probe_cmd(struct vm_backdoor *frame, uint16_t cmd)
     314             : {
     315           0 :         bzero(frame, sizeof(*frame));
     316             : 
     317           0 :         (frame->eax).word = VM_MAGIC;
     318           0 :         (frame->ebx).word = ~VM_MAGIC;
     319           0 :         (frame->ecx).part.low = cmd;
     320           0 :         (frame->ecx).part.high = 0xffff;
     321           0 :         (frame->edx).part.low  = VM_PORT_CMD;
     322           0 :         (frame->edx).part.high = 0;
     323             : 
     324           0 :         vm_cmd(frame);
     325           0 : }
     326             : 
     327             : int
     328           0 : vmt_probe(void)
     329             : {
     330           0 :         struct vm_backdoor frame;
     331             : 
     332           0 :         vmt_probe_cmd(&frame, VM_CMD_GET_VERSION);
     333           0 :         if (frame.eax.word == 0xffffffff ||
     334           0 :             frame.ebx.word != VM_MAGIC)
     335           0 :                 return (0);
     336             : 
     337           0 :         vmt_probe_cmd(&frame, VM_CMD_GET_SPEED);
     338           0 :         if (frame.eax.word == VM_MAGIC)
     339           0 :                 return (0);
     340             : 
     341           0 :         return (1);
     342           0 : }
     343             : 
     344             : int
     345           0 : vmt_match(struct device *parent, void *match, void *aux)
     346             : {
     347           0 :         struct pv_attach_args   *pva = aux;
     348           0 :         struct pvbus_hv         *hv = &pva->pva_hv[PVBUS_VMWARE];
     349             : 
     350           0 :         if (hv->hv_base == 0)
     351           0 :                 return (0);
     352           0 :         if (!vmt_probe())
     353           0 :                 return (0);
     354             : 
     355           0 :         return (1);
     356           0 : }
     357             : 
     358             : void
     359           0 : vmt_attach(struct device *parent, struct device *self, void *aux)
     360             : {
     361           0 :         struct vmt_softc *sc = (struct vmt_softc *)self;
     362           0 :         struct pv_attach_args   *pva = aux;
     363           0 :         struct pvbus_hv         *hv = &pva->pva_hv[PVBUS_VMWARE];
     364             : 
     365           0 :         printf("\n");
     366           0 :         sc->sc_rpc_buf = malloc(VMT_RPC_BUFLEN, M_DEVBUF, M_NOWAIT);
     367           0 :         if (sc->sc_rpc_buf == NULL) {
     368           0 :                 printf("%s: unable to allocate buffer for RPC\n",
     369           0 :                     DEVNAME(sc));
     370           0 :                 return;
     371             :         }
     372             : 
     373           0 :         if (vm_rpc_open(&sc->sc_tclo_rpc, VM_RPC_OPEN_TCLO) != 0) {
     374           0 :                 printf("%s: failed to open backdoor RPC channel "
     375           0 :                     "(TCLO protocol)\n", DEVNAME(sc));
     376           0 :                 goto free;
     377             :         }
     378             : 
     379             :         /* don't know if this is important at all yet */
     380           0 :         if (vm_rpc_send_rpci_tx(sc,
     381           0 :             "tools.capability.hgfs_server toolbox 1") != 0) {
     382           0 :                 printf(": failed to set HGFS server capability\n");
     383           0 :                 goto free;
     384             :         }
     385             : 
     386           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
     387             :             sizeof(sc->sc_sensordev.xname));
     388             : 
     389           0 :         sc->sc_sensor.type = SENSOR_TIMEDELTA;
     390           0 :         sc->sc_sensor.status = SENSOR_S_UNKNOWN;
     391             : 
     392           0 :         sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
     393           0 :         sensordev_install(&sc->sc_sensordev);
     394             : 
     395           0 :         config_mountroot(self, vmt_tick_hook);
     396             : 
     397           0 :         timeout_set(&sc->sc_tclo_tick, vmt_tclo_tick, sc);
     398           0 :         timeout_add_sec(&sc->sc_tclo_tick, 1);
     399           0 :         sc->sc_tclo_ping = 1;
     400             : 
     401             :         /* pvbus(4) key/value interface */
     402           0 :         hv->hv_kvop = vmt_kvop;
     403           0 :         hv->hv_arg = sc;
     404             : 
     405           0 :         return;
     406             : 
     407             : free:
     408           0 :         free(sc->sc_rpc_buf, M_DEVBUF, VMT_RPC_BUFLEN);
     409           0 : }
     410             : 
     411             : int
     412           0 : vmt_kvop(void *arg, int op, char *key, char *value, size_t valuelen)
     413             : {
     414           0 :         struct vmt_softc *sc = arg;
     415             :         char *buf = NULL, *ptr;
     416             :         size_t bufsz;
     417             :         int error = 0;
     418             : 
     419             :         bufsz = VMT_RPC_BUFLEN;
     420           0 :         buf = malloc(bufsz, M_TEMP|M_ZERO, M_WAITOK);
     421             : 
     422           0 :         switch (op) {
     423             :         case PVBUS_KVWRITE:
     424           0 :                 if ((size_t)snprintf(buf, bufsz, "info-set %s %s",
     425           0 :                     key, value) >= bufsz) {
     426             :                         DPRINTF("%s: write command too long", DEVNAME(sc));
     427             :                         error = EINVAL;
     428           0 :                         goto done;
     429             :                 }
     430             :                 break;
     431             :         case PVBUS_KVREAD:
     432           0 :                 if ((size_t)snprintf(buf, bufsz, "info-get %s",
     433           0 :                     key) >= bufsz) {
     434             :                         DPRINTF("%s: read command too long", DEVNAME(sc));
     435             :                         error = EINVAL;
     436           0 :                         goto done;
     437             :                 }
     438             :                 break;
     439             :         default:
     440             :                 error = EOPNOTSUPP;
     441           0 :                 goto done;
     442             :         }
     443             : 
     444           0 :         if (vm_rpc_send_rpci_tx(sc, "%s", buf) != 0) {
     445             :                 DPRINTF("%s: error sending command: %s\n", DEVNAME(sc), buf);
     446           0 :                 sc->sc_rpc_error = 1;
     447             :                 error = EIO;
     448           0 :                 goto done;
     449             :         }
     450             : 
     451           0 :         if (vm_rpci_response_successful(sc) == 0) {
     452             :                 DPRINTF("%s: host rejected command: %s\n", DEVNAME(sc), buf);
     453             :                 error = EINVAL;
     454           0 :                 goto done;
     455             :         }
     456             : 
     457             :         /* skip response that was tested in vm_rpci_response_successful() */
     458           0 :         ptr = sc->sc_rpc_buf + 2;
     459             : 
     460             :         /* might truncat, copy anyway but return error */
     461           0 :         if (strlcpy(value, ptr, valuelen) >= valuelen)
     462           0 :                 error = ENOMEM;
     463             : 
     464             :  done:
     465           0 :         free(buf, M_TEMP, bufsz);
     466           0 :         return (error);
     467             : }
     468             : 
     469             : void
     470           0 : vmt_resume(void)
     471             : {
     472           0 :         struct vm_backdoor frame;
     473             :         extern void rdrand(void *);
     474             : 
     475           0 :         bzero(&frame, sizeof(frame));
     476           0 :         frame.eax.word = VM_MAGIC;
     477           0 :         frame.ecx.part.low = VM_CMD_GET_TIME_FULL;
     478           0 :         frame.edx.part.low  = VM_PORT_CMD;
     479           0 :         vm_cmd(&frame);
     480             : 
     481           0 :         rdrand(NULL);
     482           0 :         enqueue_randomness(frame.eax.word);
     483           0 :         enqueue_randomness(frame.esi.word);
     484           0 :         enqueue_randomness(frame.edx.word);
     485           0 :         enqueue_randomness(frame.ebx.word);
     486           0 :         resume_randomness(NULL, 0);
     487           0 : }
     488             : 
     489             : int
     490           0 : vmt_activate(struct device *self, int act)
     491             : {
     492             :         int rv = 0;
     493             : 
     494           0 :         switch (act) {
     495             :         case DVACT_POWERDOWN:
     496           0 :                 vmt_shutdown(self);
     497           0 :                 break;
     498             :         case DVACT_RESUME:
     499           0 :                 vmt_resume();
     500           0 :                 break;
     501             :         }
     502           0 :         return (rv);
     503             : }
     504             : 
     505             : 
     506             : void
     507           0 : vmt_update_guest_uptime(struct vmt_softc *sc)
     508             : {
     509             :         /* host wants uptime in hundredths of a second */
     510           0 :         if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo  %d %lld00",
     511           0 :             VM_GUEST_INFO_UPTIME, (long long)time_uptime) != 0) {
     512             :                 DPRINTF("%s: unable to set guest uptime", DEVNAME(sc));
     513           0 :                 sc->sc_rpc_error = 1;
     514           0 :         }
     515           0 : }
     516             : 
     517             : void
     518           0 : vmt_update_guest_info(struct vmt_softc *sc)
     519             : {
     520           0 :         if (strncmp(sc->sc_hostname, hostname, sizeof(sc->sc_hostname)) != 0) {
     521           0 :                 strlcpy(sc->sc_hostname, hostname, sizeof(sc->sc_hostname));
     522             : 
     523           0 :                 if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo  %d %s",
     524           0 :                     VM_GUEST_INFO_DNS_NAME, sc->sc_hostname) != 0) {
     525             :                         DPRINTF("%s: unable to set hostname", DEVNAME(sc));
     526           0 :                         sc->sc_rpc_error = 1;
     527           0 :                 }
     528             :         }
     529             : 
     530             :         /*
     531             :          * We're supposed to pass the full network address information back
     532             :          * here, but that involves xdr (sunrpc) data encoding, which seems a
     533             :          * bit unreasonable.
     534             :          */
     535             : 
     536           0 :         if (sc->sc_set_guest_os == 0) {
     537           0 :                 if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo  %d %s %s %s",
     538             :                     VM_GUEST_INFO_OS_NAME_FULL,
     539           0 :                     ostype, osrelease, osversion) != 0) {
     540             :                         DPRINTF("%s: unable to set full guest OS", DEVNAME(sc));
     541           0 :                         sc->sc_rpc_error = 1;
     542           0 :                 }
     543             : 
     544             :                 /*
     545             :                  * Host doesn't like it if we send an OS name it doesn't
     546             :                  * recognise, so use the closest match, which happens
     547             :                  * to be FreeBSD.
     548             :                  */
     549             : 
     550           0 :                 if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo  %d %s",
     551           0 :                     VM_GUEST_INFO_OS_NAME, "FreeBSD") != 0) {
     552             :                         DPRINTF("%s: unable to set guest OS", DEVNAME(sc));
     553           0 :                         sc->sc_rpc_error = 1;
     554           0 :                 }
     555             : 
     556           0 :                 sc->sc_set_guest_os = 1;
     557           0 :         }
     558           0 : }
     559             : 
     560             : void
     561           0 : vmt_tick_hook(struct device *self)
     562             : {
     563           0 :         struct vmt_softc *sc = (struct vmt_softc *)self;
     564             : 
     565           0 :         timeout_set(&sc->sc_tick, vmt_tick, sc);
     566           0 :         vmt_tick(sc);
     567           0 : }
     568             : 
     569             : void
     570           0 : vmt_tick(void *xarg)
     571             : {
     572           0 :         struct vmt_softc *sc = xarg;
     573           0 :         struct vm_backdoor frame;
     574           0 :         struct timeval *guest = &sc->sc_sensor.tv;
     575             :         struct timeval host, diff;
     576             : 
     577           0 :         microtime(guest);
     578             : 
     579           0 :         bzero(&frame, sizeof(frame));
     580           0 :         frame.eax.word = VM_MAGIC;
     581           0 :         frame.ecx.part.low = VM_CMD_GET_TIME_FULL;
     582           0 :         frame.edx.part.low  = VM_PORT_CMD;
     583           0 :         vm_cmd(&frame);
     584             : 
     585           0 :         if (frame.eax.word != 0xffffffff) {
     586           0 :                 host.tv_sec = ((uint64_t)frame.esi.word << 32) | frame.edx.word;
     587           0 :                 host.tv_usec = frame.ebx.word;
     588             : 
     589           0 :                 timersub(guest, &host, &diff);
     590             : 
     591           0 :                 sc->sc_sensor.value = (u_int64_t)diff.tv_sec * 1000000000LL +
     592           0 :                     (u_int64_t)diff.tv_usec * 1000LL;
     593           0 :                 sc->sc_sensor.status = SENSOR_S_OK;
     594           0 :         } else {
     595           0 :                 sc->sc_sensor.status = SENSOR_S_UNKNOWN;
     596             :         }
     597             : 
     598           0 :         vmt_update_guest_info(sc);
     599           0 :         vmt_update_guest_uptime(sc);
     600             : 
     601           0 :         timeout_add_sec(&sc->sc_tick, 15);
     602           0 : }
     603             : 
     604             : void
     605           0 : vmt_tclo_state_change_success(struct vmt_softc *sc, int success, char state)
     606             : {
     607           0 :         if (vm_rpc_send_rpci_tx(sc, "tools.os.statechange.status %d %d",
     608           0 :             success, state) != 0) {
     609             :                 DPRINTF("%s: unable to send state change result\n",
     610             :                     DEVNAME(sc));
     611           0 :                 sc->sc_rpc_error = 1;
     612           0 :         }
     613           0 : }
     614             : 
     615             : void
     616           0 : vmt_do_shutdown(struct vmt_softc *sc)
     617             : {
     618           0 :         vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_HALT);
     619           0 :         vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK);
     620           0 :         pvbus_shutdown(&sc->sc_dev);
     621           0 : }
     622             : 
     623             : void
     624           0 : vmt_do_reboot(struct vmt_softc *sc)
     625             : {
     626           0 :         vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_REBOOT);
     627           0 :         vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK);
     628           0 :         pvbus_reboot(&sc->sc_dev);
     629           0 : }
     630             : 
     631             : void
     632           0 : vmt_shutdown(void *arg)
     633             : {
     634           0 :         struct vmt_softc *sc = arg;
     635             : 
     636           0 :         if (vm_rpc_send_rpci_tx(sc,
     637             :             "tools.capability.hgfs_server toolbox 0") != 0) {
     638             :                 DPRINTF("%s: failed to disable hgfs server capability\n",
     639             :                     DEVNAME(sc));
     640             :         }
     641             : 
     642           0 :         if (vm_rpc_send(&sc->sc_tclo_rpc, NULL, 0) != 0) {
     643             :                 DPRINTF("%s: failed to send shutdown ping\n", DEVNAME(sc));
     644             :         }
     645             : 
     646           0 :         vm_rpc_close(&sc->sc_tclo_rpc);
     647           0 : }
     648             : 
     649             : void
     650           0 : vmt_tclo_reset(struct vmt_softc *sc)
     651             : {
     652           0 :         if (sc->sc_rpc_error != 0) {
     653             :                 DPRINTF("%s: resetting rpc\n", DEVNAME(sc));
     654           0 :                 vm_rpc_close(&sc->sc_tclo_rpc);
     655             : 
     656             :                 /* reopen and send the reset reply next time around */
     657           0 :                 sc->sc_rpc_error = 1;
     658           0 :                 return;
     659             :         }
     660             : 
     661           0 :         if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_RESET_REPLY) != 0) {
     662             :                 DPRINTF("%s: failed to send reset reply\n", DEVNAME(sc));
     663           0 :                 sc->sc_rpc_error = 1;
     664           0 :         }
     665           0 : }
     666             : 
     667             : void
     668           0 : vmt_tclo_ping(struct vmt_softc *sc)
     669             : {
     670           0 :         vmt_update_guest_info(sc);
     671             : 
     672           0 :         if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
     673             :                 DPRINTF("%s: error sending ping response\n", DEVNAME(sc));
     674           0 :                 sc->sc_rpc_error = 1;
     675           0 :         }
     676           0 : }
     677             : 
     678             : void
     679           0 : vmt_tclo_halt(struct vmt_softc *sc)
     680             : {
     681           0 :         vmt_do_shutdown(sc);
     682           0 : }
     683             : 
     684             : void
     685           0 : vmt_tclo_reboot(struct vmt_softc *sc)
     686             : {
     687           0 :         vmt_do_reboot(sc);
     688           0 : }
     689             : 
     690             : void
     691           0 : vmt_tclo_poweron(struct vmt_softc *sc)
     692             : {
     693           0 :         vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_POWERON);
     694             : 
     695           0 :         if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
     696             :                 DPRINTF("%s: error sending poweron response\n", DEVNAME(sc));
     697           0 :                 sc->sc_rpc_error = 1;
     698           0 :         }
     699           0 : }
     700             : 
     701             : void
     702           0 : vmt_tclo_suspend(struct vmt_softc *sc)
     703             : {
     704           0 :         log(LOG_KERN | LOG_NOTICE,
     705             :             "VMware guest entering suspended state\n");
     706             : 
     707           0 :         suspend_randomness();
     708             : 
     709           0 :         vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_SUSPEND);
     710           0 :         if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
     711             :                 DPRINTF("%s: error sending suspend response\n", DEVNAME(sc));
     712           0 :                 sc->sc_rpc_error = 1;
     713           0 :         }
     714           0 : }
     715             : 
     716             : void
     717           0 : vmt_tclo_resume(struct vmt_softc *sc)
     718             : {
     719           0 :         log(LOG_KERN | LOG_NOTICE,
     720             :             "VMware guest resuming from suspended state\n");
     721             : 
     722             :         /* force guest info update */
     723           0 :         sc->sc_hostname[0] = '\0';
     724           0 :         sc->sc_set_guest_os = 0;
     725           0 :         vmt_update_guest_info(sc);
     726           0 :         vmt_resume();
     727             : 
     728           0 :         vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_RESUME);
     729           0 :         if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
     730             :                 DPRINTF("%s: error sending resume response\n", DEVNAME(sc));
     731           0 :                 sc->sc_rpc_error = 1;
     732           0 :         }
     733           0 : }
     734             : 
     735             : void
     736           0 : vmt_tclo_capreg(struct vmt_softc *sc)
     737             : {
     738             :         /* don't know if this is important at all */
     739           0 :         if (vm_rpc_send_rpci_tx(sc,
     740           0 :             "vmx.capability.unified_loop toolbox") != 0) {
     741             :                 DPRINTF("%s: unable to set unified loop\n", DEVNAME(sc));
     742           0 :                 sc->sc_rpc_error = 1;
     743           0 :         }
     744             : 
     745           0 :         if (vm_rpci_response_successful(sc) == 0) {
     746             :                 DPRINTF("%s: host rejected unified loop setting\n",
     747             :                     DEVNAME(sc));
     748             :         }
     749             : 
     750             :         /* the trailing space is apparently important here */
     751           0 :         if (vm_rpc_send_rpci_tx(sc,
     752           0 :             "tools.capability.statechange ") != 0) {
     753             :                 DPRINTF("%s: unable to send statechange capability\n",
     754             :                     DEVNAME(sc));
     755           0 :                 sc->sc_rpc_error = 1;
     756           0 :         }
     757             : 
     758           0 :         if (vm_rpci_response_successful(sc) == 0) {
     759             :                 DPRINTF("%s: host rejected statechange capability\n",
     760             :                     DEVNAME(sc));
     761             :         }
     762             : 
     763           0 :         if (vm_rpc_send_rpci_tx(sc, "tools.set.version %u",
     764           0 :             VM_VERSION_UNMANAGED) != 0) {
     765             :                 DPRINTF("%s: unable to set tools version\n",
     766             :                     DEVNAME(sc));
     767           0 :                 sc->sc_rpc_error = 1;
     768           0 :         }
     769             : 
     770           0 :         vmt_update_guest_uptime(sc);
     771             : 
     772           0 :         if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
     773             :                 DPRINTF("%s: error sending capabilities_register"
     774             :                     " response\n", DEVNAME(sc));
     775           0 :                 sc->sc_rpc_error = 1;
     776           0 :         }
     777           0 : }
     778             : 
     779             : void
     780           0 : vmt_tclo_broadcastip(struct vmt_softc *sc)
     781             : {
     782             :         struct ifnet *iface;
     783             :         struct sockaddr_in *guest_ip;
     784             : 
     785             :         /* find first available ipv4 address */
     786             :         guest_ip = NULL;
     787           0 :         TAILQ_FOREACH(iface, &ifnet, if_list) {
     788             :                 struct ifaddr *iface_addr;
     789             : 
     790             :                 /* skip loopback */
     791           0 :                 if (strncmp(iface->if_xname, "lo", 2) == 0 &&
     792           0 :                     iface->if_xname[2] >= '0' &&
     793           0 :                     iface->if_xname[2] <= '9') {
     794           0 :                         continue;
     795             :                 }
     796             : 
     797           0 :                 TAILQ_FOREACH(iface_addr, &iface->if_addrlist,
     798             :                     ifa_list) {
     799           0 :                         if (iface_addr->ifa_addr->sa_family != AF_INET)
     800             :                                 continue;
     801             : 
     802           0 :                         guest_ip = satosin(iface_addr->ifa_addr);
     803           0 :                         break;
     804             :                 }
     805           0 :         }
     806             : 
     807           0 :         if (guest_ip != NULL) {
     808           0 :                 char ip[INET_ADDRSTRLEN];
     809             : 
     810           0 :                 inet_ntop(AF_INET, &guest_ip->sin_addr, ip, sizeof(ip));
     811           0 :                 if (vm_rpc_send_rpci_tx(sc, "info-set guestinfo.ip %s",
     812           0 :                     ip) != 0) {
     813             :                         DPRINTF("%s: unable to send guest IP address\n",
     814             :                             DEVNAME(sc));
     815           0 :                         sc->sc_rpc_error = 1;
     816           0 :                 }
     817             : 
     818           0 :                 if (vm_rpc_send_str(&sc->sc_tclo_rpc,
     819           0 :                     VM_RPC_REPLY_OK) != 0) {
     820             :                         DPRINTF("%s: error sending broadcastIP"
     821             :                             " response\n", DEVNAME(sc));
     822           0 :                         sc->sc_rpc_error = 1;
     823           0 :                 }
     824           0 :         } else {
     825           0 :                 if (vm_rpc_send_str(&sc->sc_tclo_rpc,
     826           0 :                     VM_RPC_REPLY_ERROR_IP_ADDR) != 0) {
     827             :                         DPRINTF("%s: error sending broadcastIP"
     828             :                             " error response\n", DEVNAME(sc));
     829           0 :                         sc->sc_rpc_error = 1;
     830           0 :                 }
     831             :         }
     832           0 : }
     833             : 
     834             : void
     835           0 : vmt_set_backup_status(struct vmt_softc *sc, const char *state, int code,
     836             :     const char *desc)
     837             : {
     838           0 :         if (vm_rpc_send_rpci_tx(sc, "vmbackup.eventSet %s %d %s",
     839             :             state, code, desc) != 0) {
     840             :                 DPRINTF("%s: setting backup status failed\n", DEVNAME(sc));
     841             :         }
     842           0 : }
     843             : 
     844             : void
     845           0 : vmt_quiesce_task(void *data)
     846             : {
     847           0 :         struct vmt_softc *sc = data;
     848             :         int err;
     849             : 
     850             :         DPRINTF("%s: quiescing filesystems for backup\n", DEVNAME(sc));
     851           0 :         err = vfs_stall(curproc, 1);
     852           0 :         if (err != 0) {
     853           0 :                 printf("%s: unable to quiesce filesystems\n", DEVNAME(sc));
     854           0 :                 vfs_stall(curproc, 0);
     855             : 
     856           0 :                 vmt_set_backup_status(sc, "req.aborted", VM_BACKUP_SYNC_ERROR,
     857             :                     "vfs_stall failed");
     858           0 :                 vmt_set_backup_status(sc, "req.done", VM_BACKUP_SUCCESS, "");
     859           0 :                 sc->sc_quiesce = 0;
     860           0 :                 return;
     861             :         }
     862             : 
     863             :         DPRINTF("%s: filesystems quiesced\n", DEVNAME(sc));
     864           0 :         vmt_set_backup_status(sc, "prov.snapshotCommit", VM_BACKUP_SUCCESS, "");
     865           0 : }
     866             : 
     867             : void
     868           0 : vmt_quiesce_done_task(void *data)
     869             : {
     870           0 :         struct vmt_softc *sc = data;
     871             : 
     872           0 :         vfs_stall(curproc, 0);
     873             : 
     874           0 :         if (sc->sc_quiesce == -1)
     875           0 :                 vmt_set_backup_status(sc, "req.aborted", VM_BACKUP_REMOTE_ABORT,
     876             :                     "");
     877             : 
     878           0 :         vmt_set_backup_status(sc, "req.done", VM_BACKUP_SUCCESS, "");
     879           0 :         sc->sc_quiesce = 0;
     880           0 : }
     881             : 
     882             : void
     883           0 : vmt_tclo_abortbackup(struct vmt_softc *sc)
     884             : {
     885             :         const char *reply = VM_RPC_REPLY_OK;
     886             : 
     887           0 :         if (sc->sc_quiesce > 0) {
     888             :                 DPRINTF("%s: aborting backup\n", DEVNAME(sc));
     889           0 :                 sc->sc_quiesce = -1;
     890           0 :                 task_set(&sc->sc_quiesce_task, vmt_quiesce_done_task, sc);
     891           0 :                 task_add(systq, &sc->sc_quiesce_task);
     892           0 :         } else {
     893             :                 DPRINTF("%s: can't abort, no backup in progress\n",
     894             :                     DEVNAME(sc));
     895             :                 reply = VM_RPC_REPLY_ERROR;
     896             :         }
     897             : 
     898           0 :         if (vm_rpc_send_str(&sc->sc_tclo_rpc, reply) != 0) {
     899             :                 DPRINTF("%s: error sending vmbackup.abort reply\n",
     900             :                     DEVNAME(sc));
     901           0 :                 sc->sc_rpc_error = 1;
     902           0 :         }
     903           0 : }
     904             : 
     905             : void
     906           0 : vmt_tclo_startbackup(struct vmt_softc *sc)
     907             : {
     908             :         const char *reply = VM_RPC_REPLY_OK;
     909             : 
     910           0 :         if (sc->sc_quiesce == 0) {
     911             :                 DPRINTF("%s: starting quiesce\n", DEVNAME(sc));
     912           0 :                 vmt_set_backup_status(sc, "reset", VM_BACKUP_SUCCESS, "");
     913             : 
     914           0 :                 task_set(&sc->sc_quiesce_task, vmt_quiesce_task, sc);
     915           0 :                 task_add(systq, &sc->sc_quiesce_task);
     916           0 :                 sc->sc_quiesce = 1;
     917           0 :         } else {
     918             :                 DPRINTF("%s: can't start backup, already in progress\n",
     919             :                     DEVNAME(sc));
     920             :                 reply = VM_RPC_REPLY_ERROR;
     921             :         }
     922             : 
     923           0 :         if (vm_rpc_send_str(&sc->sc_tclo_rpc, reply) != 0) {
     924             :                 DPRINTF("%s: error sending vmbackup.start reply\n",
     925             :                     DEVNAME(sc));
     926           0 :                 sc->sc_rpc_error = 1;
     927           0 :         }
     928           0 : }
     929             : 
     930             : void
     931           0 : vmt_tclo_backupdone(struct vmt_softc *sc)
     932             : {
     933             :         const char *reply = VM_RPC_REPLY_OK;
     934           0 :         if (sc->sc_quiesce > 0) {
     935             :                 DPRINTF("%s: backup complete\n", DEVNAME(sc));
     936           0 :                 task_set(&sc->sc_quiesce_task, vmt_quiesce_done_task, sc);
     937           0 :                 task_add(systq, &sc->sc_quiesce_task);
     938           0 :         } else {
     939             :                 DPRINTF("%s: got backup complete, but not doing a backup\n",
     940             :                     DEVNAME(sc));
     941             :                 reply = VM_RPC_REPLY_ERROR;
     942             :         }
     943             : 
     944           0 :         if (vm_rpc_send_str(&sc->sc_tclo_rpc, reply) != 0) {
     945             :                 DPRINTF("%s: error sending vmbackup.snapshotDone reply\n",
     946             :                     DEVNAME(sc));
     947           0 :                 sc->sc_rpc_error = 1;
     948           0 :         }
     949           0 : }
     950             : 
     951             : int
     952           0 : vmt_tclo_process(struct vmt_softc *sc, const char *name)
     953             : {
     954             :         int i;
     955             : 
     956             :         /* Search for rpc command and call handler */
     957           0 :         for (i = 0; vmt_tclo_rpc[i].name != NULL; i++) {
     958           0 :                 if (strcmp(vmt_tclo_rpc[i].name, sc->sc_rpc_buf) == 0) {
     959           0 :                         vmt_tclo_rpc[i].cb(sc);
     960           0 :                         return (0);
     961             :                 }
     962             :         }
     963             : 
     964             :         DPRINTF("%s: unknown command: \"%s\"\n", DEVNAME(sc), name);
     965             : 
     966           0 :         return (-1);
     967           0 : }
     968             : 
     969             : void
     970           0 : vmt_tclo_tick(void *xarg)
     971             : {
     972           0 :         struct vmt_softc *sc = xarg;
     973           0 :         u_int32_t rlen;
     974           0 :         u_int16_t ack;
     975             :         int delay;
     976             : 
     977             :         /* By default, poll every second for new messages */
     978             :         delay = 1;
     979             : 
     980           0 :         if (sc->sc_quiesce > 0) {
     981             :                 /* abort quiesce if it's taking too long */
     982           0 :                 if (sc->sc_quiesce++ == VM_BACKUP_TIMEOUT) {
     983           0 :                         printf("%s: aborting quiesce\n", DEVNAME(sc));
     984           0 :                         sc->sc_quiesce = -1;
     985           0 :                         task_set(&sc->sc_quiesce_task, vmt_quiesce_done_task,
     986             :                             sc);
     987           0 :                         task_add(systq, &sc->sc_quiesce_task);
     988           0 :                 } else
     989           0 :                         vmt_set_backup_status(sc, "req.keepAlive",
     990             :                             VM_BACKUP_SUCCESS, "");
     991             :         }
     992             : 
     993             :         /* reopen tclo channel if it's currently closed */
     994           0 :         if (sc->sc_tclo_rpc.channel == 0 &&
     995           0 :             sc->sc_tclo_rpc.cookie1 == 0 &&
     996           0 :             sc->sc_tclo_rpc.cookie2 == 0) {
     997           0 :                 if (vm_rpc_open(&sc->sc_tclo_rpc, VM_RPC_OPEN_TCLO) != 0) {
     998             :                         DPRINTF("%s: unable to reopen TCLO channel\n",
     999             :                             DEVNAME(sc));
    1000             :                         delay = 15;
    1001           0 :                         goto out;
    1002             :                 }
    1003             : 
    1004           0 :                 if (vm_rpc_send_str(&sc->sc_tclo_rpc,
    1005           0 :                     VM_RPC_RESET_REPLY) != 0) {
    1006             :                         DPRINTF("%s: failed to send reset reply\n",
    1007             :                             DEVNAME(sc));
    1008           0 :                         sc->sc_rpc_error = 1;
    1009           0 :                         goto out;
    1010             :                 } else {
    1011           0 :                         sc->sc_rpc_error = 0;
    1012             :                 }
    1013           0 :         }
    1014             : 
    1015           0 :         if (sc->sc_tclo_ping) {
    1016           0 :                 if (vm_rpc_send(&sc->sc_tclo_rpc, NULL, 0) != 0) {
    1017             :                         DPRINTF("%s: failed to send TCLO outgoing ping\n",
    1018             :                             DEVNAME(sc));
    1019           0 :                         sc->sc_rpc_error = 1;
    1020           0 :                         goto out;
    1021             :                 }
    1022             :         }
    1023             : 
    1024           0 :         if (vm_rpc_get_length(&sc->sc_tclo_rpc, &rlen, &ack) != 0) {
    1025             :                 DPRINTF("%s: failed to get length of incoming TCLO data\n",
    1026             :                     DEVNAME(sc));
    1027           0 :                 sc->sc_rpc_error = 1;
    1028           0 :                 goto out;
    1029             :         }
    1030             : 
    1031           0 :         if (rlen == 0) {
    1032           0 :                 sc->sc_tclo_ping = 1;
    1033           0 :                 goto out;
    1034             :         }
    1035             : 
    1036           0 :         if (rlen >= VMT_RPC_BUFLEN) {
    1037           0 :                 rlen = VMT_RPC_BUFLEN - 1;
    1038           0 :         }
    1039           0 :         if (vm_rpc_get_data(&sc->sc_tclo_rpc, sc->sc_rpc_buf, rlen, ack) != 0) {
    1040             :                 DPRINTF("%s: failed to get incoming TCLO data\n", DEVNAME(sc));
    1041           0 :                 sc->sc_rpc_error = 1;
    1042           0 :                 goto out;
    1043             :         }
    1044           0 :         sc->sc_tclo_ping = 0;
    1045             : 
    1046             :         /* The VM host can queue multiple messages; continue without delay */
    1047             :         delay = 0;
    1048             : 
    1049           0 :         if (vmt_tclo_process(sc, sc->sc_rpc_buf) != 0) {
    1050           0 :                 if (vm_rpc_send_str(&sc->sc_tclo_rpc,
    1051           0 :                     VM_RPC_REPLY_ERROR) != 0) {
    1052             :                         DPRINTF("%s: error sending unknown command reply\n",
    1053             :                             DEVNAME(sc));
    1054           0 :                         sc->sc_rpc_error = 1;
    1055           0 :                 }
    1056             :         }
    1057             : 
    1058           0 :         if (sc->sc_rpc_error == 1) {
    1059             :                 /* On error, give time to recover and wait a second */
    1060             :                 delay = 1;
    1061           0 :         }
    1062             : 
    1063             : out:
    1064           0 :         timeout_add_sec(&sc->sc_tclo_tick, delay);
    1065           0 : }
    1066             : 
    1067             : #define BACKDOOR_OP_I386(op, frame)             \
    1068             :         __asm__ volatile (                      \
    1069             :                 "pushal;"                     \
    1070             :                 "pushl %%eax;"                        \
    1071             :                 "movl 0x18(%%eax), %%ebp;"    \
    1072             :                 "movl 0x14(%%eax), %%edi;"    \
    1073             :                 "movl 0x10(%%eax), %%esi;"    \
    1074             :                 "movl 0x0c(%%eax), %%edx;"    \
    1075             :                 "movl 0x08(%%eax), %%ecx;"    \
    1076             :                 "movl 0x04(%%eax), %%ebx;"    \
    1077             :                 "movl 0x00(%%eax), %%eax;"    \
    1078             :                 op                              \
    1079             :                 "xchgl %%eax, 0x00(%%esp);"   \
    1080             :                 "movl %%ebp, 0x18(%%eax);"    \
    1081             :                 "movl %%edi, 0x14(%%eax);"    \
    1082             :                 "movl %%esi, 0x10(%%eax);"    \
    1083             :                 "movl %%edx, 0x0c(%%eax);"    \
    1084             :                 "movl %%ecx, 0x08(%%eax);"    \
    1085             :                 "movl %%ebx, 0x04(%%eax);"    \
    1086             :                 "popl 0x00(%%eax);"           \
    1087             :                 "popal;"                      \
    1088             :                 ::"a"(frame)                  \
    1089             :         )
    1090             : 
    1091             : #define BACKDOOR_OP_AMD64(op, frame)            \
    1092             :         __asm__ volatile (                      \
    1093             :                 "pushq %%rbp;                      \n\t" \
    1094             :                 "pushq %%rax;                      \n\t" \
    1095             :                 "movq 0x30(%%rax), %%rbp;  \n\t" \
    1096             :                 "movq 0x28(%%rax), %%rdi;  \n\t" \
    1097             :                 "movq 0x20(%%rax), %%rsi;  \n\t" \
    1098             :                 "movq 0x18(%%rax), %%rdx;  \n\t" \
    1099             :                 "movq 0x10(%%rax), %%rcx;  \n\t" \
    1100             :                 "movq 0x08(%%rax), %%rbx;  \n\t" \
    1101             :                 "movq 0x00(%%rax), %%rax;  \n\t" \
    1102             :                 op                              "\n\t" \
    1103             :                 "xchgq %%rax, 0x00(%%rsp); \n\t" \
    1104             :                 "movq %%rbp, 0x30(%%rax);  \n\t" \
    1105             :                 "movq %%rdi, 0x28(%%rax);  \n\t" \
    1106             :                 "movq %%rsi, 0x20(%%rax);  \n\t" \
    1107             :                 "movq %%rdx, 0x18(%%rax);  \n\t" \
    1108             :                 "movq %%rcx, 0x10(%%rax);  \n\t" \
    1109             :                 "movq %%rbx, 0x08(%%rax);  \n\t" \
    1110             :                 "popq 0x00(%%rax);         \n\t" \
    1111             :                 "popq %%rbp;                       \n\t" \
    1112             :                 : /* No outputs. */ : "a" (frame) \
    1113             :                   /* No pushal on amd64 so warn gcc about the clobbered registers. */ \
    1114             :                 : "rbx", "rcx", "rdx", "rdi", "rsi", "cc", "memory" \
    1115             :         )
    1116             : 
    1117             : 
    1118             : #ifdef __i386__
    1119             : #define BACKDOOR_OP(op, frame) BACKDOOR_OP_I386(op, frame)
    1120             : #else
    1121             : #define BACKDOOR_OP(op, frame) BACKDOOR_OP_AMD64(op, frame)
    1122             : #endif
    1123             : 
    1124             : void
    1125           0 : vm_cmd(struct vm_backdoor *frame)
    1126             : {
    1127           0 :         BACKDOOR_OP("inl %%dx, %%eax;", frame);
    1128           0 : }
    1129             : 
    1130             : void
    1131           0 : vm_ins(struct vm_backdoor *frame)
    1132             : {
    1133           0 :         BACKDOOR_OP("cld;\n\trep insb;", frame);
    1134           0 : }
    1135             : 
    1136             : void
    1137           0 : vm_outs(struct vm_backdoor *frame)
    1138             : {
    1139           0 :         BACKDOOR_OP("cld;\n\trep outsb;", frame);
    1140           0 : }
    1141             : 
    1142             : int
    1143           0 : vm_rpc_open(struct vm_rpc *rpc, uint32_t proto)
    1144             : {
    1145           0 :         struct vm_backdoor frame;
    1146             : 
    1147           0 :         bzero(&frame, sizeof(frame));
    1148           0 :         frame.eax.word      = VM_MAGIC;
    1149           0 :         frame.ebx.word      = proto | VM_RPC_FLAG_COOKIE;
    1150           0 :         frame.ecx.part.low  = VM_CMD_RPC;
    1151           0 :         frame.ecx.part.high = VM_RPC_OPEN;
    1152           0 :         frame.edx.part.low  = VM_PORT_CMD;
    1153           0 :         frame.edx.part.high = 0;
    1154             : 
    1155           0 :         vm_cmd(&frame);
    1156             : 
    1157           0 :         if (frame.ecx.part.high != 1 || frame.edx.part.low != 0) {
    1158             :                 /* open-vm-tools retries without VM_RPC_FLAG_COOKIE here.. */
    1159             :                 DPRINTF("vmware: open failed, eax=%08x, ecx=%08x, edx=%08x\n",
    1160             :                     frame.eax.word, frame.ecx.word, frame.edx.word);
    1161           0 :                 return EIO;
    1162             :         }
    1163             : 
    1164           0 :         rpc->channel = frame.edx.part.high;
    1165           0 :         rpc->cookie1 = frame.esi.word;
    1166           0 :         rpc->cookie2 = frame.edi.word;
    1167             : 
    1168           0 :         return 0;
    1169           0 : }
    1170             : 
    1171             : int
    1172           0 : vm_rpc_close(struct vm_rpc *rpc)
    1173             : {
    1174           0 :         struct vm_backdoor frame;
    1175             : 
    1176           0 :         bzero(&frame, sizeof(frame));
    1177           0 :         frame.eax.word      = VM_MAGIC;
    1178           0 :         frame.ebx.word      = 0;
    1179           0 :         frame.ecx.part.low  = VM_CMD_RPC;
    1180           0 :         frame.ecx.part.high = VM_RPC_CLOSE;
    1181           0 :         frame.edx.part.low  = VM_PORT_CMD;
    1182           0 :         frame.edx.part.high = rpc->channel;
    1183           0 :         frame.edi.word      = rpc->cookie2;
    1184           0 :         frame.esi.word      = rpc->cookie1;
    1185             : 
    1186           0 :         vm_cmd(&frame);
    1187             : 
    1188           0 :         if (frame.ecx.part.high == 0 || frame.ecx.part.low != 0) {
    1189             :                 DPRINTF("vmware: close failed, eax=%08x, ecx=%08x\n",
    1190             :                     frame.eax.word, frame.ecx.word);
    1191           0 :                 return EIO;
    1192             :         }
    1193             : 
    1194           0 :         rpc->channel = 0;
    1195           0 :         rpc->cookie1 = 0;
    1196           0 :         rpc->cookie2 = 0;
    1197             : 
    1198           0 :         return 0;
    1199           0 : }
    1200             : 
    1201             : int
    1202           0 : vm_rpc_send(const struct vm_rpc *rpc, const uint8_t *buf, uint32_t length)
    1203             : {
    1204           0 :         struct vm_backdoor frame;
    1205             : 
    1206             :         /* Send the length of the command. */
    1207           0 :         bzero(&frame, sizeof(frame));
    1208           0 :         frame.eax.word = VM_MAGIC;
    1209           0 :         frame.ebx.word = length;
    1210           0 :         frame.ecx.part.low  = VM_CMD_RPC;
    1211           0 :         frame.ecx.part.high = VM_RPC_SET_LENGTH;
    1212           0 :         frame.edx.part.low  = VM_PORT_CMD;
    1213           0 :         frame.edx.part.high = rpc->channel;
    1214           0 :         frame.esi.word = rpc->cookie1;
    1215           0 :         frame.edi.word = rpc->cookie2;
    1216             : 
    1217           0 :         vm_cmd(&frame);
    1218             : 
    1219           0 :         if ((frame.ecx.part.high & VM_RPC_REPLY_SUCCESS) == 0) {
    1220             :                 DPRINTF("vmware: sending length failed, eax=%08x, ecx=%08x\n",
    1221             :                     frame.eax.word, frame.ecx.word);
    1222           0 :                 return EIO;
    1223             :         }
    1224             : 
    1225           0 :         if (length == 0)
    1226           0 :                 return 0; /* Only need to poke once if command is null. */
    1227             : 
    1228             :         /* Send the command using enhanced RPC. */
    1229           0 :         bzero(&frame, sizeof(frame));
    1230           0 :         frame.eax.word = VM_MAGIC;
    1231           0 :         frame.ebx.word = VM_RPC_ENH_DATA;
    1232           0 :         frame.ecx.word = length;
    1233           0 :         frame.edx.part.low  = VM_PORT_RPC;
    1234           0 :         frame.edx.part.high = rpc->channel;
    1235           0 :         frame.ebp.word = rpc->cookie1;
    1236           0 :         frame.edi.word = rpc->cookie2;
    1237             : #ifdef __amd64__
    1238           0 :         frame.esi.quad = (uint64_t)buf;
    1239             : #else
    1240             :         frame.esi.word = (uint32_t)buf;
    1241             : #endif
    1242             : 
    1243           0 :         vm_outs(&frame);
    1244             : 
    1245           0 :         if (frame.ebx.word != VM_RPC_ENH_DATA) {
    1246             :                 /* open-vm-tools retries on VM_RPC_REPLY_CHECKPOINT */
    1247             :                 DPRINTF("vmware: send failed, ebx=%08x\n", frame.ebx.word);
    1248           0 :                 return EIO;
    1249             :         }
    1250             : 
    1251           0 :         return 0;
    1252           0 : }
    1253             : 
    1254             : int
    1255           0 : vm_rpc_send_str(const struct vm_rpc *rpc, const uint8_t *str)
    1256             : {
    1257           0 :         return vm_rpc_send(rpc, str, strlen(str));
    1258             : }
    1259             : 
    1260             : int
    1261           0 : vm_rpc_get_data(const struct vm_rpc *rpc, char *data, uint32_t length,
    1262             :     uint16_t dataid)
    1263             : {
    1264           0 :         struct vm_backdoor frame;
    1265             : 
    1266             :         /* Get data using enhanced RPC. */
    1267           0 :         bzero(&frame, sizeof(frame));
    1268           0 :         frame.eax.word      = VM_MAGIC;
    1269           0 :         frame.ebx.word      = VM_RPC_ENH_DATA;
    1270           0 :         frame.ecx.word      = length;
    1271           0 :         frame.edx.part.low  = VM_PORT_RPC;
    1272           0 :         frame.edx.part.high = rpc->channel;
    1273           0 :         frame.esi.word      = rpc->cookie1;
    1274             : #ifdef __amd64__
    1275           0 :         frame.edi.quad      = (uint64_t)data;
    1276             : #else
    1277             :         frame.edi.word      = (uint32_t)data;
    1278             : #endif
    1279           0 :         frame.ebp.word      = rpc->cookie2;
    1280             : 
    1281           0 :         vm_ins(&frame);
    1282             : 
    1283             :         /* NUL-terminate the data */
    1284           0 :         data[length] = '\0';
    1285             : 
    1286           0 :         if (frame.ebx.word != VM_RPC_ENH_DATA) {
    1287             :                 DPRINTF("vmware: get data failed, ebx=%08x\n",
    1288             :                     frame.ebx.word);
    1289           0 :                 return EIO;
    1290             :         }
    1291             : 
    1292             :         /* Acknowledge data received. */
    1293           0 :         bzero(&frame, sizeof(frame));
    1294           0 :         frame.eax.word      = VM_MAGIC;
    1295           0 :         frame.ebx.word      = dataid;
    1296           0 :         frame.ecx.part.low  = VM_CMD_RPC;
    1297           0 :         frame.ecx.part.high = VM_RPC_GET_END;
    1298           0 :         frame.edx.part.low  = VM_PORT_CMD;
    1299           0 :         frame.edx.part.high = rpc->channel;
    1300           0 :         frame.esi.word      = rpc->cookie1;
    1301           0 :         frame.edi.word      = rpc->cookie2;
    1302             : 
    1303           0 :         vm_cmd(&frame);
    1304             : 
    1305           0 :         if (frame.ecx.part.high == 0) {
    1306             :                 DPRINTF("vmware: ack data failed, eax=%08x, ecx=%08x\n",
    1307             :                     frame.eax.word, frame.ecx.word);
    1308           0 :                 return EIO;
    1309             :         }
    1310             : 
    1311           0 :         return 0;
    1312           0 : }
    1313             : 
    1314             : int
    1315           0 : vm_rpc_get_length(const struct vm_rpc *rpc, uint32_t *length, uint16_t *dataid)
    1316             : {
    1317           0 :         struct vm_backdoor frame;
    1318             : 
    1319           0 :         bzero(&frame, sizeof(frame));
    1320           0 :         frame.eax.word      = VM_MAGIC;
    1321           0 :         frame.ebx.word      = 0;
    1322           0 :         frame.ecx.part.low  = VM_CMD_RPC;
    1323           0 :         frame.ecx.part.high = VM_RPC_GET_LENGTH;
    1324           0 :         frame.edx.part.low  = VM_PORT_CMD;
    1325           0 :         frame.edx.part.high = rpc->channel;
    1326           0 :         frame.esi.word      = rpc->cookie1;
    1327           0 :         frame.edi.word      = rpc->cookie2;
    1328             : 
    1329           0 :         vm_cmd(&frame);
    1330             : 
    1331           0 :         if ((frame.ecx.part.high & VM_RPC_REPLY_SUCCESS) == 0) {
    1332             :                 DPRINTF("vmware: get length failed, eax=%08x, ecx=%08x\n",
    1333             :                     frame.eax.word, frame.ecx.word);
    1334           0 :                 return EIO;
    1335             :         }
    1336           0 :         if ((frame.ecx.part.high & VM_RPC_REPLY_DORECV) == 0) {
    1337           0 :                 *length = 0;
    1338           0 :                 *dataid = 0;
    1339           0 :         } else {
    1340           0 :                 *length = frame.ebx.word;
    1341           0 :                 *dataid = frame.edx.part.high;
    1342             :         }
    1343             : 
    1344           0 :         return 0;
    1345           0 : }
    1346             : 
    1347             : int
    1348           0 : vm_rpci_response_successful(struct vmt_softc *sc)
    1349             : {
    1350           0 :         return (sc->sc_rpc_buf[0] == '1' && sc->sc_rpc_buf[1] == ' ');
    1351             : }
    1352             : 
    1353             : int
    1354           0 : vm_rpc_send_rpci_tx_buf(struct vmt_softc *sc, const uint8_t *buf,
    1355             :     uint32_t length)
    1356             : {
    1357           0 :         struct vm_rpc rpci;
    1358           0 :         u_int32_t rlen;
    1359           0 :         u_int16_t ack;
    1360             :         int result = 0;
    1361             : 
    1362           0 :         if (vm_rpc_open(&rpci, VM_RPC_OPEN_RPCI) != 0) {
    1363             :                 DPRINTF("%s: rpci channel open failed\n", DEVNAME(sc));
    1364           0 :                 return EIO;
    1365             :         }
    1366             : 
    1367           0 :         if (vm_rpc_send(&rpci, sc->sc_rpc_buf, length) != 0) {
    1368             :                 DPRINTF("%s: unable to send rpci command\n", DEVNAME(sc));
    1369             :                 result = EIO;
    1370           0 :                 goto out;
    1371             :         }
    1372             : 
    1373           0 :         if (vm_rpc_get_length(&rpci, &rlen, &ack) != 0) {
    1374             :                 DPRINTF("%s: failed to get length of rpci response data\n",
    1375             :                     DEVNAME(sc));
    1376             :                 result = EIO;
    1377           0 :                 goto out;
    1378             :         }
    1379             : 
    1380           0 :         if (rlen > 0) {
    1381           0 :                 if (rlen >= VMT_RPC_BUFLEN) {
    1382           0 :                         rlen = VMT_RPC_BUFLEN - 1;
    1383           0 :                 }
    1384             : 
    1385           0 :                 if (vm_rpc_get_data(&rpci, sc->sc_rpc_buf, rlen, ack) != 0) {
    1386             :                         DPRINTF("%s: failed to get rpci response data\n",
    1387             :                             DEVNAME(sc));
    1388             :                         result = EIO;
    1389           0 :                         goto out;
    1390             :                 }
    1391             :         }
    1392             : 
    1393             : out:
    1394           0 :         if (vm_rpc_close(&rpci) != 0) {
    1395             :                 DPRINTF("%s: unable to close rpci channel\n", DEVNAME(sc));
    1396             :         }
    1397             : 
    1398           0 :         return result;
    1399           0 : }
    1400             : 
    1401             : int
    1402           0 : vm_rpc_send_rpci_tx(struct vmt_softc *sc, const char *fmt, ...)
    1403             : {
    1404           0 :         va_list args;
    1405             :         int len;
    1406             : 
    1407           0 :         va_start(args, fmt);
    1408           0 :         len = vsnprintf(sc->sc_rpc_buf, VMT_RPC_BUFLEN, fmt, args);
    1409           0 :         va_end(args);
    1410             : 
    1411           0 :         if (len >= VMT_RPC_BUFLEN) {
    1412             :                 DPRINTF("%s: rpci command didn't fit in buffer\n", DEVNAME(sc));
    1413           0 :                 return EIO;
    1414             :         }
    1415             : 
    1416           0 :         return vm_rpc_send_rpci_tx_buf(sc, sc->sc_rpc_buf, len);
    1417           0 : }
    1418             : 
    1419             : #if 0
    1420             :         struct vm_backdoor frame;
    1421             : 
    1422             :         bzero(&frame, sizeof(frame));
    1423             : 
    1424             :         frame.eax.word = VM_MAGIC;
    1425             :         frame.ecx.part.low = VM_CMD_GET_VERSION;
    1426             :         frame.edx.part.low  = VM_PORT_CMD;
    1427             : 
    1428             :         printf("\n");
    1429             :         printf("eax 0x%08x\n", frame.eax.word);
    1430             :         printf("ebx 0x%08x\n", frame.ebx.word);
    1431             :         printf("ecx 0x%08x\n", frame.ecx.word);
    1432             :         printf("edx 0x%08x\n", frame.edx.word);
    1433             :         printf("ebp 0x%08x\n", frame.ebp.word);
    1434             :         printf("edi 0x%08x\n", frame.edi.word);
    1435             :         printf("esi 0x%08x\n", frame.esi.word);
    1436             : 
    1437             :         vm_cmd(&frame);
    1438             : 
    1439             :         printf("-\n");
    1440             :         printf("eax 0x%08x\n", frame.eax.word);
    1441             :         printf("ebx 0x%08x\n", frame.ebx.word);
    1442             :         printf("ecx 0x%08x\n", frame.ecx.word);
    1443             :         printf("edx 0x%08x\n", frame.edx.word);
    1444             :         printf("ebp 0x%08x\n", frame.ebp.word);
    1445             :         printf("edi 0x%08x\n", frame.edi.word);
    1446             :         printf("esi 0x%08x\n", frame.esi.word);
    1447             : #endif
    1448             : 
    1449             : /*
    1450             :  * Notes on tracing backdoor activity in vmware-guestd:
    1451             :  *
    1452             :  * - Find the addresses of the inl / rep insb / rep outsb
    1453             :  *   instructions used to perform backdoor operations.
    1454             :  *   One way to do this is to disassemble vmware-guestd:
    1455             :  *
    1456             :  *   $ objdump -S /emul/freebsd/sbin/vmware-guestd > vmware-guestd.S
    1457             :  *
    1458             :  *   and search for '<tab>in ' in the resulting file.  The rep insb and
    1459             :  *   rep outsb code is directly below that.
    1460             :  *
    1461             :  * - Run vmware-guestd under gdb, setting up breakpoints as follows:
    1462             :  *   (the addresses shown here are the ones from VMware-server-1.0.10-203137,
    1463             :  *   the last version that actually works in FreeBSD emulation on OpenBSD)
    1464             :  *
    1465             :  * break *0x805497b   (address of 'in' instruction)
    1466             :  * commands 1
    1467             :  * silent
    1468             :  * echo INOUT\n
    1469             :  * print/x $ecx
    1470             :  * print/x $ebx
    1471             :  * print/x $edx
    1472             :  * continue
    1473             :  * end
    1474             :  * break *0x805497c   (address of instruction after 'in')
    1475             :  * commands 2
    1476             :  * silent
    1477             :  * echo ===\n
    1478             :  * print/x $ecx
    1479             :  * print/x $ebx
    1480             :  * print/x $edx
    1481             :  * echo \n
    1482             :  * continue
    1483             :  * end
    1484             :  * break *0x80549b7   (address of instruction before 'rep insb')
    1485             :  * commands 3
    1486             :  * silent
    1487             :  * set variable $inaddr = $edi
    1488             :  * set variable $incount = $ecx
    1489             :  * continue
    1490             :  * end
    1491             :  * break *0x80549ba   (address of instruction after 'rep insb')
    1492             :  * commands 4
    1493             :  * silent
    1494             :  * echo IN\n
    1495             :  * print $incount
    1496             :  * x/s $inaddr
    1497             :  * echo \n
    1498             :  * continue
    1499             :  * end
    1500             :  * break *0x80549fb    (address of instruction before 'rep outsb')
    1501             :  * commands 5
    1502             :  * silent
    1503             :  * echo OUT\n
    1504             :  * print $ecx
    1505             :  * x/s $esi
    1506             :  * echo \n
    1507             :  * continue
    1508             :  * end
    1509             :  *
    1510             :  * This will produce a log of the backdoor operations, including the
    1511             :  * data sent and received and the relevant register values.  You can then
    1512             :  * match the register values to the various constants in this file.
    1513             :  */

Generated by: LCOV version 1.13