From: dlg Date: Tue, 8 Jul 2008 05:21:59 +0000 (+0000) Subject: vmt(4) is a kernel level implementation of the vmware tools. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ad51f2079808f6279b4c201f7282999c90a51918;p=openbsd vmt(4) is a kernel level implementation of the vmware tools. it only provides the hosts machines clock as a timedelta sensor so far. getting it into the tree so people can work on it as suggested by fgsch@ --- diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index d38ecd1ece4..c3f068eddaf 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.630 2008/06/26 01:28:48 brad Exp $ +# $OpenBSD: GENERIC,v 1.631 2008/07/08 05:21:59 dlg Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -44,6 +44,7 @@ apm0 at bios0 flags 0x0000 # flags 0x0101 to force protocol version 1.1 acpi0 at bios? pcibios0 at bios0 flags 0x0000 # use 0x30 for a total verbose ipmi0 at mainbus? # IPMI +#vmt0 at mainbus? # VMware Tools esm0 at mainbus? # Dell Embedded Server Management amdmsr0 at mainbus? # MSR access for AMD Geode LX CPUs with GP diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index a49a3394367..2eb74d13a7c 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.181 2008/06/25 15:27:34 mbalmer Exp $ +# $OpenBSD: files.i386,v 1.182 2008/07/08 05:22:00 dlg Exp $ # # new style config file for i386 architecture # @@ -430,6 +430,9 @@ file arch/i386/i386/acpi_machdep.c acpi # attach ipmi at mainbus +# VMware Tools +attach vmt at mainbus + # Dell Embedded Systems Management device esm attach esm at mainbus diff --git a/sys/arch/i386/i386/mainbus.c b/sys/arch/i386/i386/mainbus.c index 42582e1f77f..a84966c5fc3 100644 --- a/sys/arch/i386/i386/mainbus.c +++ b/sys/arch/i386/i386/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.41 2008/06/18 20:15:54 mbalmer Exp $ */ +/* $OpenBSD: mainbus.c,v 1.42 2008/07/08 05:22:00 dlg Exp $ */ /* $NetBSD: mainbus.c,v 1.21 1997/06/06 23:14:20 thorpej Exp $ */ /* @@ -53,6 +53,7 @@ #include "acpi.h" #include "ipmi.h" #include "esm.h" +#include "vmt.h" #include "vesabios.h" #include "amdmsr.h" @@ -70,6 +71,10 @@ #include #endif +#if NVMT > 0 +#include +#endif + #if NAMDMSR > 0 #include #endif @@ -160,6 +165,13 @@ mainbus_attach(struct device *parent, struct device *self, void *aux) } #endif +#if NVMT > 0 + if (vmt_probe()) { + mba.mba_busname = "vmware"; + config_found(self, &mba.mba_busname, mainbus_print); + } +#endif + #if NMPBIOS > 0 if (mpbios_probe(self)) mpbios_scan(self); diff --git a/sys/conf/files b/sys/conf/files index 0b9f9238b09..d599c5de112 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.436 2008/06/15 06:56:09 mpf Exp $ +# $OpenBSD: files,v 1.437 2008/07/08 05:22:00 dlg Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -441,6 +441,10 @@ file dev/radio.c radio needs-flag device ipmi file dev/ipmi.c ipmi needs-flag +# VMware Tools +device vmt +file dev/vmt.c vmt needs-flag + # Software RAID device softraid: scsi attach softraid at root diff --git a/sys/dev/vmt.c b/sys/dev/vmt.c new file mode 100644 index 00000000000..93bb0057e3a --- /dev/null +++ b/sys/dev/vmt.c @@ -0,0 +1,595 @@ +/* $OpenBSD: vmt.c,v 1.1 2008/07/08 05:22:00 dlg Exp $ */ + +/* + * Copyright (c) 2007 David Crawshaw + * Copyright (c) 2008 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__i386__) +#error vmware(4) is only supported on i386 +#endif + +#include + +/* + * Protocol reverse engineered by Ken Kato: + * http://chitchat.at.infoseek.co.jp/vmware/backdoor.html + */ + +#include +#include +#include +#include +#include +#include + +/* "The" magic number, always occupies the EAX register. */ +#define VM_MAGIC 0x564D5868UL + +/* Port numbers, passed on EDX.LOW . */ +#define VM_PORT_CMD 0x5658 +#define VM_PORT_RPC 0x5659 + +/* Commands, passed on ECX.LOW. */ +#define VM_CMD_GET_SPEED 0x01 +#define VM_CMD_APM 0x02 +#define VM_CMD_GET_MOUSEPOS 0x04 +#define VM_CMD_SET_MOUSEPOS 0x05 +#define VM_CMD_GET_CLIPBOARD_LEN 0x06 +#define VM_CMD_GET_CLIPBOARD 0x07 +#define VM_CMD_SET_CLIPBOARD_LEN 0x08 +#define VM_CMD_SET_CLIPBOARD 0x09 +#define VM_CMD_GET_VERSION 0x0a +#define VM_VERSION_UNMANAGED 0x7fffffff +#define VM_CMD_GET_DEVINFO 0x0b +#define VM_CMD_DEV_ADDREMOVE 0x0c +#define VM_CMD_GET_GUI_OPTIONS 0x0d +#define VM_CMD_SET_GUI_OPTIONS 0x0e +#define VM_CMD_GET_SCREEN_SIZE 0x0f +#define VM_CMD_GET_HWVER 0x11 +#define VM_CMD_POPUP_OSNOTFOUND 0x12 +#define VM_CMD_GET_BIOS_UUID 0x13 +#define VM_CMD_GET_MEM_SIZE 0x14 +#define VM_CMD_GET_TIME 0x17 +#define VM_CMD_RPC 0x1e + +/* RPC sub-commands, passed on ECX.HIGH. */ +#define VM_RPC_OPEN 0x00 +#define VM_RPC_SET_LENGTH 0x01 +#define VM_RPC_SET_DATA 0x02 +#define VM_RPC_GET_LENGTH 0x03 +#define VM_RPC_GET_DATA 0x04 +#define VM_RPC_GET_END 0x05 +#define VM_RPC_CLOSE 0x06 + +/* RPC magic numbers, passed on EBX. */ +#define VM_RPC_OPEN_RPCI 0x49435052UL /* with VM_RPC_OPEN. */ +#define VM_RPC_OPEN_RPCI_ENH 0xC9435052UL /* with VM_RPC_OPEN, enhanced. */ +#define VM_RPC_ENH_DATA 0x00010000UL /* with enhanced RPC data calls. */ + +/* A register. */ +union vm_reg { + struct { + uint16_t low; + uint16_t high; + } part; + uint32_t word; +} __packed; + +/* A register frame. */ +struct vm_backdoor { + union vm_reg eax; + union vm_reg ebx; + union vm_reg ecx; + union vm_reg edx; + union vm_reg ebp; + union vm_reg edi; + union vm_reg esi; +} __packed; + +/* RPC context. */ +struct vm_rpc { + uint16_t channel; + uint32_t cookie1; + uint32_t cookie2; +}; + +int vmt_match(struct device *, void *, void *); +void vmt_attach(struct device *, struct device *, void *); + +struct vmt_softc { + struct device sc_dev; + + struct vm_rpc sc_rpc; + char *sc_rpc_buf; +#define VMT_RPC_BUFLEN 256 + + struct timeout sc_tick; + struct ksensordev sc_sensordev; + struct ksensor sc_sensor; + + char sc_hostname[MAXHOSTNAMELEN]; +}; +#define DEVNAME(_s) ((_s)->sc_dev.dv_xname) + +struct cfattach vmt_ca = { + sizeof(struct vmt_softc), + vmt_match, + vmt_attach +}; + +struct cfdriver vmt_cd = { + NULL, + "vmt", + DV_DULL +}; + +void vm_cmd(struct vm_backdoor *); +void vm_ins(struct vm_backdoor *); +void vm_outs(struct vm_backdoor *); + +/* Functions for communicating with the VM Host. */ +int vm_rpc_open(struct vm_rpc *); +int vm_rpc_close(struct vm_rpc *); +int vm_rpc_send(const struct vm_rpc *, const uint8_t *, uint32_t); +int vm_rpc_get_length(const struct vm_rpc *, uint32_t *, uint16_t *); +int vm_rpc_get_data(const struct vm_rpc *, char *, uint32_t, uint16_t); + +void vmt_tick(void *); + +extern char hostname[MAXHOSTNAMELEN]; + +int +vmt_probe(void) +{ + struct vm_backdoor frame; + + bzero(&frame, sizeof(frame)); + + frame.eax.word = VM_MAGIC; + frame.ebx.word = ~VM_MAGIC; + frame.ecx.part.low = VM_CMD_GET_VERSION; + frame.ecx.part.high = 0xffff; + frame.edx.part.low = VM_PORT_CMD; + frame.edx.part.high = 0; + + vm_cmd(&frame); + + if (frame.eax.word == 0xffffffff || + frame.ebx.word != VM_MAGIC) + return (0); + + return (1); +} + +int +vmt_match(struct device *parent, void *match, void *aux) +{ + /* we cant get here unless vmt_probe previously succeeded */ + return (1); +} + +void +vmt_attach(struct device *parent, struct device *self, void *aux) +{ + struct vmt_softc *sc = (struct vmt_softc *)self; + size_t len; + u_int32_t rlen; + u_int16_t ack; + + sc->sc_rpc_buf = malloc(VMT_RPC_BUFLEN, M_DEVBUF, M_NOWAIT); + if (sc->sc_rpc_buf == NULL) { + printf(": unable to allocate buffer for RPC\n"); + return; + } + + if (vm_rpc_open(&sc->sc_rpc) != 0) { + printf(": failed to open backdoor RPC channel\n"); + goto free; + } + + len = snprintf(sc->sc_rpc_buf, VMT_RPC_BUFLEN, "tools.set.version %u ", + VM_VERSION_UNMANAGED); +#if DIAGNOSTIC + if (len > VMT_RPC_BUFLEN) + panic("vmt rpc buffer is too small"); +#endif + + if (vm_rpc_send(&sc->sc_rpc, sc->sc_rpc_buf, len) != 0) { + printf("%s: failed to send version\n", DEVNAME(sc)); + return; + } + + if (vm_rpc_get_length(&sc->sc_rpc, &rlen, &ack) != 0) { + printf("%s: failed to get length of version reply\n", + DEVNAME(sc)); + return; + } + + if (rlen > VMT_RPC_BUFLEN) { + printf("%s: reply is too large for version buffer\n", + DEVNAME(sc)); + return; + } + + bzero(sc->sc_rpc_buf, VMT_RPC_BUFLEN); + if (vm_rpc_get_data(&sc->sc_rpc, sc->sc_rpc_buf, rlen, ack) != 0) { + printf("%s: failed to get version reply\n", DEVNAME(sc)); + return; + } + + if (sc->sc_rpc_buf[0] != '1' && sc->sc_rpc_buf[1] != ' ') { + printf("%s: setting version failed\n", DEVNAME(sc)); + return; + } + + strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, + sizeof(sc->sc_sensordev.xname)); + + sc->sc_sensor.type = SENSOR_TIMEDELTA; + sc->sc_sensor.status = SENSOR_S_UNKNOWN; + sc->sc_sensor.value = 0LL; + sc->sc_sensor.flags = 0; + + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); + sensordev_install(&sc->sc_sensordev); + + timeout_set(&sc->sc_tick, vmt_tick, sc); + timeout_add(&sc->sc_tick, hz); + + printf("\n"); + return; + +free: + free(sc->sc_rpc_buf, M_DEVBUF); +} + +void +vmt_tick(void *xarg) +{ + struct vmt_softc *sc = xarg; + struct vm_backdoor frame; + struct timeval *guest = &sc->sc_sensor.tv; + struct timeval host, diff; + + size_t len; + u_int32_t rlen; + u_int16_t ack; + + microtime(guest); + + bzero(&frame, sizeof(frame)); + frame.eax.word = VM_MAGIC; + frame.ecx.part.low = VM_CMD_GET_TIME; + frame.edx.part.low = VM_PORT_CMD; + vm_cmd(&frame); + + if (frame.eax.word == 0xffffffff) { + sc->sc_sensor.status = SENSOR_S_UNKNOWN; + goto out; + } + + host.tv_sec = frame.eax.word; + host.tv_usec = frame.ebx.word; + + timersub(guest, &host, &diff); + + sc->sc_sensor.value = (u_int64_t)diff.tv_sec * 1000000000LL + + (u_int64_t)diff.tv_usec * 1000LL; + sc->sc_sensor.status = SENSOR_S_OK; + + if (strncmp(sc->sc_hostname, hostname, sizeof(sc->sc_hostname)) != 0) { + strlcpy(sc->sc_hostname, hostname, sizeof(sc->sc_hostname)); + + len = snprintf(sc->sc_rpc_buf, VMT_RPC_BUFLEN, + "info-set guestinfo.ip %s ", "192.168.1.1"); +#if DIAGNOSTIC + if (len > VMT_RPC_BUFLEN) + panic("vmt rpc buffer is too small"); +#endif + + if (vm_rpc_send(&sc->sc_rpc, sc->sc_rpc_buf, len) != 0) { + goto out; + } + + if (vm_rpc_get_length(&sc->sc_rpc, &rlen, &ack) != 0) { + goto out; + } + + bzero(sc->sc_rpc_buf, VMT_RPC_BUFLEN); + if (vm_rpc_get_data(&sc->sc_rpc, sc->sc_rpc_buf, + rlen, ack) != 0) { + return; + } + + if (sc->sc_rpc_buf[0] != '1' && sc->sc_rpc_buf[1] != ' ') { + printf("%s: setting hostname failed\n", DEVNAME(sc)); + return; + } + + printf("%s: hostname set to %s\n", DEVNAME(sc), + sc->sc_hostname); + } + + if (vm_rpc_get_length(&sc->sc_rpc, &rlen, &ack) != 0) { + printf("%s: failed to get length of version reply\n", + DEVNAME(sc)); + return; + } + + if (rlen == 0) + goto out; + + if (vm_rpc_get_data(&sc->sc_rpc, sc->sc_rpc_buf, rlen, ack) != 0) { + printf("%s: failed to get version reply\n", DEVNAME(sc)); + return; + } + + printf("%s: \"%s\"\n", DEVNAME(sc), sc->sc_rpc_buf); + +out: + timeout_add(&sc->sc_tick, hz * 15); +} + +#define BACKDOOR_OP(op, frame) \ + __asm__ __volatile__ ( \ + "pushal;" \ + "pushl %%eax;" \ + "movl 0x18(%%eax), %%esi;" \ + "movl 0x14(%%eax), %%edi;" \ + "movl 0x10(%%eax), %%ebp;" \ + "movl 0x0c(%%eax), %%edx;" \ + "movl 0x08(%%eax), %%ecx;" \ + "movl 0x04(%%eax), %%ebx;" \ + "movl 0x00(%%eax), %%eax;" \ + op \ + "xchgl %%eax, 0x00(%%esp);" \ + "movl %%esi, 0x18(%%eax);" \ + "movl %%edi, 0x14(%%eax);" \ + "movl %%ebp, 0x10(%%eax);" \ + "movl %%edx, 0x0c(%%eax);" \ + "movl %%ecx, 0x08(%%eax);" \ + "movl %%ebx, 0x04(%%eax);" \ + "popl 0x00(%%eax);" \ + "popal;" \ + ::"a"(frame) \ + ) + +void +vm_cmd(struct vm_backdoor *frame) +{ + BACKDOOR_OP("inl (%%dx);", frame); +} + +void +vm_ins(struct vm_backdoor *frame) +{ + BACKDOOR_OP("pushf; cld; rep insb; popf;", frame); +} + +void +vm_outs(struct vm_backdoor *frame) +{ + BACKDOOR_OP("pushf; cld; rep outsb; popf;", frame); +} + +int +vm_rpc_open(struct vm_rpc *rpc) +{ + struct vm_backdoor frame; + + frame.eax.word = VM_MAGIC; + frame.ebx.word = VM_RPC_OPEN_RPCI_ENH; + frame.ecx.part.low = VM_CMD_RPC; + frame.ecx.part.high = VM_RPC_OPEN; + frame.edx.part.low = VM_PORT_CMD; + frame.edx.part.high = 0; + + vm_cmd(&frame); + + if (frame.eax.word != 0 || frame.ecx.part.high != 1 + || frame.edx.part.low != 0) { + printf("vmware: open failed, eax=%08x, ecx=%08x, edx=%08x\n", + frame.eax.word, frame.ecx.word, frame.edx.word); + return EIO; + } + + rpc->channel = frame.edx.part.high; + rpc->cookie1 = frame.esi.word; + rpc->cookie2 = frame.edi.word; + + return 0; +} + +int +vm_rpc_close(struct vm_rpc *rpc) +{ + struct vm_backdoor frame; + + frame.eax.word = VM_MAGIC; + frame.ebx.word = 0; + frame.ecx.part.low = VM_CMD_RPC; + frame.ecx.part.high = VM_RPC_CLOSE; + frame.edx.part.low = VM_PORT_CMD; + frame.edx.part.high = rpc->channel; + frame.esi.word = rpc->cookie1; + frame.edi.word = rpc->cookie2; + frame.ebp.word = 0; + + vm_cmd(&frame); + + if (frame.eax.word != 0 || frame.ecx.part.high == 0 + || frame.ecx.part.low != 0) { + printf("vmware: close failed, eax=%08x, ecx=%08x\n", + frame.eax.word, frame.ecx.word); + return EIO; + } + + rpc->channel = 0; + rpc->cookie1 = 0; + rpc->cookie2 = 0; + + return 0; +} + +int +vm_rpc_send(const struct vm_rpc *rpc, const uint8_t *buf, uint32_t length) +{ + struct vm_backdoor frame; + + /* Send the length of the command. */ + frame.eax.word = VM_MAGIC; + frame.ebx.word = length; + frame.ecx.part.low = VM_CMD_RPC; + frame.ecx.part.high = VM_RPC_SET_LENGTH; + frame.edx.part.low = VM_PORT_CMD; + frame.edx.part.high = rpc->channel; + frame.esi.word = rpc->cookie1; + frame.edi.word = rpc->cookie2; + + vm_cmd(&frame); + + if (frame.eax.word != 0 || frame.ecx.part.high == 0) { + printf("vmware: sending length failed, eax=%08x, ecx=%08x\n", + frame.eax.word, frame.ecx.word); + return EIO; + } + + if (length == 0) + return 0; /* Only need to poke once if command is null. */ + + /* Send the command using enhanced RPC. */ + frame.eax.word = VM_MAGIC; + frame.ebx.word = VM_RPC_ENH_DATA; + frame.ecx.word = length; + frame.edx.part.low = VM_PORT_RPC; + frame.edx.part.high = rpc->channel; + frame.esi.word = (uint32_t)buf; + frame.edi.word = rpc->cookie2; + frame.ebp.word = rpc->cookie1; + + vm_outs(&frame); + + if (frame.ebx.word != VM_RPC_ENH_DATA) { + printf("vmware: send failed, ebx=%08x\n", frame.ebx.word); + return EIO; + } + + return 0; +} + +int +vm_rpc_get_data(const struct vm_rpc *rpc, char *data, uint32_t length, + uint16_t dataid) +{ + struct vm_backdoor frame; + + /* Get data using enhanced RPC. */ + frame.eax.word = VM_MAGIC; + frame.ebx.word = VM_RPC_ENH_DATA; + frame.ecx.word = length; + frame.edx.part.low = VM_PORT_RPC; + frame.edx.part.high = rpc->channel; + frame.esi.word = rpc->cookie1; + frame.edi.word = (uint32_t)data; + frame.ebp.word = rpc->cookie2; + + vm_ins(&frame); + + if (frame.ebx.word != VM_RPC_ENH_DATA) { + printf("vmware: get data failed, ebx=%08x\n", + frame.ebx.word); + return EIO; + } + + /* Acknowledge data received. */ + frame.eax.word = VM_MAGIC; + frame.ebx.word = dataid; + frame.ecx.part.low = VM_CMD_RPC; + frame.ecx.part.high = VM_RPC_GET_END; + frame.edx.part.low = VM_PORT_CMD; + frame.edx.part.high = rpc->channel; + frame.esi.word = rpc->cookie1; + frame.edi.word = rpc->cookie2; + + vm_cmd(&frame); + + if (frame.eax.word != 0 || frame.ecx.part.high == 0) { + printf("vmware: ack data failed, eax=%08x, ecx=%08x\n", + frame.eax.word, frame.ecx.word); + return EIO; + } + + return 0; +} + +int +vm_rpc_get_length(const struct vm_rpc *rpc, uint32_t *length, uint16_t *dataid) +{ + struct vm_backdoor frame; + + frame.eax.word = VM_MAGIC; + frame.ebx.word = 0; + frame.ecx.part.low = VM_CMD_RPC; + frame.ecx.part.high = VM_RPC_GET_LENGTH; + frame.edx.part.low = VM_PORT_CMD; + frame.edx.part.high = rpc->channel; + frame.esi.word = rpc->cookie1; + frame.edi.word = rpc->cookie2; + + vm_cmd(&frame); + + if (frame.eax.word != 0 || frame.ecx.part.high == 0) { + printf("vmware: get length failed, eax=%08x, ecx=%08x\n", + frame.eax.word, frame.ecx.word); + return EIO; + } + + *length = frame.ebx.word; + *dataid = frame.edx.part.high; + + return 0; +} + + +#if 0 + struct vm_backdoor frame; + + bzero(&frame, sizeof(frame)); + + frame.eax.word = VM_MAGIC; + frame.ecx.part.low = VM_CMD_GET_VERSION; + frame.edx.part.low = VM_PORT_CMD; + + printf("\n"); + printf("eax 0x%08x\n", frame.eax.word); + printf("ebx 0x%08x\n", frame.ebx.word); + printf("ecx 0x%08x\n", frame.ecx.word); + printf("edx 0x%08x\n", frame.edx.word); + printf("ebp 0x%08x\n", frame.ebp.word); + printf("edi 0x%08x\n", frame.edi.word); + printf("esi 0x%08x\n", frame.esi.word); + + vm_cmd(&frame); + + printf("-\n"); + printf("eax 0x%08x\n", frame.eax.word); + printf("ebx 0x%08x\n", frame.ebx.word); + printf("ecx 0x%08x\n", frame.ecx.word); + printf("edx 0x%08x\n", frame.edx.word); + printf("ebp 0x%08x\n", frame.ebp.word); + printf("edi 0x%08x\n", frame.edi.word); + printf("esi 0x%08x\n", frame.esi.word); +#endif diff --git a/sys/dev/vmtvar.h b/sys/dev/vmtvar.h new file mode 100644 index 00000000000..5029d5e6085 --- /dev/null +++ b/sys/dev/vmtvar.h @@ -0,0 +1,19 @@ +/* $OpenBSD: vmtvar.h,v 1.1 2008/07/08 05:22:00 dlg Exp $ */ + +/* + * Copyright (c) 2008 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +int vmt_probe(void);