Compare commits
38
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4f6964c1f | ||
|
|
c2ffc6093b | ||
|
|
093dd4fc3c | ||
|
|
b24f99bc14 | ||
|
|
d1c9f72082 | ||
|
|
18c2fe502a | ||
|
|
7329228887 | ||
|
|
9f39254000 | ||
|
|
4f3ac281ee | ||
|
|
5ecf2faaa6 | ||
|
|
48812705d7 | ||
|
|
c43ae31438 | ||
|
|
6a5ae5be25 | ||
|
|
688ba2efb3 | ||
|
|
95fa769616 | ||
|
|
8a9708499f | ||
|
|
aad370a5e2 | ||
|
|
5923003b57 | ||
|
|
f6af9290e7 | ||
|
|
f9b614fbf9 | ||
|
|
b7b47d354b | ||
|
|
1eea8af1f8 | ||
|
|
a11ba8d6c6 | ||
|
|
d907ced352 | ||
|
|
1497314820 | ||
|
|
446f5092d7 | ||
|
|
7af65d06e9 | ||
|
|
b09b058b57 | ||
|
|
383dbae078 | ||
|
|
8a6a4706e7 | ||
|
|
666525a919 | ||
|
|
b5aff64550 | ||
|
|
3635eff81d | ||
|
|
84f16afb1f | ||
|
|
027dd56418 | ||
|
|
0e634ffbf1 | ||
|
|
c62c78e908 | ||
|
|
4f648692e4 |
No files matched your search
+11
-10
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/make -f
|
||||
##########################################################
|
||||
# Copyright (C) 1998-2020 VMware, Inc. All rights reserved.
|
||||
# Copyright (C) 1998-2015 VMware, Inc. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
@@ -84,6 +84,8 @@ endif
|
||||
|
||||
ifneq ($(VM_KBUILD), no)
|
||||
|
||||
VMCCVER := $(shell $(CC) -dumpversion)
|
||||
|
||||
# If there is no version defined, we are in toplevel pass, not yet in kernel makefiles...
|
||||
ifeq ($(VERSION),)
|
||||
|
||||
@@ -98,12 +100,13 @@ auto-build: $(DRIVER_KO)
|
||||
$(DRIVER): $(DRIVER_KO)
|
||||
if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi
|
||||
|
||||
# Use SUBDIRS on 2.x, 3.x, 4.x. Use M on newer kernels.
|
||||
ifeq ($(filter-out 2 3 4,$(firstword $(subst ., ,$(VM_UNAME)))),)
|
||||
DIRVAR := SUBDIRS
|
||||
else
|
||||
DIRVAR := M
|
||||
endif
|
||||
# Pass gcc version down the chain, so we can detect if kernel attempts to use unapproved compiler
|
||||
VM_CCVER := $(VMCCVER)
|
||||
export VM_CCVER
|
||||
VM_CC := $(CC)
|
||||
export VM_CC
|
||||
|
||||
MAKEOVERRIDES := $(filter-out CC=%,$(MAKEOVERRIDES))
|
||||
|
||||
#
|
||||
# Define a setup target that gets built before the actual driver.
|
||||
@@ -114,7 +117,7 @@ prebuild:: ;
|
||||
postbuild:: ;
|
||||
|
||||
$(DRIVER_KO): prebuild
|
||||
$(MAKE) -C $(BUILD_DIR) $(DIRVAR)=$$PWD SRCROOT=$$PWD/$(SRCROOT) \
|
||||
$(MAKE) -C $(BUILD_DIR) M=$$PWD SRCROOT=$$PWD/$(SRCROOT) \
|
||||
MODULEBUILDDIR=$(MODULEBUILDDIR) modules
|
||||
$(MAKE) -C $$PWD SRCROOT=$$PWD/$(SRCROOT) \
|
||||
MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild
|
||||
@@ -136,8 +139,6 @@ ifdef VMX86_DEBUG
|
||||
CC_OPTS += -DVMX86_DEBUG
|
||||
endif
|
||||
|
||||
# Add Spectre options when available
|
||||
|
||||
include $(SRCROOT)/Makefile.kernel
|
||||
|
||||
else
|
||||
|
||||
@@ -24,14 +24,16 @@ INCLUDE := -I$(SRCROOT)/include -I$(SRCROOT)/common -I$(SRCROOT)/linux \
|
||||
|
||||
EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE)
|
||||
|
||||
EXTRA_CFLAGS += $(call vm_check_build, $(SRCROOT)/autoconf/smpcall.c, -DVMW_HAVE_SMP_CALL_3ARG, )
|
||||
EXTRA_CFLAGS += $(call vm_check_build, $(SRCROOT)/autoconf/tsc_khz.c, -DVMW_HAVE_TSC_KHZ, )
|
||||
|
||||
obj-m += $(DRIVER).o
|
||||
|
||||
$(DRIVER)-y := $(subst $(SRCROOT)/, , $(patsubst %.c, %.o, \
|
||||
$(wildcard $(SRCROOT)/linux/*.c $(SRCROOT)/common/*.c $(SRCROOT)/vmcore/*.c \
|
||||
$(SRCROOT)/bootstrap/*.c)))
|
||||
$(wildcard $(SRCROOT)/linux/*.c $(SRCROOT)/common/*.c $(SRCROOT)/vmcore/*.c)))
|
||||
|
||||
clean:
|
||||
rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \
|
||||
rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions .cache.mk \
|
||||
Module.symvers Modules.symvers Module.markers modules.order \
|
||||
$(foreach dir,linux/ common/ vmcore/ bootstrap/ \
|
||||
$(foreach dir,linux/ common/ vmcore/ \
|
||||
./,$(addprefix $(dir),.*.cmd .*.o.flags *.o)))
|
||||
+11
-19
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/make -f
|
||||
##########################################################
|
||||
# Copyright (C) 1998,2015,2017,2020 VMware, Inc. All rights reserved.
|
||||
# Copyright (C) 1998,2015 VMware, Inc. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
@@ -26,7 +26,7 @@ vm_check_build = $(shell if $(CC) $(CC_OPTS) $(INCLUDE) -Werror -S -o /dev/null
|
||||
DESTDIR := driver-$(VM_UNAME)
|
||||
|
||||
####
|
||||
#### DRIVERNAME should be untouched unless you have a good reason to change
|
||||
#### DRIVERNAME should be untouched unless you have a good reason to change
|
||||
#### it. The form below is how the scripts expect it.
|
||||
####
|
||||
DRIVERNAME := $(DRIVER)-xxx-$(VM_UNAME)
|
||||
@@ -49,7 +49,7 @@ endif
|
||||
#### If desparate, I think that bringing in <linux/bitops.h> might
|
||||
#### suffice.
|
||||
####
|
||||
CC_WARNINGS := -Wall -Wstrict-prototypes
|
||||
CC_WARNINGS := -Wall -Wstrict-prototypes
|
||||
# Don't use -pipe or egcs-2.91.66 (shipped with RedHat) will die
|
||||
CC_KFLAGS := -D__KERNEL__ -fno-strength-reduce -fno-omit-frame-pointer \
|
||||
-fno-common -DKBUILD_MODNAME=$(DRIVER)
|
||||
@@ -63,7 +63,7 @@ else
|
||||
CC_KFLAGS += -DCPU=586 $(call check_gcc,-march=i586,-m486)
|
||||
endif
|
||||
|
||||
CC_OPTS := -O2 -DMODULE -DVMMON -DVMCORE $(GLOBAL_DEFS) $(CC_KFLAGS) $(CC_WARNINGS)
|
||||
CC_OPTS := -O2 -DMODULE -DVMMON -DVMCORE $(GLOBAL_DEFS) $(CC_KFLAGS) $(CC_WARNINGS)
|
||||
|
||||
INCLUDE := -I$(SRCROOT)/include -I$(SRCROOT)/common -I$(SRCROOT)/linux \
|
||||
-I$(SRCROOT)/vmcore -I$(HEADER_DIR)
|
||||
@@ -71,16 +71,16 @@ INCLUDE := -I$(SRCROOT)/include -I$(SRCROOT)/common -I$(SRCROOT)/linux \
|
||||
INCLUDE += $(shell $(CC) $(INCLUDE) -E $(SRCROOT)/autoconf/geninclude.c \
|
||||
| sed -n -e 's!^APATH!-I$(HEADER_DIR)/asm!p')
|
||||
|
||||
CC_OPTS += $(call vm_check_build, $(SRCROOT)/autoconf/smpcall.c, -DVMW_HAVE_SMP_CALL_3ARG, )
|
||||
CC_OPTS += $(call vm_check_build, $(SRCROOT)/autoconf/tsc_khz.c, -DVMW_HAVE_TSC_KHZ, )
|
||||
|
||||
C_TARGETS_LINUX := driver.o hostif.o driverLog.o
|
||||
C_TARGETS_COMMON := vmx86.o memtrack.o phystrack.o cpuid.o task.o crosspage.o
|
||||
C_TARGETS_COMMON := vmx86.o memtrack.o phystrack.o cpuid.o task.o hashFunc.o
|
||||
C_TARGETS_VMCORE := moduleloop.o
|
||||
C_TARGETS_BOOTSTRAP := bootstrap.o
|
||||
C_TARGETS_LINUX_D := ${C_TARGETS_LINUX:.o=.d}
|
||||
C_TARGETS_COMMON_D := ${C_TARGETS_COMMON:.o=.d}
|
||||
C_TARGETS_VMCORE_D := ${C_TARGETS_VMCORE:.o=.d}
|
||||
C_TARGETS_BOOTSTRAP_D := ${C_TARGETS_BOOTSTRAP:.o=.d}
|
||||
C_TARGETS := $(C_TARGETS_LINUX) $(C_TARGETS_COMMON) $(C_TARGETS_VMCORE) \
|
||||
$(C_TARGETS_BOOTSTRAP)
|
||||
C_TARGETS := $(C_TARGETS_LINUX) $(C_TARGETS_COMMON) $(C_TARGETS_VMCORE)
|
||||
|
||||
####
|
||||
#### Make Targets are beneath here.
|
||||
@@ -116,10 +116,6 @@ $(C_TARGETS_VMCORE): %.o: $(SRCROOT)/vmcore/%.c
|
||||
$(ECHO) "Compiling vmcore/$(<F)"
|
||||
$(CC) $(CC_OPTS) $(INCLUDE) -c $<
|
||||
|
||||
$(C_TARGETS_BOOTSTRAP): %.o: $(SRCROOT)/bootstrap/%.c
|
||||
$(ECHO) "Compiling bootstrap/$(<F)"
|
||||
$(CC) $(CC_OPTS) $(INCLUDE) -c $<
|
||||
|
||||
clean:
|
||||
rm -rf $(DESTDIR)/
|
||||
|
||||
@@ -135,12 +131,8 @@ $(C_TARGETS_VMCORE_D): %.d: $(SRCROOT)/vmcore/%.c
|
||||
$(ECHO) "Dependencies for $(<F)"
|
||||
$(CC) -MM $(CC_OPTS) $(INCLUDE) $< > $@
|
||||
|
||||
$(C_TARGETS_BOOTSTRAP_D): %.d: $(SRCROOT)/bootstrap/%.c
|
||||
$(ECHO) "Dependencies for $(<F)"
|
||||
$(CC) -MM $(CC_OPTS) $(INCLUDE) $< > $@
|
||||
|
||||
deps: setup
|
||||
$(MAKE) -C $(DESTDIR) -f ../Makefile SRCROOT=../$(SRCROOT) driver_deps
|
||||
deps: setup
|
||||
$(MAKE) -C $(DESTDIR) -f ../Makefile SRCROOT=../$(SRCROOT) driver_deps
|
||||
|
||||
driver_deps: ${C_TARGETS:.o=.d}
|
||||
|
||||
|
||||
+2
-2
@@ -3,11 +3,11 @@ portion of the VMware Virtual Machine Monitor. In order to build, make
|
||||
certain the Makefile is correct, especially in whether or not your system
|
||||
is multi-processor and then just type
|
||||
|
||||
make
|
||||
make
|
||||
|
||||
from this directory. A copy of the module will be left in
|
||||
|
||||
driver-<kernel version>/vmmon.o
|
||||
driver-<kernel version>/vmmon.o
|
||||
|
||||
(e.g. driver-up-2.0.32/vmmon.o).
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2008 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* Detect whether smp_call_function has 4 or 3 arguments.
|
||||
* Change happened between 2.6.26 and 2.6.27-rc1.
|
||||
*/
|
||||
|
||||
#include "compat_version.h"
|
||||
#include "compat_autoconf.h"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
|
||||
# error This compile test intentionally fails.
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
|
||||
# include <linux/smp.h>
|
||||
|
||||
int
|
||||
vmware_smp_call_function(void (*func)(void *info), void *info, int wait)
|
||||
{
|
||||
return smp_call_function(func, info, wait);
|
||||
}
|
||||
#endif
|
||||
@@ -17,37 +17,16 @@
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* bootstrap.c --
|
||||
*
|
||||
* Implements the early VMM bootstraping code that is executed
|
||||
* by the host (vmmon/VMKernel) to create the VMM context.
|
||||
* Detect if tsc_khz is available.
|
||||
*/
|
||||
|
||||
#include "vm_basic_types.h"
|
||||
#include "vm_basic_defs.h"
|
||||
#include "bootstrap_vmm.h"
|
||||
#include "compat_version.h"
|
||||
#include "compat_autoconf.h"
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------
|
||||
*
|
||||
* BSVMM_Validate --
|
||||
*
|
||||
* Validates the VMM bootstrap blob. For now, we do it by checking
|
||||
* the magic number. Returns the bootstrap parameter table if
|
||||
* successful, NULL otherwise.
|
||||
*
|
||||
*---------------------------------------------------------------------
|
||||
*/
|
||||
BSVMM_HostParams *
|
||||
BSVMM_Validate(void *buf, uint32 nbytes)
|
||||
#include <linux/cpu.h>
|
||||
|
||||
int
|
||||
vmw_tsc_khz(void)
|
||||
{
|
||||
BSVMM_HostParams *bsParams = buf;
|
||||
|
||||
if (nbytes < sizeof *bsParams) {
|
||||
return NULL;
|
||||
}
|
||||
if (bsParams->magic != BOOTSTRAP_MAGIC) {
|
||||
return NULL;
|
||||
}
|
||||
return bsParams;
|
||||
return tsc_khz;
|
||||
}
|
||||
@@ -1,963 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2015-2019 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* monLoader.c --
|
||||
*
|
||||
* Processes the monitor loader header.
|
||||
*
|
||||
* See monLoader.h for a full description.
|
||||
*/
|
||||
|
||||
#if defined VMKERNEL
|
||||
|
||||
#include "vmkernel.h"
|
||||
#include "libc.h"
|
||||
#include "vm_libc.h"
|
||||
|
||||
#define UINT_MAX (~0U)
|
||||
|
||||
#elif defined VMMON
|
||||
|
||||
#include "hostKernel.h"
|
||||
|
||||
#ifdef __linux__
|
||||
# include "driver-config.h"
|
||||
# include <linux/string.h>
|
||||
# include <linux/kernel.h>
|
||||
#elif defined __APPLE__
|
||||
# include <machine/limits.h>
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <limits.h>
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#include "vm_assert.h"
|
||||
|
||||
#else /* !defined VMKERNEL && !defined VMMON */
|
||||
#error MonLoader cannot be built as part of this environment
|
||||
#endif
|
||||
|
||||
#include "vm_basic_types.h"
|
||||
#include "monLoader.h"
|
||||
#include "vcpuid.h"
|
||||
#include "vm_pagetable.h"
|
||||
#include "address_defs.h"
|
||||
#include "monLoaderLog.h"
|
||||
|
||||
#define CANONICAL_MASK MASK64(36)
|
||||
/* The index of VPN v within an array of LxEs where index 0 maps VPN b. */
|
||||
#define L4EArrayIdx(b,v) ((unsigned)((((v) - (b)) & CANONICAL_MASK) >> 36))
|
||||
#define L3EArrayIdx(b,v) ((unsigned)((((v) - (b)) & CANONICAL_MASK) >> 27))
|
||||
#define L2EArrayIdx(b,v) ((unsigned)((((v) - (b)) & CANONICAL_MASK) >> 18))
|
||||
#define L1EArrayIdx(b,v) ((unsigned)((((v) - (b)) & CANONICAL_MASK) >> 9))
|
||||
|
||||
/* The maximum (canonical-address) VPN */
|
||||
#define VPN_MAX MASK64(52)
|
||||
|
||||
/* Sufficient MPN counts to accommodate the monitor's top 64MB. */
|
||||
#define L4MPNCOUNTMAX 1
|
||||
#define L3MPNCOUNTMAX 1
|
||||
#define L2MPNCOUNTMAX 1
|
||||
#define L1MPNCOUNTMAX 32
|
||||
|
||||
#define LINE_INVALID ((unsigned)-1)
|
||||
|
||||
typedef struct MonPTMPNs {
|
||||
MPN L4MPNs[L4MPNCOUNTMAX]; /* The page root. Definitely only one page. */
|
||||
MPN L3MPNs[L3MPNCOUNTMAX];
|
||||
MPN L2MPNs[L2MPNCOUNTMAX];
|
||||
MPN L1MPNs[L1MPNCOUNTMAX];
|
||||
unsigned L4MPNCount;
|
||||
unsigned L3MPNCount;
|
||||
unsigned L2MPNCount;
|
||||
unsigned L1MPNCount;
|
||||
} MonPTMPNs;
|
||||
|
||||
typedef struct MonLoaderContext {
|
||||
struct MonLoaderEnvContext *envCtx; /* Environment-specific context */
|
||||
struct {
|
||||
MonPTMPNs ptMPNs; /* Mappings into the AS for the current VCPU. */
|
||||
VPN ASFirstVPN; /* first VPN in the address space */
|
||||
VPN ASLastVPN; /* last VPN in the address space (inclusive) */
|
||||
uint64 ASPTEFlags; /* PTE flags for L4->L1 connection. */
|
||||
Vcpuid currentVCPU;
|
||||
Bool hasAddrSpace;
|
||||
} vcpu;
|
||||
} MonLoaderContext;
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderTranslateMonVPNToL1E --
|
||||
*
|
||||
* Translates a monitor VPN to a level 1 page table entry, for the current
|
||||
* VCPU. Assumes preallocated and connected page tables, so only the L1
|
||||
* table is examined.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK and a PTE if successful, some other value on error. Fails if a
|
||||
* page table page is not already allocated or the VPN is not in the
|
||||
* context's address space's defined range.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderTranslateMonVPNToL1E(MonLoaderContext *ctx, // IN/OUT
|
||||
VPN monVPN, // IN
|
||||
PT_L1E *pte) // OUT
|
||||
{
|
||||
Vcpuid vcpu = ctx->vcpu.currentVCPU;
|
||||
/* Only modify the L1E as L4->L1 are guaranteed connected already. */
|
||||
unsigned L1Off = PT_LPN_2_L1OFF(monVPN);
|
||||
unsigned L1Page = L1EArrayIdx(ctx->vcpu.ASFirstVPN, monVPN);
|
||||
|
||||
if (monVPN < ctx->vcpu.ASFirstVPN || monVPN > ctx->vcpu.ASLastVPN) {
|
||||
return ML_ERROR_INVALID_VPN; /* Address is outside address space. */
|
||||
}
|
||||
if (ctx->vcpu.ptMPNs.L1MPNs[L1Page] == INVALID_MPN) {
|
||||
return ML_ERROR_MAP; /* Page table not sufficiently preallocated. */
|
||||
}
|
||||
if (!MonLoaderCallout_GetPTE(ctx->envCtx, ctx->vcpu.ptMPNs.L1MPNs[L1Page],
|
||||
L1Off, vcpu, pte)) {
|
||||
return ML_ERROR_CALLOUT_GETPTE;
|
||||
}
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderIsMapped --
|
||||
*
|
||||
* Checks whether a VPN has an existing mapping on the current VCPU.
|
||||
* Assumes preallocated and connected page tables.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error. Fails if a page table
|
||||
* page is not already allocated or the VPN is not in the context's
|
||||
* address space's defined range.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderIsMapped(MonLoaderContext *ctx, // IN/OUT
|
||||
VPN monVPN, // IN
|
||||
Bool *mapped) // OUT
|
||||
{
|
||||
PT_L1E pte;
|
||||
MonLoaderError ret = MonLoaderTranslateMonVPNToL1E(ctx, monVPN, &pte);
|
||||
|
||||
if (ret != ML_OK) {
|
||||
return ret;
|
||||
}
|
||||
*mapped = ML_PERM_PRESENT(pte);
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderAllocMPN --
|
||||
*
|
||||
* Allocates a new MPN.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK and an MPN, on success. An error and no MPN on failure.
|
||||
*
|
||||
* Side effects:
|
||||
* An MPN may be allocated.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderAllocMPN(MonLoaderContext *ctx, // IN
|
||||
MPN *mpn) // OUT
|
||||
{
|
||||
*mpn = MonLoaderCallout_AllocMPN(ctx->envCtx, ctx->vcpu.currentVCPU);
|
||||
if (*mpn == INVALID_MPN) {
|
||||
return ML_ERROR_ALLOC;
|
||||
}
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderMapMPN --
|
||||
*
|
||||
* Maps an MPN into the current VCPU's address space at a VPN.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error. Fails if a page table
|
||||
* page is not already allocated or the VPN is not in the context's
|
||||
* address space's defined range.
|
||||
*
|
||||
* Side effects:
|
||||
* An MPN is mapped on success. Nothing on failure.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderMapMPN(MonLoaderContext *ctx, // IN/OUT
|
||||
MPN mpn, // IN
|
||||
uint64 flags, // IN
|
||||
VPN monVPN) // IN
|
||||
{
|
||||
MonPTMPNs *ptMPNs = &ctx->vcpu.ptMPNs;
|
||||
/* Only modify the L1E, as L4->L1 are guaranteed connected already. */
|
||||
unsigned L1Off = PT_LPN_2_L1OFF(monVPN);
|
||||
unsigned L1Page = L1EArrayIdx(ctx->vcpu.ASFirstVPN, monVPN);
|
||||
|
||||
if (vmx86_debug) {
|
||||
MonLoaderError ret;
|
||||
Bool mapped;
|
||||
if (monVPN < ctx->vcpu.ASFirstVPN || monVPN > ctx->vcpu.ASLastVPN) {
|
||||
LOG(5, "%s: monVPN=0x%"FMTVPN"x, AS=0x%"FMTVPN"x-0x%"FMTVPN"x\n",
|
||||
__FUNCTION__, monVPN, ctx->vcpu.ASFirstVPN,
|
||||
ctx->vcpu.ASLastVPN);
|
||||
return ML_ERROR_INVALID_VPN; /* Address is outside address space. */
|
||||
}
|
||||
if (ptMPNs->L1MPNs[L1Page] == INVALID_MPN) {
|
||||
return ML_ERROR_MAP; /* Page table not sufficiently preallocated. */
|
||||
}
|
||||
ret = MonLoaderIsMapped(ctx, monVPN, &mapped);
|
||||
if (ret != ML_OK) {
|
||||
return ret;
|
||||
}
|
||||
if (mapped) {
|
||||
return ML_ERROR_ALREADY_MAPPED;
|
||||
}
|
||||
}
|
||||
if (!MonLoaderCallout_MapMPNInPTE(ctx->envCtx, ptMPNs->L1MPNs[L1Page], L1Off,
|
||||
flags, mpn, ctx->vcpu.currentVCPU)) {
|
||||
return ML_ERROR_CALLOUT_MAPINPTE;
|
||||
}
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderBuildsPtLevel --
|
||||
*
|
||||
* Determines whether MonLoader allocates and maps the page table(s) for
|
||||
* the monitor at the given level.
|
||||
*
|
||||
* Result:
|
||||
* TRUE if MonLoader creates the page table at the given level, FALSE
|
||||
* otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static Bool
|
||||
MonLoaderCreatesPtLevel(PT_Level level)
|
||||
{
|
||||
ASSERT(level >= PT_LEVEL_STOP && level <= PT_MAX_LEVELS);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCreateAddressSpace --
|
||||
*
|
||||
* Creates or verifies an address space. The VPN range specified by
|
||||
* firstVPN and size is used to determine page counts at each page table
|
||||
* level to map every page. Sufficient pages are then allocated or
|
||||
* verified.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error.
|
||||
*
|
||||
* Side effects:
|
||||
* MPNs are allocated if not importing. Sets ctx->vcpu.hasAddrSpace.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderCreateAddressSpace(MonLoaderContext *ctx, // IN/OUT
|
||||
VPN firstVPN, // IN
|
||||
uint64 flags, // IN
|
||||
uint64 monPages) // IN
|
||||
{
|
||||
Vcpuid vcpu = ctx->vcpu.currentVCPU;
|
||||
VPN lastVPN = firstVPN + monPages - 1;
|
||||
unsigned L3MPNsNeeded = L3EArrayIdx(0, lastVPN) -
|
||||
L3EArrayIdx(0, firstVPN) + 1;
|
||||
unsigned L2MPNsNeeded = L2EArrayIdx(0, lastVPN) -
|
||||
L2EArrayIdx(0, firstVPN) + 1;
|
||||
unsigned L1MPNsNeeded = L1EArrayIdx(0, lastVPN) -
|
||||
L1EArrayIdx(0, firstVPN) + 1;
|
||||
unsigned i;
|
||||
MPN mpn;
|
||||
MonPTMPNs *ptMPNs;
|
||||
|
||||
if (vcpu == VCPUID_INVALID) {
|
||||
return ML_ERROR_ARGS;
|
||||
}
|
||||
|
||||
/* Verify MonPTMPNs is large enough for this address space. */
|
||||
if (L3MPNsNeeded > L3MPNCOUNTMAX || L2MPNsNeeded > L2MPNCOUNTMAX ||
|
||||
L1MPNsNeeded > L1MPNCOUNTMAX) {
|
||||
return ML_ERROR_ADDRSPACE_TOO_LARGE;
|
||||
}
|
||||
ctx->vcpu.ASFirstVPN = firstVPN;
|
||||
ctx->vcpu.ASLastVPN = lastVPN;
|
||||
ctx->vcpu.ASPTEFlags = flags;
|
||||
|
||||
ptMPNs = &ctx->vcpu.ptMPNs;
|
||||
|
||||
if (MonLoaderCreatesPtLevel(PT_LEVEL_4)) {
|
||||
NOT_IMPLEMENTED();
|
||||
} else {
|
||||
/* Verify the VMX's allocation. */
|
||||
mpn = MonLoaderCallout_GetPageRoot(ctx->envCtx, vcpu);
|
||||
if (mpn == INVALID_MPN) {
|
||||
return ML_ERROR_CALLOUT_PAGEROOT_GET;
|
||||
}
|
||||
LOG(5, "%s: vcpu %u page root=0x%"FMT64"x\n", __FUNCTION__, vcpu, mpn);
|
||||
ptMPNs->L4MPNs[0] = mpn;
|
||||
MonLoaderCallout_ImportPage(ctx->envCtx, mpn, vcpu);
|
||||
}
|
||||
ptMPNs->L4MPNCount = 1;
|
||||
|
||||
for (i = 0; i < L3MPNsNeeded; i++) {
|
||||
if (MonLoaderCreatesPtLevel(PT_LEVEL_3)) {
|
||||
NOT_IMPLEMENTED();
|
||||
} else {
|
||||
VPN monVPN = firstVPN + i * PT_PAGES_PER_L4E;
|
||||
unsigned L4Off = PT_LPN_2_L4OFF(monVPN);
|
||||
PT_L1E pte;
|
||||
if (!MonLoaderCallout_GetPTE(ctx->envCtx, ptMPNs->L4MPNs[0], L4Off,
|
||||
vcpu, &pte)) {
|
||||
return ML_ERROR_CALLOUT_GETPTE;
|
||||
}
|
||||
LOG(5, "%s: monVPN=0x%"FMTVPN"x: L4E=0x%"FMT64"x\n", __FUNCTION__,
|
||||
monVPN, pte);
|
||||
mpn = ML_PTE_2_PFN(pte);
|
||||
if (mpn == INVALID_MPN || !ML_PERMS_MATCH(pte, flags)) {
|
||||
return ML_ERROR_PAGE_TABLE_IMPORT;
|
||||
}
|
||||
MonLoaderCallout_ImportPage(ctx->envCtx, mpn, vcpu);
|
||||
}
|
||||
ptMPNs->L3MPNs[i] = mpn;
|
||||
}
|
||||
ptMPNs->L3MPNCount = L3MPNsNeeded;
|
||||
|
||||
for (i = 0; i < L2MPNsNeeded; i++) {
|
||||
if (MonLoaderCreatesPtLevel(PT_LEVEL_2)) {
|
||||
NOT_IMPLEMENTED();
|
||||
} else {
|
||||
VPN monVPN = firstVPN + i * PT_PAGES_PER_L3E;
|
||||
unsigned L3Off = PT_LPN_2_L3OFF(monVPN);
|
||||
unsigned L3Page = L3EArrayIdx(ctx->vcpu.ASFirstVPN, monVPN);
|
||||
PT_L1E pte;
|
||||
if (!MonLoaderCallout_GetPTE(ctx->envCtx, ptMPNs->L3MPNs[L3Page],
|
||||
L3Off, vcpu, &pte)) {
|
||||
return ML_ERROR_CALLOUT_GETPTE;
|
||||
}
|
||||
LOG(5, "%s: monVPN=0x%"FMTVPN"x: L3E=0x%"FMT64"x\n", __FUNCTION__,
|
||||
monVPN, pte);
|
||||
mpn = ML_PTE_2_PFN(pte);
|
||||
if (mpn == INVALID_MPN || !ML_PERMS_MATCH(pte, flags)) {
|
||||
return ML_ERROR_PAGE_TABLE_IMPORT;
|
||||
}
|
||||
MonLoaderCallout_ImportPage(ctx->envCtx, mpn, vcpu);
|
||||
}
|
||||
ptMPNs->L2MPNs[i] = mpn;
|
||||
}
|
||||
ptMPNs->L2MPNCount = L2MPNsNeeded;
|
||||
|
||||
for (i = 0; i < L1MPNsNeeded; i++) {
|
||||
if (MonLoaderCreatesPtLevel(PT_LEVEL_1)) {
|
||||
NOT_IMPLEMENTED();
|
||||
} else {
|
||||
VPN monVPN = firstVPN + i * PT_PAGES_PER_L2E;
|
||||
unsigned L2Off = PT_LPN_2_L2OFF(monVPN);
|
||||
unsigned L2Page = L2EArrayIdx(ctx->vcpu.ASFirstVPN, monVPN);
|
||||
PT_L1E pte;
|
||||
if (!MonLoaderCallout_GetPTE(ctx->envCtx, ptMPNs->L2MPNs[L2Page],
|
||||
L2Off, vcpu, &pte)) {
|
||||
return ML_ERROR_CALLOUT_GETPTE;
|
||||
}
|
||||
LOG(5, "%s: monVPN=0x%"FMTVPN"x: L2E=0x%"FMT64"x\n", __FUNCTION__,
|
||||
monVPN, pte);
|
||||
if (!ML_PERM_PRESENT(pte)) {
|
||||
ptMPNs->L1MPNs[i] = INVALID_MPN;
|
||||
continue;
|
||||
}
|
||||
mpn = ML_PTE_2_PFN(pte);
|
||||
if (mpn == INVALID_MPN || !ML_PERMS_MATCH(pte, flags)) {
|
||||
return ML_ERROR_PAGE_TABLE_IMPORT;
|
||||
}
|
||||
MonLoaderCallout_ImportPage(ctx->envCtx, mpn, vcpu);
|
||||
}
|
||||
ptMPNs->L1MPNs[i] = mpn;
|
||||
}
|
||||
ptMPNs->L1MPNCount = L1MPNsNeeded;
|
||||
|
||||
ctx->vcpu.hasAddrSpace = TRUE;
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderMapPageTables --
|
||||
*
|
||||
* Maps in the page tables for the specified level, or verifies that the
|
||||
* existing mappings match internal state and flags if the address space
|
||||
* was imported. Assumes pre-allocated memory at all levels and
|
||||
* pre-connected L4->L1 page tables.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error.
|
||||
*
|
||||
* Side effects:
|
||||
* Page tables are updated if mappings are created.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderMapPageTables(MonLoaderContext *ctx, // IN/OUT
|
||||
PT_Level level, // IN
|
||||
uint64 flags, // IN
|
||||
VPN monVPN, // IN
|
||||
uint64 monPages) // IN
|
||||
{
|
||||
Bool verify = !MonLoaderCreatesPtLevel(level);
|
||||
uint64 i;
|
||||
unsigned count;
|
||||
MPN *ptMPNs;
|
||||
|
||||
if (vmx86_debug) {
|
||||
if (!ctx->vcpu.hasAddrSpace) {
|
||||
return ML_ERROR_NO_ADDRSPACE;
|
||||
}
|
||||
if (level < PT_LEVEL_STOP || level > PT_MAX_LEVELS) {
|
||||
return ML_ERROR_ARGS;
|
||||
}
|
||||
}
|
||||
|
||||
switch (level) {
|
||||
case PT_LEVEL_4:
|
||||
count = ctx->vcpu.ptMPNs.L4MPNCount;
|
||||
ptMPNs = ctx->vcpu.ptMPNs.L4MPNs;
|
||||
break;
|
||||
case PT_LEVEL_3:
|
||||
count = ctx->vcpu.ptMPNs.L3MPNCount;
|
||||
ptMPNs = ctx->vcpu.ptMPNs.L3MPNs;
|
||||
break;
|
||||
case PT_LEVEL_2:
|
||||
count = ctx->vcpu.ptMPNs.L2MPNCount;
|
||||
ptMPNs = ctx->vcpu.ptMPNs.L2MPNs;
|
||||
break;
|
||||
case PT_LEVEL_1:
|
||||
count = ctx->vcpu.ptMPNs.L1MPNCount;
|
||||
ptMPNs = ctx->vcpu.ptMPNs.L1MPNs;
|
||||
break;
|
||||
default:
|
||||
return ML_ERROR_ARGS;
|
||||
break;
|
||||
|
||||
if (monPages != count) {
|
||||
return ML_ERROR_PAGE_TABLE_MAP_SIZE;
|
||||
}
|
||||
|
||||
for (i = 0; i < monPages; i++) {
|
||||
VPN vpn = monVPN + i;
|
||||
if (verify) {
|
||||
PT_L1E l1e;
|
||||
if (ptMPNs[i] == INVALID_MPN && level == PT_LEVEL_1) {
|
||||
continue;
|
||||
}
|
||||
if (MonLoaderTranslateMonVPNToL1E(ctx, vpn, &l1e) != ML_OK ||
|
||||
ML_PTE_2_PFN(l1e) != ptMPNs[i] || !ML_PERMS_MATCH(l1e, flags)) {
|
||||
return ML_ERROR_PAGE_TABLE_VERIFY;
|
||||
}
|
||||
} else {
|
||||
NOT_IMPLEMENTED();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderZero --
|
||||
*
|
||||
* Allocates new pages, zeroes them and maps them on the current VCPU.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error. The number of
|
||||
* MPNs allocated in *allocs is incremented.
|
||||
*
|
||||
* Side effects:
|
||||
* Allocations, zeroing, mapping and accounting are performed.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderZero(MonLoaderContext *ctx, // IN/OUT
|
||||
uint64 flags, // IN
|
||||
VPN monVPN, // IN
|
||||
uint64 numPages, // IN
|
||||
uint64 monPages, // IN
|
||||
unsigned *allocs) // IN/OUT
|
||||
{
|
||||
uint64 i;
|
||||
|
||||
if (numPages == 0 || numPages > monPages) {
|
||||
return ML_ERROR_SIZE;
|
||||
}
|
||||
for (i = 0; i < numPages; i++) {
|
||||
MPN mpn;
|
||||
MonLoaderError ret = MonLoaderAllocMPN(ctx, &mpn);
|
||||
if (ret != ML_OK) {
|
||||
return ret;
|
||||
}
|
||||
if (!MonLoaderCallout_FillPage(ctx->envCtx, 0, mpn,
|
||||
ctx->vcpu.currentVCPU)) {
|
||||
return ML_ERROR_CALLOUT_ZERO;
|
||||
}
|
||||
ret = MonLoaderMapMPN(ctx, mpn, flags, monVPN + i);
|
||||
if (ret != ML_OK) {
|
||||
return ret;
|
||||
}
|
||||
*allocs += 1;
|
||||
}
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCopyFromBlob --
|
||||
*
|
||||
* Allocates new pages, copies blob contents and maps the pages.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error. The number of
|
||||
* MPNs allocated in *allocs is incremented.
|
||||
*
|
||||
* Side effects:
|
||||
* Allocations, copying, mapping and accounting are performed.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderCopyFromBlob(MonLoaderContext *ctx, // IN/OUT
|
||||
uint64 flags, // IN
|
||||
VPN monVPN, // IN
|
||||
uint64 monBytes, // IN
|
||||
uint64 blobOffset, // IN
|
||||
uint64 blobSize, // IN
|
||||
unsigned *allocs) // IN/OUT
|
||||
{
|
||||
uint64 bytesLeft = blobSize;
|
||||
|
||||
if (blobSize > monBytes || blobSize == 0) {
|
||||
return ML_ERROR_SIZE; /* Entry corrupt: size mismatch. */
|
||||
}
|
||||
while (bytesLeft) {
|
||||
MPN mpn;
|
||||
uint64 toCopy = MIN(bytesLeft, PAGE_SIZE);
|
||||
|
||||
MonLoaderError ret = MonLoaderAllocMPN(ctx, &mpn);
|
||||
if (ret != ML_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = MonLoaderMapMPN(ctx, mpn, flags, monVPN);
|
||||
if (ret != ML_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!MonLoaderCallout_CopyFromBlob(ctx->envCtx, blobOffset, toCopy, mpn,
|
||||
ctx->vcpu.currentVCPU)) {
|
||||
return ML_ERROR_CALLOUT_COPY;
|
||||
}
|
||||
|
||||
monVPN++;
|
||||
blobOffset += toCopy;
|
||||
bytesLeft -= toCopy;
|
||||
*allocs += 1;
|
||||
}
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderShareWork --
|
||||
*
|
||||
* Maps user or host pages in. monPages is a maximum, so partial sharing
|
||||
* is considered successful and remaining monitor pages will not be mapped.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error.
|
||||
*
|
||||
* Side effects:
|
||||
* User or host pages may be mapped in.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderShareWork(MonLoaderContext *ctx, // IN/OUT
|
||||
uint64 flags, // IN
|
||||
VPN monVPN, // IN
|
||||
uint64 monPages, // IN
|
||||
uint64 subIndex, // IN
|
||||
Bool user) // IN
|
||||
{
|
||||
Vcpuid vcpu = ctx->vcpu.currentVCPU;
|
||||
uint64 i;
|
||||
|
||||
if (monPages == 0 || monPages > UINT_MAX) {
|
||||
return ML_ERROR_SIZE; /* Entry corrupt: size mismatch. */
|
||||
}
|
||||
for (i = 0; i < monPages; i++) {
|
||||
MPN mpn;
|
||||
MonLoaderError ret;
|
||||
unsigned pgNum = (unsigned)i;
|
||||
|
||||
if (user) {
|
||||
mpn = MonLoaderCallout_GetSharedUserPage(ctx->envCtx, subIndex, pgNum,
|
||||
vcpu);
|
||||
} else {
|
||||
mpn = MonLoaderCallout_GetSharedHostPage(ctx->envCtx, subIndex, pgNum,
|
||||
vcpu);
|
||||
}
|
||||
if (mpn == INVALID_MPN) {
|
||||
if (subIndex == MONLOADER_HT_MAP_IDX) {
|
||||
/*
|
||||
* This item is tied to a vmkernel feature.
|
||||
* When the feature is disabled, there is nothing to share.
|
||||
*/
|
||||
ASSERT(vmx86_server);
|
||||
return ML_OK;
|
||||
}
|
||||
/* Partial sharing is allowed. Return success if any occurred. */
|
||||
return i != 0 ? ML_OK : ML_ERROR_SHARE;
|
||||
}
|
||||
ret = MonLoaderMapMPN(ctx, mpn, flags, monVPN + i);
|
||||
if (ret != ML_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderShareFromUser --
|
||||
*
|
||||
* Maps user pages in. monPages is a maximum, so partial sharing is
|
||||
* considered successful and remaining monitor pages will not be mapped.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error.
|
||||
*
|
||||
* Side effects:
|
||||
* User pages may be mapped in.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderShareFromUser(MonLoaderContext *ctx, // IN/OUT
|
||||
uint64 flags, // IN
|
||||
VPN monVPN, // IN
|
||||
uint64 monPages, // IN
|
||||
uint64 subIndex) // IN
|
||||
{
|
||||
return MonLoaderShareWork(ctx, flags, monVPN, monPages, subIndex, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderShareFromHost --
|
||||
*
|
||||
* Maps host pages in. monPages is a maximum, so partial sharing is
|
||||
* considered successful and remaining monitor pages will not be mapped.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error.
|
||||
*
|
||||
* Side effects:
|
||||
* Host pages may be mapped in.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderShareFromHost(MonLoaderContext *ctx, // IN/OUT
|
||||
uint64 flags, // IN
|
||||
VPN monVPN, // IN
|
||||
uint64 monPages, // IN
|
||||
uint64 subIndex) // IN
|
||||
{
|
||||
return MonLoaderShareWork(ctx, flags, monVPN, monPages, subIndex, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderShareFromBlob --
|
||||
*
|
||||
* Maps blob pages in. monPages is a maximum, so partial sharing is
|
||||
* considered successful and remaining monitor pages will not be
|
||||
* mapped. blobOffset must be page-aligned and blobSize must be a
|
||||
* multiple of PAGE_SIZE. Writeable mappings are not allowed.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error.
|
||||
*
|
||||
* Side effects:
|
||||
* Blob pages may be mapped in.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static MonLoaderError
|
||||
MonLoaderShareFromBlob(MonLoaderContext *ctx, // IN/OUT
|
||||
uint64 flags, // IN
|
||||
VPN monVPN, // IN
|
||||
uint64 monBytes, // IN
|
||||
uint64 blobOffset, // IN
|
||||
uint64 blobSize) // IN
|
||||
{
|
||||
uint64 endOff = blobOffset + blobSize;
|
||||
|
||||
if ((blobOffset & (PAGE_SIZE - 1)) != 0 ||
|
||||
(blobSize & (PAGE_SIZE - 1)) != 0 ||
|
||||
ML_PERM_WRITEABLE(flags)) {
|
||||
return ML_ERROR_SHARE;
|
||||
}
|
||||
if (blobSize > monBytes || blobSize == 0) {
|
||||
return ML_ERROR_SIZE;
|
||||
}
|
||||
while (blobOffset < endOff) {
|
||||
MonLoaderError ret;
|
||||
MPN mpn = MonLoaderCallout_GetBlobMpn(ctx->envCtx, blobOffset);
|
||||
if (mpn == INVALID_MPN) {
|
||||
return ML_ERROR_INVALID_VPN;
|
||||
}
|
||||
ret = MonLoaderMapMPN(ctx, mpn, flags, monVPN);
|
||||
if (ret != ML_OK) {
|
||||
return ret;
|
||||
}
|
||||
blobOffset += PAGE_SIZE;
|
||||
monVPN++;
|
||||
}
|
||||
ASSERT(blobOffset == endOff);
|
||||
return ML_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoader_Process --
|
||||
*
|
||||
* Builds and populates a monitor address space per the given a header and
|
||||
* VCPU count. Calls out to support functions.
|
||||
*
|
||||
* Result:
|
||||
* ML_OK if successful, some other value on error. If an error occurs,
|
||||
* *line contains the line in the table at which the failure occurred and
|
||||
* *vcpu contains the VCPU for which processing was running.
|
||||
*
|
||||
* Side effects:
|
||||
* An address space and page table mappings are created or verified, for
|
||||
* all VCPUs. Callouts are called.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
MonLoaderError
|
||||
MonLoader_Process(MonLoaderHeader *header, // IN/OUT
|
||||
unsigned numVCPUs, // IN
|
||||
void *args, // IN
|
||||
unsigned *line, // OUT
|
||||
Vcpuid *vcpu) // OUT
|
||||
{
|
||||
unsigned i;
|
||||
MonLoaderError ret;
|
||||
MonLoaderContext ctx;
|
||||
|
||||
if (numVCPUs > MAX_VCPUS) {
|
||||
return ML_ERROR_ARGS;
|
||||
}
|
||||
|
||||
if (header->magic != LOADER_HEADER_MAGIC) {
|
||||
return ML_ERROR_MAGIC;
|
||||
}
|
||||
|
||||
if (vmx86_debug && !line) {
|
||||
return ML_ERROR_ARGS;
|
||||
}
|
||||
*line = LINE_INVALID;
|
||||
|
||||
if (header->entries == 0 || header->count == 0) {
|
||||
return ML_ERROR_TABLE_MISSING;
|
||||
}
|
||||
|
||||
if (!MonLoaderCallout_Init(args, &ctx.envCtx, numVCPUs)) {
|
||||
return ML_ERROR_CALLOUT_INIT;
|
||||
}
|
||||
ret = ML_OK;
|
||||
for (*vcpu = 0; *vcpu < numVCPUs && ret == ML_OK; (*vcpu) += 1) {
|
||||
/* Reset VCPU-specific part of context. */
|
||||
memset(&ctx.vcpu, 0, sizeof ctx.vcpu);
|
||||
ctx.vcpu.currentVCPU = *vcpu;
|
||||
ctx.vcpu.hasAddrSpace = FALSE;
|
||||
for (i = 0; i < header->count && ret == ML_OK; i++) {
|
||||
MonLoaderEntry *entry = &header->entries[i];
|
||||
MonLoaderContentType content = entry->content;
|
||||
MonLoaderSourceType source = entry->source;
|
||||
VPN monVPN = entry->monVPN;
|
||||
uint64 blobOffset = entry->blobSrc.offset;
|
||||
uint64 blobSize = entry->blobSrc.size;
|
||||
uint64 flags = entry->flags;
|
||||
uint64 monPages = entry->monPages;
|
||||
uint64 monBytes = PAGES_2_BYTES(monPages);
|
||||
uint64 subIndex = entry->subIndex;
|
||||
uint64 bspOnly = entry->bspOnly;
|
||||
*line = i;
|
||||
|
||||
/*
|
||||
* The entry is specific to the bootstrap, which only runs in VCPU 0.
|
||||
*/
|
||||
if (bspOnly && !IS_BOOT_VCPUID(*vcpu)) {
|
||||
continue;
|
||||
}
|
||||
if (monPages == 0 || monVPN + monPages - 1 > VPN_MAX) {
|
||||
ret = ML_ERROR_SIZE;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (content) {
|
||||
case ML_CONTENT_ADDRSPACE:
|
||||
if (ctx.vcpu.hasAddrSpace) {
|
||||
ret = ML_ERROR_DUPLICATE;
|
||||
continue;
|
||||
}
|
||||
/* Create or verify the address space and page table MPNs. */
|
||||
ret = MonLoaderCreateAddressSpace(&ctx, monVPN, flags, monPages);
|
||||
break;
|
||||
case ML_CONTENT_PAGETABLE_L4:
|
||||
case ML_CONTENT_PAGETABLE_L3:
|
||||
case ML_CONTENT_PAGETABLE_L2:
|
||||
case ML_CONTENT_PAGETABLE_L1:
|
||||
/* Create or verify page table mappings. */
|
||||
ret = MonLoaderMapPageTables(&ctx, CONTENT_TO_PTLEVEL(content),
|
||||
flags, monVPN, monPages);
|
||||
break;
|
||||
case ML_CONTENT_ALLOCZERO: {
|
||||
uint64 numPages;
|
||||
if (source == ML_SOURCE_NONE) {
|
||||
numPages = monPages;
|
||||
} else if (source == ML_SOURCE_BLOB) {
|
||||
/*
|
||||
* Used for loading the uninitialized data section
|
||||
* (.bss), which has a blob size but no blob image
|
||||
* associated with it.
|
||||
*/
|
||||
numPages = CEILING(blobSize, PAGE_SIZE);
|
||||
} else {
|
||||
ret = ML_ERROR_SOURCE_INVALID;
|
||||
break;
|
||||
}
|
||||
ret = MonLoaderZero(&ctx, flags, monVPN, numPages, monPages,
|
||||
&entry->allocs);
|
||||
break;
|
||||
}
|
||||
case ML_CONTENT_COPY:
|
||||
switch (source) {
|
||||
case ML_SOURCE_BLOB:
|
||||
ret = MonLoaderCopyFromBlob(&ctx, flags, monVPN, monBytes,
|
||||
blobOffset, blobSize,
|
||||
&entry->allocs);
|
||||
break;
|
||||
default:
|
||||
ret = ML_ERROR_SOURCE_INVALID;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ML_CONTENT_SHARE:
|
||||
switch (source) {
|
||||
case ML_SOURCE_USER:
|
||||
ret = MonLoaderShareFromUser(&ctx, flags, monVPN,
|
||||
monPages, subIndex);
|
||||
break;
|
||||
case ML_SOURCE_HOST:
|
||||
ret = MonLoaderShareFromHost(&ctx, flags, monVPN,
|
||||
monPages, subIndex);
|
||||
break;
|
||||
case ML_SOURCE_BLOB:
|
||||
ret = MonLoaderShareFromBlob(&ctx, flags, monVPN,
|
||||
monBytes, blobOffset,
|
||||
blobSize);
|
||||
break;
|
||||
default:
|
||||
ret = ML_ERROR_SOURCE_INVALID;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ML_CONTENT_INVALID:
|
||||
default:
|
||||
ret = ML_ERROR_CONTENT_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef VMKERNEL
|
||||
if (ret == ML_OK) {
|
||||
if (ctx.vcpu.ASLastVPN == 0) {
|
||||
ret = ML_ERROR_NO_ADDRSPACE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
MonLoaderCallout_CleanUp(ctx.envCtx);
|
||||
return ret;
|
||||
}
|
||||
@@ -1,514 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2016-2020 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* monLoaderVmmon.c --
|
||||
*
|
||||
* vmmon implementation of the MonLoader callouts.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
# include "driver-config.h"
|
||||
# include <linux/string.h>
|
||||
#else
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#include "vm_assert.h"
|
||||
#include "vcpuid.h"
|
||||
#include "x86types.h"
|
||||
#include "hostif.h"
|
||||
#include "x86paging_common.h"
|
||||
#include "x86paging_64.h"
|
||||
#include "vmx86.h"
|
||||
#include "monLoader.h"
|
||||
#include "monLoaderLog.h"
|
||||
#include "vmmblob.h"
|
||||
#include "memtrack.h"
|
||||
|
||||
typedef struct MonLoaderEnvContext {
|
||||
VMDriver *vm;
|
||||
VMSharedRegion *shRegions;
|
||||
} MonLoaderEnvContext;
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_Init --
|
||||
*
|
||||
* Initializes platform-specific MonLoader context.
|
||||
*
|
||||
* Returns:
|
||||
* TRUE if successful, FALSE if not.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
MonLoaderCallout_Init(void *args, MonLoaderEnvContext **ctx, unsigned numVCPUs)
|
||||
{
|
||||
MonLoaderEnvContext *c;
|
||||
MonLoaderArgs *mlArgs = (MonLoaderArgs *)args;
|
||||
|
||||
c = HostIF_AllocKernelMem(sizeof *c, FALSE);
|
||||
if (c == NULL) {
|
||||
Log("Failed to allocate memory for MonLoader context\n");
|
||||
return FALSE;
|
||||
}
|
||||
memset(c, 0, sizeof *c);
|
||||
c->vm = mlArgs->vm;
|
||||
c->shRegions = mlArgs->shRegions;
|
||||
|
||||
*ctx = c;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_Cleanup --
|
||||
*
|
||||
* Cleans up platform-specific MonLoader context.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
MonLoaderCallout_CleanUp(MonLoaderEnvContext *ctx)
|
||||
{
|
||||
ASSERT(ctx != NULL);
|
||||
Vmx86_CleanupVMMPages(ctx->vm);
|
||||
HostIF_FreeKernelMem(ctx);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_GetPageRoot --
|
||||
*
|
||||
* Gets the page root MPN for a VCPU.
|
||||
*
|
||||
* Returns:
|
||||
* An MPN, or INVALID_MPN in case of error.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
MPN
|
||||
MonLoaderCallout_GetPageRoot(MonLoaderEnvContext *ctx, // IN
|
||||
Vcpuid vcpu) // IN
|
||||
{
|
||||
VMDriver *vm = ctx->vm;
|
||||
|
||||
if (vcpu >= vm->numVCPUs) {
|
||||
return INVALID_MPN;
|
||||
}
|
||||
return vm->ptRootMpns[vcpu];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_GetPTE --
|
||||
*
|
||||
* Gets the page table entry at index idx in a page table MPN.
|
||||
*
|
||||
* Returns:
|
||||
* TRUE and sets *pte on success. FALSE otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
MonLoaderCallout_GetPTE(MonLoaderEnvContext *ctx, // IN
|
||||
MPN ptMPN, // IN
|
||||
unsigned idx, // IN
|
||||
Vcpuid vcpu, // IN
|
||||
PT_L1E *pte) // OUT
|
||||
{
|
||||
VMDriver *vm = ctx->vm;
|
||||
MA pteMA = MPN_2_MA(ptMPN) + idx * sizeof *pte;
|
||||
|
||||
ASSERT(idx < (PAGE_SIZE / sizeof *pte));
|
||||
if (HostIF_ReadPhysical(vm, pteMA, PtrToVA64(pte), TRUE, sizeof *pte) != 0) {
|
||||
Log("Failed to read PTE %d from MPN %"FMT64"x\n", idx, ptMPN);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
Bool
|
||||
MonLoaderCallout_ImportPage(MonLoaderEnvContext *ctx, // IN
|
||||
MPN mpn, // IN
|
||||
Vcpuid vcpu) // IN
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_AllocMPN --
|
||||
*
|
||||
* Allocates and maps a new VMM page for the specified VCPU.
|
||||
*
|
||||
* Returns:
|
||||
* An MPN on success, INVALID_MPN on failure.
|
||||
*
|
||||
* Side effects:
|
||||
* The allocated page is accounted for and its mapping tracked.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MPN
|
||||
MonLoaderCallout_AllocMPN(MonLoaderEnvContext *ctx, // IN
|
||||
Vcpuid vcpu) // IN
|
||||
{
|
||||
VMDriver *vm = ctx->vm;
|
||||
MemTrackEntry *entry;
|
||||
MPN mpn;
|
||||
VPN vpn;
|
||||
|
||||
if (Vmx86_AllocLockedPages(vm, (VA64)&mpn, 1, TRUE, FALSE) != 1) {
|
||||
Log("Failed to allocate page\n");
|
||||
return INVALID_MPN;
|
||||
}
|
||||
vpn = Vmx86_MapPage(mpn);
|
||||
if (vpn == 0) {
|
||||
Log("Failed to map MPN 0x%"FMT64"x\n", mpn);
|
||||
Vmx86_FreeLockedPages(vm, &mpn, 1);
|
||||
return INVALID_MPN;
|
||||
}
|
||||
HostIF_VMLock(vm, 41);
|
||||
entry = MemTrack_Add(vm->vmmTracker, vpn, mpn);
|
||||
HostIF_VMUnlock(vm, 41);
|
||||
if (entry == NULL) {
|
||||
Log("Failed to track mapping from VPN 0x%"FMTVPN"x to MPN 0x%"FMT64"x\n",
|
||||
vpn, mpn);
|
||||
Vmx86_UnmapPage(vpn);
|
||||
Vmx86_FreeLockedPages(vm, &mpn, 1);
|
||||
return INVALID_MPN;
|
||||
}
|
||||
return mpn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_MapMPNInPTE --
|
||||
*
|
||||
* Maps an MPN into a page table at the specified index.
|
||||
*
|
||||
* Returns:
|
||||
* TRUE on success, FALSE on failure.
|
||||
*
|
||||
* Side effects:
|
||||
* A mapping is created.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
MonLoaderCallout_MapMPNInPTE(MonLoaderEnvContext *ctx, // IN
|
||||
MPN ptMPN, // IN
|
||||
unsigned idx, // IN
|
||||
uint64 flags, // IN
|
||||
MPN mpn, // IN
|
||||
Vcpuid vcpu) // IN
|
||||
{
|
||||
VMDriver *vm = ctx->vm;
|
||||
PT_L1E pte = LM_MAKE_PTE(mpn, 0, flags);
|
||||
MA pteMA = MPN_2_MA(ptMPN) + idx * sizeof pte;
|
||||
|
||||
ASSERT(idx < (PAGE_SIZE / sizeof pte));
|
||||
if (HostIF_WritePhysical(vm, pteMA, PtrToVA64(&pte), TRUE, sizeof pte) !=
|
||||
0) {
|
||||
Warning("Failed to map MPN %"FMT64"x\n", mpn);
|
||||
return FALSE;
|
||||
}
|
||||
LOG(5, "MonLoader mapped MPN %"FMT64"x at PT index %u for VCPU %u\n",
|
||||
mpn, idx, vcpu);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_FillPage --
|
||||
*
|
||||
* Fills a page with a pattern, given the MPN of the page.
|
||||
*
|
||||
* Returns:
|
||||
* TRUE on success, FALSE if a mapping of the page was not found or
|
||||
* invalid.
|
||||
*
|
||||
* Side effects:
|
||||
* The page is filled.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
MonLoaderCallout_FillPage(MonLoaderEnvContext *ctx, // IN
|
||||
uint8 pattern, // IN
|
||||
MPN mpn, // IN
|
||||
Vcpuid vcpu) // IN
|
||||
{
|
||||
VMDriver *vm = ctx->vm;
|
||||
MemTrackEntry *entry;
|
||||
|
||||
HostIF_VMLock(vm, 42);
|
||||
entry = MemTrack_LookupMPN(vm->vmmTracker, mpn);
|
||||
HostIF_VMUnlock(vm, 42);
|
||||
if (entry == NULL || entry->mpn != mpn || entry->vpn == 0) {
|
||||
Log("Failed to look up MPN 0x%"FMT64"x\n", mpn);
|
||||
return FALSE;
|
||||
}
|
||||
memset((void *)VPN_2_VA(entry->vpn), pattern, PAGE_SIZE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_CopyFromBlob --
|
||||
*
|
||||
* Copies contents of up to PAGE_SIZE length from the blob at a
|
||||
* given offset into the page specified by the given MPN. Zero-fills
|
||||
* the remaining space.
|
||||
*
|
||||
* Returns:
|
||||
* TRUE on success, FALSE on failure.
|
||||
*
|
||||
* Side effects:
|
||||
* The page is filled with blob contents.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
MonLoaderCallout_CopyFromBlob(MonLoaderEnvContext *ctx, // IN
|
||||
uint64 blobOffset, // IN
|
||||
size_t copySize, // IN
|
||||
MPN mpn, // IN
|
||||
Vcpuid vcpu) // IN
|
||||
{
|
||||
MemTrackEntry *entry;
|
||||
VMDriver *vm = ctx->vm;
|
||||
uint64 blobSize = VmmBlob_GetSize(vm);
|
||||
uint8 *blob = VmmBlob_GetPtr(vm);
|
||||
uint8 *buf;
|
||||
|
||||
if (copySize > PAGE_SIZE || copySize == 0 || blobSize < copySize ||
|
||||
blobOffset > blobSize - copySize) {
|
||||
Log("Invalid VMM blob copy parameters: blobOffset 0x%"FMT64"x, "
|
||||
"copySize 0x%"FMTSZ"x, blobSize 0x%"FMT64"x\n", blobOffset, copySize,
|
||||
blobSize);
|
||||
return FALSE;
|
||||
}
|
||||
HostIF_VMLock(vm, 44);
|
||||
entry = MemTrack_LookupMPN(vm->vmmTracker, mpn);
|
||||
HostIF_VMUnlock(vm, 44);
|
||||
if (entry == NULL || entry->vpn == 0) {
|
||||
Log("Failed to look up MPN 0x%"FMT64"x\n", mpn);
|
||||
return FALSE;
|
||||
}
|
||||
buf = (uint8 *)VPN_2_VA(entry->vpn);
|
||||
memcpy(buf, blob + blobOffset, copySize);
|
||||
memset(buf + copySize, 0, PAGE_SIZE - copySize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderFindSharedRegion --
|
||||
*
|
||||
* Searches the shared region table for the given index and returns
|
||||
* the corresponding descriptor.
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to the shared region descriptor or NULL if not found.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static VMSharedRegion *
|
||||
MonLoaderFindSharedRegion(MonLoaderEnvContext *ctx,
|
||||
uint64 index)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ML_SHARED_REGIONS_MAX; i++) {
|
||||
if (ctx->shRegions[i].index == index &&
|
||||
ctx->shRegions[i].baseVpn != INVALID_VPN) {
|
||||
return &ctx->shRegions[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderGetSharedRegionMPN --
|
||||
*
|
||||
* Gets shared page's MPN. Assumes vcpuid == 0 for the bootstrap.
|
||||
*
|
||||
* Returns:
|
||||
* An MPN or INVALID_MPN.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static MPN
|
||||
MonLoaderGetSharedRegionMPN(MonLoaderEnvContext *ctx,
|
||||
uint64 index,
|
||||
Vcpuid vcpuid,
|
||||
unsigned pgOffset)
|
||||
{
|
||||
VMSharedRegion *s;
|
||||
VA addr;
|
||||
MPN mpn;
|
||||
|
||||
ASSERT(IS_BOOT_VCPUID(vcpuid));
|
||||
|
||||
s = MonLoaderFindSharedRegion(ctx, index);
|
||||
if (s == NULL) {
|
||||
return INVALID_MPN;
|
||||
}
|
||||
if (pgOffset >= s->numPages) {
|
||||
return INVALID_MPN;
|
||||
}
|
||||
addr = VPN_2_VA(s->baseVpn) + pgOffset * PAGE_SIZE;
|
||||
HostIF_VMLock(ctx->vm, 43);
|
||||
if (HostIF_LookupUserMPN(ctx->vm, addr, &mpn) != PAGE_LOOKUP_SUCCESS) {
|
||||
HostIF_VMUnlock(ctx->vm, 43);
|
||||
Log("Failed to lookup MPN for shared region VA %"FMTVA"x\n", addr);
|
||||
return INVALID_MPN;
|
||||
}
|
||||
HostIF_VMUnlock(ctx->vm, 43);
|
||||
return mpn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_GetSharedUserPage --
|
||||
*
|
||||
* Gets a shared page's MPN for a VCPU.
|
||||
*
|
||||
* Returns:
|
||||
* An MPN or INVALID_MPN.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MPN
|
||||
MonLoaderCallout_GetSharedUserPage(MonLoaderEnvContext *ctx, // IN
|
||||
uint64 subIndex, // IN
|
||||
unsigned page, // IN
|
||||
Vcpuid vcpu) // IN
|
||||
{
|
||||
if (subIndex == MONLOADER_HEADER_IDX) {
|
||||
return VmmBlob_GetHeaderMpn(ctx->vm);
|
||||
} else {
|
||||
return MonLoaderGetSharedRegionMPN(ctx, subIndex, vcpu, page);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MPN
|
||||
MonLoaderCallout_GetSharedHostPage(MonLoaderEnvContext *ctx, // IN
|
||||
uint64 subIndex, // IN
|
||||
unsigned page, // IN
|
||||
Vcpuid vcpu) // IN
|
||||
{
|
||||
switch (subIndex) {
|
||||
case MONLOADER_CROSS_PAGE_DATA_IDX:
|
||||
return HostIF_GetCrossPageDataMPN(ctx->vm->crosspage[vcpu]);
|
||||
case MONLOADER_CROSS_PAGE_CODE_IDX:
|
||||
return HostIF_GetCrossPageCodeMPN();
|
||||
default:
|
||||
return MonLoaderGetSharedRegionMPN(ctx, subIndex, vcpu, page);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoaderCallout_GetBlobMpn --
|
||||
*
|
||||
* Returns the MPN backing the given VMM blob offset.
|
||||
*
|
||||
* Returns:
|
||||
* An MPN, or INVALID_MPN
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MPN
|
||||
MonLoaderCallout_GetBlobMpn(MonLoaderEnvContext *ctx, // IN
|
||||
uint64 offset) // IN
|
||||
{
|
||||
ASSERT((offset & (PAGE_SIZE - 1)) == 0);
|
||||
return VmmBlob_GetMpn(ctx->vm, BYTES_2_PAGES(offset));
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2017-2019 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* vmmblob.c --
|
||||
*
|
||||
* VMM blob management.
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
# include "driver-config.h"
|
||||
#endif
|
||||
#include "vmware.h"
|
||||
#include "vm_assert.h"
|
||||
#include "hostif.h"
|
||||
#include "vmmblob.h"
|
||||
#include "monLoader.h"
|
||||
|
||||
#define VMMBLOB_SIZE_MAX (22 * 1024 * 1024) /* Ensure enough space for
|
||||
* obj build with * GCOV_VMM=1. */
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VmmBlob_GetPtr --
|
||||
*
|
||||
* Returns a pointer to the buffer containing the VMM blob.
|
||||
*
|
||||
* Results:
|
||||
* A pointer.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
uint8 *
|
||||
VmmBlob_GetPtr(VMDriver *vm)
|
||||
{
|
||||
return vm->blobInfo->blobPtr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VmmBlob_GetSize --
|
||||
*
|
||||
* Returns the size of the VMM blob in bytes.
|
||||
*
|
||||
* Results:
|
||||
* Number of bytes.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
uint64
|
||||
VmmBlob_GetSize(VMDriver *vm)
|
||||
{
|
||||
return vm->blobInfo->numBytes;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VmmBlob_GetMpn --
|
||||
*
|
||||
* Returns the MPN backing a VMM blob page.
|
||||
*
|
||||
* Results:
|
||||
* An MPN, or INVALID_MPN.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MPN
|
||||
VmmBlob_GetMpn(VMDriver *vm, uint64 pgOffset)
|
||||
{
|
||||
VmmBlobInfo *bi = vm->blobInfo;
|
||||
uint32 blobNumPages = CEILING(bi->numBytes, PAGE_SIZE);
|
||||
MPN mpn = INVALID_MPN;
|
||||
|
||||
if (pgOffset < blobNumPages) {
|
||||
mpn = bi->mpns[pgOffset];
|
||||
}
|
||||
return mpn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VmmBlob_GetHeaderMpn --
|
||||
*
|
||||
* Returns the MPN backing the MonLoader header.
|
||||
*
|
||||
* Results:
|
||||
* An MPN, or INVALID_MPN.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MPN
|
||||
VmmBlob_GetHeaderMpn(VMDriver *vm)
|
||||
{
|
||||
VmmBlobInfo *bi = vm->blobInfo;
|
||||
uint64 headerOffset = (uint8 *)bi->header - (uint8 *)bi->blobPtr;
|
||||
ASSERT((headerOffset & (PAGE_SIZE - 1)) == 0);
|
||||
return VmmBlob_GetMpn(vm, BYTES_2_PAGES(headerOffset));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VmmBlob_Cleanup --
|
||||
*
|
||||
* Cleans up VMM blob state by freeing its memory and associated
|
||||
* metadata.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
VmmBlob_Cleanup(VmmBlobInfo *bi)
|
||||
{
|
||||
const uint32 numPages = CEILING(bi->numBytes, PAGE_SIZE);
|
||||
|
||||
HostIF_FreeKernelPages(numPages, bi->blobPtr);
|
||||
HostIF_FreeKernelMem(bi->mpns);
|
||||
HostIF_FreeKernelMem(bi);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VmmBlob_Load --
|
||||
*
|
||||
* Copies and instantiates a VMM bootstrap blob from userspace.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if successful, FALSE if not.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
VmmBlob_Load(UserVA64 blobAddr,
|
||||
uint32 numBytes,
|
||||
uint32 headerOffset,
|
||||
VmmBlobInfo **blobInfo)
|
||||
{
|
||||
uint8 *blob = NULL;
|
||||
MPN *mpns = NULL;
|
||||
MonLoaderHeader *header;
|
||||
VmmBlobInfo *bi = NULL;
|
||||
uint32 numPages = CEILING(numBytes, PAGE_SIZE);
|
||||
size_t fixedHdrSize = MonLoader_GetFixedHeaderSize();
|
||||
|
||||
if (numBytes > VMMBLOB_SIZE_MAX || headerOffset > numBytes ||
|
||||
fixedHdrSize > numBytes - headerOffset) {
|
||||
Warning("Invalid arguments for processing bootstrap. "
|
||||
"Header offset: %u, Fixed header size: %"FMTSZ"u bytes, "
|
||||
"Blob size: %u bytes\n", headerOffset, fixedHdrSize, numBytes);
|
||||
goto error;
|
||||
}
|
||||
mpns = HostIF_AllocKernelMem(numPages * sizeof(*mpns), FALSE);
|
||||
if (mpns == NULL) {
|
||||
Warning("Memory allocation for VMM bootstrap blob failed\n");
|
||||
goto error;
|
||||
}
|
||||
bi = HostIF_AllocKernelMem(sizeof *bi, FALSE);
|
||||
if (bi == NULL) {
|
||||
Warning("Memory allocation for VMM bootstrap blob failed\n");
|
||||
goto error;
|
||||
}
|
||||
blob = HostIF_AllocKernelPages(numPages, mpns);
|
||||
if (blob == NULL) {
|
||||
Warning("Memory allocation for VMM bootstrap blob failed\n");
|
||||
goto error;
|
||||
}
|
||||
if (HostIF_CopyFromUser(blob, blobAddr, numBytes) != 0) {
|
||||
Warning("Error copying VMM bootstrap blob from userspace\n");
|
||||
goto error;
|
||||
}
|
||||
header = (MonLoaderHeader *)(blob + headerOffset);
|
||||
if (header->count > (numBytes - headerOffset - fixedHdrSize) /
|
||||
sizeof (MonLoaderEntry)) {
|
||||
Warning("Invalid arguments for processing bootstrap. "
|
||||
"Header offset: %u, Number of header entries: %u, "
|
||||
"Blob size: %u bytes\n", headerOffset, header->count, numBytes);
|
||||
goto error;
|
||||
}
|
||||
bi->mpns = mpns;
|
||||
bi->blobPtr = blob;
|
||||
bi->numBytes = numBytes;
|
||||
bi->header = header;
|
||||
*blobInfo = bi;
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
if (blob != NULL) {
|
||||
HostIF_FreeKernelPages(numPages, blob);
|
||||
}
|
||||
if (bi != NULL) {
|
||||
HostIF_FreeKernelMem(bi);
|
||||
}
|
||||
if (mpns != NULL) {
|
||||
HostIF_FreeKernelMem(mpns);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
+17
-16
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2011, 2016, 2018 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2011 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -17,8 +17,7 @@
|
||||
*********************************************************/
|
||||
|
||||
#include "vmware.h"
|
||||
#include "x86apic.h"
|
||||
#include "x86msr.h"
|
||||
#include "hostif.h"
|
||||
#include "x86cpuid_asm.h"
|
||||
#include "vm_asm.h"
|
||||
#include "cpuid.h"
|
||||
@@ -57,7 +56,7 @@ APIC_GetMA(void)
|
||||
|
||||
if (cpuVendor != CPUID_VENDOR_INTEL &&
|
||||
cpuVendor != CPUID_VENDOR_AMD &&
|
||||
cpuVendor != CPUID_VENDOR_HYGON) {
|
||||
cpuVendor != CPUID_VENDOR_VIA) {
|
||||
return (MA)-1;
|
||||
}
|
||||
|
||||
@@ -65,7 +64,7 @@ APIC_GetMA(void)
|
||||
* Check if X2 APIC mode is enabled.
|
||||
*/
|
||||
|
||||
if ((X86MSR_GetMSR(MSR_APIC_BASE) & APIC_MSR_X2APIC_ENABLED) != 0) {
|
||||
if ((__GET_MSR(MSR_APIC_BASE) & APIC_MSR_X2APIC_ENABLED) != 0) {
|
||||
return (MA)-1;
|
||||
}
|
||||
|
||||
@@ -75,16 +74,18 @@ APIC_GetMA(void)
|
||||
*/
|
||||
|
||||
// Mask out goo in the low 12 bits, which is unrelated to the address.
|
||||
result = X86MSR_GetMSR(MSR_APIC_BASE) & ~MASK64(PAGE_SHIFT);
|
||||
result = __GET_MSR(MSR_APIC_BASE) & ~MASK64(PAGE_SHIFT);
|
||||
|
||||
/*
|
||||
* On Intel, the high bits are reserved so we mask.
|
||||
* On AMD and Hygon, high bits are explicitly MBZ, so no need.
|
||||
* On AMD, high bits are explicitly MBZ, so no need.
|
||||
* Via doesn't specify, so we'll assume reserved.
|
||||
*/
|
||||
if (cpuVendor == CPUID_VENDOR_INTEL) {
|
||||
if (cpuVendor == CPUID_VENDOR_INTEL || cpuVendor == CPUID_VENDOR_VIA) {
|
||||
/*
|
||||
* Intel suggests using CPUID 0x80000008.eax[7-0] (physical
|
||||
* address size), with 36 (24 bit MPNs) as a fallback.
|
||||
* Via has that cpuid leaf as well.
|
||||
*/
|
||||
unsigned numPhysicalBits = 36;
|
||||
|
||||
@@ -122,7 +123,7 @@ APIC_Read(const APICDescriptor *desc, // IN
|
||||
int regNum) // IN
|
||||
{
|
||||
if (desc->isX2) {
|
||||
return (uint32)X86MSR_GetMSR(MSR_X2APIC_BASE + regNum);
|
||||
return (uint32 )__GET_MSR(MSR_X2APIC_BASE + regNum);
|
||||
} else {
|
||||
return desc->base[regNum][0];
|
||||
}
|
||||
@@ -164,7 +165,7 @@ APIC_ReadID(const APICDescriptor *desc) // IN
|
||||
*
|
||||
* APIC_Write --
|
||||
*
|
||||
* Writes the given value to the given APIC register using the proper
|
||||
* Writes the given value to the given APIC register using the proper
|
||||
* interface. Does not check to see if the register number is valid.
|
||||
*
|
||||
* Side effects:
|
||||
@@ -182,7 +183,7 @@ APIC_Write(const APICDescriptor *desc, // IN
|
||||
uint32 val) // IN
|
||||
{
|
||||
if (desc->isX2) {
|
||||
X86MSR_SetMSR(MSR_X2APIC_BASE + regNum, val);
|
||||
__SET_MSR(MSR_X2APIC_BASE + regNum, val);
|
||||
} else {
|
||||
desc->base[regNum][0] = val;
|
||||
}
|
||||
@@ -194,7 +195,7 @@ APIC_Write(const APICDescriptor *desc, // IN
|
||||
*
|
||||
* APIC_ReadICR --
|
||||
*
|
||||
* Reads the APIC ICR using the proper interface. The semantics of the
|
||||
* Reads the APIC ICR using the proper interface. The semantics of the
|
||||
* ICR are different in X2APIC mode so APIC_Read() should not be used.
|
||||
*
|
||||
* Side effects:
|
||||
@@ -206,11 +207,11 @@ APIC_Write(const APICDescriptor *desc, // IN
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
uint64
|
||||
uint64
|
||||
APIC_ReadICR(const APICDescriptor *desc) // IN
|
||||
{
|
||||
if (desc->isX2) {
|
||||
return X86MSR_GetMSR(MSR_X2APIC_BASE + APICR_ICRLO);
|
||||
return __GET_MSR(MSR_X2APIC_BASE + APICR_ICRLO);
|
||||
} else {
|
||||
uint32 icrHi = desc->base[APICR_ICRHI][0];
|
||||
uint32 icrLo = desc->base[APICR_ICRLO][0];
|
||||
@@ -224,7 +225,7 @@ APIC_ReadICR(const APICDescriptor *desc) // IN
|
||||
*
|
||||
* APIC_WriteICR --
|
||||
*
|
||||
* Writes the given value to the APIC ICR using the proper interface.
|
||||
* Writes the given value to the APIC ICR using the proper interface.
|
||||
* The semantics of the ICR are different in X2APIC mode so APIC_Write()
|
||||
* should not be used.
|
||||
*
|
||||
@@ -244,7 +245,7 @@ APIC_WriteICR(const APICDescriptor *desc, // IN
|
||||
{
|
||||
if (desc->isX2) {
|
||||
uint64 icr = (uint64) id << 32 | icrLo;
|
||||
X86MSR_SetMSR(MSR_X2APIC_BASE + APICR_ICRLO, icr);
|
||||
__SET_MSR(MSR_X2APIC_BASE + APICR_ICRLO, icr);
|
||||
} else {
|
||||
ASSERT(!(id & ~(APIC_ICRHI_DEST_MASK >> APIC_ICRHI_DEST_OFFSET)));
|
||||
desc->base[APICR_ICRHI][0] = id << APIC_ICRHI_DEST_OFFSET;
|
||||
|
||||
@@ -19,20 +19,20 @@
|
||||
/*
|
||||
* comport.c --
|
||||
*
|
||||
* Simple COM1 port routines for debugging code that can't do any real
|
||||
* Simple COM1 port routines for debugging code that can't do any real
|
||||
* host IO, such as the worldswitch and related.
|
||||
*
|
||||
* They all wait for the last character to complete transmission so if the
|
||||
* system crashes immediately on return, the last character will be seen
|
||||
* They all wait for the last character to complete transmission so if the
|
||||
* system crashes immediately on return, the last character will be seen
|
||||
* by the remote end.
|
||||
*
|
||||
* These routines do not have any external dependencies so can be called
|
||||
* These routines do not have any external dependencies so can be called
|
||||
* by any code that has privilege to access IO ports.
|
||||
*
|
||||
* Under Windows, they can be made to forward output to DbgPrint for
|
||||
* printing via the debugger. Just have USE_DBGPRINT set to 1. If you
|
||||
* let USE_DBGPRINT be 0 with Windows, make sure the comport hardware is
|
||||
* powered-up by leaving Hyperterm running with the comport open, else
|
||||
* Under Windows, they can be made to forward output to DbgPrint for
|
||||
* printing via the debugger. Just have USE_DBGPRINT set to 1. If you
|
||||
* let USE_DBGPRINT be 0 with Windows, make sure the comport hardware is
|
||||
* powered-up by leaving Hyperterm running with the comport open, else
|
||||
* Windows will power the chip down.
|
||||
*/
|
||||
|
||||
|
||||
+107
-24
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998, 2016-2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998,2018 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef linux
|
||||
/* Must come before any kernel header file --hpreg */
|
||||
# include "driver-config.h"
|
||||
|
||||
@@ -31,16 +31,11 @@
|
||||
#include "hostif.h"
|
||||
#include "cpuid.h"
|
||||
#include "x86cpuid_asm.h"
|
||||
#include "x86svm.h"
|
||||
#include "x86vt.h"
|
||||
|
||||
uint32 cpuidFeatures;
|
||||
CpuidVendor cpuidVendor = CPUID_NUM_VENDORS;
|
||||
uint32 cpuidVersion;
|
||||
Bool hostSupportsVT;
|
||||
Bool hostSupportsSVM;
|
||||
Bool hostHasSpecCtrl;
|
||||
Bool hostSupportsXSave;
|
||||
uint32 cpuidFeatures;
|
||||
static CpuidVendor vendor = CPUID_NUM_VENDORS;
|
||||
static uint32 version;
|
||||
static Bool hasSpecCtrl;
|
||||
|
||||
|
||||
/*
|
||||
@@ -83,9 +78,8 @@ CPUID_Init(void)
|
||||
char name[16];
|
||||
|
||||
__GET_CPUID(1, ®s);
|
||||
cpuidVersion = regs.eax;
|
||||
version = regs.eax;
|
||||
cpuidFeatures = regs.edx;
|
||||
hostSupportsXSave = CPUID_ISSET(1, ECX, XSAVE, regs.ecx);
|
||||
|
||||
__GET_CPUID(0, ®s);
|
||||
ptr = (uint32 *)name;
|
||||
@@ -95,25 +89,91 @@ CPUID_Init(void)
|
||||
ptr[3] = 0;
|
||||
|
||||
if (strcmp(name, CPUID_INTEL_VENDOR_STRING_FIXED) == 0) {
|
||||
cpuidVendor = CPUID_VENDOR_INTEL;
|
||||
vendor = CPUID_VENDOR_INTEL;
|
||||
} else if (strcmp(name, CPUID_AMD_VENDOR_STRING_FIXED) == 0) {
|
||||
cpuidVendor = CPUID_VENDOR_AMD;
|
||||
vendor = CPUID_VENDOR_AMD;
|
||||
} else if (strcmp(name, CPUID_CYRIX_VENDOR_STRING_FIXED) == 0) {
|
||||
cpuidVendor = CPUID_VENDOR_CYRIX;
|
||||
} else if (strcmp(name, CPUID_HYGON_VENDOR_STRING_FIXED) == 0) {
|
||||
cpuidVendor = CPUID_VENDOR_HYGON;
|
||||
vendor = CPUID_VENDOR_CYRIX;
|
||||
} else {
|
||||
Warning("VMMON CPUID: Unrecognized CPU\n");
|
||||
cpuidVendor = CPUID_VENDOR_UNKNOWN;
|
||||
vendor = CPUID_VENDOR_UNKNOWN;
|
||||
}
|
||||
|
||||
__GET_CPUID2(7, 0, ®s);
|
||||
hostHasSpecCtrl = cpuidVendor == CPUID_VENDOR_INTEL &&
|
||||
(CPUID_ISSET(7, EDX, IBRSIBPB, regs.edx) ||
|
||||
CPUID_ISSET(7, EDX, STIBP, regs.edx));
|
||||
hasSpecCtrl = vendor == CPUID_VENDOR_INTEL && ((regs.edx >> 26) & 0x3) != 0;
|
||||
}
|
||||
|
||||
hostSupportsVT = VT_CapableCPU();
|
||||
hostSupportsSVM = SVM_CapableCPU();
|
||||
|
||||
CpuidVendor
|
||||
CPUID_GetVendor(void)
|
||||
{
|
||||
ASSERT(vendor != CPUID_NUM_VENDORS);
|
||||
return vendor;
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
CPUID_GetVersion(void)
|
||||
{
|
||||
ASSERT(vendor != CPUID_NUM_VENDORS);
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* CPUID_SyscallSupported --
|
||||
*
|
||||
* Determine whether processor supports syscall opcode and MSRs.
|
||||
*
|
||||
* Results:
|
||||
* FALSE if processor does not support syscall
|
||||
* TRUE if processor supports syscall
|
||||
*
|
||||
* Side effects:
|
||||
* It determines value only on first call, caching it for future.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
CPUID_SyscallSupported(void)
|
||||
{
|
||||
/*
|
||||
* It is OK to use local static variables here as 'result' does not depend
|
||||
* on any work done in CPUID_Init(). It purely depends on the CPU.
|
||||
*/
|
||||
static Bool initialized = FALSE;
|
||||
static Bool result;
|
||||
|
||||
if (UNLIKELY(!initialized)) {
|
||||
result = CPUIDExtendedSupported() >= 0x80000001
|
||||
&& (__GET_EDX_FROM_CPUID(0x80000001) & (1 << 11));
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Bool
|
||||
CPUID_LongModeSupported(void)
|
||||
{
|
||||
/*
|
||||
* It is OK to use local static variables here as 'result' does not depend
|
||||
* on any work done in CPUID_Init(). It purely depends on the CPU.
|
||||
*/
|
||||
static Bool initialized = FALSE;
|
||||
static Bool result;
|
||||
|
||||
if (UNLIKELY(!initialized)) {
|
||||
result = CPUIDExtendedSupported() >= 0x80000001
|
||||
&& (__GET_EDX_FROM_CPUID(0x80000001) & (1 << 29));
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,3 +211,26 @@ CPUID_AddressSizeSupported(void)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* CPUID_HostSupportsSpecCtrl --
|
||||
*
|
||||
* Determine whether the processor supports MSR_SPEC_CTRL.
|
||||
*
|
||||
* Results:
|
||||
* True iff the processor supports the required features.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
CPUID_HostSupportsSpecCtrl(void)
|
||||
{
|
||||
return hasSpecCtrl;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998, 2016-2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998,2016,2018 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -31,66 +31,22 @@
|
||||
|
||||
#include "x86cpuid.h"
|
||||
|
||||
extern uint32 cpuidFeatures;
|
||||
extern uint32 cpuidVersion;
|
||||
extern CpuidVendor cpuidVendor;
|
||||
extern Bool hostSupportsVT;
|
||||
extern Bool hostSupportsSVM;
|
||||
extern Bool hostHasSpecCtrl;
|
||||
extern Bool hostSupportsXSave;
|
||||
extern uint32 cpuidFeatures;
|
||||
|
||||
void CPUID_Init(void);
|
||||
CpuidVendor CPUID_GetVendor(void);
|
||||
uint32 CPUID_GetVersion(void);
|
||||
Bool CPUID_SyscallSupported(void);
|
||||
Bool CPUID_LongModeSupported(void);
|
||||
Bool CPUID_AddressSizeSupported(void);
|
||||
Bool CPUID_HostSupportsSpecCtrl(void);
|
||||
|
||||
static INLINE uint32
|
||||
static INLINE uint32
|
||||
CPUID_GetFeatures(void)
|
||||
{
|
||||
return cpuidFeatures;
|
||||
}
|
||||
|
||||
static INLINE CpuidVendor
|
||||
CPUID_GetVendor(void)
|
||||
{
|
||||
ASSERT(cpuidVendor != CPUID_NUM_VENDORS);
|
||||
return cpuidVendor;
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
CPUID_GetVersion(void)
|
||||
{
|
||||
return cpuidVersion;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
CPUID_HostSupportsVT(void)
|
||||
{
|
||||
return hostSupportsVT;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
CPUID_HostSupportsSVM(void)
|
||||
{
|
||||
return hostSupportsSVM;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
CPUID_HostSupportsHV(void)
|
||||
{
|
||||
return hostSupportsVT || hostSupportsSVM;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
CPUID_HostSupportsSpecCtrl(void)
|
||||
{
|
||||
return hostHasSpecCtrl;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
CPUID_HostSupportsXSave(void)
|
||||
{
|
||||
return hostSupportsXSave;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
CPUID_SSE2Supported(void)
|
||||
{
|
||||
@@ -98,3 +54,4 @@ CPUID_SSE2Supported(void)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,609 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2016-2020 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* crosspage.c --
|
||||
*
|
||||
* Cross page code and data.
|
||||
*
|
||||
* The cross code page contains world switch code and interrupt/exception
|
||||
* handlers in support of world switch. A separate data page is also mapped
|
||||
* in both the vmm and vmmon address spaces to describe the host and monitor
|
||||
* state.
|
||||
*
|
||||
* Both the monitor and the vmmon driver call into the cross page to switch
|
||||
* worlds. The world switch from host->vmm is able to refer directly to the
|
||||
* various symbols defined in CrossPage_CodePage. On the vmm->host path
|
||||
* the VmmToHost entry point is stored in the data page. Data references
|
||||
* must be handled as offsets from the base of the data page.
|
||||
*
|
||||
* Use of inline assembly in C code is delicate as the compiler has many
|
||||
* possible reasons to emit unexpected instructions surrounding any assembly
|
||||
* in a C function. Frame pointers are inconvenient to disable on a per-file
|
||||
* basis given structure of the Linux Makefile so they are being emitted
|
||||
* in the C wrapper function. NORETURN and NOT_REACHED_MINIMAL are used to
|
||||
* omit a function epilogue. The output/clobber lists of the assembly blocks
|
||||
* are not used as the compiler needs not compensate for the register use of
|
||||
* these hand-written assembly functions.
|
||||
* Each assembly function begins with a label denoting the proper entry point
|
||||
* for that function. Only a handful of the functions need to be exported
|
||||
* out of this file, see crosspage.h.
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
# include "driver-config.h"
|
||||
# if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||
# include <linux/objtool.h>
|
||||
# elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)
|
||||
# include <linux/frame.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "modulecall.h"
|
||||
#include "iocontrols.h"
|
||||
#include "segs.h"
|
||||
#include "x86_basic_defs.h"
|
||||
#include "vm_basic_defs.h"
|
||||
#include "vm_idt_x86.h"
|
||||
#include "crosspage.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
/*
|
||||
* The Mac compiler expects symbols to have a _ prefix.
|
||||
* This arranges for any symbol being exported out of the assembly code
|
||||
* to be accessible.
|
||||
*/
|
||||
#define ASM_PREFIX "_"
|
||||
/*
|
||||
* OSX uses a segment,section style syntax for specifying output sections.
|
||||
* https://developer.apple.com/library/archive/documentation/Performance/
|
||||
* Conceptual/CodeFootprint/Articles/MachOOverview.html
|
||||
*/
|
||||
#define ASM_SECTION "__TEXT,cross"
|
||||
#else
|
||||
/*
|
||||
* This is a COFF grouped section identifier. This ensures the crosspage code
|
||||
* is merged with the normal .text area but as a separate unit so it can have
|
||||
* its own alignment properties.
|
||||
* https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
*
|
||||
* The Linux build will handle the section based on its contents (code).
|
||||
*/
|
||||
#define ASM_SECTION ".text$cross"
|
||||
#define ASM_PREFIX
|
||||
#endif
|
||||
|
||||
#define EXPORTED_ASM_SYMBOL(fn) ".global " ASM_PREFIX #fn "\n" \
|
||||
ASM_PREFIX #fn ":\n"
|
||||
|
||||
/*
|
||||
* Tag the crosspage code C wrapper with the crosspage section and page
|
||||
* alignment.
|
||||
*/
|
||||
#define CPCODE __attribute__((section(ASM_SECTION))) \
|
||||
__attribute__((aligned(PAGE_SIZE)))
|
||||
|
||||
/* No special handling is needed for the data. */
|
||||
#define CPDATA
|
||||
|
||||
#define VMMDATALA(off) (LPN_2_LA(CROSS_PAGE_DATA_START) + (off))
|
||||
|
||||
#define NOT_REACHED_MINIMAL __builtin_unreachable
|
||||
|
||||
#ifdef ANNOTATE_INTRA_FUNCTION_CALL
|
||||
#define ANNOTATE_ASM_CALL_STR2(x) #x
|
||||
#define ANNOTATE_ASM_CALL_STR(x) ANNOTATE_ASM_CALL_STR2(x) "\n"
|
||||
#define ANNOTATE_ASM_CALL ANNOTATE_ASM_CALL_STR(ANNOTATE_INTRA_FUNCTION_CALL)
|
||||
#else
|
||||
#define ANNOTATE_ASM_CALL
|
||||
#endif
|
||||
|
||||
void VmmToHost(void);
|
||||
|
||||
CPDATA const VMCrossPageData cpDataTemplate = {
|
||||
.version = CROSSPAGE_VERSION,
|
||||
.vmmonVersion = VMMON_VERSION,
|
||||
|
||||
.monRSP = VMM_LRET_STACK_TOP,
|
||||
.monSS = SYSTEM_DATA_SELECTOR,
|
||||
.monDS = SYSTEM_DATA_SELECTOR,
|
||||
.monES = SYSTEM_DATA_SELECTOR,
|
||||
|
||||
.vmmToHostLA = (VA)VmmToHost,
|
||||
.wsCR0 = CR0_PE | CR0_MP | CR0_EM | CR0_NE | CR0_WP | CR0_PG,
|
||||
.wsCR4 = CR4_PAE | CR4_OSFXSR,
|
||||
|
||||
.monTask.rsp[0] = VMM_STACK_TOP, /* Monitor stack. */
|
||||
.monTask.rsp[1] = VPN_2_VA(VMM_STACK_GUARD_START), /* CPL1 is not used. */
|
||||
.monTask.rsp[2] = VPN_2_VA(VMM_STACK_GUARD_START), /* CPL2 is not used. */
|
||||
|
||||
.monTask.ist[IST_NONE] = 0, /* No stack switch. */
|
||||
.monTask.ist[IST_VMM_DF] = DF_STACK_TOP,
|
||||
.monTask.ist[IST_VMM_NMI] = NMI_STACK_TOP,
|
||||
.monTask.ist[IST_VMM_MCE] = MC_STACK_TOP,
|
||||
|
||||
.monTask.IOMapBase = sizeof(Task64),
|
||||
|
||||
.monGDTR.limit = GDT_LIMIT,
|
||||
.monGDTR.offset = GDT_START_VA,
|
||||
|
||||
.shadowDR[6].ureg64 = DR6_DEFAULT,
|
||||
.shadowDR[7].ureg64 = DR7_ONES,
|
||||
|
||||
/*
|
||||
* switchHostIDT and switchHostIDTR are initialized in vmmon.
|
||||
* switchMonIDTR is static and can be fully initialized at compile-time.
|
||||
* switchMonIDT is mostly static with all non-present entries except for
|
||||
* the 4 handled exceptions which are populated by the crosspage setup
|
||||
* code in task.c
|
||||
*/
|
||||
.switchMonIDTR = { sizeof(Gate64) * NUM_EXCEPTIONS - 1,
|
||||
VMMDATALA(offsetof(VMCrossPageData, switchMonIDT)) },
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* CrossPage_CodePage --
|
||||
*
|
||||
* This function only serves as an anchor and wrapper for the code that
|
||||
* runs in the world switch's cross page. The function must not be called
|
||||
* directly. Its address may be used to locate the cross page code.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
CPCODE void
|
||||
CrossPage_CodePage(void)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* SwitchDBHandler --
|
||||
*
|
||||
* DB handler that operates during worldswitch (in both directions).
|
||||
*
|
||||
* This handler is expected to be used in two cases:
|
||||
* 1) If the host kernel has set the DR7_GD (guard) bit, when switch
|
||||
* code attempts to save debug registers, a #DB will be thrown. In
|
||||
* this case, the handler sets wsException[EXC_DB] and returns.
|
||||
* 2) When stress-testing the worldswitch code, RFLAGS.TF is set across
|
||||
* most switch paths. This causes a #DB to be thrown before each
|
||||
* instruction is executed. In this case, the handler must set
|
||||
* RFLAGS.RF in the return frame to guarantee progress while
|
||||
* RFLAGS.TF is set. For added stress, the handler induces a
|
||||
* simulated #NMI.
|
||||
*
|
||||
* In case (1), returning is accomplished via a simulated iret in order
|
||||
* to preserve any NMI-blocking. In case (2), the inherent
|
||||
* incompatibility of RFLAGS.RF for single-stepping and simulating an
|
||||
* iret via popf and lretq necessitates the use of an actual iret. As
|
||||
* a result, there is no strong NMI-blocking guarantee when
|
||||
* stress-testing the switch path.
|
||||
*
|
||||
* Input:
|
||||
*
|
||||
* 0(%rsp) = previous RIP
|
||||
* 8(%rsp) = previous CS
|
||||
* 16(%rsp) = previous RFLAGS
|
||||
* 24(%rsp) = previous RSP
|
||||
* 32(%rsp) = previous SS
|
||||
*
|
||||
* Output:
|
||||
*
|
||||
* wsException[EXC_DB] = TRUE
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
".p2align 4\n"
|
||||
EXPORTED_ASM_SYMBOL(SwitchDBHandler)
|
||||
"pushq %%rax\n"
|
||||
ANNOTATE_ASM_CALL
|
||||
"call SwitchExcGetCrossPageData\n"
|
||||
"addq %[wsExceptionDB], %%rax\n"
|
||||
"movb $1, (%%rax)\n" /* log EXC_DB */
|
||||
"popq %%rax\n"
|
||||
"testl %[EFLAGS_TF], 16(%%rsp)\n" /* check trap flag */
|
||||
"jz return_without_enabling_nmi\n"
|
||||
"orl %[EFLAGS_RF], 16(%%rsp)\n"
|
||||
"int $2\n"
|
||||
"iretq\n"
|
||||
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* SwitchUDHandler --
|
||||
*
|
||||
* UD handler that operates during worldswitch (in both directions).
|
||||
*
|
||||
* It sets the wsException[EXC_UD] flag then returns.
|
||||
*
|
||||
* Input:
|
||||
*
|
||||
* 0(%rsp) = previous RIP
|
||||
* 8(%rsp) = previous CS
|
||||
* 16(%rsp) = previous RFLAGS
|
||||
* 24(%rsp) = previous RSP
|
||||
* 32(%rsp) = previous SS
|
||||
*
|
||||
* Output:
|
||||
*
|
||||
* wsException[EXC_UD] = TRUE
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
".p2align 4\n"
|
||||
EXPORTED_ASM_SYMBOL(SwitchUDHandler)
|
||||
"pushq %%rax\n"
|
||||
"pushq %%rbx\n"
|
||||
"pushq %%rcx\n"
|
||||
ANNOTATE_ASM_CALL
|
||||
"call SwitchExcGetCrossPageData\n"
|
||||
"movl %[wsExceptionUD], %%ecx\n" /* log EXC_UD */
|
||||
"movb $1, (%%rax, %%rcx)\n"
|
||||
/* Check if the exception came from a monitor RIP. */
|
||||
"cmpq %[MONITOR_MINIMUM_VA], 24(%%rsp)\n"
|
||||
"jae monitor_context\n"
|
||||
/* Check if the exception came from the crosspage code. */
|
||||
"movq 24(%%rsp), %%rbx\n"
|
||||
"andq %[PageAlignMask], %%rbx\n"
|
||||
"movl %[crosspageCodeLA], %%ecx\n"
|
||||
"cmpq (%%rax, %%rcx), %%rbx\n"
|
||||
"je monitor_context\n"
|
||||
/*
|
||||
* Linux halts the processor on host #UD2. Act similarly. PR 1281662.
|
||||
* Note that this can escape due to an #NMI, #MC, or #DB.
|
||||
*/
|
||||
"cli\n"
|
||||
"hlt\n"
|
||||
/* Advance 2 bytes to skip past the #UD2 instruction. */
|
||||
"monitor_context:\n"
|
||||
"movq 24(%%rsp), %%rbx\n"
|
||||
"movl %[wsUD2], %%ecx\n"
|
||||
"movq %%rbx, (%%rax, %%rcx)\n"
|
||||
"addq $2, 24(%%rsp)\n"
|
||||
"popq %%rcx\n"
|
||||
"popq %%rbx\n"
|
||||
"popq %%rax\n"
|
||||
"jmp return_without_enabling_nmi\n"
|
||||
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* SwitchNMIHandler --
|
||||
*
|
||||
* NMI handler that operates during worldswitch (in both
|
||||
* directions).
|
||||
*
|
||||
* It 'simply' sets the wsException[EXC_NMI] flag then returns,
|
||||
* leaving further NMI delivery inhibited.
|
||||
*
|
||||
* As long as we don't execute 'iret', the CPU will not allow further
|
||||
* NMIs to be delivered; this is how the CPU protects itself from
|
||||
* runaway NMIs eating up the stack and triple-faulting.
|
||||
*
|
||||
* See Vol 3, 5.5.1, Handling multiple NMIs.
|
||||
*
|
||||
* Input:
|
||||
*
|
||||
* 0(%rsp) = previous RIP
|
||||
* 8(%rsp) = previous CS
|
||||
* 16(%rsp) = previous RFLAGS
|
||||
* 24(%rsp) = previous RSP
|
||||
* 32(%rsp) = previous SS
|
||||
*
|
||||
* Output:
|
||||
*
|
||||
* wsException[EXC_NMI] = TRUE
|
||||
* further NMI delivery inhibited
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
".p2align 4\n"
|
||||
EXPORTED_ASM_SYMBOL(SwitchNMIHandler)
|
||||
"pushq %%rax\n"
|
||||
ANNOTATE_ASM_CALL
|
||||
"call SwitchExcGetCrossPageData\n"
|
||||
"addq %[wsExceptionNMI], %%rax\n"
|
||||
"movb $1, (%%rax)\n" /* log EXC_NMI */
|
||||
"popq %%rax\n"
|
||||
"jmp return_without_enabling_nmi\n"
|
||||
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* SwitchMCEHandler --
|
||||
*
|
||||
* MCE handler that operates during worldswitch (in both
|
||||
* directions).
|
||||
*
|
||||
* It simply sets the wsException[EXC_MC] flag then returns.
|
||||
*
|
||||
* Input:
|
||||
*
|
||||
* 0(%rsp) = previous RIP
|
||||
* 8(%rsp) = previous CS
|
||||
* 16(%rsp) = previous RFLAGS
|
||||
* 24(%rsp) = previous RSP
|
||||
* 32(%rsp) = previous SS
|
||||
*
|
||||
* Output:
|
||||
*
|
||||
* wsException[EXC_MC] = TRUE
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
".p2align 4\n"
|
||||
EXPORTED_ASM_SYMBOL(SwitchMCEHandler)
|
||||
"pushq %%rax\n"
|
||||
ANNOTATE_ASM_CALL
|
||||
"call SwitchExcGetCrossPageData\n"
|
||||
"addq %[wsExceptionMC], %%rax\n"
|
||||
"movb $1, (%%rax)\n" /* log EXC_MC */
|
||||
"popq %%rax\n"
|
||||
"jmp return_without_enabling_nmi\n"
|
||||
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* SwitchHandlerReturns --
|
||||
*
|
||||
* Shared code to return without enabling NMIs. Switch handlers call
|
||||
* directly to these labels as needed.
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
".p2align 4\n"
|
||||
"return_without_enabling_nmi:\n"
|
||||
"pushq %%rbp\n"
|
||||
"pushq %%rax\n"
|
||||
"movq 40(%%rsp), %%rbp\n"
|
||||
"subq $32, %%rbp\n"
|
||||
"movq 24(%%rsp), %%rax\n"
|
||||
"movq %%rax, 24(%%rbp)\n"
|
||||
"movq 16(%%rsp), %%rax\n"
|
||||
"movq %%rax, 16(%%rbp)\n"
|
||||
"movq 32(%%rsp), %%rax\n"
|
||||
"movq %%rax, 8(%%rbp)\n"
|
||||
"movq 8(%%rsp), %%rax\n"
|
||||
"movq %%rax, (%%rbp)\n"
|
||||
"popq %%rax\n"
|
||||
"movq %%rbp, %%rsp\n"
|
||||
"popq %%rbp\n"
|
||||
"popfq\n"
|
||||
"lretq\n"
|
||||
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* HostToVmm --
|
||||
*
|
||||
* Switch from host to monitor.
|
||||
*
|
||||
* Entered with:
|
||||
* RCX = crosspage host address
|
||||
* (RSP) = return to host address
|
||||
*
|
||||
* Must preserve:
|
||||
* RBX, RSI, RDI, RBP, RSP, R12..R15
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
".p2align 4\n"
|
||||
EXPORTED_ASM_SYMBOL(HostToVmm)
|
||||
/* Create an lret frame on the host stack. */
|
||||
"pushq (%%rsp)\n"
|
||||
"mov %%cs, 8(%%rsp)\n"
|
||||
"movq %%rsp, %%rax\n" /* Temporarily hold host %rsp */
|
||||
|
||||
/* Start from the "empty" host context and save. */
|
||||
"leaq %c[hostContextEmpty](%%rcx), %%rsp\n"
|
||||
/* Note that only %ss is stored, not %ds/%es. */
|
||||
"movw %%ss, %%dx\n"
|
||||
"pushw %%dx\n"
|
||||
"pushq %%rax\n" /* host %rsp */
|
||||
"pushq %%r15\n"
|
||||
"pushq %%r14\n"
|
||||
"pushq %%r13\n"
|
||||
"pushq %%r12\n"
|
||||
"pushq %%rdi\n"
|
||||
"pushq %%rsi\n"
|
||||
"pushq %%rbp\n"
|
||||
"pushq %%rbx\n"
|
||||
"movq %%cr3, %%rax\n"
|
||||
"pushq %%rax\n"
|
||||
|
||||
/* Start from the "full" monitor context and load. */
|
||||
"leaq %c[monContextFull](%%rcx), %%rsp\n"
|
||||
"popq %%rsi\n" /* monitor %cr3 */
|
||||
"popq %%rbx\n"
|
||||
"popq %%rbp\n"
|
||||
"popq %%r12\n"
|
||||
"popq %%r13\n"
|
||||
"popq %%r14\n"
|
||||
"popq %%r15\n"
|
||||
"popq %%rax\n" /* monitor %rsp */
|
||||
"popw %%dx\n" /* monitor %ss */
|
||||
/* Load the cross GDT before reloading segments, %cr3 */
|
||||
"lgdtq %c[crossGDTHKLADesc](%%rcx)\n"
|
||||
/* Load %cr3 last to flush the TLB after all stack ops. */
|
||||
"movq %%rsi, %%cr3\n"
|
||||
/* Reload the monitor's %ss into %ds/%es. */
|
||||
"movw %%dx, %%ds\n"
|
||||
"movw %%dx, %%es\n"
|
||||
"movw %%dx, %%ss\n"
|
||||
"movq %%rax, %%rsp\n"
|
||||
|
||||
"lretq\n"
|
||||
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* VmmToHost --
|
||||
*
|
||||
* Switch from monitor to host.
|
||||
*
|
||||
* Must preserve:
|
||||
* RBX, RBP, RSP, R12..R15
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
".p2align 4\n"
|
||||
EXPORTED_ASM_SYMBOL(VmmToHost)
|
||||
"movq %c[VMMCROSSPAGE] + %c[crosspageDataLA], %%rcx\n"
|
||||
/* Create an lret frame on the monitor stack. */
|
||||
"pushq (%%rsp)\n"
|
||||
"mov %%cs, 8(%%rsp)\n"
|
||||
"movq %%rsp, %%rax\n" /* Temporarily hold monitor %rsp */
|
||||
|
||||
/* Start from the "empty" monitor context and save. */
|
||||
"leaq %c[VMMCROSSPAGE] + %c[monContextEmpty], %%rsp\n"
|
||||
/* Note that only %ss is stored, not %ds/%es. */
|
||||
"movw %%ss, %%dx\n"
|
||||
"pushw %%dx\n"
|
||||
"pushq %%rax\n" /* monitor %rsp */
|
||||
"pushq %%r15\n"
|
||||
"pushq %%r14\n"
|
||||
"pushq %%r13\n"
|
||||
"pushq %%r12\n"
|
||||
"pushq %%rbp\n"
|
||||
"pushq %%rbx\n"
|
||||
"movq %%cr3, %%rax\n"
|
||||
"pushq %%rax\n"
|
||||
|
||||
/* Start from the "full" host context and load. */
|
||||
"leaq %c[hostContextFull](%%rcx), %%rsp\n"
|
||||
"popq %%r9\n" /* host %cr3 */
|
||||
"popq %%rbx\n"
|
||||
"popq %%rbp\n"
|
||||
"popq %%rsi\n" /* Not ABI-required. */
|
||||
"popq %%rdi\n" /* Not ABI-required. */
|
||||
"popq %%r12\n"
|
||||
"popq %%r13\n"
|
||||
"popq %%r14\n"
|
||||
"popq %%r15\n"
|
||||
|
||||
"popq %%rax\n" /* host %rsp */
|
||||
"popw %%dx\n" /* host %ss */
|
||||
/* Load the cross GDT and IDT before reloading segments, %cr3 */
|
||||
"lgdtq %c[crossGDTHKLADesc](%%rcx)\n"
|
||||
"lidtq %c[switchHostIDTR](%%rcx)\n"
|
||||
/* Load %cr3 last to flush the TLB after all stack ops. */
|
||||
"movq %%r9, %%cr3\n"
|
||||
/* Reload the host's %ss into %ds/%es. Technically wrong. */
|
||||
"movw %%dx, %%ds\n"
|
||||
"movw %%dx, %%es\n"
|
||||
"movw %%dx, %%ss\n"
|
||||
"movq %%rax, %%rsp\n"
|
||||
|
||||
/* Microsoft RTL/codegen assumes EFLAGS<DF> = 0. */
|
||||
"cld\n"
|
||||
"lretq\n"
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------------------
|
||||
*
|
||||
* SwitchExcGetCrossPageData --
|
||||
*
|
||||
* Common function for the exception handlers to locate the data
|
||||
* crosspage so they can record their respective events. In order to
|
||||
* reach this code an exception had to vector through the IDT. The IDT
|
||||
* is known to be in the data page. Therefore, the data page can be
|
||||
* found by accessing IDTR and rounding down to page alignment.
|
||||
*
|
||||
* Input:
|
||||
* None
|
||||
*
|
||||
* Output:
|
||||
* %rax = Page aligned address of the current crosspage data area.
|
||||
*
|
||||
* Note:
|
||||
* %rax (return value) and %rflags are destroyed, all other registers
|
||||
* are preserved. Since this is only called by exception handlers, the
|
||||
* CPU has already saved %rflags so no additional handling is required.
|
||||
*
|
||||
*---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
".p2align 4\n"
|
||||
"SwitchExcGetCrossPageData:\n"
|
||||
"subq $0x10, %%rsp\n"
|
||||
"sidt 0(%%rsp)\n"
|
||||
"movq 2(%%rsp), %%rax\n" /* DTR.offset */
|
||||
"addq $0x10, %%rsp\n"
|
||||
"andq %[PageAlignMask], %%rax\n"
|
||||
"ret\n"
|
||||
|
||||
EXPORTED_ASM_SYMBOL(CrossPage_CodeEnd)
|
||||
|
||||
: /* No output list, this is not really C code. */
|
||||
: [MONITOR_MINIMUM_VA] "i" (MONITOR_LINEAR_START),
|
||||
[PageAlignMask] "i" (~PAGE_MASK),
|
||||
[EFLAGS_TF] "i" (EFLAGS_TF),
|
||||
[EFLAGS_RF] "i" (EFLAGS_RF),
|
||||
[VMMCROSSPAGE] "i" (CROSS_PAGE_DATA_START * PAGE_SIZE),
|
||||
[wsUD2] "i" (offsetof(VMCrossPageData, wsUD2)),
|
||||
|
||||
[wsExceptionDB] "i" (offsetof(VMCrossPageData, wsException[EXC_DB])),
|
||||
[wsExceptionUD] "i" (offsetof(VMCrossPageData, wsException[EXC_UD])),
|
||||
[wsExceptionNMI] "i" (offsetof(VMCrossPageData, wsException[EXC_NMI])),
|
||||
[wsExceptionMC] "i" (offsetof(VMCrossPageData, wsException[EXC_MC])),
|
||||
|
||||
[hostContextEmpty] "i" (offsetof(VMCrossPageData, hostDS)),
|
||||
[monContextEmpty] "i" (offsetof(VMCrossPageData, monDS)),
|
||||
|
||||
[hostContextFull] "i" (offsetof(VMCrossPageData, hostCR3)),
|
||||
[monContextFull] "i" (offsetof(VMCrossPageData, monCR3)),
|
||||
|
||||
[crosspageDataLA] "i" (offsetof(VMCrossPageData, crosspageDataLA)),
|
||||
[crosspageCodeLA] "i" (offsetof(VMCrossPageData, crosspageCodeLA)),
|
||||
[crossGDTHKLADesc] "i" (offsetof(VMCrossPageData, crossGDTHKLADesc)),
|
||||
[switchHostIDTR] "i" (offsetof(VMCrossPageData, switchHostIDTR))
|
||||
);
|
||||
NOT_REACHED_MINIMAL();
|
||||
}
|
||||
|
||||
#ifdef STACK_FRAME_NON_STANDARD
|
||||
STACK_FRAME_NON_STANDARD(CrossPage_CodePage);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The crosspage data must not exceed a single page.
|
||||
* The code area also must fit in a single page but that size isn't available
|
||||
* until link time.
|
||||
*/
|
||||
MY_ASSERTS(CROSSPAGE_DATA,
|
||||
ASSERT_ON_COMPILE(sizeof(VMCrossPageData) <= PAGE_SIZE);
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2001 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
|
||||
/*
|
||||
* hashFunc.c --
|
||||
*
|
||||
* The core implementation lives in lib/shared/hashFunc.h because it
|
||||
* is shared by the vmkernel and vmmon.
|
||||
*/
|
||||
|
||||
#include "hashFunc.h"
|
||||
|
||||
/*
|
||||
* Wrappers
|
||||
*/
|
||||
|
||||
// arbitrary constant
|
||||
#define HASH_INIT_VALUE (42)
|
||||
|
||||
// 64-bit hash for one 4K page
|
||||
uint64
|
||||
HashFunc_HashPage(const void *addr)
|
||||
{
|
||||
return hash2((uint64 *)addr, PAGE_SIZE / sizeof (uint64), HASH_INIT_VALUE);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998,2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -27,7 +27,7 @@
|
||||
# define __HOST_KERNEL_H__
|
||||
|
||||
|
||||
# ifdef __linux__
|
||||
# ifdef linux
|
||||
/*
|
||||
* In some cases, this files needs to include Linux kernel header file
|
||||
* asm/page.h.
|
||||
|
||||
+30
-43
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2017 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -17,8 +17,8 @@
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* hostif.h - Platform dependent interface for supporting
|
||||
* the vmx86 device driver.
|
||||
* hostif.h - Platform dependent interface for supporting
|
||||
* the vmx86 device driver.
|
||||
*/
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "hostifGlobalLock.h"
|
||||
|
||||
/*
|
||||
* Host-specific definitions.
|
||||
* Host-specific definitions.
|
||||
*/
|
||||
#if !__linux__ && !defined(WINNT_DDK) && !defined __APPLE__
|
||||
#error "Only Linux or NT or Mac OS defined for now."
|
||||
@@ -59,24 +59,21 @@
|
||||
|
||||
#define CROSSCALL_SLEEP_US 1000
|
||||
|
||||
typedef struct HostIFContigMemMap {
|
||||
MPN mpn;
|
||||
void *addr;
|
||||
PageCnt pages;
|
||||
struct HostIFContigMemMap *next;
|
||||
} HostIFContigMemMap;
|
||||
/* Return value for HostIF_IPI. */
|
||||
typedef enum {
|
||||
IPI_NONE, // No IPI was sent.
|
||||
IPI_UNICAST, // Unicast IPIs were sent.
|
||||
IPI_BROADCAST // A broadcast IPI was sent to all PCPUs.
|
||||
} HostIFIPIMode;
|
||||
|
||||
EXTERN Bool HostIF_Init(VMDriver *vm, uint32 numVCPUs);
|
||||
EXTERN int HostIF_Init(VMDriver *vm);
|
||||
EXTERN int HostIF_LookupUserMPN(VMDriver *vm, VA64 uAddr, MPN *mpn);
|
||||
|
||||
EXTERN MPN HostIF_GetCrossPageDataMPN(VMCrossPageData *crosspageData);
|
||||
EXTERN MPN HostIF_GetCrossPageCodeMPN(void);
|
||||
EXTERN void *HostIF_MapCrossPage(VMDriver *vm, VA64 uAddr);
|
||||
EXTERN void HostIF_InitFP(VMDriver *vm);
|
||||
|
||||
EXTERN void *HostIF_AllocPage(void);
|
||||
EXTERN void HostIF_FreePage(void *ptr);
|
||||
|
||||
EXTERN VPN HostIF_MapPage(MPN mpn);
|
||||
EXTERN void HostIF_UnmapPage(VPN vpn);
|
||||
EXTERN int HostIF_LockPage(VMDriver *vm, VA64 uAddr,
|
||||
Bool allowMultipleMPNsPerVA, MPN *mpn);
|
||||
EXTERN int HostIF_UnlockPage(VMDriver *vm, VA64 uAddr);
|
||||
@@ -85,36 +82,29 @@ EXTERN Bool HostIF_IsLockedByMPN(VMDriver *vm, MPN mpn);
|
||||
EXTERN void HostIF_FreeAllResources(VMDriver *vm);
|
||||
EXTERN uint64 HostIF_ReadUptime(void);
|
||||
EXTERN uint64 HostIF_UptimeFrequency(void);
|
||||
EXTERN PageCnt HostIF_EstimateLockedPageLimit(const VMDriver *vm,
|
||||
PageCnt lockedPages);
|
||||
EXTERN unsigned int HostIF_EstimateLockedPageLimit(const VMDriver *vm,
|
||||
unsigned int lockedPages);
|
||||
EXTERN void HostIF_Wait(unsigned int timeoutMs);
|
||||
EXTERN void HostIF_WaitForFreePages(unsigned int timeoutMs);
|
||||
EXTERN void *HostIF_AllocKernelPages(PageCnt numPages, MPN *mpns);
|
||||
EXTERN void HostIF_FreeKernelPages(PageCnt numPages, void *ptr);
|
||||
EXTERN HostIFContigMemMap *HostIF_AllocContigPages(VMDriver *vm,
|
||||
PageCnt numPages);
|
||||
EXTERN void HostIF_FreeContigPages(VMDriver *vm, HostIFContigMemMap *mapping);
|
||||
EXTERN void *HostIF_AllocCrossGDT(uint32 numPages, MPN maxValidFirst,
|
||||
MPN *crossGDTMPNs);
|
||||
EXTERN void HostIF_FreeCrossGDT(uint32 numPages, void *crossGDT);
|
||||
EXTERN void HostIF_VMLock(VMDriver *vm, int callerID);
|
||||
EXTERN void HostIF_VMUnlock(VMDriver *vm, int callerID);
|
||||
#ifdef VMX86_DEBUG
|
||||
EXTERN Bool HostIF_VMLockIsHeld(VMDriver *vm);
|
||||
#endif
|
||||
|
||||
EXTERN void HostIF_APICInit(VMDriver *vm);
|
||||
EXTERN uint8 HostIF_GetMonitorIPIVector(void);
|
||||
EXTERN uint8 HostIF_GetHVIPIVector(void);
|
||||
EXTERN uint8 HostIF_GetPerfCtrVector(void);
|
||||
EXTERN void HostIF_GetTimerVectors(uint8 *v0, uint8 *v1);
|
||||
EXTERN Bool HostIF_APICInit(VMDriver *vm, Bool setVMPtr, Bool probe);
|
||||
|
||||
EXTERN int HostIF_SemaphoreWait(VMDriver *vm,
|
||||
Vcpuid vcpuid,
|
||||
uint64 *args);
|
||||
|
||||
EXTERN int HostIF_SemaphoreSignal(VMDriver *vm, uint64 *args);
|
||||
EXTERN int HostIF_SemaphoreSignal(uint64 *args);
|
||||
|
||||
EXTERN void HostIF_SemaphoreForceWakeup(VMDriver *vm, const VCPUSet *vcs);
|
||||
EXTERN void HostIF_IPI(VMDriver *vm, const VCPUSet *vcs);
|
||||
EXTERN void HostIF_OneIPI(VMDriver *vm, Vcpuid v);
|
||||
EXTERN HostIFIPIMode HostIF_IPI(VMDriver *vm, const VCPUSet *vcs);
|
||||
|
||||
EXTERN uint32 HostIF_GetCurrentPCPU(void);
|
||||
EXTERN void HostIF_CallOnEachCPU(void (*func)(void *), void *data);
|
||||
@@ -124,17 +114,17 @@ EXTERN void HostIF_WaitForThreads(VMDriver *vm, Vcpuid currVcpu);
|
||||
EXTERN void HostIF_CancelWaitForThreads(VMDriver *vm, Vcpuid currVcpu);
|
||||
EXTERN void HostIF_WakeUpYielders(VMDriver *vm, Vcpuid currVcpu);
|
||||
|
||||
EXTERN int64 HostIF_AllocLockedPages(VMDriver *vm, VA64 addr,
|
||||
PageCnt numPages, Bool kernelMPNBuffer);
|
||||
EXTERN int HostIF_FreeLockedPages(VMDriver *vm, MPN *mpns, PageCnt numPages);
|
||||
EXTERN int HostIF_AllocLockedPages(VMDriver *vm, VA64 addr,
|
||||
unsigned int numPages, Bool kernelMPNBuffer);
|
||||
EXTERN int HostIF_FreeLockedPages(VMDriver *vm, VA64 addr,
|
||||
unsigned int numPages, Bool kernelMPNBuffer);
|
||||
EXTERN MPN HostIF_GetNextAnonPage(VMDriver *vm, MPN mpn);
|
||||
EXTERN PageCnt HostIF_GetNumAnonPages(VMDriver *vm);
|
||||
EXTERN MPN HostIF_AllocLowPage(VMDriver *vm);
|
||||
EXTERN int HostIF_GetLockedPageList(VMDriver *vm, VA64 uAddr,
|
||||
unsigned int numPages);
|
||||
|
||||
EXTERN int HostIF_ReadPhysical(VMDriver *vm, MA ma, VA64 addr,
|
||||
Bool kernelBuffer, size_t len);
|
||||
EXTERN int HostIF_WritePhysical(VMDriver *vm, MA ma, VA64 addr,
|
||||
Bool kernelBuffer, size_t len);
|
||||
EXTERN int HostIF_ReadPage(VMDriver *vm, MPN mpn, VA64 addr, Bool kernelBuffer);
|
||||
EXTERN int HostIF_WritePage(VMDriver *vm, MPN mpn, VA64 addr,
|
||||
Bool kernelBuffer);
|
||||
EXTERN int HostIF_WriteMachinePage(MPN mpn, VA64 addr);
|
||||
#if defined __APPLE__
|
||||
// There is no need for a fast clock lock on Mac OS.
|
||||
@@ -151,9 +141,6 @@ EXTERN void HostIF_FreeMachinePage(MPN mpn);
|
||||
|
||||
EXTERN int HostIF_SafeRDMSR(uint32 msr, uint64 *val);
|
||||
|
||||
EXTERN int HostIF_CopyFromUser(void *dst, VA64 src, size_t len);
|
||||
EXTERN int HostIF_CopyToUser(VA64 dst, const void *src, size_t len);
|
||||
|
||||
#if defined __APPLE__
|
||||
EXTERN void HostIF_PageUnitTest(void);
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998, 2008, 2018 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -29,10 +29,9 @@
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
#include "vm_basic_types.h"
|
||||
|
||||
|
||||
void *HostIF_AllocKernelMem(size_t size, Bool nonPageable);
|
||||
void *HostIF_AllocKernelMem(size_t size, int nonPageable);
|
||||
void HostIF_FreeKernelMem(void *ptr);
|
||||
|
||||
#endif // ifdef _HOSTIFMEM_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2018 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2017 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -96,7 +96,7 @@
|
||||
* Modify this value to increase the maximum number of tracked pages
|
||||
* per MemTrack instance.
|
||||
*/
|
||||
#define MEMTRACK_MAX_TRACKED GBYTES_2_PAGES(119)
|
||||
#define MEMTRACK_MAX_TRACKED MBYTES_2_PAGES(4096)
|
||||
|
||||
/*
|
||||
* Linux uses a 3-level directory, because we want to keep allocations
|
||||
@@ -148,10 +148,10 @@ typedef uint64 MemTrackHTKey;
|
||||
|
||||
typedef struct MemTrack {
|
||||
VMDriver *vm; /* The VM instance. */
|
||||
PageCnt numPages; /* Number of pages tracked. */
|
||||
unsigned numPages; /* Number of pages tracked. */
|
||||
MemTrackDir1 dir1; /* First level directory. */
|
||||
MemTrackHT vpnHashTable; /* VPN to entry hashtable. */
|
||||
MemTrackHT *mpnHashTable; /* MPN to entry hashtable. */
|
||||
MemTrackHT mpnHashTable; /* MPN to entry hashtable. */
|
||||
} MemTrack;
|
||||
|
||||
/*
|
||||
@@ -197,7 +197,7 @@ MemTrackAllocPage(void)
|
||||
|
||||
#define MEMTRACK_ALLOCDFN(_name, _itype, _otype) \
|
||||
static INLINE _otype * \
|
||||
_name(_itype *arg, uint64 pos) \
|
||||
_name(_itype *arg, unsigned pos) \
|
||||
{ \
|
||||
if (arg->dir[pos] == NULL) { \
|
||||
arg->dir[pos] = MemTrackAllocPage(); \
|
||||
@@ -273,10 +273,9 @@ MemTrackHTInsert(MemTrackHT *ht, // IN
|
||||
static void
|
||||
MemTrackCleanup(MemTrack *mt) // IN
|
||||
{
|
||||
PageCnt idx;
|
||||
uint64 p1;
|
||||
unsigned idx;
|
||||
unsigned p1;
|
||||
MemTrackDir1 *dir1;
|
||||
Bool freeBackMap = mt != NULL && mt->mpnHashTable != NULL;
|
||||
|
||||
if (mt == NULL) {
|
||||
return;
|
||||
@@ -284,7 +283,7 @@ MemTrackCleanup(MemTrack *mt) // IN
|
||||
dir1 = &mt->dir1;
|
||||
|
||||
for (p1 = 0; p1 < MEMTRACK_DIR1_ENTRIES; p1++) {
|
||||
uint64 p2;
|
||||
unsigned p2;
|
||||
MemTrackDir2 *dir2 = MEMTRACK_GETDIR2(dir1, p1);
|
||||
|
||||
if (dir2 == NULL) {
|
||||
@@ -305,15 +304,10 @@ MemTrackCleanup(MemTrack *mt) // IN
|
||||
if (mt->vpnHashTable.pages[idx] != NULL) {
|
||||
HostIF_FreePage(mt->vpnHashTable.pages[idx]);
|
||||
}
|
||||
if (freeBackMap) {
|
||||
if (mt->mpnHashTable->pages[idx] != NULL) {
|
||||
HostIF_FreePage(mt->mpnHashTable->pages[idx]);
|
||||
}
|
||||
if (mt->mpnHashTable.pages[idx] != NULL) {
|
||||
HostIF_FreePage(mt->mpnHashTable.pages[idx]);
|
||||
}
|
||||
}
|
||||
if (freeBackMap) {
|
||||
HostIF_FreeKernelMem(mt->mpnHashTable);
|
||||
}
|
||||
|
||||
HostIF_FreeKernelMem(mt);
|
||||
}
|
||||
@@ -339,7 +333,7 @@ MemTrack *
|
||||
MemTrack_Init(VMDriver *vm) // IN:
|
||||
{
|
||||
MemTrack *mt;
|
||||
PageCnt idx;
|
||||
unsigned idx;
|
||||
|
||||
#if defined(MEMTRACK_3LEVEL)
|
||||
ASSERT_ON_COMPILE(sizeof *mt <= PAGE_SIZE);
|
||||
@@ -359,27 +353,20 @@ MemTrack_Init(VMDriver *vm) // IN:
|
||||
MemTrackHTPage *htPage = MemTrackAllocPage();
|
||||
|
||||
if (htPage == NULL) {
|
||||
Warning("MemTrack failed to allocate VPN hash table (%"FMT64"d).\n",
|
||||
idx);
|
||||
Warning("MemTrack failed to allocate VPN hash table (%d).\n", idx);
|
||||
goto error;
|
||||
}
|
||||
mt->vpnHashTable.pages[idx] = htPage;
|
||||
}
|
||||
|
||||
mt->mpnHashTable = HostIF_AllocKernelMem(sizeof *mt->mpnHashTable, FALSE);
|
||||
if (mt->mpnHashTable == NULL) {
|
||||
Warning("MemTrack failed to allocate MPN hash table.\n");
|
||||
goto error;
|
||||
}
|
||||
memset(mt->mpnHashTable, 0, sizeof *mt->mpnHashTable);
|
||||
for (idx = 0; idx < MEMTRACK_HT_PAGES; idx++) {
|
||||
MemTrackHTPage *htPage = MemTrackAllocPage();
|
||||
|
||||
if (htPage == NULL) {
|
||||
Warning("MemTrack failed to allocate MPN hash table (%"FMT64"d).\n",
|
||||
idx);
|
||||
Warning("MemTrack failed to allocate MPN hash table (%d).\n", idx);
|
||||
goto error;
|
||||
}
|
||||
mt->mpnHashTable->pages[idx] = htPage;
|
||||
mt->mpnHashTable.pages[idx] = htPage;
|
||||
}
|
||||
|
||||
return mt;
|
||||
@@ -411,15 +398,14 @@ MemTrack_Add(MemTrack *mt, // IN
|
||||
VPN64 vpn, // IN
|
||||
MPN mpn) // IN
|
||||
{
|
||||
PageCnt idx = mt->numPages;
|
||||
uint64 p1, p2, p3;
|
||||
unsigned idx = mt->numPages;
|
||||
unsigned p1, p2, p3;
|
||||
MemTrackEntry *ent;
|
||||
MemTrackDir1 *dir1 = &mt->dir1;
|
||||
MemTrackDir2 *dir2;
|
||||
MemTrackDir3 *dir3;
|
||||
MEMTRACK_IDX2DIR(idx, p1, p2, p3);
|
||||
|
||||
|
||||
ASSERT(HostIF_VMLockIsHeld(mt->vm));
|
||||
|
||||
if (p1 >= MEMTRACK_DIR1_ENTRIES ||
|
||||
@@ -443,7 +429,7 @@ MemTrack_Add(MemTrack *mt, // IN
|
||||
ent->mpn = mpn;
|
||||
|
||||
MemTrackHTInsert(&mt->vpnHashTable, ent, &ent->vpnChain, ent->vpn);
|
||||
MemTrackHTInsert(mt->mpnHashTable, ent, &ent->mpnChain, ent->mpn);
|
||||
MemTrackHTInsert(&mt->mpnHashTable, ent, &ent->mpnChain, ent->mpn);
|
||||
|
||||
mt->numPages++;
|
||||
|
||||
@@ -506,7 +492,7 @@ MemTrack_LookupMPN(MemTrack *mt, // IN
|
||||
{
|
||||
MemTrackEntry *next;
|
||||
ASSERT(HostIF_VMLockIsHeld(mt->vm));
|
||||
next = *MemTrackHTLookup(mt->mpnHashTable, mpn);
|
||||
next = *MemTrackHTLookup(&mt->mpnHashTable, mpn);
|
||||
|
||||
while (next != NULL) {
|
||||
if (next->mpn == mpn) {
|
||||
@@ -537,16 +523,16 @@ MemTrack_LookupMPN(MemTrack *mt, // IN
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
PageCnt
|
||||
unsigned
|
||||
MemTrack_Cleanup(MemTrack *mt, // IN
|
||||
MemTrackCleanupCb *cb, // IN
|
||||
void *cData) // IN
|
||||
{
|
||||
PageCnt idx;
|
||||
PageCnt count = 0;
|
||||
unsigned idx;
|
||||
unsigned count = 0;
|
||||
|
||||
for (idx = 0; idx < mt->numPages; idx++) {
|
||||
uint64 p1, p2, p3;
|
||||
unsigned p1, p2, p3;
|
||||
MemTrackEntry *ent;
|
||||
MemTrackDir1 *dir1 = &mt->dir1;
|
||||
MEMTRACK_IDX2DIR(idx, p1, p2, p3);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998,2017-2018 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2017 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -20,7 +20,7 @@
|
||||
* memtrack.h --
|
||||
*
|
||||
* Utility module for tracking pinned memory, which allows later
|
||||
* lookup by VPN and optionally by MPN.
|
||||
* lookup by VPN.
|
||||
*/
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ typedef struct MemTrackEntry {
|
||||
typedef void (MemTrackCleanupCb)(void *cData, MemTrackEntry *entry);
|
||||
|
||||
extern struct MemTrack *MemTrack_Init(VMDriver *vm);
|
||||
extern PageCnt MemTrack_Cleanup(struct MemTrack *mt, MemTrackCleanupCb *cb,
|
||||
void *cbData);
|
||||
extern unsigned MemTrack_Cleanup(struct MemTrack *mt, MemTrackCleanupCb *cb,
|
||||
void *cbData);
|
||||
extern MemTrackEntry *MemTrack_Add(struct MemTrack *mt, VPN64 vpn, MPN mpn);
|
||||
extern MemTrackEntry *MemTrack_LookupVPN(struct MemTrack *mt, VPN64 vpn);
|
||||
extern MemTrackEntry *MemTrack_LookupMPN(struct MemTrack *mt, MPN mpn);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998,2014,2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998,2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -24,15 +24,16 @@
|
||||
* Depending on configuration phystracker provides either 2-level or
|
||||
* 3-level structure to track whether page (specified by its MPN) is
|
||||
* locked or no. Linux uses 3-level structures with top limit of
|
||||
* 1TB (32bit) or 16TB (64bit). Windows and Mac use 2-level structures
|
||||
* ready to hold 128GB (32bit) or 2TB (64bit) of memory.
|
||||
* 1TB (32bit) or 16TB (64bit). Windows use 2-level structures
|
||||
* ready to hold 128GB (32bit) or 2TB (64bit) of memory. On Mac
|
||||
* limit is 2-level 128GB.
|
||||
*
|
||||
* 2-level phystracker is built on top of 3-level one by collapsing
|
||||
* middle level.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef linux
|
||||
/* Must come before any kernel header file --hpreg */
|
||||
# include "driver-config.h"
|
||||
|
||||
@@ -49,7 +50,9 @@
|
||||
#define BYTES_PER_ENTRY (PAGE_SIZE)
|
||||
#define PHYSTRACK_L3_ENTRIES (8 * BYTES_PER_ENTRY) /* 128MB */
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(WINNT_DDK)
|
||||
#define PHYSTRACK_L1_ENTRIES (PHYSTRACK_MAX_SUPPORTED_GB * 8)
|
||||
#elif defined(__linux__)
|
||||
#define PHYSTRACK_L2_ENTRIES (BYTES_PER_ENTRY / sizeof(void *)) /* 64GB or 128GB */
|
||||
/*
|
||||
* Currently MPN is 32 bits. 15 bits are in L3, 9 bits are in L2,
|
||||
@@ -57,7 +60,7 @@
|
||||
*/
|
||||
#define PHYSTRACK_L1_ENTRIES (256) /* 16TB. */
|
||||
#else
|
||||
#define PHYSTRACK_L1_ENTRIES (PHYSTRACK_MAX_SUPPORTED_GB * 8)
|
||||
#define PHYSTRACK_L1_ENTRIES ((128 + 4) * 8) /* 128 GB */
|
||||
#endif
|
||||
|
||||
#ifndef PHYSTRACK_L2_ENTRIES
|
||||
@@ -223,7 +226,7 @@ PhysTrack_Alloc(VMDriver *vm)
|
||||
}
|
||||
|
||||
return tracker;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -235,7 +238,7 @@ PhysTrack_Alloc(VMDriver *vm)
|
||||
*
|
||||
* Results:
|
||||
* reallocates all structures, including 'tracker'
|
||||
*
|
||||
*
|
||||
* Side effects:
|
||||
* tracker deallocated
|
||||
*
|
||||
@@ -243,7 +246,7 @@ PhysTrack_Alloc(VMDriver *vm)
|
||||
*/
|
||||
|
||||
void
|
||||
PhysTrack_Free(PhysTracker *tracker)
|
||||
PhysTrack_Free(PhysTracker *tracker)
|
||||
{
|
||||
unsigned int p1;
|
||||
|
||||
@@ -490,32 +493,3 @@ PhysTrack_GetNext(const PhysTracker *tracker, // IN
|
||||
return INVALID_MPN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* PhysTrack_GetNumTrackedPages --
|
||||
*
|
||||
* Returns the total number of tracked pages
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
PageCnt
|
||||
PhysTrack_GetNumTrackedPages(const PhysTracker *tracker)
|
||||
{
|
||||
PageCnt numTrackedMPNs = 0;
|
||||
MPN nextMPN;
|
||||
ASSERT(tracker);
|
||||
ASSERT(HostIF_VMLockIsHeld(tracker->vm));
|
||||
nextMPN = PhysTrack_GetNext(tracker, INVALID_MPN);
|
||||
while (nextMPN != INVALID_MPN) {
|
||||
numTrackedMPNs++;
|
||||
nextMPN = PhysTrack_GetNext(tracker, nextMPN);
|
||||
}
|
||||
return numTrackedMPNs;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998,2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -29,7 +29,7 @@
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
|
||||
#if !defined (__linux__)
|
||||
#if defined(WINNT_DDK)
|
||||
/* XXX: can be more efficient based on server vs. desktop and version of Windows */
|
||||
#define PHYSTRACK_MAX_SUPPORTED_GB (2048 + 4) /* 2 TB 64-bit W2k8 + 4 GB PCI */
|
||||
#endif
|
||||
@@ -44,7 +44,6 @@ EXTERN void PhysTrack_Add(struct PhysTracker *, MPN);
|
||||
EXTERN void PhysTrack_Remove(struct PhysTracker *, MPN);
|
||||
EXTERN Bool PhysTrack_Test(const struct PhysTracker *, MPN);
|
||||
EXTERN MPN PhysTrack_GetNext(const struct PhysTracker *, MPN);
|
||||
EXTERN PageCnt PhysTrack_GetNumTrackedPages(const struct PhysTracker *);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,299 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2018 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* sharedAreaVmmon.c --
|
||||
*
|
||||
* VMMon shared area management.
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
# include "driver-config.h"
|
||||
# include <linux/string.h> /* memset() in the kernel. */
|
||||
#else
|
||||
# include <string.h>
|
||||
#endif
|
||||
#include "vmware.h"
|
||||
#include "vm_assert.h"
|
||||
#include "hostif.h"
|
||||
#include "sharedAreaVmmon.h"
|
||||
#include "vmx86.h"
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* SharedAreaVmmonIsMultiVCPU --
|
||||
*
|
||||
* Helper function for determining if a shared area type represents
|
||||
* a region that has VCPU-specific memory.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if type has VCPU-specific memory, FALSE otherwise.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static Bool
|
||||
SharedAreaVmmonIsMultiVCPU(SharedAreaType type)
|
||||
{
|
||||
switch (type) {
|
||||
case SHARED_AREA_PER_VM:
|
||||
case SHARED_AREA_PER_VM_VMX:
|
||||
return FALSE;
|
||||
default:
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* SharedAreaVmmon_Init --
|
||||
*
|
||||
* Initializes the shared area component of the VM Driver.
|
||||
*
|
||||
* Results:
|
||||
* A pointer to the VMMon shared area.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
SharedAreaVmmon *
|
||||
SharedAreaVmmon_Init(VMDriver *vm)
|
||||
{
|
||||
SharedAreaVmmon *sa;
|
||||
|
||||
/*
|
||||
* Allocate the shared area pointer here. The pages in each region are
|
||||
* lazily allocated when a region is registered.
|
||||
*/
|
||||
sa = HostIF_AllocKernelMem(sizeof *sa, FALSE);
|
||||
if (sa == NULL) {
|
||||
Warning("SharedArea failed to allocate handle.\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(sa, 0, sizeof *sa);
|
||||
return sa;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* SharedAreaVmmon_Cleanup --
|
||||
*
|
||||
* Cleans up the shared area component of the VM Driver by freeing all
|
||||
* previously allocated VMMon shared area memory.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
SharedAreaVmmon_Cleanup(SharedAreaVmmon *area)
|
||||
{
|
||||
SharedAreaType t;
|
||||
|
||||
if (area == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (t = 0; t < NUM_SHARED_AREAS; t++) {
|
||||
SharedAreaVmmonRegion *region = &area->regions[t];
|
||||
|
||||
if (region->pages != NULL) {
|
||||
HostIF_FreeKernelMem(region->pages);
|
||||
}
|
||||
}
|
||||
HostIF_FreeKernelMem(area);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* SharedAreaVmmon_ValidateRegionArgs --
|
||||
*
|
||||
* Validate the given VMMon shared area region registration block.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the block is valid and can be used to register a shared
|
||||
* area region for a VCPU, FALSE otherwise.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
SharedAreaVmmon_ValidateRegionArgs(VMDriver *vm,
|
||||
VMSharedAreaRegistrationBlock *block)
|
||||
{
|
||||
SharedAreaVmmonRegion *region;
|
||||
Vcpuid vcpu = block->vcpu;
|
||||
SharedAreaType type = block->region.index;
|
||||
PageCnt numPages = block->region.numPages;
|
||||
|
||||
if (vm == NULL ||
|
||||
vm->sharedArea == NULL ||
|
||||
vcpu >= vm->numVCPUs ||
|
||||
numPages == 0 ||
|
||||
type >= NUM_SHARED_AREAS ||
|
||||
(!SharedAreaVmmonIsMultiVCPU(type) && vcpu > 0)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
region = &vm->sharedArea->regions[type];
|
||||
if (region->pagesPerVcpu != 0) {
|
||||
|
||||
/*
|
||||
* A region that was previously registered for a given VCPU should have
|
||||
* the same number of pages as originally specified. Also, a region can
|
||||
* only be reserved once for a given VCPU throughout the runtime of a VM.
|
||||
*/
|
||||
return region->pagesPerVcpu == numPages &&
|
||||
region->pages[vcpu * region->pagesPerVcpu] == INVALID_MPN;
|
||||
} else {
|
||||
/* First registration for this region. */
|
||||
ASSERT(region->pages == NULL);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* SharedAreaVmmon_RegisterRegion --
|
||||
*
|
||||
* Register a VMMon shared area region for a given VCPU with the VM Driver.
|
||||
* A successful return value indicates that the backing pages of the
|
||||
* shared area region are locked and tracked by the VM Driver.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the region was successfully registered for the given VCPU,
|
||||
* FALSE otherwise.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
SharedAreaVmmon_RegisterRegion(VMDriver *vm,
|
||||
VMSharedAreaRegistrationBlock *block)
|
||||
{
|
||||
Vcpuid vcpu = block->vcpu;
|
||||
SharedAreaType type = block->region.index;
|
||||
SharedAreaVmmonRegion *region;
|
||||
MPN *pages;
|
||||
PageCnt page;
|
||||
|
||||
ASSERT(SharedAreaVmmon_ValidateRegionArgs(vm, block));
|
||||
region = &vm->sharedArea->regions[type];
|
||||
if (region->pagesPerVcpu == 0) {
|
||||
PageCnt pagesInRegion = block->region.numPages;
|
||||
|
||||
if (SharedAreaVmmonIsMultiVCPU(type)) {
|
||||
pagesInRegion *= vm->numVCPUs;
|
||||
}
|
||||
region->pages = HostIF_AllocKernelMem(sizeof *pages * pagesInRegion,
|
||||
FALSE);
|
||||
if (region->pages == NULL) {
|
||||
Warning("Failed to allocate pages array for region %u\n", type);
|
||||
return FALSE;
|
||||
}
|
||||
for (page = 0; page < pagesInRegion; page++) {
|
||||
region->pages[page] = INVALID_MPN;
|
||||
}
|
||||
region->pagesPerVcpu = block->region.numPages;
|
||||
}
|
||||
|
||||
pages = region->pages + vcpu * region->pagesPerVcpu;
|
||||
for (page = 0; page < region->pagesPerVcpu; page++) {
|
||||
ASSERT(pages[page] == INVALID_MPN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lock all shared area backing pages throughout the runtime of the monitor.
|
||||
* The pages remain locked until they are freed by HostIF during VM Driver
|
||||
* tear-down.
|
||||
*/
|
||||
for (page = 0; page < region->pagesPerVcpu; page++) {
|
||||
VPN vmxVPN = block->region.baseVpn + page;
|
||||
VA64 uAddr = VPN_2_VA(vmxVPN);
|
||||
int status = Vmx86_LockPage(vm, uAddr, FALSE, pages + page);
|
||||
|
||||
if (status != PAGE_LOCK_SUCCESS) {
|
||||
PageCnt resetPage;
|
||||
|
||||
/* Reset the region pages for this VCPU to their original state. */
|
||||
for (resetPage = 0; resetPage < page; resetPage++) {
|
||||
status = Vmx86_UnlockPage(vm, uAddr);
|
||||
ASSERT(status == PAGE_UNLOCK_SUCCESS);
|
||||
pages[resetPage] = INVALID_MPN;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* SharedAreaVmmon_GetRegionMPN --
|
||||
*
|
||||
* For the shared area region corresponding to the given type and VCPU,
|
||||
* get the MPN backing the region at the given offset.
|
||||
*
|
||||
* Results:
|
||||
* The MPN backing the region, or INVALID_MPN if no MPN is found.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MPN
|
||||
SharedAreaVmmon_GetRegionMPN(VMDriver *vm, SharedAreaVmmonRequest *request)
|
||||
{
|
||||
SharedAreaType type = request->type;
|
||||
Vcpuid vcpu = request->vcpu;
|
||||
SharedAreaVmmonRegion *region;
|
||||
PageCnt pgOffset = request->offset;
|
||||
MPN *pages;
|
||||
|
||||
ASSERT(vcpu < vm->numVCPUs);
|
||||
ASSERT(type < NUM_SHARED_AREAS);
|
||||
ASSERT(IMPLIES(!SharedAreaVmmonIsMultiVCPU(type), vcpu == 0));
|
||||
region = &vm->sharedArea->regions[type];
|
||||
pages = region->pages + vcpu * region->pagesPerVcpu;
|
||||
if (region->pages == NULL || region->pagesPerVcpu == 0) {
|
||||
Warning("(%s) Requested unregistered region %u, VCPU %u\n", __FUNCTION__,
|
||||
type, vcpu);
|
||||
return INVALID_MPN;
|
||||
}
|
||||
if (pgOffset >= region->pagesPerVcpu) {
|
||||
Warning("(%s) Offset %"FMT64"u (type %u, per-VCPU size %"FMT64"u)\n",
|
||||
__FUNCTION__, pgOffset, type, region->pagesPerVcpu);
|
||||
return INVALID_MPN;
|
||||
}
|
||||
|
||||
return pages[pgOffset];
|
||||
}
|
||||
@@ -1,282 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2018-2019 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* statVarsVmmon.c --
|
||||
*
|
||||
* VMMon stat variables management.
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
# include "driver-config.h"
|
||||
# include <linux/string.h> /* memset() in the kernel. */
|
||||
#else
|
||||
# include <string.h>
|
||||
#endif
|
||||
#include "vmware.h"
|
||||
#include "vm_assert.h"
|
||||
#include "hostif.h"
|
||||
#include "statVarsVmmon.h"
|
||||
#include "vmx86.h"
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* StatVarsVmmon_Init --
|
||||
*
|
||||
* Initializes the stat vars component of the VM Driver.
|
||||
*
|
||||
* Results:
|
||||
* A pointer to the VMMon stat vars struct.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
StatVarsVmmon *
|
||||
StatVarsVmmon_Init(VMDriver *vm)
|
||||
{
|
||||
StatVarsVmmon *statVars;
|
||||
|
||||
statVars = HostIF_AllocKernelMem(sizeof *statVars, FALSE);
|
||||
if (statVars == NULL) {
|
||||
Warning("StatVars failed to allocate handle.\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(statVars, 0, sizeof *statVars);
|
||||
return statVars;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* StatVarsVmmon_Cleanup --
|
||||
*
|
||||
* Cleans up the stat vars component of the VM Driver by freeing all
|
||||
* previously allocated VMMon stat vars memory.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
StatVarsVmmon_Cleanup(StatVarsVmmon *statVars)
|
||||
{
|
||||
if (statVars == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (statVars->pages != NULL) {
|
||||
HostIF_FreeKernelMem(statVars->pages);
|
||||
}
|
||||
HostIF_FreeKernelMem(statVars);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* StatVarsVmmonValidateRegistration --
|
||||
*
|
||||
* Validate the given VMMon stat vars registration block.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the block is valid and can be used to register stat vars
|
||||
* backing pages for a VCPU, FALSE otherwise.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static Bool
|
||||
StatVarsVmmonValidateRegistration(VMDriver *vm,
|
||||
VMStatVarsRegistrationBlock *block)
|
||||
{
|
||||
Vcpuid vcpu = block->vcpu;
|
||||
PageCnt numPages = block->numPages;
|
||||
PageCnt pagesPerVcpu;
|
||||
MPN *pages;
|
||||
|
||||
if (vm == NULL ||
|
||||
vm->statVars == NULL ||
|
||||
numPages == 0 ||
|
||||
vcpu >= vm->numVCPUs) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pagesPerVcpu = vm->statVars->pagesPerVcpu;
|
||||
pages = vm->statVars->pages;
|
||||
if (pagesPerVcpu == 0) {
|
||||
ASSERT(pages == NULL);
|
||||
return TRUE;
|
||||
} else {
|
||||
return pagesPerVcpu == numPages &&
|
||||
pages[vcpu * pagesPerVcpu] == INVALID_MPN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* StatVarsVmmon_RegisterVCPU --
|
||||
*
|
||||
* Register stat vars backing pages for the given VCPU with VMMon.
|
||||
* A successful return value indicates that stat vars backing pages
|
||||
* for the given VCPU are locked and tracked by the VM Driver.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the backing pages were successfully registered for the
|
||||
* given VCPU, FALSE otherwise.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Bool
|
||||
StatVarsVmmon_RegisterVCPU(VMDriver *vm,
|
||||
VMStatVarsRegistrationBlock *block)
|
||||
{
|
||||
Vcpuid vcpu = block->vcpu;
|
||||
PageCnt pagesPerVcpu = block->numPages;
|
||||
StatVarsVmmon *statVars = vm->statVars;
|
||||
MPN *pages;
|
||||
PageCnt page;
|
||||
|
||||
HostIF_VMLock(vm, 45);
|
||||
if (!StatVarsVmmonValidateRegistration(vm, block)) {
|
||||
HostIF_VMUnlock(vm, 45);
|
||||
return FALSE;
|
||||
}
|
||||
if (statVars->pagesPerVcpu == 0) {
|
||||
PageCnt totalPages = pagesPerVcpu * vm->numVCPUs;
|
||||
statVars->pages = HostIF_AllocKernelMem(totalPages * sizeof *pages,
|
||||
FALSE);
|
||||
if (statVars->pages == NULL) {
|
||||
HostIF_VMUnlock(vm, 45);
|
||||
return FALSE;
|
||||
}
|
||||
for (page = 0; page < totalPages; page++) {
|
||||
statVars->pages[page] = INVALID_MPN;
|
||||
}
|
||||
statVars->pagesPerVcpu = pagesPerVcpu;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate that all pages in this VCPU's region are still invalid. Before
|
||||
* unlocking, temporarily set the first page to 0 to prevent a malicious user
|
||||
* from triggering an ASSERT by firing parallel ioctls for the same VCPU.
|
||||
*/
|
||||
pages = statVars->pages + vcpu * pagesPerVcpu;
|
||||
for (page = 0; page < pagesPerVcpu; page++) {
|
||||
ASSERT(pages[page] == INVALID_MPN);
|
||||
}
|
||||
ASSERT_ON_COMPILE(INVALID_MPN != 0);
|
||||
pages[0] = 0;
|
||||
HostIF_VMUnlock(vm, 45);
|
||||
|
||||
/*
|
||||
* Verify that all stat vars backing pages are locked. The pages are
|
||||
* assumed to remain locked either until they are unlocked by the VMX
|
||||
* following a NUMA migration, or by HostIF during VM Driver tear-down.
|
||||
*/
|
||||
for (page = 0; page < pagesPerVcpu; page++) {
|
||||
VPN vmxVPN = block->baseVpn + page;
|
||||
VA64 uAddr = VPN_2_VA(vmxVPN);
|
||||
PageCnt resetPage;
|
||||
MPN *currPage = pages + page;
|
||||
Bool verifiedLocked = FALSE;
|
||||
int status = Vmx86_LockPage(vm, uAddr, FALSE, currPage);
|
||||
|
||||
/*
|
||||
* Backing pages are expected to be locked by the VMX before being
|
||||
* registered.
|
||||
*/
|
||||
if (status == PAGE_LOCK_ALREADY_LOCKED) {
|
||||
verifiedLocked = TRUE;
|
||||
status = Vmx86_LookupUserMPN(vm, uAddr, currPage);
|
||||
/*
|
||||
* PR 2260615: Some platforms return PAGE_LOCK_SUCCESS for a successful
|
||||
* user MPN lookup, others return PAGE_LOOKUP_SUCCESS, but they both
|
||||
* happen to equal the same value.
|
||||
*/
|
||||
ASSERT_ON_COMPILE(PAGE_LOOKUP_SUCCESS == PAGE_LOCK_SUCCESS);
|
||||
if (status == PAGE_LOOKUP_SUCCESS) {
|
||||
/*
|
||||
* The backing page was verified as previously locked, and was
|
||||
* successfully recorded.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The backing page was either not previously locked, or was not recorded.
|
||||
* In either case, reset all previously recorded pages to INVALID_MPN.
|
||||
*/
|
||||
if (!verifiedLocked && status == PAGE_LOCK_SUCCESS) {
|
||||
status = Vmx86_UnlockPage(vm, uAddr);
|
||||
ASSERT(status == PAGE_UNLOCK_SUCCESS);
|
||||
}
|
||||
for (resetPage = 0; resetPage <= page; resetPage++) {
|
||||
pages[resetPage] = INVALID_MPN;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* StatVarsVmmon_GetRegionMPN --
|
||||
*
|
||||
* Obtain the backing MPN for stat vars for the given VCPU at
|
||||
* the given offset.
|
||||
*
|
||||
* Results:
|
||||
* The backing stat vars MPN for the given VCPU at the given offset
|
||||
* if it has been registered, or INVALID_MPN otherwise.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MPN
|
||||
StatVarsVmmon_GetRegionMPN(struct VMDriver *vm, Vcpuid vcpu, PageCnt offset)
|
||||
{
|
||||
MPN *pages;
|
||||
MPN backingPage;
|
||||
StatVarsVmmon *statVars = vm->statVars;
|
||||
|
||||
ASSERT(vcpu < vm->numVCPUs);
|
||||
|
||||
HostIF_VMLock(vm, 46);
|
||||
if (offset >= statVars->pagesPerVcpu) {
|
||||
HostIF_VMUnlock(vm, 46);
|
||||
Warning("(%s) Requested MPN at invalid offset %"FMT64"u for VCPU %u\n",
|
||||
__FUNCTION__, offset, vcpu);
|
||||
return INVALID_MPN;
|
||||
}
|
||||
|
||||
pages = statVars->pages + vcpu * statVars->pagesPerVcpu;
|
||||
backingPage = pages[offset];
|
||||
HostIF_VMUnlock(vm, 46);
|
||||
return backingPage;
|
||||
}
|
||||
+497
-1237
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2013,2015,2019-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2013 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -16,25 +16,26 @@
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef TASK_H
|
||||
#define TASK_H
|
||||
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
#include "bootstrap_vmm.h"
|
||||
|
||||
struct MonLoaderHeader;
|
||||
struct InitBlock;
|
||||
struct InitCrossGDT;
|
||||
|
||||
extern Bool Task_CreateCrossGDT(BSVMM_GDTInit *gdt);
|
||||
extern Bool Task_InitCrosspage(VMDriver *vm, LPN monStartLPN, LPN monEndLPN,
|
||||
PerVcpuPages *perVcpuPages);
|
||||
extern Bool Task_Switch(VMDriver *vm, Vcpuid vcpuid);
|
||||
extern Bool Task_AllocCrossGDT(struct InitBlock *initBlock);
|
||||
extern int Task_InitCrosspage(VMDriver *vm, struct InitBlock *params);
|
||||
extern int Task_InitCrossGDT(struct InitCrossGDT *initCrossGDT);
|
||||
extern void Task_Switch(VMDriver *vm, Vcpuid vcpuid);
|
||||
extern Bool Task_Initialize(void);
|
||||
extern void Task_Terminate(void);
|
||||
extern MPN Task_GetHVRootPageForPCPU(uint32 pCPU);
|
||||
extern Descriptor *Task_GetTmpGDT(uint32 pCPU);
|
||||
extern void Task_SwitchPTPPageCleanup(VMDriver *vm);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+522
-1303
File diff suppressed because it is too large.
Load diff
+48
-81
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2017 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -32,26 +32,23 @@
|
||||
#include "x86msr.h"
|
||||
#include "modulecall.h"
|
||||
#include "vcpuid.h"
|
||||
#include "initblock.h"
|
||||
#include "iocontrols.h"
|
||||
#include "numa_defs.h"
|
||||
#include "rateconv.h"
|
||||
#include "vmmem_shared.h"
|
||||
#include "apic.h"
|
||||
#include "bootstrap_vmm.h"
|
||||
#include "sharedAreaVmmon.h"
|
||||
#include "statVarsVmmon.h"
|
||||
|
||||
typedef struct PseudoTSCOffsetInfo {
|
||||
uint32 inVMMCnt; /* Number of vcpus executing in the VMM. */
|
||||
uint32 vcpuid; /* Index into VMDriver.ptscOffsets. */
|
||||
} PseudoTSCOffsetInfo;
|
||||
|
||||
typedef struct TSCDelta {
|
||||
Atomic_uint64 min;
|
||||
Atomic_uint64 max;
|
||||
} TSCDelta;
|
||||
|
||||
struct VmmBlobInfo;
|
||||
|
||||
struct HostIFContigMemMap;
|
||||
|
||||
extern struct HostIFContigMemMap *hvIOBitmap;
|
||||
|
||||
/*
|
||||
* VMDriver - the main data structure for the driver side of a
|
||||
* virtual machine.
|
||||
@@ -59,43 +56,31 @@ extern struct HostIFContigMemMap *hvIOBitmap;
|
||||
|
||||
typedef struct VMDriver {
|
||||
/* Unique (in the driver), strictly positive, VM ID used by userland. */
|
||||
int userID;
|
||||
Vcpuid numVCPUs; /* Number of vcpus in VM. */
|
||||
struct VMDriver *nextDriver; /* Next on list of all VMDrivers */
|
||||
struct VMHost *vmhost; /* Host-specific fields. */
|
||||
MPN *ptRootMpns; /* numVCPUs-sized array. */
|
||||
struct VmmBlobInfo *blobInfo; /* VMM bootstrap blob info. */
|
||||
SharedAreaVmmon *sharedArea; /* VMMon shared area info. */
|
||||
StatVarsVmmon *statVars; /* VMMon stat vars info. */
|
||||
int userID;
|
||||
|
||||
struct VMDriver *nextDriver; /* Next on list of all VMDrivers */
|
||||
|
||||
Vcpuid numVCPUs; /* Number of vcpus in VM. */
|
||||
struct VMHost *vmhost; /* Host-specific fields. */
|
||||
|
||||
/* Pointers to the crossover pages shared with the monitor. */
|
||||
struct VMCrossPageData **crosspage; /* numVCPUs-sized array. */
|
||||
struct MemTrack *ptpTracker; /* Tracks page table patch pages */
|
||||
struct MemTrack *vmmTracker; /* Tracks allocated VMM pages */
|
||||
VCPUSet *crosscallWaitSet; /* numVCPUs-sized array. */
|
||||
APICDescriptor hostAPIC;
|
||||
struct MemTrack *memtracker; /* Memory tracker pointer */
|
||||
Bool checkFuncFailed;
|
||||
struct PerfCounter *perfCounter;
|
||||
VMMemMgmtInfo memInfo;
|
||||
unsigned fastClockRate; /* Protected by FastClockLock. */
|
||||
Atomic_uint64 ptscOffsetInfo; /* Volatile per PR 699101#29. */
|
||||
Atomic_uint64 ptscLatest;
|
||||
int64 *ptscOffsets; /* numVCPUs-sized array. */
|
||||
Atomic_uint32 *currentHostCpu; /* numVCPUs-sized array. */
|
||||
PageCnt numPTPPages; /* Num PTP pages allocated. */
|
||||
/*
|
||||
* List of physically contiguous allocations associated with this VM.
|
||||
* Access is protected by the VM lock.
|
||||
*/
|
||||
struct HostIFContigMemMap *contigMappings;
|
||||
struct VMCrossPage *crosspage[MAX_INITBLOCK_CPUS];
|
||||
volatile uint32 currentHostCpu[MAX_INITBLOCK_CPUS];
|
||||
VCPUSet crosscallWaitSet[MAX_INITBLOCK_CPUS];
|
||||
APICDescriptor hostAPIC;
|
||||
|
||||
struct MemTrack *memtracker; /* Memory tracker pointer */
|
||||
Bool checkFuncFailed;
|
||||
struct PerfCounter *perfCounter;
|
||||
VMMemMgmtInfo memInfo;
|
||||
unsigned fastClockRate;/* Protected by FastClockLock. */
|
||||
int fastSuspResFlag;
|
||||
|
||||
volatile PseudoTSCOffsetInfo ptscOffsetInfo; /* Volatile per PR 699101#29. */
|
||||
Atomic_uint64 ptscLatest;
|
||||
int64 ptscOffsets[MAX_INITBLOCK_CPUS];
|
||||
} VMDriver;
|
||||
|
||||
typedef struct MonLoaderArgs {
|
||||
VMDriver *vm;
|
||||
VMSharedRegion *shRegions;
|
||||
} MonLoaderArgs;
|
||||
|
||||
typedef struct VmTimeStart {
|
||||
uint64 count;
|
||||
uint64 time;
|
||||
@@ -118,21 +103,12 @@ typedef struct PseudoTSC {
|
||||
|
||||
extern PseudoTSC pseudoTSC;
|
||||
|
||||
#define MAX_LOCKED_PAGES MAX_PPN
|
||||
#define MAX_LOCKED_PAGES (-1)
|
||||
|
||||
extern void Vmx86_CacheNXState(void);
|
||||
extern VMDriver *Vmx86_CreateVM(VA64 bsBlob,
|
||||
uint32 bsBlobSize,
|
||||
uint32 numVCPUs);
|
||||
extern Bool Vmx86_ProcessBootstrap(VMDriver *vm,
|
||||
VA64 bsBlobAddr,
|
||||
uint32 numBytes,
|
||||
uint32 headerOffset,
|
||||
uint16 numVCPUs,
|
||||
PerVcpuPages *perVcpuPages,
|
||||
VMSharedRegion *shRegions);
|
||||
extern VMDriver *Vmx86_CreateVM(void);
|
||||
extern int Vmx86_LookupUserMPN(VMDriver *vm, VA64 uAddr, MPN *mpn);
|
||||
extern int Vmx86_ReleaseVM(VMDriver *vm);
|
||||
extern int Vmx86_InitVM(VMDriver *vm, InitBlock *initParams);
|
||||
extern int Vmx86_LateInitVM(VMDriver *vm);
|
||||
extern int Vmx86_RunVM(VMDriver *vm, Vcpuid vcpuid);
|
||||
extern void Vmx86_YieldToSet(VMDriver *vm, Vcpuid currVcpu, const VCPUSet *req,
|
||||
@@ -149,21 +125,19 @@ extern int Vmx86_UnlockPage(VMDriver *vm, VA64 uAddr);
|
||||
extern int Vmx86_UnlockPageByMPN(VMDriver *vm, MPN mpn, VA64 uAddr);
|
||||
extern MPN Vmx86_GetRecycledPage(VMDriver *vm);
|
||||
extern int Vmx86_ReleaseAnonPage(VMDriver *vm, MPN mpn);
|
||||
extern int64 Vmx86_AllocLockedPages(VMDriver *vm, VA64 addr,
|
||||
PageCnt numPages, Bool kernelMPNBuffer,
|
||||
Bool ignoreLimits);
|
||||
extern int Vmx86_FreeLockedPages(VMDriver *vm, MPN *mpns, PageCnt numPages);
|
||||
extern int Vmx86_AllocLockedPages(VMDriver *vm, VA64 addr,
|
||||
unsigned numPages, Bool kernelMPNBuffer,
|
||||
Bool ignoreLimits);
|
||||
extern int Vmx86_FreeLockedPages(VMDriver *vm, VA64 addr,
|
||||
unsigned numPages, Bool kernelMPNBuffer);
|
||||
extern MPN Vmx86_GetNextAnonPage(VMDriver *vm, MPN mpn);
|
||||
extern MPN Vmx86_GetNumAnonPages(VMDriver *vm);
|
||||
extern MPN Vmx86_AllocLowPage(VMDriver *vm, Bool ignoreLimits);
|
||||
extern void *Vmx86_Calloc(size_t numElements,
|
||||
size_t elementSize,
|
||||
Bool nonPageable);
|
||||
extern void Vmx86_Free(void *ptr);
|
||||
extern int Vmx86_GetLockedPageList(VMDriver *vm, VA64 uAddr,
|
||||
unsigned int numPages);
|
||||
|
||||
extern int32 Vmx86_GetNumVMs(void);
|
||||
extern Bool Vmx86_SetConfiguredLockedPagesLimit(PageCnt limit);
|
||||
extern void Vmx86_SetDynamicLockedPagesLimit(PageCnt limit);
|
||||
extern int32 Vmx86_GetTotalMemUsage(void);
|
||||
extern Bool Vmx86_SetConfiguredLockedPagesLimit(unsigned limit);
|
||||
extern void Vmx86_SetDynamicLockedPagesLimit(unsigned limit);
|
||||
extern Bool Vmx86_GetMemInfo(VMDriver *curVM,
|
||||
Bool curVMOnly,
|
||||
VMMemInfoArgs *args,
|
||||
@@ -173,15 +147,15 @@ extern Bool Vmx86_Readmit(VMDriver *curVM, OvhdMem_Deltas *delta);
|
||||
extern void Vmx86_UpdateMemInfo(VMDriver *curVM,
|
||||
const VMMemMgmtInfoPatch *patch);
|
||||
extern void Vmx86_Add2MonPageTable(VMDriver *vm, VPN vpn, MPN mpn,
|
||||
Bool readOnly);
|
||||
Bool readOnly);
|
||||
extern Bool Vmx86_PAEEnabled(void);
|
||||
extern Bool Vmx86_VMXEnabled(void);
|
||||
extern Bool Vmx86_GetAllMSRs(MSRQuery *query);
|
||||
extern Bool Vmx86_CheckMSRUniformity(void);
|
||||
extern void Vmx86_FlushVMCSAllCPUs(MA vmcs);
|
||||
extern void Vmx86_MonTimerIPI(void);
|
||||
extern void Vmx86_InitIDList(void);
|
||||
extern Bool Vmx86_CreateHVIOBitmap(void);
|
||||
extern void Vmx86_CleanupHVIOBitmap(void);
|
||||
extern Bool Vmx86_GetPageRoot(VMDriver *vm, Vcpuid vcpuid, MPN *mpn);
|
||||
extern VMDriver *Vmx86_LookupVMByUserID(int userID);
|
||||
extern Bool Vmx86_FastSuspResSetOtherFlag(VMDriver *vm, int otherVmUserId);
|
||||
extern int Vmx86_FastSuspResGetMyFlag(VMDriver *vm, Bool blockWait);
|
||||
extern void Vmx86_Open(void);
|
||||
extern void Vmx86_Close(void);
|
||||
|
||||
@@ -225,11 +199,4 @@ extern uint64 Vmx86_GetPseudoTSC(void);
|
||||
|
||||
extern uint64 Vmx86_GetUnavailablePerfCtrs(void);
|
||||
|
||||
extern Bool Vmx86_GetMonitorContext(VMDriver *vm, Vcpuid vcpuid,
|
||||
Context64 *context);
|
||||
extern void Vmx86_CleanupVMMPages(VMDriver *vm);
|
||||
|
||||
extern VPN Vmx86_MapPage(MPN mpn);
|
||||
extern void Vmx86_UnmapPage(VPN vpn);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -36,11 +36,6 @@
|
||||
|
||||
#include "vm_basic_defs.h" // For PAGE_SHIFT
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Virtual, physical, machine address and page conversion macros
|
||||
*/
|
||||
@@ -97,9 +92,4 @@ IsGoodMPNOrMemref(MPN mpn)
|
||||
return IsGoodMPN(mpn) || mpn == MEMREF_MPN;
|
||||
}
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _ADDRESS_DEFS_H_
|
||||
@@ -1,319 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2007-2020 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
#ifndef _ADDRLAYOUT_H_
|
||||
#define _ADDRLAYOUT_H_
|
||||
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_VMX
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "vm_basic_types.h"
|
||||
#include "vm_basic_defs.h"
|
||||
#include "address_defs.h"
|
||||
#include "x86desc.h"
|
||||
#include "x86types.h"
|
||||
#include "vmm_constants.h"
|
||||
|
||||
#define DIRECT_EXEC_USER_RPL 3
|
||||
#define BINARY_TRANSLATION_RPL 1
|
||||
typedef char x86_PAGE[PAGE_SIZE];
|
||||
|
||||
#define MAX_VADDR CONST64U(0xffffffffffffffff)
|
||||
#define MONITOR_SIZE (64 * 1024 * 1024)
|
||||
#define MONITOR_LINEAR_START (MAX_VADDR - MONITOR_SIZE + 1)
|
||||
#define MONITOR_LINEAR_END (MAX_VADDR)
|
||||
#define NUM_MONITOR_PAGES (MONITOR_SIZE / PAGE_SIZE)
|
||||
#define MONITOR_BASE_VPN (MONITOR_LINEAR_START >> PAGE_SHIFT)
|
||||
|
||||
#define MONITOR_AS_START MONITOR_BASE_VPN
|
||||
#define MONITOR_AS_LEN NUM_MONITOR_PAGES
|
||||
|
||||
/*
|
||||
* Regions and items necessarily overlap. Build parallel structures for each.
|
||||
* These 'field' structures are used to determine page numbers and offsets.
|
||||
* AddrLayout contains zero-length regions used for alignment-checking. (These
|
||||
* are used by gcc as Windows prohibits zero-length arrays.)
|
||||
*/
|
||||
|
||||
/* Item layout. */
|
||||
typedef struct {
|
||||
#if defined __GNUC__
|
||||
#define REGION(name, length) x86_PAGE name##_REGION_MARKER_FIELD[0];
|
||||
#else
|
||||
#define REGION(name, length)
|
||||
#endif
|
||||
#define ITEM(name, length) x86_PAGE name##_FIELD[length];
|
||||
#include "addrlayout_table.h"
|
||||
} AddrLayout;
|
||||
#undef REGION
|
||||
#undef ITEM
|
||||
#define FIELD_PAGE_NUMBER(name) PAGE_NUMBER(&(((AddrLayout *)0)->name##_FIELD))
|
||||
|
||||
|
||||
/* Region layout. */
|
||||
typedef struct {
|
||||
#define REGION(name, length) x86_PAGE name##_REGION_FIELD[length];
|
||||
#define ITEM(name, length)
|
||||
#include "addrlayout_table.h"
|
||||
} RegionAddrLayout;
|
||||
#undef REGION
|
||||
#undef ITEM
|
||||
#define REGION_FIELD_PAGE_NUMBER(name) \
|
||||
PAGE_NUMBER(&(((RegionAddrLayout *)0)->name##_REGION_FIELD))
|
||||
|
||||
#if defined __GNUC__
|
||||
/*
|
||||
* The sum of sizes of items in a region must add up to the region's size.
|
||||
* AddrLayout contains zero-sized region markers at their correct offsets.
|
||||
* RegionAddrLayout contains full-sized regions (but no items). Comparing the
|
||||
* marker and region offsets ensures that all items sizes in the previous
|
||||
* region sum to the size of the previous region. To check the final region
|
||||
* (as it has no successor) we assert the sizes of the tables match.
|
||||
*
|
||||
* We also assert 2MB region granularity.
|
||||
*
|
||||
* This checking is only performed when using gcc.
|
||||
*/
|
||||
#define REGION(name, length) static INLINE void name(void) { \
|
||||
ASSERT_ON_COMPILE(FIELD_PAGE_NUMBER(name##_REGION_MARKER) == \
|
||||
REGION_FIELD_PAGE_NUMBER(name)); \
|
||||
ASSERT_ON_COMPILE((length % 512) == 0); \
|
||||
ASSERT_ON_COMPILE(sizeof(AddrLayout) == sizeof(RegionAddrLayout)); \
|
||||
ASSERT_ON_COMPILE(sizeof(RegionAddrLayout) == MONITOR_SIZE); \
|
||||
}
|
||||
#define ITEM(name, length)
|
||||
#include "addrlayout_table.h"
|
||||
#undef REGION
|
||||
#undef ITEM
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Sizes.
|
||||
*/
|
||||
|
||||
enum {
|
||||
#define REGION(name, length) name##_REGION_LEN = length,
|
||||
#define ITEM(name, length) name##_LEN = length,
|
||||
#include "addrlayout_table.h"
|
||||
};
|
||||
#undef REGION
|
||||
#undef ITEM
|
||||
|
||||
/*
|
||||
* Starts.
|
||||
*/
|
||||
|
||||
#if defined __GNUC__
|
||||
/* Windows compiler and gdb do not accept 64-bit enumerations, but gcc
|
||||
* does. These are used by geninfo.c.
|
||||
*/
|
||||
enum {
|
||||
#define REGION(name, length) _asm_##name##_REGION_START = \
|
||||
0ULL + MONITOR_BASE_VPN + REGION_FIELD_PAGE_NUMBER(name),
|
||||
#define ITEM(name, length) _asm_##name##_START = \
|
||||
0ULL + MONITOR_BASE_VPN + FIELD_PAGE_NUMBER(name),
|
||||
#include "addrlayout_table.h"
|
||||
};
|
||||
#undef REGION
|
||||
#undef ITEM
|
||||
|
||||
enum {
|
||||
#define REGION(name, length) name##_REGION_START = \
|
||||
MONITOR_BASE_VPN + REGION_FIELD_PAGE_NUMBER(name),
|
||||
#define ITEM(name, length) name##_START = \
|
||||
MONITOR_BASE_VPN + FIELD_PAGE_NUMBER(name),
|
||||
#include "addrlayout_table.h"
|
||||
};
|
||||
#undef REGION
|
||||
#undef ITEM
|
||||
|
||||
#else
|
||||
#define REGION(name, length) \
|
||||
static const uint64 name##_REGION_START = \
|
||||
MONITOR_BASE_VPN + REGION_FIELD_PAGE_NUMBER(name);
|
||||
#define ITEM(name, length) \
|
||||
static const uint64 name##_START = \
|
||||
MONITOR_BASE_VPN + FIELD_PAGE_NUMBER(name);
|
||||
#include "addrlayout_table.h"
|
||||
#undef REGION
|
||||
#undef ITEM
|
||||
#endif
|
||||
|
||||
enum {
|
||||
#define REGION(name, length) name##_REGION_start_page = \
|
||||
REGION_FIELD_PAGE_NUMBER(name),
|
||||
#define ITEM(name, length) name##_start_page = \
|
||||
FIELD_PAGE_NUMBER(name),
|
||||
#include "addrlayout_table.h"
|
||||
};
|
||||
#undef REGION
|
||||
#undef ITEM
|
||||
|
||||
|
||||
/* Derive the bootstrap start address from table contents. */
|
||||
#define MONITOR_BOOTSTRAP_START_LA VPN_2_VA(BS_TXT_START)
|
||||
|
||||
#ifndef VMX86_SERVER
|
||||
#define SWITCH_PAGE_TABLE_LEN 12
|
||||
#endif
|
||||
|
||||
#define VMM_STACK_TOP_HW VPN_2_VA(MON_STACK_PAGES_START + \
|
||||
MON_STACK_PAGES_LEN)
|
||||
/*
|
||||
* VMM_STKTOP_HW_LEN needs to contain an ExcFrame64ForCopy (72 bytes) and
|
||||
* some more bytes for a "no man's land" region. We make sure the "no
|
||||
* man's land" region is 0 on BT_Resume and HV_Resume. Because we
|
||||
* check "no man's land" in 8-byte chunks, VMM_STKTOP_HW_LEN must be
|
||||
* divisible by 8.
|
||||
*/
|
||||
#define VMM_STKTOP_HW_LEN 168
|
||||
#define VMM_STKTOP_HW_LRET_LEN (VMM_STKTOP_HW_LEN + sizeof(LretFrame64))
|
||||
#define VMM_STKTOP_LRET_OFFSET (PAGE_SIZE - VMM_STKTOP_HW_LRET_LEN)
|
||||
|
||||
#define MON_STACK_BASE VPN_2_VA(MON_STACK_PAGES_START)
|
||||
#define MON_STACK_TOP VPN_2_VA(MON_STACK_PAGES_START + \
|
||||
MON_STACK_PAGES_LEN)
|
||||
#define DF_STACK_BASE VPN_2_VA(DF_STACK_PAGES_START)
|
||||
#define DF_STACK_TOP VPN_2_VA(DF_STACK_PAGES_START + \
|
||||
DF_STACK_PAGES_LEN)
|
||||
#define MC_STACK_BASE VPN_2_VA(MC_STACK_PAGES_START)
|
||||
#define MC_STACK_TOP VPN_2_VA(MC_STACK_PAGES_START + \
|
||||
MC_STACK_PAGES_LEN)
|
||||
#define NMI_STACK_BASE VPN_2_VA(NMI_STACK_PAGES_START)
|
||||
#define NMI_STACK_TOP VPN_2_VA(NMI_STACK_PAGES_START + \
|
||||
NMI_STACK_PAGES_LEN)
|
||||
|
||||
#define NUM_MON_PTABS MON_PAGE_TABLE_L1_LEN
|
||||
|
||||
#define MON_START_L5OFF PT_LA_2_L5OFF(MONITOR_LINEAR_START)
|
||||
#define MON_START_L4OFF PT_LA_2_L4OFF(MONITOR_LINEAR_START)
|
||||
#define MON_START_L3OFF PT_LA_2_L3OFF(MONITOR_LINEAR_START)
|
||||
#define MON_START_L2OFF PT_LA_2_L2OFF(MONITOR_LINEAR_START)
|
||||
|
||||
/*
|
||||
* Allocated wired pages for the monitor.
|
||||
* Currently we allocate wired pages for the:
|
||||
* 0) The shared area between user and monitor;
|
||||
* a) GDT of the monitor
|
||||
* a1) BT (CP1) stack
|
||||
* b) The monitor's page table with one page directory under 4 GB
|
||||
* and two page table pages.
|
||||
* c) Pages for the monitor's stack.
|
||||
* d) The BT area pages
|
||||
* e) The cross driver/monitor page.
|
||||
* f) The physical memory array for the machine.
|
||||
* g) The SMRAM memory
|
||||
*
|
||||
* We allocate the shared area separately since it must be read/write
|
||||
* in the monitor. See SharedArea_PowerOn().
|
||||
*/
|
||||
|
||||
#define MON_BOOTSTRAP_PAGE_TABLE_PAGES (BOOTSTRAP_REGION_LEN / \
|
||||
PAE_PTES_PER_PGTBL)
|
||||
#ifdef VMX86_SERVER
|
||||
#define NUM_MONWIRED_PAGES 0
|
||||
|
||||
#define MON_PAGE_TABLE_ALLOC_PAGES 0
|
||||
#define NUM_MONWIRED_BOOTSTRAP_PAGES 0
|
||||
|
||||
#define NUM_MONWIRED_NUMA_PAGES_ML (MON_STACK_PAGES_LEN + \
|
||||
DF_STACK_PAGES_LEN + \
|
||||
MC_STACK_PAGES_LEN + \
|
||||
NMI_STACK_PAGES_LEN + \
|
||||
HV_CURRENT_VMCB_LEN + \
|
||||
IDT_NORMAL_LEN + \
|
||||
GDT_AND_TASK_LEN)
|
||||
|
||||
#else
|
||||
#define NUM_MONWIRED_PAGES (CROSS_PAGE_CODE_LEN + \
|
||||
CROSS_PAGE_DATA_LEN + \
|
||||
MON_PAGE_TABLE_L4_LEN + \
|
||||
MON_PAGE_TABLE_L3_LEN + \
|
||||
MON_PAGE_TABLE_L2_LEN)
|
||||
|
||||
#define MON_PAGE_TABLE_ALLOC_PAGES ((MONITOR_READONLY_REGION_LEN + \
|
||||
MONITOR_DATA_REGION_LEN + \
|
||||
MONITOR_MISC_REGION_LEN) / \
|
||||
PAE_PTES_PER_PGTBL)
|
||||
|
||||
#define NUM_MONWIRED_BOOTSTRAP_PAGES MON_BOOTSTRAP_PAGE_TABLE_PAGES
|
||||
|
||||
#define NUM_MONWIRED_NUMA_PAGES_ML (MON_STACK_PAGES_LEN + \
|
||||
DF_STACK_PAGES_LEN + \
|
||||
MC_STACK_PAGES_LEN + \
|
||||
NMI_STACK_PAGES_LEN + \
|
||||
GDT_AND_TASK_LEN + \
|
||||
IDT_NORMAL_LEN + \
|
||||
HV_CURRENT_VMCB_LEN + \
|
||||
SWITCH_PAGE_TABLE_LEN)
|
||||
#endif
|
||||
|
||||
#define MON_PAGE_TABLE_L5 VPN_2_VA(MON_PAGE_TABLE_L5_START)
|
||||
#define MON_PAGE_TABLE_L4 VPN_2_VA(MON_PAGE_TABLE_L4_START)
|
||||
#define VMM_STACK_TOP (VMM_STACK_TOP_HW - VMM_STKTOP_HW_LEN)
|
||||
#define VMM_LRET_STACK_TOP (VMM_STACK_TOP_HW - VMM_STKTOP_HW_LRET_LEN)
|
||||
/*
|
||||
* Mark out a guard page for the VMM stack, this is not in the addrlayout_table
|
||||
* explicitly because it overlaps the last page of the MONITOR_READONLY region.
|
||||
*/
|
||||
#define VMM_STACK_GUARD_START MON_STACK_PAGES_START
|
||||
#define VMM_STACK_GUARD_LEN PAGE_SIZE
|
||||
|
||||
/*
|
||||
* Following functions return true if the range [va, va+len) is within
|
||||
* range of a particular monitor stack. (Don't adjust without
|
||||
* considering uint64 overflow when va is very high.)
|
||||
*/
|
||||
static INLINE Bool
|
||||
AddrLayout_InMonStack(VA64 va, size_t len)
|
||||
{
|
||||
return VPN_2_VA(MON_STACK_PAGES_START) <= va &&
|
||||
va <= VMM_STACK_TOP_HW - len;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
AddrLayout_InNMIStack(VA64 va, size_t len)
|
||||
{
|
||||
return va >= NMI_STACK_BASE && va <= NMI_STACK_TOP - len;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
AddrLayout_InDFStack(VA64 va, size_t len)
|
||||
{
|
||||
return va >= DF_STACK_BASE && va <= DF_STACK_TOP - len;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
AddrLayout_InMCStack(VA64 va, size_t len)
|
||||
{
|
||||
return va >= MC_STACK_BASE && va <= MC_STACK_TOP - len;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
AddrLayout_InAMonitorStack(VA va, size_t len)
|
||||
{
|
||||
return AddrLayout_InMonStack(va, len) ||
|
||||
AddrLayout_InNMIStack(va, len) ||
|
||||
AddrLayout_InDFStack(va, len) ||
|
||||
AddrLayout_InMCStack(va, len);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,144 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2020 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* addrlayout_table.h --
|
||||
*
|
||||
* Named elements in the monitor's address space of fixed size and location.
|
||||
* All units are 4 kilobyte pages. Also used for vmmlayout output.
|
||||
*
|
||||
* The monitor's address space is populated three different ways:
|
||||
* 1) For elements of a fixed size and location, at compile-time.
|
||||
* 2) For well-known program sections and the shared area, at link-time.
|
||||
* 3) Dynamically, by the allocator, during bootstrapping and monitor power-on.
|
||||
*
|
||||
* This file describes all of the monitor's main 64MB address space. All of
|
||||
* (1) is described specifically. Ranges for (2) and (3) are accounted for,
|
||||
* but their contents are described generally here.
|
||||
*
|
||||
* The monitor's address space is organized into container regions which are an
|
||||
* integer number of 2MB "large" pages. Within a container region, items
|
||||
* comprised of one or more 4KB pages may be described.
|
||||
*
|
||||
* All container regions and items are described by a name and a size in pages.
|
||||
* No two items may have the same name nor may two regions.
|
||||
*
|
||||
* REGION(region-name, number-of-pages)
|
||||
* ITEM(item-name, number-of-pages) // first item in region
|
||||
* ITEM(item-name, number-of-pages) // second item in region
|
||||
* <...>
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Monitor .rodata/.text. Mapped large (reducing TLB pressure) and read-only.
|
||||
*/
|
||||
REGION(MONITOR_READONLY, 1024)
|
||||
ITEM(MONITOR_READONLY_LINKER, 1024) // Used by linker.
|
||||
|
||||
/*
|
||||
* Monitor .data/.bss. Mapped large (reducing TLB pressure) and read-write.
|
||||
*/
|
||||
REGION(MONITOR_DATA, 512)
|
||||
ITEM(MON_STACK_PAGES, 8) // Monitor stack.
|
||||
ITEM(IDT_NORMAL, 1) // Normal IDT (used for all but SVM).
|
||||
ITEM(MONITOR_DATA, 503) // Used by linker and TC.
|
||||
|
||||
/*
|
||||
* The monitor's translation cache. This object starts at the page boundary
|
||||
* following the end of the used space in MONITOR_DATA and extends through
|
||||
* the TC_REGION.
|
||||
*/
|
||||
REGION(TC_REGION, 1024)
|
||||
ITEM(TC_BLOCK, 1024)
|
||||
|
||||
/*
|
||||
* The monitor's pages for architectural state, stacks, page tables, shared
|
||||
* pages, and dynamic allocation. This region also contains the linked shared
|
||||
* area and other contents.
|
||||
* Mapped small (allowing non-present mappings and sharing) and read-write.
|
||||
*/
|
||||
REGION(MONITOR_MISC, 5632)
|
||||
#ifdef VMX86_SERVER
|
||||
ITEM(GUARD_PAGE, 2) // Reserved (for symmetry with hosted).
|
||||
#else
|
||||
ITEM(CROSS_PAGE_DATA, 1) // Cross page data (RW).
|
||||
ITEM(CROSS_PAGE_CODE, 1) // Cross page code (RX).
|
||||
#endif
|
||||
ITEM(GDT_AND_TASK, 1) // GDT and Task State Segment.
|
||||
|
||||
ITEM(MON_PAGE_TABLE_L5, 1) // Monitor page root, if 5-Level PT used.
|
||||
ITEM(MON_PAGE_TABLE_L4, 1) // Monitor page root, if 4-Level PT used.
|
||||
ITEM(MON_PAGE_TABLE_L3, 1) // Monitor L3 page table.
|
||||
ITEM(MON_PAGE_TABLE_L2, 1) // Monitor L2 page table.
|
||||
ITEM(MON_PAGE_TABLE_L1, 32) // Monitor L1 page tables.
|
||||
|
||||
ITEM(HOST_APIC, 1) // Physical APIC.
|
||||
ITEM(GUEST_APIC, 1) // Guest APIC.
|
||||
|
||||
ITEM(DF_GUARD_PAGE, 1) // Double Fault stack guard page.
|
||||
ITEM(DF_STACK_PAGES, 1) // Double Fault stack; need ~768 bytes.
|
||||
|
||||
ITEM(MC_GUARD_PAGE, 1) // Machine Check stack guard page.
|
||||
ITEM(MC_STACK_PAGES, 1) // Machine Check stack.
|
||||
|
||||
ITEM(NMI_GUARD_PAGE, 1) // NMI stack guard page.
|
||||
ITEM(NMI_STACK_PAGES, 4) // NMI stack. Profiling requires a larger
|
||||
// stack than MC/DF.
|
||||
|
||||
ITEM(HV_SWITCH, 1) // SVM switch page
|
||||
ITEM(HV_CURRENT_VMCB, 1) // SVM current VMCB
|
||||
ITEM(HV_STD_NATIVE_VMCB, 1) // SVM/VT standard VMCB/VMCS
|
||||
ITEM(HV_AUX_NATIVE_VMCB, 1) // SVM/VT auxiliary VMCB/VMCS
|
||||
ITEM(VHV_GUEST_VMCB, 1) // VSVM/VVT guest VMCB/VMCS
|
||||
ITEM(HV_SEV_VMSA, 1) // SVM SEV-ES state save area
|
||||
ITEM(VPROBE_MON_RELOC, 1) // VProbe monitor reloc page.
|
||||
ITEM(GART_LIST_PAGES, 48) // PhysMem vmm gart list pages.
|
||||
ITEM(GART_ALT_LIST_PAGES, 48) // Alternate vmm gart pages
|
||||
// (for invalidation).
|
||||
ITEM(GART_BF_PAGES, 8) // Gart Bloom filter memory pages.
|
||||
ITEM(VVT_GUEST_VIRT_APIC, 1) // Inner guest virtual APIC page.
|
||||
ITEM(HT_STATE_MAP, 8) // Information used by the SecureHT module
|
||||
ITEM(SHARED_RW_DATA, 5462) // R/W shared data, including the shared
|
||||
// area and stat vars. Any remaining pages
|
||||
// are left to the dynamic allocator, which
|
||||
// extends throughout the entire reclaimed
|
||||
// bootstrap region.
|
||||
/*
|
||||
* Bootstrap-used space. This space is reclaimed when bootstrap is done, and
|
||||
* is used by the allocator thereafter. The allocator starts at the first
|
||||
* unused page in the SHARED_RW_DATA item from the MONITOR_MISC region and
|
||||
* extends through to the end of the VMM address space once the bootstrap region
|
||||
* is reclaimed.
|
||||
*/
|
||||
REGION(BOOTSTRAP, 8192)
|
||||
ITEM(BS_TXT, 17) // bootstrap's .text
|
||||
ITEM(BS_RODATA, 10) // bootstrap's .rodata
|
||||
ITEM(BS_DATA, 10) // bootstrap's .data
|
||||
ITEM(BS_BSS, 10) // bootstrap's .bss
|
||||
ITEM(BS_HEADER, 1) // MonLoaderHeader mapping
|
||||
ITEM(BS_VCPU_L1PT_RANGE, 32) // VCPU L1PT mappings
|
||||
ITEM(BS_VCPU_L1PT_PT, 1) // L1PT that maps a VCPU's L1 page tables
|
||||
ITEM(BS_INIT_POOL, 1) // pool for initializing VMM pages
|
||||
ITEM(BS_DYNAMIC_ALLOC, 1880) // bs_alloc's dynamic allocator pages
|
||||
ITEM(IDT_BOOTSTRAP, 1) // bootstrap IDT
|
||||
ITEM(IDT_BOOTSTRAP_STUBS, 2) // bootstrap IDT gate stubs
|
||||
ITEM(BS_PER_VM_VMX, 300) // vmm64's shared_per_vm_vmx
|
||||
ITEM(BS_PER_VCPU, 8) // vmm64's shared_per_vcpu for VCPU 0
|
||||
ITEM(BS_PER_VCPU_VMX, 136) // vmm64's shared_per_vcpu_vmx for VCPU 0
|
||||
ITEM(VMM_MODULES, 5783) // ~22.6MB for unlinked VMM modules
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2018-2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2006 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -17,32 +17,44 @@
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* statVarsVmmon.h --
|
||||
* basic_initblock.h --
|
||||
*
|
||||
* VMMon stat vars management.
|
||||
* VM initialization block.
|
||||
*/
|
||||
|
||||
#ifndef STAT_VARS_VMMON_H
|
||||
#define STAT_VARS_VMMON_H
|
||||
#ifndef _BASIC_INITBLOCK_H_
|
||||
#define _BASIC_INITBLOCK_H_
|
||||
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_VMK_MODULE
|
||||
#define INCLUDE_ALLOW_DISTRIBUTE
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "iocontrols.h"
|
||||
|
||||
struct VMDriver;
|
||||
#include "vcpuid.h"
|
||||
|
||||
/* The VMMon Driver stat vars area. */
|
||||
typedef struct StatVarsVmmon {
|
||||
PageCnt pagesPerVcpu;
|
||||
MPN *pages;
|
||||
} StatVarsVmmon;
|
||||
|
||||
StatVarsVmmon *StatVarsVmmon_Init(struct VMDriver *vm);
|
||||
void StatVarsVmmon_Cleanup(StatVarsVmmon *statVars);
|
||||
Bool StatVarsVmmon_RegisterVCPU(struct VMDriver *driver,
|
||||
VMStatVarsRegistrationBlock *block);
|
||||
MPN StatVarsVmmon_GetRegionMPN(struct VMDriver *vm, Vcpuid vcpuid,
|
||||
PageCnt offset);
|
||||
#endif /* STAT_VARS_VMMON_H */
|
||||
#define MAX_INITBLOCK_CPUS 128
|
||||
|
||||
|
||||
typedef
|
||||
#include "vmware_pack_begin.h"
|
||||
struct InitBlock {
|
||||
uint32 magicNumber; /* Magic number (INIT_BLOCK_MAGIC) */
|
||||
Vcpuid numVCPUs;
|
||||
VA64 crosspage[MAX_INITBLOCK_CPUS];
|
||||
uint32 vmInitFailurePeriod;
|
||||
LA64 crossGDTHKLA;
|
||||
MPN crossGDTMPNs[5]; // CROSSGDT_NUMPAGES
|
||||
}
|
||||
#include "vmware_pack_end.h"
|
||||
InitBlock;
|
||||
|
||||
|
||||
#endif // _BASIC_INITBLOCK_H_
|
||||
@@ -1,65 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2015,2017 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* bootstrap_vmm.h --
|
||||
*
|
||||
* Public VMM bootstrap declarations.
|
||||
*/
|
||||
|
||||
#ifndef _BOOTSTRAP_VMM_H
|
||||
#define _BOOTSTRAP_VMM_H
|
||||
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
|
||||
#include "includeCheck.h"
|
||||
#include "vm_basic_types.h"
|
||||
#include "monAddrLayout.h"
|
||||
|
||||
#define BOOTSTRAP_MAGIC 42
|
||||
#define BOOTSTRAP_MAX_GDT_DESCS 2
|
||||
|
||||
typedef struct BSVMM_GDTInitEntry {
|
||||
uint16 index;
|
||||
LA32 base;
|
||||
VA32 limit;
|
||||
uint32 type;
|
||||
uint32 S;
|
||||
uint32 DPL;
|
||||
uint32 present;
|
||||
uint32 longmode;
|
||||
uint32 DB;
|
||||
uint32 gran;
|
||||
} BSVMM_GDTInitEntry;
|
||||
|
||||
typedef struct BSVMM_GDTInit {
|
||||
BSVMM_GDTInitEntry entries[BOOTSTRAP_MAX_GDT_DESCS];
|
||||
} BSVMM_GDTInit;
|
||||
|
||||
typedef struct BSVMM_HostParams {
|
||||
uint32 magic;
|
||||
VMM64_AddrLayout addrLayout;
|
||||
BSVMM_GDTInit gdtInit;
|
||||
} BSVMM_HostParams;
|
||||
|
||||
BSVMM_HostParams* BSVMM_Validate(void *buf, uint32 nbytes);
|
||||
|
||||
#endif
|
||||
+106
-185
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2017,2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -32,126 +32,75 @@
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "vmware.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ListItem {
|
||||
struct ListItem *prev;
|
||||
struct ListItem *next;
|
||||
} ListItem;
|
||||
|
||||
/* A list with no elements is a null pointer. */
|
||||
#define LIST_ITEM_DEF(name) \
|
||||
ListItem * name = NULL
|
||||
|
||||
#define LIST_EMPTY(l) ((l) == NULL)
|
||||
|
||||
/* initialize list item */
|
||||
#define INIT_LIST_ITEM(p) \
|
||||
do { \
|
||||
(p)->prev = (p)->next = (p); \
|
||||
} while (0)
|
||||
|
||||
/* check if initialized */
|
||||
#define IS_LIST_ITEM_INITIALIZED(li) \
|
||||
(((li) == (li)->prev) && ((li) == (li)->next))
|
||||
|
||||
/* return first element in the list */
|
||||
#define LIST_FIRST(l) (l)
|
||||
#define LIST_FIRST_CHK(l) (l)
|
||||
|
||||
/* return last element in the list */
|
||||
#define LIST_LAST(l) ((l)->prev)
|
||||
#define LIST_LAST_CHK(l) (LIST_EMPTY(l) ? NULL : LIST_LAST(l))
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_IsEmpty --
|
||||
*
|
||||
* A NULL list is an empty list.
|
||||
*
|
||||
* Result:
|
||||
* TRUE if list is empty, FALSE otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE Bool
|
||||
CircList_IsEmpty(const ListItem *item) // IN
|
||||
{
|
||||
return item == NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_InitItem --
|
||||
*
|
||||
* Initialize item as a single-element circular list.
|
||||
*
|
||||
* Result:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
CircList_InitItem(ListItem *item) // OUT
|
||||
{
|
||||
item->prev = item->next = item;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_First --
|
||||
*
|
||||
* Return first item in the list.
|
||||
*
|
||||
* Result:
|
||||
* First item.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE ListItem *
|
||||
CircList_First(ListItem *item) // IN
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_Last --
|
||||
*
|
||||
* Return last item in the list.
|
||||
*
|
||||
* Result:
|
||||
* Last item.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE ListItem *
|
||||
CircList_Last(ListItem *item)
|
||||
{
|
||||
return item->prev;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* CIRC_LIST_CONTAINER - get the struct for this entry (like list_entry)
|
||||
* LIST_CONTAINER - get the struct for this entry (like list_entry)
|
||||
* @ptr: the &struct ListItem pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list struct within the struct.
|
||||
*/
|
||||
#define CIRC_LIST_CONTAINER(ptr, type, member) \
|
||||
#define LIST_CONTAINER(ptr, type, member) \
|
||||
VMW_CONTAINER_OF(ptr, type, member)
|
||||
/*
|
||||
* Historical name, left here to reduce churn.
|
||||
* TODO: remove, all LIST_CONTAINER uses should be
|
||||
* VMW_CONTAINER_OF and stop depending on circList.h
|
||||
* to provide the definition.
|
||||
|
||||
/*
|
||||
* delete item from the list
|
||||
*/
|
||||
#define LIST_CONTAINER(ptr, type, member) VMW_CONTAINER_OF(ptr, type, member)
|
||||
#define LIST_DEL DelListItem
|
||||
|
||||
/*
|
||||
* link two lists together
|
||||
*/
|
||||
#define LIST_SPLICE SpliceLists
|
||||
|
||||
/*
|
||||
* Split a list into two lists
|
||||
*/
|
||||
#define LIST_SPLIT SplitLists
|
||||
|
||||
/*
|
||||
* Add item to front of stack. List pointer points to new head.
|
||||
*/
|
||||
#define LIST_PUSH PushListItem
|
||||
|
||||
/*
|
||||
* Add item at back of queue. List pointer only changes if list was empty.
|
||||
*/
|
||||
#define LIST_QUEUE QueueListItem
|
||||
|
||||
/*
|
||||
* Get the list size.
|
||||
*/
|
||||
#define LIST_SIZE GetListSize
|
||||
|
||||
/*
|
||||
* LIST_SCAN_FROM scans the list from "from" up until "until".
|
||||
@@ -160,32 +109,38 @@ CircList_Last(ListItem *item)
|
||||
* "until" is the element where search should stop.
|
||||
* member is the field to use for the search - either "next" or "prev".
|
||||
*/
|
||||
#define CIRC_LIST_SCAN_FROM(p, from, until, member) \
|
||||
#define LIST_SCAN_FROM(p, from, until, member) \
|
||||
for (p = (from); (p) != NULL; \
|
||||
(p) = (((p)->member == (until)) ? NULL : (p)->member))
|
||||
|
||||
/* scan the entire list (non-destructively) */
|
||||
#define CIRC_LIST_SCAN(p, l) \
|
||||
CIRC_LIST_SCAN_FROM(p, CircList_First(l), CircList_First(l), next)
|
||||
#define LIST_SCAN(p, l) \
|
||||
LIST_SCAN_FROM(p, LIST_FIRST(l), LIST_FIRST(l), next)
|
||||
|
||||
|
||||
/* scan a list backward from last element to first (non-destructively) */
|
||||
#define LIST_SCAN_BACK(p, l) \
|
||||
LIST_SCAN_FROM(p, LIST_LAST_CHK(l), LIST_LAST(l), prev)
|
||||
|
||||
/* scan the entire list where loop element may be destroyed */
|
||||
#define CIRC_LIST_SCAN_SAFE(p, pn, l) \
|
||||
if (!CircList_IsEmpty(l)) \
|
||||
for (p = (l), (pn) = CircList_Next(p, l); (p) != NULL; \
|
||||
(p) = (pn), (pn) = CircList_Next(p, l))
|
||||
#define LIST_SCAN_SAFE(p, pn, l) \
|
||||
if (!LIST_EMPTY(l)) \
|
||||
for (p = (l), (pn) = NextListItem(p, l); (p) != NULL; \
|
||||
(p) = (pn), (pn) = NextListItem(p, l))
|
||||
|
||||
/* scan the entire list backwards where loop element may be destroyed */
|
||||
#define CIRC_LIST_SCAN_BACK_SAFE(p, pn, l) \
|
||||
if (!CircList_IsEmpty(l)) \
|
||||
for (p = CircList_Last(l), (pn) = CircList_Prev(p, l); (p) != NULL; \
|
||||
(p) = (pn), (pn) = CircList_Prev(p, l))
|
||||
#define LIST_SCAN_BACK_SAFE(p, pn, l) \
|
||||
if (!LIST_EMPTY(l)) \
|
||||
for (p = LIST_LAST(l), (pn) = PrevListItem(p, l); (p) != NULL; \
|
||||
(p) = (pn), (pn) = PrevListItem(p, l))
|
||||
|
||||
|
||||
/* function definitions */
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_Next --
|
||||
* NextListItem --
|
||||
*
|
||||
* Returns the next member of a doubly linked list, or NULL if last.
|
||||
* Assumes: p is member of the list headed by head.
|
||||
@@ -201,8 +156,8 @@ CircList_Last(ListItem *item)
|
||||
*/
|
||||
|
||||
static INLINE ListItem *
|
||||
CircList_Next(ListItem *p, // IN
|
||||
ListItem *head) // IN
|
||||
NextListItem(ListItem *p, // IN
|
||||
ListItem *head) // IN
|
||||
{
|
||||
if (head == NULL || p == NULL) {
|
||||
return NULL;
|
||||
@@ -216,7 +171,7 @@ CircList_Next(ListItem *p, // IN
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_Prev --
|
||||
* PrevListItem --
|
||||
*
|
||||
* Returns the prev member of a doubly linked list, or NULL if first.
|
||||
* Assumes: p is member of the list headed by head.
|
||||
@@ -232,8 +187,8 @@ CircList_Next(ListItem *p, // IN
|
||||
*/
|
||||
|
||||
static INLINE ListItem *
|
||||
CircList_Prev(ListItem *p, // IN
|
||||
ListItem *head) // IN
|
||||
PrevListItem(ListItem *p, // IN
|
||||
ListItem *head) // IN
|
||||
{
|
||||
if (head == NULL || p == NULL) {
|
||||
return NULL;
|
||||
@@ -246,7 +201,7 @@ CircList_Prev(ListItem *p, // IN
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_DeleteItem --
|
||||
* DelListItem --
|
||||
*
|
||||
* Deletes a member of a doubly linked list, possibly modifies the
|
||||
* list header itself.
|
||||
@@ -262,13 +217,13 @@ CircList_Prev(ListItem *p, // IN
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
CircList_DeleteItem(ListItem *p, // IN
|
||||
ListItem **headp) // IN/OUT
|
||||
DelListItem(ListItem *p, // IN
|
||||
ListItem **headp) // IN/OUT
|
||||
{
|
||||
ListItem *next;
|
||||
|
||||
ASSERT(p != NULL);
|
||||
ASSERT(headp != NULL);
|
||||
ASSERT(p);
|
||||
ASSERT(headp);
|
||||
|
||||
next = p->next;
|
||||
if (p == next) {
|
||||
@@ -286,7 +241,7 @@ CircList_DeleteItem(ListItem *p, // IN
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_Queue --
|
||||
* QueueListItem --
|
||||
*
|
||||
* Adds a new member to the back of a doubly linked list (queue)
|
||||
* Assumes neither p nor headp is null and p is not a member of *headp.
|
||||
@@ -301,14 +256,14 @@ CircList_DeleteItem(ListItem *p, // IN
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
CircList_Queue(ListItem *p, // IN
|
||||
ListItem **headp) // IN/OUT
|
||||
QueueListItem(ListItem *p, // IN
|
||||
ListItem **headp) // IN/OUT
|
||||
{
|
||||
ListItem *head;
|
||||
|
||||
head = *headp;
|
||||
if (CircList_IsEmpty(head)) {
|
||||
CircList_InitItem(p);
|
||||
if (LIST_EMPTY(head)) {
|
||||
INIT_LIST_ITEM(p);
|
||||
*headp = p;
|
||||
} else {
|
||||
p->prev = head->prev;
|
||||
@@ -322,7 +277,7 @@ CircList_Queue(ListItem *p, // IN
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_Push --
|
||||
* PushListItem --
|
||||
*
|
||||
* Adds a new member to the front of a doubly linked list (stack)
|
||||
* Assumes neither p nor headp is null and p is not a member of *headp.
|
||||
@@ -337,10 +292,10 @@ CircList_Queue(ListItem *p, // IN
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
CircList_Push(ListItem *p, // IN
|
||||
ListItem **headp) // IN/OUT
|
||||
PushListItem(ListItem *p, // IN
|
||||
ListItem **headp) // IN/OUT
|
||||
{
|
||||
CircList_Queue(p, headp);
|
||||
QueueListItem(p, headp);
|
||||
*headp = p;
|
||||
}
|
||||
|
||||
@@ -348,35 +303,7 @@ CircList_Push(ListItem *p, // IN
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_InsertAfter --
|
||||
*
|
||||
* Adds a new member to the list after the provided item. Assumes p
|
||||
* is not a member of a list already.
|
||||
*
|
||||
* Result:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
CircList_InsertAfter(ListItem *p, // IN:
|
||||
ListItem *after) // IN:
|
||||
{
|
||||
p->prev = after;
|
||||
p->next = after->next;
|
||||
p->next->prev = p;
|
||||
after->next = p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_Splice --
|
||||
* SpliceLists --
|
||||
*
|
||||
* Make a single list {l1 l2} from {l1} and {l2} and return it.
|
||||
* It is okay for one or both lists to be NULL.
|
||||
@@ -393,16 +320,16 @@ CircList_InsertAfter(ListItem *p, // IN:
|
||||
*/
|
||||
|
||||
static INLINE ListItem *
|
||||
CircList_Splice(ListItem *l1, // IN
|
||||
ListItem *l2) // IN
|
||||
SpliceLists(ListItem *l1, // IN
|
||||
ListItem *l2) // IN
|
||||
{
|
||||
ListItem *l1Last, *l2Last;
|
||||
|
||||
if (CircList_IsEmpty(l1)) {
|
||||
if (LIST_EMPTY(l1)) {
|
||||
return l2;
|
||||
}
|
||||
|
||||
if (CircList_IsEmpty(l2)) {
|
||||
if (LIST_EMPTY(l2)) {
|
||||
return l1;
|
||||
}
|
||||
|
||||
@@ -422,11 +349,10 @@ CircList_Splice(ListItem *l1, // IN
|
||||
}
|
||||
|
||||
|
||||
#if 0 /* Presently unused, enable if a use is found */
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_Split --
|
||||
* SplitLists --
|
||||
*
|
||||
* Make a list l = {l1 l2} into two separate lists {l1} and {l2}, where:
|
||||
* l = { ... x -> p -> ... } split into:
|
||||
@@ -446,14 +372,14 @@ CircList_Splice(ListItem *l1, // IN
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
CircList_Split(ListItem *p, // IN
|
||||
ListItem *l, // IN
|
||||
ListItem **l1p, // OUT
|
||||
ListItem **l2p) // OUT
|
||||
SplitLists(ListItem *p, // IN
|
||||
ListItem *l, // IN
|
||||
ListItem **l1p, // OUT
|
||||
ListItem **l2p) // OUT
|
||||
{
|
||||
ListItem *last;
|
||||
|
||||
if (p == CircList_First(l)) { /* first element */
|
||||
if (p == LIST_FIRST(l)) { /* first element */
|
||||
*l1p = NULL;
|
||||
*l2p = l;
|
||||
return;
|
||||
@@ -469,13 +395,12 @@ CircList_Split(ListItem *p, // IN
|
||||
p->prev = last;
|
||||
last->next = p;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CircList_Size --
|
||||
* GetListSize --
|
||||
*
|
||||
* Return the number of items in the list.
|
||||
*
|
||||
@@ -489,19 +414,15 @@ CircList_Split(ListItem *p, // IN
|
||||
*/
|
||||
|
||||
static INLINE int
|
||||
CircList_Size(ListItem *head) // IN
|
||||
GetListSize(ListItem *head) // IN
|
||||
{
|
||||
ListItem *li;
|
||||
int ret = 0;
|
||||
|
||||
CIRC_LIST_SCAN(li, head) {
|
||||
LIST_SCAN(li, head) {
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* _CIRCLIST_H_ */
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2009-2016 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2002 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
#ifndef __COMPAT_CRED_H__
|
||||
# define __COMPAT_CRED_H__
|
||||
|
||||
|
||||
/*
|
||||
* Include linux/cred.h via linux/sched.h - it is not nice, but
|
||||
* as cpp does not have #ifexist...
|
||||
*/
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
||||
#include <linux/sched.h>
|
||||
#else
|
||||
#include <linux/cred.h>
|
||||
#endif
|
||||
|
||||
#if !defined(current_fsuid) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
|
||||
#define current_uid() (current->uid)
|
||||
#define current_euid() (current->euid)
|
||||
#define current_fsuid() (current->fsuid)
|
||||
#define current_gid() (current->gid)
|
||||
#define current_egid() (current->egid)
|
||||
#define current_fsgid() (current->fsgid)
|
||||
#endif
|
||||
|
||||
#if !defined(cap_set_full)
|
||||
/* cap_set_full was removed in kernel version 3.0-rc4. */
|
||||
#define cap_set_full(_c) do { (_c) = CAP_FULL_SET; } while (0)
|
||||
#endif
|
||||
|
||||
#if !defined(GLOBAL_ROOT_UID)
|
||||
#define GLOBAL_ROOT_UID (0)
|
||||
#endif
|
||||
|
||||
#endif /* __COMPAT_CRED_H__ */
|
||||
@@ -0,0 +1,32 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2012 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
#ifndef __COMPAT_HIGHMEM_H__
|
||||
# define __COMPAT_HIGHMEM_H__
|
||||
|
||||
#include <linux/highmem.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
|
||||
# define compat_kmap_atomic(_page) kmap_atomic(_page)
|
||||
# define compat_kunmap_atomic(_page) kunmap_atomic(_page)
|
||||
#else
|
||||
# define compat_kmap_atomic(_page) kmap_atomic((_page), KM_USER0)
|
||||
# define compat_kunmap_atomic(_page) kunmap_atomic((_page), KM_USER0)
|
||||
#endif
|
||||
|
||||
#endif /* __COMPAT_HIGHMEM_H__ */
|
||||
@@ -0,0 +1,55 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2003 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
#ifndef __COMPAT_INTERRUPT_H__
|
||||
# define __COMPAT_INTERRUPT_H__
|
||||
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 69)
|
||||
/*
|
||||
* We cannot just define irqreturn_t, as some 2.4.x kernels have
|
||||
* typedef void irqreturn_t; for "increasing" backward compatibility.
|
||||
*/
|
||||
typedef void compat_irqreturn_t;
|
||||
#define COMPAT_IRQ_NONE
|
||||
#define COMPAT_IRQ_HANDLED
|
||||
#define COMPAT_IRQ_RETVAL(x)
|
||||
#else
|
||||
typedef irqreturn_t compat_irqreturn_t;
|
||||
#define COMPAT_IRQ_NONE IRQ_NONE
|
||||
#define COMPAT_IRQ_HANDLED IRQ_HANDLED
|
||||
#define COMPAT_IRQ_RETVAL(x) IRQ_RETVAL(x)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
|
||||
#define COMPAT_IRQF_DISABLED SA_INTERRUPT
|
||||
#define COMPAT_IRQF_SHARED SA_SHIRQ
|
||||
#else
|
||||
#define COMPAT_IRQF_DISABLED IRQF_DISABLED
|
||||
#define COMPAT_IRQF_SHARED IRQF_SHARED
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
|
||||
#define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp, struct pt_regs *regs)
|
||||
#else
|
||||
#define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp)
|
||||
#endif
|
||||
|
||||
#endif /* __COMPAT_INTERRUPT_H__ */
|
||||
@@ -0,0 +1,63 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2003 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
#ifndef __COMPAT_IOPORT_H__
|
||||
# define __COMPAT_IOPORT_H__
|
||||
|
||||
|
||||
#include <linux/ioport.h>
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
|
||||
static inline void *
|
||||
compat_request_region(unsigned long start, unsigned long len, const char *name)
|
||||
{
|
||||
if (check_region(start, len)) {
|
||||
return NULL;
|
||||
}
|
||||
request_region(start, len, name);
|
||||
return (void*)1;
|
||||
}
|
||||
#else
|
||||
#define compat_request_region(start, len, name) request_region(start, len, name)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 7)
|
||||
/* mmap io support starts from 2.3.7, fail the call for kernel prior to that */
|
||||
static inline void *
|
||||
compat_request_mem_region(unsigned long start, unsigned long len, const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
compat_release_mem_region(unsigned long start, unsigned long len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
#define compat_request_mem_region(start, len, name) request_mem_region(start, len, name)
|
||||
#define compat_release_mem_region(start, len) release_mem_region(start, len)
|
||||
#endif
|
||||
|
||||
/* these two macro defs are needed by compat_pci_request_region */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 15)
|
||||
# define IORESOURCE_IO 0x00000100
|
||||
# define IORESOURCE_MEM 0x00000200
|
||||
#endif
|
||||
|
||||
#endif /* __COMPAT_IOPORT_H__ */
|
||||
@@ -0,0 +1,72 @@
|
||||
/*********************************************************
|
||||
* 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 General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* compat_pci.h: PCI compatibility wrappers.
|
||||
*/
|
||||
|
||||
#ifndef __COMPAT_PCI_H__
|
||||
#define __COMPAT_PCI_H__
|
||||
|
||||
#include "compat_ioport.h"
|
||||
#include <linux/pci.h>
|
||||
|
||||
#ifndef DMA_BIT_MASK
|
||||
# define DMA_BIT_MASK(n) DMA_##n##BIT_MASK
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Power Management related compat wrappers.
|
||||
*/
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
|
||||
# define compat_pci_save_state(pdev) pci_save_state((pdev), NULL)
|
||||
# define compat_pci_restore_state(pdev) pci_restore_state((pdev), NULL)
|
||||
#else
|
||||
# define compat_pci_save_state(pdev) pci_save_state((pdev))
|
||||
# define compat_pci_restore_state(pdev) pci_restore_state((pdev))
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
|
||||
# define pm_message_t u32
|
||||
# define compat_pci_choose_state(pdev, state) (state)
|
||||
# define PCI_D0 0
|
||||
# define PCI_D3hot 3
|
||||
#else
|
||||
# define compat_pci_choose_state(pdev, state) pci_choose_state((pdev), (state))
|
||||
#endif
|
||||
|
||||
/* 2.6.14 changed the PCI shutdown callback */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
|
||||
# define COMPAT_PCI_SHUTDOWN(func) .driver = { .shutdown = (func), }
|
||||
# define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct device *(var))
|
||||
# define COMPAT_PCI_TO_DEV(dev) (to_pci_dev(dev))
|
||||
#else
|
||||
# define COMPAT_PCI_SHUTDOWN(func) .shutdown = (func)
|
||||
# define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct pci_dev *(var))
|
||||
# define COMPAT_PCI_TO_DEV(dev) (dev)
|
||||
#endif
|
||||
|
||||
/* 2.6.26 introduced the device_set_wakeup_enable() function */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
|
||||
# define compat_device_set_wakeup_enable(dev, val) do {} while(0)
|
||||
#else
|
||||
# define compat_device_set_wakeup_enable(dev, val) \
|
||||
device_set_wakeup_enable(dev, val)
|
||||
#endif
|
||||
|
||||
#endif /* __COMPAT_PCI_H__ */
|
||||
@@ -48,6 +48,11 @@ typedef p4d_t compat_p4d_t;
|
||||
# define COMPAT_P4D_MASK 0 /* Not used */
|
||||
typedef pgd_t compat_p4d_t;
|
||||
#endif
|
||||
/* p[gu]d_large did not exist before 2.6.25 */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
|
||||
# define pud_large(pud) 0
|
||||
# define pgd_large(pgd) 0
|
||||
#endif
|
||||
/* pud_pfn did not exist before 3.8. */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
|
||||
# define pud_pfn(pud) INVALID_MPN
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef __COMPAT_POLL_H__
|
||||
#define __COMPAT_POLL_H__
|
||||
|
||||
#include <linux/poll.h>
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0))
|
||||
|
||||
#ifndef __poll_t
|
||||
typedef unsigned int __poll_t;
|
||||
#endif
|
||||
|
||||
static inline __poll_t compat_vfs_poll(struct file *file,
|
||||
struct poll_table_struct *pt)
|
||||
{
|
||||
if (unlikely(!file->f_op->poll))
|
||||
return DEFAULT_POLLMASK;
|
||||
return file->f_op->poll(file, pt);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline __poll_t compat_vfs_poll(struct file *file,
|
||||
struct poll_table_struct *pt)
|
||||
{
|
||||
return vfs_poll(file, pt);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __COMPAT_POLL_H__ */
|
||||
@@ -0,0 +1,49 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2002 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
#ifndef __COMPAT_SEMAPHORE_H__
|
||||
# define __COMPAT_SEMAPHORE_H__
|
||||
|
||||
|
||||
/* <= 2.6.25 have asm only, 2.6.26 has both, and 2.6.27-rc2+ has linux only. */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
|
||||
# include <asm/semaphore.h>
|
||||
#else
|
||||
# include <linux/semaphore.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The init_MUTEX_LOCKED() API appeared in 2.2.18, and is also in
|
||||
* 2.2.17-21mdk --hpreg
|
||||
*/
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)
|
||||
#ifndef init_MUTEX_LOCKED
|
||||
#define init_MUTEX_LOCKED(_sem) *(_sem) = MUTEX_LOCKED
|
||||
#endif
|
||||
#ifndef DECLARE_MUTEX
|
||||
#define DECLARE_MUTEX(name) struct semaphore name = MUTEX
|
||||
#endif
|
||||
#ifndef DECLARE_MUTEX_LOCKED
|
||||
#define DECLARE_MUTEX_LOCKED(name) struct semaphore name = MUTEX_LOCKED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __COMPAT_SEMAPHORE_H__ */
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef __COMPAT_TIMER_H__
|
||||
# define __COMPAT_TIMER_H__
|
||||
|
||||
#include <linux/timer.h>
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)) && !defined(timer_setup)
|
||||
|
||||
typedef unsigned long compat_timer_arg_t;
|
||||
|
||||
static inline void compat_timer_setup(struct timer_list *timer,
|
||||
void (*func)(compat_timer_arg_t),
|
||||
unsigned int flags)
|
||||
{
|
||||
init_timer(timer);
|
||||
timer->function = func;
|
||||
timer->data = 0;
|
||||
timer->flags = flags;
|
||||
}
|
||||
|
||||
#else /* new timer interface since 4.15 */
|
||||
|
||||
typedef struct timer_list *compat_timer_arg_t;
|
||||
|
||||
static inline void compat_timer_setup(struct timer_list *timer,
|
||||
void (*func)(compat_timer_arg_t),
|
||||
unsigned int flags)
|
||||
{
|
||||
timer_setup(timer, func, flags);
|
||||
}
|
||||
|
||||
#endif /* new timer interface since 4.15 */
|
||||
|
||||
#endif /* __COMPAT_TIMER_H__ */
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2005-2014,2017 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2005-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -26,11 +26,9 @@
|
||||
#ifndef _CONTEXTINFO_H
|
||||
#define _CONTEXTINFO_H
|
||||
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMX
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "x86desc.h"
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
typedef uint32 PCPU;
|
||||
#define INVALID_PCPU ((PCPU) -1)
|
||||
|
||||
#define MAX_PCPUS 1024
|
||||
#define MAX_PCPUS 576
|
||||
#define MAX_PCPUS_BITS 10 // MAX_PCPUS <= (1 << MAX_PCPUS_BITS)
|
||||
#define MAX_PCPUS_MASK ((1 << MAX_PCPUS_BITS) - 1)
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
#ifndef _CPUID_INFO_H
|
||||
#define _CPUID_INFO_H
|
||||
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "vm_basic_asm.h"
|
||||
#include "x86cpuid_asm.h"
|
||||
|
||||
|
||||
typedef struct CPUID0 {
|
||||
int numEntries;
|
||||
char name[16]; // 4 extra bytes to null terminate
|
||||
} CPUID0;
|
||||
|
||||
typedef struct CPUID1 {
|
||||
uint32 version;
|
||||
uint32 ebx;
|
||||
uint32 ecxFeatures;
|
||||
uint32 edxFeatures;
|
||||
} CPUID1;
|
||||
|
||||
typedef struct CPUID80 {
|
||||
uint32 numEntries;
|
||||
uint32 ebx;
|
||||
uint32 ecx;
|
||||
uint32 edx;
|
||||
} CPUID80;
|
||||
|
||||
typedef struct CPUID81 {
|
||||
uint32 eax;
|
||||
uint32 ebx;
|
||||
uint32 ecxFeatures;
|
||||
uint32 edxFeatures;
|
||||
} CPUID81;
|
||||
|
||||
typedef struct CPUIDSummary {
|
||||
CPUID0 id0;
|
||||
CPUID1 id1;
|
||||
CPUIDRegs ida;
|
||||
CPUID80 id80;
|
||||
CPUID81 id81;
|
||||
CPUIDRegs id88, id8a;
|
||||
} CPUIDSummary;
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CPUIDSummary_RegsFromCpuid0 --
|
||||
*
|
||||
* Fills in the given CPUIDRegs struct with the values from the CPUID0 struct.
|
||||
*
|
||||
* Results:
|
||||
* Returns the CPUIDRegs pointer passed in.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE CPUIDRegs*
|
||||
CPUIDSummary_RegsFromCpuid0(CPUID0* id0In,
|
||||
CPUIDRegs* id0Out)
|
||||
{
|
||||
id0Out->eax = id0In->numEntries;
|
||||
id0Out->ebx = *(uint32 *) (id0In->name + 0);
|
||||
id0Out->edx = *(uint32 *) (id0In->name + 4);
|
||||
id0Out->ecx = *(uint32 *) (id0In->name + 8);
|
||||
return id0Out;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2006-2017 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2006-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -24,19 +24,6 @@
|
||||
* There is only one in the whole host system, shared by all VMs.
|
||||
* It is allocated when the first VCPU is started and freed when the
|
||||
* driver is unloaded.
|
||||
*
|
||||
* The crossGDT size is exactly one page.
|
||||
*
|
||||
* The hosted world switch code is based on the assumption that by
|
||||
* placing VMM descriptors at the end of the page, they will not
|
||||
* overlap with host kernel descriptors in use when "crossing over".
|
||||
*
|
||||
* All necessary host segments must be from first page of GDT.
|
||||
* In Nov 2006, host GDT limits easily met this constraint:
|
||||
*
|
||||
* Linux 64 bit: 80 (yes 80, not 7F)
|
||||
* MacOS 64 bit: 8F
|
||||
* Windows 64 bit: 6F
|
||||
*/
|
||||
|
||||
#ifndef _CROSSGDT_H_
|
||||
@@ -51,9 +38,42 @@
|
||||
#include "vm_basic_defs.h" // PAGE_SIZE
|
||||
#include "x86types.h" // Descriptor
|
||||
|
||||
|
||||
typedef struct CrossGDT {
|
||||
Descriptor gdtes[PAGE_SIZE / sizeof(Descriptor)];
|
||||
Descriptor gdtes[0x5000 / sizeof (Descriptor)]; // 0x5000 > GDT_LIMIT
|
||||
} CrossGDT;
|
||||
|
||||
#define CROSSGDT_NUMPAGES ((sizeof (CrossGDT) + PAGE_SIZE - 1) / PAGE_SIZE)
|
||||
|
||||
/*
|
||||
* Out of the 5 pages, only the first and last are really used.
|
||||
*
|
||||
* All we need to map are the first and last pages. This mask tells
|
||||
* the setup code which pages it can put stuff in and it tells the
|
||||
* mapping and invalidation code which pages are mapped and unmapped.
|
||||
*/
|
||||
#define CROSSGDT_PAGEMASK 0x11
|
||||
|
||||
/*
|
||||
* These segments are placed in the first crossGDT page. We assume
|
||||
* they do not overlap any host segments (checked by
|
||||
* Task_InitCrossGDT). The only real requirement is that they (and
|
||||
* the host CS/SS) be physically contiguous with the start of the
|
||||
* crossGDT so they will remain valid when paging is turned off.
|
||||
*
|
||||
* As of this writing (Nov 2006), host GDT limits:
|
||||
* Linux 64 bit: 80 (yes 80, not 7F)
|
||||
* 32 bit: FF
|
||||
* MacOS 64 bit: 8F
|
||||
* 32 bit: 8F
|
||||
* Windows 64 bit: 6F
|
||||
* 32 bit: 3FF
|
||||
*/
|
||||
#define CROSSGDT_LOWSEG (0x0FD0 / 8) // all host segs must be below this
|
||||
#define CROSSGDT_64BITCS (0x0FD0 / 8) // 64-bit code segment
|
||||
#define CROSSGDT_64BITSS (0x0FD8 / 8) // 64-bit data segment
|
||||
#define CROSSGDT_FLAT32CS (0x0FE0 / 8) // 32-bit flat code seg
|
||||
#define CROSSGDT_FLAT32SS (0x0FE8 / 8) // 32-bit flat data seg
|
||||
#define CROSSGDT_MON32CS (0x0FF0 / 8) // 32-bit FFC00000 base code seg
|
||||
#define CROSSGDT_MON32SS (0x0FF8 / 8) // 32-bit FFC00000 base data seg
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,346 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2001,2016 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
#ifndef _HASH_FUNC_H
|
||||
#define _HASH_FUNC_H
|
||||
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
|
||||
#include "includeCheck.h"
|
||||
|
||||
/*
|
||||
* hashFunc.h --
|
||||
*
|
||||
* Hash functions defined as simple wrappers around code placed
|
||||
* in the public domain by Bob Jenkins. His original code can
|
||||
* be used freely for any purpose, including commercial (see the
|
||||
* original comments in the enclosed code).
|
||||
*/
|
||||
|
||||
#include "vm_basic_types.h"
|
||||
#include "vm_basic_defs.h"
|
||||
#include "vm_assert.h"
|
||||
|
||||
/*
|
||||
* operations
|
||||
*/
|
||||
|
||||
extern uint64 HashFunc_HashBytes(const uint8 *key, uint32 nBytes);
|
||||
extern uint64 HashFunc_HashMoreBytes(const uint8 *key, uint32 nBytes,
|
||||
uint64 initialValue);
|
||||
extern uint64 HashFunc_HashBytesSlow(const uint8 *key, uint32 nBytes);
|
||||
extern uint64 HashFunc_HashQuads(const uint64 *key, uint32 nQuads);
|
||||
extern uint64 HashFunc_HashPage(const void *addr);
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------
|
||||
Hashes 32-bit key and returns a value that can fit into numBits bits.
|
||||
--------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE uint32
|
||||
HashFunc_TruncHash32(uint32 key, unsigned numBits)
|
||||
{
|
||||
const uint32 hashConst = 0x9e3779b9; /* the golden ratio */
|
||||
ASSERT(numBits > 0 && numBits <= 32);
|
||||
return (key * hashConst) >> (32 - numBits);
|
||||
}
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------
|
||||
Hashes 64-bit key and returns a value that can fit into numBits bits.
|
||||
--------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE uint32
|
||||
HashFunc_TruncHash64(uint64 key, unsigned numBits)
|
||||
{
|
||||
return HashFunc_TruncHash32((uint32)(key ^ (key >> 32)), numBits);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Original Bob Jenkins public-domain code with minor modifications
|
||||
* (static functions, 32-bit length args, disabled self-test code).
|
||||
*/
|
||||
|
||||
|
||||
typedef uint64 ub8; /* unsigned 8-byte quantities */
|
||||
typedef uint32 ub4; /* unsigned 4-byte quantities */
|
||||
typedef uint8 ub1;
|
||||
|
||||
#define hashsize(n) ((ub8)1<<(n))
|
||||
#define hashmask(n) (hashsize(n)-1)
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------
|
||||
mix -- mix 3 64-bit values reversibly.
|
||||
mix() takes 48 machine instructions, but only 24 cycles on a superscalar
|
||||
machine (like Intel's new MMX architecture). It requires 4 64-bit
|
||||
registers for 4::2 parallelism.
|
||||
All 1-bit deltas, all 2-bit deltas, all deltas composed of top bits of
|
||||
(a,b,c), and all deltas of bottom bits were tested. All deltas were
|
||||
tested both on random keys and on keys that were nearly all zero.
|
||||
These deltas all cause every bit of c to change between 1/3 and 2/3
|
||||
of the time (well, only 113/400 to 287/400 of the time for some
|
||||
2-bit delta). These deltas all cause at least 80 bits to change
|
||||
among (a,b,c) when the mix is run either forward or backward (yes it
|
||||
is reversible).
|
||||
This implies that a hash using mix64 has no funnels. There may be
|
||||
characteristics with 3-bit deltas or bigger, I didn't test for
|
||||
those.
|
||||
--------------------------------------------------------------------
|
||||
*/
|
||||
#define mix64(a,b,c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>43); \
|
||||
b -= c; b -= a; b ^= (a<<9); \
|
||||
c -= a; c -= b; c ^= (b>>8); \
|
||||
a -= b; a -= c; a ^= (c>>38); \
|
||||
b -= c; b -= a; b ^= (a<<23); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>35); \
|
||||
b -= c; b -= a; b ^= (a<<49); \
|
||||
c -= a; c -= b; c ^= (b>>11); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<18); \
|
||||
c -= a; c -= b; c ^= (b>>22); \
|
||||
}
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------
|
||||
hash() -- hash a variable-length key into a 64-bit value
|
||||
k : the key (the unaligned variable-length array of bytes)
|
||||
len : the length of the key, counting by bytes
|
||||
level : can be any 8-byte value
|
||||
Returns a 64-bit value. Every bit of the key affects every bit of
|
||||
the return value. No funnels. Every 1-bit and 2-bit delta achieves
|
||||
avalanche. About 41+5len instructions.
|
||||
|
||||
The best hash table sizes are powers of 2. There is no need to do
|
||||
mod a prime (mod is sooo slow!). If you need less than 64 bits,
|
||||
use a bitmask. For example, if you need only 10 bits, do
|
||||
h = (h & hashmask(10));
|
||||
In which case, the hash table should have hashsize(10) elements.
|
||||
|
||||
If you are hashing n strings (ub1 **)k, do it like this:
|
||||
for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
|
||||
|
||||
By Bob Jenkins, Jan 4 1997. bob_jenkins@burtleburtle.net. You may
|
||||
use this code any way you wish, private, educational, or commercial,
|
||||
as long as this whole comment accompanies it.
|
||||
|
||||
See http://burtleburtle.net/bob/hash/evahash.html
|
||||
Use for hash table lookup, or anything where one collision in 2^^64
|
||||
is acceptable. Do NOT use for cryptographic purposes.
|
||||
--------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE ub8 hash(register const ub1 *k, /* the key */
|
||||
register ub4 length, /* the length of the key */
|
||||
register ub8 level) /* the previous hash, or an arbitrary value */
|
||||
{
|
||||
register ub8 a,b,c;
|
||||
ub4 len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = b = level; /* the previous hash value */
|
||||
c = CONST64U(0x9e3779b97f4a7c13); /* the golden ratio; an arbitrary value */
|
||||
|
||||
/*---------------------------------------- handle most of the key */
|
||||
while (len >= 24)
|
||||
{
|
||||
a += (k[0] +((ub8)k[ 1]<< 8)+((ub8)k[ 2]<<16)+((ub8)k[ 3]<<24)
|
||||
+((ub8)k[4 ]<<32)+((ub8)k[ 5]<<40)+((ub8)k[ 6]<<48)+((ub8)k[ 7]<<56));
|
||||
b += (k[8] +((ub8)k[ 9]<< 8)+((ub8)k[10]<<16)+((ub8)k[11]<<24)
|
||||
+((ub8)k[12]<<32)+((ub8)k[13]<<40)+((ub8)k[14]<<48)+((ub8)k[15]<<56));
|
||||
c += (k[16] +((ub8)k[17]<< 8)+((ub8)k[18]<<16)+((ub8)k[19]<<24)
|
||||
+((ub8)k[20]<<32)+((ub8)k[21]<<40)+((ub8)k[22]<<48)+((ub8)k[23]<<56));
|
||||
mix64(a,b,c);
|
||||
k += 24; len -= 24;
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 23 bytes */
|
||||
c += length;
|
||||
switch(len) /* all the case statements fall through */
|
||||
{
|
||||
case 23: c+=((ub8)k[22]<<56);
|
||||
case 22: c+=((ub8)k[21]<<48);
|
||||
case 21: c+=((ub8)k[20]<<40);
|
||||
case 20: c+=((ub8)k[19]<<32);
|
||||
case 19: c+=((ub8)k[18]<<24);
|
||||
case 18: c+=((ub8)k[17]<<16);
|
||||
case 17: c+=((ub8)k[16]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 16: b+=((ub8)k[15]<<56);
|
||||
case 15: b+=((ub8)k[14]<<48);
|
||||
case 14: b+=((ub8)k[13]<<40);
|
||||
case 13: b+=((ub8)k[12]<<32);
|
||||
case 12: b+=((ub8)k[11]<<24);
|
||||
case 11: b+=((ub8)k[10]<<16);
|
||||
case 10: b+=((ub8)k[ 9]<<8);
|
||||
case 9: b+=((ub8)k[ 8]);
|
||||
case 8: a+=((ub8)k[ 7]<<56);
|
||||
case 7: a+=((ub8)k[ 6]<<48);
|
||||
case 6: a+=((ub8)k[ 5]<<40);
|
||||
case 5: a+=((ub8)k[ 4]<<32);
|
||||
case 4: a+=((ub8)k[ 3]<<24);
|
||||
case 3: a+=((ub8)k[ 2]<<16);
|
||||
case 2: a+=((ub8)k[ 1]<<8);
|
||||
case 1: a+=((ub8)k[ 0]);
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix64(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------
|
||||
This works on all machines, is identical to hash() on little-endian
|
||||
machines, and it is much faster than hash(), but it requires
|
||||
-- that the key be an array of ub8's, and
|
||||
-- that all your machines have the same endianness, and
|
||||
-- that the length be the number of ub8's in the key
|
||||
--------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE ub8 hash2(register const ub8 *k, /* the key */
|
||||
register ub4 length, /* the length of the key */
|
||||
register ub8 level) /* the previous hash, or an arbitrary value */
|
||||
{
|
||||
register ub8 a,b,c;
|
||||
ub4 len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = b = level; /* the previous hash value */
|
||||
c = CONST64U(0x9e3779b97f4a7c13); /* the golden ratio; an arbitrary value */
|
||||
|
||||
/*---------------------------------------- handle most of the key */
|
||||
while (len >= 3)
|
||||
{
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
mix64(a,b,c);
|
||||
k += 3; len -= 3;
|
||||
}
|
||||
|
||||
/*-------------------------------------- handle the last 2 ub8's */
|
||||
c += length;
|
||||
switch(len) /* all the case statements fall through */
|
||||
{
|
||||
/* c is reserved for the length */
|
||||
case 2: b+=k[1];
|
||||
/* fall through */
|
||||
case 1: a+=k[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix64(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------
|
||||
This is identical to hash() on little-endian machines, and it is much
|
||||
faster than hash(), but a little slower than hash2(), and it requires
|
||||
-- that all your machines be little-endian, for example all Intel x86
|
||||
chips or all VAXen. It gives wrong results on big-endian machines.
|
||||
--------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE ub8 hash3(register const ub1 *k, /* the key */
|
||||
register ub4 length, /* the length of the key */
|
||||
register ub8 level) /* the previous hash, or an arbitrary value */
|
||||
{
|
||||
register ub8 a,b,c;
|
||||
ub4 len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = length;
|
||||
a = b = level; /* the previous hash value */
|
||||
c = CONST64U(0x9e3779b97f4a7c13); /* the golden ratio; an arbitrary value */
|
||||
|
||||
/*---------------------------------------- handle most of the key */
|
||||
if (((size_t)k)&7)
|
||||
{
|
||||
while (len >= 24)
|
||||
{
|
||||
a += (k[0] +((ub8)k[ 1]<< 8)+((ub8)k[ 2]<<16)+((ub8)k[ 3]<<24)
|
||||
+((ub8)k[4 ]<<32)+((ub8)k[ 5]<<40)+((ub8)k[ 6]<<48)+((ub8)k[ 7]<<56));
|
||||
b += (k[8] +((ub8)k[ 9]<< 8)+((ub8)k[10]<<16)+((ub8)k[11]<<24)
|
||||
+((ub8)k[12]<<32)+((ub8)k[13]<<40)+((ub8)k[14]<<48)+((ub8)k[15]<<56));
|
||||
c += (k[16] +((ub8)k[17]<< 8)+((ub8)k[18]<<16)+((ub8)k[19]<<24)
|
||||
+((ub8)k[20]<<32)+((ub8)k[21]<<40)+((ub8)k[22]<<48)+((ub8)k[23]<<56));
|
||||
mix64(a,b,c);
|
||||
k += 24; len -= 24;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (len >= 24) /* aligned */
|
||||
{
|
||||
a += *(ub8 *)(k+0);
|
||||
b += *(ub8 *)(k+8);
|
||||
c += *(ub8 *)(k+16);
|
||||
mix64(a,b,c);
|
||||
k += 24; len -= 24;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------- handle the last 23 bytes */
|
||||
c += length;
|
||||
switch(len) /* all the case statements fall through */
|
||||
{
|
||||
case 23: c+=((ub8)k[22]<<56);
|
||||
case 22: c+=((ub8)k[21]<<48);
|
||||
case 21: c+=((ub8)k[20]<<40);
|
||||
case 20: c+=((ub8)k[19]<<32);
|
||||
case 19: c+=((ub8)k[18]<<24);
|
||||
case 18: c+=((ub8)k[17]<<16);
|
||||
case 17: c+=((ub8)k[16]<<8);
|
||||
/* the first byte of c is reserved for the length */
|
||||
case 16: b+=((ub8)k[15]<<56);
|
||||
case 15: b+=((ub8)k[14]<<48);
|
||||
case 14: b+=((ub8)k[13]<<40);
|
||||
case 13: b+=((ub8)k[12]<<32);
|
||||
case 12: b+=((ub8)k[11]<<24);
|
||||
case 11: b+=((ub8)k[10]<<16);
|
||||
case 10: b+=((ub8)k[ 9]<<8);
|
||||
case 9: b+=((ub8)k[ 8]);
|
||||
case 8: a+=((ub8)k[ 7]<<56);
|
||||
case 7: a+=((ub8)k[ 6]<<48);
|
||||
case 6: a+=((ub8)k[ 5]<<40);
|
||||
case 5: a+=((ub8)k[ 4]<<32);
|
||||
case 4: a+=((ub8)k[ 3]<<24);
|
||||
case 3: a+=((ub8)k[ 2]<<16);
|
||||
case 2: a+=((ub8)k[ 1]<<8);
|
||||
case 1: a+=((ub8)k[ 0]);
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
mix64(a,b,c);
|
||||
/*-------------------------------------------- report the result */
|
||||
return c;
|
||||
}
|
||||
|
||||
#endif //_HASH_FUNC_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2008,2018-2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2008 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2018 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -16,32 +16,28 @@
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* sharedAreaType.h --
|
||||
*
|
||||
* This file contains shared area type definitions.
|
||||
*/
|
||||
#ifndef _INITBLOCK_H
|
||||
#define _INITBLOCK_H
|
||||
|
||||
#ifndef _SHAREDAREATYPE_H_
|
||||
#define _SHAREDAREATYPE_H_
|
||||
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_VMX
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
|
||||
#include "includeCheck.h"
|
||||
|
||||
typedef enum {
|
||||
SHARED_AREA_PER_VM_VMX = 0,
|
||||
SHARED_AREA_INTER_VCPU_VMX,
|
||||
SHARED_AREA_PER_VCPU_VMX,
|
||||
SHARED_AREA_PER_VM,
|
||||
SHARED_AREA_INTER_VCPU,
|
||||
SHARED_AREA_PER_VCPU,
|
||||
NUM_SHARED_AREAS
|
||||
} SharedAreaType;
|
||||
|
||||
#endif // _SHAREDAREATYPE_H_
|
||||
#include "basic_initblock.h"
|
||||
|
||||
|
||||
#define MAX_LOGFILE_NAME_LENGTH 256
|
||||
#define MAX_MONITOR_REGIONS 8
|
||||
#define INIT_BLOCK_MAGIC (0x1789+14)
|
||||
|
||||
|
||||
/*
|
||||
* Option flags
|
||||
*/
|
||||
/* None yet */
|
||||
|
||||
|
||||
#endif
|
||||
+159
-157
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2015,2018 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -37,25 +37,12 @@
|
||||
#error iocontrols.h is for hosted vmmon, do not use on visor
|
||||
#endif
|
||||
|
||||
#include "basic_initblock.h"
|
||||
#include "x86segdescrs.h"
|
||||
#include "rateconv.h"
|
||||
#include "overheadmem_types.h"
|
||||
#include "pageLock_defs.h"
|
||||
#include "numa_defs.h"
|
||||
#include "bootstrap_vmm.h"
|
||||
#include "contextinfo.h"
|
||||
#include "vcpuid.h"
|
||||
#include "sharedAreaType.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Maximum number of shared regions that can be passed to MonLoader.
|
||||
*/
|
||||
#define ML_SHARED_REGIONS_MAX 3
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
@@ -140,15 +127,13 @@ PtrToVA64(void const *ptr) // IN
|
||||
* vmcore, and rest-of-bora. The vmmon driver is largely outside
|
||||
* vmcore and vmcore imports functionality from vmmon. Addition,
|
||||
* deletion or modification of an iocontrol used only by rest-of-bora
|
||||
* does not break vmcore compatibility.
|
||||
* does not break vmcore compatibility.
|
||||
*
|
||||
* See bora/doc/vmcore details.
|
||||
*
|
||||
* If you increment VMMON_VERSION, you must also increment
|
||||
* the NT specific VMX86_DRIVER_VERSION.
|
||||
*/
|
||||
|
||||
#define VMMON_VERSION (401 << 16 | 0)
|
||||
#define VMMON_VERSION (309 << 16 | 0)
|
||||
#define VMMON_VERSION_MAJOR(v) ((uint32) (v) >> 16)
|
||||
#define VMMON_VERSION_MINOR(v) ((uint16) (v))
|
||||
|
||||
@@ -157,10 +142,13 @@ PtrToVA64(void const *ptr) // IN
|
||||
* ENOMEM returned after MAX_VMS virtual machines created
|
||||
*/
|
||||
|
||||
#ifdef VMX86_SERVER
|
||||
#define MAX_VMS 128
|
||||
#else
|
||||
#define MAX_VMS 64
|
||||
|
||||
/*
|
||||
* MsgWaitForMultipleObjects doesn't scale well enough on Win32.
|
||||
#endif
|
||||
/*
|
||||
* MsgWaitForMultipleObjects doesn't scale well enough on Win32.
|
||||
* Allocate with MAX_VMS so static buffers are large, but do
|
||||
* admissions control with this value on Win32 until we check
|
||||
* scalability (probably in authd).
|
||||
@@ -209,14 +197,13 @@ enum IOCTLCmd {
|
||||
#endif
|
||||
IOCTLCMD(VERSION) = IOCTLCMD(FIRST),
|
||||
IOCTLCMD(CREATE_VM),
|
||||
IOCTLCMD(PROCESS_BOOTSTRAP),
|
||||
IOCTLCMD(REGISTER_SHARED),
|
||||
IOCTLCMD(REGISTER_STATVARS),
|
||||
IOCTLCMD(RELEASE_VM),
|
||||
IOCTLCMD(GET_NUM_VMS),
|
||||
IOCTLCMD(ALLOC_CROSSGDT),
|
||||
IOCTLCMD(INIT_VM),
|
||||
IOCTLCMD(INIT_CROSSGDT),
|
||||
IOCTLCMD(RUN_VM),
|
||||
IOCTLCMD(LOOK_UP_MPN),
|
||||
IOCTLCMD(GET_VMM_PAGE_ROOT),
|
||||
IOCTLCMD(LOCK_PAGE),
|
||||
IOCTLCMD(UNLOCK_PAGE),
|
||||
IOCTLCMD(APIC_INIT),
|
||||
@@ -225,6 +212,8 @@ enum IOCTLCmd {
|
||||
IOCTLCMD(ADMIT),
|
||||
IOCTLCMD(UPDATE_MEM_INFO),
|
||||
IOCTLCMD(READMIT),
|
||||
IOCTLCMD(PAE_ENABLED),
|
||||
IOCTLCMD(GET_TOTAL_MEM_USAGE),
|
||||
IOCTLCMD(GET_KHZ_ESTIMATE),
|
||||
IOCTLCMD(SET_HOST_CLOCK_RATE),
|
||||
IOCTLCMD(READ_PAGE),
|
||||
@@ -233,11 +222,14 @@ enum IOCTLCmd {
|
||||
IOCTLCMD(UNLOCK_PAGE_BY_MPN),
|
||||
/* AWE calls */
|
||||
IOCTLCMD(ALLOC_LOCKED_PAGES),
|
||||
IOCTLCMD(FREE_LOCKED_PAGES),
|
||||
IOCTLCMD(GET_NEXT_ANON_PAGE),
|
||||
IOCTLCMD(GET_NUM_ANON_PAGES),
|
||||
IOCTLCMD(GET_LOCKED_PAGES_LIST),
|
||||
|
||||
IOCTLCMD(GET_ALL_MSRS),
|
||||
|
||||
IOCTLCMD(COUNT_PRESENT_PAGES),
|
||||
|
||||
IOCTLCMD(GET_REFERENCE_CLOCK_HZ),
|
||||
IOCTLCMD(INIT_PSEUDO_TSC),
|
||||
IOCTLCMD(CHECK_PSEUDO_TSC),
|
||||
@@ -247,8 +239,6 @@ enum IOCTLCmd {
|
||||
|
||||
IOCTLCMD(GET_IPI_VECTORS),
|
||||
IOCTLCMD(SEND_IPI),
|
||||
IOCTLCMD(SEND_ONE_IPI),
|
||||
IOCTLCMD(GET_SWITCH_ERROR_ADDR),
|
||||
|
||||
/*
|
||||
* Keep host-specific calls at the end so they can be undefined
|
||||
@@ -257,29 +247,48 @@ enum IOCTLCmd {
|
||||
|
||||
#if defined __linux__
|
||||
IOCTLCMD(SET_UID), // VMX86_DEVEL only
|
||||
#endif
|
||||
|
||||
#if defined __linux__ || defined __APPLE__
|
||||
IOCTLCMD(GET_ALL_CPUID),
|
||||
IOCTLCMD(GET_KERNEL_CLOCK_RATE),
|
||||
#endif
|
||||
|
||||
#if defined _WIN32 || defined __APPLE__
|
||||
IOCTLCMD(ALLOC_CONTIG_PAGES),
|
||||
#endif
|
||||
|
||||
#if defined _WIN32
|
||||
IOCTLCMD(HARD_LIMIT_MONITOR_STATUS), // used by vmauthd on Windows
|
||||
IOCTLCMD(CHANGE_HARD_LIMIT), // used by vmauthd on Windows
|
||||
IOCTLCMD(READ_DISASM_PROC_BINARY),
|
||||
IOCTLCMD(CHECK_CANDIDATE_VA64),
|
||||
IOCTLCMD(FREE_CONTIG_PAGES),
|
||||
IOCTLCMD(HARD_LIMIT_MONITOR_STATUS), // Windows 2000 only
|
||||
IOCTLCMD(BLUE_SCREEN), // USE_BLUE_SCREEN only
|
||||
IOCTLCMD(CHANGE_HARD_LIMIT),
|
||||
IOCTLCMD(GET_KERNEL_PROC_ADDRESS),
|
||||
IOCTLCMD(READ_VA64),
|
||||
IOCTLCMD(SET_MEMORY_PARAMS),
|
||||
IOCTLCMD(REMEMBER_KHZ_ESTIMATE),
|
||||
IOCTLCMD(REMAP_SCATTER_LIST),
|
||||
IOCTLCMD(REMAP_SCATTER_LIST_RO), // map the list as read-only
|
||||
IOCTLCMD(UNMAP_SCATTER_LIST),
|
||||
#endif
|
||||
|
||||
#if defined __APPLE__
|
||||
IOCTLCMD(GET_NUM_RESPONDING_CPUS),
|
||||
IOCTLCMD(ALLOC_LOW_PAGES),
|
||||
IOCTLCMD(INIT_DRIVER),
|
||||
IOCTLCMD(BLUEPILL),
|
||||
#endif
|
||||
|
||||
IOCTLCMD(SET_POLL_TIMEOUT_PTR),
|
||||
|
||||
IOCTLCMD(FAST_SUSP_RES_SET_OTHER_FLAG),
|
||||
IOCTLCMD(FAST_SUSP_RES_GET_MY_FLAG),
|
||||
|
||||
#if defined __linux__
|
||||
IOCTLCMD(SET_HOST_CLOCK_PRIORITY),
|
||||
IOCTLCMD(VMX_ENABLED),
|
||||
IOCTLCMD(SET_HOST_SWAP_SIZE),
|
||||
#endif
|
||||
|
||||
IOCTLCMD(GET_UNAVAIL_PERF_CTRS),
|
||||
IOCTLCMD(GET_MONITOR_CONTEXT),
|
||||
// Must be last.
|
||||
IOCTLCMD(LAST)
|
||||
};
|
||||
@@ -309,17 +318,14 @@ enum IOCTLCmd {
|
||||
#define IOCTL_VMX86_VERSION VMIOCTL_BUFFERED(VERSION)
|
||||
#define IOCTL_VMX86_CREATE_VM VMIOCTL_BUFFERED(CREATE_VM)
|
||||
#define IOCTL_VMX86_RELEASE_VM VMIOCTL_BUFFERED(RELEASE_VM)
|
||||
#define IOCTL_VMX86_PROCESS_BOOTSTRAP VMIOCTL_BUFFERED(PROCESS_BOOTSTRAP)
|
||||
#define IOCTL_VMX86_REGISTER_SHARED VMIOCTL_BUFFERED(REGISTER_SHARED)
|
||||
#define IOCTL_VMX86_REGISTER_STATVARS VMIOCTL_BUFFERED(REGISTER_STATVARS)
|
||||
#define IOCTL_VMX86_GET_NUM_VMS VMIOCTL_BUFFERED(GET_NUM_VMS)
|
||||
#define IOCTL_VMX86_ALLOC_CROSSGDT VMIOCTL_BUFFERED(ALLOC_CROSSGDT)
|
||||
#define IOCTL_VMX86_INIT_VM VMIOCTL_BUFFERED(INIT_VM)
|
||||
#define IOCTL_VMX86_INIT_CROSSGDT VMIOCTL_BUFFERED(INIT_CROSSGDT)
|
||||
#define IOCTL_VMX86_RUN_VM VMIOCTL_NEITHER(RUN_VM)
|
||||
#define IOCTL_VMX86_SEND_IPI VMIOCTL_NEITHER(SEND_IPI)
|
||||
#define IOCTL_VMX86_SEND_ONE_IPI VMIOCTL_BUFFERED(SEND_ONE_IPI)
|
||||
#define IOCTL_VMX86_GET_IPI_VECTORS VMIOCTL_BUFFERED(GET_IPI_VECTORS)
|
||||
#define IOCTL_VMX86_GET_SWITCH_ERROR_ADDR VMIOCTL_BUFFERED(GET_SWITCH_ERROR_ADDR)
|
||||
#define IOCTL_VMX86_LOOK_UP_MPN VMIOCTL_BUFFERED(LOOK_UP_MPN)
|
||||
#define IOCTL_VMX86_GET_VMM_PAGE_ROOT VMIOCTL_BUFFERED(GET_VMM_PAGE_ROOT)
|
||||
#define IOCTL_VMX86_LOCK_PAGE VMIOCTL_BUFFERED(LOCK_PAGE)
|
||||
#define IOCTL_VMX86_UNLOCK_PAGE VMIOCTL_BUFFERED(UNLOCK_PAGE)
|
||||
#define IOCTL_VMX86_APIC_INIT VMIOCTL_BUFFERED(APIC_INIT)
|
||||
@@ -328,8 +334,12 @@ enum IOCTLCmd {
|
||||
#define IOCTL_VMX86_ADMIT VMIOCTL_BUFFERED(ADMIT)
|
||||
#define IOCTL_VMX86_READMIT VMIOCTL_BUFFERED(READMIT)
|
||||
#define IOCTL_VMX86_UPDATE_MEM_INFO VMIOCTL_BUFFERED(UPDATE_MEM_INFO)
|
||||
#define IOCTL_VMX86_PAE_ENABLED VMIOCTL_BUFFERED(PAE_ENABLED)
|
||||
#define IOCTL_VMX86_BEEP VMIOCTL_BUFFERED(BEEP)
|
||||
#define IOCTL_VMX86_HARD_LIMIT_MONITOR_STATUS VMIOCTL_BUFFERED(HARD_LIMIT_MONITOR_STATUS)
|
||||
#define IOCTL_VMX86_CHANGE_HARD_LIMIT VMIOCTL_BUFFERED(CHANGE_HARD_LIMIT)
|
||||
#define IOCTL_VMX86_ALLOC_CONTIG_PAGES VMIOCTL_BUFFERED(ALLOC_CONTIG_PAGES)
|
||||
#define IOCTL_VMX86_FREE_CONTIG_PAGES VMIOCTL_BUFFERED(FREE_CONTIG_PAGES)
|
||||
|
||||
#define IOCTL_VMX86_GET_TOTAL_MEM_USAGE VMIOCTL_BUFFERED(GET_TOTAL_MEM_USAGE)
|
||||
#define IOCTL_VMX86_GET_KHZ_ESTIMATE VMIOCTL_BUFFERED(GET_KHZ_ESTIMATE)
|
||||
@@ -340,33 +350,40 @@ enum IOCTLCmd {
|
||||
#define IOCTL_VMX86_LOCK_PAGE_NEW VMIOCTL_BUFFERED(LOCK_PAGE_NEW)
|
||||
#define IOCTL_VMX86_UNLOCK_PAGE_BY_MPN VMIOCTL_BUFFERED(UNLOCK_PAGE_BY_MPN)
|
||||
#define IOCTL_VMX86_ALLOC_LOCKED_PAGES VMIOCTL_BUFFERED(ALLOC_LOCKED_PAGES)
|
||||
#define IOCTL_VMX86_FREE_LOCKED_PAGES VMIOCTL_BUFFERED(FREE_LOCKED_PAGES)
|
||||
#define IOCTL_VMX86_GET_NEXT_ANON_PAGE VMIOCTL_BUFFERED(GET_NEXT_ANON_PAGE)
|
||||
#define IOCTL_VMX86_GET_NUM_ANON_PAGES VMIOCTL_BUFFERED(GET_NUM_ANON_PAGES)
|
||||
|
||||
#define IOCTL_VMX86_READ_DISASM_PROC_BINARY \
|
||||
VMIOCTL_BUFFERED(READ_DISASM_PROC_BINARY)
|
||||
#define IOCTL_VMX86_CHECK_CANDIDATE_VA64 VMIOCTL_BUFFERED(CHECK_CANDIDATE_VA64)
|
||||
#define IOCTL_VMX86_GET_LOCKED_PAGES_LIST VMIOCTL_BUFFERED(GET_LOCKED_PAGES_LIST)
|
||||
|
||||
#define IOCTL_VMX86_GET_KERNEL_PROC_ADDRESS VMIOCTL_BUFFERED(GET_KERNEL_PROC_ADDRESS)
|
||||
#define IOCTL_VMX86_READ_VA64 VMIOCTL_BUFFERED(READ_VA64)
|
||||
#define IOCTL_VMX86_SET_MEMORY_PARAMS VMIOCTL_BUFFERED(SET_MEMORY_PARAMS)
|
||||
|
||||
#define IOCTL_VMX86_REMEMBER_KHZ_ESTIMATE VMIOCTL_BUFFERED(REMEMBER_KHZ_ESTIMATE)
|
||||
|
||||
#define IOCTL_VMX86_GET_ALL_MSRS VMIOCTL_BUFFERED(GET_ALL_MSRS)
|
||||
#define IOCTL_VMX86_COUNT_PRESENT_PAGES VMIOCTL_BUFFERED(COUNT_PRESENT_PAGES)
|
||||
|
||||
#define IOCTL_VMX86_FAST_SUSP_RES_SET_OTHER_FLAG VMIOCTL_BUFFERED(FAST_SUSP_RES_SET_OTHER_FLAG)
|
||||
#define IOCTL_VMX86_FAST_SUSP_RES_GET_MY_FLAG VMIOCTL_BUFFERED(FAST_SUSP_RES_GET_MY_FLAG)
|
||||
|
||||
#define IOCTL_VMX86_GET_REFERENCE_CLOCK_HZ VMIOCTL_BUFFERED(GET_REFERENCE_CLOCK_HZ)
|
||||
#define IOCTL_VMX86_INIT_PSEUDO_TSC VMIOCTL_BUFFERED(INIT_PSEUDO_TSC)
|
||||
#define IOCTL_VMX86_CHECK_PSEUDO_TSC VMIOCTL_BUFFERED(CHECK_PSEUDO_TSC)
|
||||
#define IOCTL_VMX86_GET_PSEUDO_TSC VMIOCTL_NEITHER(GET_PSEUDO_TSC)
|
||||
#define IOCTL_VMX86_SET_HOST_CLOCK_PRIORITY VMIOCTL_BUFFERED(SET_HOST_CLOCK_PRIORITY)
|
||||
#define IOCTL_VMX86_GET_UNAVAIL_PERF_CTRS VMIOCTL_NEITHER(GET_UNAVAIL_PERF_CTRS)
|
||||
#define IOCTL_VMX86_GET_MONITOR_CONTEXT VMIOCTL_BUFFERED(GET_MONITOR_CONTEXT)
|
||||
#define IOCTL_VMX86_REMAP_SCATTER_LIST VMIOCTL_BUFFERED(REMAP_SCATTER_LIST)
|
||||
#define IOCTL_VMX86_REMAP_SCATTER_LIST_RO VMIOCTL_BUFFERED(REMAP_SCATTER_LIST_RO)
|
||||
#define IOCTL_VMX86_UNMAP_SCATTER_LIST VMIOCTL_BUFFERED(UNMAP_SCATTER_LIST)
|
||||
#define IOCTL_VMX86_REMAP_SCATTER_LIST VMIOCTL_BUFFERED(REMAP_SCATTER_LIST)
|
||||
#define IOCTL_VMX86_UNMAP_SCATTER_LIST VMIOCTL_BUFFERED(UNMAP_SCATTER_LIST)
|
||||
#endif
|
||||
|
||||
|
||||
#define INIT_BLOCK_MAGIC (0x1789 + 14)
|
||||
/*
|
||||
* Flags sent into APICBASE ioctl
|
||||
*/
|
||||
|
||||
#define APIC_FLAG_DISABLE_NMI 0x00000001
|
||||
#define APIC_FLAG_PROBE 0x00000002
|
||||
#define APIC_FLAG_FORCE_ENABLE 0x00000004
|
||||
|
||||
typedef
|
||||
#include "vmware_pack_begin.h"
|
||||
@@ -386,31 +403,27 @@ union {
|
||||
#include "vmware_pack_end.h"
|
||||
VMLockPage;
|
||||
|
||||
typedef
|
||||
#include "vmware_pack_begin.h"
|
||||
union {
|
||||
Vcpuid vcpuid; // IN: VCPU
|
||||
MPN pageRoot; // OUT: MPN of the VCPU's page root
|
||||
}
|
||||
#include "vmware_pack_end.h"
|
||||
VcpuPageRoot;
|
||||
|
||||
#define VMX86_DRIVER_VCPUID_OFFSET 1000
|
||||
typedef struct VMAPICInfo {
|
||||
uint32 flags;
|
||||
} VMAPICInfo;
|
||||
|
||||
#define VMX86_DRIVER_VCPUID_OFFSET 1000
|
||||
|
||||
|
||||
/*
|
||||
* We keep track of 3 different limits on the number of pages we can lock.
|
||||
* The host limit is determined at driver load time (in windows only) to
|
||||
* make sure we do not starve the host by locking too many pages.
|
||||
* The static limit is user defined in the UI and the dynamic limit is
|
||||
* The static limit is user defined in the UI and the dynamic limit is
|
||||
* set by authd's hardLimitMonitor code (windows only), which queries
|
||||
* host load and adjusts the limit accordingly. We lock the minimum of
|
||||
* host load and adjusts the limit accordingly. We lock the minimum of
|
||||
* all these values at any given time.
|
||||
*/
|
||||
typedef struct LockedPageLimit {
|
||||
PageCnt host; // driver calculated maximum for this host
|
||||
PageCnt configured; // user defined maximum pages to lock
|
||||
PageCnt dynamic; // authd hardLimitMonitor pages to lock
|
||||
uint32 host; // driver calculated maximum for this host
|
||||
uint32 configured; // user defined maximum pages to lock
|
||||
uint32 dynamic; // authd hardLimitMonitor pages to lock
|
||||
} LockedPageLimit;
|
||||
|
||||
/*
|
||||
@@ -431,15 +444,15 @@ typedef struct LockedPageLimit {
|
||||
*/
|
||||
|
||||
typedef struct VMMemMgmtInfo {
|
||||
PageCnt minAllocation; // minimum pages for vm
|
||||
PageCnt maxAllocation; // maximum pages the vm could lock
|
||||
PageCnt nonpaged; // overhead memory (guest, mmap)
|
||||
PageCnt paged; // vmx memory (malloc, statics)
|
||||
PageCnt anonymous; // vmm memory
|
||||
PageCnt mainMemSize; // guest main memory size
|
||||
PageCnt locked; // number of pages locked by this vm
|
||||
PageCnt perVMOverhead; // memory for vmx/vmmon overheads
|
||||
uint32 minAllocation; // minimum pages for vm
|
||||
uint32 maxAllocation; // maximum pages the vm could lock
|
||||
uint32 shares; // proportional sharing weight
|
||||
uint32 nonpaged; // overhead memory (guest, mmap)
|
||||
uint32 paged; // vmx memory (malloc, statics)
|
||||
uint32 anonymous; // vmm memory
|
||||
uint32 mainMemSize; // guest main memory size
|
||||
uint32 locked; // number of pages locked by this vm
|
||||
uint32 perVMOverhead; // memory for vmx/vmmon overheads
|
||||
Percent touchedPct; // % of guest memory being touched
|
||||
Percent dirtiedPct; // % of guest memory being dirtied
|
||||
Bool admitted; // admission control
|
||||
@@ -461,15 +474,15 @@ typedef struct VMMemMgmtInfoPatch {
|
||||
*/
|
||||
|
||||
typedef struct VMMemInfoArgs {
|
||||
uint64 currentTime; // Host time in secs of the call.
|
||||
PageCnt globalMinAllocation;// pages that must fit in maxLockedPages
|
||||
PageCnt numLockedPages; // total locked pages by all vms
|
||||
uint64 currentTime; // Host time in secs of the call.
|
||||
uint32 minVmMemPct; // % of vm that must fit in memory
|
||||
uint32 globalMinAllocation;// pages that must fit in maxLockedPages
|
||||
uint32 numLockedPages; // total locked pages by all vms
|
||||
LockedPageLimit lockedPageLimit; // set of locked page limits
|
||||
PageCnt maxLockedPages; // effective limit on locked pages
|
||||
uint32 maxLockedPages; // effective limit on locked pages
|
||||
uint32 callerIndex; // this vm's index memInfo array
|
||||
uint32 numVMs; // number of running VMs
|
||||
Percent minVmMemPct; // % of vm that must fit in memory
|
||||
uint8 _pad[7];
|
||||
uint8 _pad[4];
|
||||
VMMemMgmtInfo memInfo[1];
|
||||
} VMMemInfoArgs;
|
||||
|
||||
@@ -482,12 +495,19 @@ typedef struct VMMPNNext {
|
||||
} VMMPNNext;
|
||||
|
||||
typedef struct VMMPNList {
|
||||
PageCnt mpnCount; // IN (and OUT on Mac OS)
|
||||
uint32 mpnCount; // IN (and OUT on Mac OS)
|
||||
Bool ignoreLimits;
|
||||
uint8 _pad[7];
|
||||
uint8 _pad[3];
|
||||
VA64 mpnList; // IN: User VA of an array of 64-bit MPNs.
|
||||
} VMMPNList;
|
||||
|
||||
typedef struct VARange {
|
||||
VA64 addr;
|
||||
VA64 bv;
|
||||
unsigned len;
|
||||
uint32 pad;
|
||||
} VARange;
|
||||
|
||||
typedef struct VMMUnlockPageByMPN {
|
||||
MPN mpn;
|
||||
VA64 uAddr; /* IN: User VA of the page (optional). */
|
||||
@@ -498,6 +518,11 @@ typedef struct VMMReadWritePage {
|
||||
VA64 uAddr; // IN: User VA of a PAGE_SIZE-large buffer.
|
||||
} VMMReadWritePage;
|
||||
|
||||
struct passthrough_iorange {
|
||||
unsigned short ioBase; /* Base of range to pass through. */
|
||||
unsigned short numPorts; /* Length of range. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Data structure for the INIT_PSEUDO_TSC and CHECK_PSEUDO_TSC.
|
||||
*/
|
||||
@@ -520,102 +545,79 @@ typedef struct PTSCCheckParams {
|
||||
uint8 _pad[7];
|
||||
} PTSCCheckParams;
|
||||
|
||||
#ifndef VMX86_SERVER
|
||||
|
||||
typedef struct IPIVectors {
|
||||
/*
|
||||
* Vector(s) the host uses for its own IPIs; we use this as a performance
|
||||
* hint.
|
||||
*/
|
||||
uint8 hostIPIVectors[2];
|
||||
/*
|
||||
* Vectors we have allocated or stolen for the monitor interrupts.
|
||||
*/
|
||||
uint8 monitorIPIVector;
|
||||
uint8 monitorIPIVector;
|
||||
uint8 hvIPIVector;
|
||||
} IPIVectors;
|
||||
|
||||
/*
|
||||
* Arguments and return value for VM creation.
|
||||
*/
|
||||
typedef struct VMCreateBlock {
|
||||
VA64 bsBlob; // IN: User VA of the VMM bootstrap blob.
|
||||
VA64 vmmonData; // IN: User VA of a userlevel scratch area
|
||||
// required by the Linux vmmon
|
||||
uint32 bsBlobSize; // IN: Size of VMM bootstrap blob.
|
||||
uint32 numVCPUs; // IN: Number of VCPUs.
|
||||
uint16 vmid; // OUT: VM ID for the created VM.
|
||||
} VMCreateBlock;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Information about a shared region.
|
||||
* This struct is passed to IOCTL_VMX86_INIT_CROSSGDT to fill in a crossGDT
|
||||
* entry.
|
||||
*/
|
||||
typedef struct VMSharedRegion {
|
||||
SharedAreaType index;
|
||||
VPN baseVpn;
|
||||
uint32 numPages;
|
||||
} VMSharedRegion;
|
||||
typedef struct InitCrossGDT {
|
||||
uint32 index; // index in crossGDT to update (offset / 8)
|
||||
Descriptor value; // value to set the crossGDT entry to
|
||||
} InitCrossGDT;
|
||||
|
||||
#if defined __linux__
|
||||
|
||||
/*
|
||||
* Arguments for VMM shared area registration.
|
||||
* Linux uses mmap(2) to allocate contiguous locked pages, and uses these
|
||||
* macros to marshall real arguments to mmap's made-up 'offset' argument.
|
||||
*/
|
||||
typedef struct VMSharedAreaRegistrationBlock {
|
||||
Vcpuid vcpu; // IN: VCPU being registered.
|
||||
VMSharedRegion region; // IN: Shared region being registered.
|
||||
} VMSharedAreaRegistrationBlock;
|
||||
|
||||
#define VMMON_MAP_MT_LOW4GB 0
|
||||
#define VMMON_MAP_MT_LOW16MB 1
|
||||
#define VMMON_MAP_MT_ANY 2
|
||||
|
||||
#define VMMON_MAP_OFFSET_SHIFT 0
|
||||
#define VMMON_MAP_OFFSET_MASK 0x00000FFF
|
||||
#define VMMON_MAP_ORDER_SHIFT 12
|
||||
#define VMMON_MAP_ORDER_MASK 0xF
|
||||
#define VMMON_MAP_MT_SHIFT 16
|
||||
#define VMMON_MAP_MT_MASK 0x7
|
||||
#define VMMON_MAP_RSVD_SHIFT 19
|
||||
|
||||
#define VMMON_MAP_RSVD(base) \
|
||||
((base) >> VMMON_MAP_RSVD_SHIFT)
|
||||
#define VMMON_MAP_MT(base) \
|
||||
(((base) >> VMMON_MAP_MT_SHIFT) & VMMON_MAP_MT_MASK)
|
||||
#define VMMON_MAP_ORDER(base) \
|
||||
(((base) >> VMMON_MAP_ORDER_SHIFT) & VMMON_MAP_ORDER_MASK)
|
||||
#define VMMON_MAP_OFFSET(base) \
|
||||
(((base) >> VMMON_MAP_OFFSET_SHIFT) & VMMON_MAP_OFFSET_MASK)
|
||||
|
||||
#define VMMON_MAP_BASE(mt, order) (((mt) << VMMON_MAP_MT_SHIFT) | \
|
||||
((order) << VMMON_MAP_ORDER_SHIFT))
|
||||
|
||||
#elif defined _WIN32
|
||||
/*
|
||||
* Information about a VM's statvars.
|
||||
* Windows uses an ioctl to allocate contiguous locked pages.
|
||||
*/
|
||||
typedef struct VMStatVarsRegistrationBlock {
|
||||
VPN baseVpn;
|
||||
PageCnt numPages;
|
||||
Vcpuid vcpu;
|
||||
} VMStatVarsRegistrationBlock;
|
||||
|
||||
typedef struct {
|
||||
VA64 ptRoot; // IN: User VA of VCPU L4 page table root.
|
||||
} PerVcpuPages;
|
||||
|
||||
/*
|
||||
* Arguments for VMM bootstrap processing.
|
||||
*/
|
||||
typedef struct VMProcessBootstrapBlock {
|
||||
VA64 bsBlobAddr; // IN: User VA of the VMM bootstrap blob.
|
||||
uint32 numBytes; // IN: Size of VMM bootstrap blob.
|
||||
uint32 headerOffset; // IN: Offset of header in blob.
|
||||
uint16 numVCPUs; // IN: Number of VCPUs.
|
||||
VMSharedRegion shRegions[ML_SHARED_REGIONS_MAX]; // IN: Shared regions.
|
||||
PerVcpuPages perVcpuPages[0];
|
||||
} VMProcessBootstrapBlock;
|
||||
|
||||
/*
|
||||
* Arguments for retrieving the switch error address.
|
||||
*/
|
||||
typedef struct VMSwitchErrorArgs {
|
||||
Vcpuid vcpuid; // IN: The VCPU of interest.
|
||||
uint64 addr; // OUT: The code address that a failure was detected at, or 0
|
||||
// if no failure has occurred.
|
||||
} VMSwitchErrorArgs;
|
||||
|
||||
static INLINE size_t
|
||||
GetVMProcessBootstrapBlockSize(unsigned numVCPUs)
|
||||
{
|
||||
VMProcessBootstrapBlock *args = NULL;
|
||||
return sizeof *args + numVCPUs * sizeof args->perVcpuPages[0];
|
||||
}
|
||||
|
||||
/*
|
||||
* Arguments for VMM context retrieval.
|
||||
*/
|
||||
typedef union {
|
||||
Vcpuid vcpuid; // IN
|
||||
Context64 context; // OUT
|
||||
} VMMonContext;
|
||||
|
||||
#if defined __APPLE__
|
||||
typedef struct VMAllocContiguousMem {
|
||||
VA64 mpnList; // IN: User VA of an array of 64-bit MPNs.
|
||||
uint32 mpnCount; // IN
|
||||
uint32 order; // IN
|
||||
MPN maxMPN; // IN
|
||||
} VMAllocContiguousMem;
|
||||
#elif defined __APPLE__
|
||||
# include "iocontrolsMacos.h"
|
||||
#endif
|
||||
|
||||
/* Clean up helper macros */
|
||||
#undef IOCTLCMD
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // ifndef _IOCONTROLS_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2016 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2012 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -24,15 +24,12 @@
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "vm_basic_math.h"
|
||||
#include "vm_basic_defs.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MEMDEFAULTS_MIN_HOST_PAGES MBYTES_2_PAGES(128)
|
||||
|
||||
|
||||
@@ -154,8 +151,4 @@ MemDefaults_CalcMinReservedMBs(uint32 hostMem) // IN:
|
||||
void MemDefaults_GetReservedMemory(uint32 *host, uint32 *min,
|
||||
uint32 *max, uint32 *recommended);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+211
-142
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2015,2018 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -41,37 +41,22 @@
|
||||
#include "modulecallstructs.h"
|
||||
#include "mon_assert.h"
|
||||
|
||||
#define NUM_EXCEPTIONS 20 /* EXC_DE ... EXC_XF. */
|
||||
|
||||
#define NUM_EXCEPTIONS 20 /* EXC_DE ... EXC_XF. */
|
||||
|
||||
#define MODULECALL_TABLE \
|
||||
MC(INTR) \
|
||||
MC(SEMAWAIT) \
|
||||
MC(SEMASIGNAL) \
|
||||
MC(SEMAFORCEWAKEUP) \
|
||||
MC(IPI) /* Hit multiple threads with IPI. */ \
|
||||
MC(ONE_IPI) /* Hit a single thread with IPI. */ \
|
||||
MC(IPI) /* Hit thread with IPI. */ \
|
||||
MC(USERRETURN) /* Return codes for user calls. */ \
|
||||
MC(GET_RECYCLED_PAGES) \
|
||||
MC(RELEASE_ANON_PAGES) \
|
||||
MC(LOOKUP_MPN) \
|
||||
MC(COSCHED) \
|
||||
MC(ALLOC_CONTIG_PAGES) \
|
||||
MC(ALLOC_VMX_PAGE) \
|
||||
MC(ALLOC_TMP_GDT) \
|
||||
MC(PIN_MPN) \
|
||||
MC(VMCLEAR_VMCS_ALL_CPUS) \
|
||||
MC(GET_PAGE_ROOT) \
|
||||
MC(ALLOC_ANON_LOW_PAGE) \
|
||||
MC(GET_MON_IPI_VECTOR) \
|
||||
MC(GET_HV_IPI_VECTOR) \
|
||||
MC(GET_PERF_CTR_VECTOR) \
|
||||
MC(GET_HOST_TIMER_VECTORS) \
|
||||
MC(BOOTSTRAP_CLEANUP) \
|
||||
MC(GET_SHARED_AREA) \
|
||||
MC(GET_STAT_VARS) \
|
||||
MC(GET_NUM_PTP_PAGES) \
|
||||
MC(GET_HV_IO_BITMAP) \
|
||||
MC(GET_MSR) \
|
||||
MC(PIN_MPN)
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -80,6 +65,9 @@
|
||||
*
|
||||
* Enumeration of support calls done by the module.
|
||||
*
|
||||
* If anything changes in the enum, please update kstatModuleCallPtrs
|
||||
* for stats purposes.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -109,8 +97,8 @@ typedef enum ModuleCallType {
|
||||
*/
|
||||
|
||||
#if defined(VMX86_UCCOST) && !defined(VMX86_SERVER)
|
||||
#define UCTIMESTAMP(ptr, stamp) \
|
||||
do { (ptr)[UCCOST_ ## stamp] = RDTSC(); } while (0)
|
||||
#define UCTIMESTAMP(cp, stamp) \
|
||||
do { (cp)->ucTimeStamps[UCCOST_ ## stamp] = RDTSC(); } while (0)
|
||||
#else
|
||||
#define UCTIMESTAMP(cp, stamp)
|
||||
#endif
|
||||
@@ -130,12 +118,62 @@ typedef struct UCCostResults {
|
||||
} UCCostResults;
|
||||
|
||||
typedef enum UCCostStamp {
|
||||
#define UC(x, y) UCCOST_ ## x,
|
||||
#define UC(x) UCCOST_ ## x,
|
||||
#include "uccostTable.h"
|
||||
UCCOST_MAX
|
||||
} UCCostStamp;
|
||||
#endif // VMX86_SERVER
|
||||
|
||||
/*
|
||||
* Header for the wsBody64.S worldswitch code file.
|
||||
*/
|
||||
typedef struct WSModule {
|
||||
uint32 vmmonVersion; // VMMON_VERSION when assembled as part of monitor
|
||||
uint16 moduleSize; // size of whole wsBody64 module
|
||||
uint16 hostToVmm; // offset from beginning of header to hostToVmm
|
||||
uint16 vmm64ToHost;
|
||||
uint16 _pad[3];
|
||||
|
||||
uint8 code[1024]; // big enough for MAX('.wsBody64', 'wsBody64Log')
|
||||
} WSModule;
|
||||
|
||||
typedef
|
||||
#include "vmware_pack_begin.h"
|
||||
struct SwitchNMIOffsets {
|
||||
uint16 db; // offset to start of #DB handler
|
||||
uint16 nmi; // offset to start of #NMI handler
|
||||
uint16 df; // offset to start of #DF handler
|
||||
uint16 ud; // offset to start of #UD handler
|
||||
uint16 gp; // offset to start of #GP handler
|
||||
uint16 pf; // offset to start of #PF handler
|
||||
uint16 mce; // offset to start of #MCE handler
|
||||
}
|
||||
#include "vmware_pack_end.h"
|
||||
SwitchNMIOffsets;
|
||||
|
||||
/*
|
||||
* This is a header for the switchNMI.S module. It contains code for
|
||||
* exceptions occurring during worldswitch. The code gets copied to
|
||||
* the crosspage by initialization.
|
||||
*/
|
||||
typedef
|
||||
#include "vmware_pack_begin.h"
|
||||
struct SwitchNMI { // see switchNMI.S
|
||||
uint16 switchNMISize;
|
||||
SwitchNMIOffsets host; // offsets to handlers
|
||||
volatile Bool wsException[NUM_EXCEPTIONS]; // EXC_DE ... EXC_XF
|
||||
// TRUE -> fault occurred in
|
||||
// worldswitch
|
||||
uint64 wsUD2; // IP of ud2 instruction
|
||||
// 0ULL == unset
|
||||
// other == worldswitch IP
|
||||
uint8 codeBlock[768]; // Enough for
|
||||
// max('.switchNMI',
|
||||
// '.switchNMILog').
|
||||
}
|
||||
#include "vmware_pack_end.h"
|
||||
SwitchNMI;
|
||||
|
||||
#define SHADOW_DR(cpData, n) (cpData)->shadowDR[n].ureg64
|
||||
|
||||
|
||||
@@ -144,8 +182,8 @@ typedef enum UCCostStamp {
|
||||
* MAX_SWITCH_PT_PATCHES
|
||||
*
|
||||
* This is the maximum number of patches that must be placed into
|
||||
* the monitor page tables so that the host GDT, crosspage data, and
|
||||
* crosspage code can be accessed during worldswitch.
|
||||
* the monitor page tables so that two pages of the host GDT and the
|
||||
* crosspage can be accessed during worldswitch.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -173,7 +211,7 @@ typedef enum UCCostStamp {
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
*
|
||||
* VMMPageTablePatch
|
||||
* VMM64PageTablePatch
|
||||
*
|
||||
* Describes an entry in the monitor page table which needs to be
|
||||
* patched during the back-to-host worldswitch.
|
||||
@@ -186,16 +224,28 @@ typedef enum UCCostStamp {
|
||||
* This is the level in the page table to which the patch must
|
||||
* be applied: L4, L3, L2, L1. This information is used to
|
||||
* determine the base of the region of memory which must be
|
||||
* patched. The value zero is reserved to indicate an empty spot
|
||||
* in the array of patches.
|
||||
* patched. The level value corresponds to the following
|
||||
* regions in monitor memory:
|
||||
*
|
||||
* o index
|
||||
* MMU_ROOT_64
|
||||
* MMU_L3_64
|
||||
* MMU_L2_64
|
||||
* MON_PAGE_TABLE_64
|
||||
*
|
||||
* The index of the PTE at the given page table.
|
||||
* The value zero is reserved to indicate an empty spot in the
|
||||
* array of patches.
|
||||
*
|
||||
* o ptIdx
|
||||
* o level offset
|
||||
*
|
||||
* The index of the page table at the given level.
|
||||
* The monitor memory regions corresponding to the page table
|
||||
* levels may be more than one page in length, so a 'page
|
||||
* offset' is required to know the starting address of the page
|
||||
* table page which must be patched in 'level'.
|
||||
*
|
||||
* o page index
|
||||
*
|
||||
* The 'index' value specifies the element in the page which
|
||||
* should be patched.
|
||||
*
|
||||
* o pte
|
||||
*
|
||||
@@ -206,131 +256,105 @@ typedef enum UCCostStamp {
|
||||
*/
|
||||
typedef
|
||||
#include "vmware_pack_begin.h"
|
||||
struct VMMPageTablePatch {
|
||||
struct VMM64PageTablePatch {
|
||||
#define PTP_EMPTY (0U) /* Unused array entry. (must be 0) */
|
||||
#define PTP_LEVEL_L1 (1U)
|
||||
#define PTP_LEVEL_L1 (1U) /* leaf level */
|
||||
#define PTP_LEVEL_L2 (2U)
|
||||
#define PTP_LEVEL_L3 (3U)
|
||||
#define PTP_LEVEL_L4 (4U) /* root level */
|
||||
uint32 level; /* [0, 4] (maximal size: 3 bits) */
|
||||
uint32 pteIdx; /* Index of the PTE in the page table. */
|
||||
uint64 pteGlobalIdx; /* Global index of the PTE in 'level'. */
|
||||
LPN lpn; /* Logical page number mapped by patch. */
|
||||
VM_PDPTE pte; /* PTE. */
|
||||
uint16 level; /* [0, 4] (maximal size: 3 bits) */
|
||||
uint16 page; /* Index of 'page' in 'level'. */
|
||||
uint32 index; /* Index of 'pte' in 'page'. */
|
||||
VM_PDPTE pte; /* PTE. */
|
||||
}
|
||||
#include "vmware_pack_end.h"
|
||||
VMMPageTablePatch;
|
||||
VMM64PageTablePatch;
|
||||
|
||||
#define MODULECALL_NUM_ARGS 4
|
||||
|
||||
/*
|
||||
* The cross page contains tiny stacks upon which interrupt and exception
|
||||
* handlers in the switch path may temporarily run. Each stack must be
|
||||
* large enough for the sum of:
|
||||
*
|
||||
* - 1 #DB exception frame (5 * uint64)
|
||||
* - 1 #NMI exception frame (5 * uint64)
|
||||
* - 1 #MCE exception frame (5 * uint64)
|
||||
* - the largest stack use instantaneously possible by #MCE handling code
|
||||
* - the largest stack use instantaneously possible by #NMI handling code
|
||||
* - the largest stack use instantaneously possible by #DB handling code
|
||||
* - one high-water uint32 used to detect stack overflows when debugging
|
||||
*
|
||||
* A breakdown of the worst-case exception handler stack usage (SwitchUDHandler)
|
||||
* is: 5 * uint64 (Hardware) + 1 * uint64 (RAX) + 1 * uint64 (RBX) +
|
||||
* 1 * uint64 (RCX) + 1 * uint64 (call) + 2 * uint64 (sidt) = 11 * uint64
|
||||
* This is a slight over-estimate of the possible usage at any time but there
|
||||
* is plenty of space available in the cross page data area.
|
||||
*
|
||||
* 264 (11 * sizeof(uint64) * 3) bytes is slightly more than enough as of
|
||||
* 2020/06/14.
|
||||
*/
|
||||
#define TINY_STACK_SIZE 264
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VMCrossPageData --
|
||||
*
|
||||
* Data which is stored on the cross page.
|
||||
* Data which is stored on the VMCrossPage.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
typedef
|
||||
#include "vmware_pack_begin.h"
|
||||
struct VMCrossPageData {
|
||||
uint32 version; // CROSSPAGE_VERSION
|
||||
uint32 vmmonVersion; // VMMON_VERSION
|
||||
|
||||
/*
|
||||
* The following stacks and contexts are ordered for performance and code
|
||||
* simplicity. Both HostToVmm and VmmToHost strictly require this ordering.
|
||||
* For any change to this data, both functions must be updated.
|
||||
* Use VMX86_UCCOST to measure performance when changing the layout.
|
||||
* A tiny stack upon which interrupt and exception handlers in the switch
|
||||
* path temporarily run. Keep the end 16-byte aligned. This stack must
|
||||
* be large enough for the sum of:
|
||||
*
|
||||
* - 1 #DB exception frame (5 * uint64)
|
||||
* - 1 #NMI exception frame (5 * uint64)
|
||||
* - 1 #MCE exception frame (5 * uint64)
|
||||
* - the largest stack use instantaneously possible by #MCE handling code
|
||||
* - the largest stack use instantaneously possible by #NMI handling code
|
||||
* - the largest stack use instantaneously possible by #DB handling code
|
||||
* - one high-water uint32 used to detect stack overflows when debugging
|
||||
* - remaining pad bytes to align to 16 bytes
|
||||
*
|
||||
* 184 bytes is slightly more than enough as of 2015/03/17 -- fjacobs.
|
||||
*/
|
||||
uint32 tinyStack[46];
|
||||
|
||||
/* A tiny stack and the host context. */
|
||||
uint64 hostTinyStack[TINY_STACK_SIZE / sizeof(uint64)];
|
||||
uint64 hostCR3; /* Edge of context saved/restored in assembly. */
|
||||
uint64 hostCR3;
|
||||
uint32 crosspageMA;
|
||||
|
||||
uint8 hostDRSaved; // Host DR spilled to hostDR[x].
|
||||
uint8 hostDRInHW; // 0 -> shadowDR in h/w, 1 -> hostDR in h/w.
|
||||
// contains host-sized DB,NMI,MCE entries
|
||||
uint16 hostSS;
|
||||
uint64 hostRSP;
|
||||
uint64 hostDR[8];
|
||||
uint64 hostRBX;
|
||||
uint64 hostRBP;
|
||||
uint64 hostRSI;
|
||||
uint64 hostRDI;
|
||||
uint64 hostRBP;
|
||||
uint64 hostR12;
|
||||
uint64 hostR13;
|
||||
uint64 hostR14;
|
||||
uint64 hostR15;
|
||||
uint64 hostRSP;
|
||||
uint16 hostSS; /* Edge of context saved/restored in assembly. */
|
||||
uint16 hostDS; /* Not saved/restored in assembly switch */
|
||||
uint16 hostES; /* Not saved/restored in assembly switch */
|
||||
uint16 hostPad;
|
||||
|
||||
/* A tiny stack and the monitor context. */
|
||||
uint64 monTinyStack[TINY_STACK_SIZE / sizeof(uint64)];
|
||||
uint64 monCR3; /* Edge of context saved/restored in assembly. */
|
||||
uint64 monRBX;
|
||||
uint64 monRBP;
|
||||
uint64 monR12;
|
||||
uint64 monR13;
|
||||
uint64 monR14;
|
||||
uint64 monR15;
|
||||
uint64 monRSP;
|
||||
uint16 monSS; /* Edge of context saved/restored in assembly. */
|
||||
uint16 monDS; /* Not saved/restored in assembly switch */
|
||||
uint16 monES; /* Not saved/restored in assembly switch */
|
||||
uint16 monPad;
|
||||
|
||||
uint64 crosspageDataMA;
|
||||
|
||||
uint64 hostDR[8];
|
||||
LA64 crosspageDataLA; // where host/PTP map the cross data page
|
||||
LA64 crossGDTLA; // where host/PTP map the cross GDT
|
||||
LA64 crosspageCodeLA; // where host/PTP map the cross code page
|
||||
LA64 vmmToHostLA; // where host has placed the VmmToHost function
|
||||
LA64 hostCrossPageLA; // where host has crosspage mapped
|
||||
uint16 hostInitial64CS;
|
||||
uint8 hostDRSaved; // Host DR spilled to hostDR[x].
|
||||
uint8 hostDRInHW; // 0 -> shadowDR in h/w, 1 -> hostDR in h/w.
|
||||
uint32 _pad0;
|
||||
uint16 _pad0[3];
|
||||
|
||||
uint64 wsCR0;
|
||||
uint64 wsCR4;
|
||||
|
||||
DTR64 crossGDTHKLADesc; // always uses host kernel linear address
|
||||
uint16 _pad1[3];
|
||||
DTR64 monGDTR;
|
||||
uint16 _pad2[3];
|
||||
/* A hardcoded value for monitor %rip which facilitates backtraces. */
|
||||
uint64 monRIP;
|
||||
Task64 monTask; /* vmm's task */
|
||||
DTR64 mon64GDTR;
|
||||
uint16 mon64ES;
|
||||
uint16 mon64SS;
|
||||
uint16 mon64DS;
|
||||
uint64 mon64CR3;
|
||||
uint64 mon64RBX;
|
||||
uint64 mon64RSP;
|
||||
uint64 mon64RBP;
|
||||
uint64 mon64RSI;
|
||||
uint64 mon64RDI;
|
||||
uint64 mon64R12;
|
||||
uint64 mon64R13;
|
||||
uint64 mon64R14;
|
||||
uint64 mon64R15;
|
||||
uint64 mon64RIP;
|
||||
Task64 monTask64; /* vmm64's task */
|
||||
|
||||
VMMPageTablePatch vmmPTP[MAX_SWITCH_PT_PATCHES]; /* page table patch */
|
||||
VMM64PageTablePatch vmm64PTP[MAX_SWITCH_PT_PATCHES]; /* page table patch */
|
||||
LA64 vmm64CrossPageLA;
|
||||
LA64 vmm64CrossGDTLA; // where crossGDT mapped by PT patch
|
||||
// 64-bit host: host kernel linear
|
||||
// address
|
||||
|
||||
/*
|
||||
* The monitor may requests up to two actions when returning to the
|
||||
* host. The moduleCallType field and args encode a request for
|
||||
* some action in the driver. The vcpuSet field is an additional
|
||||
* argument used in some calls. The userCallType field (together
|
||||
* some action in the driver. The userCallType field (together
|
||||
* with the RPC block) encodes a user call request. The two
|
||||
* requests are independent. The user call is executed first, with
|
||||
* the exception of MODULECALL_INTR which has a special effect.
|
||||
@@ -338,19 +362,15 @@ struct VMCrossPageData {
|
||||
ModuleCallType moduleCallType;
|
||||
uint32 retval;
|
||||
uint64 args[MODULECALL_NUM_ARGS];
|
||||
#if !defined(VMX86_SERVER)
|
||||
VCPUSet vcpuSet;
|
||||
#endif
|
||||
int userCallType;
|
||||
uint32 pcpuNum; /* Used as extra module call arg within vmmon. */
|
||||
|
||||
VCPUSet yieldVCPUs;
|
||||
|
||||
#if !defined(VMX86_SERVER)
|
||||
uint64 ucTimeStamps[UCCOST_MAX];
|
||||
uint8 _ucPad[8];
|
||||
#endif
|
||||
|
||||
SwitchedMSRState switchedMSRState;
|
||||
|
||||
/*
|
||||
* The values in the shadow debug registers must match those in the
|
||||
* hardware debug register immediately after a task switch in
|
||||
@@ -360,11 +380,8 @@ struct VMCrossPageData {
|
||||
SharedUReg64 shadowDR[8];
|
||||
uint8 shadowDRInHW; // bit n set iff %DRn == shadowDR[n]
|
||||
|
||||
/* TRUE if no bits are set in yieldVCPUs, FALSE otherwise. */
|
||||
Bool yieldVCPUsIsEmpty;
|
||||
uint8 _pad3[6];
|
||||
|
||||
VCPUSet yieldVCPUs;
|
||||
SwitchedMSRState switchedMSRState;
|
||||
uint8 _pad2[7];
|
||||
|
||||
/*
|
||||
* Adjustment for machines where the hardware TSC does not run
|
||||
@@ -380,6 +397,8 @@ struct VMCrossPageData {
|
||||
VmAbsoluteTS hstTimerExpiry; // PTSC of host timer interrupt
|
||||
VmAbsoluteTS monTimerExpiry; // PTSC of next MonTimer callback
|
||||
|
||||
Bool activateVMX; // TRUE -> activate Intel VMX extensions
|
||||
Bool activateSVM; // TRUE -> activate AMD SVM extensions
|
||||
Bool retryWorldSwitch; // TRUE -> return to host on host->vmm switch
|
||||
/*
|
||||
* TRUE if moduleCall was interrupted by signal. Only
|
||||
@@ -387,41 +406,91 @@ struct VMCrossPageData {
|
||||
* restart RunVM call, nobody else should look at it.
|
||||
*/
|
||||
Bool moduleCallInterrupted;
|
||||
uint8 _pad4[6];
|
||||
uint8 _pad3[4];
|
||||
|
||||
DTR64 switchHostIDTR; // baseLA = switchHostIDT's host kernel LA
|
||||
DTR64 switchHostIDTR; // baseLA = switchHostIDT's host knl LA
|
||||
uint16 _pad4[3];
|
||||
DTR64 switchMon64IDTR; // has baseLA = switchMon64IDT's monitor LA
|
||||
// contains 64-bit DB,NMI,MCE entries
|
||||
uint16 _pad5[3];
|
||||
DTR64 switchMonIDTR; // baseLA = switchMonIDT's monitor LA
|
||||
uint16 _pad6[3];
|
||||
|
||||
/*
|
||||
* Descriptors and interrupt tables for switchNMI handlers. Each
|
||||
* IDT has only enough space for the hardware exceptions; they are
|
||||
* sized to accommodate 64-bit descriptors.
|
||||
*/
|
||||
Gate64 switchHostIDT[NUM_EXCEPTIONS]; // hostCS:hostVA
|
||||
Gate64 switchMonIDT[NUM_EXCEPTIONS]; // monCS:monVA
|
||||
volatile Bool wsException[NUM_EXCEPTIONS]; // Tracks faults in worldswitch.
|
||||
uint8 _pad7[4];
|
||||
uint64 wsUD2; // IP of ud2 instr or 0 if unset.
|
||||
uint8 switchHostIDT [sizeof(Gate64) * NUM_EXCEPTIONS]; // hostCS:hostVA
|
||||
uint8 switchMon64IDT[sizeof(Gate64) * NUM_EXCEPTIONS]; // 64-bit monCS:monVA
|
||||
uint64 specCtrl; /* host MSR_SPEC_CTRL value before world switch. */
|
||||
}
|
||||
#include "vmware_pack_end.h"
|
||||
VMCrossPageData;
|
||||
|
||||
#define CROSSPAGE_VERSION_BASE 0xc12 /* increment by 1 */
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VMCrossPageCode --
|
||||
*
|
||||
* Code which is stored on the VMCrossPage.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
typedef
|
||||
#include "vmware_pack_begin.h"
|
||||
struct VMCrossPageCode {
|
||||
WSModule worldswitch;
|
||||
SwitchNMI faultHandler;
|
||||
}
|
||||
#include "vmware_pack_end.h"
|
||||
VMCrossPageCode;
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VMCrossPage --
|
||||
*
|
||||
* Data structure shared between the monitor and the module
|
||||
* that is used for crossing between the two.
|
||||
* Accessible as vm->cross (kernel module) and CROSS_PAGE
|
||||
* (monitor)
|
||||
*
|
||||
* Exactly one page long
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
typedef
|
||||
#include "vmware_pack_begin.h"
|
||||
struct VMCrossPage {
|
||||
uint32 version; /* 4 bytes. Must be at offset zero. */
|
||||
uint32 crosspage_size; /* 4 bytes. Must be at offset 4. */
|
||||
VMCrossPageData crosspageData;
|
||||
uint8 _pad[PAGE_SIZE - (sizeof(uint32) /* version */ +
|
||||
sizeof(uint32) /* crosspage_size */ +
|
||||
sizeof(VMCrossPageData) +
|
||||
sizeof(VMCrossPageCode))];
|
||||
VMCrossPageCode crosspageCode;
|
||||
}
|
||||
#include "vmware_pack_end.h"
|
||||
VMCrossPage;
|
||||
|
||||
#define CROSSPAGE_VERSION_BASE 0xbf2 /* increment by 1 */
|
||||
#define CROSSPAGE_VERSION ((CROSSPAGE_VERSION_BASE << 1) + WS_INTR_STRESS)
|
||||
|
||||
#if !defined(VMX86_SERVER) && defined(VMM)
|
||||
#define CROSS_PAGE ((VMCrossPageData *) \
|
||||
VPN_2_VA(CROSS_PAGE_DATA_START))
|
||||
#define VMM_SWITCH_SHARED_DATA ((VMCrossPageData * const) \
|
||||
VPN_2_VA(CROSS_PAGE_DATA_START))
|
||||
#define CROSS_PAGE ((VMCrossPage * const) VPN_2_VA(CROSS_PAGE_START))
|
||||
#define VMM_SWITCH_SHARED_DATA ((VMCrossPageData *)&CROSS_PAGE->crosspageData)
|
||||
#endif
|
||||
|
||||
#define NULLPAGE_LINEAR_START (MONITOR_LINEAR_START + \
|
||||
PAGE_SIZE * CPL0_GUARD_PAGE_START)
|
||||
|
||||
#define MX_WAITINTERRUPTED 3
|
||||
#define MX_WAITTIMEDOUT 2
|
||||
#define MX_WAITNORMAL 1
|
||||
#define MX_WAITERROR 0
|
||||
#define MX_WAITNORMAL 1 // Must equal one; see linux module code.
|
||||
#define MX_WAITERROR 0 // Use MX_ISWAITERROR() to test for error.
|
||||
|
||||
// Any zero or negative value denotes error.
|
||||
#define MX_ISWAITERROR(e) ((e) <= MX_WAITERROR)
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2006,2009-2011,2013-2015,2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2006,2009-2011,2013-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -93,6 +93,7 @@ typedef struct SwitchedMSRValues {
|
||||
typedef struct SwitchedMSRState {
|
||||
SwitchedMSRValues smv;
|
||||
uint8 flags[NUM_SWITCHED_MSRS];
|
||||
uint32 _pad;
|
||||
} SwitchedMSRState;
|
||||
|
||||
#endif
|
||||
@@ -1,75 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2005-2019 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* monAddrLayout.h --
|
||||
*
|
||||
* Address layout of the monitor.
|
||||
*/
|
||||
|
||||
#ifndef _MON_ADDR_LAYOUT_H
|
||||
#define _MON_ADDR_LAYOUT_H
|
||||
|
||||
#include "vm_pagetable.h"
|
||||
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
#include "includeCheck.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct VMM64_AddrLayout {
|
||||
/*
|
||||
*All address are VPNs and all lengths are numPages
|
||||
*/
|
||||
uint64 monBase; // MONITOR_BASE_VPN
|
||||
uint64 monL5Start; // MON_PAGE_TABLE_L5_START
|
||||
uint32 monL5Len; // MON_PAGE_TABLE_L5_LEN
|
||||
uint64 monL4Start; // MON_PAGE_TABLE_L4_START
|
||||
uint32 monL4Len; // MON_PAGE_TABLE_L4_LEN
|
||||
uint64 monL3Start; // MON_PAGE_TABLE_L3_START
|
||||
uint32 monL3Len; // MON_PAGE_TABLE_L3_LEN
|
||||
uint64 monL2Start; // MON_PAGE_TABLE_L2_START
|
||||
uint32 monL2Len; // MON_PAGE_TABLE_L2_LEN
|
||||
uint64 monL1Start; // MON_PAGE_TABLE_L1_START
|
||||
uint32 monL1Len; // MON_PAGE_TABLE_L1_LEN
|
||||
#ifndef VMX86_SERVER
|
||||
uint64 monCpStart; // CROSS_PAGE_START
|
||||
#endif
|
||||
} VMM64_AddrLayout;
|
||||
#pragma pack(pop)
|
||||
|
||||
#define VMM_MONAS_4LP_FIRST_L4OFF 1
|
||||
#define VMM_MONAS_4LP_LAST_L4OFF 130
|
||||
|
||||
#define VMM_MONAS_5LP_FIRST_L5OFF 1
|
||||
#define VMM_MONAS_5LP_LAST_L5OFF 34
|
||||
|
||||
static INLINE PT_Level
|
||||
MonAS_GetPagingLevel(void)
|
||||
{
|
||||
return PT_LEVEL_4;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
MonAS_Uses5LevelPaging(void)
|
||||
{
|
||||
return MonAS_GetPagingLevel() == PT_LEVEL_5;
|
||||
}
|
||||
#endif
|
||||
@@ -1,341 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2015-2020 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* monLoader.h --
|
||||
*
|
||||
* Describes the monitor loader, its header and support code for
|
||||
* processing this header.
|
||||
*
|
||||
*
|
||||
* Overview
|
||||
* ========
|
||||
*
|
||||
* Before the monitor or its in-context bootstrap code can run, a monitor
|
||||
* address space must be created and partially populated. This address space
|
||||
* contains code and data statically built, empty but allocated space, shared
|
||||
* and run-time initialized content. The monitor loader header regularizes
|
||||
* encoding of address space information, allowing a common representation and
|
||||
* common code to be re-used for different contexts (vmmon for hosted
|
||||
* and vmkernel for ESX).
|
||||
*
|
||||
* The Header
|
||||
* ==========
|
||||
*
|
||||
* The monitor loader header contains a sequence of entries describing content.
|
||||
* Each entry has a start and end VPN, an optional content source, permission
|
||||
* flags to be applied when mapping, an optional subIndex specifying a shared
|
||||
* region (for shared content types) and a flag specifying whether to process
|
||||
* this entry for all VCPUs or just the bootstrap processor.
|
||||
*
|
||||
* Content types
|
||||
* =============
|
||||
*
|
||||
* ADDRSPACE: Must be first. Describes the address space in which all other
|
||||
* entries reside. Page tables from L4 to L1 will be allocated, in order,
|
||||
* eagerly. These page tables will be wired with the permissions of this entry
|
||||
* from L4 to L1. This allows easy access to the L1E for any VPN in the space.
|
||||
*
|
||||
* ML_CONTENT_PAGETABLE_Lx: Maps the page tables for a given level. It must be
|
||||
* exactly the size of the tables preallocated by ADDRSPACE for the level.
|
||||
*
|
||||
* ML_CONTENT_ALLOCZERO: Allocates new MPNs, zeroes the pages and maps them.
|
||||
*
|
||||
* ML_CONTENT_COPY: Allocates new MPNs, maps them and copies from the specified
|
||||
* source.
|
||||
*
|
||||
* ML_CONTENT_SHARE: Memory provided by user, host kernel, or VMM blob,
|
||||
* and mapped into the monitor address space. The subIndex field
|
||||
* specifies which region, as multiple regions may be shared for each
|
||||
* source.
|
||||
*
|
||||
* Processing
|
||||
* ==========
|
||||
*
|
||||
* The monitor loader can be built in different contexts. Each context must
|
||||
* provide implementations of callout functions. To fully build the context,
|
||||
* callouts for memory allocation, access and reporting of resources will be
|
||||
* added, as will accounting functionality.
|
||||
*
|
||||
* Callouts
|
||||
* ========
|
||||
*
|
||||
* Memory-accessing callouts take a Vcpuid as memory is tracked per-VCPU.
|
||||
*
|
||||
* MonLoaderCallout_AllocMPN(MPN): Allocate a new MPN.
|
||||
* MonLoaderCallout_CleanUp(): Release temporary MonLoader callout resources.
|
||||
* MonLoaderCallout_CopyFromBlob(blobOffset, size, MPN): Copy blob contents.
|
||||
* MonLoaderCallout_FillPage(pattern, mpn): fill a page with a pattern.
|
||||
* MonLoaderCallout_GetPTE(MPN, index, *pte): Get indexth PTE in a PT MPN.
|
||||
* MonLoaderCallout_GetPageRoot(vcpu): Get a VCPU's page root.
|
||||
* MonLoaderCallout_ImportPage(MPN): Import an MPN for tracking and future use.
|
||||
* MonLoaderCallout_Init(): Initialize MonLoader callouts.
|
||||
* MonLoaderCallout_GetSharedHostPage(subIdx, page): Get shared host page MPN.
|
||||
* MonLoaderCallout_GetSharedUserPage(subIdx, page): Get shared user page MPN.
|
||||
*
|
||||
* Building vs Importing
|
||||
* =====================
|
||||
*
|
||||
* While legacy VMX is still responsible for building part of the monitor
|
||||
* context, the monitor loader must cooperate. Rather than building the
|
||||
* context itself, the monitor loader verifies its environment matches its
|
||||
* header's expectations. This includes verifying sufficient allocations,
|
||||
* permissions of page table wiring and page table self-mapping.
|
||||
*
|
||||
* Errors
|
||||
* ======
|
||||
*
|
||||
* To avoid ASSERTs across contexts, errors are returned and clean-up is done
|
||||
* carefully if processing fails at any stage. Some errors are debug-only and
|
||||
* essentially verify invariants for debug builds. The line in the table at
|
||||
* which the error was encountered is returned for logging and debugging.
|
||||
*
|
||||
* Compatibility
|
||||
* =============
|
||||
*
|
||||
* bootstrap-offsets.pl relies on MonLoaderContentType, MonLoaderSourceType and
|
||||
* the structure of MonLoaderEntry to determine and set blob offsets for
|
||||
* ML_CONTENT_COPY + ML_SOURCE_BLOB. If these are changed, the script should
|
||||
* be updated accordingly.
|
||||
*/
|
||||
|
||||
#ifndef _MON_LOADER
|
||||
#define _MON_LOADER
|
||||
|
||||
#include "vm_basic_types.h"
|
||||
#include "vm_pagetable.h"
|
||||
#include "vcpuid.h" /* Vcpuid */
|
||||
|
||||
#if defined VM_X86_64
|
||||
#include "x86paging_64.h"
|
||||
#elif defined VM_ARM_64
|
||||
#include "arm64_vmsa.h"
|
||||
#endif
|
||||
|
||||
#define ML_NAME_MAX 16
|
||||
|
||||
/* ML perms are simple and abbreviated. */
|
||||
|
||||
#if defined VM_X86_64
|
||||
|
||||
#define ML_PERM_RWX (PTE_P | PTE_RW)
|
||||
#define ML_PERM_RW (PTE_P | PTE_RW | PTE_NX)
|
||||
#define ML_PERM_RO (PTE_P | PTE_NX)
|
||||
#define ML_PERM_RX PTE_P
|
||||
|
||||
#define ML_PERM_TBL ML_PERM_RWX
|
||||
#define ML_PERM_MASK (PTE_P| PTE_RW | PTE_NX | PTE_US)
|
||||
|
||||
#define ML_PERM_PRESENT(_flags) (((_flags) & PTE_P) != 0)
|
||||
#define ML_PERM_WRITEABLE(_flags) (((_flags) & PTE_RW) != 0)
|
||||
|
||||
#define ML_PTE_2_PFN(_pte) LM_PTE_2_PFN(_pte)
|
||||
|
||||
#elif defined VM_ARM_64
|
||||
|
||||
#define _ML_PERM_COMMON (ARM_PTE_BLOCK_AP(ARM_AP_PL0) | ARM_PTE_BLOCK_AF | \
|
||||
ARM_PTE_BLOCK_SH(ARM_SH_OUTER) | ARM_PTE_BLOCK_L3_TYPE)
|
||||
#define ARM_PTE_BLOCK_AP_RO ARM_PTE_BLOCK_AP(ARM_AP_RO)
|
||||
|
||||
#define ML_PERM_RW (_ML_PERM_COMMON | ARM_PTE_BLOCK_XN)
|
||||
#define ML_PERM_RO (_ML_PERM_COMMON | ARM_PTE_BLOCK_AP_RO | ARM_PTE_BLOCK_XN)
|
||||
#define ML_PERM_RX (_ML_PERM_COMMON | ARM_PTE_BLOCK_AP_RO )
|
||||
|
||||
#define ML_PERM_TBL ML_PERM_RW
|
||||
#define ML_PERM_MASK (_ML_PERM_COMMON | ARM_PTE_BLOCK_AP_RO | ARM_PTE_BLOCK_XN)
|
||||
|
||||
#define ML_PERM_PRESENT(_flags) (((_flags) & ARM_PTE_VALID) != 0)
|
||||
#define ML_PERM_WRITEABLE(_flags) (((_flags) & ARM_PTE_BLOCK_AP_RO) == 0)
|
||||
|
||||
#define ML_PTE_2_PFN(_pte) (((_pte) & ARM_PTE_PFN_MASK) >> PT_PTE_PFN_SHIFT)
|
||||
|
||||
#endif
|
||||
|
||||
#define ML_PERMS_MATCH(x,p) (((x) & ML_PERM_MASK) == ((p) & ML_PERM_MASK))
|
||||
|
||||
#define LOADER_HEADER_MAGIC 0x8675309E98675309
|
||||
|
||||
typedef enum {
|
||||
ML_CONTENT_INVALID = 0,
|
||||
ML_CONTENT_ADDRSPACE, /* The static address space. */
|
||||
ML_CONTENT_ALLOCZERO, /* Allocate, zero-fill and map. */
|
||||
ML_CONTENT_COPY, /* Copy data from external source. */
|
||||
ML_CONTENT_PAGETABLE_L4, /* Mappings for level 4 page tables in AS. */
|
||||
ML_CONTENT_PAGETABLE_L3, /* Mappings for level 3 page tables in AS. */
|
||||
ML_CONTENT_PAGETABLE_L2, /* Mappings for level 2 page tables in AS. */
|
||||
ML_CONTENT_PAGETABLE_L1, /* Mappings for level 1 page tables in AS. */
|
||||
ML_CONTENT_SHARE, /* Share data from external source. */
|
||||
} MonLoaderContentType;
|
||||
|
||||
#define CONTENT_TO_PTLEVEL(x) (x == ML_CONTENT_PAGETABLE_L4 ? PT_LEVEL_4 : \
|
||||
x == ML_CONTENT_PAGETABLE_L3 ? PT_LEVEL_3 : \
|
||||
x == ML_CONTENT_PAGETABLE_L2 ? PT_LEVEL_2 : \
|
||||
x == ML_CONTENT_PAGETABLE_L1 ? PT_LEVEL_1 : \
|
||||
0)
|
||||
|
||||
/* Sources of content, for pages not zeroed, unmapped or otherwise special. */
|
||||
typedef enum MonLoaderSourceType {
|
||||
ML_SOURCE_INVALID = 0x0,
|
||||
ML_SOURCE_NONE,
|
||||
ML_SOURCE_BLOB,
|
||||
ML_SOURCE_USER,
|
||||
ML_SOURCE_HOST,
|
||||
} MonLoaderSourceType;
|
||||
|
||||
/*
|
||||
* NOTE: When modifying MonLoaderEntry, corresponding changes must be
|
||||
* made to vmcore/make/misc/bootstrap-offsets.pl.
|
||||
*/
|
||||
typedef struct {
|
||||
MonLoaderContentType content; /* Content type. */
|
||||
MonLoaderSourceType source; /* Source, if any, for content. */
|
||||
VPN monVPN; /* Destination in monitor AS. */
|
||||
uint64 monPages; /* Size in pages. */
|
||||
uint64 flags; /* PTE permissions */
|
||||
unsigned allocs; /* MPNs allocated (all VCPUs). */
|
||||
/* Set for source ML_SOURCE_BLOB: */
|
||||
struct blobSrc {
|
||||
uint64 offset; /* offset within the blob, in bytes. */
|
||||
uint64 size; /* size of content, in bytes. */
|
||||
} blobSrc;
|
||||
uint64 bspOnly; /* Process only on BSP. */
|
||||
uint64 subIndex; /* Region ID for ML_CONTENT_COPY. */
|
||||
} MonLoaderEntry;
|
||||
|
||||
|
||||
/*
|
||||
* Packed for easy consumption by bootstrap-offsets.pl. If the contents of the
|
||||
* MonLoaderHeader struct are changed then $HEADER_SIZE must be updated
|
||||
* accordingly in bootstrap-offsets.pl.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
typedef struct MonLoaderHeader {
|
||||
uint64 magic;
|
||||
uint32 entrySize;
|
||||
uint32 count;
|
||||
/* cs:rip */
|
||||
uint16 codeSelector;
|
||||
VA64 codeEntrypoint;
|
||||
/* ss:rip */
|
||||
uint16 stackSelector;
|
||||
VA64 stackEntrypoint;
|
||||
LPN64 monStartLPN;
|
||||
LPN64 monEndLPN;
|
||||
MonLoaderEntry entries[];
|
||||
} MonLoaderHeader;
|
||||
#pragma pack(pop)
|
||||
|
||||
/* Environment context structure, defined by the environment. */
|
||||
struct MonLoaderEnvContext;
|
||||
|
||||
/* Callout prototypes */
|
||||
MPN MonLoaderCallout_AllocMPN(struct MonLoaderEnvContext *, Vcpuid);
|
||||
void MonLoaderCallout_CleanUp(struct MonLoaderEnvContext *);
|
||||
Bool MonLoaderCallout_CopyFromBlob(struct MonLoaderEnvContext *, uint64,
|
||||
size_t, MPN, Vcpuid);
|
||||
Bool MonLoaderCallout_FillPage(struct MonLoaderEnvContext *, uint8, MPN,
|
||||
Vcpuid);
|
||||
MPN MonLoaderCallout_GetPageRoot(struct MonLoaderEnvContext *, Vcpuid);
|
||||
Bool MonLoaderCallout_GetPTE(struct MonLoaderEnvContext *, MPN, unsigned,
|
||||
Vcpuid, PT_L1E *);
|
||||
Bool MonLoaderCallout_ImportPage(struct MonLoaderEnvContext *, MPN, Vcpuid);
|
||||
Bool MonLoaderCallout_Init(void *, struct MonLoaderEnvContext **, unsigned);
|
||||
Bool MonLoaderCallout_MapMPNInPTE(struct MonLoaderEnvContext *, MPN, unsigned,
|
||||
uint64, MPN, Vcpuid);
|
||||
MPN MonLoaderCallout_GetSharedUserPage(struct MonLoaderEnvContext *, uint64,
|
||||
unsigned, Vcpuid);
|
||||
MPN MonLoaderCallout_GetSharedHostPage(struct MonLoaderEnvContext *, uint64,
|
||||
unsigned, Vcpuid);
|
||||
MPN MonLoaderCallout_GetBlobMpn(struct MonLoaderEnvContext *, uint64);
|
||||
|
||||
typedef enum MonLoaderError {
|
||||
ML_OK = 0,
|
||||
ML_ERROR_ADDRSPACE_TOO_LARGE,
|
||||
ML_ERROR_ALLOC,
|
||||
ML_ERROR_ALREADY_MAPPED,
|
||||
ML_ERROR_ARGS,
|
||||
ML_ERROR_CALLOUT_INIT,
|
||||
ML_ERROR_CALLOUT_COPY,
|
||||
ML_ERROR_CALLOUT_GETPTE,
|
||||
ML_ERROR_CALLOUT_MAPINPTE,
|
||||
ML_ERROR_CALLOUT_PAGEROOT_GET,
|
||||
ML_ERROR_CALLOUT_ZERO,
|
||||
ML_ERROR_CONTENT_INVALID,
|
||||
ML_ERROR_CONTEXT_INIT,
|
||||
ML_ERROR_DUPLICATE,
|
||||
ML_ERROR_INVALID_VPN,
|
||||
ML_ERROR_MAGIC,
|
||||
ML_ERROR_MAP,
|
||||
ML_ERROR_NO_ADDRSPACE,
|
||||
ML_ERROR_PAGE_TABLE_IMPORT,
|
||||
ML_ERROR_PAGE_TABLE_MAP_SIZE,
|
||||
ML_ERROR_PAGE_TABLE_VERIFY,
|
||||
ML_ERROR_SHARE,
|
||||
ML_ERROR_SIZE,
|
||||
ML_ERROR_SOURCE_INVALID,
|
||||
ML_ERROR_TABLE_MISSING,
|
||||
} MonLoaderError;
|
||||
|
||||
|
||||
/*
|
||||
* Values above shared area subindices for sharing of MonLoaderHeader
|
||||
* and htSchedStateMap.
|
||||
*/
|
||||
#define MONLOADER_HEADER_IDX 6
|
||||
#define MONLOADER_HT_MAP_IDX 7
|
||||
#define MONLOADER_CROSS_PAGE_CODE_IDX 8
|
||||
#define MONLOADER_CROSS_PAGE_DATA_IDX 9
|
||||
|
||||
MonLoaderError MonLoader_Process(MonLoaderHeader *header, unsigned numVCPUs,
|
||||
void *args, unsigned *line, Vcpuid *vcpu);
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoader_GetFixedHeaderSize --
|
||||
*
|
||||
* Returns the size of the fixed portion of MonLoaderHeader.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE size_t
|
||||
MonLoader_GetFixedHeaderSize(void)
|
||||
{
|
||||
return sizeof(MonLoaderHeader);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MonLoader_GetFullHeaderSize --
|
||||
*
|
||||
* Returns the size of the full MonLoaderHeader, including the
|
||||
* variable size portion.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE size_t
|
||||
MonLoader_GetFullHeaderSize(MonLoaderHeader *header)
|
||||
{
|
||||
return MonLoader_GetFixedHeaderSize() +
|
||||
header->count * sizeof(MonLoaderEntry);
|
||||
}
|
||||
|
||||
#endif /* !_MON_LOADER */
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2007-2015,2018 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2007-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -60,21 +60,20 @@
|
||||
* lengths, and this causes the 'monitor-modular-size' script to
|
||||
* report differences in '.rodata'.
|
||||
*
|
||||
* o Each __FILE__ is put into its own .assert_pathname_##__FILE
|
||||
* section. The monitor's runtime linker (not ld) then uses the name
|
||||
* of this section to recover the name of the corresponding source file.
|
||||
* o To avoid differences in '.rodata', each __FILE__ is put into
|
||||
* its own section. The monitor's linker (not ld) will use the
|
||||
* name of the section to recover the name of the source file.
|
||||
*
|
||||
* o At run time, prior to loading, when our linker is creating an
|
||||
* executable image of the monitor and extensions, all the file
|
||||
* names are extracted from these sections, the '${VMTREE}' prefix
|
||||
* is removed, and the resulting table of shortened file names is
|
||||
* added to a non-loadable section called '.assert_pathnames' in the
|
||||
* VMX linker (not the bootstrap linker which does not need them).
|
||||
* added to '.rodata'.
|
||||
*
|
||||
* Further, during linkage, each relocation to the original
|
||||
* section containing the path name is modified so that the low
|
||||
* 16-bits contain an offset from the start of the .assert_pathnames
|
||||
* section rather than the base of the original containing section.
|
||||
* 16-bits contain an offset from '__vmm_pathnames_start' rather
|
||||
* than the base of the original containing section.
|
||||
*
|
||||
* Only three types of relocations to the assertion strings are
|
||||
* supported (32-bit PC-relative and 32-bit/64-bit absolute) because that
|
||||
@@ -112,12 +111,42 @@ typedef struct Assert_Info {
|
||||
Assert_MonSrcLoc loc;
|
||||
} Assert_Info;
|
||||
|
||||
/*
|
||||
* The portion of the __attribute__ line after __FILE__ is there so that
|
||||
* the .assert_pathname_* sections are not marked as ALLOC, since we only
|
||||
* need them in the vmx and do not need them loaded.
|
||||
*/
|
||||
#define __VMM__FILE__SECTION \
|
||||
__attribute__((section (".assert_pathname_" __FILE__ ",\"\"#")))
|
||||
#define __VMM__FILE__ ({ \
|
||||
static __VMM__FILE__SECTION const char file[] = ""; \
|
||||
file; \
|
||||
})
|
||||
|
||||
#define ASSERT_MONSRCFILEOFFSET(loc) LOWORD(loc)
|
||||
#define ASSERT_MONSRCLINE(loc) HIWORD(loc)
|
||||
|
||||
#define ASSERT_NULL_MONSRCLOC 0 // there is never line 0
|
||||
|
||||
#if defined(VMM) && !defined(MONITOR_APP) // {
|
||||
#ifdef VMM // {
|
||||
#ifdef MONITOR_APP // {
|
||||
|
||||
#define ASSERT_MONSRCLOC() ASSERT_NULL_MONSRCLOC
|
||||
|
||||
#else // } {
|
||||
|
||||
#define ASSERT_MONSRCLOC() ({ \
|
||||
const uintptr_t offset = ((__LINE__ << 16) + \
|
||||
(uintptr_t)__VMM__FILE__); \
|
||||
const Assert_MonSrcLoc loc = offset; \
|
||||
loc; \
|
||||
})
|
||||
|
||||
extern const char __vmm_pathnames_start;
|
||||
#define ASSERT_MONSRCFILE(loc) \
|
||||
(&__vmm_pathnames_start + ASSERT_MONSRCFILEOFFSET(loc))
|
||||
|
||||
|
||||
/*
|
||||
* Assertion information is collected in a non-loadable section
|
||||
* named .assert_info. Each record in this section contains
|
||||
@@ -140,25 +169,8 @@ typedef struct Assert_Info {
|
||||
* seen to hoist code into the failing arm of the assertion, where it
|
||||
* can then tell that, because of the assertion failure, the code ends
|
||||
* up accessing an array out of bounds.
|
||||
*
|
||||
* Assertion failures for the monitor's bootstrap are reduced to panics
|
||||
* logging the current %rip. As such, no .assert_info section is created
|
||||
* and VMX merely processes the panic.
|
||||
*/
|
||||
|
||||
#ifndef VMM_BOOTSTRAP
|
||||
/*
|
||||
* The portion of the __attribute__ line after __FILE__ is there so that
|
||||
* the .assert_pathname_* sections are not marked as ALLOC, since we only
|
||||
* need them in the vmx and do not need them loaded.
|
||||
*/
|
||||
#define __VMM__FILE__SECTION \
|
||||
__attribute__((section (".assert_pathname_" __FILE__ ",\"\"#")))
|
||||
#define __VMM__FILE__ ({ \
|
||||
static __VMM__FILE__SECTION const char file[] = ""; \
|
||||
file; \
|
||||
})
|
||||
|
||||
#define ASSERT_RECORDINFO(assembly, assertType, bugNr) \
|
||||
__asm__ __volatile__(".pushsection .assert_info;" \
|
||||
".quad 0f;" \
|
||||
@@ -170,16 +182,6 @@ typedef struct Assert_Info {
|
||||
[file] "i" (__VMM__FILE__), \
|
||||
[type] "i" (assertType), \
|
||||
[bug] "i" (bugNr))
|
||||
#else
|
||||
|
||||
extern uint64 bsAssertRIP;
|
||||
#define ASSERT_RECORDINFO(assembly, assertType, bugNr) \
|
||||
__asm__ __volatile__("lea 0(%%rip), %0\n\t" \
|
||||
: "=r"(bsAssertRIP)); \
|
||||
Panic("Bootstrap: %s failure at rip=0x%lx", \
|
||||
assertType == AssertType_AssertVerify ? "VERIFY" : "ASSERT", \
|
||||
bsAssertRIP);
|
||||
#endif /* VMM_BOOTSTRAP */
|
||||
|
||||
#define _ASSERT_PANIC(name) \
|
||||
({COMPILER_MEM_BARRIER(); \
|
||||
@@ -198,6 +200,8 @@ extern uint64 bsAssertRIP;
|
||||
({COMPILER_MEM_BARRIER(); \
|
||||
ASSERT_RECORDINFO("", AssertType_##name##Bug, bug); \
|
||||
__builtin_trap();})
|
||||
#endif // VMM && !MONITOR_APP}
|
||||
|
||||
#endif // _MON_ASSERT_H_
|
||||
#endif // MONITOR_APP }
|
||||
#endif // VMM }
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2010-2017 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2013 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -22,22 +22,135 @@
|
||||
#define INCLUDE_ALLOW_VMX
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_DISTRIBUTE
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "vm_assert.h"
|
||||
#include "vm_atomic.h"
|
||||
#include "vm_basic_types.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Please bump the version number if your change will break the
|
||||
* compatability to the drivers.
|
||||
*/
|
||||
#define ACTION_EXPORTED_VERSION 2
|
||||
|
||||
#define ACTION_WORD_SIZE (sizeof(uint64) * 8)
|
||||
#define ACTION_NUM_WORDS (2)
|
||||
#define ACTION_NUM_IDS (ACTION_NUM_WORDS * ACTION_WORD_SIZE)
|
||||
|
||||
#define MONACTION_INVALID MAX_UINT32
|
||||
|
||||
typedef uint32 MonitorIdemAction;
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
/*
|
||||
* Representation of a set of actions.
|
||||
*/
|
||||
typedef struct MonitorActionSet {
|
||||
volatile uint64 word[ACTION_NUM_WORDS];
|
||||
} MonitorActionSet;
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef enum MonitorActionSetName MonitorActionSetName;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Summary of action and interrupt states.
|
||||
*/
|
||||
typedef struct MonitorActionIntr {
|
||||
MonitorActionSet pendingSet;
|
||||
volatile Bool action;
|
||||
Bool intr;
|
||||
Bool nmi;
|
||||
Bool db;
|
||||
uint32 _pad;
|
||||
} MonitorActionIntr;
|
||||
|
||||
/*
|
||||
*------------------------------------------------------------------------
|
||||
* MonitorActionSet_AtomicInclude --
|
||||
*
|
||||
* This function atomically adds an action to an action set.
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the action being added did not exist in the action set.
|
||||
* FALSE otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* The given action set will be updated.
|
||||
*------------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE Bool
|
||||
MonitorActionSet_AtomicInclude(MonitorActionSet *set, const uint32 actionID)
|
||||
{
|
||||
Atomic_uint64 *atomicSet =
|
||||
Atomic_VolatileToAtomic64(&set->word[actionID / ACTION_WORD_SIZE]);
|
||||
uint64 mask = (uint64)1 << (actionID % ACTION_WORD_SIZE);
|
||||
uint64 oldWord;
|
||||
uint64 newWord;
|
||||
|
||||
ASSERT_ON_COMPILE((ACTION_WORD_SIZE & (ACTION_WORD_SIZE - 1)) == 0);
|
||||
#ifdef VMX86_DEBUG
|
||||
/* If ASSERT is not desirable, do explicit check. Please see PR 567811. */
|
||||
#ifdef MODULE
|
||||
if (UNLIKELY(actionID / ACTION_WORD_SIZE >= ACTION_NUM_WORDS)) {
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
ASSERT(actionID / ACTION_WORD_SIZE < ACTION_NUM_WORDS);
|
||||
#endif // MODULE
|
||||
#endif // VMX86_DEBUG
|
||||
do {
|
||||
oldWord = Atomic_Read64(atomicSet);
|
||||
newWord = oldWord | mask;
|
||||
} while (!Atomic_CMPXCHG64(atomicSet, &oldWord, &newWord));
|
||||
return (oldWord & mask) == 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------------
|
||||
* MonitorAction_SetBits --
|
||||
*
|
||||
* The core logic for posting an action. Update the set of pending
|
||||
* actions of the target VCPU in the shared area to mark the action
|
||||
* as present. Make sure the bit is set in the pendingSet first to
|
||||
* avoid a race with the drain loop.
|
||||
*
|
||||
* It's the responsibility of the callers to ensure that the change
|
||||
* to actionIntr->action is globally visible before any IPI is sent
|
||||
* (the change to pendingSet is pushed out by the cmpxchg in
|
||||
* MonitorActionSet_AtomicInclude).
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the action being posted was not pending before.
|
||||
* FALSE otherwise (other threads could have posted the same action).
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE Bool
|
||||
MonitorAction_SetBits(MonitorActionIntr *actionIntr, MonitorIdemAction actionID)
|
||||
{
|
||||
/* Careful if optimizing this: see PR70016. */
|
||||
Bool newAction =
|
||||
MonitorActionSet_AtomicInclude(&actionIntr->pendingSet, actionID);
|
||||
actionIntr->action = TRUE;
|
||||
return newAction;
|
||||
}
|
||||
|
||||
/*
|
||||
* C1 states entered by monitor while waiting for an action
|
||||
*/
|
||||
typedef enum {
|
||||
VMM_C1_STATE_INVALID = 0,
|
||||
VMM_C1_STATE_HLT,
|
||||
VMM_C1_STATE_MWAIT,
|
||||
VMM_C1_STATE_PAUSE
|
||||
} vmmC1StateType;
|
||||
|
||||
#endif // _MONITORACTION_EXPORTED_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2006,2009-2017 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2006 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -39,20 +39,15 @@
|
||||
|
||||
/* Machine NUMA nodes */
|
||||
typedef uint32 NUMA_Node;
|
||||
typedef uint32 NUMA_PxmID;
|
||||
typedef uint64 NUMA_NodeMask;
|
||||
typedef uint32 NUMA_NodeMask;
|
||||
typedef uint8 NUMA_MemRangeID;
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
#define NUMA_MAX_NODES 64
|
||||
#define NUMA_MAX_NODES 32
|
||||
#define NUMA_MAX_CPUS_PER_NODE (vmx86_server ? MAX_PCPUS : 32)
|
||||
#ifdef VMKBOOT
|
||||
#define NUMA_MAX_MEM_RANGES 64
|
||||
#else
|
||||
#define NUMA_MAX_MEM_RANGES 256
|
||||
#endif
|
||||
#define INVALID_NUMANODE ((NUMA_Node)-1)
|
||||
#define NUMA_NODE_MASK_ANY ((NUMA_NodeMask)-1)
|
||||
#define NUMA_NODE_MASK_NONE ((NUMA_NodeMask)0)
|
||||
@@ -64,7 +59,7 @@ typedef uint8 NUMA_MemRangeID;
|
||||
typedef struct {
|
||||
MPN startMPN;
|
||||
MPN endMPN;
|
||||
NUMA_PxmID id;
|
||||
NUMA_Node id;
|
||||
Bool isReliable;
|
||||
Bool isVolatile;
|
||||
} NUMA_MemRange;
|
||||
@@ -74,10 +69,4 @@ typedef struct NUMA_MemRangesList {
|
||||
NUMA_MemRange memRange[NUMA_MAX_MEM_RANGES];
|
||||
} NUMA_MemRangesList;
|
||||
|
||||
|
||||
typedef struct NUMA_MemRangesListRef {
|
||||
uint64 numMemRanges;
|
||||
const NUMA_MemRange *memRange;
|
||||
} NUMA_MemRangesListRef;
|
||||
|
||||
#endif // _NUMA_DEFS_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2010-2014,2017 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2010-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -36,11 +36,6 @@
|
||||
#include "vm_assert.h"
|
||||
#include "vmcore_types.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Sets of pages are passed between the monitor and the platform to be
|
||||
* shared, invalidated, remapped, or swapped.
|
||||
@@ -52,17 +47,19 @@ extern "C" {
|
||||
typedef struct PageListEntry {
|
||||
CompressedBPN cbpn;
|
||||
Bool voided;
|
||||
uint8 _pad[1];
|
||||
uint8 _pad[2];
|
||||
} PageListEntry;
|
||||
#pragma pack(pop)
|
||||
|
||||
#define PAGELIST_MAX (PAGE_SIZE / sizeof(PageListEntry))
|
||||
|
||||
static INLINE void
|
||||
PageList_SetEntry(PageListEntry *ple, BPN bpn)
|
||||
static INLINE PageListEntry
|
||||
PageList_CreateEntry(BPN bpn)
|
||||
{
|
||||
CompressedBPN_Write(&ple->cbpn, bpn);
|
||||
ple->voided = FALSE;
|
||||
PageListEntry ple;
|
||||
CompressedBPN_Write(&ple.cbpn, bpn);
|
||||
ple.voided = FALSE;
|
||||
return ple;
|
||||
}
|
||||
|
||||
static INLINE BPN
|
||||
@@ -101,9 +98,4 @@ PageList_IsBPNDup(const PageListEntry *pageList, unsigned i, BPN bpn)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _PAGELIST_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2009-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -55,19 +55,26 @@ typedef enum PCIPassthruVectorIndex {
|
||||
} PCIPassthruVectorIndex;
|
||||
|
||||
typedef enum PCIPassthru_IntrType {
|
||||
PCIPASSTHRU_INTR_NONE = 0x00,
|
||||
PCIPASSTHRU_INTR_IOAPIC = 0x01,
|
||||
PCIPASSTHRU_INTR_MSI = 0x02,
|
||||
PCIPASSTHRU_INTR_MSIX = 0x04,
|
||||
PCIPASSTHRU_INTR_MSI_INT = 0x08,
|
||||
PCIPASSTHRU_INTR_NONE = 0x00,
|
||||
PCIPASSTHRU_INTR_IOAPIC = 0x01,
|
||||
PCIPASSTHRU_INTR_MSI = 0x02,
|
||||
PCIPASSTHRU_INTR_MSIX = 0x04,
|
||||
} PCIPassthru_IntrType;
|
||||
|
||||
#define PCIPASSTHRU_INTR_MSI_COMBINED \
|
||||
(PCIPASSTHRU_INTR_MSI | PCIPASSTHRU_INTR_MSI_INT)
|
||||
|
||||
typedef struct FPTIntrProxyInfo {
|
||||
uint32 adapterIndex;
|
||||
uint32 vectorIndex;
|
||||
MonitorIdemAction actionID;
|
||||
uint32 _pad0;
|
||||
|
||||
/*
|
||||
* These addresses are only needed for hosted platforms, where our kernel
|
||||
* modules lack a SharedArea API.
|
||||
*/
|
||||
#ifndef VMX86_SERVER
|
||||
VA64 notifyUVA;
|
||||
VA64 vectorIndexUVA;
|
||||
#endif
|
||||
} FPTIntrProxyInfo;
|
||||
|
||||
typedef struct UPTIntrProxyInfo {
|
||||
@@ -75,15 +82,9 @@ typedef struct UPTIntrProxyInfo {
|
||||
MonitorIdemAction actionID;
|
||||
} UPTIntrProxyInfo;
|
||||
|
||||
typedef struct MPTIntrProxyInfo {
|
||||
uint32 adapterIndex;
|
||||
MonitorIdemAction actionID;
|
||||
} MPTIntrProxyInfo;
|
||||
|
||||
typedef union PCIPassthru_IntrProxyInfo {
|
||||
FPTIntrProxyInfo fpt;
|
||||
UPTIntrProxyInfo upt;
|
||||
MPTIntrProxyInfo mpt;
|
||||
} PCIPassthru_IntrProxyInfo;
|
||||
|
||||
typedef enum PCIPassthru_ErrorType {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2012,2014-2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2012,2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -17,12 +17,12 @@
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* perfctr.h --
|
||||
* perfctr_generic.h --
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PERFCTR_H_
|
||||
#define _PERFCTR_H_
|
||||
#ifndef _PERFCTR_GENERIC_H_
|
||||
#define _PERFCTR_GENERIC_H_
|
||||
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
|
||||
@@ -33,9 +33,7 @@
|
||||
|
||||
#include "includeCheck.h"
|
||||
#include "vm_basic_types.h"
|
||||
#include "perfctr_arch.h"
|
||||
|
||||
#define PERF_EVENT_NAME_LEN 64
|
||||
/*
|
||||
* nmiNo -- vmm peer is not attempting to do nmi profiling this run
|
||||
* nmiYes -- vmm peer is doing nmi profiling and nmis are currently enabled
|
||||
@@ -71,51 +69,4 @@ typedef struct {
|
||||
uint8 _pad[3];
|
||||
} CrossProfShared;
|
||||
|
||||
/*
|
||||
* PerfCtr_Config --
|
||||
* Describes configuration for a single hardware performance counter
|
||||
*
|
||||
* Since this is only used to record general performance counters, we
|
||||
* made the assumption in nmiProfiler.c that the type is GENERAL and
|
||||
* index is counter number of type GENERAL.
|
||||
*
|
||||
* **** x86 ****
|
||||
* On AMD K8 and GH:
|
||||
* index: Which perf ctr, 0 to 3. RDPMC argument
|
||||
* addr: MSR of raw perf ctr (0xc0010004 + index).
|
||||
* escrAddr: MSR # of the Perf Event Selector (0xc0010000 + index).
|
||||
* escrVal: Value placed in PerfEvtSel MSR; what to measure.
|
||||
*
|
||||
* On AMD with PerfCtrExtCore support:
|
||||
* index: Which perf ctr, 0 to 5. RDPMC argument
|
||||
* addr: MSR of raw perf ctr (0xc0010201 + 2 * index).
|
||||
* aliased PMCs 0 - 3 (0xc0010004 + index).
|
||||
* escrAddr: MSR # of the Perf Event Selector (0xc0010200 + 2 * index).
|
||||
* aliased PMCs 0 - 3 (0xc0010000 + index).
|
||||
* escrVal: Value placed in PerfEvtSel MSR; what to measure.
|
||||
*
|
||||
* On Intel Core architecture:
|
||||
* <to be documented>
|
||||
*
|
||||
* **** ARM ****
|
||||
* escrVal: Value placed in PMEVTYPER<n>_EL0 to configure event counter
|
||||
* index: Index of the event counter.
|
||||
*/
|
||||
typedef struct PerfCtr_Config {
|
||||
uint64 escrVal;
|
||||
uint32 index;
|
||||
uint32 periodMean;
|
||||
|
||||
/*
|
||||
* Random number (whose absolute value is capped at
|
||||
* periodJitterMask) is used to randomize sampling interval.
|
||||
*/
|
||||
uint32 periodJitterMask;
|
||||
uint32 seed; // seed is used to compute next random number
|
||||
uint16 config;
|
||||
Bool valid;
|
||||
PERFCTR_CONFIG_ARCH_FIELDS
|
||||
} PerfCtr_Config;
|
||||
|
||||
|
||||
#endif // ifndef _PERFCTR_H_
|
||||
#endif // ifndef _PERFCTR_GENERIC_H_
|
||||
@@ -41,10 +41,9 @@
|
||||
*/
|
||||
|
||||
#define PSHARE_PAGELIST_MAX (PAGELIST_MAX)
|
||||
#define PSHARE_P2M_BUFFER_MPNS_MAX (32)
|
||||
#define PSHARE_P2M_BUFFER_MPNS_DEFAULT (5)
|
||||
#define PSHARE_P2M_BUFFER_MPNS_MAX (16)
|
||||
#define PSHARE_P2M_BUFFER_MPNS_DEFAULT (4)
|
||||
#define PSHARE_P2M_BUFFER_SLOTS_PER_MPN (PAGE_SIZE / sizeof(PShare_P2MUpdate))
|
||||
#define PSHARE_P2M_BUFFER_SLOTS_MIN (2)
|
||||
|
||||
#define PSHARE_POISON_MARKER (CONST64U(0xAAAAAAAAAAAAAAAA))
|
||||
|
||||
@@ -58,16 +57,8 @@ MY_ASSERTS(PSHARE_EXT,
|
||||
* types
|
||||
*/
|
||||
|
||||
typedef union {
|
||||
MPN mpn;
|
||||
uint64 vpmemRef;
|
||||
} PShare_P2MUpdateReference;
|
||||
|
||||
#define PSHARE_SET_INVALID_P2MUPDATE_REFERENCE(ref) ((ref).vpmemRef = CONST64U(-1))
|
||||
#define PSHARE_IS_INVALID_P2MUPDATE_REFERENCE(ref) ((ref).vpmemRef == CONST64U(-1))
|
||||
|
||||
typedef struct PShare_P2MUpdate {
|
||||
BPN bpn;
|
||||
PShare_P2MUpdateReference reference;
|
||||
BPN bpn;
|
||||
MPN mpn;
|
||||
} PShare_P2MUpdate;
|
||||
#endif
|
||||
+36
-40
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2014,2017,2019-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -97,7 +97,6 @@ extern PTSCInfo ptscInfo;
|
||||
Bool PTSC_Init(uint64 tscHz);
|
||||
VmAbsoluteTS PTSC_InitialCount(const char *module,
|
||||
const char *option,
|
||||
Bool stress,
|
||||
VmIntervalTS freq,
|
||||
VmAbsoluteTS defaultCnt);
|
||||
Bool PTSC_HasPerfectlySynchronizedTSCs(void);
|
||||
@@ -125,7 +124,7 @@ PTSC_MHz(void)
|
||||
|
||||
#if defined(VM_X86_64) || defined(VM_ARM_64)
|
||||
|
||||
/*
|
||||
/*
|
||||
* Conversions to/from cycles. Note that the conversions operate on
|
||||
* signed values, so be careful when taking the difference of two
|
||||
* VmAbsoluteTS (which is unsigned) that that value is not out of range
|
||||
@@ -171,8 +170,38 @@ int64 PTSC_CyclesToUS(VmRelativeTS ts);
|
||||
/*
|
||||
* ESX with userworld VMX
|
||||
*/
|
||||
#include "x86types.h"
|
||||
#include "user_layout.h"
|
||||
|
||||
#ifdef VM_ARM_64
|
||||
static INLINE VmAbsoluteTS
|
||||
PTSC_Get(void)
|
||||
{
|
||||
extern __thread User_ThreadData vmkUserTdata;
|
||||
|
||||
register RateConv_Params params;
|
||||
register uint64 pseudoTSC;
|
||||
|
||||
/*
|
||||
* On ARM64 the generic timer guarantees that the counters are synchronous
|
||||
* and independent of CPU frequency.
|
||||
*/
|
||||
params = vmkUserTdata.pseudoTSCConv;
|
||||
pseudoTSC = RDTSC();
|
||||
|
||||
/*
|
||||
* assert that conversion rate is `identity'.
|
||||
* we'll have to revisit that when/if this assumption changes
|
||||
* on some platform
|
||||
*/
|
||||
ASSERT((params.mult == 1 && params.shift == 0) ||
|
||||
(params.mult == 0x80000000 && params.shift == 31));
|
||||
|
||||
pseudoTSC += params.add;
|
||||
|
||||
return pseudoTSC;
|
||||
}
|
||||
#else
|
||||
static INLINE VmAbsoluteTS
|
||||
PTSC_Get(void)
|
||||
{
|
||||
@@ -186,7 +215,7 @@ PTSC_Get(void)
|
||||
ASSERT((int64)ptsc >= 0);
|
||||
return ptsc;
|
||||
}
|
||||
|
||||
#endif
|
||||
#else
|
||||
|
||||
/*
|
||||
@@ -197,13 +226,13 @@ VmAbsoluteTS PTSC_Get(void);
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* PTSC_HasSynchronizedTSCs --
|
||||
*
|
||||
* Returns TRUE iff the platform TSCs are known to be synchronized.
|
||||
*
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -214,7 +243,7 @@ PTSC_HasSynchronizedTSCs(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* PTSC_HostAdjustedTSCs --
|
||||
@@ -231,37 +260,4 @@ PTSC_HostAdjustedTSCs(void)
|
||||
return ptscInfo.hwTSCsAdjusted;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* PTSC_AdvanceTimer --
|
||||
*
|
||||
* Advance '*deadline' in 'period' increments such that it is
|
||||
* greater than 'now'. Return the number of ticks incremented.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE uint64
|
||||
PTSC_AdvanceTimer(VmAbsoluteTS now,
|
||||
VmIntervalTS period,
|
||||
VmAbsoluteTS *deadline)
|
||||
{
|
||||
VmAbsoluteTS d = *deadline;
|
||||
if (now >= d) {
|
||||
uint64 count = 1;
|
||||
d += period;
|
||||
if (UNLIKELY(now >= d)) {
|
||||
uint64 t = (now - d) / period + 1;
|
||||
VmIntervalTS diff = t * period;
|
||||
count += t;
|
||||
d += diff;
|
||||
}
|
||||
*deadline = d;
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ifndef _PTSC_H_ */
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2003-2016, 2018 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2003 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -31,6 +31,7 @@
|
||||
#define _VM_RATECONV_H_
|
||||
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_VMK_MODULE
|
||||
@@ -43,12 +44,6 @@
|
||||
#include "vm_basic_asm.h"
|
||||
#include "vm_assert.h"
|
||||
#include "vm_atomic.h"
|
||||
#include "versioned_atomic.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* RateConv_Params is part of vmx<->vmmon interface (INIT_PSEUDO_TSC ioctl) */
|
||||
typedef struct RateConv_Params {
|
||||
@@ -59,7 +54,8 @@ typedef struct RateConv_Params {
|
||||
|
||||
typedef struct RateConv_ParamsVolatile {
|
||||
RateConv_Params p;
|
||||
VersionedAtomic vers;
|
||||
Bool changed;
|
||||
uint8 pad[7];
|
||||
} RateConv_ParamsVolatile;
|
||||
|
||||
typedef struct RateConv_Ratio {
|
||||
@@ -97,7 +93,7 @@ void RateConv_LogRatio(const char *prefix,
|
||||
static INLINE uint64
|
||||
RateConv_Unsigned(const RateConv_Params *conv, uint64 x)
|
||||
{
|
||||
return Mul64x3264(x, conv->mult, conv->shift) + (uint64)conv->add;
|
||||
return Mul64x3264(x, conv->mult, conv->shift) + conv->add;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,8 +115,4 @@ RateConv_Signed(const RateConv_Params *conv, int64 x)
|
||||
}
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _VM_RATECONV_H_
|
||||
@@ -1,176 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2018-2020 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* segs.h --
|
||||
*
|
||||
* Describes segment descriptors and structures containing them for both
|
||||
* the monitor (in hosted and ESX) and the vmkernel.
|
||||
*/
|
||||
|
||||
#ifndef _SEGS_H_
|
||||
#define _SEGS_H_
|
||||
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "vm_basic_types.h"
|
||||
#include "vm_basic_defs.h"
|
||||
#include "x86types.h"
|
||||
#include "x86segdescrs.h"
|
||||
#include "x86sel.h"
|
||||
#include "addrlayout.h"
|
||||
|
||||
|
||||
/*
|
||||
* Segment map of the monitor.
|
||||
*
|
||||
* The GDT and Task State Segment reside consecutively on one page. The
|
||||
* monitor segments are placed at the end of the GDT. The vmkernel can use all
|
||||
* lower-numbered segments for user-mode as well as higher-numbered segments
|
||||
* (though the vmkernel should not use monitor-private segments). The high
|
||||
* segment placement ensures that there is no selector-overlap with hosted
|
||||
* kernel segments (the hosted world switch code can be a bit faster then, as
|
||||
* it can use a single cross GDT).
|
||||
*/
|
||||
|
||||
#define GDT_SIZE (sizeof(Descriptor) * NUM_VALID_SEGMENTS)
|
||||
#define GDT_LIMIT (GDT_SIZE - 1)
|
||||
|
||||
#define IRB_SIZE 32 /* Interrupt redirection bitmap. */
|
||||
#define TSS_SIZE (sizeof(Task64) + IRB_SIZE)
|
||||
|
||||
#define GDT_START_VA (VPN_2_VA(GDT_AND_TASK_START))
|
||||
#define TASK_START_VA (VPN_2_VA(GDT_AND_TASK_START) + GDT_SIZE)
|
||||
|
||||
/*
|
||||
* vmkBoot uses some of the lower-numbered segments, as do host kernels on
|
||||
* hosted. User segments could start earlier than 32; see bug #1904257.
|
||||
* Descriptor is used to describe boot, user and kernel segments.
|
||||
* Descriptor64 (twice as large) is used for task segments.
|
||||
*/
|
||||
#define NUM_BOOT_SEGMENTS 32
|
||||
#define NUM_USER_SEGMENTS (FIRST_SYSTEM_SEGMENT - FIRST_USER_SEGMENT)
|
||||
#define NUM_SYSTEM_SEGMENTS 2
|
||||
#define NUM_TASK_SEGMENTS 2
|
||||
|
||||
#define FIRST_USER_SEGMENT NUM_BOOT_SEGMENTS
|
||||
#define FIRST_SYSTEM_SEGMENT (PAGE_SIZE / sizeof(Descriptor) - \
|
||||
NUM_SYSTEM_SEGMENTS - \
|
||||
NUM_TASK_SEGMENTS * 2 - \
|
||||
TSS_SIZE / sizeof(Descriptor))
|
||||
|
||||
#define GDT_USER_TLS_MIN USER_TLS_1_SEGMENT
|
||||
#define GDT_USER_TLS_MAX USER_TLS_3_SEGMENT
|
||||
#define USER_TLS_COUNT ((USER_TLS_3_SEGMENT - USER_TLS_1_SEGMENT) + 1)
|
||||
|
||||
#define FOREACH_USER_TLS_INDEX(_i) \
|
||||
{ \
|
||||
unsigned _i; \
|
||||
for (_i = 0; _i < USER_TLS_COUNT; _i++) { \
|
||||
|
||||
#define FOREACH_USER_TLS_INDEX_DONE \
|
||||
} \
|
||||
}
|
||||
|
||||
#define NULL_LDTR 0
|
||||
|
||||
/*
|
||||
* The descriptor after SYSTEM_CODE_SEGMENT (loaded into %cs) must be
|
||||
* appropriate for %ss because of the syscall instruction for 64-bit
|
||||
* user worlds. Thus SYSTEM_DATA_SEGMENT is directly after it.
|
||||
*/
|
||||
typedef enum VmwSegs {
|
||||
NULL_SEGMENT = 0,
|
||||
/* (... reserved for host operating system or vmkBoot segments). */
|
||||
|
||||
USER32_CODE_SEGMENT = FIRST_USER_SEGMENT,
|
||||
USER_DATA_SEGMENT,
|
||||
USER64_SYSRET_SEGMENT,
|
||||
USER64_STACK_SEGMENT,
|
||||
USER64_CODE_SEGMENT,
|
||||
USER_TLS_1_SEGMENT,
|
||||
USER_TLS_2_SEGMENT,
|
||||
USER_TLS_3_SEGMENT,
|
||||
|
||||
AFTER_LAST_USER_SEGMENT,
|
||||
|
||||
SYSTEM_CODE_SEGMENT = FIRST_SYSTEM_SEGMENT,
|
||||
SYSTEM_DATA_SEGMENT,
|
||||
VMKERNEL_TASK_SEGMENT,
|
||||
VMKERNEL_TASK_SEGMENT_HI,
|
||||
MONITOR_TASK_SEGMENT,
|
||||
MONITOR_TASK_SEGMENT_HI,
|
||||
|
||||
NUM_VALID_SEGMENTS
|
||||
} VmwSegs;
|
||||
|
||||
#define GDT_SYSTEM_SEL(x) MAKE_SELECTOR(x##_SEGMENT, SELECTOR_GDT, 0)
|
||||
#define GDT_SYSTEM_SEL_UNCHECKED(x) \
|
||||
MAKE_SELECTOR_UNCHECKED(x##_SEGMENT, SELECTOR_GDT, 0)
|
||||
#define GDT_USER_SEL(x) MAKE_SELECTOR(x##_SEGMENT, SELECTOR_GDT, 3)
|
||||
#define GDT_USER_SEL_UNCHECKED(x) \
|
||||
MAKE_SELECTOR_UNCHECKED(x##_SEGMENT, SELECTOR_GDT, 3)
|
||||
|
||||
/* Selectors used statically in code or in assembly must be unchecked. */
|
||||
#define SYSTEM_NULL_SELECTOR GDT_SYSTEM_SEL(NULL)
|
||||
#define USER32_CODE_SELECTOR GDT_USER_SEL_UNCHECKED(USER32_CODE)
|
||||
#define USER_DATA_SELECTOR GDT_USER_SEL_UNCHECKED(USER_DATA)
|
||||
#define USER64_CODE_SELECTOR GDT_USER_SEL_UNCHECKED(USER64_CODE)
|
||||
#define USER64_SYSRET_SELECTOR GDT_USER_SEL(USER64_SYSRET)
|
||||
#define SYSTEM_CODE_SELECTOR GDT_SYSTEM_SEL_UNCHECKED(SYSTEM_CODE)
|
||||
#define SYSTEM_DATA_SELECTOR GDT_SYSTEM_SEL_UNCHECKED(SYSTEM_DATA)
|
||||
#define MONITOR_TASK_SELECTOR GDT_SYSTEM_SEL(MONITOR_TASK)
|
||||
#define VMKERNEL_TASK_SELECTOR GDT_SYSTEM_SEL(VMKERNEL_TASK)
|
||||
|
||||
/*
|
||||
* The VMM GDT is comprised of many segment descriptors with one initial
|
||||
* Task State Segment system descriptor. The VMM Task State Segment is
|
||||
* on the same page sequentially after its GDT.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
typedef struct StaticGDTAndTSS {
|
||||
Descriptor empty[NUM_BOOT_SEGMENTS + NUM_USER_SEGMENTS];
|
||||
Descriptor systemSegs[NUM_SYSTEM_SEGMENTS];
|
||||
Descriptor64 vmkTask;
|
||||
Descriptor64 monTask;
|
||||
Task64 monTSS;
|
||||
uint8 TSSIRBitmap[IRB_SIZE];
|
||||
} StaticGDTAndTSS;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct VmkernelGDT {
|
||||
Descriptor bootSegs[NUM_BOOT_SEGMENTS];
|
||||
Descriptor userSegs[NUM_USER_SEGMENTS];
|
||||
Descriptor systemSegs[NUM_SYSTEM_SEGMENTS]; /* VMM/VMK-shared. */
|
||||
Descriptor64 vmkTask;
|
||||
Descriptor64 monTask;
|
||||
} VmkernelGDT;
|
||||
#pragma pack(pop)
|
||||
|
||||
MY_ASSERTS(segs,
|
||||
ASSERT_ON_COMPILE(SYSTEM_CODE_SEGMENT + 1 == SYSTEM_DATA_SEGMENT);
|
||||
ASSERT_ON_COMPILE(AFTER_LAST_USER_SEGMENT - FIRST_USER_SEGMENT <=
|
||||
NUM_USER_SEGMENTS);
|
||||
ASSERT_ON_COMPILE(AFTER_LAST_USER_SEGMENT <= FIRST_SYSTEM_SEGMENT);
|
||||
)
|
||||
|
||||
#endif /* _SEGS_H_ */
|
||||
@@ -1,62 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2018 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* sharedAreaVmmon.h --
|
||||
*
|
||||
* VMMon shared area management.
|
||||
*/
|
||||
|
||||
#ifndef SHARED_AREA_VMMON_H
|
||||
#define SHARED_AREA_VMMON_H
|
||||
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "iocontrols.h"
|
||||
|
||||
struct VMDriver;
|
||||
|
||||
/* A collection of pages backing a shared area region. */
|
||||
typedef struct SharedAreaVmmonRegion {
|
||||
PageCnt pagesPerVcpu;
|
||||
MPN *pages;
|
||||
} SharedAreaVmmonRegion;
|
||||
|
||||
/* The VMMon Driver shared area. */
|
||||
typedef struct SharedAreaVmmon {
|
||||
SharedAreaVmmonRegion regions[NUM_SHARED_AREAS];
|
||||
} SharedAreaVmmon;
|
||||
|
||||
/* Request for a backing MPN for a shared area region at a given VCPU/offset. */
|
||||
typedef struct SharedAreaVmmonRequest {
|
||||
SharedAreaType type;
|
||||
Vcpuid vcpu;
|
||||
PageCnt offset;
|
||||
} SharedAreaVmmonRequest;
|
||||
|
||||
SharedAreaVmmon *SharedAreaVmmon_Init(struct VMDriver *vm);
|
||||
void SharedAreaVmmon_Cleanup(SharedAreaVmmon *area);
|
||||
Bool SharedAreaVmmon_RegisterRegion(struct VMDriver *driver,
|
||||
VMSharedAreaRegistrationBlock *block);
|
||||
Bool SharedAreaVmmon_ValidateRegionArgs(struct VMDriver *driver,
|
||||
VMSharedAreaRegistrationBlock *block);
|
||||
MPN SharedAreaVmmon_GetRegionMPN(struct VMDriver *vm,
|
||||
SharedAreaVmmonRequest *request);
|
||||
#endif /* SHARED_AREA_VMMON_H */
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2014,2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -20,12 +20,15 @@
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#include "includeCheck.h"
|
||||
|
||||
UC(CALL_START, FALSE)
|
||||
UC(BEGIN_BACK_TO_HOST, FALSE)
|
||||
UC(SWITCHED_TO_MODULE, TRUE)
|
||||
UC(VMX_HANDLER_START, FALSE)
|
||||
UC(SWITCHING_TO_MONITOR, TRUE)
|
||||
UC(DONE_BACK_TO_HOST, FALSE)
|
||||
UC(CALL_END, FALSE)
|
||||
UC(CALL_START)
|
||||
UC(BEGIN_BACK_TO_HOST)
|
||||
UC(SWITCHED_TO_MODULE)
|
||||
UC(VMX_SELECT_RETURN)
|
||||
UC(VMX_HANDLER_START)
|
||||
UC(VMX_SIGNAL)
|
||||
UC(MODULE_SIGNAL)
|
||||
UC(SWITCHING_TO_MONITOR)
|
||||
UC(DONE_BACK_TO_HOST)
|
||||
UC(CALL_END)
|
||||
|
||||
#undef UC
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2008,2019-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2008 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifndef USERCALLDEFS_H
|
||||
#define USERCALLDEFS_H
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef linux
|
||||
#include <linux/errno.h>
|
||||
#define USERCALL_RESTART (-ERESTARTNOINTR)
|
||||
#else
|
||||
@@ -31,6 +31,5 @@
|
||||
* failing DeviceIoControl on Windows.
|
||||
*/
|
||||
#define USERCALL_VMX86ALLOCERR (-8192)
|
||||
#define USERCALL_SWITCHERR (-8193)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
+14
-18
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2014, 2016-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -38,32 +38,28 @@
|
||||
|
||||
#include "vm_basic_types.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint32 Vcpuid; // VCPU number
|
||||
typedef uint32 Vcpuid; // VCPU number
|
||||
|
||||
#define VCPUID_INVALID (~0U)
|
||||
#define VCPUID_INVALID (~0U)
|
||||
|
||||
#define BOOT_VCPU_ID 0
|
||||
#define IS_BOOT_VCPUID(vcpuid) ((vcpuid) == BOOT_VCPU_ID)
|
||||
|
||||
#define MAX_VCPUS 2048
|
||||
#define MAX_VCPUS 128
|
||||
|
||||
#define MAX_CORES_PER_SOCKET 64
|
||||
#define MAX_VCPU_SOCKETS 128
|
||||
|
||||
/*
|
||||
* There are several properties of the VM which change at the 128 VCPU
|
||||
* boundary. EFI firmware, x2APIC, and IOMMU are required among others.
|
||||
*/
|
||||
#define MAX_SMALL_VM_VCPUS 128
|
||||
#ifdef VMM
|
||||
#include "vcpuset.h"
|
||||
|
||||
/* Supported limit. */
|
||||
#define MAX_SUPPORTED_VCPUS (FEATURE_STATE_IS_ENABLED(MonsterVM) ? 768 : 256)
|
||||
/* In VMM, CurVcpuid() is available everywhere. */
|
||||
extern const Vcpuid curVcpuid;
|
||||
extern const VCPUSet curVcpuidSet;
|
||||
#define CurVcpuid() (curVcpuid)
|
||||
#define CurVcpuidSet() (&curVcpuidSet)
|
||||
#define IS_BOOT_VCPU() IS_BOOT_VCPUID(CurVcpuid())
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif /* VMM */
|
||||
|
||||
#endif // ifndef _VCPUID_H_
|
||||
+65
-154
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2002-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2002-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -19,7 +19,7 @@
|
||||
/*
|
||||
* vcpuset.h --
|
||||
*
|
||||
* ADT for a set of VCPUs. Implemented as an array of bitmasks.
|
||||
* ADT for a set of VCPUs. Implemented as an array of bitmasks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -44,11 +44,10 @@
|
||||
# include "str.h" /* Str_Snprintf */
|
||||
# define VCS_SNPRINTF Str_Snprintf
|
||||
#elif defined MONITOR_APP
|
||||
# include <stdio.h> /* libc snprintf */
|
||||
# if defined WIN32
|
||||
# include "str.h" /* Str_Snprintf */
|
||||
# define VCS_SNPRINTF Str_Snprintf
|
||||
# define VCS_SNPRINTF _snprintf
|
||||
# else
|
||||
# include <stdio.h> /* libc snprintf */
|
||||
# define VCS_SNPRINTF snprintf
|
||||
# endif
|
||||
#elif defined VMM || defined VMKERNEL
|
||||
@@ -81,39 +80,22 @@
|
||||
|
||||
extern VCPUSet vcpuSetFull;
|
||||
|
||||
#define FOR_EACH_VCPU_IN_SET_WITH_MAX(_vcpuSet, _v, _numVcpus) \
|
||||
do { \
|
||||
Vcpuid _v; \
|
||||
const VCPUSet *__vcs = (_vcpuSet); \
|
||||
unsigned _subsetIdx = 0; \
|
||||
uint64 _subset = VCPUSet_Subset(__vcs, _subsetIdx); \
|
||||
unsigned _maxSubsets = VCS_VCPUID_SUBSET_IDX((_numVcpus) - 1) + 1; \
|
||||
ASSERT(_maxSubsets <= VCS_SUBSET_COUNT); \
|
||||
while ((_v = VCPUSet_FindFirstInSubset(__vcs, &_subset, &_subsetIdx, \
|
||||
_maxSubsets)) != VCPUID_INVALID) {\
|
||||
#define FOR_EACH_VCPU_IN_SET(_vcpuSet, _v) \
|
||||
do { \
|
||||
Vcpuid _v; \
|
||||
VCPUSet __vcs; \
|
||||
VCPUSet_Copy(&__vcs, _vcpuSet); \
|
||||
while ((_v = VCPUSet_FindFirst(&__vcs)) != VCPUID_INVALID) { \
|
||||
VCPUSet_Remove(&__vcs, _v);
|
||||
|
||||
#define ROF_EACH_VCPU_IN_SET_WITH_MAX() \
|
||||
} \
|
||||
#define ROF_EACH_VCPU_IN_SET() \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define FOR_EACH_VCPU_IN_SET(_vcpuSet, _v) \
|
||||
FOR_EACH_VCPU_IN_SET_WITH_MAX(_vcpuSet, _v, MAX_VCPUS)
|
||||
|
||||
#define ROF_EACH_VCPU_IN_SET() \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FOR_EACH_VCPU_IN_POPULATED_VCPUS(_vcpuSet, _v) \
|
||||
FOR_EACH_VCPU_IN_SET_WITH_MAX(_vcpuSet, _v, NumVCPUs())
|
||||
|
||||
#define ROF_EACH_VCPU_IN_POPULATED_VCPUS() \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FOR_EACH_SUBSET_IN_SET(_setIndex) \
|
||||
do { \
|
||||
unsigned _setIndex; \
|
||||
int _setIndex; \
|
||||
for (_setIndex = 0; _setIndex < VCS_SUBSET_COUNT; _setIndex++) {
|
||||
|
||||
#define ROF_EACH_SUBSET_IN_SET() \
|
||||
@@ -123,18 +105,18 @@ extern VCPUSet vcpuSetFull;
|
||||
|
||||
#define FOR_EACH_SUBSET_IN_SET_COUNTDOWN(_setIndex) \
|
||||
do { \
|
||||
unsigned _setIndex = VCS_SUBSET_COUNT; \
|
||||
while (_setIndex-- > 0) {
|
||||
int _setIndex; \
|
||||
for (_setIndex = VCS_SUBSET_COUNT - 1; _setIndex >= 0; _setIndex--) {
|
||||
|
||||
#define ROF_EACH_SUBSET_IN_SET_COUNTDOWN() \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define FOR_EACH_POPULATED_SUBSET_IN_SET(_setIndex, _numVcpus) \
|
||||
#define FOR_EACH_POPULATED_SUBSET_IN_SET(_setIndex) \
|
||||
do { \
|
||||
unsigned _setIndex; \
|
||||
unsigned _maxSubsets = VCS_VCPUID_SUBSET_IDX(_numVcpus - 1); \
|
||||
int _setIndex; \
|
||||
int _maxSubsets = VCS_VCPUID_SUBSET_IDX(NumVCPUs() - 1); \
|
||||
for (_setIndex = 0; _setIndex <= _maxSubsets; _setIndex++) {
|
||||
|
||||
#define ROF_EACH_POPULATED_SUBSET_IN_SET() \
|
||||
@@ -146,7 +128,7 @@ extern VCPUSet vcpuSetFull;
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_Empty --
|
||||
*
|
||||
*
|
||||
* Clear all bits in a VCPUSet.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -165,7 +147,7 @@ VCPUSet_Empty(VCPUSet *vcs)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_IsEmpty --
|
||||
*
|
||||
*
|
||||
* Return TRUE iff a VCPUSet has no bits set.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -210,7 +192,7 @@ VCPUSet_Full(void)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_Copy --
|
||||
*
|
||||
*
|
||||
* Copy one VCPUSet's contents to another.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -229,7 +211,7 @@ VCPUSet_Copy(VCPUSet *dest, const VCPUSet *src)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_Equals --
|
||||
*
|
||||
*
|
||||
* Compare two VCPUSets, return TRUE iff their contents match.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -251,7 +233,7 @@ VCPUSet_Equals(const VCPUSet *vcs1, const VCPUSet *vcs2)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_IsMember --
|
||||
*
|
||||
*
|
||||
* Return TRUE iff the given Vcpuid is present in a VCPUSet.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -270,7 +252,7 @@ VCPUSet_IsMember(const VCPUSet *vcs, Vcpuid v)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_AtomicIsMember --
|
||||
*
|
||||
*
|
||||
* Return TRUE iff the given Vcpuid is present in a VCPUSet.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -291,7 +273,7 @@ VCPUSet_AtomicIsMember(VCPUSet *vcs, Vcpuid v)
|
||||
*
|
||||
* VCPUSet_FindFirst --
|
||||
* VCPUSet_FindLast --
|
||||
*
|
||||
*
|
||||
* Find the first (lowest-numbered) or last (highest-numbered)
|
||||
* Vcpuid in a VCPUSet.
|
||||
*
|
||||
@@ -308,7 +290,7 @@ VCPUSet_FindFirst(const VCPUSet *vcs)
|
||||
FOR_EACH_SUBSET_IN_SET(idx) {
|
||||
uint64 subset = vcs->subset[idx];
|
||||
if (subset != 0) {
|
||||
return lssb64(subset) - 1 + (idx << VCS_SUBSET_SHIFT);
|
||||
return lssb64_0(subset) + (idx << VCS_SUBSET_SHIFT);
|
||||
}
|
||||
} ROF_EACH_SUBSET_IN_SET();
|
||||
return VCPUID_INVALID;
|
||||
@@ -320,62 +302,19 @@ VCPUSet_FindLast(const VCPUSet *vcs)
|
||||
FOR_EACH_SUBSET_IN_SET_COUNTDOWN(idx) {
|
||||
uint64 subset = vcs->subset[idx];
|
||||
if (subset != 0) {
|
||||
return mssb64(subset) - 1 + (idx << VCS_SUBSET_SHIFT);
|
||||
return mssb64_0(subset) + (idx << VCS_SUBSET_SHIFT);
|
||||
}
|
||||
} ROF_EACH_SUBSET_IN_SET_COUNTDOWN();
|
||||
return VCPUID_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_FindFirstInSubset --
|
||||
*
|
||||
* Find the first (lowest-numbered) Vcpuid in the given subset of a
|
||||
* VCPUSet object. It is required that *subset is initialized to
|
||||
* a subset of *vcs and *subsetIdx must hold the index of the subset
|
||||
* stored in *subset.
|
||||
*
|
||||
* Results:
|
||||
* Vcpuid if at least one is present in a set.
|
||||
* VCPUID_INVALID if the set is empty.
|
||||
*
|
||||
* Side effects:
|
||||
* This function is intended to be used for iterating over all bits
|
||||
* of a VCPUSet, it will modify *subset to clear the bit associated
|
||||
* with the returned Vcpuid (if any). The *subsetIdx argument may
|
||||
* also be updated.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE Vcpuid
|
||||
VCPUSet_FindFirstInSubset(const VCPUSet *vcs, uint64 *subset,
|
||||
unsigned *subsetIdx, unsigned maxSubsets)
|
||||
{
|
||||
ASSERT(*subsetIdx < maxSubsets && maxSubsets <= VCS_SUBSET_COUNT);
|
||||
do {
|
||||
if (*subset != 0) {
|
||||
unsigned bit = (unsigned)lssb64_0(*subset);
|
||||
*subset &= ~(CONST64U(1) << bit);
|
||||
return bit + (*subsetIdx << VCS_SUBSET_SHIFT);
|
||||
}
|
||||
++*subsetIdx;
|
||||
if (*subsetIdx < maxSubsets) {
|
||||
*subset = vcs->subset[*subsetIdx];
|
||||
}
|
||||
} while (*subsetIdx < maxSubsets);
|
||||
return VCPUID_INVALID;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_Remove --
|
||||
* VCPUSet_AtomicRemove --
|
||||
*
|
||||
*
|
||||
* Remove or atomically remove a single Vcpuid from a VCPUSet.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -432,7 +371,7 @@ VCPUSet_RemoveSet(VCPUSet *dest, const VCPUSet *src)
|
||||
*
|
||||
* VCPUSet_Include --
|
||||
* VCPUSet_AtomicInclude --
|
||||
*
|
||||
*
|
||||
* Add or atomically add a single Vcpuid to a VCPUSet.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -455,33 +394,12 @@ VCPUSet_AtomicInclude(VCPUSet *vcs, Vcpuid v)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_AtomicTestInclude --
|
||||
*
|
||||
* Atomically add a single Vcpuid to a VCPUSet, and
|
||||
* return TRUE iff the given Vcpuid was present in the VCPUSet.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE Bool
|
||||
VCPUSet_AtomicTestInclude(VCPUSet *vcs, Vcpuid v)
|
||||
{
|
||||
volatile uint64 *subset = &vcs->subset[VCS_VCPUID_SUBSET_IDX(v)];
|
||||
ASSERT(v < MAX_VCPUS);
|
||||
return Atomic_TestSetBit64(Atomic_VolatileToAtomic64(subset),
|
||||
v & VCS_SUBSET_MASK);
|
||||
}
|
||||
|
||||
|
||||
#if defined(VMM) && !defined(MONITOR_APP)
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_PackCareful --
|
||||
*
|
||||
*
|
||||
* Pack a VCPUSet into the bytes at "ptr".
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -498,14 +416,14 @@ VCPUSet_PackCareful(unsigned numVCPUs, const VCPUSet *vcs, void *ptr)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_UnpackCareful --
|
||||
*
|
||||
* Unpack a VCPUSet from the bytes at "ptr".
|
||||
*
|
||||
* Unpack a VCPUSet from the bytes at "src".
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
VCPUSet_UnpackCareful(unsigned numVCPUs, VCPUSet *vcs, const void *ptr)
|
||||
VCPUSet_UnpackCareful(unsigned numVCPUs, VCPUSet *vcs, void *ptr)
|
||||
{
|
||||
memcpy(vcs->subset, ptr, (numVCPUs + 7) / 8);
|
||||
}
|
||||
@@ -565,7 +483,7 @@ VCPUSet_Populate(VCPUSet *vcs, unsigned numVCPUs)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_Subset --
|
||||
*
|
||||
*
|
||||
* Return the specified subset of a VCPUSet.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -584,7 +502,7 @@ VCPUSet_Subset(const VCPUSet *vcs,
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_SubsetPtr --
|
||||
*
|
||||
*
|
||||
* Return a pointer to the specified subset of a VCPUSet.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -602,7 +520,7 @@ VCPUSet_SubsetPtr(VCPUSet *vcs, unsigned subset)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_IsSupersetOrEqual --
|
||||
*
|
||||
*
|
||||
* Return TRUE iff vcs1 contains a superset of the VCPUs in vcs2
|
||||
* or vcs1 and vcs2 contain exactly the same VCPUs.
|
||||
*
|
||||
@@ -625,7 +543,7 @@ VCPUSet_IsSupersetOrEqual(const VCPUSet *vcs1, const VCPUSet *vcs2)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_IsSubsetOrEqual --
|
||||
*
|
||||
*
|
||||
* Return TRUE iff vcs1 contains a subset of the VCPUs in vcs2
|
||||
* or vcs1 and vcs2 contain exactly the same VCPUs.
|
||||
*
|
||||
@@ -643,7 +561,7 @@ VCPUSet_IsSubsetOrEqual(const VCPUSet *vcs1, const VCPUSet *vcs2)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_MakeSingleton --
|
||||
*
|
||||
*
|
||||
* Add a single Vcpuid to a VCPUSet and remove all others.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -660,34 +578,27 @@ VCPUSet_MakeSingleton(VCPUSet *vcs, Vcpuid v)
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_FindSingleton --
|
||||
*
|
||||
* Return the VCPU in the set iff vcs contains exactly one VCPU.
|
||||
* Return VCPUID_INVALID otherwise.
|
||||
* VCPUSet_IsSingleton --
|
||||
*
|
||||
* Return TRUE iff vcs contains exactly one VCPU.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE Vcpuid
|
||||
VCPUSet_FindSingleton(const VCPUSet *vcs)
|
||||
static INLINE Bool
|
||||
VCPUSet_IsSingleton(const VCPUSet *vcs)
|
||||
{
|
||||
uint64 foundSub = 0;
|
||||
uint32 foundIdx = 0;
|
||||
Bool foundOnce = FALSE;
|
||||
FOR_EACH_SUBSET_IN_SET(idx) {
|
||||
uint64 sub = vcs->subset[idx];
|
||||
if (sub != 0) {
|
||||
if (foundSub != 0 || (sub & (sub - 1)) != 0) {
|
||||
return VCPUID_INVALID;
|
||||
if (foundOnce || (sub & (sub - 1)) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
foundSub = sub;
|
||||
foundIdx = idx;
|
||||
foundOnce = TRUE;
|
||||
}
|
||||
} ROF_EACH_SUBSET_IN_SET();
|
||||
if (foundSub != 0) {
|
||||
return lssb64(foundSub) - 1 + (foundIdx << VCS_SUBSET_SHIFT);
|
||||
} else {
|
||||
return VCPUID_INVALID;
|
||||
}
|
||||
return foundOnce;
|
||||
}
|
||||
|
||||
|
||||
@@ -711,7 +622,7 @@ VCPUSet_IsFull(const VCPUSet *vcs)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_AtomicReadWriteSubset --
|
||||
*
|
||||
*
|
||||
* For the nth aligned 64-VCPU subset of a VCPU set, atomically
|
||||
* read then write. Return the contents read. Set 0 is VCPUs
|
||||
* 0-63 and set 1 is VCPUs 64-127.
|
||||
@@ -756,7 +667,7 @@ VCPUSet_Size(const VCPUSet *vcs)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_UnionSubset --
|
||||
*
|
||||
*
|
||||
* Given an 64-bit value and a subset number, add the VCPUs
|
||||
* represented to the set.
|
||||
*
|
||||
@@ -775,7 +686,7 @@ VCPUSet_UnionSubset(VCPUSet *vcs, uint64 vcpus, unsigned n)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_SubtractSubset --
|
||||
*
|
||||
*
|
||||
* Given an 64-bit value and a subset number, remove the VCPUs
|
||||
* represented in the subset from the set.
|
||||
*
|
||||
@@ -794,7 +705,7 @@ VCPUSet_SubtractSubset(VCPUSet *vcs, uint64 vcpus, unsigned n)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_AtomicUnionSubset --
|
||||
*
|
||||
*
|
||||
* Given a 64-bit value and a subset number, atomically add
|
||||
* the VCPUs represented to the set.
|
||||
*
|
||||
@@ -814,7 +725,7 @@ VCPUSet_AtomicUnionSubset(VCPUSet *vcs, uint64 vcpus, unsigned n)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_Invert --
|
||||
*
|
||||
*
|
||||
* Makes all non-present valid VCPUs in a set present and all
|
||||
* VCPUs present non-present.
|
||||
*
|
||||
@@ -835,7 +746,7 @@ VCPUSet_Invert(VCPUSet *vcs)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_Intersection
|
||||
*
|
||||
*
|
||||
* Given two VCPUSets, populate the destination set with only the
|
||||
* VCPUs common to both.
|
||||
*
|
||||
@@ -855,7 +766,7 @@ VCPUSet_Intersection(VCPUSet *dest, const VCPUSet *src)
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* VCPUSet_LogFormat --
|
||||
*
|
||||
*
|
||||
* Given a buffer of at least VCS_BUF_SIZE to fill, write into it a
|
||||
* string suitable for use in Log() or LOG().
|
||||
* Returns the buffer which was passed as an argument, after
|
||||
@@ -866,27 +777,27 @@ VCPUSet_Intersection(VCPUSet *dest, const VCPUSet *src)
|
||||
|
||||
#ifdef VCS_SNPRINTF
|
||||
static INLINE char *
|
||||
VCPUSet_LogFormat(char *buf, size_t size, const VCPUSet *vcs)
|
||||
VCPUSet_LogFormat(char *buf, const int size, const VCPUSet *vcs)
|
||||
{
|
||||
unsigned offset = 0;
|
||||
Vcpuid highest = VCPUSet_FindLast(vcs);
|
||||
unsigned idx = (highest == VCPUID_INVALID) ? 0 : highest / 8;
|
||||
|
||||
int offset = 0;
|
||||
Vcpuid highest = VCPUSet_FindLast(vcs);
|
||||
int idx = (highest == VCPUID_INVALID) ? 0 : highest / 8;
|
||||
ASSERT(size >= VCS_BUF_SIZE);
|
||||
#define VCS_LOGF(...) \
|
||||
{ \
|
||||
int ret = VCS_SNPRINTF(buf + offset, size - offset, __VA_ARGS__); \
|
||||
ASSERT(0 <= ret && size >= offset && ret < (int)(size - offset)); \
|
||||
offset += (unsigned)ret; \
|
||||
ASSERT(0 <= ret && ret < size - offset); \
|
||||
offset += ret; \
|
||||
}
|
||||
/* Print the leading value with no zero-extension. */
|
||||
VCS_LOGF("%#x", ((unsigned char *)vcs)[idx]);
|
||||
VCS_LOGF("%#x", ((unsigned char *)vcs)[idx--]);
|
||||
|
||||
while (idx-- > 0) {
|
||||
while (idx >= 0) {
|
||||
if ((idx + 1) % (VCS_SUBSET_WIDTH / 8) == 0) {
|
||||
VCS_LOGF(".");
|
||||
}
|
||||
VCS_LOGF("%02x", ((unsigned char *)vcs)[idx]);
|
||||
idx--;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2002-2013, 2016-2017 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2002-2013 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -19,7 +19,7 @@
|
||||
/*
|
||||
* vcpuset_types.h --
|
||||
*
|
||||
* ADT for a set of VCPUs. Implemented as an array of bitmasks.
|
||||
* ADT for a set of VCPUs. Implemented as an array of bitmasks.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -35,14 +35,14 @@
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "vm_basic_asm.h"
|
||||
#include "vm_atomic.h"
|
||||
#include "vcpuid.h"
|
||||
#include "vm_assert.h"
|
||||
|
||||
#define VCS_SUBSET_WIDTH 64
|
||||
#define VCS_SUBSET_SHIFT 6
|
||||
#define VCS_SUBSET_MASK ((CONST64U(1) << VCS_SUBSET_SHIFT) - 1)
|
||||
#define VCS_SUBSET_COUNT 32
|
||||
|
||||
#define VCS_SUBSET_COUNT 2
|
||||
|
||||
#define VCS_VCPUID_SUBSET_IDX(v) ((v) >> VCS_SUBSET_SHIFT)
|
||||
#define VCS_VCPUID_SUBSET_BIT(v) (CONST64U(1) << ((v) & VCS_SUBSET_MASK))
|
||||
@@ -55,17 +55,4 @@ typedef struct VCPUSet {
|
||||
uint64 subset[VCS_SUBSET_COUNT];
|
||||
} VCPUSet;
|
||||
|
||||
MY_ASSERTS(VCPUSET_ASSERTS,
|
||||
ASSERT_ON_COMPILE(VCS_SUBSET_WIDTH * VCS_SUBSET_COUNT >= MAX_VCPUS);
|
||||
/*
|
||||
* Catch changes in VCPUSet which need to be reflected in
|
||||
* bora/public/iocontrolsMacosTable.h.
|
||||
*/
|
||||
ASSERT_ON_COMPILE(VCS_SUBSET_COUNT == 32);
|
||||
/*
|
||||
* There is code that depends on sizeof(VCPUSet) being a power of
|
||||
* 2 in at least vcpuHotPlug.c and possible other places.
|
||||
*/
|
||||
ASSERT_ON_COMPILE((sizeof(VCPUSet) & (sizeof(VCPUSet) - 1)) == 0);
|
||||
)
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998,2015-2016 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -17,62 +17,28 @@
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* versioned_atomic.h --
|
||||
* Versioned atomic synchronization:
|
||||
*
|
||||
* This file implements versioned atomic synchronization, which allows
|
||||
* concurrent accesses to shared data by a single writer and multiple
|
||||
* readers. The algorithm is lock-free (it does not use a mutual exclusion
|
||||
* mechanism), and the writer is wait-free (it never waits for readers).
|
||||
* These synchronization macros allow single-writer/many-reader
|
||||
* access to data, based on Leslie Lamport's paper "Concurrent
|
||||
* Reading and Writing", Communications of the ACM, November 1977.
|
||||
*
|
||||
* Many-writer/many-reader can be implemented on top of versioned atomics
|
||||
* by adding an external mutual exclusion mechanism to serialize all
|
||||
* writer threads into a single logical writer thread. This is preferable
|
||||
* for cases where readers are expected to greatly outnumber writers.
|
||||
* many-writer/many-reader can be implemented on top of versioned
|
||||
* atomics by using an additional spin lock to synchronize
|
||||
* writers. This is preferable for cases where readers are expected to
|
||||
* greatly outnumber writers.
|
||||
*
|
||||
* Implementation
|
||||
* --------------
|
||||
* This implementation is based on Leslie Lamport's paper "Concurrent
|
||||
* Reading and Writing", Communications of the ACM, November 1977
|
||||
* (http://url.eng.vmware.com/udcc ).
|
||||
* Multiple concurrent writers to the version variables are not
|
||||
* allowed. Even if writers are working on lock-free or disjoint
|
||||
* data, the version counters are not interlocked for read-modify-write.
|
||||
*
|
||||
* Lamport's algorithm was designed for systems in which the reader and
|
||||
* the writers run on separate computers and where the version variables
|
||||
* (v0 and v1 in this implementation) are stored on a shared hard disk. So
|
||||
* it did not assume that the version variables could be accessed
|
||||
* atomically. Instead, it assumed that the version variables were made of
|
||||
* multiple basic units of data, called "digits", and that each digit
|
||||
* could be accessed atomically. The upper-left corner of page 4 of the
|
||||
* paper precisely and concisely describes the algorithm, and in
|
||||
* particular the order in which digits of the version variables must be
|
||||
* accessed (left to right, right to left, or no particular order).
|
||||
*
|
||||
* This implementation is designed for systems in which the reader and the
|
||||
* writers run on the same computer and where the version variables are
|
||||
* stored in shared memory. So it assumes that the version variables can
|
||||
* be accessed atomically. As a result, this implementation uses a
|
||||
* simplified version of Lamport's algorithm, where:
|
||||
* o Each left to right or right to left access in Lamport's algorithm is
|
||||
* replaced with a single atomic access in this implementation.
|
||||
* o Each access in no particular order in Lamport's algorithm is replaced
|
||||
* with a single non-atomic access in this implementation.
|
||||
* Note: The writer is the only thread which writes to version variables,
|
||||
* so it is allowed to read them non-atomically.
|
||||
*
|
||||
* Multiple concurrent writers to the version variables are not allowed.
|
||||
* Even if writers are working on lock-free or disjoint data, the version
|
||||
* variables are not interlocked for read-modify-write. See PR514764.
|
||||
*
|
||||
* Recursive use of versioned atomics in writers is currently not
|
||||
* supported. See PR514764.
|
||||
* Recursive use of versioned atomics in writers is currently not supported.
|
||||
*/
|
||||
|
||||
#ifndef _VERSIONED_ATOMIC_H
|
||||
#define _VERSIONED_ATOMIC_H
|
||||
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
#define INCLUDE_ALLOW_VMK_MODULE
|
||||
#define INCLUDE_ALLOW_DISTRIBUTE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
@@ -80,12 +46,6 @@
|
||||
|
||||
#include "vm_basic_asm.h"
|
||||
#include "vm_assert.h"
|
||||
#include "vm_atomic.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Users with attribute(packed) structs must ensure any
|
||||
@@ -96,179 +56,115 @@ extern "C" {
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint32 v0;
|
||||
uint32 v1;
|
||||
volatile uint32 v0;
|
||||
volatile uint32 v1;
|
||||
} ALIGNED(4) VersionedAtomic;
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* VersionedAtomic_BeginWrite --
|
||||
*
|
||||
* Called by the writer to indicate that it is about to write to the
|
||||
* shared data protected by 'versions'. Effectively locks out all readers
|
||||
* until VersionedAtomic_EndWrite() is called.
|
||||
*
|
||||
* Called by a writer to indicate that the data protected by
|
||||
* a given atomic version is about to change. Effectively locks out
|
||||
* all readers until EndWrite is called.
|
||||
*
|
||||
* Results:
|
||||
* None
|
||||
* .
|
||||
*
|
||||
* Side effects:
|
||||
* None
|
||||
*
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
VersionedAtomic_BeginWrite(VersionedAtomic *versions) // IN
|
||||
VersionedAtomic_BeginWrite(VersionedAtomic *versions)
|
||||
{
|
||||
/* Catch improper initialization or unsupported recursive use. */
|
||||
/*
|
||||
* As long as the variable is on natural boundary it is guaranteed
|
||||
* to be atomic, so we don't need to write from left to right as in
|
||||
* Lamport's original algorithm.
|
||||
*/
|
||||
ASSERT(((size_t)(&versions->v0) & (sizeof(versions->v0) - 1)) == 0);
|
||||
/* If recursive use is needed demand for support in PR514764 */
|
||||
ASSERT(versions->v1 == versions->v0);
|
||||
|
||||
/*
|
||||
* Do not use Atomic_Inc32() below: it is more expensive than
|
||||
* Atomic_Write32() and unnecessary: only the write needs to be atomic, not
|
||||
* the whole read + inc + write.
|
||||
*/
|
||||
#if !defined VMM
|
||||
/*
|
||||
* Atomic_Write32() below requires the address to be naturally aligned, but
|
||||
* currently only checks that condition when VMM is defined (tracked by
|
||||
* PR1055836). So until that PR is fixed, we must check that condition here
|
||||
* when VMM is not defined.
|
||||
*/
|
||||
ASSERT(((uintptr_t)&versions->v0 % sizeof versions->v0) == 0);
|
||||
#endif
|
||||
Atomic_Write32((Atomic_uint32 *)&versions->v0, versions->v0 + 1);
|
||||
|
||||
/*
|
||||
* The write to 'versions->v0' must be observed by all other OS CPUs before
|
||||
* the write(s) to the shared data.
|
||||
*/
|
||||
SMP_W_BARRIER_W();
|
||||
versions->v0++;
|
||||
COMPILER_MEM_BARRIER();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* VersionedAtomic_EndWrite --
|
||||
*
|
||||
* Called by the writer to indicate that it has finished writing to the
|
||||
* shared data protected by 'versions'. Lets pending and new readers
|
||||
* proceed.
|
||||
*
|
||||
* Called by a writer after it is done updating shared data. Lets
|
||||
* pending and new readers proceed on shared data.
|
||||
*
|
||||
* Results:
|
||||
* None
|
||||
* .
|
||||
*
|
||||
* Side effects:
|
||||
* None
|
||||
*
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
VersionedAtomic_EndWrite(VersionedAtomic *versions) // IN
|
||||
VersionedAtomic_EndWrite(VersionedAtomic *versions)
|
||||
{
|
||||
/*
|
||||
* The write(s) to the shared data must be observed by all other OS CPUs
|
||||
* before the write to 'versions->v1'.
|
||||
*/
|
||||
SMP_W_BARRIER_W();
|
||||
|
||||
ASSERT(((size_t)(&versions->v1) & (sizeof(versions->v1) - 1)) == 0);
|
||||
ASSERT(versions->v1 + 1 == versions->v0);
|
||||
|
||||
#if !defined VMM
|
||||
/*
|
||||
* Atomic_Write32() below requires the address to be naturally aligned, but
|
||||
* currently only checks that condition when VMM is defined (tracked by
|
||||
* PR1055836). So until that PR is fixed, we must check that condition here
|
||||
* when VMM is not defined.
|
||||
*/
|
||||
ASSERT(((uintptr_t)&versions->v1 % sizeof versions->v1) == 0);
|
||||
#endif
|
||||
Atomic_Write32((Atomic_uint32 *)&versions->v1, versions->v0);
|
||||
COMPILER_MEM_BARRIER();
|
||||
versions->v1 = versions->v0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* VersionedAtomic_BeginTryRead --
|
||||
*
|
||||
* Called by a reader before it starts reading the shared data protected
|
||||
* by 'versions'.
|
||||
*
|
||||
* Called by a reader before it tried to read shared data.
|
||||
*
|
||||
* Results:
|
||||
* A version number for the caller to pass to the matching call to
|
||||
* VersionedAtomic_EndTryRead(), if any.
|
||||
* Returns a version number to the reader. This version number
|
||||
* is required to confirm validity of the read operation when reader
|
||||
* calls EndTryRead.
|
||||
*
|
||||
* Side effects:
|
||||
* None
|
||||
*
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE uint32
|
||||
VersionedAtomic_BeginTryRead(VersionedAtomic const *versions) // IN
|
||||
VersionedAtomic_BeginTryRead(const VersionedAtomic *versions)
|
||||
{
|
||||
uint32 readVersion = Atomic_Read32((Atomic_uint32 *)&versions->v1);
|
||||
uint32 readVersion;
|
||||
|
||||
/*
|
||||
* The read from 'versions->v1' must happen on this CPU before the read(s)
|
||||
* from the shared data.
|
||||
*/
|
||||
SMP_R_BARRIER_R();
|
||||
readVersion = versions->v1;
|
||||
COMPILER_MEM_BARRIER();
|
||||
|
||||
return readVersion;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* VersionedAtomic_EndTryRead --
|
||||
*
|
||||
* Called by a reader after it has finished reading the shared data
|
||||
* protected by 'versions', to confirm that the data is consistent, i.e.
|
||||
* that the writer has not modified the data while the reader was reading
|
||||
* it.
|
||||
*
|
||||
* Called by a reader after it finishes reading shared data, to confirm
|
||||
* validity of the data that was just read (IOW, to make sure that a
|
||||
* writer did not intervene while the read was in progress).
|
||||
*
|
||||
* Results:
|
||||
* TRUE if the shared data read between VersionedAtomic_BeginTryRead() and
|
||||
* this call is consistent.
|
||||
* FALSE otherwise.
|
||||
* TRUE if the data read between BeginTryRead() and this call is
|
||||
* valid. FALSE otherwise.
|
||||
*
|
||||
* Side effects:
|
||||
* None
|
||||
*
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE Bool
|
||||
VersionedAtomic_EndTryRead(VersionedAtomic const *versions, // IN
|
||||
uint32 readVersion) // IN
|
||||
VersionedAtomic_EndTryRead(const VersionedAtomic *versions,
|
||||
uint32 readVersion)
|
||||
{
|
||||
/*
|
||||
* The read(s) from the shared data must happen on this CPU before the read
|
||||
* from 'versions->v0'.
|
||||
*/
|
||||
SMP_R_BARRIER_R();
|
||||
|
||||
/*
|
||||
* There is a theoretical ABA issue here: if the writer updates the shared
|
||||
* data exactly 2^32 times while a reader reads it, the read will
|
||||
* incorrectly be considered consistent. In practice, this issue is
|
||||
* unlikely, so we ignore it. But should we need it, we could make the issue
|
||||
* even less likely by using 64-bit version variables.
|
||||
*/
|
||||
return LIKELY( Atomic_Read32((Atomic_uint32 *)&versions->v0)
|
||||
== readVersion);
|
||||
COMPILER_MEM_BARRIER();
|
||||
return LIKELY(versions->v0 == readVersion);
|
||||
}
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif //_VERSIONED_ATOMIC_H
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2014,2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -41,47 +41,52 @@
|
||||
|
||||
#include "vm_basic_asm.h"
|
||||
#include "x86msr.h"
|
||||
|
||||
#ifdef VM_X86_64
|
||||
#include "vm_asm_x86_64.h"
|
||||
#else
|
||||
#include "vm_asm_x86.h"
|
||||
#endif
|
||||
|
||||
|
||||
static INLINE void
|
||||
SET_FS64(uint64 fs64)
|
||||
{
|
||||
X86MSR_SetMSR(MSR_FSBASE, fs64);
|
||||
__SET_MSR(MSR_FSBASE, fs64);
|
||||
}
|
||||
|
||||
|
||||
static INLINE void
|
||||
SET_GS64(uint64 gs64)
|
||||
{
|
||||
X86MSR_SetMSR(MSR_GSBASE, gs64);
|
||||
__SET_MSR(MSR_GSBASE, gs64);
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
SET_KernelGS64(uint64 kgs64)
|
||||
{
|
||||
X86MSR_SetMSR(MSR_KERNELGSBASE, kgs64);
|
||||
__SET_MSR(MSR_KERNELGSBASE, kgs64);
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint64
|
||||
GET_FS64(void)
|
||||
{
|
||||
return X86MSR_GetMSR(MSR_FSBASE);
|
||||
return __GET_MSR(MSR_FSBASE);
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint64
|
||||
GET_GS64(void)
|
||||
{
|
||||
return X86MSR_GetMSR(MSR_GSBASE);
|
||||
return __GET_MSR(MSR_GSBASE);
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint64
|
||||
GET_KernelGS64(void)
|
||||
{
|
||||
return X86MSR_GetMSR(MSR_KERNELGSBASE);
|
||||
return __GET_MSR(MSR_KERNELGSBASE);
|
||||
}
|
||||
|
||||
#endif // VM_ARM_64
|
||||
|
||||
+556
-232
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2014,2016-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -19,7 +19,7 @@
|
||||
/*
|
||||
* vm_asm_x86.h
|
||||
*
|
||||
* IA32 asm macros
|
||||
* IA32 asm macros
|
||||
*/
|
||||
|
||||
#ifndef _VM_ASM_X86_H_
|
||||
@@ -49,6 +49,10 @@
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if defined __APPLE__
|
||||
/* PR 352418: GCC produces error if the non-Apple version is used */
|
||||
#define ASSERT_ON_COMPILE_SELECTOR_SIZE(expr)
|
||||
#else
|
||||
/* ASSERT_ON_COMPILE_SELECTOR_SIZE:
|
||||
*
|
||||
* - Selector must be 16-bits.
|
||||
@@ -62,16 +66,26 @@
|
||||
* ((__builtin_constant_p(expr) ? ((expr) >> 16) == 0) \
|
||||
* : sizeof(expr) <= 2)
|
||||
*/
|
||||
#ifndef USE_UBSAN
|
||||
#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1)
|
||||
#define ASSERT_ON_COMPILE_SELECTOR_SIZE(expr) \
|
||||
ASSERT_ON_COMPILE(sizeof(Selector) == 2 && \
|
||||
((__builtin_constant_p(expr) && ((expr) >> 16) == 0) || \
|
||||
sizeof(expr) <= 2))
|
||||
#else
|
||||
/* gcc 3.3.3 is not able to produce a constant expression (PR 356383) */
|
||||
#define ASSERT_ON_COMPILE_SELECTOR_SIZE(expr)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* [GS]ET_[GI]DT() are defined as macros wrapping a function
|
||||
* so we can pass the argument implicitly by reference (requires
|
||||
* a macro) and get type checking too (requires a function).
|
||||
*/
|
||||
|
||||
#define SET_GDT(var) _Set_GDT(&(var))
|
||||
|
||||
/* Checked against the Intel manual and GCC --hpreg */
|
||||
static INLINE void
|
||||
_Set_GDT(_GETSET_DTR_TYPE *dtr)
|
||||
@@ -83,6 +97,8 @@ _Set_GDT(_GETSET_DTR_TYPE *dtr)
|
||||
);
|
||||
}
|
||||
|
||||
#define SET_IDT(var) _Set_IDT(&(var))
|
||||
|
||||
/* Checked against the Intel manual and GCC --hpreg */
|
||||
static INLINE void
|
||||
_Set_IDT(_GETSET_DTR_TYPE *dtr)
|
||||
@@ -94,6 +110,8 @@ _Set_IDT(_GETSET_DTR_TYPE *dtr)
|
||||
);
|
||||
}
|
||||
|
||||
#define GET_GDT(var) _Get_GDT(&(var))
|
||||
|
||||
/*
|
||||
* Checked against the Intel manual and GCC --hpreg
|
||||
* volatile because there's a hidden input (the [IG]DTR) that can change
|
||||
@@ -108,6 +126,8 @@ _Get_GDT(_GETSET_DTR_TYPE *dtr)
|
||||
);
|
||||
}
|
||||
|
||||
#define GET_IDT(var) _Get_IDT(&(var))
|
||||
|
||||
/*
|
||||
* Checked against the Intel manual and GCC --hpreg
|
||||
* volatile because the [IG]DT can change without the compiler knowing it
|
||||
@@ -155,6 +175,7 @@ _GET_LDT(Selector * const result)
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Checked against the Intel manual and GCC --thutt */
|
||||
#define _BUILD_SET_R(func, reg) \
|
||||
static INLINE void \
|
||||
func(uintptr_t r) \
|
||||
@@ -165,20 +186,24 @@ _GET_LDT(Selector * const result)
|
||||
: "memory"); \
|
||||
}
|
||||
|
||||
/*
|
||||
* The inline asm is marked 'volatile' because CRs and DRs can change
|
||||
* without the compiler knowing it (when there is a page fault, when a
|
||||
* breakpoint occurs, and moreover it seems there is no way to teach
|
||||
* gcc that smsw clobbers cr0 for example).
|
||||
/* Not yet checked against the Intel manual and GCC --slava
|
||||
*
|
||||
* 'volatile' because CRs and DRs can change without the compiler
|
||||
* knowing it (when there is a page fault, when a breakpoint occurs,
|
||||
* and moreover it seems there is no way to teach gcc that smsw
|
||||
* clobbers cr0 for example).
|
||||
*
|
||||
* The parameter is a 'uintptr_t *' so that the size of the actual
|
||||
* parameter must exactly match the size of the hardware register.
|
||||
* This prevents the use of 32-bit variables when building 64-bit
|
||||
* code.
|
||||
*/
|
||||
#define _BUILD_GET_R(func, reg) \
|
||||
static INLINE uintptr_t \
|
||||
func(void) \
|
||||
static INLINE void \
|
||||
func(uintptr_t *result) \
|
||||
{ \
|
||||
uintptr_t result; \
|
||||
__asm__ __volatile__("mov %%" #reg ", %0" \
|
||||
: "=r" (result)); \
|
||||
return result; \
|
||||
: "=r" (*result)); \
|
||||
}
|
||||
|
||||
_BUILD_SET_R(_SET_CR0, cr0)
|
||||
@@ -193,6 +218,22 @@ _BUILD_GET_R(_GET_CR3, cr3)
|
||||
_BUILD_GET_R(_GET_CR4, cr4)
|
||||
_BUILD_GET_R(_GET_CR8, cr8)
|
||||
|
||||
#if defined __APPLE__
|
||||
/* Mac OS gcc 4 uses DBx instead of DRx register names. */
|
||||
_BUILD_SET_R(_SET_DR0, db0)
|
||||
_BUILD_SET_R(_SET_DR1, db1)
|
||||
_BUILD_SET_R(_SET_DR2, db2)
|
||||
_BUILD_SET_R(_SET_DR3, db3)
|
||||
_BUILD_SET_R(_SET_DR6, db6)
|
||||
_BUILD_SET_R(_SET_DR7, db7)
|
||||
|
||||
_BUILD_GET_R(_GET_DR0, db0)
|
||||
_BUILD_GET_R(_GET_DR1, db1)
|
||||
_BUILD_GET_R(_GET_DR2, db2)
|
||||
_BUILD_GET_R(_GET_DR3, db3)
|
||||
_BUILD_GET_R(_GET_DR6, db6)
|
||||
_BUILD_GET_R(_GET_DR7, db7)
|
||||
#else
|
||||
_BUILD_SET_R(_SET_DR0, dr0)
|
||||
_BUILD_SET_R(_SET_DR1, dr1)
|
||||
_BUILD_SET_R(_SET_DR2, dr2)
|
||||
@@ -206,8 +247,47 @@ _BUILD_GET_R(_GET_DR2, dr2)
|
||||
_BUILD_GET_R(_GET_DR3, dr3)
|
||||
_BUILD_GET_R(_GET_DR6, dr6)
|
||||
_BUILD_GET_R(_GET_DR7, dr7)
|
||||
#endif
|
||||
|
||||
#define SET_CR_DR(regType, regNum, expr) \
|
||||
do { \
|
||||
/* Ensure no implicit truncation of 'expr' */ \
|
||||
ASSERT_ON_COMPILE(sizeof(expr) <= sizeof(uintptr_t)); \
|
||||
_SET_##regType##regNum(expr); \
|
||||
} while (0)
|
||||
|
||||
#define GET_CR_DR(regType, regNum, var) \
|
||||
do { \
|
||||
_GET_##regType##regNum(&(var)); \
|
||||
} while (0)
|
||||
|
||||
#define SET_CR0(expr) SET_CR_DR(CR, 0, expr)
|
||||
#define SET_CR2(expr) SET_CR_DR(CR, 2, expr)
|
||||
#define SET_CR3(expr) SET_CR_DR(CR, 3, expr)
|
||||
#define SET_CR4(expr) SET_CR_DR(CR, 4, expr)
|
||||
#define SET_CR8(expr) SET_CR_DR(CR, 8, expr)
|
||||
|
||||
/* Undefine GET_CR0; it is defined in mach_asm.h for SLES cross-compile */
|
||||
#undef GET_CR0
|
||||
#define GET_CR0(var) GET_CR_DR(CR, 0, var)
|
||||
#define GET_CR2(var) GET_CR_DR(CR, 2, var)
|
||||
#define GET_CR3(var) GET_CR_DR(CR, 3, var)
|
||||
#define GET_CR4(var) GET_CR_DR(CR, 4, var)
|
||||
#define GET_CR8(var) GET_CR_DR(CR, 8, var)
|
||||
|
||||
#define SET_DR0(expr) SET_CR_DR(DR, 0, expr)
|
||||
#define SET_DR1(expr) SET_CR_DR(DR, 1, expr)
|
||||
#define SET_DR2(expr) SET_CR_DR(DR, 2, expr)
|
||||
#define SET_DR3(expr) SET_CR_DR(DR, 3, expr)
|
||||
#define SET_DR6(expr) SET_CR_DR(DR, 6, expr)
|
||||
#define SET_DR7(expr) SET_CR_DR(DR, 7, expr)
|
||||
|
||||
#define GET_DR0(var) GET_CR_DR(DR, 0, var)
|
||||
#define GET_DR1(var) GET_CR_DR(DR, 1, var)
|
||||
#define GET_DR2(var) GET_CR_DR(DR, 2, var)
|
||||
#define GET_DR3(var) GET_CR_DR(DR, 3, var)
|
||||
#define GET_DR6(var) GET_CR_DR(DR, 6, var)
|
||||
#define GET_DR7(var) GET_CR_DR(DR, 7, var)
|
||||
|
||||
#define SET_SEGREG(reg, expr) \
|
||||
do { \
|
||||
@@ -346,200 +426,443 @@ CLTS(void)
|
||||
/* Beginning of the section whose correctness has NOT been checked */
|
||||
#define FNCLEX() __asm__("fnclex" ::);
|
||||
|
||||
/* TLB_INVALIDATE_PAGE is not checked yet */
|
||||
/* TLB_INVALIDATE_xxx are not checked yet */
|
||||
#define TLB_INVALIDATE_PAGE(_addr) do { \
|
||||
__asm__ __volatile__("invlpg %0": :"m" (*(char *) (_addr)):"memory"); \
|
||||
} while (0)
|
||||
|
||||
#define TLB_INVALIDATE_PAGE_OFF_FS(_addr) do { \
|
||||
__asm__ __volatile__("fs; invlpg %0": :"m" (*(char *) (_addr)):"memory"); \
|
||||
} while (0)
|
||||
|
||||
#if ! defined(VMKBOOT)
|
||||
#define RESTORE_FLAGS _Set_flags
|
||||
#define ENABLE_INTERRUPTS() __asm__ __volatile__ ("sti": : :"memory")
|
||||
#define CLEAR_INTERRUPTS() __asm__ __volatile__ ("cli": : :"memory")
|
||||
#endif
|
||||
|
||||
#define RAISE_INTERRUPT(_x) __asm__ __volatile__("int %0" :: "g" (_x))
|
||||
#define RETURN_FROM_INT() __asm__ __volatile__("iret" :: )
|
||||
|
||||
#if ! defined(VMKERNEL) && ! defined(VMKBOOT)
|
||||
#define NO_INTERRUPTS_BEGIN() do { \
|
||||
uintptr_t _flags; \
|
||||
SAVE_FLAGS(_flags); \
|
||||
CLEAR_INTERRUPTS();
|
||||
|
||||
#define NO_INTERRUPTS_END() RESTORE_FLAGS(_flags); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/* End of the section whose correctness has NOT been checked */
|
||||
|
||||
#elif defined _MSC_VER /* !__GNUC__ */
|
||||
|
||||
#define _BUILD_SET_DR(func, reg) \
|
||||
static INLINE void \
|
||||
func(uintptr_t r) \
|
||||
{ \
|
||||
__writedr(reg, r); \
|
||||
}
|
||||
#define SET_IDT(_idt) _Set_IDT(&(_idt))
|
||||
#define SET_GDT(_gdt) _Set_GDT(&(_gdt))
|
||||
#define SET_TR(_tr) _Set_TR(_tr)
|
||||
#define SET_LDT(_tr) _Set_LDT(_tr)
|
||||
|
||||
#define _BUILD_GET_DR(func, reg) \
|
||||
static INLINE uintptr_t \
|
||||
func(void) \
|
||||
{ \
|
||||
return __readdr(reg); \
|
||||
}
|
||||
#define GET_IDT(_idt) _Get_IDT(&(_idt))
|
||||
#define GET_GDT(_gdt) _Get_GDT(&(_gdt))
|
||||
#define GET_TR(_tr) do { _tr = _Get_TR(); } while (0)
|
||||
#define GET_LDT(_tr) do { _tr = _Get_LDT(); } while (0)
|
||||
|
||||
#define _BUILD_SET_CR(func, reg) \
|
||||
static INLINE void \
|
||||
func(uintptr_t r) \
|
||||
{ \
|
||||
__writecr##reg(r); \
|
||||
}
|
||||
|
||||
#define _BUILD_GET_CR(func, reg) \
|
||||
static INLINE uintptr_t \
|
||||
func(void) \
|
||||
{ \
|
||||
return __readcr##reg(); \
|
||||
}
|
||||
|
||||
_BUILD_SET_DR(_SET_DR0, 0)
|
||||
_BUILD_SET_DR(_SET_DR1, 1)
|
||||
_BUILD_SET_DR(_SET_DR2, 2)
|
||||
_BUILD_SET_DR(_SET_DR3, 3)
|
||||
_BUILD_SET_DR(_SET_DR6, 6)
|
||||
_BUILD_SET_DR(_SET_DR7, 7)
|
||||
|
||||
_BUILD_GET_DR(_GET_DR0, 0)
|
||||
_BUILD_GET_DR(_GET_DR1, 1)
|
||||
_BUILD_GET_DR(_GET_DR2, 2)
|
||||
_BUILD_GET_DR(_GET_DR3, 3)
|
||||
_BUILD_GET_DR(_GET_DR6, 6)
|
||||
_BUILD_GET_DR(_GET_DR7, 7)
|
||||
|
||||
_BUILD_SET_CR(_SET_CR0, 0);
|
||||
_BUILD_SET_CR(_SET_CR3, 3);
|
||||
_BUILD_SET_CR(_SET_CR4, 4);
|
||||
_BUILD_SET_CR(_SET_CR8, 8);
|
||||
|
||||
_BUILD_GET_CR(_GET_CR0, 0);
|
||||
_BUILD_GET_CR(_GET_CR2, 2);
|
||||
_BUILD_GET_CR(_GET_CR3, 3);
|
||||
_BUILD_GET_CR(_GET_CR4, 4);
|
||||
_BUILD_GET_CR(_GET_CR8, 8);
|
||||
|
||||
static INLINE void
|
||||
_Set_GDT(_GETSET_DTR_TYPE *dtr)
|
||||
{
|
||||
_lgdt(dtr);
|
||||
#define GET_CR0(_reg) __asm mov eax, cr0 __asm mov _reg, eax
|
||||
#define SET_CR0(_reg) __asm mov eax, _reg __asm mov cr0, eax
|
||||
#define GET_CR2(_reg) __asm mov eax, cr2 __asm mov _reg, eax
|
||||
#define SET_CR2(_reg) __asm mov eax, _reg __asm mov cr2, eax
|
||||
#define GET_CR3(_reg) __asm mov eax, cr3 __asm mov _reg, eax
|
||||
#define SET_CR3(_reg) __asm mov eax, _reg __asm mov cr3, eax
|
||||
/*
|
||||
* MSC doesn't seem to like CR4 in __asm statements. We emit
|
||||
* the opcode for MOV EAX,CR4 = 0xf020e0 and MOV CR4,EAX = 0xf022e0
|
||||
*/
|
||||
#define GET_CR4(_reg) { \
|
||||
__asm _emit 0x0f __asm _emit 0x20 __asm _emit 0xe0 \
|
||||
__asm mov _reg, eax \
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
_Get_GDT(_GETSET_DTR_TYPE *dtr)
|
||||
{
|
||||
_sgdt(dtr);
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
_Set_IDT(_GETSET_DTR_TYPE *dtr)
|
||||
{
|
||||
__lidt(dtr);
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
_Get_IDT(_GETSET_DTR_TYPE *dtr)
|
||||
{
|
||||
__sidt(dtr);
|
||||
#define SET_CR4(_reg) { \
|
||||
__asm mov eax, _reg \
|
||||
__asm _emit 0x0f __asm _emit 0x22 __asm _emit 0xe0 \
|
||||
}
|
||||
|
||||
|
||||
#define ENABLE_INTERRUPTS() _enable()
|
||||
#define CLEAR_INTERRUPTS() _disable()
|
||||
#define GET_DR0(_reg) do { __asm mov eax,dr0 __asm mov _reg,eax } while (0)
|
||||
#define SET_DR0(_reg) do { __asm mov eax,_reg __asm mov dr0,eax } while (0)
|
||||
#define GET_DR1(_reg) do { __asm mov eax,dr1 __asm mov _reg,eax } while (0)
|
||||
#define SET_DR1(_reg) do { __asm mov eax,_reg __asm mov dr1,eax } while (0)
|
||||
#define GET_DR2(_reg) do { __asm mov eax,dr2 __asm mov _reg,eax } while (0)
|
||||
#define SET_DR2(_reg) do { __asm mov eax,_reg __asm mov dr2,eax } while (0)
|
||||
#define GET_DR3(_reg) do { __asm mov eax,dr3 __asm mov _reg,eax } while (0)
|
||||
#define SET_DR3(_reg) do { __asm mov eax,_reg __asm mov dr3,eax } while (0)
|
||||
#define GET_DR6(_reg) do { __asm mov eax,dr6 __asm mov _reg,eax } while (0)
|
||||
#define SET_DR6(_reg) do { __asm mov eax,_reg __asm mov dr6,eax } while (0)
|
||||
#define GET_DR7(_reg) do { __asm mov eax,dr7 __asm mov _reg,eax } while (0)
|
||||
#define SET_DR7(_reg) do { __asm mov eax,_reg __asm mov dr7,eax } while (0)
|
||||
|
||||
#define SAVE_FLAGS(x) do { \
|
||||
(x) = __readeflags(); \
|
||||
} while (0)
|
||||
|
||||
#define RESTORE_FLAGS(x) __writeeflags(x)
|
||||
#define CLTS() __asm clts
|
||||
|
||||
#define FNCLEX() __asm fnclex
|
||||
|
||||
#define TLB_INVALIDATE_PAGE(_addr) { \
|
||||
void *_a = (_addr); \
|
||||
__asm mov eax, _a __asm invlpg [eax] \
|
||||
}
|
||||
|
||||
#define TLB_INVALIDATE_PAGE_OFF_FS(_addr) { \
|
||||
uint32 __a = (uint32) (_addr); \
|
||||
__asm mov eax, __a _asm invlpg fs:[eax] \
|
||||
}
|
||||
|
||||
|
||||
#define ENABLE_INTERRUPTS() { __asm sti }
|
||||
#define CLEAR_INTERRUPTS() { __asm cli }
|
||||
|
||||
#define RAISE_INTERRUPT(_x) {__asm int _x }
|
||||
#define RETURN_FROM_INT() {__asm iretd }
|
||||
|
||||
|
||||
#define SAVE_FLAGS(x) { \
|
||||
__asm pushfd __asm pop eax __asm mov x, eax \
|
||||
}
|
||||
|
||||
#define RESTORE_FLAGS(x) { \
|
||||
__asm push x __asm popfd\
|
||||
}
|
||||
|
||||
|
||||
|
||||
static INLINE void SET_DS(Selector val)
|
||||
{
|
||||
__asm mov ax, val
|
||||
__asm mov ds, ax
|
||||
}
|
||||
|
||||
static INLINE void SET_ES(Selector val)
|
||||
{
|
||||
__asm mov ax, val
|
||||
__asm mov es, ax
|
||||
}
|
||||
|
||||
static INLINE void SET_FS(Selector val)
|
||||
{
|
||||
__asm mov ax, val
|
||||
__asm mov fs, ax
|
||||
}
|
||||
|
||||
static INLINE void SET_GS(Selector val)
|
||||
{
|
||||
__asm mov ax, val
|
||||
__asm mov gs, ax
|
||||
}
|
||||
|
||||
static INLINE void SET_SS(Selector val)
|
||||
{
|
||||
__asm mov ax, val
|
||||
__asm mov ss, ax
|
||||
}
|
||||
|
||||
static INLINE Selector GET_FS(void)
|
||||
{
|
||||
Selector _v;
|
||||
__asm mov _v,fs
|
||||
return _v;
|
||||
}
|
||||
|
||||
static INLINE Selector GET_GS(void)
|
||||
{
|
||||
Selector _v;
|
||||
__asm mov _v,gs
|
||||
return _v;
|
||||
}
|
||||
|
||||
|
||||
static INLINE Selector GET_DS(void)
|
||||
{
|
||||
Selector _v;
|
||||
__asm mov _v,ds
|
||||
return _v;
|
||||
}
|
||||
|
||||
static INLINE Selector GET_ES(void)
|
||||
{
|
||||
Selector _v;
|
||||
__asm mov _v,es
|
||||
return _v;
|
||||
}
|
||||
|
||||
static INLINE Selector GET_SS(void)
|
||||
{
|
||||
Selector _v;
|
||||
__asm mov _v,ss
|
||||
return _v;
|
||||
}
|
||||
|
||||
static INLINE Selector GET_CS(void)
|
||||
{
|
||||
Selector _v;
|
||||
__asm mov _v,cs
|
||||
return _v;
|
||||
}
|
||||
|
||||
#pragma warning( disable : 4035)
|
||||
|
||||
static INLINE uint32 GET_WORD_FROM_FS(uint32 *_addr) {
|
||||
__asm mov eax, _addr
|
||||
__asm mov eax, fs:[eax]
|
||||
}
|
||||
|
||||
static INLINE uint16 GET_SHORT_FROM_FS(uint16 *_addr) {
|
||||
__asm mov eax, _addr
|
||||
__asm mov ax, fs:[eax]
|
||||
}
|
||||
|
||||
static INLINE uint8 GET_BYTE_FROM_FS(uint8 *_addr) {
|
||||
__asm mov eax, _addr
|
||||
__asm mov al, fs:[eax]
|
||||
}
|
||||
|
||||
#pragma warning (default: 4035)
|
||||
|
||||
static INLINE void SET_WORD_FS(uint32 *_addr, uint32 _val) {
|
||||
__asm mov eax, _addr
|
||||
__asm mov ebx, _val
|
||||
__asm mov fs:[eax], ebx
|
||||
}
|
||||
|
||||
static INLINE void SET_SHORT_FS(uint32 *_addr, uint16 _val) {
|
||||
__asm mov eax, _addr
|
||||
__asm mov bx, _val
|
||||
__asm mov fs:[eax], bx
|
||||
}
|
||||
|
||||
static INLINE void SET_BYTE_FS(uint32 *_addr, uint8 _val) {
|
||||
__asm mov eax, _addr
|
||||
__asm mov bl, _val
|
||||
__asm mov fs:[eax], bl
|
||||
}
|
||||
|
||||
static INLINE void _Set_GDT(_GETSET_DTR_TYPE *dtr) {
|
||||
__asm mov eax, dtr
|
||||
__asm lgdt [eax]
|
||||
}
|
||||
|
||||
static INLINE void _Set_IDT(_GETSET_DTR_TYPE *dtr) {
|
||||
__asm mov eax, dtr
|
||||
__asm lidt [eax]
|
||||
}
|
||||
|
||||
static INLINE void _Set_LDT(Selector val)
|
||||
{
|
||||
__asm lldt val
|
||||
}
|
||||
|
||||
static INLINE void _Set_TR(Selector val)
|
||||
{
|
||||
__asm ltr val
|
||||
}
|
||||
|
||||
static INLINE void _Get_GDT(_GETSET_DTR_TYPE *dtr) {
|
||||
__asm mov eax, dtr
|
||||
__asm sgdt [eax]
|
||||
}
|
||||
|
||||
static INLINE void _Get_IDT(_GETSET_DTR_TYPE *dtr) {
|
||||
__asm mov eax, dtr
|
||||
__asm sidt [eax]
|
||||
}
|
||||
|
||||
static INLINE Selector _Get_LDT(void) {
|
||||
Selector sel;
|
||||
__asm sldt sel
|
||||
return sel;
|
||||
}
|
||||
|
||||
static INLINE Selector _Get_TR(void) {
|
||||
Selector sel;
|
||||
__asm str sel
|
||||
return sel;
|
||||
}
|
||||
|
||||
|
||||
static INLINE void
|
||||
MEMCOPY_TO_FS(VA to,
|
||||
char * from,
|
||||
unsigned long n)
|
||||
{
|
||||
unsigned long i =0;
|
||||
while (i+4 <=n) {
|
||||
uint32 x = *(uint32*) (from + i);
|
||||
uint32 _faddr = (uint32) (to+i);
|
||||
__asm mov eax, _faddr
|
||||
__asm mov ebx, x
|
||||
__asm mov fs:[eax], ebx
|
||||
i +=4;
|
||||
}
|
||||
while (i<n) {
|
||||
uint8 x = from[i];
|
||||
uint32 _faddr = (uint32) (to+i);
|
||||
__asm mov eax, _faddr
|
||||
__asm mov bl, x
|
||||
__asm mov fs:[eax], bl
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static INLINE void
|
||||
MEMCOPY_FROM_FS(char * to,
|
||||
VA from,
|
||||
unsigned long n)
|
||||
{
|
||||
unsigned long i =0;
|
||||
while (i+4 <=n) {
|
||||
uint32 x;
|
||||
uint32 _faddr = (uint32)(from+i);
|
||||
__asm mov eax, _faddr
|
||||
__asm mov ebx, fs:[eax]
|
||||
__asm mov x,ebx
|
||||
*(uint32*)(to+i)=x;
|
||||
i +=4;
|
||||
}
|
||||
while (i<n) {
|
||||
uint8 x;
|
||||
uint32 _faddr = (uint32) (from+i);
|
||||
__asm mov eax, _faddr;
|
||||
__asm mov bl, fs:[eax]
|
||||
__asm mov x, bl
|
||||
*(uint8*)(to+i)=x;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#error No compiler defined for get/set
|
||||
#endif /* !__GNUC__ && !_MSC_VER */
|
||||
|
||||
|
||||
#define SET_CR_DR(regType, regNum, expr) \
|
||||
do { \
|
||||
/* Ensure no implicit truncation of 'expr' */ \
|
||||
ASSERT_ON_COMPILE(sizeof(expr) <= sizeof(uintptr_t)); \
|
||||
_SET_##regType##regNum(expr); \
|
||||
} while (0)
|
||||
|
||||
#define GET_CR_DR(regType, regNum, var) \
|
||||
do { \
|
||||
var = _GET_##regType##regNum(); \
|
||||
} while (0)
|
||||
|
||||
#define SET_DR0(expr) SET_CR_DR(DR, 0, expr)
|
||||
#define SET_DR1(expr) SET_CR_DR(DR, 1, expr)
|
||||
#define SET_DR2(expr) SET_CR_DR(DR, 2, expr)
|
||||
#define SET_DR3(expr) SET_CR_DR(DR, 3, expr)
|
||||
#define SET_DR6(expr) SET_CR_DR(DR, 6, expr)
|
||||
#define SET_DR7(expr) SET_CR_DR(DR, 7, expr)
|
||||
|
||||
#define GET_DR0(var) GET_CR_DR(DR, 0, var)
|
||||
#define GET_DR1(var) GET_CR_DR(DR, 1, var)
|
||||
#define GET_DR2(var) GET_CR_DR(DR, 2, var)
|
||||
#define GET_DR3(var) GET_CR_DR(DR, 3, var)
|
||||
#define GET_DR6(var) GET_CR_DR(DR, 6, var)
|
||||
#define GET_DR7(var) GET_CR_DR(DR, 7, var)
|
||||
|
||||
/* Undefine GET_CR0; it is defined in mach_asm.h for SLES cross-compile */
|
||||
#undef GET_CR0
|
||||
#define GET_CR0(var) GET_CR_DR(CR, 0, var)
|
||||
#define GET_CR2(var) GET_CR_DR(CR, 2, var)
|
||||
#define GET_CR3(var) GET_CR_DR(CR, 3, var)
|
||||
#define GET_CR4(var) GET_CR_DR(CR, 4, var)
|
||||
#define GET_CR8(var) GET_CR_DR(CR, 8, var)
|
||||
|
||||
#define SET_CR0(expr) SET_CR_DR(CR, 0, expr)
|
||||
#define SET_CR3(expr) SET_CR_DR(CR, 3, expr)
|
||||
#define SET_CR4(expr) SET_CR_DR(CR, 4, expr)
|
||||
#define SET_CR8(expr) SET_CR_DR(CR, 8, expr)
|
||||
|
||||
/*
|
||||
* When the ULM macro-defines INTERRUPTS_ENABLED, attempting to define
|
||||
* it as a function produces hard-to-diagnose compile-time errors.
|
||||
*/
|
||||
#if !defined(ULM) && !defined(INTERRUPTS_ENABLED)
|
||||
static INLINE Bool
|
||||
INTERRUPTS_ENABLED(void)
|
||||
{
|
||||
uintptr_t flags;
|
||||
SAVE_FLAGS(flags);
|
||||
return ((flags & EFLAGS_IF) != 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* [GS]ET_[GI]DT() are defined as macros wrapping a function
|
||||
* so we can pass the argument implicitly by reference (requires
|
||||
* a macro) and get type checking too (requires a function).
|
||||
*/
|
||||
|
||||
#define SET_GDT(_gdt) _Set_GDT(&(_gdt))
|
||||
#define GET_GDT(_gdt) _Get_GDT(&(_gdt))
|
||||
|
||||
#define SET_IDT(_idt) _Set_IDT(&(_idt))
|
||||
#define GET_IDT(_idt) _Get_IDT(&(_idt))
|
||||
|
||||
#if !defined(VMKERNEL)
|
||||
#define NO_INTERRUPTS_BEGIN() do { \
|
||||
uintptr_t _flags; \
|
||||
SAVE_FLAGS(_flags); \
|
||||
CLEAR_INTERRUPTS();
|
||||
|
||||
#define NO_INTERRUPTS_END() RESTORE_FLAGS(_flags); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined (__GNUC__)
|
||||
static INLINE unsigned
|
||||
CURRENT_CPL(void)
|
||||
#ifdef __GNUC__
|
||||
static INLINE unsigned CURRENT_CPL(void)
|
||||
{
|
||||
return SELECTOR_RPL(GET_CS());
|
||||
}
|
||||
#elif defined _MSC_VER
|
||||
static INLINE unsigned CURRENT_CPL(void) {
|
||||
volatile Selector _v;
|
||||
__asm mov ax, cs _asm mov _v, ax
|
||||
return SELECTOR_RPL(_v);
|
||||
}
|
||||
#else
|
||||
#error No compiler defined for CURRENT_CPL
|
||||
#endif
|
||||
|
||||
|
||||
static INLINE uint64
|
||||
RDPMC(int counter)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
/* Checked against the Intel manual and GCC --hpreg
|
||||
|
||||
volatile because the msr can change without the compiler knowing it
|
||||
(when we use wrmsr). */
|
||||
static INLINE uint64 __GET_MSR(int cx)
|
||||
{
|
||||
uint64 msr;
|
||||
#ifdef VM_X86_64
|
||||
__asm__ __volatile__(
|
||||
"rdmsr; shlq $32, %%rdx; orq %%rdx, %%rax"
|
||||
: "=a" (msr)
|
||||
: "c" (cx)
|
||||
: "%rdx"
|
||||
);
|
||||
#else
|
||||
__asm__ __volatile__(
|
||||
"rdmsr"
|
||||
: "=A" (msr)
|
||||
: "c" (cx)
|
||||
);
|
||||
#endif
|
||||
return msr;
|
||||
}
|
||||
#elif defined _MSC_VER
|
||||
#pragma warning( disable : 4035)
|
||||
static INLINE uint64 __GET_MSR(int input)
|
||||
{
|
||||
__asm push ecx
|
||||
__asm mov ecx, input
|
||||
__asm _emit 0x0f __asm _emit 0x32
|
||||
__asm pop ecx
|
||||
}
|
||||
|
||||
static INLINE void __SET_MSR(int input, uint64 val)
|
||||
{
|
||||
uint32 hival = (uint32)(val >> 32);
|
||||
uint32 loval = (uint32)val;
|
||||
__asm push edx
|
||||
__asm push ecx
|
||||
__asm push eax
|
||||
__asm mov eax, loval
|
||||
__asm mov edx, hival
|
||||
__asm mov ecx, input
|
||||
__asm _emit 0x0f __asm _emit 0x30
|
||||
__asm pop eax
|
||||
__asm pop ecx
|
||||
__asm pop edx
|
||||
}
|
||||
#pragma warning (default: 4035)
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
static INLINE void __SET_MSR(int cx, uint64 val)
|
||||
{
|
||||
#ifdef VM_X86_64
|
||||
__asm__ __volatile__(
|
||||
"wrmsr"
|
||||
: /* no outputs */
|
||||
: "a" ((uint32) val), "d" ((uint32)(val >> 32)), "c" (cx)
|
||||
);
|
||||
#else
|
||||
__asm__ __volatile__(
|
||||
"wrmsr"
|
||||
: /* no outputs */
|
||||
: "A" (val),
|
||||
"c" (cx)
|
||||
);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* RDMSR/WRMSR access the 64bit MSRs as two
|
||||
* 32 bit quantities, whereas GET_MSR/SET_MSR
|
||||
* above access the MSRs as one 64bit quantity.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
#undef RDMSR
|
||||
#undef WRMSR
|
||||
#define RDMSR(msrNum, low, high) do { \
|
||||
__asm__ __volatile__( \
|
||||
"rdmsr" \
|
||||
: "=a" (low), "=d" (high) \
|
||||
: "c" (msrNum) \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
#define WRMSR(msrNum, low, high) do { \
|
||||
__asm__ __volatile__( \
|
||||
"wrmsr" \
|
||||
: /* no outputs */ \
|
||||
: "c" (msrNum), \
|
||||
"a" (low), \
|
||||
"d" (high) \
|
||||
); \
|
||||
} while (0)
|
||||
|
||||
static INLINE uint64 RDPMC(int cx)
|
||||
{
|
||||
#ifdef VM_X86_64
|
||||
uint64 pmcLow;
|
||||
uint64 pmcHigh;
|
||||
@@ -547,7 +870,7 @@ RDPMC(int counter)
|
||||
__asm__ __volatile__(
|
||||
"rdpmc"
|
||||
: "=a" (pmcLow), "=d" (pmcHigh)
|
||||
: "c" (counter)
|
||||
: "c" (cx)
|
||||
);
|
||||
|
||||
return pmcHigh << 32 | pmcLow;
|
||||
@@ -557,26 +880,43 @@ RDPMC(int counter)
|
||||
__asm__ __volatile__(
|
||||
"rdpmc"
|
||||
: "=A" (pmc)
|
||||
: "c" (counter)
|
||||
: "c" (cx)
|
||||
);
|
||||
|
||||
return pmc;
|
||||
#endif
|
||||
}
|
||||
#elif defined _MSC_VER
|
||||
return __readpmc(counter);
|
||||
#endif
|
||||
#ifndef VM_X86_64 // XXX Switch to intrinsics with the new 32 and 64-bit compilers.
|
||||
|
||||
static INLINE uint64 RDPMC(int counter)
|
||||
{
|
||||
__asm mov ecx, counter
|
||||
__asm rdpmc
|
||||
}
|
||||
|
||||
static INLINE void WRMSR(uint32 msrNum, uint32 lo, uint32 hi)
|
||||
{
|
||||
__asm mov ecx, msrNum
|
||||
__asm mov eax, lo
|
||||
__asm mov edx, hi
|
||||
__asm wrmsr
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(VMM) || defined(VMKERNEL) || defined(FROBOS) || defined (ULM)
|
||||
static INLINE uint64
|
||||
__XGETBV(int cx)
|
||||
|
||||
#if defined(__GNUC__) && (defined(VMM) || defined(VMKERNEL) || defined(FROBOS))
|
||||
static INLINE uint64 __XGETBV(int cx)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
#ifdef VM_X86_64
|
||||
uint64 lowval, hival;
|
||||
__asm__ __volatile__(
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
".byte 0x0f, 0x01, 0xd0"
|
||||
#else
|
||||
"xgetbv"
|
||||
#endif
|
||||
: "=a" (lowval), "=d" (hival)
|
||||
: "c" (cx)
|
||||
);
|
||||
@@ -584,91 +924,75 @@ __XGETBV(int cx)
|
||||
#else
|
||||
uint64 val;
|
||||
__asm__ __volatile__(
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
".byte 0x0f, 0x01, 0xd0"
|
||||
#else
|
||||
"xgetbv"
|
||||
#endif
|
||||
: "=A" (val)
|
||||
: "c" (cx)
|
||||
);
|
||||
return val;
|
||||
#endif
|
||||
#elif defined _MSC_VER
|
||||
return _xgetbv((unsigned)cx);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
__XSETBV(int cx, uint64 val)
|
||||
static INLINE void __XSETBV(int cx, uint64 val)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__(
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
".byte 0x0f, 0x01, 0xd1"
|
||||
#else
|
||||
"xsetbv"
|
||||
#endif
|
||||
: /* no outputs */
|
||||
: "a" ((uint32)val), "d" ((uint32)(val >> 32)), "c" (cx)
|
||||
);
|
||||
#elif defined _MSC_VER
|
||||
_xsetbv((unsigned)cx, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE uint64
|
||||
GET_XCR0(void)
|
||||
static INLINE uint64 GET_XCR0(void)
|
||||
{
|
||||
return __XGETBV(0);
|
||||
}
|
||||
|
||||
#define SET_XCR0(val) __XSETBV(0, val)
|
||||
|
||||
static INLINE void
|
||||
SET_XCR0_IF_NEEDED(uint64 newVal, uint64 oldVal)
|
||||
static INLINE void SET_XCR0_IF_NEEDED(uint64 newVal, uint64 oldVal)
|
||||
{
|
||||
#ifndef VMM_BOOTSTRAP
|
||||
ASSERT(oldVal == GET_XCR0());
|
||||
if (newVal != oldVal) {
|
||||
SET_XCR0(newVal);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static INLINE uint32
|
||||
RDTSCP_AuxOnly(void)
|
||||
#define START_TRACING() { \
|
||||
uintptr_t flags; \
|
||||
SAVE_FLAGS(flags); \
|
||||
flags |= EFLAGS_TF; \
|
||||
RESTORE_FLAGS(flags); \
|
||||
}
|
||||
|
||||
#define STOP_TRACING() { \
|
||||
uintptr_t flags; \
|
||||
SAVE_FLAGS(flags); \
|
||||
flags &= ~EFLAGS_TF; \
|
||||
RESTORE_FLAGS(flags); \
|
||||
}
|
||||
|
||||
|
||||
static INLINE Bool
|
||||
INTERRUPTS_ENABLED(void)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
uint32 tscLow, tscHigh, tscAux;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"rdtscp"
|
||||
: "=a" (tscLow), "=d" (tscHigh), "=c" (tscAux)
|
||||
);
|
||||
|
||||
return tscAux;
|
||||
#elif defined _MSC_VER
|
||||
uint32 tscAux;
|
||||
|
||||
__rdtscp(&tscAux);
|
||||
|
||||
return tscAux;
|
||||
#endif
|
||||
uintptr_t flags;
|
||||
SAVE_FLAGS(flags);
|
||||
return ((flags & EFLAGS_IF) != 0);
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint64
|
||||
RDTSCP(void)
|
||||
static INLINE void
|
||||
SET_KERNEL_PER_CORE(uint64 val)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
uint32 tscLow, tscHigh, tscAux;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"rdtscp"
|
||||
:"=a" (tscLow), "=d" (tscHigh), "=c" (tscAux)
|
||||
);
|
||||
|
||||
return QWORD(tscHigh, tscLow);
|
||||
#elif defined _MSC_VER
|
||||
uint32 tscAux;
|
||||
|
||||
return __rdtscp(&tscAux);
|
||||
#endif
|
||||
__SET_MSR(MSR_GSBASE, val);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,136 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* vm_asm_x86_64.h
|
||||
*
|
||||
* x86-64 asm macros
|
||||
*/
|
||||
|
||||
#ifndef _VM_ASM_X86_64_H_
|
||||
#define _VM_ASM_X86_64_H_
|
||||
|
||||
|
||||
#define INCLUDE_ALLOW_VMX
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMK_MODULE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_DISTRIBUTE
|
||||
#include "includeCheck.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include "vm_asm_x86.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file contains inline assembly routines used by x86_64 code.
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
/* nop; prevents #error for no compiler definition from firing */
|
||||
|
||||
#elif defined _MSC_VER /* !__GNUC__ */
|
||||
|
||||
/*
|
||||
* x86-64 windows doesn't support inline asm so we have to use these
|
||||
* intrinsic functions defined in the compiler. Not all of these are well
|
||||
* documented. There is an array in the compiler dll (c1.dll) which has
|
||||
* an array of the names of all the intrinsics minus the leading
|
||||
* underscore. Searching around in the ntddk.h file can also be helpful.
|
||||
*
|
||||
* The declarations for the intrinsic functions were taken from the DDK.
|
||||
* Our declarations must match the ddk's otherwise the 64-bit c++ compiler
|
||||
* will complain about second linkage of the intrinsic functions.
|
||||
* We define the intrinsic using the basic types corresponding to the
|
||||
* Windows typedefs. This avoids having to include windows header files
|
||||
* to get to the windows types.
|
||||
*/
|
||||
|
||||
#ifdef _WIN64
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
unsigned __int64 __readmsr(unsigned long);
|
||||
void __writemsr(unsigned long, unsigned __int64);
|
||||
#pragma intrinsic(__readmsr, __writemsr)
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static INLINE uint64
|
||||
RDPMC(int counter)
|
||||
{
|
||||
return __readpmc(counter);
|
||||
}
|
||||
|
||||
|
||||
static INLINE void
|
||||
WRMSR(uint32 msrNum, uint32 lo, uint32 hi)
|
||||
{
|
||||
uint64 value = QWORD(hi, lo);
|
||||
__writemsr(msrNum, value);
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint64
|
||||
__GET_MSR(int input)
|
||||
{
|
||||
return __readmsr((unsigned long)input);
|
||||
}
|
||||
|
||||
|
||||
static INLINE void
|
||||
__SET_MSR(int cx, uint64 val)
|
||||
{
|
||||
__writemsr((unsigned long)cx, (unsigned __int64)val);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error No compiler defined for get/set
|
||||
#endif /* !__GNUC__ && !_MSC_VER */
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
static INLINE void
|
||||
SWAPGS(void)
|
||||
{
|
||||
__asm__ __volatile__("swapgs");
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint64
|
||||
RDTSCP_AuxOnly(void)
|
||||
{
|
||||
uint64 tscLow, tscHigh, tscAux;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"rdtscp"
|
||||
: "=a" (tscLow), "=d" (tscHigh), "=c" (tscAux)
|
||||
);
|
||||
|
||||
return tscAux;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -67,6 +67,7 @@ extern "C" {
|
||||
#if defined (VMKPANIC)
|
||||
#include "vmk_assert.h"
|
||||
#else /* !VMKPANIC */
|
||||
#include <linux/kernel.h>
|
||||
#define _ASSERT_PANIC(name) \
|
||||
Panic(_##name##Fmt "\n", __FILE__, __LINE__)
|
||||
#define _ASSERT_PANIC_BUG(bug, name) \
|
||||
@@ -99,15 +100,26 @@ void Warning(const char *fmt, ...) PRINTF_DECL(1, 2);
|
||||
#if defined VMKPANIC
|
||||
void Panic_SaveRegs(void);
|
||||
|
||||
#ifdef VMX86_DEBUG
|
||||
void Panic_NoSave(const char *fmt, ...) PRINTF_DECL(1, 2);
|
||||
#else
|
||||
NORETURN void Panic_NoSave(const char *fmt, ...) PRINTF_DECL(1, 2);
|
||||
#endif
|
||||
|
||||
NORETURN void Panic_NoSaveNoReturn(const char *fmt, ...) PRINTF_DECL(1, 2);
|
||||
|
||||
#define Panic(fmt...) do { \
|
||||
Panic_SaveRegs(); \
|
||||
Panic_NoSave(fmt); \
|
||||
} while(0)
|
||||
|
||||
#define Panic_NoReturn(fmt...) do { \
|
||||
Panic_SaveRegs(); \
|
||||
Panic_NoSaveNoReturn(fmt); \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
NORETURN void Panic(const char *fmt, ...) PRINTF_DECL(1, 2);
|
||||
#define Panic panic
|
||||
#endif
|
||||
|
||||
void LogThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3);
|
||||
@@ -165,6 +177,8 @@ void WarningThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3);
|
||||
|
||||
#define ASSERT_NOT_IMPLEMENTED(cond) \
|
||||
ASSERT_IFNOT(cond, NOT_IMPLEMENTED())
|
||||
#define ASSERT_NOT_IMPLEMENTED_BUG(bug, cond) \
|
||||
ASSERT_IFNOT(cond, NOT_IMPLEMENTED_BUG(bug))
|
||||
|
||||
#if defined VMKPANIC || defined VMM
|
||||
#define NOT_IMPLEMENTED() _ASSERT_PANIC_NORETURN(AssertNotImplemented)
|
||||
@@ -189,8 +203,10 @@ void WarningThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3);
|
||||
ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertMemAlloc))
|
||||
|
||||
#ifdef VMX86_DEVEL
|
||||
#define ASSERT_DEVEL(cond) ASSERT(cond)
|
||||
#define NOT_TESTED() Warning(_AssertNotTestedFmt "\n", __FILE__, __LINE__)
|
||||
#else
|
||||
#define ASSERT_DEVEL(cond) ((void)0)
|
||||
#define NOT_TESTED() Log(_AssertNotTestedFmt "\n", __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
@@ -202,12 +218,12 @@ void WarningThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3);
|
||||
|
||||
#define NOT_TESTED_1024() \
|
||||
do { \
|
||||
static MONITOR_ONLY(PERVCPU) uint16 count = 0; \
|
||||
static uint16 count = 0; \
|
||||
if (UNLIKELY(count == 0)) { NOT_TESTED(); } \
|
||||
count = (count + 1) & 1023; \
|
||||
} while (0)
|
||||
|
||||
#define LOG_ONCE(...) DO_ONCE(Log(__VA_ARGS__))
|
||||
#define LOG_ONCE(_s) DO_ONCE(Log _s)
|
||||
|
||||
|
||||
/*
|
||||
@@ -290,7 +306,7 @@ void WarningThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3);
|
||||
#define ASSERT_ON_COMPILE(e) \
|
||||
do { \
|
||||
_Static_assert(e, #e); \
|
||||
} while (0)
|
||||
} while (0);
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -314,17 +330,6 @@ void WarningThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3);
|
||||
assertions \
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid generating extra code due to asserts which are required by
|
||||
* Clang static analyzer, e.g. right before a statement would fail, using
|
||||
* the __clang_analyzer__ macro defined only when clang SA is parsing files.
|
||||
*/
|
||||
#ifdef __clang_analyzer__
|
||||
#define ANALYZER_ASSERT(cond) ASSERT(cond)
|
||||
#else
|
||||
#define ANALYZER_ASSERT(cond) ((void)0)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
+1167
-1113
File diff suppressed because it is too large.
Load diff
+198
-191
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2003-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2003-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -35,13 +35,6 @@
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
|
||||
#if defined _MSC_VER && !defined BORA_NO_WIN32_INTRINS
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4255) // disable no-prototype() to (void) warning
|
||||
#include <intrin.h>
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "vm_basic_types.h"
|
||||
|
||||
#if defined VM_X86_64
|
||||
@@ -50,22 +43,14 @@
|
||||
#elif defined VM_X86_32
|
||||
#include "vm_basic_asm_x86_common.h"
|
||||
#include "vm_basic_asm_x86.h"
|
||||
#elif defined VM_ARM_32
|
||||
#include "vm_basic_asm_arm32.h"
|
||||
#define MUL64_NO_ASM 1
|
||||
#include "mul64.h"
|
||||
#elif defined VM_ARM_64
|
||||
#include "arm64_basic_defs.h"
|
||||
#include "vm_basic_asm_arm64.h"
|
||||
#else
|
||||
#define MUL64_NO_ASM 1
|
||||
#include "mul64.h"
|
||||
#endif
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Locate most and least significant bit set functions. Use our own name
|
||||
* space to avoid namespace collisions. The new names follow a pattern,
|
||||
@@ -227,9 +212,8 @@ mssb64_0(const uint64 value)
|
||||
#endif
|
||||
|
||||
static INLINE int
|
||||
lssb32_0(uint32 v)
|
||||
lssb32_0(uint32 value)
|
||||
{
|
||||
int value = (int)v;
|
||||
#ifdef USE_ARCH_X86_CUSTOM
|
||||
if (!__builtin_constant_p(value)) {
|
||||
if (UNLIKELY(value == 0)) {
|
||||
@@ -269,10 +253,8 @@ mssb32_0(uint32 value)
|
||||
}
|
||||
|
||||
static INLINE int
|
||||
lssb64_0(const uint64 v)
|
||||
lssb64_0(const uint64 value)
|
||||
{
|
||||
int64 value = (int64)v;
|
||||
|
||||
#ifdef USE_ARCH_X86_CUSTOM
|
||||
if (!__builtin_constant_p(value)) {
|
||||
if (UNLIKELY(value == 0)) {
|
||||
@@ -382,10 +364,10 @@ lssbPtr_0(const uintptr_t value)
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE unsigned
|
||||
static INLINE int
|
||||
lssbPtr(const uintptr_t value)
|
||||
{
|
||||
return (unsigned)lssbPtr_0(value) + 1;
|
||||
return lssbPtr_0(value) + 1;
|
||||
}
|
||||
|
||||
static INLINE int
|
||||
@@ -398,34 +380,34 @@ mssbPtr_0(const uintptr_t value)
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE unsigned
|
||||
static INLINE int
|
||||
mssbPtr(const uintptr_t value)
|
||||
{
|
||||
return (unsigned)mssbPtr_0(value) + 1;
|
||||
return mssbPtr_0(value) + 1;
|
||||
}
|
||||
|
||||
static INLINE unsigned
|
||||
static INLINE int
|
||||
lssb32(const uint32 value)
|
||||
{
|
||||
return (unsigned)lssb32_0(value) + 1;
|
||||
return lssb32_0(value) + 1;
|
||||
}
|
||||
|
||||
static INLINE unsigned
|
||||
static INLINE int
|
||||
mssb32(const uint32 value)
|
||||
{
|
||||
return (unsigned)mssb32_0(value) + 1;
|
||||
return mssb32_0(value) + 1;
|
||||
}
|
||||
|
||||
static INLINE unsigned
|
||||
static INLINE int
|
||||
lssb64(const uint64 value)
|
||||
{
|
||||
return (unsigned)lssb64_0(value) + 1;
|
||||
return lssb64_0(value) + 1;
|
||||
}
|
||||
|
||||
static INLINE unsigned
|
||||
static INLINE int
|
||||
mssb64(const uint64 value)
|
||||
{
|
||||
return (unsigned)mssb64_0(value) + 1;
|
||||
return mssb64_0(value) + 1;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
@@ -506,7 +488,7 @@ uint16set(void *dst, uint16 val, size_t count)
|
||||
"strh %w2, [%0]\n"
|
||||
"4:"
|
||||
: "+r" (tmpDst), "+r" (count), "+r" (tmpVal)
|
||||
: "r" ((uint64)val)
|
||||
: "r" (val)
|
||||
: "cc", "memory");
|
||||
#else
|
||||
size_t dummy0;
|
||||
@@ -559,7 +541,6 @@ uint32set(void *dst, uint32 val, size_t count)
|
||||
: "cc", "memory");
|
||||
#elif defined(VM_ARM_64)
|
||||
void *tmpDst = dst;
|
||||
uint64 tmpVal = val;
|
||||
|
||||
if (count == 0) {
|
||||
return dst;
|
||||
@@ -596,7 +577,7 @@ uint32set(void *dst, uint32 val, size_t count)
|
||||
"cbz %1, 4f\n\t"
|
||||
"str %w2, [%0]\n\t" // No incr
|
||||
"4:"
|
||||
: "+r" (tmpDst), "+r" (count), "+r" (tmpVal)
|
||||
: "+r" (tmpDst), "+r" (count), "+r" (val)
|
||||
:
|
||||
: "cc", "memory");
|
||||
#else
|
||||
@@ -640,12 +621,16 @@ uint32set(void *dst, uint32 val, size_t count)
|
||||
static INLINE void *
|
||||
uint16set(void *dst, uint16 val, size_t count)
|
||||
{
|
||||
#ifdef VM_X86_ANY
|
||||
#ifdef VM_X86_64
|
||||
__stosw((uint16*)dst, val, count);
|
||||
#else
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
((uint16 *)dst)[i] = val;
|
||||
__asm { pushf;
|
||||
mov ax, val;
|
||||
mov ecx, count;
|
||||
mov edi, dst;
|
||||
cld;
|
||||
rep stosw;
|
||||
popf;
|
||||
}
|
||||
#endif
|
||||
return dst;
|
||||
@@ -654,12 +639,16 @@ uint16set(void *dst, uint16 val, size_t count)
|
||||
static INLINE void *
|
||||
uint32set(void *dst, uint32 val, size_t count)
|
||||
{
|
||||
#ifdef VM_X86_ANY
|
||||
#ifdef VM_X86_64
|
||||
__stosd((unsigned long*)dst, (unsigned long)val, count);
|
||||
#else
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
((uint32 *)dst)[i] = val;
|
||||
__asm { pushf;
|
||||
mov eax, val;
|
||||
mov ecx, count;
|
||||
mov edi, dst;
|
||||
cld;
|
||||
rep stosd;
|
||||
popf;
|
||||
}
|
||||
#endif
|
||||
return dst;
|
||||
@@ -684,7 +673,7 @@ static INLINE uint16
|
||||
Bswap16(uint16 v)
|
||||
{
|
||||
#if defined(VM_ARM_64)
|
||||
__asm__("rev16 %w0, %w0" : "+r"(v));
|
||||
__asm__("rev16 %0, %0" : "+r"(v));
|
||||
return v;
|
||||
#else
|
||||
return ((v >> 8) & 0x00ff) | ((v << 8) & 0xff00);
|
||||
@@ -713,12 +702,12 @@ Bswap32(uint32 v) // IN
|
||||
: "0" (v)
|
||||
);
|
||||
return v;
|
||||
#elif defined(VM_ARM_32) && !defined(__ANDROID__) && !defined(_MSC_VER)
|
||||
#elif defined(VM_ARM_32) && !defined(__ANDROID__)
|
||||
__asm__("rev %0, %0" : "+r"(v));
|
||||
return v;
|
||||
#elif defined(VM_ARM_64)
|
||||
__asm__("rev32 %x0, %x0" : "+r"(v));
|
||||
return v;
|
||||
__asm__("rev32 %0, %0" : "+r"(v));
|
||||
return v;
|
||||
#else
|
||||
return (v >> 24)
|
||||
| ((v >> 8) & 0xFF00)
|
||||
@@ -751,6 +740,63 @@ Bswap64(uint64 v) // IN
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* COMPILER_MEM_BARRIER prevents the compiler from re-ordering memory
|
||||
* references accross the barrier. NOTE: It does not generate any
|
||||
* instruction, so the CPU is free to do whatever it wants to...
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
#define COMPILER_MEM_BARRIER() __asm__ __volatile__ ("": : :"memory")
|
||||
#define COMPILER_READ_BARRIER() COMPILER_MEM_BARRIER()
|
||||
#define COMPILER_WRITE_BARRIER() COMPILER_MEM_BARRIER()
|
||||
#elif defined(_MSC_VER)
|
||||
#define COMPILER_MEM_BARRIER() _ReadWriteBarrier()
|
||||
#define COMPILER_READ_BARRIER() _ReadBarrier()
|
||||
#define COMPILER_WRITE_BARRIER() _WriteBarrier()
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* COMPILER_FORCED_LOAD_AND_MEM_BARRIER --
|
||||
*
|
||||
* This macro prevents the compiler from re-ordering memory references
|
||||
* across the barrier. In addition it emits a forced load from the given
|
||||
* memory reference. The memory reference has to be either 1, 2, 4 or 8
|
||||
* bytes wide.
|
||||
* The forced load of a memory reference can be used exploit details of a
|
||||
* given CPUs memory model. For example x86 CPUs won't reorder stores to
|
||||
* a memory location x with loads from a memory location x.
|
||||
* NOTE: It does not generate any fencing instruction, so the CPU is free
|
||||
* to reorder instructions according to its memory model.
|
||||
*
|
||||
* Results:
|
||||
* None
|
||||
*
|
||||
* Side Effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef VM_X86_64
|
||||
#ifdef __GNUC__
|
||||
|
||||
#define COMPILER_FORCED_LOAD_AND_MEM_BARRIER(_memory_reference) \
|
||||
do { \
|
||||
typeof(_memory_reference) _dummy; \
|
||||
\
|
||||
asm volatile("mov %1, %0\n\t" \
|
||||
: "=r" (_dummy) /* Let compiler choose reg for _dummy */ \
|
||||
: "m" (_memory_reference) \
|
||||
: "memory"); \
|
||||
} while(0)
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* VM_X86_64 */
|
||||
|
||||
|
||||
/*
|
||||
* PAUSE is a P4 instruction that improves spinlock power+performance;
|
||||
* on non-P4 IA32 systems, the encoding is interpreted as a REPZ-NOP.
|
||||
@@ -758,23 +804,29 @@ Bswap64(uint64 v) // IN
|
||||
*/
|
||||
static INLINE void
|
||||
PAUSE(void)
|
||||
#if defined(__GNUC__) || defined(VM_ARM_32)
|
||||
#ifdef __GNUC__
|
||||
{
|
||||
#ifdef VM_ARM_64
|
||||
__asm__ __volatile__("yield");
|
||||
#elif defined VM_ARM_32
|
||||
#ifdef VM_ARM_ANY
|
||||
/*
|
||||
* YIELD is available in ARMv6K and above, so we could probably refine this
|
||||
* instead of leaving it empty.
|
||||
* ARM has no instruction to execute "spin-wait loop", just leave it
|
||||
* empty.
|
||||
*/
|
||||
#else // x86
|
||||
#else
|
||||
__asm__ __volatile__( "pause" :);
|
||||
#endif
|
||||
}
|
||||
#elif defined(_MSC_VER)
|
||||
#ifdef VM_X86_64
|
||||
{
|
||||
_mm_pause();
|
||||
}
|
||||
#else /* VM_X86_64 */
|
||||
#pragma warning( disable : 4035)
|
||||
{
|
||||
__asm _emit 0xf3 __asm _emit 0x90
|
||||
}
|
||||
#pragma warning (default: 4035)
|
||||
#endif /* VM_X86_64 */
|
||||
#else /* __GNUC__ */
|
||||
#error No compiler defined for PAUSE
|
||||
#endif
|
||||
@@ -822,20 +874,17 @@ RDTSC(void)
|
||||
#endif
|
||||
}
|
||||
#elif defined(_MSC_VER)
|
||||
#ifdef VM_X86_ANY
|
||||
#ifdef VM_X86_64
|
||||
{
|
||||
return __rdtsc();
|
||||
}
|
||||
#else
|
||||
#pragma warning( disable : 4035)
|
||||
{
|
||||
/*
|
||||
* We need to do more inverstagetion here to find
|
||||
* a microsoft equivalent of that code
|
||||
*/
|
||||
NOT_IMPLEMENTED();
|
||||
return 0;
|
||||
__asm _emit 0x0f __asm _emit 0x31
|
||||
}
|
||||
#endif /* VM_X86_ANY */
|
||||
#pragma warning (default: 4035)
|
||||
#endif /* VM_X86_64 */
|
||||
#else /* __GNUC__ */
|
||||
#error No compiler defined for RDTSC
|
||||
#endif /* __GNUC__ */
|
||||
@@ -868,7 +917,7 @@ RDTSC(void)
|
||||
*
|
||||
* {Clear,Set,Test}Bit{32,64} --
|
||||
*
|
||||
* Sets tests or clears a specified single bit in the provided variable.
|
||||
* Sets or clears a specified single bit in the provided variable.
|
||||
*
|
||||
* The index input value specifies which bit to modify and is 0-based.
|
||||
* Index is truncated by hardware to a 5-bit or 6-bit offset for the
|
||||
@@ -882,39 +931,111 @@ RDTSC(void)
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
SetBit32(uint32 *var, unsigned index)
|
||||
SetBit32(uint32 *var, uint32 index)
|
||||
{
|
||||
*var |= 1 << index;
|
||||
#if defined(__GNUC__) && defined(VM_X86_ANY)
|
||||
__asm__ (
|
||||
"bts %1, %0"
|
||||
: "+mr" (*var)
|
||||
: "rI" (index)
|
||||
: "cc"
|
||||
);
|
||||
#elif defined(_MSC_VER)
|
||||
_bittestandset((long *)var, index);
|
||||
#else
|
||||
*var |= (1 << index);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
ClearBit32(uint32 *var, unsigned index)
|
||||
ClearBit32(uint32 *var, uint32 index)
|
||||
{
|
||||
#if defined(__GNUC__) && defined(VM_X86_ANY)
|
||||
__asm__ (
|
||||
"btr %1, %0"
|
||||
: "+mr" (*var)
|
||||
: "rI" (index)
|
||||
: "cc"
|
||||
);
|
||||
#elif defined(_MSC_VER)
|
||||
_bittestandreset((long *)var, index);
|
||||
#else
|
||||
*var &= ~(1 << index);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
SetBit64(uint64 *var, unsigned index)
|
||||
SetBit64(uint64 *var, uint64 index)
|
||||
{
|
||||
*var |= CONST64U(1) << index;
|
||||
#if defined(VM_64BIT) && !defined(VM_ARM_64)
|
||||
#ifdef __GNUC__
|
||||
__asm__ (
|
||||
"bts %1, %0"
|
||||
: "+mr" (*var)
|
||||
: "rJ" (index)
|
||||
: "cc"
|
||||
);
|
||||
#elif defined(_MSC_VER)
|
||||
_bittestandset64((__int64 *)var, index);
|
||||
#endif
|
||||
#else
|
||||
*var |= ((uint64)1 << index);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
ClearBit64(uint64 *var, unsigned index)
|
||||
ClearBit64(uint64 *var, uint64 index)
|
||||
{
|
||||
*var &= ~(CONST64U(1) << index);
|
||||
#if defined(VM_64BIT) && !defined(VM_ARM_64)
|
||||
#ifdef __GNUC__
|
||||
__asm__ (
|
||||
"btrq %1, %0"
|
||||
: "+mr" (*var)
|
||||
: "rJ" (index)
|
||||
: "cc"
|
||||
);
|
||||
#elif defined(_MSC_VER)
|
||||
_bittestandreset64((__int64 *)var, index);
|
||||
#endif
|
||||
#else
|
||||
*var &= ~((uint64)1 << index);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
TestBit32(const uint32 *var, unsigned index)
|
||||
TestBit32(const uint32 *var, uint32 index)
|
||||
{
|
||||
#if defined(__GNUC__) && defined(VM_X86_ANY)
|
||||
Bool bit;
|
||||
__asm__ (
|
||||
"bt %[index], %[var] \n"
|
||||
"setc %[bit]"
|
||||
: [bit] "=qQm" (bit)
|
||||
: [index] "rI" (index), [var] "r" (*var)
|
||||
: "cc"
|
||||
);
|
||||
return bit;
|
||||
#else
|
||||
return (*var & (1 << index)) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
TestBit64(const uint64 *var, unsigned index)
|
||||
TestBit64(const uint64 *var, uint64 index)
|
||||
{
|
||||
#if defined __GNUC__ && defined VM_X86_64
|
||||
Bool bit;
|
||||
__asm__ (
|
||||
"bt %[index], %[var] \n"
|
||||
"setc %[bit]"
|
||||
: [bit] "=qQm" (bit)
|
||||
: [index] "rJ" (index), [var] "r" (*var)
|
||||
: "cc"
|
||||
);
|
||||
return bit;
|
||||
#else
|
||||
return (*var & (CONST64U(1) << index)) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -964,7 +1085,7 @@ ClearBitVector(void *var, int32 index)
|
||||
"setc %0"
|
||||
: "=qQm" (bit), "+m" (*(uint32 *)var)
|
||||
: "rI" (index)
|
||||
: "memory", "cc"
|
||||
: "cc"
|
||||
);
|
||||
return bit;
|
||||
#elif defined(_MSC_VER)
|
||||
@@ -986,7 +1107,7 @@ ComplementBitVector(void *var, int32 index)
|
||||
"setc %0"
|
||||
: "=qQm" (bit), "+m" (*(uint32 *)var)
|
||||
: "rI" (index)
|
||||
: "memory", "cc"
|
||||
: "cc"
|
||||
);
|
||||
return bit;
|
||||
#elif defined(_MSC_VER)
|
||||
@@ -1078,9 +1199,7 @@ RoundUpPow2C32(uint32 value)
|
||||
if (value <= 1 || value > (1U << 31)) {
|
||||
return 1; // Match the assembly's undefined value for large inputs.
|
||||
} else {
|
||||
int mssb32 = mssb32_0(value - 1);
|
||||
/* invariant: mssb32 >= 0 */
|
||||
return (2U << (uint32)mssb32);
|
||||
return (2 << mssb32_0(value - 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1135,117 +1254,5 @@ RoundUpPow2_32(uint32 value)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* PopCount32 --
|
||||
*
|
||||
* Counts "1" bits in a uint32.
|
||||
*
|
||||
* Results:
|
||||
* Returns the number of bits set to 1.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE unsigned
|
||||
PopCount32(uint32 value)
|
||||
{
|
||||
#if defined(__GNUC__) && !defined(FEWER_BUILTINS) && defined(__POPCNT__)
|
||||
return __builtin_popcount(value);
|
||||
#else
|
||||
/*
|
||||
* Attribution:
|
||||
* This algorithm was copied from:
|
||||
* http://www.aggregate.org/MAGIC#Population Count (Ones Count)
|
||||
*
|
||||
* A virtually identical version (but in assembly) appears in an
|
||||
* AMD reference manual.
|
||||
*
|
||||
* No license appears in the original code, but the website
|
||||
* header states:
|
||||
*
|
||||
* "None of the following coding tricks came from proprietary
|
||||
* sources; further, we believe that each of the tricks we did
|
||||
* not invent is essentially "standard engineering practice" in
|
||||
* the specialized niche where it applies. Thus, although we
|
||||
* have not conducted patent searches, etc., to confirm it, we
|
||||
* believe that these are tricks that freely can be used for
|
||||
* any purpose. Of course, The Aggregate accepts no
|
||||
* responsibility for your use of these tricks; you must
|
||||
* confirm that the trick does what you want and that you can
|
||||
* use it as you intend. That said, we do intend to maintain
|
||||
* this page by adding new algorithms and/or correcting
|
||||
* existing entries. If you have any comments, please contact
|
||||
* Professor Hank Dietz, http://aggregate.org/hankd/"
|
||||
*
|
||||
* "This document should be cited using something like the
|
||||
* following bibtex entry:" (most recent retrieval date added)
|
||||
*
|
||||
* @techreport{magicalgorithms,
|
||||
* author={Henry Gordon Dietz},
|
||||
* title={{The Aggregate Magic Algorithms}},
|
||||
* institution={University of Kentucky},
|
||||
* howpublished={Aggregate.Org online technical report},
|
||||
* URL={http://aggregate.org/MAGIC/},
|
||||
* urldate={2016-01-27}
|
||||
* }
|
||||
*/
|
||||
value -= ((value >> 1) & 0x55555555);
|
||||
value = (((value >> 2) & 0x33333333) + (value & 0x33333333));
|
||||
value = (((value >> 4) + value) & 0x0f0f0f0f);
|
||||
value += (value >> 8);
|
||||
value += (value >> 16);
|
||||
return value & 0x0000003f;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* PopCount64 --
|
||||
*
|
||||
* Counts "1" bits in a uint64.
|
||||
*
|
||||
* Results:
|
||||
* Returns the number of bits set to 1.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE unsigned
|
||||
PopCount64(uint64 value)
|
||||
{
|
||||
#if defined(__GNUC__) && !defined(FEWER_BUILTINS) && defined(__POPCNT__)
|
||||
#if defined(VM_X86_64)
|
||||
return __builtin_popcountll(value);
|
||||
#else
|
||||
return PopCount32(value) + PopCount32(value >> 32);
|
||||
#endif
|
||||
#else
|
||||
value -= (value >> 1) & 0x5555555555555555ULL;
|
||||
value = ((value >> 2) & 0x3333333333333333ULL) +
|
||||
(value & 0x3333333333333333ULL);
|
||||
value = ((value >> 4) + value) & 0x0f0f0f0f0f0f0f0fULL;
|
||||
value += value >> 8;
|
||||
value += value >> 16;
|
||||
value += value >> 32;
|
||||
return (unsigned) (value & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _VM_BASIC_ASM_H_
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -35,11 +35,6 @@
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef VM_X86_64
|
||||
/*
|
||||
* The gcc inline asm uses the "A" constraint which differs in 32 & 64
|
||||
@@ -52,25 +47,16 @@ extern "C" {
|
||||
* XTEST
|
||||
* Return TRUE if processor is in transaction region.
|
||||
*
|
||||
* Using condition codes as output values (=@ccnz) requires gcc6 or
|
||||
* above. Clang does not support condition codes as output
|
||||
* constraints.
|
||||
*
|
||||
*/
|
||||
#if defined(__GNUC__) && (defined(VMM) || defined(VMKERNEL) || defined(FROBOS))
|
||||
static INLINE Bool
|
||||
xtest(void)
|
||||
{
|
||||
Bool result;
|
||||
#if defined(__clang__)
|
||||
__asm__ __volatile__("xtest\n"
|
||||
"setnz %%al"
|
||||
: "=a" (result) : : "cc");
|
||||
#else
|
||||
__asm__ __volatile__("xtest"
|
||||
: "=@ccnz" (result) : : "cc");
|
||||
#endif
|
||||
return result;
|
||||
uint8 al;
|
||||
__asm__ __volatile__(".byte 0x0f, 0x01, 0xd6 # xtest \n"
|
||||
"setnz %%al\n"
|
||||
: "=a"(al) : : "cc");
|
||||
return al;
|
||||
}
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
@@ -144,32 +130,49 @@ FXRSTOR_AMD_ES0(const void *load)
|
||||
static INLINE void
|
||||
XSAVE_ES1(void *save, uint64 mask)
|
||||
{
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
__asm__ __volatile__ (
|
||||
".byte 0x0f, 0xae, 0x21 \n"
|
||||
:
|
||||
: "c" ((uint8 *)save), "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"xsave %0 \n"
|
||||
: "=m" (*(uint8 *)save)
|
||||
: "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
XSAVEOPT_ES1(void *save, uint64 mask)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
"xsaveopt %0 \n"
|
||||
: "=m" (*(uint8 *)save)
|
||||
: "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
".byte 0x0f, 0xae, 0x31 \n"
|
||||
:
|
||||
: "c" ((uint8 *)save), "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
XRSTOR_ES1(const void *load, uint64 mask)
|
||||
{
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
__asm__ __volatile__ (
|
||||
".byte 0x0f, 0xae, 0x29 \n"
|
||||
:
|
||||
: "c" ((const uint8 *)load),
|
||||
"a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"xrstor %0 \n"
|
||||
:
|
||||
: "m" (*(const uint8 *)load),
|
||||
"a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
@@ -187,10 +190,17 @@ XRSTOR_AMD_ES0(const void *load, uint64 mask)
|
||||
"fildl %0 \n" // Dummy Load from "safe address" changes all
|
||||
// x87 exception pointers.
|
||||
"mov %%ebx, %%eax \n"
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
".byte 0x0f, 0xae, 0x29 \n"
|
||||
:
|
||||
: "m" (dummy), "c" ((const uint8 *)load),
|
||||
"b" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
#else
|
||||
"xrstor %1 \n"
|
||||
:
|
||||
: "m" (dummy), "m" (*(const uint8 *)load),
|
||||
"b" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
#endif
|
||||
: "eax", "memory");
|
||||
}
|
||||
#endif /* __GNUC__ */
|
||||
@@ -400,7 +410,7 @@ Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift)
|
||||
shr edx, cl
|
||||
jmp SHORT l3
|
||||
l2:
|
||||
Xor esi, esi
|
||||
xor esi, esi
|
||||
shrd eax, edx, cl // result = hi(p2):hi(p1):lo(p1) >> shift
|
||||
adc esi, 0 // Get highest order bit shifted out, from CF
|
||||
shrd edx, ebx, cl
|
||||
@@ -521,7 +531,7 @@ Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift)
|
||||
sar edx, cl
|
||||
jmp SHORT l3
|
||||
l2:
|
||||
Xor esi, esi
|
||||
xor esi, esi
|
||||
shrd eax, edx, cl // result = hi(p2):hi(p1):lo(p1) << shift
|
||||
adc esi, 0 // Get highest order bit shifted out, from CF
|
||||
shrd edx, ebx, cl
|
||||
@@ -535,9 +545,4 @@ Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift)
|
||||
#pragma warning(default: 4035)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // _VM_BASIC_ASM_X86_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -39,25 +39,44 @@
|
||||
#error "This file is x86-64 only!"
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(BORA_NO_WIN32_INTRINS)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
uint64 _umul128(uint64 multiplier, uint64 multiplicand,
|
||||
uint64 *highProduct);
|
||||
int64 _mul128(int64 multiplier, int64 multiplicand,
|
||||
int64 *highProduct);
|
||||
uint64 __shiftright128(uint64 lowPart, uint64 highPart, uint8 shift);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma intrinsic(_umul128, _mul128, __shiftright128)
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if defined(__GNUC__)
|
||||
/*
|
||||
* GET_CURRENT_PC
|
||||
* GET_CURRENT_RIP
|
||||
*
|
||||
* Returns the current program counter (i.e. instruction pointer i.e. rip
|
||||
* register on x86_64). In the example below:
|
||||
* Returns the current instruction pointer. In the example below:
|
||||
*
|
||||
* foo.c
|
||||
* L123: Foo(GET_CURRENT_PC())
|
||||
* L123: Foo(GET_CURRENT_RIP())
|
||||
*
|
||||
* the return value from GET_CURRENT_PC will point a debugger to L123.
|
||||
* the return value from GET_CURRENT_RIP will point a debugger to L123.
|
||||
*/
|
||||
#define GET_CURRENT_PC() ({ \
|
||||
#define GET_CURRENT_RIP() ({ \
|
||||
void *__rip; \
|
||||
asm("lea 0(%%rip), %0;\n\t" \
|
||||
: "=r" (__rip)); \
|
||||
__rip; \
|
||||
})
|
||||
|
||||
#define GET_CURRENT_PC() GET_CURRENT_RIP()
|
||||
|
||||
/*
|
||||
* GET_CURRENT_LOCATION
|
||||
*
|
||||
@@ -95,57 +114,40 @@
|
||||
* The workaround (FXRSTOR_AMD_ES0) only costs 1 cycle more than just doing an
|
||||
* fxrstor, on both AMD Opteron and Intel Core CPUs.
|
||||
*/
|
||||
#if defined(__GNUC__)
|
||||
|
||||
#if defined(VMM) || defined(VMKERNEL) || defined(FROBOS) || defined(ULM)
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
FXSAVE_ES1(void *save)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__ ("fxsaveq %0 \n" : "=m" (*(uint8 *)save) : : "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_fxsave64(save);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
FXSAVE_COMPAT_ES1(void *save)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__ ("fxsave %0 \n" : "=m" (*(uint8 *)save) : : "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_fxsave(save);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
FXRSTOR_ES1(const void *load)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__ ("fxrstorq %0 \n"
|
||||
: : "m" (*(const uint8 *)load) : "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_fxrstor64(load);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
FXRSTOR_COMPAT_ES1(const void *load)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__ ("fxrstor %0 \n"
|
||||
: : "m" (*(const uint8 *)load) : "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_fxrstor(load);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
FXRSTOR_AMD_ES0(const void *load)
|
||||
{
|
||||
uint64 dummy = 0;
|
||||
|
||||
__asm__ __volatile__
|
||||
__asm__ __volatile__
|
||||
("fnstsw %%ax \n" // Grab x87 ES bit
|
||||
"bt $7,%%ax \n" // Test ES bit
|
||||
"jnc 1f \n" // Jump if ES=0
|
||||
@@ -169,100 +171,100 @@ FXRSTOR_AMD_ES0(const void *load)
|
||||
* The pointer passed in must be 64-byte aligned.
|
||||
* See above comment for more information.
|
||||
*/
|
||||
#if defined(__GNUC__) && (defined(VMM) || defined(VMKERNEL) || defined(FROBOS))
|
||||
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
XSAVE_ES1(void *save, uint64 mask)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
__asm__ __volatile__ (
|
||||
".byte 0x48, 0x0f, 0xae, 0x21 \n"
|
||||
:
|
||||
: "c" ((uint8 *)save), "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"xsaveq %0 \n"
|
||||
: "=m" (*(uint8 *)save)
|
||||
: "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_xsave64(save, mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
XSAVE_COMPAT_ES1(void *save, uint64 mask)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
__asm__ __volatile__ (
|
||||
".byte 0x0f, 0xae, 0x21 \n"
|
||||
:
|
||||
: "c" ((uint8 *)save), "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"xsave %0 \n"
|
||||
: "=m" (*(uint8 *)save)
|
||||
: "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_xsave(save, mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
XSAVEOPT_ES1(void *save, uint64 mask)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__ (
|
||||
"xsaveoptq %0 \n"
|
||||
: "=m" (*(uint8 *)save)
|
||||
: "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
".byte 0x48, 0x0f, 0xae, 0x31 \n"
|
||||
:
|
||||
: "c" ((uint8 *)save), "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_xsaveopt64(save, mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
XSAVEC_COMPAT_ES1(void *save, uint64 mask)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__ (
|
||||
"xsavec %0 \n"
|
||||
: "=m" (*(uint8 *)save)
|
||||
: "a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_xsavec(save, mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
XRSTOR_ES1(const void *load, uint64 mask)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
__asm__ __volatile__ (
|
||||
".byte 0x48, 0x0f, 0xae, 0x29 \n"
|
||||
:
|
||||
: "c" ((const uint8 *)load),
|
||||
"a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"xrstorq %0 \n"
|
||||
:
|
||||
: "m" (*(const uint8 *)load),
|
||||
"a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_xrstor64(load, mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
XRSTOR_COMPAT_ES1(const void *load, uint64 mask)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
__asm__ __volatile__ (
|
||||
".byte 0x0f, 0xae, 0x29 \n"
|
||||
:
|
||||
: "c" ((const uint8 *)load),
|
||||
"a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#else
|
||||
__asm__ __volatile__ (
|
||||
"xrstor %0 \n"
|
||||
:
|
||||
: "m" (*(const uint8 *)load),
|
||||
"a" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
: "memory");
|
||||
#elif defined(_MSC_VER)
|
||||
_xrstor(load, mask);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__GNUC__)
|
||||
static INLINE void
|
||||
static INLINE void
|
||||
XRSTOR_AMD_ES0(const void *load, uint64 mask)
|
||||
{
|
||||
uint64 dummy = 0;
|
||||
|
||||
__asm__ __volatile__
|
||||
__asm__ __volatile__
|
||||
("fnstsw %%ax \n" // Grab x87 ES bit
|
||||
"bt $7,%%ax \n" // Test ES bit
|
||||
"jnc 1f \n" // Jump if ES=0
|
||||
@@ -272,39 +274,36 @@ XRSTOR_AMD_ES0(const void *load, uint64 mask)
|
||||
"fildl %0 \n" // Dummy Load from "safe address" changes all
|
||||
// x87 exception pointers.
|
||||
"mov %%ebx, %%eax \n"
|
||||
#if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1
|
||||
".byte 0x48, 0x0f, 0xae, 0x29 \n"
|
||||
:
|
||||
: "m" (dummy), "c" ((const uint8 *)load),
|
||||
"b" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
#else
|
||||
"xrstorq %1 \n"
|
||||
:
|
||||
: "m" (dummy), "m" (*(const uint8 *)load),
|
||||
"b" ((uint32)mask), "d" ((uint32)(mask >> 32))
|
||||
#endif
|
||||
: "eax", "memory");
|
||||
}
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* VMM || VMKERNEL || FROBOS || ULM */
|
||||
|
||||
/*
|
||||
* XTEST
|
||||
* Return TRUE if processor is in transaction region.
|
||||
*
|
||||
* Using condition codes as output values (=@ccnz) requires gcc6 or
|
||||
* above. Clang does not support condition codes as output
|
||||
* constraints.
|
||||
*
|
||||
*/
|
||||
#if defined(__GNUC__) && (defined(VMM) || defined(VMKERNEL) || defined(FROBOS))
|
||||
static INLINE Bool
|
||||
xtest(void)
|
||||
{
|
||||
Bool result;
|
||||
#if defined(__clang__)
|
||||
__asm__ __volatile__("xtest\n"
|
||||
"setnz %%al"
|
||||
: "=a" (result) : : "cc");
|
||||
#else
|
||||
__asm__ __volatile__("xtest"
|
||||
: "=@ccnz" (result) : : "cc");
|
||||
#endif
|
||||
return result;
|
||||
uint8 al;
|
||||
__asm__ __volatile__(".byte 0x0f, 0x01, 0xd6 # xtest \n"
|
||||
"setnz %%al\n"
|
||||
: "=a"(al) : : "cc");
|
||||
return al;
|
||||
}
|
||||
|
||||
#endif /* __GNUC__ */
|
||||
@@ -316,7 +315,7 @@ xtest(void)
|
||||
*
|
||||
* Unsigned integer by fixed point multiplication, with rounding:
|
||||
* result = floor(multiplicand * multiplier * 2**(-shift) + 0.5)
|
||||
*
|
||||
*
|
||||
* Unsigned 64-bit integer multiplicand.
|
||||
* Unsigned 64-bit fixed point multiplier, represented as
|
||||
* (multiplier, shift), where shift < 64.
|
||||
@@ -398,7 +397,7 @@ Mul64x6464(uint64 multiplicand,
|
||||
*
|
||||
* Signed integer by fixed point multiplication, with rounding:
|
||||
* result = floor(multiplicand * multiplier * 2**(-shift) + 0.5)
|
||||
*
|
||||
*
|
||||
* Signed 64-bit integer multiplicand.
|
||||
* Unsigned 64-bit fixed point multiplier, represented as
|
||||
* (multiplier, shift), where shift < 64.
|
||||
@@ -483,7 +482,7 @@ Muls64x64s64(int64 multiplicand,
|
||||
*
|
||||
* Unsigned integer by fixed point multiplication, with rounding:
|
||||
* result = floor(multiplicand * multiplier * 2**(-shift) + 0.5)
|
||||
*
|
||||
*
|
||||
* Unsigned 64-bit integer multiplicand.
|
||||
* Unsigned 32-bit fixed point multiplier, represented as
|
||||
* (multiplier, shift), where shift < 64.
|
||||
@@ -507,7 +506,7 @@ Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift)
|
||||
*
|
||||
* Signed integer by fixed point multiplication, with rounding:
|
||||
* result = floor(multiplicand * multiplier * 2**(-shift) + 0.5)
|
||||
*
|
||||
*
|
||||
* Signed 64-bit integer multiplicand.
|
||||
* Unsigned 32-bit fixed point multiplier, represented as
|
||||
* (multiplier, shift), where shift < 64.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2013-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2013 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -38,6 +38,94 @@
|
||||
#error "Should be included only in x86 builds"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* x86-64 windows doesn't support inline asm so we have to use these
|
||||
* intrinsic functions defined in the compiler. Not all of these are well
|
||||
* documented. There is an array in the compiler dll (c1.dll) which has
|
||||
* an array of the names of all the intrinsics minus the leading
|
||||
* underscore. Searching around in the ntddk.h file can also be helpful.
|
||||
*
|
||||
* The declarations for the intrinsic functions were taken from the DDK.
|
||||
* Our declarations must match the ddk's otherwise the 64-bit c++ compiler
|
||||
* will complain about second linkage of the intrinsic functions.
|
||||
* We define the intrinsic using the basic types corresponding to the
|
||||
* Windows typedefs. This avoids having to include windows header files
|
||||
* to get to the windows types.
|
||||
*/
|
||||
#if defined(_MSC_VER) && !defined(BORA_NO_WIN32_INTRINS)
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* It seems x86 & x86-64 windows still implements these intrinsic
|
||||
* functions. The documentation for the x86-64 suggest the
|
||||
* __inbyte/__outbyte intrinsics even though the _in/_out work fine and
|
||||
* __inbyte/__outbyte aren't supported on x86.
|
||||
*/
|
||||
int _inp(unsigned short);
|
||||
unsigned short _inpw(unsigned short);
|
||||
unsigned long _inpd(unsigned short);
|
||||
|
||||
int _outp(unsigned short, int);
|
||||
unsigned short _outpw(unsigned short, unsigned short);
|
||||
unsigned long _outpd(uint16, unsigned long);
|
||||
#pragma intrinsic(_inp, _inpw, _inpd, _outp, _outpw, _outpw, _outpd)
|
||||
|
||||
/*
|
||||
* Prevents compiler from re-ordering reads, writes and reads&writes.
|
||||
* These functions do not add any instructions thus only affect
|
||||
* the compiler ordering.
|
||||
*
|
||||
* See:
|
||||
* `Lockless Programming Considerations for Xbox 360 and Microsoft Windows'
|
||||
* http://msdn.microsoft.com/en-us/library/bb310595(VS.85).aspx
|
||||
*/
|
||||
void _ReadBarrier(void);
|
||||
void _WriteBarrier(void);
|
||||
void _ReadWriteBarrier(void);
|
||||
#pragma intrinsic(_ReadBarrier, _WriteBarrier, _ReadWriteBarrier)
|
||||
|
||||
void _mm_mfence(void);
|
||||
void _mm_lfence(void);
|
||||
#pragma intrinsic(_mm_mfence, _mm_lfence)
|
||||
|
||||
unsigned int __getcallerseflags(void);
|
||||
#pragma intrinsic(__getcallerseflags)
|
||||
|
||||
#ifdef VM_X86_64
|
||||
/*
|
||||
* intrinsic functions only supported by x86-64 windows as of 2k3sp1
|
||||
*/
|
||||
unsigned __int64 __rdtsc(void);
|
||||
void __stosw(unsigned short *, unsigned short, size_t);
|
||||
void __stosd(unsigned long *, unsigned long, size_t);
|
||||
void _mm_pause(void);
|
||||
#pragma intrinsic(__rdtsc, __stosw, __stosd, _mm_pause)
|
||||
|
||||
unsigned char _BitScanForward64(unsigned long *, unsigned __int64);
|
||||
unsigned char _BitScanReverse64(unsigned long *, unsigned __int64);
|
||||
#pragma intrinsic(_BitScanForward64, _BitScanReverse64)
|
||||
#endif /* VM_X86_64 */
|
||||
|
||||
unsigned char _BitScanForward(unsigned long *, unsigned long);
|
||||
unsigned char _BitScanReverse(unsigned long *, unsigned long);
|
||||
#pragma intrinsic(_BitScanForward, _BitScanReverse)
|
||||
|
||||
unsigned char _bittest(const long *, long);
|
||||
unsigned char _bittestandset(long *, long);
|
||||
unsigned char _bittestandreset(long *, long);
|
||||
unsigned char _bittestandcomplement(long *, long);
|
||||
#pragma intrinsic(_bittest, _bittestandset, _bittestandreset, _bittestandcomplement)
|
||||
#ifdef VM_X86_64
|
||||
unsigned char _bittestandset64(__int64 *, __int64);
|
||||
unsigned char _bittestandreset64(__int64 *, __int64);
|
||||
#pragma intrinsic(_bittestandset64, _bittestandreset64)
|
||||
#endif // VM_X86_64
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // _MSC_VER
|
||||
|
||||
#ifdef __GNUC__
|
||||
/*
|
||||
* Checked against the Intel manual and GCC --hpreg
|
||||
@@ -88,6 +176,9 @@ __GCC_IN(l, uint32, IN32)
|
||||
#define OUTW(port, val) __GCC_OUT(w, w, port, val)
|
||||
#define OUT32(port, val) __GCC_OUT(l, , port, val)
|
||||
|
||||
#define GET_CURRENT_EIP(_eip) \
|
||||
__asm__ __volatile("call 0\n\tpopl %0" : "=r" (_eip): );
|
||||
|
||||
static INLINE unsigned int
|
||||
GetCallerEFlags(void)
|
||||
{
|
||||
@@ -97,35 +188,35 @@ GetCallerEFlags(void)
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
static INLINE uint8
|
||||
static INLINE uint8
|
||||
INB(uint16 port)
|
||||
{
|
||||
return __inbyte(port);
|
||||
return (uint8)_inp(port);
|
||||
}
|
||||
static INLINE void
|
||||
OUTB(uint16 port, uint8 value)
|
||||
{
|
||||
__outbyte(port, value);
|
||||
_outp(port, value);
|
||||
}
|
||||
static INLINE uint16
|
||||
INW(uint16 port)
|
||||
{
|
||||
return __inword(port);
|
||||
return _inpw(port);
|
||||
}
|
||||
static INLINE void
|
||||
OUTW(uint16 port, uint16 value)
|
||||
{
|
||||
__outword(port, value);
|
||||
_outpw(port, value);
|
||||
}
|
||||
static INLINE uint32
|
||||
IN32(uint16 port)
|
||||
{
|
||||
return __indword(port);
|
||||
return _inpd(port);
|
||||
}
|
||||
static INLINE void
|
||||
OUT32(uint16 port, uint32 value)
|
||||
{
|
||||
__outdword(port, value);
|
||||
_outpd(port, value);
|
||||
}
|
||||
|
||||
#ifndef VM_X86_64
|
||||
@@ -133,6 +224,11 @@ OUT32(uint16 port, uint32 value)
|
||||
#undef NEAR
|
||||
#endif
|
||||
|
||||
#define GET_CURRENT_EIP(_eip) do { \
|
||||
__asm call NEAR PTR $+5 \
|
||||
__asm pop eax \
|
||||
__asm mov _eip, eax \
|
||||
} while (0)
|
||||
#endif // VM_X86_64
|
||||
|
||||
static INLINE unsigned int
|
||||
@@ -145,127 +241,9 @@ GetCallerEFlags(void)
|
||||
|
||||
/* Sequence recommended by Intel for the Pentium 4. */
|
||||
#define INTEL_MICROCODE_VERSION() ( \
|
||||
X86MSR_SetMSR(MSR_BIOS_SIGN_ID, 0), \
|
||||
__SET_MSR(MSR_BIOS_SIGN_ID, 0), \
|
||||
__GET_EAX_FROM_CPUID(1), \
|
||||
X86MSR_GetMSR(MSR_BIOS_SIGN_ID))
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* MFENCE --
|
||||
*
|
||||
* Wrapper around the MFENCE instruction.
|
||||
*
|
||||
* Caveat Emptor! This function is _NOT_ _PORTABLE_ and most certainly
|
||||
* not something you should use. Take a look at the SMP_*_BARRIER_*,
|
||||
* DMA_*_BARRIER_* and MMIO_*_BARRIER_* interfaces instead, when writing
|
||||
* general OS/VMM code.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* See MFENCE instruction in Intel SDM or AMD Programmer's Manual.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
MFENCE(void)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__(
|
||||
"mfence"
|
||||
::: "memory"
|
||||
);
|
||||
#elif defined _MSC_VER
|
||||
_ReadWriteBarrier();
|
||||
_mm_mfence();
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
#error No compiler defined for MFENCE
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* LFENCE --
|
||||
*
|
||||
* Wrapper around the LFENCE instruction.
|
||||
*
|
||||
* Caveat Emptor! This function is _NOT_ _PORTABLE_ and most certainly
|
||||
* not something you should use. Take a look at the SMP_*_BARRIER_*,
|
||||
* DMA_*_BARRIER_* and MMIO_*_BARRIER_* interfaces instead, when writing
|
||||
* general OS/VMM code.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* See LFENCE instruction in Intel SDM or AMD Programmer's Manual.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
LFENCE(void)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__(
|
||||
"lfence"
|
||||
: : : "memory"
|
||||
);
|
||||
#elif defined _MSC_VER
|
||||
_ReadWriteBarrier();
|
||||
_mm_lfence();
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
#error No compiler defined for LFENCE
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* SFENCE --
|
||||
*
|
||||
* Wrapper around the SFENCE instruction.
|
||||
*
|
||||
* Caveat Emptor! This function is _NOT_ _PORTABLE_ and most certainly
|
||||
* not something you should use. Take a look at the SMP_*_BARRIER_*,
|
||||
* DMA_*_BARRIER_* and MMIO_*_BARRIER_* interfaces instead, when writing
|
||||
* general OS/VMM code.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* See SFENCE instruction in Intel SDM or AMD Programmer's Manual.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
SFENCE(void)
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__(
|
||||
"sfence"
|
||||
: : : "memory"
|
||||
);
|
||||
#elif defined _MSC_VER
|
||||
_ReadWriteBarrier();
|
||||
_mm_sfence();
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
#error No compiler defined for SFENCE
|
||||
#endif
|
||||
}
|
||||
|
||||
__GET_MSR(MSR_BIOS_SIGN_ID))
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
@@ -297,391 +275,39 @@ SFENCE(void)
|
||||
static INLINE void
|
||||
RDTSC_BARRIER(void)
|
||||
{
|
||||
MFENCE();
|
||||
LFENCE();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* LOCKED_INSN_BARRIER --
|
||||
*
|
||||
* Implements a full WB load/store barrier using a locked instruction.
|
||||
*
|
||||
* See PR 1674199 for details. You may choose to use this for
|
||||
* performance reasons over MFENCE iff you are only dealing with
|
||||
* WB memory accesses.
|
||||
*
|
||||
* DANGER! Do not use this barrier instead of MFENCE when dealing
|
||||
* with non-temporal instructions or UC/WC memory accesses.
|
||||
*
|
||||
* Caveat Emptor! This function is _NOT_ _PORTABLE_ and most certainly
|
||||
* not something you should use. Take a look at the SMP_*_BARRIER_*,
|
||||
* DMA_*_BARRIER_* and MMIO_*_BARRIER_* interfaces instead, when writing
|
||||
* general OS/VMM code.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Cause WB loads and stores before the call to be globally visible
|
||||
* before WB loads and stores after this call.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
LOCKED_INSN_BARRIER(void)
|
||||
{
|
||||
volatile long temp = 0;
|
||||
|
||||
#if defined __GNUC__
|
||||
__asm__ __volatile__ (
|
||||
"lock xorl $1, %0"
|
||||
: "+m" (temp)
|
||||
: /* no additional inputs */
|
||||
: "cc", "memory");
|
||||
#ifdef __GNUC__
|
||||
__asm__ __volatile__(
|
||||
"mfence \n\t"
|
||||
"lfence \n\t"
|
||||
::: "memory"
|
||||
);
|
||||
#elif defined _MSC_VER
|
||||
/*
|
||||
* Ignore warning about _InterlockedXor operation on a local variable; we are
|
||||
* using the operation for its side-effects only.
|
||||
*/
|
||||
#pragma warning(suppress:28113)
|
||||
_InterlockedXor(&temp, 1);
|
||||
/* Prevent compiler from moving code across mfence/lfence. */
|
||||
_ReadWriteBarrier();
|
||||
_mm_mfence();
|
||||
_mm_lfence();
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
#error LOCKED_INSN_BARRIER not defined for this compiler
|
||||
#error No compiler defined for RDTSC_BARRIER
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory Barriers
|
||||
* ===============
|
||||
*
|
||||
* Terminology
|
||||
* -----------
|
||||
*
|
||||
* A compiler memory barrier prevents the compiler from re-ordering memory
|
||||
* accesses accross the barrier. It is not a CPU instruction, it is a compiler
|
||||
* directive (i.e. it does not emit any code).
|
||||
*
|
||||
* A CPU memory barrier prevents the CPU from re-ordering memory accesses
|
||||
* accross the barrier. It is a CPU instruction.
|
||||
*
|
||||
* A memory barrier is the union of a compiler memory barrier and a CPU memory
|
||||
* barrier. A compiler memory barrier is a useless construct by itself. It is
|
||||
* only useful when combined with a CPU memory barrier, to implement a memory
|
||||
* barrier.
|
||||
*
|
||||
* Semantics
|
||||
* ---------
|
||||
*
|
||||
* At the time COMPILER_*_BARRIER were created (and references to them were
|
||||
* added to the code), the code was only targetting x86. The intent of the code
|
||||
* was really to use a memory barrier, but because x86 uses a strongly ordered
|
||||
* memory model, the CPU would not re-order memory accesses, and the code could
|
||||
* get away with using just a compiler memory barrier. So COMPILER_*_BARRIER
|
||||
* were born and were implemented as compiler memory barriers _on x86_. But
|
||||
* make no mistake, _the semantics that the code expects from
|
||||
* COMPILER_*_BARRIER are that of a memory barrier_!
|
||||
*
|
||||
* DO NOT USE!
|
||||
* -----------
|
||||
*
|
||||
* On at least one non-x86 architecture, COMPILER_*_BARRIER are
|
||||
* 1) Misnomers
|
||||
* 2) Not fine-grained enough to provide the best performance.
|
||||
* For the above two reasons, usage of COMPILER_*_BARRIER is now deprecated.
|
||||
* _Do not add new references to COMPILER_*_BARRIER._ Instead, precisely
|
||||
* document the intent of your code by using
|
||||
* <mem_type/purpose>_<before_access_type>_BARRIER_<after_access_type>.
|
||||
* Existing references to COMPILER_*_BARRIER are being slowly but surely
|
||||
* converted, and when no references are left, COMPILER_*_BARRIER will be
|
||||
* retired.
|
||||
*
|
||||
* Thanks for pasting this whole comment into every architecture header.
|
||||
*/
|
||||
|
||||
#if defined __GNUC__
|
||||
# define COMPILER_READ_BARRIER() COMPILER_MEM_BARRIER()
|
||||
# define COMPILER_WRITE_BARRIER() COMPILER_MEM_BARRIER()
|
||||
# define COMPILER_MEM_BARRIER() __asm__ __volatile__("" ::: "memory")
|
||||
#elif defined _MSC_VER
|
||||
# define COMPILER_READ_BARRIER() _ReadBarrier()
|
||||
# define COMPILER_WRITE_BARRIER() _WriteBarrier()
|
||||
# define COMPILER_MEM_BARRIER() _ReadWriteBarrier()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory barriers. These take the form of
|
||||
*
|
||||
* <mem_type/purpose>_<before_access_type>_BARRIER_<after_access_type>
|
||||
*
|
||||
* where:
|
||||
* <mem_type/purpose> is either SMP, DMA, or MMIO.
|
||||
* <*_access type> is either R(load), W(store) or RW(any).
|
||||
*
|
||||
* Above every use of these memory barriers in the code, there _must_ be a
|
||||
* comment to justify the use, i.e. a comment which:
|
||||
*
|
||||
* 1) Precisely identifies which memory accesses must not be re-ordered across
|
||||
* the memory barrier.
|
||||
* 2) Explains why it is important that the memory accesses not be re-ordered.
|
||||
*
|
||||
* Thanks for pasting this whole comment into every architecture header.
|
||||
*
|
||||
* This is a simplified version of Table 7-3 (Memory Access Ordering Rules) from
|
||||
* AMD AMD64 Architecture Programmer's Manual Volume 2: System Programming
|
||||
* (September 2018, Publication 24593, Revision 3.30).
|
||||
*
|
||||
* https://www.amd.com/system/files/TechDocs/24593.pdf#page=228
|
||||
*
|
||||
* This table only includes the memory types we care about in the context of
|
||||
* SMP, DMA and MMIO barriers.
|
||||
*
|
||||
* +-------------+------+------+------+------+------+------+
|
||||
* |\ 2nd mem op | | | | | | |
|
||||
* | `---------. | R WB | R UC | R WC | W WB | W UC | W WC |
|
||||
* | 1st mem op \| | | | | | |
|
||||
* +-------------+------+------+------+------+------+------+
|
||||
* | R WB | | | LF1 | | | |
|
||||
* +-------------+------+------+------+------+------+------+
|
||||
* | R UC | | | LF1 | | | |
|
||||
* +-------------+------+------+------+------+------+------+
|
||||
* | R WC | | | LF1 | | | |
|
||||
* +-------------+------+------+------+------+------+------+
|
||||
* | W WB | MF1 | | MF1 | | | SF2 |
|
||||
* +-------------+------+------+------+------+------+------+
|
||||
* | W UC | MF1 | | MF1 | | | SF2 |
|
||||
* +-------------+------+------+------+------+------+------+
|
||||
* | W WC | MF1 | | MF1 | SF1 | | SF2 |
|
||||
* +-------------+------+------+------+------+------+------+
|
||||
*
|
||||
* MF1 - WB or WC load may pass a previous non-conflicting WB, WC or UC store.
|
||||
* Use MFENCE. This is a combination of rules 'e' and 'i' in the AMD
|
||||
* diagram.
|
||||
* LF1 - WC load may pass a previous WB, WC or UC load. Use LFENCE. This is
|
||||
* rule 'b' in the AMD diagram.
|
||||
* SF1 - WB store may pass a previous WC store. Use SFENCE. This is rule 'j' in
|
||||
* the AMD diagram.
|
||||
* SF2 - WC store may pass a previous UC, WB or non-conflicting WC store. Use
|
||||
* SFENCE. This is rule 'h' in the AMD diagram.
|
||||
*
|
||||
* To figure out the specific barrier required, pick and collapse the relevant
|
||||
* rows and columns, choosing the strongest barrier.
|
||||
*
|
||||
* SMP barriers only concern with access to "normal memory" (write-back cached
|
||||
* i.e. WB using above terminology), so we only need to worry about store-load
|
||||
* reordering. In other cases a compiler barrier is sufficient. SMP store-load
|
||||
* reordering is handled with a locked XOR (instead of a proper MFENCE
|
||||
* instructon) for performance reasons. See PR 1674199 for more details.
|
||||
*
|
||||
* DMA barriers are equivalent to SMP barriers on x86.
|
||||
*
|
||||
* MMIO barriers are used to mix access to different memory types, so more
|
||||
* reordering is possible, and is handled via LFENCE/SFENCE. Also, a proper
|
||||
* MFENCE must be used instead of the locked XOR trick, due to the latter
|
||||
* not guarding non-temporal/WC accesses.
|
||||
* Compiler/CPU barriers. These take the form of <mem access type>_<mem access
|
||||
* type>_MEM_BARRIER, where <mem access type> is either LD (load), ST (store) or
|
||||
* LDST (any). On x86 we only need to care specifically about store-load
|
||||
* reordering on normal memory types and mfence, otherwise only a compiler
|
||||
* barrier is needed.
|
||||
*/
|
||||
|
||||
#define SMP_R_BARRIER_R() COMPILER_READ_BARRIER()
|
||||
#define SMP_R_BARRIER_W() COMPILER_MEM_BARRIER()
|
||||
#define SMP_R_BARRIER_RW() COMPILER_MEM_BARRIER()
|
||||
#define SMP_W_BARRIER_R() LOCKED_INSN_BARRIER()
|
||||
#define SMP_W_BARRIER_W() COMPILER_WRITE_BARRIER()
|
||||
#define SMP_W_BARRIER_RW() LOCKED_INSN_BARRIER()
|
||||
#define SMP_RW_BARRIER_R() LOCKED_INSN_BARRIER()
|
||||
#define SMP_RW_BARRIER_W() COMPILER_MEM_BARRIER()
|
||||
#define SMP_RW_BARRIER_RW() LOCKED_INSN_BARRIER()
|
||||
|
||||
/*
|
||||
* Like the above, only for use with observers other than CPUs,
|
||||
* i.e. DMA masters. Same as SMP barriers for x86.
|
||||
*/
|
||||
|
||||
#define DMA_R_BARRIER_R() SMP_R_BARRIER_R()
|
||||
#define DMA_R_BARRIER_W() SMP_R_BARRIER_W()
|
||||
#define DMA_R_BARRIER_RW() SMP_R_BARRIER_RW()
|
||||
#define DMA_W_BARRIER_R() SMP_W_BARRIER_R()
|
||||
#define DMA_W_BARRIER_W() SMP_W_BARRIER_W()
|
||||
#define DMA_W_BARRIER_RW() SMP_W_BARRIER_RW()
|
||||
#define DMA_RW_BARRIER_R() SMP_RW_BARRIER_R()
|
||||
#define DMA_RW_BARRIER_W() SMP_RW_BARRIER_W()
|
||||
#define DMA_RW_BARRIER_RW() SMP_RW_BARRIER_RW()
|
||||
|
||||
/*
|
||||
* And finally a set for use with MMIO accesses. These barriers must be stronger
|
||||
* because they are used when mixing accesses to different memory types.
|
||||
*/
|
||||
|
||||
#define MMIO_R_BARRIER_R() LFENCE()
|
||||
#define MMIO_R_BARRIER_W() SMP_R_BARRIER_W()
|
||||
#define MMIO_R_BARRIER_RW() LFENCE()
|
||||
#define MMIO_W_BARRIER_R() MFENCE()
|
||||
#define MMIO_W_BARRIER_W() SFENCE()
|
||||
#define MMIO_W_BARRIER_RW() MFENCE()
|
||||
#define MMIO_RW_BARRIER_R() MFENCE()
|
||||
#define MMIO_RW_BARRIER_W() SFENCE()
|
||||
#define MMIO_RW_BARRIER_RW() MFENCE()
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MMIORead8 --
|
||||
*
|
||||
* IO read from address "addr".
|
||||
*
|
||||
* Results:
|
||||
* 8-bit value at given location.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE uint8
|
||||
MMIORead8(const volatile void *addr)
|
||||
{
|
||||
volatile uint8 *addr8 = (volatile uint8 *) addr;
|
||||
|
||||
return *addr8;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MMIOWrite8 --
|
||||
*
|
||||
* IO write to address "addr".
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE void
|
||||
MMIOWrite8(volatile void *addr, // IN
|
||||
uint8 val) // IN
|
||||
{
|
||||
volatile uint8 *addr8 = (volatile uint8 *) addr;
|
||||
|
||||
*addr8 = val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MMIORead16 --
|
||||
*
|
||||
* IO read from address "addr".
|
||||
*
|
||||
* Results:
|
||||
* 16-bit value at given location.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE uint16
|
||||
MMIORead16(const volatile void *addr)
|
||||
{
|
||||
volatile uint16 *addr16 = (volatile uint16 *) addr;
|
||||
|
||||
return *addr16;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MMIOWrite16 --
|
||||
*
|
||||
* IO write to address "addr".
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE void
|
||||
MMIOWrite16(volatile void *addr, // IN
|
||||
uint16 val) // IN
|
||||
{
|
||||
volatile uint16 *addr16 = (volatile uint16 *) addr;
|
||||
|
||||
*addr16 = val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MMIORead32 --
|
||||
*
|
||||
* IO read from address "addr".
|
||||
*
|
||||
* Results:
|
||||
* 32-bit value at given location.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE uint32
|
||||
MMIORead32(const volatile void *addr)
|
||||
{
|
||||
volatile uint32 *addr32 = (volatile uint32 *) addr;
|
||||
|
||||
return *addr32;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MMIOWrite32 --
|
||||
*
|
||||
* IO write to address "addr".
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE void
|
||||
MMIOWrite32(volatile void *addr, // OUT
|
||||
uint32 val)
|
||||
{
|
||||
volatile uint32 *addr32 = (volatile uint32 *) addr;
|
||||
|
||||
*addr32 = val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MMIORead64 --
|
||||
*
|
||||
* IO read from address "addr".
|
||||
*
|
||||
* Results:
|
||||
* 64-bit value at given location.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE uint64
|
||||
MMIORead64(const volatile void *addr)
|
||||
{
|
||||
volatile uint64 *addr64 = (volatile uint64 *) addr;
|
||||
|
||||
return *addr64;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* MMIOWrite64 --
|
||||
*
|
||||
* IO write to address "addr".
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE void
|
||||
MMIOWrite64(volatile void *addr, // OUT
|
||||
uint64 val)
|
||||
{
|
||||
volatile uint64 *addr64 = (volatile uint64 *) addr;
|
||||
|
||||
*addr64 = val;
|
||||
}
|
||||
#define LD_LD_MEM_BARRIER() COMPILER_MEM_BARRIER()
|
||||
#define LD_ST_MEM_BARRIER() COMPILER_MEM_BARRIER()
|
||||
#define LD_LDST_MEM_BARRIER() COMPILER_MEM_BARRIER()
|
||||
#define ST_LD_MEM_BARRIER() asm volatile ("mfence" ::: "memory")
|
||||
#define ST_ST_MEM_BARRIER() COMPILER_MEM_BARRIER()
|
||||
#define ST_LDST_MEM_BARRIER() ST_LD_MEM_BARRIER()
|
||||
#define LDST_LD_MEM_BARRIER() ST_LD_MEM_BARRIER()
|
||||
#define LDST_ST_MEM_BARRIER() COMPILER_MEM_BARRIER()
|
||||
#define LDST_LDST_MEM_BARRIER() ST_LD_MEM_BARRIER()
|
||||
|
||||
#endif // _VM_BASIC_ASM_X86_COMMON_H_
|
||||
+160
-189
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2003-2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2003-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -37,51 +37,15 @@
|
||||
#include "vm_basic_types.h" // For INLINE.
|
||||
|
||||
/* Checks for FreeBSD, filtering out VMKERNEL. */
|
||||
#if !defined(VMKERNEL) && defined(__FreeBSD__)
|
||||
#define __IS_FREEBSD__ 1
|
||||
#else
|
||||
#define __IS_FREEBSD__ 0
|
||||
#endif
|
||||
#define __IS_FREEBSD__ (!defined(VMKERNEL) && defined(__FreeBSD__))
|
||||
#define __IS_FREEBSD_VER__(ver) (__IS_FREEBSD__ && __FreeBSD_version >= (ver))
|
||||
|
||||
/*
|
||||
* <stddef.h> provides definitions for:
|
||||
* NULL, offsetof
|
||||
* References:
|
||||
* C90 7.17, C99 7.19, C11 7.19
|
||||
*/
|
||||
#if !defined(VMKERNEL)
|
||||
# include <stddef.h>
|
||||
#else
|
||||
/*
|
||||
* Vmkernel's bogus __FreeBSD__ value causes gcc <stddef.h> to break.
|
||||
* Work around by doing similar things. Bug 2116887 and 2229647.
|
||||
*/
|
||||
# ifndef offsetof
|
||||
/*
|
||||
* We use the builtin offset for gcc/clang, except when we're running
|
||||
* under the vmkernel's GDB macro preprocessor, since gdb doesn't
|
||||
* understand __builtin_offsetof.
|
||||
*/
|
||||
# if defined VMKERNEL_GDB_MACRO_BUILDER
|
||||
# define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
# else
|
||||
# define offsetof __builtin_offsetof
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef NULL
|
||||
# ifdef __cplusplus
|
||||
# define NULL 0
|
||||
# else
|
||||
# define NULL ((void *)0)
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif // VMKERNEL
|
||||
|
||||
#if defined _WIN32 && defined USERLEVEL
|
||||
#include <windows.h> // for Sleep() and LOWORD() etc.
|
||||
#include <stddef.h> /*
|
||||
* We redefine offsetof macro from stddef; make
|
||||
* sure that it's already defined before we do that.
|
||||
*/
|
||||
#include <windows.h> // for Sleep() and LOWORD() etc.
|
||||
#undef GetFreeSpace // Unpollute preprocessor namespace.
|
||||
#endif
|
||||
|
||||
@@ -90,8 +54,42 @@
|
||||
* Simple macros
|
||||
*/
|
||||
|
||||
#ifndef vmw_offsetof
|
||||
#define vmw_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
#if (defined __APPLE__ || defined __FreeBSD__) && \
|
||||
(!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
|
||||
# include <stddef.h>
|
||||
#else
|
||||
#ifndef offsetof
|
||||
#define VMW_DEFINED_OFFSETOF
|
||||
|
||||
/*
|
||||
* XXX While the _WIN32 implementation appears to be identical to vmw_offsetof
|
||||
* in terms of behavior, they need to be separate to match verbatim the
|
||||
* definition used by the respective compilers, to avoid a redefinition warning.
|
||||
*
|
||||
* This is necessary until we eliminate the inclusion of <windows.h> above.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#define offsetof(s,m) (size_t)&(((s *)0)->m)
|
||||
/*
|
||||
* We use the builtin offset for gcc/clang, except when we're running under the
|
||||
* vmkernel's GDB macro preprocessor, since gdb doesn't understand
|
||||
* __builtin_offsetof.
|
||||
*/
|
||||
#elif defined __GNUC__ && !defined VMKERNEL_GDB_MACRO_BUILDER
|
||||
#define offsetof __builtin_offsetof
|
||||
#else
|
||||
#define offsetof vmw_offsetof
|
||||
#endif
|
||||
|
||||
#endif // offsetof
|
||||
#endif // __APPLE__
|
||||
|
||||
#define VMW_CONTAINER_OF(ptr, type, member) \
|
||||
((type *)((char *)(ptr) - offsetof(type, member)))
|
||||
((type *)((char *)(ptr) - vmw_offsetof(type, member)))
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(a) (sizeof (a) / sizeof *(a))
|
||||
@@ -103,7 +101,7 @@
|
||||
|
||||
/* The Solaris 9 cross-compiler complains about these not being used */
|
||||
#ifndef sun
|
||||
static INLINE int
|
||||
static INLINE int
|
||||
Min(int a, int b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
@@ -115,7 +113,7 @@ Min(int a, int b)
|
||||
#endif
|
||||
|
||||
#ifndef sun
|
||||
static INLINE int
|
||||
static INLINE int
|
||||
Max(int a, int b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
@@ -157,8 +155,20 @@ Max(int a, int b)
|
||||
|
||||
#define IMPLIES(a,b) (!(a) || (b))
|
||||
|
||||
|
||||
/*
|
||||
* Not everybody (e.g., the monitor) has NULL
|
||||
*/
|
||||
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Token concatenation
|
||||
*
|
||||
* The C preprocessor doesn't prescan arguments when they are
|
||||
@@ -195,7 +205,7 @@ Max(int a, int b)
|
||||
*/
|
||||
|
||||
#ifndef PAGE_SHIFT // {
|
||||
#if defined __x86_64__ || defined __i386__
|
||||
#if defined VM_I386
|
||||
#define PAGE_SHIFT 12
|
||||
#elif defined __APPLE__
|
||||
#define PAGE_SHIFT 12
|
||||
@@ -241,55 +251,28 @@ Max(int a, int b)
|
||||
#define PAGES_2_BYTES(_npages) (((uint64)(_npages)) << PAGE_SHIFT)
|
||||
#endif
|
||||
|
||||
#ifndef KBYTES_SHIFT
|
||||
#define KBYTES_SHIFT 10
|
||||
#endif
|
||||
|
||||
#ifndef MBYTES_SHIFT
|
||||
#define MBYTES_SHIFT 20
|
||||
#endif
|
||||
|
||||
#ifndef MBYTES_2_PAGES
|
||||
#define MBYTES_2_PAGES(_nbytes) \
|
||||
((uint64)(_nbytes) << (MBYTES_SHIFT - PAGE_SHIFT))
|
||||
#define MBYTES_2_PAGES(_nbytes) ((_nbytes) << (20 - PAGE_SHIFT))
|
||||
#endif
|
||||
|
||||
#ifndef PAGES_2_MBYTES
|
||||
#define PAGES_2_MBYTES(_npages) ((_npages) >> (MBYTES_SHIFT - PAGE_SHIFT))
|
||||
#endif
|
||||
|
||||
#ifndef ROUNDUP_PAGES_2_MBYTES
|
||||
#define ROUNDUP_PAGES_2_MBYTES(_npages) \
|
||||
(((_npages) + MASK(MBYTES_SHIFT - PAGE_SHIFT)) >> (MBYTES_SHIFT - PAGE_SHIFT))
|
||||
#endif
|
||||
|
||||
#ifndef ROUNDDOWN_PAGES_2_MBYTES
|
||||
#define ROUNDDOWN_PAGES_2_MBYTES(_npages) \
|
||||
((_npages) >> (MBYTES_SHIFT - PAGE_SHIFT))
|
||||
#define PAGES_2_MBYTES(_npages) ((_npages) >> (20 - PAGE_SHIFT))
|
||||
#endif
|
||||
|
||||
#ifndef GBYTES_2_PAGES
|
||||
#define GBYTES_2_PAGES(_nbytes) ((uint64)(_nbytes) << (30 - PAGE_SHIFT))
|
||||
#define GBYTES_2_PAGES(_nbytes) ((_nbytes) << (30 - PAGE_SHIFT))
|
||||
#endif
|
||||
|
||||
#ifndef PAGES_2_GBYTES
|
||||
#define PAGES_2_GBYTES(_npages) ((_npages) >> (30 - PAGE_SHIFT))
|
||||
#endif
|
||||
|
||||
#ifndef BYTES_2_KBYTES
|
||||
#define BYTES_2_KBYTES(_nbytes) ((_nbytes) >> KBYTES_SHIFT)
|
||||
#endif
|
||||
|
||||
#ifndef KBYTES_2_BYTES
|
||||
#define KBYTES_2_BYTES(_nbytes) ((uint64)(_nbytes) << KBYTES_SHIFT)
|
||||
#endif
|
||||
|
||||
#ifndef BYTES_2_MBYTES
|
||||
#define BYTES_2_MBYTES(_nbytes) ((_nbytes) >> MBYTES_SHIFT)
|
||||
#define BYTES_2_MBYTES(_nbytes) ((_nbytes) >> 20)
|
||||
#endif
|
||||
|
||||
#ifndef MBYTES_2_BYTES
|
||||
#define MBYTES_2_BYTES(_nbytes) ((uint64)(_nbytes) << MBYTES_SHIFT)
|
||||
#define MBYTES_2_BYTES(_nbytes) ((uint64)(_nbytes) << 20)
|
||||
#endif
|
||||
|
||||
#ifndef BYTES_2_GBYTES
|
||||
@@ -316,26 +299,6 @@ Max(int a, int b)
|
||||
#define VM_PAE_LARGE_2_SMALL_PAGES (BYTES_2_PAGES(VM_PAE_LARGE_PAGE_SIZE))
|
||||
#endif
|
||||
|
||||
#ifndef VM_PAE_LARGE_2_BYTES
|
||||
#define VM_PAE_LARGE_2_BYTES(_2mbytes) ((_2mbytes) << VM_PAE_LARGE_PAGE_SHIFT)
|
||||
#endif
|
||||
|
||||
#ifndef VM_1GB_PAGE_SHIFT
|
||||
#define VM_1GB_PAGE_SHIFT 30
|
||||
#endif
|
||||
|
||||
#ifndef VM_1GB_PAGE_SIZE
|
||||
#define VM_1GB_PAGE_SIZE (1 << VM_1GB_PAGE_SHIFT)
|
||||
#endif
|
||||
|
||||
#ifndef VM_1GB_2_PAGES
|
||||
#define VM_1GB_2_PAGES (BYTES_2_PAGES(VM_1GB_PAGE_SIZE))
|
||||
#endif
|
||||
|
||||
#ifndef VM_1GB_2_PDIRS
|
||||
#define VM_1GB_2_PDIRS (VM_1GB_PAGE_SIZE / VM_PAE_LARGE_PAGE_SIZE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Word operations
|
||||
*/
|
||||
@@ -382,7 +345,7 @@ Max(int a, int b)
|
||||
#ifdef _MSC_VER
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
#endif
|
||||
void *_ReturnAddress(void);
|
||||
#pragma intrinsic(_ReturnAddress)
|
||||
#define GetReturnAddress() _ReturnAddress()
|
||||
@@ -425,19 +388,37 @@ void *_ReturnAddress(void);
|
||||
|
||||
#ifdef USERLEVEL // {
|
||||
|
||||
/*
|
||||
* Note this might be a problem on NT b/c while sched_yield guarantees it
|
||||
* moves you to the end of your priority list, Sleep(0) offers no such
|
||||
* guarantee. Bummer. --Jeremy.
|
||||
*/
|
||||
|
||||
#if defined(N_PLAT_NLM)
|
||||
/* We do not have YIELD() as we do not need it yet... */
|
||||
#elif defined(_WIN32)
|
||||
# define YIELD() Sleep(0)
|
||||
#elif defined(VMKERNEL)
|
||||
/* We don't have a YIELD macro in the vmkernel */
|
||||
#else
|
||||
# include <sched.h> // For sched_yield. Don't ask. --Jeremy.
|
||||
# define YIELD() sched_yield()
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Standardize some Posix names on Windows.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32 // {
|
||||
|
||||
/* Conflict with definition of Visual Studio 2015 */
|
||||
#if (_MSC_VER < 1900)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#define strtok_r strtok_s
|
||||
|
||||
#if (_MSC_VER < 1500)
|
||||
#define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
typedef int uid_t;
|
||||
typedef int gid_t;
|
||||
|
||||
@@ -461,9 +442,20 @@ typedef int pid_t;
|
||||
#define W_OK 2
|
||||
#define R_OK 4
|
||||
|
||||
#endif // } _WIN32
|
||||
#endif // }
|
||||
|
||||
#endif // } USERLEVEL
|
||||
/*
|
||||
* Macro for username comparison.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32 // {
|
||||
#define USERCMP(x,y) Str_Strcasecmp(x,y)
|
||||
#else
|
||||
#define USERCMP(x,y) strcmp(x,y)
|
||||
#endif // }
|
||||
|
||||
|
||||
#endif // }
|
||||
|
||||
#ifndef va_copy
|
||||
|
||||
@@ -479,8 +471,19 @@ typedef int pid_t;
|
||||
|
||||
#elif defined(__APPLE__) && defined(KERNEL)
|
||||
|
||||
// The macOS kernel SDK defines va_copy in stdarg.h.
|
||||
#include "availabilityMacOS.h"
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||
// The Mac OS 10.5 kernel SDK defines va_copy in stdarg.h.
|
||||
#include <stdarg.h>
|
||||
#else
|
||||
/*
|
||||
* The Mac OS 10.4 kernel SDK needs va_copy. Based on inspection of
|
||||
* stdarg.h from the MacOSX10.4u.sdk kernel framework, this should
|
||||
* work.
|
||||
*/
|
||||
#define va_copy(dest, src) ((dest) = (src))
|
||||
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
|
||||
#elif defined(__GNUC__) && (__GNUC__ < 3)
|
||||
|
||||
@@ -500,7 +503,7 @@ typedef int pid_t;
|
||||
* driver.
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
#ifdef _WIN32
|
||||
#define PATH_MAX 256
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp(_s1,_s2) _stricmp((_s1),(_s2))
|
||||
@@ -510,6 +513,29 @@ typedef int pid_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined __linux__ && !defined __KERNEL__ && !defined MODULE && \
|
||||
!defined VMM && !defined FROBOS && !defined __ANDROID__
|
||||
#include <features.h>
|
||||
#if __GLIBC_PREREQ(2, 1) && !defined GLIBC_VERSION_21
|
||||
#define GLIBC_VERSION_21
|
||||
#endif
|
||||
#if __GLIBC_PREREQ(2, 2) && !defined GLIBC_VERSION_22
|
||||
#define GLIBC_VERSION_22
|
||||
#endif
|
||||
#if __GLIBC_PREREQ(2, 3) && !defined GLIBC_VERSION_23
|
||||
#define GLIBC_VERSION_23
|
||||
#endif
|
||||
#if __GLIBC_PREREQ(2, 4) && !defined GLIBC_VERSION_24
|
||||
#define GLIBC_VERSION_24
|
||||
#endif
|
||||
#if __GLIBC_PREREQ(2, 5) && !defined GLIBC_VERSION_25
|
||||
#define GLIBC_VERSION_25
|
||||
#endif
|
||||
#if __GLIBC_PREREQ(2, 12) && !defined GLIBC_VERSION_212
|
||||
#define GLIBC_VERSION_212
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Convenience definitions of unicode characters.
|
||||
*/
|
||||
@@ -539,10 +565,10 @@ typedef int pid_t;
|
||||
#undef DEBUG_ONLY
|
||||
#ifdef VMX86_DEBUG
|
||||
#define vmx86_debug 1
|
||||
#define DEBUG_ONLY(...) __VA_ARGS__
|
||||
#define DEBUG_ONLY(x) x
|
||||
#else
|
||||
#define vmx86_debug 0
|
||||
#define DEBUG_ONLY(...)
|
||||
#define DEBUG_ONLY(x)
|
||||
#endif
|
||||
|
||||
#ifdef VMX86_STATS
|
||||
@@ -582,7 +608,7 @@ typedef int pid_t;
|
||||
#define RELEASE_ONLY(x) x
|
||||
#else
|
||||
#define vmx86_release 0
|
||||
#define RELEASE_ONLY(x)
|
||||
#define RELEASE_ONLY(x)
|
||||
#endif
|
||||
|
||||
#ifdef VMX86_SERVER
|
||||
@@ -626,49 +652,28 @@ typedef int pid_t;
|
||||
#define APPLE_ONLY(x) x
|
||||
#else
|
||||
#define vmx86_apple 0
|
||||
#define APPLE_ONLY(x)
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(VMW_APPLE_SANDBOX)
|
||||
#define vmw_apple_sandbox 1
|
||||
#else
|
||||
#define vmw_apple_sandbox 0
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(VMW_APPLE_APP_STORE)
|
||||
#define vmw_apple_app_store 1
|
||||
#else
|
||||
#define vmw_apple_app_store 0
|
||||
#define APPLE_ONLY(x)
|
||||
#endif
|
||||
|
||||
#ifdef VMM
|
||||
#define vmx86_vmm 1
|
||||
#define VMM_ONLY(x) x
|
||||
#else
|
||||
#define vmx86_vmm 0
|
||||
#define VMM_ONLY(x)
|
||||
#endif
|
||||
|
||||
#ifdef ULM
|
||||
#define vmx86_ulm 1
|
||||
#define ULM_ONLY(x) x
|
||||
#else
|
||||
#define vmx86_ulm 0
|
||||
#define ULM_ONLY(x)
|
||||
#endif
|
||||
|
||||
#if defined(VMM) || defined(ULM)
|
||||
#define MONITOR_ONLY(x) x
|
||||
#else
|
||||
#define MONITOR_ONLY(x)
|
||||
#endif
|
||||
|
||||
#if defined(VMM) || defined(VMKERNEL)
|
||||
#define USER_ONLY(x)
|
||||
#else
|
||||
#define VMM_ONLY(x)
|
||||
#define USER_ONLY(x) x
|
||||
#endif
|
||||
|
||||
/* VMVISOR ifdef only allowed in the vmkernel */
|
||||
#ifdef VMKERNEL
|
||||
#ifdef VMVISOR
|
||||
#define vmvisor 1
|
||||
#define VMVISOR_ONLY(x) x
|
||||
#else
|
||||
#define vmvisor 0
|
||||
#define VMVISOR_ONLY(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define VMW_INVALID_HANDLE INVALID_HANDLE_VALUE
|
||||
#else
|
||||
@@ -686,6 +691,7 @@ typedef int pid_t;
|
||||
* display/printer drivers only.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#ifndef USES_OLD_WINDDK
|
||||
#if defined(VMX86_LOG)
|
||||
#ifdef _WIN64
|
||||
#define WinDrvPrint(arg, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, (ULONG)~0, arg, __VA_ARGS__)
|
||||
@@ -697,8 +703,15 @@ typedef int pid_t;
|
||||
#define WinDrvPrint(arg, ...)
|
||||
#define WinDrvEngPrint(arg, ...)
|
||||
#endif
|
||||
#endif
|
||||
#endif // _WIN32
|
||||
|
||||
#ifdef HOSTED_LG_PG
|
||||
#define hosted_lg_pg 1
|
||||
#else
|
||||
#define hosted_lg_pg 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Use to initialize cbSize for this structure to preserve < Vista
|
||||
* compatibility.
|
||||
@@ -709,7 +722,7 @@ typedef int pid_t;
|
||||
/* This is not intended to be thread-safe. */
|
||||
#define DO_ONCE(code) \
|
||||
do { \
|
||||
static MONITOR_ONLY(PERVCPU) Bool _doOnceDone = FALSE; \
|
||||
static Bool _doOnceDone = FALSE; \
|
||||
if (UNLIKELY(!_doOnceDone)) { \
|
||||
_doOnceDone = TRUE; \
|
||||
code; \
|
||||
@@ -768,48 +781,6 @@ typedef int pid_t;
|
||||
#define SIZE_80BIT 10
|
||||
#define SIZE_128BIT 16
|
||||
#define SIZE_256BIT 32
|
||||
#define SIZE_512BIT 64
|
||||
|
||||
/*
|
||||
* Allocate a variable of type _type, aligned to _align bytes, returning a
|
||||
* pointer to the variable in _var. Potentially _align - 1 bytes may be
|
||||
* wasted. On x86, GCC 6.3.0 behaves sub-optimally when variables are declared
|
||||
* on the stack using the aligned attribute, so this pattern is preferred.
|
||||
* See PRs 1795155, 1819963.
|
||||
*/
|
||||
#define WITH_PTR_TO_ALIGNED_VAR(_type, _align, _var) \
|
||||
do { \
|
||||
uint8 _buf_##_var[sizeof(_type) + (_align) - 1]; \
|
||||
_type *_var = (_type *) ((uintptr_t)(_buf_##_var + (_align) - 1) & \
|
||||
~((uintptr_t) ((_align) - 1)));
|
||||
|
||||
#define END_PTR_TO_ALIGNED_VAR \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* -Wswitch means that when you pass switch an enum that it's looking for
|
||||
* all values from that enum, and only that enum, to be accounted for.
|
||||
* "default:;" is fine for catching values you don't care about. But today
|
||||
* we have a bunch of code that uses internal and external enum values, or
|
||||
* in other words combines two enums into a single variable. This cast is
|
||||
* the workaround, but we really need to fix this mess.
|
||||
*/
|
||||
#define UNCHECKED_SWITCH__FIXME(x) switch ((uint64)(x))
|
||||
|
||||
|
||||
/*
|
||||
* When clang static analyzer parses source files, it implicitly defines
|
||||
* __clang_analyzer__ macro. We use this to define our custom macro to stop
|
||||
* its execution for the current path of analysis by calling a function that
|
||||
* doesn't return, making it think that it hit a failed assertion.
|
||||
*
|
||||
* DO NOT use to silence the analyzer! See PR2447238.
|
||||
*/
|
||||
#ifdef __clang_analyzer__
|
||||
#define VMW_CLANG_ANALYZER_NORETURN() Panic("Disable Clang static analyzer")
|
||||
#else
|
||||
#define VMW_CLANG_ANALYZER_NORETURN() ((void)0)
|
||||
#endif
|
||||
|
||||
#endif // ifndef _VM_BASIC_DEFS_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2008-2017 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2008-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -38,10 +38,6 @@
|
||||
#include "vm_basic_types.h" // For INLINE.
|
||||
#include "vm_basic_asm.h" // For Div64...
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
static INLINE uint32
|
||||
RatioOf(uint32 numer1, uint32 numer2, uint32 denom)
|
||||
@@ -66,36 +62,13 @@ ExponentialAvg(uint32 avg, uint32 value, uint32 gainNumer, uint32 gainDenom)
|
||||
return (term1 + term2) / gainDenom;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* IsZeroOrPowerOfTwo --
|
||||
* IsZeroOrPowerOfTwo64 --
|
||||
*
|
||||
* Results:
|
||||
* TRUE iff the value is 0 or a power of two.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE Bool
|
||||
IsZeroOrPowerOfTwo64(uint64 x)
|
||||
IsPowerOfTwo(uint32 x)
|
||||
{
|
||||
/* Does not check for zero. Callers depend on this. */
|
||||
return !(x & (x - 1));
|
||||
}
|
||||
|
||||
|
||||
static INLINE Bool
|
||||
IsZeroOrPowerOfTwo(uint32 x) // IN
|
||||
{
|
||||
return !(x & (x - 1));
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint32
|
||||
GetPowerOfTwo(uint32 x)
|
||||
{
|
||||
@@ -190,8 +163,4 @@ RotateRight64(uint64 value, uint8 shift)
|
||||
#endif // if !defined(_WIN32) && !defined(_WIN64)
|
||||
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // ifndef _VM_BASIC_MATH_H_
|
||||
+339
-209
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -38,6 +38,24 @@
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
|
||||
/* STRICT ANSI means the Xserver build and X defines Bool differently. */
|
||||
#if !defined(_XTYPEDEF_BOOL) && \
|
||||
(!defined(__STRICT_ANSI__) || defined(__FreeBSD__) || defined(__MINGW32__))
|
||||
#define _XTYPEDEF_BOOL
|
||||
typedef char Bool;
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define IsBool(x) (((x) & ~1) == 0)
|
||||
#define IsBool2(x, y) ((((x) | (y)) & ~1) == 0)
|
||||
|
||||
/*
|
||||
* Macros __i386__ and __ia64 are intrinsically defined by GCC
|
||||
*/
|
||||
@@ -63,9 +81,17 @@
|
||||
* - VM_<arch>_32 for the 32-bit variant.
|
||||
* - VM_<arch>_64 for the 64-bit variant.
|
||||
* - VM_<arch>_ANY for any variant of <arch>.
|
||||
*
|
||||
* VM_X86_ANY is synonymous with the confusing and deprecated VM_I386 (which
|
||||
* should really be VM_X86_32).
|
||||
*/
|
||||
|
||||
#ifdef __i386__
|
||||
/* VM_I386 is historically synonymous with VM_X86_ANY in bora, but misleading,
|
||||
* since it is confused with the __i386__ gcc but defined for both 32- and
|
||||
* 64-bit x86. We retain it here for legacy compatibility.
|
||||
*/
|
||||
#define VM_I386
|
||||
#define VM_X86_32
|
||||
#define VM_X86_ANY
|
||||
#define VM_32BIT
|
||||
@@ -73,11 +99,12 @@
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define VM_X86_64
|
||||
#define vm_x86_64 1
|
||||
#define VM_I386
|
||||
#define VM_X86_ANY
|
||||
#define VM_64BIT
|
||||
#define vm_x86_64 (1)
|
||||
#else
|
||||
#define vm_x86_64 0
|
||||
#define vm_x86_64 (0)
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
@@ -88,20 +115,17 @@
|
||||
|
||||
#ifdef __aarch64__
|
||||
#define VM_ARM_64
|
||||
#define vm_arm_64 1
|
||||
#define VM_ARM_ANY
|
||||
#define VM_64BIT
|
||||
#define vm_arm_64 (1)
|
||||
#else
|
||||
#define vm_arm_64 0
|
||||
#define vm_arm_64 (0)
|
||||
#endif
|
||||
|
||||
#define vm_64bit (sizeof (void *) == 8)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma warning (3 :4505) // unreferenced local function
|
||||
#pragma warning (disable :4018) // signed/unsigned mismatch
|
||||
#pragma warning (suppress:4619) // suppress warning next line (C4761 was removed in vs2019u4)
|
||||
#pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied
|
||||
#pragma warning (disable :4305) // truncation from 'const int' to 'short'
|
||||
#pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char'
|
||||
@@ -111,91 +135,16 @@
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) && (__FreeBSD__ + 0 < 5)
|
||||
# error FreeBSD detected without major version (PR 2116887)
|
||||
#endif
|
||||
#if defined(__linux__) && defined(__cplusplus) && __cplusplus >= 201103L
|
||||
|
||||
/*
|
||||
* C99 <stdint.h> or equivalent
|
||||
* Special cases:
|
||||
* - Linux kernel lacks <stdint.h>, preferring <linux/types.h>
|
||||
* (and defines uintptr_t since 2.6.24, but not intptr_t)
|
||||
* - Solaris collides with gcc <stdint.h>, but has <sys/stdint.h>
|
||||
* - VMKernel + FreeBSD collides with gcc <stdint.h>, but has <sys/stdint.h>
|
||||
* - VMKernel (+DECODERLIB) share macros with Linux kernel
|
||||
* - Windows only added <stdint.h> in vc10/vs2010 (MSC ver 1600),
|
||||
* and WDKs lack it.
|
||||
*
|
||||
* NB about LLP64 in LP64 environments:
|
||||
* - Apple uses 'long long' uint64_t
|
||||
* - Linux kernel uses 'long long' uint64_t
|
||||
* - Linux userlevel uses 'long' uint64_t
|
||||
* We're using stdint.h instead of cstdint below because of libstdcpp.cpp.
|
||||
* It looks like a C++ file. When being preprocessed all the C++ specific
|
||||
* defines(e.g. __cplusplus) are set, but the C++ include paths are not.
|
||||
*/
|
||||
#if !defined(VMKERNEL) && !defined(DECODERLIB) && \
|
||||
defined(__linux__) && defined(__KERNEL__)
|
||||
# include <linux/types.h>
|
||||
# include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
|
||||
typedef unsigned long uintptr_t;
|
||||
#endif
|
||||
typedef signed long intptr_t;
|
||||
#elif (defined(__sun__) && defined(_KERNEL)) || \
|
||||
(defined(VMKERNEL) && defined(__FreeBSD__)) || \
|
||||
defined(_SYS_STDINT_H_)
|
||||
# include <sys/stdint.h>
|
||||
#elif !defined(_MSC_VER)
|
||||
/* Common case */
|
||||
# include <stdint.h>
|
||||
#else
|
||||
/* COMPAT: until pre-vc10 is retired */
|
||||
# include <crtdefs.h> // uintptr_t
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
typedef __int64 int64_t;
|
||||
typedef int int32_t;
|
||||
typedef short int16_t;
|
||||
typedef signed char int8_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* size_t and ssize_t, or equivalent
|
||||
* Options:
|
||||
* C90+ <stddef.h> has size_t, but is incompatible with many kernels.
|
||||
* POSIX <sys/types.h> has size_t and ssize_t, is always available at
|
||||
* userlevel but is missing from some kernels.
|
||||
*
|
||||
* Special cases:
|
||||
* - Linux kernel (again) does everything via <linux/types.h>
|
||||
* - VMKernel may or may not have POSIX headers (tcpip only)
|
||||
* - VMM does not have POSIX headers
|
||||
* - Windows <sys/types.h> does not define ssize_t
|
||||
*/
|
||||
#if defined(VMKERNEL) || defined(VMM) || defined(DECODERLIB)
|
||||
/* Guard against FreeBSD <sys/types.h> collison. */
|
||||
# if !defined(_SIZE_T_DEFINED) && !defined(_SIZE_T)
|
||||
# define _SIZE_T_DEFINED
|
||||
# define _SIZE_T
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
#endif
|
||||
# if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T)
|
||||
# define _SSIZE_T_DEFINED
|
||||
# define _SSIZE_T
|
||||
typedef int64_t ssize_t;
|
||||
# endif
|
||||
#elif defined(__linux__) && defined(__KERNEL__)
|
||||
/* <linux/types.h> provided size_t, ssize_t. */
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# if defined(_WIN64)
|
||||
typedef int64_t ssize_t;
|
||||
# elif defined(_WIN32)
|
||||
typedef int32_t ssize_t;
|
||||
# endif
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
typedef char Bool;
|
||||
|
||||
typedef uint64_t uint64;
|
||||
typedef int64_t int64;
|
||||
@@ -206,35 +155,78 @@ typedef int16_t int16;
|
||||
typedef uint8_t uint8;
|
||||
typedef int8_t int8;
|
||||
|
||||
typedef uint64 BA;
|
||||
typedef uint64 MA;
|
||||
typedef uint32 MPN32;
|
||||
|
||||
#elif defined(__APPLE__) || defined(HAVE_STDINT_H)
|
||||
|
||||
/*
|
||||
* The _XTYPEDEF_BOOL guard prevents colliding with:
|
||||
* <X11/Xlib.h> #define Bool int
|
||||
* <X11/Xdefs.h> typedef int Bool;
|
||||
* If using this header AND X11 headers, be sure to #undef Bool and
|
||||
* be careful about the different size.
|
||||
* TODO: This is a C99 standard header. We should be able to test for
|
||||
* #if __STDC_VERSION__ >= 199901L, but that breaks the Netware build
|
||||
* (which doesn't have stdint.h).
|
||||
*/
|
||||
#if !defined(_XTYPEDEF_BOOL)
|
||||
#define _XTYPEDEF_BOOL
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint64_t uint64;
|
||||
typedef int64_t int64;
|
||||
typedef uint32_t uint32;
|
||||
typedef int32_t int32;
|
||||
typedef uint16_t uint16;
|
||||
typedef int16_t int16;
|
||||
typedef uint8_t uint8;
|
||||
typedef int8_t int8;
|
||||
|
||||
/*
|
||||
* C does not specify whether char is signed or unsigned, and
|
||||
* both gcc and msvc implement it as a non-signed, non-unsigned type.
|
||||
* Thus, (uint8_t *)&Bool and (int8_t *)&Bool are possible compile errors.
|
||||
* This is intentional.
|
||||
* Note: C does not specify whether char is signed or unsigned, and
|
||||
* both gcc and msvc implement processor-specific signedness. With
|
||||
* three types:
|
||||
* typeof(char) != typeof(signed char) != typeof(unsigned char)
|
||||
*
|
||||
* Be careful here, because gcc (4.0.1 and others) likes to warn about
|
||||
* conversions between signed char * and char *.
|
||||
*/
|
||||
typedef char Bool;
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#else /* !HAVE_STDINT_H */
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#define IS_BOOL(x) (((x) & ~1) == 0)
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef signed __int64 int64;
|
||||
|
||||
#elif __GNUC__
|
||||
/* The Xserver source compiles with -ansi -pendantic */
|
||||
# if !defined(__STRICT_ANSI__) || defined(__FreeBSD__)
|
||||
# if defined(VM_X86_64) || defined(VM_ARM_64)
|
||||
typedef unsigned long uint64;
|
||||
typedef long int64;
|
||||
# else
|
||||
typedef unsigned long long uint64;
|
||||
typedef long long int64;
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
# error - Need compiler define for int64/uint64
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned char uint8;
|
||||
|
||||
typedef int int32;
|
||||
typedef short int16;
|
||||
typedef signed char int8;
|
||||
|
||||
#endif /* HAVE_STDINT_H */
|
||||
|
||||
/*
|
||||
* FreeBSD (for the tools build) unconditionally defines these in
|
||||
* sys/inttypes.h so don't redefine them if this file has already
|
||||
* been included. [greg]
|
||||
*
|
||||
* This applies to Solaris as well.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Before trying to do the includes based on OS defines, see if we can use
|
||||
@@ -244,6 +236,9 @@ typedef char Bool;
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_INTTYPES_H
|
||||
#include <sys/inttypes.h>
|
||||
#endif
|
||||
@@ -257,11 +252,14 @@ typedef char Bool;
|
||||
|
||||
#if !defined(USING_AUTOCONF)
|
||||
# if defined(__FreeBSD__) || defined(sun)
|
||||
# ifndef KLD_MODULE
|
||||
# ifdef KLD_MODULE
|
||||
# include <sys/types.h>
|
||||
# else
|
||||
# if __FreeBSD_version >= 500043
|
||||
# if !defined(VMKERNEL)
|
||||
# include <inttypes.h>
|
||||
# endif
|
||||
# include <sys/types.h>
|
||||
# else
|
||||
# include <sys/inttypes.h>
|
||||
# endif
|
||||
@@ -269,28 +267,51 @@ typedef char Bool;
|
||||
# elif defined __APPLE__
|
||||
# if KERNEL
|
||||
# include <sys/unistd.h>
|
||||
# include <sys/types.h> /* mostly for size_t */
|
||||
# include <stdint.h>
|
||||
# else
|
||||
# include <unistd.h>
|
||||
# include <inttypes.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdint.h>
|
||||
# endif
|
||||
# elif defined __ANDROID__
|
||||
# include <stdint.h>
|
||||
# else
|
||||
# if !defined(__intptr_t_defined) && !defined(intptr_t)
|
||||
# ifdef VM_I386
|
||||
# define __intptr_t_defined
|
||||
# if defined(VM_X86_64)
|
||||
typedef int64 intptr_t;
|
||||
# else
|
||||
typedef int32 intptr_t;
|
||||
# endif
|
||||
# elif defined(VM_ARM_64)
|
||||
# define __intptr_t_defined
|
||||
typedef int64 intptr_t;
|
||||
# elif defined(__arm__)
|
||||
# define __intptr_t_defined
|
||||
typedef int32 intptr_t;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef _STDINT_H
|
||||
# ifdef VM_I386
|
||||
# if defined(VM_X86_64)
|
||||
typedef uint64 uintptr_t;
|
||||
# else
|
||||
typedef uint32 uintptr_t;
|
||||
# endif
|
||||
# elif defined(VM_ARM_64)
|
||||
typedef uint64 uintptr_t;
|
||||
# elif defined(__arm__)
|
||||
typedef uint32 uintptr_t;
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__GNUC__) && defined(__SIZEOF_INT128__)
|
||||
|
||||
typedef unsigned __int128 uint128;
|
||||
typedef __int128 int128;
|
||||
|
||||
#define MIN_INT128 ((int128)1 << 127)
|
||||
#define MAX_INT128 (~MIN_INT128)
|
||||
#define MIN_UINT128 ((uint128)0)
|
||||
#define MAX_UINT128 (~MIN_UINT128)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Time
|
||||
* XXX These should be cleaned up. -- edward
|
||||
@@ -310,7 +331,6 @@ typedef int64 VmTimeVirtualClock; /* Virtual Clock kept in CPU cycles */
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* MSVC added C99-compatible formatting in vs2015. */
|
||||
#define FMT64 "I64"
|
||||
#ifdef VM_X86_64
|
||||
#define FMTSZ "I64"
|
||||
@@ -321,31 +341,60 @@ typedef int64 VmTimeVirtualClock; /* Virtual Clock kept in CPU cycles */
|
||||
#define FMTPD "I"
|
||||
#define FMTH "I"
|
||||
#endif
|
||||
#elif defined __APPLE__ || (!defined VMKERNEL && !defined DECODERLIB && \
|
||||
defined __linux__ && defined __KERNEL__)
|
||||
/* semi-LLP64 targets; 'long' is 64-bit, but uint64_t is 'long long' */
|
||||
#define FMT64 "ll"
|
||||
#if defined(__APPLE__) && KERNEL
|
||||
/* macOS osfmk/kern added 'z' length specifier in 10.13 */
|
||||
#define FMTSZ "l"
|
||||
#elif defined __APPLE__
|
||||
/* Mac OS hosts use the same formatters for 32- and 64-bit. */
|
||||
#define FMT64 "ll"
|
||||
#if KERNEL
|
||||
#define FMTSZ "l"
|
||||
#else
|
||||
#define FMTSZ "z"
|
||||
#define FMTSZ "z"
|
||||
#endif
|
||||
#define FMTPD "l"
|
||||
#define FMTH ""
|
||||
#elif defined __GNUC__
|
||||
/*
|
||||
* Every POSIX system we target has C99-compatible printf
|
||||
* (supports 'z' for size_t and 'll' for long long).
|
||||
*/
|
||||
#define FMTH ""
|
||||
#define FMTSZ "z"
|
||||
#if defined(VM_X86_64) || defined(VM_ARM_64)
|
||||
#define FMT64 "l"
|
||||
#define FMTPD "l"
|
||||
#define FMTPD "l"
|
||||
#define FMTH ""
|
||||
#elif __GNUC__
|
||||
#define FMTH ""
|
||||
#if defined(N_PLAT_NLM) || defined(sun) || \
|
||||
(defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5))
|
||||
/*
|
||||
* Why (__FreeBSD__ + 0)? See bug 141008.
|
||||
* Yes, we really need to test both (__FreeBSD__ + 0) and
|
||||
* ((__FreeBSD__ + 0) < 5). No, we can't remove "+ 0" from
|
||||
* ((__FreeBSD__ + 0) < 5).
|
||||
*/
|
||||
#if defined(VM_X86_64) || defined(VM_ARM_64)
|
||||
#define FMTSZ "l"
|
||||
#define FMTPD "l"
|
||||
#else
|
||||
#define FMTSZ ""
|
||||
#define FMTPD ""
|
||||
#endif
|
||||
#elif defined(__linux__) \
|
||||
|| (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \
|
||||
|| (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \
|
||||
|| (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L)
|
||||
/* BSD, Linux */
|
||||
#define FMTSZ "z"
|
||||
|
||||
#if defined(VM_X86_64) || defined(VM_ARM_64)
|
||||
#define FMTPD "l"
|
||||
#else
|
||||
#define FMTPD ""
|
||||
#endif
|
||||
#else
|
||||
#define FMT64 "ll"
|
||||
#define FMTPD ""
|
||||
/* Systems with a pre-C99 libc */
|
||||
#define FMTSZ "Z"
|
||||
#if defined(VM_X86_64) || defined(VM_ARM_64)
|
||||
#define FMTPD "l"
|
||||
#else
|
||||
#define FMTPD ""
|
||||
#endif
|
||||
#endif
|
||||
#if defined(VM_X86_64) || defined(VM_ARM_64)
|
||||
#define FMT64 "l"
|
||||
#elif defined(sun) || defined(__FreeBSD__)
|
||||
#define FMT64 "ll"
|
||||
#else
|
||||
#define FMT64 "L"
|
||||
#endif
|
||||
#else
|
||||
#error - Need compiler define for FMT64 and FMTSZ
|
||||
@@ -429,22 +478,26 @@ typedef uint8 *TCA; /* Pointer into TC (usually). */
|
||||
* Type big enough to hold an integer between 0..100
|
||||
*/
|
||||
typedef uint8 Percent;
|
||||
#define AsPercent(v) ((Percent)(v))
|
||||
#define AsPercent(v) ((Percent)(v))
|
||||
|
||||
|
||||
typedef uintptr_t VA;
|
||||
typedef uintptr_t VPN;
|
||||
|
||||
typedef uint64 PA;
|
||||
typedef uint64 PPN;
|
||||
typedef uint32 PPN;
|
||||
|
||||
typedef uint64 TPA;
|
||||
typedef uint64 TPPN;
|
||||
typedef uint32 TPPN;
|
||||
|
||||
typedef uint64 PhysMemOff;
|
||||
typedef uint64 PhysMemSize;
|
||||
|
||||
/* The Xserver source compiles with -ansi -pendantic */
|
||||
#ifndef __STRICT_ANSI__
|
||||
typedef uint64 BA;
|
||||
#endif
|
||||
|
||||
#ifdef VMKERNEL
|
||||
typedef void *BPN;
|
||||
#else
|
||||
@@ -454,10 +507,9 @@ typedef uint64 BPN;
|
||||
#define UINT64_2_BPN(u) ((BPN)(u))
|
||||
#define BPN_2_UINT64(b) ((uint64)(b))
|
||||
|
||||
typedef uint64 PageCnt;
|
||||
typedef uint64 PageNum;
|
||||
typedef unsigned MemHandle;
|
||||
typedef unsigned IoHandle;
|
||||
typedef uint32 PageNum;
|
||||
typedef unsigned MemHandle;
|
||||
typedef unsigned int IoHandle;
|
||||
typedef int32 World_ID;
|
||||
|
||||
/* !! do not alter the definition of INVALID_WORLD_ID without ensuring
|
||||
@@ -491,18 +543,16 @@ typedef uint16 UReg16;
|
||||
typedef uint32 UReg32;
|
||||
typedef uint64 UReg64;
|
||||
|
||||
#if defined(__GNUC__) && defined(__SIZEOF_INT128__)
|
||||
typedef int128 Reg128;
|
||||
typedef uint128 UReg128;
|
||||
#endif
|
||||
|
||||
#if defined(VMM) || defined(COREQUERY) || defined(EXTDECODER) || \
|
||||
defined (VMKERNEL) || defined (VMKBOOT) || defined (ULM)
|
||||
defined (VMKERNEL) || defined (VMKBOOT)
|
||||
typedef Reg64 Reg;
|
||||
typedef UReg64 UReg;
|
||||
#endif
|
||||
/* The Xserver source compiles with -ansi -pendantic */
|
||||
#ifndef __STRICT_ANSI__
|
||||
typedef uint64 MA;
|
||||
typedef uint32 MPN32;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This type should be used for variables that contain sector
|
||||
@@ -553,7 +603,6 @@ typedef uint64 LA64;
|
||||
typedef uint64 LPN64;
|
||||
typedef uint64 PA64;
|
||||
typedef uint64 PPN64;
|
||||
typedef uint64 TPPN64;
|
||||
typedef uint64 MA64;
|
||||
typedef uint64 MPN;
|
||||
|
||||
@@ -579,15 +628,12 @@ typedef void * UserVA;
|
||||
#endif
|
||||
|
||||
|
||||
/* Maximal observable PPN value. */
|
||||
#define MAX_PPN_BITS 33
|
||||
#define MAX_PPN (((PPN)1 << MAX_PPN_BITS) - 1)
|
||||
#define MAX_PPN_BITS 31
|
||||
#define MAX_PPN (((PPN)1 << MAX_PPN_BITS) - 1) /* Maximal observable PPN value. */
|
||||
#define INVALID_PPN ((PPN)0xffffffff)
|
||||
#define APIC_INVALID_PPN ((PPN)0xfffffffe)
|
||||
|
||||
#define INVALID_PPN ((PPN)0x000fffffffffffffull)
|
||||
#define INVALID_PPN32 ((PPN32)0xffffffff)
|
||||
#define APIC_INVALID_PPN ((PPN)0x000ffffffffffffeull)
|
||||
|
||||
#define INVALID_BPN ((BPN)0x0000ffffffffffffull)
|
||||
#define INVALID_BPN ((BPN)0x000000ffffffffffull)
|
||||
|
||||
#define MPN38_MASK ((1ull << 38) - 1)
|
||||
|
||||
@@ -605,8 +651,7 @@ typedef void * UserVA;
|
||||
#define INVALID_LPN ((LPN)-1)
|
||||
#define INVALID_VPN ((VPN)-1)
|
||||
#define INVALID_LPN64 ((LPN64)-1)
|
||||
#define INVALID_PAGENUM ((PageNum)0x000000ffffffffffull)
|
||||
#define INVALID_PAGENUM32 ((uint32)-1)
|
||||
#define INVALID_PAGENUM ((PageNum)-1)
|
||||
|
||||
/*
|
||||
* Format modifier for printing VA, LA, and VPN.
|
||||
@@ -628,17 +673,10 @@ typedef void * UserVA;
|
||||
#endif
|
||||
#define CONST const
|
||||
|
||||
|
||||
#ifndef INLINE
|
||||
# ifdef _MSC_VER
|
||||
/*
|
||||
* On UWP(Universal Windows Platform),
|
||||
* Only X86 32bit support '__inline'
|
||||
*/
|
||||
# if defined(VM_WIN_UWP) && !defined(VM_X86_32)
|
||||
# define INLINE
|
||||
# else
|
||||
# define INLINE __inline
|
||||
# endif
|
||||
# define INLINE __inline
|
||||
# else
|
||||
# define INLINE inline
|
||||
# endif
|
||||
@@ -688,28 +726,14 @@ typedef void * UserVA;
|
||||
|
||||
/*
|
||||
* At present, we effectively require a compiler that is at least
|
||||
* gcc-4.1 (circa 2006). Enforce this here, various things below
|
||||
* gcc-3.3 (circa 2003). Enforce this here, various things below
|
||||
* this line depend upon it.
|
||||
*
|
||||
* Current oldest compilers:
|
||||
* - guest tools: 4.1.2 (freebsd/solaris)
|
||||
* - buildhost compiler: 4.4.3
|
||||
* - hosted kernel modules: 4.5
|
||||
*
|
||||
* SWIG's preprocessor is exempt.
|
||||
* In practice, most things presently compile with gcc-4.1 or gcc-4.4.
|
||||
* The various linux kernel modules may use older (gcc-3.3) compilers.
|
||||
*/
|
||||
#ifndef SWIG
|
||||
#if defined __GNUC__ && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1))
|
||||
#error "gcc version is too old, need gcc-4.1 or better"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Similarly, we require a compiler that is at least vs2012.
|
||||
* Enforce this here.
|
||||
*/
|
||||
#if defined _MSC_VER && _MSC_VER < 1700
|
||||
#error "cl.exe version is too old, need vs2012 or better"
|
||||
#if defined __GNUC__ && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3))
|
||||
#error "gcc version is too old to compile assembly, need gcc-3.3 or better"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -740,7 +764,7 @@ typedef void * UserVA;
|
||||
#define INLINE_SINGLE_CALLER INLINE_ALWAYS
|
||||
|
||||
/*
|
||||
* Used when a hard guarantee of no inlining is needed. Very few
|
||||
* Used when a hard guaranteed of no inlining is needed. Very few
|
||||
* instances need this since the absence of INLINE is a good hint
|
||||
* that gcc will not do inlining.
|
||||
*/
|
||||
@@ -825,7 +849,7 @@ typedef void * UserVA;
|
||||
* will convert any !=0 to a 1.
|
||||
*/
|
||||
#define LIKELY(_exp) __builtin_expect(!!(_exp), 1)
|
||||
#define UNLIKELY(_exp) __builtin_expect(!!(_exp), 0)
|
||||
#define UNLIKELY(_exp) __builtin_expect((_exp), 0)
|
||||
#else
|
||||
#define LIKELY(_exp) (_exp)
|
||||
#define UNLIKELY(_exp) (_exp)
|
||||
@@ -863,18 +887,18 @@ typedef void * UserVA;
|
||||
#ifndef UNUSED_PARAM
|
||||
# if defined(__GNUC__)
|
||||
# define UNUSED_PARAM(_parm) _parm __attribute__((__unused__))
|
||||
# elif defined _MSC_VER
|
||||
# define UNUSED_PARAM(_parm) __pragma(warning(suppress:4100)) _parm
|
||||
# else
|
||||
# define UNUSED_PARAM(_parm) _parm
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef UNUSED_TYPE
|
||||
// XXX _Pragma would better but doesn't always work right now.
|
||||
# define UNUSED_TYPE(_parm) UNUSED_PARAM(_parm)
|
||||
#endif
|
||||
|
||||
#ifndef UNUSED_VARIABLE
|
||||
// XXX is there a better way?
|
||||
# define UNUSED_VARIABLE(_var) (void)_var
|
||||
#endif
|
||||
|
||||
@@ -889,21 +913,14 @@ typedef void * UserVA;
|
||||
|
||||
/*
|
||||
* ALIGNED specifies minimum alignment in "n" bytes.
|
||||
*
|
||||
* NOTE: __declspec(align) has limited syntax; it must essentially be
|
||||
* an integer literal. Expressions, such as sizeof(), do not
|
||||
* work.
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ALIGNED(n) __attribute__((__aligned__(n)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define ALIGNED(n) __declspec(align(n))
|
||||
#else
|
||||
#define ALIGNED(n)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Once upon a time, this was used to silence compiler warnings that
|
||||
* get generated when the compiler thinks that a function returns
|
||||
@@ -912,6 +929,82 @@ typedef void * UserVA;
|
||||
|
||||
#define INFINITE_LOOP() do { } while (1)
|
||||
|
||||
/*
|
||||
* On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_
|
||||
* is defined. Use the same logic here so we don't define it twice. [greg]
|
||||
*/
|
||||
#ifdef __FreeBSD__
|
||||
# ifdef _BSD_SIZE_T_
|
||||
# undef _BSD_SIZE_T_
|
||||
# ifdef VM_I386
|
||||
# ifdef VM_X86_64
|
||||
typedef uint64 size_t;
|
||||
# else
|
||||
typedef uint32 size_t;
|
||||
# endif
|
||||
# endif /* VM_I386 */
|
||||
# endif
|
||||
|
||||
# ifdef _BSD_SSIZE_T_
|
||||
# undef _BSD_SSIZE_T_
|
||||
# ifdef VM_I386
|
||||
# ifdef VM_X86_64
|
||||
typedef int64 ssize_t;
|
||||
# else
|
||||
typedef int32 ssize_t;
|
||||
# endif
|
||||
# endif /* VM_I386 */
|
||||
# endif
|
||||
|
||||
#else
|
||||
# if !defined(_SIZE_T) && !defined(_SIZE_T_DEFINED)
|
||||
# ifdef VM_I386
|
||||
# define _SIZE_T
|
||||
# ifdef VM_X86_64
|
||||
typedef uint64 size_t;
|
||||
# else
|
||||
typedef uint32 size_t;
|
||||
# endif
|
||||
# elif defined(VM_ARM_64)
|
||||
# define _SIZE_T
|
||||
typedef uint64 size_t;
|
||||
# elif defined(__arm__)
|
||||
# define _SIZE_T
|
||||
typedef uint32 size_t;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(_SSIZE_T_) && \
|
||||
!defined(ssize_t) && !defined(__ssize_t_defined) && \
|
||||
!defined(_SSIZE_T_DECLARED) && !defined(_SSIZE_T_DEFINED) && \
|
||||
!defined(_SSIZE_T_DEFINED_)
|
||||
# ifdef VM_I386
|
||||
# define _SSIZE_T
|
||||
# define __ssize_t_defined
|
||||
# define _SSIZE_T_DECLARED
|
||||
# define _SSIZE_T_DEFINED_
|
||||
# ifdef VM_X86_64
|
||||
typedef int64 ssize_t;
|
||||
# else
|
||||
typedef int32 ssize_t;
|
||||
# endif
|
||||
# elif defined(VM_ARM_64)
|
||||
# define _SSIZE_T
|
||||
# define __ssize_t_defined
|
||||
# define _SSIZE_T_DECLARED
|
||||
# define _SSIZE_T_DEFINED_
|
||||
typedef int64 ssize_t;
|
||||
# elif defined(__arm__)
|
||||
# define _SSIZE_T
|
||||
# define __ssize_t_defined
|
||||
# define _SSIZE_T_DECLARED
|
||||
# define _SSIZE_T_DEFINED_
|
||||
typedef int32 ssize_t;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Format modifier for printing pid_t. On sun the pid_t is a ulong, but on
|
||||
* Linux it's an int.
|
||||
@@ -957,6 +1050,33 @@ typedef void * UserVA;
|
||||
# define FMTMODE "o"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Format modifier for printing time_t. Most platforms define a time_t to be
|
||||
* a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed
|
||||
* size quantity. Refer to the definition of FMTSZ to see why we need silly
|
||||
* preprocessor arithmetic.
|
||||
* Use this like this: printf("The mode is %" FMTTIME ".\n", time);
|
||||
*/
|
||||
#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5)
|
||||
# define FMTTIME FMTSZ"d"
|
||||
#else
|
||||
# if defined(_MSC_VER)
|
||||
# ifndef _SAFETIME_H_
|
||||
# if (_MSC_VER < 1400) || defined(_USE_32BIT_TIME_T)
|
||||
# define FMTTIME "ld"
|
||||
# else
|
||||
# define FMTTIME FMT64"d"
|
||||
# endif
|
||||
# else
|
||||
# ifndef FMTTIME
|
||||
# error "safetime.h did not define FMTTIME"
|
||||
# endif
|
||||
# endif
|
||||
# else
|
||||
# define FMTTIME "ld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
/*
|
||||
* Format specifier for all these annoying types such as {S,U}Int32
|
||||
@@ -982,6 +1102,16 @@ typedef void * UserVA;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define MXSemaHandle here so both vmmon and vmx see this definition.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef uintptr_t MXSemaHandle;
|
||||
#else
|
||||
typedef int MXSemaHandle;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define type for poll device handles.
|
||||
*/
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2012,2017-2018,2020 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* vm_idt_x86.h --
|
||||
*
|
||||
* Definitions for IDT use in x86/x86-64 ESX and hosted VMware Products.
|
||||
*/
|
||||
|
||||
#ifndef _VM_IDT_X86_H_
|
||||
#define _VM_IDT_X86_H_
|
||||
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_VMK_MODULE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* User worlds are the only worlds that expect to receive
|
||||
* interrupts on a stack specified in the %rsp entries of
|
||||
* the TSS.
|
||||
*/
|
||||
#define TSS_RSP0 0
|
||||
#define TSS_RSP1 1
|
||||
#define TSS_RSP2 2
|
||||
|
||||
/*
|
||||
* The monitor and the vmkernel use gate stub handlers of a single size in
|
||||
* their IDTs. The only exception is the #PF gate (#14) which is twice as
|
||||
* long in the monitor IDT, to copy CR2.
|
||||
*/
|
||||
#define IDT_STUB_SIZE 16
|
||||
|
||||
#define IST_NONE 0
|
||||
/* IST entries for the monitor. */
|
||||
#define IST_VMM_DF 1
|
||||
#define IST_VMM_NMI 2
|
||||
#define IST_VMM_MCE 3
|
||||
#define MAX_VMM_IST 3
|
||||
/* IST entries for the vmkernel. */
|
||||
#define IST_VMK_MCE 5
|
||||
#define IST_VMK_DF 6
|
||||
#define IST_VMK_NMI 7
|
||||
|
||||
|
||||
static INLINE int
|
||||
IDT_MonitorISTForVector(int v)
|
||||
{
|
||||
/*
|
||||
* For non-SVM execution, the monitor uses the IST for #DF, #NMI, and #MC.
|
||||
*/
|
||||
if (v == EXC_DF) {
|
||||
return IST_VMM_DF;
|
||||
} else if (v == EXC_NMI) {
|
||||
return IST_VMM_NMI;
|
||||
} else if (v == EXC_MC) {
|
||||
return IST_VMM_MCE;
|
||||
}
|
||||
return IST_NONE;
|
||||
}
|
||||
|
||||
#if defined __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* _VM_IDT_X86_H_ */
|
||||
@@ -1,140 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2014-2019 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* vm_pagetable.h --
|
||||
*
|
||||
* Virtual memory page table definitions
|
||||
*/
|
||||
|
||||
#ifndef _VM_PAGETABLE_H_
|
||||
#define _VM_PAGETABLE_H_
|
||||
|
||||
#define INCLUDE_ALLOW_MODULE
|
||||
#define INCLUDE_ALLOW_VMK_MODULE
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_DISTRIBUTE
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#define INCLUDE_ALLOW_USERLEVEL
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include "vm_basic_types.h"
|
||||
#include "vm_basic_defs.h"
|
||||
|
||||
/*
|
||||
* These definitions suit both the x64 and arm64 architectures. In particular
|
||||
* - At all levels, a page table is a 4KB page containing 512 8-byte entries.
|
||||
* - Each entry maps 48, 39, 30, 21 and 12 bits at the respective page table
|
||||
* levels (with standard page sizes).
|
||||
*/
|
||||
|
||||
typedef uint64 PT_Entry;
|
||||
typedef PT_Entry PT_L5E;
|
||||
typedef PT_Entry PT_L4E;
|
||||
typedef PT_Entry PT_L3E;
|
||||
typedef PT_Entry PT_L2E;
|
||||
typedef PT_Entry PT_L1E;
|
||||
|
||||
typedef enum {
|
||||
PT_LEVEL_1 = 1,
|
||||
PT_LEVEL_2,
|
||||
PT_LEVEL_3,
|
||||
PT_LEVEL_4,
|
||||
PT_LEVEL_5,
|
||||
PT_LEVEL_STOP = PT_LEVEL_1,
|
||||
PT_MAX_LEVELS = PT_LEVEL_5
|
||||
} PT_Level;
|
||||
|
||||
#define PT_PTE_SIZE 8
|
||||
#define PT_LEVEL_SHIFT 9
|
||||
|
||||
#define PT_PTE_PFN_SHIFT PAGE_SHIFT
|
||||
#define PT_ENTRIES_PER_PT (1 << PT_LEVEL_SHIFT)
|
||||
#define PT_OFF_MASK (PT_ENTRIES_PER_PT - 1)
|
||||
|
||||
/* Align any page number type to the 2M containing page number. */
|
||||
#define PT_2M_ALIGN_PN(x) ((x) & ~PT_OFF_MASK)
|
||||
|
||||
/*
|
||||
* log2 of the
|
||||
* address space size (in 4KB pages) covered by a level-_l page table entry.
|
||||
*/
|
||||
#define PT_LE_PG_SHIFT(_l) (PT_LEVEL_SHIFT * ((_l) - PT_LEVEL_1))
|
||||
|
||||
/* Address space size (in 4KB pages) covered by a level-_l page table entry. */
|
||||
#define PT_PAGES_PER_LE(_l) ((uint64)1 << PT_LE_PG_SHIFT(_l))
|
||||
#define PT_PAGES_PER_L5E PT_PAGES_PER_LE(PT_LEVEL_5)
|
||||
#define PT_PAGES_PER_L4E PT_PAGES_PER_LE(PT_LEVEL_4)
|
||||
#define PT_PAGES_PER_L3E PT_PAGES_PER_LE(PT_LEVEL_3)
|
||||
#define PT_PAGES_PER_L2E PT_PAGES_PER_LE(PT_LEVEL_2)
|
||||
#define PT_PAGES_PER_L1E PT_PAGES_PER_LE(PT_LEVEL_1)
|
||||
|
||||
/*
|
||||
* log2 of the
|
||||
* address space size (in bytes) covered by a level-_l page table entry.
|
||||
*/
|
||||
#define PT_LE_SHIFT(_l) (PAGE_SHIFT + PT_LE_PG_SHIFT(_l))
|
||||
#define PT_L5E_SHIFT PT_LE_SHIFT(PT_LEVEL_5)
|
||||
#define PT_L4E_SHIFT PT_LE_SHIFT(PT_LEVEL_4)
|
||||
#define PT_L3E_SHIFT PT_LE_SHIFT(PT_LEVEL_3)
|
||||
#define PT_L2E_SHIFT PT_LE_SHIFT(PT_LEVEL_2)
|
||||
#define PT_L1E_SHIFT PT_LE_SHIFT(PT_LEVEL_1)
|
||||
|
||||
/* Address space size (in bytes) covered by a level-_l page table entry. */
|
||||
#define PT_LE_SIZE(_l) ((uint64)1 << PT_LE_SHIFT(_l))
|
||||
#define PT_L5E_SIZE PT_LE_SIZE(PT_LEVEL_5)
|
||||
#define PT_L4E_SIZE PT_LE_SIZE(PT_LEVEL_4)
|
||||
#define PT_L3E_SIZE PT_LE_SIZE(PT_LEVEL_3)
|
||||
#define PT_L2E_SIZE PT_LE_SIZE(PT_LEVEL_2)
|
||||
#define PT_L1E_SIZE PT_LE_SIZE(PT_LEVEL_1)
|
||||
|
||||
/*
|
||||
* For a given LA,
|
||||
* determine the offset (== index) of the level-_l page table entry.
|
||||
*/
|
||||
#define PT_LA_2_LOFF(_a, _l) (((_a) >> PT_LE_SHIFT(_l)) & PT_OFF_MASK)
|
||||
#define PT_LA_2_L5OFF(_a) PT_LA_2_LOFF(_a, PT_LEVEL_5)
|
||||
#define PT_LA_2_L4OFF(_a) PT_LA_2_LOFF(_a, PT_LEVEL_4)
|
||||
#define PT_LA_2_L3OFF(_a) PT_LA_2_LOFF(_a, PT_LEVEL_3)
|
||||
#define PT_LA_2_L2OFF(_a) PT_LA_2_LOFF(_a, PT_LEVEL_2)
|
||||
#define PT_LA_2_L1OFF(_a) PT_LA_2_LOFF(_a, PT_LEVEL_1)
|
||||
|
||||
/*
|
||||
* For a given LPN,
|
||||
* determine the offset (== index) of the level-_l page table entry.
|
||||
*/
|
||||
#define PT_LPN_2_LOFF(_a, _l) (((_a) >> PT_LE_PG_SHIFT(_l)) & PT_OFF_MASK)
|
||||
#define PT_LPN_2_L5OFF(_a) PT_LPN_2_LOFF(_a, PT_LEVEL_5)
|
||||
#define PT_LPN_2_L4OFF(_a) PT_LPN_2_LOFF(_a, PT_LEVEL_4)
|
||||
#define PT_LPN_2_L3OFF(_a) PT_LPN_2_LOFF(_a, PT_LEVEL_3)
|
||||
#define PT_LPN_2_L2OFF(_a) PT_LPN_2_LOFF(_a, PT_LEVEL_2)
|
||||
#define PT_LPN_2_L1OFF(_a) PT_LPN_2_LOFF(_a, PT_LEVEL_1)
|
||||
|
||||
/* Size (in bytes) of a 1GB page. */
|
||||
#define PT_1G_PAGE_SIZE PT_L3E_SIZE
|
||||
#define PT_1G_PAGE_MASK (PT_L3E_SIZE - 1)
|
||||
|
||||
/* Size (in bytes) of a 2MB page. */
|
||||
#define PT_2M_PAGE_SIZE PT_L2E_SIZE
|
||||
#define PT_2M_PAGE_MASK (PT_L2E_SIZE - 1)
|
||||
|
||||
#define PT_LE_NXT_PG(_a, _l) ((((_a) >> PT_LE_PG_SHIFT(_l)) + 1) \
|
||||
<< PT_LE_PG_SHIFT(_l))
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2018 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -30,6 +30,9 @@
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#include "includeCheck.h"
|
||||
|
||||
#define INTERRUPT_REDIRECTION_BITMAP_SIZE 32
|
||||
#define IO_PERMISSION_BITMAP_SIZE 0
|
||||
|
||||
|
||||
#define VMM_PANIC_NONE 0
|
||||
#define VMM_PANIC_MSG_COPYING 1
|
||||
@@ -39,4 +42,7 @@
|
||||
|
||||
#define VMM_PANIC_MSG_SIZE 256
|
||||
|
||||
#define VMM_CPL0_STACK 1
|
||||
#define VMM_CPL1_STACK 2
|
||||
|
||||
#endif
|
||||
@@ -1,50 +0,0 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2017-2018 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation version 2 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 GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*********************************************************/
|
||||
|
||||
/*
|
||||
* vmmblob.h --
|
||||
*
|
||||
* VMM blob management.
|
||||
*/
|
||||
|
||||
#ifndef VMMBLOB_H
|
||||
#define VMMBLOB_H
|
||||
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#define INCLUDE_ALLOW_VMMON
|
||||
#include "includeCheck.h"
|
||||
|
||||
struct VMDriver;
|
||||
struct MonLoaderHeader;
|
||||
|
||||
typedef struct VmmBlobInfo {
|
||||
uint8 *blobPtr;
|
||||
uint32 numBytes;
|
||||
MPN *mpns;
|
||||
struct MonLoaderHeader *header;
|
||||
} VmmBlobInfo;
|
||||
|
||||
void VmmBlob_Cleanup(VmmBlobInfo *bi);
|
||||
Bool VmmBlob_Load(VA64 bsBlobAddr, uint32 numBytes, uint32 headerOffset,
|
||||
VmmBlobInfo **blobInfo);
|
||||
MPN VmmBlob_GetMpn(struct VMDriver *vm, uint64 blobOffset);
|
||||
MPN VmmBlob_GetHeaderMpn(struct VMDriver *vm);
|
||||
uint8 *VmmBlob_GetPtr(VMDriver *vm);
|
||||
uint64 VmmBlob_GetSize(VMDriver *vm);
|
||||
|
||||
#endif /* VMMBLOB_H */
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2000-2015,2017-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2000-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -32,7 +32,6 @@
|
||||
#define INCLUDE_ALLOW_VMKERNEL
|
||||
#define INCLUDE_ALLOW_VMX
|
||||
#include "includeCheck.h"
|
||||
#include "community_source.h"
|
||||
|
||||
/*
|
||||
* Page remapping definitions.
|
||||
@@ -41,42 +40,34 @@
|
||||
#define VMMEM_FLAG_BIT(x) (1 << (x))
|
||||
|
||||
#define VMMEM_ANON_LOW_MEM VMMEM_FLAG_BIT(0)
|
||||
#define VMMEM_ANON_CONTIG VMMEM_FLAG_BIT(1)
|
||||
#define VMMEM_ANON_LARGE_PAGE VMMEM_FLAG_BIT(1)
|
||||
#define VMMEM_ANON_CAN_FAIL VMMEM_FLAG_BIT(2)
|
||||
#define VMMEM_ANON_USE_PREALLOC VMMEM_FLAG_BIT(3)
|
||||
#define VMMEM_ANON_IOABLE_PAGE VMMEM_FLAG_BIT(4)
|
||||
#define VMMEM_ANON_ALL_FLAGS MASK(5)
|
||||
|
||||
#define VMMEM_GUEST_NO_FLAGS 0
|
||||
#define VMMEM_GUEST_WRITEABLE VMMEM_FLAG_BIT(0)
|
||||
#define VMMEM_GUEST_BREAKCOW VMMEM_FLAG_BIT(1)
|
||||
#define VMMEM_GUEST_2M_PAGE VMMEM_FLAG_BIT(2)
|
||||
#define VMMEM_GUEST_1G_PAGE VMMEM_FLAG_BIT(3)
|
||||
#define VMMEM_GUEST_CAN_FAIL VMMEM_FLAG_BIT(4)
|
||||
#define VMMEM_GUEST_TEST_ZEROCOW VMMEM_FLAG_BIT(5)
|
||||
#define VMMEM_GUEST_TRY_ZEROCOW VMMEM_FLAG_BIT(6)
|
||||
#define VMMEM_GUEST_TRY_POISONCOW VMMEM_FLAG_BIT(7)
|
||||
#define VMMEM_GUEST_PREALLOC VMMEM_FLAG_BIT(8)
|
||||
#define VMMEM_GUEST_ALL_FLAGS MASK(9)
|
||||
#define VMMEM_GUEST_LARGE_PAGE VMMEM_FLAG_BIT(2)
|
||||
#define VMMEM_GUEST_CAN_FAIL VMMEM_FLAG_BIT(3)
|
||||
#define VMMEM_GUEST_TEST_ZEROCOW VMMEM_FLAG_BIT(4)
|
||||
#define VMMEM_GUEST_TRY_ZEROCOW VMMEM_FLAG_BIT(5)
|
||||
#define VMMEM_GUEST_TRY_POISONCOW VMMEM_FLAG_BIT(6)
|
||||
#define VMMEM_GUEST_PREALLOC VMMEM_FLAG_BIT(7)
|
||||
#define VMMEM_GUEST_ALL_FLAGS MASK(8)
|
||||
#define VMMEM_GUEST_TRY_COW (VMMEM_GUEST_TEST_ZEROCOW | \
|
||||
VMMEM_GUEST_TRY_ZEROCOW | \
|
||||
VMMEM_GUEST_TRY_POISONCOW)
|
||||
#define VMMEM_GUEST_LARGE_PAGE (VMMEM_GUEST_2M_PAGE | \
|
||||
VMMEM_GUEST_1G_PAGE)
|
||||
|
||||
#define VMMEM_PLATFORM_CHECK_OK VMMEM_FLAG_BIT(0)
|
||||
#define VMMEM_PLATFORM_KEY_OK VMMEM_FLAG_BIT(1)
|
||||
#define VMMEM_PLATFORM_COW VMMEM_FLAG_BIT(2)
|
||||
#define VMMEM_PLATFORM_EXPOSED_TO_VMM VMMEM_FLAG_BIT(3)
|
||||
#define VMMEM_PLATFORM_P2M_UPDATE_PENDING VMMEM_FLAG_BIT(4)
|
||||
#define VMMEM_PLATFORM_DIRTY VMMEM_FLAG_BIT(5)
|
||||
#define VMMEM_PLATFORM_IS_2M_PAGE VMMEM_FLAG_BIT(6)
|
||||
#define VMMEM_PLATFORM_IS_1G_PAGE VMMEM_FLAG_BIT(7)
|
||||
#define VMMEM_PLATFORM_TRY_COW_SUCCESS VMMEM_FLAG_BIT(5)
|
||||
#define VMMEM_PLATFORM_DIRTY VMMEM_FLAG_BIT(6)
|
||||
#define VMMEM_PLATFORM_BACKED_LARGE VMMEM_FLAG_BIT(7)
|
||||
#define VMMEM_PLATFORM_LARGE_RETRY VMMEM_FLAG_BIT(8)
|
||||
#define VMMEM_PLATFORM_TRY_COW_SUCCESS VMMEM_FLAG_BIT(9)
|
||||
|
||||
#define VMMEM_PLATFORM_BACKED_LARGE (VMMEM_PLATFORM_IS_2M_PAGE | \
|
||||
VMMEM_PLATFORM_IS_1G_PAGE)
|
||||
|
||||
|
||||
#define MAX_PLATFORM_PAGE_INFO_PAGES 240
|
||||
@@ -85,10 +76,11 @@
|
||||
* Structure used to query platform about the page state.
|
||||
*/
|
||||
typedef struct PlatformPageInfoList {
|
||||
PageCnt numPages;
|
||||
BPN bpn[MAX_PLATFORM_PAGE_INFO_PAGES]; // bpns to check
|
||||
MPN mpn[MAX_PLATFORM_PAGE_INFO_PAGES]; // filled in by host
|
||||
uint8 flags[MAX_PLATFORM_PAGE_INFO_PAGES]; // filled in by host
|
||||
uint32 numPages;
|
||||
uint32 _pad;
|
||||
BPN bpn[MAX_PLATFORM_PAGE_INFO_PAGES]; // bpns to check
|
||||
MPN mpn[MAX_PLATFORM_PAGE_INFO_PAGES]; // filled in by host
|
||||
uint8 flags[MAX_PLATFORM_PAGE_INFO_PAGES]; // filled in by host
|
||||
} PlatformPageInfoList;
|
||||
|
||||
#define VMMEM_SERVICES_TYPE_2_MASK(type) \
|
||||
@@ -98,12 +90,9 @@ typedef struct PlatformPageInfoList {
|
||||
#define VMMEM_SERVICES_CLEAR_MASK(typeMask, type) \
|
||||
(typeMask & ~VMMEM_SERVICES_TYPE_2_MASK(type))
|
||||
|
||||
#define MDEF_DRAINER
|
||||
|
||||
#define VMMEM_SERVICES_DEFS \
|
||||
MDEF(VMMEM_SERVICES_TYPE_P2M, P2MUpdate_FilterPages) \
|
||||
MDEF(VMMEM_SERVICES_TYPE_SWAP, BusMemSwap_FilterPages) \
|
||||
MDEF_DRAINER
|
||||
#define VMMEM_SERVICES_DEFS \
|
||||
MDEF(VMMEM_SERVICES_TYPE_P2M, P2MUpdate_FilterPages) \
|
||||
MDEF(VMMEM_SERVICES_TYPE_SWAP, BusMemSwap_FilterPages)
|
||||
|
||||
#define MDEF(_type, _cb) _type,
|
||||
typedef enum VmMemServices_Type {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2003-2016 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2003-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2002-2016 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2002-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2002-2016 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2002-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2002-2016 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2002-2015 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2006-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2006-2013 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -35,6 +35,8 @@
|
||||
#define INCLUDE_ALLOW_VMCORE
|
||||
#include "includeCheck.h"
|
||||
|
||||
#include <asm/processor-flags.h>
|
||||
|
||||
#define X86_MAX_INSTR_LEN 15 /* Max byte length of an x86 instruction. */
|
||||
|
||||
#define NUM_IDT_VECTORS 256
|
||||
@@ -54,20 +56,7 @@
|
||||
#define CR0_NW 0x20000000
|
||||
#define CR0_CD 0x40000000
|
||||
#define CR0_PG 0x80000000
|
||||
|
||||
#define CR0_CACHE_CONTROL (CR0_CD | CR0_NW)
|
||||
|
||||
#define CR0_RESERVED CONST64U(0xffffffff1ffaffc0)
|
||||
/*
|
||||
* Note: The "Not Reserved" bits in CR0 are:
|
||||
* PG, CD, NW, AM, WP, NE, ET, TS, EM, MP, PE
|
||||
* | | | | | |
|
||||
* | | +---------------+---+---+---> CR0_MUTABLE
|
||||
* | |
|
||||
* +---+--> CR0_CACHE_CONTROL
|
||||
*
|
||||
* (CR0_MUTABLE is defined in vmkernel/private/x86/cpu.h)
|
||||
*/
|
||||
|
||||
#define CR3_PWT 0x00000008
|
||||
#define CR3_PCD 0x00000010
|
||||
@@ -75,7 +64,9 @@
|
||||
#define CR3_PDB_MASK 0xfffff000
|
||||
#define CR3_IGNORE 0xFFF
|
||||
#define PAE_CR3_IGNORE 0x1F
|
||||
#ifndef CR3_PCID_MASK
|
||||
#define CR3_PCID_MASK 0xFFF
|
||||
#endif
|
||||
#define CR3_NO_FLUSH (1ULL << 63)
|
||||
|
||||
#define CR4_VME 0x00000001
|
||||
@@ -89,8 +80,6 @@
|
||||
#define CR4_PCE 0x00000100
|
||||
#define CR4_OSFXSR 0x00000200 // CPU/OS supports SIMD insts
|
||||
#define CR4_OSXMMEXCPT 0x00000400 // #XF exception enable PIII only
|
||||
#define CR4_UMIP 0x00000800
|
||||
#define CR4_LA57 0x00001000
|
||||
#define CR4_VMXE 0x00002000
|
||||
#define CR4_SMXE 0x00004000
|
||||
#define CR4_FSGSBASE 0x00010000
|
||||
@@ -98,9 +87,8 @@
|
||||
#define CR4_OSXSAVE 0x00040000
|
||||
#define CR4_SMEP 0x00100000
|
||||
#define CR4_SMAP 0x00200000
|
||||
#define CR4_PKE 0x00400000
|
||||
#define CR4_CET 0x00800000
|
||||
#define CR4_RESERVED CONST64U(0xffffffffff889000)
|
||||
/* Removing a bit from CR4_RESERVED causes Task_Switch to leave the bit set. */
|
||||
#define CR4_RESERVED CONST64U(0xffffffffffc89800)
|
||||
#define CR8_RESERVED CONST64U(0xfffffffffffffff0)
|
||||
|
||||
/*
|
||||
@@ -202,17 +190,8 @@
|
||||
#define EXC_MF 16
|
||||
#define EXC_AC 17
|
||||
#define EXC_MC 18
|
||||
#define EXC_XF 19 // SIMD exception.
|
||||
#define EXC_VE 20 // Virtualization exception - VT only.
|
||||
#define EXC_CP 21 // Control Protection exception.
|
||||
#define EXC_VC 29 // VMM communication exception (SVM / SEV-ES only).
|
||||
#define EXC_SX 30 // Security exception (SVM only).
|
||||
|
||||
/* Bitmap of the exception vectors that have associated error codes. */
|
||||
#define EXC_WITH_ERR_CODE_MASK ((1u << EXC_DF) | (1u << EXC_TS) | \
|
||||
(1u << EXC_NP) | (1u << EXC_SS) | \
|
||||
(1u << EXC_GP) | (1u << EXC_PF) | \
|
||||
(1u << EXC_AC) | (1u << EXC_CP))
|
||||
#define EXC_XF 19 /* SIMD exception. */
|
||||
#define EXC_SX 30 /* Security exception (SVM only). */
|
||||
|
||||
/*
|
||||
* eflag/rflag definitions.
|
||||
@@ -222,24 +201,24 @@
|
||||
|
||||
typedef enum x86_FLAGS {
|
||||
EFLAGS_NONE = 0,
|
||||
EFLAGS_CF = (1 << 0), /* User */
|
||||
EFLAGS_SET = (1 << 1),
|
||||
EFLAGS_PF = (1 << 2), /* User */
|
||||
EFLAGS_AF = (1 << 4), /* User */
|
||||
EFLAGS_ZF = (1 << 6), /* User */
|
||||
EFLAGS_SF = (1 << 7), /* User */
|
||||
EFLAGS_TF = (1 << 8), /* Priv */
|
||||
EFLAGS_IF = (1 << 9), /* Priv */
|
||||
EFLAGS_DF = (1 << 10), /* User */
|
||||
EFLAGS_OF = (1 << 11), /* User */
|
||||
EFLAGS_NT = (1 << 14), /* Priv */
|
||||
EFLAGS_RF = (1 << 16), /* Priv */
|
||||
EFLAGS_VM = (1 << 17), /* Priv */
|
||||
EFLAGS_AC = (1 << 18), /* Priv */
|
||||
EFLAGS_VIF = (1 << 19), /* Priv */
|
||||
EFLAGS_VIP = (1 << 20), /* Priv */
|
||||
EFLAGS_CF = (1 << 0), /* User */
|
||||
EFLAGS_SET = (1 << 1),
|
||||
EFLAGS_PF = (1 << 2), /* User */
|
||||
EFLAGS_AF = (1 << 4), /* User */
|
||||
EFLAGS_ZF = (1 << 6), /* User */
|
||||
EFLAGS_SF = (1 << 7), /* User */
|
||||
EFLAGS_TF = (1 << 8), /* Priv */
|
||||
EFLAGS_IF = (1 << 9), /* Priv */
|
||||
EFLAGS_DF = (1 << 10), /* User */
|
||||
EFLAGS_OF = (1 << 11), /* User */
|
||||
EFLAGS_NT = (1 << 14), /* Priv */
|
||||
EFLAGS_RF = (1 << 16), /* Priv */
|
||||
EFLAGS_VM = (1 << 17), /* Priv */
|
||||
EFLAGS_AC = (1 << 18), /* Priv */
|
||||
EFLAGS_VIF = (1 << 19), /* Priv */
|
||||
EFLAGS_VIP = (1 << 20), /* Priv */
|
||||
EFLAGS_ID = (1 << 21), /* Priv */
|
||||
|
||||
|
||||
EFLAGS_IOPL = 3 << EFLAGS_IOPL_SHIFT,
|
||||
EFLAGS_ARITH = (EFLAGS_CF | EFLAGS_PF | EFLAGS_AF | EFLAGS_ZF |
|
||||
EFLAGS_SF | EFLAGS_OF),
|
||||
@@ -251,7 +230,7 @@ typedef enum x86_FLAGS {
|
||||
EFLAGS_ALL = (EFLAGS_CF | EFLAGS_PF | EFLAGS_AF | EFLAGS_ZF |
|
||||
EFLAGS_SF | EFLAGS_DF | EFLAGS_OF | EFLAGS_TF |
|
||||
EFLAGS_IF | EFLAGS_IOPL | EFLAGS_NT | EFLAGS_RF |
|
||||
EFLAGS_VM | EFLAGS_AC | EFLAGS_VIF | EFLAGS_VIP |
|
||||
EFLAGS_VM | EFLAGS_AC | EFLAGS_VIF | EFLAGS_VIP |
|
||||
EFLAGS_ID),
|
||||
EFLAGS_ALL_16 = EFLAGS_ALL & 0xffff,
|
||||
EFLAGS_REAL_32 = (EFLAGS_ALL & ~(EFLAGS_VIP | EFLAGS_VIF | EFLAGS_VM)),
|
||||
@@ -263,12 +242,5 @@ typedef enum x86_FLAGS {
|
||||
EFLAGS__4 = 0x7fffffff /* ensure 4 byte encoding */
|
||||
} x86_FLAGS;
|
||||
|
||||
/*
|
||||
* MPX bound configuration registers
|
||||
*/
|
||||
#define BNDCFG_EN 0x00000001
|
||||
#define BNDCFG_BNDPRSV 0x00000002
|
||||
#define BNDCFG_RSVD 0x00000ffc
|
||||
#define BNDCFG_BDBASE CONST64U(0xfffffffffffff000)
|
||||
|
||||
#endif // ifndef _VM_BASIC_DEFS_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998,2015-2017 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -45,7 +45,6 @@
|
||||
#define X2APIC_VERSION_0x15 0x15
|
||||
#define APIC_MAXLVT_0x4 0x4
|
||||
#define XAPIC_MAXLVT_0x5 0x5
|
||||
#define XAPIC_MAXLVT_0x6 0x6 // Intel only: Nehalem (1A) and onward
|
||||
#define APIC_VERSION_MASK 0xff
|
||||
#define APIC_MAX_LVT_MASK 0xff
|
||||
#define APIC_MAX_LVT_SHIFT 16
|
||||
@@ -121,7 +120,7 @@
|
||||
|
||||
/*
|
||||
* Use APIC_MSR_BASEMASK as mask only for reading the MSR_APIC_BASE.
|
||||
* Use guestReservedAPIC as mask when writing MSR_APIC_BASE.
|
||||
* Use VMCORESHARED->reservedAPIC as mask when writing MSR_APIC_BASE.
|
||||
*/
|
||||
#define APIC_MSR_BASEMASK CONST64U(0x0000fffffffff000)
|
||||
#define APIC_MSR_X2APIC_ENABLED 0x00000400
|
||||
|
||||
+815
-1361
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 2003-2020 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 2003-2015,2018 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -39,6 +39,46 @@
|
||||
#include "x86cpuid.h"
|
||||
|
||||
|
||||
/*
|
||||
* x86-64 windows doesn't support inline asm so we have to use these
|
||||
* intrinsic functions defined in the compiler. Not all of these are well
|
||||
* documented. There is an array in the compiler dll (c1.dll) which has
|
||||
* an array of the names of all the intrinsics minus the leading
|
||||
* underscore. Searching around in the ntddk.h file can also be helpful.
|
||||
*
|
||||
* The declarations for the intrinsic functions were taken from the DDK.
|
||||
* Our declarations must match the ddk's otherwise the 64-bit c++ compiler
|
||||
* will complain about second linkage of the intrinsic functions.
|
||||
* We define the intrinsic using the basic types corresponding to the
|
||||
* Windows typedefs. This avoids having to include windows header files
|
||||
* to get to the windows types.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef VM_X86_64
|
||||
/*
|
||||
* intrinsic functions only supported by x86-64 windows as of 2k3sp1
|
||||
*/
|
||||
void __cpuid(int regs[4], int eax);
|
||||
#pragma intrinsic(__cpuid)
|
||||
|
||||
/*
|
||||
* __cpuidex has been supported since VS2008
|
||||
*/
|
||||
#if _MSC_VER >= 1500
|
||||
void __cpuidex(int regs[4], int eax, int ecx);
|
||||
#pragma intrinsic(__cpuidex)
|
||||
#endif /* _MSC_VER >= 1500 */
|
||||
#endif /* VM_X86_64 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
|
||||
#ifdef __GNUC__ // {
|
||||
|
||||
/*
|
||||
@@ -49,57 +89,68 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined VM_X86_64 || !defined __PIC__
|
||||
#define VM_CPUID_BLOCK "cpuid"
|
||||
#define VM_EBX_OUT(reg) "=b"(reg)
|
||||
/*
|
||||
* %ebx is reserved on i386 PIC. Apple's gcc-5493 (gcc 4.0) compiling
|
||||
* for x86_64 incorrectly errors out saying %ebx is reserved. This is
|
||||
* Apple bug 7304232.
|
||||
*/
|
||||
#if vm_x86_64 ? (defined __APPLE_CC__ && __APPLE_CC__ == 5493) : defined __PIC__
|
||||
#if vm_x86_64
|
||||
/*
|
||||
* Note that this generates movq %rbx,%rbx; cpuid; xchgq %rbx,%rbx ...
|
||||
* Unfortunately Apple's assembler does not have .ifnes, and I cannot
|
||||
* figure out how to do that with .if. If we ever enable this code
|
||||
* on other 64bit systems, both movq & xchgq should be surrounded by
|
||||
* .ifnes \"%%rbx\", \"%q1\" & .endif
|
||||
*/
|
||||
#define VM_CPUID_BLOCK "movq %%rbx, %q1\n\t" \
|
||||
"cpuid\n\t" \
|
||||
"xchgq %%rbx, %q1\n\t"
|
||||
#define VM_EBX_OUT(reg) "=&r"(reg)
|
||||
#else
|
||||
/* %ebx is reserved on i386 PIC. */
|
||||
#define VM_CPUID_BLOCK "movl %%ebx, %1\n\t" \
|
||||
"cpuid\n\t" \
|
||||
"xchgl %%ebx, %1\n\t"
|
||||
#define VM_EBX_OUT(reg) "=&rm"(reg)
|
||||
#endif
|
||||
#else
|
||||
#define VM_CPUID_BLOCK "cpuid"
|
||||
#define VM_EBX_OUT(reg) "=b"(reg)
|
||||
#endif
|
||||
|
||||
static INLINE void
|
||||
__GET_CPUID(uint32 eax, // IN
|
||||
__GET_CPUID(int eax, // IN
|
||||
CPUIDRegs *regs) // OUT
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
VM_CPUID_BLOCK
|
||||
: "=a" (regs->eax),
|
||||
VM_EBX_OUT(regs->ebx),
|
||||
"=c" (regs->ecx),
|
||||
"=d" (regs->edx)
|
||||
: "=a" (regs->eax), VM_EBX_OUT(regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
|
||||
: "a" (eax)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
__GET_CPUID2(uint32 eax, // IN
|
||||
uint32 ecx, // IN
|
||||
__GET_CPUID2(int eax, // IN
|
||||
int ecx, // IN
|
||||
CPUIDRegs *regs) // OUT
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
VM_CPUID_BLOCK
|
||||
: "=a" (regs->eax),
|
||||
VM_EBX_OUT(regs->ebx),
|
||||
"=c" (regs->ecx),
|
||||
"=d" (regs->edx)
|
||||
: "=a" (regs->eax), VM_EBX_OUT(regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
|
||||
: "a" (eax), "c" (ecx)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
__GET_EAX_FROM_CPUID(uint32 eax) // IN
|
||||
__GET_EAX_FROM_CPUID(int eax) // IN
|
||||
{
|
||||
uint32 ebx;
|
||||
|
||||
__asm__ __volatile__(
|
||||
VM_CPUID_BLOCK
|
||||
: "=a" (eax),
|
||||
VM_EBX_OUT(ebx)
|
||||
: "=a" (eax), VM_EBX_OUT(ebx)
|
||||
: "a" (eax)
|
||||
: "memory", "%ecx", "%edx"
|
||||
);
|
||||
@@ -108,7 +159,7 @@ __GET_EAX_FROM_CPUID(uint32 eax) // IN
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
__GET_EBX_FROM_CPUID(uint32 eax) // IN
|
||||
__GET_EBX_FROM_CPUID(int eax) // IN
|
||||
{
|
||||
uint32 ebx;
|
||||
|
||||
@@ -123,16 +174,14 @@ __GET_EBX_FROM_CPUID(uint32 eax) // IN
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
__GET_ECX_FROM_CPUID(uint32 eax) // IN
|
||||
__GET_ECX_FROM_CPUID(int eax) // IN
|
||||
{
|
||||
uint32 ecx;
|
||||
uint32 ebx;
|
||||
|
||||
__asm__ __volatile__(
|
||||
VM_CPUID_BLOCK
|
||||
: "=a" (eax),
|
||||
VM_EBX_OUT(ebx),
|
||||
"=c" (ecx)
|
||||
: "=a" (eax), VM_EBX_OUT(ebx), "=c" (ecx)
|
||||
: "a" (eax)
|
||||
: "memory", "%edx"
|
||||
);
|
||||
@@ -141,16 +190,14 @@ __GET_ECX_FROM_CPUID(uint32 eax) // IN
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
__GET_EDX_FROM_CPUID(uint32 eax) // IN
|
||||
__GET_EDX_FROM_CPUID(int eax) // IN
|
||||
{
|
||||
uint32 edx;
|
||||
uint32 ebx;
|
||||
|
||||
__asm__ __volatile__(
|
||||
VM_CPUID_BLOCK
|
||||
: "=a" (eax),
|
||||
VM_EBX_OUT(ebx),
|
||||
"=d" (edx)
|
||||
: "=a" (eax), VM_EBX_OUT(ebx), "=d" (edx)
|
||||
: "a" (eax)
|
||||
: "memory", "%ecx"
|
||||
);
|
||||
@@ -159,59 +206,263 @@ __GET_EDX_FROM_CPUID(uint32 eax) // IN
|
||||
}
|
||||
|
||||
|
||||
static INLINE uint32
|
||||
__GET_EAX_FROM_CPUID4(int ecx) // IN
|
||||
{
|
||||
uint32 eax;
|
||||
uint32 ebx;
|
||||
|
||||
__asm__ __volatile__(
|
||||
VM_CPUID_BLOCK
|
||||
: "=a" (eax), VM_EBX_OUT(ebx), "=c" (ecx)
|
||||
: "a" (4), "c" (ecx)
|
||||
: "memory", "%edx"
|
||||
);
|
||||
|
||||
return eax;
|
||||
}
|
||||
|
||||
#undef VM_CPUID_BLOCK
|
||||
#undef VM_EBX_OUT
|
||||
|
||||
#elif defined(_MSC_VER) // } {
|
||||
|
||||
static INLINE void
|
||||
__GET_CPUID(uint32 input, CPUIDRegs *regs)
|
||||
__GET_CPUID(int input, CPUIDRegs *regs)
|
||||
{
|
||||
#ifdef VM_X86_64
|
||||
__cpuid((int *)regs, input);
|
||||
#else
|
||||
__asm push esi
|
||||
__asm push ebx
|
||||
__asm push ecx
|
||||
__asm push edx
|
||||
|
||||
__asm mov eax, input
|
||||
__asm mov esi, regs
|
||||
__asm _emit 0x0f __asm _emit 0xa2
|
||||
__asm mov 0x0[esi], eax
|
||||
__asm mov 0x4[esi], ebx
|
||||
__asm mov 0x8[esi], ecx
|
||||
__asm mov 0xC[esi], edx
|
||||
|
||||
__asm pop edx
|
||||
__asm pop ecx
|
||||
__asm pop ebx
|
||||
__asm pop esi
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef VM_X86_64
|
||||
|
||||
#if _MSC_VER >= 1500
|
||||
|
||||
/*
|
||||
* __cpuidex has been supported since VS2008
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
__GET_CPUID2(uint32 inputEax, uint32 inputEcx, CPUIDRegs *regs)
|
||||
__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs)
|
||||
{
|
||||
__cpuidex((int *)regs, inputEax, inputEcx);
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
__GET_EAX_FROM_CPUID(uint32 input)
|
||||
#else // _MSC_VER >= 1500
|
||||
|
||||
/*
|
||||
* No inline assembly in Win64. Implemented in bora/lib/misc in
|
||||
* cpuidMasm64.asm.
|
||||
*/
|
||||
|
||||
extern void
|
||||
__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs);
|
||||
#endif // _MSC_VER >= 1500
|
||||
|
||||
#else // VM_X86_64
|
||||
|
||||
static INLINE void
|
||||
__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs)
|
||||
{
|
||||
__asm push esi
|
||||
__asm push ebx
|
||||
__asm push ecx
|
||||
__asm push edx
|
||||
|
||||
__asm mov eax, inputEax
|
||||
__asm mov ecx, inputEcx
|
||||
__asm mov esi, regs
|
||||
__asm _emit 0x0f __asm _emit 0xa2
|
||||
__asm mov 0x0[esi], eax
|
||||
__asm mov 0x4[esi], ebx
|
||||
__asm mov 0x8[esi], ecx
|
||||
__asm mov 0xC[esi], edx
|
||||
|
||||
__asm pop edx
|
||||
__asm pop ecx
|
||||
__asm pop ebx
|
||||
__asm pop esi
|
||||
}
|
||||
#endif
|
||||
|
||||
static INLINE uint32
|
||||
__GET_EAX_FROM_CPUID(int input)
|
||||
{
|
||||
#ifdef VM_X86_64
|
||||
CPUIDRegs regs;
|
||||
__cpuid((int *)®s, input);
|
||||
return regs.eax;
|
||||
#else
|
||||
uint32 output;
|
||||
|
||||
//NOT_TESTED();
|
||||
__asm push ebx
|
||||
__asm push ecx
|
||||
__asm push edx
|
||||
|
||||
__asm mov eax, input
|
||||
__asm _emit 0x0f __asm _emit 0xa2
|
||||
__asm mov output, eax
|
||||
|
||||
__asm pop edx
|
||||
__asm pop ecx
|
||||
__asm pop ebx
|
||||
|
||||
return output;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
__GET_EBX_FROM_CPUID(uint32 input)
|
||||
__GET_EBX_FROM_CPUID(int input)
|
||||
{
|
||||
#ifdef VM_X86_64
|
||||
CPUIDRegs regs;
|
||||
__cpuid((int *)®s, input);
|
||||
return regs.ebx;
|
||||
#else
|
||||
uint32 output;
|
||||
|
||||
//NOT_TESTED();
|
||||
__asm push ebx
|
||||
__asm push ecx
|
||||
__asm push edx
|
||||
|
||||
__asm mov eax, input
|
||||
__asm _emit 0x0f __asm _emit 0xa2
|
||||
__asm mov output, ebx
|
||||
|
||||
__asm pop edx
|
||||
__asm pop ecx
|
||||
__asm pop ebx
|
||||
|
||||
return output;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
__GET_ECX_FROM_CPUID(uint32 input)
|
||||
__GET_ECX_FROM_CPUID(int input)
|
||||
{
|
||||
#ifdef VM_X86_64
|
||||
CPUIDRegs regs;
|
||||
__cpuid((int *)®s, input);
|
||||
return regs.ecx;
|
||||
#else
|
||||
uint32 output;
|
||||
|
||||
//NOT_TESTED();
|
||||
__asm push ebx
|
||||
__asm push ecx
|
||||
__asm push edx
|
||||
|
||||
__asm mov eax, input
|
||||
__asm _emit 0x0f __asm _emit 0xa2
|
||||
__asm mov output, ecx
|
||||
|
||||
__asm pop edx
|
||||
__asm pop ecx
|
||||
__asm pop ebx
|
||||
|
||||
return output;
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
__GET_EDX_FROM_CPUID(uint32 input)
|
||||
__GET_EDX_FROM_CPUID(int input)
|
||||
{
|
||||
#ifdef VM_X86_64
|
||||
CPUIDRegs regs;
|
||||
__cpuid((int *)®s, input);
|
||||
return regs.edx;
|
||||
#else
|
||||
uint32 output;
|
||||
|
||||
//NOT_TESTED();
|
||||
__asm push ebx
|
||||
__asm push ecx
|
||||
__asm push edx
|
||||
|
||||
__asm mov eax, input
|
||||
__asm _emit 0x0f __asm _emit 0xa2
|
||||
__asm mov output, edx
|
||||
|
||||
__asm pop edx
|
||||
__asm pop ecx
|
||||
__asm pop ebx
|
||||
|
||||
return output;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef VM_X86_64
|
||||
|
||||
/*
|
||||
* No inline assembly in Win64. Implemented in bora/lib/misc in
|
||||
* cpuidMasm64.asm.
|
||||
*/
|
||||
|
||||
extern uint32
|
||||
__GET_EAX_FROM_CPUID4(int inputEcx);
|
||||
|
||||
#else // VM_X86_64
|
||||
|
||||
static INLINE uint32
|
||||
__GET_EAX_FROM_CPUID4(int inputEcx)
|
||||
{
|
||||
uint32 output;
|
||||
|
||||
//NOT_TESTED();
|
||||
__asm push ebx
|
||||
__asm push ecx
|
||||
__asm push edx
|
||||
|
||||
__asm mov eax, 4
|
||||
__asm mov ecx, inputEcx
|
||||
__asm _emit 0x0f __asm _emit 0xa2
|
||||
__asm mov output, eax
|
||||
|
||||
__asm pop edx
|
||||
__asm pop ecx
|
||||
__asm pop ebx
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif // VM_X86_64
|
||||
|
||||
#else // }
|
||||
#error
|
||||
#endif
|
||||
|
||||
#define CPUID_FOR_SIDE_EFFECTS() ((void)__GET_EAX_FROM_CPUID(0))
|
||||
|
||||
/* The first parameter is used as an rvalue and then as an lvalue. */
|
||||
#define GET_CPUID(_ax, _bx, _cx, _dx) { \
|
||||
CPUIDRegs regs; \
|
||||
__GET_CPUID(_ax, ®s); \
|
||||
_ax = regs.eax; \
|
||||
_bx = regs.ebx; \
|
||||
_cx = regs.ecx; \
|
||||
_dx = regs.edx; \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*********************************************************
|
||||
* Copyright (C) 1998-2019 VMware, Inc. All rights reserved.
|
||||
* Copyright (C) 1998-2014 VMware, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
@@ -97,78 +97,43 @@ static INLINE uint32 Desc_LongMode(const Descriptor *d) { return d->longmode; }
|
||||
static INLINE uint32 Desc_DB(const Descriptor *d) { return d->DB; }
|
||||
static INLINE uint32 Desc_Gran(const Descriptor *d) { return d->gran; }
|
||||
|
||||
static INLINE uint32
|
||||
Desc64_Type(const Descriptor64 *d)
|
||||
{
|
||||
return (uint32)d->type;
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
Desc64_S(const Descriptor64 *d)
|
||||
{
|
||||
return (uint32)d->S;
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
Desc64_DPL(const Descriptor64 *d)
|
||||
{
|
||||
return (uint32)d->DPL;
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
Desc64_Present(const Descriptor64 *d)
|
||||
{
|
||||
return (uint32)d->present;
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
Desc64_AVL(const Descriptor64 *d)
|
||||
{
|
||||
return (uint32)d->AVL;
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
Desc64_Gran(const Descriptor64 *d)
|
||||
{
|
||||
return (uint32)d->gran;
|
||||
}
|
||||
|
||||
static INLINE uint32
|
||||
Desc64_ExtAttrs(const Descriptor64 *d)
|
||||
{
|
||||
return (uint32)d->ext_attrs;
|
||||
}
|
||||
static INLINE uint32 Desc64_Type(const Descriptor64 *d) { return d->type; }
|
||||
static INLINE uint32 Desc64_S(const Descriptor64 *d) { return d->S; }
|
||||
static INLINE uint32 Desc64_DPL(const Descriptor64 *d) { return d->DPL; }
|
||||
static INLINE uint32 Desc64_Present(const Descriptor64 *d) { return d->present; }
|
||||
static INLINE uint32 Desc64_AVL(const Descriptor64 *d) { return d->AVL; }
|
||||
static INLINE uint32 Desc64_Gran(const Descriptor64 *d) { return d->gran; }
|
||||
static INLINE uint32 Desc64_ExtAttrs(const Descriptor64 *d) { return d->ext_attrs; }
|
||||
|
||||
static INLINE LA32
|
||||
Desc_GetBase(const Descriptor *d)
|
||||
{
|
||||
return ((unsigned)d->base_hi << 24) |
|
||||
((unsigned)d->base_mid << 16) | d->base_lo;
|
||||
return (d->base_hi << 24) | (d->base_mid << 16) | d->base_lo;
|
||||
}
|
||||
|
||||
static INLINE LA64
|
||||
Desc64_GetBase(const Descriptor64 *d)
|
||||
{
|
||||
return ((uint64)d->base_hi << 32) |
|
||||
((uint64)d->base_mid << 24) | (uint64)d->base_lo;
|
||||
return ((uint64)d->base_hi << 32) |
|
||||
((uint64)d->base_mid << 24) | (uint32)d->base_lo;
|
||||
}
|
||||
|
||||
static INLINE LA32
|
||||
Desc64_GetBaseHi(const Descriptor64 *d)
|
||||
{
|
||||
return (LA32)d->base_hi;
|
||||
return d->base_hi;
|
||||
}
|
||||
|
||||
static INLINE VA32
|
||||
Desc_GetLimit(const Descriptor *d)
|
||||
{
|
||||
return ((unsigned)d->limit_hi << 16) | d->limit_lo;
|
||||
return (d->limit_hi << 16) | d->limit_lo;
|
||||
}
|
||||
|
||||
static INLINE VA32
|
||||
Desc64_GetLimit(const Descriptor64 *d)
|
||||
{
|
||||
return (VA32)(((unsigned)d->limit_hi << 16) | d->limit_lo);
|
||||
return ((uint32)d->limit_hi << 16) | (uint32)d->limit_lo;
|
||||
}
|
||||
|
||||
static INLINE Bool
|
||||
@@ -345,13 +310,12 @@ static INLINE uint32 DESC_PRESENT(Descriptor d) { return d.present; }
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static INLINE void
|
||||
Desc_SetSystemDescriptor64(Descriptor *d, uint64 base, uint32 limit,
|
||||
uint32 type, uint32 DPL, uint32 present,
|
||||
uint32 DB, uint32 gran)
|
||||
static INLINE void
|
||||
Desc_SetSystemDescriptor64(Descriptor *d, uint64 base, uint32 limit, uint32 type,
|
||||
uint32 DPL, uint32 present, uint32 DB, uint32 gran)
|
||||
{
|
||||
uint32 baseHi = (uint32)(base >> 32);
|
||||
uint32 baseLo = (uint32)base;
|
||||
uint32 baseHi = (uint32) (base >> 32);
|
||||
uint32 baseLo = (uint32) base;
|
||||
|
||||
/*
|
||||
* The first half of a 16-byte descriptor is a valid 8-byte descriptor
|
||||
@@ -372,17 +336,15 @@ Desc_SetSystemDescriptor64(Descriptor *d, uint64 base, uint32 limit,
|
||||
* Given descriptor, return the code/stack size that it specifies.
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static INLINE unsigned
|
||||
static INLINE int
|
||||
Desc_DBSize(const Descriptor *desc)
|
||||
{
|
||||
/*
|
||||
* Code/stack size is determined by the D/B bit; bit 22 of the 2nd word.
|
||||
* Shift the bit to position 1, mask it out, add 2.
|
||||
*
|
||||
* Result: 2 or 4.
|
||||
* Shift the bit to position 1, mask it out, add 2. Result: 2 or 4.
|
||||
*/
|
||||
unsigned cSz = ((((const uint32 *)desc)[1] >> 21) & 2) + 2;
|
||||
ASSERT(cSz == (Desc_DB(desc) ? 4U : 2U));
|
||||
int cSz = ((((const uint32*)desc)[1] >> 21) & 2) + 2;
|
||||
ASSERT(cSz == (Desc_DB(desc) ? 4 : 2));
|
||||
return cSz;
|
||||
}
|
||||
|
||||
@@ -564,7 +526,7 @@ typedef struct Gate {
|
||||
static INLINE VA
|
||||
CallGate_GetOffset(const Gate *cg)
|
||||
{
|
||||
return ((unsigned)cg->offset_hi << 16) | cg->offset_lo;
|
||||
return (cg->offset_hi << 16) | cg->offset_lo;
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
|
||||
Loaded 100 of 151 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user