[vmware] Expose GuestRPC mechanism in 64-bit builds

The GuestRPC mechanism (used for VMWARE_SETTINGS and CONSOLE_VMWARE)
does not use any real-mode code and so can be exposed in both 64-bit
and 32-bit builds.

Reported-by: Matthew Helton <mwhelton@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2016-01-05 17:20:36 +00:00
parent 29cb090f98
commit dd485992dc
8 changed files with 1 additions and 1 deletions

View File

@@ -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,
};

View File

@@ -0,0 +1,332 @@
/*
* 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.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @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;
}

View File

@@ -0,0 +1,138 @@
/*
* 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.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @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,
};

View File

@@ -0,0 +1,62 @@
/*
* 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.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @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;
}