From: VMware, Inc <> Date: Mon, 15 Oct 2012 04:53:17 +0000 (-0700) Subject: vmmemctl: use capability based system to advertise balloon features X-Git-Tag: 2012.10.14-874563~21 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=adf63a09d612ddebf402435bf6b1ee9ba6f693ba;p=thirdparty%2Fopen-vm-tools.git vmmemctl: use capability based system to advertise balloon features Use a capability based system instead of versioning to advertise and negotiate balloon features. On START command, the guest is sending its capability and the monitor returns the masked capability. That way, the guest knows exactly what features are supported by the monitor. Currently the capability use two bits: if the bit 1 is set, then the unbatched lock and unlock are supported, and if the bit 2 is set, then the batched lock and unlock are supported. Bit 1 was chosen to be backward compatible with "protocol v2", and bit 0 is unused to avoid issue with the screwed "protocol v3". Signed-off-by: Dmitry Torokhov --- diff --git a/open-vm-tools/modules/freebsd/vmmemctl/os.c b/open-vm-tools/modules/freebsd/vmmemctl/os.c index 29f25a5c8..caee2a661 100644 --- a/open-vm-tools/modules/freebsd/vmmemctl/os.c +++ b/open-vm-tools/modules/freebsd/vmmemctl/os.c @@ -230,13 +230,13 @@ OS_ReservedPageGetLimit(void) /* *----------------------------------------------------------------------------- * - * OS_ReservedPageGetPPN -- + * OS_ReservedPageGetPA -- * * Convert a page handle (of a physical page previously reserved with - * OS_ReservedPageAlloc()) to a ppn. + * OS_ReservedPageAlloc()) to a pa. * * Results: - * The ppn. + * The pa. * * Side effects: * None. @@ -244,10 +244,10 @@ OS_ReservedPageGetLimit(void) *----------------------------------------------------------------------------- */ -PPN64 -OS_ReservedPageGetPPN(PageHandle handle) // IN: A valid page handle +PA64 +OS_ReservedPageGetPA(PageHandle handle) // IN: A valid page handle { - return (((vm_page_t)handle)->phys_addr) >> PAGE_SHIFT; + return (((vm_page_t)handle)->phys_addr); } @@ -256,7 +256,7 @@ OS_ReservedPageGetPPN(PageHandle handle) // IN: A valid page handle * * OS_ReservedPageGetHandle -- * - * Convert a ppn (of a physical page previously reserved with + * Convert a pa (of a physical page previously reserved with * OS_ReservedPageAlloc()) to a page handle. * * Results: @@ -269,9 +269,9 @@ OS_ReservedPageGetPPN(PageHandle handle) // IN: A valid page handle */ PageHandle -OS_ReservedPageGetHandle(PPN64 ppn) // IN +OS_ReservedPageGetHandle(PA64 pa) // IN { - return (PageHandle)PHYS_TO_VM_PAGE(ppn << PAGE_SHIFT); + return (PageHandle)PHYS_TO_VM_PAGE(pa); } @@ -516,7 +516,7 @@ os_balloonobject_create(void) * 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() + * On success: A valid page handle that can be passed to OS_ReservedPageGetPA() * or OS_ReservedPageFree(). * On failure: PAGE_HANDLE_INVALID * diff --git a/open-vm-tools/modules/shared/vmmemctl/backdoor_balloon.c b/open-vm-tools/modules/shared/vmmemctl/backdoor_balloon.c index 674391b64..5837e41fc 100644 --- a/open-vm-tools/modules/shared/vmmemctl/backdoor_balloon.c +++ b/open-vm-tools/modules/shared/vmmemctl/backdoor_balloon.c @@ -121,14 +121,15 @@ Backdoor_MonitorStart(Balloon *b, // IN status = bp.out.ax.word; /* - * If return code is BALLOON_SUCCESS_WITH_VERSION, then ESX is - * sending the protocol version to be used into cx. + * If return code is BALLOON_SUCCESS_WITH_CAPABILITY, then ESX is + * sending the common capabilities supported by the monitor and the + * guest in cx. */ - if (status == BALLOON_SUCCESS_WITH_VERSION) { - b->hypervisorProtocolVersion = bp.out.cx.word; + if (status == BALLOON_SUCCESS_WITH_CAPABILITIES) { + b->hypervisorCapabilities = bp.out.cx.word; status = BALLOON_SUCCESS; } else if (status == BALLOON_SUCCESS) { - b->hypervisorProtocolVersion = BALLOON_PROTOCOL_VERSION_2; + b->hypervisorCapabilities = BALLOON_BASIC_CMDS; } /* update stats */ @@ -285,13 +286,11 @@ Backdoor_MonitorLockPage(Balloon *b, // IN { uint32 status; Backdoor_proto bp; + uint32 ppn32 = (uint32)ppn; - if (b->hypervisorProtocolVersion == BALLOON_PROTOCOL_VERSION_2) { - /* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */ - uint32 ppn32 = (uint32)ppn; - if (ppn32 != ppn) { - return BALLOON_ERROR_PPN_INVALID; - } + /* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */ + if (ppn32 != ppn) { + return BALLOON_ERROR_PPN_INVALID; } /* prepare backdoor args */ @@ -343,13 +342,11 @@ Backdoor_MonitorUnlockPage(Balloon *b, // IN { uint32 status; Backdoor_proto bp; + uint32 ppn32 = (uint32)ppn; - if (b->hypervisorProtocolVersion == BALLOON_PROTOCOL_VERSION_2) { - /* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */ - uint32 ppn32 = (uint32)ppn; - if (ppn32 != ppn) { - return BALLOON_ERROR_PPN_INVALID; - } + /* Ensure PPN fits in 32-bits, i.e. guest memory is limited to 16TB. */ + if (ppn32 != ppn) { + return BALLOON_ERROR_PPN_INVALID; } /* prepare backdoor args */ @@ -375,3 +372,101 @@ Backdoor_MonitorUnlockPage(Balloon *b, // IN return status; } + +/* + *---------------------------------------------------------------------- + * + * Backdoor_MonitorLockPagesBatched -- + * + * Balloon all PPNs listed in the batch page. + * + * Results: + * Returns BALLOON_SUCCESS if successful, otherwise error code. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Backdoor_MonitorLockPagesBatched(Balloon *b, // IN + PPN64 ppn, // IN + uint32 nPages) // IN +{ + uint32 status; + Backdoor_proto bp; + + /* prepare backdoor args */ + bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_BATCHED_LOCK; + bp.in.size = (size_t)ppn; + bp.in.si.word = nPages; + + /* invoke backdoor */ + BackdoorBalloon(&bp); + + /* parse return values */ + status = bp.out.ax.word; + + /* set flag if reset requested */ + if (status == BALLOON_ERROR_RESET) { + b->resetFlag = 1; + } + + /* update stats */ + STATS_INC(b->stats.lock); + if (status != BALLOON_SUCCESS) { + STATS_INC(b->stats.lockFail); + } + + return status; +} + +/* + *---------------------------------------------------------------------- + * + * Backdoor_MonitorUnlockPagesBatched -- + * + * Unballoon all PPNs listed in the batch page. + * + * Results: + * Returns BALLOON_SUCCESS if successful, otherwise error code. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Backdoor_MonitorUnlockPagesBatched(Balloon *b, // IN + PPN64 ppn, // IN + uint32 nPages) // IN +{ + uint32 status; + Backdoor_proto bp; + + /* prepare backdoor args */ + bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_BATCHED_UNLOCK; + bp.in.size = (size_t)ppn; + bp.in.si.word = nPages; + + /* invoke backdoor */ + BackdoorBalloon(&bp); + + /* parse return values */ + status = bp.out.ax.word; + + /* set flag if reset requested */ + if (status == BALLOON_ERROR_RESET) { + b->resetFlag = 1; + } + + /* update stats */ + STATS_INC(b->stats.unlock); + if (status != BALLOON_SUCCESS) { + STATS_INC(b->stats.unlockFail); + } + + return status; +} diff --git a/open-vm-tools/modules/shared/vmmemctl/backdoor_balloon.h b/open-vm-tools/modules/shared/vmmemctl/backdoor_balloon.h index 724ffd832..3cb53296a 100644 --- a/open-vm-tools/modules/shared/vmmemctl/backdoor_balloon.h +++ b/open-vm-tools/modules/shared/vmmemctl/backdoor_balloon.h @@ -77,5 +77,7 @@ int Backdoor_MonitorGuestType(Balloon *b); int Backdoor_MonitorGetTarget(Balloon *b, uint32 *target); int Backdoor_MonitorLockPage(Balloon *b, PPN64 ppn); int Backdoor_MonitorUnlockPage(Balloon *b, PPN64 ppn); +int Backdoor_MonitorLockPagesBatched(Balloon *b, PPN64 ppn, uint32 nPages); +int Backdoor_MonitorUnlockPagesBatched(Balloon *b, PPN64 ppn, uint32 nPages); #endif /* _BACKDOOR_BALLOON_H_ */ diff --git a/open-vm-tools/modules/shared/vmmemctl/balloonInt.h b/open-vm-tools/modules/shared/vmmemctl/balloonInt.h index 9ffc54b09..facca9ebe 100644 --- a/open-vm-tools/modules/shared/vmmemctl/balloonInt.h +++ b/open-vm-tools/modules/shared/vmmemctl/balloonInt.h @@ -68,9 +68,13 @@ #define BALLOON_NAME_VERBOSE "VMware memory control driver" #if defined __linux__ || defined __FreeBSD__ || defined _WIN32 -#define BALLOON_PROTOCOL_VERSION BALLOON_PROTOCOL_VERSION_3 +/* + * FIXME: Even if the driver support batched commands keep using the + * non-batched one until more testing has been done. + */ +#define BALLOON_CAPABILITIES BALLOON_BASIC_CMDS #else -#define BALLOON_PROTOCOL_VERSION BALLOON_PROTOCOL_VERSION_2 +#define BALLOON_CAPABILITIES BALLOON_BASIC_CMDS #endif #define BALLOON_RATE_ADAPT 1 @@ -107,4 +111,7 @@ #define STATS_DEC(stat) #endif +#define PPN_2_PA(_ppn) ((_ppn) << PAGE_SHIFT) +#define PA_2_PPN(_pa) ((_pa) >> PAGE_SHIFT) + #endif /* !BALLOONINT_H_ */ diff --git a/open-vm-tools/modules/shared/vmmemctl/balloon_def.h b/open-vm-tools/modules/shared/vmmemctl/balloon_def.h index da607bee4..ef870cdad 100644 --- a/open-vm-tools/modules/shared/vmmemctl/balloon_def.h +++ b/open-vm-tools/modules/shared/vmmemctl/balloon_def.h @@ -59,7 +59,7 @@ *********************************************************/ /* - * balloon_def.h -- + * balloon_def.h -- * * Definitions for server "balloon" mechanism for reclaiming * physical memory from a VM. @@ -82,10 +82,6 @@ * constants */ -/* protocol versions */ -#define BALLOON_PROTOCOL_VERSION_2 (2) -#define BALLOON_PROTOCOL_VERSION_3 (3) - /* backdoor port */ #define BALLOON_BDOOR_PORT (0x5670) #define BALLOON_BDOOR_MAGIC (0x456c6d6f) @@ -93,33 +89,52 @@ /* * Backdoor commands availability: * - * +====================+===============+ - * | CMD | Protocol | - * +--------------------+---------------+ - * | START | 2 (*) | - * | TARGET | 2 | - * | LOCK | 2 (*) | - * | UNLOCK | 2 (*) | - * | GUEST_ID | 2 | - * +====================+===============+ - * - * (*) The START, LOCK and UNLOCK has been slightly modified when - * protocol v3 is used: - * - START now returns BALLOON_SUCCESS_WITH_VERSION, with the protocol - * version stored in %ecx, only if guest also support protocol v3 or - * up. - * - LOCK and UNLOCK are now taking a PPN of a page that contains a - * BalloonBatchPage, instead of directly taking the PPN to - * lock/unlock. + * +====================+======================+ + * | CMD | Capabilities | + * +--------------------+----------------------+ + * | START | Always available (*) | + * | TARGET | Always available | + * | LOCK | BASIC_CMDS | + * | UNLOCK | BASIC_CMDS | + * | GUEST_ID | Always available | + * | BATCHED_LOCK | BATCHED_CMDS | + * | BATCHED_UNLOCK | BATCHED_CMDS | + * +====================+======================+ + * + * (*) The START command has been slightly modified when more than the + * basic commands are available: It returns + * BALLOON_SUCCESS_WITH_CAPABILITIES with the available capabilities + * stored in %ecx. Previously, a versioned protocol was used, and the + * protocol that should be used was also returned in %ecx. Protocol + * version 2 was the initial version and the only one shipped. Version 3 + * was temporary used internally but has caused several issue due to + * protocol mismatch between monitor and guest. * */ /* backdoor command numbers */ -#define BALLOON_BDOOR_CMD_START (0) -#define BALLOON_BDOOR_CMD_TARGET (1) -#define BALLOON_BDOOR_CMD_LOCK (2) -#define BALLOON_BDOOR_CMD_UNLOCK (3) -#define BALLOON_BDOOR_CMD_GUEST_ID (4) +#define BALLOON_BDOOR_CMD_START (0) +#define BALLOON_BDOOR_CMD_TARGET (1) +#define BALLOON_BDOOR_CMD_LOCK (2) +#define BALLOON_BDOOR_CMD_UNLOCK (3) +#define BALLOON_BDOOR_CMD_GUEST_ID (4) +/* The command 5 was shortly used between 1881144 and 1901153. */ +#define BALLOON_BDOOR_CMD_BATCHED_LOCK (6) +#define BALLOON_BDOOR_CMD_BATCHED_UNLOCK (7) + +/* balloon capabilities */ +typedef enum { + /* + * Bit 0 is not used and shouldn't be used, due to issue with + * protocol v3, to avoid ambiguity between protocol v3 and + * capabilities, leave this bit as 0. That way, by masking guest + * capabilities with monitor capabilities, bit 0 will always be set + * to 0, and buggy v3 tool will automatically switch to unbatched + * LOCK and UNLOCK. + */ + BALLOON_BASIC_CMDS = (1 << 1), + BALLOON_BATCHED_CMDS = (1 << 2) +} BalloonCapabilities; /* use config value for max balloon size */ #define BALLOON_MAX_SIZE_USE_CONFIG (0) @@ -141,113 +156,56 @@ typedef enum { } BalloonGuest; /* error codes */ -#define BALLOON_SUCCESS (0) -#define BALLOON_FAILURE (-1) -#define BALLOON_ERROR_CMD_INVALID (1) -#define BALLOON_ERROR_PPN_INVALID (2) -#define BALLOON_ERROR_PPN_LOCKED (3) -#define BALLOON_ERROR_PPN_UNLOCKED (4) -#define BALLOON_ERROR_PPN_PINNED (5) -#define BALLOON_ERROR_PPN_NOTNEEDED (6) -#define BALLOON_ERROR_RESET (7) -#define BALLOON_ERROR_BUSY (8) -/* - * Sent on CMD_START to inform the guest to use the protocol v3 or - * higher. - */ -#define BALLOON_SUCCESS_WITH_VERSION (0x03000000) +#define BALLOON_SUCCESS (0) +#define BALLOON_FAILURE (-1) +#define BALLOON_ERROR_CMD_INVALID (1) +#define BALLOON_ERROR_PPN_INVALID (2) +#define BALLOON_ERROR_PPN_LOCKED (3) +#define BALLOON_ERROR_PPN_UNLOCKED (4) +#define BALLOON_ERROR_PPN_PINNED (5) +#define BALLOON_ERROR_PPN_NOTNEEDED (6) +#define BALLOON_ERROR_RESET (7) +#define BALLOON_ERROR_BUSY (8) + +#define BALLOON_SUCCESS_WITH_CAPABILITIES (0x03000000) /* * BatchPage. */ -#define BALLOON_BATCH_MAX_PAGES \ - ((PAGE_SIZE - sizeof(uint64)) / sizeof(PPN64)) - -#define BALLOON_BATCH_STATUS_SHIFT 56 - -typedef struct BalloonBatchPage { - uint64 nPages; - PPN64 pages[BALLOON_BATCH_MAX_PAGES]; -} BalloonBatchPage; - +#define BALLOON_BATCH_MAX_PAGES (PAGE_SIZE / sizeof(PA64)) /* - *----------------------------------------------------------------------------- + * We are using the fact that for 4k pages, the 12LSB are set to 0, so + * we can use them and mask those bit when we need the real PA. * - * Balloon_BatchInit -- + * +=============+==========+========+ + * | | | | + * | Page number | Reserved | Status | + * | | | | + * +=============+==========+========+ + * 64 PAGE_SHIFT 6 0 * - * Results: - * Return the number of pages that can be embedded inside the batch - * page. If the protocol does not support batching, return 0. + * For now, only 4k pages are supported by the monitor, but by using + * reserved bit we can in the future add some flags that will indicate + * whether the page is a 2M page or a 1G page. * - * Side effects: - * None. + * The reserved field should be set to 0. * - *----------------------------------------------------------------------------- */ -static INLINE uint16 -Balloon_BatchInit(uint32 protoVersion) // IN -{ - switch (protoVersion) { - case BALLOON_PROTOCOL_VERSION_3: - return BALLOON_BATCH_MAX_PAGES; - case BALLOON_PROTOCOL_VERSION_2: - default: - return 0; - } -} -/* - *----------------------------------------------------------------------------- - * - * Balloon_BatchGetNumPages -- - * - * Return the number of pages contained in the batch page. - * - * Results: - * See above. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ -static INLINE uint64 -Balloon_BatchGetNumPages(BalloonBatchPage *batchPage) // IN -{ - return batchPage->nPages; -} +#define BALLOON_BATCH_STATUS_MASK MASK64(5) +#define BALLOON_BATCH_PAGE_MASK (~MASK64(PAGE_SHIFT)) - -/* - *----------------------------------------------------------------------------- - * - * Balloon_BatchSetNumPages -- - * - * Set the number of pages contained in the batch page. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ -static INLINE void -Balloon_BatchSetNumPages(BalloonBatchPage *batchPage, // IN - uint64 nPages) // IN -{ - ASSERT(nPages <= BALLOON_BATCH_MAX_PAGES); - batchPage->nPages = nPages; -} +typedef struct BalloonBatchPage { + PA64 pages[BALLOON_BATCH_MAX_PAGES]; +} BalloonBatchPage; /* *----------------------------------------------------------------------------- * - * Balloon_BatchGetPPN -- + * Balloon_BatchGetPA -- * * Get the page stored in the batch page at idx. * @@ -259,12 +217,12 @@ Balloon_BatchSetNumPages(BalloonBatchPage *batchPage, // IN * *----------------------------------------------------------------------------- */ -static INLINE PPN64 -Balloon_BatchGetPPN(BalloonBatchPage *batchPage, // IN - uint16 idx) // IN +static INLINE PA64 +Balloon_BatchGetPA(BalloonBatchPage *batchPage, // IN + uint16 idx) // IN { - ASSERT(idx < batchPage->nPages); - return batchPage->pages[idx] & MASK64(BALLOON_BATCH_STATUS_SHIFT); + ASSERT(idx < BALLOON_BATCH_MAX_PAGES); + return batchPage->pages[idx] & BALLOON_BATCH_PAGE_MASK; } @@ -287,15 +245,15 @@ static INLINE uint8 Balloon_BatchGetStatus(BalloonBatchPage *batchPage, // IN uint16 idx) // IN { - ASSERT(idx < batchPage->nPages); - return (uint8)(batchPage->pages[idx] >> BALLOON_BATCH_STATUS_SHIFT); + ASSERT(idx < BALLOON_BATCH_MAX_PAGES); + return (uint8)(batchPage->pages[idx] & BALLOON_BATCH_STATUS_MASK); } /* *----------------------------------------------------------------------------- * - * Balloon_BatchSetPPN -- + * Balloon_BatchSetPA -- * * Store the page in the batch page at idx. * @@ -308,12 +266,13 @@ Balloon_BatchGetStatus(BalloonBatchPage *batchPage, // IN *----------------------------------------------------------------------------- */ static INLINE void -Balloon_BatchSetPPN(BalloonBatchPage *batchPage, // IN - uint16 idx, // IN - PPN64 ppn) // IN +Balloon_BatchSetPA(BalloonBatchPage *batchPage, // IN + uint16 idx, // IN + PA64 pa) // IN { ASSERT(idx < BALLOON_BATCH_MAX_PAGES); - batchPage->pages[idx] = ppn; + ASSERT((pa & ~BALLOON_BATCH_PAGE_MASK) == 0); + batchPage->pages[idx] = pa; } @@ -337,12 +296,10 @@ Balloon_BatchSetStatus(BalloonBatchPage *batchPage, // IN uint16 idx, // IN int error) // IN { - PPN64 ppn; - + PA64 pa = Balloon_BatchGetPA(batchPage, idx); ASSERT(idx < BALLOON_BATCH_MAX_PAGES); - ppn = Balloon_BatchGetPPN(batchPage, idx); - ppn |= ((PPN64)error << BALLOON_BATCH_STATUS_SHIFT); - batchPage->pages[idx] = ppn; + ASSERT(error <= BALLOON_ERROR_BUSY && error >= BALLOON_FAILURE); + batchPage->pages[idx] = pa | (PPN64)error; } MY_ASSERTS(BALLOON_BATCH_SIZE, diff --git a/open-vm-tools/modules/shared/vmmemctl/os.h b/open-vm-tools/modules/shared/vmmemctl/os.h index 2f3fe29db..9ef969792 100644 --- a/open-vm-tools/modules/shared/vmmemctl/os.h +++ b/open-vm-tools/modules/shared/vmmemctl/os.h @@ -93,8 +93,8 @@ extern void OS_Free(void *ptr, size_t size); extern void OS_Yield(void); extern unsigned long OS_ReservedPageGetLimit(void); -extern PPN64 OS_ReservedPageGetPPN(PageHandle handle); -extern PageHandle OS_ReservedPageGetHandle(PPN64 ppn); +extern PA64 OS_ReservedPageGetPA(PageHandle handle); +extern PageHandle OS_ReservedPageGetHandle(PA64 pa); extern PageHandle OS_ReservedPageAlloc(int canSleep); extern void OS_ReservedPageFree(PageHandle handle); diff --git a/open-vm-tools/modules/shared/vmmemctl/vmballoon.c b/open-vm-tools/modules/shared/vmmemctl/vmballoon.c index 2674bbb29..15b56df29 100644 --- a/open-vm-tools/modules/shared/vmmemctl/vmballoon.c +++ b/open-vm-tools/modules/shared/vmmemctl/vmballoon.c @@ -109,12 +109,12 @@ static int BalloonPageFree(Balloon *b); static int BalloonAdjustSize(Balloon *b, uint32 target); static void BalloonReset(Balloon *b); -static void BalloonAddPagev2(Balloon *b, uint16 idx, PageHandle page); -static void BalloonAddPagev3(Balloon *b, uint16 idx, PageHandle page); -static int BalloonLockv2(Balloon *b, uint16 nPages); -static int BalloonLockv3(Balloon *b, uint16 nPages); -static int BalloonUnlockv2(Balloon *b, uint16 nPages); -static int BalloonUnlockv3(Balloon *b, uint16 nPages); +static void BalloonAddPage(Balloon *b, uint16 idx, PageHandle page); +static void BalloonAddPageBatched(Balloon *b, uint16 idx, PageHandle page); +static int BalloonLock(Balloon *b, uint16 nPages); +static int BalloonLockBatched(Balloon *b, uint16 nPages); +static int BalloonUnlock(Balloon *b, uint16 nPages); +static int BalloonUnlockBatched(Balloon *b, uint16 nPages); /* * Globals @@ -122,16 +122,16 @@ static int BalloonUnlockv3(Balloon *b, uint16 nPages); static Balloon globalBalloon; -static const BalloonOps balloonOpsv2 = { - .addPage = BalloonAddPagev2, - .lock = BalloonLockv2, - .unlock = BalloonUnlockv2 +static const BalloonOps balloonOps = { + .addPage = BalloonAddPage, + .lock = BalloonLock, + .unlock = BalloonUnlock }; -static const struct BalloonOps balloonOpsv3 = { - .addPage = BalloonAddPagev3, - .lock = BalloonLockv3, - .unlock = BalloonUnlockv3 +static const struct BalloonOps balloonOpsBatched = { + .addPage = BalloonAddPageBatched, + .lock = BalloonLockBatched, + .unlock = BalloonUnlockBatched }; /* @@ -178,7 +178,7 @@ Balloon_GetStats(void) * BalloonChunk_Create -- * * Creates a new BalloonChunk object capable of tracking - * BALLOON_CHUNK_PAGES PPNs. + * BALLOON_CHUNK_PAGES PAs. * * We do not bother to define two versions (NOSLEEP and CANSLEEP) * of OS_Malloc because Chunk_Create does not require a new page @@ -268,17 +268,15 @@ Balloon_Deallocate(Balloon *b) // IN } /* Release the batch page */ - if (b->hypervisorProtocolVersion > BALLOON_PROTOCOL_VERSION_2) { - if (b->batchPageMapping != MAPPING_INVALID) { - OS_UnmapPage(b->batchPageMapping); - b->batchPageMapping = MAPPING_INVALID; - b->batchPage = NULL; - } + if (b->batchPageMapping != MAPPING_INVALID) { + OS_UnmapPage(b->batchPageMapping); + b->batchPageMapping = MAPPING_INVALID; + b->batchPage = NULL; + } - if (b->pageHandle != PAGE_HANDLE_INVALID) { - OS_ReservedPageFree(b->pageHandle); - b->pageHandle = PAGE_HANDLE_INVALID; - } + if (b->pageHandle != PAGE_HANDLE_INVALID) { + OS_ReservedPageFree(b->pageHandle); + b->pageHandle = PAGE_HANDLE_INVALID; } } @@ -301,8 +299,7 @@ Balloon_Deallocate(Balloon *b) // IN static int BalloonInitBatching(Balloon *b) // IN { - b->batchMaxPages = Balloon_BatchInit(b->hypervisorProtocolVersion); - ASSERT(b->batchMaxPages != 0); + b->batchMaxPages = BALLOON_BATCH_MAX_PAGES; b->pageHandle = OS_ReservedPageAlloc(BALLOON_PAGE_ALLOC_NOSLEEP); if (b->pageHandle == PAGE_HANDLE_INVALID) { @@ -346,30 +343,30 @@ BalloonReset(Balloon *b) // IN /* free all pages, skipping monitor unlock */ Balloon_Deallocate(b); - status = Backdoor_MonitorStart(b, BALLOON_PROTOCOL_VERSION); + status = Backdoor_MonitorStart(b, BALLOON_CAPABILITIES); if (status != BALLOON_SUCCESS) { return; } - if (b->hypervisorProtocolVersion > BALLOON_PROTOCOL_VERSION_2) { + if ((b->hypervisorCapabilities & BALLOON_BATCHED_CMDS) != 0) { status = BalloonInitBatching(b); if (status != BALLOON_SUCCESS) { - status = Backdoor_MonitorStart(b, BALLOON_PROTOCOL_VERSION_2); - if (status != BALLOON_SUCCESS) { - return; - } + /* + * We failed to initialize the batching in the guest, inform + * the monitor about that by sending a null capability. + * + * The guest will retry to init itself in one second. + */ + Backdoor_MonitorStart(b, 0); + return; } } - switch (b->hypervisorProtocolVersion) { - case BALLOON_PROTOCOL_VERSION_3: - b->balloonOps = &balloonOpsv3; - break; - case BALLOON_PROTOCOL_VERSION_2: - default: - b->balloonOps = &balloonOpsv2; + if ((b->hypervisorCapabilities & BALLOON_BATCHED_CMDS) != 0) { + b->balloonOps = &balloonOpsBatched; + } else if ((b->hypervisorCapabilities & BALLOON_BASIC_CMDS) != 0) { + b->balloonOps = &balloonOps; b->batchMaxPages = 1; - break; } /* clear flag */ @@ -778,10 +775,10 @@ BalloonInflate(Balloon *b, // IN /* *---------------------------------------------------------------------- * - * BalloonLockv3 -- + * BalloonLockBatched -- * * Lock all the batched page, previously stored by - * BalloonAddPagev3. + * BalloonAddPageBatched. * * Results: * BALLOON_SUCCESS or an error code. @@ -792,8 +789,8 @@ BalloonInflate(Balloon *b, // IN *---------------------------------------------------------------------- */ static int -BalloonLockv3(Balloon *b, // IN - uint16 nPages) // IN +BalloonLockBatched(Balloon *b, // IN + uint16 nPages) // IN { int status; uint32 i; @@ -802,8 +799,7 @@ BalloonLockv3(Balloon *b, // IN PPN64 batchPagePPN; BalloonChunk *chunk = NULL; - Balloon_BatchSetNumPages(b->batchPage, nPages); - batchPagePPN = OS_ReservedPageGetPPN(b->pageHandle); + batchPagePPN = PA_2_PPN(OS_ReservedPageGetPA(b->pageHandle)); /* * Make sure that we will always have an available chunk before doing @@ -814,13 +810,13 @@ BalloonLockv3(Balloon *b, // IN if (b->fallbackChunk == NULL) { status = BALLOON_PAGE_ALLOC_FAILURE; } else { - status = Backdoor_MonitorLockPage(b, batchPagePPN); + status = Backdoor_MonitorLockPagesBatched(b, batchPagePPN, nPages); } if (status != BALLOON_SUCCESS) { for (i = 0; i < nPages; i++) { - PPN64 ppn = Balloon_BatchGetPPN(b->batchPage, i); - handle = OS_ReservedPageGetHandle(ppn); + PA64 pa = Balloon_BatchGetPA(b->batchPage, i); + handle = OS_ReservedPageGetHandle(pa); OS_ReservedPageFree(handle); } @@ -830,11 +826,11 @@ BalloonLockv3(Balloon *b, // IN nLockedPages = 0; for (i = 0; i < nPages; i++) { - PPN64 ppn; + PA64 pa; int error; - ppn = Balloon_BatchGetPPN(b->batchPage, i); - handle = OS_ReservedPageGetHandle(ppn); + pa = Balloon_BatchGetPA(b->batchPage, i); + handle = OS_ReservedPageGetHandle(pa); error = Balloon_BatchGetStatus(b->batchPage, i); if (error != BALLOON_SUCCESS) { switch (error) { @@ -885,10 +881,10 @@ out: /* *---------------------------------------------------------------------- * - * BalloonUnlockv3 -- + * BalloonUnlockBatched -- * * Unlock all the batched page, previously stored by - * BalloonAddPagev3. + * BalloonAddPageBatched. * * Results: * BALLOON_SUCCESS or an error code. @@ -899,8 +895,8 @@ out: *---------------------------------------------------------------------- */ static int -BalloonUnlockv3(Balloon *b, // IN - uint16 nPages) // IN +BalloonUnlockBatched(Balloon *b, // IN + uint16 nPages) // IN { uint32 i; int status = BALLOON_SUCCESS; @@ -908,14 +904,13 @@ BalloonUnlockv3(Balloon *b, // IN PPN64 batchPagePPN; BalloonChunk *chunk = NULL; - Balloon_BatchSetNumPages(b->batchPage, nPages); - batchPagePPN = OS_ReservedPageGetPPN(b->pageHandle); - status = Backdoor_MonitorUnlockPage(b, batchPagePPN); + batchPagePPN = PA_2_PPN(OS_ReservedPageGetPA(b->pageHandle)); + status = Backdoor_MonitorUnlockPagesBatched(b, batchPagePPN, nPages); if (status != BALLOON_SUCCESS) { for (i = 0; i < nPages; i++) { - PPN64 ppn = Balloon_BatchGetPPN(b->batchPage, i); - PageHandle handle = OS_ReservedPageGetHandle(ppn); + PA64 pa = Balloon_BatchGetPA(b->batchPage, i); + PageHandle handle = OS_ReservedPageGetHandle(pa); chunk = BalloonGetChunkOrFallback(b); BalloonPageStore(chunk, handle); @@ -926,8 +921,8 @@ BalloonUnlockv3(Balloon *b, // IN nUnlockedPages = 0; for (i = 0; i < nPages; i++) { int status = Balloon_BatchGetStatus(b->batchPage, i); - PPN64 ppn = Balloon_BatchGetPPN(b->batchPage, i); - PageHandle handle = OS_ReservedPageGetHandle(ppn); + PA64 pa = Balloon_BatchGetPA(b->batchPage, i); + PageHandle handle = OS_ReservedPageGetHandle(pa); if (status != BALLOON_SUCCESS) { chunk = BalloonGetChunkOrFallback(b); @@ -954,7 +949,7 @@ out: /* *---------------------------------------------------------------------- * - * BalloonAddPagev3 -- + * BalloonAddPageBatched -- * * Add a page to the batch page, that will be ballooned later. * @@ -968,20 +963,20 @@ out: */ static void -BalloonAddPagev3(Balloon *b, // IN - uint16 idx, // IN - PageHandle page) // IN +BalloonAddPageBatched(Balloon *b, // IN + uint16 idx, // IN + PageHandle page) // IN { - PPN64 ppn = OS_ReservedPageGetPPN(page); - Balloon_BatchSetPPN(b->batchPage, idx, ppn); + PA64 pa = OS_ReservedPageGetPA(page); + Balloon_BatchSetPA(b->batchPage, idx, pa); } /* *---------------------------------------------------------------------- * - * Balloonlockv2 -- + * BalloonLock -- * - * Lock a page, previously stored with a call to BalloonAddPagev2, + * Lock a page, previously stored with a call to BalloonAddPage, * by notifying the monitor. * * Results: @@ -994,8 +989,8 @@ BalloonAddPagev3(Balloon *b, // IN */ static int -BalloonLockv2(Balloon *b, // IN - uint16 nPages) // IN +BalloonLock(Balloon *b, // IN + uint16 nPages) // IN { PPN pagePPN; BalloonChunk *chunk; @@ -1009,7 +1004,7 @@ BalloonLockv2(Balloon *b, // IN } /* inform monitor via backdoor */ - pagePPN = OS_ReservedPageGetPPN(b->pageHandle); + pagePPN = PA_2_PPN(OS_ReservedPageGetPA(b->pageHandle)); status = Backdoor_MonitorLockPage(b, pagePPN); if (status != BALLOON_SUCCESS) { int old_status = status; @@ -1042,10 +1037,10 @@ BalloonLockv2(Balloon *b, // IN /* *---------------------------------------------------------------------- * - * BalloonUnlockv2 -- + * BalloonUnlock -- * * Unlock a page, previously stored with a call to - * BalloonAddPagev2, by notifying the monitor. + * BalloonAddPage, by notifying the monitor. * * Results: * BALLOON_SUCCESS or an error code. @@ -1057,10 +1052,10 @@ BalloonLockv2(Balloon *b, // IN */ static int -BalloonUnlockv2(Balloon *b, // IN - uint16 nPages) // IN +BalloonUnlock(Balloon *b, // IN + uint16 nPages) // IN { - PPN pagePPN = OS_ReservedPageGetPPN(b->pageHandle); + PPN pagePPN = PA_2_PPN(OS_ReservedPageGetPA(b->pageHandle)); int status = Backdoor_MonitorUnlockPage(b, pagePPN); if (status != BALLOON_SUCCESS) { @@ -1083,7 +1078,7 @@ out: /* *---------------------------------------------------------------------- * - * BalloonAddPagev2 -- + * BalloonAddPage -- * * Add a page to be ballooned later. * @@ -1097,9 +1092,9 @@ out: */ static void -BalloonAddPagev2(Balloon *b, // IN - uint16 idx, // IN - PageHandle page) // IN +BalloonAddPage(Balloon *b, // IN + uint16 idx, // IN + PageHandle page) // IN { b->pageHandle = page; } @@ -1288,7 +1283,7 @@ Balloon_Cleanup(void) * Reset connection before deallocating memory to avoid potential for * additional spurious resets from guest touching deallocated pages. */ - Backdoor_MonitorStart(b, BALLOON_PROTOCOL_VERSION); + Backdoor_MonitorStart(b, BALLOON_CAPABILITIES); Balloon_Deallocate(b); } diff --git a/open-vm-tools/modules/shared/vmmemctl/vmballoon.h b/open-vm-tools/modules/shared/vmmemctl/vmballoon.h index c859f4595..c8d5f0ede 100644 --- a/open-vm-tools/modules/shared/vmmemctl/vmballoon.h +++ b/open-vm-tools/modules/shared/vmmemctl/vmballoon.h @@ -160,10 +160,10 @@ typedef struct { /* statistics */ BalloonStats stats; - /* balloon protocol to use */ - uint32 hypervisorProtocolVersion; + /* hypervisor exposed capabilities */ + BalloonCapabilities hypervisorCapabilities; - /* balloon operations, tied to the protocol version */ + /* balloon operations, tied to the capabilities */ const struct BalloonOps *balloonOps; /* Either the batch page handle, or the page to lock on v2 */ diff --git a/open-vm-tools/modules/solaris/vmmemctl/os.c b/open-vm-tools/modules/solaris/vmmemctl/os.c index daf8a617d..93b762263 100644 --- a/open-vm-tools/modules/solaris/vmmemctl/os.c +++ b/open-vm-tools/modules/solaris/vmmemctl/os.c @@ -221,13 +221,13 @@ OS_ReservedPageGetLimit(void) /* *----------------------------------------------------------------------------- * - * OS_ReservedPageGetPPN -- + * OS_ReservedPageGetPA -- * * Convert a page handle (of a physical page previously reserved with - * OS_ReservedPageAlloc()) to a ppn. + * OS_ReservedPageAlloc()) to a pa. * * Results: - * The ppn. + * The pa. * * Side effects: * None. @@ -235,10 +235,10 @@ OS_ReservedPageGetLimit(void) *----------------------------------------------------------------------------- */ -PPN64 -OS_ReservedPageGetPPN(PageHandle handle) // IN: A valid page handle +PA64 +OS_ReservedPageGetPA(PageHandle handle) // IN: A valid page handle { - return page_pptonum(((os_page *)handle)->pp); + return ptob(page_pptonum(((os_page *)handle)->pp)); } @@ -247,7 +247,7 @@ OS_ReservedPageGetPPN(PageHandle handle) // IN: A valid page handle * * OS_ReservedPageGetHandle -- * - * Convert a ppn (of a physical page previously reserved with + * Convert a pa (of a physical page previously reserved with * OS_ReservedPageAlloc()) to a page handle. * * Results: @@ -263,9 +263,9 @@ OS_ReservedPageGetPPN(PageHandle handle) // IN: A valid page handle */ PageHandle -OS_ReservedPageGetHandle(PPN64 ppn) // IN +OS_ReservedPageGetHandle(PA64 pa) // IN { - // Solaris does not use protocol v3. + // Solaris does not use batched commands. NOT_IMPLEMENTED(); } @@ -293,7 +293,7 @@ OS_ReservedPageGetHandle(PPN64 ppn) // IN Mapping OS_MapPageHandle(PageHandle handle) // IN { - // Solaris does not use protocol v3. + // Solaris does not use batched commands. NOT_IMPLEMENTED(); } @@ -321,7 +321,7 @@ OS_MapPageHandle(PageHandle handle) // IN void * OS_Mapping2Addr(Mapping mapping) // IN { - // Solaris does not use protocol v3. + // Solaris does not use batched commands. NOT_IMPLEMENTED(); } @@ -381,7 +381,7 @@ OS_UnmapPage(Mapping mapping) // IN * eliminate some of this. * * Results: - * On success: A valid page handle that can be passed to OS_ReservedPageGetPPN() + * On success: A valid page handle that can be passed to OS_ReservedPageGetPA() * or OS_ReservedPageFree(). * On failure: PAGE_HANDLE_INVALID *