Compare commits

..
8 Commits
Author SHA1 Message Date
Michal Kubecek 63ff06f34c Merge branch 'master' into player-12.5.5 2018-04-02 15:37:20 +02:00
Michal Kubecek 5027ee962c mark branch player-12.5.5 as retired 2018-04-02 15:33:40 +02:00
Michal Kubecek 1e192ab478 vmmon: adapt to 5-level page table hierarchy
Since commit  f2a6a7050109 ("x86: Convert the rest of the code to support
p4d_t") in v4.12-rc1 we need to handle the 5-level page table hierarchy
(pgd -> p4d -> pud -> pmd -> pte).
2017-05-31 09:26:39 +02:00
Michal Kubecek 21d7ca2ad5 vmmon: use standard definition of MSR_MISC_FEATURES_ENABLES if available
The MSR_MISC_FEATURES_ENABLES macro is defined in mainline since commit
ab6d9468631a ("x86/msr: Rename MISC_FEATURE_ENABLES to
MISC_FEATURES_ENABLES") in v4.12-rc1.

The MSR_MISC_FEATURES_ENABLES_CPUID_FAULT macro is defined in mainline
since commit e9ea1e7f53b8 ("x86/arch_prctl: Add ARCH_[GET|SET]_CPUID") in
v4.12-rc1.
2017-05-31 09:26:39 +02:00
Michal Kubecek 1678e8dfec all: add explicit includes for signal headers
Since commit c3edc4010e9d ("sched/headers: Move task_struct::signal and
task_struct::sighand types and accessors into <linux/sched/signal.h>") in
v4.11-rc1, force_sig() and signal_pending() are in <linux/sched/signal.h>

Since commit  192c9414516e ("sched/headers: Remove <linux/signal.h> from
<linux/sched.h>") in v4.11-rc1, <linux/signal.h> needs to be included
explicitely, it's no longer included via <linux/sched.h>
2017-05-31 09:26:39 +02:00
Michal Kubecek c1ee74ac5e vmmon: drop vma parameter of vm_operations_struct::fault
Since commit 11bac8000449 ("mm, fs: reduce fault, page_mkwrite, and
pfn_mkwrite to take only vmf") in v4.11-rc1, fault() callback in struct
vm_operations_struct takes only one argument.
2017-05-31 09:26:39 +02:00
Michal Kubecek b7d3ea5042 vmnet: use standard definition of PCI_VENDOR_ID_VMWARE_VMXNET3 if available
The PCI_DEVICE_ID_VMWARE_VMXNET3 macro is defined in mainline pci_ids.h
since commit b1226c7db1d9 ("vmxnet3: Move PCI Id to pci_ids.h") in
v4.10-rc1.
2017-05-31 09:26:27 +02:00
Michal Kubecek 15cfc0391c vmnet: use standard definition of PCI_VENDOR_ID_VMWARE if available
The PCI_VENDOR_ID_VMWARE macro is defined in mainline pci_ids.h since
commit 94e57fea6202 ("PCI: Move PCI_VENDOR_ID_VMWARE to pci_ids.h")
in v3.18-rc1.
2017-05-31 09:24:53 +02:00
158 changed files with 15458 additions and 19090 deletions

No files matched your search

+1 -1
View File
@@ -150,7 +150,7 @@ test build).
When using a downloaded tarball, simply run
tar -cf vmmon.tar vmmon-only
tar -cf vmnet.tar vmnet-only
tar -cf vmnet.tar vmmon-only
to create the tarballs. In this case, there is no protection against
unwanted local changes.
-1
View File
@@ -43,7 +43,6 @@ install: retiredcheck $(MODFILES)
if test -z "$(DESTDIR)"; then $(DEPMOD) -a $(VM_UNAME); fi
clean: $(SUBDIRS)
rm -f *.o
tarballs: $(TARBALLS)
+7
View File
@@ -0,0 +1,7 @@
*-----------------------------------------------------------------------------
* Branch player-12.5.5 has been retired on 2017-05-31 and has not been
* receiving any updates since. Please switch to latest 12.5.x version
* available.
*
* Latest kernel version this branch is intended to work with is 4.11.
*-----------------------------------------------------------------------------
+11 -10
View File
@@ -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) SUBDIRS=$$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
+5 -3
View File
@@ -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 \
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
View File
@@ -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
View File
@@ -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).
+37
View File
@@ -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;
}
-963
View File
@@ -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;
}
-514
View File
@@ -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));
}
-231
View File
@@ -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
View File
@@ -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;
+8 -8
View File
@@ -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.
*/
+81 -25
View File
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 1998, 2016-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
@@ -16,7 +16,7 @@
*
*********************************************************/
#ifdef __linux__
#ifdef linux
/* Must come before any kernel header file --hpreg */
# include "driver-config.h"
@@ -31,16 +31,10 @@
#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;
/*
@@ -83,9 +77,8 @@ CPUID_Init(void)
char name[16];
__GET_CPUID(1, &regs);
cpuidVersion = regs.eax;
version = regs.eax;
cpuidFeatures = regs.edx;
hostSupportsXSave = CPUID_ISSET(1, ECX, XSAVE, regs.ecx);
__GET_CPUID(0, &regs);
ptr = (uint32 *)name;
@@ -95,25 +88,88 @@ 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;
}
}
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;
}
__GET_CPUID2(7, 0, &regs);
hostHasSpecCtrl = cpuidVendor == CPUID_VENDOR_INTEL &&
(CPUID_ISSET(7, EDX, IBRSIBPB, regs.edx) ||
CPUID_ISSET(7, EDX, STIBP, regs.edx));
return result;
}
hostSupportsVT = VT_CapableCPU();
hostSupportsSVM = SVM_CapableCPU();
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;
}
+8 -52
View File
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 1998, 2016-2019 VMware, Inc. All rights reserved.
* Copyright (C) 1998,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
@@ -31,66 +31,21 @@
#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);
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 +53,4 @@ CPUID_SSE2Supported(void)
}
#endif
-609
View File
@@ -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);
)
+41
View File
@@ -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);
}
+2 -2
View File
@@ -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.
+34 -47
View File
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 1998-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
@@ -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,18 +114,22 @@ 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(MPN mpn, VA64 addr, Bool kernelBuffer);
EXTERN int HostIF_WritePage(MPN mpn, VA64 addr, Bool kernelBuffer);
#ifdef _WIN32
/* Add a HostIF_ReadMachinePage() if/when needed */
EXTERN int HostIF_WriteMachinePage(MPN mpn, VA64 addr);
#else
#define HostIF_WriteMachinePage(_a, _b) HostIF_WritePage((_a), (_b), TRUE)
#endif
#if defined __APPLE__
// There is no need for a fast clock lock on Mac OS.
#define HostIF_FastClockLock(_callerID) do {} while (0)
@@ -151,11 +145,4 @@ 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
#endif // ifdef _HOSTIF_H_
+2 -3
View File
@@ -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_
+34 -46
View File
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 1998-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
@@ -88,7 +88,6 @@
#include "vmware.h"
#include "hostif.h"
#include "vmx86.h"
#include "memtrack.h"
@@ -96,7 +95,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
@@ -147,11 +146,12 @@ typedef struct MemTrackHT {
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. */
#if defined(MEMTRACK_MPN_LOOKUP)
MemTrackHT mpnHashTable; /* MPN to entry hashtable. */
#endif
} 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,14 +304,11 @@ 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 defined(MEMTRACK_MPN_LOOKUP)
if (mt->mpnHashTable.pages[idx] != NULL) {
HostIF_FreePage(mt->mpnHashTable.pages[idx]);
}
}
if (freeBackMap) {
HostIF_FreeKernelMem(mt->mpnHashTable);
#endif
}
HostIF_FreeKernelMem(mt);
@@ -336,10 +332,10 @@ MemTrackCleanup(MemTrack *mt) // IN
*/
MemTrack *
MemTrack_Init(VMDriver *vm) // IN:
MemTrack_Init(void)
{
MemTrack *mt;
PageCnt idx;
unsigned idx;
#if defined(MEMTRACK_3LEVEL)
ASSERT_ON_COMPILE(sizeof *mt <= PAGE_SIZE);
@@ -353,34 +349,28 @@ MemTrack_Init(VMDriver *vm) // IN:
goto error;
}
memset(mt, 0, sizeof *mt);
mt->vm = vm;
for (idx = 0; idx < MEMTRACK_HT_PAGES; idx++) {
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);
#if defined(MEMTRACK_MPN_LOOKUP)
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;
}
#endif
return mt;
@@ -411,17 +401,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 ||
p2 >= MEMTRACK_DIR2_ENTRIES ||
p3 >= MEMTRACK_DIR3_ENTRIES) {
@@ -443,7 +430,9 @@ MemTrack_Add(MemTrack *mt, // IN
ent->mpn = mpn;
MemTrackHTInsert(&mt->vpnHashTable, ent, &ent->vpnChain, ent->vpn);
MemTrackHTInsert(mt->mpnHashTable, ent, &ent->mpnChain, ent->mpn);
#if defined(MEMTRACK_MPN_LOOKUP)
MemTrackHTInsert(&mt->mpnHashTable, ent, &ent->mpnChain, ent->mpn);
#endif
mt->numPages++;
@@ -472,7 +461,6 @@ MemTrack_LookupVPN(MemTrack *mt, // IN
VPN64 vpn) // IN
{
MemTrackEntry *next = *MemTrackHTLookup(&mt->vpnHashTable, vpn);
ASSERT(HostIF_VMLockIsHeld(mt->vm));
while (next != NULL) {
if (next->vpn == vpn) {
@@ -485,6 +473,7 @@ MemTrack_LookupVPN(MemTrack *mt, // IN
}
#if defined(MEMTRACK_MPN_LOOKUP)
/*
*----------------------------------------------------------------------
*
@@ -504,9 +493,7 @@ MemTrackEntry *
MemTrack_LookupMPN(MemTrack *mt, // IN
MPN mpn) // IN
{
MemTrackEntry *next;
ASSERT(HostIF_VMLockIsHeld(mt->vm));
next = *MemTrackHTLookup(mt->mpnHashTable, mpn);
MemTrackEntry *next = *MemTrackHTLookup(&mt->mpnHashTable, mpn);
while (next != NULL) {
if (next->mpn == mpn) {
@@ -517,6 +504,7 @@ MemTrack_LookupMPN(MemTrack *mt, // IN
return NULL;
}
#endif
/*
@@ -537,16 +525,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);
+13 -5
View File
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 1998,2017-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
@@ -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.
*/
@@ -31,22 +31,30 @@
#define INCLUDE_ALLOW_VMCORE
#include "includeCheck.h"
#if defined(VMX86_DEBUG)
#define MEMTRACK_MPN_LOOKUP
#endif
struct MemTrack;
typedef struct MemTrackEntry {
VPN64 vpn;
MPN mpn;
struct MemTrackEntry *vpnChain;
#if defined(MEMTRACK_MPN_LOOKUP)
struct MemTrackEntry *mpnChain;
#endif
} 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 struct MemTrack *MemTrack_Init(void);
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);
#if defined(MEMTRACK_MPN_LOOKUP)
extern MemTrackEntry *MemTrack_LookupMPN(struct MemTrack *mt, MPN mpn);
#endif
#endif // _MEMTRACK_H_
+12 -38
View File
@@ -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;
}
+2 -3
View File
@@ -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
-299
View File
@@ -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];
}
-282
View File
@@ -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;
}
+472 -1283
View File
File diff suppressed because it is too large. Load diff
+9 -8
View File
@@ -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 -1332
View File
File diff suppressed because it is too large. Load diff
+48 -82
View File
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 1998-2020 VMware, Inc. All rights reserved.
* Copyright (C) 1998-2013,2015-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
@@ -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,11 @@ 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 int Vmx86_LookupUserMPN(VMDriver *vm, VA64 uAddr, MPN *mpn);
extern VMDriver *Vmx86_CreateVM(void);
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 +124,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 +146,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 +198,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
-10
View File
@@ -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_
-319
View File
@@ -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
-144
View File
@@ -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_
-65
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
+47
View File
@@ -0,0 +1,47 @@
/*********************************************************
* 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...
*/
#include <linux/sched.h>
#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__ */
+32
View File
@@ -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__ */
+55
View File
@@ -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__ */
+63
View File
@@ -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__ */
+72
View File
@@ -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__ */
+92 -15
View File
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 2002-2017 VMware, Inc. All rights reserved.
* 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
@@ -30,27 +30,100 @@
#include <asm/pgtable.h>
/* pte_page() API modified in 2.3.23 to return a struct page * --hpreg */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 23)
# define compat_pte_page pte_page
#else
# include "compat_page.h"
# define compat_pte_page(_pte) virt_to_page(pte_page(_pte))
#endif
/* Appeared in 2.5.5 --hpreg */
#ifndef pte_offset_map
/* Appeared in SuSE 8.0's 2.4.18 --hpreg */
# ifdef pte_offset_atomic
# define pte_offset_map pte_offset_atomic
# define pte_unmap pte_kunmap
# else
# define pte_offset_map pte_offset
# define pte_unmap(_pte)
# endif
#endif
/* Appeared in 2.5.74-mmX --petr */
#ifndef pmd_offset_map
# define pmd_offset_map(pgd, address) pmd_offset(pgd, address)
# define pmd_unmap(pmd)
#endif
/*
* p4d level appeared in 4.12.
* Appeared in 2.6.10-rc2-mm1. Older kernels did L4 page tables as
* part of pgd_offset, or they did not have L4 page tables at all.
* In 2.6.11 pml4 -> pgd -> pmd -> pte hierarchy was replaced by
* pgd -> pud -> pmd -> pte hierarchy. In 4.12, it was replaced by
* pgd -> p4d -> pud -> pmd -> pte hierarchy (5-level page tables).
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
#ifdef P4D_MASK
# define compat_pgd_offset(mm, address) pgd_offset(mm, address)
# define compat_pgd_present(pgd) pgd_present(pgd)
# define compat_p4d_offset(pgd, address) p4d_offset(pgd, address)
# define compat_p4d_present(p4d) p4d_present(p4d)
# define compat_p4d_large(p4d) p4d_large(p4d)
# define compat_p4d_pfn(p4d) p4d_pfn(p4d)
# define COMPAT_P4D_MASK P4D_MASK
typedef p4d_t compat_p4d_t;
#else
# define compat_pud_offset(p4d, address) pud_offset(p4d, address)
# define compat_pud_present(pud) pud_present(pud)
typedef pgd_t compat_pgd_t;
typedef p4d_t compat_p4d_t;
typedef pud_t compat_pud_t;
#elif defined(PUD_MASK)
# define compat_pgd_offset(mm, address) pgd_offset(mm, address)
# define compat_pgd_present(pgd) pgd_present(pgd)
# define compat_p4d_offset(pgd, address) (pgd)
# define compat_p4d_present(p4d) (1)
# define compat_p4d_large(p4d) (0)
# define compat_p4d_pfn(p4d) INVALID_MPN /* Not used */
# define COMPAT_P4D_MASK 0 /* Not used */
typedef pgd_t compat_p4d_t;
# define compat_pud_offset(p4d, address) pud_offset(p4d, address)
# define compat_pud_present(pud) pud_present(pud)
typedef pgd_t compat_pgd_t;
typedef pgd_t compat_p4d_t;
typedef pud_t compat_pud_t;
#elif defined(pml4_offset)
# define compat_pgd_offset(mm, address) pml4_offset(mm, address)
# define compat_pgd_present(pml4) pml4_present(pml4)
# define compat_p4d_offset(pml4, address) (pml4)
# define compat_p4d_present(pml4) (1)
# define compat_pud_offset(pml4, address) pml4_pgd_offset(pml4, address)
# define compat_pud_present(pgd) pgd_present(pgd)
typedef pml4_t compat_pgd_t;
typedef pml4_t compat_p4d_t;
typedef pgd_t compat_pud_t;
#else
# define compat_pgd_offset(mm, address) pgd_offset(mm, address)
# define compat_pgd_present(pgd) pgd_present(pgd)
# define compat_p4d_offset(pgd, address) (pgd)
# define compat_p4d_present(p4d) (1)
# define compat_pud_offset(p4d, address) (p4d)
# define compat_pud_present(pud) (1)
typedef pgd_t compat_pgd_t;
typedef pgd_t compat_p4d_t;
typedef pgd_t compat_pud_t;
#endif
/* pud_pfn did not exist before 3.8. */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
# define pud_pfn(pud) INVALID_MPN
#define compat_pgd_offset_k(mm, address) pgd_offset_k(address)
/* Introduced somewhere in 2.6.0, + backported to some 2.4 RedHat kernels */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pte_pfn)
# define pte_pfn(pte) page_to_pfn(compat_pte_page(pte))
#endif
/* A page_table_lock field is added to struct mm_struct in 2.3.10 --hpreg */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 10)
# define compat_get_page_table_lock(_mm) (&(_mm)->page_table_lock)
#else
# define compat_get_page_table_lock(_mm) NULL
#endif
@@ -75,8 +148,12 @@ typedef pgd_t compat_p4d_t;
#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL
#endif
#else
#ifdef PAGE_KERNEL_EXECUTABLE
#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXECUTABLE
#else
#define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC
#endif
#endif
#endif /* __COMPAT_PGTABLE_H__ */
+49
View File
@@ -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__ */
+1 -3
View File
@@ -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"
+1 -1
View File
@@ -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)
+95
View File
@@ -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
+36 -16
View File
@@ -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
+345
View File
@@ -0,0 +1,345 @@
/*********************************************************
* 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];
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 -1
View File
@@ -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
View File
@@ -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
@@ -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 (308 << 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_
+2 -9
View File
@@ -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 -143
View File
@@ -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
@@ -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,90 @@ 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.
uint64 specCtrl; /* host MSR_SPEC_CTRL value before world switch. */
uint8 switchHostIDT [sizeof(Gate64) * NUM_EXCEPTIONS]; // hostCS:hostVA
uint8 switchMon64IDT[sizeof(Gate64) * NUM_EXCEPTIONS]; // 64-bit monCS:monVA
}
#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 0xbf1 /* 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
+2 -1
View File
@@ -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
-75
View File
@@ -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
-341
View File
@@ -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 */
+42 -38
View File
@@ -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
+119 -6
View File
@@ -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_
+4 -15
View File
@@ -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
+8 -16
View File
@@ -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
+16 -15
View File
@@ -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_
+305 -59
View File
@@ -1,5 +1,5 @@
/*********************************************************
* Copyright (C) 2002,2014-2017 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
@@ -26,14 +26,160 @@
#include "compat_spinlock.h"
#include "compat_page.h"
/*
*-----------------------------------------------------------------------------
*
* PgtblPte2MPN --
*
* Returns the page structure associated to a Page Table Entry.
*
* This function is not allowed to schedule() because it can be called while
* holding a spinlock --hpreg
*
* Results:
* INVALID_MPN on failure
* mpn on success
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE MPN
PgtblPte2MPN(pte_t *pte) // IN
{
MPN mpn;
if (pte_present(*pte) == 0) {
return INVALID_MPN;
}
mpn = pte_pfn(*pte);
if (mpn >= INVALID_MPN) {
return INVALID_MPN;
}
return mpn;
}
/*
*-----------------------------------------------------------------------------
*
* PgtblPte2Page --
*
* Returns the page structure associated to a Page Table Entry.
*
* This function is not allowed to schedule() because it can be called while
* holding a spinlock --hpreg
*
* Results:
* The page structure if the page table entry points to a physical page
* NULL if the page table entry does not point to a physical page
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE struct page *
PgtblPte2Page(pte_t *pte) // IN
{
if (pte_present(*pte) == 0) {
return NULL;
}
return compat_pte_page(*pte);
}
/*
*-----------------------------------------------------------------------------
*
* PgtblPGD2PTELocked --
*
* Walks through the hardware page tables to try to find the pte
* associated to a virtual address.
*
* Results:
* pte. Caller must call pte_unmap if valid pte returned.
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE pte_t *
PgtblPGD2PTELocked(compat_pgd_t *pgd, // IN: PGD to start with
VA addr) // IN: Address in the virtual address
// space of that process
{
compat_p4d_t *p4d;
compat_pud_t *pud;
pmd_t *pmd;
pte_t *pte;
if (compat_pgd_present(*pgd) == 0) {
return NULL;
}
p4d = compat_p4d_offset(pgd, addr);
if (compat_p4d_present(*p4d) == 0) {
return NULL;
}
pud = compat_pud_offset(p4d, addr);
if (compat_pud_present(*pud) == 0) {
return NULL;
}
pmd = pmd_offset_map(pud, addr);
if (pmd_present(*pmd) == 0) {
pmd_unmap(pmd);
return NULL;
}
pte = pte_offset_map(pmd, addr);
pmd_unmap(pmd);
return pte;
}
/*
*-----------------------------------------------------------------------------
*
* PgtblVa2PTELocked --
*
* Walks through the hardware page tables to try to find the pte
* associated to a virtual address.
*
* Results:
* pte. Caller must call pte_unmap if valid pte returned.
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE pte_t *
PgtblVa2PTELocked(struct mm_struct *mm, // IN: Mm structure of a process
VA addr) // IN: Address in the virtual address
// space of that process
{
return PgtblPGD2PTELocked(compat_pgd_offset(mm, addr), addr);
}
/*
*-----------------------------------------------------------------------------
*
* PgtblVa2MPNLocked --
*
* Walks through the hardware page tables to try to find the pte
* associated to a virtual address. Then maps PTE to MPN.
* Retrieve MPN for a given va.
*
* Caller must call pte_unmap if valid pte returned. The mm->page_table_lock
* must be held, so this function is not allowed to schedule() --hpreg
*
* Results:
* INVALID_MPN on failure
@@ -48,66 +194,91 @@
static INLINE MPN
PgtblVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a process
VA addr) // IN: Address in the virtual address
// space of that process
{
pgd_t *pgd;
compat_p4d_t *p4d;
MPN mpn;
pte_t *pte;
pgd = pgd_offset(mm, addr);
if (pgd_present(*pgd) == 0) {
return INVALID_MPN;
pte = PgtblVa2PTELocked(mm, addr);
if (pte != NULL) {
MPN mpn = PgtblPte2MPN(pte);
pte_unmap(pte);
return mpn;
}
if (pgd_large(*pgd)) {
/* Linux kernel does not support PGD huge pages. */
/* return pgd_pfn(*pgd) + ((addr & PGD_MASK) >> PAGE_SHIFT); */
return INVALID_MPN;
}
p4d = compat_p4d_offset(pgd, addr);
if (compat_p4d_present(*p4d) == 0) {
return INVALID_MPN;
}
if (compat_p4d_large(*p4d)) {
mpn = compat_p4d_pfn(*p4d) + ((addr & ~COMPAT_P4D_MASK) >> PAGE_SHIFT);
} else {
pud_t *pud;
pud = pud_offset(p4d, addr);
if (pud_present(*pud) == 0) {
return INVALID_MPN;
}
if (pud_large(*pud)) {
mpn = pud_pfn(*pud) + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
} else {
pmd_t *pmd;
pmd = pmd_offset(pud, addr);
if (pmd_present(*pmd) == 0) {
return INVALID_MPN;
}
if (pmd_large(*pmd)) {
mpn = pmd_pfn(*pmd) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
} else {
pte_t *pte;
pte = pte_offset_map(pmd, addr);
if (pte_present(*pte) == 0) {
pte_unmap(pte);
return INVALID_MPN;
}
mpn = pte_pfn(*pte);
pte_unmap(pte);
}
}
}
if (mpn >= INVALID_MPN) {
mpn = INVALID_MPN;
}
return mpn;
return INVALID_MPN;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
/*
*-----------------------------------------------------------------------------
*
* PgtblKVa2MPNLocked --
*
* Retrieve MPN for a given kernel va.
*
* Caller must call pte_unmap if valid pte returned. The mm->page_table_lock
* must be held, so this function is not allowed to schedule() --hpreg
*
* Results:
* INVALID_MPN on failure
* mpn on success
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE MPN
PgtblKVa2MPNLocked(struct mm_struct *mm, // IN: Mm structure of a caller
VA addr) // IN: Address in the virtual address
{
pte_t *pte;
pte = PgtblPGD2PTELocked(compat_pgd_offset_k(mm, addr), addr);
if (pte != NULL) {
MPN mpn = PgtblPte2MPN(pte);
pte_unmap(pte);
return mpn;
}
return INVALID_MPN;
}
#endif
/*
*-----------------------------------------------------------------------------
*
* PgtblVa2PageLocked --
*
* Return the "page" struct for a given va.
*
* Results:
* struct page or NULL. The mm->page_table_lock must be held, so this
* function is not allowed to schedule() --hpreg
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE struct page *
PgtblVa2PageLocked(struct mm_struct *mm, // IN: Mm structure of a process
VA addr) // IN: Address in the virtual address
{
pte_t *pte;
pte = PgtblVa2PTELocked(mm, addr);
if (pte != NULL) {
struct page *page = PgtblPte2Page(pte);
pte_unmap(pte);
return page;
} else {
return NULL;
}
}
/*
*-----------------------------------------------------------------------------
*
@@ -133,10 +304,85 @@ PgtblVa2MPN(VA addr) // IN
/* current->mm is NULL for kernel threads, so use active_mm. */
mm = current->active_mm;
spin_lock(&mm->page_table_lock);
if (compat_get_page_table_lock(mm)) {
spin_lock(compat_get_page_table_lock(mm));
}
mpn = PgtblVa2MPNLocked(mm, addr);
spin_unlock(&mm->page_table_lock);
if (compat_get_page_table_lock(mm)) {
spin_unlock(compat_get_page_table_lock(mm));
}
return mpn;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
/*
*-----------------------------------------------------------------------------
*
* PgtblKVa2MPN --
*
* Walks through the hardware page tables of the current process to try to
* find the page structure associated to a virtual address.
*
* Results:
* Same as PgtblVa2MPNLocked()
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE MPN
PgtblKVa2MPN(VA addr) // IN
{
struct mm_struct *mm = current->active_mm;
MPN mpn;
if (compat_get_page_table_lock(mm)) {
spin_lock(compat_get_page_table_lock(mm));
}
mpn = PgtblKVa2MPNLocked(mm, addr);
if (compat_get_page_table_lock(mm)) {
spin_unlock(compat_get_page_table_lock(mm));
}
return mpn;
}
#endif
/*
*-----------------------------------------------------------------------------
*
* PgtblVa2Page --
*
* Walks through the hardware page tables of the current process to try to
* find the page structure associated to a virtual address.
*
* Results:
* Same as PgtblVa2PageLocked()
*
* Side effects:
* None
*
*-----------------------------------------------------------------------------
*/
static INLINE struct page *
PgtblVa2Page(VA addr) // IN
{
struct mm_struct *mm = current->active_mm;
struct page *page;
if (compat_get_page_table_lock(mm)) {
spin_lock(compat_get_page_table_lock(mm));
}
page = PgtblVa2PageLocked(mm, addr);
if (compat_get_page_table_lock(mm)) {
spin_unlock(compat_get_page_table_lock(mm));
}
return page;
}
#endif /* __PGTBL_H__ */
+4 -13
View File
@@ -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
View File
@@ -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_ */
+5 -13
View File
@@ -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_
-176
View File
@@ -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_ */
-62
View File
@@ -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 */
+11 -8
View File
@@ -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
+3 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+5 -18
View File
@@ -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
+62 -166
View File
@@ -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
+12 -7
View File
@@ -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
View File
@@ -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
+136
View File
@@ -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
+19 -15
View File
@@ -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
@@ -99,13 +99,24 @@ 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);
#endif
@@ -165,6 +176,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 +202,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 +217,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 +305,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 +329,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
File diff suppressed because it is too large. Load diff
+198 -191
View File
@@ -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_
+35 -30
View File
@@ -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_
+90 -91
View File
@@ -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.
+132 -506
View File
@@ -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
View File
@@ -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_
+3 -34
View File
@@ -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
View File
@@ -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.
*/
-88
View File
@@ -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_ */
-140
View File
@@ -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
+7 -1
View File
@@ -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
-50
View File
@@ -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 */
+20 -31
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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
+23 -55
View File
@@ -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
@@ -54,20 +54,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
@@ -89,8 +76,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 +83,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 +186,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 +197,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 +226,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 +238,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_
+2 -3
View File
@@ -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
File diff suppressed because it is too large. Load diff
Loaded 100 of 158 files, more files were not shown because too many files have changed in this diff. Show more