2009-04-13 02:05:42 -05:00
|
|
|
/**********************************************************
|
|
|
|
* Copyright 2008-2009 VMware, Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person
|
|
|
|
* obtaining a copy of this software and associated documentation
|
|
|
|
* files (the "Software"), to deal in the Software without
|
|
|
|
* restriction, including without limitation the rights to use, copy,
|
|
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
|
|
* of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be
|
|
|
|
* included in all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
|
|
|
*
|
|
|
|
**********************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* vmbackdoor.c --
|
|
|
|
*
|
|
|
|
* This is a tiny and self-contained client implementation of
|
|
|
|
* VMware's backdoor protocols for VMMouse, logging, and time.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "vmbackdoor.h"
|
|
|
|
#include "backdoor_def.h"
|
|
|
|
#include "vmmouse_defs.h"
|
2009-04-17 16:49:50 -05:00
|
|
|
#include "console.h"
|
2009-04-13 02:05:42 -05:00
|
|
|
|
|
|
|
#define BACKDOOR_VARS() \
|
|
|
|
uint32 eax = 0, ebx = 0, ecx = 0, edx = 0, esi = 0, edi = 0; \
|
|
|
|
|
|
|
|
#define BACKDOOR_ASM(op, port) \
|
|
|
|
{ \
|
|
|
|
eax = BDOOR_MAGIC; \
|
|
|
|
edx = (edx & 0xFFFF0000) | port; \
|
|
|
|
asm volatile (op : "+a" (eax), "+b" (ebx), \
|
|
|
|
"+c" (ecx), "+d" (edx), "+S" (esi), "+D" (edi)); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define BACKDOOR_ASM_IN() BACKDOOR_ASM("in %%dx, %0", BDOOR_PORT)
|
|
|
|
#define BACKDOOR_ASM_HB_OUT() BACKDOOR_ASM("cld; rep; outsb", BDOORHB_PORT)
|
|
|
|
#define BACKDOOR_ASM_HB_IN() BACKDOOR_ASM("cld; rep; insb", BDOORHB_PORT)
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_MouseInit --
|
|
|
|
*
|
|
|
|
* Initialize the backdoor VMMouse device. This is the virtualized
|
|
|
|
* mouse device that all modern versions of VMware Tools use.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* Puts the mouse in absolute or relative mode.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
VMBackdoor_MouseInit(Bool absolute) // IN
|
|
|
|
{
|
|
|
|
BACKDOOR_VARS()
|
|
|
|
|
|
|
|
ebx = VMMOUSE_CMD_READ_ID;
|
|
|
|
ecx = BDOOR_CMD_ABSPOINTER_COMMAND;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
|
|
|
ebx = 0;
|
|
|
|
ecx = BDOOR_CMD_ABSPOINTER_STATUS;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
|
|
|
ebx = 1;
|
|
|
|
ecx = BDOOR_CMD_ABSPOINTER_DATA;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
|
|
|
ebx = absolute ? VMMOUSE_CMD_REQUEST_ABSOLUTE : VMMOUSE_CMD_REQUEST_RELATIVE;
|
|
|
|
ecx = BDOOR_CMD_ABSPOINTER_COMMAND;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_MouseGetPacket --
|
|
|
|
*
|
|
|
|
* Poll for VMMouse packets.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* If a packet is available, returns TRUE and copies it to 'packet'.
|
|
|
|
* Returns FALSE if no packet is available.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
Bool
|
|
|
|
VMBackdoor_MouseGetPacket(VMMousePacket *packet) // OUT
|
|
|
|
{
|
|
|
|
const uint32 wordsToRead = 4;
|
|
|
|
BACKDOOR_VARS()
|
|
|
|
|
|
|
|
ebx = 0;
|
|
|
|
ecx = BDOOR_CMD_ABSPOINTER_STATUS;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
|
|
|
/* Low word of 'status' is the number of DWORDs in the device's FIFO */
|
|
|
|
if ((eax & 0x0000ffff) < wordsToRead) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ebx = wordsToRead;
|
|
|
|
ecx = BDOOR_CMD_ABSPOINTER_DATA;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
|
|
|
packet->x = (int32)ebx;
|
|
|
|
packet->y = (int32)ecx;
|
|
|
|
packet->z = (int32)edx;
|
|
|
|
packet->flags = eax >> 16;
|
|
|
|
packet->buttons = eax & 0xFFFF;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_GetTime --
|
|
|
|
*
|
|
|
|
* Read the host's real-time clock, with microsecond precision.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
VMBackdoor_GetTime(VMTime *time) // OUT
|
|
|
|
{
|
|
|
|
BACKDOOR_VARS()
|
|
|
|
|
|
|
|
ebx = 0;
|
|
|
|
ecx = BDOOR_CMD_GETTIMEFULL;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
|
|
|
time->usecs = ebx;
|
|
|
|
time->maxTimeLag = ecx;
|
|
|
|
time->secsLow = edx;
|
|
|
|
time->secsHigh = esi;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_TimeDiffUS --
|
|
|
|
*
|
|
|
|
* Compute the differene, in microseconds, of two time values in VMTime format.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* Number of microseconds.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
int32
|
|
|
|
VMBackdoor_TimeDiffUS(VMTime *first, // IN
|
|
|
|
VMTime *second) // IN
|
|
|
|
{
|
|
|
|
int32 secs = second->secsLow - first->secsLow;
|
|
|
|
int32 usec = second->usecs - first->usecs;
|
|
|
|
|
|
|
|
return (secs * 1000000) + usec;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_MsgOpen --
|
|
|
|
*
|
|
|
|
* Open a backdoor message channel.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* Initializes 'channel'.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
VMBackdoor_MsgOpen(VMMessageChannel *channel, // OUT
|
|
|
|
uint32 proto) // IN
|
|
|
|
{
|
|
|
|
BACKDOOR_VARS()
|
|
|
|
|
|
|
|
ecx = BDOOR_CMD_MESSAGE | 0x00000000; /* Open */
|
|
|
|
ebx = proto;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
|
|
|
if ((ecx & 0x00010000) == 0) {
|
2009-04-17 16:49:50 -05:00
|
|
|
Console_Panic("VMBackDoor: Failed to open message channel 0x%08x\n",
|
|
|
|
proto);
|
2009-04-13 02:05:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
channel->proto = proto;
|
|
|
|
channel->id = edx >> 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_MsgClose --
|
|
|
|
*
|
|
|
|
* Close a backdoor message channel.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* void.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
VMBackdoor_MsgClose(VMMessageChannel *channel) // OUT
|
|
|
|
{
|
|
|
|
BACKDOOR_VARS()
|
|
|
|
|
|
|
|
ecx = BDOOR_CMD_MESSAGE | 0x00060000; /* Close */
|
|
|
|
ebx = 0;
|
|
|
|
edx = channel->id << 16;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_MsgSend --
|
|
|
|
*
|
|
|
|
* Send a message over a VMMessageChannel.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* void.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
VMBackdoor_MsgSend(VMMessageChannel *channel, // IN
|
|
|
|
const void *buf, // IN
|
|
|
|
uint32 size) // IN
|
|
|
|
{
|
|
|
|
BACKDOOR_VARS()
|
|
|
|
|
|
|
|
ecx = BDOOR_CMD_MESSAGE | 0x00010000; /* Send size */
|
|
|
|
ebx = size;
|
|
|
|
edx = channel->id << 16;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
2009-04-17 16:49:50 -05:00
|
|
|
if (size == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-04-13 02:05:42 -05:00
|
|
|
if (((ecx >> 16) & 0x0081) != 0x0081) {
|
2009-04-17 16:49:50 -05:00
|
|
|
Console_Panic("VMBackdoor: Only the high-bandwidth backdoor port is supported.");
|
2009-04-13 02:05:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
ebx = 0x00010000 | BDOORHB_CMD_MESSAGE;
|
|
|
|
ecx = size;
|
|
|
|
edx = channel->id << 16;
|
|
|
|
esi = (uint32)buf;
|
|
|
|
BACKDOOR_ASM_HB_OUT()
|
|
|
|
|
|
|
|
/* Success? */
|
|
|
|
if (!(ebx & 0x00010000)) {
|
2009-04-17 16:49:50 -05:00
|
|
|
Console_Panic("VMBackdoor: Failed to send %d byte message:\n%s", size, buf);
|
2009-04-13 02:05:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_MsgReceive --
|
|
|
|
*
|
|
|
|
* Receive a message waiting on a VMMessageChannel.
|
|
|
|
*
|
|
|
|
* Results:
|
2009-04-17 16:49:50 -05:00
|
|
|
* Returns the number of bytes received, or 0 if no
|
|
|
|
* message is available.
|
2009-04-13 02:05:42 -05:00
|
|
|
*
|
|
|
|
* Side effects:
|
2009-04-17 16:49:50 -05:00
|
|
|
* Console_Panic on protocol error or buffer overflow.
|
2009-04-13 02:05:42 -05:00
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint32
|
|
|
|
VMBackdoor_MsgReceive(VMMessageChannel *channel, // IN
|
|
|
|
void *buf, // IN
|
|
|
|
uint32 bufSize) // IN
|
|
|
|
{
|
|
|
|
uint32 size;
|
|
|
|
BACKDOOR_VARS()
|
|
|
|
|
|
|
|
ecx = BDOOR_CMD_MESSAGE | 0x00030000; /* Receive size */
|
|
|
|
edx = channel->id << 16;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
2009-04-17 16:49:50 -05:00
|
|
|
if ((edx >> 16) != 0x0001) {
|
|
|
|
Console_Panic("VMBackdoor: Error receiving message size.");
|
2009-04-13 02:05:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
size = ebx;
|
|
|
|
if (size > bufSize) {
|
2009-04-17 16:49:50 -05:00
|
|
|
Console_Panic("VMBackdoor: Receive buffer overflow.");
|
|
|
|
}
|
|
|
|
if (size == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (((ecx >> 16) & 0x0083) != 0x0083) {
|
|
|
|
Console_Panic("VMBackdoor: Only the high-bandwidth backdoor port is supported.");
|
2009-04-13 02:05:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Receive payload */
|
|
|
|
ebx = BDOORHB_CMD_MESSAGE | 0x00010000;
|
|
|
|
ecx = size;
|
|
|
|
edx = channel->id << 16;
|
|
|
|
edi = (uint32)buf;
|
|
|
|
BACKDOOR_ASM_HB_IN()
|
|
|
|
|
|
|
|
/* Success? */
|
|
|
|
if (!(ebx & 0x00010000)) {
|
2009-04-17 16:49:50 -05:00
|
|
|
Console_Panic("VMBackdoor: Failed to receive %d byte message.", size);
|
2009-04-13 02:05:42 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Acknowledge status */
|
|
|
|
ecx = BDOOR_CMD_MESSAGE | 0x00050000;
|
|
|
|
ebx = 0x0001;
|
|
|
|
edx = channel->id << 16;
|
|
|
|
BACKDOOR_ASM_IN()
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_GetRPCIChannel --
|
|
|
|
*
|
|
|
|
* Return the channel to use for RPCI messages.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* Always returns a VMMessageChannel.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* Opens the channel if necessary.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
VMMessageChannel *
|
|
|
|
VMBackdoor_GetRPCIChannel(void)
|
|
|
|
{
|
|
|
|
static VMMessageChannel channel;
|
|
|
|
static Bool initialized;
|
|
|
|
|
|
|
|
if (!initialized) {
|
|
|
|
VMBackdoor_MsgOpen(&channel, 0x49435052); /* 'RPCI' */
|
|
|
|
initialized = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &channel;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-17 16:49:50 -05:00
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_GetTCLOChannel --
|
|
|
|
*
|
|
|
|
* Return the channel to use for TCLO messages.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* Always returns a VMMessageChannel.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* Opens the channel if necessary.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
VMMessageChannel *
|
|
|
|
VMBackdoor_GetTCLOChannel(void)
|
|
|
|
{
|
|
|
|
static VMMessageChannel channel;
|
|
|
|
static Bool initialized;
|
|
|
|
|
|
|
|
if (!initialized) {
|
|
|
|
VMBackdoor_MsgOpen(&channel, 0x4f4c4354); /* 'TCLO' */
|
|
|
|
initialized = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &channel;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-13 02:05:42 -05:00
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_RPCI --
|
|
|
|
*
|
|
|
|
* Synchronously deliver an RPCI message and collect its response.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* Returns the number of response bytes.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* Opens the channel if necessary.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint32
|
|
|
|
VMBackdoor_RPCI(const void *request, // IN
|
|
|
|
uint32 reqSize, // IN
|
|
|
|
void *replyBuffer, // OUT
|
|
|
|
uint32 replyBufferLen) // IN
|
|
|
|
{
|
|
|
|
VMMessageChannel *channel = VMBackdoor_GetRPCIChannel();
|
|
|
|
VMBackdoor_MsgSend(channel, request, reqSize);
|
|
|
|
return VMBackdoor_MsgReceive(channel, replyBuffer, replyBufferLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
2009-04-17 16:49:50 -05:00
|
|
|
* VMBackdoor_CheckedRPCI --
|
2009-04-13 02:05:42 -05:00
|
|
|
*
|
|
|
|
* Synchronously deliver an RPCI message, and expect a status
|
|
|
|
* response ("1" on success).
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* Opens the channel if necessary.
|
2009-04-17 16:49:50 -05:00
|
|
|
* Console_Panic on error.
|
2009-04-13 02:05:42 -05:00
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2009-04-17 16:49:50 -05:00
|
|
|
VMBackdoor_CheckedRPCI(const void *request, // IN
|
|
|
|
uint32 reqSize) // IN
|
2009-04-13 02:05:42 -05:00
|
|
|
{
|
|
|
|
uint8 replyBuf[16];
|
|
|
|
uint32 replyLen = VMBackdoor_RPCI(request, reqSize, replyBuf, sizeof replyBuf);
|
|
|
|
if (replyLen < 1 || replyBuf[0] != '1') {
|
2009-04-17 16:49:50 -05:00
|
|
|
Console_Panic("VMBackdoor: RPCI response invalid (%s)\n", replyBuf);
|
2009-04-13 02:05:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_VGAScreenshot --
|
|
|
|
*
|
|
|
|
* Log a screenshot of the VGA framebuffer over the backdoor.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* None.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* Opens the channel if necessary.
|
2009-04-17 16:49:50 -05:00
|
|
|
* Console_Panic on error.
|
2009-04-13 02:05:42 -05:00
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
VMBackdoor_VGAScreenshot(void)
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
const uint8 *fb = (void*)0xB8000;
|
|
|
|
static const char prefix[] = "log VGA: [00] ";
|
|
|
|
char lineBuf[81 + sizeof prefix];
|
|
|
|
char *linePtr;
|
|
|
|
uint32 lineLen;
|
|
|
|
|
|
|
|
memcpy(lineBuf, prefix, sizeof prefix);
|
|
|
|
|
|
|
|
for (y = 0; y < 25; y++) {
|
|
|
|
linePtr = lineBuf + sizeof prefix - 1;
|
|
|
|
lineLen = 0;
|
|
|
|
|
|
|
|
lineBuf[10] = '0' + y / 10;
|
|
|
|
lineBuf[11] = '0' + y % 10;
|
|
|
|
|
|
|
|
for (x = 0; x < 80; x++) {
|
|
|
|
*linePtr = *fb;
|
|
|
|
linePtr++;
|
|
|
|
if (*fb != ' ') {
|
|
|
|
lineLen = linePtr - lineBuf;
|
|
|
|
}
|
|
|
|
fb += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lineLen > 0) {
|
2009-04-17 16:49:50 -05:00
|
|
|
VMBackdoor_CheckedRPCI(lineBuf, lineLen);
|
2009-04-13 02:05:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-04-17 16:49:50 -05:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_PollTCLO --
|
|
|
|
*
|
|
|
|
* Poll for incoming commands from the TCLO channel, and flush
|
|
|
|
* the last reply if we had one. We internally handle the 'ping'
|
|
|
|
* and 'reset' commands.
|
|
|
|
*
|
|
|
|
* If 'verbose' is set, we print all incoming and outgoing
|
|
|
|
* messages to the console.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* Sets replyLen to zero, populates the 'command' buffer and sets
|
|
|
|
* commandLen.
|
|
|
|
*
|
|
|
|
* Returns TRUE if there was a command.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* Opens the channel if necessary.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
Bool
|
|
|
|
VMBackdoor_PollTCLO(VMTCLOState *state, // IN/OUT
|
|
|
|
Bool verbose) // IN
|
|
|
|
{
|
|
|
|
VMMessageChannel *channel = VMBackdoor_GetTCLOChannel();
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
if (state->replyLen && verbose) {
|
|
|
|
Console_Format("[TCLO OUT] '%s'\n", state->reply);
|
|
|
|
}
|
|
|
|
|
|
|
|
VMBackdoor_MsgSend(channel, state->reply, state->replyLen);
|
|
|
|
state->replyLen = 0;
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
memset(state->reply, 0, sizeof state->reply);
|
|
|
|
memset(state->command, 0, sizeof state->command);
|
|
|
|
}
|
|
|
|
|
|
|
|
state->commandLen = VMBackdoor_MsgReceive(channel, state->command,
|
|
|
|
sizeof state->command);
|
|
|
|
|
|
|
|
if (state->commandLen == 0) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
Console_Format("[TCLO IN ] '%s'\n", state->command);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VMBackdoor_CheckPrefixTCLO(state, "reset")) {
|
|
|
|
/* Send "Answer To Reply" */
|
|
|
|
VMBackdoor_ReplyTCLO(state, TCLO_SUCCESS "ATR toolbox");
|
|
|
|
|
|
|
|
} else if (VMBackdoor_CheckPrefixTCLO(state, "ping")) {
|
|
|
|
VMBackdoor_ReplyTCLO(state, TCLO_SUCCESS);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_CheckPrefixTCLO --
|
|
|
|
*
|
|
|
|
* Check for a particular TCLO command, by examining the command prefix.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* TRUE if 'prefix' matches, FALSE if not.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
Bool
|
|
|
|
VMBackdoor_CheckPrefixTCLO(VMTCLOState *state, // IN
|
|
|
|
const char *prefix) // IN
|
|
|
|
{
|
|
|
|
char *cmd = (char*) state->command;
|
|
|
|
char *cmdEnd = (char*) state->command + state->commandLen;
|
|
|
|
|
|
|
|
while (cmd < cmdEnd) {
|
|
|
|
if (*prefix == '\0') {
|
|
|
|
/* End of prefix. Matched! */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (*cmd != *prefix) {
|
|
|
|
/* Not matched */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
cmd++;
|
|
|
|
prefix++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Command length is <= prefix length. We only matched successfully
|
|
|
|
* if this is also the end of the prefix.
|
|
|
|
*/
|
|
|
|
return *prefix == '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_IntParamTCLO --
|
|
|
|
*
|
|
|
|
* Parse an integer parameter out of a TCLO command.
|
|
|
|
* "index" is the zero-based index of the command token to start
|
|
|
|
* at. Zero is the command prefix, one is the first space-separated
|
|
|
|
* token after the prefix, etc.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* Returns the parsed integer.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
int32
|
|
|
|
VMBackdoor_IntParamTCLO(VMTCLOState *state, // IN
|
|
|
|
int index) // IN
|
|
|
|
{
|
|
|
|
char *reply = (char*) state->command;
|
|
|
|
char *replyEnd = (char*) state->command + state->commandLen;
|
|
|
|
int32 result = 0;
|
|
|
|
Bool sign = FALSE;
|
|
|
|
|
|
|
|
while (reply < replyEnd && index > 0) {
|
|
|
|
if (*reply == ' ') {
|
|
|
|
index--;
|
|
|
|
}
|
|
|
|
reply++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (reply < replyEnd) {
|
|
|
|
char c = *reply;
|
|
|
|
|
|
|
|
if (c == '-') {
|
|
|
|
sign = !sign;
|
|
|
|
} else if (c >= '0' && c <= '9') {
|
|
|
|
result *= 10;
|
|
|
|
result += c - '0';
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
reply++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sign ? -result : result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* VMBackdoor_ReplyTCLO --
|
|
|
|
*
|
|
|
|
* Copy a reply string to the current TCLO state.
|
|
|
|
*
|
|
|
|
* Results:
|
|
|
|
* Modifies the reply buffer.
|
|
|
|
*
|
|
|
|
* Side effects:
|
|
|
|
* Panic on buffer overflow.
|
|
|
|
*
|
|
|
|
*-----------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
VMBackdoor_ReplyTCLO(VMTCLOState *state, // IN/OUT
|
|
|
|
const char *reply) // IN
|
|
|
|
{
|
|
|
|
state->replyLen = 0;
|
|
|
|
|
|
|
|
while (*reply) {
|
|
|
|
if (state->replyLen >= sizeof state->reply) {
|
|
|
|
Console_Panic("VMBackdoor: TCLO reply buffer overflow");
|
|
|
|
}
|
|
|
|
|
|
|
|
state->reply[state->replyLen] = *reply;
|
|
|
|
|
|
|
|
state->replyLen++;
|
|
|
|
reply++;
|
|
|
|
}
|
|
|
|
}
|