optString = StrUtil_GetNextToken(&idx, option, "=");
ASSERT(optString);
- if (StrUtil_GetNextIntToken(&ttl, &idx, option, "=") && ttl > 0) {
+ if (StrUtil_GetNextIntToken(&ttl, &idx, option, "=") && ttl >= 0) {
LOG("Setting maximum attribute TTL to %u\n", ttl);
mountInfo->ttl = ttl;
success = TRUE;
EXTERN int FileUnlockIntrinsic(ConstUnicode filePathName,
const void *lockToken);
+EXTERN Bool FileLockIsLocked(ConstUnicode filePath,
+ int *err);
+
EXTERN Bool FileLockValidOwner(const char *executionID,
const char *payload);
normalizedPath = FileLockNormalizePath(filePath);
if (normalizedPath == NULL) {
*err = EINVAL;
+
return NULL;
}
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * FileLock_IsLocked --
+ *
+ * Is a file currently locked (at the time of the call)?
+ *
+ * Results:
+ * TRUE YES
+ * FALSE NO; if err is not NULL may check *err for an error
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+FileLock_IsLocked(ConstUnicode filePath, // IN:
+ int *err) // OUT:
+{
+ Bool isLocked;
+ Unicode normalizedPath;
+
+ ASSERT(filePath);
+
+ normalizedPath = FileLockNormalizePath(filePath);
+ if (normalizedPath == NULL) {
+ if (err != NULL) {
+ *err = EINVAL;
+ }
+
+ return FALSE;
+ }
+
+ isLocked = FileLockIsLocked(normalizedPath, err);
+
+ Unicode_Free(normalizedPath);
+
+ return isLocked;
+}
+
+
/*
*----------------------------------------------------------------------
*
return err;
}
+
/*
*-----------------------------------------------------------------------------
*
return 0;
}
+
/*
*-----------------------------------------------------------------------------
*
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * FileLockIsLocked --
+ *
+ * Is a file currently locked (at the time of the call)?
+ *
+ * Results:
+ * TRUE YES
+ * FALSE NO; if err is not NULL may check *err for an error
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+FileLockIsLocked(ConstUnicode pathName, // IN:
+ int *err) // OUT:
+{
+ uint32 i;
+ int errValue;
+ int numEntries;
+ Unicode lockDir;
+
+ Bool isLocked = FALSE;
+ Unicode *fileList = NULL;
+
+ lockDir = Unicode_Append(pathName, FILELOCK_SUFFIX);
+
+ numEntries = FileListDirectoryRobust(lockDir, &fileList);
+
+ if (numEntries == -1) {
+ errValue = errno;
+
+ goto bail;
+ }
+
+ for (i = 0; i < numEntries; i++) {
+ if (Unicode_StartsWith(fileList[i], "M")) {
+ isLocked = TRUE;
+ break;
+ }
+ }
+
+ for (i = 0; i < numEntries; i++) {
+ Unicode_Free(fileList[i]);
+ }
+
+ free(fileList);
+
+ errValue = 0;
+
+bail:
+ Unicode_Free(lockDir);
+
+ if (err != NULL) {
+ *err = errValue;
+ }
+
+ return isLocked;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
#include "vix.h"
#include "foundryThreads.h"
+#include "vixOpenSource.h"
+#include "str.h"
+#include "msg.h"
#if _WIN32
#include <objbase.h.> // For CoInitializeEx
#else // Linux
#include <pthread.h>
static void *FoundryThreadWrapperProc(void *lpParameter);
+#if defined(linux)
+#include <sys/prctl.h>
+#endif
#endif
FoundryWorkerThread *
FoundryThreads_StartThread(FoundryThreadProc proc, // IN
- void *threadParam) // IN
+ void *threadParam, // IN
+ const char *threadName) // IN
{
VixError err = VIX_OK;
FoundryWorkerThread *threadState = NULL;
threadState = (FoundryWorkerThread *) Util_SafeCalloc(1, sizeof(*threadState));
threadState->threadProc = proc;
threadState->threadParam = threadParam;
+ threadState->threadName = threadName;
#ifdef _WIN32
threadState->threadHandle = CreateThread(NULL,
ASSERT(0);
goto abort;
}
+#if defined(linux) && defined(PR_SET_NAME)
+ {
+ char threadName[64];
+ int retval;
+ Str_Sprintf(threadName, sizeof threadName, "vix-%s", threadState->threadName);
+ retval = prctl(PR_SET_NAME, (unsigned long)threadName, 0,0, 0);
+ if (retval != 0) {
+ VIX_DEBUG(("%s prctl PR_SET_NAME failed = %s\n", __FUNCTION__, Msg_ErrString()));
+ }
+ }
+#endif
if (NULL != threadState->threadProc) {
(*(threadState->threadProc))(threadState);
#include "productState.h"
#include "posix.h"
-#if !defined(N_PLAT_NLM)
-# include "hgfs.h"
-# include "cpName.h"
-# include "cpNameUtil.h"
-#endif
+#include "hgfs.h"
+#include "cpName.h"
+#include "cpNameUtil.h"
#ifdef _MSC_VER
#include <windows.h>
* intelligent for that platform as well.
*/
-#if defined(N_PLAT_NLM)
-#define GUESTAPP_TOOLS_INSTALL_PATH "SYS:\\ETC\\VMWTOOL"
-#elif defined(_WIN32)
+#if defined(_WIN32)
#define GUESTAPP_TOOLS_INSTALL_PATH ""
#else
#define GUESTAPP_TOOLS_INSTALL_PATH "/etc/vmware-tools"
return FALSE;
}
-#if (defined N_PLAT_NLM || defined _WIN32)
+#if defined (_WIN32)
return (stricmp(value, "TRUE") == 0);
#else
return (strcasecmp(value, "TRUE") == 0);
}
-#if !defined(N_PLAT_NLM)
/*
*----------------------------------------------------------------------------
*
free(rpcMessage);
return TRUE;
}
-#endif
/*
#define BDOOR_CMD_GET_HOST_VIDEO_MODES 59 /* Not in use */
#define BDOOR_CMD_ACPI_HOTPLUG_CPU 60
#define BDOOR_CMD_USB_HOTPLUG_MOUSE 61 /* Not in use */
-#define BDOOR_CMD_MAX 62
+#define BDOOR_CMD_XPMODE 62
+#define BDOOR_CMD_MAX 63
/*
#include "guestApp.h"
-#ifdef N_PLAT_NLM
-#define CONF_FILE "tools.cfg"
-#else
#define CONF_FILE "tools.conf"
-#endif
-#ifdef N_PLAT_NLM
-# define CONFVAL_POWERONSCRIPT_DEFAULT "POWERON.NCF"
-# define CONFVAL_POWEROFFSCRIPT_DEFAULT "POWEROFF.NCF"
-# define CONFVAL_RESUMESCRIPT_DEFAULT "RESUME.NCF"
-# define CONFVAL_SUSPENDSCRIPT_DEFAULT "SUSPEND.NCF"
-#elif ! defined(_WIN32)
+#if ! defined(_WIN32)
# define CONFVAL_POWERONSCRIPT_DEFAULT "poweron-vm-default"
# define CONFVAL_POWEROFFSCRIPT_DEFAULT "poweroff-vm-default"
# define CONFVAL_RESUMESCRIPT_DEFAULT "resume-vm-default"
* Directory containing the tools library files. Currently only intended
* for vmware-user.
*/
-#if !defined(_WIN32) && !defined(N_PLAT_NLM)
+#if !defined(_WIN32)
# define CONFNAME_LIBDIR "libdir"
#endif
DynBuf_Copy(DynBuf *src, // IN
DynBuf *dest); // OUT
+void
+DynBuf_SafeInternalAppend(DynBuf *b, // IN
+ void const *data, // IN
+ size_t size, // IN
+ char const *file, // IN
+ unsigned int lineno); // IN
+
+#define DynBuf_SafeAppend(_buf, _data, _size) \
+ DynBuf_SafeInternalAppend(_buf, _data, _size, __FILE__, __LINE__)
+
/*
*-----------------------------------------------------------------------------
EXTERN int FileLock_Unlock(ConstUnicode filePath,
const void *fileLockToken);
+EXTERN Bool FileLock_IsLocked(ConstUnicode filePath,
+ int *err);
+
EXTERN int FileLock_Remove(ConstUnicode filePath);
EXTERN int FileLock_CleanupVM(ConstUnicode cfgfilePath);
typedef void (*FoundryThreadProc)(struct FoundryWorkerThread *threadState);
struct FoundryWorkerThread *FoundryThreads_StartThread(FoundryThreadProc proc,
- void *threadParam);
+ void *threadParam,
+ const char *threadName);
void FoundryThreads_StopThread(struct FoundryWorkerThread *threadState);
void FoundryThreads_Free(struct FoundryWorkerThread *threadState);
Bool FoundryThreads_IsCurrentThread(struct FoundryWorkerThread *threadState);
Bool stopThread;
void *threadParam;
+ const char *threadName;
} FoundryWorkerThread;
LOGLEVEL_VAR(ipc), \
LOGLEVEL_VAR(smbios), \
LOGLEVEL_VAR(acpi), \
+ LOGLEVEL_VAR(xpmode), \
LOGLEVEL_VAR(snapshot), \
LOGLEVEL_VAR(asyncsocket), \
LOGLEVEL_VAR(mainMem), \
LOGLEVEL_VAR(brtalk), /* macWireless and wpa_supplicant */ \
LOGLEVEL_VAR(button), \
LOGLEVEL_VAR(util), \
+ LOGLEVEL_VAR(win32util), \
LOGLEVEL_VAR(largepage), \
- LOGLEVEL_VAR(guestAppMonitor),
+ LOGLEVEL_VAR(guestAppMonitor), \
+
LOGLEVEL_EXTENSION_DECLARE(LOGLEVEL_USER);
typedef Bool (*MessageCloseProcType)(Message_Channel *chan);
-/*
- * This tells the message layer to use an alternate transport
- * for messages. By default, we use the backdoor, so this function
- * overrides that default at runtime and switches everything over to
- * an alternate transport.
- */
-void Message_SetTransport(MessageOpenProcType openProc,
- MessageGetReadEventProcType getReadEeventProc,
- MessageSendProcType sendProc,
- MessageReceiveProcType receiveProc,
- MessageCloseProcType closeProc);
-
-void MessageStub_RegisterTransport(void);
-
Message_Channel *
Message_Open(uint32 proto); // IN
-/*
- * This allows higher levels of the IPC stack to use an event to detect
- * when a message has arrived. This allows an interrupt-model rather than
- * continually calling Message_Receive in a busy loop. This may only be supported
- * by some transports. The backdoor does not, so the IPC code will still
- * have to poll in those cases.
- */
-Bool
-Message_GetReadEvent(Message_Channel *chan, // IN
- int64 *event); // OUT
-
Bool
Message_Send(Message_Channel *chan, // IN/OUT
const unsigned char *buf, // IN
#endif
#include "vm_basic_types.h"
-
-#if !defined(N_PLAT_NLM)
-# include "guestInfo.h"
-#endif
+#include "guestInfo.h"
/*
* Interface types as assigned by IANA.
char *NetUtil_GetPrimaryIP(void);
-#if !defined(N_PLAT_NLM)
GuestNic *NetUtil_GetPrimaryNic(void);
-#endif
#ifdef _WIN32
DWORD NetUtil_LoadIpHlpApiDll(void);
void NetUtilWin32_FreeMibTable(PMIB_IPFORWARD_TABLE2);
#endif
-#ifdef N_PLAT_NLM
-/* Monitoring IP changes */
-void NetUtil_MonitorIPStart(void);
-void NetUtil_MonitorIPStop(void);
-#endif
-
#ifdef WIN32
int NetUtil_InetPToN(int af, const char *src, void *dst);
const char *NetUtil_InetNToP(int af, const void *src, char *dst,
# define __PROCMGR_H__
#include "vm_basic_types.h"
-#if !defined(N_PLAT_NLM)
#include "auth.h"
+#if !defined(_WIN32)
+# include <sys/types.h>
#endif
-#if defined(N_PLAT_NLM)
-#include <nwconio.h>
-#elif !defined(_WIN32)
-#include <sys/types.h>
-#endif
-
-#if !defined(N_PLAT_NLM)
#include <time.h>
-#endif
/*
* Keeps track of the platform-specific handle(s) to an asynchronous process.
*/
typedef struct ProcMgr_AsyncProc ProcMgr_AsyncProc;
-#if defined(N_PLAT_NLM)
- typedef LONG ProcMgr_Pid;
-#elif defined(_WIN32)
+#if defined(_WIN32)
typedef DWORD ProcMgr_Pid;
#else /* POSIX */
typedef pid_t ProcMgr_Pid;
#if defined(_WIN32)
Bool *procDebugged;
#endif
-#if !defined(N_PLAT_NLM)
time_t *startTime;
-#endif
} ProcMgr_ProcList;
Bool ProcMgr_IsAsyncProcRunning(ProcMgr_AsyncProc *asyncProc);
int ProcMgr_GetExitCode(ProcMgr_AsyncProc *asyncProc, int *result);
void ProcMgr_Free(ProcMgr_AsyncProc *asyncProc);
-#if !defined(N_PLAT_NLM) && !defined(_WIN32)
+#if !defined(_WIN32)
Bool ProcMgr_ImpersonateUserStart(const char *user, // UTF-8
AuthToken token);
Bool ProcMgr_ImpersonateUserStop(void);
* then acted upon and translates to a -DPOSIX_LIKE_ENVIRONMENT
* preprocessor option.
*/
-#if !defined(_WIN32) && !defined(N_PLAT_NLM)
+#if !defined(_WIN32)
Bool System_WritePidFile(const char *fileName, pid_t pid);
const char **System_GetNativeEnviron(const char **compatEnviron);
void System_FreeNativeEnviron(const char **nativeEnviron);
/*
* The current Tools version, derived from vm_tools_version.h. Do not modify this.
*/
-#define TOOLS_VERSION "2009.08.24"
+#define TOOLS_VERSION TOOLS_VERSION_CURRENT_STR
#ifdef VMX86_VPX
#define VIM_API_TYPE "VirtualCenter"
HMODULE W32Util_GetModuleByAddress(const void *addr);
+Bool Win32Util_VerifyXPModeHostLicense(void);
+
#endif // _WIN32
#endif // WIN32UTIL_H_
libMessage_la_SOURCES =
libMessage_la_SOURCES += message.c
-libMessage_la_SOURCES += messageBackdoor.c
-libMessage_la_SOURCES += messageStub.c
#include "backdoor.h"
#include "message.h"
-static MessageOpenProcType externalOpenProc = NULL;
-static MessageGetReadEventProcType externalGetReadEventProc = NULL;
-static MessageSendProcType externalSendProc = NULL;
-static MessageReceiveProcType externalReceiveProc = NULL;
-static MessageCloseProcType externalCloseProc = NULL;
-
-/*
- * Currently, the default implementation is to use the backdoor. Soon,
- * this will not be the default, as we will explicitly set it when we
- * decide to use the backdoor.
- */
-EXTERN Message_Channel *MessageBackdoor_Open(uint32 proto);
-
-EXTERN Bool MessageBackdoor_GetReadEvent(Message_Channel *chan,
- int64 *event);
-
-EXTERN Bool MessageBackdoor_Send(Message_Channel *chan,
- const unsigned char *buf,
- size_t bufSize);
-
-EXTERN Bool MessageBackdoor_Receive(Message_Channel *chan,
- unsigned char **buf,
- size_t *bufSize);
-
-EXTERN Bool MessageBackdoor_Close(Message_Channel *chan);
+#if defined(MESSAGE_DEBUG)
+# define MESSAGE_LOG(...) Warning(__VA_ARGS__)
+#else
+# define MESSAGE_LOG(...)
+#endif
+/* The channel object */
+struct Message_Channel {
+ /* Identifier */
+ uint16 id;
-/*
- *-----------------------------------------------------------------------------
- *
- * Message_SetTransport --
- *
- * This tells the message layer to use an alternate transport
- * for messages. By default, we use the backdoor, so this function
- * overrides that default at runtime and switches everything over to
- * an alternate transport.
- *
- * Result:
- * None
- *
- * Side-effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
+ /* Reception buffer */
+ /* Data */
+ unsigned char *in;
+ /* Allocated size */
+ size_t inAlloc;
-void
-Message_SetTransport(MessageOpenProcType openProc, // IN
- MessageGetReadEventProcType getReadEeventProc, // IN
- MessageSendProcType sendProc, // IN
- MessageReceiveProcType receiveProc, // IN
- MessageCloseProcType closeProc) // IN
-{
- externalOpenProc = openProc;
- externalGetReadEventProc = getReadEeventProc;
- externalSendProc = sendProc;
- externalReceiveProc = receiveProc;
- externalCloseProc = closeProc;
-}
+ /* The cookie */
+ uint32 cookieHigh;
+ uint32 cookieLow;
+};
/*
Message_Channel *
Message_Open(uint32 proto) // IN
{
- /*
- * If there is an alterate backdoor implementation, then call that.
- */
- if (NULL != externalOpenProc) {
- return((*externalOpenProc)(proto));
+ Message_Channel *chan;
+ uint32 flags;
+ Backdoor_proto bp;
+
+ chan = (Message_Channel *)malloc(sizeof(*chan));
+ if (chan == NULL) {
+ goto error_quit;
}
- /*
- * Otherwise, we default to the backdoor.
- */
- return(MessageBackdoor_Open(proto));
-}
+ flags = GUESTMSG_FLAG_COOKIE;
+retry:
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_OPEN;
+ /* IN: Magic number of the protocol and flags */
+ bp.in.size = proto | flags;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if (flags) {
+ /* Cookies not supported. Fall back to no cookie. --hpreg */
+ flags = 0;
+ goto retry;
+ }
+
+ MESSAGE_LOG("Message: Unable to open a communication channel\n");
+ goto error_quit;
+ }
+ /* OUT: Id and cookie */
+ chan->id = bp.in.dx.halfs.high;
+ chan->cookieHigh = bp.out.si.word;
+ chan->cookieLow = bp.out.di.word;
-/*
- *-----------------------------------------------------------------------------
- *
- * Message_GetReadEvent --
- *
- * This allows higher levels of the IPC stack to use an event to detect
- * when a message has arrived. This allows an asynchronous, event-based-model
- * rather than continually calling Message_Receive in a busy loop. This may
- * only be supported by some transports. The backdoor does not, so the IPC
- * code will still have to poll in those cases.
- *
- * Result:
- * Bool - whether this feature is supported by this transport.
- *
- * Side-effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
+ /* Initialize the channel */
+ chan->in = NULL;
+ chan->inAlloc = 0;
-Bool
-Message_GetReadEvent(Message_Channel *chan, // IN
- int64 *event) // OUT
-{
- /*
- * If there is an alterate backdoor implementation, then call that.
- */
- if (NULL != externalGetReadEventProc) {
- return((*externalGetReadEventProc)(chan, event));
- }
+ return chan;
- /*
- * Otherwise, we default to the backdoor.
- */
- return(MessageBackdoor_GetReadEvent(chan, event));
+error_quit:
+ free(chan);
+ chan = NULL;
+ return NULL;
}
const unsigned char *buf, // IN
size_t bufSize) // IN
{
+ const unsigned char *myBuf;
+ size_t myBufSize;
+ Backdoor_proto bp;
+
+retry:
+ myBuf = buf;
+ myBufSize = bufSize;
+
/*
- * If there is an alterate backdoor implementation, then call that.
+ * Send the size.
*/
- if (NULL != externalSendProc) {
- return((*externalSendProc)(chan, buf, bufSize));
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_SENDSIZE;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Size */
+ bp.in.size = myBufSize;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ MESSAGE_LOG("Message: Unable to send a message over the communication "
+ "channel %u\n", chan->id);
+ return FALSE;
}
- /*
- * Otherwise, we default to the backdoor.
- */
- return(MessageBackdoor_Send(chan, buf, bufSize));
+ if (bp.in.cx.halfs.high & MESSAGE_STATUS_HB) {
+ /*
+ * High-bandwidth backdoor port supported. Send the message in one
+ * backdoor operation. --hpreg
+ */
+
+ if (myBufSize) {
+ Backdoor_proto_hb bphb;
+
+ bphb.in.bx.halfs.low = BDOORHB_CMD_MESSAGE;
+ bphb.in.bx.halfs.high = MESSAGE_STATUS_SUCCESS;
+ bphb.in.dx.halfs.high = chan->id;
+ bphb.in.bp.word = chan->cookieHigh;
+ bphb.in.dstAddr = chan->cookieLow;
+ bphb.in.size = myBufSize;
+ bphb.in.srcAddr = (uintptr_t) myBuf;
+ Backdoor_HbOut(&bphb);
+ if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG("Message: Unable to send a message over the "
+ "communication channel %u\n", chan->id);
+ return FALSE;
+ }
+ }
+ } else {
+ /*
+ * High-bandwidth backdoor port not supported. Send the message, 4 bytes
+ * at a time. --hpreg
+ */
+
+ for (;;) {
+ if (myBufSize == 0) {
+ /* We are done */
+ break;
+ }
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_SENDPAYLOAD;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Piece of message */
+ /*
+ * Beware in case we are not allowed to read extra bytes beyond the
+ * end of the buffer.
+ */
+ switch (myBufSize) {
+ case 1:
+ bp.in.size = myBuf[0];
+ myBufSize -= 1;
+ break;
+ case 2:
+ bp.in.size = myBuf[0] | myBuf[1] << 8;
+ myBufSize -= 2;
+ break;
+ case 3:
+ bp.in.size = myBuf[0] | myBuf[1] << 8 | myBuf[2] << 16;
+ myBufSize -= 3;
+ break;
+ default:
+ bp.in.size = *(const uint32 *)myBuf;
+ myBufSize -= 4;
+ break;
+ }
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG("Message: Unable to send a message over the "
+ "communication channel %u\n", chan->id);
+ return FALSE;
+ }
+
+ myBuf += 4;
+ }
+ }
+
+ return TRUE;
}
unsigned char **buf, // OUT
size_t *bufSize) // OUT
{
+ Backdoor_proto bp;
+ size_t myBufSize;
+ unsigned char *myBuf;
+
+retry:
+ /*
+ * Is there a message waiting for our retrieval?
+ */
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVSIZE;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ MESSAGE_LOG("Message: Unable to poll for messages over the "
+ "communication channel %u\n", chan->id);
+ return FALSE;
+ }
+
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_DORECV) == 0) {
+ /* No message to retrieve */
+ *bufSize = 0;
+ return TRUE;
+ }
+
/*
- * If there is an alterate backdoor implementation, then call that.
+ * Receive the size.
*/
- if (NULL != externalReceiveProc) {
- return((*externalReceiveProc)(chan, buf, bufSize));
+
+ /* OUT: Type */
+ if (bp.in.dx.halfs.high != MESSAGE_TYPE_SENDSIZE) {
+ MESSAGE_LOG("Message: Protocol error. Expected a "
+ "MESSAGE_TYPE_SENDSIZE request from vmware\n");
+ return FALSE;
}
+ /* OUT: Size */
+ myBufSize = bp.out.bx.word;
+
/*
- * Otherwise, we default to the backdoor.
+ * Allocate an extra byte for a trailing NUL character. The code that will
+ * deal with this message may not know about binary strings, and may expect
+ * a C string instead. --hpreg
*/
- return(MessageBackdoor_Receive(chan, buf, bufSize));
+ if (myBufSize + 1 > chan->inAlloc) {
+ myBuf = (unsigned char *)realloc(chan->in, myBufSize + 1);
+ if (myBuf == NULL) {
+ MESSAGE_LOG("Message: Not enough memory to receive a message over "
+ "the communication channel %u\n", chan->id);
+ goto error_quit;
+ }
+
+ chan->in = myBuf;
+ chan->inAlloc = myBufSize + 1;
+ }
+ *bufSize = myBufSize;
+ myBuf = *buf = chan->in;
+
+ if (bp.in.cx.halfs.high & MESSAGE_STATUS_HB) {
+ /*
+ * High-bandwidth backdoor port supported. Receive the message in one
+ * backdoor operation. --hpreg
+ */
+
+ if (myBufSize) {
+ Backdoor_proto_hb bphb;
+
+ bphb.in.bx.halfs.low = BDOORHB_CMD_MESSAGE;
+ bphb.in.bx.halfs.high = MESSAGE_STATUS_SUCCESS;
+ bphb.in.dx.halfs.high = chan->id;
+ bphb.in.srcAddr = chan->cookieHigh;
+ bphb.in.bp.word = chan->cookieLow;
+ bphb.in.size = myBufSize;
+ bphb.in.dstAddr = (uintptr_t) myBuf;
+ Backdoor_HbIn(&bphb);
+ if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG("Message: Unable to receive a message over the "
+ "communication channel %u\n", chan->id);
+ goto error_quit;
+ }
+ }
+ } else {
+ /*
+ * High-bandwidth backdoor port not supported. Receive the message, 4
+ * bytes at a time. --hpreg
+ */
+
+ for (;;) {
+ if (myBufSize == 0) {
+ /* We are done */
+ break;
+ }
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVPAYLOAD;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Status for the previous request (that succeeded) */
+ bp.in.size = MESSAGE_STATUS_SUCCESS;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG("Message: Unable to receive a message over the "
+ "communication channel %u\n", chan->id);
+ goto error_quit;
+ }
+
+ /* OUT: Type */
+ if (bp.in.dx.halfs.high != MESSAGE_TYPE_SENDPAYLOAD) {
+ MESSAGE_LOG("Message: Protocol error. Expected a "
+ "MESSAGE_TYPE_SENDPAYLOAD from vmware\n");
+ goto error_quit;
+ }
+
+ /* OUT: Piece of message */
+ /*
+ * Beware in case we are not allowed to write extra bytes beyond the
+ * end of the buffer. --hpreg
+ */
+ switch (myBufSize) {
+ case 1:
+ myBuf[0] = bp.out.bx.word & 0xff;
+ myBufSize -= 1;
+ break;
+ case 2:
+ myBuf[0] = bp.out.bx.word & 0xff;
+ myBuf[1] = (bp.out.bx.word >> 8) & 0xff;
+ myBufSize -= 2;
+ break;
+ case 3:
+ myBuf[0] = bp.out.bx.word & 0xff;
+ myBuf[1] = (bp.out.bx.word >> 8) & 0xff;
+ myBuf[2] = (bp.out.bx.word >> 16) & 0xff;
+ myBufSize -= 3;
+ break;
+ default:
+ *(uint32 *)myBuf = bp.out.bx.word;
+ myBufSize -= 4;
+ break;
+ }
+
+ myBuf += 4;
+ }
+ }
+
+ /* Write a trailing NUL just after the message. --hpreg */
+ chan->in[*bufSize] = '\0';
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVSTATUS;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Status for the previous request (that succeeded) */
+ bp.in.size = MESSAGE_STATUS_SUCCESS;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
+ /* A checkpoint occurred. Retry the operation. --hpreg */
+ goto retry;
+ }
+
+ MESSAGE_LOG("Message: Unable to receive a message over the "
+ "communication channel %u\n", chan->id);
+ goto error_quit;
+ }
+
+ return TRUE;
+
+error_quit:
+ /* IN: Type */
+ if (myBufSize == 0) {
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVSTATUS;
+ } else {
+ bp.in.cx.halfs.high = MESSAGE_TYPE_RECVPAYLOAD;
+ }
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+ /* IN: Status for the previous request (that failed) */
+ bp.in.size = 0;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ MESSAGE_LOG("Message: Unable to signal an error of reception over the "
+ "communication channel %u\n", chan->id);
+ return FALSE;
+ }
+
+ return FALSE;
}
Bool
Message_Close(Message_Channel *chan) // IN/OUT
{
- /*
- * If there is an alterate backdoor implementation, then call that.
- */
- if (NULL != externalCloseProc) {
- return((*externalCloseProc)(chan));
+ Backdoor_proto bp;
+ Bool ret = TRUE;
+
+ /* IN: Type */
+ bp.in.cx.halfs.high = MESSAGE_TYPE_CLOSE;
+ /* IN: Id and cookie */
+ bp.in.dx.halfs.high = chan->id;
+ bp.in.si.word = chan->cookieHigh;
+ bp.in.di.word = chan->cookieLow;
+
+ bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
+ Backdoor(&bp);
+
+ /* OUT: Status */
+ if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
+ MESSAGE_LOG("Message: Unable to close the communication channel %u\n",
+ chan->id);
+ ret = FALSE;
}
- /*
- * Otherwise, we default to the backdoor.
- */
- return(MessageBackdoor_Close(chan));
+ free(chan->in);
+ chan->in = NULL;
+
+ free(chan);
+ return ret;
}
#ifdef __cplusplus
+++ /dev/null
-/*********************************************************
- * Copyright (C) 1999 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-/*********************************************************
- * The contents of this file are subject to the terms of the Common
- * Development and Distribution License (the "License") version 1.0
- * and no later version. You may not use this file except in
- * compliance with the License.
- *
- * You can obtain a copy of the License at
- * http://www.opensource.org/licenses/cddl1.php
- *
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- *********************************************************/
-
-/*
- * messageBackdoor.c --
- *
- * Second layer of the internal communication channel between guest
- * applications and vmware
- *
- * Build a generic messaging system between guest applications and vmware.
- *
- * The protocol is not completely symmetrical, because:
- * . basic requests can only be sent by guest applications (when vmware
- * wants to post a message to a guest application, the message will be
- * really fetched only when the guest application will poll for new
- * available messages)
- * . several guest applications can talk to vmware, while the contrary is
- * not true
- *
- * Operations that are not atomic (in terms of number of backdoor calls)
- * can be aborted by vmware if a checkpoint/restore occurs in the middle of
- * such an operation. This layer takes care of retrying those operations.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-#if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL)
-# include "kernelStubs.h"
-#else
-# include <stdio.h>
-# include <stdlib.h>
-# include "debug.h"
-#endif
-
-#ifdef MESSAGE_DEBUG
-# define MESSAGE_LOG(args) Debug args
-#else /* MESSAGE_DEBUG */
-# define MESSAGE_LOG(args)
-#endif /* MESSAGE_DEBUG */
-
-
-#include "backdoor_def.h"
-#include "guest_msg_def.h"
-#include "backdoor.h"
-#include "message.h"
-
-
-/* The channel object */
-struct Message_Channel {
- /* Identifier */
- uint16 id;
-
- /* Reception buffer */
- /* Data */
- unsigned char *in;
- /* Allocated size */
- size_t inAlloc;
-
- /* The cookie */
- uint32 cookieHigh;
- uint32 cookieLow;
-};
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MessageBackdoor_Open --
- *
- * Open a communication channel
- *
- * Result:
- * An allocated Message_Channel on success
- * NULL on failure
- *
- * Side-effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Message_Channel *
-MessageBackdoor_Open(uint32 proto) // IN
-{
- Message_Channel *chan;
- uint32 flags;
- Backdoor_proto bp;
-
- chan = (Message_Channel *)malloc(sizeof(*chan));
- if (chan == NULL) {
- MESSAGE_LOG(("Message: Not enough memory\n"));
- goto error_quit;
- }
-
- flags = GUESTMSG_FLAG_COOKIE;
-retry:
- /* IN: Type */
- bp.in.cx.halfs.high = MESSAGE_TYPE_OPEN;
- /* IN: Magic number of the protocol and flags */
- bp.in.size = proto | flags;
-
- bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
- Backdoor(&bp);
-
- /* OUT: Status */
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- if (flags) {
- /* Cookies not supported. Fall back to no cookie. --hpreg */
- flags = 0;
- goto retry;
- }
-
- MESSAGE_LOG(("Message: Unable to open a communication channel\n"));
- goto error_quit;
- }
-
- /* OUT: Id and cookie */
- chan->id = bp.in.dx.halfs.high;
- chan->cookieHigh = bp.out.si.word;
- chan->cookieLow = bp.out.di.word;
-
- /* Initialize the channel */
- chan->in = NULL;
- chan->inAlloc = 0;
-
- MESSAGE_LOG(("Message: Communication channel %u opened\n", chan->id));
- return chan;
-
-error_quit:
- free(chan);
- chan = NULL;
- return NULL;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MessageBackdoor_GetReadEvent --
- *
- * This allows higher levels of the IPC stack to use an event to detect
- * when a message has arrived. This allows an interrupt-model rather than
- * continually calling Message_Receive in a busy loop. This may only be supported
- * by some transports. The backdoor does not, so the IPC code will still
- * have to poll in those cases.
- *
- * Result:
- * Bool - whether this feature is supported by this transport.
- *
- * Side-effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-MessageBackdoor_GetReadEvent(Message_Channel *chan, // IN
- int64 *event) // OUT
-{
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MessageBackdoor_Send --
- *
- * Send a message over a communication channel
- *
- * Result:
- * TRUE on success
- * FALSE on failure (the message is discarded by vmware)
- *
- * Side-effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-MessageBackdoor_Send(Message_Channel *chan, // IN/OUT
- const unsigned char *buf, // IN
- size_t bufSize) // IN
-{
- const unsigned char *myBuf;
- size_t myBufSize;
- Backdoor_proto bp;
-
-retry:
- myBuf = buf;
- myBufSize = bufSize;
-
- /*
- * Send the size.
- */
-
- /* IN: Type */
- bp.in.cx.halfs.high = MESSAGE_TYPE_SENDSIZE;
- /* IN: Id and cookie */
- bp.in.dx.halfs.high = chan->id;
- bp.in.si.word = chan->cookieHigh;
- bp.in.di.word = chan->cookieLow;
- /* IN: Size */
- bp.in.size = myBufSize;
-
- bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
- Backdoor(&bp);
-
- /* OUT: Status */
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- MESSAGE_LOG(("Message: Unable to send a message over the communication "
- "channel %u\n", chan->id));
- return FALSE;
- }
-
- if (bp.in.cx.halfs.high & MESSAGE_STATUS_HB) {
- /*
- * High-bandwidth backdoor port supported. Send the message in one
- * backdoor operation. --hpreg
- */
-
- if (myBufSize) {
- Backdoor_proto_hb bphb;
-
- bphb.in.bx.halfs.low = BDOORHB_CMD_MESSAGE;
- bphb.in.bx.halfs.high = MESSAGE_STATUS_SUCCESS;
- bphb.in.dx.halfs.high = chan->id;
- bphb.in.bp.word = chan->cookieHigh;
- bphb.in.dstAddr = chan->cookieLow;
- bphb.in.size = myBufSize;
- bphb.in.srcAddr = (uintptr_t) myBuf;
- Backdoor_HbOut(&bphb);
- if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
- /* A checkpoint occurred. Retry the operation. --hpreg */
- goto retry;
- }
-
- MESSAGE_LOG(("Message: Unable to send a message over the "
- "communication channel %u\n", chan->id));
- return FALSE;
- }
- }
- } else {
- /*
- * High-bandwidth backdoor port not supported. Send the message, 4 bytes
- * at a time. --hpreg
- */
-
- for (;;) {
- if (myBufSize == 0) {
- /* We are done */
- break;
- }
-
- /* IN: Type */
- bp.in.cx.halfs.high = MESSAGE_TYPE_SENDPAYLOAD;
- /* IN: Id and cookie */
- bp.in.dx.halfs.high = chan->id;
- bp.in.si.word = chan->cookieHigh;
- bp.in.di.word = chan->cookieLow;
- /* IN: Piece of message */
- /*
- * Beware in case we are not allowed to read extra bytes beyond the
- * end of the buffer.
- */
- switch (myBufSize) {
- case 1:
- bp.in.size = myBuf[0];
- myBufSize -= 1;
- break;
- case 2:
- bp.in.size = myBuf[0] | myBuf[1] << 8;
- myBufSize -= 2;
- break;
- case 3:
- bp.in.size = myBuf[0] | myBuf[1] << 8 | myBuf[2] << 16;
- myBufSize -= 3;
- break;
- default:
- bp.in.size = *(const uint32 *)myBuf;
- myBufSize -= 4;
- break;
- }
-
- bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
- Backdoor(&bp);
-
- /* OUT: Status */
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
- /* A checkpoint occurred. Retry the operation. --hpreg */
- goto retry;
- }
-
- MESSAGE_LOG(("Message: Unable to send a message over the "
- "communication channel %u\n", chan->id));
- return FALSE;
- }
-
- myBuf += 4;
- }
- }
-
- MESSAGE_LOG(("Message: Sent a message over the communication channel %u\n",
- chan->id));
-
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MessageBackdoor_Receive --
- *
- * If vmware has posted a message for this channel, retrieve it
- *
- * Result:
- * TRUE on success (bufSize is 0 if there is no message)
- * FALSE on failure
- *
- * Side-effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-MessageBackdoor_Receive(Message_Channel *chan, // IN/OUT
- unsigned char **buf, // OUT
- size_t *bufSize) // OUT
-{
- Backdoor_proto bp;
- size_t myBufSize;
- unsigned char *myBuf;
-
-retry:
- /*
- * Is there a message waiting for our retrieval?
- */
-
- /* IN: Type */
- bp.in.cx.halfs.high = MESSAGE_TYPE_RECVSIZE;
- /* IN: Id and cookie */
- bp.in.dx.halfs.high = chan->id;
- bp.in.si.word = chan->cookieHigh;
- bp.in.di.word = chan->cookieLow;
-
- bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
- Backdoor(&bp);
-
- /* OUT: Status */
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- MESSAGE_LOG(("Message: Unable to poll for messages over the "
- "communication channel %u\n", chan->id));
- return FALSE;
- }
-
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_DORECV) == 0) {
- /* No message to retrieve */
- *bufSize = 0;
- return TRUE;
- }
-
- /*
- * Receive the size.
- */
-
- /* OUT: Type */
- if (bp.in.dx.halfs.high != MESSAGE_TYPE_SENDSIZE) {
- MESSAGE_LOG(("Message: Protocol error. Expected a "
- "MESSAGE_TYPE_SENDSIZE request from vmware\n"));
- return FALSE;
- }
-
- /* OUT: Size */
- myBufSize = bp.out.bx.word;
-
- /*
- * Allocate an extra byte for a trailing NUL character. The code that will
- * deal with this message may not know about binary strings, and may expect
- * a C string instead. --hpreg
- */
- if (myBufSize + 1 > chan->inAlloc) {
- myBuf = (unsigned char *)realloc(chan->in, myBufSize + 1);
- if (myBuf == NULL) {
- MESSAGE_LOG(("Message: Not enough memory to receive a message over "
- "the communication channel %u\n", chan->id));
- goto error_quit;
- }
-
- chan->in = myBuf;
- chan->inAlloc = myBufSize + 1;
- }
- *bufSize = myBufSize;
- myBuf = *buf = chan->in;
-
- if (bp.in.cx.halfs.high & MESSAGE_STATUS_HB) {
- /*
- * High-bandwidth backdoor port supported. Receive the message in one
- * backdoor operation. --hpreg
- */
-
- if (myBufSize) {
- Backdoor_proto_hb bphb;
-
- bphb.in.bx.halfs.low = BDOORHB_CMD_MESSAGE;
- bphb.in.bx.halfs.high = MESSAGE_STATUS_SUCCESS;
- bphb.in.dx.halfs.high = chan->id;
- bphb.in.srcAddr = chan->cookieHigh;
- bphb.in.bp.word = chan->cookieLow;
- bphb.in.size = myBufSize;
- bphb.in.dstAddr = (uintptr_t) myBuf;
- Backdoor_HbIn(&bphb);
- if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- if ((bphb.in.bx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
- /* A checkpoint occurred. Retry the operation. --hpreg */
- goto retry;
- }
-
- MESSAGE_LOG(("Message: Unable to receive a message over the "
- "communication channel %u\n", chan->id));
- goto error_quit;
- }
- }
- } else {
- /*
- * High-bandwidth backdoor port not supported. Receive the message, 4
- * bytes at a time. --hpreg
- */
-
- for (;;) {
- if (myBufSize == 0) {
- /* We are done */
- break;
- }
-
- /* IN: Type */
- bp.in.cx.halfs.high = MESSAGE_TYPE_RECVPAYLOAD;
- /* IN: Id and cookie */
- bp.in.dx.halfs.high = chan->id;
- bp.in.si.word = chan->cookieHigh;
- bp.in.di.word = chan->cookieLow;
- /* IN: Status for the previous request (that succeeded) */
- bp.in.size = MESSAGE_STATUS_SUCCESS;
-
- bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
- Backdoor(&bp);
-
- /* OUT: Status */
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
- /* A checkpoint occurred. Retry the operation. --hpreg */
- goto retry;
- }
-
- MESSAGE_LOG(("Message: Unable to receive a message over the "
- "communication channel %u\n", chan->id));
- goto error_quit;
- }
-
- /* OUT: Type */
- if (bp.in.dx.halfs.high != MESSAGE_TYPE_SENDPAYLOAD) {
- MESSAGE_LOG(("Message: Protocol error. Expected a "
- "MESSAGE_TYPE_SENDPAYLOAD from vmware\n"));
- goto error_quit;
- }
-
- /* OUT: Piece of message */
- /*
- * Beware in case we are not allowed to write extra bytes beyond the
- * end of the buffer. --hpreg
- */
- switch (myBufSize) {
- case 1:
- myBuf[0] = bp.out.bx.word & 0xff;
- myBufSize -= 1;
- break;
- case 2:
- myBuf[0] = bp.out.bx.word & 0xff;
- myBuf[1] = (bp.out.bx.word >> 8) & 0xff;
- myBufSize -= 2;
- break;
- case 3:
- myBuf[0] = bp.out.bx.word & 0xff;
- myBuf[1] = (bp.out.bx.word >> 8) & 0xff;
- myBuf[2] = (bp.out.bx.word >> 16) & 0xff;
- myBufSize -= 3;
- break;
- default:
- *(uint32 *)myBuf = bp.out.bx.word;
- myBufSize -= 4;
- break;
- }
-
- myBuf += 4;
- }
- }
-
- /* Write a trailing NUL just after the message. --hpreg */
- chan->in[*bufSize] = '\0';
-
- /* IN: Type */
- bp.in.cx.halfs.high = MESSAGE_TYPE_RECVSTATUS;
- /* IN: Id and cookie */
- bp.in.dx.halfs.high = chan->id;
- bp.in.si.word = chan->cookieHigh;
- bp.in.di.word = chan->cookieLow;
- /* IN: Status for the previous request (that succeeded) */
- bp.in.size = MESSAGE_STATUS_SUCCESS;
-
- bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
- Backdoor(&bp);
-
- /* OUT: Status */
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_CPT) != 0) {
- /* A checkpoint occurred. Retry the operation. --hpreg */
- goto retry;
- }
-
- MESSAGE_LOG(("Message: Unable to receive a message over the "
- "communication channel %u\n", chan->id));
- goto error_quit;
- }
-
- return TRUE;
-
-error_quit:
- /* IN: Type */
- if (myBufSize == 0) {
- bp.in.cx.halfs.high = MESSAGE_TYPE_RECVSTATUS;
- } else {
- bp.in.cx.halfs.high = MESSAGE_TYPE_RECVPAYLOAD;
- }
- /* IN: Id and cookie */
- bp.in.dx.halfs.high = chan->id;
- bp.in.si.word = chan->cookieHigh;
- bp.in.di.word = chan->cookieLow;
- /* IN: Status for the previous request (that failed) */
- bp.in.size = 0;
-
- bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
- Backdoor(&bp);
-
- /* OUT: Status */
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- MESSAGE_LOG(("Message: Unable to signal an error of reception over the "
- "communication channel %u\n", chan->id));
- return FALSE;
- }
-
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MessageBackdoor_Close --
- *
- * Close a communication channel
- *
- * Result:
- * TRUE on success, the channel is destroyed
- * FALSE on failure
- *
- * Side-effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-MessageBackdoor_Close(Message_Channel *chan) // IN/OUT
-{
- Backdoor_proto bp;
- Bool ret = TRUE;
-
- /* IN: Type */
- bp.in.cx.halfs.high = MESSAGE_TYPE_CLOSE;
- /* IN: Id and cookie */
- bp.in.dx.halfs.high = chan->id;
- bp.in.si.word = chan->cookieHigh;
- bp.in.di.word = chan->cookieLow;
-
- bp.in.cx.halfs.low = BDOOR_CMD_MESSAGE;
- Backdoor(&bp);
-
- /* OUT: Status */
- if ((bp.in.cx.halfs.high & MESSAGE_STATUS_SUCCESS) == 0) {
- MESSAGE_LOG(("Message: Unable to close the communication channel %u\n",
- chan->id));
- ret = FALSE;
- } else {
- MESSAGE_LOG(("Message: Communication channel %u closed\n", chan->id));
- }
-
- free(chan->in);
- chan->in = NULL;
-
- free(chan);
- return ret;
-}
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/*********************************************************
- * Copyright (C) 2004 VMware, Inc. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation version 2.1 and no 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 Lesser GNU General Public
- * License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- *********************************************************/
-
-/*********************************************************
- * The contents of this file are subject to the terms of the Common
- * Development and Distribution License (the "License") version 1.0
- * and no later version. You may not use this file except in
- * compliance with the License.
- *
- * You can obtain a copy of the License at
- * http://www.opensource.org/licenses/cddl1.php
- *
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- *********************************************************/
-
-/*
- * MessageStub.c --
- *
- * Implement the message interface that does nothing.
- *
- */
-
-#if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL)
-# include "kernelStubs.h"
-#else
-# include <stdio.h>
-# include <stdlib.h>
-# include "debug.h"
-#endif
-
-#include "backdoor_def.h"
-#include "guest_msg_def.h"
-#include "backdoor.h"
-#include "message.h"
-
-
-static Message_Channel *MessageStub_Open(uint32 proto);
-
-static Bool MessageStub_Close(Message_Channel *chan);
-
-static Bool MessageStub_Receive(Message_Channel *chan,
- unsigned char **buf,
- size_t *bufSize);
-
-static Bool MessageStub_Send(Message_Channel *chan,
- const unsigned char *buf,
- size_t bufSize);
-
-static Bool MessageStub_GetReadEvent(Message_Channel *chan,
- int64 *readEvent);
-
-
-static int globalStubChannel = 0;
-
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MessageStub_RegisterTransport --
- *
- *
- * Results:
- * Bool
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-MessageStub_RegisterTransport(void)
-{
- Message_SetTransport(MessageStub_Open,
- MessageStub_GetReadEvent,
- MessageStub_Send,
- MessageStub_Receive,
- MessageStub_Close);
-} // MessageStub_RegisterTransport
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MessageStub_Open --
- *
- * Open a new channel, which can receive new socket connections.
- *
- * Results:
- * Bool
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Message_Channel *
-MessageStub_Open(uint32 proto) // IN
-{
- return((Message_Channel *) &globalStubChannel);
-} // MessageStub_Open
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MessageStub_Close --
- *
- * Close the channel and all socket connections.
- *
- * Results:
- * Bool
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-MessageStub_Close(Message_Channel *chan) // IN
-{
- return(TRUE);
-} // MessageStub_Close
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * MessageStub_GetReadEvent --
- * *
- * Results:
- * Bool
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-MessageStub_GetReadEvent(Message_Channel *chan, // IN
- int64 *readEvent) // OUT
-{
- return(FALSE);
-} // MessageStub_GetReadEvent
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * MessageStub_Receive --
- *
- * Results:
- * Bool.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-MessageStub_Receive(Message_Channel *chan, // IN
- unsigned char **buf, // IN
- size_t *bufSize) // IN
-{
- if (NULL != buf) {
- *buf = NULL;
- }
- if (NULL != bufSize) {
- *bufSize = 0;
- }
-
- return(TRUE);
-} // MessageStub_Receive
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * MessageStub_Send --
- *
- * Results:
- * Bool.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-MessageStub_Send(Message_Channel *chan, // IN
- const unsigned char *buf, // IN
- size_t bufSize) // IN
-{
- return(TRUE);
-} // MessageStub_Send
-
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynBuf_SafeInternalAppend --
+ *
+ * Append data at the end of a dynamic buffer. Memory allocation failure
+ * are handled the same way as Util_SafeMalloc, that is to say, with a
+ * Panic.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+DynBuf_SafeInternalAppend(DynBuf *b, // IN
+ void const *data, // IN
+ size_t size, // IN
+ char const *file, // IN
+ unsigned int lineno) // IN
+{
+ if (!DynBuf_Append(b, data, size)) {
+ Panic("Unrecoverable memory allocation failure at %s:%u\n",
+ file, lineno);
+ }
+}
+
+
/*
*-----------------------------------------------------------------------------
*
#ifdef _WIN32
osFamily = GUEST_OS_FAMILY_WINDOWS;
-#elif defined(N_PLAT_NLM)
- osFamily = GUEST_OS_FAMILY_NETWARE;
#else
osFamily = GUEST_OS_FAMILY_LINUX;
#endif
hgfsPacket = ((char *) requestMsg) + sizeof(*requestMsg);
hgfsPacketSize = requestMsg->hgfsPacketSize;
-#if !defined(N_PLAT_NLM) && !defined(__FreeBSD__)
+#if !defined(__FreeBSD__)
/*
* Impersonation was okay, so let's give our packet to
* the HGFS server and forward the reply packet back.
#include "backdoor_def.h"
#include "debug.h"
-#if !defined(_WIN32) && !defined(N_PLAT_NLM)
+#if !defined(_WIN32)
# include "vmsignal.h"
# include "setjmp.h"
#endif
-#if !defined(_WIN32) && !defined(N_PLAT_NLM)
+#if !defined(_WIN32)
static sigjmp_buf jmpBuf;
static Bool jmpIsSet;
{
uint32 version;
uint32 dummy;
-#ifdef N_PLAT_NLM
- /*
- * We are running at CPL0. So we'll not receive SIGSEGV on access
- * and we must do it other way... --petr
- */
- if (!VmCheck_GetVersion(&version, &dummy)) {
- return FALSE;
- }
-#elif defined _WIN32
+#if defined _WIN32
__try {
VmCheck_GetVersion(&version, &dummy);
} __except (GetExceptionCode() == STATUS_PRIVILEGED_INSTRUCTION) {
COMMON_SRCS += hgfsBd.c
COMMON_SRCS += rpcout.c
COMMON_SRCS += message.c
-COMMON_SRCS += messageBackdoor.c
COMMON_SRCS += backdoor.c
.if $(MACHINE_ARCH) == "amd64"
COMMON_SRCS += backdoorGcc64.c
/* use config value for max balloon size */
#define BALLOON_MAX_SIZE_USE_CONFIG (0)
-/* guest identities */
-#define BALLOON_GUEST_UNKNOWN (0)
-#define BALLOON_GUEST_LINUX (1)
-#define BALLOON_GUEST_BSD (2)
-#define BALLOON_GUEST_WINDOWS_NT4 (3)
-#define BALLOON_GUEST_WINDOWS_NT5 (4)
-#define BALLOON_GUEST_SOLARIS (5)
+/*
+ * Guest identities
+ *
+ * Note : all values should fit in 32 bits
+ */
+typedef enum {
+ BALLOON_GUEST_UNKNOWN = 0,
+ BALLOON_GUEST_LINUX = 1,
+ BALLOON_GUEST_BSD = 2,
+ BALLOON_GUEST_WINDOWS_NT4 = 3,
+ BALLOON_GUEST_WINDOWS_NT5 = 4,
+ BALLOON_GUEST_SOLARIS = 5,
+ BALLOON_GUEST_MACOS = 6,
+} BalloonGuest;
/* error codes */
#define BALLOON_SUCCESS (0)
#include <machine/stdarg.h>
#include "os.h"
+#include "vmballoon.h"
/*
* Constants
void *
OS_Malloc(size_t size) // IN
{
- return(malloc(size, M_VMMEMCTL, M_NOWAIT));
+ return malloc(size, M_VMMEMCTL, M_NOWAIT);
}
return result;
}
+
/*
- * System-Dependent Operations
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Identity --
+ *
+ * Returns an identifier for the guest OS family.
+ *
+ * Results:
+ * The identifier
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
*/
-const char *
+BalloonGuest
OS_Identity(void)
{
- return("bsd");
+ return BALLOON_GUEST_BSD;
}
+
/*
- * Predict the maximum achievable balloon size.
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageGetLimit --
*
- * Currently we just return the total memory pages.
+ * Predict the maximum achievable balloon size.
+ *
+ * Results:
+ * Total memory pages.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
*/
-unsigned int
-OS_PredictMaxReservedPages(void)
+
+unsigned long
+OS_ReservedPageGetLimit(void)
{
- return(cnt.v_page_count);
+ return cnt.v_page_count;
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageGetPPN --
+ *
+ * Convert a page handle (of a physical page previously reserved with
+ * OS_ReservedPageAlloc()) to a ppn.
+ *
+ * Results:
+ * The ppn.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
unsigned long
-OS_AddrToPPN(unsigned long addr)
+OS_ReservedPageGetPPN(PageHandle handle) // IN: A valid page handle
{
- return (((vm_page_t)addr)->phys_addr) >> PAGE_SHIFT;
+ return (((vm_page_t)handle)->phys_addr) >> PAGE_SHIFT;
}
+
static void os_pmap_alloc(os_pmap *p)
{
/* number of pages (div. 8) */
OFF_TO_IDX(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS));
}
-unsigned long
-OS_AllocReservedPage(int canSleep)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageAlloc --
+ *
+ * Reserve a physical page for the exclusive use of this driver.
+ *
+ * Results:
+ * On success: A valid page handle that can be passed to OS_ReservedPageGetPPN()
+ * or OS_ReservedPageFree().
+ * On failure: PAGE_HANDLE_INVALID
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+PageHandle
+OS_ReservedPageAlloc(int canSleep) // IN
{
- return (unsigned long)os_kmem_alloc(canSleep);
+ vm_page_t page;
+
+ page = os_kmem_alloc(canSleep);
+ if (page == NULL) {
+ return PAGE_HANDLE_INVALID;
+ }
+
+ return (PageHandle)page;
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageFree --
+ *
+ * Unreserve a physical page previously reserved with OS_ReservedPageAlloc().
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
void
-OS_FreeReservedPage(unsigned long page)
+OS_ReservedPageFree(PageHandle handle) // IN: A valid page handle
{
- os_kmem_free((vm_page_t)page);
+ os_kmem_free((vm_page_t)handle);
}
+
static void os_timer_internal(void *data)
{
os_timer *t = (os_timer *) data;
}
}
-void
-OS_TimerInit(OSTimerHandler *handler, // IN
- void *clientData, // IN
- int period) // IN
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_TimerStart --
+ *
+ * Setup the timer callback function, then start it.
+ *
+ * Results:
+ * Always TRUE, cannot fail.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+OS_TimerStart(OSTimerHandler *handler, // IN
+ void *clientData) // IN
{
os_timer *t = &global_state.timer;
+ /* setup the timer structure */
callout_handle_init(&t->callout_handle);
t->handler = handler;
t->data = clientData;
- t->period = period;
- t->stop = 0;
-}
-
-void
-OS_TimerStart(void)
-{
- os_timer *t = &global_state.timer;
+ t->period = hz;
/* clear termination flag */
t->stop = 0;
/* scheduler timer handler */
t->callout_handle = timeout(os_timer_internal, t, t->period);
+
+ return TRUE;
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_TimerStop --
+ *
+ * Stop the timer.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
void
OS_TimerStop(void)
{
untimeout(os_timer_internal, t, t->callout_handle);
}
-unsigned int
-OS_TimerHz(void)
-{
- return hz;
-}
-
/*
*-----------------------------------------------------------------------------
* Module Load/Unload Operations
*/
-extern int init_module(void);
-extern void cleanup_module(void);
-
static int vmmemctl_load(module_t mod, int cmd, void *arg)
{
int err = 0;
switch (cmd) {
case MOD_LOAD:
- (void) init_module();
+ if (Balloon_ModuleInit() != BALLOON_SUCCESS) {
+ err = EAGAIN;
+ }
break;
case MOD_UNLOAD:
/* prevent moudle unload */
err = EBUSY;
} else {
- cleanup_module();
+ Balloon_ModuleCleanup();
}
break;
break;
}
- return(err);
+ return err;
}
/* All these interfaces got added in 4.x, so we support 5.0 and above with them */
#ifndef OS_H
#define OS_H
+#include "vm_basic_types.h"
+#include "balloon_def.h"
+
/*
* Types
*/
typedef void OSTimerHandler(void *clientData);
typedef int OSStatusHandler(char *buf, size_t size);
+typedef uintptr_t PageHandle;
+
+#define PAGE_HANDLE_INVALID 0
/*
* Operations
const char *nameVerbose,
OSStatusHandler *handler);
extern void OS_Cleanup(void);
-extern const char *OS_Identity(void);
+extern BalloonGuest OS_Identity(void);
extern void OS_MemZero(void *ptr, size_t size);
extern void OS_MemCopy(void *dest, const void *src, size_t size);
extern void OS_Yield(void);
-extern unsigned int OS_TimerHz(void);
-extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period);
-extern void OS_TimerStart(void);
+extern Bool OS_TimerStart(OSTimerHandler *handler, void *clientData);
extern void OS_TimerStop(void);
-extern unsigned int OS_PredictMaxReservedPages(void);
-extern unsigned long OS_AddrToPPN(unsigned long addr);
-extern unsigned long OS_AllocReservedPage(int canSleep);
-extern void OS_FreeReservedPage(unsigned long page);
+extern unsigned long OS_ReservedPageGetLimit(void);
+extern unsigned long OS_ReservedPageGetPPN(PageHandle handle);
+extern PageHandle OS_ReservedPageAlloc(int canSleep);
+extern void OS_ReservedPageFree(PageHandle handle);
#endif /* OS_H */
* Includes
*/
-#include "balloon_def.h"
#include "os.h"
#include "backdoor.h"
#include "backdoor_balloon.h"
*/
typedef struct BalloonChunk {
- unsigned long page[BALLOON_CHUNK_PAGES];
+ PageHandle page[BALLOON_CHUNK_PAGES];
uint32 nextPage;
- struct BalloonChunk *prev, *next;
+ struct BalloonChunk *prev;
+ struct BalloonChunk *next;
} BalloonChunk;
typedef struct {
- unsigned long page[BALLOON_ERROR_PAGES];
+ PageHandle page[BALLOON_ERROR_PAGES];
uint32 nextPage;
} BalloonErrorPages;
*/
static Balloon globalBalloon;
+static Bool timerStarted;
/*
* Forward Declarations
*/
-static int BalloonGuestType(void);
-
-static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
-static void BalloonPrimFreePage(unsigned long page);
-
static int Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
static int Balloon_FreePage(Balloon *b, int monitorUnlock);
static int Balloon_AdjustSize(Balloon *b, uint32 target);
static void Balloon_Reset(Balloon *b);
-static void Balloon_StartTimer(Balloon *b);
-static void Balloon_StopTimer(Balloon *b);
static void BalloonTimerHandler(void *clientData);
static int Balloon_MonitorStart(Balloon *b);
static int Balloon_MonitorGuestType(Balloon *b);
static int Balloon_MonitorGetTarget(Balloon *b, uint32 *nPages);
-static int Balloon_MonitorLockPage(Balloon *b, unsigned long addr);
-static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr);
+static int Balloon_MonitorLockPage(Balloon *b, PageHandle handle);
+static int Balloon_MonitorUnlockPage(Balloon *b, PageHandle handle);
/*
* Macros
int len = 0;
BalloonStats stats;
- BalloonGetStats(&stats);
+ Balloon_GetStats(&stats);
/* format size info */
len += OS_Snprintf(buf + len, size - len,
* Utility Operations
*/
-/*
- *----------------------------------------------------------------------
- *
- * AddrToPPN --
- *
- * Return the physical page number corresponding to the specified
- * kernel-mapped address.
- *
- * Results:
- * Returns PPN for "addr".
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static inline unsigned long
-AddrToPPN(unsigned long addr)
-{
- return OS_AddrToPPN(addr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * BalloonPrimAllocPage --
- *
- * Attempts to allocate and reserve a physical page.
- *
- * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
- * The allocation can wait (sleep) for page writeout (swap)
- * by the guest.
- * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
- * If allocation of a page requires disk writeout, then
- * just fail. DON'T sleep.
- *
- * Results:
- * Returns the physical address of the allocated page, or 0 if error.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static unsigned long
-BalloonPrimAllocPage(BalloonPageAllocType canSleep)
-{
- return OS_AllocReservedPage(canSleep);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * BalloonPrimFreePage --
- *
- * Unreserves and deallocates specified physical page.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static void
-BalloonPrimFreePage(unsigned long page)
-{
- return OS_FreeReservedPage(page);
-}
/*
*----------------------------------------------------------------------
*
- * BalloonGuestType --
+ * Balloon_GetStats --
*
- * Return balloon guest OS identifier obtained by parsing
- * system-dependent identity string.
+ * Returns information about balloon state, including the current and
+ * target size, rates for allocating and freeing pages, and statistics
+ * about past activity.
*
* Results:
- * Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
+ * None
*
* Side effects:
- * None.
+ * None
*
*----------------------------------------------------------------------
*/
-static int
-BalloonGuestType(void)
-{
- const char *identity;
-
- /* obtain OS identify string */
- identity = OS_Identity();
-
- /* unknown if not specified */
- if (identity == NULL) {
- return(BALLOON_GUEST_UNKNOWN);
- }
- /* classify based on first letter (avoid defining strcmp) */
- switch (identity[0]) {
- case 'l':
- case 'L':
- return BALLOON_GUEST_LINUX;
- case 'b':
- case 'B':
- return BALLOON_GUEST_BSD;
- case 's':
- case 'S':
- return BALLOON_GUEST_SOLARIS;
- default:
- break;
- }
-
- /* unknown */
- return BALLOON_GUEST_UNKNOWN;
-}
-
-/*
- * Returns information about balloon state, including the current and
- * target size, rates for allocating and freeing pages, and statistics
- * about past activity.
- */
-void BalloonGetStats(BalloonStats *stats)
+void
+Balloon_GetStats(BalloonStats *stats) // OUT
{
Balloon *b = &globalBalloon;
/*
* Copy statistics out of global structure.
*/
- OS_MemCopy(stats, &b->stats, sizeof (BalloonStats));
+ OS_MemCopy(stats, &b->stats, sizeof *stats);
/*
* Fill in additional information about size and rates, which is
stats->rateFree = b->rateFree;
}
-/*
- * BalloonChunk Operations
- */
/*
*----------------------------------------------------------------------
/* initialize */
OS_MemZero(chunk, sizeof *chunk);
- /* everything OK */
return chunk;
}
/* initialize reset flag */
b->resetFlag = 1;
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
/*
BalloonTimerHandler(void *clientData)
{
Balloon *b = (Balloon *) clientData;
- uint32 target;
+ uint32 target = 0; // Silence compiler warning.
int status;
/* update stats */
}
}
-/*
- *----------------------------------------------------------------------
- *
- * Balloon_StartTimer --
- *
- * Schedules next execution of balloon timer handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static void
-Balloon_StartTimer(Balloon *b)
-{
- OS_TimerStart();
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Balloon_StopTimer --
- *
- * Deschedules balloon timer handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static void
-Balloon_StopTimer(Balloon *b)
-{
- OS_TimerStop();
-}
-
/*
*----------------------------------------------------------------------
/* free all non-balloonable "error" pages */
for (i = 0; i < b->errors.nextPage; i++) {
- BalloonPrimFreePage(b->errors.page[i]);
- b->errors.page[i] = 0;
+ OS_ReservedPageFree(b->errors.page[i]);
+ b->errors.page[i] = PAGE_HANDLE_INVALID;
STATS_INC(b->stats.primErrorPageFree);
}
b->errors.nextPage = 0;
Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType)
{
BalloonChunk *chunk;
- unsigned long page;
+ PageHandle page;
int status;
retry:
/* allocate page, fail if unable */
STATS_INC(b->stats.primAlloc[allocType]);
- page = BalloonPrimAllocPage(allocType);
+ /*
+ * Attempts to allocate and reserve a physical page.
+ *
+ * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
+ * The allocation can wait (sleep) for page writeout (swap) by the guest.
+ * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
+ * If allocation of a page requires disk writeout, then just fail. DON'T sleep.
+ *
+ * Returns the physical address of the allocated page, or 0 if error.
+ */
+ page = OS_ReservedPageAlloc(allocType);
- if (page == 0) {
+ if (page == PAGE_HANDLE_INVALID) {
STATS_INC(b->stats.primAllocFail[allocType]);
- return(BALLOON_PAGE_ALLOC_FAILURE);
+ return BALLOON_PAGE_ALLOC_FAILURE;
}
/* find chunk with space, create if necessary */
chunk = b->chunks;
if ((chunk == NULL) || (chunk->nextPage >= BALLOON_CHUNK_PAGES)) {
/* create new chunk */
- if ((chunk = BalloonChunk_Create()) == NULL) {
+ chunk = BalloonChunk_Create();
+ if (chunk == NULL) {
/* reclaim storage, fail */
- BalloonPrimFreePage(page);
- return(BALLOON_PAGE_ALLOC_FAILURE);
+ OS_ReservedPageFree(page);
+ return BALLOON_PAGE_ALLOC_FAILURE;
}
BalloonChunk_Insert(&b->chunks, chunk);
}
/* reclaim storage, fail */
- BalloonPrimFreePage(page);
- return(status);
+ OS_ReservedPageFree(page);
+ return status;
}
/* track allocated page */
/* update balloon size */
b->nPages++;
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
/*
Balloon_FreePage(Balloon *b, int monitorUnlock)
{
BalloonChunk *chunk;
- unsigned long page;
+ PageHandle page;
int status;
chunk = b->chunks;
}
/* deallocate page */
- BalloonPrimFreePage(page);
+ OS_ReservedPageFree(page);
STATS_INC(b->stats.primFree);
/* update balloon size */
b->nChunks--;
}
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
/*
}
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
BalloonInflate(Balloon *b, uint32 target)
{
return(BALLOON_SUCCESS);
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
BalloonDeflate(Balloon *b, uint32 target)
{
BALLOON_RATE_FREE_MAX);
}
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
Balloon_AdjustSize(Balloon *b, uint32 target)
{
*
*----------------------------------------------------------------------
*/
+
static int
Balloon_MonitorStart(Balloon *b)
{
STATS_INC(b->stats.startFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
Balloon_MonitorGuestType(Balloon *b)
{
uint32 status, target;
+ BalloonGuest identity;
Backdoor_proto bp;
+ identity = OS_Identity();
+ ASSERT(identity == (uint32) identity);
+
/* prepare backdoor args */
bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_GUEST_ID;
- bp.in.size = BalloonGuestType();
+ bp.in.size = identity;
/* invoke backdoor */
Backdoor_Balloon(&bp);
STATS_INC(b->stats.guestTypeFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
*----------------------------------------------------------------------
*
* Predicts the maximum achievable balloon size and sends it
* to vmm => vmkernel via vEbx register.
*
- * OS_PredictMaxReservedPages() returns either predicted max balloon
+ * OS_ReservedPageGetLimit() returns either predicted max balloon
* pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
* vmkernel uses global config options for determining a guest's max
* balloon size. Note that older vmballoon drivers set vEbx to
*
*----------------------------------------------------------------------
*/
+
static int
-Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
+Balloon_MonitorGetTarget(Balloon *b, // IN
+ uint32 *target) // OUT
{
Backdoor_proto bp;
+ unsigned long limit;
+ uint32 limit32;
uint32 status;
+ limit = OS_ReservedPageGetLimit();
+
+ /* Ensure limit fits in 32-bits */
+ limit32 = (uint32)limit;
+ if (limit32 != limit) {
+ return BALLOON_FAILURE;
+ }
+
/* prepare backdoor args */
bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
- bp.in.size = OS_PredictMaxReservedPages();
+ bp.in.size = limit;
/* invoke backdoor */
Backdoor_Balloon(&bp);
STATS_INC(b->stats.targetFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
*----------------------------------------------------------------------
*
* Balloon_MonitorLockPage --
*
- * Attempts to contact monitor and add PPN containing "addr"
- * to set of "balloon locked" pages.
+ * Attempts to contact monitor and add PPN corresponding to
+ * the page handle to set of "balloon locked" pages.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
*----------------------------------------------------------------------
*/
+
static int
-Balloon_MonitorLockPage(Balloon *b, unsigned long addr)
+Balloon_MonitorLockPage(Balloon *b, // IN
+ PageHandle handle) // IN
{
unsigned long ppn;
uint32 ppn32;
uint32 status, target;
Backdoor_proto bp;
- /* convert kernel-mapped "physical addr" to ppn */
- ppn = AddrToPPN(addr);
+ ppn = OS_ReservedPageGetPPN(handle);
/* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */
ppn32 = (uint32)ppn;
STATS_INC(b->stats.lockFail);
}
- /* everything OK */
- return(status);
+ return status;
}
/*
*
* Balloon_MonitorUnlockPage --
*
- * Attempts to contact monitor and remove PPN containing "addr"
- * from set of "balloon locked" pages.
+ * Attempts to contact monitor and remove PPN corresponding to
+ * the page handle from set of "balloon locked" pages.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*----------------------------------------------------------------------
*/
static int
-Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr)
+Balloon_MonitorUnlockPage(Balloon *b, // IN
+ PageHandle handle) // IN
{
unsigned long ppn;
uint32 ppn32;
uint32 status, target;
Backdoor_proto bp;
- /* convert kernel-mapped "physical addr" to ppn */
- ppn = AddrToPPN(addr);
+ ppn = OS_ReservedPageGetPPN(handle);
/* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */
ppn32 = (uint32)ppn;
STATS_INC(b->stats.unlockFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
- * Module Operations
+ *----------------------------------------------------------------------
+ *
+ * Balloon_ModuleInit --
+ *
+ * Startup the balloon module.
+ *
+ * Results:
+ * On success: BALLOON_SUCCESS
+ * On failure: BALLOON_FAILURE
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
*/
-static int
-BalloonModuleInit(void)
+int
+Balloon_ModuleInit(void)
{
static int initialized = 0;
Balloon *b = &globalBalloon;
/* initialize only once */
if (initialized++) {
- return(BALLOON_FAILURE);
+ return BALLOON_FAILURE;
}
/* os-specific initialization */
Balloon_Init(b);
/* start timer */
- OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz());
- Balloon_StartTimer(b);
+ timerStarted = FALSE;
+ if (!OS_TimerStart(BalloonTimerHandler, b)) {
+ Balloon_ModuleCleanup();
+ return BALLOON_FAILURE;
+ }
- /* everything OK */
+ timerStarted = TRUE;
return BALLOON_SUCCESS;
}
-static void
-BalloonModuleCleanup(void)
+/*
+ *----------------------------------------------------------------------
+ *
+ * Balloon_ModuleCleanup --
+ *
+ * Terminate and cleanup the balloon module.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Balloon_ModuleCleanup(void)
{
Balloon *b = &globalBalloon;
/* stop timer */
- Balloon_StopTimer(b);
+ if (timerStarted) {
+ OS_TimerStop();
+ }
/*
* Deallocate all reserved memory, and reset connection with monitor.
* Reset connection before deallocating memory to avoid potential for
* additional spurious resets from guest touching deallocated pages.
*/
- (void) Balloon_MonitorStart(b);
+ Balloon_MonitorStart(b);
Balloon_Deallocate(b);
/* os-specific cleanup */
OS_Cleanup();
}
-int init_module(void)
-{
- return(BalloonModuleInit());
-}
-
-void cleanup_module(void)
-{
- BalloonModuleCleanup();
-}
-
#ifdef __cplusplus
}
#endif
* Operations
*/
-extern void BalloonGetStats(BalloonStats *stats);
-extern int init_module(void);
-extern void cleanup_module(void);
+extern int Balloon_ModuleInit(void);
+extern void Balloon_ModuleCleanup(void);
+
+extern void Balloon_GetStats(BalloonStats *stats);
#endif /* VMBALLOON_H */
if (sdstat != SAM_STAT_GOOD &&
(btstat == BTSTAT_SUCCESS ||
btstat == BTSTAT_LINKED_COMMAND_COMPLETED ||
- btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG))
- switch (sdstat) {
- case SAM_STAT_CHECK_CONDITION:
- /*
- * Sense data is set by the emulation.
- * Linux seems to want DID_OK despite the error.
- */
- cmd->result = (DID_OK << 16) | (SAM_STAT_CHECK_CONDITION);
- if (cmd->sense_buffer)
- cmd->result |= (DRIVER_SENSE << 24);
- break;
- case SAM_STAT_BUSY:
- /* Back off. */
- cmd->result = (DID_OK << 16) | sdstat;
- break;
- default:
- cmd->result = (DID_ERROR << 16);
- LOG(0, "Unhandled SCSI status: 0x%x\n", sdstat);
- }
-
- else
+ btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) {
+ cmd->result = (DID_OK << 16) | sdstat;
+ if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer)
+ cmd->result |= (DRIVER_SENSE << 24);
+ } else
switch (btstat) {
case BTSTAT_SUCCESS:
case BTSTAT_LINKED_COMMAND_COMPLETED:
#ifndef _PVSCSI_VERSION_H_
#define _PVSCSI_VERSION_H_
-#define PVSCSI_DRIVER_VERSION 0.0.1.0
-#define PVSCSI_DRIVER_VERSION_COMMAS 0,0,1,0
-#define PVSCSI_DRIVER_VERSION_STRING "0.0.1.0"
+#define PVSCSI_DRIVER_VERSION 0.0.1.1
+#define PVSCSI_DRIVER_VERSION_COMMAS 0,0,1,1
+#define PVSCSI_DRIVER_VERSION_STRING "0.0.1.1"
#endif /* _PVSCSI_VERSION_H_ */
#include "vmware_pack_end.h"
SCSIMediumRemovalCmd;
+#define SCSI_RW10_MAX_LBN 0xffffffffu
+#define SCSI_RW10_MAX_LENGTH 0xffffu
/*
* Format of READ CAPACITY (10) and (16) request and response blocks.
uint8 rel :1,
:4,
lun :3;
-#define SCSI_RW10_MAX_LBN 0xffffffffu
uint32 lbn;
uint8 reserved[2];
uint8 pmi :1,
return h;
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMCI_HANDLE_TO_UINT64 --
+ *
+ * Helper for VMCI handle to uint64 conversion.
+ *
+ * Results:
+ * The uint64 value.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE uint64
+VMCI_HANDLE_TO_UINT64(VMCIHandle handle) // IN:
+{
+ uint64 handle64;
+
+ handle64 = handle.context;
+ handle64 <<= 32;
+ handle64 |= handle.resource;
+ return handle64;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMCI_UINT64_TO_HANDLE --
+ *
+ * Helper for uint64 to VMCI handle conversion.
+ *
+ * Results:
+ * The VMCI handle value.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE VMCIHandle
+VMCI_UINT64_TO_HANDLE(uint64 handle64) // IN:
+{
+ VMCIId context = (VMCIId)(handle64 >> 32);
+ VMCIId resource = (VMCIId)handle64;
+
+ return VMCI_MAKE_HANDLE(context, resource);
+}
+
#define VMCI_HANDLE_TO_CONTEXT_ID(_handle) ((_handle).context)
#define VMCI_HANDLE_TO_RESOURCE_ID(_handle) ((_handle).resource)
#define VMCI_HANDLE_EQUAL(_h1, _h2) ((_h1).context == (_h2).context && \
/* Used to determine what checkpoint state to get and set. */
#define VMCI_NOTIFICATION_CPT_STATE 0x1
#define VMCI_WELLKNOWN_CPT_STATE 0x2
-#define VMCI_QP_CPT_STATE 0x3
-#define VMCI_QP_INFO_CPT_STATE 0x4
/* Used to control the VMCI device in the vmkernel */
#define VMCI_DEV_RESET 0x01
-#define VMCI_DEV_QP_RESET 0x02
+#define VMCI_DEV_QP_RESET 0x02 // DEPRECATED
#define VMCI_DEV_QUIESCE 0x03
#define VMCI_DEV_UNQUIESCE 0x04
-#define VMCI_DEV_QP_BREAK_SHARING 0x05
+#define VMCI_DEV_QP_BREAK_SHARING 0x05 // DEPRECATED
+
/*
*-------------------------------------------------------------------------
uint32 flags;
uint64 produceSize;
uint64 consumeSize;
+#if !defined(VMX86_SERVER) && !defined(VMKERNEL)
VA64 producePageFile; /* User VA. */
VA64 consumePageFile; /* User VA. */
uint64 producePageFileSize; /* Size of the file name array. */
uint64 consumePageFileSize; /* Size of the file name array. */
+#else
+ PPN * PPNs;
+ uint64 numPPNs;
+#endif
int32 result;
uint32 _pad;
} VMCIQueuePairAllocInfo;
typedef struct VMCIQueuePairPageFileInfo {
VMCIHandle handle;
+#if !defined(VMX86_SERVER) && !defined(VMKERNEL)
VA64 producePageFile; /* User VA. */
VA64 consumePageFile; /* User VA. */
uint64 producePageFileSize; /* Size of the file name array. */
uint64 consumePageFileSize; /* Size of the file name array. */
+#endif
int32 result;
uint32 version; /* Was _pad. */
VA64 produceVA; /* User VA of the mapped file. */
LIBHGFSBD := hgfsBd.o
LIBMESSAGE := message.o
-LIBMESSAGE += messageBackdoor.o
LIBRPCOUT := rpcout.o
OBJS += hgfsUtil.o
OBJS += kernelStubsLinux.o
OBJS += message.o
-OBJS += messageBackdoor.o
OBJS += rpcout.o
ifeq ($(MACHINE),x86_64)
LIBHGFSBD := hgfsBd.o
LIBMESSAGE := message.o
-LIBMESSAGE += messageBackdoor.o
LIBRPCOUT := rpcout.o
oldInode = HgfsInodeLookup(sb, attr->hostFileId);
if (oldInode) {
-
/*
* If this inode's inode number was generated via iunique(), we
* have a collision and cannot use the server's inode number.
- * Otherwise, we should reuse this inode.
+ * Or, if the dentry is for a directory, we should not reuse the
+ * inode in case there are two directory dentries referring to the
+ * same inode. Otherwise, we should reuse this inode.
+ *
+ * Be careful of the following setting when resuing inodes:
+ * host dir -> share name
+ * C:/parent/ -> host1
+ * C:/parent/child/ -> host2
+ * /mnt/hgfs/host1/child and /mnt/hgfs/host2 are actually the
+ * same directory in host. It also happens to the files in child.
+ * Here, we should prevent the inode reusing because in Linux kernel
+ * no inode can be pointed to by multiple directory entries; whereas
+ * it is OK to do that for the files in /mnt/hgfs/child/.
*/
iinfo = INODE_GET_II_P(oldInode);
- if (iinfo->isFakeInodeNumber) {
- LOG(6, (KERN_DEBUG "VMware hgfs: HgfsIget: found existing "
- "iuniqued inode %"FMT64"d, generating new one\n",
- attr->hostFileId));
+ if (iinfo->isFakeInodeNumber ||
+ attr->type == HGFS_FILE_TYPE_DIRECTORY) {
+ LOG(6, ("VMware hgfs: %s: found existing iuniqued inode or "
+ "directory inode %"FMT64"d, generating new one\n",
+ __func__, attr->hostFileId));
ino = iunique(sb, HGFS_RESERVED_INO);
isFakeInodeNumber = TRUE;
} else {
goto out;
}
+ if (oldDentry->d_inode && newDentry->d_inode) {
+ HgfsInodeInfo *oldIinfo;
+ HgfsInodeInfo *newIinfo;
+ /*
+ * Don't do rename if the source and target are identical (from the
+ * viewpoint of the host). It is possible that multiple guest inodes
+ * point to the same host inode under the case that both one folder
+ * and its subfolder are mapped as hgfs sharese. Please also see the
+ * comments at fsutil.c/HgfsIget.
+ */
+ oldIinfo = INODE_GET_II_P(oldDentry->d_inode);
+ newIinfo = INODE_GET_II_P(newDentry->d_inode);
+ if (oldIinfo->hostFileId !=0 && newIinfo->hostFileId != 0 &&
+ oldIinfo->hostFileId == newIinfo->hostFileId) {
+ LOG(4, ("VMware hgfs: %s: source and target are the same file.\n",
+ __func__));
+ result = -EEXIST;
+ goto out;
+ }
+ }
+
req = HgfsGetNewRequest();
if (!req) {
LOG(4, (KERN_DEBUG "VMware hgfs: HgfsRename: out of memory while "
/* use config value for max balloon size */
#define BALLOON_MAX_SIZE_USE_CONFIG (0)
-/* guest identities */
-#define BALLOON_GUEST_UNKNOWN (0)
-#define BALLOON_GUEST_LINUX (1)
-#define BALLOON_GUEST_BSD (2)
-#define BALLOON_GUEST_WINDOWS_NT4 (3)
-#define BALLOON_GUEST_WINDOWS_NT5 (4)
-#define BALLOON_GUEST_SOLARIS (5)
+/*
+ * Guest identities
+ *
+ * Note : all values should fit in 32 bits
+ */
+typedef enum {
+ BALLOON_GUEST_UNKNOWN = 0,
+ BALLOON_GUEST_LINUX = 1,
+ BALLOON_GUEST_BSD = 2,
+ BALLOON_GUEST_WINDOWS_NT4 = 3,
+ BALLOON_GUEST_WINDOWS_NT5 = 4,
+ BALLOON_GUEST_SOLARIS = 5,
+ BALLOON_GUEST_MACOS = 6,
+} BalloonGuest;
/* error codes */
#define BALLOON_SUCCESS (0)
#include "vmmemctl_version.h"
#include "os.h"
+#include "vmballoon.h"
/*
static os_state global_state;
+static int os_timer_thread_loop(void *clientData);
+
/*
*-----------------------------------------------------------------------------
void *
OS_Malloc(size_t size) // IN
{
- return(kmalloc(size, OS_KMALLOC_NOSLEEP));
+ return kmalloc(size, OS_KMALLOC_NOSLEEP);
}
return result;
}
+
/*
- * System-Dependent Operations
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Identity --
+ *
+ * Returns an identifier for the guest OS family.
+ *
+ * Results:
+ * The identifier
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
*/
-const char *
+BalloonGuest
OS_Identity(void)
{
- return("linux");
+ return BALLOON_GUEST_LINUX;
}
+
/*
- * Predict the maximum achievable balloon size.
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageGetLimit --
+ *
+ * Predict the maximum achievable balloon size.
+ *
+ * In 2.4.x and 2.6.x kernels, the balloon driver can guess the number of pages
+ * that can be ballooned. But, for now let us just pass the totalram-size as the
+ * maximum achievable balloon size. Note that normally (unless guest kernel is
+ * booted with a mem=XX parameter) the totalram-size is equal to alloc.max.
+ *
+ * Results:
+ * The maximum achievable balloon size in pages.
*
- * In 2.4.x and 2.6.x kernels, the balloon driver can guess the number of pages
- * that can be ballooned. But, for now let us just pass the totalram-size as the
- * maximum achievable balloon size. Note that normally (unless guest kernel is
- * booted with a mem=XX parameter) the totalram-size is equal to alloc.max.
+ * Side effects:
+ * None
*
- * Returns the maximum achievable balloon size in pages
+ *-----------------------------------------------------------------------------
*/
-unsigned int
-OS_PredictMaxReservedPages(void)
+
+unsigned long
+OS_ReservedPageGetLimit(void)
{
struct sysinfo info;
os_state *state = &global_state;
return state->totalMemoryPages;
}
+
/*
- * Use newer alloc_page() interface on 2.4.x kernels.
- * Use "struct page *" value as page handle for clients.
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageGetPPN --
+ *
+ * Convert a page handle (of a physical page previously reserved with
+ * OS_ReservedPageAlloc()) to a ppn.
+ *
+ * Use newer alloc_page() interface on 2.4.x kernels.
+ *
+ * Results:
+ * The ppn.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
*/
+
unsigned long
-OS_AddrToPPN(unsigned long addr)
+OS_ReservedPageGetPPN(PageHandle handle) // IN: A valid page handle
{
- struct page *page = (struct page *) addr;
+ struct page *page = (struct page *)handle;
return page_to_pfn(page);
}
-unsigned long
-OS_AllocReservedPage(int canSleep)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageAlloc --
+ *
+ * Reserve a physical page for the exclusive use of this driver.
+ *
+ * Results:
+ * On success: A valid page handle that can be passed to OS_ReservedPageGetPPN()
+ * or OS_ReservedPageFree().
+ * On failure: PAGE_HANDLE_INVALID
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+PageHandle
+OS_ReservedPageAlloc(int canSleep) // IN
{
- struct page *page = alloc_page(canSleep ?
- OS_PAGE_ALLOC_CANSLEEP : OS_PAGE_ALLOC_NOSLEEP);
+ struct page *page;
- return (unsigned long)page;
+ page = alloc_page(canSleep ? OS_PAGE_ALLOC_CANSLEEP : OS_PAGE_ALLOC_NOSLEEP);
+ if (page == NULL) {
+ return PAGE_HANDLE_INVALID;
+ }
+
+ return (PageHandle)page;
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageFree --
+ *
+ * Unreserve a physical page previously reserved with OS_ReservedPageAlloc().
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
void
-OS_FreeReservedPage(unsigned long addr)
+OS_ReservedPageFree(PageHandle handle) // IN: A valid page handle
{
- /* deallocate page */
- struct page *page = (struct page *) addr;
+ struct page *page = (struct page *)handle;
+
__free_page(page);
}
-void
-OS_TimerInit(OSTimerHandler *handler, // IN
- void *clientData, // IN
- int period) // IN
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_TimerStart --
+ *
+ * Setup the timer callback function, then start it.
+ *
+ * Results:
+ * On success: TRUE
+ * On failure: FALSE
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+OS_TimerStart(OSTimerHandler *handler, // IN
+ void *clientData) // IN
{
os_timer *t = &global_state.timer;
+ os_status *s = &global_state.status;
+
+ /* initialize the timer structure */
t->handler = handler;
t->data = clientData;
- t->period = period;
+ t->period = HZ;
+
+ /* initialize sync objects */
+ init_waitqueue_head(&t->delay);
+
+ /* create kernel thread */
+ t->task = kthread_run(os_timer_thread_loop, t, "vmmemctl");
+ if (IS_ERR(t->task)) {
+ printk(KERN_WARNING "%s: unable to create kernel thread\n", s->name);
+ return FALSE;
+ }
+ if (OS_DEBUG) {
+ printk(KERN_DEBUG "%s: started kernel thread pid=%d\n", s->name, t->task->pid);
+ }
+
+ return TRUE;
}
-static int os_timer_thread_loop(void *data)
+
+static int
+os_timer_thread_loop(void *clientData) // IN
{
- os_timer *t = (os_timer *) data;
+ os_timer *t = clientData;
/* we are running */
compat_set_freezable();
t->handler(t->data);
}
- /* terminate */
- return(0);
+ return 0;
}
-void
-OS_TimerStart(void)
-{
- os_timer *t = &global_state.timer;
- os_status *s = &global_state.status;
-
- /* initialize sync objects */
- init_waitqueue_head(&t->delay);
- /* create kernel thread */
- t->task = kthread_run(os_timer_thread_loop, t, "vmmemctl");
- if (IS_ERR(t->task)) {
- /* fail */
- printk(KERN_WARNING "%s: unable to create kernel thread\n", s->name);
- } else if (OS_DEBUG) {
- printk(KERN_DEBUG "%s: started kernel thread pid=%d\n", s->name,
- t->task->pid);
- }
-}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_TimerStop --
+ *
+ * Stop the timer.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
void
OS_TimerStop(void)
kthread_stop(global_state.timer.task);
}
-unsigned int
-OS_TimerHz(void)
-{
- return HZ;
-}
-
/*
*-----------------------------------------------------------------------------
cond_resched();
}
+
#ifdef CONFIG_PROC_FS
static int os_proc_show(struct seq_file *f,
void *data)
return err;
}
+
static int os_proc_open(struct inode *inode,
struct file *file)
{
#endif
+
void
OS_Init(const char *name,
const char *name_verbose,
printk(KERN_INFO "%s initialized\n", state->status.name_verbose);
}
+
void
OS_Cleanup(void)
{
printk(KERN_INFO "%s unloaded\n", s->name_verbose);
}
+
+int
+init_module(void)
+{
+ if (Balloon_ModuleInit() == BALLOON_SUCCESS) {
+ return 0;
+ } else {
+ return -EAGAIN;
+ }
+}
+
+
+void
+cleanup_module(void)
+{
+ /*
+ * We cannot use module_exit(Balloon_ModuleCleanup) because compilation
+ * would fail for 'Kernel Verify Build Status', see bug #459403.
+ */
+ Balloon_ModuleCleanup();
+}
+
+
/* Module information. */
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Memory Control Driver");
#ifndef OS_H
#define OS_H
+#include "vm_basic_types.h"
+#include "balloon_def.h"
+
/*
* Types
*/
typedef void OSTimerHandler(void *clientData);
typedef int OSStatusHandler(char *buf, size_t size);
+typedef uintptr_t PageHandle;
+
+#define PAGE_HANDLE_INVALID 0
/*
* Operations
const char *nameVerbose,
OSStatusHandler *handler);
extern void OS_Cleanup(void);
-extern const char *OS_Identity(void);
+extern BalloonGuest OS_Identity(void);
extern void OS_MemZero(void *ptr, size_t size);
extern void OS_MemCopy(void *dest, const void *src, size_t size);
extern void OS_Yield(void);
-extern unsigned int OS_TimerHz(void);
-extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period);
-extern void OS_TimerStart(void);
+extern Bool OS_TimerStart(OSTimerHandler *handler, void *clientData);
extern void OS_TimerStop(void);
-extern unsigned int OS_PredictMaxReservedPages(void);
-extern unsigned long OS_AddrToPPN(unsigned long addr);
-extern unsigned long OS_AllocReservedPage(int canSleep);
-extern void OS_FreeReservedPage(unsigned long page);
+extern unsigned long OS_ReservedPageGetLimit(void);
+extern unsigned long OS_ReservedPageGetPPN(PageHandle handle);
+extern PageHandle OS_ReservedPageAlloc(int canSleep);
+extern void OS_ReservedPageFree(PageHandle handle);
#endif /* OS_H */
* Includes
*/
-#include "balloon_def.h"
#include "os.h"
#include "backdoor.h"
#include "backdoor_balloon.h"
*/
typedef struct BalloonChunk {
- unsigned long page[BALLOON_CHUNK_PAGES];
+ PageHandle page[BALLOON_CHUNK_PAGES];
uint32 nextPage;
- struct BalloonChunk *prev, *next;
+ struct BalloonChunk *prev;
+ struct BalloonChunk *next;
} BalloonChunk;
typedef struct {
- unsigned long page[BALLOON_ERROR_PAGES];
+ PageHandle page[BALLOON_ERROR_PAGES];
uint32 nextPage;
} BalloonErrorPages;
*/
static Balloon globalBalloon;
+static Bool timerStarted;
/*
* Forward Declarations
*/
-static int BalloonGuestType(void);
-
-static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
-static void BalloonPrimFreePage(unsigned long page);
-
static int Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
static int Balloon_FreePage(Balloon *b, int monitorUnlock);
static int Balloon_AdjustSize(Balloon *b, uint32 target);
static void Balloon_Reset(Balloon *b);
-static void Balloon_StartTimer(Balloon *b);
-static void Balloon_StopTimer(Balloon *b);
static void BalloonTimerHandler(void *clientData);
static int Balloon_MonitorStart(Balloon *b);
static int Balloon_MonitorGuestType(Balloon *b);
static int Balloon_MonitorGetTarget(Balloon *b, uint32 *nPages);
-static int Balloon_MonitorLockPage(Balloon *b, unsigned long addr);
-static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr);
+static int Balloon_MonitorLockPage(Balloon *b, PageHandle handle);
+static int Balloon_MonitorUnlockPage(Balloon *b, PageHandle handle);
/*
* Macros
int len = 0;
BalloonStats stats;
- BalloonGetStats(&stats);
+ Balloon_GetStats(&stats);
/* format size info */
len += OS_Snprintf(buf + len, size - len,
* Utility Operations
*/
-/*
- *----------------------------------------------------------------------
- *
- * AddrToPPN --
- *
- * Return the physical page number corresponding to the specified
- * kernel-mapped address.
- *
- * Results:
- * Returns PPN for "addr".
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static inline unsigned long
-AddrToPPN(unsigned long addr)
-{
- return OS_AddrToPPN(addr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * BalloonPrimAllocPage --
- *
- * Attempts to allocate and reserve a physical page.
- *
- * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
- * The allocation can wait (sleep) for page writeout (swap)
- * by the guest.
- * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
- * If allocation of a page requires disk writeout, then
- * just fail. DON'T sleep.
- *
- * Results:
- * Returns the physical address of the allocated page, or 0 if error.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static unsigned long
-BalloonPrimAllocPage(BalloonPageAllocType canSleep)
-{
- return OS_AllocReservedPage(canSleep);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * BalloonPrimFreePage --
- *
- * Unreserves and deallocates specified physical page.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static void
-BalloonPrimFreePage(unsigned long page)
-{
- return OS_FreeReservedPage(page);
-}
/*
*----------------------------------------------------------------------
*
- * BalloonGuestType --
+ * Balloon_GetStats --
*
- * Return balloon guest OS identifier obtained by parsing
- * system-dependent identity string.
+ * Returns information about balloon state, including the current and
+ * target size, rates for allocating and freeing pages, and statistics
+ * about past activity.
*
* Results:
- * Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
+ * None
*
* Side effects:
- * None.
+ * None
*
*----------------------------------------------------------------------
*/
-static int
-BalloonGuestType(void)
-{
- const char *identity;
-
- /* obtain OS identify string */
- identity = OS_Identity();
-
- /* unknown if not specified */
- if (identity == NULL) {
- return(BALLOON_GUEST_UNKNOWN);
- }
- /* classify based on first letter (avoid defining strcmp) */
- switch (identity[0]) {
- case 'l':
- case 'L':
- return BALLOON_GUEST_LINUX;
- case 'b':
- case 'B':
- return BALLOON_GUEST_BSD;
- case 's':
- case 'S':
- return BALLOON_GUEST_SOLARIS;
- default:
- break;
- }
-
- /* unknown */
- return BALLOON_GUEST_UNKNOWN;
-}
-
-/*
- * Returns information about balloon state, including the current and
- * target size, rates for allocating and freeing pages, and statistics
- * about past activity.
- */
-void BalloonGetStats(BalloonStats *stats)
+void
+Balloon_GetStats(BalloonStats *stats) // OUT
{
Balloon *b = &globalBalloon;
/*
* Copy statistics out of global structure.
*/
- OS_MemCopy(stats, &b->stats, sizeof (BalloonStats));
+ OS_MemCopy(stats, &b->stats, sizeof *stats);
/*
* Fill in additional information about size and rates, which is
stats->rateFree = b->rateFree;
}
-/*
- * BalloonChunk Operations
- */
/*
*----------------------------------------------------------------------
/* initialize */
OS_MemZero(chunk, sizeof *chunk);
- /* everything OK */
return chunk;
}
/* initialize reset flag */
b->resetFlag = 1;
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
/*
BalloonTimerHandler(void *clientData)
{
Balloon *b = (Balloon *) clientData;
- uint32 target;
+ uint32 target = 0; // Silence compiler warning.
int status;
/* update stats */
}
}
-/*
- *----------------------------------------------------------------------
- *
- * Balloon_StartTimer --
- *
- * Schedules next execution of balloon timer handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static void
-Balloon_StartTimer(Balloon *b)
-{
- OS_TimerStart();
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Balloon_StopTimer --
- *
- * Deschedules balloon timer handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static void
-Balloon_StopTimer(Balloon *b)
-{
- OS_TimerStop();
-}
-
/*
*----------------------------------------------------------------------
/* free all non-balloonable "error" pages */
for (i = 0; i < b->errors.nextPage; i++) {
- BalloonPrimFreePage(b->errors.page[i]);
- b->errors.page[i] = 0;
+ OS_ReservedPageFree(b->errors.page[i]);
+ b->errors.page[i] = PAGE_HANDLE_INVALID;
STATS_INC(b->stats.primErrorPageFree);
}
b->errors.nextPage = 0;
Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType)
{
BalloonChunk *chunk;
- unsigned long page;
+ PageHandle page;
int status;
retry:
/* allocate page, fail if unable */
STATS_INC(b->stats.primAlloc[allocType]);
- page = BalloonPrimAllocPage(allocType);
+ /*
+ * Attempts to allocate and reserve a physical page.
+ *
+ * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
+ * The allocation can wait (sleep) for page writeout (swap) by the guest.
+ * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
+ * If allocation of a page requires disk writeout, then just fail. DON'T sleep.
+ *
+ * Returns the physical address of the allocated page, or 0 if error.
+ */
+ page = OS_ReservedPageAlloc(allocType);
- if (page == 0) {
+ if (page == PAGE_HANDLE_INVALID) {
STATS_INC(b->stats.primAllocFail[allocType]);
- return(BALLOON_PAGE_ALLOC_FAILURE);
+ return BALLOON_PAGE_ALLOC_FAILURE;
}
/* find chunk with space, create if necessary */
chunk = b->chunks;
if ((chunk == NULL) || (chunk->nextPage >= BALLOON_CHUNK_PAGES)) {
/* create new chunk */
- if ((chunk = BalloonChunk_Create()) == NULL) {
+ chunk = BalloonChunk_Create();
+ if (chunk == NULL) {
/* reclaim storage, fail */
- BalloonPrimFreePage(page);
- return(BALLOON_PAGE_ALLOC_FAILURE);
+ OS_ReservedPageFree(page);
+ return BALLOON_PAGE_ALLOC_FAILURE;
}
BalloonChunk_Insert(&b->chunks, chunk);
}
/* reclaim storage, fail */
- BalloonPrimFreePage(page);
- return(status);
+ OS_ReservedPageFree(page);
+ return status;
}
/* track allocated page */
/* update balloon size */
b->nPages++;
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
/*
Balloon_FreePage(Balloon *b, int monitorUnlock)
{
BalloonChunk *chunk;
- unsigned long page;
+ PageHandle page;
int status;
chunk = b->chunks;
}
/* deallocate page */
- BalloonPrimFreePage(page);
+ OS_ReservedPageFree(page);
STATS_INC(b->stats.primFree);
/* update balloon size */
b->nChunks--;
}
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
/*
}
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
BalloonInflate(Balloon *b, uint32 target)
{
return(BALLOON_SUCCESS);
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
BalloonDeflate(Balloon *b, uint32 target)
{
BALLOON_RATE_FREE_MAX);
}
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
Balloon_AdjustSize(Balloon *b, uint32 target)
{
*
*----------------------------------------------------------------------
*/
+
static int
Balloon_MonitorStart(Balloon *b)
{
STATS_INC(b->stats.startFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
Balloon_MonitorGuestType(Balloon *b)
{
uint32 status, target;
+ BalloonGuest identity;
Backdoor_proto bp;
+ identity = OS_Identity();
+ ASSERT(identity == (uint32) identity);
+
/* prepare backdoor args */
bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_GUEST_ID;
- bp.in.size = BalloonGuestType();
+ bp.in.size = identity;
/* invoke backdoor */
Backdoor_Balloon(&bp);
STATS_INC(b->stats.guestTypeFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
*----------------------------------------------------------------------
*
* Predicts the maximum achievable balloon size and sends it
* to vmm => vmkernel via vEbx register.
*
- * OS_PredictMaxReservedPages() returns either predicted max balloon
+ * OS_ReservedPageGetLimit() returns either predicted max balloon
* pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
* vmkernel uses global config options for determining a guest's max
* balloon size. Note that older vmballoon drivers set vEbx to
*
*----------------------------------------------------------------------
*/
+
static int
-Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
+Balloon_MonitorGetTarget(Balloon *b, // IN
+ uint32 *target) // OUT
{
Backdoor_proto bp;
+ unsigned long limit;
+ uint32 limit32;
uint32 status;
+ limit = OS_ReservedPageGetLimit();
+
+ /* Ensure limit fits in 32-bits */
+ limit32 = (uint32)limit;
+ if (limit32 != limit) {
+ return BALLOON_FAILURE;
+ }
+
/* prepare backdoor args */
bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
- bp.in.size = OS_PredictMaxReservedPages();
+ bp.in.size = limit;
/* invoke backdoor */
Backdoor_Balloon(&bp);
STATS_INC(b->stats.targetFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
*----------------------------------------------------------------------
*
* Balloon_MonitorLockPage --
*
- * Attempts to contact monitor and add PPN containing "addr"
- * to set of "balloon locked" pages.
+ * Attempts to contact monitor and add PPN corresponding to
+ * the page handle to set of "balloon locked" pages.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
*----------------------------------------------------------------------
*/
+
static int
-Balloon_MonitorLockPage(Balloon *b, unsigned long addr)
+Balloon_MonitorLockPage(Balloon *b, // IN
+ PageHandle handle) // IN
{
unsigned long ppn;
uint32 ppn32;
uint32 status, target;
Backdoor_proto bp;
- /* convert kernel-mapped "physical addr" to ppn */
- ppn = AddrToPPN(addr);
+ ppn = OS_ReservedPageGetPPN(handle);
/* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */
ppn32 = (uint32)ppn;
STATS_INC(b->stats.lockFail);
}
- /* everything OK */
- return(status);
+ return status;
}
/*
*
* Balloon_MonitorUnlockPage --
*
- * Attempts to contact monitor and remove PPN containing "addr"
- * from set of "balloon locked" pages.
+ * Attempts to contact monitor and remove PPN corresponding to
+ * the page handle from set of "balloon locked" pages.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*----------------------------------------------------------------------
*/
static int
-Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr)
+Balloon_MonitorUnlockPage(Balloon *b, // IN
+ PageHandle handle) // IN
{
unsigned long ppn;
uint32 ppn32;
uint32 status, target;
Backdoor_proto bp;
- /* convert kernel-mapped "physical addr" to ppn */
- ppn = AddrToPPN(addr);
+ ppn = OS_ReservedPageGetPPN(handle);
/* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */
ppn32 = (uint32)ppn;
STATS_INC(b->stats.unlockFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
- * Module Operations
+ *----------------------------------------------------------------------
+ *
+ * Balloon_ModuleInit --
+ *
+ * Startup the balloon module.
+ *
+ * Results:
+ * On success: BALLOON_SUCCESS
+ * On failure: BALLOON_FAILURE
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
*/
-static int
-BalloonModuleInit(void)
+int
+Balloon_ModuleInit(void)
{
static int initialized = 0;
Balloon *b = &globalBalloon;
/* initialize only once */
if (initialized++) {
- return(BALLOON_FAILURE);
+ return BALLOON_FAILURE;
}
/* os-specific initialization */
Balloon_Init(b);
/* start timer */
- OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz());
- Balloon_StartTimer(b);
+ timerStarted = FALSE;
+ if (!OS_TimerStart(BalloonTimerHandler, b)) {
+ Balloon_ModuleCleanup();
+ return BALLOON_FAILURE;
+ }
- /* everything OK */
+ timerStarted = TRUE;
return BALLOON_SUCCESS;
}
-static void
-BalloonModuleCleanup(void)
+/*
+ *----------------------------------------------------------------------
+ *
+ * Balloon_ModuleCleanup --
+ *
+ * Terminate and cleanup the balloon module.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Balloon_ModuleCleanup(void)
{
Balloon *b = &globalBalloon;
/* stop timer */
- Balloon_StopTimer(b);
+ if (timerStarted) {
+ OS_TimerStop();
+ }
/*
* Deallocate all reserved memory, and reset connection with monitor.
* Reset connection before deallocating memory to avoid potential for
* additional spurious resets from guest touching deallocated pages.
*/
- (void) Balloon_MonitorStart(b);
+ Balloon_MonitorStart(b);
Balloon_Deallocate(b);
/* os-specific cleanup */
OS_Cleanup();
}
-int init_module(void)
-{
- return(BalloonModuleInit());
-}
-
-void cleanup_module(void)
-{
- BalloonModuleCleanup();
-}
-
#ifdef __cplusplus
}
#endif
* Operations
*/
-extern void BalloonGetStats(BalloonStats *stats);
-extern int init_module(void);
-extern void cleanup_module(void);
+extern int Balloon_ModuleInit(void);
+extern void Balloon_ModuleCleanup(void);
+
+extern void Balloon_GetStats(BalloonStats *stats);
#endif /* VMBALLOON_H */
SOLHGFS_LIB_OBJS += hgfsEscape.o
SOLHGFS_LIB_OBJS += hgfsUtil.o
SOLHGFS_LIB_OBJS += message.o
-SOLHGFS_LIB_OBJS += messageBackdoor.o
SOLHGFS_LIB_OBJS += rpcout.o
SOLHGFS_LIB_OBJS += sha1.o
/* use config value for max balloon size */
#define BALLOON_MAX_SIZE_USE_CONFIG (0)
-/* guest identities */
-#define BALLOON_GUEST_UNKNOWN (0)
-#define BALLOON_GUEST_LINUX (1)
-#define BALLOON_GUEST_BSD (2)
-#define BALLOON_GUEST_WINDOWS_NT4 (3)
-#define BALLOON_GUEST_WINDOWS_NT5 (4)
-#define BALLOON_GUEST_SOLARIS (5)
+/*
+ * Guest identities
+ *
+ * Note : all values should fit in 32 bits
+ */
+typedef enum {
+ BALLOON_GUEST_UNKNOWN = 0,
+ BALLOON_GUEST_LINUX = 1,
+ BALLOON_GUEST_BSD = 2,
+ BALLOON_GUEST_WINDOWS_NT4 = 3,
+ BALLOON_GUEST_WINDOWS_NT5 = 4,
+ BALLOON_GUEST_SOLARIS = 5,
+ BALLOON_GUEST_MACOS = 6,
+} BalloonGuest;
/* error codes */
#define BALLOON_SUCCESS (0)
#include <sys/ksynch.h>
#include "os.h"
+#include "vmballoon.h"
#include "vm_assert.h"
#include "balloon_def.h"
#include "vmballoon_kstats.h"
return 0;
}
+
/*
- * System-Dependent Operations
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Identity --
+ *
+ * Returns an identifier for the guest OS family.
+ *
+ * Results:
+ * The identifier
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
*/
-const char *
+BalloonGuest
OS_Identity(void)
{
- return "solaris";
+ return BALLOON_GUEST_SOLARIS;
}
+
/*
- * Predict the maximum achievable balloon size.
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageGetLimit --
*
- * Currently we just return the total memory pages.
+ * Predict the maximum achievable balloon size.
+ *
+ * Results:
+ * Currently we just return the total memory pages.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
*/
-unsigned int
-OS_PredictMaxReservedPages(void)
+
+unsigned long
+OS_ReservedPageGetLimit(void)
{
- return(maxmem);
+ return maxmem;
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageGetPPN --
+ *
+ * Convert a page handle (of a physical page previously reserved with
+ * OS_ReservedPageAlloc()) to a ppn.
+ *
+ * Results:
+ * The ppn.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
unsigned long
-OS_AddrToPPN(unsigned long addr)
+OS_ReservedPageGetPPN(PageHandle handle) // IN: A valid page handle
{
- return (ulong_t)page_pptonum(((os_page *)addr)->pp);
+ return page_pptonum(((os_page *)handle)->pp);
}
+
/*
* NOTE: cast id before shifting to avoid overflow (id_t is 32 bits,
* u_offset_t is 64 bits). Also, can't use ptob because it will
#define idtooff(id) ((u_offset_t)(id) << PAGESHIFT)
#define offtoid(off) ((id_t)((off) >> PAGESHIFT))
+
/*
- * This is a bit ugly. In order to allocate a page, we need a vnode to
- * hang it from and a unique offset within that vnode. We do this by
- * using our own vnode (used only to hang pages from) and allocating
- * offsets by use of the id space allocator. The id allocator hands
- * us back unique integers between 0 and INT_MAX; we can then use those
- * as page indices into our fake vnode space.
- *
- * Future versions of Solaris will have a devmap_pmem_alloc/free
- * interface for allocating physical pages that may allow us to
- * eliminate some of this.
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageAlloc --
+ *
+ * Reserve a physical page for the exclusive use of this driver.
+ *
+ * This is a bit ugly. In order to allocate a page, we need a vnode to
+ * hang it from and a unique offset within that vnode. We do this by
+ * using our own vnode (used only to hang pages from) and allocating
+ * offsets by use of the id space allocator. The id allocator hands
+ * us back unique integers between 0 and INT_MAX; we can then use those
+ * as page indices into our fake vnode space.
+ *
+ * Future versions of Solaris will have a devmap_pmem_alloc/free
+ * interface for allocating physical pages that may allow us to
+ * eliminate some of this.
+ *
+ * Results:
+ * On success: A valid page handle that can be passed to OS_ReservedPageGetPPN()
+ * or OS_ReservedPageFree().
+ * On failure: PAGE_HANDLE_INVALID
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
*/
-unsigned long
-OS_AllocReservedPage(int canSleep)
+
+PageHandle
+OS_ReservedPageAlloc(int canSleep) // IN
{
os_state *state = &global_state;
page_t *pp;
*/
flags = canSleep ? KM_SLEEP : KM_NOSLEEP;
if (!page_resv(1, flags))
- return 0; /* no space! */
+ return PAGE_HANDLE_INVALID; /* no space! */
/*
* Allocating space for os_page early simplifies error handling.
*/
if ((page = kmem_alloc(sizeof (os_page), flags)) == NULL) {
page_unresv(1);
- return 0;
+ return PAGE_HANDLE_INVALID;
}
- /*
+ /*
* Construct an offset for page_create.
*/
off = idtooff(id_alloc(idp));
page = NULL;
}
- return (unsigned long)page;
+ return (PageHandle)page;
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_ReservedPageFree --
+ *
+ * Unreserve a physical page previously reserved with OS_ReservedPageAlloc().
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
void
-OS_FreeReservedPage(unsigned long addr)
+OS_ReservedPageFree(PageHandle handle) // IN: A valid page handle
{
os_state *state = &global_state;
- os_page *page = (os_page *)addr;
+ os_page *page = (os_page *)handle;
page_t *pp = page->pp;
u_offset_t off = page->offset;
id_space_t *idp = state->id_space;
kmem_free(page, sizeof (os_page));
}
+
/*
* Worker thread that periodically calls the timer handler. This is
* executed by a user context thread so that it can block waiting for
return 0; /* normal termination */
}
+
/*
- * Initialize timer data.
+ *-----------------------------------------------------------------------------
+ *
+ * OS_TimerStart --
+ *
+ * Setup the timer callback function, then start it.
+ *
+ * Results:
+ * Always TRUE, cannot fail.
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
*/
-void
-OS_TimerInit(OSTimerHandler *handler, // IN
- void *clientData, // IN
- int period) // IN
+
+Bool
+OS_TimerStart(OSTimerHandler *handler, // IN
+ void *clientData) // IN
{
os_timer *t = &global_state.timer;
+ /* setup the timer structure */
t->id = 0;
t->handler = handler;
t->data = clientData;
- t->period = period;
- t->stop = 0;
+ t->period = drv_usectohz(ONE_SECOND_IN_MICROSECONDS);
mutex_init(&t->lock, NULL, MUTEX_DRIVER, NULL);
cv_init(&t->cv, NULL, CV_DRIVER, NULL);
-}
-
-void
-OS_TimerStart(void)
-{
- os_timer *t = &global_state.timer;
+ /* start the timer */
t->stop = 0;
+
+ return TRUE;
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_TimerStop --
+ *
+ * Stop the timer.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
void
OS_TimerStop(void)
{
cv_destroy(&timer->cv);
}
-unsigned int
-OS_TimerHz(void)
-{
- return drv_usectohz(ONE_SECOND_IN_MICROSECONDS);
-}
-
/*
*-----------------------------------------------------------------------------
cmn_err(CE_CONT, "!%s unloaded\n", state->name_verbose);
}
-/*
- * Module Load/Unload Operations
- */
-
-extern int init_module(void);
-extern void cleanup_module(void);
/*
* Device configuration entry points
{
int error;
- if (init_module() != BALLOON_SUCCESS)
- return EINVAL;
- if ((error = mod_install(&vmmodlinkage)) != 0)
- cleanup_module();
+ if (Balloon_ModuleInit() != BALLOON_SUCCESS) {
+ return EAGAIN;
+ }
+ error = mod_install(&vmmodlinkage);
+ if (error != 0) {
+ Balloon_ModuleCleanup();
+ }
return error;
}
* Check if the module is busy (i.e., there's a worker thread active)
* before cleaning up.
*/
- if ((error = mod_remove(&vmmodlinkage)) == 0)
- cleanup_module();
+ error = mod_remove(&vmmodlinkage);
+ if (error == 0) {
+ Balloon_ModuleCleanup();
+ }
return error;
}
#ifndef OS_H
#define OS_H
+#include "vm_basic_types.h"
+#include "balloon_def.h"
+
/*
* Types
*/
typedef void OSTimerHandler(void *clientData);
typedef int OSStatusHandler(char *buf, size_t size);
+typedef uintptr_t PageHandle;
+
+#define PAGE_HANDLE_INVALID 0
/*
* Operations
const char *nameVerbose,
OSStatusHandler *handler);
extern void OS_Cleanup(void);
-extern const char *OS_Identity(void);
+extern BalloonGuest OS_Identity(void);
extern void OS_MemZero(void *ptr, size_t size);
extern void OS_MemCopy(void *dest, const void *src, size_t size);
extern void OS_Yield(void);
-extern unsigned int OS_TimerHz(void);
-extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period);
-extern void OS_TimerStart(void);
+extern Bool OS_TimerStart(OSTimerHandler *handler, void *clientData);
extern void OS_TimerStop(void);
-extern unsigned int OS_PredictMaxReservedPages(void);
-extern unsigned long OS_AddrToPPN(unsigned long addr);
-extern unsigned long OS_AllocReservedPage(int canSleep);
-extern void OS_FreeReservedPage(unsigned long page);
+extern unsigned long OS_ReservedPageGetLimit(void);
+extern unsigned long OS_ReservedPageGetPPN(PageHandle handle);
+extern PageHandle OS_ReservedPageAlloc(int canSleep);
+extern void OS_ReservedPageFree(PageHandle handle);
#endif /* OS_H */
* Includes
*/
-#include "balloon_def.h"
#include "os.h"
#include "backdoor.h"
#include "backdoor_balloon.h"
*/
typedef struct BalloonChunk {
- unsigned long page[BALLOON_CHUNK_PAGES];
+ PageHandle page[BALLOON_CHUNK_PAGES];
uint32 nextPage;
- struct BalloonChunk *prev, *next;
+ struct BalloonChunk *prev;
+ struct BalloonChunk *next;
} BalloonChunk;
typedef struct {
- unsigned long page[BALLOON_ERROR_PAGES];
+ PageHandle page[BALLOON_ERROR_PAGES];
uint32 nextPage;
} BalloonErrorPages;
*/
static Balloon globalBalloon;
+static Bool timerStarted;
/*
* Forward Declarations
*/
-static int BalloonGuestType(void);
-
-static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
-static void BalloonPrimFreePage(unsigned long page);
-
static int Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
static int Balloon_FreePage(Balloon *b, int monitorUnlock);
static int Balloon_AdjustSize(Balloon *b, uint32 target);
static void Balloon_Reset(Balloon *b);
-static void Balloon_StartTimer(Balloon *b);
-static void Balloon_StopTimer(Balloon *b);
static void BalloonTimerHandler(void *clientData);
static int Balloon_MonitorStart(Balloon *b);
static int Balloon_MonitorGuestType(Balloon *b);
static int Balloon_MonitorGetTarget(Balloon *b, uint32 *nPages);
-static int Balloon_MonitorLockPage(Balloon *b, unsigned long addr);
-static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr);
+static int Balloon_MonitorLockPage(Balloon *b, PageHandle handle);
+static int Balloon_MonitorUnlockPage(Balloon *b, PageHandle handle);
/*
* Macros
int len = 0;
BalloonStats stats;
- BalloonGetStats(&stats);
+ Balloon_GetStats(&stats);
/* format size info */
len += OS_Snprintf(buf + len, size - len,
* Utility Operations
*/
-/*
- *----------------------------------------------------------------------
- *
- * AddrToPPN --
- *
- * Return the physical page number corresponding to the specified
- * kernel-mapped address.
- *
- * Results:
- * Returns PPN for "addr".
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static inline unsigned long
-AddrToPPN(unsigned long addr)
-{
- return OS_AddrToPPN(addr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * BalloonPrimAllocPage --
- *
- * Attempts to allocate and reserve a physical page.
- *
- * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
- * The allocation can wait (sleep) for page writeout (swap)
- * by the guest.
- * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
- * If allocation of a page requires disk writeout, then
- * just fail. DON'T sleep.
- *
- * Results:
- * Returns the physical address of the allocated page, or 0 if error.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static unsigned long
-BalloonPrimAllocPage(BalloonPageAllocType canSleep)
-{
- return OS_AllocReservedPage(canSleep);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * BalloonPrimFreePage --
- *
- * Unreserves and deallocates specified physical page.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static void
-BalloonPrimFreePage(unsigned long page)
-{
- return OS_FreeReservedPage(page);
-}
/*
*----------------------------------------------------------------------
*
- * BalloonGuestType --
+ * Balloon_GetStats --
*
- * Return balloon guest OS identifier obtained by parsing
- * system-dependent identity string.
+ * Returns information about balloon state, including the current and
+ * target size, rates for allocating and freeing pages, and statistics
+ * about past activity.
*
* Results:
- * Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
+ * None
*
* Side effects:
- * None.
+ * None
*
*----------------------------------------------------------------------
*/
-static int
-BalloonGuestType(void)
-{
- const char *identity;
-
- /* obtain OS identify string */
- identity = OS_Identity();
-
- /* unknown if not specified */
- if (identity == NULL) {
- return(BALLOON_GUEST_UNKNOWN);
- }
- /* classify based on first letter (avoid defining strcmp) */
- switch (identity[0]) {
- case 'l':
- case 'L':
- return BALLOON_GUEST_LINUX;
- case 'b':
- case 'B':
- return BALLOON_GUEST_BSD;
- case 's':
- case 'S':
- return BALLOON_GUEST_SOLARIS;
- default:
- break;
- }
-
- /* unknown */
- return BALLOON_GUEST_UNKNOWN;
-}
-
-/*
- * Returns information about balloon state, including the current and
- * target size, rates for allocating and freeing pages, and statistics
- * about past activity.
- */
-void BalloonGetStats(BalloonStats *stats)
+void
+Balloon_GetStats(BalloonStats *stats) // OUT
{
Balloon *b = &globalBalloon;
/*
* Copy statistics out of global structure.
*/
- OS_MemCopy(stats, &b->stats, sizeof (BalloonStats));
+ OS_MemCopy(stats, &b->stats, sizeof *stats);
/*
* Fill in additional information about size and rates, which is
stats->rateFree = b->rateFree;
}
-/*
- * BalloonChunk Operations
- */
/*
*----------------------------------------------------------------------
/* initialize */
OS_MemZero(chunk, sizeof *chunk);
- /* everything OK */
return chunk;
}
/* initialize reset flag */
b->resetFlag = 1;
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
/*
BalloonTimerHandler(void *clientData)
{
Balloon *b = (Balloon *) clientData;
- uint32 target;
+ uint32 target = 0; // Silence compiler warning.
int status;
/* update stats */
}
}
-/*
- *----------------------------------------------------------------------
- *
- * Balloon_StartTimer --
- *
- * Schedules next execution of balloon timer handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static void
-Balloon_StartTimer(Balloon *b)
-{
- OS_TimerStart();
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * Balloon_StopTimer --
- *
- * Deschedules balloon timer handler.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-static void
-Balloon_StopTimer(Balloon *b)
-{
- OS_TimerStop();
-}
-
/*
*----------------------------------------------------------------------
/* free all non-balloonable "error" pages */
for (i = 0; i < b->errors.nextPage; i++) {
- BalloonPrimFreePage(b->errors.page[i]);
- b->errors.page[i] = 0;
+ OS_ReservedPageFree(b->errors.page[i]);
+ b->errors.page[i] = PAGE_HANDLE_INVALID;
STATS_INC(b->stats.primErrorPageFree);
}
b->errors.nextPage = 0;
Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType)
{
BalloonChunk *chunk;
- unsigned long page;
+ PageHandle page;
int status;
retry:
/* allocate page, fail if unable */
STATS_INC(b->stats.primAlloc[allocType]);
- page = BalloonPrimAllocPage(allocType);
+ /*
+ * Attempts to allocate and reserve a physical page.
+ *
+ * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
+ * The allocation can wait (sleep) for page writeout (swap) by the guest.
+ * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
+ * If allocation of a page requires disk writeout, then just fail. DON'T sleep.
+ *
+ * Returns the physical address of the allocated page, or 0 if error.
+ */
+ page = OS_ReservedPageAlloc(allocType);
- if (page == 0) {
+ if (page == PAGE_HANDLE_INVALID) {
STATS_INC(b->stats.primAllocFail[allocType]);
- return(BALLOON_PAGE_ALLOC_FAILURE);
+ return BALLOON_PAGE_ALLOC_FAILURE;
}
/* find chunk with space, create if necessary */
chunk = b->chunks;
if ((chunk == NULL) || (chunk->nextPage >= BALLOON_CHUNK_PAGES)) {
/* create new chunk */
- if ((chunk = BalloonChunk_Create()) == NULL) {
+ chunk = BalloonChunk_Create();
+ if (chunk == NULL) {
/* reclaim storage, fail */
- BalloonPrimFreePage(page);
- return(BALLOON_PAGE_ALLOC_FAILURE);
+ OS_ReservedPageFree(page);
+ return BALLOON_PAGE_ALLOC_FAILURE;
}
BalloonChunk_Insert(&b->chunks, chunk);
}
/* reclaim storage, fail */
- BalloonPrimFreePage(page);
- return(status);
+ OS_ReservedPageFree(page);
+ return status;
}
/* track allocated page */
/* update balloon size */
b->nPages++;
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
/*
Balloon_FreePage(Balloon *b, int monitorUnlock)
{
BalloonChunk *chunk;
- unsigned long page;
+ PageHandle page;
int status;
chunk = b->chunks;
}
/* deallocate page */
- BalloonPrimFreePage(page);
+ OS_ReservedPageFree(page);
STATS_INC(b->stats.primFree);
/* update balloon size */
b->nChunks--;
}
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
/*
}
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
BalloonInflate(Balloon *b, uint32 target)
{
return(BALLOON_SUCCESS);
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
BalloonDeflate(Balloon *b, uint32 target)
{
BALLOON_RATE_FREE_MAX);
}
- /* everything OK */
- return(BALLOON_SUCCESS);
+ return BALLOON_SUCCESS;
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
Balloon_AdjustSize(Balloon *b, uint32 target)
{
*
*----------------------------------------------------------------------
*/
+
static int
Balloon_MonitorStart(Balloon *b)
{
STATS_INC(b->stats.startFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
*----------------------------------------------------------------------
*
*
*----------------------------------------------------------------------
*/
+
static int
Balloon_MonitorGuestType(Balloon *b)
{
uint32 status, target;
+ BalloonGuest identity;
Backdoor_proto bp;
+ identity = OS_Identity();
+ ASSERT(identity == (uint32) identity);
+
/* prepare backdoor args */
bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_GUEST_ID;
- bp.in.size = BalloonGuestType();
+ bp.in.size = identity;
/* invoke backdoor */
Backdoor_Balloon(&bp);
STATS_INC(b->stats.guestTypeFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
*----------------------------------------------------------------------
*
* Predicts the maximum achievable balloon size and sends it
* to vmm => vmkernel via vEbx register.
*
- * OS_PredictMaxReservedPages() returns either predicted max balloon
+ * OS_ReservedPageGetLimit() returns either predicted max balloon
* pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
* vmkernel uses global config options for determining a guest's max
* balloon size. Note that older vmballoon drivers set vEbx to
*
*----------------------------------------------------------------------
*/
+
static int
-Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
+Balloon_MonitorGetTarget(Balloon *b, // IN
+ uint32 *target) // OUT
{
Backdoor_proto bp;
+ unsigned long limit;
+ uint32 limit32;
uint32 status;
+ limit = OS_ReservedPageGetLimit();
+
+ /* Ensure limit fits in 32-bits */
+ limit32 = (uint32)limit;
+ if (limit32 != limit) {
+ return BALLOON_FAILURE;
+ }
+
/* prepare backdoor args */
bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
- bp.in.size = OS_PredictMaxReservedPages();
+ bp.in.size = limit;
/* invoke backdoor */
Backdoor_Balloon(&bp);
STATS_INC(b->stats.targetFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
*----------------------------------------------------------------------
*
* Balloon_MonitorLockPage --
*
- * Attempts to contact monitor and add PPN containing "addr"
- * to set of "balloon locked" pages.
+ * Attempts to contact monitor and add PPN corresponding to
+ * the page handle to set of "balloon locked" pages.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*
*----------------------------------------------------------------------
*/
+
static int
-Balloon_MonitorLockPage(Balloon *b, unsigned long addr)
+Balloon_MonitorLockPage(Balloon *b, // IN
+ PageHandle handle) // IN
{
unsigned long ppn;
uint32 ppn32;
uint32 status, target;
Backdoor_proto bp;
- /* convert kernel-mapped "physical addr" to ppn */
- ppn = AddrToPPN(addr);
+ ppn = OS_ReservedPageGetPPN(handle);
/* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */
ppn32 = (uint32)ppn;
STATS_INC(b->stats.lockFail);
}
- /* everything OK */
- return(status);
+ return status;
}
/*
*
* Balloon_MonitorUnlockPage --
*
- * Attempts to contact monitor and remove PPN containing "addr"
- * from set of "balloon locked" pages.
+ * Attempts to contact monitor and remove PPN corresponding to
+ * the page handle from set of "balloon locked" pages.
*
* Results:
* Returns BALLOON_SUCCESS if successful, otherwise error code.
*----------------------------------------------------------------------
*/
static int
-Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr)
+Balloon_MonitorUnlockPage(Balloon *b, // IN
+ PageHandle handle) // IN
{
unsigned long ppn;
uint32 ppn32;
uint32 status, target;
Backdoor_proto bp;
- /* convert kernel-mapped "physical addr" to ppn */
- ppn = AddrToPPN(addr);
+ ppn = OS_ReservedPageGetPPN(handle);
/* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */
ppn32 = (uint32)ppn;
STATS_INC(b->stats.unlockFail);
}
- /* everything OK */
- return(status);
+ return status;
}
+
/*
- * Module Operations
+ *----------------------------------------------------------------------
+ *
+ * Balloon_ModuleInit --
+ *
+ * Startup the balloon module.
+ *
+ * Results:
+ * On success: BALLOON_SUCCESS
+ * On failure: BALLOON_FAILURE
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
*/
-static int
-BalloonModuleInit(void)
+int
+Balloon_ModuleInit(void)
{
static int initialized = 0;
Balloon *b = &globalBalloon;
/* initialize only once */
if (initialized++) {
- return(BALLOON_FAILURE);
+ return BALLOON_FAILURE;
}
/* os-specific initialization */
Balloon_Init(b);
/* start timer */
- OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz());
- Balloon_StartTimer(b);
+ timerStarted = FALSE;
+ if (!OS_TimerStart(BalloonTimerHandler, b)) {
+ Balloon_ModuleCleanup();
+ return BALLOON_FAILURE;
+ }
- /* everything OK */
+ timerStarted = TRUE;
return BALLOON_SUCCESS;
}
-static void
-BalloonModuleCleanup(void)
+/*
+ *----------------------------------------------------------------------
+ *
+ * Balloon_ModuleCleanup --
+ *
+ * Terminate and cleanup the balloon module.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Balloon_ModuleCleanup(void)
{
Balloon *b = &globalBalloon;
/* stop timer */
- Balloon_StopTimer(b);
+ if (timerStarted) {
+ OS_TimerStop();
+ }
/*
* Deallocate all reserved memory, and reset connection with monitor.
* Reset connection before deallocating memory to avoid potential for
* additional spurious resets from guest touching deallocated pages.
*/
- (void) Balloon_MonitorStart(b);
+ Balloon_MonitorStart(b);
Balloon_Deallocate(b);
/* os-specific cleanup */
OS_Cleanup();
}
-int init_module(void)
-{
- return(BalloonModuleInit());
-}
-
-void cleanup_module(void)
-{
- BalloonModuleCleanup();
-}
-
#ifdef __cplusplus
}
#endif
* Operations
*/
-extern void BalloonGetStats(BalloonStats *stats);
-extern int init_module(void);
-extern void cleanup_module(void);
+extern int Balloon_ModuleInit(void);
+extern void Balloon_ModuleCleanup(void);
+
+extern void Balloon_GetStats(BalloonStats *stats);
#endif /* VMBALLOON_H */
if (rw == KSTAT_WRITE)
return (EACCES);
- BalloonGetStats(&stats);
+ Balloon_GetStats(&stats);
/* size info */
bkp->nPagesTarget.value.ui32 = stats.nPagesTarget;
# `which' may be a bit noisy, so we'll shush it.
dbusSend=`which dbus-send 2>/dev/null`
if [ $? -eq 0 ]; then
+ # NetworkManager 0.6
+ $dbusSend --system --dest=org.freedesktop.NetworkManager \
+ /org/freedesktop/NetworkManager \
+ org.freedesktop.NetworkManager.wake
+ # NetworkManager 0.7.0
$dbusSend --system --dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager \
org.freedesktop.NetworkManager.Sleep boolean:false
# `which' may be a bit noisy, so we'll shush it.
dbusSend=`which dbus-send 2>/dev/null`
if [ $? -eq 0 ]; then
+ # NetworkManager 0.6
+ $dbusSend --system --dest=org.freedesktop.NetworkManager \
+ /org/freedesktop/NetworkManager \
+ org.freedesktop.NetworkManager.sleep
+ # NetworkManager 0.7.0
$dbusSend --system --dest=org.freedesktop.NetworkManager \
/org/freedesktop/NetworkManager \
org.freedesktop.NetworkManager.Sleep boolean:true