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