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