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 = . 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