diff options
| author | fishsoupisgood <github@madingley.org> | 2019-04-29 01:17:54 +0100 | 
|---|---|---|
| committer | fishsoupisgood <github@madingley.org> | 2019-05-27 03:43:43 +0100 | 
| commit | 3f2546b2ef55b661fd8dd69682b38992225e86f6 (patch) | |
| tree | 65ca85f13617aee1dce474596800950f266a456c /roms/ipxe/src/arch/i386/interface/vmware | |
| download | qemu-master.tar.gz qemu-master.tar.bz2 qemu-master.zip | |
Diffstat (limited to 'roms/ipxe/src/arch/i386/interface/vmware')
| -rw-r--r-- | roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c | 271 | ||||
| -rw-r--r-- | roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c | 328 | ||||
| -rw-r--r-- | roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c | 134 | ||||
| -rw-r--r-- | roms/ipxe/src/arch/i386/interface/vmware/vmware.c | 58 | 
4 files changed, 791 insertions, 0 deletions
| diff --git a/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c b/roms/ipxe/src/arch/i386/interface/vmware/guestinfo.c new file mode 100644 index 00000000..a0530c8d --- /dev/null +++ b/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/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c b/roms/ipxe/src/arch/i386/interface/vmware/guestrpc.c new file mode 100644 index 00000000..390fc554 --- /dev/null +++ b/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/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c b/roms/ipxe/src/arch/i386/interface/vmware/vmconsole.c new file mode 100644 index 00000000..c6b9fff1 --- /dev/null +++ b/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/roms/ipxe/src/arch/i386/interface/vmware/vmware.c b/roms/ipxe/src/arch/i386/interface/vmware/vmware.c new file mode 100644 index 00000000..8074e611 --- /dev/null +++ b/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; +} | 
