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