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