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