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