vmt.c 32 KB

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