1*3dc92541Spho /* $NetBSD: vmt_subr.c,v 1.10 2024/05/09 12:09:59 pho Exp $ */
20b42d22aSryo /* $OpenBSD: vmt.c,v 1.11 2011/01/27 21:29:25 dtucker Exp $ */
30b42d22aSryo
40b42d22aSryo /*
50b42d22aSryo * Copyright (c) 2007 David Crawshaw <david@zentus.com>
60b42d22aSryo * Copyright (c) 2008 David Gwynne <dlg@openbsd.org>
70b42d22aSryo *
80b42d22aSryo * Permission to use, copy, modify, and distribute this software for any
90b42d22aSryo * purpose with or without fee is hereby granted, provided that the above
100b42d22aSryo * copyright notice and this permission notice appear in all copies.
110b42d22aSryo *
120b42d22aSryo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
130b42d22aSryo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
140b42d22aSryo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
150b42d22aSryo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
160b42d22aSryo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
170b42d22aSryo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
180b42d22aSryo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
190b42d22aSryo */
200b42d22aSryo
210b42d22aSryo /*
220b42d22aSryo * Protocol reverse engineered by Ken Kato:
23*3dc92541Spho * https://sites.google.com/site/chitchatvmback/backdoor (dead link)
24*3dc92541Spho * https://web.archive.org/web/20230325103442/https://sites.google.com/site/chitchatvmback/backdoor (archive)
250b42d22aSryo */
260b42d22aSryo
270b42d22aSryo #include <sys/param.h>
280b42d22aSryo #include <sys/types.h>
290b42d22aSryo #include <sys/callout.h>
300b42d22aSryo #include <sys/device.h>
310b42d22aSryo #include <sys/endian.h>
320b42d22aSryo #include <sys/kernel.h>
330b42d22aSryo #include <sys/kmem.h>
340b42d22aSryo #include <sys/module.h>
350b42d22aSryo #include <sys/proc.h>
360b42d22aSryo #include <sys/reboot.h>
370b42d22aSryo #include <sys/socket.h>
380b42d22aSryo #include <sys/sysctl.h>
390b42d22aSryo #include <sys/syslog.h>
400b42d22aSryo #include <sys/systm.h>
410b42d22aSryo #include <sys/timetc.h>
420b42d22aSryo
430b42d22aSryo #include <net/if.h>
440b42d22aSryo #include <netinet/in.h>
450b42d22aSryo
460b42d22aSryo #include <dev/sysmon/sysmonvar.h>
470b42d22aSryo #include <dev/sysmon/sysmon_taskq.h>
480b42d22aSryo #include <dev/vmt/vmtreg.h>
490b42d22aSryo #include <dev/vmt/vmtvar.h>
500b42d22aSryo
510b42d22aSryo /* #define VMT_DEBUG */
520b42d22aSryo
530b42d22aSryo static int vmt_sysctl_setup_root(device_t);
540b42d22aSryo static int vmt_sysctl_setup_clock_sync(device_t, const struct sysctlnode *);
550b42d22aSryo static int vmt_sysctl_update_clock_sync_period(SYSCTLFN_PROTO);
560b42d22aSryo
570b42d22aSryo static void vm_cmd(struct vm_backdoor *);
580b42d22aSryo static void vm_ins(struct vm_backdoor *);
590b42d22aSryo static void vm_outs(struct vm_backdoor *);
600b42d22aSryo
610b42d22aSryo /* Functions for communicating with the VM Host. */
620b42d22aSryo static int vm_rpc_open(struct vm_rpc *, uint32_t);
630b42d22aSryo static int vm_rpc_close(struct vm_rpc *);
640b42d22aSryo static int vm_rpc_send(const struct vm_rpc *, const uint8_t *, uint32_t);
650b42d22aSryo static int vm_rpc_send_str(const struct vm_rpc *, const uint8_t *);
660b42d22aSryo static int vm_rpc_get_length(const struct vm_rpc *, uint32_t *, uint16_t *);
670b42d22aSryo static int vm_rpc_get_data(const struct vm_rpc *, char *, uint32_t, uint16_t);
680b42d22aSryo static int vm_rpc_send_rpci_tx_buf(struct vmt_softc *, const uint8_t *, uint32_t);
690b42d22aSryo static int vm_rpc_send_rpci_tx(struct vmt_softc *, const char *, ...)
700b42d22aSryo __printflike(2, 3);
710b42d22aSryo static int vm_rpci_response_successful(struct vmt_softc *);
720b42d22aSryo
730b42d22aSryo static void vmt_tclo_state_change_success(struct vmt_softc *, int, char);
740b42d22aSryo static void vmt_do_reboot(struct vmt_softc *);
750b42d22aSryo static void vmt_do_shutdown(struct vmt_softc *);
766b3bcb1fSmsaitoh static bool vmt_shutdown(device_t, int);
770b42d22aSryo
780b42d22aSryo static void vmt_update_guest_info(struct vmt_softc *);
790b42d22aSryo static void vmt_update_guest_uptime(struct vmt_softc *);
800b42d22aSryo static void vmt_sync_guest_clock(struct vmt_softc *);
810b42d22aSryo
820b42d22aSryo static void vmt_tick(void *);
830b42d22aSryo static void vmt_clock_sync_tick(void *);
840b42d22aSryo static void vmt_pswitch_event(void *);
850b42d22aSryo
8641309a54Smsaitoh static void vmt_tclo_tick(void *);
8741309a54Smsaitoh static int vmt_tclo_process(struct vmt_softc *, const char *);
8841309a54Smsaitoh static void vmt_tclo_reset(struct vmt_softc *);
8941309a54Smsaitoh static void vmt_tclo_ping(struct vmt_softc *);
9041309a54Smsaitoh static void vmt_tclo_halt(struct vmt_softc *);
9141309a54Smsaitoh static void vmt_tclo_reboot(struct vmt_softc *);
9241309a54Smsaitoh static void vmt_tclo_poweron(struct vmt_softc *);
9341309a54Smsaitoh static void vmt_tclo_suspend(struct vmt_softc *);
9441309a54Smsaitoh static void vmt_tclo_resume(struct vmt_softc *);
9541309a54Smsaitoh static void vmt_tclo_capreg(struct vmt_softc *);
9641309a54Smsaitoh static void vmt_tclo_broadcastip(struct vmt_softc *);
9741309a54Smsaitoh
9841309a54Smsaitoh struct vmt_tclo_rpc {
9941309a54Smsaitoh const char *name;
10041309a54Smsaitoh void (*cb)(struct vmt_softc *);
10141309a54Smsaitoh } vmt_tclo_rpc[] = {
10241309a54Smsaitoh /* Keep sorted by name (case-sensitive) */
10341309a54Smsaitoh { "Capabilities_Register", vmt_tclo_capreg },
10441309a54Smsaitoh { "OS_Halt", vmt_tclo_halt },
10541309a54Smsaitoh { "OS_PowerOn", vmt_tclo_poweron },
10641309a54Smsaitoh { "OS_Reboot", vmt_tclo_reboot },
10741309a54Smsaitoh { "OS_Resume", vmt_tclo_resume },
10841309a54Smsaitoh { "OS_Suspend", vmt_tclo_suspend },
10941309a54Smsaitoh { "Set_Option broadcastIP 1", vmt_tclo_broadcastip },
11041309a54Smsaitoh { "ping", vmt_tclo_ping },
11141309a54Smsaitoh { "reset", vmt_tclo_reset },
11241309a54Smsaitoh #if 0
11341309a54Smsaitoh /* Various unsupported commands */
11441309a54Smsaitoh { "Set_Option autohide 0" },
11541309a54Smsaitoh { "Set_Option copypaste 1" },
11641309a54Smsaitoh { "Set_Option enableDnD 1" },
11741309a54Smsaitoh { "Set_Option enableMessageBusTunnel 0" },
11841309a54Smsaitoh { "Set_Option linkRootHgfsShare 0" },
11941309a54Smsaitoh { "Set_Option mapRootHgfsShare 0" },
12041309a54Smsaitoh { "Set_Option synctime 1" },
12141309a54Smsaitoh { "Set_Option synctime.period 0" },
12241309a54Smsaitoh { "Set_Option time.synchronize.tools.enable 1" },
12341309a54Smsaitoh { "Set_Option time.synchronize.tools.percentCorrection 0" },
12441309a54Smsaitoh { "Set_Option time.synchronize.tools.slewCorrection 1" },
12541309a54Smsaitoh { "Set_Option time.synchronize.tools.startup 1" },
12641309a54Smsaitoh { "Set_Option toolScripts.afterPowerOn 1" },
12741309a54Smsaitoh { "Set_Option toolScripts.afterResume 1" },
12841309a54Smsaitoh { "Set_Option toolScripts.beforePowerOff 1" },
12941309a54Smsaitoh { "Set_Option toolScripts.beforeSuspend 1" },
13041309a54Smsaitoh { "Time_Synchronize 0" },
13141309a54Smsaitoh { "Vix_1_Relayed_Command \"38cdcae40e075d66\"" },
13241309a54Smsaitoh #endif
133b9343ab6Schristos { NULL, NULL },
13441309a54Smsaitoh };
13541309a54Smsaitoh
1360b42d22aSryo extern char hostname[MAXHOSTNAMELEN];
1370b42d22aSryo
1380b42d22aSryo static void
vmt_probe_cmd(struct vm_backdoor * frame,uint16_t cmd)1390b42d22aSryo vmt_probe_cmd(struct vm_backdoor *frame, uint16_t cmd)
1400b42d22aSryo {
1410b42d22aSryo memset(frame, 0, sizeof(*frame));
1420b42d22aSryo
14358b879d3Sryo frame->eax = VM_MAGIC;
14458b879d3Sryo frame->ebx = ~VM_MAGIC & VM_REG_WORD_MASK;
14558b879d3Sryo frame->ecx = VM_REG_CMD(0xffff, cmd);
14658b879d3Sryo frame->edx = VM_REG_CMD(0, VM_PORT_CMD);
1470b42d22aSryo
1480b42d22aSryo vm_cmd(frame);
1490b42d22aSryo }
1500b42d22aSryo
1510b42d22aSryo bool
vmt_probe(void)1520b42d22aSryo vmt_probe(void)
1530b42d22aSryo {
1540b42d22aSryo struct vm_backdoor frame;
1550b42d22aSryo
1560b42d22aSryo vmt_probe_cmd(&frame, VM_CMD_GET_VERSION);
15758b879d3Sryo if (__SHIFTOUT(frame.eax, VM_REG_WORD_MASK) == 0xffffffff ||
15858b879d3Sryo __SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) != VM_MAGIC)
1590b42d22aSryo return false;
1600b42d22aSryo
1610b42d22aSryo vmt_probe_cmd(&frame, VM_CMD_GET_SPEED);
16258b879d3Sryo if (__SHIFTOUT(frame.eax, VM_REG_WORD_MASK) == VM_MAGIC)
1630b42d22aSryo return false;
1640b42d22aSryo
1650b42d22aSryo return true;
1660b42d22aSryo }
1670b42d22aSryo
1680b42d22aSryo void
vmt_common_attach(struct vmt_softc * sc)1690b42d22aSryo vmt_common_attach(struct vmt_softc *sc)
1700b42d22aSryo {
1710b42d22aSryo device_t self;
1720b42d22aSryo struct vm_backdoor frame;
1730b42d22aSryo int rv;
1740b42d22aSryo
1750b42d22aSryo self = sc->sc_dev;
1760b42d22aSryo sc->sc_log = NULL;
1770b42d22aSryo
1780b42d22aSryo /* check again */
1790b42d22aSryo vmt_probe_cmd(&frame, VM_CMD_GET_VERSION);
18058b879d3Sryo if (__SHIFTOUT(frame.eax, VM_REG_WORD_MASK) == 0xffffffff ||
18158b879d3Sryo __SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) != VM_MAGIC) {
1820b42d22aSryo aprint_error_dev(self, "failed to get VMware version\n");
1830b42d22aSryo return;
1840b42d22aSryo }
1850b42d22aSryo
1860b42d22aSryo /* show uuid */
1870b42d22aSryo {
1880b42d22aSryo struct uuid uuid;
1890b42d22aSryo uint32_t u;
1900b42d22aSryo
1910b42d22aSryo vmt_probe_cmd(&frame, VM_CMD_GET_BIOS_UUID);
19258b879d3Sryo uuid.time_low =
19358b879d3Sryo bswap32(__SHIFTOUT(frame.eax, VM_REG_WORD_MASK));
19458b879d3Sryo u = bswap32(__SHIFTOUT(frame.ebx, VM_REG_WORD_MASK));
1950b42d22aSryo uuid.time_mid = u >> 16;
1960b42d22aSryo uuid.time_hi_and_version = u;
19758b879d3Sryo u = bswap32(__SHIFTOUT(frame.ecx, VM_REG_WORD_MASK));
1980b42d22aSryo uuid.clock_seq_hi_and_reserved = u >> 24;
1990b42d22aSryo uuid.clock_seq_low = u >> 16;
2000b42d22aSryo uuid.node[0] = u >> 8;
2010b42d22aSryo uuid.node[1] = u;
20258b879d3Sryo u = bswap32(__SHIFTOUT(frame.edx, VM_REG_WORD_MASK));
2030b42d22aSryo uuid.node[2] = u >> 24;
2040b42d22aSryo uuid.node[3] = u >> 16;
2050b42d22aSryo uuid.node[4] = u >> 8;
2060b42d22aSryo uuid.node[5] = u;
2070b42d22aSryo
2080b42d22aSryo uuid_snprintf(sc->sc_uuid, sizeof(sc->sc_uuid), &uuid);
2090c3dd7e3Sryo aprint_verbose_dev(sc->sc_dev, "UUID: %s\n", sc->sc_uuid);
2100b42d22aSryo }
2110b42d22aSryo
2120b42d22aSryo callout_init(&sc->sc_tick, 0);
2130b42d22aSryo callout_init(&sc->sc_tclo_tick, 0);
2140b42d22aSryo callout_init(&sc->sc_clock_sync_tick, 0);
2150b42d22aSryo
2160b42d22aSryo sc->sc_clock_sync_period_seconds = VMT_CLOCK_SYNC_PERIOD_SECONDS;
2170b42d22aSryo
2180b42d22aSryo rv = vmt_sysctl_setup_root(self);
2190b42d22aSryo if (rv != 0) {
2200b42d22aSryo aprint_error_dev(self, "failed to initialize sysctl "
2210b42d22aSryo "(err %d)\n", rv);
2220b42d22aSryo goto free;
2230b42d22aSryo }
2240b42d22aSryo
2250b42d22aSryo sc->sc_rpc_buf = kmem_alloc(VMT_RPC_BUFLEN, KM_SLEEP);
2260b42d22aSryo
2270b42d22aSryo if (vm_rpc_open(&sc->sc_tclo_rpc, VM_RPC_OPEN_TCLO) != 0) {
2289e0e4167Smsaitoh aprint_error_dev(self, "failed to open backdoor RPC channel "
2299e0e4167Smsaitoh "(TCLO protocol)\n");
2300b42d22aSryo goto free;
2310b42d22aSryo }
2320b42d22aSryo sc->sc_tclo_rpc_open = true;
2330b42d22aSryo
2340b42d22aSryo /* don't know if this is important at all yet */
2359e0e4167Smsaitoh if (vm_rpc_send_rpci_tx(sc,
2369e0e4167Smsaitoh "tools.capability.hgfs_server toolbox 1") != 0) {
2379e0e4167Smsaitoh aprint_error_dev(self,
2389e0e4167Smsaitoh "failed to set HGFS server capability\n");
2390b42d22aSryo goto free;
2400b42d22aSryo }
2410b42d22aSryo
2420b42d22aSryo pmf_device_register1(self, NULL, NULL, vmt_shutdown);
2430b42d22aSryo
2440b42d22aSryo sysmon_task_queue_init();
2450b42d22aSryo
2460b42d22aSryo sc->sc_ev_power.ev_smpsw.smpsw_type = PSWITCH_TYPE_POWER;
2470b42d22aSryo sc->sc_ev_power.ev_smpsw.smpsw_name = device_xname(self);
2480b42d22aSryo sc->sc_ev_power.ev_code = PSWITCH_EVENT_PRESSED;
2490b42d22aSryo sysmon_pswitch_register(&sc->sc_ev_power.ev_smpsw);
2500b42d22aSryo sc->sc_ev_reset.ev_smpsw.smpsw_type = PSWITCH_TYPE_RESET;
2510b42d22aSryo sc->sc_ev_reset.ev_smpsw.smpsw_name = device_xname(self);
2520b42d22aSryo sc->sc_ev_reset.ev_code = PSWITCH_EVENT_PRESSED;
2530b42d22aSryo sysmon_pswitch_register(&sc->sc_ev_reset.ev_smpsw);
2540b42d22aSryo sc->sc_ev_sleep.ev_smpsw.smpsw_type = PSWITCH_TYPE_SLEEP;
2550b42d22aSryo sc->sc_ev_sleep.ev_smpsw.smpsw_name = device_xname(self);
2560b42d22aSryo sc->sc_ev_sleep.ev_code = PSWITCH_EVENT_RELEASED;
2570b42d22aSryo sysmon_pswitch_register(&sc->sc_ev_sleep.ev_smpsw);
2580b42d22aSryo sc->sc_smpsw_valid = true;
2590b42d22aSryo
2600b42d22aSryo callout_setfunc(&sc->sc_tick, vmt_tick, sc);
2610b42d22aSryo callout_schedule(&sc->sc_tick, hz);
2620b42d22aSryo
2630b42d22aSryo callout_setfunc(&sc->sc_tclo_tick, vmt_tclo_tick, sc);
2640b42d22aSryo callout_schedule(&sc->sc_tclo_tick, hz);
2650b42d22aSryo sc->sc_tclo_ping = 1;
2660b42d22aSryo
2670b42d22aSryo callout_setfunc(&sc->sc_clock_sync_tick, vmt_clock_sync_tick, sc);
2680b42d22aSryo callout_schedule(&sc->sc_clock_sync_tick,
2690b42d22aSryo mstohz(sc->sc_clock_sync_period_seconds * 1000));
2700b42d22aSryo
2710b42d22aSryo vmt_sync_guest_clock(sc);
2720b42d22aSryo
2730b42d22aSryo return;
2740b42d22aSryo
2750b42d22aSryo free:
2760b42d22aSryo if (sc->sc_rpc_buf)
2770b42d22aSryo kmem_free(sc->sc_rpc_buf, VMT_RPC_BUFLEN);
2780b42d22aSryo pmf_device_register(self, NULL, NULL);
2790b42d22aSryo if (sc->sc_log)
2800b42d22aSryo sysctl_teardown(&sc->sc_log);
2810b42d22aSryo }
2820b42d22aSryo
2830b42d22aSryo int
vmt_common_detach(struct vmt_softc * sc)2840b42d22aSryo vmt_common_detach(struct vmt_softc *sc)
2850b42d22aSryo {
2860b42d22aSryo if (sc->sc_tclo_rpc_open)
2870b42d22aSryo vm_rpc_close(&sc->sc_tclo_rpc);
2880b42d22aSryo
2890b42d22aSryo if (sc->sc_smpsw_valid) {
2900b42d22aSryo sysmon_pswitch_unregister(&sc->sc_ev_sleep.ev_smpsw);
2910b42d22aSryo sysmon_pswitch_unregister(&sc->sc_ev_reset.ev_smpsw);
2920b42d22aSryo sysmon_pswitch_unregister(&sc->sc_ev_power.ev_smpsw);
2930b42d22aSryo }
2940b42d22aSryo
2950b42d22aSryo callout_halt(&sc->sc_tick, NULL);
2960b42d22aSryo callout_destroy(&sc->sc_tick);
2970b42d22aSryo
2980b42d22aSryo callout_halt(&sc->sc_tclo_tick, NULL);
2990b42d22aSryo callout_destroy(&sc->sc_tclo_tick);
3000b42d22aSryo
3010b42d22aSryo callout_halt(&sc->sc_clock_sync_tick, NULL);
3020b42d22aSryo callout_destroy(&sc->sc_clock_sync_tick);
3030b42d22aSryo
3040b42d22aSryo if (sc->sc_rpc_buf)
3050b42d22aSryo kmem_free(sc->sc_rpc_buf, VMT_RPC_BUFLEN);
3060b42d22aSryo
3070b42d22aSryo if (sc->sc_log) {
3080b42d22aSryo sysctl_teardown(&sc->sc_log);
3090b42d22aSryo sc->sc_log = NULL;
3100b42d22aSryo }
3110b42d22aSryo
3120b42d22aSryo return 0;
3130b42d22aSryo }
3140b42d22aSryo
3150b42d22aSryo static int
vmt_sysctl_setup_root(device_t self)3160b42d22aSryo vmt_sysctl_setup_root(device_t self)
3170b42d22aSryo {
3180b42d22aSryo const struct sysctlnode *machdep_node, *vmt_node;
3190b42d22aSryo struct vmt_softc *sc = device_private(self);
3200b42d22aSryo int rv;
3210b42d22aSryo
3220b42d22aSryo rv = sysctl_createv(&sc->sc_log, 0, NULL, &machdep_node,
3230b42d22aSryo CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
3240b42d22aSryo NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
3250b42d22aSryo if (rv != 0)
3260b42d22aSryo goto fail;
3270b42d22aSryo
3280b42d22aSryo rv = sysctl_createv(&sc->sc_log, 0, &machdep_node, &vmt_node,
3290b42d22aSryo 0, CTLTYPE_NODE, device_xname(self), NULL,
3300b42d22aSryo NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
3310b42d22aSryo if (rv != 0)
3320b42d22aSryo goto fail;
3330b42d22aSryo
3340b42d22aSryo rv = sysctl_createv(&sc->sc_log, 0, &vmt_node, NULL,
3350b42d22aSryo CTLFLAG_READONLY, CTLTYPE_STRING, "uuid",
3360b42d22aSryo SYSCTL_DESCR("UUID of virtual machine"),
3370b42d22aSryo NULL, 0, sc->sc_uuid, 0,
3380b42d22aSryo CTL_CREATE, CTL_EOL);
3390b42d22aSryo
3400b42d22aSryo rv = vmt_sysctl_setup_clock_sync(self, vmt_node);
3410b42d22aSryo if (rv != 0)
3420b42d22aSryo goto fail;
3430b42d22aSryo
3440b42d22aSryo return 0;
3450b42d22aSryo
3460b42d22aSryo fail:
3470b42d22aSryo sysctl_teardown(&sc->sc_log);
3480b42d22aSryo sc->sc_log = NULL;
3490b42d22aSryo
3500b42d22aSryo return rv;
3510b42d22aSryo }
3520b42d22aSryo
3530b42d22aSryo static int
vmt_sysctl_setup_clock_sync(device_t self,const struct sysctlnode * root_node)3540b42d22aSryo vmt_sysctl_setup_clock_sync(device_t self, const struct sysctlnode *root_node)
3550b42d22aSryo {
3560b42d22aSryo const struct sysctlnode *node, *period_node;
3570b42d22aSryo struct vmt_softc *sc = device_private(self);
3580b42d22aSryo int rv;
3590b42d22aSryo
3600b42d22aSryo rv = sysctl_createv(&sc->sc_log, 0, &root_node, &node,
3610b42d22aSryo 0, CTLTYPE_NODE, "clock_sync", NULL,
3620b42d22aSryo NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
3630b42d22aSryo if (rv != 0)
3640b42d22aSryo return rv;
3650b42d22aSryo
3660b42d22aSryo rv = sysctl_createv(&sc->sc_log, 0, &node, &period_node,
3670b42d22aSryo CTLFLAG_READWRITE, CTLTYPE_INT, "period",
3680b42d22aSryo SYSCTL_DESCR("Period, in seconds, at which to update the "
3690b42d22aSryo "guest's clock"),
3700b42d22aSryo vmt_sysctl_update_clock_sync_period, 0, (void *)sc, 0,
3710b42d22aSryo CTL_CREATE, CTL_EOL);
3720b42d22aSryo return rv;
3730b42d22aSryo }
3740b42d22aSryo
3750b42d22aSryo static int
vmt_sysctl_update_clock_sync_period(SYSCTLFN_ARGS)3760b42d22aSryo vmt_sysctl_update_clock_sync_period(SYSCTLFN_ARGS)
3770b42d22aSryo {
3780b42d22aSryo int error, period;
3790b42d22aSryo struct sysctlnode node;
3800b42d22aSryo struct vmt_softc *sc;
3810b42d22aSryo
3820b42d22aSryo node = *rnode;
3830b42d22aSryo sc = (struct vmt_softc *)node.sysctl_data;
3840b42d22aSryo
3850b42d22aSryo period = sc->sc_clock_sync_period_seconds;
3860b42d22aSryo node.sysctl_data = .
3870b42d22aSryo error = sysctl_lookup(SYSCTLFN_CALL(&node));
3880b42d22aSryo if (error || newp == NULL)
3890b42d22aSryo return error;
3900b42d22aSryo
3910b42d22aSryo if (sc->sc_clock_sync_period_seconds != period) {
3920b42d22aSryo callout_halt(&sc->sc_clock_sync_tick, NULL);
3930b42d22aSryo sc->sc_clock_sync_period_seconds = period;
3940b42d22aSryo if (sc->sc_clock_sync_period_seconds > 0)
3950b42d22aSryo callout_schedule(&sc->sc_clock_sync_tick,
3960b42d22aSryo mstohz(sc->sc_clock_sync_period_seconds * 1000));
3970b42d22aSryo }
3980b42d22aSryo return 0;
3990b42d22aSryo }
4000b42d22aSryo
4010b42d22aSryo static void
vmt_clock_sync_tick(void * xarg)4020b42d22aSryo vmt_clock_sync_tick(void *xarg)
4030b42d22aSryo {
4040b42d22aSryo struct vmt_softc *sc = xarg;
4050b42d22aSryo
4060b42d22aSryo vmt_sync_guest_clock(sc);
4070b42d22aSryo
4080b42d22aSryo callout_schedule(&sc->sc_clock_sync_tick,
4090b42d22aSryo mstohz(sc->sc_clock_sync_period_seconds * 1000));
4100b42d22aSryo }
4110b42d22aSryo
4120b42d22aSryo static void
vmt_update_guest_uptime(struct vmt_softc * sc)4130b42d22aSryo vmt_update_guest_uptime(struct vmt_softc *sc)
4140b42d22aSryo {
4150b42d22aSryo /* host wants uptime in hundredths of a second */
4160b42d22aSryo if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo %d %" PRId64 "00",
4170b42d22aSryo VM_GUEST_INFO_UPTIME, time_uptime) != 0) {
4180b42d22aSryo device_printf(sc->sc_dev, "unable to set guest uptime\n");
4190b42d22aSryo sc->sc_rpc_error = 1;
4200b42d22aSryo }
4210b42d22aSryo }
4220b42d22aSryo
4230b42d22aSryo static void
vmt_update_guest_info(struct vmt_softc * sc)4240b42d22aSryo vmt_update_guest_info(struct vmt_softc *sc)
4250b42d22aSryo {
4260b42d22aSryo if (strncmp(sc->sc_hostname, hostname, sizeof(sc->sc_hostname)) != 0) {
4270b42d22aSryo strlcpy(sc->sc_hostname, hostname, sizeof(sc->sc_hostname));
4280b42d22aSryo if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo %d %s",
4290b42d22aSryo VM_GUEST_INFO_DNS_NAME, sc->sc_hostname) != 0) {
4300b42d22aSryo device_printf(sc->sc_dev, "unable to set hostname\n");
4310b42d22aSryo sc->sc_rpc_error = 1;
4320b42d22aSryo }
4330b42d22aSryo }
4340b42d22aSryo
4350b42d22aSryo /*
4369e0e4167Smsaitoh * we're supposed to pass the full network address information back
4379e0e4167Smsaitoh * here, but that involves xdr (sunrpc) data encoding, which seems
4389e0e4167Smsaitoh * a bit unreasonable.
4390b42d22aSryo */
4400b42d22aSryo
4410b42d22aSryo if (sc->sc_set_guest_os == 0) {
4420b42d22aSryo if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo %d %s %s %s",
4439e0e4167Smsaitoh VM_GUEST_INFO_OS_NAME_FULL,
4449e0e4167Smsaitoh ostype, osrelease, machine_arch) != 0) {
4459e0e4167Smsaitoh device_printf(sc->sc_dev,
4469e0e4167Smsaitoh "unable to set full guest OS\n");
4470b42d22aSryo sc->sc_rpc_error = 1;
4480b42d22aSryo }
4490b42d22aSryo
4500b42d22aSryo /*
4519e0e4167Smsaitoh * Host doesn't like it if we send an OS name it doesn't
4529e0e4167Smsaitoh * recognise, so use "other" for i386 and "other-64" for amd64.
4530b42d22aSryo */
4540b42d22aSryo if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo %d %s",
4550b42d22aSryo VM_GUEST_INFO_OS_NAME, VM_OS_NAME) != 0) {
4560b42d22aSryo device_printf(sc->sc_dev, "unable to set guest OS\n");
4570b42d22aSryo sc->sc_rpc_error = 1;
4580b42d22aSryo }
4590b42d22aSryo
4600b42d22aSryo sc->sc_set_guest_os = 1;
4610b42d22aSryo }
4620b42d22aSryo }
4630b42d22aSryo
4640b42d22aSryo static void
vmt_sync_guest_clock(struct vmt_softc * sc)4650b42d22aSryo vmt_sync_guest_clock(struct vmt_softc *sc)
4660b42d22aSryo {
4670b42d22aSryo struct vm_backdoor frame;
4680b42d22aSryo struct timespec ts;
4690b42d22aSryo
4700b42d22aSryo memset(&frame, 0, sizeof(frame));
47158b879d3Sryo frame.eax = VM_MAGIC;
47258b879d3Sryo frame.ecx = VM_CMD_GET_TIME_FULL;
47358b879d3Sryo frame.edx = VM_REG_CMD(0, VM_PORT_CMD);
4740b42d22aSryo vm_cmd(&frame);
4750b42d22aSryo
47658b879d3Sryo if (__SHIFTOUT(frame.eax, VM_REG_WORD_MASK) != 0xffffffff) {
47758b879d3Sryo ts.tv_sec = ((uint64_t)(
47858b879d3Sryo __SHIFTOUT(frame.esi, VM_REG_WORD_MASK) << 32)) |
47958b879d3Sryo __SHIFTOUT(frame.edx, VM_REG_WORD_MASK);
48058b879d3Sryo ts.tv_nsec = __SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) * 1000;
4810b42d22aSryo tc_setclock(&ts);
4820b42d22aSryo }
4830b42d22aSryo }
4840b42d22aSryo
4850b42d22aSryo static void
vmt_tick(void * xarg)4860b42d22aSryo vmt_tick(void *xarg)
4870b42d22aSryo {
4880b42d22aSryo struct vmt_softc *sc = xarg;
4890b42d22aSryo
4900b42d22aSryo vmt_update_guest_info(sc);
4910b42d22aSryo vmt_update_guest_uptime(sc);
4920b42d22aSryo
4930b42d22aSryo callout_schedule(&sc->sc_tick, hz * 15);
4940b42d22aSryo }
4950b42d22aSryo
4960b42d22aSryo static void
vmt_tclo_state_change_success(struct vmt_softc * sc,int success,char state)4970b42d22aSryo vmt_tclo_state_change_success(struct vmt_softc *sc, int success, char state)
4980b42d22aSryo {
4990b42d22aSryo if (vm_rpc_send_rpci_tx(sc, "tools.os.statechange.status %d %d",
5000b42d22aSryo success, state) != 0) {
5019e0e4167Smsaitoh device_printf(sc->sc_dev,
5029e0e4167Smsaitoh "unable to send state change result\n");
5030b42d22aSryo sc->sc_rpc_error = 1;
5040b42d22aSryo }
5050b42d22aSryo }
5060b42d22aSryo
5070b42d22aSryo static void
vmt_do_shutdown(struct vmt_softc * sc)5080b42d22aSryo vmt_do_shutdown(struct vmt_softc *sc)
5090b42d22aSryo {
5100b42d22aSryo vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_HALT);
5110b42d22aSryo vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK);
5120b42d22aSryo
5130b42d22aSryo device_printf(sc->sc_dev, "host requested shutdown\n");
5140b42d22aSryo sysmon_task_queue_sched(0, vmt_pswitch_event, &sc->sc_ev_power);
5150b42d22aSryo }
5160b42d22aSryo
5170b42d22aSryo static void
vmt_do_reboot(struct vmt_softc * sc)5180b42d22aSryo vmt_do_reboot(struct vmt_softc *sc)
5190b42d22aSryo {
5200b42d22aSryo vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_REBOOT);
5210b42d22aSryo vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK);
5220b42d22aSryo
5230b42d22aSryo device_printf(sc->sc_dev, "host requested reboot\n");
5240b42d22aSryo sysmon_task_queue_sched(0, vmt_pswitch_event, &sc->sc_ev_reset);
5250b42d22aSryo }
5260b42d22aSryo
5270b42d22aSryo static void
vmt_do_resume(struct vmt_softc * sc)5280b42d22aSryo vmt_do_resume(struct vmt_softc *sc)
5290b42d22aSryo {
5300b42d22aSryo device_printf(sc->sc_dev, "guest resuming from suspended state\n");
5310b42d22aSryo
5320b42d22aSryo vmt_sync_guest_clock(sc);
5330b42d22aSryo
5340b42d22aSryo /* force guest info update */
5350b42d22aSryo sc->sc_hostname[0] = '\0';
5360b42d22aSryo sc->sc_set_guest_os = 0;
5370b42d22aSryo vmt_update_guest_info(sc);
5380b42d22aSryo
5390b42d22aSryo vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_RESUME);
5400b42d22aSryo if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
5410b42d22aSryo device_printf(sc->sc_dev, "error sending resume response\n");
5420b42d22aSryo sc->sc_rpc_error = 1;
5430b42d22aSryo }
5440b42d22aSryo
5450b42d22aSryo sysmon_task_queue_sched(0, vmt_pswitch_event, &sc->sc_ev_sleep);
5460b42d22aSryo }
5470b42d22aSryo
5480b42d22aSryo static bool
vmt_shutdown(device_t self,int flags)5490b42d22aSryo vmt_shutdown(device_t self, int flags)
5500b42d22aSryo {
5510b42d22aSryo struct vmt_softc *sc = device_private(self);
5520b42d22aSryo
5539e0e4167Smsaitoh if (vm_rpc_send_rpci_tx(sc,
5549e0e4167Smsaitoh "tools.capability.hgfs_server toolbox 0") != 0) {
5559e0e4167Smsaitoh device_printf(sc->sc_dev,
5569e0e4167Smsaitoh "failed to disable hgfs server capability\n");
5570b42d22aSryo }
5580b42d22aSryo
5590b42d22aSryo if (vm_rpc_send(&sc->sc_tclo_rpc, NULL, 0) != 0) {
5600b42d22aSryo device_printf(sc->sc_dev, "failed to send shutdown ping\n");
5610b42d22aSryo }
5620b42d22aSryo
5630b42d22aSryo vm_rpc_close(&sc->sc_tclo_rpc);
5640b42d22aSryo
5650b42d22aSryo return true;
5660b42d22aSryo }
5670b42d22aSryo
5680b42d22aSryo static void
vmt_pswitch_event(void * xarg)5690b42d22aSryo vmt_pswitch_event(void *xarg)
5700b42d22aSryo {
5710b42d22aSryo struct vmt_event *ev = xarg;
5720b42d22aSryo
5730b42d22aSryo sysmon_pswitch_event(&ev->ev_smpsw, ev->ev_code);
5740b42d22aSryo }
5750b42d22aSryo
5760b42d22aSryo static void
vmt_tclo_reset(struct vmt_softc * sc)57741309a54Smsaitoh vmt_tclo_reset(struct vmt_softc *sc)
57841309a54Smsaitoh {
57941309a54Smsaitoh
58041309a54Smsaitoh if (sc->sc_rpc_error != 0) {
58141309a54Smsaitoh device_printf(sc->sc_dev, "resetting rpc\n");
58241309a54Smsaitoh vm_rpc_close(&sc->sc_tclo_rpc);
58341309a54Smsaitoh
58441309a54Smsaitoh /* reopen and send the reset reply next time around */
58541309a54Smsaitoh return;
58641309a54Smsaitoh }
58741309a54Smsaitoh
58841309a54Smsaitoh if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_RESET_REPLY) != 0) {
58941309a54Smsaitoh device_printf(sc->sc_dev, "failed to send reset reply\n");
59041309a54Smsaitoh sc->sc_rpc_error = 1;
59141309a54Smsaitoh }
59241309a54Smsaitoh
59341309a54Smsaitoh }
59441309a54Smsaitoh
59541309a54Smsaitoh static void
vmt_tclo_ping(struct vmt_softc * sc)59641309a54Smsaitoh vmt_tclo_ping(struct vmt_softc *sc)
59741309a54Smsaitoh {
59841309a54Smsaitoh
59941309a54Smsaitoh vmt_update_guest_info(sc);
60041309a54Smsaitoh if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
60141309a54Smsaitoh device_printf(sc->sc_dev, "error sending ping response\n");
60241309a54Smsaitoh sc->sc_rpc_error = 1;
60341309a54Smsaitoh }
60441309a54Smsaitoh }
60541309a54Smsaitoh
60641309a54Smsaitoh static void
vmt_tclo_halt(struct vmt_softc * sc)60741309a54Smsaitoh vmt_tclo_halt(struct vmt_softc *sc)
60841309a54Smsaitoh {
60941309a54Smsaitoh
61041309a54Smsaitoh vmt_do_shutdown(sc);
61141309a54Smsaitoh }
61241309a54Smsaitoh
61341309a54Smsaitoh static void
vmt_tclo_reboot(struct vmt_softc * sc)61441309a54Smsaitoh vmt_tclo_reboot(struct vmt_softc *sc)
61541309a54Smsaitoh {
61641309a54Smsaitoh
61741309a54Smsaitoh vmt_do_reboot(sc);
61841309a54Smsaitoh }
61941309a54Smsaitoh
62041309a54Smsaitoh static void
vmt_tclo_poweron(struct vmt_softc * sc)62141309a54Smsaitoh vmt_tclo_poweron(struct vmt_softc *sc)
62241309a54Smsaitoh {
62341309a54Smsaitoh
62441309a54Smsaitoh vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_POWERON);
62541309a54Smsaitoh if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
62641309a54Smsaitoh device_printf(sc->sc_dev, "error sending poweron response\n");
62741309a54Smsaitoh sc->sc_rpc_error = 1;
62841309a54Smsaitoh }
62941309a54Smsaitoh }
63041309a54Smsaitoh
63141309a54Smsaitoh static void
vmt_tclo_suspend(struct vmt_softc * sc)63241309a54Smsaitoh vmt_tclo_suspend(struct vmt_softc *sc)
63341309a54Smsaitoh {
63441309a54Smsaitoh
63541309a54Smsaitoh log(LOG_KERN | LOG_NOTICE,
63641309a54Smsaitoh "VMware guest entering suspended state\n");
63741309a54Smsaitoh
63841309a54Smsaitoh vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_SUSPEND);
63941309a54Smsaitoh if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
64041309a54Smsaitoh device_printf(sc->sc_dev, "error sending suspend response\n");
64141309a54Smsaitoh sc->sc_rpc_error = 1;
64241309a54Smsaitoh }
64341309a54Smsaitoh }
64441309a54Smsaitoh
64541309a54Smsaitoh static void
vmt_tclo_resume(struct vmt_softc * sc)64641309a54Smsaitoh vmt_tclo_resume(struct vmt_softc *sc)
64741309a54Smsaitoh {
64841309a54Smsaitoh
64941309a54Smsaitoh vmt_do_resume(sc); /* XXX msaitoh extract */
65041309a54Smsaitoh }
65141309a54Smsaitoh
65241309a54Smsaitoh static void
vmt_tclo_capreg(struct vmt_softc * sc)65341309a54Smsaitoh vmt_tclo_capreg(struct vmt_softc *sc)
65441309a54Smsaitoh {
65541309a54Smsaitoh
65641309a54Smsaitoh /* don't know if this is important at all */
65741309a54Smsaitoh if (vm_rpc_send_rpci_tx(sc,
65841309a54Smsaitoh "vmx.capability.unified_loop toolbox") != 0) {
65941309a54Smsaitoh device_printf(sc->sc_dev, "unable to set unified loop\n");
66041309a54Smsaitoh sc->sc_rpc_error = 1;
66141309a54Smsaitoh }
66241309a54Smsaitoh if (vm_rpci_response_successful(sc) == 0) {
66341309a54Smsaitoh device_printf(sc->sc_dev,
66441309a54Smsaitoh "host rejected unified loop setting\n");
66541309a54Smsaitoh }
66641309a54Smsaitoh
66741309a54Smsaitoh /* the trailing space is apparently important here */
66841309a54Smsaitoh if (vm_rpc_send_rpci_tx(sc,
66941309a54Smsaitoh "tools.capability.statechange ") != 0) {
67041309a54Smsaitoh device_printf(sc->sc_dev,
67141309a54Smsaitoh "unable to send statechange capability\n");
67241309a54Smsaitoh sc->sc_rpc_error = 1;
67341309a54Smsaitoh }
67441309a54Smsaitoh if (vm_rpci_response_successful(sc) == 0) {
67541309a54Smsaitoh device_printf(sc->sc_dev,
67641309a54Smsaitoh "host rejected statechange capability\n");
67741309a54Smsaitoh }
67841309a54Smsaitoh
67941309a54Smsaitoh if (vm_rpc_send_rpci_tx(sc,
68041309a54Smsaitoh "tools.set.version %u", VM_VERSION_UNMANAGED) != 0) {
68141309a54Smsaitoh device_printf(sc->sc_dev, "unable to set tools version\n");
68241309a54Smsaitoh sc->sc_rpc_error = 1;
68341309a54Smsaitoh }
68441309a54Smsaitoh
68541309a54Smsaitoh vmt_update_guest_uptime(sc);
68641309a54Smsaitoh
68741309a54Smsaitoh if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
68841309a54Smsaitoh device_printf(sc->sc_dev,
68941309a54Smsaitoh "error sending capabilities_register response\n");
69041309a54Smsaitoh sc->sc_rpc_error = 1;
69141309a54Smsaitoh }
69241309a54Smsaitoh }
69341309a54Smsaitoh
69441309a54Smsaitoh static void
vmt_tclo_broadcastip(struct vmt_softc * sc)69541309a54Smsaitoh vmt_tclo_broadcastip(struct vmt_softc *sc)
69641309a54Smsaitoh {
69741309a54Smsaitoh struct ifaddr *iface_addr = NULL;
69841309a54Smsaitoh struct ifnet *iface;
69941309a54Smsaitoh struct sockaddr_in *guest_ip;
70041309a54Smsaitoh int s;
70141309a54Smsaitoh struct psref psref;
70241309a54Smsaitoh
70341309a54Smsaitoh /* find first available ipv4 address */
70441309a54Smsaitoh guest_ip = NULL;
70541309a54Smsaitoh s = pserialize_read_enter();
70641309a54Smsaitoh IFNET_READER_FOREACH(iface) {
70741309a54Smsaitoh
70841309a54Smsaitoh /* skip loopback */
70941309a54Smsaitoh if (strncmp(iface->if_xname, "lo", 2) == 0 &&
71041309a54Smsaitoh iface->if_xname[2] >= '0' &&
71141309a54Smsaitoh iface->if_xname[2] <= '9') {
71241309a54Smsaitoh continue;
71341309a54Smsaitoh }
71441309a54Smsaitoh
71541309a54Smsaitoh IFADDR_READER_FOREACH(iface_addr, iface) {
71641309a54Smsaitoh if (iface_addr->ifa_addr->sa_family != AF_INET) {
71741309a54Smsaitoh continue;
71841309a54Smsaitoh }
71941309a54Smsaitoh
72041309a54Smsaitoh guest_ip = satosin(iface_addr->ifa_addr);
72141309a54Smsaitoh ifa_acquire(iface_addr, &psref);
72241309a54Smsaitoh goto got;
72341309a54Smsaitoh }
72441309a54Smsaitoh }
72541309a54Smsaitoh got:
72641309a54Smsaitoh pserialize_read_exit(s);
72741309a54Smsaitoh
72841309a54Smsaitoh if (guest_ip != NULL) {
72941309a54Smsaitoh if (vm_rpc_send_rpci_tx(sc, "info-set guestinfo.ip %s",
73041309a54Smsaitoh inet_ntoa(guest_ip->sin_addr)) != 0) {
73141309a54Smsaitoh device_printf(sc->sc_dev,
73241309a54Smsaitoh "unable to send guest IP address\n");
73341309a54Smsaitoh sc->sc_rpc_error = 1;
73441309a54Smsaitoh }
73541309a54Smsaitoh ifa_release(iface_addr, &psref);
73641309a54Smsaitoh
73741309a54Smsaitoh if (vm_rpc_send_str(&sc->sc_tclo_rpc,
73841309a54Smsaitoh VM_RPC_REPLY_OK) != 0) {
73941309a54Smsaitoh device_printf(sc->sc_dev,
74041309a54Smsaitoh "error sending broadcastIP response\n");
74141309a54Smsaitoh sc->sc_rpc_error = 1;
74241309a54Smsaitoh }
74341309a54Smsaitoh } else {
74441309a54Smsaitoh if (vm_rpc_send_str(&sc->sc_tclo_rpc,
74541309a54Smsaitoh VM_RPC_REPLY_ERROR_IP_ADDR) != 0) {
74641309a54Smsaitoh device_printf(sc->sc_dev,
74741309a54Smsaitoh "error sending broadcastIP"
74841309a54Smsaitoh " error response\n");
74941309a54Smsaitoh sc->sc_rpc_error = 1;
75041309a54Smsaitoh }
75141309a54Smsaitoh }
75241309a54Smsaitoh }
75341309a54Smsaitoh
75441309a54Smsaitoh int
vmt_tclo_process(struct vmt_softc * sc,const char * name)75541309a54Smsaitoh vmt_tclo_process(struct vmt_softc *sc, const char *name)
75641309a54Smsaitoh {
75741309a54Smsaitoh int i;
75841309a54Smsaitoh
75941309a54Smsaitoh /* Search for rpc command and call handler */
76041309a54Smsaitoh for (i = 0; vmt_tclo_rpc[i].name != NULL; i++) {
76141309a54Smsaitoh if (strcmp(vmt_tclo_rpc[i].name, sc->sc_rpc_buf) == 0) {
76241309a54Smsaitoh vmt_tclo_rpc[i].cb(sc);
76341309a54Smsaitoh return (0);
76441309a54Smsaitoh }
76541309a54Smsaitoh }
76641309a54Smsaitoh
76741309a54Smsaitoh device_printf(sc->sc_dev, "unknown command: \"%s\"\n", name);
76841309a54Smsaitoh
76941309a54Smsaitoh return (-1);
77041309a54Smsaitoh }
77141309a54Smsaitoh
77241309a54Smsaitoh static void
vmt_tclo_tick(void * xarg)7730b42d22aSryo vmt_tclo_tick(void *xarg)
7740b42d22aSryo {
7750b42d22aSryo struct vmt_softc *sc = xarg;
7760b42d22aSryo u_int32_t rlen;
7770b42d22aSryo u_int16_t ack;
778c7dff692Smsaitoh int delay;
779c7dff692Smsaitoh
780c7dff692Smsaitoh /* By default, poll every second for new messages */
781c7dff692Smsaitoh delay = 1;
7820b42d22aSryo
7830b42d22aSryo /* reopen tclo channel if it's currently closed */
7840b42d22aSryo if (sc->sc_tclo_rpc.channel == 0 &&
7850b42d22aSryo sc->sc_tclo_rpc.cookie1 == 0 &&
7860b42d22aSryo sc->sc_tclo_rpc.cookie2 == 0) {
7870b42d22aSryo if (vm_rpc_open(&sc->sc_tclo_rpc, VM_RPC_OPEN_TCLO) != 0) {
7889e0e4167Smsaitoh device_printf(sc->sc_dev,
7899e0e4167Smsaitoh "unable to reopen TCLO channel\n");
790c7dff692Smsaitoh delay = 15;
791c7dff692Smsaitoh goto out;
7920b42d22aSryo }
7930b42d22aSryo
7949e0e4167Smsaitoh if (vm_rpc_send_str(&sc->sc_tclo_rpc,
7959e0e4167Smsaitoh VM_RPC_RESET_REPLY) != 0) {
7969e0e4167Smsaitoh device_printf(sc->sc_dev,
7979e0e4167Smsaitoh "failed to send reset reply\n");
7980b42d22aSryo sc->sc_rpc_error = 1;
7990b42d22aSryo goto out;
8000b42d22aSryo } else {
8010b42d22aSryo sc->sc_rpc_error = 0;
8020b42d22aSryo }
8030b42d22aSryo }
8040b42d22aSryo
8050b42d22aSryo if (sc->sc_tclo_ping) {
8060b42d22aSryo if (vm_rpc_send(&sc->sc_tclo_rpc, NULL, 0) != 0) {
8079e0e4167Smsaitoh device_printf(sc->sc_dev,
8089e0e4167Smsaitoh "failed to send TCLO outgoing ping\n");
8090b42d22aSryo sc->sc_rpc_error = 1;
8100b42d22aSryo goto out;
8110b42d22aSryo }
8120b42d22aSryo }
8130b42d22aSryo
8140b42d22aSryo if (vm_rpc_get_length(&sc->sc_tclo_rpc, &rlen, &ack) != 0) {
8159e0e4167Smsaitoh device_printf(sc->sc_dev,
8169e0e4167Smsaitoh "failed to get length of incoming TCLO data\n");
8170b42d22aSryo sc->sc_rpc_error = 1;
8180b42d22aSryo goto out;
8190b42d22aSryo }
8200b42d22aSryo
8210b42d22aSryo if (rlen == 0) {
8220b42d22aSryo sc->sc_tclo_ping = 1;
8230b42d22aSryo goto out;
8240b42d22aSryo }
8250b42d22aSryo
8260b42d22aSryo if (rlen >= VMT_RPC_BUFLEN) {
8270b42d22aSryo rlen = VMT_RPC_BUFLEN - 1;
8280b42d22aSryo }
8290b42d22aSryo if (vm_rpc_get_data(&sc->sc_tclo_rpc, sc->sc_rpc_buf, rlen, ack) != 0) {
8309e0e4167Smsaitoh device_printf(sc->sc_dev,
8319e0e4167Smsaitoh "failed to get incoming TCLO data\n");
8320b42d22aSryo sc->sc_rpc_error = 1;
8330b42d22aSryo goto out;
8340b42d22aSryo }
8350b42d22aSryo sc->sc_tclo_ping = 0;
8360b42d22aSryo
837c7dff692Smsaitoh /* The VM host can queue multiple messages; continue without delay */
838c7dff692Smsaitoh delay = 0;
839c7dff692Smsaitoh
8400b42d22aSryo #ifdef VMT_DEBUG
8410b42d22aSryo printf("vmware: received message '%s'\n", sc->sc_rpc_buf);
8420b42d22aSryo #endif
8430b42d22aSryo
84441309a54Smsaitoh if (vmt_tclo_process(sc, sc->sc_rpc_buf) != 0) {
8459e0e4167Smsaitoh if (vm_rpc_send_str(&sc->sc_tclo_rpc,
8469e0e4167Smsaitoh VM_RPC_REPLY_ERROR) != 0) {
8479e0e4167Smsaitoh device_printf(sc->sc_dev,
8489e0e4167Smsaitoh "error sending unknown command reply\n");
8490b42d22aSryo sc->sc_rpc_error = 1;
8500b42d22aSryo }
8510b42d22aSryo }
8520b42d22aSryo
853c7dff692Smsaitoh if (sc->sc_rpc_error == 1) {
854ce13a26bSmsaitoh /* On error, give time to recover and wait a second */
855c7dff692Smsaitoh delay = 1;
856c7dff692Smsaitoh }
857c7dff692Smsaitoh
858c7dff692Smsaitoh out:
859c7dff692Smsaitoh callout_schedule(&sc->sc_tclo_tick, hz * delay);
8600b42d22aSryo }
8610b42d22aSryo
8620b42d22aSryo static void
vm_cmd(struct vm_backdoor * frame)8630b42d22aSryo vm_cmd(struct vm_backdoor *frame)
8640b42d22aSryo {
8650b42d22aSryo BACKDOOR_OP(BACKDOOR_OP_CMD, frame);
8660b42d22aSryo }
8670b42d22aSryo
8680b42d22aSryo static void
vm_ins(struct vm_backdoor * frame)8690b42d22aSryo vm_ins(struct vm_backdoor *frame)
8700b42d22aSryo {
8710b42d22aSryo BACKDOOR_OP(BACKDOOR_OP_IN, frame);
8720b42d22aSryo }
8730b42d22aSryo
8740b42d22aSryo static void
vm_outs(struct vm_backdoor * frame)8750b42d22aSryo vm_outs(struct vm_backdoor *frame)
8760b42d22aSryo {
8770b42d22aSryo BACKDOOR_OP(BACKDOOR_OP_OUT, frame);
8780b42d22aSryo }
8790b42d22aSryo
8800b42d22aSryo static int
vm_rpc_open(struct vm_rpc * rpc,uint32_t proto)8810b42d22aSryo vm_rpc_open(struct vm_rpc *rpc, uint32_t proto)
8820b42d22aSryo {
8830b42d22aSryo struct vm_backdoor frame;
8840b42d22aSryo
8850b42d22aSryo memset(&frame, 0, sizeof(frame));
88658b879d3Sryo frame.eax = VM_MAGIC;
88758b879d3Sryo frame.ebx = proto | VM_RPC_FLAG_COOKIE;
88858b879d3Sryo frame.ecx = VM_REG_CMD_RPC(VM_RPC_OPEN);
88958b879d3Sryo frame.edx = VM_REG_PORT_CMD(0);
8900b42d22aSryo
8910b42d22aSryo vm_cmd(&frame);
8920b42d22aSryo
89358b879d3Sryo if (__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) != 1 ||
89458b879d3Sryo __SHIFTOUT(frame.edx, VM_REG_LOW_MASK) != 0) {
8950b42d22aSryo /* open-vm-tools retries without VM_RPC_FLAG_COOKIE here.. */
89658b879d3Sryo printf("vmware: open failed, eax=%#"PRIxREGISTER
89758b879d3Sryo ", ecx=%#"PRIxREGISTER", edx=%#"PRIxREGISTER"\n",
89858b879d3Sryo frame.eax, frame.ecx, frame.edx);
8990b42d22aSryo return EIO;
9000b42d22aSryo }
9010b42d22aSryo
90258b879d3Sryo rpc->channel = __SHIFTOUT(frame.edx, VM_REG_HIGH_MASK);
90358b879d3Sryo rpc->cookie1 = __SHIFTOUT(frame.esi, VM_REG_WORD_MASK);
90458b879d3Sryo rpc->cookie2 = __SHIFTOUT(frame.edi, VM_REG_WORD_MASK);
9050b42d22aSryo
9060b42d22aSryo return 0;
9070b42d22aSryo }
9080b42d22aSryo
9090b42d22aSryo static int
vm_rpc_close(struct vm_rpc * rpc)9100b42d22aSryo vm_rpc_close(struct vm_rpc *rpc)
9110b42d22aSryo {
9120b42d22aSryo struct vm_backdoor frame;
9130b42d22aSryo
9140b42d22aSryo memset(&frame, 0, sizeof(frame));
91558b879d3Sryo frame.eax = VM_MAGIC;
91658b879d3Sryo frame.ebx = 0;
91758b879d3Sryo frame.ecx = VM_REG_CMD_RPC(VM_RPC_CLOSE);
91858b879d3Sryo frame.edx = VM_REG_PORT_CMD(rpc->channel);
91958b879d3Sryo frame.edi = rpc->cookie2;
92058b879d3Sryo frame.esi = rpc->cookie1;
9210b42d22aSryo
9220b42d22aSryo vm_cmd(&frame);
9230b42d22aSryo
92458b879d3Sryo if (__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) == 0 ||
92558b879d3Sryo __SHIFTOUT(frame.ecx, VM_REG_LOW_MASK) != 0) {
92658b879d3Sryo printf("vmware: close failed, "
92758b879d3Sryo "eax=%#"PRIxREGISTER", ecx=%#"PRIxREGISTER"\n",
92858b879d3Sryo frame.eax, frame.ecx);
9290b42d22aSryo return EIO;
9300b42d22aSryo }
9310b42d22aSryo
9320b42d22aSryo rpc->channel = 0;
9330b42d22aSryo rpc->cookie1 = 0;
9340b42d22aSryo rpc->cookie2 = 0;
9350b42d22aSryo
9360b42d22aSryo return 0;
9370b42d22aSryo }
9380b42d22aSryo
9390b42d22aSryo static int
vm_rpc_send(const struct vm_rpc * rpc,const uint8_t * buf,uint32_t length)9400b42d22aSryo vm_rpc_send(const struct vm_rpc *rpc, const uint8_t *buf, uint32_t length)
9410b42d22aSryo {
9420b42d22aSryo struct vm_backdoor frame;
9430b42d22aSryo
9440b42d22aSryo /* Send the length of the command. */
9450b42d22aSryo memset(&frame, 0, sizeof(frame));
94658b879d3Sryo frame.eax = VM_MAGIC;
94758b879d3Sryo frame.ebx = length;
94858b879d3Sryo frame.ecx = VM_REG_CMD_RPC(VM_RPC_SET_LENGTH);
94958b879d3Sryo frame.edx = VM_REG_PORT_CMD(rpc->channel);
95058b879d3Sryo frame.esi = rpc->cookie1;
95158b879d3Sryo frame.edi = rpc->cookie2;
9520b42d22aSryo
9530b42d22aSryo vm_cmd(&frame);
9540b42d22aSryo
95558b879d3Sryo if ((__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) & VM_RPC_REPLY_SUCCESS) ==
95658b879d3Sryo 0) {
95758b879d3Sryo printf("vmware: sending length failed, "
95858b879d3Sryo "eax=%#"PRIxREGISTER", ecx=%#"PRIxREGISTER"\n",
95958b879d3Sryo frame.eax, frame.ecx);
9600b42d22aSryo return EIO;
9610b42d22aSryo }
9620b42d22aSryo
9630b42d22aSryo if (length == 0)
9640b42d22aSryo return 0; /* Only need to poke once if command is null. */
9650b42d22aSryo
9660b42d22aSryo /* Send the command using enhanced RPC. */
9670b42d22aSryo memset(&frame, 0, sizeof(frame));
96858b879d3Sryo frame.eax = VM_MAGIC;
96958b879d3Sryo frame.ebx = VM_RPC_ENH_DATA;
97058b879d3Sryo frame.ecx = length;
97158b879d3Sryo frame.edx = VM_REG_PORT_RPC(rpc->channel);
97258b879d3Sryo frame.ebp = rpc->cookie1;
97358b879d3Sryo frame.edi = rpc->cookie2;
97458b879d3Sryo frame.esi = (register_t)buf;
9750b42d22aSryo
9760b42d22aSryo vm_outs(&frame);
9770b42d22aSryo
97858b879d3Sryo if (__SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) != VM_RPC_ENH_DATA) {
9790b42d22aSryo /* open-vm-tools retries on VM_RPC_REPLY_CHECKPOINT */
98058b879d3Sryo printf("vmware: send failed, ebx=%#"PRIxREGISTER"\n",
98158b879d3Sryo frame.ebx);
9820b42d22aSryo return EIO;
9830b42d22aSryo }
9840b42d22aSryo
9850b42d22aSryo return 0;
9860b42d22aSryo }
9870b42d22aSryo
9880b42d22aSryo static int
vm_rpc_send_str(const struct vm_rpc * rpc,const uint8_t * str)9890b42d22aSryo vm_rpc_send_str(const struct vm_rpc *rpc, const uint8_t *str)
9900b42d22aSryo {
9910b42d22aSryo return vm_rpc_send(rpc, str, strlen(str));
9920b42d22aSryo }
9930b42d22aSryo
9940b42d22aSryo static int
vm_rpc_get_data(const struct vm_rpc * rpc,char * data,uint32_t length,uint16_t dataid)9950b42d22aSryo vm_rpc_get_data(const struct vm_rpc *rpc, char *data, uint32_t length,
9960b42d22aSryo uint16_t dataid)
9970b42d22aSryo {
9980b42d22aSryo struct vm_backdoor frame;
9990b42d22aSryo
10000b42d22aSryo /* Get data using enhanced RPC. */
10010b42d22aSryo memset(&frame, 0, sizeof(frame));
100258b879d3Sryo frame.eax = VM_MAGIC;
100358b879d3Sryo frame.ebx = VM_RPC_ENH_DATA;
100458b879d3Sryo frame.ecx = length;
100558b879d3Sryo frame.edx = VM_REG_PORT_RPC(rpc->channel);
100658b879d3Sryo frame.esi = rpc->cookie1;
100758b879d3Sryo frame.edi = (register_t)data;
100858b879d3Sryo frame.ebp = rpc->cookie2;
10090b42d22aSryo
10100b42d22aSryo vm_ins(&frame);
10110b42d22aSryo
10120b42d22aSryo /* NUL-terminate the data */
10130b42d22aSryo data[length] = '\0';
10140b42d22aSryo
101558b879d3Sryo if (__SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) != VM_RPC_ENH_DATA) {
101658b879d3Sryo printf("vmware: get data failed, ebx=%#"PRIxREGISTER"\n",
101758b879d3Sryo frame.ebx);
10180b42d22aSryo return EIO;
10190b42d22aSryo }
10200b42d22aSryo
10210b42d22aSryo /* Acknowledge data received. */
10220b42d22aSryo memset(&frame, 0, sizeof(frame));
102358b879d3Sryo frame.eax = VM_MAGIC;
102458b879d3Sryo frame.ebx = dataid;
102558b879d3Sryo frame.ecx = VM_REG_CMD_RPC(VM_RPC_GET_END);
102658b879d3Sryo frame.edx = VM_REG_PORT_CMD(rpc->channel);
102758b879d3Sryo frame.esi = rpc->cookie1;
102858b879d3Sryo frame.edi = rpc->cookie2;
10290b42d22aSryo
10300b42d22aSryo vm_cmd(&frame);
10310b42d22aSryo
103258b879d3Sryo if (__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) == 0) {
103358b879d3Sryo printf("vmware: ack data failed, "
103458b879d3Sryo "eax=%#"PRIxREGISTER", ecx=%#"PRIxREGISTER"\n",
103558b879d3Sryo frame.eax, frame.ecx);
10360b42d22aSryo return EIO;
10370b42d22aSryo }
10380b42d22aSryo
10390b42d22aSryo return 0;
10400b42d22aSryo }
10410b42d22aSryo
10420b42d22aSryo static int
vm_rpc_get_length(const struct vm_rpc * rpc,uint32_t * length,uint16_t * dataid)10430b42d22aSryo vm_rpc_get_length(const struct vm_rpc *rpc, uint32_t *length, uint16_t *dataid)
10440b42d22aSryo {
10450b42d22aSryo struct vm_backdoor frame;
10460b42d22aSryo
10470b42d22aSryo memset(&frame, 0, sizeof(frame));
104858b879d3Sryo frame.eax = VM_MAGIC;
104958b879d3Sryo frame.ebx = 0;
105058b879d3Sryo frame.ecx = VM_REG_CMD_RPC(VM_RPC_GET_LENGTH);
105158b879d3Sryo frame.edx = VM_REG_PORT_CMD(rpc->channel);
105258b879d3Sryo frame.esi = rpc->cookie1;
105358b879d3Sryo frame.edi = rpc->cookie2;
10540b42d22aSryo
10550b42d22aSryo vm_cmd(&frame);
10560b42d22aSryo
105758b879d3Sryo if ((__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) & VM_RPC_REPLY_SUCCESS) ==
105858b879d3Sryo 0) {
105958b879d3Sryo printf("vmware: get length failed, "
106058b879d3Sryo "eax=%#"PRIxREGISTER", ecx=%#"PRIxREGISTER"\n",
106158b879d3Sryo frame.eax, frame.ecx);
10620b42d22aSryo return EIO;
10630b42d22aSryo }
106458b879d3Sryo if ((__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) & VM_RPC_REPLY_DORECV) ==
106558b879d3Sryo 0) {
10660b42d22aSryo *length = 0;
10670b42d22aSryo *dataid = 0;
10680b42d22aSryo } else {
106958b879d3Sryo *length = __SHIFTOUT(frame.ebx, VM_REG_WORD_MASK);
107058b879d3Sryo *dataid = __SHIFTOUT(frame.edx, VM_REG_HIGH_MASK);
10710b42d22aSryo }
10720b42d22aSryo
10730b42d22aSryo return 0;
10740b42d22aSryo }
10750b42d22aSryo
10760b42d22aSryo static int
vm_rpci_response_successful(struct vmt_softc * sc)10770b42d22aSryo vm_rpci_response_successful(struct vmt_softc *sc)
10780b42d22aSryo {
10790b42d22aSryo return (sc->sc_rpc_buf[0] == '1' && sc->sc_rpc_buf[1] == ' ');
10800b42d22aSryo }
10810b42d22aSryo
10820b42d22aSryo static int
vm_rpc_send_rpci_tx_buf(struct vmt_softc * sc,const uint8_t * buf,uint32_t length)10839e0e4167Smsaitoh vm_rpc_send_rpci_tx_buf(struct vmt_softc *sc, const uint8_t *buf,
10849e0e4167Smsaitoh uint32_t length)
10850b42d22aSryo {
10860b42d22aSryo struct vm_rpc rpci;
10870b42d22aSryo u_int32_t rlen;
10880b42d22aSryo u_int16_t ack;
10890b42d22aSryo int result = 0;
10900b42d22aSryo
10910b42d22aSryo if (vm_rpc_open(&rpci, VM_RPC_OPEN_RPCI) != 0) {
10920b42d22aSryo device_printf(sc->sc_dev, "rpci channel open failed\n");
10930b42d22aSryo return EIO;
10940b42d22aSryo }
10950b42d22aSryo
10960b42d22aSryo if (vm_rpc_send(&rpci, sc->sc_rpc_buf, length) != 0) {
10970b42d22aSryo device_printf(sc->sc_dev, "unable to send rpci command\n");
10980b42d22aSryo result = EIO;
10990b42d22aSryo goto out;
11000b42d22aSryo }
11010b42d22aSryo
11020b42d22aSryo if (vm_rpc_get_length(&rpci, &rlen, &ack) != 0) {
11039e0e4167Smsaitoh device_printf(sc->sc_dev,
11049e0e4167Smsaitoh "failed to get length of rpci response data\n");
11050b42d22aSryo result = EIO;
11060b42d22aSryo goto out;
11070b42d22aSryo }
11080b42d22aSryo
11090b42d22aSryo if (rlen > 0) {
11100b42d22aSryo if (rlen >= VMT_RPC_BUFLEN) {
11110b42d22aSryo rlen = VMT_RPC_BUFLEN - 1;
11120b42d22aSryo }
11130b42d22aSryo
11140b42d22aSryo if (vm_rpc_get_data(&rpci, sc->sc_rpc_buf, rlen, ack) != 0) {
11159e0e4167Smsaitoh device_printf(sc->sc_dev,
11169e0e4167Smsaitoh "failed to get rpci response data\n");
11170b42d22aSryo result = EIO;
11180b42d22aSryo goto out;
11190b42d22aSryo }
11200b42d22aSryo }
11210b42d22aSryo
11220b42d22aSryo out:
11230b42d22aSryo if (vm_rpc_close(&rpci) != 0) {
11240b42d22aSryo device_printf(sc->sc_dev, "unable to close rpci channel\n");
11250b42d22aSryo }
11260b42d22aSryo
11270b42d22aSryo return result;
11280b42d22aSryo }
11290b42d22aSryo
11300b42d22aSryo static int
vm_rpc_send_rpci_tx(struct vmt_softc * sc,const char * fmt,...)11310b42d22aSryo vm_rpc_send_rpci_tx(struct vmt_softc *sc, const char *fmt, ...)
11320b42d22aSryo {
11330b42d22aSryo va_list args;
11340b42d22aSryo int len;
11350b42d22aSryo
11360b42d22aSryo va_start(args, fmt);
11370b42d22aSryo len = vsnprintf(sc->sc_rpc_buf, VMT_RPC_BUFLEN, fmt, args);
11380b42d22aSryo va_end(args);
11390b42d22aSryo
11400b42d22aSryo if (len >= VMT_RPC_BUFLEN) {
11419e0e4167Smsaitoh device_printf(sc->sc_dev,
11429e0e4167Smsaitoh "rpci command didn't fit in buffer\n");
11430b42d22aSryo return EIO;
11440b42d22aSryo }
11450b42d22aSryo
11460b42d22aSryo return vm_rpc_send_rpci_tx_buf(sc, sc->sc_rpc_buf, len);
11470b42d22aSryo }
11480b42d22aSryo
11490b42d22aSryo #if 0
11500b42d22aSryo struct vm_backdoor frame;
11510b42d22aSryo
11520b42d22aSryo memset(&frame, 0, sizeof(frame));
11530b42d22aSryo
115458b879d3Sryo frame.eax = VM_MAGIC;
115558b879d3Sryo frame.ecx = VM_CMD_GET_VERSION;
115658b879d3Sryo frame.edx = VM_PORT_CMD;
11570b42d22aSryo
11580b42d22aSryo printf("\n");
115958b879d3Sryo printf("eax %#"PRIxREGISTER"\n", frame.eax);
116058b879d3Sryo printf("ebx %#"PRIxREGISTER"\n", frame.ebx);
116158b879d3Sryo printf("ecx %#"PRIxREGISTER"\n", frame.ecx);
116258b879d3Sryo printf("edx %#"PRIxREGISTER"\n", frame.edx)
116358b879d3Sryo printf("ebp %#"PRIxREGISTER"\n", frame.ebp);
116458b879d3Sryo printf("edi %#"PRIxREGISTER"\n", frame.edi);
116558b879d3Sryo printf("esi %#"PRIxREGISTER"\n", frame.esi);
11660b42d22aSryo
11670b42d22aSryo vm_cmd(&frame);
11680b42d22aSryo
11690b42d22aSryo printf("-\n");
117058b879d3Sryo printf("eax %#"PRIxREGISTER"\n", frame.eax);
117158b879d3Sryo printf("ebx %#"PRIxREGISTER"\n", frame.ebx);
117258b879d3Sryo printf("ecx %#"PRIxREGISTER"\n", frame.ecx);
117358b879d3Sryo printf("edx %#"PRIxREGISTER"\n", frame.edx);
117458b879d3Sryo printf("ebp %#"PRIxREGISTER"\n", frame.ebp);
117558b879d3Sryo printf("edi %#"PRIxREGISTER"\n", frame.edi);
117658b879d3Sryo printf("esi %#"PRIxREGISTER"\n", frame.esi);
11770b42d22aSryo #endif
11780b42d22aSryo
11790b42d22aSryo /*
11800b42d22aSryo * Notes on tracing backdoor activity in vmware-guestd:
11810b42d22aSryo *
11820b42d22aSryo * - Find the addresses of the inl / rep insb / rep outsb
11830b42d22aSryo * instructions used to perform backdoor operations.
11840b42d22aSryo * One way to do this is to disassemble vmware-guestd:
11850b42d22aSryo *
11860b42d22aSryo * $ objdump -S /emul/freebsd/sbin/vmware-guestd > vmware-guestd.S
11870b42d22aSryo *
11880b42d22aSryo * and search for '<tab>in ' in the resulting file. The rep insb and
11890b42d22aSryo * rep outsb code is directly below that.
11900b42d22aSryo *
11910b42d22aSryo * - Run vmware-guestd under gdb, setting up breakpoints as follows:
11920b42d22aSryo * (the addresses shown here are the ones from VMware-server-1.0.10-203137,
11930b42d22aSryo * the last version that actually works in FreeBSD emulation on OpenBSD)
11940b42d22aSryo *
11950b42d22aSryo * break *0x805497b (address of 'in' instruction)
11960b42d22aSryo * commands 1
11970b42d22aSryo * silent
11980b42d22aSryo * echo INOUT\n
11990b42d22aSryo * print/x $ecx
12000b42d22aSryo * print/x $ebx
12010b42d22aSryo * print/x $edx
12020b42d22aSryo * continue
12030b42d22aSryo * end
12040b42d22aSryo * break *0x805497c (address of instruction after 'in')
12050b42d22aSryo * commands 2
12060b42d22aSryo * silent
12070b42d22aSryo * echo ===\n
12080b42d22aSryo * print/x $ecx
12090b42d22aSryo * print/x $ebx
12100b42d22aSryo * print/x $edx
12110b42d22aSryo * echo \n
12120b42d22aSryo * continue
12130b42d22aSryo * end
12140b42d22aSryo * break *0x80549b7 (address of instruction before 'rep insb')
12150b42d22aSryo * commands 3
12160b42d22aSryo * silent
12170b42d22aSryo * set variable $inaddr = $edi
12180b42d22aSryo * set variable $incount = $ecx
12190b42d22aSryo * continue
12200b42d22aSryo * end
12210b42d22aSryo * break *0x80549ba (address of instruction after 'rep insb')
12220b42d22aSryo * commands 4
12230b42d22aSryo * silent
12240b42d22aSryo * echo IN\n
12250b42d22aSryo * print $incount
12260b42d22aSryo * x/s $inaddr
12270b42d22aSryo * echo \n
12280b42d22aSryo * continue
12290b42d22aSryo * end
12300b42d22aSryo * break *0x80549fb (address of instruction before 'rep outsb')
12310b42d22aSryo * commands 5
12320b42d22aSryo * silent
12330b42d22aSryo * echo OUT\n
12340b42d22aSryo * print $ecx
12350b42d22aSryo * x/s $esi
12360b42d22aSryo * echo \n
12370b42d22aSryo * continue
12380b42d22aSryo * end
12390b42d22aSryo *
12400b42d22aSryo * This will produce a log of the backdoor operations, including the
12410b42d22aSryo * data sent and received and the relevant register values. You can then
12420b42d22aSryo * match the register values to the various constants in this file.
12430b42d22aSryo */
1244