Home | History | Annotate | Line # | Download | only in vmt
vmt_subr.c revision 1.4
      1 /* $NetBSD: vmt_subr.c,v 1.4 2024/03/20 23:31:54 msaitoh Exp $ */
      2 /* $OpenBSD: vmt.c,v 1.11 2011/01/27 21:29:25 dtucker Exp $ */
      3 
      4 /*
      5  * Copyright (c) 2007 David Crawshaw <david (at) zentus.com>
      6  * Copyright (c) 2008 David Gwynne <dlg (at) openbsd.org>
      7  *
      8  * Permission to use, copy, modify, and distribute this software for any
      9  * purpose with or without fee is hereby granted, provided that the above
     10  * copyright notice and this permission notice appear in all copies.
     11  *
     12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     19  */
     20 
     21 /*
     22  * Protocol reverse engineered by Ken Kato:
     23  * https://sites.google.com/site/chitchatvmback/backdoor
     24  */
     25 
     26 #include <sys/param.h>
     27 #include <sys/types.h>
     28 #include <sys/callout.h>
     29 #include <sys/device.h>
     30 #include <sys/endian.h>
     31 #include <sys/kernel.h>
     32 #include <sys/kmem.h>
     33 #include <sys/module.h>
     34 #include <sys/proc.h>
     35 #include <sys/reboot.h>
     36 #include <sys/socket.h>
     37 #include <sys/sysctl.h>
     38 #include <sys/syslog.h>
     39 #include <sys/systm.h>
     40 #include <sys/timetc.h>
     41 
     42 #include <net/if.h>
     43 #include <netinet/in.h>
     44 
     45 #include <dev/sysmon/sysmonvar.h>
     46 #include <dev/sysmon/sysmon_taskq.h>
     47 #include <dev/vmt/vmtreg.h>
     48 #include <dev/vmt/vmtvar.h>
     49 
     50 /* #define VMT_DEBUG */
     51 
     52 static int vmt_sysctl_setup_root(device_t);
     53 static int vmt_sysctl_setup_clock_sync(device_t, const struct sysctlnode *);
     54 static int vmt_sysctl_update_clock_sync_period(SYSCTLFN_PROTO);
     55 
     56 static void vm_cmd(struct vm_backdoor *);
     57 static void vm_ins(struct vm_backdoor *);
     58 static void vm_outs(struct vm_backdoor *);
     59 
     60 /* Functions for communicating with the VM Host. */
     61 static int vm_rpc_open(struct vm_rpc *, uint32_t);
     62 static int vm_rpc_close(struct vm_rpc *);
     63 static int vm_rpc_send(const struct vm_rpc *, const uint8_t *, uint32_t);
     64 static int vm_rpc_send_str(const struct vm_rpc *, const uint8_t *);
     65 static int vm_rpc_get_length(const struct vm_rpc *, uint32_t *, uint16_t *);
     66 static int vm_rpc_get_data(const struct vm_rpc *, char *, uint32_t, uint16_t);
     67 static int vm_rpc_send_rpci_tx_buf(struct vmt_softc *, const uint8_t *, uint32_t);
     68 static int vm_rpc_send_rpci_tx(struct vmt_softc *, const char *, ...)
     69     __printflike(2, 3);
     70 static int vm_rpci_response_successful(struct vmt_softc *);
     71 
     72 static void vmt_tclo_state_change_success(struct vmt_softc *, int, char);
     73 static void vmt_do_reboot(struct vmt_softc *);
     74 static void vmt_do_shutdown(struct vmt_softc *);
     75 
     76 static void vmt_update_guest_info(struct vmt_softc *);
     77 static void vmt_update_guest_uptime(struct vmt_softc *);
     78 static void vmt_sync_guest_clock(struct vmt_softc *);
     79 
     80 static void vmt_tick(void *);
     81 static void vmt_tclo_tick(void *);
     82 static void vmt_clock_sync_tick(void *);
     83 static bool vmt_shutdown(device_t, int);
     84 static void vmt_pswitch_event(void *);
     85 
     86 extern char hostname[MAXHOSTNAMELEN];
     87 
     88 static void
     89 vmt_probe_cmd(struct vm_backdoor *frame, uint16_t cmd)
     90 {
     91 	memset(frame, 0, sizeof(*frame));
     92 
     93 	frame->eax = VM_MAGIC;
     94 	frame->ebx = ~VM_MAGIC & VM_REG_WORD_MASK;
     95 	frame->ecx = VM_REG_CMD(0xffff, cmd);
     96 	frame->edx = VM_REG_CMD(0, VM_PORT_CMD);
     97 
     98 	vm_cmd(frame);
     99 }
    100 
    101 bool
    102 vmt_probe(void)
    103 {
    104 	struct vm_backdoor frame;
    105 
    106 	vmt_probe_cmd(&frame, VM_CMD_GET_VERSION);
    107 	if (__SHIFTOUT(frame.eax, VM_REG_WORD_MASK) == 0xffffffff ||
    108 	    __SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) != VM_MAGIC)
    109 		return false;
    110 
    111 	vmt_probe_cmd(&frame, VM_CMD_GET_SPEED);
    112 	if (__SHIFTOUT(frame.eax, VM_REG_WORD_MASK) == VM_MAGIC)
    113 		return false;
    114 
    115 	return true;
    116 }
    117 
    118 void
    119 vmt_common_attach(struct vmt_softc *sc)
    120 {
    121 	device_t self;
    122 	struct vm_backdoor frame;
    123 	int rv;
    124 
    125 	self = sc->sc_dev;
    126 	sc->sc_log = NULL;
    127 
    128 	/* check again */
    129 	vmt_probe_cmd(&frame, VM_CMD_GET_VERSION);
    130 	if (__SHIFTOUT(frame.eax, VM_REG_WORD_MASK) == 0xffffffff ||
    131 	    __SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) != VM_MAGIC) {
    132 		aprint_error_dev(self, "failed to get VMware version\n");
    133 		return;
    134 	}
    135 
    136 	/* show uuid */
    137 	{
    138 		struct uuid uuid;
    139 		uint32_t u;
    140 
    141 		vmt_probe_cmd(&frame, VM_CMD_GET_BIOS_UUID);
    142 		uuid.time_low =
    143 		    bswap32(__SHIFTOUT(frame.eax, VM_REG_WORD_MASK));
    144 		u = bswap32(__SHIFTOUT(frame.ebx, VM_REG_WORD_MASK));
    145 		uuid.time_mid = u >> 16;
    146 		uuid.time_hi_and_version = u;
    147 		u = bswap32(__SHIFTOUT(frame.ecx, VM_REG_WORD_MASK));
    148 		uuid.clock_seq_hi_and_reserved = u >> 24;
    149 		uuid.clock_seq_low = u >> 16;
    150 		uuid.node[0] = u >> 8;
    151 		uuid.node[1] = u;
    152 		u = bswap32(__SHIFTOUT(frame.edx, VM_REG_WORD_MASK));
    153 		uuid.node[2] = u >> 24;
    154 		uuid.node[3] = u >> 16;
    155 		uuid.node[4] = u >> 8;
    156 		uuid.node[5] = u;
    157 
    158 		uuid_snprintf(sc->sc_uuid, sizeof(sc->sc_uuid), &uuid);
    159 		aprint_verbose_dev(sc->sc_dev, "UUID: %s\n", sc->sc_uuid);
    160 	}
    161 
    162 	callout_init(&sc->sc_tick, 0);
    163 	callout_init(&sc->sc_tclo_tick, 0);
    164 	callout_init(&sc->sc_clock_sync_tick, 0);
    165 
    166 	sc->sc_clock_sync_period_seconds = VMT_CLOCK_SYNC_PERIOD_SECONDS;
    167 
    168 	rv = vmt_sysctl_setup_root(self);
    169 	if (rv != 0) {
    170 		aprint_error_dev(self, "failed to initialize sysctl "
    171 		    "(err %d)\n", rv);
    172 		goto free;
    173 	}
    174 
    175 	sc->sc_rpc_buf = kmem_alloc(VMT_RPC_BUFLEN, KM_SLEEP);
    176 
    177 	if (vm_rpc_open(&sc->sc_tclo_rpc, VM_RPC_OPEN_TCLO) != 0) {
    178 		aprint_error_dev(self, "failed to open backdoor RPC channel "
    179 		    "(TCLO protocol)\n");
    180 		goto free;
    181 	}
    182 	sc->sc_tclo_rpc_open = true;
    183 
    184 	/* don't know if this is important at all yet */
    185 	if (vm_rpc_send_rpci_tx(sc,
    186 	    "tools.capability.hgfs_server toolbox 1") != 0) {
    187 		aprint_error_dev(self,
    188 		    "failed to set HGFS server capability\n");
    189 		goto free;
    190 	}
    191 
    192 	pmf_device_register1(self, NULL, NULL, vmt_shutdown);
    193 
    194 	sysmon_task_queue_init();
    195 
    196 	sc->sc_ev_power.ev_smpsw.smpsw_type = PSWITCH_TYPE_POWER;
    197 	sc->sc_ev_power.ev_smpsw.smpsw_name = device_xname(self);
    198 	sc->sc_ev_power.ev_code = PSWITCH_EVENT_PRESSED;
    199 	sysmon_pswitch_register(&sc->sc_ev_power.ev_smpsw);
    200 	sc->sc_ev_reset.ev_smpsw.smpsw_type = PSWITCH_TYPE_RESET;
    201 	sc->sc_ev_reset.ev_smpsw.smpsw_name = device_xname(self);
    202 	sc->sc_ev_reset.ev_code = PSWITCH_EVENT_PRESSED;
    203 	sysmon_pswitch_register(&sc->sc_ev_reset.ev_smpsw);
    204 	sc->sc_ev_sleep.ev_smpsw.smpsw_type = PSWITCH_TYPE_SLEEP;
    205 	sc->sc_ev_sleep.ev_smpsw.smpsw_name = device_xname(self);
    206 	sc->sc_ev_sleep.ev_code = PSWITCH_EVENT_RELEASED;
    207 	sysmon_pswitch_register(&sc->sc_ev_sleep.ev_smpsw);
    208 	sc->sc_smpsw_valid = true;
    209 
    210 	callout_setfunc(&sc->sc_tick, vmt_tick, sc);
    211 	callout_schedule(&sc->sc_tick, hz);
    212 
    213 	callout_setfunc(&sc->sc_tclo_tick, vmt_tclo_tick, sc);
    214 	callout_schedule(&sc->sc_tclo_tick, hz);
    215 	sc->sc_tclo_ping = 1;
    216 
    217 	callout_setfunc(&sc->sc_clock_sync_tick, vmt_clock_sync_tick, sc);
    218 	callout_schedule(&sc->sc_clock_sync_tick,
    219 	    mstohz(sc->sc_clock_sync_period_seconds * 1000));
    220 
    221 	vmt_sync_guest_clock(sc);
    222 
    223 	return;
    224 
    225 free:
    226 	if (sc->sc_rpc_buf)
    227 		kmem_free(sc->sc_rpc_buf, VMT_RPC_BUFLEN);
    228 	pmf_device_register(self, NULL, NULL);
    229 	if (sc->sc_log)
    230 		sysctl_teardown(&sc->sc_log);
    231 }
    232 
    233 int
    234 vmt_common_detach(struct vmt_softc *sc)
    235 {
    236 	if (sc->sc_tclo_rpc_open)
    237 		vm_rpc_close(&sc->sc_tclo_rpc);
    238 
    239 	if (sc->sc_smpsw_valid) {
    240 		sysmon_pswitch_unregister(&sc->sc_ev_sleep.ev_smpsw);
    241 		sysmon_pswitch_unregister(&sc->sc_ev_reset.ev_smpsw);
    242 		sysmon_pswitch_unregister(&sc->sc_ev_power.ev_smpsw);
    243 	}
    244 
    245 	callout_halt(&sc->sc_tick, NULL);
    246 	callout_destroy(&sc->sc_tick);
    247 
    248 	callout_halt(&sc->sc_tclo_tick, NULL);
    249 	callout_destroy(&sc->sc_tclo_tick);
    250 
    251 	callout_halt(&sc->sc_clock_sync_tick, NULL);
    252 	callout_destroy(&sc->sc_clock_sync_tick);
    253 
    254 	if (sc->sc_rpc_buf)
    255 		kmem_free(sc->sc_rpc_buf, VMT_RPC_BUFLEN);
    256 
    257 	if (sc->sc_log) {
    258 		sysctl_teardown(&sc->sc_log);
    259 		sc->sc_log = NULL;
    260 	}
    261 
    262 	return 0;
    263 }
    264 
    265 static int
    266 vmt_sysctl_setup_root(device_t self)
    267 {
    268 	const struct sysctlnode *machdep_node, *vmt_node;
    269 	struct vmt_softc *sc = device_private(self);
    270 	int rv;
    271 
    272 	rv = sysctl_createv(&sc->sc_log, 0, NULL, &machdep_node,
    273 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
    274 	    NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
    275 	if (rv != 0)
    276 		goto fail;
    277 
    278 	rv = sysctl_createv(&sc->sc_log, 0, &machdep_node, &vmt_node,
    279 	    0, CTLTYPE_NODE, device_xname(self), NULL,
    280 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
    281 	if (rv != 0)
    282 		goto fail;
    283 
    284 	rv = sysctl_createv(&sc->sc_log, 0, &vmt_node, NULL,
    285 	    CTLFLAG_READONLY, CTLTYPE_STRING, "uuid",
    286 	    SYSCTL_DESCR("UUID of virtual machine"),
    287 	    NULL, 0, sc->sc_uuid, 0,
    288 	    CTL_CREATE, CTL_EOL);
    289 
    290 	rv = vmt_sysctl_setup_clock_sync(self, vmt_node);
    291 	if (rv != 0)
    292 		goto fail;
    293 
    294 	return 0;
    295 
    296 fail:
    297 	sysctl_teardown(&sc->sc_log);
    298 	sc->sc_log = NULL;
    299 
    300 	return rv;
    301 }
    302 
    303 static int
    304 vmt_sysctl_setup_clock_sync(device_t self, const struct sysctlnode *root_node)
    305 {
    306 	const struct sysctlnode *node, *period_node;
    307 	struct vmt_softc *sc = device_private(self);
    308 	int rv;
    309 
    310 	rv = sysctl_createv(&sc->sc_log, 0, &root_node, &node,
    311 	    0, CTLTYPE_NODE, "clock_sync", NULL,
    312 	    NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
    313 	if (rv != 0)
    314 		return rv;
    315 
    316 	rv = sysctl_createv(&sc->sc_log, 0, &node, &period_node,
    317 	    CTLFLAG_READWRITE, CTLTYPE_INT, "period",
    318 	    SYSCTL_DESCR("Period, in seconds, at which to update the "
    319 		"guest's clock"),
    320 	    vmt_sysctl_update_clock_sync_period, 0, (void *)sc, 0,
    321 	    CTL_CREATE, CTL_EOL);
    322 	return rv;
    323 }
    324 
    325 static int
    326 vmt_sysctl_update_clock_sync_period(SYSCTLFN_ARGS)
    327 {
    328 	int error, period;
    329 	struct sysctlnode node;
    330 	struct vmt_softc *sc;
    331 
    332 	node = *rnode;
    333 	sc = (struct vmt_softc *)node.sysctl_data;
    334 
    335 	period = sc->sc_clock_sync_period_seconds;
    336 	node.sysctl_data = &period;
    337 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
    338 	if (error || newp == NULL)
    339 		return error;
    340 
    341 	if (sc->sc_clock_sync_period_seconds != period) {
    342 		callout_halt(&sc->sc_clock_sync_tick, NULL);
    343 		sc->sc_clock_sync_period_seconds = period;
    344 		if (sc->sc_clock_sync_period_seconds > 0)
    345 			callout_schedule(&sc->sc_clock_sync_tick,
    346 			    mstohz(sc->sc_clock_sync_period_seconds * 1000));
    347 	}
    348 	return 0;
    349 }
    350 
    351 static void
    352 vmt_clock_sync_tick(void *xarg)
    353 {
    354 	struct vmt_softc *sc = xarg;
    355 
    356 	vmt_sync_guest_clock(sc);
    357 
    358 	callout_schedule(&sc->sc_clock_sync_tick,
    359 	    mstohz(sc->sc_clock_sync_period_seconds * 1000));
    360 }
    361 
    362 static void
    363 vmt_update_guest_uptime(struct vmt_softc *sc)
    364 {
    365 	/* host wants uptime in hundredths of a second */
    366 	if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo  %d %" PRId64 "00",
    367 	    VM_GUEST_INFO_UPTIME, time_uptime) != 0) {
    368 		device_printf(sc->sc_dev, "unable to set guest uptime\n");
    369 		sc->sc_rpc_error = 1;
    370 	}
    371 }
    372 
    373 static void
    374 vmt_update_guest_info(struct vmt_softc *sc)
    375 {
    376 	if (strncmp(sc->sc_hostname, hostname, sizeof(sc->sc_hostname)) != 0) {
    377 		strlcpy(sc->sc_hostname, hostname, sizeof(sc->sc_hostname));
    378 		if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo  %d %s",
    379 		    VM_GUEST_INFO_DNS_NAME, sc->sc_hostname) != 0) {
    380 			device_printf(sc->sc_dev, "unable to set hostname\n");
    381 			sc->sc_rpc_error = 1;
    382 		}
    383 	}
    384 
    385 	/*
    386 	 * we're supposed to pass the full network address information back
    387 	 * here, but that involves xdr (sunrpc) data encoding, which seems
    388 	 * a bit unreasonable.
    389 	 */
    390 
    391 	if (sc->sc_set_guest_os == 0) {
    392 		if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo  %d %s %s %s",
    393 		    VM_GUEST_INFO_OS_NAME_FULL,
    394 		    ostype, osrelease, machine_arch) != 0) {
    395 			device_printf(sc->sc_dev,
    396 			    "unable to set full guest OS\n");
    397 			sc->sc_rpc_error = 1;
    398 		}
    399 
    400 		/*
    401 		 * Host doesn't like it if we send an OS name it doesn't
    402 		 * recognise, so use "other" for i386 and "other-64" for amd64.
    403 		 */
    404 		if (vm_rpc_send_rpci_tx(sc, "SetGuestInfo  %d %s",
    405 		    VM_GUEST_INFO_OS_NAME, VM_OS_NAME) != 0) {
    406 			device_printf(sc->sc_dev, "unable to set guest OS\n");
    407 			sc->sc_rpc_error = 1;
    408 		}
    409 
    410 		sc->sc_set_guest_os = 1;
    411 	}
    412 }
    413 
    414 static void
    415 vmt_sync_guest_clock(struct vmt_softc *sc)
    416 {
    417 	struct vm_backdoor frame;
    418 	struct timespec ts;
    419 
    420 	memset(&frame, 0, sizeof(frame));
    421 	frame.eax = VM_MAGIC;
    422 	frame.ecx = VM_CMD_GET_TIME_FULL;
    423 	frame.edx = VM_REG_CMD(0, VM_PORT_CMD);
    424 	vm_cmd(&frame);
    425 
    426 	if (__SHIFTOUT(frame.eax, VM_REG_WORD_MASK) != 0xffffffff) {
    427 		ts.tv_sec = ((uint64_t)(
    428 		    __SHIFTOUT(frame.esi, VM_REG_WORD_MASK) << 32)) |
    429 		    __SHIFTOUT(frame.edx, VM_REG_WORD_MASK);
    430 		ts.tv_nsec = __SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) * 1000;
    431 		tc_setclock(&ts);
    432 	}
    433 }
    434 
    435 static void
    436 vmt_tick(void *xarg)
    437 {
    438 	struct vmt_softc *sc = xarg;
    439 
    440 	vmt_update_guest_info(sc);
    441 	vmt_update_guest_uptime(sc);
    442 
    443 	callout_schedule(&sc->sc_tick, hz * 15);
    444 }
    445 
    446 static void
    447 vmt_tclo_state_change_success(struct vmt_softc *sc, int success, char state)
    448 {
    449 	if (vm_rpc_send_rpci_tx(sc, "tools.os.statechange.status %d %d",
    450 	    success, state) != 0) {
    451 		device_printf(sc->sc_dev,
    452 		    "unable to send state change result\n");
    453 		sc->sc_rpc_error = 1;
    454 	}
    455 }
    456 
    457 static void
    458 vmt_do_shutdown(struct vmt_softc *sc)
    459 {
    460 	vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_HALT);
    461 	vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK);
    462 
    463 	device_printf(sc->sc_dev, "host requested shutdown\n");
    464 	sysmon_task_queue_sched(0, vmt_pswitch_event, &sc->sc_ev_power);
    465 }
    466 
    467 static void
    468 vmt_do_reboot(struct vmt_softc *sc)
    469 {
    470 	vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_REBOOT);
    471 	vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK);
    472 
    473 	device_printf(sc->sc_dev, "host requested reboot\n");
    474 	sysmon_task_queue_sched(0, vmt_pswitch_event, &sc->sc_ev_reset);
    475 }
    476 
    477 static void
    478 vmt_do_resume(struct vmt_softc *sc)
    479 {
    480 	device_printf(sc->sc_dev, "guest resuming from suspended state\n");
    481 
    482 	vmt_sync_guest_clock(sc);
    483 
    484 	/* force guest info update */
    485 	sc->sc_hostname[0] = '\0';
    486 	sc->sc_set_guest_os = 0;
    487 	vmt_update_guest_info(sc);
    488 
    489 	vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_RESUME);
    490 	if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
    491 		device_printf(sc->sc_dev, "error sending resume response\n");
    492 		sc->sc_rpc_error = 1;
    493 	}
    494 
    495 	sysmon_task_queue_sched(0, vmt_pswitch_event, &sc->sc_ev_sleep);
    496 }
    497 
    498 static bool
    499 vmt_shutdown(device_t self, int flags)
    500 {
    501 	struct vmt_softc *sc = device_private(self);
    502 
    503 	if (vm_rpc_send_rpci_tx(sc,
    504 	    "tools.capability.hgfs_server toolbox 0") != 0) {
    505 		device_printf(sc->sc_dev,
    506 		    "failed to disable hgfs server capability\n");
    507 	}
    508 
    509 	if (vm_rpc_send(&sc->sc_tclo_rpc, NULL, 0) != 0) {
    510 		device_printf(sc->sc_dev, "failed to send shutdown ping\n");
    511 	}
    512 
    513 	vm_rpc_close(&sc->sc_tclo_rpc);
    514 
    515 	return true;
    516 }
    517 
    518 static void
    519 vmt_pswitch_event(void *xarg)
    520 {
    521 	struct vmt_event *ev = xarg;
    522 
    523 	sysmon_pswitch_event(&ev->ev_smpsw, ev->ev_code);
    524 }
    525 
    526 static void
    527 vmt_tclo_tick(void *xarg)
    528 {
    529 	struct vmt_softc *sc = xarg;
    530 	u_int32_t rlen;
    531 	u_int16_t ack;
    532 
    533 	/* reopen tclo channel if it's currently closed */
    534 	if (sc->sc_tclo_rpc.channel == 0 &&
    535 	    sc->sc_tclo_rpc.cookie1 == 0 &&
    536 	    sc->sc_tclo_rpc.cookie2 == 0) {
    537 		if (vm_rpc_open(&sc->sc_tclo_rpc, VM_RPC_OPEN_TCLO) != 0) {
    538 			device_printf(sc->sc_dev,
    539 			    "unable to reopen TCLO channel\n");
    540 			callout_schedule(&sc->sc_tclo_tick, hz * 15);
    541 			return;
    542 		}
    543 
    544 		if (vm_rpc_send_str(&sc->sc_tclo_rpc,
    545 		    VM_RPC_RESET_REPLY) != 0) {
    546 			device_printf(sc->sc_dev,
    547 			    "failed to send reset reply\n");
    548 			sc->sc_rpc_error = 1;
    549 			goto out;
    550 		} else {
    551 			sc->sc_rpc_error = 0;
    552 		}
    553 	}
    554 
    555 	if (sc->sc_tclo_ping) {
    556 		if (vm_rpc_send(&sc->sc_tclo_rpc, NULL, 0) != 0) {
    557 			device_printf(sc->sc_dev,
    558 			    "failed to send TCLO outgoing ping\n");
    559 			sc->sc_rpc_error = 1;
    560 			goto out;
    561 		}
    562 	}
    563 
    564 	if (vm_rpc_get_length(&sc->sc_tclo_rpc, &rlen, &ack) != 0) {
    565 		device_printf(sc->sc_dev,
    566 		    "failed to get length of incoming TCLO data\n");
    567 		sc->sc_rpc_error = 1;
    568 		goto out;
    569 	}
    570 
    571 	if (rlen == 0) {
    572 		sc->sc_tclo_ping = 1;
    573 		goto out;
    574 	}
    575 
    576 	if (rlen >= VMT_RPC_BUFLEN) {
    577 		rlen = VMT_RPC_BUFLEN - 1;
    578 	}
    579 	if (vm_rpc_get_data(&sc->sc_tclo_rpc, sc->sc_rpc_buf, rlen, ack) != 0) {
    580 		device_printf(sc->sc_dev,
    581 		    "failed to get incoming TCLO data\n");
    582 		sc->sc_rpc_error = 1;
    583 		goto out;
    584 	}
    585 	sc->sc_tclo_ping = 0;
    586 
    587 #ifdef VMT_DEBUG
    588 	printf("vmware: received message '%s'\n", sc->sc_rpc_buf);
    589 #endif
    590 
    591 	if (strcmp(sc->sc_rpc_buf, "reset") == 0) {
    592 
    593 		if (sc->sc_rpc_error != 0) {
    594 			device_printf(sc->sc_dev, "resetting rpc\n");
    595 			vm_rpc_close(&sc->sc_tclo_rpc);
    596 			/* reopen and send the reset reply next time around */
    597 			goto out;
    598 		}
    599 
    600 		if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_RESET_REPLY) != 0) {
    601 			device_printf(sc->sc_dev,
    602 			    "failed to send reset reply\n");
    603 			sc->sc_rpc_error = 1;
    604 		}
    605 
    606 	} else if (strcmp(sc->sc_rpc_buf, "ping") == 0) {
    607 
    608 		vmt_update_guest_info(sc);
    609 		if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
    610 			device_printf(sc->sc_dev,
    611 			    "error sending ping response\n");
    612 			sc->sc_rpc_error = 1;
    613 		}
    614 
    615 	} else if (strcmp(sc->sc_rpc_buf, "OS_Halt") == 0) {
    616 		vmt_do_shutdown(sc);
    617 	} else if (strcmp(sc->sc_rpc_buf, "OS_Reboot") == 0) {
    618 		vmt_do_reboot(sc);
    619 	} else if (strcmp(sc->sc_rpc_buf, "OS_PowerOn") == 0) {
    620 		vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_POWERON);
    621 		if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
    622 			device_printf(sc->sc_dev,
    623 			    "error sending poweron response\n");
    624 			sc->sc_rpc_error = 1;
    625 		}
    626 	} else if (strcmp(sc->sc_rpc_buf, "OS_Suspend") == 0) {
    627 		log(LOG_KERN | LOG_NOTICE,
    628 		    "VMware guest entering suspended state\n");
    629 
    630 		vmt_tclo_state_change_success(sc, 1, VM_STATE_CHANGE_SUSPEND);
    631 		if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
    632 			device_printf(sc->sc_dev,
    633 			    "error sending suspend response\n");
    634 			sc->sc_rpc_error = 1;
    635 		}
    636 	} else if (strcmp(sc->sc_rpc_buf, "OS_Resume") == 0) {
    637 		vmt_do_resume(sc);
    638 	} else if (strcmp(sc->sc_rpc_buf, "Capabilities_Register") == 0) {
    639 
    640 		/* don't know if this is important at all */
    641 		if (vm_rpc_send_rpci_tx(sc,
    642 		    "vmx.capability.unified_loop toolbox") != 0) {
    643 			device_printf(sc->sc_dev,
    644 			    "unable to set unified loop\n");
    645 			sc->sc_rpc_error = 1;
    646 		}
    647 		if (vm_rpci_response_successful(sc) == 0) {
    648 			device_printf(sc->sc_dev,
    649 			    "host rejected unified loop setting\n");
    650 		}
    651 
    652 		/* the trailing space is apparently important here */
    653 		if (vm_rpc_send_rpci_tx(sc,
    654 		    "tools.capability.statechange ") != 0) {
    655 			device_printf(sc->sc_dev,
    656 			    "unable to send statechange capability\n");
    657 			sc->sc_rpc_error = 1;
    658 		}
    659 		if (vm_rpci_response_successful(sc) == 0) {
    660 			device_printf(sc->sc_dev,
    661 			    "host rejected statechange capability\n");
    662 		}
    663 
    664 		if (vm_rpc_send_rpci_tx(sc,
    665 		    "tools.set.version %u", VM_VERSION_UNMANAGED) != 0) {
    666 			device_printf(sc->sc_dev,
    667 			    "unable to set tools version\n");
    668 			sc->sc_rpc_error = 1;
    669 		}
    670 
    671 		vmt_update_guest_uptime(sc);
    672 
    673 		if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
    674 			device_printf(sc->sc_dev,
    675 			    "error sending capabilities_register response\n");
    676 			sc->sc_rpc_error = 1;
    677 		}
    678 	} else if (strcmp(sc->sc_rpc_buf, "Set_Option broadcastIP 1") == 0) {
    679 		struct ifaddr *iface_addr = NULL;
    680 		struct ifnet *iface;
    681 		struct sockaddr_in *guest_ip;
    682 		int s;
    683 		struct psref psref;
    684 
    685 		/* find first available ipv4 address */
    686 		guest_ip = NULL;
    687 		s = pserialize_read_enter();
    688 		IFNET_READER_FOREACH(iface) {
    689 
    690 			/* skip loopback */
    691 			if (strncmp(iface->if_xname, "lo", 2) == 0 &&
    692 			    iface->if_xname[2] >= '0' &&
    693 			    iface->if_xname[2] <= '9') {
    694 				continue;
    695 			}
    696 
    697 			IFADDR_READER_FOREACH(iface_addr, iface) {
    698 				if (iface_addr->ifa_addr->sa_family != AF_INET) {
    699 					continue;
    700 				}
    701 
    702 				guest_ip = satosin(iface_addr->ifa_addr);
    703 				ifa_acquire(iface_addr, &psref);
    704 				goto got;
    705 			}
    706 		}
    707 	got:
    708 		pserialize_read_exit(s);
    709 
    710 		if (guest_ip != NULL) {
    711 			if (vm_rpc_send_rpci_tx(sc, "info-set guestinfo.ip %s",
    712 			    inet_ntoa(guest_ip->sin_addr)) != 0) {
    713 				device_printf(sc->sc_dev,
    714 				    "unable to send guest IP address\n");
    715 				sc->sc_rpc_error = 1;
    716 			}
    717 			ifa_release(iface_addr, &psref);
    718 
    719 			if (vm_rpc_send_str(&sc->sc_tclo_rpc,
    720 			    VM_RPC_REPLY_OK) != 0) {
    721 				device_printf(sc->sc_dev,
    722 				    "error sending broadcastIP response\n");
    723 				sc->sc_rpc_error = 1;
    724 			}
    725 		} else {
    726 			if (vm_rpc_send_str(&sc->sc_tclo_rpc,
    727 			    VM_RPC_REPLY_ERROR_IP_ADDR) != 0) {
    728 				device_printf(sc->sc_dev,
    729 				    "error sending broadcastIP"
    730 				    " error response\n");
    731 				sc->sc_rpc_error = 1;
    732 			}
    733 		}
    734 	} else {
    735 		if (vm_rpc_send_str(&sc->sc_tclo_rpc,
    736 		    VM_RPC_REPLY_ERROR) != 0) {
    737 			device_printf(sc->sc_dev,
    738 			    "error sending unknown command reply\n");
    739 			sc->sc_rpc_error = 1;
    740 		}
    741 	}
    742 
    743 out:
    744 	callout_schedule(&sc->sc_tclo_tick, sc->sc_tclo_ping ? hz : 1);
    745 }
    746 
    747 static void
    748 vm_cmd(struct vm_backdoor *frame)
    749 {
    750 	BACKDOOR_OP(BACKDOOR_OP_CMD, frame);
    751 }
    752 
    753 static void
    754 vm_ins(struct vm_backdoor *frame)
    755 {
    756 	BACKDOOR_OP(BACKDOOR_OP_IN, frame);
    757 }
    758 
    759 static void
    760 vm_outs(struct vm_backdoor *frame)
    761 {
    762 	BACKDOOR_OP(BACKDOOR_OP_OUT, frame);
    763 }
    764 
    765 static int
    766 vm_rpc_open(struct vm_rpc *rpc, uint32_t proto)
    767 {
    768 	struct vm_backdoor frame;
    769 
    770 	memset(&frame, 0, sizeof(frame));
    771 	frame.eax = VM_MAGIC;
    772 	frame.ebx = proto | VM_RPC_FLAG_COOKIE;
    773 	frame.ecx = VM_REG_CMD_RPC(VM_RPC_OPEN);
    774 	frame.edx = VM_REG_PORT_CMD(0);
    775 
    776 	vm_cmd(&frame);
    777 
    778 	if (__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) != 1 ||
    779 	    __SHIFTOUT(frame.edx, VM_REG_LOW_MASK) != 0) {
    780 		/* open-vm-tools retries without VM_RPC_FLAG_COOKIE here.. */
    781 		printf("vmware: open failed, eax=%#"PRIxREGISTER
    782 		    ", ecx=%#"PRIxREGISTER", edx=%#"PRIxREGISTER"\n",
    783 		    frame.eax, frame.ecx, frame.edx);
    784 		return EIO;
    785 	}
    786 
    787 	rpc->channel = __SHIFTOUT(frame.edx, VM_REG_HIGH_MASK);
    788 	rpc->cookie1 = __SHIFTOUT(frame.esi, VM_REG_WORD_MASK);
    789 	rpc->cookie2 = __SHIFTOUT(frame.edi, VM_REG_WORD_MASK);
    790 
    791 	return 0;
    792 }
    793 
    794 static int
    795 vm_rpc_close(struct vm_rpc *rpc)
    796 {
    797 	struct vm_backdoor frame;
    798 
    799 	memset(&frame, 0, sizeof(frame));
    800 	frame.eax = VM_MAGIC;
    801 	frame.ebx = 0;
    802 	frame.ecx = VM_REG_CMD_RPC(VM_RPC_CLOSE);
    803 	frame.edx = VM_REG_PORT_CMD(rpc->channel);
    804 	frame.edi = rpc->cookie2;
    805 	frame.esi = rpc->cookie1;
    806 
    807 	vm_cmd(&frame);
    808 
    809 	if (__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) == 0 ||
    810 	    __SHIFTOUT(frame.ecx, VM_REG_LOW_MASK) != 0) {
    811 		printf("vmware: close failed, "
    812 		    "eax=%#"PRIxREGISTER", ecx=%#"PRIxREGISTER"\n",
    813 		    frame.eax, frame.ecx);
    814 		return EIO;
    815 	}
    816 
    817 	rpc->channel = 0;
    818 	rpc->cookie1 = 0;
    819 	rpc->cookie2 = 0;
    820 
    821 	return 0;
    822 }
    823 
    824 static int
    825 vm_rpc_send(const struct vm_rpc *rpc, const uint8_t *buf, uint32_t length)
    826 {
    827 	struct vm_backdoor frame;
    828 
    829 	/* Send the length of the command. */
    830 	memset(&frame, 0, sizeof(frame));
    831 	frame.eax = VM_MAGIC;
    832 	frame.ebx = length;
    833 	frame.ecx = VM_REG_CMD_RPC(VM_RPC_SET_LENGTH);
    834 	frame.edx = VM_REG_PORT_CMD(rpc->channel);
    835 	frame.esi = rpc->cookie1;
    836 	frame.edi = rpc->cookie2;
    837 
    838 	vm_cmd(&frame);
    839 
    840 	if ((__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) & VM_RPC_REPLY_SUCCESS) ==
    841 	    0) {
    842 		printf("vmware: sending length failed, "
    843 		    "eax=%#"PRIxREGISTER", ecx=%#"PRIxREGISTER"\n",
    844 		    frame.eax, frame.ecx);
    845 		return EIO;
    846 	}
    847 
    848 	if (length == 0)
    849 		return 0; /* Only need to poke once if command is null. */
    850 
    851 	/* Send the command using enhanced RPC. */
    852 	memset(&frame, 0, sizeof(frame));
    853 	frame.eax = VM_MAGIC;
    854 	frame.ebx = VM_RPC_ENH_DATA;
    855 	frame.ecx = length;
    856 	frame.edx = VM_REG_PORT_RPC(rpc->channel);
    857 	frame.ebp = rpc->cookie1;
    858 	frame.edi = rpc->cookie2;
    859 	frame.esi = (register_t)buf;
    860 
    861 	vm_outs(&frame);
    862 
    863 	if (__SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) != VM_RPC_ENH_DATA) {
    864 		/* open-vm-tools retries on VM_RPC_REPLY_CHECKPOINT */
    865 		printf("vmware: send failed, ebx=%#"PRIxREGISTER"\n",
    866 		    frame.ebx);
    867 		return EIO;
    868 	}
    869 
    870 	return 0;
    871 }
    872 
    873 static int
    874 vm_rpc_send_str(const struct vm_rpc *rpc, const uint8_t *str)
    875 {
    876 	return vm_rpc_send(rpc, str, strlen(str));
    877 }
    878 
    879 static int
    880 vm_rpc_get_data(const struct vm_rpc *rpc, char *data, uint32_t length,
    881     uint16_t dataid)
    882 {
    883 	struct vm_backdoor frame;
    884 
    885 	/* Get data using enhanced RPC. */
    886 	memset(&frame, 0, sizeof(frame));
    887 	frame.eax = VM_MAGIC;
    888 	frame.ebx = VM_RPC_ENH_DATA;
    889 	frame.ecx = length;
    890 	frame.edx = VM_REG_PORT_RPC(rpc->channel);
    891 	frame.esi = rpc->cookie1;
    892 	frame.edi = (register_t)data;
    893 	frame.ebp = rpc->cookie2;
    894 
    895 	vm_ins(&frame);
    896 
    897 	/* NUL-terminate the data */
    898 	data[length] = '\0';
    899 
    900 	if (__SHIFTOUT(frame.ebx, VM_REG_WORD_MASK) != VM_RPC_ENH_DATA) {
    901 		printf("vmware: get data failed, ebx=%#"PRIxREGISTER"\n",
    902 		    frame.ebx);
    903 		return EIO;
    904 	}
    905 
    906 	/* Acknowledge data received. */
    907 	memset(&frame, 0, sizeof(frame));
    908 	frame.eax = VM_MAGIC;
    909 	frame.ebx = dataid;
    910 	frame.ecx = VM_REG_CMD_RPC(VM_RPC_GET_END);
    911 	frame.edx = VM_REG_PORT_CMD(rpc->channel);
    912 	frame.esi = rpc->cookie1;
    913 	frame.edi = rpc->cookie2;
    914 
    915 	vm_cmd(&frame);
    916 
    917 	if (__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) == 0) {
    918 		printf("vmware: ack data failed, "
    919 		    "eax=%#"PRIxREGISTER", ecx=%#"PRIxREGISTER"\n",
    920 		    frame.eax, frame.ecx);
    921 		return EIO;
    922 	}
    923 
    924 	return 0;
    925 }
    926 
    927 static int
    928 vm_rpc_get_length(const struct vm_rpc *rpc, uint32_t *length, uint16_t *dataid)
    929 {
    930 	struct vm_backdoor frame;
    931 
    932 	memset(&frame, 0, sizeof(frame));
    933 	frame.eax = VM_MAGIC;
    934 	frame.ebx = 0;
    935 	frame.ecx = VM_REG_CMD_RPC(VM_RPC_GET_LENGTH);
    936 	frame.edx = VM_REG_PORT_CMD(rpc->channel);
    937 	frame.esi = rpc->cookie1;
    938 	frame.edi = rpc->cookie2;
    939 
    940 	vm_cmd(&frame);
    941 
    942 	if ((__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) & VM_RPC_REPLY_SUCCESS) ==
    943 	    0) {
    944 		printf("vmware: get length failed, "
    945 		    "eax=%#"PRIxREGISTER", ecx=%#"PRIxREGISTER"\n",
    946 		    frame.eax, frame.ecx);
    947 		return EIO;
    948 	}
    949 	if ((__SHIFTOUT(frame.ecx, VM_REG_HIGH_MASK) & VM_RPC_REPLY_DORECV) ==
    950 	    0) {
    951 		*length = 0;
    952 		*dataid = 0;
    953 	} else {
    954 		*length = __SHIFTOUT(frame.ebx, VM_REG_WORD_MASK);
    955 		*dataid = __SHIFTOUT(frame.edx, VM_REG_HIGH_MASK);
    956 	}
    957 
    958 	return 0;
    959 }
    960 
    961 static int
    962 vm_rpci_response_successful(struct vmt_softc *sc)
    963 {
    964 	return (sc->sc_rpc_buf[0] == '1' && sc->sc_rpc_buf[1] == ' ');
    965 }
    966 
    967 static int
    968 vm_rpc_send_rpci_tx_buf(struct vmt_softc *sc, const uint8_t *buf,
    969     uint32_t length)
    970 {
    971 	struct vm_rpc rpci;
    972 	u_int32_t rlen;
    973 	u_int16_t ack;
    974 	int result = 0;
    975 
    976 	if (vm_rpc_open(&rpci, VM_RPC_OPEN_RPCI) != 0) {
    977 		device_printf(sc->sc_dev, "rpci channel open failed\n");
    978 		return EIO;
    979 	}
    980 
    981 	if (vm_rpc_send(&rpci, sc->sc_rpc_buf, length) != 0) {
    982 		device_printf(sc->sc_dev, "unable to send rpci command\n");
    983 		result = EIO;
    984 		goto out;
    985 	}
    986 
    987 	if (vm_rpc_get_length(&rpci, &rlen, &ack) != 0) {
    988 		device_printf(sc->sc_dev,
    989 		    "failed to get length of rpci response data\n");
    990 		result = EIO;
    991 		goto out;
    992 	}
    993 
    994 	if (rlen > 0) {
    995 		if (rlen >= VMT_RPC_BUFLEN) {
    996 			rlen = VMT_RPC_BUFLEN - 1;
    997 		}
    998 
    999 		if (vm_rpc_get_data(&rpci, sc->sc_rpc_buf, rlen, ack) != 0) {
   1000 			device_printf(sc->sc_dev,
   1001 			    "failed to get rpci response data\n");
   1002 			result = EIO;
   1003 			goto out;
   1004 		}
   1005 	}
   1006 
   1007 out:
   1008 	if (vm_rpc_close(&rpci) != 0) {
   1009 		device_printf(sc->sc_dev, "unable to close rpci channel\n");
   1010 	}
   1011 
   1012 	return result;
   1013 }
   1014 
   1015 static int
   1016 vm_rpc_send_rpci_tx(struct vmt_softc *sc, const char *fmt, ...)
   1017 {
   1018 	va_list args;
   1019 	int len;
   1020 
   1021 	va_start(args, fmt);
   1022 	len = vsnprintf(sc->sc_rpc_buf, VMT_RPC_BUFLEN, fmt, args);
   1023 	va_end(args);
   1024 
   1025 	if (len >= VMT_RPC_BUFLEN) {
   1026 		device_printf(sc->sc_dev,
   1027 		    "rpci command didn't fit in buffer\n");
   1028 		return EIO;
   1029 	}
   1030 
   1031 	return vm_rpc_send_rpci_tx_buf(sc, sc->sc_rpc_buf, len);
   1032 }
   1033 
   1034 #if 0
   1035 	struct vm_backdoor frame;
   1036 
   1037 	memset(&frame, 0, sizeof(frame));
   1038 
   1039 	frame.eax = VM_MAGIC;
   1040 	frame.ecx = VM_CMD_GET_VERSION;
   1041 	frame.edx = VM_PORT_CMD;
   1042 
   1043 	printf("\n");
   1044 	printf("eax %#"PRIxREGISTER"\n", frame.eax);
   1045 	printf("ebx %#"PRIxREGISTER"\n", frame.ebx);
   1046 	printf("ecx %#"PRIxREGISTER"\n", frame.ecx);
   1047 	printf("edx %#"PRIxREGISTER"\n", frame.edx)
   1048 	printf("ebp %#"PRIxREGISTER"\n", frame.ebp);
   1049 	printf("edi %#"PRIxREGISTER"\n", frame.edi);
   1050 	printf("esi %#"PRIxREGISTER"\n", frame.esi);
   1051 
   1052 	vm_cmd(&frame);
   1053 
   1054 	printf("-\n");
   1055 	printf("eax %#"PRIxREGISTER"\n", frame.eax);
   1056 	printf("ebx %#"PRIxREGISTER"\n", frame.ebx);
   1057 	printf("ecx %#"PRIxREGISTER"\n", frame.ecx);
   1058 	printf("edx %#"PRIxREGISTER"\n", frame.edx);
   1059 	printf("ebp %#"PRIxREGISTER"\n", frame.ebp);
   1060 	printf("edi %#"PRIxREGISTER"\n", frame.edi);
   1061 	printf("esi %#"PRIxREGISTER"\n", frame.esi);
   1062 #endif
   1063 
   1064 /*
   1065  * Notes on tracing backdoor activity in vmware-guestd:
   1066  *
   1067  * - Find the addresses of the inl / rep insb / rep outsb
   1068  *   instructions used to perform backdoor operations.
   1069  *   One way to do this is to disassemble vmware-guestd:
   1070  *
   1071  *   $ objdump -S /emul/freebsd/sbin/vmware-guestd > vmware-guestd.S
   1072  *
   1073  *   and search for '<tab>in ' in the resulting file.  The rep insb and
   1074  *   rep outsb code is directly below that.
   1075  *
   1076  * - Run vmware-guestd under gdb, setting up breakpoints as follows:
   1077  *   (the addresses shown here are the ones from VMware-server-1.0.10-203137,
   1078  *   the last version that actually works in FreeBSD emulation on OpenBSD)
   1079  *
   1080  * break *0x805497b   (address of 'in' instruction)
   1081  * commands 1
   1082  * silent
   1083  * echo INOUT\n
   1084  * print/x $ecx
   1085  * print/x $ebx
   1086  * print/x $edx
   1087  * continue
   1088  * end
   1089  * break *0x805497c   (address of instruction after 'in')
   1090  * commands 2
   1091  * silent
   1092  * echo ===\n
   1093  * print/x $ecx
   1094  * print/x $ebx
   1095  * print/x $edx
   1096  * echo \n
   1097  * continue
   1098  * end
   1099  * break *0x80549b7   (address of instruction before 'rep insb')
   1100  * commands 3
   1101  * silent
   1102  * set variable $inaddr = $edi
   1103  * set variable $incount = $ecx
   1104  * continue
   1105  * end
   1106  * break *0x80549ba   (address of instruction after 'rep insb')
   1107  * commands 4
   1108  * silent
   1109  * echo IN\n
   1110  * print $incount
   1111  * x/s $inaddr
   1112  * echo \n
   1113  * continue
   1114  * end
   1115  * break *0x80549fb    (address of instruction before 'rep outsb')
   1116  * commands 5
   1117  * silent
   1118  * echo OUT\n
   1119  * print $ecx
   1120  * x/s $esi
   1121  * echo \n
   1122  * continue
   1123  * end
   1124  *
   1125  * This will produce a log of the backdoor operations, including the
   1126  * data sent and received and the relevant register values.  You can then
   1127  * match the register values to the various constants in this file.
   1128  */
   1129