summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/arch/i386/interface/vmware
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/ipxe/src/arch/i386/interface/vmware
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/arch/i386/interface/vmware')
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c271
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c328
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c134
-rw-r--r--qemu/roms/ipxe/src/arch/i386/interface/vmware/vmware.c58
4 files changed, 791 insertions, 0 deletions
diff --git a/qemu/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c b/qemu/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c
new file mode 100644
index 000000000..a0530c8d1
--- /dev/null
+++ b/qemu/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * VMware GuestInfo settings
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/init.h>
+#include <ipxe/settings.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/guestrpc.h>
+
+/** GuestInfo GuestRPC channel */
+static int guestinfo_channel;
+
+/**
+ * Fetch value of typed GuestInfo setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to fetch
+ * @v type Setting type to attempt (or NULL for default)
+ * @v data Buffer to fill with setting data
+ * @v len Length of buffer
+ * @ret found Setting found in GuestInfo
+ * @ret len Length of setting data, or negative error
+ */
+static int guestinfo_fetch_type ( struct settings *settings,
+ struct setting *setting,
+ const struct setting_type *type,
+ void *data, size_t len, int *found ) {
+ const char *parent_name = settings->parent->name;
+ char command[ 24 /* "info-get guestinfo.ipxe." */ +
+ strlen ( parent_name ) + 1 /* "." */ +
+ strlen ( setting->name ) + 1 /* "." */ +
+ ( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ];
+ struct setting *predefined;
+ char *info;
+ int info_len;
+ int check_len;
+ int ret;
+
+ /* Construct info-get command */
+ snprintf ( command, sizeof ( command ),
+ "info-get guestinfo.ipxe.%s%s%s%s%s",
+ parent_name, ( parent_name[0] ? "." : "" ), setting->name,
+ ( type ? "." : "" ), ( type ? type->name : "" ) );
+
+ /* Check for existence and obtain length of GuestInfo value */
+ info_len = guestrpc_command ( guestinfo_channel, command, NULL, 0 );
+ if ( info_len < 0 ) {
+ ret = info_len;
+ goto err_get_info_len;
+ }
+
+ /* Mark as found */
+ *found = 1;
+
+ /* Determine default type if necessary */
+ if ( ! type ) {
+ predefined = find_setting ( setting->name );
+ type = ( predefined ? predefined->type : &setting_type_string );
+ }
+ assert ( type != NULL );
+
+ /* Allocate temporary block to hold GuestInfo value */
+ info = zalloc ( info_len + 1 /* NUL */ );
+ if ( ! info ) {
+ DBGC ( settings, "GuestInfo %p could not allocate %d bytes\n",
+ settings, info_len );
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+ info[info_len] = '\0';
+
+ /* Fetch GuestInfo value */
+ check_len = guestrpc_command ( guestinfo_channel, command,
+ info, info_len );
+ if ( check_len < 0 ) {
+ ret = check_len;
+ goto err_get_info;
+ }
+ if ( check_len != info_len ) {
+ DBGC ( settings, "GuestInfo %p length mismatch (expected %d, "
+ "got %d)\n", settings, info_len, check_len );
+ ret = -EIO;
+ goto err_get_info;
+ }
+ DBGC2 ( settings, "GuestInfo %p found %s = \"%s\"\n",
+ settings, &command[9] /* Skip "info-get " */, info );
+
+ /* Parse GuestInfo value according to type */
+ ret = setting_parse ( type, info, data, len );
+ if ( ret < 0 ) {
+ DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: "
+ "%s\n", settings, info, type->name, strerror ( ret ) );
+ goto err_parse;
+ }
+
+ err_parse:
+ err_get_info:
+ free ( info );
+ err_alloc:
+ err_get_info_len:
+ return ret;
+}
+
+/**
+ * Fetch value of GuestInfo setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to fetch
+ * @v data Buffer to fill with setting data
+ * @v len Length of buffer
+ * @ret len Length of setting data, or negative error
+ */
+static int guestinfo_fetch ( struct settings *settings,
+ struct setting *setting,
+ void *data, size_t len ) {
+ struct setting_type *type;
+ int found = 0;
+ int ret;
+
+ /* Try default type first */
+ ret = guestinfo_fetch_type ( settings, setting, NULL,
+ data, len, &found );
+ if ( found )
+ return ret;
+
+ /* Otherwise, try all possible types */
+ for_each_table_entry ( type, SETTING_TYPES ) {
+ ret = guestinfo_fetch_type ( settings, setting, type,
+ data, len, &found );
+ if ( found )
+ return ret;
+ }
+
+ /* Not found */
+ return -ENOENT;
+}
+
+/** GuestInfo settings operations */
+static struct settings_operations guestinfo_settings_operations = {
+ .fetch = guestinfo_fetch,
+};
+
+/** GuestInfo settings */
+static struct settings guestinfo_settings = {
+ .refcnt = NULL,
+ .siblings = LIST_HEAD_INIT ( guestinfo_settings.siblings ),
+ .children = LIST_HEAD_INIT ( guestinfo_settings.children ),
+ .op = &guestinfo_settings_operations,
+};
+
+/** Initialise GuestInfo settings */
+static void guestinfo_init ( void ) {
+ int rc;
+
+ /* Open GuestRPC channel */
+ guestinfo_channel = guestrpc_open();
+ if ( guestinfo_channel < 0 ) {
+ rc = guestinfo_channel;
+ DBG ( "GuestInfo could not open channel: %s\n",
+ strerror ( rc ) );
+ return;
+ }
+
+ /* Register root GuestInfo settings */
+ if ( ( rc = register_settings ( &guestinfo_settings, NULL,
+ "vmware" ) ) != 0 ) {
+ DBG ( "GuestInfo could not register settings: %s\n",
+ strerror ( rc ) );
+ return;
+ }
+}
+
+/** GuestInfo settings initialiser */
+struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = {
+ .initialise = guestinfo_init,
+};
+
+/**
+ * Create per-netdevice GuestInfo settings
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int guestinfo_net_probe ( struct net_device *netdev ) {
+ struct settings *settings;
+ int rc;
+
+ /* Do nothing unless we have a GuestInfo channel available */
+ if ( guestinfo_channel < 0 )
+ return 0;
+
+ /* Allocate and initialise settings block */
+ settings = zalloc ( sizeof ( *settings ) );
+ if ( ! settings ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ settings_init ( settings, &guestinfo_settings_operations, NULL, NULL );
+
+ /* Register settings */
+ if ( ( rc = register_settings ( settings, netdev_settings ( netdev ),
+ "vmware" ) ) != 0 ) {
+ DBGC ( settings, "GuestInfo %p could not register for %s: %s\n",
+ settings, netdev->name, strerror ( rc ) );
+ goto err_register;
+ }
+ DBGC ( settings, "GuestInfo %p registered for %s\n",
+ settings, netdev->name );
+
+ return 0;
+
+ err_register:
+ free ( settings );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Remove per-netdevice GuestInfo settings
+ *
+ * @v netdev Network device
+ */
+static void guestinfo_net_remove ( struct net_device *netdev ) {
+ struct settings *parent = netdev_settings ( netdev );
+ struct settings *settings;
+
+ list_for_each_entry ( settings, &parent->children, siblings ) {
+ if ( settings->op == &guestinfo_settings_operations ) {
+ DBGC ( settings, "GuestInfo %p unregistered for %s\n",
+ settings, netdev->name );
+ unregister_settings ( settings );
+ free ( settings );
+ return;
+ }
+ }
+}
+
+/** GuestInfo per-netdevice driver */
+struct net_driver guestinfo_net_driver __net_driver = {
+ .name = "GuestInfo",
+ .probe = guestinfo_net_probe,
+ .remove = guestinfo_net_remove,
+};
diff --git a/qemu/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c b/qemu/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c
new file mode 100644
index 000000000..390fc5545
--- /dev/null
+++ b/qemu/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * VMware GuestRPC mechanism
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/vmware.h>
+#include <ipxe/guestrpc.h>
+
+/* Disambiguate the various error causes */
+#define EPROTO_OPEN __einfo_error ( EINFO_EPROTO_OPEN )
+#define EINFO_EPROTO_OPEN \
+ __einfo_uniqify ( EINFO_EPROTO, 0x00, "GuestRPC open failed" )
+#define EPROTO_COMMAND_LEN __einfo_error ( EINFO_EPROTO_COMMAND_LEN )
+#define EINFO_EPROTO_COMMAND_LEN \
+ __einfo_uniqify ( EINFO_EPROTO, 0x01, "GuestRPC command length failed" )
+#define EPROTO_COMMAND_DATA __einfo_error ( EINFO_EPROTO_COMMAND_DATA )
+#define EINFO_EPROTO_COMMAND_DATA \
+ __einfo_uniqify ( EINFO_EPROTO, 0x02, "GuestRPC command data failed" )
+#define EPROTO_REPLY_LEN __einfo_error ( EINFO_EPROTO_REPLY_LEN )
+#define EINFO_EPROTO_REPLY_LEN \
+ __einfo_uniqify ( EINFO_EPROTO, 0x03, "GuestRPC reply length failed" )
+#define EPROTO_REPLY_DATA __einfo_error ( EINFO_EPROTO_REPLY_DATA )
+#define EINFO_EPROTO_REPLY_DATA \
+ __einfo_uniqify ( EINFO_EPROTO, 0x04, "GuestRPC reply data failed" )
+#define EPROTO_REPLY_FINISH __einfo_error ( EINFO_EPROTO_REPLY_FINISH )
+#define EINFO_EPROTO_REPLY_FINISH \
+ __einfo_uniqify ( EINFO_EPROTO, 0x05, "GuestRPC reply finish failed" )
+#define EPROTO_CLOSE __einfo_error ( EINFO_EPROTO_CLOSE )
+#define EINFO_EPROTO_CLOSE \
+ __einfo_uniqify ( EINFO_EPROTO, 0x06, "GuestRPC close failed" )
+
+/**
+ * Open GuestRPC channel
+ *
+ * @ret channel Channel number, or negative error
+ */
+int guestrpc_open ( void ) {
+ uint16_t channel;
+ uint32_t discard_b;
+ uint32_t status;
+
+ /* Issue GuestRPC command */
+ status = vmware_cmd_guestrpc ( 0, GUESTRPC_OPEN, GUESTRPC_MAGIC,
+ &channel, &discard_b );
+ if ( status != GUESTRPC_OPEN_SUCCESS ) {
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC open failed: status %08x\n",
+ status );
+ return -EPROTO_OPEN;
+ }
+
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d opened\n", channel );
+ return channel;
+}
+
+/**
+ * Send GuestRPC command length
+ *
+ * @v channel Channel number
+ * @v len Command length
+ * @ret rc Return status code
+ */
+static int guestrpc_command_len ( int channel, size_t len ) {
+ uint16_t discard_d;
+ uint32_t discard_b;
+ uint32_t status;
+
+ /* Issue GuestRPC command */
+ status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_LEN, len,
+ &discard_d, &discard_b );
+ if ( status != GUESTRPC_COMMAND_LEN_SUCCESS ) {
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
+ "length %zd failed: status %08x\n",
+ channel, len, status );
+ return -EPROTO_COMMAND_LEN;
+ }
+
+ return 0;
+}
+
+/**
+ * Send GuestRPC command data
+ *
+ * @v channel Channel number
+ * @v data Command data
+ * @ret rc Return status code
+ */
+static int guestrpc_command_data ( int channel, uint32_t data ) {
+ uint16_t discard_d;
+ uint32_t discard_b;
+ uint32_t status;
+
+ /* Issue GuestRPC command */
+ status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_DATA, data,
+ &discard_d, &discard_b );
+ if ( status != GUESTRPC_COMMAND_DATA_SUCCESS ) {
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command "
+ "data %08x failed: status %08x\n",
+ channel, data, status );
+ return -EPROTO_COMMAND_DATA;
+ }
+
+ return 0;
+}
+
+/**
+ * Receive GuestRPC reply length
+ *
+ * @v channel Channel number
+ * @ret reply_id Reply ID
+ * @ret len Reply length, or negative error
+ */
+static int guestrpc_reply_len ( int channel, uint16_t *reply_id ) {
+ uint32_t len;
+ uint32_t status;
+
+ /* Issue GuestRPC command */
+ status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_LEN, 0,
+ reply_id, &len );
+ if ( status != GUESTRPC_REPLY_LEN_SUCCESS ) {
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
+ "length failed: status %08x\n", channel, status );
+ return -EPROTO_REPLY_LEN;
+ }
+
+ return len;
+}
+
+/**
+ * Receive GuestRPC reply data
+ *
+ * @v channel Channel number
+ * @v reply_id Reply ID
+ * @ret data Reply data
+ * @ret rc Return status code
+ */
+static int guestrpc_reply_data ( int channel, uint16_t reply_id,
+ uint32_t *data ) {
+ uint16_t discard_d;
+ uint32_t status;
+
+ /* Issue GuestRPC command */
+ status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_DATA, reply_id,
+ &discard_d, data );
+ if ( status != GUESTRPC_REPLY_DATA_SUCCESS ) {
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply "
+ "%d data failed: status %08x\n",
+ channel, reply_id, status );
+ return -EPROTO_REPLY_DATA;
+ }
+
+ return 0;
+}
+
+/**
+ * Finish receiving GuestRPC reply
+ *
+ * @v channel Channel number
+ * @v reply_id Reply ID
+ * @ret rc Return status code
+ */
+static int guestrpc_reply_finish ( int channel, uint16_t reply_id ) {
+ uint16_t discard_d;
+ uint32_t discard_b;
+ uint32_t status;
+
+ /* Issue GuestRPC command */
+ status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_FINISH, reply_id,
+ &discard_d, &discard_b );
+ if ( status != GUESTRPC_REPLY_FINISH_SUCCESS ) {
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d finish reply %d "
+ "failed: status %08x\n", channel, reply_id, status );
+ return -EPROTO_REPLY_FINISH;
+ }
+
+ return 0;
+}
+
+/**
+ * Close GuestRPC channel
+ *
+ * @v channel Channel number
+ */
+void guestrpc_close ( int channel ) {
+ uint16_t discard_d;
+ uint32_t discard_b;
+ uint32_t status;
+
+ /* Issue GuestRPC command */
+ status = vmware_cmd_guestrpc ( channel, GUESTRPC_CLOSE, 0,
+ &discard_d, &discard_b );
+ if ( status != GUESTRPC_CLOSE_SUCCESS ) {
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d close failed: "
+ "status %08x\n", channel, status );
+ return;
+ }
+
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d closed\n", channel );
+}
+
+/**
+ * Issue GuestRPC command
+ *
+ * @v channel Channel number
+ * @v command Command
+ * @v reply Reply buffer
+ * @v reply_len Length of reply buffer
+ * @ret len Length of reply, or negative error
+ *
+ * The actual length of the reply will be returned even if the buffer
+ * was too small.
+ */
+int guestrpc_command ( int channel, const char *command, char *reply,
+ size_t reply_len ) {
+ const uint8_t *command_bytes = ( ( const void * ) command );
+ uint8_t *reply_bytes = ( ( void * ) reply );
+ size_t command_len = strlen ( command );
+ int orig_reply_len = reply_len;
+ uint16_t status;
+ uint8_t *status_bytes = ( ( void * ) &status );
+ size_t status_len = sizeof ( status );
+ uint32_t data;
+ uint16_t reply_id;
+ int len;
+ int remaining;
+ unsigned int i;
+ int rc;
+
+ DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d issuing command:\n",
+ channel );
+ DBGC2_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
+
+ /* Sanity check */
+ assert ( ( reply != NULL ) || ( reply_len == 0 ) );
+
+ /* Send command length */
+ if ( ( rc = guestrpc_command_len ( channel, command_len ) ) < 0 )
+ return rc;
+
+ /* Send command data */
+ while ( command_len ) {
+ data = 0;
+ for ( i = sizeof ( data ) ; i ; i-- ) {
+ if ( command_len ) {
+ data = ( ( data & ~0xff ) |
+ *(command_bytes++) );
+ command_len--;
+ }
+ data = ( ( data << 24 ) | ( data >> 8 ) );
+ }
+ if ( ( rc = guestrpc_command_data ( channel, data ) ) < 0 )
+ return rc;
+ }
+
+ /* Receive reply length */
+ if ( ( len = guestrpc_reply_len ( channel, &reply_id ) ) < 0 ) {
+ rc = len;
+ return rc;
+ }
+
+ /* Receive reply */
+ for ( remaining = len ; remaining > 0 ; remaining -= sizeof ( data ) ) {
+ if ( ( rc = guestrpc_reply_data ( channel, reply_id,
+ &data ) ) < 0 ) {
+ return rc;
+ }
+ for ( i = sizeof ( data ) ; i ; i-- ) {
+ if ( status_len ) {
+ *(status_bytes++) = ( data & 0xff );
+ status_len--;
+ len--;
+ } else if ( reply_len ) {
+ *(reply_bytes++) = ( data & 0xff );
+ reply_len--;
+ }
+ data = ( ( data << 24 ) | ( data >> 8 ) );
+ }
+ }
+
+ /* Finish receiving RPC reply */
+ if ( ( rc = guestrpc_reply_finish ( channel, reply_id ) ) < 0 )
+ return rc;
+
+ DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d received reply (id %d, "
+ "length %d):\n", channel, reply_id, len );
+ DBGC2_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
+ DBGC2_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
+ ( ( len < orig_reply_len ) ? len : orig_reply_len ) );
+
+ /* Check reply status */
+ if ( status != GUESTRPC_SUCCESS ) {
+ DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d command failed "
+ "(status %04x, reply id %d, reply length %d):\n",
+ channel, status, reply_id, len );
+ DBGC_HDA ( GUESTRPC_MAGIC, 0, command, command_len );
+ DBGC_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) );
+ DBGC_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply,
+ ( ( len < orig_reply_len ) ? len : orig_reply_len ));
+ return -EIO;
+ }
+
+ return len;
+}
diff --git a/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c b/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c
new file mode 100644
index 000000000..c6b9fff12
--- /dev/null
+++ b/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * VMware logfile console
+ *
+ */
+
+#include <string.h>
+#include <ipxe/console.h>
+#include <ipxe/lineconsole.h>
+#include <ipxe/init.h>
+#include <ipxe/guestrpc.h>
+#include <config/console.h>
+
+/** VMware logfile console buffer size */
+#define VMCONSOLE_BUFSIZE 128
+
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_VMWARE ) && CONSOLE_EXPLICIT ( CONSOLE_VMWARE ) )
+#undef CONSOLE_VMWARE
+#define CONSOLE_VMWARE ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI )
+#endif
+
+/** VMware logfile console GuestRPC channel */
+static int vmconsole_channel;
+
+/** VMware logfile console line buffer */
+static struct {
+ char prefix[4];
+ char message[VMCONSOLE_BUFSIZE];
+} vmconsole_buffer = {
+ .prefix = "log ",
+};
+
+/** VMware logfile console ANSI escape sequence handlers */
+static struct ansiesc_handler vmconsole_handlers[] = {
+ { 0, NULL }
+};
+
+/** VMware logfile line console */
+static struct line_console vmconsole_line = {
+ .buffer = vmconsole_buffer.message,
+ .len = sizeof ( vmconsole_buffer.message ),
+ .ctx = {
+ .handlers = vmconsole_handlers,
+ },
+};
+
+/** VMware logfile console recursion marker */
+static int vmconsole_entered;
+
+/**
+ * Print a character to VMware logfile console
+ *
+ * @v character Character to be printed
+ */
+static void vmconsole_putchar ( int character ) {
+ int rc;
+
+ /* Ignore if we are already mid-logging */
+ if ( vmconsole_entered )
+ return;
+
+ /* Fill line buffer */
+ if ( line_putchar ( &vmconsole_line, character ) == 0 )
+ return;
+
+ /* Guard against re-entry */
+ vmconsole_entered = 1;
+
+ /* Send log message */
+ if ( ( rc = guestrpc_command ( vmconsole_channel,
+ vmconsole_buffer.prefix, NULL, 0 ) ) <0){
+ DBG ( "VMware console could not send log message: %s\n",
+ strerror ( rc ) );
+ }
+
+ /* Clear re-entry flag */
+ vmconsole_entered = 0;
+}
+
+/** VMware logfile console driver */
+struct console_driver vmconsole __console_driver = {
+ .putchar = vmconsole_putchar,
+ .disabled = CONSOLE_DISABLED,
+ .usage = CONSOLE_VMWARE,
+};
+
+/**
+ * Initialise VMware logfile console
+ *
+ */
+static void vmconsole_init ( void ) {
+ int rc;
+
+ /* Attempt to open console */
+ vmconsole_channel = guestrpc_open();
+ if ( vmconsole_channel < 0 ) {
+ rc = vmconsole_channel;
+ DBG ( "VMware console could not be initialised: %s\n",
+ strerror ( rc ) );
+ return;
+ }
+
+ /* Mark console as available */
+ vmconsole.disabled = 0;
+}
+
+/**
+ * VMware logfile console initialisation function
+ */
+struct init_fn vmconsole_init_fn __init_fn ( INIT_CONSOLE ) = {
+ .initialise = vmconsole_init,
+};
diff --git a/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmware.c b/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmware.c
new file mode 100644
index 000000000..8074e6118
--- /dev/null
+++ b/qemu/roms/ipxe/src/arch/i386/interface/vmware/vmware.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * VMware backdoor mechanism
+ *
+ * Based on the unofficial documentation at
+ *
+ * http://sites.google.com/site/chitchatvmback/backdoor
+ *
+ */
+
+#include <stdint.h>
+#include <errno.h>
+#include <ipxe/vmware.h>
+
+/**
+ * Detect VMware presence
+ *
+ * @ret rc Return status code
+ */
+int vmware_present ( void ) {
+ uint32_t version;
+ uint32_t magic;
+ uint32_t product_type;
+
+ /* Perform backdoor call */
+ vmware_cmd_get_version ( &version, &magic, &product_type );
+
+ /* Check for VMware presence */
+ if ( magic != VMW_MAGIC ) {
+ DBGC ( VMW_MAGIC, "VMware not present\n" );
+ return -ENOENT;
+ }
+
+ DBGC ( VMW_MAGIC, "VMware product type %04x version %08x detected\n",
+ product_type, version );
+ return 0;
+}