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