Skip to content

Instantly share code, notes, and snippets.

@kikairoya
Last active June 18, 2023 19:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kikairoya/6218671 to your computer and use it in GitHub Desktop.
Save kikairoya/6218671 to your computer and use it in GitHub Desktop.
diff --git a/modules/linux/dkms.conf b/modules/linux/dkms.conf
index 3ed77f9..263921f 100644
--- a/modules/linux/dkms.conf
+++ b/modules/linux/dkms.conf
@@ -1,39 +1,35 @@
PACKAGE_NAME=open-vm-tools
PACKAGE_VERSION=2013.04.16
MAKE_CMD_TMPL="make VM_UNAME=\$kernelver \
- MODULEBUILDDIR=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build"
+ MODULEBUILDDIR=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build \
+ CC_WARNINGS=-Wno-unused-local-typedefs"
# The vsock module depends on symbols exported by the vmci module, so it
# needs to be built afterwards; the MODULEBUILDDIR variable tells the makefiles
# where to store / retrive those symbol files.
MAKE[0]="$MAKE_CMD_TMPL -C vmblock; \
- $MAKE_CMD_TMPL -C vmci; \
$MAKE_CMD_TMPL -C vmhgfs; \
$MAKE_CMD_TMPL -C vmsync; \
$MAKE_CMD_TMPL -C vmxnet; \
$MAKE_CMD_TMPL -C vsock"
CLEAN[0]="$MAKE_CMD_TMPL -C vmblock clean; \
- $MAKE_CMD_TMPL -C vmci clean; \
$MAKE_CMD_TMPL -C vmhgfs clean; \
- $MAKE_CMD_TMPL -C vmsync clean"; \
+ $MAKE_CMD_TMPL -C vmsync clean; \
$MAKE_CMD_TMPL -C vmxnet clean; \
- $MAKE_CMD_TMPL -C vsock clean
+ $MAKE_CMD_TMPL -C vsock clean"
BUILT_MODULE_NAME[0]="vmblock"
-BUILT_MODULE_NAME[1]="vmci"
-BUILT_MODULE_NAME[2]="vmhgfs"
-BUILT_MODULE_NAME[3]="vmsync"
-BUILT_MODULE_NAME[4]="vmxnet"
-BUILT_MODULE_NAME[5]="vsock"
+BUILT_MODULE_NAME[1]="vmhgfs"
+BUILT_MODULE_NAME[2]="vmsync"
+BUILT_MODULE_NAME[3]="vmxnet"
+BUILT_MODULE_NAME[4]="vsock"
BUILT_MODULE_LOCATION[0]="vmblock/"
-BUILT_MODULE_LOCATION[1]="vmci/"
-BUILT_MODULE_LOCATION[2]="vmhgfs/"
-BUILT_MODULE_LOCATION[3]="vmsync/"
-BUILT_MODULE_LOCATION[4]="vmxnet/"
-BUILT_MODULE_LOCATION[5]="vsock/"
+BUILT_MODULE_LOCATION[1]="vmhgfs/"
+BUILT_MODULE_LOCATION[2]="vmsync/"
+BUILT_MODULE_LOCATION[3]="vmxnet/"
+BUILT_MODULE_LOCATION[4]="vsock/"
DEST_MODULE_LOCATION[0]="/kernel/fs/vmblock"
-DEST_MODULE_LOCATION[1]="/kernel/drivers/misc"
-DEST_MODULE_LOCATION[2]="/kernel/fs/vmhgfs"
-DEST_MODULE_LOCATION[3]="/kernel/drivers/misc"
-DEST_MODULE_LOCATION[4]="/kernel/drivers/net"
-DEST_MODULE_LOCATION[5]="/kernel/net/vsock"
+DEST_MODULE_LOCATION[1]="/kernel/fs/vmhgfs"
+DEST_MODULE_LOCATION[2]="/kernel/drivers/misc"
+DEST_MODULE_LOCATION[3]="/kernel/drivers/net"
+DEST_MODULE_LOCATION[4]="/kernel/net/vsock"
AUTOINSTALL="YES"
diff --git a/modules/linux/vmblock/linux/control.c b/modules/linux/vmblock/linux/control.c
index 79716bd..ee64cdc 100644
--- a/modules/linux/vmblock/linux/control.c
+++ b/modules/linux/vmblock/linux/control.c
@@ -208,9 +208,10 @@ SetupProcDevice(void)
VMBlockSetProcEntryOwner(controlProcMountpoint);
/* Create /proc/fs/vmblock/dev */
- controlProcEntry = create_proc_entry(VMBLOCK_CONTROL_DEVNAME,
- VMBLOCK_CONTROL_MODE,
- controlProcDirEntry);
+ controlProcEntry = proc_create(VMBLOCK_CONTROL_DEVNAME,
+ VMBLOCK_CONTROL_MODE,
+ controlProcDirEntry,
+ &ControlFileOps);
if (!controlProcEntry) {
Warning("SetupProcDevice: could not create " VMBLOCK_DEVICE "\n");
remove_proc_entry(VMBLOCK_CONTROL_MOUNTPOINT, controlProcDirEntry);
@@ -218,7 +219,6 @@ SetupProcDevice(void)
return -EINVAL;
}
- controlProcEntry->proc_fops = &ControlFileOps;
return 0;
}
@@ -278,7 +278,7 @@ ExecuteBlockOp(const char __user *buf, // IN: buffer with name
int (*blockOp)(const char *filename, // IN: block operation
const os_blocker_id_t blocker))
{
- char *name;
+ struct filename *name;
int i;
int retval;
@@ -287,13 +287,13 @@ ExecuteBlockOp(const char __user *buf, // IN: buffer with name
return PTR_ERR(name);
}
- for (i = strlen(name) - 1; i >= 0 && name[i] == '/'; i--) {
- name[i] = '\0';
+ for (i = strlen(name->name) - 1; i >= 0 && name->name[i] == '/'; i--) {
+ ((char *)name->name)[i] = '\0';
}
- retval = i < 0 ? -EINVAL : blockOp(name, blocker);
+ retval = i < 0 ? -EINVAL : blockOp(name->name, blocker);
- putname(name);
+ __putname(name);
return retval;
}
diff --git a/modules/linux/vmblock/linux/dentry.c b/modules/linux/vmblock/linux/dentry.c
index 05ea95a..d93b2f0 100644
--- a/modules/linux/vmblock/linux/dentry.c
+++ b/modules/linux/vmblock/linux/dentry.c
@@ -31,8 +31,7 @@
#include "filesystem.h"
#include "block.h"
-
-static int DentryOpRevalidate(struct dentry *dentry, struct nameidata *nd);
+static int DentryOpRevalidate(struct dentry *dentry, unsigned int flags);
struct dentry_operations LinkDentryOps = {
.d_revalidate = DentryOpRevalidate,
@@ -60,7 +59,7 @@ struct dentry_operations LinkDentryOps = {
static int
DentryOpRevalidate(struct dentry *dentry, // IN: dentry revalidating
- struct nameidata *nd) // IN: lookup flags & intent
+ unsigned int flags) // IN: lookup flags
{
VMBlockInodeInfo *iinfo;
struct nameidata actualNd;
@@ -101,7 +100,7 @@ DentryOpRevalidate(struct dentry *dentry, // IN: dentry revalidating
if (actualDentry &&
actualDentry->d_op &&
actualDentry->d_op->d_revalidate) {
- return actualDentry->d_op->d_revalidate(actualDentry, nd);
+ return actualDentry->d_op->d_revalidate(actualDentry, flags);
}
if (compat_path_lookup(iinfo->name, 0, &actualNd)) {
diff --git a/modules/linux/vmblock/linux/inode.c b/modules/linux/vmblock/linux/inode.c
index 098c94c..ddd37f3 100644
--- a/modules/linux/vmblock/linux/inode.c
+++ b/modules/linux/vmblock/linux/inode.c
@@ -36,7 +36,7 @@
/* Inode operations */
static struct dentry *InodeOpLookup(struct inode *dir,
- struct dentry *dentry, struct nameidata *nd);
+ struct dentry *dentry, unsigned int flags);
static int InodeOpReadlink(struct dentry *dentry, char __user *buffer, int buflen);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
static void *InodeOpFollowlink(struct dentry *dentry, struct nameidata *nd);
@@ -75,7 +75,7 @@ static struct inode_operations LinkInodeOps = {
static struct dentry *
InodeOpLookup(struct inode *dir, // IN: parent directory's inode
struct dentry *dentry, // IN: dentry to lookup
- struct nameidata *nd) // IN: lookup intent and information
+ unsigned int flags) // IN: lookup flags
{
char *filename;
struct inode *inode;
diff --git a/modules/linux/vmci/COPYING b/modules/linux/vmci/COPYING
deleted file mode 100644
index d511905..0000000
--- a/modules/linux/vmci/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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; either version 2 of the License, or
- (at your option) any 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
diff --git a/modules/linux/vmci/Makefile b/modules/linux/vmci/Makefile
deleted file mode 100644
index a8cc0b7..0000000
--- a/modules/linux/vmci/Makefile
+++ /dev/null
@@ -1,171 +0,0 @@
-#!/usr/bin/make -f
-##########################################################
-# 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
-# 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
-#
-##########################################################
-
-####
-#### VMware kernel module Makefile to be distributed externally
-####
-
-####
-#### SRCROOT _must_ be a relative path.
-####
-SRCROOT = .
-
-#
-# open-vm-tools doesn't replicate shared source files for different modules;
-# instead, files are kept in shared locations. So define a few useful macros
-# to be able to handle both cases cleanly.
-#
-INCLUDE :=
-ifdef OVT_SOURCE_DIR
-AUTOCONF_DIR := $(OVT_SOURCE_DIR)/modules/linux/shared/autoconf
-VMLIB_PATH = $(OVT_SOURCE_DIR)/lib/$(1)
-INCLUDE += -I$(OVT_SOURCE_DIR)/modules/linux/shared
-INCLUDE += -I$(OVT_SOURCE_DIR)/lib/include
-else
-AUTOCONF_DIR := $(SRCROOT)/shared/autoconf
-INCLUDE += -I$(SRCROOT)/shared
-endif
-
-
-VM_UNAME = $(shell uname -r)
-
-# Header directory for the running kernel
-ifdef LINUXINCLUDE
-HEADER_DIR = $(LINUXINCLUDE)
-else
-HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include
-endif
-
-BUILD_DIR = $(HEADER_DIR)/..
-
-DRIVER := vmci
-PRODUCT := tools-source
-
-# Grep program
-GREP = /bin/grep
-
-vm_check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
- > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
-vm_check_file = $(shell if test -f $(1); then echo "yes"; else echo "no"; fi)
-
-ifndef VM_KBUILD
-VM_KBUILD := no
-ifeq ($(call vm_check_file,$(BUILD_DIR)/Makefile), yes)
-ifneq ($(call vm_check_file,$(BUILD_DIR)/Rules.make), yes)
-VM_KBUILD := 26
-endif
-endif
-export VM_KBUILD
-endif
-
-ifndef VM_KBUILD_SHOWN
-ifeq ($(VM_KBUILD), no)
-VM_DUMMY := $(shell echo >&2 "Using standalone build system.")
-else
-ifeq ($(VM_KBUILD), 24)
-VM_DUMMY := $(shell echo >&2 "Using 2.4.x kernel build system.")
-else
-VM_DUMMY := $(shell echo >&2 "Using 2.6.x kernel build system.")
-endif
-endif
-VM_KBUILD_SHOWN := yes
-export VM_KBUILD_SHOWN
-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),)
-
-ifeq ($(VM_KBUILD), 24)
-DRIVER_KO := $(DRIVER).o
-else
-DRIVER_KO := $(DRIVER).ko
-endif
-
-.PHONY: $(DRIVER_KO)
-
-auto-build: $(DRIVER_KO)
- cp -f $< $(SRCROOT)/../$(DRIVER).o
-
-# $(DRIVER_KO) is a phony target, so compare file times explicitly
-$(DRIVER): $(DRIVER_KO)
- if [ $< -nt $@ ] || [ ! -e $@ ] ; then cp -f $< $@; fi
-
-# 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.
-# This target may not be used at all, but if it is then it will be defined
-# in Makefile.kernel
-#
-prebuild:: ;
-postbuild:: ;
-
-$(DRIVER_KO): prebuild
- $(MAKE) -C $(BUILD_DIR) SUBDIRS=$$PWD SRCROOT=$$PWD/$(SRCROOT) \
- MODULEBUILDDIR=$(MODULEBUILDDIR) modules
- $(MAKE) -C $$PWD SRCROOT=$$PWD/$(SRCROOT) \
- MODULEBUILDDIR=$(MODULEBUILDDIR) postbuild
-endif
-
-vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
- $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
- $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
- -DKBUILD_BASENAME=\"$(DRIVER)\" \
- -Werror -S -o /dev/null -xc $(1) \
- > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi)
-
-CC_WARNINGS := -Wall -Wstrict-prototypes
-CC_OPTS := $(GLOBAL_DEFS) $(CC_WARNINGS) -DVMW_USING_KBUILD
-ifdef VMX86_DEVEL
-CC_OPTS += -DVMX86_DEVEL
-endif
-ifdef VMX86_DEBUG
-CC_OPTS += -DVMX86_DEBUG
-endif
-
-include $(SRCROOT)/Makefile.kernel
-
-ifdef TOPDIR
-ifeq ($(VM_KBUILD), 24)
-
-O_TARGET := $(DRIVER).o
-
-obj-y := $($(DRIVER)-y)
-
-include $(TOPDIR)/Rules.make
-endif
-endif
-
-else
-
-include $(SRCROOT)/Makefile.normal
-
-endif
-
-#.SILENT:
diff --git a/modules/linux/vmci/Makefile.kernel b/modules/linux/vmci/Makefile.kernel
deleted file mode 100644
index ba343ee..0000000
--- a/modules/linux/vmci/Makefile.kernel
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/make -f
-##########################################################
-# Copyright (C) 2007 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
-#
-##########################################################
-
-CC_OPTS += -DVMCI
-
-INCLUDE += -I$(SRCROOT)/shared -I$(SRCROOT)/common -I$(SRCROOT)/linux
-
-EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE)
-
-obj-m += $(DRIVER).o
-
-$(DRIVER)-y := $(subst $(SRCROOT)/, , $(patsubst %.c, %.o, \
- $(wildcard $(SRCROOT)/linux/*.c $(SRCROOT)/common/*.c)))
-
-#
-# In open-vm-tools, need to compile the common sources from the shared directory.
-#
-DRIVERLOG := driverLog.o
-$(DRIVER)-y += $(DRIVERLOG)
-
-VMCI_PATH := $(shell cd $(SRCROOT) && pwd)
-ifdef OVT_SOURCE_DIR
-DRIVERLOG_PATH := $(OVT_SOURCE_DIR)/modules/linux/shared
-else
-DRIVERLOG_PATH := $(VMCI_PATH)/shared
-endif
-
-$(addprefix $(VMCI_PATH)/,$(DRIVERLOG)): $(VMCI_PATH)/%.o: $(DRIVERLOG_PATH)/%.c
- $(Q)$(rule_cc_o_c)
-
-clean:
- rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \
- Module.symvers Modules.symvers Module.markers modules.order \
- $(foreach dir,linux/ common/ \
- ./,$(addprefix $(dir),.*.cmd .*.o.flags *.o)))
-ifneq ($(MODULEBUILDDIR),)
- rm -f $(MODULEBUILDDIR)/VMwareVMCIModule.symvers
-endif
-
-#
-# If this build generated a Module.symvers, copy it to a public place where
-# the VMCI Sockets build will be able to find it.
-#
-postbuild::
-ifeq ($(call vm_check_file,$(SRCROOT)/Module.symvers), yes)
-ifneq ($(MODULEBUILDDIR),)
- cp -f $(SRCROOT)/Module.symvers $(MODULEBUILDDIR)/VMwareVMCIModule.symvers
-endif
-endif
diff --git a/modules/linux/vmci/Makefile.normal b/modules/linux/vmci/Makefile.normal
deleted file mode 100644
index dda1844..0000000
--- a/modules/linux/vmci/Makefile.normal
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/usr/bin/make -f
-##########################################################
-# Copyright (C) 2007 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_check_build = $(shell if $(CC) $(CC_OPTS) $(INCLUDE) -Werror -S -o /dev/null -xc $(1) \
- > /dev/null 2>&1; then echo "$(2)"; else echo "$(3)"; fi)
-
-####
-#### DESTDIR is where the module, object files, and dependencies are built
-####
-DESTDIR := driver-$(VM_UNAME)
-
-####
-#### 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)
-
-ifneq (,$(filter x86_64%, $(shell $(CC) -dumpmachine)))
-MACHINE := x86_64
-else
-MACHINE := x386
-endif
-
-ifdef QUIET
-ECHO := @true
-else
-ECHO := @echo
-endif
-
-####
-#### You must compile with at least -O level of optimization
-#### or the module won't load.
-#### If desparate, I think that bringing in <linux/bitops.h> might
-#### suffice.
-####
-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)\"
-CC_KFLAGS += $(call vm_check_gcc,-falign-loops=2 -falign-jumps=2 -falign-functions=2, \
- -malign-loops=2 -malign-jumps=2 -malign-functions=2)
-CC_KFLAGS += $(call vm_check_gcc,-fno-strict-aliasing,)
-ifeq ($(MACHINE),x86_64)
-CC_KFLAGS += -mno-red-zone -mcmodel=kernel
-else
-# Gcc 3.0 deprecates -m486 --hpreg
-CC_KFLAGS += -DCPU=586 $(call check_gcc,-march=i586,-m486)
-endif
-
-CC_OPTS := -O2 -DMODULE -DVMCI $(GLOBAL_DEFS) $(CC_KFLAGS) $(CC_WARNINGS)
-
-INCLUDE := -I$(SRCROOT)/shared -I$(SRCROOT)/common -I$(SRCROOT)/linux \
- -I$(HEADER_DIR)
-
-INCLUDE += $(shell $(CC) $(INCLUDE) -E $(SRCROOT)/shared/autoconf/geninclude.c \
- | sed -n -e 's!^APATH!-I$(HEADER_DIR)/asm!p')
-
-ifdef OVT_SOURCE_PATH
-DRIVERLOGPATH := $(OVT_SOURCE_DIR)/modules/linux/shared
-else
-DRIVERLOGPATH := $(SRCROOT)/shared
-endif
-
-C_TARGETS_LINUX := driver.o vmciKernelIf.o
-C_TARGETS_COMMON := vmciContext.o vmciDatagram.o vmciDriver.o \
- vmciHashtable.o vmciResource.o \
- vmciQueuePair.o vmciEvent.o vmciRoute.o
-
-C_TARGETS_LINUX_D := ${C_TARGETS_LINUX:.o=.d}
-C_TARGETS_COMMON_D := ${C_TARGETS_COMMON:.o=.d}
-C_TARGETS := $(C_TARGETS_LINUX) $(C_TARGETS_COMMON) driverLog.o
-
-####
-#### Make Targets are beneath here.
-####
-
-driver: setup deps
- $(MAKE) -C $(DESTDIR) -f ../Makefile SRCROOT=../$(SRCROOT) $(DRIVER).o \
- INCLUDE_DEPS=1
-
-setup:
- @if [ -d $(DESTDIR) ] ; then true ; else mkdir $(DESTDIR); chmod 755 $(DESTDIR) ; fi
-
-$(DRIVER) $(DRIVER).o: $(DRIVERNAME)
- cp -f $< $@
-
-$(DRIVERNAME): $(C_TARGETS)
- $(ECHO) "Building $(DRIVERNAME)"
- ld -r -o $(DRIVERNAME) $(C_TARGETS)
-
-auto-build:
- $(MAKE) driver QUIET=1
- cp -f $(DESTDIR)/$(DRIVERNAME) $(SRCROOT)/../$(DRIVER).o
-
-$(C_TARGETS_LINUX): %.o: $(SRCROOT)/linux/%.c
- $(ECHO) "Compiling linux/$(<F)"
- $(CC) $(CC_OPTS) $(INCLUDE) -c $<
-
-$(C_TARGETS_COMMON): %.o: $(SRCROOT)/common/%.c
- $(ECHO) "Compiling common/$(<F)"
- $(CC) $(CC_OPTS) $(INCLUDE) -c $<
-
-driverLog.o: $(DRIVERLOGPATH)/driverLog.c
- $(CC) $(CC_OPTS) $(INCLUDE) -c $<
-
-clean:
- rm -rf $(DESTDIR)/
-
-$(C_TARGETS_COMMON_D): %.d: $(SRCROOT)/common/%.c
- $(ECHO) "Dependencies for $(<F)"
- $(CC) -MM $(CC_OPTS) $(INCLUDE) $< > $@
-
-$(C_TARGETS_LINUX_D): %.d: $(SRCROOT)/linux/%.c
- $(ECHO) "Dependencies for $(<F)"
- $(CC) -MM $(CC_OPTS) $(INCLUDE) $< > $@
-
-driverLog.d: $(DRIVERLOGPATH)/driverLog.c
- $(ECHO) "Dependencies for $(<F)"
- $(CC) -MM $(CC_OPTS) $(INCLUDE) $< > $@
-
-deps: setup
- $(MAKE) -C $(DESTDIR) -f ../Makefile SRCROOT=../$(SRCROOT) driver_deps
-
-driver_deps: ${C_TARGETS:.o=.d}
-
-ifdef INCLUDE_DEPS
-include ${C_TARGETS:.o=.d}
-endif
-
-.SILENT:
diff --git a/modules/linux/vmci/common/vmciCommonInt.h b/modules/linux/vmci/common/vmciCommonInt.h
deleted file mode 100644
index 8af33b4..0000000
--- a/modules/linux/vmci/common/vmciCommonInt.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*********************************************************
- * Copyright (C) 2006-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
- *
- *********************************************************/
-
-/*
- * vmciCommonInt.h --
- *
- * Struct definitions for VMCI internal common code.
- */
-
-#ifndef _VMCI_COMMONINT_H_
-#define _VMCI_COMMONINT_H_
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vm_atomic.h"
-#include "vmci_defs.h"
-#include "vmci_call_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmci_handle_array.h"
-#include "vmci_kernel_if.h"
-
-/*
- * The DatagramQueueEntry is a queue header for the in-kernel VMCI
- * datagram queues. It is allocated in non-paged memory, as the
- * content is accessed while holding a spinlock. The pending datagram
- * itself may be allocated from paged memory. We shadow the size of
- * the datagram in the non-paged queue entry as this size is used
- * while holding the same spinlock as above.
- */
-
-typedef struct DatagramQueueEntry {
- VMCIListItem listItem; /* For queuing. */
- size_t dgSize; /* Size of datagram. */
- VMCIDatagram *dg; /* Pending datagram. */
-} DatagramQueueEntry;
-
-
-/*
- * The VMCIFilterState captures the state of all VMCI filters in one
- * direction. The ranges array contains all filter list in a single
- * memory chunk, and the filter list pointers in the VMCIProtoFilters
- * point into the ranges array.
- */
-
-typedef struct VMCIFilterState {
- VMCIProtoFilters filters;
- VMCIIdRange *ranges;
- size_t rangesSize;
-} VMCIFilterState;
-
-
-struct VMCIContext {
- VMCIListItem listItem; /* For global VMCI list. */
- VMCIId cid;
- Atomic_uint32 refCount;
- VMCIList datagramQueue; /* Head of per VM queue. */
- uint32 pendingDatagrams;
- size_t datagramQueueSize;/* Size of datagram queue in bytes. */
- int userVersion; /*
- * Version of the code that created
- * this context; e.g., VMX.
- */
- VMCILock lock; /*
- * Locks datagramQueue, inFilters,
- * doorbellArray, pendingDoorbellArray
- * and notifierArray.
- */
- VMCIHandleArray *queuePairArray; /*
- * QueuePairs attached to. The array of
- * handles for queue pairs is accessed
- * from the code for QP API, and there
- * it is protected by the QP lock. It
- * is also accessed from the context
- * clean up path, which does not
- * require a lock. VMCILock is not
- * used to protect the QP array.
- */
- VMCIHandleArray *doorbellArray; /* Doorbells created by context. */
- VMCIHandleArray *pendingDoorbellArray; /* Doorbells pending for context. */
- VMCIHandleArray *notifierArray; /* Contexts current context is subscribing to. */
- VMCIHost hostContext;
- VMCIPrivilegeFlags privFlags;
- VMCIHostUser user;
- Bool validUser;
-#ifdef VMKERNEL
- Bool isQuiesced; /* Whether current VM is quiesced */
- VMCIId migrateCid; /* The migrate cid if it is migrating */
- VMCIMutex guestMemMutex; /*
- * Coordinates guest memory
- * registration/release during FSR.
- */
- VMCIGuestMemID curGuestMemID; /* ID of current registered guest mem */
- VMCIFilterState *inFilters; /* Ingoing filters for VMCI traffic. */
-#endif
-#ifndef VMX86_SERVER
- Bool *notify; /* Notify flag pointer - hosted only. */
-# ifdef __linux__
- struct page *notifyPage; /* Page backing the notify UVA. */
-# endif
-#endif
-};
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDenyInteraction --
- *
- * Utilility function that checks whether two entities are allowed
- * to interact. If one of them is restricted, the other one must
- * be trusted.
- *
- * Result:
- * TRUE if the two entities are not allowed to interact. FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static INLINE Bool
-VMCIDenyInteraction(VMCIPrivilegeFlags partOne, // IN
- VMCIPrivilegeFlags partTwo) // IN
-{
- return (((partOne & VMCI_PRIVILEGE_FLAG_RESTRICTED) &&
- !(partTwo & VMCI_PRIVILEGE_FLAG_TRUSTED)) ||
- ((partTwo & VMCI_PRIVILEGE_FLAG_RESTRICTED) &&
- !(partOne & VMCI_PRIVILEGE_FLAG_TRUSTED)));
-}
-
-#endif /* _VMCI_COMMONINT_H_ */
diff --git a/modules/linux/vmci/common/vmciContext.c b/modules/linux/vmci/common/vmciContext.c
deleted file mode 100644
index 5a698e3..0000000
--- a/modules/linux/vmci/common/vmciContext.c
+++ /dev/null
@@ -1,2716 +0,0 @@
-/*********************************************************
- * Copyright (C) 2006-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
- *
- *********************************************************/
-
-/*
- * vmciContext.c --
- *
- * Platform independent routines for VMCI calls.
- */
-
-#include "vmci_kernel_if.h"
-#include "vm_assert.h"
-#include "vmci_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmciCommonInt.h"
-#include "vmciContext.h"
-#include "vmciDatagram.h"
-#include "vmciDoorbell.h"
-#include "vmciDriver.h"
-#include "vmciEvent.h"
-#include "vmciKernelAPI.h"
-#include "vmciQueuePair.h"
-#if defined(VMKERNEL)
-# include "vmciVmkInt.h"
-# include "vm_libc.h"
-# include "helper_ext.h"
-#endif
-
-#define LGPFX "VMCIContext: "
-
-static void VMCIContextFreeContext(VMCIContext *context);
-static Bool VMCIContextExists(VMCIId cid);
-static int VMCIContextFireNotification(VMCIId contextID,
- VMCIPrivilegeFlags privFlags);
-#if defined(VMKERNEL)
-static void VMCIContextReleaseGuestMemLocked(VMCIContext *context,
- VMCIGuestMemID gid);
-static void VMCIContextInFilterCleanup(VMCIContext *context);
-#endif
-
-/*
- * List of current VMCI contexts.
- */
-
-static struct {
- VMCIList head;
- VMCILock lock;
- VMCILock firingLock;
-} contextList;
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContextSignalNotify --
- *
- * Sets the notify flag to TRUE. Assumes that the context lock is
- * held.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIContextSignalNotify(VMCIContext *context) // IN:
-{
-#ifndef VMX86_SERVER
- if (context->notify) {
- *context->notify = TRUE;
- }
-#endif
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContextClearNotify --
- *
- * Sets the notify flag to FALSE. Assumes that the context lock is
- * held.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIContextClearNotify(VMCIContext *context) // IN:
-{
-#ifndef VMX86_SERVER
- if (context->notify) {
- *context->notify = FALSE;
- }
-#endif
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContextClearNotifyAndCall --
- *
- * If nothing requires the attention of the guest, clears both
- * notify flag and call.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIContextClearNotifyAndCall(VMCIContext *context) // IN:
-{
- if (context->pendingDatagrams == 0 &&
- VMCIHandleArray_GetSize(context->pendingDoorbellArray) == 0) {
- VMCIHost_ClearCall(&context->hostContext);
- VMCIContextClearNotify(context);
- }
-}
-
-
-#ifndef VMX86_SERVER
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_CheckAndSignalNotify --
- *
- * Sets the context's notify flag iff datagrams are pending for this
- * context. Called from VMCISetupNotify().
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_CheckAndSignalNotify(VMCIContext *context) // IN:
-{
- VMCILockFlags flags;
-
- ASSERT(context);
- VMCI_GrabLock(&context->lock, &flags);
- if (context->pendingDatagrams) {
- VMCIContextSignalNotify(context);
- }
- VMCI_ReleaseLock(&context->lock, flags);
-}
-#endif
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_Init --
- *
- * Initializes the VMCI context module.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_Init(void)
-{
- int err;
-
- VMCIList_Init(&contextList.head);
-
- err = VMCI_InitLock(&contextList.lock, "VMCIContextListLock",
- VMCI_LOCK_RANK_CONTEXTLIST);
- if (err < VMCI_SUCCESS) {
- return err;
- }
-
- err = VMCI_InitLock(&contextList.firingLock, "VMCIContextFiringLock",
- VMCI_LOCK_RANK_CONTEXTFIRE);
- if (err < VMCI_SUCCESS) {
- VMCI_CleanupLock(&contextList.lock);
- }
-
- return err;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_Exit --
- *
- * Cleans up the contexts module.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_Exit(void)
-{
- VMCI_CleanupLock(&contextList.firingLock);
- VMCI_CleanupLock(&contextList.lock);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_InitContext --
- *
- * Allocates and initializes a VMCI context.
- *
- * Results:
- * Returns 0 on success, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_InitContext(VMCIId cid, // IN
- VMCIPrivilegeFlags privFlags, // IN
- uintptr_t eventHnd, // IN
- int userVersion, // IN: User's vers no.
- VMCIHostUser *user, // IN
- VMCIContext **outContext) // OUT
-{
- VMCILockFlags flags;
- VMCIContext *context;
- int result;
-
- if (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid flag (flags=0x%x) for VMCI context.\n",
- privFlags));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (userVersion == 0) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- context = VMCI_AllocKernelMem(sizeof *context, VMCI_MEMORY_NONPAGED);
- if (context == NULL) {
- VMCI_WARNING((LGPFX"Failed to allocate memory for VMCI context.\n"));
- return VMCI_ERROR_NO_MEM;
- }
- memset(context, 0, sizeof *context);
-
- VMCIList_InitEntry(&context->listItem);
- VMCIList_Init(&context->datagramQueue);
-
- context->userVersion = userVersion;
-
- context->queuePairArray = VMCIHandleArray_Create(0);
- if (!context->queuePairArray) {
- result = VMCI_ERROR_NO_MEM;
- goto error;
- }
-
- context->doorbellArray = VMCIHandleArray_Create(0);
- if (!context->doorbellArray) {
- result = VMCI_ERROR_NO_MEM;
- goto error;
- }
-
- context->pendingDoorbellArray = VMCIHandleArray_Create(0);
- if (!context->pendingDoorbellArray) {
- result = VMCI_ERROR_NO_MEM;
- goto error;
- }
-
- context->notifierArray = VMCIHandleArray_Create(0);
- if (context->notifierArray == NULL) {
- result = VMCI_ERROR_NO_MEM;
- goto error;
- }
-
- result = VMCI_InitLock(&context->lock, "VMCIContextLock",
- VMCI_LOCK_RANK_CONTEXT);
- if (result < VMCI_SUCCESS) {
- goto error;
- }
- Atomic_Write(&context->refCount, 1);
-
-#if defined(VMKERNEL)
- result = VMCIMutex_Init(&context->guestMemMutex, "VMCIGuestMem",
- VMCI_SEMA_RANK_GUESTMEM);
- if (result < VMCI_SUCCESS) {
- VMCI_CleanupLock(&context->lock);
- goto error;
- }
- context->curGuestMemID = INVALID_VMCI_GUEST_MEM_ID;
-
- context->inFilters = NULL;
-#endif
-
- /* Inititialize host-specific VMCI context. */
- VMCIHost_InitContext(&context->hostContext, eventHnd);
-
- context->privFlags = privFlags;
-
- /*
- * If we collide with an existing context we generate a new and use it
- * instead. The VMX will determine if regeneration is okay. Since there
- * isn't 4B - 16 VMs running on a given host, the below loop will terminate.
- */
- VMCI_GrabLock(&contextList.lock, &flags);
- ASSERT(cid != VMCI_INVALID_ID);
- while (VMCIContextExists(cid)) {
-
- /*
- * If the cid is below our limit and we collide we are creating duplicate
- * contexts internally so we want to assert fail in that case.
- */
- ASSERT(cid >= VMCI_RESERVED_CID_LIMIT);
-
- /* We reserve the lowest 16 ids for fixed contexts. */
- cid = MAX(cid, VMCI_RESERVED_CID_LIMIT-1) + 1;
- if (cid == VMCI_INVALID_ID) {
- cid = VMCI_RESERVED_CID_LIMIT;
- }
- }
- ASSERT(!VMCIContextExists(cid));
- context->cid = cid;
- context->validUser = user != NULL;
- if (context->validUser) {
- context->user = *user;
- }
- VMCIList_Insert(&context->listItem, &contextList.head);
- VMCI_ReleaseLock(&contextList.lock, flags);
-
-#ifdef VMKERNEL
- VMCIContext_SetFSRState(context, FALSE, VMCI_INVALID_ID, eventHnd, FALSE);
-#endif
-
-#ifndef VMX86_SERVER
- context->notify = NULL;
-# ifdef __linux__
- context->notifyPage = NULL;
-# endif
-#endif
-
- *outContext = context;
- return VMCI_SUCCESS;
-
-error:
- if (context->notifierArray) {
- VMCIHandleArray_Destroy(context->notifierArray);
- }
- if (context->queuePairArray) {
- VMCIHandleArray_Destroy(context->queuePairArray);
- }
- if (context->doorbellArray) {
- VMCIHandleArray_Destroy(context->doorbellArray);
- }
- if (context->pendingDoorbellArray) {
- VMCIHandleArray_Destroy(context->pendingDoorbellArray);
- }
- VMCI_FreeKernelMem(context, sizeof *context);
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_ReleaseContext --
- *
- * Cleans up a VMCI context.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_ReleaseContext(VMCIContext *context) // IN
-{
- VMCILockFlags flags;
-
- /* Dequeue VMCI context. */
-
- VMCI_GrabLock(&contextList.lock, &flags);
- VMCIList_Remove(&context->listItem);
- VMCI_ReleaseLock(&contextList.lock, flags);
-
- VMCIContext_Release(context);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIContextFreeContext --
- *
- * Deallocates all parts of a context datastructure. This
- * functions doesn't lock the context, because it assumes that
- * the caller is holding the last reference to context. As paged
- * memory may be freed as part of the call, the function must be
- * called without holding any spinlocks as this is not allowed on
- * Windows.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Paged memory is freed.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIContextFreeContext(VMCIContext *context) // IN
-{
- VMCIListItem *curr;
- VMCIListItem *next;
- DatagramQueueEntry *dqEntry;
- VMCIHandle tempHandle;
-
- /* Fire event to all contexts interested in knowing this context is dying. */
- VMCIContextFireNotification(context->cid, context->privFlags);
-
- /*
- * Cleanup all queue pair resources attached to context. If the VM dies
- * without cleaning up, this code will make sure that no resources are
- * leaked.
- */
-
- tempHandle = VMCIHandleArray_GetEntry(context->queuePairArray, 0);
- while (!VMCI_HANDLE_EQUAL(tempHandle, VMCI_INVALID_HANDLE)) {
- if (VMCIQPBroker_Detach(tempHandle, context) < VMCI_SUCCESS) {
- /*
- * When VMCIQPBroker_Detach() succeeds it removes the handle from the
- * array. If detach fails, we must remove the handle ourselves.
- */
- VMCIHandleArray_RemoveEntry(context->queuePairArray, tempHandle);
- }
- tempHandle = VMCIHandleArray_GetEntry(context->queuePairArray, 0);
- }
-
- /*
- * It is fine to destroy this without locking the datagramQueue, as
- * this is the only thread having a reference to the context.
- */
-
- VMCIList_ScanSafe(curr, next, &context->datagramQueue) {
- dqEntry = VMCIList_Entry(curr, DatagramQueueEntry, listItem);
- VMCIList_Remove(curr);
- ASSERT(dqEntry && dqEntry->dg);
- ASSERT(dqEntry->dgSize == VMCI_DG_SIZE(dqEntry->dg));
- VMCI_FreeKernelMem(dqEntry->dg, dqEntry->dgSize);
- VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry);
- }
-
- VMCIHandleArray_Destroy(context->notifierArray);
- VMCIHandleArray_Destroy(context->queuePairArray);
- VMCIHandleArray_Destroy(context->doorbellArray);
- VMCIHandleArray_Destroy(context->pendingDoorbellArray);
- VMCI_CleanupLock(&context->lock);
-#if defined(VMKERNEL)
- VMCIContextInFilterCleanup(context);
- VMCIMutex_Destroy(&context->guestMemMutex);
-#endif
- VMCIHost_ReleaseContext(&context->hostContext);
-#ifndef VMX86_SERVER
-# ifdef __linux__
- /* TODO Windows and Mac OS. */
- VMCIUnsetNotify(context);
-# endif
-#endif
- VMCI_FreeKernelMem(context, sizeof *context);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_PendingDatagrams --
- *
- * Returns the current number of pending datagrams. The call may
- * also serve as a synchronization point for the datagram queue,
- * as no enqueue operations can occur concurrently.
- *
- * Results:
- * Length of datagram queue for the given context.
- *
- * Side effects:
- * Locks datagram queue.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_PendingDatagrams(VMCIId cid, // IN
- uint32 *pending) // OUT
-{
- VMCIContext *context;
- VMCILockFlags flags;
-
- context = VMCIContext_Get(cid);
- if (context == NULL) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCI_GrabLock(&context->lock, &flags);
- if (pending) {
- *pending = context->pendingDatagrams;
- }
- VMCI_ReleaseLock(&context->lock, flags);
- VMCIContext_Release(context);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_EnqueueDatagram --
- *
- * Queues a VMCI datagram for the appropriate target VM
- * context.
- *
- * Results:
- * Size of enqueued data on success, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_EnqueueDatagram(VMCIId cid, // IN: Target VM
- VMCIDatagram *dg) // IN:
-{
- DatagramQueueEntry *dqEntry;
- VMCIContext *context;
- VMCILockFlags flags;
- VMCIHandle dgSrc;
- size_t vmciDgSize;
-
- ASSERT(dg);
- vmciDgSize = VMCI_DG_SIZE(dg);
- ASSERT(vmciDgSize <= VMCI_MAX_DG_SIZE);
-
- /* Get the target VM's VMCI context. */
- context = VMCIContext_Get(cid);
- if (context == NULL) {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid context (ID=0x%x).\n", cid));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- /* Allocate guest call entry and add it to the target VM's queue. */
- dqEntry = VMCI_AllocKernelMem(sizeof *dqEntry, VMCI_MEMORY_NONPAGED);
- if (dqEntry == NULL) {
- VMCI_WARNING((LGPFX"Failed to allocate memory for datagram.\n"));
- VMCIContext_Release(context);
- return VMCI_ERROR_NO_MEM;
- }
- dqEntry->dg = dg;
- dqEntry->dgSize = vmciDgSize;
- dgSrc = dg->src;
- VMCIList_InitEntry(&dqEntry->listItem);
-
- VMCI_GrabLock(&context->lock, &flags);
-
-#if defined(VMKERNEL)
- if (context->inFilters != NULL) {
- if (VMCIFilterDenyDgIn(context->inFilters->filters, dg)) {
- VMCI_ReleaseLock(&context->lock, flags);
- VMCIContext_Release(context);
- VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry);
- return VMCI_ERROR_NO_ACCESS;
- }
- }
-#endif
-
- /*
- * We put a higher limit on datagrams from the hypervisor. If the pending
- * datagram is not from hypervisor, then we check if enqueueing it would
- * exceed the VMCI_MAX_DATAGRAM_QUEUE_SIZE limit on the destination. If the
- * pending datagram is from hypervisor, we allow it to be queued at the
- * destination side provided we don't reach the
- * VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE limit.
- */
- if (context->datagramQueueSize + vmciDgSize >=
- VMCI_MAX_DATAGRAM_QUEUE_SIZE &&
- (!VMCI_HANDLE_EQUAL(dgSrc,
- VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_CONTEXT_RESOURCE_ID)) ||
- context->datagramQueueSize + vmciDgSize >=
- VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE)) {
- VMCI_ReleaseLock(&context->lock, flags);
- VMCIContext_Release(context);
- VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry);
- VMCI_DEBUG_LOG(10, (LGPFX"Context (ID=0x%x) receive queue is full.\n",
- cid));
- return VMCI_ERROR_NO_RESOURCES;
- }
-
- VMCIList_Insert(&dqEntry->listItem, &context->datagramQueue);
- context->pendingDatagrams++;
- context->datagramQueueSize += vmciDgSize;
- VMCIContextSignalNotify(context);
- VMCIHost_SignalCall(&context->hostContext);
- VMCI_ReleaseLock(&context->lock, flags);
- VMCIContext_Release(context);
-
- return vmciDgSize;
-}
-
-#undef VMCI_MAX_DATAGRAM_AND_EVENT_QUEUE_SIZE
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContextExists --
- *
- * Internal helper to check if a context with the specified context
- * ID exists. Assumes the contextList.lock is held.
- *
- * Results:
- * TRUE if a context exists with the given cid.
- * FALSE otherwise
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static Bool
-VMCIContextExists(VMCIId cid) // IN
-{
- VMCIContext *context;
- VMCIListItem *next;
- Bool rv = FALSE;
-
- VMCIList_Scan(next, &contextList.head) {
- context = VMCIList_Entry(next, VMCIContext, listItem);
- if (context->cid == cid) {
- rv = TRUE;
- break;
- }
- }
- return rv;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_Exists --
- *
- * Verifies whether a context with the specified context ID exists.
- *
- * Results:
- * TRUE if a context exists with the given cid.
- * FALSE otherwise
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-VMCIContext_Exists(VMCIId cid) // IN
-{
- VMCILockFlags flags;
- Bool rv;
-
- VMCI_GrabLock(&contextList.lock, &flags);
- rv = VMCIContextExists(cid);
- VMCI_ReleaseLock(&contextList.lock, flags);
- return rv;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_Get --
- *
- * Retrieves VMCI context corresponding to the given cid.
- *
- * Results:
- * VMCI context on success, NULL otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCIContext *
-VMCIContext_Get(VMCIId cid) // IN
-{
- VMCIContext *context = NULL;
- VMCIListItem *next;
- VMCILockFlags flags;
-
- if (cid == VMCI_INVALID_ID) {
- return NULL;
- }
-
- VMCI_GrabLock(&contextList.lock, &flags);
- if (VMCIList_Empty(&contextList.head)) {
- goto out;
- }
-
- VMCIList_Scan(next, &contextList.head) {
- context = VMCIList_Entry(next, VMCIContext, listItem);
- if (context->cid == cid) {
- /*
- * At this point, we are sure that the reference count is
- * larger already than zero. When starting the destruction of
- * a context, we always remove it from the context list
- * before decreasing the reference count. As we found the
- * context here, it hasn't been destroyed yet. This means
- * that we are not about to increase the reference count of
- * something that is in the process of being destroyed.
- */
-
- Atomic_Inc(&context->refCount);
- break;
- }
- }
-
-out:
- VMCI_ReleaseLock(&contextList.lock, flags);
- return (context && context->cid == cid) ? context : NULL;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_Release --
- *
- * Releases the VMCI context. If this is the last reference to
- * the context it will be deallocated. A context is created with
- * a reference count of one, and on destroy, it is removed from
- * the context list before its reference count is
- * decremented. Thus, if we reach zero, we are sure that nobody
- * else are about to increment it (they need the entry in the
- * context list for that). This function musn't be called with a
- * lock held.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Paged memory may be deallocated.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_Release(VMCIContext *context) // IN
-{
- uint32 refCount;
- ASSERT(context);
- refCount = Atomic_FetchAndDec(&context->refCount);
- if (refCount == 1) {
- VMCIContextFreeContext(context);
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_DequeueDatagram --
- *
- * Dequeues the next datagram and returns it to caller.
- * The caller passes in a pointer to the max size datagram
- * it can handle and the datagram is only unqueued if the
- * size is less than maxSize. If larger maxSize is set to
- * the size of the datagram to give the caller a chance to
- * set up a larger buffer for the guestcall.
- *
- * Results:
- * On success: 0 if no more pending datagrams, otherwise the size of
- * the next pending datagram.
- * On failure: appropriate error code.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_DequeueDatagram(VMCIContext *context, // IN
- size_t *maxSize, // IN/OUT: max size of datagram caller can handle.
- VMCIDatagram **dg) // OUT:
-{
- DatagramQueueEntry *dqEntry;
- VMCIListItem *listItem;
- VMCILockFlags flags;
- int rv;
-
- ASSERT(context && dg);
-
- /* Dequeue the next datagram entry. */
- VMCI_GrabLock(&context->lock, &flags);
- if (context->pendingDatagrams == 0) {
- VMCIContextClearNotifyAndCall(context);
- VMCI_ReleaseLock(&context->lock, flags);
- VMCI_DEBUG_LOG(4, (LGPFX"No datagrams pending.\n"));
- return VMCI_ERROR_NO_MORE_DATAGRAMS;
- }
-
- listItem = VMCIList_First(&context->datagramQueue);
- ASSERT (listItem != NULL);
-
- dqEntry = VMCIList_Entry(listItem, DatagramQueueEntry, listItem);
- ASSERT(dqEntry->dg);
-
- /* Check size of caller's buffer. */
- if (*maxSize < dqEntry->dgSize) {
- *maxSize = dqEntry->dgSize;
- VMCI_ReleaseLock(&context->lock, flags);
- VMCI_DEBUG_LOG(4, (LGPFX"Caller's buffer should be at least "
- "(size=%u bytes).\n", (uint32)*maxSize));
- return VMCI_ERROR_NO_MEM;
- }
-
- VMCIList_Remove(listItem);
- context->pendingDatagrams--;
- context->datagramQueueSize -= dqEntry->dgSize;
- if (context->pendingDatagrams == 0) {
- VMCIContextClearNotifyAndCall(context);
- rv = VMCI_SUCCESS;
- } else {
- /*
- * Return the size of the next datagram.
- */
- DatagramQueueEntry *nextEntry;
-
- listItem = VMCIList_First(&context->datagramQueue);
- ASSERT(listItem);
- nextEntry = VMCIList_Entry(listItem, DatagramQueueEntry, listItem);
- ASSERT(nextEntry && nextEntry->dg);
- /*
- * The following size_t -> int truncation is fine as the maximum size of
- * a (routable) datagram is 68KB.
- */
- rv = (int)nextEntry->dgSize;
- }
- VMCI_ReleaseLock(&context->lock, flags);
-
- /* Caller must free datagram. */
- ASSERT(dqEntry->dgSize == VMCI_DG_SIZE(dqEntry->dg));
- *dg = dqEntry->dg;
- dqEntry->dg = NULL;
- VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry);
-
- return rv;
-}
-
-
-#ifdef VMKERNEL
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_SetFSRState --
- *
- * Set the states related to FSR (quiesced state, migrateCid,
- * active event handle).
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_SetFSRState(VMCIContext *context, // IN
- Bool isQuiesced, // IN
- VMCIId migrateCid, // IN
- uintptr_t eventHnd, // IN
- Bool isLocked) // IN
-{
- VMCILockFlags flags;
- if (!context) {
- return;
- }
- if (!isLocked) {
- VMCI_GrabLock(&context->lock, &flags);
- }
- context->isQuiesced = isQuiesced;
- context->migrateCid = migrateCid;
- VMCIHost_SetActiveHnd(&context->hostContext, eventHnd);
- if (!isLocked) {
- VMCI_ReleaseLock(&context->lock, flags);
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_FindAndUpdateSrcFSR --
- *
- * Find the source context for fast-suspend-resume. If found, the
- * source context's FSR state is changed to reflect the new active
- * event handle.
- *
- * Results:
- * If found, source context for fast-suspend-resume, NULL otherwise.
- *
- * Side effects:
- * The source context reference count increased and the caller is
- * supposed to release the context once it is done using it.
- *
- *----------------------------------------------------------------------
- */
-
-VMCIContext *
-VMCIContext_FindAndUpdateSrcFSR(VMCIId migrateCid, // IN
- uintptr_t eventHnd, // IN
- uintptr_t *srcEventHnd) // IN/OUT
-{
- VMCIContext *contextSrc = VMCIContext_Get(migrateCid);
-
- if (contextSrc) {
- VMCILockFlags flags;
-
- VMCI_GrabLock(&contextSrc->lock, &flags);
- if (contextSrc->isQuiesced && contextSrc->migrateCid == migrateCid) {
- if (srcEventHnd) {
- *srcEventHnd = VMCIHost_GetActiveHnd(&contextSrc->hostContext);
- ASSERT(*srcEventHnd != VMCI_INVALID_ID);
- }
- VMCIContext_SetFSRState(contextSrc, FALSE, VMCI_INVALID_ID,
- eventHnd, TRUE);
- VMCI_ReleaseLock(&contextSrc->lock, flags);
- return contextSrc;
- }
- VMCI_ReleaseLock(&contextSrc->lock, flags);
- VMCIContext_Release(contextSrc);
- }
- return NULL;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_IsActiveHnd --
- *
- * Whether the curent event handle is the active handle.
- *
- * Results:
- * TRUE if the event handle is active, FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-VMCIContext_IsActiveHnd(VMCIContext *context, // IN
- uintptr_t eventHnd) // IN
-{
- VMCILockFlags flags;
- Bool isActive;
-
- ASSERT(context);
- VMCI_GrabLock(&context->lock, &flags);
- isActive = VMCIHost_IsActiveHnd(&context->hostContext, eventHnd);
- VMCI_ReleaseLock(&context->lock, flags);
- return isActive;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_GetActiveHnd --
- *
- * Returns the curent event handle.
- *
- * Results:
- * The current active handle.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-uintptr_t
-VMCIContext_GetActiveHnd(VMCIContext *context) // IN
-{
- VMCILockFlags flags;
- uintptr_t activeHnd;
-
- ASSERT(context);
- VMCI_GrabLock(&context->lock, &flags);
- activeHnd = VMCIHost_GetActiveHnd(&context->hostContext);
- VMCI_ReleaseLock(&context->lock, flags);
- return activeHnd;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_SetInactiveHnd --
- *
- * Set the handle to be the inactive one.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_SetInactiveHnd(VMCIContext *context, // IN
- uintptr_t eventHnd) // IN
-{
- VMCILockFlags flags;
-
- ASSERT(context);
- VMCI_GrabLock(&context->lock, &flags);
- VMCIHost_SetInactiveHnd(&context->hostContext, eventHnd);
- VMCI_ReleaseLock(&context->lock, flags);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_RemoveHnd --
- *
- * Remove the event handle from host context.
- *
- * Results:
- * Whether the handle exists and removed, also number of handles
- * before removal and number of handles after removal.
- *
- * Side effects:
- * If this is active handle, the inactive handle becomes active.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-VMCIContext_RemoveHnd(VMCIContext *context, // IN
- uintptr_t eventHnd, // IN
- uint32 *numOld, // OUT
- uint32 *numNew) // OUT
-{
- VMCILockFlags flags;
- uint32 numHandleOld, numHandleNew;
- Bool ret;
-
- ASSERT(context);
- VMCI_GrabLock(&context->lock, &flags);
- numHandleOld = VMCIHost_NumHnds(&context->hostContext);
- ret = VMCIHost_RemoveHnd(&context->hostContext, eventHnd);
- numHandleNew = VMCIHost_NumHnds(&context->hostContext);
- /*
- * This is needed to prevent FSR to share this
- * context while this context is being destroyed.
- */
- if (ret && numHandleOld == 1 && numHandleNew == 1) {
- context->migrateCid = VMCI_INVALID_ID;
- }
- VMCI_ReleaseLock(&context->lock, flags);
-
- if (numOld) {
- *numOld = numHandleOld;
- }
- if (numNew) {
- *numNew = numHandleNew;
- }
- return ret;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIContext_ClearDatagrams --
- *
- * Clear pending datagrams.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIContext_ClearDatagrams(VMCIContext *context) // IN
-{
- int retval;
- VMCIDatagram *dg = NULL;
- size_t size = VMCI_MAX_DG_SIZE;
- uint32 pending;
-
- /* Drop all datagrams that are currently pending for given context. */
- if (context == NULL) {
- return;
- }
- retval = VMCIContext_PendingDatagrams(context->cid, &pending);
- if (retval != VMCI_SUCCESS) {
- /*
- * This shouldn't happen as we already verified that the context
- * exists.
- */
-
- ASSERT(FALSE);
- return;
- }
-
- /*
- * We drain the queue for any datagrams pending at the beginning of
- * the loop. As datagrams may arrive at any point in time, we
- * cannot guarantee that the queue is empty after this point. Only
- * removing a fixed number of pending datagrams prevents us from
- * looping forever.
- */
-
- while (pending > 0 &&
- VMCIContext_DequeueDatagram(context, &size, &dg) >= 0) {
- ASSERT(dg);
- VMCI_FreeKernelMem(dg, VMCI_DG_SIZE(dg));
- --pending;
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_SetId --
- *
- * Set the cid of given VMCI context.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_SetId(VMCIContext *context, // IN
- VMCIId cid) // IN:
-{
- VMCILockFlags flags;
-
- if (!context) {
- return;
- }
- VMCI_GrabLock(&context->lock, &flags);
- context->cid = cid;
- VMCI_ReleaseLock(&context->lock, flags);
-}
-#endif
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_GetId --
- *
- * Retrieves cid of given VMCI context.
- *
- * Results:
- * VMCIId of context on success, VMCI_INVALID_ID otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCIId
-VMCIContext_GetId(VMCIContext *context) // IN:
-{
- if (!context) {
- return VMCI_INVALID_ID;
- }
- ASSERT(context->cid != VMCI_INVALID_ID);
- return context->cid;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * vmci_context_get_priv_flags --
- *
- * Retrieves the privilege flags of the given VMCI context ID.
- *
- * Results:
- * Context's privilege flags.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_context_get_priv_flags)
-VMCIPrivilegeFlags
-vmci_context_get_priv_flags(VMCIId contextID) // IN
-{
- if (VMCI_HostPersonalityActive()) {
- VMCIPrivilegeFlags flags;
- VMCIContext *context;
-
- context = VMCIContext_Get(contextID);
- if (!context) {
- return VMCI_LEAST_PRIVILEGE_FLAGS;
- }
- flags = context->privFlags;
- VMCIContext_Release(context);
- return flags;
- }
- return VMCI_NO_PRIVILEGE_FLAGS;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_AddNotification --
- *
- * Add remoteCID to list of contexts current contexts wants
- * notifications from/about.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * As in VMCIHandleArray_AppendEntry().
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_AddNotification(VMCIId contextID, // IN:
- VMCIId remoteCID) // IN:
-{
- int result = VMCI_ERROR_ALREADY_EXISTS;
- VMCILockFlags flags;
- VMCILockFlags firingFlags;
- VMCIHandle notifierHandle;
- VMCIContext *context = VMCIContext_Get(contextID);
- if (context == NULL) {
- return VMCI_ERROR_NOT_FOUND;
- }
-
- if (VMCI_CONTEXT_IS_VM(contextID) && VMCI_CONTEXT_IS_VM(remoteCID)) {
- VMCI_DEBUG_LOG(4, (LGPFX"Context removed notifications for other VMs not "
- "supported (src=0x%x, remote=0x%x).\n",
- contextID, remoteCID));
- result = VMCI_ERROR_DST_UNREACHABLE;
- goto out;
- }
-
- if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
- result = VMCI_ERROR_NO_ACCESS;
- goto out;
- }
-
- notifierHandle = VMCI_MAKE_HANDLE(remoteCID, VMCI_EVENT_HANDLER);
- VMCI_GrabLock(&contextList.firingLock, &firingFlags);
- VMCI_GrabLock(&context->lock, &flags);
- if (!VMCIHandleArray_HasEntry(context->notifierArray, notifierHandle)) {
- VMCIHandleArray_AppendEntry(&context->notifierArray, notifierHandle);
- result = VMCI_SUCCESS;
- }
- VMCI_ReleaseLock(&context->lock, flags);
- VMCI_ReleaseLock(&contextList.firingLock, firingFlags);
-out:
- VMCIContext_Release(context);
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_RemoveNotification --
- *
- * Remove remoteCID from current context's list of contexts it is
- * interested in getting notifications from/about.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_RemoveNotification(VMCIId contextID, // IN:
- VMCIId remoteCID) // IN:
-{
- VMCILockFlags flags;
- VMCILockFlags firingFlags;
- VMCIContext *context = VMCIContext_Get(contextID);
- VMCIHandle tmpHandle;
- if (context == NULL) {
- return VMCI_ERROR_NOT_FOUND;
- }
- VMCI_GrabLock(&contextList.firingLock, &firingFlags);
- VMCI_GrabLock(&context->lock, &flags);
- tmpHandle =
- VMCIHandleArray_RemoveEntry(context->notifierArray,
- VMCI_MAKE_HANDLE(remoteCID,
- VMCI_EVENT_HANDLER));
- VMCI_ReleaseLock(&context->lock, flags);
- VMCI_ReleaseLock(&contextList.firingLock, firingFlags);
- VMCIContext_Release(context);
-
- if (VMCI_HANDLE_EQUAL(tmpHandle, VMCI_INVALID_HANDLE)) {
- return VMCI_ERROR_NOT_FOUND;
- }
- return VMCI_SUCCESS;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContextFireNotification --
- *
- * Fire notification for all contexts interested in given cid.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-VMCIContextFireNotification(VMCIId contextID, // IN
- VMCIPrivilegeFlags privFlags) // IN
-{
- uint32 i, arraySize;
- VMCIListItem *next;
- VMCILockFlags flags;
- VMCILockFlags firingFlags;
- VMCIHandleArray *subscriberArray;
- VMCIHandle contextHandle = VMCI_MAKE_HANDLE(contextID, VMCI_EVENT_HANDLER);
-
- /*
- * We create an array to hold the subscribers we find when scanning through
- * all contexts.
- */
- subscriberArray = VMCIHandleArray_Create(0);
- if (subscriberArray == NULL) {
- return VMCI_ERROR_NO_MEM;
- }
-
- /*
- * Scan all contexts to find who is interested in being notified about
- * given contextID. We have a special firingLock that we use to synchronize
- * across all notification operations. This avoids us having to take the
- * context lock for each HasEntry call and it solves a lock ranking issue.
- */
- VMCI_GrabLock(&contextList.firingLock, &firingFlags);
- VMCI_GrabLock(&contextList.lock, &flags);
- VMCIList_Scan(next, &contextList.head) {
- VMCIContext *subCtx = VMCIList_Entry(next, VMCIContext, listItem);
-
- /*
- * We only deliver notifications of the removal of contexts, if
- * the two contexts are allowed to interact.
- */
-
- if (VMCIHandleArray_HasEntry(subCtx->notifierArray, contextHandle) &&
- !VMCIDenyInteraction(privFlags, subCtx->privFlags)) {
- VMCIHandleArray_AppendEntry(&subscriberArray,
- VMCI_MAKE_HANDLE(subCtx->cid,
- VMCI_EVENT_HANDLER));
- }
- }
- VMCI_ReleaseLock(&contextList.lock, flags);
- VMCI_ReleaseLock(&contextList.firingLock, firingFlags);
-
- /* Fire event to all subscribers. */
- arraySize = VMCIHandleArray_GetSize(subscriberArray);
- for (i = 0; i < arraySize; i++) {
- int result;
- VMCIEventMsg *eMsg;
- VMCIEventPayload_Context *evPayload;
- char buf[sizeof *eMsg + sizeof *evPayload];
-
- eMsg = (VMCIEventMsg *)buf;
-
- /* Clear out any garbage. */
- memset(eMsg, 0, sizeof *eMsg + sizeof *evPayload);
- eMsg->hdr.dst = VMCIHandleArray_GetEntry(subscriberArray, i);
- eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_CONTEXT_RESOURCE_ID);
- eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *evPayload -
- sizeof eMsg->hdr;
- eMsg->eventData.event = VMCI_EVENT_CTX_REMOVED;
- evPayload = VMCIEventMsgPayload(eMsg);
- evPayload->contextID = contextID;
-
- result = VMCIDatagram_Dispatch(VMCI_HYPERVISOR_CONTEXT_ID,
- (VMCIDatagram *)eMsg, FALSE);
- if (result < VMCI_SUCCESS) {
- VMCI_DEBUG_LOG(4, (LGPFX"Failed to enqueue event datagram "
- "(type=%d) for context (ID=0x%x).\n",
- eMsg->eventData.event, eMsg->hdr.dst.context));
- /* We continue to enqueue on next subscriber. */
- }
- }
- VMCIHandleArray_Destroy(subscriberArray);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_GetCheckpointState --
- *
- * Get current context's checkpoint state of given type.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_GetCheckpointState(VMCIId contextID, // IN:
- uint32 cptType, // IN:
- uint32 *bufSize, // IN/OUT:
- char **cptBufPtr) // OUT:
-{
- int i, result;
- VMCILockFlags flags;
- uint32 arraySize, cptDataSize;
- VMCIHandleArray *array;
- VMCIContext *context;
- char *cptBuf;
- Bool getContextID;
-
- ASSERT(bufSize && cptBufPtr);
-
- context = VMCIContext_Get(contextID);
- if (context == NULL) {
- return VMCI_ERROR_NOT_FOUND;
- }
-
- VMCI_GrabLock(&context->lock, &flags);
- if (cptType == VMCI_NOTIFICATION_CPT_STATE) {
- ASSERT(context->notifierArray);
- array = context->notifierArray;
- getContextID = TRUE;
- } else if (cptType == VMCI_WELLKNOWN_CPT_STATE) {
- /*
- * For compatibility with VMX'en with VM to VM communication, we
- * always return zero wellknown handles.
- */
-
- *bufSize = 0;
- *cptBufPtr = NULL;
- result = VMCI_SUCCESS;
- goto release;
- } else if (cptType == VMCI_DOORBELL_CPT_STATE) {
- ASSERT(context->doorbellArray);
- array = context->doorbellArray;
- getContextID = FALSE;
- } else {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid cpt state (type=%d).\n", cptType));
- result = VMCI_ERROR_INVALID_ARGS;
- goto release;
- }
-
- arraySize = VMCIHandleArray_GetSize(array);
- if (arraySize > 0) {
- if (cptType == VMCI_DOORBELL_CPT_STATE) {
- cptDataSize = arraySize * sizeof(VMCIDoorbellCptState);
- } else {
- cptDataSize = arraySize * sizeof(VMCIId);
- }
- if (*bufSize < cptDataSize) {
- *bufSize = cptDataSize;
- result = VMCI_ERROR_MORE_DATA;
- goto release;
- }
-
- cptBuf = VMCI_AllocKernelMem(cptDataSize,
- VMCI_MEMORY_NONPAGED | VMCI_MEMORY_ATOMIC);
- if (cptBuf == NULL) {
- result = VMCI_ERROR_NO_MEM;
- goto release;
- }
-
- for (i = 0; i < arraySize; i++) {
- VMCIHandle tmpHandle = VMCIHandleArray_GetEntry(array, i);
- if (cptType == VMCI_DOORBELL_CPT_STATE) {
- ((VMCIDoorbellCptState *)cptBuf)[i].handle = tmpHandle;
- } else {
- ((VMCIId *)cptBuf)[i] =
- getContextID ? tmpHandle.context : tmpHandle.resource;
- }
- }
- *bufSize = cptDataSize;
- *cptBufPtr = cptBuf;
- } else {
- *bufSize = 0;
- *cptBufPtr = NULL;
- }
- result = VMCI_SUCCESS;
-
- release:
- VMCI_ReleaseLock(&context->lock, flags);
- VMCIContext_Release(context);
-
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_SetCheckpointState --
- *
- * Set current context's checkpoint state of given type.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_SetCheckpointState(VMCIId contextID, // IN:
- uint32 cptType, // IN:
- uint32 bufSize, // IN:
- char *cptBuf) // IN:
-{
- uint32 i;
- VMCIId currentID;
- int result = VMCI_SUCCESS;
- uint32 numIDs = bufSize / sizeof(VMCIId);
- ASSERT(cptBuf);
-
- if (cptType == VMCI_WELLKNOWN_CPT_STATE && numIDs > 0) {
- /*
- * We would end up here if VMX with VM to VM communication
- * attempts to restore a checkpoint with wellknown handles.
- */
-
- VMCI_WARNING((LGPFX"Attempt to restore checkpoint with obsolete "
- "wellknown handles.\n"));
- return VMCI_ERROR_OBSOLETE;
- }
-
- if (cptType != VMCI_NOTIFICATION_CPT_STATE) {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid cpt state (type=%d).\n", cptType));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- for (i = 0; i < numIDs && result == VMCI_SUCCESS; i++) {
- currentID = ((VMCIId *)cptBuf)[i];
- result = VMCIContext_AddNotification(contextID, currentID);
- if (result != VMCI_SUCCESS) {
- break;
- }
- }
- if (result != VMCI_SUCCESS) {
- VMCI_DEBUG_LOG(4, (LGPFX"Failed to set cpt state (type=%d) (error=%d).\n",
- cptType, result));
- }
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_ReceiveNotificationsGet --
- *
- * Retrieves the specified context's pending notifications in the
- * form of a handle array. The handle arrays returned are the
- * actual data - not a copy and should not be modified by the
- * caller. They must be released using
- * VMCIContext_ReceiveNotificationsRelease.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_ReceiveNotificationsGet(VMCIId contextID, // IN
- VMCIHandleArray **dbHandleArray, // OUT
- VMCIHandleArray **qpHandleArray) // OUT
-{
- VMCIContext *context;
- VMCILockFlags flags;
- int result = VMCI_SUCCESS;
-
- ASSERT(dbHandleArray && qpHandleArray);
-
- context = VMCIContext_Get(contextID);
- if (context == NULL) {
- return VMCI_ERROR_NOT_FOUND;
- }
- VMCI_GrabLock(&context->lock, &flags);
-
- *dbHandleArray = context->pendingDoorbellArray;
- context->pendingDoorbellArray = VMCIHandleArray_Create(0);
- if (!context->pendingDoorbellArray) {
- context->pendingDoorbellArray = *dbHandleArray;
- *dbHandleArray = NULL;
- result = VMCI_ERROR_NO_MEM;
- }
- *qpHandleArray = NULL;
-
- VMCI_ReleaseLock(&context->lock, flags);
- VMCIContext_Release(context);
-
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_ReceiveNotificationsRelease --
- *
- * Releases handle arrays with pending notifications previously
- * retrieved using VMCIContext_ReceiveNotificationsGet. If the
- * notifications were not successfully handed over to the guest,
- * success must be false.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_ReceiveNotificationsRelease(VMCIId contextID, // IN
- VMCIHandleArray *dbHandleArray, // IN
- VMCIHandleArray *qpHandleArray, // IN
- Bool success) // IN
-{
- VMCIContext *context = VMCIContext_Get(contextID);
-
- if (context) {
- VMCILockFlags flags;
-
- VMCI_GrabLock(&context->lock, &flags);
- if (!success) {
- VMCIHandle handle;
-
- /*
- * New notifications may have been added while we were not
- * holding the context lock, so we transfer any new pending
- * doorbell notifications to the old array, and reinstate the
- * old array.
- */
-
- handle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray);
- while (!VMCI_HANDLE_INVALID(handle)) {
- ASSERT(VMCIHandleArray_HasEntry(context->doorbellArray, handle));
- if (!VMCIHandleArray_HasEntry(dbHandleArray, handle)) {
- VMCIHandleArray_AppendEntry(&dbHandleArray, handle);
- }
- handle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray);
- }
- VMCIHandleArray_Destroy(context->pendingDoorbellArray);
- context->pendingDoorbellArray = dbHandleArray;
- dbHandleArray = NULL;
- } else {
- VMCIContextClearNotifyAndCall(context);
- }
- VMCI_ReleaseLock(&context->lock, flags);
- VMCIContext_Release(context);
- } else {
- /*
- * The OS driver part is holding on to the context for the
- * duration of the receive notification ioctl, so it should
- * still be here.
- */
-
- ASSERT(FALSE);
- }
-
- if (dbHandleArray) {
- VMCIHandleArray_Destroy(dbHandleArray);
- }
- if (qpHandleArray) {
- VMCIHandleArray_Destroy(qpHandleArray);
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_DoorbellCreate --
- *
- * Registers that a new doorbell handle has been allocated by the
- * context. Only doorbell handles registered can be notified.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherewise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_DoorbellCreate(VMCIId contextID, // IN
- VMCIHandle handle) // IN
-{
- VMCIContext *context;
- VMCILockFlags flags;
- int result;
-
- if (contextID == VMCI_INVALID_ID || VMCI_HANDLE_INVALID(handle)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- context = VMCIContext_Get(contextID);
- if (context == NULL) {
- return VMCI_ERROR_NOT_FOUND;
- }
-
- VMCI_GrabLock(&context->lock, &flags);
- if (!VMCIHandleArray_HasEntry(context->doorbellArray, handle)) {
- VMCIHandleArray_AppendEntry(&context->doorbellArray, handle);
- result = VMCI_SUCCESS;
- } else {
- result = VMCI_ERROR_DUPLICATE_ENTRY;
- }
- VMCI_ReleaseLock(&context->lock, flags);
-
- VMCIContext_Release(context);
-
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_DoorbellDestroy --
- *
- * Unregisters a doorbell handle that was previously registered
- * with VMCIContext_DoorbellCreate.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherewise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_DoorbellDestroy(VMCIId contextID, // IN
- VMCIHandle handle) // IN
-{
- VMCIContext *context;
- VMCILockFlags flags;
- VMCIHandle removedHandle;
-
- if (contextID == VMCI_INVALID_ID || VMCI_HANDLE_INVALID(handle)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- context = VMCIContext_Get(contextID);
- if (context == NULL) {
- return VMCI_ERROR_NOT_FOUND;
- }
-
- VMCI_GrabLock(&context->lock, &flags);
- removedHandle = VMCIHandleArray_RemoveEntry(context->doorbellArray, handle);
- VMCIHandleArray_RemoveEntry(context->pendingDoorbellArray, handle);
- VMCI_ReleaseLock(&context->lock, flags);
-
- VMCIContext_Release(context);
-
- if (VMCI_HANDLE_INVALID(removedHandle)) {
- return VMCI_ERROR_NOT_FOUND;
- } else {
- return VMCI_SUCCESS;
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_DoorbellDestroyAll --
- *
- * Unregisters all doorbell handles that were previously
- * registered with VMCIContext_DoorbellCreate.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherewise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_DoorbellDestroyAll(VMCIId contextID) // IN
-{
- VMCIContext *context;
- VMCILockFlags flags;
- VMCIHandle removedHandle;
-
- if (contextID == VMCI_INVALID_ID) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- context = VMCIContext_Get(contextID);
- if (context == NULL) {
- return VMCI_ERROR_NOT_FOUND;
- }
-
- VMCI_GrabLock(&context->lock, &flags);
- do {
- removedHandle = VMCIHandleArray_RemoveTail(context->doorbellArray);
- } while(!VMCI_HANDLE_INVALID(removedHandle));
- do {
- removedHandle = VMCIHandleArray_RemoveTail(context->pendingDoorbellArray);
- } while(!VMCI_HANDLE_INVALID(removedHandle));
- VMCI_ReleaseLock(&context->lock, flags);
-
- VMCIContext_Release(context);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_NotifyDoorbell --
- *
- * Registers a notification of a doorbell handle initiated by the
- * specified source context. The notification of doorbells are
- * subject to the same isolation rules as datagram delivery. To
- * allow host side senders of notifications a finer granularity
- * of sender rights than those assigned to the sending context
- * itself, the host context is required to specify a different
- * set of privilege flags that will override the privileges of
- * the source context.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherewise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_NotifyDoorbell(VMCIId srcCID, // IN
- VMCIHandle handle, // IN
- VMCIPrivilegeFlags srcPrivFlags) // IN
-{
- VMCIContext *dstContext;
- VMCILockFlags flags;
- int result;
-
- if (VMCI_HANDLE_INVALID(handle)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- /* Get the target VM's VMCI context. */
- dstContext = VMCIContext_Get(handle.context);
- if (dstContext == NULL) {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid context (ID=0x%x).\n", handle.context));
- return VMCI_ERROR_NOT_FOUND;
- }
-
- if (srcCID != handle.context) {
- VMCIPrivilegeFlags dstPrivFlags;
-
- if (!vmkernel && VMCI_CONTEXT_IS_VM(srcCID) &&
- VMCI_CONTEXT_IS_VM(handle.context)) {
- VMCI_DEBUG_LOG(4, (LGPFX"Doorbell notification from VM to VM not "
- "supported (src=0x%x, dst=0x%x).\n",
- srcCID, handle.context));
- result = VMCI_ERROR_DST_UNREACHABLE;
- goto out;
- }
-
- result = VMCIDoorbellGetPrivFlags(handle, &dstPrivFlags);
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to get privilege flags for destination "
- "(handle=0x%x:0x%x).\n", handle.context,
- handle.resource));
- goto out;
- }
-
- if (srcCID != VMCI_HOST_CONTEXT_ID ||
- srcPrivFlags == VMCI_NO_PRIVILEGE_FLAGS) {
- srcPrivFlags = vmci_context_get_priv_flags(srcCID);
- }
-
- if (VMCIDenyInteraction(srcPrivFlags, dstPrivFlags)) {
- result = VMCI_ERROR_NO_ACCESS;
- goto out;
- }
- }
-
- if (handle.context == VMCI_HOST_CONTEXT_ID) {
- result = VMCIDoorbellHostContextNotify(srcCID, handle);
- } else {
- VMCI_GrabLock(&dstContext->lock, &flags);
-
-#if defined(VMKERNEL)
- if (dstContext->inFilters != NULL &&
- VMCIFilterProtoDeny(dstContext->inFilters->filters, handle.resource,
- VMCI_FP_DOORBELL)) {
- result = VMCI_ERROR_NO_ACCESS;
- } else
-#endif // VMKERNEL
- if (!VMCIHandleArray_HasEntry(dstContext->doorbellArray, handle)) {
- result = VMCI_ERROR_NOT_FOUND;
- } else {
- if (!VMCIHandleArray_HasEntry(dstContext->pendingDoorbellArray, handle)) {
- VMCIHandleArray_AppendEntry(&dstContext->pendingDoorbellArray, handle);
-
- VMCIContextSignalNotify(dstContext);
-#if defined(VMKERNEL)
- VMCIHost_SignalBitmap(&dstContext->hostContext);
-#else
- VMCIHost_SignalCall(&dstContext->hostContext);
-#endif
- }
- result = VMCI_SUCCESS;
- }
- VMCI_ReleaseLock(&dstContext->lock, flags);
- }
-
-out:
- VMCIContext_Release(dstContext);
-
- return result;
-}
-
-
-#ifdef VMKERNEL
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_SignalPendingDoorbells --
- *
- * Signals the guest if any doorbell notifications are
- * pending. This is used after the VMCI device is unquiesced to
- * ensure that no pending notifications go unnoticed, since
- * signals may not be fully processed while the device is
- * quiesced.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_SignalPendingDoorbells(VMCIId contextID)
-{
- VMCIContext *context;
- VMCILockFlags flags;
- Bool pending;
-
- context = VMCIContext_Get(contextID);
- if (!context) {
- ASSERT(FALSE);
- return;
- }
-
- VMCI_GrabLock(&context->lock, &flags);
- pending = VMCIHandleArray_GetSize(context->pendingDoorbellArray) > 0;
- VMCI_ReleaseLock(&context->lock, flags);
-
- if (pending) {
- VMCIHost_SignalBitmap(&context->hostContext);
- }
-
- VMCIContext_Release(context);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_SignalPendingDatagrams --
- *
- * Signals the guest if any datagrams are pending. This is used
- * after the VMCI device is unquiesced to ensure that no pending
- * datagrams go unnoticed, since signals may not be fully
- * processed while the device is quiesced.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_SignalPendingDatagrams(VMCIId contextID)
-{
- Bool pending;
- VMCIContext *context;
- VMCILockFlags flags;
-
- context = VMCIContext_Get(contextID);
- if (!context) {
- ASSERT(FALSE);
- return;
- }
-
- VMCI_GrabLock(&context->lock, &flags);
- pending = context->pendingDatagrams;
- VMCI_ReleaseLock(&context->lock, flags);
-
- if (pending) {
- VMCIHost_SignalCall(&context->hostContext);
- }
-
- VMCIContext_Release(context);
-}
-
-#endif // defined(VMKERNEL)
-
-
-/*
- *----------------------------------------------------------------------
- *
- * vmci_cid_2_host_vm_id --
- *
- * Maps a context ID to the host specific (process/world) ID
- * of the VM/VMX.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_cid_2_host_vm_id)
-int
-vmci_cid_2_host_vm_id(VMCIId contextID, // IN
- void *hostVmID, // OUT
- size_t hostVmIDLen) // IN
-{
-#if defined(VMKERNEL)
- VMCIContext *context;
- VMCIHostVmID vmID;
- int result;
-
- context = VMCIContext_Get(contextID);
- if (!context) {
- return VMCI_ERROR_NOT_FOUND;
- }
-
- result = VMCIHost_ContextToHostVmID(&context->hostContext, &vmID);
- if (result == VMCI_SUCCESS) {
- if (sizeof vmID == hostVmIDLen) {
- memcpy(hostVmID, &vmID, hostVmIDLen);
- } else {
- result = VMCI_ERROR_INVALID_ARGS;
- }
- }
-
- VMCIContext_Release(context);
-
- return result;
-#else // !defined(VMKERNEL)
- return VMCI_ERROR_UNAVAILABLE;
-#endif
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * vmci_is_context_owner --
- *
- * Determines whether a given host OS specific representation of
- * user is the owner of the VM/VMX.
- *
- * Results:
- * Linux: 1 (true) if hostUser is owner, 0 (false) otherwise.
- * Other: VMCI_SUCCESS if the hostUser is owner, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_is_context_owner)
-#if defined(linux) && !defined(VMKERNEL)
-int
-vmci_is_context_owner(VMCIId contextID, // IN
- uid_t uid) // IN
-{
- int isOwner = 0;
-
- if (VMCI_HostPersonalityActive()) {
- VMCIContext *context = VMCIContext_Get(contextID);
- if (context) {
- if (context->validUser) {
- if (VMCIHost_CompareUser((VMCIHostUser *)&uid,
- &context->user) == VMCI_SUCCESS) {
- isOwner = 1;
- }
- }
- VMCIContext_Release(context);
- }
- }
-
- return isOwner;
-}
-#else // !linux || VMKERNEL
-int
-vmci_is_context_owner(VMCIId contextID, // IN
- void *hostUser) // IN
-{
- if (VMCI_HostPersonalityActive()) {
- VMCIContext *context;
- VMCIHostUser *user = (VMCIHostUser *)hostUser;
- int retval;
-
- if (vmkernel) {
- return VMCI_ERROR_UNAVAILABLE;
- }
-
- if (!hostUser) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- context = VMCIContext_Get(contextID);
- if (!context) {
- return VMCI_ERROR_NOT_FOUND;
- }
-
- if (context->validUser) {
- retval = VMCIHost_CompareUser(user, &context->user);
- } else {
- retval = VMCI_ERROR_UNAVAILABLE;
- }
- VMCIContext_Release(context);
-
- return retval;
- }
- return VMCI_ERROR_UNAVAILABLE;
-}
-#endif // !linux || VMKERNEL
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_SupportsHostQP --
- *
- * Can host QPs be connected to this user process. The answer is
- * FALSE unless a sufficient version number has previously been set
- * by this caller.
- *
- * Results:
- * TRUE if context supports host queue pairs, FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-VMCIContext_SupportsHostQP(VMCIContext *context) // IN: Context structure
-{
-#ifdef VMKERNEL
- return TRUE;
-#else
- if (!context || context->userVersion < VMCI_VERSION_HOSTQP) {
- return FALSE;
- }
- return TRUE;
-#endif
-}
-
-
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_QueuePairCreate --
- *
- * Registers that a new queue pair handle has been allocated by
- * the context.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherewise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_QueuePairCreate(VMCIContext *context, // IN: Context structure
- VMCIHandle handle) // IN
-{
- int result;
-
- if (context == NULL || VMCI_HANDLE_INVALID(handle)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (!VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
- VMCIHandleArray_AppendEntry(&context->queuePairArray, handle);
- result = VMCI_SUCCESS;
- } else {
- result = VMCI_ERROR_DUPLICATE_ENTRY;
- }
-
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_QueuePairDestroy --
- *
- * Unregisters a queue pair handle that was previously registered
- * with VMCIContext_QueuePairCreate.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherewise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_QueuePairDestroy(VMCIContext *context, // IN: Context structure
- VMCIHandle handle) // IN
-{
- VMCIHandle removedHandle;
-
- if (context == NULL || VMCI_HANDLE_INVALID(handle)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- removedHandle = VMCIHandleArray_RemoveEntry(context->queuePairArray, handle);
-
- if (VMCI_HANDLE_INVALID(removedHandle)) {
- return VMCI_ERROR_NOT_FOUND;
- } else {
- return VMCI_SUCCESS;
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_QueuePairExists --
- *
- * Determines whether a given queue pair handle is registered
- * with the given context.
- *
- * Results:
- * TRUE, if queue pair is registered with context. FALSE, otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-VMCIContext_QueuePairExists(VMCIContext *context, // IN: Context structure
- VMCIHandle handle) // IN
-{
- Bool result;
-
- if (context == NULL || VMCI_HANDLE_INVALID(handle)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- result = VMCIHandleArray_HasEntry(context->queuePairArray, handle);
-
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_RegisterGuestMem --
- *
- * Tells the context that guest memory is available for
- * access. This should only be used when unquiescing the VMCI
- * device of a guest.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Notifies host side endpoints of queue pairs that the queue pairs
- * can be accessed.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_RegisterGuestMem(VMCIContext *context, // IN: Context structure
- VMCIGuestMemID gid) // IN: Reference to guest
-{
-#ifdef VMKERNEL
- uint32 numQueuePairs;
- uint32 cur;
-
- VMCIMutex_Acquire(&context->guestMemMutex);
-
- if (context->curGuestMemID != INVALID_VMCI_GUEST_MEM_ID) {
- if (context->curGuestMemID != gid) {
- /*
- * The guest memory has been registered with a different guest
- * memory ID. This is possible if we attempt to continue the
- * execution of the source VMX following a failed FSR.
- */
-
- VMCIContextReleaseGuestMemLocked(context, context->curGuestMemID);
- } else {
- /*
- * When unquiescing the device during a restore sync not part
- * of an FSR, we will already have registered the guest
- * memory when creating the device, so we don't need to do it
- * again. Also, there are no active queue pairs at this
- * point, so nothing to do.
- */
-
- ASSERT(VMCIHandleArray_GetSize(context->queuePairArray) == 0);
- goto out;
- }
- }
- context->curGuestMemID = gid;
-
- /*
- * It is safe to access the queue pair array here, since no changes
- * to the queuePairArray can take place until after the unquiescing
- * is complete.
- */
-
- numQueuePairs = VMCIHandleArray_GetSize(context->queuePairArray);
- for (cur = 0; cur < numQueuePairs; cur++) {
- VMCIHandle handle;
- handle = VMCIHandleArray_GetEntry(context->queuePairArray, cur);
- if (!VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE)) {
- int res;
-
- res = VMCIQPBroker_Map(handle, context, NULL);
- if (res < VMCI_SUCCESS) {
- VMCI_WARNING(("Failed to map guest memory for queue pair "
- "(handle=0x%x:0x%x, res=%d).\n",
- handle.context, handle.resource, res));
- }
- }
- }
-
-out:
- VMCIMutex_Release(&context->guestMemMutex);
-#endif
-}
-
-
-#ifdef VMKERNEL
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContextReleaseGuestMemLocked --
- *
- * A version of VMCIContext_ReleaseGuestMem that assumes that the
- * guest mem lock is already held.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-VMCIContextReleaseGuestMemLocked(VMCIContext *context, // IN: Context structure
- VMCIGuestMemID gid) // IN: Reference to guest
-{
- uint32 numQueuePairs;
- uint32 cur;
-
- /*
- * It is safe to access the queue pair array here, since no changes
- * to the queuePairArray can take place when the the quiescing
- * has been initiated.
- */
-
- numQueuePairs = VMCIHandleArray_GetSize(context->queuePairArray);
- for (cur = 0; cur < numQueuePairs; cur++) {
- VMCIHandle handle;
- handle = VMCIHandleArray_GetEntry(context->queuePairArray, cur);
- if (!VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE)) {
- int res;
-
- res = VMCIQPBroker_Unmap(handle, context, gid);
- if (res < VMCI_SUCCESS) {
- VMCI_WARNING(("Failed to unmap guest memory for queue pair "
- "(handle=0x%x:0x%x, res=%d).\n",
- handle.context, handle.resource, res));
- }
- }
- }
-}
-#endif
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_ReleaseGuestMem --
- *
- * Releases all the contexts references to guest memory, if the
- * caller identified by the gid was the last one to register the
- * guest memory. This should only be used when quiescing or
- * cleaning up the VMCI device of a guest.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIContext_ReleaseGuestMem(VMCIContext *context, // IN: Context structure
- VMCIGuestMemID gid) // IN: Reference to guest
-{
-#ifdef VMKERNEL
- VMCIMutex_Acquire(&context->guestMemMutex);
-
- if (context->curGuestMemID == gid) {
- /*
- * In the case of an FSR, we may have multiple VMX'en
- * registering and releasing guest memory concurrently. The
- * common case is that the source will clean up its device state
- * after a successful FSR, where the destination may already
- * have registered guest memory. So we only release guest
- * memory, if this is the same gid, that registered the memory.
- */
-
- VMCIContextReleaseGuestMemLocked(context, gid);
- context->curGuestMemID = INVALID_VMCI_GUEST_MEM_ID;
- }
-
- VMCIMutex_Release(&context->guestMemMutex);
-#endif
-}
-
-#if defined(VMKERNEL)
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContext_FilterSet --
- *
- * Sets an ingoing (host to guest) filter for the VMCI firewall of the
- * given context. If a filter list already exists for the given filter
- * entry, the old entry will be deleted. It is assumed that the list
- * can be used as is, and that the memory backing it will be freed by the
- * VMCI Context module once the filter is deleted.
- *
- * Results:
- * VMCI_SUCCESS on success,
- * VMCI_ERROR_NOT_FOUND if there is no active context linked to the cid,
- * VMCI_ERROR_INVALID_ARGS if a non-VM cid is specified.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIContext_FilterSet(VMCIId cid, // IN
- VMCIFilterState *filters) // IN
-{
- VMCIContext *context;
- VMCILockFlags flags;
- VMCIFilterState *oldState;
-
- if (!VMCI_CONTEXT_IS_VM(cid)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- context = VMCIContext_Get(cid);
- if (!context) {
- return VMCI_ERROR_NOT_FOUND;
- }
-
- VMCI_GrabLock(&context->lock, &flags);
-
- oldState = context->inFilters;
- context->inFilters = filters;
-
- VMCI_ReleaseLock(&context->lock, flags);
- if (oldState) {
- VMCIVMKDevFreeFilterState(oldState);
- }
- VMCIContext_Release(context);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIContextInFilterCleanup --
- *
- * When a context is destroyed, all filters will be deleted.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-VMCIContextInFilterCleanup(VMCIContext *context)
-{
- if (context->inFilters != NULL) {
- VMCIVMKDevFreeFilterState(context->inFilters);
- context->inFilters = NULL;
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCI_Uuid2ContextId --
- *
- * Given a running VM's UUID, retrieve the VM's VMCI context ID.
- * The given UUID is local to the host; it is _not_ the UUID
- * handed out by VC. It comes from the "bios.uuid" field in the
- * VMX file. We walk the context list and try to match the given
- * UUID against each context. If we get a match, we return the
- * contexts's VMCI ID.
- *
- * Results:
- * VMCI_SUCCESS if found and *contextID contains the CID.
- * VMCI_ERROR_INVALID_ARGS for bad parameters.
- * VMCI_ERROR_NOT_FOUND if no match.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCI_Uuid2ContextId(const char *uuidString, // IN
- VMCIId *contextID) // OUT
-{
- int err;
- VMCIListItem *next;
- VMCILockFlags flags;
-
- if (!uuidString || *uuidString == '\0' || !contextID) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- err = VMCI_ERROR_NOT_FOUND;
-
- VMCI_GrabLock(&contextList.lock, &flags);
- VMCIList_Scan(next, &contextList.head) {
- VMCIContext *context = VMCIList_Entry(next, VMCIContext, listItem);
- if (VMCIHost_ContextHasUuid(&context->hostContext, uuidString) ==
- VMCI_SUCCESS) {
- *contextID = context->cid;
- err = VMCI_SUCCESS;
- break;
- }
- }
- VMCI_ReleaseLock(&contextList.lock, flags);
-
- return err;
-}
-#endif // VMKERNEL
diff --git a/modules/linux/vmci/common/vmciContext.h b/modules/linux/vmci/common/vmciContext.h
deleted file mode 100644
index 93e37a8..0000000
--- a/modules/linux/vmci/common/vmciContext.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*********************************************************
- * Copyright (C) 2006-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
- *
- *********************************************************/
-
-/*
- * vmciContext.h --
- *
- * VMCI state to enable sending calls between VMs.
- */
-
-#ifndef _VMCI_CONTEXT_H_
-#define _VMCI_CONTEXT_H_
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMMON
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_defs.h"
-#include "vmci_call_defs.h"
-#include "vmci_handle_array.h"
-#include "vmci_infrastructure.h"
-#include "vmci_kernel_if.h"
-#include "vmciCommonInt.h"
-
-#define MAX_QUEUED_GUESTCALLS_PER_VM 100
-
-typedef struct VMCIContext VMCIContext;
-
-int VMCIContext_Init(void);
-void VMCIContext_Exit(void);
-int VMCIContext_InitContext(VMCIId cid, VMCIPrivilegeFlags flags,
- uintptr_t eventHnd, int version,
- VMCIHostUser *user, VMCIContext **context);
-#ifdef VMKERNEL
-void VMCIContext_SetFSRState(VMCIContext *context,
- Bool isQuiesced,
- VMCIId migrateCid,
- uintptr_t eventHnd,
- Bool isLocked);
-VMCIContext *VMCIContext_FindAndUpdateSrcFSR(VMCIId migrateCid,
- uintptr_t eventHnd,
- uintptr_t *srcEventHnd);
-Bool VMCIContext_IsActiveHnd(VMCIContext *context, uintptr_t eventHnd);
-uintptr_t VMCIContext_GetActiveHnd(VMCIContext *context);
-void VMCIContext_SetInactiveHnd(VMCIContext *context, uintptr_t eventHnd);
-Bool VMCIContext_RemoveHnd(VMCIContext *context,
- uintptr_t eventHnd,
- uint32 *numOld,
- uint32 *numNew);
-void VMCIContext_ClearDatagrams(VMCIContext *context);
-void VMCIContext_SetId(VMCIContext *context, VMCIId cid);
-#endif
-Bool VMCIContext_SupportsHostQP(VMCIContext *context);
-void VMCIContext_ReleaseContext(VMCIContext *context);
-int VMCIContext_EnqueueDatagram(VMCIId cid, VMCIDatagram *dg);
-int VMCIContext_DequeueDatagram(VMCIContext *context, size_t *maxSize,
- VMCIDatagram **dg);
-int VMCIContext_PendingDatagrams(VMCIId cid, uint32 *pending);
-VMCIContext *VMCIContext_Get(VMCIId cid);
-void VMCIContext_Release(VMCIContext *context);
-Bool VMCIContext_Exists(VMCIId cid);
-
-VMCIId VMCIContext_GetId(VMCIContext *context);
-int VMCIContext_AddNotification(VMCIId contextID, VMCIId remoteCID);
-int VMCIContext_RemoveNotification(VMCIId contextID, VMCIId remoteCID);
-int VMCIContext_GetCheckpointState(VMCIId contextID, uint32 cptType,
- uint32 *numCIDs, char **cptBufPtr);
-int VMCIContext_SetCheckpointState(VMCIId contextID, uint32 cptType,
- uint32 numCIDs, char *cptBuf);
-void VMCIContext_RegisterGuestMem(VMCIContext *context, VMCIGuestMemID gid);
-void VMCIContext_ReleaseGuestMem(VMCIContext *context, VMCIGuestMemID gid);
-
-int VMCIContext_QueuePairCreate(VMCIContext *context, VMCIHandle handle);
-int VMCIContext_QueuePairDestroy(VMCIContext *context, VMCIHandle handle);
-Bool VMCIContext_QueuePairExists(VMCIContext *context, VMCIHandle handle);
-
-#ifndef VMX86_SERVER
-void VMCIContext_CheckAndSignalNotify(VMCIContext *context);
-# ifdef __linux__
-/* TODO Windows and Mac OS. */
-void VMCIUnsetNotify(VMCIContext *context);
-# endif
-#endif
-
-int VMCIContext_DoorbellCreate(VMCIId contextID, VMCIHandle handle);
-int VMCIContext_DoorbellDestroy(VMCIId contextID, VMCIHandle handle);
-int VMCIContext_DoorbellDestroyAll(VMCIId contextID);
-int VMCIContext_NotifyDoorbell(VMCIId cid, VMCIHandle handle,
- VMCIPrivilegeFlags srcPrivFlags);
-
-int VMCIContext_ReceiveNotificationsGet(VMCIId contextID,
- VMCIHandleArray **dbHandleArray,
- VMCIHandleArray **qpHandleArray);
-void VMCIContext_ReceiveNotificationsRelease(VMCIId contextID,
- VMCIHandleArray *dbHandleArray,
- VMCIHandleArray *qpHandleArray,
- Bool success);
-#if defined(VMKERNEL)
-void VMCIContext_SignalPendingDoorbells(VMCIId contextID);
-void VMCIContext_SignalPendingDatagrams(VMCIId contextID);
-int VMCIContext_FilterSet(VMCIId cid, VMCIFilterState *filterState);
-int VMCI_Uuid2ContextId(const char *uuidString, VMCIId *contextID);
-#endif // VMKERNEL
-#endif // _VMCI_CONTEXT_H_
diff --git a/modules/linux/vmci/common/vmciDatagram.c b/modules/linux/vmci/common/vmciDatagram.c
deleted file mode 100644
index 0dbac65..0000000
--- a/modules/linux/vmci/common/vmciDatagram.c
+++ /dev/null
@@ -1,966 +0,0 @@
-/*********************************************************
- * Copyright (C) 2006-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
- * 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
- *
- *********************************************************/
-
-/*
- * vmciDatagram.c --
- *
- * This file implements the VMCI Simple Datagram API on the host.
- */
-
-#include "vmci_kernel_if.h"
-#include "vm_assert.h"
-#include "vmci_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmciCommonInt.h"
-#include "vmciContext.h"
-#include "vmciDatagram.h"
-#include "vmciDriver.h"
-#include "vmciEvent.h"
-#include "vmciHashtable.h"
-#include "vmciKernelAPI.h"
-#include "vmciResource.h"
-#include "vmciRoute.h"
-#if defined(VMKERNEL)
-# include "vmciVmkInt.h"
-# include "vm_libc.h"
-# include "helper_ext.h"
-#endif
-
-#define LGPFX "VMCIDatagram: "
-
-
-/*
- * DatagramEntry describes the datagram entity. It is used for datagram
- * entities created only on the host.
- */
-typedef struct DatagramEntry {
- VMCIResource resource;
- uint32 flags;
- Bool runDelayed;
- VMCIDatagramRecvCB recvCB;
- void *clientData;
- VMCIEvent destroyEvent;
- VMCIPrivilegeFlags privFlags;
-} DatagramEntry;
-
-typedef struct VMCIDelayedDatagramInfo {
- Bool inDGHostQueue;
- DatagramEntry *entry;
- VMCIDatagram msg;
-} VMCIDelayedDatagramInfo;
-
-
-static Atomic_uint32 delayedDGHostQueueSize;
-
-static int VMCIDatagramGetPrivFlagsInt(VMCIId contextID, VMCIHandle handle,
- VMCIPrivilegeFlags *privFlags);
-static void DatagramFreeCB(void *resource);
-static int DatagramReleaseCB(void *clientData);
-
-
-/*------------------------------ Helper functions ----------------------------*/
-
-/*
- *------------------------------------------------------------------------------
- *
- * DatagramFreeCB --
- * Callback to free datagram structure when resource is no longer used,
- * ie. the reference count reached 0.
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static void
-DatagramFreeCB(void *clientData)
-{
- DatagramEntry *entry = (DatagramEntry *)clientData;
- ASSERT(entry);
- VMCI_SignalEvent(&entry->destroyEvent);
-
- /*
- * The entry is freed in VMCIDatagram_DestroyHnd, who is waiting for the
- * above signal.
- */
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * DatagramReleaseCB --
- *
- * Callback to release the resource reference. It is called by the
- * VMCI_WaitOnEvent function before it blocks.
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-DatagramReleaseCB(void *clientData)
-{
- DatagramEntry *entry = (DatagramEntry *)clientData;
- ASSERT(entry);
- VMCIResource_Release(&entry->resource);
- return 0;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * DatagramCreateHnd --
- *
- * Internal function to create a datagram entry given a handle.
- *
- * Results:
- * VMCI_SUCCESS if created, negative errno value otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-DatagramCreateHnd(VMCIId resourceID, // IN:
- uint32 flags, // IN:
- VMCIPrivilegeFlags privFlags, // IN:
- VMCIDatagramRecvCB recvCB, // IN:
- void *clientData, // IN:
- VMCIHandle *outHandle) // OUT:
-
-{
- int result;
- VMCIId contextID;
- VMCIHandle handle;
- DatagramEntry *entry;
-
- ASSERT(recvCB != NULL);
- ASSERT(outHandle != NULL);
- ASSERT(!(privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS));
-
- if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) {
- return VMCI_ERROR_INVALID_ARGS;
- } else {
- if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0) {
- contextID = VMCI_INVALID_ID;
- } else {
- contextID = vmci_get_context_id();
- if (contextID == VMCI_INVALID_ID) {
- return VMCI_ERROR_NO_RESOURCES;
- }
- }
-
- if (resourceID == VMCI_INVALID_ID) {
- resourceID = VMCIResource_GetID(contextID);
- if (resourceID == VMCI_INVALID_ID) {
- return VMCI_ERROR_NO_HANDLE;
- }
- }
-
- handle = VMCI_MAKE_HANDLE(contextID, resourceID);
- }
-
- entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED);
- if (entry == NULL) {
- VMCI_WARNING((LGPFX"Failed allocating memory for datagram entry.\n"));
- return VMCI_ERROR_NO_MEM;
- }
-
- if (!VMCI_CanScheduleDelayedWork()) {
- if (flags & VMCI_FLAG_DG_DELAYED_CB) {
- VMCI_FreeKernelMem(entry, sizeof *entry);
- return VMCI_ERROR_INVALID_ARGS;
- }
- entry->runDelayed = FALSE;
- } else {
- entry->runDelayed = (flags & VMCI_FLAG_DG_DELAYED_CB) ? TRUE : FALSE;
- }
-
- entry->flags = flags;
- entry->recvCB = recvCB;
- entry->clientData = clientData;
- VMCI_CreateEvent(&entry->destroyEvent);
- entry->privFlags = privFlags;
-
- /* Make datagram resource live. */
- result = VMCIResource_Add(&entry->resource, VMCI_RESOURCE_TYPE_DATAGRAM,
- handle, DatagramFreeCB, entry);
- if (result != VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to add new resource (handle=0x%x:0x%x).\n",
- handle.context, handle.resource));
- VMCI_DestroyEvent(&entry->destroyEvent);
- VMCI_FreeKernelMem(entry, sizeof *entry);
- return result;
- }
- *outHandle = handle;
-
- return VMCI_SUCCESS;
-}
-
-
-/*------------------------------ Init functions ----------------------------*/
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDatagram_Init --
- *
- * Initialize Datagram API, ie. register the API functions with their
- * corresponding vectors.
- *
- * Result:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIDatagram_Init(void)
-{
- Atomic_Write(&delayedDGHostQueueSize, 0);
- return VMCI_SUCCESS;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDatagram_Exit --
- *
- * Cleanup Datagram API.
- *
- * Result:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIDatagram_Exit(void)
-{
-}
-
-
-/*------------------------------ Public API functions ------------------------*/
-
-/*
- *------------------------------------------------------------------------------
- *
- * vmci_datagram_create_handle --
- *
- * Creates a host context datagram endpoint and returns a handle to it.
- *
- * Results:
- * VMCI_SUCCESS if created, negative errno value otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_datagram_create_handle)
-int
-vmci_datagram_create_handle(
- VMCIId resourceID, // IN: Optional, generated if VMCI_INVALID_ID
- uint32 flags, // IN:
- VMCIDatagramRecvCB recvCB, // IN:
- void *clientData, // IN:
- VMCIHandle *outHandle) // OUT: newly created handle
-{
- if (outHandle == NULL) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (recvCB == NULL) {
- VMCI_DEBUG_LOG(4,
- (LGPFX"Client callback needed when creating datagram.\n"));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- return DatagramCreateHnd(resourceID, flags, VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS,
- recvCB, clientData, outHandle);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * vmci_datagram_create_handle_priv --
- *
- * Creates a host context datagram endpoint and returns a handle to it.
- *
- * Results:
- * VMCI_SUCCESS if created, negative errno value otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_datagram_create_handle_priv)
-int
-vmci_datagram_create_handle_priv(
- VMCIId resourceID, // IN: Optional, generated if VMCI_INVALID_ID
- uint32 flags, // IN:
- VMCIPrivilegeFlags privFlags, // IN:
- VMCIDatagramRecvCB recvCB, // IN:
- void *clientData, // IN:
- VMCIHandle *outHandle) // OUT: newly created handle
-{
- if (outHandle == NULL) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (recvCB == NULL) {
- VMCI_DEBUG_LOG(4,
- (LGPFX"Client callback needed when creating datagram.\n"));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- return DatagramCreateHnd(resourceID, flags, privFlags, recvCB, clientData,
- outHandle);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * vmci_datagram_destroy_handle --
- *
- * Destroys a handle.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_datagram_destroy_handle)
-int
-vmci_datagram_destroy_handle(VMCIHandle handle) // IN
-{
- DatagramEntry *entry;
- VMCIResource *resource = VMCIResource_Get(handle,
- VMCI_RESOURCE_TYPE_DATAGRAM);
- if (resource == NULL) {
- VMCI_DEBUG_LOG(4, (LGPFX"Failed to destroy datagram (handle=0x%x:0x%x).\n",
- handle.context, handle.resource));
- return VMCI_ERROR_NOT_FOUND;
- }
- entry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
-
- VMCIResource_Remove(handle, VMCI_RESOURCE_TYPE_DATAGRAM);
-
- /*
- * We now wait on the destroyEvent and release the reference we got
- * above.
- */
- VMCI_WaitOnEvent(&entry->destroyEvent, DatagramReleaseCB, entry);
-
- /*
- * We know that we are now the only reference to the above entry so
- * can safely free it.
- */
- VMCI_DestroyEvent(&entry->destroyEvent);
- VMCI_FreeKernelMem(entry, sizeof *entry);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDatagramGetPrivFlagsInt --
- *
- * Internal utilility function with the same purpose as
- * VMCIDatagram_GetPrivFlags that also takes a contextID.
- *
- * Result:
- * VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-VMCIDatagramGetPrivFlagsInt(VMCIId contextID, // IN
- VMCIHandle handle, // IN
- VMCIPrivilegeFlags *privFlags) // OUT
-{
- ASSERT(privFlags);
- ASSERT(contextID != VMCI_INVALID_ID);
-
- if (contextID == VMCI_HOST_CONTEXT_ID) {
- DatagramEntry *srcEntry;
- VMCIResource *resource;
-
- resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DATAGRAM);
- if (resource == NULL) {
- return VMCI_ERROR_INVALID_ARGS;
- }
- srcEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
- *privFlags = srcEntry->privFlags;
- VMCIResource_Release(resource);
- } else if (contextID == VMCI_HYPERVISOR_CONTEXT_ID) {
- *privFlags = VMCI_MAX_PRIVILEGE_FLAGS;
- } else {
- *privFlags = vmci_context_get_priv_flags(contextID);
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDatagram_GetPrivFlags --
- *
- * Utilility function that retrieves the privilege flags
- * associated with a given datagram handle. For hypervisor and
- * guest endpoints, the privileges are determined by the context
- * ID, but for host endpoints privileges are associated with the
- * complete handle.
- *
- * Result:
- * VMCI_SUCCESS on success, VMCI_ERROR_INVALID_ARGS if handle is invalid.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIDatagram_GetPrivFlags(VMCIHandle handle, // IN
- VMCIPrivilegeFlags *privFlags) // OUT
-{
- if (privFlags == NULL || handle.context == VMCI_INVALID_ID) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- return VMCIDatagramGetPrivFlagsInt(handle.context, handle, privFlags);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDatagramDelayedDispatchCB --
- *
- * Calls the specified callback in a delayed context.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIDatagramDelayedDispatchCB(void *data) // IN
-{
- Bool inDGHostQueue;
- VMCIDelayedDatagramInfo *dgInfo = (VMCIDelayedDatagramInfo *)data;
-
- ASSERT(data);
-
- dgInfo->entry->recvCB(dgInfo->entry->clientData, &dgInfo->msg);
-
- VMCIResource_Release(&dgInfo->entry->resource);
-
- inDGHostQueue = dgInfo->inDGHostQueue;
- VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dgInfo->msg.payloadSize);
-
- if (inDGHostQueue) {
- Atomic_Dec(&delayedDGHostQueueSize);
- }
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDatagramDispatchAsHost --
- *
- * Dispatch datagram as a host, to the host or other vm context. This
- * function cannot dispatch to hypervisor context handlers. This should
- * have been handled before we get here by VMCIDatagramDispatch.
- *
- * Result:
- * Number of bytes sent on success, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-VMCIDatagramDispatchAsHost(VMCIId contextID, // IN:
- VMCIDatagram *dg) // IN:
-{
- int retval;
- size_t dgSize;
- VMCIPrivilegeFlags srcPrivFlags;
-
- ASSERT(dg);
- ASSERT(VMCI_HostPersonalityActive());
-
- dgSize = VMCI_DG_SIZE(dg);
-
- if (contextID == VMCI_HOST_CONTEXT_ID &&
- dg->dst.context == VMCI_HYPERVISOR_CONTEXT_ID) {
- VMCI_DEBUG_LOG(4, (LGPFX"Host cannot talk to hypervisor\n"));
- return VMCI_ERROR_DST_UNREACHABLE;
- }
-
- ASSERT(dg->dst.context != VMCI_HYPERVISOR_CONTEXT_ID);
-
- /* Chatty. */
- // VMCI_DEBUG_LOG(10, (LGPFX"Sending from (handle=0x%x:0x%x) to "
- // "(handle=0x%x:0x%x) (size=%u bytes).\n",
- // dg->src.context, dg->src.resource,
- // dg->dst.context, dg->dst.resource, (uint32)dgSize));
-
- /*
- * Check that source handle matches sending context.
- */
- if (dg->src.context != contextID) {
- VMCI_DEBUG_LOG(4, (LGPFX"Sender context (ID=0x%x) is not owner of src "
- "datagram entry (handle=0x%x:0x%x).\n",
- contextID, dg->src.context, dg->src.resource));
- return VMCI_ERROR_NO_ACCESS;
- }
-
- /*
- * Get hold of privileges of sending endpoint.
- */
-
- retval = VMCIDatagramGetPrivFlagsInt(contextID, dg->src, &srcPrivFlags);
- if (retval != VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Couldn't get privileges (handle=0x%x:0x%x).\n",
- dg->src.context, dg->src.resource));
- return retval;
- }
-
- /* Determine if we should route to host or guest destination. */
- if (dg->dst.context == VMCI_HOST_CONTEXT_ID) {
- /* Route to host datagram entry. */
- DatagramEntry *dstEntry;
- VMCIResource *resource;
-
- if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
- dg->dst.resource == VMCI_EVENT_HANDLER) {
- return VMCIEvent_Dispatch(dg);
- }
-
- resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM);
- if (resource == NULL) {
- VMCI_DEBUG_LOG(4, (LGPFX"Sending to invalid destination "
- "(handle=0x%x:0x%x).\n",
- dg->dst.context, dg->dst.resource));
- return VMCI_ERROR_INVALID_RESOURCE;
- }
- dstEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
- if (VMCIDenyInteraction(srcPrivFlags, dstEntry->privFlags)) {
- VMCIResource_Release(resource);
- return VMCI_ERROR_NO_ACCESS;
- }
- ASSERT(dstEntry->recvCB);
-
- /*
- * If a VMCI datagram destined for the host is also sent by the
- * host, we always run it delayed. This ensures that no locks
- * are held when the datagram callback runs.
- */
-
- if (dstEntry->runDelayed ||
- (dg->src.context == VMCI_HOST_CONTEXT_ID &&
- VMCI_CanScheduleDelayedWork())) {
- VMCIDelayedDatagramInfo *dgInfo;
-
- if (Atomic_FetchAndAdd(&delayedDGHostQueueSize, 1) ==
- VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE) {
- Atomic_Dec(&delayedDGHostQueueSize);
- VMCIResource_Release(resource);
- return VMCI_ERROR_NO_MEM;
- }
-
- dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)dg->payloadSize,
- (VMCI_MEMORY_ATOMIC |
- VMCI_MEMORY_NONPAGED));
- if (NULL == dgInfo) {
- Atomic_Dec(&delayedDGHostQueueSize);
- VMCIResource_Release(resource);
- return VMCI_ERROR_NO_MEM;
- }
-
- dgInfo->inDGHostQueue = TRUE;
- dgInfo->entry = dstEntry;
- memcpy(&dgInfo->msg, dg, dgSize);
-
- retval = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo);
- if (retval < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to schedule delayed work for datagram "
- "(result=%d).\n", retval));
- VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dg->payloadSize);
- VMCIResource_Release(resource);
- Atomic_Dec(&delayedDGHostQueueSize);
- return retval;
- }
- } else {
- retval = dstEntry->recvCB(dstEntry->clientData, dg);
- VMCIResource_Release(resource);
- if (retval < VMCI_SUCCESS) {
- return retval;
- }
- }
- } else {
- /*
- * Route to destination VM context.
- */
-
- VMCIDatagram *newDG;
-
- if (contextID != dg->dst.context) {
- if (VMCIDenyInteraction(srcPrivFlags,
- vmci_context_get_priv_flags(dg->dst.context))) {
- VMCI_DEBUG_LOG(4, (LGPFX"Interaction denied (%X/%X - %X/%X)\n",
- contextID, srcPrivFlags,
- dg->dst.context,
- vmci_context_get_priv_flags(dg->dst.context)));
- return VMCI_ERROR_NO_ACCESS;
- } else if (VMCI_CONTEXT_IS_VM(contextID)) {
- /*
- * If the sending context is a VM, it cannot reach another VM.
- */
-
- if (!vmkernel) {
- VMCI_DEBUG_LOG(4, (LGPFX"Datagram communication between VMs not "
- "supported (src=0x%x, dst=0x%x).\n",
- contextID, dg->dst.context));
- return VMCI_ERROR_DST_UNREACHABLE;
- }
- }
- }
-
- /* We make a copy to enqueue. */
- newDG = VMCI_AllocKernelMem(dgSize, VMCI_MEMORY_NORMAL);
- if (newDG == NULL) {
- VMCI_DEBUG_LOG(4, (LGPFX"No memory for datagram\n"));
- return VMCI_ERROR_NO_MEM;
- }
- memcpy(newDG, dg, dgSize);
- retval = VMCIContext_EnqueueDatagram(dg->dst.context, newDG);
- if (retval < VMCI_SUCCESS) {
- VMCI_FreeKernelMem(newDG, dgSize);
- VMCI_DEBUG_LOG(4, (LGPFX"Enqueue failed\n"));
- return retval;
- }
- }
-
- /* The datagram is freed when the context reads it. */
-
- /* Chatty. */
- // VMCI_DEBUG_LOG(10, (LGPFX"Sent datagram (size=%u bytes).\n",
- // (uint32)dgSize));
-
- /*
- * We currently truncate the size to signed 32 bits. This doesn't
- * matter for this handler as it only support 4Kb messages.
- */
-
- return (int)dgSize;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDatagramDispatchAsGuest --
- *
- * Dispatch datagram as a guest, down through the VMX and potentially to
- * the host.
- *
- * Result:
- * Number of bytes sent on success, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-VMCIDatagramDispatchAsGuest(VMCIDatagram *dg)
-{
-#if defined(VMKERNEL)
- VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
- return VMCI_ERROR_DST_UNREACHABLE;
-#else // VMKERNEL
- int retval;
- VMCIResource *resource;
-
- resource = VMCIResource_Get(dg->src, VMCI_RESOURCE_TYPE_DATAGRAM);
- if (NULL == resource) {
- return VMCI_ERROR_NO_HANDLE;
- }
-
- retval = VMCI_SendDatagram(dg);
- VMCIResource_Release(resource);
- return retval;
-#endif // VMKERNEL
-}
-
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDatagram_Dispatch --
- *
- * Dispatch datagram. This will determine the routing for the datagram
- * and dispatch it accordingly.
- *
- * Result:
- * Number of bytes sent on success, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIDatagram_Dispatch(VMCIId contextID,
- VMCIDatagram *dg,
- Bool fromGuest)
-{
- int retval;
- VMCIRoute route;
-
- ASSERT(dg);
- ASSERT_ON_COMPILE(sizeof(VMCIDatagram) == 24);
-
- if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) {
- VMCI_DEBUG_LOG(4, (LGPFX"Payload (size=%"FMT64"u bytes) too big to "
- "send.\n", dg->payloadSize));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- retval = VMCI_Route(&dg->src, &dg->dst, fromGuest, &route);
- if (retval < VMCI_SUCCESS) {
- VMCI_DEBUG_LOG(4, (LGPFX"Failed to route datagram (src=0x%x, dst=0x%x, "
- "err=%d)\n.", dg->src.context, dg->dst.context,
- retval));
- return retval;
- }
-
- if (VMCI_ROUTE_AS_HOST == route) {
- if (VMCI_INVALID_ID == contextID) {
- contextID = VMCI_HOST_CONTEXT_ID;
- }
- return VMCIDatagramDispatchAsHost(contextID, dg);
- }
-
- if (VMCI_ROUTE_AS_GUEST == route) {
- return VMCIDatagramDispatchAsGuest(dg);
- }
-
- VMCI_WARNING((LGPFX"Unknown route (%d) for datagram.\n", route));
- return VMCI_ERROR_DST_UNREACHABLE;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDatagram_InvokeGuestHandler --
- *
- * Invoke the handler for the given datagram. This is intended to be
- * called only when acting as a guest and receiving a datagram from the
- * virtual device.
- *
- * Result:
- * VMCI_SUCCESS on success, other error values on failure.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg) // IN
-{
-#if defined(VMKERNEL)
- VMCI_WARNING((LGPFX"Cannot dispatch within guest in VMKERNEL.\n"));
- return VMCI_ERROR_DST_UNREACHABLE;
-#else // VMKERNEL
- int retval;
- VMCIResource *resource;
- DatagramEntry *dstEntry;
-
- ASSERT(dg);
-
- resource = VMCIResource_Get(dg->dst, VMCI_RESOURCE_TYPE_DATAGRAM);
- if (NULL == resource) {
- VMCI_DEBUG_LOG(4, (LGPFX"destination (handle=0x%x:0x%x) doesn't exist.\n",
- dg->dst.context, dg->dst.resource));
- return VMCI_ERROR_NO_HANDLE;
- }
-
- dstEntry = RESOURCE_CONTAINER(resource, DatagramEntry, resource);
- if (dstEntry->runDelayed) {
- VMCIDelayedDatagramInfo *dgInfo;
-
- dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)dg->payloadSize,
- (VMCI_MEMORY_ATOMIC | VMCI_MEMORY_NONPAGED));
- if (NULL == dgInfo) {
- VMCIResource_Release(resource);
- retval = VMCI_ERROR_NO_MEM;
- goto exit;
- }
-
- dgInfo->inDGHostQueue = FALSE;
- dgInfo->entry = dstEntry;
- memcpy(&dgInfo->msg, dg, VMCI_DG_SIZE(dg));
-
- retval = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo);
- if (retval < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to schedule delayed work for datagram "
- "(result=%d).\n", retval));
- VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dg->payloadSize);
- VMCIResource_Release(resource);
- dgInfo = NULL;
- goto exit;
- }
- } else {
- dstEntry->recvCB(dstEntry->clientData, dg);
- VMCIResource_Release(resource);
- retval = VMCI_SUCCESS;
- }
-
-exit:
- return retval;
-#endif // VMKERNEL
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * vmci_datagram_send --
- *
- * Sends the payload to the destination datagram handle.
- *
- * Results:
- * Returns number of bytes sent if success, or error code if failure.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_datagram_send)
-int
-vmci_datagram_send(VMCIDatagram *msg) // IN
-{
- if (msg == NULL) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- return VMCIDatagram_Dispatch(VMCI_INVALID_ID, msg, FALSE);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDatagram_Sync --
- *
- * Use this as a synchronization point when setting globals, for example,
- * during device shutdown.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIDatagram_Sync(void)
-{
- VMCIResource_Sync();
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDatagram_CheckHostCapabilities --
- *
- * Verify that the host supports the resources we need.
- * None are required for datagrams since they are implicitly supported.
- *
- * Results:
- * TRUE.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-VMCIDatagram_CheckHostCapabilities(void)
-{
- return TRUE;
-}
diff --git a/modules/linux/vmci/common/vmciDatagram.h b/modules/linux/vmci/common/vmciDatagram.h
deleted file mode 100644
index ad7ff45..0000000
--- a/modules/linux/vmci/common/vmciDatagram.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*********************************************************
- * 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
- * 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
- *
- *********************************************************/
-
-/*
- * vmciDatagram.h --
- *
- * Internal functions in the VMCI Simple Datagram API.
- */
-
-#ifndef _VMCI_DATAGRAM_H_
-#define _VMCI_DATAGRAM_H_
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMMON
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmciContext.h"
-#include "vmci_call_defs.h"
-#ifndef VMX86_SERVER
-#include "vmci_iocontrols.h"
-#endif // !VMX86_SERVER
-
-#define VMCI_MAX_DELAYED_DG_HOST_QUEUE_SIZE 256
-
-/* Init functions. */
-int VMCIDatagram_Init(void);
-void VMCIDatagram_Exit(void);
-
-/* Datagram API for non-public use. */
-int VMCIDatagram_Dispatch(VMCIId contextID, VMCIDatagram *dg, Bool fromGuest);
-int VMCIDatagram_InvokeGuestHandler(VMCIDatagram *dg);
-int VMCIDatagram_GetPrivFlags(VMCIHandle handle, VMCIPrivilegeFlags *privFlags);
-
-/* Misc. */
-void VMCIDatagram_Sync(void);
-Bool VMCIDatagram_CheckHostCapabilities(void);
-
-#endif // _VMCI_DATAGRAM_H_
-
-
diff --git a/modules/linux/vmci/common/vmciDoorbell.c b/modules/linux/vmci/common/vmciDoorbell.c
deleted file mode 100644
index 74053e1..0000000
--- a/modules/linux/vmci/common/vmciDoorbell.c
+++ /dev/null
@@ -1,1241 +0,0 @@
-/*********************************************************
- * Copyright (C) 2010 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
- *
- *********************************************************/
-
-/*
- * vmciDoorbell.c --
- *
- * This file implements the VMCI doorbell API on the host.
- */
-
-#include "vmci_kernel_if.h"
-#include "vm_assert.h"
-#include "vmci_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmciCommonInt.h"
-#include "vmciDatagram.h"
-#include "vmciDoorbell.h"
-#include "vmciDriver.h"
-#include "vmciKernelAPI.h"
-#include "vmciResource.h"
-#include "vmciRoute.h"
-#if defined(VMKERNEL)
-# include "vmciVmkInt.h"
-# include "vm_libc.h"
-# include "helper_ext.h"
-#endif
-
-#define LGPFX "VMCIDoorbell: "
-
-#if !defined(SOLARIS) && !defined(__APPLE__)
-
-#define VMCI_DOORBELL_INDEX_TABLE_SIZE 64
-#define VMCI_DOORBELL_HASH(_idx) \
- VMCI_HashId((_idx), VMCI_DOORBELL_INDEX_TABLE_SIZE)
-
-
-/*
- * DoorbellEntry describes the a doorbell notification handle allocated by the
- * host.
- */
-
-typedef struct VMCIDoorbellEntry {
- VMCIResource resource;
- uint32 idx;
- VMCIListItem idxListItem;
- VMCIPrivilegeFlags privFlags;
- Bool isDoorbell;
- Bool runDelayed;
- VMCICallback notifyCB;
- void *clientData;
- VMCIEvent destroyEvent;
- Atomic_uint32 active; // Only used by guest personality
-} VMCIDoorbellEntry;
-
-typedef struct VMCIDoorbellIndexTable {
- VMCILock lock;
- VMCIList entries[VMCI_DOORBELL_INDEX_TABLE_SIZE];
-} VMCIDoorbellIndexTable;
-
-
-/* The VMCI index table keeps track of currently registered doorbells. */
-static VMCIDoorbellIndexTable vmciDoorbellIT;
-
-
-/*
- * The maxNotifyIdx is one larger than the currently known bitmap index in
- * use, and is used to determine how much of the bitmap needs to be scanned.
- */
-
-static uint32 maxNotifyIdx;
-
-/*
- * The notifyIdxCount is used for determining whether there are free entries
- * within the bitmap (if notifyIdxCount + 1 < maxNotifyIdx).
- */
-
-static uint32 notifyIdxCount;
-
-/*
- * The lastNotifyIdxReserved is used to track the last index handed out - in
- * the case where multiple handles share a notification index, we hand out
- * indexes round robin based on lastNotifyIdxReserved.
- */
-
-static uint32 lastNotifyIdxReserved;
-
-/* This is a one entry cache used to by the index allocation. */
-static uint32 lastNotifyIdxReleased = PAGE_SIZE;
-
-
-static void VMCIDoorbellFreeCB(void *clientData);
-static int VMCIDoorbellReleaseCB(void *clientData);
-static void VMCIDoorbellDelayedDispatchCB(void *data);
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbell_Init --
- *
- * General init code.
- *
- * Result:
- * VMCI_SUCCESS on success, lock allocation error otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIDoorbell_Init(void)
-{
- uint32 bucket;
-
- for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); ++bucket) {
- VMCIList_Init(&vmciDoorbellIT.entries[bucket]);
- }
-
- return VMCI_InitLock(&vmciDoorbellIT.lock, "VMCIDoorbellIndexTableLock",
- VMCI_LOCK_RANK_DOORBELL);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbell_Exit --
- *
- * General init code.
- *
- * Result:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIDoorbell_Exit(void)
-{
- VMCI_CleanupLock(&vmciDoorbellIT.lock);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellFreeCB --
- *
- * Callback to free doorbell entry structure when resource is no longer used,
- * ie. the reference count reached 0. The entry is freed in
- * VMCIDoorbell_Destroy(), which is waiting on the signal that gets fired
- * here.
- *
- * Result:
- * None.
- *
- * Side effects:
- * Signals VMCI event.
- *
- *------------------------------------------------------------------------------
- */
-
-static void
-VMCIDoorbellFreeCB(void *clientData) // IN
-{
- VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData;
- ASSERT(entry);
- VMCI_SignalEvent(&entry->destroyEvent);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellReleaseCB --
- *
- * Callback to release the resource reference. It is called by the
- * VMCI_WaitOnEvent function before it blocks.
- *
- * Result:
- * Always 0.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-VMCIDoorbellReleaseCB(void *clientData) // IN: doorbell entry
-{
- VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)clientData;
- ASSERT(entry);
- VMCIResource_Release(&entry->resource);
- return 0;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellGetPrivFlags --
- *
- * Utility function that retrieves the privilege flags associated
- * with a given doorbell handle. For guest endpoints, the
- * privileges are determined by the context ID, but for host
- * endpoints privileges are associated with the complete
- * handle. Hypervisor endpoints are not yet supported.
- *
- * Result:
- * VMCI_SUCCESS on success,
- * VMCI_ERROR_NOT_FOUND if handle isn't found,
- * VMCI_ERROR_INVALID_ARGS if handle is invalid.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIDoorbellGetPrivFlags(VMCIHandle handle, // IN
- VMCIPrivilegeFlags *privFlags) // OUT
-{
- if (privFlags == NULL || handle.context == VMCI_INVALID_ID) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (handle.context == VMCI_HOST_CONTEXT_ID) {
- VMCIDoorbellEntry *entry;
- VMCIResource *resource;
-
- resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL);
- if (resource == NULL) {
- return VMCI_ERROR_NOT_FOUND;
- }
- entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource);
- *privFlags = entry->privFlags;
- VMCIResource_Release(resource);
- } else if (handle.context == VMCI_HYPERVISOR_CONTEXT_ID) {
- /* Hypervisor endpoints for notifications are not supported (yet). */
- return VMCI_ERROR_INVALID_ARGS;
- } else {
- *privFlags = vmci_context_get_priv_flags(handle.context);
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDoorbellIndexTableFind --
- *
- * Find doorbell entry by bitmap index.
- *
- * Results:
- * Entry if found, NULL if not.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static VMCIDoorbellEntry *
-VMCIDoorbellIndexTableFind(uint32 idx) // IN
-{
- uint32 bucket = VMCI_DOORBELL_HASH(idx);
- VMCIListItem *iter;
-
- ASSERT(VMCI_GuestPersonalityActive());
-
- VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) {
- VMCIDoorbellEntry *cur =
- VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem);
-
- ASSERT(cur);
-
- if (idx == cur->idx) {
- return cur;
- }
- }
-
- return NULL;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellIndexTableAdd --
- *
- * Add the given entry to the index table. This will hold() the entry's
- * resource so that the entry is not deleted before it is removed from the
- * table.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static void
-VMCIDoorbellIndexTableAdd(VMCIDoorbellEntry *entry) // IN/OUT
-{
- uint32 bucket;
- uint32 newNotifyIdx;
- VMCILockFlags flags;
-
- ASSERT(entry);
- ASSERT(VMCI_GuestPersonalityActive());
-
- VMCIResource_Hold(&entry->resource);
-
- VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags);
-
- /*
- * Below we try to allocate an index in the notification bitmap with "not
- * too much" sharing between resources. If we use less that the full bitmap,
- * we either add to the end if there are no unused flags within the
- * currently used area, or we search for unused ones. If we use the full
- * bitmap, we allocate the index round robin.
- */
-
- if (maxNotifyIdx < PAGE_SIZE || notifyIdxCount < PAGE_SIZE) {
- if (lastNotifyIdxReleased < maxNotifyIdx &&
- !VMCIDoorbellIndexTableFind(lastNotifyIdxReleased)) {
- newNotifyIdx = lastNotifyIdxReleased;
- lastNotifyIdxReleased = PAGE_SIZE;
- } else {
- Bool reused = FALSE;
- newNotifyIdx = lastNotifyIdxReserved;
- if (notifyIdxCount + 1 < maxNotifyIdx) {
- do {
- if (!VMCIDoorbellIndexTableFind(newNotifyIdx)) {
- reused = TRUE;
- break;
- }
- newNotifyIdx = (newNotifyIdx + 1) % maxNotifyIdx;
- } while(newNotifyIdx != lastNotifyIdxReleased);
- }
- if (!reused) {
- newNotifyIdx = maxNotifyIdx;
- maxNotifyIdx++;
- }
- }
- } else {
- newNotifyIdx = (lastNotifyIdxReserved + 1) % PAGE_SIZE;
- }
- lastNotifyIdxReserved = newNotifyIdx;
- notifyIdxCount++;
-
- entry->idx = newNotifyIdx;
- bucket = VMCI_DOORBELL_HASH(entry->idx);
- VMCIList_Insert(&entry->idxListItem, &vmciDoorbellIT.entries[bucket]);
-
- VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellIndexTableRemove --
- *
- * Remove the given entry from the index table. This will release() the
- * entry's resource.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static void
-VMCIDoorbellIndexTableRemove(VMCIDoorbellEntry *entry) // IN/OUT
-{
- VMCILockFlags flags;
-
- ASSERT(entry);
- ASSERT(VMCI_GuestPersonalityActive());
-
- VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags);
-
- VMCIList_Remove(&entry->idxListItem);
-
- notifyIdxCount--;
- if (entry->idx == maxNotifyIdx - 1) {
- /*
- * If we delete an entry with the maximum known notification index, we
- * take the opportunity to prune the current max. As there might be other
- * unused indices immediately below, we lower the maximum until we hit an
- * index in use.
- */
-
- while (maxNotifyIdx > 0 &&
- !VMCIDoorbellIndexTableFind(maxNotifyIdx - 1)) {
- maxNotifyIdx--;
- }
- }
- lastNotifyIdxReleased = entry->idx;
-
- VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags);
-
- VMCIResource_Release(&entry->resource);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellLink --
- *
- * Creates a link between the given doorbell handle and the given
- * index in the bitmap in the device backend.
- *
- * Results:
- * VMCI_SUCCESS if success, appropriate error code otherwise.
- *
- * Side effects:
- * Notification state is created in hypervisor.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-VMCIDoorbellLink(VMCIHandle handle, // IN
- Bool isDoorbell, // IN
- uint32 notifyIdx) // IN
-{
-#if defined(VMKERNEL)
- VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
- return VMCI_ERROR_DST_UNREACHABLE;
-#else // VMKERNEL
- VMCIId resourceID;
- VMCIDoorbellLinkMsg linkMsg;
-
- ASSERT(!VMCI_HANDLE_INVALID(handle));
- ASSERT(VMCI_GuestPersonalityActive());
-
- if (isDoorbell) {
- resourceID = VMCI_DOORBELL_LINK;
- } else {
- ASSERT(FALSE);
- return VMCI_ERROR_UNAVAILABLE;
- }
-
- linkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID);
- linkMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
- linkMsg.hdr.payloadSize = sizeof linkMsg - VMCI_DG_HEADERSIZE;
- linkMsg.handle = handle;
- linkMsg.notifyIdx = notifyIdx;
-
- return VMCI_SendDatagram((VMCIDatagram *)&linkMsg);
-#endif // VMKERNEL
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellUnlink --
- *
- * Unlinks the given doorbell handle from an index in the bitmap in
- * the device backend.
- *
- * Results:
- * VMCI_SUCCESS if success, appropriate error code otherwise.
- *
- * Side effects:
- * Notification state is destroyed in hypervisor.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-VMCIDoorbellUnlink(VMCIHandle handle, // IN
- Bool isDoorbell) // IN
-{
-#if defined(VMKERNEL)
- VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
- return VMCI_ERROR_DST_UNREACHABLE;
-#else // VMKERNEL
- VMCIId resourceID;
- VMCIDoorbellUnlinkMsg unlinkMsg;
-
- ASSERT(!VMCI_HANDLE_INVALID(handle));
- ASSERT(VMCI_GuestPersonalityActive());
-
- if (isDoorbell) {
- resourceID = VMCI_DOORBELL_UNLINK;
- } else {
- ASSERT(FALSE);
- return VMCI_ERROR_UNAVAILABLE;
- }
-
- unlinkMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID, resourceID);
- unlinkMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
- unlinkMsg.hdr.payloadSize = sizeof unlinkMsg - VMCI_DG_HEADERSIZE;
- unlinkMsg.handle = handle;
-
- return VMCI_SendDatagram((VMCIDatagram *)&unlinkMsg);
-#endif // VMKERNEL
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * vmci_doorbell_create --
- *
- * Creates a doorbell with the given callback. If the handle is
- * VMCI_INVALID_HANDLE, a free handle will be assigned, if
- * possible. The callback can be run immediately (potentially with
- * locks held - the default) or delayed (in a kernel thread) by
- * specifying the flag VMCI_FLAG_DELAYED_CB. If delayed execution
- * is selected, a given callback may not be run if the kernel is
- * unable to allocate memory for the delayed execution (highly
- * unlikely).
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_doorbell_create)
-int
-vmci_doorbell_create(VMCIHandle *handle, // IN/OUT
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags, // IN
- VMCICallback notifyCB, // IN
- void *clientData) // IN
-{
- VMCIDoorbellEntry *entry;
- VMCIHandle newHandle;
- int result;
-
- if (!handle || !notifyCB || flags & ~VMCI_FLAG_DELAYED_CB ||
- privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED);
- if (entry == NULL) {
- VMCI_WARNING((LGPFX"Failed allocating memory for datagram entry.\n"));
- return VMCI_ERROR_NO_MEM;
- }
-
- if (!VMCI_CanScheduleDelayedWork() && (flags & VMCI_FLAG_DELAYED_CB)) {
- result = VMCI_ERROR_INVALID_ARGS;
- goto freeMem;
- }
-
- if (VMCI_HANDLE_INVALID(*handle)) {
- VMCIId contextID = vmci_get_context_id();
- VMCIId resourceID = VMCIResource_GetID(contextID);
- if (resourceID == VMCI_INVALID_ID) {
- result = VMCI_ERROR_NO_HANDLE;
- goto freeMem;
- }
- newHandle = VMCI_MAKE_HANDLE(contextID, resourceID);
- } else {
- Bool validContext;
-
- /*
- * Validate the handle. We must do both of the checks below
- * because we can be acting as both a host and a guest at the
- * same time. We always allow the host context ID, since the
- * host functionality is in practice always there with the
- * unified driver.
- */
-
- validContext = FALSE;
- if (VMCI_HOST_CONTEXT_ID == handle->context) {
- validContext = TRUE;
- }
- if (VMCI_GuestPersonalityActive() &&
- vmci_get_context_id() == handle->context) {
- validContext = TRUE;
- }
-
- if (!validContext || VMCI_INVALID_ID == handle->resource) {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid argument (handle=0x%x:0x%x).\n",
- handle->context, handle->resource));
- result = VMCI_ERROR_INVALID_ARGS;
- goto freeMem;
- }
-
- newHandle = *handle;
- }
-
- entry->idx = 0;
- VMCIList_Init(&entry->idxListItem);
- entry->privFlags = privFlags;
- entry->isDoorbell = TRUE;
- entry->runDelayed = (flags & VMCI_FLAG_DELAYED_CB) ? TRUE : FALSE;
- entry->notifyCB = notifyCB;
- entry->clientData = clientData;
- Atomic_Write(&entry->active, 0);
- VMCI_CreateEvent(&entry->destroyEvent);
-
- result = VMCIResource_Add(&entry->resource, VMCI_RESOURCE_TYPE_DOORBELL,
- newHandle, VMCIDoorbellFreeCB, entry);
- if (result != VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to add new resource (handle=0x%x:0x%x).\n",
- newHandle.context, newHandle.resource));
- if (result == VMCI_ERROR_DUPLICATE_ENTRY) {
- result = VMCI_ERROR_ALREADY_EXISTS;
- }
- goto destroy;
- }
-
- if (VMCI_GuestPersonalityActive()) {
- VMCIDoorbellIndexTableAdd(entry);
- result = VMCIDoorbellLink(newHandle, entry->isDoorbell, entry->idx);
- if (VMCI_SUCCESS != result) {
- goto destroyResource;
- }
- Atomic_Write(&entry->active, 1);
- }
-
- if (VMCI_HANDLE_INVALID(*handle)) {
- *handle = newHandle;
- }
-
- return result;
-
-destroyResource:
- VMCIDoorbellIndexTableRemove(entry);
- VMCIResource_Remove(newHandle, VMCI_RESOURCE_TYPE_DOORBELL);
-destroy:
- VMCI_DestroyEvent(&entry->destroyEvent);
-freeMem:
- VMCI_FreeKernelMem(entry, sizeof *entry);
- return result;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * vmci_doorbell_destroy --
- *
- * Destroys a doorbell previously created with
- * vmci_doorbell_create. This operation may block waiting for a
- * callback to finish.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * May block.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_doorbell_destroy)
-int
-vmci_doorbell_destroy(VMCIHandle handle) // IN
-{
- VMCIDoorbellEntry *entry;
- VMCIResource *resource;
-
- if (VMCI_HANDLE_INVALID(handle)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL);
- if (resource == NULL) {
- VMCI_DEBUG_LOG(4, (LGPFX"Failed to destroy doorbell (handle=0x%x:0x%x).\n",
- handle.context, handle.resource));
- return VMCI_ERROR_NOT_FOUND;
- }
- entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource);
-
- if (VMCI_GuestPersonalityActive()) {
- int result;
-
- VMCIDoorbellIndexTableRemove(entry);
-
- result = VMCIDoorbellUnlink(handle, entry->isDoorbell);
- if (VMCI_SUCCESS != result) {
-
- /*
- * The only reason this should fail would be an inconsistency between
- * guest and hypervisor state, where the guest believes it has an
- * active registration whereas the hypervisor doesn't. One case where
- * this may happen is if a doorbell is unregistered following a
- * hibernation at a time where the doorbell state hasn't been restored
- * on the hypervisor side yet. Since the handle has now been removed
- * in the guest, we just print a warning and return success.
- */
-
- VMCI_DEBUG_LOG(4, (LGPFX"Unlink of %s (handle=0x%x:0x%x) unknown by "
- "hypervisor (error=%d).\n",
- entry->isDoorbell ? "doorbell" : "queuepair",
- handle.context, handle.resource, result));
- }
- }
-
- /*
- * Now remove the resource from the table. It might still be in use
- * after this, in a callback or still on the delayed work queue.
- */
-
- VMCIResource_Remove(handle, VMCI_RESOURCE_TYPE_DOORBELL);
-
- /*
- * We now wait on the destroyEvent and release the reference we got
- * above.
- */
-
- VMCI_WaitOnEvent(&entry->destroyEvent, VMCIDoorbellReleaseCB, entry);
-
- /*
- * We know that we are now the only reference to the above entry so
- * can safely free it.
- */
-
- VMCI_DestroyEvent(&entry->destroyEvent);
- VMCI_FreeKernelMem(entry, sizeof *entry);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellNotifyAsGuest --
- *
- * Notify another guest or the host. We send a datagram down to the
- * host via the hypervisor with the notification info.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * May do a hypercall.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-VMCIDoorbellNotifyAsGuest(VMCIHandle handle, // IN
- VMCIPrivilegeFlags privFlags) // IN
-{
-#if defined(VMKERNEL)
- VMCI_WARNING((LGPFX"Cannot send down to host from VMKERNEL.\n"));
- return VMCI_ERROR_DST_UNREACHABLE;
-#else // VMKERNEL
- VMCIDoorbellNotifyMsg notifyMsg;
-
- ASSERT(VMCI_GuestPersonalityActive());
-
- notifyMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_DOORBELL_NOTIFY);
- notifyMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
- notifyMsg.hdr.payloadSize = sizeof notifyMsg - VMCI_DG_HEADERSIZE;
- notifyMsg.handle = handle;
-
- return VMCI_SendDatagram((VMCIDatagram *)&notifyMsg);
-#endif // VMKERNEL
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * vmci_doorbell_notify --
- *
- * Generates a notification on the doorbell identified by the
- * handle. For host side generation of notifications, the caller
- * can specify what the privilege of the calling side is.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * May do a hypercall.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_doorbell_notify)
-int
-vmci_doorbell_notify(VMCIHandle dst, // IN
- VMCIPrivilegeFlags privFlags) // IN
-{
- int retval;
- VMCIRoute route;
- VMCIHandle src;
-
- if (VMCI_HANDLE_INVALID(dst) || (privFlags & ~VMCI_PRIVILEGE_ALL_FLAGS)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- src = VMCI_INVALID_HANDLE;
- retval = VMCI_Route(&src, &dst, FALSE, &route);
- if (retval < VMCI_SUCCESS) {
- return retval;
- }
-
- if (VMCI_ROUTE_AS_HOST == route) {
- return VMCIContext_NotifyDoorbell(VMCI_HOST_CONTEXT_ID, dst, privFlags);
- }
-
- if (VMCI_ROUTE_AS_GUEST == route) {
- return VMCIDoorbellNotifyAsGuest(dst, privFlags);
- }
-
- VMCI_WARNING((LGPFX"Unknown route (%d) for doorbell.\n", route));
- return VMCI_ERROR_DST_UNREACHABLE;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellDelayedDispatchCB --
- *
- * Calls the specified callback in a delayed context.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static void
-VMCIDoorbellDelayedDispatchCB(void *data) // IN
-{
- VMCIDoorbellEntry *entry = (VMCIDoorbellEntry *)data;
-
- ASSERT(data);
-
- entry->notifyCB(entry->clientData);
-
- VMCIResource_Release(&entry->resource);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbellHostContextNotify --
- *
- * Dispatches a doorbell notification to the host context.
- *
- * Results:
- * VMCI_SUCCESS on success. Appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIDoorbellHostContextNotify(VMCIId srcCID, // IN
- VMCIHandle handle) // IN
-{
- VMCIDoorbellEntry *entry;
- VMCIResource *resource;
- int result;
-
- ASSERT(VMCI_HostPersonalityActive());
-
- if (VMCI_HANDLE_INVALID(handle)) {
- VMCI_DEBUG_LOG(4,
- (LGPFX"Notifying an invalid doorbell (handle=0x%x:0x%x).\n",
- handle.context, handle.resource));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- resource = VMCIResource_Get(handle, VMCI_RESOURCE_TYPE_DOORBELL);
- if (resource == NULL) {
- VMCI_DEBUG_LOG(4,
- (LGPFX"Notifying an unknown doorbell (handle=0x%x:0x%x).\n",
- handle.context, handle.resource));
- return VMCI_ERROR_NOT_FOUND;
- }
- entry = RESOURCE_CONTAINER(resource, VMCIDoorbellEntry, resource);
-
- if (entry->runDelayed) {
- result = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, entry);
- if (result < VMCI_SUCCESS) {
- /*
- * If we failed to schedule the delayed work, we need to
- * release the resource immediately. Otherwise, the resource
- * will be released once the delayed callback has been
- * completed.
- */
-
- VMCI_DEBUG_LOG(10, (LGPFX"Failed to schedule delayed doorbell "
- "notification (result=%d).\n", result));
- VMCIResource_Release(resource);
- }
- } else {
- entry->notifyCB(entry->clientData);
- VMCIResource_Release(resource);
- result = VMCI_SUCCESS;
- }
- return result;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbell_Hibernate --
- *
- * When a guest leaves hibernation, the device driver state is out of sync
- * with the device state, since the driver state has doorbells registered
- * that aren't known to the device. This function takes care of
- * reregistering any doorbells. In case an error occurs during
- * reregistration (this is highly unlikely since 1) it succeeded the first
- * time 2) the device driver is the only source of doorbell registrations),
- * we simply log the error. The doorbell can still be destroyed using
- * VMCIDoorbell_Destroy.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIDoorbell_Hibernate(Bool enterHibernate)
-{
- uint32 bucket;
- VMCIListItem *iter;
- VMCILockFlags flags;
-
- if (!VMCI_GuestPersonalityActive() || enterHibernate) {
- return;
- }
-
- VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags);
-
- for (bucket = 0; bucket < ARRAYSIZE(vmciDoorbellIT.entries); bucket++) {
- VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) {
- int result;
- VMCIHandle h;
- VMCIDoorbellEntry *cur;
-
- cur = VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem);
- h = VMCIResource_Handle(&cur->resource);
- result = VMCIDoorbellLink(h, cur->isDoorbell, cur->idx);
- if (result != VMCI_SUCCESS && result != VMCI_ERROR_DUPLICATE_ENTRY) {
- VMCI_WARNING((LGPFX"Failed to reregister doorbell "
- "(handle=0x%x:0x%x) of resource %s to index "
- "(error=%d).\n",
- h.context, h.resource,
- cur->isDoorbell ? "doorbell" : "queue pair", result));
- }
- }
- }
-
- VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIDoorbell_Sync --
- *
- * Use this as a synchronization point when setting globals, for example,
- * during device shutdown.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIDoorbell_Sync(void)
-{
- VMCILockFlags flags;
- VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags);
- VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags);
- VMCIResource_Sync();
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCI_RegisterNotificationBitmap --
- *
- * Register the notification bitmap with the host.
- *
- * Results:
- * TRUE if the bitmap is registered successfully with the device, FALSE
- * otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-Bool
-VMCI_RegisterNotificationBitmap(PPN bitmapPPN)
-{
- int result;
- VMCINotifyBitmapSetMsg bitmapSetMsg;
-
- /*
- * Do not ASSERT() on the guest device here. This function can get called
- * during device initialization, so the ASSERT() will fail even though
- * the device is (almost) up.
- */
-
- bitmapSetMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_SET_NOTIFY_BITMAP);
- bitmapSetMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
- bitmapSetMsg.hdr.payloadSize = sizeof bitmapSetMsg - VMCI_DG_HEADERSIZE;
- bitmapSetMsg.bitmapPPN = bitmapPPN;
-
- result = VMCI_SendDatagram((VMCIDatagram *)&bitmapSetMsg);
- if (result != VMCI_SUCCESS) {
- VMCI_DEBUG_LOG(4, (LGPFX"Failed to register (PPN=%u) as "
- "notification bitmap (error=%d).\n",
- bitmapPPN, result));
- return FALSE;
- }
- return TRUE;
-}
-
-
-/*
- *-------------------------------------------------------------------------
- *
- * VMCIDoorbellFireEntries --
- *
- * Executes or schedules the handlers for a given notify index.
- *
- * Result:
- * Notification hash entry if found. NULL otherwise.
- *
- * Side effects:
- * Whatever the side effects of the handlers are.
- *
- *-------------------------------------------------------------------------
- */
-
-static void
-VMCIDoorbellFireEntries(uint32 notifyIdx) // IN
-{
- uint32 bucket = VMCI_DOORBELL_HASH(notifyIdx);
- VMCIListItem *iter;
- VMCILockFlags flags;
-
- ASSERT(VMCI_GuestPersonalityActive());
-
- VMCI_GrabLock_BH(&vmciDoorbellIT.lock, &flags);
-
- VMCIList_Scan(iter, &vmciDoorbellIT.entries[bucket]) {
- VMCIDoorbellEntry *cur =
- VMCIList_Entry(iter, VMCIDoorbellEntry, idxListItem);
-
- ASSERT(cur);
-
- if (cur->idx == notifyIdx && Atomic_Read(&cur->active) == 1) {
- ASSERT(cur->notifyCB);
- if (cur->runDelayed) {
- int err;
-
- VMCIResource_Hold(&cur->resource);
- err = VMCI_ScheduleDelayedWork(VMCIDoorbellDelayedDispatchCB, cur);
- if (err != VMCI_SUCCESS) {
- VMCIResource_Release(&cur->resource);
- goto out;
- }
- } else {
- cur->notifyCB(cur->clientData);
- }
- }
- }
-
-out:
- VMCI_ReleaseLock_BH(&vmciDoorbellIT.lock, flags);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCI_ScanNotificationBitmap --
- *
- * Scans the notification bitmap, collects pending notifications,
- * resets the bitmap and invokes appropriate callbacks.
- *
- * Results:
- * None.
- *
- * Side effects:
- * May schedule tasks, allocate memory and run callbacks.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCI_ScanNotificationBitmap(uint8 *bitmap)
-{
- uint32 idx;
-
- ASSERT(bitmap);
- ASSERT(VMCI_GuestPersonalityActive());
-
- for (idx = 0; idx < maxNotifyIdx; idx++) {
- if (bitmap[idx] & 0x1) {
- bitmap[idx] &= ~1;
- VMCIDoorbellFireEntries(idx);
- }
- }
-}
-
-
-#else // SOLARIS) || __APPLE__
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDoorbell_Create/VMCIDoorbell_Destroy/VMCIDoorbell_Notify/
- * VMCIDoorbellHostContextNotify/VMCIDoorbellGetPrivFlags/
- * VMCIDoorbell_Init/VMCIDoorbell_Exit --
- *
- * The doorbell functions have yet to be implemented for Solaris
- * and Mac OS X guest drivers.
- *
- * Results:
- * VMCI_ERROR_UNAVAILABLE.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(VMCIDoorbell_Create)
-int
-VMCIDoorbell_Create(VMCIHandle *handle, // IN
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags, // IN
- VMCICallback notifyCB, // IN
- void *clientData) // IN
-{
- return VMCI_ERROR_UNAVAILABLE;
-}
-
-
-VMCI_EXPORT_SYMBOL(VMCIDoorbell_Destroy)
-int
-VMCIDoorbell_Destroy(VMCIHandle handle) // IN
-{
- return VMCI_ERROR_UNAVAILABLE;
-}
-
-
-VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify)
-int
-VMCIDoorbell_Notify(VMCIHandle handle, // IN
- VMCIPrivilegeFlags privFlags) // IN
-{
- return VMCI_ERROR_UNAVAILABLE;
-}
-
-
-int
-VMCIDoorbellHostContextNotify(VMCIId srcCID, // IN
- VMCIHandle handle) // IN
-{
- return VMCI_ERROR_UNAVAILABLE;
-}
-
-
-int
-VMCIDoorbellGetPrivFlags(VMCIHandle handle, // IN
- VMCIPrivilegeFlags *privFlags) // OUT
-{
- return VMCI_ERROR_UNAVAILABLE;
-}
-
-
-int
-VMCIDoorbell_Init(void)
-{
- return VMCI_SUCCESS;
-}
-
-
-void
-VMCIDoorbell_Exit(void)
-{
-}
-
-#endif // SOLARIS) || __APPLE__
diff --git a/modules/linux/vmci/common/vmciDoorbell.h b/modules/linux/vmci/common/vmciDoorbell.h
deleted file mode 100644
index 8cb3f72..0000000
--- a/modules/linux/vmci/common/vmciDoorbell.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*********************************************************
- * Copyright (C) 2010 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
- *
- *********************************************************/
-
-/*
- * vmciDoorbell.h --
- *
- * Internal functions in the VMCI Doorbell API.
- */
-
-#ifndef VMCI_DOORBELL_H
-#define VMCI_DOORBELL_H
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_kernel_if.h"
-#include "vmci_defs.h"
-
-int VMCIDoorbell_Init(void);
-void VMCIDoorbell_Exit(void);
-void VMCIDoorbell_Hibernate(Bool enterHibernation);
-void VMCIDoorbell_Sync(void);
-
-int VMCIDoorbellHostContextNotify(VMCIId srcCID, VMCIHandle handle);
-int VMCIDoorbellGetPrivFlags(VMCIHandle handle, VMCIPrivilegeFlags *privFlags);
-
-Bool VMCI_RegisterNotificationBitmap(PPN bitmapPPN);
-void VMCI_ScanNotificationBitmap(uint8 *bitmap);
-
-#endif // VMCI_DOORBELL_H
diff --git a/modules/linux/vmci/common/vmciDriver.c b/modules/linux/vmci/common/vmciDriver.c
deleted file mode 100644
index bd0b496..0000000
--- a/modules/linux/vmci/common/vmciDriver.c
+++ /dev/null
@@ -1,688 +0,0 @@
-/*********************************************************
- * 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
- * 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
- *
- *********************************************************/
-
-/*
- * vmciDriver.c --
- *
- * VMCI initialization and ioctl handling.
- */
-
-#include "vmci_kernel_if.h"
-#include "vm_assert.h"
-#include "vmci_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmciCommonInt.h"
-#include "vmciContext.h"
-#include "vmciDatagram.h"
-#include "vmciDoorbell.h"
-#include "vmciDriver.h"
-#include "vmciEvent.h"
-#include "vmciHashtable.h"
-#include "vmciKernelAPI.h"
-#include "vmciQueuePair.h"
-#include "vmciResource.h"
-#if defined(VMKERNEL)
-# include "vmciVmkInt.h"
-# include "vm_libc.h"
-# include "helper_ext.h"
-#endif
-
-#define LGPFX "VMCI: "
-
-static VMCIId ctxUpdateSubID = VMCI_INVALID_ID;
-static VMCIContext *hostContext;
-static Atomic_uint32 vmContextID = { VMCI_INVALID_ID };
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCI_HostInit --
- *
- * Initializes the host driver specific components of VMCI.
- *
- * Results:
- * VMCI_SUCCESS if successful, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCI_HostInit(void)
-{
- int result;
-
- /*
- * In theory, it is unsafe to pass an eventHnd of -1 to platforms which use
- * it (VMKernel/Windows/Mac OS at the time of this writing). In practice we
- * are fine though, because the event is never used in the case of the host
- * context.
- */
- result = VMCIContext_InitContext(VMCI_HOST_CONTEXT_ID,
- VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS,
- -1, VMCI_VERSION, NULL, &hostContext);
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to initialize VMCIContext (result=%d).\n",
- result));
- goto errorExit;
- }
-
- result = VMCIQPBroker_Init();
- if (result < VMCI_SUCCESS) {
- goto hostContextExit;
- }
-
- VMCI_DEBUG_LOG(0, (LGPFX"host components initialized.\n"));
- return VMCI_SUCCESS;
-
-hostContextExit:
- VMCIContext_ReleaseContext(hostContext);
-errorExit:
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCI_HostCleanup --
- *
- * Cleans up the host specific components of the VMCI module.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCI_HostCleanup(void)
-{
- VMCIContext_ReleaseContext(hostContext);
- VMCIQPBroker_Exit();
-}
-
-
-#if defined(__APPLE__) || defined(SOLARIS) || defined(VMKERNEL)
-/* Windows has its own implementation of this, and Linux doesn't need one. */
-/*
- *----------------------------------------------------------------------
- *
- * vmci_device_get --
- *
- * Verifies that a valid VMCI device is present, and indicates
- * the callers intention to use the device until it calls
- * VMCI_DeviceRelease().
- *
- * Results:
- * TRUE if a valid VMCI device is present, FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_device_get)
-Bool
-vmci_device_get(uint32 *apiVersion, // IN/OUT
- VMCI_DeviceShutdownFn *deviceShutdownCB, // UNUSED
- void *userData, // UNUSED
- void **deviceRegistration) // OUT
-{
- if (NULL != deviceRegistration) {
- *deviceRegistration = NULL;
- }
-
- if (*apiVersion > VMCI_KERNEL_API_VERSION) {
- *apiVersion = VMCI_KERNEL_API_VERSION;
- return FALSE;
- }
-
- if (!VMCI_DeviceEnabled()) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * vmci_device_release --
- *
- * Indicates that the caller is done using the VMCI device.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_device_release)
-void
-vmci_device_release(void *deviceRegistration) // UNUSED
-{
-}
-#endif // __APPLE__ || SOLARIS || VMKERNEL
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIUtilCidUpdate --
- *
- * Gets called with the new context id if updated or resumed.
- *
- * Results:
- * Context id.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIUtilCidUpdate(VMCIId subID, // IN:
- VMCI_EventData *eventData, // IN:
- void *clientData) // IN:
-{
- VMCIEventPayload_Context *evPayload = VMCIEventDataPayload(eventData);
-
- if (subID != ctxUpdateSubID) {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid subscriber (ID=0x%x).\n", subID));
- return;
- }
- if (eventData == NULL || evPayload->contextID == VMCI_INVALID_ID) {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid event data.\n"));
- return;
- }
- VMCI_LOG((LGPFX"Updating context from (ID=0x%x) to (ID=0x%x) on event "
- "(type=%d).\n", Atomic_Read(&vmContextID), evPayload->contextID,
- eventData->event));
- Atomic_Write(&vmContextID, evPayload->contextID);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIUtil_Init --
- *
- * Subscribe to context id update event.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIUtil_Init(void)
-{
- /*
- * We subscribe to the VMCI_EVENT_CTX_ID_UPDATE here so we can update the
- * internal context id when needed.
- */
- if (vmci_event_subscribe(VMCI_EVENT_CTX_ID_UPDATE,
-#if !defined(linux) || defined(VMKERNEL)
- VMCI_FLAG_EVENT_NONE,
-#endif // !linux || VMKERNEL
- VMCIUtilCidUpdate, NULL,
- &ctxUpdateSubID) < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to subscribe to event (type=%d).\n",
- VMCI_EVENT_CTX_ID_UPDATE));
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIUtil_Exit --
- *
- * Cleanup
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIUtil_Exit(void)
-{
- if (vmci_event_unsubscribe(ctxUpdateSubID) < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to unsubscribe to event (type=%d) with "
- "subscriber (ID=0x%x).\n", VMCI_EVENT_CTX_ID_UPDATE,
- ctxUpdateSubID));
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIUtil_CheckHostCapabilities --
- *
- * Verify that the host supports the hypercalls we need. If it does not,
- * try to find fallback hypercalls and use those instead.
- *
- * Results:
- * TRUE if required hypercalls (or fallback hypercalls) are
- * supported by the host, FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-#define VMCI_UTIL_NUM_RESOURCES 1
-
-static Bool
-VMCIUtilCheckHostCapabilities(void)
-{
- int result;
- VMCIResourcesQueryMsg *msg;
- uint32 msgSize = sizeof(VMCIResourcesQueryHdr) +
- VMCI_UTIL_NUM_RESOURCES * sizeof(VMCI_Resource);
- VMCIDatagram *checkMsg = VMCI_AllocKernelMem(msgSize, VMCI_MEMORY_NONPAGED);
-
- if (checkMsg == NULL) {
- VMCI_WARNING((LGPFX"Check host: Insufficient memory.\n"));
- return FALSE;
- }
-
- checkMsg->dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_RESOURCES_QUERY);
- checkMsg->src = VMCI_ANON_SRC_HANDLE;
- checkMsg->payloadSize = msgSize - VMCI_DG_HEADERSIZE;
- msg = (VMCIResourcesQueryMsg *)VMCI_DG_PAYLOAD(checkMsg);
-
- msg->numResources = VMCI_UTIL_NUM_RESOURCES;
- msg->resources[0] = VMCI_GET_CONTEXT_ID;
-
- result = VMCI_SendDatagram(checkMsg);
- VMCI_FreeKernelMem(checkMsg, msgSize);
-
- /* We need the vector. There are no fallbacks. */
- return (result == 0x1);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_CheckHostCapabilities --
- *
- * Tell host which guestcalls we support and let each API check
- * that the host supports the hypercalls it needs. If a hypercall
- * is not supported, the API can check for a fallback hypercall,
- * or fail the check.
- *
- * Results:
- * TRUE if successful, FALSE otherwise.
- *
- * Side effects:
- * Fallback mechanisms may be enabled in the API and vmmon.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-VMCI_CheckHostCapabilities(void)
-{
- Bool result = VMCIEvent_CheckHostCapabilities();
- result &= VMCIDatagram_CheckHostCapabilities();
- result &= VMCIUtilCheckHostCapabilities();
-
- if (!result) {
- /* If it failed, then make sure this goes to the system event log. */
- VMCI_WARNING((LGPFX"Host capability checked failed.\n"));
- } else {
- VMCI_DEBUG_LOG(0, (LGPFX"Host capability check passed.\n"));
- }
-
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCI_ReadDatagramsFromPort --
- *
- * Reads datagrams from the data in port and dispatches them. We
- * always start reading datagrams into only the first page of the
- * datagram buffer. If the datagrams don't fit into one page, we
- * use the maximum datagram buffer size for the remainder of the
- * invocation. This is a simple heuristic for not penalizing
- * small datagrams.
- *
- * This function assumes that it has exclusive access to the data
- * in port for the duration of the call.
- *
- * Results:
- * No result.
- *
- * Side effects:
- * Datagram handlers may be invoked.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCI_ReadDatagramsFromPort(VMCIIoHandle ioHandle, // IN
- VMCIIoPort dgInPort, // IN
- uint8 *dgInBuffer, // IN
- size_t dgInBufferSize) // IN
-{
- VMCIDatagram *dg;
- size_t currentDgInBufferSize = PAGE_SIZE;
- size_t remainingBytes;
-
- ASSERT(dgInBufferSize >= PAGE_SIZE);
-
- VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
- dg = (VMCIDatagram *)dgInBuffer;
- remainingBytes = currentDgInBufferSize;
-
- while (dg->dst.resource != VMCI_INVALID_ID || remainingBytes > PAGE_SIZE) {
- unsigned dgInSize;
-
- /*
- * When the input buffer spans multiple pages, a datagram can
- * start on any page boundary in the buffer.
- */
-
- if (dg->dst.resource == VMCI_INVALID_ID) {
- ASSERT(remainingBytes > PAGE_SIZE);
- dg = (VMCIDatagram *)ROUNDUP((uintptr_t)dg + 1, PAGE_SIZE);
- ASSERT((uint8 *)dg < dgInBuffer + currentDgInBufferSize);
- remainingBytes = (size_t)(dgInBuffer + currentDgInBufferSize - (uint8 *)dg);
- continue;
- }
-
- dgInSize = VMCI_DG_SIZE_ALIGNED(dg);
-
- if (dgInSize <= dgInBufferSize) {
- int result;
-
- /*
- * If the remaining bytes in the datagram buffer doesn't
- * contain the complete datagram, we first make sure we have
- * enough room for it and then we read the reminder of the
- * datagram and possibly any following datagrams.
- */
-
- if (dgInSize > remainingBytes) {
-
- if (remainingBytes != currentDgInBufferSize) {
-
- /*
- * We move the partial datagram to the front and read
- * the reminder of the datagram and possibly following
- * calls into the following bytes.
- */
-
- memmove(dgInBuffer, dgInBuffer + currentDgInBufferSize - remainingBytes,
- remainingBytes);
-
- dg = (VMCIDatagram *)dgInBuffer;
- }
-
- if (currentDgInBufferSize != dgInBufferSize) {
- currentDgInBufferSize = dgInBufferSize;
- }
-
- VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer + remainingBytes,
- currentDgInBufferSize - remainingBytes);
- }
-
- /* We special case event datagrams from the hypervisor. */
- if (dg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
- dg->dst.resource == VMCI_EVENT_HANDLER) {
- result = VMCIEvent_Dispatch(dg);
- } else {
- result = VMCIDatagram_InvokeGuestHandler(dg);
- }
- if (result < VMCI_SUCCESS) {
- VMCI_DEBUG_LOG(4, (LGPFX"Datagram with resource (ID=0x%x) failed "
- "(err=%d).\n", dg->dst.resource, result));
- }
-
- /* On to the next datagram. */
- dg = (VMCIDatagram *)((uint8 *)dg + dgInSize);
- } else {
- size_t bytesToSkip;
-
- /*
- * Datagram doesn't fit in datagram buffer of maximal size. We drop it.
- */
-
- VMCI_DEBUG_LOG(4, (LGPFX"Failed to receive datagram (size=%u bytes).\n",
- dgInSize));
-
- bytesToSkip = dgInSize - remainingBytes;
- if (currentDgInBufferSize != dgInBufferSize) {
- currentDgInBufferSize = dgInBufferSize;
- }
- for (;;) {
- VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
- if (bytesToSkip <= currentDgInBufferSize) {
- break;
- }
- bytesToSkip -= currentDgInBufferSize;
- }
- dg = (VMCIDatagram *)(dgInBuffer + bytesToSkip);
- }
-
- remainingBytes = (size_t) (dgInBuffer + currentDgInBufferSize - (uint8 *)dg);
-
- if (remainingBytes < VMCI_DG_HEADERSIZE) {
- /* Get the next batch of datagrams. */
-
- VMCI_ReadPortBytes(ioHandle, dgInPort, dgInBuffer, currentDgInBufferSize);
- dg = (VMCIDatagram *)dgInBuffer;
- remainingBytes = currentDgInBufferSize;
- }
- }
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * vmci_get_context_id --
- *
- * Returns the current context ID. Note that since this is accessed only
- * from code running in the host, this always returns the host context ID.
- *
- * Results:
- * Context ID.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_get_context_id)
-VMCIId
-vmci_get_context_id(void)
-{
- if (VMCI_GuestPersonalityActive()) {
- if (Atomic_Read(&vmContextID) == VMCI_INVALID_ID) {
- uint32 result;
- VMCIDatagram getCidMsg;
- getCidMsg.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_GET_CONTEXT_ID);
- getCidMsg.src = VMCI_ANON_SRC_HANDLE;
- getCidMsg.payloadSize = 0;
- result = VMCI_SendDatagram(&getCidMsg);
- Atomic_Write(&vmContextID, result);
- }
- return Atomic_Read(&vmContextID);
- } else if (VMCI_HostPersonalityActive()) {
- return VMCI_HOST_CONTEXT_ID;
- }
- return VMCI_INVALID_ID;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * vmci_version --
- *
- * Returns the version of the VMCI driver.
- *
- * Results:
- * Returns a version number.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_version)
-uint32
-vmci_version(void)
-{
- return VMCI_VERSION;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCI_SharedInit --
- *
- * Initializes VMCI components shared between guest and host
- * driver. This registers core hypercalls.
- *
- * Results:
- * VMCI_SUCCESS if successful, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCI_SharedInit(void)
-{
- int result;
-
- result = VMCIResource_Init();
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to initialize VMCIResource (result=%d).\n",
- result));
- goto errorExit;
- }
-
- result = VMCIContext_Init();
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to initialize VMCIContext (result=%d).\n",
- result));
- goto resourceExit;
- }
-
- result = VMCIDatagram_Init();
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to initialize VMCIDatagram (result=%d).\n",
- result));
- goto contextExit;
- }
-
- result = VMCIEvent_Init();
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to initialize VMCIEvent (result=%d).\n",
- result));
- goto datagramExit;
- }
-
- result = VMCIDoorbell_Init();
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to initialize VMCIDoorbell (result=%d).\n",
- result));
- goto eventExit;
- }
-
- VMCI_DEBUG_LOG(0, (LGPFX"shared components initialized.\n"));
- return VMCI_SUCCESS;
-
-eventExit:
- VMCIEvent_Exit();
-datagramExit:
- VMCIDatagram_Exit();
-contextExit:
- VMCIContext_Exit();
-resourceExit:
- VMCIResource_Exit();
-errorExit:
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCI_SharedCleanup --
- *
- * Cleans up VMCI components shared between guest and host
- * driver.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCI_SharedCleanup(void)
-{
- VMCIDoorbell_Exit();
- VMCIEvent_Exit();
- VMCIDatagram_Exit();
- VMCIContext_Exit();
- VMCIResource_Exit();
-}
diff --git a/modules/linux/vmci/common/vmciDriver.h b/modules/linux/vmci/common/vmciDriver.h
deleted file mode 100644
index 9ce7995..0000000
--- a/modules/linux/vmci/common/vmciDriver.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*********************************************************
- * 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
- * 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
- *
- *********************************************************/
-
-/*
- * vmciDriver.h --
- *
- * VMCI host driver interface.
- */
-
-#ifndef _VMCI_DRIVER_H_
-#define _VMCI_DRIVER_H_
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMMON
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmciContext.h"
-
-/*
- * A few macros to encapsulate logging in common code. The macros
- * result in LOG/LOGThrottled on vmkernel and Log on hosted.
- */
-
-#ifdef _WIN32
-# include "vmciLog.h"
-#else // _WIN32
-#if defined(VMKERNEL) && !defined(VMKERNEL_OFFSET_CHECKER)
- /*
- * LOGLEVEL_MODULE is defined in another header that gets included into the
- * dummy file used by the offsetchecker, which causes it to barf on the
- * redefinition.
- */
-# define LOGLEVEL_MODULE_LEN 0
-# define LOGLEVEL_MODULE VMCIVMK
-# include "log.h"
-# ifdef VMX86_LOG
-# define _VMCILOG(_args...) LOG(i, _args)
-# define VMCI_DEBUG_LOG(_level, _args) \
- do { \
- int i = _level; \
- _VMCILOG _args ; \
- } while(FALSE)
-# else // VMX86_LOG
-# define VMCI_DEBUG_LOG(_level, _args)
-# endif // VMX86_LOG
-#else // VMKERNEL
-# define VMCI_DEBUG_LEVEL 4
-# define VMCI_DEBUG_LOG(_level, _args) \
- do { \
- if (_level < VMCI_DEBUG_LEVEL) { \
- Log _args ; \
- } \
- } while(FALSE)
-#endif // VMKERNEL
-#define VMCI_LOG(_args) Log _args
-#define VMCI_WARNING(_args) Warning _args
-#endif // _WIN32
-
-
-int VMCI_SharedInit(void);
-void VMCI_SharedCleanup(void);
-int VMCI_HostInit(void);
-void VMCI_HostCleanup(void);
-VMCIId VMCI_GetContextID(void);
-int VMCI_SendDatagram(VMCIDatagram *dg);
-
-void VMCIUtil_Init(void);
-void VMCIUtil_Exit(void);
-Bool VMCI_CheckHostCapabilities(void);
-void VMCI_ReadDatagramsFromPort(VMCIIoHandle ioHandle, VMCIIoPort dgInPort,
- uint8 *dgInBuffer, size_t dgInBufferSize);
-Bool VMCI_DeviceEnabled(void);
-#if defined(_WIN64)
-int VMCIDoSendDatagram(unsigned int dgSize, ULONG *dataPort, ULONG *resultPort,
- VMCIDatagram *dg);
-#endif // _WIN64
-
-
-#endif // _VMCI_DRIVER_H_
diff --git a/modules/linux/vmci/common/vmciEvent.c b/modules/linux/vmci/common/vmciEvent.c
deleted file mode 100644
index 0d6a569..0000000
--- a/modules/linux/vmci/common/vmciEvent.c
+++ /dev/null
@@ -1,788 +0,0 @@
-/*********************************************************
- * Copyright (C) 2007 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
- *
- *********************************************************/
-
-/*
- * vmciEvent.c --
- *
- * VMCI Event code for host and guests.
- */
-
-#include "vmci_kernel_if.h"
-#include "vmci_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmciEvent.h"
-#include "vmciKernelAPI.h"
-#if defined(VMKERNEL)
-# include "vmciVmkInt.h"
-# include "vm_libc.h"
-# include "helper_ext.h"
-# include "vmciDriver.h"
-#else
-# include "vmciDriver.h"
-#endif
-
-#define LGPFX "VMCIEvent: "
-
-#define EVENT_MAGIC 0xEABE0000
-
-typedef struct VMCISubscription {
- VMCIId id;
- int refCount;
- Bool runDelayed;
- VMCIEvent destroyEvent;
- VMCI_Event event;
- VMCI_EventCB callback;
- void *callbackData;
- VMCIListItem subscriberListItem;
-} VMCISubscription;
-
-
-static VMCISubscription *VMCIEventFind(VMCIId subID);
-static int VMCIEventDeliver(VMCIEventMsg *eventMsg);
-static int VMCIEventRegisterSubscription(VMCISubscription *sub,
- VMCI_Event event,
- uint32 flags,
- VMCI_EventCB callback,
- void *callbackData);
-static VMCISubscription *VMCIEventUnregisterSubscription(VMCIId subID);
-
-static VMCIList subscriberArray[VMCI_EVENT_MAX];
-static VMCILock subscriberLock;
-
-typedef struct VMCIDelayedEventInfo {
- VMCISubscription *sub;
- uint8 eventPayload[sizeof(VMCIEventData_Max)];
-} VMCIDelayedEventInfo;
-
-typedef struct VMCIEventRef {
- VMCISubscription *sub;
- VMCIListItem listItem;
-} VMCIEventRef;
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIEvent_Init --
- *
- * General init code.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIEvent_Init(void)
-{
- int i;
-
- for (i = 0; i < VMCI_EVENT_MAX; i++) {
- VMCIList_Init(&subscriberArray[i]);
- }
-
- return VMCI_InitLock(&subscriberLock, "VMCIEventSubscriberLock",
- VMCI_LOCK_RANK_EVENT);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIEvent_Exit --
- *
- * General exit code.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIEvent_Exit(void)
-{
- VMCIListItem *iter, *iter2;
- VMCI_Event e;
-
- /* We free all memory at exit. */
- for (e = 0; e < VMCI_EVENT_MAX; e++) {
- VMCIList_ScanSafe(iter, iter2, &subscriberArray[e]) {
- VMCISubscription *cur;
-
- /*
- * We should never get here because all events should have been
- * unregistered before we try to unload the driver module.
- * Also, delayed callbacks could still be firing so this cleanup
- * would not be safe.
- * Still it is better to free the memory than not ... so we
- * leave this code in just in case....
- *
- */
- ASSERT(FALSE);
-
- cur = VMCIList_Entry(iter, VMCISubscription, subscriberListItem);
- VMCI_FreeKernelMem(cur, sizeof *cur);
- }
- }
- VMCI_CleanupLock(&subscriberLock);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIEvent_Sync --
- *
- * Use this as a synchronization point when setting globals, for example,
- * during device shutdown.
- *
- * Results:
- * TRUE.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIEvent_Sync(void)
-{
- VMCILockFlags lockFlags;
- VMCI_GrabLock_BH(&subscriberLock, &lockFlags);
- VMCI_ReleaseLock_BH(&subscriberLock, lockFlags);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIEvent_CheckHostCapabilities --
- *
- * Verify that the host supports the hypercalls we need. If it does not,
- * try to find fallback hypercalls and use those instead.
- *
- * Results:
- * TRUE if required hypercalls (or fallback hypercalls) are
- * supported by the host, FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-VMCIEvent_CheckHostCapabilities(void)
-{
- /* VMCIEvent does not require any hypercalls. */
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIEventGet --
- *
- * Gets a reference to the given VMCISubscription.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIEventGet(VMCISubscription *entry) // IN
-{
- ASSERT(entry);
-
- entry->refCount++;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIEventRelease --
- *
- * Releases the given VMCISubscription.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Fires the destroy event if the reference count has gone to zero.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIEventRelease(VMCISubscription *entry) // IN
-{
- ASSERT(entry);
- ASSERT(entry->refCount > 0);
-
- entry->refCount--;
- if (entry->refCount == 0) {
- VMCI_SignalEvent(&entry->destroyEvent);
- }
-}
-
-
- /*
- *------------------------------------------------------------------------------
- *
- * EventReleaseCB --
- *
- * Callback to release the event entry reference. It is called by the
- * VMCI_WaitOnEvent function before it blocks.
- *
- * Result:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-EventReleaseCB(void *clientData) // IN
-{
- VMCILockFlags flags;
- VMCISubscription *sub = (VMCISubscription *)clientData;
-
- ASSERT(sub);
-
- VMCI_GrabLock_BH(&subscriberLock, &flags);
- VMCIEventRelease(sub);
- VMCI_ReleaseLock_BH(&subscriberLock, flags);
-
- return 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIEventFind --
- *
- * Find entry. Assumes lock is held.
- *
- * Results:
- * Entry if found, NULL if not.
- *
- * Side effects:
- * Increments the VMCISubscription refcount if an entry is found.
- *
- *-----------------------------------------------------------------------------
- */
-
-static VMCISubscription *
-VMCIEventFind(VMCIId subID) // IN
-{
- VMCIListItem *iter;
- VMCI_Event e;
-
- for (e = 0; e < VMCI_EVENT_MAX; e++) {
- VMCIList_Scan(iter, &subscriberArray[e]) {
- VMCISubscription *cur =
- VMCIList_Entry(iter, VMCISubscription, subscriberListItem);
- if (cur->id == subID) {
- VMCIEventGet(cur);
- return cur;
- }
- }
- }
- return NULL;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIEventDelayedDispatchCB --
- *
- * Calls the specified callback in a delayed context.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-VMCIEventDelayedDispatchCB(void *data) // IN
-{
- VMCIDelayedEventInfo *eventInfo;
- VMCISubscription *sub;
- VMCI_EventData *ed;
- VMCILockFlags flags;
-
- eventInfo = (VMCIDelayedEventInfo *)data;
-
- ASSERT(eventInfo);
- ASSERT(eventInfo->sub);
-
- sub = eventInfo->sub;
- ed = (VMCI_EventData *)eventInfo->eventPayload;
-
- sub->callback(sub->id, ed, sub->callbackData);
-
- VMCI_GrabLock_BH(&subscriberLock, &flags);
- VMCIEventRelease(sub);
- VMCI_ReleaseLock_BH(&subscriberLock, flags);
-
- VMCI_FreeKernelMem(eventInfo, sizeof *eventInfo);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * VMCIEventDeliver --
- *
- * Actually delivers the events to the subscribers.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The callback function for each subscriber is invoked.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-VMCIEventDeliver(VMCIEventMsg *eventMsg) // IN
-{
- int err = VMCI_SUCCESS;
- VMCIListItem *iter;
- VMCILockFlags flags;
-
- VMCIList noDelayList;
- VMCIList_Init(&noDelayList);
-
- ASSERT(eventMsg);
-
- VMCI_GrabLock_BH(&subscriberLock, &flags);
- VMCIList_Scan(iter, &subscriberArray[eventMsg->eventData.event]) {
- VMCISubscription *cur = VMCIList_Entry(iter, VMCISubscription,
- subscriberListItem);
- ASSERT(cur && cur->event == eventMsg->eventData.event);
-
- if (cur->runDelayed) {
- VMCIDelayedEventInfo *eventInfo;
- if ((eventInfo = VMCI_AllocKernelMem(sizeof *eventInfo,
- (VMCI_MEMORY_ATOMIC |
- VMCI_MEMORY_NONPAGED))) == NULL) {
- err = VMCI_ERROR_NO_MEM;
- goto out;
- }
-
- VMCIEventGet(cur);
-
- memset(eventInfo, 0, sizeof *eventInfo);
- memcpy(eventInfo->eventPayload, VMCI_DG_PAYLOAD(eventMsg),
- (size_t)eventMsg->hdr.payloadSize);
- eventInfo->sub = cur;
- err = VMCI_ScheduleDelayedWork(VMCIEventDelayedDispatchCB,
- eventInfo);
- if (err != VMCI_SUCCESS) {
- VMCIEventRelease(cur);
- VMCI_FreeKernelMem(eventInfo, sizeof *eventInfo);
- goto out;
- }
-
- } else {
- VMCIEventRef *eventRef;
-
- /*
- * To avoid possible lock rank voilation when holding
- * subscriberLock, we construct a local list of
- * subscribers and release subscriberLock before
- * invokes the callbacks. This is similar to delayed
- * callbacks, but callbacks is invoked right away here.
- */
- if ((eventRef = VMCI_AllocKernelMem(sizeof *eventRef,
- (VMCI_MEMORY_ATOMIC |
- VMCI_MEMORY_NONPAGED))) == NULL) {
- err = VMCI_ERROR_NO_MEM;
- goto out;
- }
-
- VMCIEventGet(cur);
- eventRef->sub = cur;
- VMCIList_InitEntry(&eventRef->listItem);
- VMCIList_Insert(&eventRef->listItem, &noDelayList);
- }
- }
-
-out:
- VMCI_ReleaseLock_BH(&subscriberLock, flags);
-
- if (!VMCIList_Empty(&noDelayList)) {
- VMCI_EventData *ed;
- VMCIListItem *iter2;
-
- VMCIList_ScanSafe(iter, iter2, &noDelayList) {
- VMCIEventRef *eventRef = VMCIList_Entry(iter, VMCIEventRef,
- listItem);
- VMCISubscription *cur = eventRef->sub;
- uint8 eventPayload[sizeof(VMCIEventData_Max)];
-
- /* We set event data before each callback to ensure isolation. */
- memset(eventPayload, 0, sizeof eventPayload);
- memcpy(eventPayload, VMCI_DG_PAYLOAD(eventMsg),
- (size_t)eventMsg->hdr.payloadSize);
- ed = (VMCI_EventData *)eventPayload;
- cur->callback(cur->id, ed, cur->callbackData);
-
- VMCI_GrabLock_BH(&subscriberLock, &flags);
- VMCIEventRelease(cur);
- VMCI_ReleaseLock_BH(&subscriberLock, flags);
- VMCI_FreeKernelMem(eventRef, sizeof *eventRef);
- }
- }
-
- return err;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIEvent_Dispatch --
- *
- * Dispatcher for the VMCI_EVENT_RECEIVE datagrams. Calls all
- * subscribers for given event.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-VMCIEvent_Dispatch(VMCIDatagram *msg) // IN
-{
- VMCIEventMsg *eventMsg = (VMCIEventMsg *)msg;
-
- ASSERT(msg &&
- msg->src.context == VMCI_HYPERVISOR_CONTEXT_ID &&
- msg->dst.resource == VMCI_EVENT_HANDLER);
-
- if (msg->payloadSize < sizeof(VMCI_Event) ||
- msg->payloadSize > sizeof(VMCIEventData_Max)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (!VMCI_EVENT_VALID(eventMsg->eventData.event)) {
- return VMCI_ERROR_EVENT_UNKNOWN;
- }
-
- VMCIEventDeliver(eventMsg);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIEventRegisterSubscription --
- *
- * Initialize and add subscription to subscriber list.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-VMCIEventRegisterSubscription(VMCISubscription *sub, // IN
- VMCI_Event event, // IN
- uint32 flags, // IN
- VMCI_EventCB callback, // IN
- void *callbackData) // IN
-{
-# define VMCI_EVENT_MAX_ATTEMPTS 10
- static VMCIId subscriptionID = 0;
- VMCILockFlags lockFlags;
- uint32 attempts = 0;
- int result;
- Bool success;
-
- ASSERT(sub);
-
- if (!VMCI_EVENT_VALID(event) || callback == NULL) {
- VMCI_DEBUG_LOG(4, (LGPFX"Failed to subscribe to event (type=%d) "
- "(callback=%p) (data=%p).\n",
- event, callback, callbackData));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (vmkernel) {
- /*
- * In the vmkernel we defer delivery of events to a helper world. This
- * makes the event delivery more consistent across hosts and guests with
- * regard to which locks are held. Memory access events are an exception
- * to this, since clients need to know immediately that the device
- * memory is disabled (if we delay such events, then clients may be
- * notified too late).
- */
- if (VMCI_EVENT_MEM_ACCESS_ON == event ||
- VMCI_EVENT_MEM_ACCESS_OFF == event) {
- /*
- * Client must expect to get such events synchronously, and should
- * perform its locking accordingly. If it can't handle this, then
- * fail.
- */
- if (flags & VMCI_FLAG_EVENT_DELAYED_CB) {
- return VMCI_ERROR_INVALID_ARGS;
- }
- sub->runDelayed = FALSE;
- } else {
- sub->runDelayed = TRUE;
- }
- } else if (!VMCI_CanScheduleDelayedWork()) {
- /*
- * If the platform doesn't support delayed work callbacks then don't
- * allow registration for them.
- */
- if (flags & VMCI_FLAG_EVENT_DELAYED_CB) {
- return VMCI_ERROR_INVALID_ARGS;
- }
- sub->runDelayed = FALSE;
- } else {
- /*
- * The platform supports delayed work callbacks. Honor the requested
- * flags
- */
- sub->runDelayed = (flags & VMCI_FLAG_EVENT_DELAYED_CB) ? TRUE : FALSE;
- }
-
- sub->refCount = 1;
- sub->event = event;
- sub->callback = callback;
- sub->callbackData = callbackData;
- VMCIList_InitEntry(&sub->subscriberListItem);
-
- VMCI_GrabLock_BH(&subscriberLock, &lockFlags);
-
- /* Check if creation of a new event is allowed. */
- if (!VMCI_CanCreate()) {
- result = VMCI_ERROR_UNAVAILABLE;
- goto exit;
- }
-
- for (success = FALSE, attempts = 0;
- success == FALSE && attempts < VMCI_EVENT_MAX_ATTEMPTS;
- attempts++) {
- VMCISubscription *existingSub = NULL;
-
- /*
- * We try to get an id a couple of time before claiming we are out of
- * resources.
- */
- sub->id = ++subscriptionID;
-
- /* Test for duplicate id. */
- existingSub = VMCIEventFind(sub->id);
- if (existingSub == NULL) {
- /* We succeeded if we didn't find a duplicate. */
- success = TRUE;
- } else {
- VMCIEventRelease(existingSub);
- }
- }
-
- if (success) {
- VMCI_CreateEvent(&sub->destroyEvent);
- VMCIList_Insert(&sub->subscriberListItem, &subscriberArray[event]);
- result = VMCI_SUCCESS;
- } else {
- result = VMCI_ERROR_NO_RESOURCES;
- }
-
-exit:
- VMCI_ReleaseLock_BH(&subscriberLock, lockFlags);
- return result;
-# undef VMCI_EVENT_MAX_ATTEMPTS
-}
-
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIEventUnregisterSubscription --
- *
- * Remove subscription from subscriber list.
- *
- * Results:
- * VMCISubscription when found, NULL otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static VMCISubscription *
-VMCIEventUnregisterSubscription(VMCIId subID) // IN
-{
- VMCILockFlags flags;
- VMCISubscription *s;
-
- VMCI_GrabLock_BH(&subscriberLock, &flags);
- s = VMCIEventFind(subID);
- if (s != NULL) {
- VMCIEventRelease(s);
- VMCIList_Remove(&s->subscriberListItem);
- }
- VMCI_ReleaseLock_BH(&subscriberLock, flags);
-
- if (s != NULL) {
- VMCI_WaitOnEvent(&s->destroyEvent, EventReleaseCB, s);
- VMCI_DestroyEvent(&s->destroyEvent);
- }
-
- return s;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * vmci_event_subscribe --
- *
- * Subscribe to given event. The callback specified can be fired
- * in different contexts depending on what flag is specified while
- * registering. If flags contains VMCI_FLAG_EVENT_NONE then the
- * callback is fired with the subscriber lock held (and BH context
- * on the guest). If flags contain VMCI_FLAG_EVENT_DELAYED_CB then
- * the callback is fired with no locks held in thread context.
- * This is useful because other VMCIEvent functions can be called,
- * but it also increases the chances that an event will be dropped.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_event_subscribe)
-int
-vmci_event_subscribe(VMCI_Event event, // IN
-#if !defined(linux) || defined(VMKERNEL)
- uint32 flags, // IN
-#endif // !linux || VMKERNEL
- VMCI_EventCB callback, // IN
- void *callbackData, // IN
- VMCIId *subscriptionID) // OUT
-{
- int retval;
-#if defined(linux) && !defined(VMKERNEL)
- uint32 flags = VMCI_FLAG_EVENT_NONE;
-#endif // linux && !VMKERNEL
- VMCISubscription *s = NULL;
-
- if (subscriptionID == NULL) {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid subscription (NULL).\n"));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- s = VMCI_AllocKernelMem(sizeof *s, VMCI_MEMORY_NONPAGED);
- if (s == NULL) {
- return VMCI_ERROR_NO_MEM;
- }
-
- retval = VMCIEventRegisterSubscription(s, event, flags,
- callback, callbackData);
- if (retval < VMCI_SUCCESS) {
- VMCI_FreeKernelMem(s, sizeof *s);
- return retval;
- }
-
- *subscriptionID = s->id;
- return retval;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * vmci_event_unsubscribe --
- *
- * Unsubscribe to given event. Removes it from list and frees it.
- * Will return callbackData if requested by caller.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_event_unsubscribe)
-int
-vmci_event_unsubscribe(VMCIId subID) // IN
-{
- VMCISubscription *s;
-
- /*
- * Return subscription. At this point we know noone else is accessing
- * the subscription so we can free it.
- */
- s = VMCIEventUnregisterSubscription(subID);
- if (s == NULL) {
- return VMCI_ERROR_NOT_FOUND;
-
- }
- VMCI_FreeKernelMem(s, sizeof *s);
-
- return VMCI_SUCCESS;
-}
diff --git a/modules/linux/vmci/common/vmciEvent.h b/modules/linux/vmci/common/vmciEvent.h
deleted file mode 100644
index 720b50d..0000000
--- a/modules/linux/vmci/common/vmciEvent.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*********************************************************
- * Copyright (C) 2007 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
- *
- *********************************************************/
-
-/*
- * vmciEvent.h --
- *
- * Event code for the vmci guest driver
- */
-
-#ifndef __VMCI_EVENT_H__
-#define __VMCI_EVENT_H__
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMMON
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_defs.h"
-#include "vmci_call_defs.h"
-
-int VMCIEvent_Init(void);
-void VMCIEvent_Exit(void);
-void VMCIEvent_Sync(void);
-int VMCIEvent_Dispatch(VMCIDatagram *msg);
-Bool VMCIEvent_CheckHostCapabilities(void);
-
-#endif //__VMCI_EVENT_H__
diff --git a/modules/linux/vmci/common/vmciHashtable.c b/modules/linux/vmci/common/vmciHashtable.c
deleted file mode 100644
index b7b577d..0000000
--- a/modules/linux/vmci/common/vmciHashtable.c
+++ /dev/null
@@ -1,607 +0,0 @@
-/*********************************************************
- * Copyright (C) 2006-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
- *
- *********************************************************/
-
-/*
- * vmciHashtable.c --
- *
- * Implementation of the VMCI Hashtable.
- * TODO: Look into what is takes to use lib/misc/hashTable.c instead of
- * our own implementation.
- */
-
-#include "vmci_kernel_if.h"
-#include "vm_assert.h"
-#include "vmci_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmciCommonInt.h"
-#include "vmciDriver.h"
-#include "vmciHashtable.h"
-#if defined(VMKERNEL)
-# include "vmciVmkInt.h"
-# include "vm_libc.h"
-# include "helper_ext.h"
-#endif
-
-#define LGPFX "VMCIHashTable: "
-
-#define VMCI_HASHTABLE_HASH(_h, _sz) \
- VMCI_HashId(VMCI_HANDLE_TO_RESOURCE_ID(_h), (_sz))
-
-static int HashTableUnlinkEntry(VMCIHashTable *table, VMCIHashEntry *entry);
-static Bool VMCIHashTableEntryExistsLocked(VMCIHashTable *table,
- VMCIHandle handle);
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTable_Create --
- * XXX Factor out the hashtable code to be shared amongst host and guest.
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCIHashTable *
-VMCIHashTable_Create(int size)
-{
- VMCIHashTable *table = VMCI_AllocKernelMem(sizeof *table,
- VMCI_MEMORY_NONPAGED);
- if (table == NULL) {
- return NULL;
- }
-
- table->entries = VMCI_AllocKernelMem(sizeof *table->entries * size,
- VMCI_MEMORY_NONPAGED);
- if (table->entries == NULL) {
- VMCI_FreeKernelMem(table, sizeof *table);
- return NULL;
- }
- memset(table->entries, 0, sizeof *table->entries * size);
- table->size = size;
- if (VMCI_InitLock(&table->lock, "VMCIHashTableLock",
- VMCI_LOCK_RANK_HASHTABLE) < VMCI_SUCCESS) {
- VMCI_FreeKernelMem(table->entries, sizeof *table->entries * size);
- VMCI_FreeKernelMem(table, sizeof *table);
- return NULL;
- }
-
- return table;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTable_Destroy --
- * This function should be called at module exit time.
- * We rely on the module ref count to insure that no one is accessing any
- * hash table entries at this point in time. Hence we should be able to just
- * remove all entries from the hash table.
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIHashTable_Destroy(VMCIHashTable *table)
-{
- VMCILockFlags flags;
-#if 0
- DEBUG_ONLY(int i;)
- DEBUG_ONLY(int leakingEntries = 0;)
-#endif
-
- ASSERT(table);
-
- VMCI_GrabLock_BH(&table->lock, &flags);
-#if 0
-#ifdef VMX86_DEBUG
- for (i = 0; i < table->size; i++) {
- VMCIHashEntry *head = table->entries[i];
- while (head) {
- leakingEntries++;
- head = head->next;
- }
- }
- if (leakingEntries) {
- VMCI_WARNING((LGPFX"Leaking entries (%d) for hash table (%p).\n",
- leakingEntries, table));
- }
-#endif // VMX86_DEBUG
-#endif
- VMCI_FreeKernelMem(table->entries, sizeof *table->entries * table->size);
- table->entries = NULL;
- VMCI_ReleaseLock_BH(&table->lock, flags);
- VMCI_CleanupLock(&table->lock);
- VMCI_FreeKernelMem(table, sizeof *table);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTable_InitEntry --
- * Initializes a hash entry;
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-void
-VMCIHashTable_InitEntry(VMCIHashEntry *entry, // IN
- VMCIHandle handle) // IN
-{
- ASSERT(entry);
- entry->handle = handle;
- entry->refCount = 0;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTable_AddEntry --
- * XXX Factor out the hashtable code to be shared amongst host and guest.
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIHashTable_AddEntry(VMCIHashTable *table, // IN
- VMCIHashEntry *entry) // IN
-{
- int idx;
- VMCILockFlags flags;
-
- ASSERT(entry);
- ASSERT(table);
-
- VMCI_GrabLock_BH(&table->lock, &flags);
-
- /* Check if creation of a new hashtable entry is allowed. */
- if (!VMCI_CanCreate()) {
- VMCI_ReleaseLock_BH(&table->lock, flags);
- return VMCI_ERROR_UNAVAILABLE;
- }
-
- if (VMCIHashTableEntryExistsLocked(table, entry->handle)) {
- VMCI_DEBUG_LOG(4, (LGPFX"Entry (handle=0x%x:0x%x) already exists.\n",
- entry->handle.context, entry->handle.resource));
- VMCI_ReleaseLock_BH(&table->lock, flags);
- return VMCI_ERROR_DUPLICATE_ENTRY;
- }
-
- idx = VMCI_HASHTABLE_HASH(entry->handle, table->size);
- ASSERT(idx < table->size);
-
- /* New entry is added to top/front of hash bucket. */
- entry->refCount++;
- entry->next = table->entries[idx];
- table->entries[idx] = entry;
- VMCI_ReleaseLock_BH(&table->lock, flags);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTable_RemoveEntry --
- * XXX Factor out the hashtable code to shared amongst API and perhaps
- * host and guest.
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIHashTable_RemoveEntry(VMCIHashTable *table, // IN
- VMCIHashEntry *entry) // IN
-{
- int result;
- VMCILockFlags flags;
-
- ASSERT(table);
- ASSERT(entry);
-
- VMCI_GrabLock_BH(&table->lock, &flags);
-
- /* First unlink the entry. */
- result = HashTableUnlinkEntry(table, entry);
- if (result != VMCI_SUCCESS) {
- /* We failed to find the entry. */
- goto done;
- }
-
- /* Decrement refcount and check if this is last reference. */
- entry->refCount--;
- if (entry->refCount == 0) {
- result = VMCI_SUCCESS_ENTRY_DEAD;
- goto done;
- }
-
- done:
- VMCI_ReleaseLock_BH(&table->lock, flags);
-
- return result;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTableGetEntryLocked --
- *
- * Looks up an entry in the hash table, that is already locked.
- *
- * Result:
- * If the element is found, a pointer to the element is returned.
- * Otherwise NULL is returned.
- *
- * Side effects:
- * The reference count of the returned element is increased.
- *
- *------------------------------------------------------------------------------
- */
-
-static VMCIHashEntry *
-VMCIHashTableGetEntryLocked(VMCIHashTable *table, // IN
- VMCIHandle handle) // IN
-{
- VMCIHashEntry *cur = NULL;
- int idx;
-
- ASSERT(!VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE));
- ASSERT(table);
-
- idx = VMCI_HASHTABLE_HASH(handle, table->size);
-
- cur = table->entries[idx];
- while (TRUE) {
- if (cur == NULL) {
- break;
- }
-
- if (VMCI_HANDLE_TO_RESOURCE_ID(cur->handle) ==
- VMCI_HANDLE_TO_RESOURCE_ID(handle)) {
- if ((VMCI_HANDLE_TO_CONTEXT_ID(cur->handle) ==
- VMCI_HANDLE_TO_CONTEXT_ID(handle)) ||
- (VMCI_INVALID_ID == VMCI_HANDLE_TO_CONTEXT_ID(cur->handle))) {
- cur->refCount++;
- break;
- }
- }
- cur = cur->next;
- }
-
- return cur;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTable_GetEntry --
- * XXX Factor out the hashtable code to shared amongst API and perhaps
- * host and guest.
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCIHashEntry *
-VMCIHashTable_GetEntry(VMCIHashTable *table, // IN
- VMCIHandle handle) // IN
-{
- VMCIHashEntry *entry;
- VMCILockFlags flags;
-
- if (VMCI_HANDLE_EQUAL(handle, VMCI_INVALID_HANDLE)) {
- return NULL;
- }
-
- ASSERT(table);
-
- VMCI_GrabLock_BH(&table->lock, &flags);
- entry = VMCIHashTableGetEntryLocked(table, handle);
- VMCI_ReleaseLock_BH(&table->lock, flags);
-
- return entry;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTable_HoldEntry --
- *
- * Hold the given entry. This will increment the entry's reference count.
- * This is like a GetEntry() but without having to lookup the entry by
- * handle.
- *
- * Result:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIHashTable_HoldEntry(VMCIHashTable *table, // IN
- VMCIHashEntry *entry) // IN/OUT
-{
- VMCILockFlags flags;
-
- ASSERT(table);
- ASSERT(entry);
-
- VMCI_GrabLock_BH(&table->lock, &flags);
- entry->refCount++;
- VMCI_ReleaseLock_BH(&table->lock, flags);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTableReleaseEntryLocked --
- *
- * Releases an element previously obtained with
- * VMCIHashTableGetEntryLocked.
- *
- * Result:
- * If the entry is removed from the hash table, VMCI_SUCCESS_ENTRY_DEAD
- * is returned. Otherwise, VMCI_SUCCESS is returned.
- *
- * Side effects:
- * The reference count of the entry is decreased and the entry is removed
- * from the hash table on 0.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-VMCIHashTableReleaseEntryLocked(VMCIHashTable *table, // IN
- VMCIHashEntry *entry) // IN
-{
- int result = VMCI_SUCCESS;
-
- ASSERT(table);
- ASSERT(entry);
-
- entry->refCount--;
- /* Check if this is last reference and report if so. */
- if (entry->refCount == 0) {
-
- /*
- * Remove entry from hash table if not already removed. This could have
- * happened already because VMCIHashTable_RemoveEntry was called to unlink
- * it. We ignore if it is not found. Datagram handles will often have
- * RemoveEntry called, whereas SharedMemory regions rely on ReleaseEntry
- * to unlink the entry, since the creator does not call RemoveEntry when
- * it detaches.
- */
-
- HashTableUnlinkEntry(table, entry);
- result = VMCI_SUCCESS_ENTRY_DEAD;
- }
-
- return result;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTable_ReleaseEntry --
- * XXX Factor out the hashtable code to shared amongst API and perhaps
- * host and guest.
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIHashTable_ReleaseEntry(VMCIHashTable *table, // IN
- VMCIHashEntry *entry) // IN
-{
- VMCILockFlags flags;
- int result;
-
- ASSERT(table);
- VMCI_GrabLock_BH(&table->lock, &flags);
- result = VMCIHashTableReleaseEntryLocked(table, entry);
- VMCI_ReleaseLock_BH(&table->lock, flags);
-
- return result;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTable_EntryExists --
- * XXX Factor out the hashtable code to shared amongst API and perhaps
- * host and guest.
- *
- * Result:
- * TRUE if handle already in hashtable. FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-Bool
-VMCIHashTable_EntryExists(VMCIHashTable *table, // IN
- VMCIHandle handle) // IN
-{
- Bool exists;
- VMCILockFlags flags;
-
- ASSERT(table);
-
- VMCI_GrabLock_BH(&table->lock, &flags);
- exists = VMCIHashTableEntryExistsLocked(table, handle);
- VMCI_ReleaseLock_BH(&table->lock, flags);
-
- return exists;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIHashTableEntryExistsLocked --
- *
- * Unlocked version of VMCIHashTable_EntryExists.
- *
- * Result:
- * TRUE if handle already in hashtable. FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static Bool
-VMCIHashTableEntryExistsLocked(VMCIHashTable *table, // IN
- VMCIHandle handle) // IN
-
-{
- VMCIHashEntry *entry;
- int idx;
-
- ASSERT(table);
-
- idx = VMCI_HASHTABLE_HASH(handle, table->size);
-
- entry = table->entries[idx];
- while (entry) {
- if (VMCI_HANDLE_TO_RESOURCE_ID(entry->handle) ==
- VMCI_HANDLE_TO_RESOURCE_ID(handle)) {
- if ((VMCI_HANDLE_TO_CONTEXT_ID(entry->handle) ==
- VMCI_HANDLE_TO_CONTEXT_ID(handle)) ||
- (VMCI_INVALID_ID == VMCI_HANDLE_TO_CONTEXT_ID(handle)) ||
- (VMCI_INVALID_ID == VMCI_HANDLE_TO_CONTEXT_ID(entry->handle))) {
- return TRUE;
- }
- }
- entry = entry->next;
- }
-
- return FALSE;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * HashTableUnlinkEntry --
- * XXX Factor out the hashtable code to shared amongst API and perhaps
- * host and guest.
- * Assumes caller holds table lock.
- *
- * Result:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static int
-HashTableUnlinkEntry(VMCIHashTable *table, // IN
- VMCIHashEntry *entry) // IN
-{
- int result;
- VMCIHashEntry *prev, *cur;
- int idx;
-
- idx = VMCI_HASHTABLE_HASH(entry->handle, table->size);
-
- prev = NULL;
- cur = table->entries[idx];
- while (TRUE) {
- if (cur == NULL) {
- result = VMCI_ERROR_NOT_FOUND;
- break;
- }
- if (VMCI_HANDLE_EQUAL(cur->handle, entry->handle)) {
- ASSERT(cur == entry);
-
- /* Remove entry and break. */
- if (prev) {
- prev->next = cur->next;
- } else {
- table->entries[idx] = cur->next;
- }
- cur->next = NULL;
- result = VMCI_SUCCESS;
- break;
- }
- prev = cur;
- cur = cur->next;
- }
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHashTable_Sync --
- *
- * Use this as a synchronization point when setting globals, for example,
- * during device shutdown.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIHashTable_Sync(VMCIHashTable *table)
-{
- VMCILockFlags flags;
- ASSERT(table);
- VMCI_GrabLock_BH(&table->lock, &flags);
- VMCI_ReleaseLock_BH(&table->lock, flags);
-}
diff --git a/modules/linux/vmci/common/vmciHashtable.h b/modules/linux/vmci/common/vmciHashtable.h
deleted file mode 100644
index a786818..0000000
--- a/modules/linux/vmci/common/vmciHashtable.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*********************************************************
- * 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
- * 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
- *
- *********************************************************/
-
-/*
- * vmciHashtable.h --
- *
- * Hash table for use in the APIs.
- */
-
-#ifndef _VMCI_HASHTABLE_H_
-#define _VMCI_HASHTABLE_H_
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMMON
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_kernel_if.h"
-#include "vmci_defs.h"
-
-typedef struct VMCIHashEntry {
- VMCIHandle handle;
- int refCount;
- struct VMCIHashEntry *next;
-} VMCIHashEntry;
-
-typedef struct VMCIHashTable {
- VMCIHashEntry **entries;
- int size; // Number of buckets in above array.
- VMCILock lock;
-} VMCIHashTable;
-
-VMCIHashTable *VMCIHashTable_Create(int size);
-void VMCIHashTable_Destroy(VMCIHashTable *table);
-void VMCIHashTable_InitEntry(VMCIHashEntry *entry, VMCIHandle handle);
-int VMCIHashTable_AddEntry(VMCIHashTable *table, VMCIHashEntry *entry);
-int VMCIHashTable_RemoveEntry(VMCIHashTable *table, VMCIHashEntry *entry);
-VMCIHashEntry *VMCIHashTable_GetEntry(VMCIHashTable *table, VMCIHandle handle);
-void VMCIHashTable_HoldEntry(VMCIHashTable *table, VMCIHashEntry *entry);
-int VMCIHashTable_ReleaseEntry(VMCIHashTable *table, VMCIHashEntry *entry);
-Bool VMCIHashTable_EntryExists(VMCIHashTable *table, VMCIHandle handle);
-void VMCIHashTable_Sync(VMCIHashTable *table);
-
-#endif // _VMCI_HASHTABLE_H_
diff --git a/modules/linux/vmci/common/vmciQPair.c b/modules/linux/vmci/common/vmciQPair.c
deleted file mode 100644
index 5c5253f..0000000
--- a/modules/linux/vmci/common/vmciQPair.c
+++ /dev/null
@@ -1,1424 +0,0 @@
-/*********************************************************
- * Copyright (C) 2010-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
- *
- *********************************************************/
-
-/*
- * vmciQPair.c --
- *
- * This file implements Queue accessor methods.
- *
- * VMCIQPair is a new interface that hides the queue pair internals.
- * Rather than access each queue in a pair directly, operations are now
- * performed on the queue as a whole. This is simpler and less
- * error-prone, and allows for future queue pair features to be added
- * under the hood with no change to the client code.
- *
- * This also helps in a particular case on Windows hosts, where the memory
- * allocated by the client (e.g., VMX) will disappear when the client does
- * (e.g., abnormal termination). The kernel can't lock user memory into
- * its address space indefinitely. By guarding access to the queue
- * contents we can correctly handle the case where the client disappears.
- *
- * On code style:
- *
- * + This entire file started its life as a cut-and-paste of the
- * static INLINE functions in bora/public/vmci_queue_pair.h.
- * From there, new copies of the routines were made named
- * without the prefix VMCI, without the underscore (the one
- * that followed VMCIQueue_). The no-underscore versions of
- * the routines require that the mutexes are held.
- *
- * + The code -always- uses the xyzLocked() version of any given
- * routine even when the wrapped function is a one-liner. The
- * reason for this decision was to ensure that we didn't have
- * copies of logic lying around that needed to be maintained.
- *
- * + Note that we still pass around 'const VMCIQueue *'s.
- *
- * + Note that mutex is a field within VMCIQueue. We skirt the
- * issue of passing around a const VMCIQueue, even though the
- * mutex field (__mutex, specifically) will get modified by not
- * ever referring to the mutex -itself- except during
- * initialization. Beyond that, the code only passes the
- * pointer to the mutex, which is also a member of VMCIQueue,
- * obviously, and which doesn't change after initialization.
- * This eliminates having to redefine all the functions that
- * are currently taking const VMCIQueue's so that these
- * functions are compatible with those definitions.
- */
-
-#include "vmci_kernel_if.h"
-#include "vm_assert.h"
-#include "vmci_handle_array.h"
-#include "vmci_defs.h"
-#include "vmciKernelAPI.h"
-#include "vmciQueue.h"
-#include "vmciQueuePair.h"
-#include "vmciRoute.h"
-
-
-/*
- * VMCIQPair
- *
- * This structure is opaque to the clients.
- */
-
-struct VMCIQPair {
- VMCIHandle handle;
- VMCIQueue *produceQ;
- VMCIQueue *consumeQ;
- uint64 produceQSize;
- uint64 consumeQSize;
- VMCIId peer;
- uint32 flags;
- VMCIPrivilegeFlags privFlags;
- Bool guestEndpoint;
- uint32 blocked;
- VMCIEvent event;
-};
-
-static int VMCIQPairMapQueueHeaders(VMCIQueue *produceQ, VMCIQueue *consumeQ,
- Bool canBlock);
-static int VMCIQPairGetQueueHeaders(const VMCIQPair *qpair,
- VMCIQueueHeader **produceQHeader,
- VMCIQueueHeader **consumeQHeader);
-static int VMCIQPairWakeupCB(void *clientData);
-static int VMCIQPairReleaseMutexCB(void *clientData);
-static Bool VMCIQPairWaitForReadyQueue(VMCIQPair *qpair);
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPairLock --
- *
- * Helper routine that will lock the QPair before subsequent operations.
- *
- * Results:
- * VMCI_SUCCESS if lock acquired. VMCI_ERROR_WOULD_BLOCK if queue mutex
- * couldn't be acquired and qpair isn't allowed to block.
- *
- * Side effects:
- * May block.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE int
-VMCIQPairLock(const VMCIQPair *qpair) // IN
-{
-#if !defined VMX86_VMX
- if (qpair->flags & VMCI_QPFLAG_PINNED) {
- VMCI_LockQueueHeader(qpair->produceQ);
- return VMCI_SUCCESS;
- }
- return VMCI_AcquireQueueMutex(qpair->produceQ,
- !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
-#else
- return VMCI_SUCCESS
-#endif
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPairUnlock --
- *
- * Helper routine that will unlock the QPair after various operations.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIQPairUnlock(const VMCIQPair *qpair) // IN
-{
-#if !defined VMX86_VMX
- if (qpair->flags & VMCI_QPFLAG_PINNED) {
- VMCI_UnlockQueueHeader(qpair->produceQ);
- } else {
- VMCI_ReleaseQueueMutex(qpair->produceQ);
- }
-#endif
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPairHeaderLock --
- *
- * Helper routine that will lock the queue pair header before subsequent
- * operations. If the queue pair is non blocking, a spinlock will be used.
- * Otherwise, a regular mutex locking the complete queue pair will be used.
- *
- * Results:
- * None.
- *
- * Side effects:
- * May block.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIQPairLockHeader(const VMCIQPair *qpair) // IN
-{
-#if !defined VMX86_VMX
- if (qpair->flags & VMCI_QPFLAG_NONBLOCK) {
- VMCI_LockQueueHeader(qpair->produceQ);
- } else {
- (void)VMCI_AcquireQueueMutex(qpair->produceQ,
- !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
- }
-#endif
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPairUnlockHeader --
- *
- * Helper routine that unlocks the queue pair header after calling
- * VMCIQPairHeaderLock.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIQPairUnlockHeader(const VMCIQPair *qpair) // IN
-{
-#if !defined VMX86_VMX
- if (qpair->flags & VMCI_QPFLAG_NONBLOCK) {
- VMCI_UnlockQueueHeader(qpair->produceQ);
- } else {
- VMCI_ReleaseQueueMutex(qpair->produceQ);
- }
-#endif
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPairGetQueueHeaders --
- *
- * Helper routine that will retrieve the produce and consume
- * headers of a given queue pair. If the guest memory of the
- * queue pair is currently not available, the saved queue headers
- * will be returned, if these are available.
- *
- * Results:
- * VMCI_SUCCESS if either current or saved queue headers are found.
- * Appropriate error code otherwise.
- *
- * Side effects:
- * May block.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQPairGetQueueHeaders(const VMCIQPair *qpair, // IN
- VMCIQueueHeader **produceQHeader, // OUT
- VMCIQueueHeader **consumeQHeader) // OUT
-{
- int result;
-
- result = VMCIQPairMapQueueHeaders(qpair->produceQ, qpair->consumeQ,
- !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
- if (result == VMCI_SUCCESS) {
- *produceQHeader = qpair->produceQ->qHeader;
- *consumeQHeader = qpair->consumeQ->qHeader;
- } else if (qpair->produceQ->savedHeader && qpair->consumeQ->savedHeader) {
- ASSERT(!qpair->guestEndpoint);
- *produceQHeader = qpair->produceQ->savedHeader;
- *consumeQHeader = qpair->consumeQ->savedHeader;
- result = VMCI_SUCCESS;
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPairMapQueueHeaders --
- *
- * The queue headers may not be mapped at all times. If a queue is
- * currently not mapped, it will be attempted to do so.
- *
- * Results:
- * VMCI_SUCCESS if queues were validated, appropriate error code otherwise.
- *
- * Side effects:
- * May attempt to map in guest memory.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQPairMapQueueHeaders(VMCIQueue *produceQ, // IN
- VMCIQueue *consumeQ, // IN
- Bool canBlock) // IN
-{
- int result;
-
- if (NULL == produceQ->qHeader || NULL == consumeQ->qHeader) {
- if (canBlock) {
- /*
- * We return data from creator of the queue in VM2VM case.
- * That should be OK, as if they do not match then there
- * is somebody else in progress of making them match, and
- * you should not be looking at somebody else's queue if
- * queue is active.
- */
- result = VMCIHost_MapQueues(0, produceQ, consumeQ, 0);
- } else {
- result = VMCI_ERROR_QUEUEPAIR_NOT_READY;
- }
- if (result < VMCI_SUCCESS) {
- if (produceQ->savedHeader && consumeQ->savedHeader) {
- return VMCI_ERROR_QUEUEPAIR_NOT_READY;
- } else {
- return VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
- }
- }
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPairWakeupCB --
- *
- * Callback from VMCI queue pair broker indicating that a queue
- * pair that was previously not ready, now either is ready or
- * gone forever.
- *
- * Results:
- * VMCI_SUCCESS always.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQPairWakeupCB(void *clientData)
-{
- VMCIQPair *qpair = (VMCIQPair *)clientData;
- ASSERT(qpair);
-
- VMCIQPairLock(qpair);
- while (qpair->blocked > 0) {
- qpair->blocked--;
- VMCI_SignalEvent(&qpair->event);
- }
- VMCIQPairUnlock(qpair);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPairReleaseMutexCB --
- *
- * Callback from VMCI_WaitOnEvent releasing the queue pair mutex
- * protecting the queue pair header state.
- *
- * Results:
- * 0 always.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQPairReleaseMutexCB(void *clientData)
-{
- VMCIQPair *qpair = (VMCIQPair *)clientData;
- ASSERT(qpair);
- VMCIQPairUnlock(qpair);
- return 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPairWaitForReadyQueue --
- *
- * Makes the calling thread wait for the queue pair to become
- * ready for host side access.
- *
- * Results:
- * TRUE when thread is woken up after queue pair state change.
- * FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-VMCIQPairWaitForReadyQueue(VMCIQPair *qpair)
-{
- if (UNLIKELY(qpair->guestEndpoint)) {
- ASSERT(FALSE);
- return FALSE;
- }
- if (qpair->flags & VMCI_QPFLAG_NONBLOCK) {
- return FALSE;
- }
- qpair->blocked++;
- VMCI_WaitOnEvent(&qpair->event, VMCIQPairReleaseMutexCB, qpair);
- VMCIQPairLock(qpair);
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_alloc --
- *
- * This is the client interface for allocating the memory for a
- * VMCIQPair structure and then attaching to the underlying
- * queue. If an error occurs allocating the memory for the
- * VMCIQPair structure, no attempt is made to attach. If an
- * error occurs attaching, then there's the VMCIQPair structure
- * is freed.
- *
- * Results:
- * An err, if < 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_alloc)
-int
-vmci_qpair_alloc(VMCIQPair **qpair, // OUT
- VMCIHandle *handle, // OUT
- uint64 produceQSize, // IN
- uint64 consumeQSize, // IN
- VMCIId peer, // IN
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags) // IN
-{
- VMCIQPair *myQPair;
- int retval;
- VMCIHandle src = VMCI_INVALID_HANDLE;
- VMCIHandle dst = VMCI_MAKE_HANDLE(peer, VMCI_INVALID_ID);
- VMCIRoute route;
- VMCIEventReleaseCB wakeupCB;
- void *clientData;
-
- /*
- * Restrict the size of a queuepair. The device already enforces a limit
- * on the total amount of memory that can be allocated to queuepairs for a
- * guest. However, we try to allocate this memory before we make the
- * queuepair allocation hypercall. On Windows and Mac OS, we request a
- * single, continguous block, and it will fail if the OS cannot satisfy the
- * request. On Linux, we allocate each page separately, which means rather
- * than fail, the guest will thrash while it tries to allocate, and will
- * become increasingly unresponsive to the point where it appears to be hung.
- * So we place a limit on the size of an individual queuepair here, and
- * leave the device to enforce the restriction on total queuepair memory.
- * (Note that this doesn't prevent all cases; a user with only this much
- * physical memory could still get into trouble.) The error used by the
- * device is NO_RESOURCES, so use that here too.
- */
-
- if (produceQSize + consumeQSize < MAX(produceQSize, consumeQSize) ||
- produceQSize + consumeQSize > VMCI_MAX_GUEST_QP_MEMORY) {
- return VMCI_ERROR_NO_RESOURCES;
- }
-
- retval = VMCI_Route(&src, &dst, FALSE, &route);
- if (retval < VMCI_SUCCESS) {
- if (VMCI_GuestPersonalityActive()) {
- route = VMCI_ROUTE_AS_GUEST;
- } else {
- route = VMCI_ROUTE_AS_HOST;
- }
- }
-
- if ((flags & (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED)) && !vmkernel) {
-#if defined(linux)
- if (VMCI_ROUTE_AS_GUEST != route)
-#endif // linux
- {
- return VMCI_ERROR_INVALID_ARGS;
- }
- }
-
- if (flags & VMCI_QPFLAG_PINNED) {
- /*
- * Pinned pages implies non-blocking mode. Technically it doesn't
- * have to, but there doesn't seem much point in pinning the pages if you
- * can block since the queues will be small, so there's no performance
- * gain to be had.
- */
-
- if (!(flags & VMCI_QPFLAG_NONBLOCK)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- /* Limit the amount of memory that can be pinned. */
-
- if (produceQSize + consumeQSize > VMCI_MAX_PINNED_QP_MEMORY) {
- return VMCI_ERROR_NO_RESOURCES;
- }
- }
-
- myQPair = VMCI_AllocKernelMem(sizeof *myQPair, VMCI_MEMORY_NONPAGED);
- if (!myQPair) {
- return VMCI_ERROR_NO_MEM;
- }
-
- myQPair->produceQSize = produceQSize;
- myQPair->consumeQSize = consumeQSize;
- myQPair->peer = peer;
- myQPair->flags = flags;
- myQPair->privFlags = privFlags;
-
- wakeupCB = clientData = NULL;
- if (VMCI_ROUTE_AS_HOST == route) {
- myQPair->guestEndpoint = FALSE;
- if (!(flags & VMCI_QPFLAG_LOCAL)) {
- myQPair->blocked = 0;
- VMCI_CreateEvent(&myQPair->event);
- wakeupCB = VMCIQPairWakeupCB;
- clientData = (void *)myQPair;
- }
- } else {
- myQPair->guestEndpoint = TRUE;
- }
-
- retval = VMCIQueuePair_Alloc(handle,
- &myQPair->produceQ,
- myQPair->produceQSize,
- &myQPair->consumeQ,
- myQPair->consumeQSize,
- myQPair->peer,
- myQPair->flags,
- myQPair->privFlags,
- myQPair->guestEndpoint,
- wakeupCB,
- clientData);
-
- if (retval < VMCI_SUCCESS) {
- if (VMCI_ROUTE_AS_HOST == route && !(flags & VMCI_QPFLAG_LOCAL)) {
- VMCI_DestroyEvent(&myQPair->event);
- }
- VMCI_FreeKernelMem(myQPair, sizeof *myQPair);
- return retval;
- }
-
- *qpair = myQPair;
- myQPair->handle = *handle;
-
- return retval;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_detach --
- *
- * This is the client interface for detaching from a VMCIQPair.
- * Note that this routine will free the memory allocated for the
- * VMCIQPair structure, too.
- *
- * Results:
- * An error, if < 0.
- *
- * Side effects:
- * Will clear the caller's pointer to the VMCIQPair structure.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_detach)
-int
-vmci_qpair_detach(VMCIQPair **qpair) // IN/OUT
-{
- int result;
- VMCIQPair *oldQPair;
-
- if (!qpair || !(*qpair)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- oldQPair = *qpair;
- result = VMCIQueuePair_Detach(oldQPair->handle, oldQPair->guestEndpoint);
-
- /*
- * The guest can fail to detach for a number of reasons, and if it does so,
- * it will cleanup the entry (if there is one). The host can fail too, but
- * it won't cleanup the entry immediately, it will do that later when the
- * context is freed. Either way, we need to release the qpair struct here;
- * there isn't much the caller can do, and we don't want to leak.
- */
-
- if (!(oldQPair->guestEndpoint || (oldQPair->flags & VMCI_QPFLAG_LOCAL))) {
- VMCI_DestroyEvent(&oldQPair->event);
- }
- VMCI_FreeKernelMem(oldQPair, sizeof *oldQPair);
- *qpair = NULL;
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_get_produce_indexes --
- *
- * This is the client interface for getting the current indexes of the
- * QPair from the point of the view of the caller as the producer.
- *
- * Results:
- * err, if < 0
- * Success otherwise.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_get_produce_indexes)
-int
-vmci_qpair_get_produce_indexes(const VMCIQPair *qpair, // IN
- uint64 *producerTail, // OUT
- uint64 *consumerHead) // OUT
-{
- VMCIQueueHeader *produceQHeader;
- VMCIQueueHeader *consumeQHeader;
- int result;
-
- if (!qpair) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPairLockHeader(qpair);
- result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
- if (result == VMCI_SUCCESS) {
- VMCIQueueHeader_GetPointers(produceQHeader, consumeQHeader,
- producerTail, consumerHead);
- }
- VMCIQPairUnlockHeader(qpair);
-
- if (result == VMCI_SUCCESS &&
- ((producerTail && *producerTail >= qpair->produceQSize) ||
- (consumerHead && *consumerHead >= qpair->produceQSize))) {
- return VMCI_ERROR_INVALID_SIZE;
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_get_consume_indexes --
- *
- * This is the client interface for getting the current indexes of the
- * QPair from the point of the view of the caller as the consumer.
- *
- * Results:
- * err, if < 0
- * Success otherwise.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_get_consume_indexes)
-int
-vmci_qpair_get_consume_indexes(const VMCIQPair *qpair, // IN
- uint64 *consumerTail, // OUT
- uint64 *producerHead) // OUT
-{
- VMCIQueueHeader *produceQHeader;
- VMCIQueueHeader *consumeQHeader;
- int result;
-
- if (!qpair) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPairLockHeader(qpair);
- result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
- if (result == VMCI_SUCCESS) {
- VMCIQueueHeader_GetPointers(consumeQHeader, produceQHeader,
- consumerTail, producerHead);
- }
- VMCIQPairUnlockHeader(qpair);
-
- if (result == VMCI_SUCCESS &&
- ((consumerTail && *consumerTail >= qpair->consumeQSize) ||
- (producerHead && *producerHead >= qpair->consumeQSize))) {
- return VMCI_ERROR_INVALID_SIZE;
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_produce_free_space --
- *
- * This is the client interface for getting the amount of free
- * space in the QPair from the point of the view of the caller as
- * the producer which is the common case.
- *
- * Results:
- * Err, if < 0.
- * Full queue if = 0.
- * Number of available bytes into which data can be enqueued if > 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_produce_free_space)
-int64
-vmci_qpair_produce_free_space(const VMCIQPair *qpair) // IN
-{
- VMCIQueueHeader *produceQHeader;
- VMCIQueueHeader *consumeQHeader;
- int64 result;
-
- if (!qpair) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPairLockHeader(qpair);
- result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
- if (result == VMCI_SUCCESS) {
- result = VMCIQueueHeader_FreeSpace(produceQHeader, consumeQHeader,
- qpair->produceQSize);
- } else {
- result = 0;
- }
- VMCIQPairUnlockHeader(qpair);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_consume_free_space --
- *
- * This is the client interface for getting the amount of free
- * space in the QPair from the point of the view of the caller as
- * the consumer which is not the common case (see
- * VMCIQPair_ProduceFreeSpace(), above).
- *
- * Results:
- * Err, if < 0.
- * Full queue if = 0.
- * Number of available bytes into which data can be enqueued if > 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_consume_free_space)
-int64
-vmci_qpair_consume_free_space(const VMCIQPair *qpair) // IN
-{
- VMCIQueueHeader *produceQHeader;
- VMCIQueueHeader *consumeQHeader;
- int64 result;
-
- if (!qpair) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPairLockHeader(qpair);
- result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
- if (result == VMCI_SUCCESS) {
- result = VMCIQueueHeader_FreeSpace(consumeQHeader, produceQHeader,
- qpair->consumeQSize);
- } else {
- result = 0;
- }
- VMCIQPairUnlockHeader(qpair);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_produce_buf_ready --
- *
- * This is the client interface for getting the amount of
- * enqueued data in the QPair from the point of the view of the
- * caller as the producer which is not the common case (see
- * VMCIQPair_ConsumeBufReady(), above).
- *
- * Results:
- * Err, if < 0.
- * Empty queue if = 0.
- * Number of bytes ready to be dequeued if > 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_produce_buf_ready)
-int64
-vmci_qpair_produce_buf_ready(const VMCIQPair *qpair) // IN
-{
- VMCIQueueHeader *produceQHeader;
- VMCIQueueHeader *consumeQHeader;
- int64 result;
-
- if (!qpair) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPairLockHeader(qpair);
- result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
- if (result == VMCI_SUCCESS) {
- result = VMCIQueueHeader_BufReady(produceQHeader, consumeQHeader,
- qpair->produceQSize);
- } else {
- result = 0;
- }
- VMCIQPairUnlockHeader(qpair);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_consume_buf_ready --
- *
- * This is the client interface for getting the amount of
- * enqueued data in the QPair from the point of the view of the
- * caller as the consumer which is the normal case.
- *
- * Results:
- * Err, if < 0.
- * Empty queue if = 0.
- * Number of bytes ready to be dequeued if > 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_consume_buf_ready)
-int64
-vmci_qpair_consume_buf_ready(const VMCIQPair *qpair) // IN
-{
- VMCIQueueHeader *produceQHeader;
- VMCIQueueHeader *consumeQHeader;
- int64 result;
-
- if (!qpair) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPairLockHeader(qpair);
- result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
- if (result == VMCI_SUCCESS) {
- result = VMCIQueueHeader_BufReady(consumeQHeader, produceQHeader,
- qpair->consumeQSize);
- } else {
- result = 0;
- }
- VMCIQPairUnlockHeader(qpair);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * EnqueueLocked --
- *
- * Enqueues a given buffer to the produce queue using the provided
- * function. As many bytes as possible (space available in the queue)
- * are enqueued.
- *
- * Assumes the queue->mutex has been acquired.
- *
- * Results:
- * VMCI_ERROR_QUEUEPAIR_NOSPACE if no space was available to enqueue data.
- * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
- * (as defined by the queue size).
- * VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer.
- * VMCI_ERROR_QUEUEPAIR_NOTATTACHED, if the queue pair pages aren't
- * available.
- * Otherwise, the number of bytes written to the queue is returned.
- *
- * Side effects:
- * Updates the tail pointer of the produce queue.
- *
- *-----------------------------------------------------------------------------
- */
-
-static ssize_t
-EnqueueLocked(VMCIQueue *produceQ, // IN
- VMCIQueue *consumeQ, // IN
- const uint64 produceQSize, // IN
- const void *buf, // IN
- size_t bufSize, // IN
- int bufType, // IN
- VMCIMemcpyToQueueFunc memcpyToQueue, // IN
- Bool canBlock) // IN
-{
- int64 freeSpace;
- uint64 tail;
- size_t written;
- ssize_t result;
-
-#if !defined VMX86_VMX
- if (UNLIKELY(VMCI_EnqueueToDevNull(produceQ))) {
- return (ssize_t) bufSize;
- }
-
- result = VMCIQPairMapQueueHeaders(produceQ, consumeQ, canBlock);
- if (UNLIKELY(result != VMCI_SUCCESS)) {
- return result;
- }
-#endif
-
- freeSpace = VMCIQueueHeader_FreeSpace(produceQ->qHeader,
- consumeQ->qHeader,
- produceQSize);
- if (freeSpace == 0) {
- return VMCI_ERROR_QUEUEPAIR_NOSPACE;
- }
-
- if (freeSpace < VMCI_SUCCESS) {
- return (ssize_t)freeSpace;
- }
-
- written = (size_t)(freeSpace > bufSize ? bufSize : freeSpace);
- tail = VMCIQueueHeader_ProducerTail(produceQ->qHeader);
- if (LIKELY(tail + written < produceQSize)) {
- result = memcpyToQueue(produceQ, tail, buf, 0, written, bufType,
- canBlock);
- } else {
- /* Tail pointer wraps around. */
-
- const size_t tmp = (size_t)(produceQSize - tail);
-
- result = memcpyToQueue(produceQ, tail, buf, 0, tmp, bufType, canBlock);
- if (result >= VMCI_SUCCESS) {
- result = memcpyToQueue(produceQ, 0, buf, tmp, written - tmp, bufType,
- canBlock);
- }
- }
-
- if (result < VMCI_SUCCESS) {
- return result;
- }
-
- VMCIQueueHeader_AddProducerTail(produceQ->qHeader, written, produceQSize);
- return written;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DequeueLocked --
- *
- * Dequeues data (if available) from the given consume queue. Writes data
- * to the user provided buffer using the provided function.
- *
- * Assumes the queue->mutex has been acquired.
- *
- * Results:
- * VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
- * VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
- * (as defined by the queue size).
- * VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer.
- * Otherwise the number of bytes dequeued is returned.
- *
- * Side effects:
- * Updates the head pointer of the consume queue.
- *
- *-----------------------------------------------------------------------------
- */
-
-static ssize_t
-DequeueLocked(VMCIQueue *produceQ, // IN
- VMCIQueue *consumeQ, // IN
- const uint64 consumeQSize, // IN
- void *buf, // IN
- size_t bufSize, // IN
- int bufType, // IN
- VMCIMemcpyFromQueueFunc memcpyFromQueue, // IN
- Bool updateConsumer, // IN
- Bool canBlock) // IN
-{
- int64 bufReady;
- uint64 head;
- size_t read;
- ssize_t result;
-
-#if !defined VMX86_VMX
- result = VMCIQPairMapQueueHeaders(produceQ, consumeQ, canBlock);
- if (UNLIKELY(result != VMCI_SUCCESS)) {
- return result;
- }
-#endif
-
- bufReady = VMCIQueueHeader_BufReady(consumeQ->qHeader,
- produceQ->qHeader,
- consumeQSize);
- if (bufReady == 0) {
- return VMCI_ERROR_QUEUEPAIR_NODATA;
- }
- if (bufReady < VMCI_SUCCESS) {
- return (ssize_t)bufReady;
- }
-
- read = (size_t)(bufReady > bufSize ? bufSize : bufReady);
- head = VMCIQueueHeader_ConsumerHead(produceQ->qHeader);
- if (LIKELY(head + read < consumeQSize)) {
- result = memcpyFromQueue(buf, 0, consumeQ, head, read, bufType, canBlock);
- } else {
- /* Head pointer wraps around. */
-
- const size_t tmp = (size_t)(consumeQSize - head);
-
- result = memcpyFromQueue(buf, 0, consumeQ, head, tmp, bufType, canBlock);
- if (result >= VMCI_SUCCESS) {
- result = memcpyFromQueue(buf, tmp, consumeQ, 0, read - tmp, bufType,
- canBlock);
- }
- }
-
- if (result < VMCI_SUCCESS) {
- return result;
- }
-
- if (updateConsumer) {
- VMCIQueueHeader_AddConsumerHead(produceQ->qHeader,
- read,
- consumeQSize);
- }
-
- return read;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_enqueue --
- *
- * This is the client interface for enqueueing data into the queue.
- *
- * Results:
- * Err, if < 0.
- * Number of bytes enqueued if >= 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_enqueue)
-ssize_t
-vmci_qpair_enqueue(VMCIQPair *qpair, // IN
- const void *buf, // IN
- size_t bufSize, // IN
- int bufType) // IN
-{
- ssize_t result;
-
- if (!qpair || !buf) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- result = VMCIQPairLock(qpair);
- if (result != VMCI_SUCCESS) {
- return result;
- }
-
- do {
- result = EnqueueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->produceQSize,
- buf, bufSize, bufType,
- qpair->flags & VMCI_QPFLAG_LOCAL?
- VMCIMemcpyToQueueLocal:
- VMCIMemcpyToQueue,
- !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
- if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
- if (!VMCIQPairWaitForReadyQueue(qpair)) {
- result = VMCI_ERROR_WOULD_BLOCK;
- }
- }
- } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
-
- VMCIQPairUnlock(qpair);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_dequeue --
- *
- * This is the client interface for dequeueing data from the queue.
- *
- * Results:
- * Err, if < 0.
- * Number of bytes dequeued if >= 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_dequeue)
-ssize_t
-vmci_qpair_dequeue(VMCIQPair *qpair, // IN
- void *buf, // IN
- size_t bufSize, // IN
- int bufType) // IN
-{
- ssize_t result;
-
- if (!qpair || !buf) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- result = VMCIQPairLock(qpair);
- if (result != VMCI_SUCCESS) {
- return result;
- }
-
- do {
- result = DequeueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->consumeQSize,
- buf, bufSize, bufType,
- qpair->flags & VMCI_QPFLAG_LOCAL?
- VMCIMemcpyFromQueueLocal:
- VMCIMemcpyFromQueue,
- TRUE, !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
- if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
- if (!VMCIQPairWaitForReadyQueue(qpair)) {
- result = VMCI_ERROR_WOULD_BLOCK;
- }
- }
- } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
-
- VMCIQPairUnlock(qpair);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_peek --
- *
- * This is the client interface for peeking into a queue. (I.e.,
- * copy data from the queue without updating the head pointer.)
- *
- * Results:
- * Err, if < 0.
- * Number of bytes peeked, if >= 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_peek)
-ssize_t
-vmci_qpair_peek(VMCIQPair *qpair, // IN
- void *buf, // IN
- size_t bufSize, // IN
- int bufType) // IN
-{
- ssize_t result;
-
- if (!qpair || !buf) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- result = VMCIQPairLock(qpair);
- if (result != VMCI_SUCCESS) {
- return result;
- }
-
- do {
- result = DequeueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->consumeQSize,
- buf, bufSize, bufType,
- qpair->flags & VMCI_QPFLAG_LOCAL?
- VMCIMemcpyFromQueueLocal:
- VMCIMemcpyFromQueue,
- FALSE, !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
- if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
- if (!VMCIQPairWaitForReadyQueue(qpair)) {
- result = VMCI_ERROR_WOULD_BLOCK;
- }
- }
- } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
-
- VMCIQPairUnlock(qpair);
-
- return result;
-}
-
-
-#if defined (SOLARIS) || (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \
- (defined(__linux__) && defined(__KERNEL__)) || \
- (defined(_WIN32) && defined(WINNT_DDK))
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_enquev --
- *
- * This is the client interface for enqueueing data into the queue.
- *
- * Results:
- * Err, if < 0.
- * Number of bytes enqueued if >= 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_enquev)
-ssize_t
-vmci_qpair_enquev(VMCIQPair *qpair, // IN
- void *iov, // IN
- size_t iovSize, // IN
- int bufType) // IN
-{
- ssize_t result;
-
- if (!qpair || !iov) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- result = VMCIQPairLock(qpair);
- if (result != VMCI_SUCCESS) {
- return result;
- }
-
- do {
- result = EnqueueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->produceQSize,
- iov, iovSize, bufType,
- qpair->flags & VMCI_QPFLAG_LOCAL?
- VMCIMemcpyToQueueVLocal:
- VMCIMemcpyToQueueV,
- !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
- if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
- if (!VMCIQPairWaitForReadyQueue(qpair)) {
- result = VMCI_ERROR_WOULD_BLOCK;
- }
- }
- } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
-
- VMCIQPairUnlock(qpair);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_dequev --
- *
- * This is the client interface for dequeueing data from the queue.
- *
- * Results:
- * Err, if < 0.
- * Number of bytes dequeued if >= 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_dequev)
-ssize_t
-vmci_qpair_dequev(VMCIQPair *qpair, // IN
- void *iov, // IN
- size_t iovSize, // IN
- int bufType) // IN
-{
- ssize_t result;
-
- if (!qpair || !iov) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- result = VMCIQPairLock(qpair);
- if (result != VMCI_SUCCESS) {
- return result;
- }
-
- do {
- result = DequeueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->consumeQSize,
- iov, iovSize, bufType,
- qpair->flags & VMCI_QPFLAG_LOCAL?
- VMCIMemcpyFromQueueVLocal:
- VMCIMemcpyFromQueueV,
- TRUE, !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
- if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
- if (!VMCIQPairWaitForReadyQueue(qpair)) {
- result = VMCI_ERROR_WOULD_BLOCK;
- }
- }
- } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
-
- VMCIQPairUnlock(qpair);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_qpair_peekv --
- *
- * This is the client interface for peeking into a queue. (I.e.,
- * copy data from the queue without updating the head pointer.)
- *
- * Results:
- * Err, if < 0.
- * Number of bytes peeked, if >= 0.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCI_EXPORT_SYMBOL(vmci_qpair_peekv)
-ssize_t
-vmci_qpair_peekv(VMCIQPair *qpair, // IN
- void *iov, // IN
- size_t iovSize, // IN
- int bufType) // IN
-{
- ssize_t result;
-
- if (!qpair || !iov) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- result = VMCIQPairLock(qpair);
- if (result != VMCI_SUCCESS) {
- return result;
- }
-
- do {
- result = DequeueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->consumeQSize,
- iov, iovSize, bufType,
- qpair->flags & VMCI_QPFLAG_LOCAL?
- VMCIMemcpyFromQueueVLocal:
- VMCIMemcpyFromQueueV,
- FALSE, !(qpair->flags & VMCI_QPFLAG_NONBLOCK));
- if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
- if (!VMCIQPairWaitForReadyQueue(qpair)) {
- result = VMCI_ERROR_WOULD_BLOCK;
- }
- }
- } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
-
- VMCIQPairUnlock(qpair);
-
- return result;
-}
-
-#endif /* Systems that support struct iovec */
diff --git a/modules/linux/vmci/common/vmciQueuePair.c b/modules/linux/vmci/common/vmciQueuePair.c
deleted file mode 100644
index 921105a..0000000
--- a/modules/linux/vmci/common/vmciQueuePair.c
+++ /dev/null
@@ -1,3041 +0,0 @@
-/*********************************************************
- * Copyright (C) 2007-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
- * 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
- *
- *********************************************************/
-
-/*
- * vmciQueuePair.c --
- *
- * VMCI QueuePair API implementation in the host driver.
- */
-
-#include "vmci_kernel_if.h"
-#include "vm_assert.h"
-#include "vmci_defs.h"
-#include "vmci_handle_array.h"
-#include "vmci_infrastructure.h"
-#include "vmciCommonInt.h"
-#include "vmciContext.h"
-#include "vmciDatagram.h"
-#include "vmciDriver.h"
-#include "vmciEvent.h"
-#include "vmciHashtable.h"
-#include "vmciKernelAPI.h"
-#include "vmciQueuePair.h"
-#include "vmciResource.h"
-#include "vmciRoute.h"
-#if defined(VMKERNEL)
-# include "vmciVmkInt.h"
-# include "vm_libc.h"
-#endif
-
-#define LGPFX "VMCIQueuePair: "
-
-
-/*
- * In the following, we will distinguish between two kinds of VMX processes -
- * the ones with versions lower than VMCI_VERSION_NOVMVM that use specialized
- * VMCI page files in the VMX and supporting VM to VM communication) and the
- * newer ones that use the guest memory directly. We will in the following refer
- * to the older VMX versions as old-style VMX'en, and the newer ones as new-style
- * VMX'en.
- *
- * The state transition datagram is as follows (the VMCIQPB_ prefix has been
- * removed for readability) - see below for more details on the transtions:
- *
- * -------------- NEW -------------
- * | |
- * \_/ \_/
- * CREATED (nomem) <-----------------> CREATED
- * | | |
- * | o-----------------------o |
- * | | |
- * \_/ \_/ \_/
- * ATTACHED (nomem) <----------------> ATTACHED
- * | | |
- * | o----------------------o |
- * | | |
- * \_/ \_/ \_/
- * SHUTDOWN (nomem) <----------------> SHUTDOWN
- * | |
- * | |
- * -------------> gone <-------------
- *
- * In more detail. When a VMCI queue pair is first created, it will be in the
- * VMCIQPB_NEW state. It will then move into one of the following states:
- * - VMCIQPB_CREATED with hasMem[0] FALSE: this state indicates that either:
- * - the created was performed by a host endpoint, in which case there is no
- * backing memory yet.
- * - the create was initiated by an old-style VMX, that uses
- * VMCIQPBroker_SetPageStore to specify the UVAs of the queue pair at a
- * later point in time. This state can be distinguished from the one above
- * by the context ID of the creator. A host side is not allowed to attach
- * until the page store has been set.
- * - VMCIQPB_CREATED with hasMem[0] TRUE: this state is the result when the
- * queue pair is created by a VMX using the queue pair device backend that
- * sets the UVAs of the queue pair immediately and stores the information
- * for later attachers. At this point, it is ready for the host side to attach
- * to it.
- * Once the queue pair is in one of the created states (with the exception of the
- * case mentioned for older VMX'en above), it is possible to attach to the queue
- * pair. Again we have two new states possible:
- * - VMCIQPB_ATTACHED with hasMem[0] TRUE: this state can be reached through
- * the following paths:
- * - from VMCIQPB_CREATED without memory when a new-style VMX allocates a queue pair,
- * and attaches to a queue pair previously created by the host side.
- * - from VMCIQPB_CREATED with memory when the host side attaches to a queue pair
- * already created by a guest.
- * - from VMCIQPB_ATTACHED without memory, when an old-style VMX calls
- * VMCIQPBroker_SetPageStore (see below).
- * - VMCIQPB_ATTACHED with hasMem[0] FALSE: If the queue pair already was in the
- * VMCIQPB_CREATED without memory due to a host side create, an old-style VMX
- * will bring the queue pair into this state. Once VMCIQPBroker_SetPageStore is
- * called to register the user memory, the VMCIQPB_ATTACH with memory state will be
- * entered.
- * From the attached queue pair, the queue pair can enter the shutdown states
- * when either side of the queue pair detaches. If the guest side detaches first,
- * the queue pair will enter the VMCIQPB_SHUTDOWN without memory state, where the content
- * of the queue pair will no longer be available. If the host side detaches first,
- * the queue pair will either enter the VMCIQPB_SHUTDOWN with memory, if the guest memory
- * is currently mapped, or VMCIQPB_SHUTDOWN without memory, if the guest memory is not
- * mapped (e.g., the host detaches while a guest is stunned).
- *
- * New-style VMX'en will also unmap guest memory, if the guest is quiesced, e.g.,
- * during a snapshot operation. In that case, the guest memory will no longer be
- * available, and the queue pair will transition from memory to memory-less state.
- * The VMX may later map the memory once more, in which case the queue
- * pair will transition from the memory-less state at that point back to the memory
- * state.
- */
-
-typedef enum {
- VMCIQPB_NEW,
- VMCIQPB_CREATED,
- VMCIQPB_ATTACHED,
- VMCIQPB_SHUTDOWN,
- VMCIQPB_GONE
-} QPBrokerState;
-
-
-/*
- * In the queue pair broker, we always use the guest point of view for
- * the produce and consume queue values and references, e.g., the
- * produce queue size stored is the guests produce queue size. The
- * host endpoint will need to swap these around. The only exception is
- * the local queue pairs on the host, in which case the host endpoint
- * that creates the queue pair will have the right orientation, and
- * the attaching host endpoint will need to swap.
- */
-
-typedef struct QueuePairEntry {
- VMCIListItem listItem;
- VMCIHandle handle;
- VMCIId peer;
- uint32 flags;
- uint64 produceSize;
- uint64 consumeSize;
- uint32 refCount;
-} QueuePairEntry;
-
-typedef struct QPBrokerEntry {
- QueuePairEntry qp;
- VMCIId createId;
- VMCIId attachId;
- QPBrokerState stateQP;
- Bool hasMem[2];
- Bool requireTrustedAttach;
- Bool createdByTrusted;
- Bool vmciPageFiles; // Created by VMX using VMCI page files
- VMCIQueue *produceQ;
- VMCIQueue *consumeQ;
- VMCIQueueHeader savedProduceQ;
- VMCIQueueHeader savedConsumeQ;
- VMCIEventReleaseCB wakeupCB;
- void *clientData;
- void *localMem; // Kernel memory for local queue pair
- Bool isVM2VM;
-} QPBrokerEntry;
-
-#if !defined(VMKERNEL)
-typedef struct QPGuestEndpoint {
- QueuePairEntry qp;
- uint64 numPPNs;
- void *produceQ;
- void *consumeQ;
- Bool hibernateFailure;
- PPNSet ppnSet;
-} QPGuestEndpoint;
-#endif
-
-typedef struct QueuePairList {
- VMCIList head;
- Atomic_uint32 hibernate;
- VMCIMutex mutex;
-} QueuePairList;
-
-static QueuePairList qpBrokerList;
-
-#define QPE_NUM_PAGES(_QPE) ((uint32)(CEILING(_QPE.produceSize, PAGE_SIZE) + \
- CEILING(_QPE.consumeSize, PAGE_SIZE) + 2))
-
-#if !defined(VMKERNEL)
- static QueuePairList qpGuestEndpoints;
- static VMCIHandleArray *hibernateFailedList;
- static VMCILock hibernateFailedListLock;
-#endif
-
-static void VMCIQPBrokerLock(void);
-static void VMCIQPBrokerUnlock(void);
-
-static QueuePairEntry *QueuePairList_FindEntry(QueuePairList *qpList,
- VMCIHandle handle);
-static void QueuePairList_AddEntry(QueuePairList *qpList,
- QueuePairEntry *entry);
-static void QueuePairList_RemoveEntry(QueuePairList *qpList,
- QueuePairEntry *entry);
-static QueuePairEntry *QueuePairList_GetHead(QueuePairList *qpList);
-
-static int QueuePairNotifyPeer(Bool attach, VMCIHandle handle, VMCIId myId,
- VMCIId peerId);
-
-static int VMCIQPBrokerAllocInt(VMCIHandle handle, VMCIId peer,
- uint32 flags, VMCIPrivilegeFlags privFlags,
- uint64 produceSize,
- uint64 consumeSize,
- QueuePairPageStore *pageStore,
- VMCIContext *context,
- VMCIEventReleaseCB wakeupCB,
- void *clientData,
- QPBrokerEntry **ent,
- Bool *swap);
-static int VMCIQPBrokerAttach(QPBrokerEntry *entry,
- VMCIId peer,
- uint32 flags,
- VMCIPrivilegeFlags privFlags,
- uint64 produceSize,
- uint64 consumeSize,
- QueuePairPageStore *pageStore,
- VMCIContext *context,
- VMCIEventReleaseCB wakeupCB,
- void *clientData,
- QPBrokerEntry **ent);
-static int VMCIQPBrokerCreate(VMCIHandle handle,
- VMCIId peer,
- uint32 flags,
- VMCIPrivilegeFlags privFlags,
- uint64 produceSize,
- uint64 consumeSize,
- QueuePairPageStore *pageStore,
- VMCIContext *context,
- VMCIEventReleaseCB wakeupCB,
- void *clientData,
- QPBrokerEntry **ent);
-static int VMCIQueuePairAllocHostWork(VMCIHandle *handle, VMCIQueue **produceQ,
- uint64 produceSize, VMCIQueue **consumeQ,
- uint64 consumeSize,
- VMCIId peer, uint32 flags,
- VMCIPrivilegeFlags privFlags,
- VMCIEventReleaseCB wakeupCB,
- void *clientData);
-static int VMCIQueuePairDetachHostWork(VMCIHandle handle);
-
-static int QueuePairSaveHeaders(QPBrokerEntry *entry, VMCIId contextId);
-static void QueuePairResetSavedHeaders(QPBrokerEntry *entry);
-
-#if !defined(VMKERNEL)
-
-static int QueuePairNotifyPeerLocal(Bool attach, VMCIHandle handle);
-
-static QPGuestEndpoint *QPGuestEndpointCreate(VMCIHandle handle,
- VMCIId peer, uint32 flags,
- uint64 produceSize,
- uint64 consumeSize,
- void *produceQ, void *consumeQ);
-static void QPGuestEndpointDestroy(QPGuestEndpoint *entry);
-static int VMCIQueuePairAllocHypercall(const QPGuestEndpoint *entry);
-static int VMCIQueuePairAllocGuestWork(VMCIHandle *handle, VMCIQueue **produceQ,
- uint64 produceSize, VMCIQueue **consumeQ,
- uint64 consumeSize,
- VMCIId peer, uint32 flags,
- VMCIPrivilegeFlags privFlags);
-static int VMCIQueuePairDetachGuestWork(VMCIHandle handle);
-static int VMCIQueuePairDetachHypercall(VMCIHandle handle);
-static void VMCIQPMarkHibernateFailed(QPGuestEndpoint *entry);
-static void VMCIQPUnmarkHibernateFailed(QPGuestEndpoint *entry);
-
-extern int VMCI_SendDatagram(VMCIDatagram *);
-
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBEGetIndex --
- *
- * Retrieve index into host's queue structures for queue entry.
- *
- * Results:
- * 0 or 1. Or crash.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static unsigned int
-VMCIQPBEGetIndex(const QPBrokerEntry *entry, // IN
- VMCIId contextId) // IN
-{
- ASSERT(entry->createId == contextId || entry->attachId == contextId);
-
- return (entry->isVM2VM && entry->createId != contextId) ? 1 : 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQueuePair_Alloc --
- *
- * Allocates a VMCI QueuePair. Only checks validity of input
- * arguments. The real work is done in the host or guest
- * specific function.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQueuePair_Alloc(VMCIHandle *handle, // IN/OUT
- VMCIQueue **produceQ, // OUT
- uint64 produceSize, // IN
- VMCIQueue **consumeQ, // OUT
- uint64 consumeSize, // IN
- VMCIId peer, // IN
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags, // IN
- Bool guestEndpoint, // IN
- VMCIEventReleaseCB wakeupCB, // IN
- void *clientData) // IN
-{
- if (!handle || !produceQ || !consumeQ || (!produceSize && !consumeSize) ||
- (flags & ~VMCI_QP_ALL_FLAGS)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (guestEndpoint) {
-#if !defined(VMKERNEL)
- return VMCIQueuePairAllocGuestWork(handle, produceQ, produceSize, consumeQ,
- consumeSize, peer, flags, privFlags);
-#else
- return VMCI_ERROR_INVALID_ARGS;
-#endif
- } else {
- return VMCIQueuePairAllocHostWork(handle, produceQ, produceSize, consumeQ,
- consumeSize, peer, flags, privFlags,
- wakeupCB, clientData);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQueuePair_Detach --
- *
- * Detaches from a VMCI QueuePair. Only checks validity of input argument.
- * Real work is done in the host or guest specific function.
- *
- * Results:
- * Success or failure.
- *
- * Side effects:
- * Memory is freed.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQueuePair_Detach(VMCIHandle handle, // IN
- Bool guestEndpoint) // IN
-{
- if (VMCI_HANDLE_INVALID(handle)) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (guestEndpoint) {
-#if !defined(VMKERNEL)
- return VMCIQueuePairDetachGuestWork(handle);
-#else
- return VMCI_ERROR_INVALID_ARGS;
-#endif
- } else {
- return VMCIQueuePairDetachHostWork(handle);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_Init --
- *
- * Initializes the list of QueuePairs.
- *
- * Results:
- * Success or failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE int
-QueuePairList_Init(QueuePairList *qpList) // IN
-{
- int ret;
-
- VMCIList_Init(&qpList->head);
- Atomic_Write(&qpList->hibernate, 0);
- ret = VMCIMutex_Init(&qpList->mutex, "VMCIQPListLock",
- VMCI_SEMA_RANK_QUEUEPAIRLIST);
- return ret;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_Destroy --
- *
- * Destroy the list's mutex.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE void
-QueuePairList_Destroy(QueuePairList *qpList)
-{
- VMCIMutex_Destroy(&qpList->mutex);
- VMCIList_Init(&qpList->head);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBrokerLock --
- *
- * Acquires the mutex protecting a VMCI queue pair broker transaction.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIQPBrokerLock(void)
-{
- VMCIMutex_Acquire(&qpBrokerList.mutex);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBrokerUnlock --
- *
- * Releases the mutex protecting a VMCI queue pair broker transaction.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIQPBrokerUnlock(void)
-{
- VMCIMutex_Release(&qpBrokerList.mutex);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_FindEntry --
- *
- * Finds the entry in the list corresponding to a given handle. Assumes
- * that the list is locked.
- *
- * Results:
- * Pointer to entry.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static QueuePairEntry *
-QueuePairList_FindEntry(QueuePairList *qpList, // IN
- VMCIHandle handle) // IN
-{
- VMCIListItem *next;
-
- if (VMCI_HANDLE_INVALID(handle)) {
- return NULL;
- }
-
- VMCIList_Scan(next, &qpList->head) {
- QueuePairEntry *entry = VMCIList_Entry(next, QueuePairEntry, listItem);
-
- if (VMCI_HANDLE_EQUAL(entry->handle, handle)) {
- return entry;
- }
- }
-
- return NULL;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_AddEntry --
- *
- * Adds the given entry to the list. Assumes that the list is locked.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-QueuePairList_AddEntry(QueuePairList *qpList, // IN
- QueuePairEntry *entry) // IN
-{
- if (entry) {
- VMCIList_Insert(&entry->listItem, &qpList->head);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_RemoveEntry --
- *
- * Removes the given entry from the list. Assumes that the list is locked.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-QueuePairList_RemoveEntry(QueuePairList *qpList, // IN
- QueuePairEntry *entry) // IN
-{
- if (entry) {
- VMCIList_Remove(&entry->listItem);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairList_GetHead --
- *
- * Returns the entry from the head of the list. Assumes that the list is
- * locked.
- *
- * Results:
- * Pointer to entry.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static QueuePairEntry *
-QueuePairList_GetHead(QueuePairList *qpList)
-{
- VMCIListItem *first = VMCIList_First(&qpList->head);
-
- if (first) {
- QueuePairEntry *entry = VMCIList_Entry(first, QueuePairEntry, listItem);
- return entry;
- }
-
- return NULL;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBroker_Init --
- *
- * Initalizes queue pair broker state.
- *
- * Results:
- * Success or failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQPBroker_Init(void)
-{
- return QueuePairList_Init(&qpBrokerList);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBroker_Exit --
- *
- * Destroys the queue pair broker state.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIQPBroker_Exit(void)
-{
- QPBrokerEntry *entry;
-
- VMCIQPBrokerLock();
-
- while ((entry = (QPBrokerEntry *)QueuePairList_GetHead(&qpBrokerList))) {
- QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp);
- VMCI_FreeKernelMem(entry, sizeof *entry);
- }
-
- VMCIQPBrokerUnlock();
- QueuePairList_Destroy(&qpBrokerList);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBroker_Alloc --
- *
- * Requests that a queue pair be allocated with the VMCI queue
- * pair broker. Allocates a queue pair entry if one does not
- * exist. Attaches to one if it exists, and retrieves the page
- * files backing that QueuePair. Assumes that the queue pair
- * broker lock is held.
- *
- * Results:
- * Success or failure.
- *
- * Side effects:
- * Memory may be allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQPBroker_Alloc(VMCIHandle handle, // IN
- VMCIId peer, // IN
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags, // IN
- uint64 produceSize, // IN
- uint64 consumeSize, // IN
- QueuePairPageStore *pageStore, // IN/OUT
- VMCIContext *context) // IN: Caller
-{
- return VMCIQPBrokerAllocInt(handle, peer, flags, privFlags,
- produceSize, consumeSize,
- pageStore, context, NULL, NULL,
- NULL, NULL);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairNotifyPeer --
- *
- * Enqueues an event datagram to notify the peer VM attached to
- * the given queue pair handle about attach/detach event by the
- * given VM.
- *
- * Results:
- * Payload size of datagram enqueued on success, error code otherwise.
- *
- * Side effects:
- * Memory is allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-QueuePairNotifyPeer(Bool attach, // IN: attach or detach?
- VMCIHandle handle, // IN
- VMCIId myId, // IN
- VMCIId peerId) // IN: CID of VM to notify
-{
- int rv;
- VMCIEventMsg *eMsg;
- VMCIEventPayload_QP *evPayload;
- char buf[sizeof *eMsg + sizeof *evPayload];
-
- if (VMCI_HANDLE_INVALID(handle) || myId == VMCI_INVALID_ID ||
- peerId == VMCI_INVALID_ID) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- /*
- * Notification message contains: queue pair handle and
- * attaching/detaching VM's context id.
- */
-
- eMsg = (VMCIEventMsg *)buf;
-
- /*
- * In VMCIContext_EnqueueDatagram() we enforce the upper limit on number of
- * pending events from the hypervisor to a given VM otherwise a rogue VM
- * could do an arbitrary number of attach and detach operations causing memory
- * pressure in the host kernel.
- */
-
- /* Clear out any garbage. */
- memset(eMsg, 0, sizeof buf);
-
- eMsg->hdr.dst = VMCI_MAKE_HANDLE(peerId, VMCI_EVENT_HANDLER);
- eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_CONTEXT_RESOURCE_ID);
- eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *evPayload - sizeof eMsg->hdr;
- eMsg->eventData.event = attach ? VMCI_EVENT_QP_PEER_ATTACH :
- VMCI_EVENT_QP_PEER_DETACH;
- evPayload = VMCIEventMsgPayload(eMsg);
- evPayload->handle = handle;
- evPayload->peerId = myId;
-
- rv = VMCIDatagram_Dispatch(VMCI_HYPERVISOR_CONTEXT_ID, (VMCIDatagram *)eMsg,
- FALSE);
- if (rv < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to enqueue QueuePair %s event datagram for "
- "context (ID=0x%x).\n", attach ? "ATTACH" : "DETACH",
- peerId));
- }
-
- return rv;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIQueuePairAllocHostWork --
- *
- * This function implements the kernel API for allocating a queue
- * pair.
- *
- * Results:
- * VMCI_SUCCESS on succes and appropriate failure code otherwise.
- *
- * Side effects:
- * May allocate memory.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-VMCIQueuePairAllocHostWork(VMCIHandle *handle, // IN/OUT
- VMCIQueue **produceQ, // OUT
- uint64 produceSize, // IN
- VMCIQueue **consumeQ, // OUT
- uint64 consumeSize, // IN
- VMCIId peer, // IN
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags, // IN
- VMCIEventReleaseCB wakeupCB, // IN
- void *clientData) // IN
-{
- VMCIContext *context;
- QPBrokerEntry *entry;
- int result;
- Bool swap;
-
- if (VMCI_HANDLE_INVALID(*handle)) {
- VMCIId resourceID = VMCIResource_GetID(VMCI_HOST_CONTEXT_ID);
- if (resourceID == VMCI_INVALID_ID) {
- return VMCI_ERROR_NO_HANDLE;
- }
- *handle = VMCI_MAKE_HANDLE(VMCI_HOST_CONTEXT_ID, resourceID);
- }
-
- context = VMCIContext_Get(VMCI_HOST_CONTEXT_ID);
- ASSERT(context);
-
- entry = NULL;
- result = VMCIQPBrokerAllocInt(*handle, peer, flags, privFlags, produceSize,
- consumeSize, NULL, context, wakeupCB, clientData,
- &entry, &swap);
- if (result == VMCI_SUCCESS) {
- if (swap) {
- /*
- * If this is a local queue pair, the attacher will swap around produce
- * and consume queues.
- */
-
- *produceQ = entry->consumeQ;
- *consumeQ = entry->produceQ;
- } else {
- *produceQ = entry->produceQ;
- *consumeQ = entry->consumeQ;
- }
- } else {
- *handle = VMCI_INVALID_HANDLE;
- VMCI_DEBUG_LOG(4, (LGPFX"queue pair broker failed to alloc (result=%d).\n",
- result));
- }
- VMCIContext_Release(context);
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIQueuePairDetachHostWork --
- *
- * This function implements the host kernel API for detaching from
- * a queue pair.
- *
- * Results:
- * VMCI_SUCCESS on success and appropriate failure code otherwise.
- *
- * Side effects:
- * May deallocate memory.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-VMCIQueuePairDetachHostWork(VMCIHandle handle) // IN
-{
- int result;
- VMCIContext *context;
-
- context = VMCIContext_Get(VMCI_HOST_CONTEXT_ID);
-
- result = VMCIQPBroker_Detach(handle, context);
-
- VMCIContext_Release(context);
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBrokerAllocInt --
- *
- * QueuePair_Alloc for use when setting up queue pair endpoints
- * on the host. Like QueuePair_Alloc, but returns a pointer to
- * the QPBrokerEntry on success.
- *
- * Results:
- * Success or failure.
- *
- * Side effects:
- * Memory may be allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQPBrokerAllocInt(VMCIHandle handle, // IN
- VMCIId peer, // IN
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags, // IN
- uint64 produceSize, // IN
- uint64 consumeSize, // IN
- QueuePairPageStore *pageStore, // IN/OUT
- VMCIContext *context, // IN: Caller
- VMCIEventReleaseCB wakeupCB, // IN
- void *clientData, // IN
- QPBrokerEntry **ent, // OUT
- Bool *swap) // OUT: swap queues?
-{
- const VMCIId contextId = VMCIContext_GetId(context);
- Bool create;
- QPBrokerEntry *entry;
- Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
- int result;
-
- if (VMCI_HANDLE_INVALID(handle) ||
- (flags & ~VMCI_QP_ALL_FLAGS) ||
- (isLocal && (!vmkernel || contextId != VMCI_HOST_CONTEXT_ID ||
- handle.context != contextId)) ||
- !(produceSize || consumeSize) ||
- !context || contextId == VMCI_INVALID_ID ||
- handle.context == VMCI_INVALID_ID) {
- VMCI_DEBUG_LOG(5, ("Invalid argument - handle, flags, whatever\n"));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (pageStore && !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore)) {
- VMCI_DEBUG_LOG(5, ("Invalid argument - page store\n"));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- /*
- * In the initial argument check, we ensure that non-vmkernel hosts
- * are not allowed to create local queue pairs.
- */
-
- ASSERT(vmkernel || !isLocal);
-
- VMCIQPBrokerLock();
-
- if (!isLocal && VMCIContext_QueuePairExists(context, handle)) {
- VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) already attached to queue pair "
- "(handle=0x%x:0x%x).\n",
- contextId, handle.context, handle.resource));
- VMCIQPBrokerUnlock();
- return VMCI_ERROR_ALREADY_EXISTS;
- }
-
- entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
- if (!entry) {
- create = TRUE;
- result = VMCIQPBrokerCreate(handle, peer, flags, privFlags, produceSize,
- consumeSize, pageStore, context, wakeupCB,
- clientData, ent);
- } else {
- create = FALSE;
- result = VMCIQPBrokerAttach(entry, peer, flags, privFlags, produceSize,
- consumeSize, pageStore, context, wakeupCB,
- clientData, ent);
- }
-
- VMCIQPBrokerUnlock();
-
- if (swap) {
- *swap = (contextId == VMCI_HOST_CONTEXT_ID) && !(create && isLocal);
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBrokerCreate --
- *
- * The first endpoint issuing a queue pair allocation will create the state
- * of the queue pair in the queue pair broker.
- *
- * If the creator is a guest, it will associate a VMX virtual address range
- * with the queue pair as specified by the pageStore. For compatibility with
- * older VMX'en, that would use a separate step to set the VMX virtual
- * address range, the virtual address range can be registered later using
- * VMCIQPBroker_SetPageStore. In that case, a pageStore of NULL should be
- * used.
- *
- * If the creator is the host, a pageStore of NULL should be used as well,
- * since the host is not able to supply a page store for the queue pair.
- *
- * For older VMX and host callers, the queue pair will be created in the
- * VMCIQPB_CREATED_NO_MEM state, and for current VMX callers, it will be
- * created in VMCOQPB_CREATED_MEM state.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * Memory will be allocated, and pages may be pinned.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQPBrokerCreate(VMCIHandle handle, // IN
- VMCIId peer, // IN
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags, // IN
- uint64 produceSize, // IN
- uint64 consumeSize, // IN
- QueuePairPageStore *pageStore, // IN
- VMCIContext *context, // IN: Caller
- VMCIEventReleaseCB wakeupCB, // IN
- void *clientData, // IN
- QPBrokerEntry **ent) // OUT
-{
- QPBrokerEntry *entry = NULL;
- const VMCIId contextId = VMCIContext_GetId(context);
- Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
- int result;
- uint64 guestProduceSize;
- uint64 guestConsumeSize;
- Bool isVM2VM;
-
- /*
- * Do not create if the caller asked not to.
- */
-
- if (flags & VMCI_QPFLAG_ATTACH_ONLY) {
- VMCI_DEBUG_LOG(5, ("QP Create - attach only\n"));
- return VMCI_ERROR_NOT_FOUND;
- }
-
- /*
- * Creator's context ID should match handle's context ID or the creator
- * must allow the context in handle's context ID as the "peer".
- */
-
- if (handle.context != contextId && handle.context != peer) {
- VMCI_DEBUG_LOG(5, ("QP Create - contextId fail, %x != %x, %x\n",
- handle.context, contextId, peer));
- return VMCI_ERROR_NO_ACCESS;
- }
-
- isVM2VM = VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(peer);
- if (!vmkernel && isVM2VM) {
- VMCI_DEBUG_LOG(5, ("QP Create - VM2VM\n"));
- return VMCI_ERROR_DST_UNREACHABLE;
- }
-
- /*
- * Creator's context ID for local queue pairs should match the
- * peer, if a peer is specified.
- */
-
- if (isLocal && peer != VMCI_INVALID_ID && contextId != peer) {
- VMCI_DEBUG_LOG(5, ("QP Create - peer %x, context %x\n",
- peer, contextId));
- return VMCI_ERROR_NO_ACCESS;
- }
-
- entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_ATOMIC);
- if (!entry) {
- VMCI_DEBUG_LOG(5, ("QP Create - no memory\n"));
- return VMCI_ERROR_NO_MEM;
- }
-
- if (VMCIContext_GetId(context) == VMCI_HOST_CONTEXT_ID && !isLocal) {
- /*
- * The queue pair broker entry stores values from the guest
- * point of view, so a creating host side endpoint should swap
- * produce and consume values -- unless it is a local queue
- * pair, in which case no swapping is necessary, since the local
- * attacher will swap queues.
- */
-
- guestProduceSize = consumeSize;
- guestConsumeSize = produceSize;
- } else {
- guestProduceSize = produceSize;
- guestConsumeSize = consumeSize;
- }
-
- memset(entry, 0, sizeof *entry);
- entry->qp.handle = handle;
- entry->qp.peer = peer;
- entry->qp.flags = flags;
- entry->qp.produceSize = guestProduceSize;
- entry->qp.consumeSize = guestConsumeSize;
- entry->qp.refCount = 1;
- entry->createId = contextId;
- entry->attachId = VMCI_INVALID_ID;
- entry->stateQP = VMCIQPB_NEW;
- entry->requireTrustedAttach =
- (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) ? TRUE : FALSE;
- entry->createdByTrusted =
- (privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED) ? TRUE : FALSE;
- entry->vmciPageFiles = FALSE;
- entry->wakeupCB = wakeupCB;
- entry->clientData = clientData;
- entry->isVM2VM = FALSE; /* It is not VM2VM until VM attaches... */
- entry->produceQ = VMCIHost_AllocQueue(guestProduceSize);
- if (entry->produceQ == NULL) {
- result = VMCI_ERROR_NO_MEM;
- VMCI_DEBUG_LOG(5, ("QP Create - no memory PQ\n"));
- goto error;
- }
- entry->consumeQ = VMCIHost_AllocQueue(guestConsumeSize);
- if (entry->consumeQ == NULL) {
- result = VMCI_ERROR_NO_MEM;
- VMCI_DEBUG_LOG(5, ("QP Create - no memory CQ\n"));
- goto error;
- }
-
- VMCI_InitQueueMutex(entry->produceQ, entry->consumeQ);
-
- VMCIList_InitEntry(&entry->qp.listItem);
-
- if (isLocal) {
- ASSERT(pageStore == NULL);
-
- entry->localMem = VMCI_AllocKernelMem(QPE_NUM_PAGES(entry->qp) * PAGE_SIZE,
- VMCI_MEMORY_NONPAGED);
- if (entry->localMem == NULL) {
- result = VMCI_ERROR_NO_MEM;
- VMCI_DEBUG_LOG(5, ("QP Create - no memory LM\n"));
- goto error;
- }
- entry->stateQP = VMCIQPB_CREATED;
- entry->hasMem[0] = TRUE;
- entry->produceQ->qHeader = entry->localMem;
- entry->consumeQ->qHeader =
- (VMCIQueueHeader *)((uint8 *)entry->localMem +
- (CEILING(entry->qp.produceSize, PAGE_SIZE) + 1) * PAGE_SIZE);
- VMCIQueueHeader_Init(entry->produceQ->qHeader, handle);
- VMCIQueueHeader_Init(entry->consumeQ->qHeader, handle);
- } else if (pageStore) {
- ASSERT(entry->createId != VMCI_HOST_CONTEXT_ID);
-
- /*
- * The VMX already initialized the queue pair headers, so no
- * need for the kernel side to do that.
- */
-
- result = VMCIHost_RegisterUserMemory(0, pageStore,
- entry->produceQ,
- entry->consumeQ);
- if (result < VMCI_SUCCESS) {
- VMCI_DEBUG_LOG(5, ("QP Create - cannot register user memory\n"));
- goto error;
- }
- VMCIHost_MarkQueuesAvailable(0, entry->produceQ, entry->consumeQ);
- entry->stateQP = VMCIQPB_CREATED;
- entry->hasMem[0] = TRUE;
- } else {
- /*
- * A create without a pageStore may be either a host side create (in which
- * case we are waiting for the guest side to supply the memory) or an old
- * style queue pair create (in which case we will expect a set page store
- * call as the next step).
- */
-
- entry->stateQP = VMCIQPB_CREATED;
- }
-
- QueuePairList_AddEntry(&qpBrokerList, &entry->qp);
- if (ent != NULL) {
- *ent = entry;
- }
-
- VMCIContext_QueuePairCreate(context, handle);
-
- return VMCI_SUCCESS;
-
-error:
- if (entry != NULL) {
- if (entry->produceQ != NULL) {
- VMCIHost_FreeQueue(entry->produceQ, guestProduceSize);
- }
- if (entry->consumeQ != NULL) {
- VMCIHost_FreeQueue(entry->consumeQ, guestConsumeSize);
- }
- VMCI_FreeKernelMem(entry, sizeof *entry);
- }
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBrokerAttach --
- *
- * The second endpoint issuing a queue pair allocation will attach to the
- * queue pair registered with the queue pair broker.
- *
- * If the attacher is a guest, it will associate a VMX virtual address range
- * with the queue pair as specified by the pageStore. At this point, the
- * already attach host endpoint may start using the queue pair, and an
- * attach event is sent to it. For compatibility with older VMX'en, that
- * used a separate step to set the VMX virtual address range, the virtual
- * address range can be registered later using VMCIQPBroker_SetPageStore. In
- * that case, a pageStore of NULL should be used, and the attach event will
- * be generated once the actual page store has been set.
- *
- * If the attacher is the host, a pageStore of NULL should be used as well,
- * since the page store information is already set by the guest.
- *
- * For new VMX and host callers, the queue pair will be moved to the
- * VMCIQPB_ATTACHED_MEM state, and for older VMX callers, it will be
- * moved to the VMCOQPB_ATTACHED_NO_MEM state.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * Memory will be allocated, and pages may be pinned.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQPBrokerAttach(QPBrokerEntry *entry, // IN
- VMCIId peer, // IN
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags, // IN
- uint64 produceSize, // IN
- uint64 consumeSize, // IN
- QueuePairPageStore *pageStore, // IN/OUT
- VMCIContext *context, // IN: Caller
- VMCIEventReleaseCB wakeupCB, // IN
- void *clientData, // IN
- QPBrokerEntry **ent) // OUT
-{
- const VMCIId contextId = VMCIContext_GetId(context);
- Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
- int result;
- Bool isVM2VM;
-
- if (entry->stateQP != VMCIQPB_CREATED) {
- VMCI_DEBUG_LOG(5, ("QP Attach - state is %x\n", entry->stateQP));
- return VMCI_ERROR_UNAVAILABLE;
- }
-
- if (isLocal) {
- if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) ||
- contextId != entry->createId) {
- VMCI_DEBUG_LOG(5, ("QP Attach - invalid args, ctx=%x, createId=%x\n",
- contextId, entry->createId));
- return VMCI_ERROR_INVALID_ARGS;
- }
- } else if (contextId == entry->createId || contextId == entry->attachId) {
- VMCI_DEBUG_LOG(5, ("QP Attach - already, ctx=%x, create=%x, attach=%x\n",
- contextId, entry->createId, entry->attachId));
- return VMCI_ERROR_ALREADY_EXISTS;
- }
-
- ASSERT(entry->qp.refCount < 2);
- ASSERT(entry->attachId == VMCI_INVALID_ID);
-
- isVM2VM = VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(entry->createId);
- if (!vmkernel && isVM2VM) {
- VMCI_DEBUG_LOG(5, ("QP Attach - VM2VM\n"));
- return VMCI_ERROR_DST_UNREACHABLE;
- }
-
- /*
- * If we are attaching from a restricted context then the queuepair
- * must have been created by a trusted endpoint.
- */
-
- if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
- if (!entry->createdByTrusted) {
- VMCI_DEBUG_LOG(5, ("QP Attach - restricted vs trusted\n"));
- return VMCI_ERROR_NO_ACCESS;
- }
- }
-
- /*
- * If we are attaching to a queuepair that was created by a restricted
- * context then we must be trusted.
- */
-
- if (entry->requireTrustedAttach) {
- if (!(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) {
- VMCI_DEBUG_LOG(5, ("QP Attach - trusted attach required\n"));
- return VMCI_ERROR_NO_ACCESS;
- }
- }
-
- /*
- * If the creator specifies VMCI_INVALID_ID in "peer" field, access
- * control check is not performed.
- */
-
- if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != contextId) {
- VMCI_DEBUG_LOG(5, ("QP Attach - bad peer id %x != %x\n",
- contextId, entry->qp.peer));
- return VMCI_ERROR_NO_ACCESS;
- }
-
- if (entry->createId == VMCI_HOST_CONTEXT_ID) {
- /*
- * Do not attach if the caller doesn't support Host Queue Pairs
- * and a host created this queue pair.
- */
-
- if (!VMCIContext_SupportsHostQP(context)) {
- VMCI_DEBUG_LOG(5, ("QP Attach - no attach to host qp\n"));
- return VMCI_ERROR_INVALID_RESOURCE;
- }
- } else if (contextId == VMCI_HOST_CONTEXT_ID) {
- VMCIContext *createContext;
- Bool supportsHostQP;
-
- /*
- * Do not attach a host to a user created queue pair if that
- * user doesn't support host queue pair end points.
- */
-
- createContext = VMCIContext_Get(entry->createId);
- supportsHostQP = VMCIContext_SupportsHostQP(createContext);
- VMCIContext_Release(createContext);
-
- if (!supportsHostQP) {
- VMCI_DEBUG_LOG(5, ("QP Attach - no host attach to qp\n"));
- return VMCI_ERROR_INVALID_RESOURCE;
- }
- }
-
- if ((entry->qp.flags & ~VMCI_QP_ASYMM) != (flags & ~VMCI_QP_ASYMM_PEER)) {
- VMCI_DEBUG_LOG(5, ("QP Attach - flags mismatch\n"));
- return VMCI_ERROR_QUEUEPAIR_MISMATCH;
- }
-
- if (contextId != VMCI_HOST_CONTEXT_ID && !isVM2VM) {
- /*
- * The queue pair broker entry stores values from the guest
- * point of view, so an attaching guest should match the values
- * stored in the entry.
- */
-
- if (entry->qp.produceSize != produceSize ||
- entry->qp.consumeSize != consumeSize) {
- VMCI_DEBUG_LOG(5, ("QP Attach - queue size mismatch\n"));
- return VMCI_ERROR_QUEUEPAIR_MISMATCH;
- }
- } else if (entry->qp.produceSize != consumeSize ||
- entry->qp.consumeSize != produceSize) {
- VMCI_DEBUG_LOG(5, ("QP Attach - host queue size mismatch\n"));
- return VMCI_ERROR_QUEUEPAIR_MISMATCH;
- }
-
- if (contextId != VMCI_HOST_CONTEXT_ID) {
- /*
- * If a guest attached to a queue pair, it will supply the backing memory.
- * If this is a pre NOVMVM vmx, the backing memory will be supplied by
- * calling VMCIQPBroker_SetPageStore() following the return of the
- * VMCIQPBroker_Alloc() call. If it is a vmx of version NOVMVM or later,
- * the page store must be supplied as part of the VMCIQPBroker_Alloc call.
- * Under all circumstances must the initially created queue pair not have
- * any memory associated with it already.
- */
-
- if (isVM2VM) {
- if (!pageStore || entry->stateQP != VMCIQPB_CREATED) {
- VMCI_DEBUG_LOG(5, ("QP Attach - bad QP state for VM2VM, %x, %p\n", entry->stateQP, pageStore));
- return VMCI_ERROR_INVALID_ARGS;
- }
- } else {
- if (entry->stateQP != VMCIQPB_CREATED || entry->hasMem[0]) {
- VMCI_DEBUG_LOG(5, ("QP Attach - bad QP state, %x\n", entry->stateQP));
- return VMCI_ERROR_INVALID_ARGS;
- }
- }
-
- if (pageStore != NULL) {
- unsigned int index;
-
- ASSERT(entry->isVM2VM == FALSE);
- entry->isVM2VM = isVM2VM;
-
- /*
- * Patch up host state to point to guest supplied memory. The VMX
- * already initialized the queue pair headers, so no need for the
- * kernel side to do that.
- */
-
- index = isVM2VM ? 1 : 0;
- result = VMCIHost_RegisterUserMemory(index,
- pageStore,
- entry->produceQ,
- entry->consumeQ);
- if (result < VMCI_SUCCESS) {
- VMCI_DEBUG_LOG(5, ("QP Attach - cannot register memory\n"));
- entry->isVM2VM = FALSE;
- return result;
- }
- VMCIHost_MarkQueuesAvailable(index, entry->produceQ, entry->consumeQ);
- if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
- result = VMCIHost_MapQueues(index, entry->produceQ, entry->consumeQ,
- entry->qp.flags);
- if (result < VMCI_SUCCESS) {
- VMCIHost_ReleaseUserMemory(index, entry->produceQ, entry->consumeQ);
- entry->isVM2VM = FALSE;
- VMCI_DEBUG_LOG(5, ("QP Attach - cannot map queues\n"));
- return result;
- }
- }
- entry->stateQP = VMCIQPB_ATTACHED;
- entry->hasMem[index] = TRUE;
- } else {
- entry->stateQP = VMCIQPB_ATTACHED;
- }
- } else if (entry->stateQP == VMCIQPB_CREATED && !entry->hasMem[0]) {
- /*
- * The host side is attempting to attach to a queue pair that doesn't have
- * any memory associated with it. This must be a pre NOVMVM vmx that hasn't
- * set the page store information yet, or a quiesced VM.
- */
-
- VMCI_DEBUG_LOG(5, ("QP Attach - QP without memory\n"));
- return VMCI_ERROR_UNAVAILABLE;
- } else {
- /*
- * For non-blocking queue pairs, we cannot rely on enqueue/dequeue to map
- * in the pages on the host-side, since it may block, so we make an attempt
- * here.
- */
-
- if (flags & VMCI_QPFLAG_NONBLOCK) {
- /*
- * We only have to do work here if this is a host-to-VM queuepair.
- * Otherwise there's nothing to map, since the pages backing the
- * queues are allocated directly out of host memory.
- */
-
- if (!isLocal) {
- VMCIHost_MarkQueuesAvailable(0, entry->produceQ, entry->consumeQ);
- result = VMCIHost_MapQueues(0, entry->produceQ, entry->consumeQ, flags);
- if (result < VMCI_SUCCESS) {
- VMCI_DEBUG_LOG(5, ("QP Attach - cannot map queues for host\n"));
- return result;
- }
- }
- entry->qp.flags |= flags & (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED);
- }
-
- /*
- * The host side has successfully attached to a queue pair.
- */
-
- entry->stateQP = VMCIQPB_ATTACHED;
- }
-
- if (entry->stateQP == VMCIQPB_ATTACHED && entry->hasMem[0] && (!entry->isVM2VM || entry->hasMem[1])) {
- result = QueuePairNotifyPeer(TRUE, entry->qp.handle, contextId,
- entry->createId);
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to notify peer (ID=0x%x) of attach to queue "
- "pair (handle=0x%x:0x%x).\n", entry->createId,
- entry->qp.handle.context, entry->qp.handle.resource));
- }
- }
-
- entry->attachId = contextId;
- entry->qp.refCount++;
- if (wakeupCB) {
- ASSERT(!entry->wakeupCB);
- entry->wakeupCB = wakeupCB;
- entry->clientData = clientData;
- }
-
- /*
- * When attaching to local queue pairs, the context already has
- * an entry tracking the queue pair, so don't add another one.
- */
-
- if (!isLocal) {
- VMCIContext_QueuePairCreate(context, entry->qp.handle);
- } else {
- ASSERT(VMCIContext_QueuePairExists(context, entry->qp.handle));
- }
- if (ent != NULL) {
- *ent = entry;
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBroker_SetPageStore --
- *
- * VMX'en with versions lower than VMCI_VERSION_NOVMVM use a separate
- * step to add the UVAs of the VMX mapping of the queue pair. This function
- * provides backwards compatibility with such VMX'en, and takes care of
- * registering the page store for a queue pair previously allocated by the
- * VMX during create or attach. This function will move the queue pair state
- * to either from VMCIQBP_CREATED_NO_MEM to VMCIQBP_CREATED_MEM or
- * VMCIQBP_ATTACHED_NO_MEM to VMCIQBP_ATTACHED_MEM. If moving to the
- * attached state with memory, the queue pair is ready to be used by the
- * host peer, and an attached event will be generated.
- *
- * Assumes that the queue pair broker lock is held.
- *
- * This function is only used by the hosted platform, since there is no
- * issue with backwards compatibility for vmkernel.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * Pages may get pinned.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQPBroker_SetPageStore(VMCIHandle handle, // IN
- VA64 produceUVA, // IN
- VA64 consumeUVA, // IN
- VMCIContext *context) // IN: Caller
-{
- QPBrokerEntry *entry;
- int result;
- const VMCIId contextId = VMCIContext_GetId(context);
- unsigned int index;
-
- if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- /*
- * We only support guest to host queue pairs, so the VMX must
- * supply UVAs for the mapped page files.
- */
-
- if (produceUVA == 0 || consumeUVA == 0) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPBrokerLock();
-
- if (!VMCIContext_QueuePairExists(context, handle)) {
- VMCI_WARNING((LGPFX"Context (ID=0x%x) not attached to queue pair "
- "(handle=0x%x:0x%x).\n", contextId, handle.context,
- handle.resource));
- result = VMCI_ERROR_NOT_FOUND;
- goto out;
- }
-
- entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
- if (!entry) {
- result = VMCI_ERROR_NOT_FOUND;
- goto out;
- }
-
- /*
- * If I'm the owner then I can set the page store.
- *
- * Or, if a host created the QueuePair and I'm the attached peer
- * then I can set the page store.
- */
-
- if (entry->createId != contextId &&
- (entry->createId != VMCI_HOST_CONTEXT_ID ||
- entry->attachId != contextId)) {
- result = VMCI_ERROR_QUEUEPAIR_NOTOWNER;
- goto out;
- }
-
- index = VMCIQPBEGetIndex(entry, contextId);
-
- if (entry->hasMem[index] ||
- (entry->stateQP != VMCIQPB_CREATED && entry->stateQP == VMCIQPB_ATTACHED)) {
- result = VMCI_ERROR_UNAVAILABLE;
- goto out;
- }
-
- result = VMCIHost_GetUserMemory(index, produceUVA, consumeUVA,
- entry->produceQ, entry->consumeQ);
- if (result < VMCI_SUCCESS) {
- goto out;
- }
- VMCIHost_MarkQueuesAvailable(index, entry->produceQ, entry->consumeQ);
- result = VMCIHost_MapQueues(index, entry->produceQ, entry->consumeQ, 0);
- if (result < VMCI_SUCCESS) {
- VMCIHost_ReleaseUserMemory(index, entry->produceQ, entry->consumeQ);
- goto out;
- }
-
- entry->hasMem[index] = TRUE;
- entry->vmciPageFiles = TRUE;
-
- if (entry->stateQP == VMCIQPB_ATTACHED && entry->hasMem[0] && (!entry->isVM2VM || entry->hasMem[1])) {
- result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to notify peer (ID=0x%x) of attach to queue "
- "pair (handle=0x%x:0x%x).\n", entry->createId,
- entry->qp.handle.context, entry->qp.handle.resource));
- }
- }
-
- result = VMCI_SUCCESS;
-out:
- VMCIQPBrokerUnlock();
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBroker_Detach --
- *
- * The main entry point for detaching from a queue pair registered with the
- * queue pair broker. If more than one endpoint is attached to the queue
- * pair, the first endpoint will mainly decrement a reference count and
- * generate a notification to its peer. The last endpoint will clean up
- * the queue pair state registered with the broker.
- *
- * When a guest endpoint detaches, it will unmap and unregister the guest
- * memory backing the queue pair. If the host is still attached, it will
- * no longer be able to access the queue pair content.
- *
- * If the queue pair is already in a state where there is no memory
- * registered for the queue pair (any *_NO_MEM state), it will transition to
- * the VMCIQPB_SHUTDOWN_NO_MEM state. This will also happen, if a guest
- * endpoint is the first of two endpoints to detach. If the host endpoint is
- * the first out of two to detach, the queue pair will move to the
- * VMCIQPB_SHUTDOWN_MEM state.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * Memory may be freed, and pages may be unpinned.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQPBroker_Detach(VMCIHandle handle, // IN
- VMCIContext *context) // IN
-{
- QPBrokerEntry *entry;
- const VMCIId contextId = VMCIContext_GetId(context);
- VMCIId peerId;
- Bool isLocal = FALSE;
- int result;
- unsigned int index;
-
- if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPBrokerLock();
-
- if (!VMCIContext_QueuePairExists(context, handle)) {
- VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
- "(handle=0x%x:0x%x).\n",
- contextId, handle.context, handle.resource));
- result = VMCI_ERROR_NOT_FOUND;
- goto out;
- }
-
- entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
- if (!entry) {
- VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair "
- "(handle=0x%x:0x%x) that isn't present in broker.\n",
- contextId, handle.context, handle.resource));
- result = VMCI_ERROR_NOT_FOUND;
- goto out;
- }
-
- if (contextId != entry->createId && contextId != entry->attachId) {
- result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
- goto out;
- }
-
- index = VMCIQPBEGetIndex(entry, contextId);
-
- if (contextId == entry->createId) {
- peerId = entry->attachId;
- entry->createId = VMCI_INVALID_ID;
- } else {
- peerId = entry->createId;
- entry->attachId = VMCI_INVALID_ID;
- }
- entry->qp.refCount--;
-
- isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
-
- if (contextId != VMCI_HOST_CONTEXT_ID) {
- int result;
- Bool headersMapped;
-
- ASSERT(!isLocal);
-
- /*
- * Pre NOVMVM vmx'en may detach from a queue pair before setting the page
- * store, and in that case there is no user memory to detach from. Also,
- * more recent VMX'en may detach from a queue pair in the quiesced state.
- */
-
- VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
- headersMapped = entry->produceQ->qHeader || entry->consumeQ->qHeader;
- if (entry->hasMem[index]) {
- VMCIHost_MarkQueuesUnavailable(index, entry->produceQ, entry->consumeQ);
- result = VMCIHost_UnmapQueues(index, INVALID_VMCI_GUEST_MEM_ID,
- entry->produceQ,
- entry->consumeQ);
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to unmap queue headers for queue pair "
- "(handle=0x%x:0x%x,result=%d).\n", handle.context,
- handle.resource, result));
- }
- if (entry->vmciPageFiles) {
- VMCIHost_ReleaseUserMemory(index, entry->produceQ, entry->consumeQ);
- } else {
- VMCIHost_UnregisterUserMemory(index, entry->produceQ, entry->consumeQ);
- }
- entry->hasMem[index] = FALSE;
- }
- if (!headersMapped) {
- QueuePairResetSavedHeaders(entry);
- }
- if (index == 1) {
- entry->isVM2VM = FALSE;
- }
- VMCI_ReleaseQueueMutex(entry->produceQ);
- if (!headersMapped && entry->wakeupCB) {
- entry->wakeupCB(entry->clientData);
- }
- } else {
- if (entry->wakeupCB) {
- entry->wakeupCB = NULL;
- entry->clientData = NULL;
- }
- }
-
- if (entry->qp.refCount == 0) {
- QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp);
-
- if (isLocal) {
- VMCI_FreeKernelMem(entry->localMem, QPE_NUM_PAGES(entry->qp) * PAGE_SIZE);
- entry->hasMem[0] = FALSE;
- }
- ASSERT(entry->hasMem[0] == FALSE);
- ASSERT(entry->hasMem[1] == FALSE);
- VMCI_CleanupQueueMutex(entry->produceQ, entry->consumeQ);
- VMCIHost_FreeQueue(entry->produceQ, entry->qp.produceSize);
- VMCIHost_FreeQueue(entry->consumeQ, entry->qp.consumeSize);
- VMCI_FreeKernelMem(entry, sizeof *entry);
-
- VMCIContext_QueuePairDestroy(context, handle);
- } else {
- ASSERT(peerId != VMCI_INVALID_ID);
- QueuePairNotifyPeer(FALSE, handle, contextId, peerId);
- entry->stateQP = VMCIQPB_SHUTDOWN;
- if (!isLocal) {
- VMCIContext_QueuePairDestroy(context, handle);
- }
- }
- result = VMCI_SUCCESS;
-out:
- VMCIQPBrokerUnlock();
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBroker_Map --
- *
- * Establishes the necessary mappings for a queue pair given a
- * reference to the queue pair guest memory. This is usually
- * called when a guest is unquiesced and the VMX is allowed to
- * map guest memory once again.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * Memory may be allocated, and pages may be pinned.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQPBroker_Map(VMCIHandle handle, // IN
- VMCIContext *context, // IN
- VMCIQPGuestMem guestMem) // IN
-{
- QPBrokerEntry *entry;
- const VMCIId contextId = VMCIContext_GetId(context);
- Bool isLocal = FALSE;
- int result;
- unsigned int endpoint;
- unsigned int index;
-
- if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPBrokerLock();
-
- if (!VMCIContext_QueuePairExists(context, handle)) {
- VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
- "(handle=0x%x:0x%x).\n",
- contextId, handle.context, handle.resource));
- result = VMCI_ERROR_NOT_FOUND;
- goto out;
- }
-
- entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
- if (!entry) {
- VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair "
- "(handle=0x%x:0x%x) that isn't present in broker.\n",
- contextId, handle.context, handle.resource));
- result = VMCI_ERROR_NOT_FOUND;
- goto out;
- }
-
- if (contextId != entry->createId && contextId != entry->attachId) {
- result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
- goto out;
- }
- index = VMCIQPBEGetIndex(entry, contextId);
- endpoint = contextId == entry->createId ? 0 : 1;
-
- isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
-
- if (vmkernel) {
- /*
- * On vmkernel, the readiness of the queue pair can be signalled
- * immediately since the guest memory is already registered.
- */
-
- VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
- VMCIHost_MarkQueuesAvailable(index, entry->produceQ, entry->consumeQ);
- if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
- result = VMCIHost_MapQueues(index, entry->produceQ, entry->consumeQ,
- entry->qp.flags);
- } else {
- result = VMCI_SUCCESS;
- }
- if (result == VMCI_SUCCESS) {
- QueuePairResetSavedHeaders(entry);
- }
- VMCI_ReleaseQueueMutex(entry->produceQ);
- if (result == VMCI_SUCCESS) {
- if (entry->wakeupCB) {
- entry->wakeupCB(entry->clientData);
- }
- }
- } else if (contextId != VMCI_HOST_CONTEXT_ID) {
- QueuePairPageStore pageStore;
-
- ASSERT((entry->stateQP == VMCIQPB_CREATED ||
- entry->stateQP == VMCIQPB_SHUTDOWN ||
- entry->stateQP == VMCIQPB_ATTACHED) && !entry->hasMem[0]);
- ASSERT(!isLocal);
-
- pageStore.pages = guestMem;
- pageStore.len = QPE_NUM_PAGES(entry->qp);
-
- VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
- QueuePairResetSavedHeaders(entry);
- result = VMCIHost_RegisterUserMemory(index, &pageStore, entry->produceQ, entry->consumeQ);
- VMCIHost_MarkQueuesAvailable(index, entry->produceQ, entry->consumeQ);
- VMCI_ReleaseQueueMutex(entry->produceQ);
- if (result == VMCI_SUCCESS) {
- entry->hasMem[index] = TRUE;
- if (entry->wakeupCB) {
- entry->wakeupCB(entry->clientData);
- }
- }
- } else {
- result = VMCI_SUCCESS;
- }
-
-out:
- VMCIQPBrokerUnlock();
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairSaveHeaders --
- *
- * Saves a snapshot of the queue headers for the given QP broker
- * entry. Should be used when guest memory is unmapped.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code if guest memory
- * can't be accessed..
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-QueuePairSaveHeaders(QPBrokerEntry *entry, // IN
- VMCIId contextId) // IN
-{
- int result;
-
- if (entry->produceQ->savedHeader != NULL &&
- entry->consumeQ->savedHeader != NULL) {
- /*
- * If the headers have already been saved, we don't need to do
- * it again, and we don't want to map in the headers
- * unnecessarily.
- */
- return VMCI_SUCCESS;
- }
- if (NULL == entry->produceQ->qHeader || NULL == entry->consumeQ->qHeader) {
- unsigned int index;
-
- /*
- * If this is second VM, do not save headers: qHeader is for VM which
- * created queue pair only. And no API which uses savedHeader should
- * be used together with VM2VM queue pair anyway.
- */
- index = VMCIQPBEGetIndex(entry, contextId);
- if (index != 0) {
- return VMCI_SUCCESS;
- }
- result = VMCIHost_MapQueues(index, entry->produceQ, entry->consumeQ, 0);
- if (result < VMCI_SUCCESS) {
- return result;
- }
- }
- memcpy(&entry->savedProduceQ, entry->produceQ->qHeader,
- sizeof entry->savedProduceQ);
- entry->produceQ->savedHeader = &entry->savedProduceQ;
- memcpy(&entry->savedConsumeQ, entry->consumeQ->qHeader,
- sizeof entry->savedConsumeQ);
- entry->consumeQ->savedHeader = &entry->savedConsumeQ;
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QueuePairResetSavedHeaders --
- *
- * Resets saved queue headers for the given QP broker
- * entry. Should be used when guest memory becomes available
- * again, or the guest detaches.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-QueuePairResetSavedHeaders(QPBrokerEntry *entry) // IN
-{
- if (vmkernel) {
- VMCI_LockQueueHeader(entry->produceQ);
- }
- entry->produceQ->savedHeader = NULL;
- entry->consumeQ->savedHeader = NULL;
- if (vmkernel) {
- VMCI_UnlockQueueHeader(entry->produceQ);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPBroker_Unmap --
- *
- * Removes all references to the guest memory of a given queue pair, and
- * will move the queue pair from state *_MEM to *_NO_MEM. It is usually
- * called when a VM is being quiesced where access to guest memory should
- * avoided.
- *
- * Results:
- * VMCI_SUCCESS on success, appropriate error code otherwise.
- *
- * Side effects:
- * Memory may be freed, and pages may be unpinned.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQPBroker_Unmap(VMCIHandle handle, // IN
- VMCIContext *context, // IN
- VMCIGuestMemID gid) // IN
-{
- QPBrokerEntry *entry;
- const VMCIId contextId = VMCIContext_GetId(context);
- Bool isLocal = FALSE;
- int result;
- unsigned int index;
-
- if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIQPBrokerLock();
- if (!VMCIContext_QueuePairExists(context, handle)) {
- VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
- "(handle=0x%x:0x%x).\n",
- contextId, handle.context, handle.resource));
- result = VMCI_ERROR_NOT_FOUND;
- goto out;
- }
-
- entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
- if (!entry) {
- VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair "
- "(handle=0x%x:0x%x) that isn't present in broker.\n",
- contextId, handle.context, handle.resource));
- result = VMCI_ERROR_NOT_FOUND;
- goto out;
- }
-
- if (contextId != entry->createId && contextId != entry->attachId) {
- result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
- goto out;
- }
- index = VMCIQPBEGetIndex(entry, contextId);
- isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
-
- if (contextId != VMCI_HOST_CONTEXT_ID) {
- ASSERT(entry->hasMem[index]);
- ASSERT(!isLocal);
-
- VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
- result = QueuePairSaveHeaders(entry, contextId);
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Failed to save queue headers for queue pair "
- "(handle=0x%x:0x%x,result=%d).\n", handle.context,
- handle.resource, result));
- }
- VMCIHost_MarkQueuesUnavailable(index, entry->produceQ, entry->consumeQ);
- VMCIHost_UnmapQueues(index, gid, entry->produceQ, entry->consumeQ);
- if (!vmkernel) {
- /*
- * On hosted, when we unmap queue pairs, the VMX will also
- * unmap the guest memory, so we invalidate the previously
- * registered memory. If the queue pair is mapped again at a
- * later point in time, we will need to reregister the user
- * memory with a possibly new user VA.
- */
-
- VMCIHost_UnregisterUserMemory(index, entry->produceQ, entry->consumeQ);
- entry->hasMem[index] = FALSE;
- }
-
- VMCI_ReleaseQueueMutex(entry->produceQ);
- }
-
- result = VMCI_SUCCESS;
-out:
- VMCIQPBrokerUnlock();
- return result;
-}
-
-#if !defined(VMKERNEL)
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPGuestEndpoints_Init --
- *
- * Initalizes data structure state keeping track of queue pair
- * guest endpoints.
- *
- * Results:
- * VMCI_SUCCESS on success and appropriate failure code otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQPGuestEndpoints_Init(void)
-{
- int err;
-
- err = QueuePairList_Init(&qpGuestEndpoints);
- if (err < VMCI_SUCCESS) {
- return err;
- }
-
- hibernateFailedList = VMCIHandleArray_Create(0);
- if (NULL == hibernateFailedList) {
- QueuePairList_Destroy(&qpGuestEndpoints);
- return VMCI_ERROR_NO_MEM;
- }
-
- /*
- * The lock rank must be lower than subscriberLock in vmciEvent,
- * since we hold the hibernateFailedListLock while generating
- * detach events.
- */
-
- err = VMCI_InitLock(&hibernateFailedListLock, "VMCIQPHibernateFailed",
- VMCI_LOCK_RANK_QPHIBERNATE);
- if (err < VMCI_SUCCESS) {
- VMCIHandleArray_Destroy(hibernateFailedList);
- hibernateFailedList = NULL;
- QueuePairList_Destroy(&qpGuestEndpoints);
- }
-
- return err;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPGuestEndpoints_Exit --
- *
- * Destroys all guest queue pair endpoints. If active guest queue
- * pairs still exist, hypercalls to attempt detach from these
- * queue pairs will be made. Any failure to detach is silently
- * ignored.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIQPGuestEndpoints_Exit(void)
-{
- QPGuestEndpoint *entry;
-
- VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
-
- while ((entry = (QPGuestEndpoint *)QueuePairList_GetHead(&qpGuestEndpoints))) {
- /*
- * Don't make a hypercall for local QueuePairs.
- */
- if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL)) {
- VMCIQueuePairDetachHypercall(entry->qp.handle);
- }
- /*
- * We cannot fail the exit, so let's reset refCount.
- */
- entry->qp.refCount = 0;
- QueuePairList_RemoveEntry(&qpGuestEndpoints, &entry->qp);
- QPGuestEndpointDestroy(entry);
- }
-
- Atomic_Write(&qpGuestEndpoints.hibernate, 0);
- VMCIMutex_Release(&qpGuestEndpoints.mutex);
- QueuePairList_Destroy(&qpGuestEndpoints);
- VMCI_CleanupLock(&hibernateFailedListLock);
- VMCIHandleArray_Destroy(hibernateFailedList);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPGuestEndpoints_Sync --
- *
- * Use this as a synchronization point when setting globals, for example,
- * during device shutdown.
- *
- * Results:
- * TRUE.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIQPGuestEndpoints_Sync(void)
-{
- VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
- VMCIMutex_Release(&qpGuestEndpoints.mutex);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QPGuestEndpointCreate --
- *
- * Allocates and initializes a QPGuestEndpoint structure.
- * Allocates a QueuePair rid (and handle) iff the given entry has
- * an invalid handle. 0 through VMCI_RESERVED_RESOURCE_ID_MAX
- * are reserved handles. Assumes that the QP list mutex is held
- * by the caller.
- *
- * Results:
- * Pointer to structure intialized.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-QPGuestEndpoint *
-QPGuestEndpointCreate(VMCIHandle handle, // IN
- VMCIId peer, // IN
- uint32 flags, // IN
- uint64 produceSize, // IN
- uint64 consumeSize, // IN
- void *produceQ, // IN
- void *consumeQ) // IN
-{
- static VMCIId queuePairRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
- QPGuestEndpoint *entry;
- const uint64 numPPNs = CEILING(produceSize, PAGE_SIZE) +
- CEILING(consumeSize, PAGE_SIZE) +
- 2; /* One page each for the queue headers. */
-
- ASSERT((produceSize || consumeSize) && produceQ && consumeQ);
-
- if (VMCI_HANDLE_INVALID(handle)) {
- VMCIId contextID = vmci_get_context_id();
- VMCIId oldRID = queuePairRID;
-
- /*
- * Generate a unique QueuePair rid. Keep on trying until we wrap around
- * in the RID space.
- */
- ASSERT(oldRID > VMCI_RESERVED_RESOURCE_ID_MAX);
- do {
- handle = VMCI_MAKE_HANDLE(contextID, queuePairRID);
- entry = (QPGuestEndpoint *)QueuePairList_FindEntry(&qpGuestEndpoints,
- handle);
- queuePairRID++;
- if (UNLIKELY(!queuePairRID)) {
- /*
- * Skip the reserved rids.
- */
- queuePairRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
- }
- } while (entry && queuePairRID != oldRID);
-
- if (UNLIKELY(entry != NULL)) {
- ASSERT(queuePairRID == oldRID);
- /*
- * We wrapped around --- no rids were free.
- */
- return NULL;
- }
- }
-
- ASSERT(!VMCI_HANDLE_INVALID(handle) &&
- QueuePairList_FindEntry(&qpGuestEndpoints, handle) == NULL);
- entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NORMAL);
- if (entry) {
- entry->qp.handle = handle;
- entry->qp.peer = peer;
- entry->qp.flags = flags;
- entry->qp.produceSize = produceSize;
- entry->qp.consumeSize = consumeSize;
- entry->qp.refCount = 0;
- entry->numPPNs = numPPNs;
- memset(&entry->ppnSet, 0, sizeof entry->ppnSet);
- entry->produceQ = produceQ;
- entry->consumeQ = consumeQ;
- VMCIList_InitEntry(&entry->qp.listItem);
- }
- return entry;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * QPGuestEndpointDestroy --
- *
- * Frees a QPGuestEndpoint structure.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-QPGuestEndpointDestroy(QPGuestEndpoint *entry) // IN
-{
- ASSERT(entry);
- ASSERT(entry->qp.refCount == 0);
-
- VMCI_FreePPNSet(&entry->ppnSet);
- VMCI_CleanupQueueMutex(entry->produceQ, entry->consumeQ);
- VMCI_FreeQueue(entry->produceQ, entry->qp.produceSize);
- VMCI_FreeQueue(entry->consumeQ, entry->qp.consumeSize);
- VMCI_FreeKernelMem(entry, sizeof *entry);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQueuePairAllocHypercall --
- *
- * Helper to make a QueuePairAlloc hypercall when the driver is
- * supporting a guest device.
- *
- * Results:
- * Result of the hypercall.
- *
- * Side effects:
- * Memory is allocated & freed.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQueuePairAllocHypercall(const QPGuestEndpoint *entry) // IN
-{
- VMCIQueuePairAllocMsg *allocMsg;
- size_t msgSize;
- int result;
-
- if (!entry || entry->numPPNs <= 2) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- ASSERT(!(entry->qp.flags & VMCI_QPFLAG_LOCAL));
-
- msgSize = sizeof *allocMsg + (size_t)entry->numPPNs * sizeof(PPN);
- allocMsg = VMCI_AllocKernelMem(msgSize, VMCI_MEMORY_NONPAGED);
- if (!allocMsg) {
- return VMCI_ERROR_NO_MEM;
- }
-
- allocMsg->hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_QUEUEPAIR_ALLOC);
- allocMsg->hdr.src = VMCI_ANON_SRC_HANDLE;
- allocMsg->hdr.payloadSize = msgSize - VMCI_DG_HEADERSIZE;
- allocMsg->handle = entry->qp.handle;
- allocMsg->peer = entry->qp.peer;
- allocMsg->flags = entry->qp.flags;
- allocMsg->produceSize = entry->qp.produceSize;
- allocMsg->consumeSize = entry->qp.consumeSize;
- allocMsg->numPPNs = entry->numPPNs;
- result = VMCI_PopulatePPNList((uint8 *)allocMsg + sizeof *allocMsg, &entry->ppnSet);
- if (result == VMCI_SUCCESS) {
- result = VMCI_SendDatagram((VMCIDatagram *)allocMsg);
- }
- VMCI_FreeKernelMem(allocMsg, msgSize);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQueuePairAllocGuestWork --
- *
- * This functions handles the actual allocation of a VMCI queue
- * pair guest endpoint. Allocates physical pages for the queue
- * pair. It makes OS dependent calls through generic wrappers.
- *
- * Results:
- * Success or failure.
- *
- * Side effects:
- * Memory is allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQueuePairAllocGuestWork(VMCIHandle *handle, // IN/OUT
- VMCIQueue **produceQ, // OUT
- uint64 produceSize, // IN
- VMCIQueue **consumeQ, // OUT
- uint64 consumeSize, // IN
- VMCIId peer, // IN
- uint32 flags, // IN
- VMCIPrivilegeFlags privFlags) // IN
-
-{
- const uint64 numProducePages = CEILING(produceSize, PAGE_SIZE) + 1;
- const uint64 numConsumePages = CEILING(consumeSize, PAGE_SIZE) + 1;
- void *myProduceQ = NULL;
- void *myConsumeQ = NULL;
- int result;
- QPGuestEndpoint *queuePairEntry = NULL;
-
- /*
- * XXX Check for possible overflow of 'size' arguments when passed to
- * compat_get_order (after some arithmetic ops).
- */
-
- ASSERT(handle && produceQ && consumeQ && (produceSize || consumeSize));
-
- if (privFlags != VMCI_NO_PRIVILEGE_FLAGS) {
- return VMCI_ERROR_NO_ACCESS;
- }
-
- VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
-
- /* Check if creation/attachment of a queuepair is allowed. */
- if (!VMCI_CanCreate()) {
- result = VMCI_ERROR_UNAVAILABLE;
- goto error;
- }
-
- if ((Atomic_Read(&qpGuestEndpoints.hibernate) == 1) &&
- !(flags & VMCI_QPFLAG_LOCAL)) {
- /*
- * While guest OS is in hibernate state, creating non-local
- * queue pairs is not allowed after the point where the VMCI
- * guest driver converted the existing queue pairs to local
- * ones.
- */
-
- result = VMCI_ERROR_UNAVAILABLE;
- goto error;
- }
-
- if ((queuePairEntry = (QPGuestEndpoint *)
- QueuePairList_FindEntry(&qpGuestEndpoints, *handle))) {
- if (queuePairEntry->qp.flags & VMCI_QPFLAG_LOCAL) {
- /* Local attach case. */
- if (queuePairEntry->qp.refCount > 1) {
- VMCI_DEBUG_LOG(4, (LGPFX"Error attempting to attach more than "
- "once.\n"));
- result = VMCI_ERROR_UNAVAILABLE;
- goto errorKeepEntry;
- }
-
- if (queuePairEntry->qp.produceSize != consumeSize ||
- queuePairEntry->qp.consumeSize != produceSize ||
- queuePairEntry->qp.flags != (flags & ~VMCI_QPFLAG_ATTACH_ONLY)) {
- VMCI_DEBUG_LOG(4, (LGPFX"Error mismatched queue pair in local "
- "attach.\n"));
- result = VMCI_ERROR_QUEUEPAIR_MISMATCH;
- goto errorKeepEntry;
- }
-
- /*
- * Do a local attach. We swap the consume and produce queues for the
- * attacher and deliver an attach event.
- */
- result = QueuePairNotifyPeerLocal(TRUE, *handle);
- if (result < VMCI_SUCCESS) {
- goto errorKeepEntry;
- }
- myProduceQ = queuePairEntry->consumeQ;
- myConsumeQ = queuePairEntry->produceQ;
- goto out;
- }
- result = VMCI_ERROR_ALREADY_EXISTS;
- goto errorKeepEntry;
- }
-
- myProduceQ = VMCI_AllocQueue(produceSize, flags);
- if (!myProduceQ) {
- VMCI_WARNING((LGPFX"Error allocating pages for produce queue.\n"));
- result = VMCI_ERROR_NO_MEM;
- goto error;
- }
-
- myConsumeQ = VMCI_AllocQueue(consumeSize, flags);
- if (!myConsumeQ) {
- VMCI_WARNING((LGPFX"Error allocating pages for consume queue.\n"));
- result = VMCI_ERROR_NO_MEM;
- goto error;
- }
-
- queuePairEntry = QPGuestEndpointCreate(*handle, peer, flags,
- produceSize, consumeSize,
- myProduceQ, myConsumeQ);
- if (!queuePairEntry) {
- VMCI_WARNING((LGPFX"Error allocating memory in %s.\n", __FUNCTION__));
- result = VMCI_ERROR_NO_MEM;
- goto error;
- }
-
- result = VMCI_AllocPPNSet(myProduceQ, numProducePages, myConsumeQ,
- numConsumePages, &queuePairEntry->ppnSet);
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"VMCI_AllocPPNSet failed.\n"));
- goto error;
- }
-
- /*
- * It's only necessary to notify the host if this queue pair will be
- * attached to from another context.
- */
- if (queuePairEntry->qp.flags & VMCI_QPFLAG_LOCAL) {
- /* Local create case. */
- VMCIId contextId = vmci_get_context_id();
-
- /*
- * Enforce similar checks on local queue pairs as we do for regular ones.
- * The handle's context must match the creator or attacher context id
- * (here they are both the current context id) and the attach-only flag
- * cannot exist during create. We also ensure specified peer is this
- * context or an invalid one.
- */
- if (queuePairEntry->qp.handle.context != contextId ||
- (queuePairEntry->qp.peer != VMCI_INVALID_ID &&
- queuePairEntry->qp.peer != contextId)) {
- result = VMCI_ERROR_NO_ACCESS;
- goto error;
- }
-
- if (queuePairEntry->qp.flags & VMCI_QPFLAG_ATTACH_ONLY) {
- result = VMCI_ERROR_NOT_FOUND;
- goto error;
- }
- } else {
- result = VMCIQueuePairAllocHypercall(queuePairEntry);
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"VMCIQueuePairAllocHypercall result = %d.\n",
- result));
- goto error;
- }
- }
-
- VMCI_InitQueueMutex((VMCIQueue *)myProduceQ, (VMCIQueue *)myConsumeQ);
-
- QueuePairList_AddEntry(&qpGuestEndpoints, &queuePairEntry->qp);
-
-out:
- queuePairEntry->qp.refCount++;
- *handle = queuePairEntry->qp.handle;
- *produceQ = (VMCIQueue *)myProduceQ;
- *consumeQ = (VMCIQueue *)myConsumeQ;
-
- /*
- * We should initialize the queue pair header pages on a local queue pair
- * create. For non-local queue pairs, the hypervisor initializes the header
- * pages in the create step.
- */
- if ((queuePairEntry->qp.flags & VMCI_QPFLAG_LOCAL) &&
- queuePairEntry->qp.refCount == 1) {
- VMCIQueueHeader_Init((*produceQ)->qHeader, *handle);
- VMCIQueueHeader_Init((*consumeQ)->qHeader, *handle);
- }
-
- VMCIMutex_Release(&qpGuestEndpoints.mutex);
-
- return VMCI_SUCCESS;
-
-error:
- VMCIMutex_Release(&qpGuestEndpoints.mutex);
- if (queuePairEntry) {
- /* The queues will be freed inside the destroy routine. */
- QPGuestEndpointDestroy(queuePairEntry);
- } else {
- if (myProduceQ) {
- VMCI_FreeQueue(myProduceQ, produceSize);
- }
- if (myConsumeQ) {
- VMCI_FreeQueue(myConsumeQ, consumeSize);
- }
- }
- return result;
-
-errorKeepEntry:
- /* This path should only be used when an existing entry was found. */
- ASSERT(queuePairEntry->qp.refCount > 0);
- VMCIMutex_Release(&qpGuestEndpoints.mutex);
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQueuePairDetachHypercall --
- *
- * Helper to make a QueuePairDetach hypercall when the driver is
- * supporting a guest device.
- *
- * Results:
- * Result of the hypercall.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIQueuePairDetachHypercall(VMCIHandle handle) // IN
-{
- VMCIQueuePairDetachMsg detachMsg;
-
- detachMsg.hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_QUEUEPAIR_DETACH);
- detachMsg.hdr.src = VMCI_ANON_SRC_HANDLE;
- detachMsg.hdr.payloadSize = sizeof handle;
- detachMsg.handle = handle;
-
- return VMCI_SendDatagram((VMCIDatagram *)&detachMsg);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQueuePairDetachGuestWork --
- *
- * Helper for VMCI QueuePair detach interface. Frees the physical
- * pages for the queue pair.
- *
- * Results:
- * Success or failure.
- *
- * Side effects:
- * Memory may be freed.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIQueuePairDetachGuestWork(VMCIHandle handle) // IN
-{
- int result;
- QPGuestEndpoint *entry;
- uint32 refCount;
-
- ASSERT(!VMCI_HANDLE_INVALID(handle));
-
- VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
-
- entry = (QPGuestEndpoint *)QueuePairList_FindEntry(&qpGuestEndpoints, handle);
- if (!entry) {
- VMCIMutex_Release(&qpGuestEndpoints.mutex);
- return VMCI_ERROR_NOT_FOUND;
- }
-
- ASSERT(entry->qp.refCount >= 1);
-
- if (entry->qp.flags & VMCI_QPFLAG_LOCAL) {
- result = VMCI_SUCCESS;
-
- if (entry->qp.refCount > 1) {
- result = QueuePairNotifyPeerLocal(FALSE, handle);
- /*
- * We can fail to notify a local queuepair because we can't allocate.
- * We still want to release the entry if that happens, so don't bail
- * out yet.
- */
- }
- } else {
- result = VMCIQueuePairDetachHypercall(handle);
- if (entry->hibernateFailure) {
- if (result == VMCI_ERROR_NOT_FOUND) {
- /*
- * If a queue pair detach failed when entering
- * hibernation, the guest driver and the device may
- * disagree on its existence when coming out of
- * hibernation. The guest driver will regard it as a
- * non-local queue pair, but the device state is gone,
- * since the device has been powered off. In this case, we
- * treat the queue pair as a local queue pair with no
- * peer.
- */
-
- ASSERT(entry->qp.refCount == 1);
- result = VMCI_SUCCESS;
- }
- if (result == VMCI_SUCCESS) {
- VMCIQPUnmarkHibernateFailed(entry);
- }
- }
- if (result < VMCI_SUCCESS) {
- /*
- * We failed to notify a non-local queuepair. That other queuepair
- * might still be accessing the shared memory, so don't release the
- * entry yet. It will get cleaned up by VMCIQueuePair_Exit()
- * if necessary (assuming we are going away, otherwise why did this
- * fail?).
- */
-
- VMCIMutex_Release(&qpGuestEndpoints.mutex);
- return result;
- }
- }
-
- /*
- * If we get here then we either failed to notify a local queuepair, or
- * we succeeded in all cases. Release the entry if required.
- */
-
- entry->qp.refCount--;
- if (entry->qp.refCount == 0) {
- QueuePairList_RemoveEntry(&qpGuestEndpoints, &entry->qp);
- }
-
- /* If we didn't remove the entry, this could change once we unlock. */
- refCount = entry ? entry->qp.refCount :
- 0xffffffff; /*
- * Value does not matter, silence the
- * compiler.
- */
-
- VMCIMutex_Release(&qpGuestEndpoints.mutex);
-
- if (refCount == 0) {
- QPGuestEndpointDestroy(entry);
- }
- return result;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * QueuePairNotifyPeerLocal --
- *
- * Dispatches a queue pair event message directly into the local event
- * queue.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static int
-QueuePairNotifyPeerLocal(Bool attach, // IN: attach or detach?
- VMCIHandle handle) // IN: queue pair handle
-{
- VMCIEventMsg *eMsg;
- VMCIEventPayload_QP *ePayload;
- /* buf is only 48 bytes. */
- char buf[sizeof *eMsg + sizeof *ePayload];
- VMCIId contextId = vmci_get_context_id();
-
- eMsg = (VMCIEventMsg *)buf;
- ePayload = VMCIEventMsgPayload(eMsg);
-
- eMsg->hdr.dst = VMCI_MAKE_HANDLE(contextId, VMCI_EVENT_HANDLER);
- eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
- VMCI_CONTEXT_RESOURCE_ID);
- eMsg->hdr.payloadSize = sizeof *eMsg + sizeof *ePayload - sizeof eMsg->hdr;
- eMsg->eventData.event = attach ? VMCI_EVENT_QP_PEER_ATTACH :
- VMCI_EVENT_QP_PEER_DETACH;
- ePayload->peerId = contextId;
- ePayload->handle = handle;
-
- return VMCIEvent_Dispatch((VMCIDatagram *)eMsg);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPMarkHibernateFailed --
- *
- * Helper function that marks a queue pair entry as not being
- * converted to a local version during hibernation. Must be
- * called with the queue pair list mutex held.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIQPMarkHibernateFailed(QPGuestEndpoint *entry) // IN
-{
- VMCILockFlags flags;
- VMCIHandle handle;
-
- /*
- * entry->handle is located in paged memory, so it can't be
- * accessed while holding a spinlock.
- */
-
- handle = entry->qp.handle;
- entry->hibernateFailure = TRUE;
- VMCI_GrabLock_BH(&hibernateFailedListLock, &flags);
- VMCIHandleArray_AppendEntry(&hibernateFailedList, handle);
- VMCI_ReleaseLock_BH(&hibernateFailedListLock, flags);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPUnmarkHibernateFailed --
- *
- * Helper function that removes a queue pair entry from the group
- * of handles marked as having failed hibernation. Must be called
- * with the queue pair list lock held.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIQPUnmarkHibernateFailed(QPGuestEndpoint *entry) // IN
-{
- VMCILockFlags flags;
- VMCIHandle handle;
-
- /*
- * entry->handle is located in paged memory, so it can't be
- * accessed while holding a spinlock.
- */
-
- handle = entry->qp.handle;
- entry->hibernateFailure = FALSE;
- VMCI_GrabLock_BH(&hibernateFailedListLock, &flags);
- VMCIHandleArray_RemoveEntry(hibernateFailedList, handle);
- VMCI_ReleaseLock_BH(&hibernateFailedListLock, flags);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * VMCIQPGuestEndpoints_Convert --
- *
- * Guest queue pair endpoints may be converted to local ones in
- * two cases: when entering hibernation or when the device is
- * powered off before entering a sleep mode. Below we first
- * discuss the case of hibernation and then the case of entering
- * sleep state.
- *
- * When the guest enters hibernation, any non-local queue pairs
- * will disconnect no later than at the time the VMCI device
- * powers off. To preserve the content of the non-local queue
- * pairs for this guest, we make a local copy of the content and
- * disconnect from the queue pairs. This will ensure that the
- * peer doesn't continue to update the queue pair state while the
- * guest OS is checkpointing the memory (otherwise we might end
- * up with a inconsistent snapshot where the pointers of the
- * consume queue are checkpointed later than the data pages they
- * point to, possibly indicating that non-valid data is
- * valid). While we are in hibernation mode, we block the
- * allocation of new non-local queue pairs. Note that while we
- * are doing the conversion to local queue pairs, we are holding
- * the queue pair list lock, which will prevent concurrent
- * creation of additional non-local queue pairs.
- *
- * The hibernation cannot fail, so if we are unable to either
- * save the queue pair state or detach from a queue pair, we deal
- * with it by keeping the queue pair around, and converting it to
- * a local queue pair when going out of hibernation. Since
- * failing a detach is highly unlikely (it would require a queue
- * pair being actively used as part of a DMA operation), this is
- * an acceptable fall back. Once we come back from hibernation,
- * these queue pairs will no longer be external, so we simply
- * mark them as local at that point.
- *
- * For the sleep state, the VMCI device will also be put into the
- * D3 power state, which may make the device inaccessible to the
- * guest driver (Windows unmaps the I/O space). When entering
- * sleep state, the hypervisor is likely to suspend the guest as
- * well, which will again convert all queue pairs to local ones.
- * However, VMCI device clients, e.g., VMCI Sockets, may attempt
- * to use queue pairs after the device has been put into the D3
- * power state, so we convert the queue pairs to local ones in
- * that case as well. When exiting the sleep states, the device
- * has not been reset, so all device state is still in sync with
- * the device driver, so no further processing is necessary at
- * that point.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Queue pairs are detached.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-VMCIQPGuestEndpoints_Convert(Bool toLocal, // IN
- Bool deviceReset) // IN
-{
- if (toLocal) {
- VMCIListItem *next;
-
- VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
-
- VMCIList_Scan(next, &qpGuestEndpoints.head) {
- QPGuestEndpoint *entry = (QPGuestEndpoint *)VMCIList_Entry(
- next,
- QueuePairEntry,
- listItem);
-
- if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL)) {
- UNUSED_PARAM(VMCIQueue *prodQ); // Only used on Win32
- UNUSED_PARAM(VMCIQueue *consQ); // Only used on Win32
- void *oldProdQ;
- UNUSED_PARAM(void *oldConsQ); // Only used on Win32
- int result;
-
- prodQ = (VMCIQueue *)entry->produceQ;
- consQ = (VMCIQueue *)entry->consumeQ;
- oldConsQ = oldProdQ = NULL;
-
- VMCI_AcquireQueueMutex(prodQ, TRUE);
-
- result = VMCI_ConvertToLocalQueue(consQ, prodQ,
- entry->qp.consumeSize,
- TRUE, &oldConsQ);
- if (result != VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Hibernate failed to create local consume "
- "queue from handle %x:%x (error: %d)\n",
- entry->qp.handle.context, entry->qp.handle.resource,
- result));
- VMCI_ReleaseQueueMutex(prodQ);
- VMCIQPMarkHibernateFailed(entry);
- continue;
- }
- result = VMCI_ConvertToLocalQueue(prodQ, consQ,
- entry->qp.produceSize,
- FALSE, &oldProdQ);
- if (result != VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Hibernate failed to create local produce "
- "queue from handle %x:%x (error: %d)\n",
- entry->qp.handle.context, entry->qp.handle.resource,
- result));
- VMCI_RevertToNonLocalQueue(consQ, oldConsQ,
- entry->qp.consumeSize);
- VMCI_ReleaseQueueMutex(prodQ);
- VMCIQPMarkHibernateFailed(entry);
- continue;
- }
-
- /*
- * Now that the contents of the queue pair has been saved,
- * we can detach from the non-local queue pair. This will
- * discard the content of the non-local queues.
- */
-
- result = VMCIQueuePairDetachHypercall(entry->qp.handle);
- if (result < VMCI_SUCCESS) {
- VMCI_WARNING((LGPFX"Hibernate failed to detach from handle "
- "%x:%x\n",
- entry->qp.handle.context,
- entry->qp.handle.resource));
- VMCI_RevertToNonLocalQueue(consQ, oldConsQ,
- entry->qp.consumeSize);
- VMCI_RevertToNonLocalQueue(prodQ, oldProdQ,
- entry->qp.produceSize);
- VMCI_ReleaseQueueMutex(prodQ);
- VMCIQPMarkHibernateFailed(entry);
- continue;
- }
-
- entry->qp.flags |= VMCI_QPFLAG_LOCAL;
-
- VMCI_ReleaseQueueMutex(prodQ);
-
- VMCI_FreeQueueBuffer(oldProdQ, entry->qp.produceSize);
- VMCI_FreeQueueBuffer(oldConsQ, entry->qp.consumeSize);
-
- QueuePairNotifyPeerLocal(FALSE, entry->qp.handle);
- }
- }
- Atomic_Write(&qpGuestEndpoints.hibernate, 1);
-
- VMCIMutex_Release(&qpGuestEndpoints.mutex);
- } else {
- VMCILockFlags flags;
- VMCIHandle handle;
-
- /*
- * When a guest enters hibernation, there may be queue pairs
- * around, that couldn't be converted to local queue
- * pairs. When coming out of hibernation, these queue pairs
- * will be restored as part of the guest main mem by the OS
- * hibernation code and they can now be regarded as local
- * versions. Since they are no longer connected, detach
- * notifications are sent to the local endpoint.
- */
-
- VMCI_GrabLock_BH(&hibernateFailedListLock, &flags);
- while (VMCIHandleArray_GetSize(hibernateFailedList) > 0) {
- handle = VMCIHandleArray_RemoveTail(hibernateFailedList);
- if (deviceReset) {
- QueuePairNotifyPeerLocal(FALSE, handle);
- }
- }
- VMCI_ReleaseLock_BH(&hibernateFailedListLock, flags);
-
- Atomic_Write(&qpGuestEndpoints.hibernate, 0);
- }
-}
-
-#endif /* !VMKERNEL */
diff --git a/modules/linux/vmci/common/vmciQueuePair.h b/modules/linux/vmci/common/vmciQueuePair.h
deleted file mode 100644
index 9c0be14..0000000
--- a/modules/linux/vmci/common/vmciQueuePair.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*********************************************************
- * Copyright (C) 2007 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
- *
- *********************************************************/
-
-/*
- * vmciQueuePair.h --
- *
- * VMCI QueuePair API implementation in the host driver.
- */
-
-#ifndef _VMCI_QUEUE_PAIR_H_
-#define _VMCI_QUEUE_PAIR_H_
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMMON
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_defs.h"
-#include "vmci_iocontrols.h"
-#include "vmci_kernel_if.h"
-#include "vmciContext.h"
-#include "vmciQueue.h"
-
-/*
- * QueuePairPageStore describes how the memory of a given queue pair
- * is backed. When the queue pair is between the host and a guest, the
- * page store consists of references to the guest pages. On vmkernel,
- * this is a list of PPNs, and on hosted, it is a user VA where the
- * queue pair is mapped into the VMX address space.
- */
-
-typedef struct QueuePairPageStore {
- VMCIQPGuestMem pages; // Reference to pages backing the queue pair.
- uint32 len; // Length of pageList/virtual addres range (in pages).
-} QueuePairPageStore;
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCI_QP_PAGESTORE_IS_WELLFORMED --
- *
- * Utility function that checks whether the fields of the page
- * store contain valid values.
- *
- * Result:
- * TRUE if the page store is wellformed. FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-static INLINE Bool
-VMCI_QP_PAGESTORE_IS_WELLFORMED(QueuePairPageStore *pageStore) // IN
-{
- return pageStore->len >= 2;
-}
-
-int VMCIQPBroker_Init(void);
-void VMCIQPBroker_Exit(void);
-int VMCIQPBroker_Alloc(VMCIHandle handle, VMCIId peer, uint32 flags,
- VMCIPrivilegeFlags privFlags,
- uint64 produceSize, uint64 consumeSize,
- QueuePairPageStore *pageStore,
- VMCIContext *context);
-int VMCIQPBroker_SetPageStore(VMCIHandle handle, VA64 produceUVA, VA64 consumeUVA,
- VMCIContext *context);
-int VMCIQPBroker_Detach(VMCIHandle handle, VMCIContext *context);
-
-int VMCIQPGuestEndpoints_Init(void);
-void VMCIQPGuestEndpoints_Exit(void);
-void VMCIQPGuestEndpoints_Sync(void);
-void VMCIQPGuestEndpoints_Convert(Bool toLocal, Bool deviceReset);
-
-int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
- uint64 produceSize, VMCIQueue **consumeQ,
- uint64 consumeSize, VMCIId peer, uint32 flags,
- VMCIPrivilegeFlags privFlags, Bool guestEndpoint,
- VMCIEventReleaseCB wakeupCB, void *clientData);
-int VMCIQueuePair_Detach(VMCIHandle handle, Bool guestEndpoint);
-int VMCIQPBroker_Map(VMCIHandle handle, VMCIContext *context, VMCIQPGuestMem guestMem);
-int VMCIQPBroker_Unmap(VMCIHandle handle, VMCIContext *context, VMCIGuestMemID gid);
-
-
-#endif /* !_VMCI_QUEUE_PAIR_H_ */
-
diff --git a/modules/linux/vmci/common/vmciResource.c b/modules/linux/vmci/common/vmciResource.c
deleted file mode 100644
index 720924b..0000000
--- a/modules/linux/vmci/common/vmciResource.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/*********************************************************
- * 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
- * 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
- *
- *********************************************************/
-
-/*
- * vmciResource.c --
- *
- * Implementation of the VMCI Resource Access Control API.
- */
-
-#include "vmci_kernel_if.h"
-#include "vm_assert.h"
-#include "vmci_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmciCommonInt.h"
-#include "vmciHashtable.h"
-#include "vmciResource.h"
-#if defined(VMKERNEL)
-# include "vmciVmkInt.h"
-# include "vm_libc.h"
-# include "helper_ext.h"
-# include "vmciDriver.h"
-#else
-# include "vmciDriver.h"
-#endif
-
-#define LGPFX "VMCIResource: "
-
-/* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */
-static uint32 resourceID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
-static VMCILock resourceIdLock;
-
-static void VMCIResourceDoRemove(VMCIResource *resource);
-
-static VMCIHashTable *resourceTable = NULL;
-
-
-/* Public Resource Access Control API. */
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_Init --
- *
- * Initializes the VMCI Resource Access Control API. Creates a hashtable
- * to hold all resources, and registers vectors and callbacks for
- * hypercalls.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIResource_Init(void)
-{
- int err = VMCI_InitLock(&resourceIdLock, "VMCIRIDLock",
- VMCI_LOCK_RANK_RESOURCE);
- if (err < VMCI_SUCCESS) {
- return err;
- }
-
- resourceTable = VMCIHashTable_Create(128);
- if (resourceTable == NULL) {
- VMCI_WARNING((LGPFX"Failed creating a resource hash table for VMCI.\n"));
- VMCI_CleanupLock(&resourceIdLock);
- return VMCI_ERROR_NO_MEM;
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_Exit --
- *
- * Cleans up resources.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIResource_Exit(void)
-{
- /* Cleanup resources.*/
- VMCI_CleanupLock(&resourceIdLock);
-
- if (resourceTable) {
- VMCIHashTable_Destroy(resourceTable);
- }
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_GetID --
- *
- * Return resource ID. The first VMCI_RESERVED_RESOURCE_ID_MAX are
- * reserved so we start from its value + 1.
- *
- * Result:
- * VMCI resource id on success, VMCI_INVALID_ID on failure.
- *
- * Side effects:
- * None.
- *
- *
- *------------------------------------------------------------------------------
- */
-
-VMCIId
-VMCIResource_GetID(VMCIId contextID)
-{
- VMCIId oldRID = resourceID;
- VMCIId currentRID;
- Bool foundRID = FALSE;
-
- /*
- * Generate a unique resource ID. Keep on trying until we wrap around
- * in the RID space.
- */
- ASSERT(oldRID > VMCI_RESERVED_RESOURCE_ID_MAX);
-
- do {
- VMCILockFlags flags;
- VMCIHandle handle;
-
- VMCI_GrabLock(&resourceIdLock, &flags);
- currentRID = resourceID;
- handle = VMCI_MAKE_HANDLE(contextID, currentRID);
- resourceID++;
- if (UNLIKELY(resourceID == VMCI_INVALID_ID)) {
- /*
- * Skip the reserved rids.
- */
-
- resourceID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
- }
- VMCI_ReleaseLock(&resourceIdLock, flags);
- foundRID = !VMCIHashTable_EntryExists(resourceTable, handle);
- } while (!foundRID && resourceID != oldRID);
-
- if (UNLIKELY(!foundRID)) {
- return VMCI_INVALID_ID;
- } else {
- return currentRID;
- }
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_Add --
- *
- * Results:
- * VMCI_SUCCESS if successful, error code if not.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIResource_Add(VMCIResource *resource, // IN
- VMCIResourceType resourceType, // IN
- VMCIHandle resourceHandle, // IN
- VMCIResourceFreeCB containerFreeCB, // IN
- void *containerObject) // IN
-{
- int result;
-
- ASSERT(resource);
-
- if (VMCI_HANDLE_EQUAL(resourceHandle, VMCI_INVALID_HANDLE)) {
- VMCI_DEBUG_LOG(4, (LGPFX"Invalid argument resource (handle=0x%x:0x%x).\n",
- resourceHandle.context, resourceHandle.resource));
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- VMCIHashTable_InitEntry(&resource->hashEntry, resourceHandle);
- resource->type = resourceType;
- resource->containerFreeCB = containerFreeCB;
- resource->containerObject = containerObject;
-
- /* Add resource to hashtable. */
- result = VMCIHashTable_AddEntry(resourceTable, &resource->hashEntry);
- if (result != VMCI_SUCCESS) {
- VMCI_DEBUG_LOG(4, (LGPFX"Failed to add entry to hash table "
- "(result=%d).\n", result));
- return result;
- }
-
- return result;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_Remove --
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIResource_Remove(VMCIHandle resourceHandle, // IN:
- VMCIResourceType resourceType) // IN:
-{
- VMCIResource *resource = VMCIResource_Get(resourceHandle, resourceType);
- if (resource == NULL) {
- return;
- }
-
- /* Remove resource from hashtable. */
- VMCIHashTable_RemoveEntry(resourceTable, &resource->hashEntry);
-
- VMCIResource_Release(resource);
- /* resource could be freed by now. */
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_Get --
- *
- * Results:
- * Resource is successful. Otherwise NULL.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCIResource *
-VMCIResource_Get(VMCIHandle resourceHandle, // IN
- VMCIResourceType resourceType) // IN
-{
- VMCIResource *resource;
- VMCIHashEntry *entry = VMCIHashTable_GetEntry(resourceTable, resourceHandle);
- if (entry == NULL) {
- return NULL;
- }
- resource = RESOURCE_CONTAINER(entry, VMCIResource, hashEntry);
- if (resourceType == VMCI_RESOURCE_TYPE_ANY ||
- resource->type == resourceType) {
- return resource;
- }
- VMCIHashTable_ReleaseEntry(resourceTable, entry);
- return NULL;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_Hold --
- *
- * Hold the given resource. This will hold the hashtable entry. This
- * is like doing a Get() but without having to lookup the resource by
- * handle.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIResource_Hold(VMCIResource *resource)
-{
- ASSERT(resource);
- VMCIHashTable_HoldEntry(resourceTable, &resource->hashEntry);
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResourceDoRemove --
- *
- * Deallocates data structures associated with the given resource
- * and invoke any call back registered for the resource.
- *
- * Results:
- * None.
- *
- * Side effects:
- * May deallocate memory and invoke a callback for the removed resource.
- *
- *------------------------------------------------------------------------------
- */
-
-static void INLINE
-VMCIResourceDoRemove(VMCIResource *resource)
-{
- ASSERT(resource);
-
- if (resource->containerFreeCB) {
- resource->containerFreeCB(resource->containerObject);
- /* Resource has been freed don't dereference it. */
- }
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_Release --
- *
- * Results:
- * None.
- *
- * Side effects:
- * resource's containerFreeCB will get called if last reference.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCIResource_Release(VMCIResource *resource)
-{
- int result;
-
- ASSERT(resource);
-
- result = VMCIHashTable_ReleaseEntry(resourceTable, &resource->hashEntry);
- if (result == VMCI_SUCCESS_ENTRY_DEAD) {
- VMCIResourceDoRemove(resource);
- }
-
- /*
- * We propagate the information back to caller in case it wants to know
- * whether entry was freed.
- */
- return result;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_Handle --
- *
- * Get the handle for the given resource.
- *
- * Results:
- * The resource's associated handle.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-VMCIHandle
-VMCIResource_Handle(VMCIResource *resource)
-{
- ASSERT(resource);
- return resource->hashEntry.handle;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCIResource_Sync --
- *
- * Use this as a synchronization point when setting globals, for example,
- * during device shutdown.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-void
-VMCIResource_Sync(void)
-{
- VMCIHashTable_Sync(resourceTable);
-}
diff --git a/modules/linux/vmci/common/vmciResource.h b/modules/linux/vmci/common/vmciResource.h
deleted file mode 100644
index da056d1..0000000
--- a/modules/linux/vmci/common/vmciResource.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*********************************************************
- * 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
- * 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
- *
- *********************************************************/
-
-/*
- * vmciResource.h --
- *
- * VMCI Resource Access Control API.
- */
-
-#ifndef _VMCI_RESOURCE_H_
-#define _VMCI_RESOURCE_H_
-
-#define INCLUDE_ALLOW_VMMON
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_defs.h"
-#include "vmci_kernel_if.h"
-#include "vmciHashtable.h"
-#include "vmciContext.h"
-
-#define RESOURCE_CONTAINER(ptr, type, member) \
- ((type *)((char *)(ptr) - offsetof(type, member)))
-
-typedef void(*VMCIResourceFreeCB)(void *resource);
-
-typedef enum {
- VMCI_RESOURCE_TYPE_ANY,
- VMCI_RESOURCE_TYPE_API,
- VMCI_RESOURCE_TYPE_GROUP,
- VMCI_RESOURCE_TYPE_DATAGRAM,
- VMCI_RESOURCE_TYPE_DOORBELL,
-} VMCIResourceType;
-
-typedef struct VMCIResource {
- VMCIHashEntry hashEntry;
- VMCIResourceType type;
- VMCIResourceFreeCB containerFreeCB; // Callback to free container
- // object when refCount is 0.
- void *containerObject; // Container object reference.
-} VMCIResource;
-
-
-int VMCIResource_Init(void);
-void VMCIResource_Exit(void);
-void VMCIResource_Sync(void);
-
-VMCIId VMCIResource_GetID(VMCIId contextID);
-
-int VMCIResource_Add(VMCIResource *resource, VMCIResourceType resourceType,
- VMCIHandle resourceHandle,
- VMCIResourceFreeCB containerFreeCB, void *containerObject);
-void VMCIResource_Remove(VMCIHandle resourceHandle,
- VMCIResourceType resourceType);
-VMCIResource *VMCIResource_Get(VMCIHandle resourceHandle,
- VMCIResourceType resourceType);
-void VMCIResource_Hold(VMCIResource *resource);
-int VMCIResource_Release(VMCIResource *resource);
-VMCIHandle VMCIResource_Handle(VMCIResource *resource);
-
-
-#endif // _VMCI_RESOURCE_H_
diff --git a/modules/linux/vmci/common/vmciRoute.c b/modules/linux/vmci/common/vmciRoute.c
deleted file mode 100644
index 6dd1eb9..0000000
--- a/modules/linux/vmci/common/vmciRoute.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*********************************************************
- * Copyright (C) 2011-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
- *
- *********************************************************/
-
-/*
- * vmciRoute.c --
- *
- * Implementation of VMCI routing rules.
- */
-
-#include "vmci_kernel_if.h"
-#include "vm_assert.h"
-#include "vmci_defs.h"
-#include "vmci_infrastructure.h"
-#include "vmciCommonInt.h"
-#include "vmciContext.h"
-#include "vmciDriver.h"
-#include "vmciKernelAPI.h"
-#include "vmciRoute.h"
-#if defined(VMKERNEL)
-# include "vmciVmkInt.h"
-# include "vm_libc.h"
-# include "helper_ext.h"
-#endif
-
-#define LGPFX "VMCIRoute: "
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCI_Route --
- *
- * Make a routing decision for the given source and destination handles.
- * This will try to determine the route using the handles and the available
- * devices.
- *
- * Result:
- * A VMCIRoute value.
- *
- * Side effects:
- * Sets the source context if it is invalid.
- *
- *------------------------------------------------------------------------------
- */
-
-int
-VMCI_Route(VMCIHandle *src, // IN/OUT
- const VMCIHandle *dst, // IN
- Bool fromGuest, // IN
- VMCIRoute *route) // OUT
-{
- Bool hasHostDevice;
- Bool hasGuestDevice;
-
- ASSERT(src);
- ASSERT(dst);
- ASSERT(route);
-
- *route = VMCI_ROUTE_NONE;
-
- /*
- * "fromGuest" is only ever set to TRUE by IOCTL_VMCI_DATAGRAM_SEND (or by
- * the vmkernel equivalent), which comes from the VMX, so we know it is
- * coming from a guest.
- */
-
- /*
- * To avoid inconsistencies, test these once. We will test them again
- * when we do the actual send to ensure that we do not touch a non-existent
- * device.
- */
-
- hasHostDevice = VMCI_HostPersonalityActive();
- hasGuestDevice = VMCI_GuestPersonalityActive();
-
- /* Must have a valid destination context. */
- if (VMCI_INVALID_ID == dst->context) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- /* Anywhere to hypervisor. */
- if (VMCI_HYPERVISOR_CONTEXT_ID == dst->context) {
- /*
- * If this message already came from a guest then we cannot send it
- * to the hypervisor. It must come from a local client.
- */
-
- if (fromGuest) {
- return VMCI_ERROR_DST_UNREACHABLE;
- }
-
- /* We must be acting as a guest in order to send to the hypervisor. */
- if (!hasGuestDevice) {
- return VMCI_ERROR_DEVICE_NOT_FOUND;
- }
-
- /* And we cannot send if the source is the host context. */
- if (VMCI_HOST_CONTEXT_ID == src->context) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- /*
- * If the client passed the ANON source handle then respect it (both
- * context and resource are invalid). However, if they passed only
- * an invalid context, then they probably mean ANY, in which case we
- * should set the real context here before passing it down.
- */
-
- if (VMCI_INVALID_ID == src->context && VMCI_INVALID_ID != src->resource) {
- src->context = vmci_get_context_id();
- }
-
- /* Send from local client down to the hypervisor. */
- *route = VMCI_ROUTE_AS_GUEST;
- return VMCI_SUCCESS;
- }
-
- /* Anywhere to local client on host. */
- if (VMCI_HOST_CONTEXT_ID == dst->context) {
- /*
- * If it is not from a guest but we are acting as a guest, then we need
- * to send it down to the host. Note that if we are also acting as a
- * host then this will prevent us from sending from local client to
- * local client, but we accept that restriction as a way to remove
- * any ambiguity from the host context.
- */
-
- if (src->context == VMCI_HYPERVISOR_CONTEXT_ID) {
- /*
- * If the hypervisor is the source, this is host local
- * communication. The hypervisor may send vmci event
- * datagrams to the host itself, but it will never send
- * datagrams to an "outer host" through the guest device.
- */
-
- if (hasHostDevice) {
- *route = VMCI_ROUTE_AS_HOST;
- return VMCI_SUCCESS;
- } else {
- return VMCI_ERROR_DEVICE_NOT_FOUND;
- }
- }
-
- if (!fromGuest && hasGuestDevice) {
- /* If no source context then use the current. */
- if (VMCI_INVALID_ID == src->context) {
- src->context = vmci_get_context_id();
- }
-
- /* Send it from local client down to the host. */
- *route = VMCI_ROUTE_AS_GUEST;
- return VMCI_SUCCESS;
- }
-
- /*
- * Otherwise we already received it from a guest and it is destined
- * for a local client on this host, or it is from another local client
- * on this host. We must be acting as a host to service it.
- */
-
- if (!hasHostDevice) {
- return VMCI_ERROR_DEVICE_NOT_FOUND;
- }
-
- if (VMCI_INVALID_ID == src->context) {
- /*
- * If it came from a guest then it must have a valid context.
- * Otherwise we can use the host context.
- */
-
- if (fromGuest) {
- return VMCI_ERROR_INVALID_ARGS;
- }
- src->context = VMCI_HOST_CONTEXT_ID;
- }
-
- /* Route to local client. */
- *route = VMCI_ROUTE_AS_HOST;
- return VMCI_SUCCESS;
- }
-
- /* If we are acting as a host then this might be destined for a guest. */
- if (hasHostDevice) {
- /* It will have a context if it is meant for a guest. */
- if (VMCIContext_Exists(dst->context)) {
- if (VMCI_INVALID_ID == src->context) {
- /*
- * If it came from a guest then it must have a valid context.
- * Otherwise we can use the host context.
- */
-
- if (fromGuest) {
- return VMCI_ERROR_INVALID_ARGS;
- }
- src->context = VMCI_HOST_CONTEXT_ID;
- } else if (VMCI_CONTEXT_IS_VM(src->context) &&
- src->context != dst->context) {
- /*
- * VM to VM communication is not allowed. Since we catch
- * all communication destined for the host above, this
- * must be destined for a VM since there is a valid
- * context.
- */
-
- ASSERT(VMCI_CONTEXT_IS_VM(dst->context));
-
- if (!vmkernel) {
- return VMCI_ERROR_DST_UNREACHABLE;
- }
- }
-
- /* Pass it up to the guest. */
- *route = VMCI_ROUTE_AS_HOST;
- return VMCI_SUCCESS;
- } else if (!hasGuestDevice) {
- /*
- * The host is attempting to reach a CID without an active context, and
- * we can't send it down, since we have no guest device.
- */
-
- return VMCI_ERROR_DST_UNREACHABLE;
- }
- }
-
- /*
- * We must be a guest trying to send to another guest, which means
- * we need to send it down to the host. We do not filter out VM to
- * VM communication here, since we want to be able to use the guest
- * driver on older versions that do support VM to VM communication.
- */
-
- if (!hasGuestDevice) {
- /*
- * Ending up here means we have neither guest nor host device. That
- * shouldn't happen, since any VMCI client in the kernel should have done
- * a successful VMCI_DeviceGet.
- */
-
- ASSERT(FALSE);
-
- return VMCI_ERROR_DEVICE_NOT_FOUND;
- }
-
- /* If no source context then use the current context. */
- if (VMCI_INVALID_ID == src->context) {
- src->context = vmci_get_context_id();
- }
-
- /*
- * Send it from local client down to the host, which will route it to
- * the other guest for us.
- */
-
- *route = VMCI_ROUTE_AS_GUEST;
- return VMCI_SUCCESS;
-}
-
-
-/*
- *------------------------------------------------------------------------------
- *
- * VMCI_RouteString --
- *
- * Get a string for the given route.
- *
- * Result:
- * A string representing the route, if the route is valid, otherwise an
- * empty string.
- *
- * Side effects:
- * None.
- *
- *------------------------------------------------------------------------------
- */
-
-const char *
-VMCI_RouteString(VMCIRoute route) // IN
-{
- const char *vmciRouteStrings[] = {
- "none",
- "as host",
- "as guest",
- };
- if (route >= VMCI_ROUTE_NONE && route <= VMCI_ROUTE_AS_GUEST) {
- return vmciRouteStrings[route];
- }
- return "";
-}
diff --git a/modules/linux/vmci/common/vmciRoute.h b/modules/linux/vmci/common/vmciRoute.h
deleted file mode 100644
index a595862..0000000
--- a/modules/linux/vmci/common/vmciRoute.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*********************************************************
- * 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
- * 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
- *
- *********************************************************/
-
-/*
- * vmciRoute.h --
- *
- * VMCI Routing.
- */
-
-#ifndef _VMCI_ROUTE_H_
-#define _VMCI_ROUTE_H_
-
-#define INCLUDE_ALLOW_VMMON
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_defs.h"
-
-
-typedef enum {
- VMCI_ROUTE_NONE,
- VMCI_ROUTE_AS_HOST,
- VMCI_ROUTE_AS_GUEST,
-} VMCIRoute;
-
-
-int VMCI_Route(VMCIHandle *src, const VMCIHandle *dst, Bool fromGuest,
- VMCIRoute *route);
-const char *VMCI_RouteString(VMCIRoute route);
-
-
-#endif // _VMCI_ROUTE_H_
diff --git a/modules/linux/vmci/linux/driver.c b/modules/linux/vmci/linux/driver.c
deleted file mode 100644
index 82738e4..0000000
--- a/modules/linux/vmci/linux/driver.c
+++ /dev/null
@@ -1,2509 +0,0 @@
-/*********************************************************
- * 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
- * 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
- *
- *********************************************************/
-
-/* Must come before any kernel header file */
-#include "driver-config.h"
-
-#define EXPORT_SYMTAB
-
-#include <asm/atomic.h>
-#include <asm/io.h>
-
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
-# include <linux/ioctl32.h>
-/* Use weak: not all kernels export sys_ioctl for use by modules */
-asmlinkage __attribute__((weak)) long
-sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-#endif
-#include <linux/miscdevice.h>
-#include <linux/moduleparam.h>
-#include <linux/poll.h>
-#include <linux/smp.h>
-
-#include "compat_highmem.h"
-#include "compat_interrupt.h"
-#include "compat_ioport.h"
-#include "compat_kernel.h"
-#include "compat_mm.h"
-#include "compat_module.h"
-#include "compat_mutex.h"
-#include "compat_page.h"
-#include "compat_pci.h"
-#include "compat_sched.h"
-#include "compat_slab.h"
-#include "compat_uaccess.h"
-#include "compat_version.h"
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-# error "Linux kernels before 2.6.9 are not supported."
-#endif
-
-#include "vm_basic_types.h"
-#include "vm_device_version.h"
-
-#include "vmware.h"
-#include "driverLog.h"
-#include "pgtbl.h"
-#include "vmci_defs.h"
-#include "vmci_handle_array.h"
-#include "vmci_infrastructure.h"
-#include "vmci_iocontrols.h"
-#include "vmci_version.h"
-#include "vmci_kernel_if.h"
-#include "vmciCommonInt.h"
-#include "vmciContext.h"
-#include "vmciDatagram.h"
-#include "vmciDoorbell.h"
-#include "vmciDriver.h"
-#include "vmciEvent.h"
-#include "vmciKernelAPI.h"
-#include "vmciQueuePair.h"
-#include "vmciResource.h"
-
-#define LGPFX "VMCI: "
-
-#define VMCI_DEVICE_NAME "vmci"
-#define VMCI_MODULE_NAME "vmci"
-
-
-/*
- *----------------------------------------------------------------------
- *
- * PCI Device interface --
- *
- * Declarations of types and functions related to the VMCI PCI
- * device personality.
- *
- *
- *----------------------------------------------------------------------
- */
-
-/*
- * VMCI PCI driver state
- */
-
-typedef struct vmci_device {
- compat_mutex_t lock;
-
- unsigned int ioaddr;
- unsigned int ioaddr_size;
- unsigned int irq;
- unsigned int intr_type;
- Bool exclusive_vectors;
- struct msix_entry msix_entries[VMCI_MAX_INTRS];
-
- Bool enabled;
- spinlock_t dev_spinlock;
- atomic_t datagrams_allowed;
-} vmci_device;
-
-static const struct pci_device_id vmci_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_VMCI), },
- { 0 },
-};
-
-static int vmci_probe_device(struct pci_dev *pdev,
- const struct pci_device_id *id);
-static void vmci_remove_device(struct pci_dev* pdev);
-
-static struct pci_driver vmci_driver = {
- .name = VMCI_DEVICE_NAME,
- .id_table = vmci_ids,
- .probe = vmci_probe_device,
- .remove = vmci_remove_device,
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
-static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id,
- struct pt_regs * regs);
-static compat_irqreturn_t vmci_interrupt_bm(int irq, void *dev_id,
- struct pt_regs * regs);
-#else
-static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id);
-static compat_irqreturn_t vmci_interrupt_bm(int irq, void *dev_id);
-#endif
-static void dispatch_datagrams(unsigned long data);
-static void process_bitmap(unsigned long data);
-
-/* MSI-X has performance problems in < 2.6.19 */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
-# define VMCI_DISABLE_MSIX 0
-#else
-# define VMCI_DISABLE_MSIX 1
-#endif
-
-static vmci_device vmci_dev;
-static compat_mod_param_bool vmci_disable_host = 0;
-static compat_mod_param_bool vmci_disable_guest = 0;
-static compat_mod_param_bool vmci_disable_msi;
-static compat_mod_param_bool vmci_disable_msix = VMCI_DISABLE_MSIX;
-
-DECLARE_TASKLET(vmci_dg_tasklet, dispatch_datagrams,
- (unsigned long)&vmci_dev);
-
-DECLARE_TASKLET(vmci_bm_tasklet, process_bitmap,
- (unsigned long)&vmci_dev);
-
-/*
- * Allocate a buffer for incoming datagrams globally to avoid repeated
- * allocation in the interrupt handler's atomic context.
- */
-
-static uint8 *data_buffer = NULL;
-static uint32 data_buffer_size = VMCI_MAX_DG_SIZE;
-
-/*
- * If the VMCI hardware supports the notification bitmap, we allocate
- * and register a page with the device.
- */
-
-static uint8 *notification_bitmap = NULL;
-
-
-/*
- *----------------------------------------------------------------------
- *
- * Host device node interface --
- *
- * Implements VMCI by implementing open/close/ioctl functions
- *
- *
- *----------------------------------------------------------------------
- */
-
-/*
- * Per-instance host state
- */
-
-typedef struct VMCILinux {
- VMCIContext *context;
- int userVersion;
- VMCIObjType ctType;
-#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL)
- compat_mutex_t lock;
-#endif
-} VMCILinux;
-
-/*
- * Static driver state.
- */
-
-#define VM_DEVICE_NAME_SIZE 32
-#define LINUXLOG_BUFFER_SIZE 1024
-
-typedef struct VMCILinuxState {
- struct miscdevice misc;
- char buf[LINUXLOG_BUFFER_SIZE];
- atomic_t activeContexts;
-} VMCILinuxState;
-
-static int VMCISetupNotify(VMCIContext *context, VA notifyUVA);
-static void VMCIUnsetNotifyInt(VMCIContext *context, Bool useLock);
-
-static int LinuxDriver_Open(struct inode *inode, struct file *filp);
-
-static int LinuxDriver_Ioctl(struct inode *inode, struct file *filp,
- u_int iocmd, unsigned long ioarg);
-
-#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL)
-static long LinuxDriver_UnlockedIoctl(struct file *filp,
- u_int iocmd, unsigned long ioarg);
-#endif
-
-static int LinuxDriver_Close(struct inode *inode, struct file *filp);
-static unsigned int LinuxDriverPoll(struct file *file, poll_table *wait);
-
-
-#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL)
-#define LinuxDriverLockIoctlPerFD(mutex) compat_mutex_lock(mutex)
-#define LinuxDriverUnlockIoctlPerFD(mutex) compat_mutex_unlock(mutex)
-#else
-#define LinuxDriverLockIoctlPerFD(mutex) do {} while (0)
-#define LinuxDriverUnlockIoctlPerFD(mutex) do {} while (0)
-#endif
-
-/* should be const if not for older kernels support */
-static struct file_operations vmuser_fops = {
- .owner = THIS_MODULE,
- .open = LinuxDriver_Open,
- .release = LinuxDriver_Close,
- .poll = LinuxDriverPoll,
-#ifdef HAVE_UNLOCKED_IOCTL
- .unlocked_ioctl = LinuxDriver_UnlockedIoctl,
-#else
- .ioctl = LinuxDriver_Ioctl,
-#endif
-#ifdef HAVE_COMPAT_IOCTL
- .compat_ioctl = LinuxDriver_UnlockedIoctl,
-#endif
-};
-
-static struct VMCILinuxState linuxState = {
- .misc = {
- .name = VMCI_DEVICE_NAME,
- .minor = MISC_DYNAMIC_MINOR,
- .fops = &vmuser_fops,
- },
- .activeContexts = ATOMIC_INIT(0),
-};
-
-
-/*
- *----------------------------------------------------------------------
- *
- * Shared VMCI device definitions --
- *
- * Types and variables shared by both host and guest personality
- *
- *
- *----------------------------------------------------------------------
- */
-
-static Bool guestDeviceInit;
-static atomic_t guestDeviceActive;
-static Bool hostDeviceInit;
-
-/*
- *-----------------------------------------------------------------------------
- *
- * Host device support --
- *
- * The following functions implement the support for the VMCI
- * host driver.
- *
- *
- *-----------------------------------------------------------------------------
- */
-
-
-#ifdef VM_X86_64
-#ifndef HAVE_COMPAT_IOCTL
-static int
-LinuxDriver_Ioctl32_Handler(unsigned int fd, unsigned int iocmd,
- unsigned long ioarg, struct file * filp)
-{
- int ret;
- ret = -ENOTTY;
- if (filp && filp->f_op && filp->f_op->ioctl == LinuxDriver_Ioctl) {
- ret = LinuxDriver_Ioctl(filp->f_dentry->d_inode, filp, iocmd, ioarg);
- }
- return ret;
-}
-#endif /* !HAVE_COMPAT_IOCTL */
-
-static int
-register_ioctl32_handlers(void)
-{
-#ifndef HAVE_COMPAT_IOCTL
- {
- int i;
-
- for (i = IOCTL_VMCI_FIRST; i < IOCTL_VMCI_LAST; i++) {
- int retval = register_ioctl32_conversion(i,
- LinuxDriver_Ioctl32_Handler);
-
- if (retval) {
- Warning(LGPFX"Failed to register ioctl32 conversion "
- "(cmd=%d,err=%d).\n", i, retval);
- return retval;
- }
- }
-
- for (i = IOCTL_VMCI_FIRST2; i < IOCTL_VMCI_LAST2; i++) {
- int retval = register_ioctl32_conversion(i,
- LinuxDriver_Ioctl32_Handler);
-
- if (retval) {
- Warning(LGPFX"Failed to register ioctl32 conversion "
- "(cmd=%d,err=%d).\n", i, retval);
- return retval;
- }
- }
- }
-#endif /* !HAVE_COMPAT_IOCTL */
- return 0;
-}
-
-static void
-unregister_ioctl32_handlers(void)
-{
-#ifndef HAVE_COMPAT_IOCTL
- {
- int i;
-
- for (i = IOCTL_VMCI_FIRST; i < IOCTL_VMCI_LAST; i++) {
- int retval = unregister_ioctl32_conversion(i);
-
- if (retval) {
- Warning(LGPFX"Failed to unregister ioctl32 conversion "
- "(cmd=%d,err=%d).\n", i, retval);
- }
- }
-
- for (i = IOCTL_VMCI_FIRST2; i < IOCTL_VMCI_LAST2; i++) {
- int retval = unregister_ioctl32_conversion(i);
-
- if (retval) {
- Warning(LGPFX"Failed to unregister ioctl32 conversion "
- "(cmd=%d,err=%d).\n", i, retval);
- }
- }
- }
-#endif /* !HAVE_COMPAT_IOCTL */
-}
-#else /* VM_X86_64 */
-#define register_ioctl32_handlers() (0)
-#define unregister_ioctl32_handlers() do { } while (0)
-#endif /* VM_X86_64 */
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_host_init --
- *
- * Initializes the VMCI host device driver.
- *
- * Results:
- * 0 on success, other error codes on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-vmci_host_init(void)
-{
- int error;
-
- if (VMCI_HostInit() < VMCI_SUCCESS) {
- return -ENOMEM;
- }
-
- error = misc_register(&linuxState.misc);
- if (error) {
- Warning(LGPFX "Module registration error "
- "(name=%s, major=%d, minor=%d, err=%d).\n",
- linuxState.misc.name, MISC_MAJOR, linuxState.misc.minor,
- error);
- goto err_host_cleanup;
- }
-
- error = register_ioctl32_handlers();
- if (error) {
- Warning(LGPFX "Failed to register ioctl32 handlers, err: %d\n", error);
- goto err_misc_unregister;
- }
-
- Log(LGPFX "Module registered (name=%s, major=%d, minor=%d).\n",
- linuxState.misc.name, MISC_MAJOR, linuxState.misc.minor);
-
- return 0;
-
-err_misc_unregister:
- misc_deregister(&linuxState.misc);
-err_host_cleanup:
- VMCI_HostCleanup();
- return error;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * LinuxDriver_Open --
- *
- * Called on open of /dev/vmci.
- *
- * Side effects:
- * Increment use count used to determine eventual deallocation of
- * the module
- *
- *----------------------------------------------------------------------
- */
-
-static int
-LinuxDriver_Open(struct inode *inode, // IN
- struct file *filp) // IN
-{
- VMCILinux *vmciLinux;
-
- vmciLinux = kmalloc(sizeof *vmciLinux, GFP_KERNEL);
- if (vmciLinux == NULL) {
- return -ENOMEM;
- }
- memset(vmciLinux, 0, sizeof *vmciLinux);
- vmciLinux->ctType = VMCIOBJ_NOT_SET;
- vmciLinux->userVersion = 0;
-#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL)
- compat_mutex_init(&vmciLinux->lock);
-#endif
-
- filp->private_data = vmciLinux;
-
- return 0;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * LinuxDriver_Close --
- *
- * Called on close of /dev/vmci, most often when the process
- * exits.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-LinuxDriver_Close(struct inode *inode, // IN
- struct file *filp) // IN
-{
- VMCILinux *vmciLinux;
-
- vmciLinux = (VMCILinux *)filp->private_data;
- ASSERT(vmciLinux);
-
- if (vmciLinux->ctType == VMCIOBJ_CONTEXT) {
- ASSERT(vmciLinux->context);
-
- VMCIContext_ReleaseContext(vmciLinux->context);
- vmciLinux->context = NULL;
-
- /*
- * The number of active contexts is used to track whether any
- * VMX'en are using the host personality. It is incremented when
- * a context is created through the IOCTL_VMCI_INIT_CONTEXT
- * ioctl.
- */
-
- atomic_dec(&linuxState.activeContexts);
- }
- vmciLinux->ctType = VMCIOBJ_NOT_SET;
-
- kfree(vmciLinux);
- filp->private_data = NULL;
- return 0;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * LinuxDriverPoll --
- *
- * This is used to wake up the VMX when a VMCI call arrives, or
- * to wake up select() or poll() at the next clock tick.
- *
- *----------------------------------------------------------------------
- */
-
-static unsigned int
-LinuxDriverPoll(struct file *filp,
- poll_table *wait)
-{
- VMCILockFlags flags;
- VMCILinux *vmciLinux = (VMCILinux *) filp->private_data;
- unsigned int mask = 0;
-
- if (vmciLinux->ctType == VMCIOBJ_CONTEXT) {
- ASSERT(vmciLinux->context != NULL);
- /*
- * Check for VMCI calls to this VM context.
- */
-
- if (wait != NULL) {
- poll_wait(filp, &vmciLinux->context->hostContext.waitQueue, wait);
- }
-
- VMCI_GrabLock(&vmciLinux->context->lock, &flags);
- if (vmciLinux->context->pendingDatagrams > 0 ||
- VMCIHandleArray_GetSize(vmciLinux->context->pendingDoorbellArray) > 0) {
- mask = POLLIN;
- }
- VMCI_ReleaseLock(&vmciLinux->context->lock, flags);
- }
- return mask;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCICopyHandleArrayToUser --
- *
- * Copies the handles of a handle array into a user buffer, and
- * returns the new length in userBufferSize. If the copy to the
- * user buffer fails, the functions still returns VMCI_SUCCESS,
- * but retval != 0.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-VMCICopyHandleArrayToUser(void *userBufUVA, // IN
- uint64 *userBufSize, // IN/OUT
- VMCIHandleArray *handleArray, // IN
- int *retval) // IN
-{
- uint32 arraySize;
- VMCIHandle *handles;
-
- if (handleArray) {
- arraySize = VMCIHandleArray_GetSize(handleArray);
- } else {
- arraySize = 0;
- }
-
- if (arraySize * sizeof *handles > *userBufSize) {
- return VMCI_ERROR_MORE_DATA;
- }
-
- *userBufSize = arraySize * sizeof *handles;
- if (*userBufSize) {
- *retval = copy_to_user(userBufUVA,
- VMCIHandleArray_GetHandles(handleArray),
- *userBufSize);
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIDoQPBrokerAlloc --
- *
- * Helper function for creating queue pair and copying the result
- * to user memory.
- *
- * Results:
- * 0 if result value was copied to user memory, -EFAULT otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCIDoQPBrokerAlloc(VMCIHandle handle,
- VMCIId peer,
- uint32 flags,
- uint64 produceSize,
- uint64 consumeSize,
- QueuePairPageStore *pageStore,
- VMCIContext *context,
- Bool vmToVm,
- void *resultUVA)
-{
- VMCIId cid;
- int result;
- int retval;
-
- cid = VMCIContext_GetId(context);
-
- result = VMCIQPBroker_Alloc(handle, peer, flags, VMCI_NO_PRIVILEGE_FLAGS,
- produceSize, consumeSize, pageStore, context);
- if (result == VMCI_SUCCESS && vmToVm) {
- result = VMCI_SUCCESS_QUEUEPAIR_CREATE;
- }
- retval = copy_to_user(resultUVA, &result, sizeof result);
- if (retval) {
- retval = -EFAULT;
- if (result >= VMCI_SUCCESS) {
- result = VMCIQPBroker_Detach(handle, context);
- ASSERT(result >= VMCI_SUCCESS);
- }
- }
-
- return retval;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * LinuxDriver_Ioctl --
- *
- * Main path for UserRPC
- *
- * Results:
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-LinuxDriver_Ioctl(struct inode *inode,
- struct file *filp,
- u_int iocmd,
- unsigned long ioarg)
-{
- VMCILinux *vmciLinux = (VMCILinux *) filp->private_data;
- int retval = 0;
-
- switch (iocmd) {
- case IOCTL_VMCI_VERSION2: {
- int verFromUser;
-
- if (copy_from_user(&verFromUser, (void *)ioarg, sizeof verFromUser)) {
- retval = -EFAULT;
- break;
- }
-
- vmciLinux->userVersion = verFromUser;
- }
- /* Fall through. */
- case IOCTL_VMCI_VERSION:
- /*
- * The basic logic here is:
- *
- * If the user sends in a version of 0 tell it our version.
- * If the user didn't send in a version, tell it our version.
- * If the user sent in an old version, tell it -its- version.
- * If the user sent in an newer version, tell it our version.
- *
- * The rationale behind telling the caller its version is that
- * Workstation 6.5 required that VMX and VMCI kernel module were
- * version sync'd. All new VMX users will be programmed to
- * handle the VMCI kernel module version.
- */
-
- if (vmciLinux->userVersion > 0 &&
- vmciLinux->userVersion < VMCI_VERSION_HOSTQP) {
- retval = vmciLinux->userVersion;
- } else {
- retval = VMCI_VERSION;
- }
- break;
-
- case IOCTL_VMCI_INIT_CONTEXT: {
- VMCIInitBlock initBlock;
- VMCIHostUser user;
-
- retval = copy_from_user(&initBlock, (void *)ioarg, sizeof initBlock);
- if (retval != 0) {
- Log(LGPFX"Error reading init block.\n");
- retval = -EFAULT;
- break;
- }
-
- LinuxDriverLockIoctlPerFD(&vmciLinux->lock);
- if (vmciLinux->ctType != VMCIOBJ_NOT_SET) {
- Log(LGPFX"Received VMCI init on initialized handle.\n");
- retval = -EINVAL;
- goto init_release;
- }
-
- if (initBlock.flags & ~VMCI_PRIVILEGE_FLAG_RESTRICTED) {
- Log(LGPFX"Unsupported VMCI restriction flag.\n");
- retval = -EINVAL;
- goto init_release;
- }
-
- user = current_uid();
- retval = VMCIContext_InitContext(initBlock.cid, initBlock.flags,
- 0 /* Unused */, vmciLinux->userVersion,
- &user, &vmciLinux->context);
- if (retval < VMCI_SUCCESS) {
- Log(LGPFX"Error initializing context.\n");
- retval = retval == VMCI_ERROR_DUPLICATE_ENTRY ? -EEXIST : -EINVAL;
- goto init_release;
- }
-
- /*
- * Copy cid to userlevel, we do this to allow the VMX to enforce its
- * policy on cid generation.
- */
- initBlock.cid = VMCIContext_GetId(vmciLinux->context);
- retval = copy_to_user((void *)ioarg, &initBlock, sizeof initBlock);
- if (retval != 0) {
- VMCIContext_ReleaseContext(vmciLinux->context);
- vmciLinux->context = NULL;
- Log(LGPFX"Error writing init block.\n");
- retval = -EFAULT;
- goto init_release;
- }
- ASSERT(initBlock.cid != VMCI_INVALID_ID);
-
- vmciLinux->ctType = VMCIOBJ_CONTEXT;
-
- atomic_inc(&linuxState.activeContexts);
-
- init_release:
- LinuxDriverUnlockIoctlPerFD(&vmciLinux->lock);
- break;
- }
-
- case IOCTL_VMCI_DATAGRAM_SEND: {
- VMCIDatagramSendRecvInfo sendInfo;
- VMCIDatagram *dg = NULL;
- VMCIId cid;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Warning(LGPFX"Ioctl only valid for context handle (iocmd=%d).\n", iocmd);
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&sendInfo, (void *) ioarg, sizeof sendInfo);
- if (retval) {
- Warning(LGPFX"copy_from_user failed.\n");
- retval = -EFAULT;
- break;
- }
-
- if (sendInfo.len > VMCI_MAX_DG_SIZE) {
- Warning(LGPFX"Datagram too big (size=%d).\n", sendInfo.len);
- retval = -EINVAL;
- break;
- }
-
- if (sendInfo.len < sizeof *dg) {
- Warning(LGPFX"Datagram too small (size=%d).\n", sendInfo.len);
- retval = -EINVAL;
- break;
- }
-
- dg = VMCI_AllocKernelMem(sendInfo.len, VMCI_MEMORY_NORMAL);
- if (dg == NULL) {
- Log(LGPFX"Cannot allocate memory to dispatch datagram.\n");
- retval = -ENOMEM;
- break;
- }
-
- retval = copy_from_user(dg, (char *)(VA)sendInfo.addr, sendInfo.len);
- if (retval != 0) {
- Log(LGPFX"Error getting datagram (err=%d).\n", retval);
- VMCI_FreeKernelMem(dg, sendInfo.len);
- retval = -EFAULT;
- break;
- }
-
- VMCI_DEBUG_LOG(10, (LGPFX"Datagram dst (handle=0x%x:0x%x) src "
- "(handle=0x%x:0x%x), payload (size=%"FMT64"u "
- "bytes).\n", dg->dst.context, dg->dst.resource,
- dg->src.context, dg->src.resource,
- dg->payloadSize));
-
- /* Get source context id. */
- ASSERT(vmciLinux->context);
- cid = VMCIContext_GetId(vmciLinux->context);
- ASSERT(cid != VMCI_INVALID_ID);
- sendInfo.result = VMCIDatagram_Dispatch(cid, dg, TRUE);
- VMCI_FreeKernelMem(dg, sendInfo.len);
- retval = copy_to_user((void *)ioarg, &sendInfo, sizeof sendInfo);
- break;
- }
-
- case IOCTL_VMCI_DATAGRAM_RECEIVE: {
- VMCIDatagramSendRecvInfo recvInfo;
- VMCIDatagram *dg = NULL;
- size_t size;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Warning(LGPFX"Ioctl only valid for context handle (iocmd=%d).\n",
- iocmd);
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&recvInfo, (void *) ioarg, sizeof recvInfo);
- if (retval) {
- Warning(LGPFX"copy_from_user failed.\n");
- retval = -EFAULT;
- break;
- }
-
- ASSERT(vmciLinux->ctType == VMCIOBJ_CONTEXT);
-
- size = recvInfo.len;
- ASSERT(vmciLinux->context);
- recvInfo.result = VMCIContext_DequeueDatagram(vmciLinux->context,
- &size, &dg);
-
- if (recvInfo.result >= VMCI_SUCCESS) {
- ASSERT(dg);
- retval = copy_to_user((void *) ((uintptr_t) recvInfo.addr), dg,
- VMCI_DG_SIZE(dg));
- VMCI_FreeKernelMem(dg, VMCI_DG_SIZE(dg));
- if (retval != 0) {
- break;
- }
- }
- retval = copy_to_user((void *)ioarg, &recvInfo, sizeof recvInfo);
- break;
- }
-
- case IOCTL_VMCI_QUEUEPAIR_ALLOC: {
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_ALLOC only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- if (vmciLinux->userVersion < VMCI_VERSION_NOVMVM) {
- VMCIQueuePairAllocInfo_VMToVM queuePairAllocInfo;
- VMCIQueuePairAllocInfo_VMToVM *info = (VMCIQueuePairAllocInfo_VMToVM *)ioarg;
-
- retval = copy_from_user(&queuePairAllocInfo, (void *)ioarg,
- sizeof queuePairAllocInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- retval = VMCIDoQPBrokerAlloc(queuePairAllocInfo.handle,
- queuePairAllocInfo.peer,
- queuePairAllocInfo.flags,
- queuePairAllocInfo.produceSize,
- queuePairAllocInfo.consumeSize,
- NULL,
- vmciLinux->context,
- TRUE, // VM to VM style create
- &info->result);
- } else {
- VMCIQueuePairAllocInfo queuePairAllocInfo;
- VMCIQueuePairAllocInfo *info = (VMCIQueuePairAllocInfo *)ioarg;
- QueuePairPageStore pageStore;
-
- retval = copy_from_user(&queuePairAllocInfo, (void *)ioarg,
- sizeof queuePairAllocInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- pageStore.pages = queuePairAllocInfo.ppnVA;
- pageStore.len = queuePairAllocInfo.numPPNs;
-
- retval = VMCIDoQPBrokerAlloc(queuePairAllocInfo.handle,
- queuePairAllocInfo.peer,
- queuePairAllocInfo.flags,
- queuePairAllocInfo.produceSize,
- queuePairAllocInfo.consumeSize,
- &pageStore,
- vmciLinux->context,
- FALSE, // Not VM to VM style create
- &info->result);
- }
- break;
- }
-
- case IOCTL_VMCI_QUEUEPAIR_SETVA: {
- VMCIQueuePairSetVAInfo setVAInfo;
- VMCIQueuePairSetVAInfo *info = (VMCIQueuePairSetVAInfo *)ioarg;
- int32 result;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_SETVA only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- if (vmciLinux->userVersion < VMCI_VERSION_NOVMVM) {
- Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_SETVA not supported for this VMX version.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&setVAInfo, (void *)ioarg, sizeof setVAInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- if (setVAInfo.va) {
- /*
- * VMX is passing down a new VA for the queue pair mapping.
- */
-
- result = VMCIQPBroker_Map(setVAInfo.handle, vmciLinux->context, setVAInfo.va);
- } else {
- /*
- * The queue pair is about to be unmapped by the VMX.
- */
-
- result = VMCIQPBroker_Unmap(setVAInfo.handle, vmciLinux->context, 0);
- }
-
- retval = copy_to_user(&info->result, &result, sizeof result);
- if (retval) {
- retval = -EFAULT;
- }
-
- break;
- }
-
- case IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE: {
- VMCIQueuePairPageFileInfo pageFileInfo;
- VMCIQueuePairPageFileInfo *info = (VMCIQueuePairPageFileInfo *)ioarg;
- int32 result;
-
- if (vmciLinux->userVersion < VMCI_VERSION_HOSTQP ||
- vmciLinux->userVersion >= VMCI_VERSION_NOVMVM) {
- Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE not supported this VMX "
- "(version=%d).\n", vmciLinux->userVersion);
- retval = -EINVAL;
- break;
- }
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&pageFileInfo, (void *)ioarg, sizeof *info);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- /*
- * Communicate success pre-emptively to the caller. Note that
- * the basic premise is that it is incumbent upon the caller not
- * to look at the info.result field until after the ioctl()
- * returns. And then, only if the ioctl() result indicates no
- * error. We send up the SUCCESS status before calling
- * SetPageStore() store because failing to copy up the result
- * code means unwinding the SetPageStore().
- *
- * It turns out the logic to unwind a SetPageStore() opens a can
- * of worms. For example, if a host had created the QueuePair
- * and a guest attaches and SetPageStore() is successful but
- * writing success fails, then ... the host has to be stopped
- * from writing (anymore) data into the QueuePair. That means
- * an additional test in the VMCI_Enqueue() code path. Ugh.
- */
-
- result = VMCI_SUCCESS;
- retval = copy_to_user(&info->result, &result, sizeof result);
- if (retval == 0) {
- result = VMCIQPBroker_SetPageStore(pageFileInfo.handle,
- pageFileInfo.produceVA,
- pageFileInfo.consumeVA,
- vmciLinux->context);
- if (result < VMCI_SUCCESS) {
-
- retval = copy_to_user(&info->result, &result, sizeof result);
- if (retval != 0) {
- /*
- * Note that in this case the SetPageStore() call
- * failed but we were unable to communicate that to the
- * caller (because the copy_to_user() call failed).
- * So, if we simply return an error (in this case
- * -EFAULT) then the caller will know that the
- * SetPageStore failed even though we couldn't put the
- * result code in the result field and indicate exactly
- * why it failed.
- *
- * That says nothing about the issue where we were once
- * able to write to the caller's info memory and now
- * can't. Something more serious is probably going on
- * than the fact that SetPageStore() didn't work.
- */
- retval = -EFAULT;
- }
- }
-
- } else {
- /*
- * In this case, we can't write a result field of the
- * caller's info block. So, we don't even try to
- * SetPageStore().
- */
- retval = -EFAULT;
- }
-
- break;
- }
-
- case IOCTL_VMCI_QUEUEPAIR_DETACH: {
- VMCIQueuePairDetachInfo detachInfo;
- VMCIQueuePairDetachInfo *info = (VMCIQueuePairDetachInfo *)ioarg;
- int32 result;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_QUEUEPAIR_DETACH only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&detachInfo, (void *)ioarg, sizeof detachInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- result = VMCIQPBroker_Detach(detachInfo.handle, vmciLinux->context);
- if (result == VMCI_SUCCESS &&
- vmciLinux->userVersion < VMCI_VERSION_NOVMVM) {
- result = VMCI_SUCCESS_LAST_DETACH;
- }
-
- retval = copy_to_user(&info->result, &result, sizeof result);
- if (retval) {
- retval = -EFAULT;
- }
-
- break;
- }
-
- case IOCTL_VMCI_CTX_ADD_NOTIFICATION: {
- VMCINotifyAddRemoveInfo arInfo;
- VMCINotifyAddRemoveInfo *info = (VMCINotifyAddRemoveInfo *)ioarg;
- int32 result;
- VMCIId cid;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_CTX_ADD_NOTIFICATION only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&arInfo, (void *)ioarg, sizeof arInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- cid = VMCIContext_GetId(vmciLinux->context);
- result = VMCIContext_AddNotification(cid, arInfo.remoteCID);
- retval = copy_to_user(&info->result, &result, sizeof result);
- if (retval) {
- retval = -EFAULT;
- break;
- }
- break;
- }
-
- case IOCTL_VMCI_CTX_REMOVE_NOTIFICATION: {
- VMCINotifyAddRemoveInfo arInfo;
- VMCINotifyAddRemoveInfo *info = (VMCINotifyAddRemoveInfo *)ioarg;
- int32 result;
- VMCIId cid;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_CTX_REMOVE_NOTIFICATION only valid for "
- "contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&arInfo, (void *)ioarg, sizeof arInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- cid = VMCIContext_GetId(vmciLinux->context);
- result = VMCIContext_RemoveNotification(cid, arInfo.remoteCID);
- retval = copy_to_user(&info->result, &result, sizeof result);
- if (retval) {
- retval = -EFAULT;
- break;
- }
- break;
- }
-
- case IOCTL_VMCI_CTX_GET_CPT_STATE: {
- VMCICptBufInfo getInfo;
- VMCIId cid;
- char *cptBuf;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_CTX_GET_CPT_STATE only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&getInfo, (void *)ioarg, sizeof getInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- cid = VMCIContext_GetId(vmciLinux->context);
- getInfo.result = VMCIContext_GetCheckpointState(cid, getInfo.cptType,
- &getInfo.bufSize,
- &cptBuf);
- if (getInfo.result == VMCI_SUCCESS && getInfo.bufSize) {
- retval = copy_to_user((void *)(VA)getInfo.cptBuf, cptBuf,
- getInfo.bufSize);
- VMCI_FreeKernelMem(cptBuf, getInfo.bufSize);
- if (retval) {
- retval = -EFAULT;
- break;
- }
- }
- retval = copy_to_user((void *)ioarg, &getInfo, sizeof getInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
- break;
- }
-
- case IOCTL_VMCI_CTX_SET_CPT_STATE: {
- VMCICptBufInfo setInfo;
- VMCIId cid;
- char *cptBuf;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_CTX_SET_CPT_STATE only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&setInfo, (void *)ioarg, sizeof setInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- cptBuf = VMCI_AllocKernelMem(setInfo.bufSize, VMCI_MEMORY_NORMAL);
- if (cptBuf == NULL) {
- Log(LGPFX"Cannot allocate memory to set cpt state (type=%d).\n",
- setInfo.cptType);
- retval = -ENOMEM;
- break;
- }
- retval = copy_from_user(cptBuf, (void *)(VA)setInfo.cptBuf,
- setInfo.bufSize);
- if (retval) {
- VMCI_FreeKernelMem(cptBuf, setInfo.bufSize);
- retval = -EFAULT;
- break;
- }
-
- cid = VMCIContext_GetId(vmciLinux->context);
- setInfo.result = VMCIContext_SetCheckpointState(cid, setInfo.cptType,
- setInfo.bufSize, cptBuf);
- VMCI_FreeKernelMem(cptBuf, setInfo.bufSize);
- retval = copy_to_user((void *)ioarg, &setInfo, sizeof setInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
- break;
- }
-
- case IOCTL_VMCI_GET_CONTEXT_ID: {
- VMCIId cid = VMCI_HOST_CONTEXT_ID;
-
- retval = copy_to_user((void *)ioarg, &cid, sizeof cid);
- break;
- }
-
- case IOCTL_VMCI_SET_NOTIFY: {
- VMCISetNotifyInfo notifyInfo;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_SET_NOTIFY only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&notifyInfo, (void *)ioarg, sizeof notifyInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- if ((VA)notifyInfo.notifyUVA != (VA)NULL) {
- notifyInfo.result = VMCISetupNotify(vmciLinux->context,
- (VA)notifyInfo.notifyUVA);
- } else {
- VMCIUnsetNotifyInt(vmciLinux->context, TRUE);
- notifyInfo.result = VMCI_SUCCESS;
- }
-
- retval = copy_to_user((void *)ioarg, &notifyInfo, sizeof notifyInfo);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- break;
- }
-
- case IOCTL_VMCI_NOTIFY_RESOURCE: {
- VMCINotifyResourceInfo info;
- VMCIId cid;
-
- if (vmciLinux->userVersion < VMCI_VERSION_NOTIFY) {
- Log(LGPFX"IOCTL_VMCI_NOTIFY_RESOURCE is invalid for current"
- " VMX versions.\n");
- retval = -EINVAL;
- break;
- }
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_NOTIFY_RESOURCE is only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&info, (void *)ioarg, sizeof info);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- cid = VMCIContext_GetId(vmciLinux->context);
- switch (info.action) {
- case VMCI_NOTIFY_RESOURCE_ACTION_NOTIFY:
- if (info.resource == VMCI_NOTIFY_RESOURCE_DOOR_BELL) {
- info.result = VMCIContext_NotifyDoorbell(cid, info.handle,
- VMCI_NO_PRIVILEGE_FLAGS);
- } else {
- info.result = VMCI_ERROR_UNAVAILABLE;
- }
- break;
- case VMCI_NOTIFY_RESOURCE_ACTION_CREATE:
- info.result = VMCIContext_DoorbellCreate(cid, info.handle);
- break;
- case VMCI_NOTIFY_RESOURCE_ACTION_DESTROY:
- info.result = VMCIContext_DoorbellDestroy(cid, info.handle);
- break;
- default:
- Log(LGPFX"IOCTL_VMCI_NOTIFY_RESOURCE got unknown action (action=%d).\n",
- info.action);
- info.result = VMCI_ERROR_INVALID_ARGS;
- }
- retval = copy_to_user((void *)ioarg, &info,
- sizeof info);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- break;
- }
-
- case IOCTL_VMCI_NOTIFICATIONS_RECEIVE: {
- VMCINotificationReceiveInfo info;
- VMCIHandleArray *dbHandleArray;
- VMCIHandleArray *qpHandleArray;
- VMCIId cid;
-
- if (vmciLinux->ctType != VMCIOBJ_CONTEXT) {
- Log(LGPFX"IOCTL_VMCI_NOTIFICATIONS_RECEIVE is only valid for contexts.\n");
- retval = -EINVAL;
- break;
- }
-
- if (vmciLinux->userVersion < VMCI_VERSION_NOTIFY) {
- Log(LGPFX"IOCTL_VMCI_NOTIFICATIONS_RECEIVE is not supported for the"
- " current vmx version.\n");
- retval = -EINVAL;
- break;
- }
-
- retval = copy_from_user(&info, (void *)ioarg, sizeof info);
- if (retval) {
- retval = -EFAULT;
- break;
- }
-
- if ((info.dbHandleBufSize && !info.dbHandleBufUVA) ||
- (info.qpHandleBufSize && !info.qpHandleBufUVA)) {
- retval = -EINVAL;
- break;
- }
-
- cid = VMCIContext_GetId(vmciLinux->context);
- info.result = VMCIContext_ReceiveNotificationsGet(cid,
- &dbHandleArray,
- &qpHandleArray);
- if (info.result == VMCI_SUCCESS) {
- info.result =
- VMCICopyHandleArrayToUser((void *)(VA)info.dbHandleBufUVA,
- &info.dbHandleBufSize,
- dbHandleArray,
- &retval);
- if (info.result == VMCI_SUCCESS && !retval) {
- info.result =
- VMCICopyHandleArrayToUser((void *)(VA)info.qpHandleBufUVA,
- &info.qpHandleBufSize,
- qpHandleArray,
- &retval);
- }
- if (!retval) {
- retval = copy_to_user((void *)ioarg, &info, sizeof info);
- }
- VMCIContext_ReceiveNotificationsRelease(cid, dbHandleArray, qpHandleArray,
- info.result == VMCI_SUCCESS && !retval);
- } else {
- retval = copy_to_user((void *)ioarg, &info, sizeof info);
- }
- break;
- }
-
- default:
- Warning(LGPFX"Unknown ioctl (iocmd=%d).\n", iocmd);
- retval = -EINVAL;
- }
-
- return retval;
-}
-
-
-#if defined(HAVE_COMPAT_IOCTL) || defined(HAVE_UNLOCKED_IOCTL)
-/*
- *-----------------------------------------------------------------------------
- *
- * LinuxDriver_UnlockedIoctl --
- *
- * Wrapper for LinuxDriver_Ioctl supporting the compat_ioctl and
- * unlocked_ioctl methods that have signatures different from the
- * old ioctl. Used as compat_ioctl method for 32bit apps running
- * on 64bit kernel and for unlocked_ioctl on systems supporting
- * those. LinuxDriver_Ioctl may safely be called without holding
- * the BKL.
- *
- * Results:
- * Same as LinuxDriver_Ioctl.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static long
-LinuxDriver_UnlockedIoctl(struct file *filp,
- u_int iocmd,
- unsigned long ioarg)
-{
- return LinuxDriver_Ioctl(NULL, filp, iocmd, ioarg);
-}
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIUserVAInvalidPointer --
- *
- * Checks if a given user VA is valid or not. Copied from
- * bora/modules/vmnet/linux/hostif.c:VNetUserIfInvalidPointer(). TODO
- * libify the common code.
- *
- * Results:
- * TRUE iff invalid.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE Bool
-VMCIUserVAInvalidPointer(VA uva, // IN:
- size_t size) // IN:
-{
- return !access_ok(VERIFY_WRITE, (void *)uva, size);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIUserVALockPage --
- *
- * Lock physical page backing a given user VA. Copied from
- * bora/modules/vmnet/linux/userif.c:UserIfLockPage(). TODO libify the
- * common code.
- *
- * Results:
- * Pointer to struct page on success, NULL otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE struct page *
-VMCIUserVALockPage(VA addr) // IN:
-{
- struct page *page = NULL;
- int retval;
-
- down_read(&current->mm->mmap_sem);
- retval = get_user_pages(current, current->mm, addr,
- 1, 1, 0, &page, NULL);
- up_read(&current->mm->mmap_sem);
-
- if (retval != 1) {
- return NULL;
- }
-
- return page;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMapBoolPtr --
- *
- * Lock physical page backing a given user VA and maps it to kernel
- * address space. The range of the mapped memory should be within a
- * single page otherwise an error is returned. Copied from
- * bora/modules/vmnet/linux/userif.c:VNetUserIfMapUint32Ptr(). TODO
- * libify the common code.
- *
- * Results:
- * 0 on success, negative error code otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE int
-VMCIMapBoolPtr(VA notifyUVA, // IN:
- struct page **p, // OUT:
- Bool **notifyPtr) // OUT:
-{
- if (VMCIUserVAInvalidPointer(notifyUVA, sizeof **notifyPtr) ||
- (((notifyUVA + sizeof **notifyPtr - 1) & ~(PAGE_SIZE - 1)) !=
- (notifyUVA & ~(PAGE_SIZE - 1)))) {
- return -EINVAL;
- }
-
- *p = VMCIUserVALockPage(notifyUVA);
- if (*p == NULL) {
- return -EAGAIN;
- }
-
- *notifyPtr = (Bool *)((uint8 *)kmap(*p) + (notifyUVA & (PAGE_SIZE - 1)));
- return 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCISetupNotify --
- *
- * Sets up a given context for notify to work. Calls VMCIMapBoolPtr()
- * which maps the notify boolean in user VA in kernel space.
- *
- * Results:
- * VMCI_SUCCESS on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-VMCISetupNotify(VMCIContext *context, // IN:
- VA notifyUVA) // IN:
-{
- int retval;
-
- if (context->notify) {
- Warning(LGPFX"Notify mechanism is already set up.\n");
- return VMCI_ERROR_DUPLICATE_ENTRY;
- }
-
- retval =
- VMCIMapBoolPtr(notifyUVA, &context->notifyPage, &context->notify) == 0 ?
- VMCI_SUCCESS : VMCI_ERROR_GENERIC;
- if (retval == VMCI_SUCCESS) {
- VMCIContext_CheckAndSignalNotify(context);
- }
-
- return retval;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIUnsetNotifyInt --
- *
- * Internal version of VMCIUnsetNotify, that allows for locking
- * the context before unsetting the notify pointer. If useLock is
- * TRUE, the context lock is grabbed.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIUnsetNotifyInt(VMCIContext *context, // IN
- Bool useLock) // IN
-{
- VMCILockFlags flags;
-
- if (useLock) {
- VMCI_GrabLock(&context->lock, &flags);
- }
-
- if (context->notifyPage) {
- struct page *notifyPage = context->notifyPage;
-
- context->notify = NULL;
- context->notifyPage = NULL;
-
- if (useLock) {
- VMCI_ReleaseLock(&context->lock, flags);
- }
-
- kunmap(notifyPage);
- put_page(notifyPage);
- } else {
- if (useLock) {
- VMCI_ReleaseLock(&context->lock, flags);
- }
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIUnsetNotify --
- *
- * Reverts actions set up by VMCISetupNotify(). Unmaps and unlocks the
- * page mapped/locked by VMCISetupNotify().
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIUnsetNotify(VMCIContext *context) // IN:
-{
- VMCIUnsetNotifyInt(context, FALSE);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * PCI device support --
- *
- * The following functions implement the support for the VMCI
- * guest device. This includes initializing the device and
- * interrupt handling.
- *
- *-----------------------------------------------------------------------------
- */
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_guest_init --
- *
- * Initializes the VMCI PCI device. The initialization might fail
- * if there is no VMCI PCI device.
- *
- * Results:
- * 0 on success, other error codes on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-vmci_guest_init(void)
-{
- int retval;
-
- /* Initialize guest device data. */
- compat_mutex_init(&vmci_dev.lock);
- vmci_dev.intr_type = VMCI_INTR_TYPE_INTX;
- vmci_dev.exclusive_vectors = FALSE;
- spin_lock_init(&vmci_dev.dev_spinlock);
- vmci_dev.enabled = FALSE;
- atomic_set(&vmci_dev.datagrams_allowed, 0);
- atomic_set(&guestDeviceActive, 0);
-
- data_buffer = vmalloc(data_buffer_size);
- if (!data_buffer) {
- return -ENOMEM;
- }
-
- /* This should be last to make sure we are done initializing. */
- retval = pci_register_driver(&vmci_driver);
- if (retval < 0) {
- vfree(data_buffer);
- data_buffer = NULL;
- return retval;
- }
-
- return 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_enable_msix --
- *
- * Enable MSI-X. Try exclusive vectors first, then shared vectors.
- *
- * Results:
- * 0 on success, other error codes on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-vmci_enable_msix(struct pci_dev *pdev) // IN
-{
- int i;
- int result;
-
- for (i = 0; i < VMCI_MAX_INTRS; ++i) {
- vmci_dev.msix_entries[i].entry = i;
- vmci_dev.msix_entries[i].vector = i;
- }
-
- result = pci_enable_msix(pdev, vmci_dev.msix_entries, VMCI_MAX_INTRS);
- if (!result) {
- vmci_dev.exclusive_vectors = TRUE;
- } else if (result > 0) {
- result = pci_enable_msix(pdev, vmci_dev.msix_entries, 1);
- }
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_probe_device --
- *
- * Most of the initialization at module load time is done here.
- *
- * Results:
- * Returns 0 for success, an error otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static int
-vmci_probe_device(struct pci_dev *pdev, // IN: vmci PCI device
- const struct pci_device_id *id) // IN: matching device ID
-{
- unsigned int ioaddr;
- unsigned int ioaddr_size;
- unsigned int capabilities;
- int result;
-
- printk(KERN_INFO "Probing for vmci/PCI.\n");
-
- result = pci_enable_device(pdev);
- if (result) {
- printk(KERN_ERR "Cannot VMCI device %s: error %d\n",
- pci_name(pdev), result);
- return result;
- }
- pci_set_master(pdev); /* To enable QueuePair functionality. */
- ioaddr = pci_resource_start(pdev, 0);
- ioaddr_size = pci_resource_len(pdev, 0);
-
- /*
- * Request I/O region with adjusted base address and size. The adjusted
- * values are needed and used if we release the region in case of failure.
- */
-
- if (!compat_request_region(ioaddr, ioaddr_size, "vmci")) {
- printk(KERN_INFO "vmci: Another driver already loaded "
- "for device in slot %s.\n", pci_name(pdev));
- goto pci_disable;
- }
-
- printk(KERN_INFO "Found vmci/PCI at %#x, irq %u.\n", ioaddr, pdev->irq);
-
- /*
- * Verify that the VMCI Device supports the capabilities that
- * we need. If the device is missing capabilities that we would
- * like to use, check for fallback capabilities and use those
- * instead (so we can run a new VM on old hosts). Fail the load if
- * a required capability is missing and there is no fallback.
- *
- * Right now, we need datagrams. There are no fallbacks.
- */
- capabilities = inl(ioaddr + VMCI_CAPS_ADDR);
-
- if ((capabilities & VMCI_CAPS_DATAGRAM) == 0) {
- printk(KERN_ERR "VMCI device does not support datagrams.\n");
- goto release;
- }
-
- /*
- * If the hardware supports notifications, we will use that as
- * well.
- */
- if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
- capabilities = VMCI_CAPS_DATAGRAM;
- notification_bitmap = vmalloc(PAGE_SIZE);
- if (notification_bitmap == NULL) {
- printk(KERN_ERR "VMCI device unable to allocate notification bitmap.\n");
- } else {
- memset(notification_bitmap, 0, PAGE_SIZE);
- capabilities |= VMCI_CAPS_NOTIFICATIONS;
- }
- } else {
- capabilities = VMCI_CAPS_DATAGRAM;
- }
- printk(KERN_INFO "VMCI: using capabilities 0x%x.\n", capabilities);
-
- /* Let the host know which capabilities we intend to use. */
- outl(capabilities, ioaddr + VMCI_CAPS_ADDR);
-
- /* Device struct initialization. */
- compat_mutex_lock(&vmci_dev.lock);
- if (vmci_dev.enabled) {
- printk(KERN_ERR "VMCI device already enabled.\n");
- goto unlock;
- }
-
- vmci_dev.ioaddr = ioaddr;
- vmci_dev.ioaddr_size = ioaddr_size;
- atomic_set(&vmci_dev.datagrams_allowed, 1);
-
- /*
- * Register notification bitmap with device if that capability is
- * used
- */
- if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
- unsigned long bitmapPPN;
- bitmapPPN = page_to_pfn(vmalloc_to_page(notification_bitmap));
- if (!VMCI_RegisterNotificationBitmap(bitmapPPN)) {
- printk(KERN_ERR "VMCI device unable to register notification bitmap "
- "with PPN 0x%x.\n", (uint32)bitmapPPN);
- goto datagram_disallow;
- }
- }
-
- /* Check host capabilities. */
- if (!VMCI_CheckHostCapabilities()) {
- goto remove_bitmap;
- }
-
- /* Enable device. */
- vmci_dev.enabled = TRUE;
- pci_set_drvdata(pdev, &vmci_dev);
-
- /*
- * We do global initialization here because we need datagrams
- * during VMCIUtil_Init, since it registers for VMCI events. If we
- * ever support more than one VMCI device we will have to create
- * seperate LateInit/EarlyExit functions that can be used to do
- * initialization/cleanup that depends on the device being
- * accessible. We need to initialize VMCI components before
- * requesting an irq - the VMCI interrupt handler uses these
- * components, and it may be invoked once request_irq() has
- * registered the handler (as the irq line may be shared).
- */
- VMCIUtil_Init();
-
- if (VMCIQPGuestEndpoints_Init() < VMCI_SUCCESS) {
- goto util_exit;
- }
-
- /*
- * Enable interrupts. Try MSI-X first, then MSI, and then fallback on
- * legacy interrupts.
- */
- if (!vmci_disable_msix && !vmci_enable_msix(pdev)) {
- vmci_dev.intr_type = VMCI_INTR_TYPE_MSIX;
- vmci_dev.irq = vmci_dev.msix_entries[0].vector;
- } else if (!vmci_disable_msi && !pci_enable_msi(pdev)) {
- vmci_dev.intr_type = VMCI_INTR_TYPE_MSI;
- vmci_dev.irq = pdev->irq;
- } else {
- vmci_dev.intr_type = VMCI_INTR_TYPE_INTX;
- vmci_dev.irq = pdev->irq;
- }
-
- /* Request IRQ for legacy or MSI interrupts, or for first MSI-X vector. */
- result = request_irq(vmci_dev.irq, vmci_interrupt, COMPAT_IRQF_SHARED,
- "vmci", &vmci_dev);
- if (result) {
- printk(KERN_ERR "vmci: irq %u in use: %d\n", vmci_dev.irq, result);
- goto components_exit;
- }
-
- /*
- * For MSI-X with exclusive vectors we need to request an interrupt for each
- * vector so that we get a separate interrupt handler routine. This allows
- * us to distinguish between the vectors.
- */
-
- if (vmci_dev.exclusive_vectors) {
- ASSERT(vmci_dev.intr_type == VMCI_INTR_TYPE_MSIX);
- result = request_irq(vmci_dev.msix_entries[1].vector, vmci_interrupt_bm,
- 0, "vmci", &vmci_dev);
- if (result) {
- printk(KERN_ERR "vmci: irq %u in use: %d\n",
- vmci_dev.msix_entries[1].vector, result);
- free_irq(vmci_dev.irq, &vmci_dev);
- goto components_exit;
- }
- }
-
- printk(KERN_INFO "Registered vmci device.\n");
-
- atomic_inc(&guestDeviceActive);
-
- compat_mutex_unlock(&vmci_dev.lock);
-
- /* Enable specific interrupt bits. */
- if (capabilities & VMCI_CAPS_NOTIFICATIONS) {
- outl(VMCI_IMR_DATAGRAM | VMCI_IMR_NOTIFICATION,
- vmci_dev.ioaddr + VMCI_IMR_ADDR);
- } else {
- outl(VMCI_IMR_DATAGRAM, vmci_dev.ioaddr + VMCI_IMR_ADDR);
- }
-
- /* Enable interrupts. */
- outl(VMCI_CONTROL_INT_ENABLE, vmci_dev.ioaddr + VMCI_CONTROL_ADDR);
-
- return 0;
-
- components_exit:
- VMCIQPGuestEndpoints_Exit();
- util_exit:
- VMCIUtil_Exit();
- vmci_dev.enabled = FALSE;
- if (vmci_dev.intr_type == VMCI_INTR_TYPE_MSIX) {
- pci_disable_msix(pdev);
- } else if (vmci_dev.intr_type == VMCI_INTR_TYPE_MSI) {
- pci_disable_msi(pdev);
- }
- remove_bitmap:
- if (notification_bitmap) {
- outl(VMCI_CONTROL_RESET, vmci_dev.ioaddr + VMCI_CONTROL_ADDR);
- }
- datagram_disallow:
- atomic_set(&vmci_dev.datagrams_allowed, 0);
- unlock:
- compat_mutex_unlock(&vmci_dev.lock);
- release:
- if (notification_bitmap) {
- vfree(notification_bitmap);
- notification_bitmap = NULL;
- }
- release_region(ioaddr, ioaddr_size);
- pci_disable:
- pci_disable_device(pdev);
- return -EBUSY;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_remove_device --
- *
- * Cleanup, called for each device on unload.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-vmci_remove_device(struct pci_dev* pdev)
-{
- struct vmci_device *dev = pci_get_drvdata(pdev);
-
- printk(KERN_INFO "Removing vmci device\n");
-
- atomic_dec(&guestDeviceActive);
-
- VMCIQPGuestEndpoints_Exit();
- VMCIUtil_Exit();
-
- compat_mutex_lock(&dev->lock);
-
- atomic_set(&vmci_dev.datagrams_allowed, 0);
-
- printk(KERN_INFO "Resetting vmci device\n");
- outl(VMCI_CONTROL_RESET, vmci_dev.ioaddr + VMCI_CONTROL_ADDR);
-
- /*
- * Free IRQ and then disable MSI/MSI-X as appropriate. For MSI-X, we might
- * have multiple vectors, each with their own IRQ, which we must free too.
- */
-
- free_irq(dev->irq, dev);
- if (dev->intr_type == VMCI_INTR_TYPE_MSIX) {
- if (dev->exclusive_vectors) {
- free_irq(dev->msix_entries[1].vector, dev);
- }
- pci_disable_msix(pdev);
- } else if (dev->intr_type == VMCI_INTR_TYPE_MSI) {
- pci_disable_msi(pdev);
- }
- dev->exclusive_vectors = FALSE;
- dev->intr_type = VMCI_INTR_TYPE_INTX;
-
- release_region(dev->ioaddr, dev->ioaddr_size);
- dev->enabled = FALSE;
- if (notification_bitmap) {
- /*
- * The device reset above cleared the bitmap state of the
- * device, so we can safely free it here.
- */
-
- vfree(notification_bitmap);
- notification_bitmap = NULL;
- }
-
- printk(KERN_INFO "Unregistered vmci device.\n");
- compat_mutex_unlock(&dev->lock);
-
- pci_disable_device(pdev);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_interrupt --
- *
- * Interrupt handler for legacy or MSI interrupt, or for first MSI-X
- * interrupt (vector VMCI_INTR_DATAGRAM).
- *
- * Results:
- * COMPAT_IRQ_HANDLED if the interrupt is handled, COMPAT_IRQ_NONE if
- * not an interrupt.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
-static compat_irqreturn_t
-vmci_interrupt(int irq, // IN
- void *clientdata, // IN
- struct pt_regs *regs) // IN
-#else
-static compat_irqreturn_t
-vmci_interrupt(int irq, // IN
- void *clientdata) // IN
-#endif
-{
- vmci_device *dev = clientdata;
-
- if (dev == NULL) {
- printk(KERN_DEBUG "vmci_interrupt(): irq %d for unknown device.\n", irq);
- return COMPAT_IRQ_NONE;
- }
-
- /*
- * If we are using MSI-X with exclusive vectors then we simply schedule
- * the datagram tasklet, since we know the interrupt was meant for us.
- * Otherwise we must read the ICR to determine what to do.
- */
-
- if (dev->intr_type == VMCI_INTR_TYPE_MSIX && dev->exclusive_vectors) {
- tasklet_schedule(&vmci_dg_tasklet);
- } else {
- unsigned int icr;
-
- ASSERT(dev->intr_type == VMCI_INTR_TYPE_INTX ||
- dev->intr_type == VMCI_INTR_TYPE_MSI);
-
- /* Acknowledge interrupt and determine what needs doing. */
- icr = inl(dev->ioaddr + VMCI_ICR_ADDR);
- if (icr == 0 || icr == 0xffffffff) {
- return COMPAT_IRQ_NONE;
- }
-
- if (icr & VMCI_ICR_DATAGRAM) {
- tasklet_schedule(&vmci_dg_tasklet);
- icr &= ~VMCI_ICR_DATAGRAM;
- }
- if (icr & VMCI_ICR_NOTIFICATION) {
- tasklet_schedule(&vmci_bm_tasklet);
- icr &= ~VMCI_ICR_NOTIFICATION;
- }
- if (icr != 0) {
- printk(KERN_INFO LGPFX"Ignoring unknown interrupt cause (%d).\n", icr);
- }
- }
-
- return COMPAT_IRQ_HANDLED;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * vmci_interrupt_bm --
- *
- * Interrupt handler for MSI-X interrupt vector VMCI_INTR_NOTIFICATION,
- * which is for the notification bitmap. Will only get called if we are
- * using MSI-X with exclusive vectors.
- *
- * Results:
- * COMPAT_IRQ_HANDLED if the interrupt is handled, COMPAT_IRQ_NONE if
- * not an interrupt.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
-static compat_irqreturn_t
-vmci_interrupt_bm(int irq, // IN
- void *clientdata, // IN
- struct pt_regs *regs) // IN
-#else
-static compat_irqreturn_t
-vmci_interrupt_bm(int irq, // IN
- void *clientdata) // IN
-#endif
-{
- vmci_device *dev = clientdata;
-
- if (dev == NULL) {
- printk(KERN_DEBUG "vmci_interrupt_bm(): irq %d for unknown device.\n", irq);
- return COMPAT_IRQ_NONE;
- }
-
- /* For MSI-X we can just assume it was meant for us. */
- ASSERT(dev->intr_type == VMCI_INTR_TYPE_MSIX && dev->exclusive_vectors);
- tasklet_schedule(&vmci_bm_tasklet);
-
- return COMPAT_IRQ_HANDLED;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_DeviceEnabled --
- *
- * Checks whether the VMCI device is enabled.
- *
- * Results:
- * TRUE if device is enabled, FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-VMCI_DeviceEnabled(void)
-{
- return VMCI_GuestPersonalityActive() || VMCI_HostPersonalityActive();
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_SendDatagram --
- *
- * VM to hypervisor call mechanism. We use the standard VMware naming
- * convention since shared code is calling this function as well.
- *
- * Results:
- * The result of the hypercall.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCI_SendDatagram(VMCIDatagram *dg)
-{
- unsigned long flags;
- int result;
-
- /* Check args. */
- if (dg == NULL) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (atomic_read(&vmci_dev.datagrams_allowed) == 0) {
- return VMCI_ERROR_UNAVAILABLE;
- }
-
- /*
- * Need to acquire spinlock on the device because
- * the datagram data may be spread over multiple pages and the monitor may
- * interleave device user rpc calls from multiple VCPUs. Acquiring the
- * spinlock precludes that possibility. Disabling interrupts to avoid
- * incoming datagrams during a "rep out" and possibly landing up in this
- * function.
- */
- spin_lock_irqsave(&vmci_dev.dev_spinlock, flags);
-
- /*
- * Send the datagram and retrieve the return value from the result register.
- */
- __asm__ __volatile__(
- "cld\n\t"
- "rep outsb\n\t"
- : /* No output. */
- : "d"(vmci_dev.ioaddr + VMCI_DATA_OUT_ADDR),
- "c"(VMCI_DG_SIZE(dg)), "S"(dg)
- );
-
- /*
- * XXX Should read result high port as well when updating handlers to
- * return 64bit.
- */
- result = inl(vmci_dev.ioaddr + VMCI_RESULT_LOW_ADDR);
- spin_unlock_irqrestore(&vmci_dev.dev_spinlock, flags);
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * dispatch_datagrams --
- *
- * Reads and dispatches incoming datagrams.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Reads data from the device.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-dispatch_datagrams(unsigned long data)
-{
- vmci_device *dev = (vmci_device *)data;
-
- if (dev == NULL) {
- printk(KERN_DEBUG "vmci: dispatch_datagrams(): no vmci device"
- "present.\n");
- return;
- }
-
- if (data_buffer == NULL) {
- printk(KERN_DEBUG "vmci: dispatch_datagrams(): no buffer present.\n");
- return;
- }
-
-
- VMCI_ReadDatagramsFromPort((VMCIIoHandle) 0, dev->ioaddr + VMCI_DATA_IN_ADDR,
- data_buffer, data_buffer_size);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * process_bitmap --
- *
- * Scans the notification bitmap for raised flags, clears them
- * and handles the notifications.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-process_bitmap(unsigned long data)
-{
- vmci_device *dev = (vmci_device *)data;
-
- if (dev == NULL) {
- printk(KERN_DEBUG "vmci: process_bitmaps(): no vmci device"
- "present.\n");
- return;
- }
-
- if (notification_bitmap == NULL) {
- printk(KERN_DEBUG "vmci: process_bitmaps(): no bitmap present.\n");
- return;
- }
-
-
- VMCI_ScanNotificationBitmap(notification_bitmap);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * Shared functions --
- *
- * Functions shared between host and guest personality.
- *
- *----------------------------------------------------------------------
- */
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_GuestPersonalityActive --
- *
- * Determines whether the VMCI PCI device has been successfully
- * initialized.
- *
- * Results:
- * TRUE, if VMCI guest device is operational, FALSE otherwise.
- *
- * Side effects:
- * Reads data from the device.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-VMCI_GuestPersonalityActive(void)
-{
- return guestDeviceInit && atomic_read(&guestDeviceActive) > 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_HostPersonalityActive --
- *
- * Determines whether the VMCI host personality is
- * available. Since the core functionality of the host driver is
- * always present, all guests could possibly use the host
- * personality. However, to minimize the deviation from the
- * pre-unified driver state of affairs, we only consider the host
- * device active, if there is no active guest device, or if there
- * are VMX'en with active VMCI contexts using the host device.
- *
- * Results:
- * TRUE, if VMCI host driver is operational, FALSE otherwise.
- *
- * Side effects:
- * Reads data from the device.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-VMCI_HostPersonalityActive(void)
-{
- return hostDeviceInit &&
- (!VMCI_GuestPersonalityActive() ||
- atomic_read(&linuxState.activeContexts) > 0);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * Module definitions --
- *
- * Implements support for module load/unload.
- *
- *----------------------------------------------------------------------
- */
-
-
-/*
- *----------------------------------------------------------------------
- *
- * vmci_init --
- *
- * linux module entry point. Called by /sbin/insmod command
- *
- * Results:
- * registers a device driver for a major # that depends
- * on the uid. Add yourself to that list. List is now in
- * private/driver-private.c.
- *
- *----------------------------------------------------------------------
- */
-
-static int __init
-vmci_init(void)
-{
- int retval;
-
- retval = VMCI_SharedInit();
- if (retval != VMCI_SUCCESS) {
- Warning(LGPFX"Failed to initialize VMCI common components (err=%d).\n",
- retval);
- return -ENOMEM;
- }
-
- if (!vmci_disable_guest) {
- retval = vmci_guest_init();
- if (retval != 0) {
- Warning(LGPFX"VMCI PCI device not initialized (err=%d).\n", retval);
- } else {
- guestDeviceInit = TRUE;
- if (VMCI_GuestPersonalityActive()) {
- Log(LGPFX"Using guest personality\n");
- }
- }
- }
-
- if (!vmci_disable_host) {
- retval = vmci_host_init();
- if (retval != 0) {
- Warning(LGPFX"Unable to initialize host personality (err=%d).\n",
- retval);
- } else {
- hostDeviceInit = TRUE;
- Log(LGPFX"Using host personality\n");
- }
- }
-
- if (!guestDeviceInit && !hostDeviceInit) {
- VMCI_SharedCleanup();
- return -ENODEV;
- }
-
- Log(LGPFX"Module (name=%s) is initialized\n", VMCI_MODULE_NAME);
-
- return 0;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * vmci_exit --
- *
- * Called by /sbin/rmmod
- *
- *
- *----------------------------------------------------------------------
- */
-
-static void __exit
-vmci_exit(void)
-{
- int retval;
-
- if (guestDeviceInit) {
- pci_unregister_driver(&vmci_driver);
- vfree(data_buffer);
- guestDeviceInit = FALSE;
- }
-
- if (hostDeviceInit) {
- unregister_ioctl32_handlers();
-
- VMCI_HostCleanup();
-
- retval = misc_deregister(&linuxState.misc);
- if (retval) {
- Warning(LGPFX "Module %s: error unregistering\n", VMCI_MODULE_NAME);
- } else {
- Log(LGPFX"Module %s: unloaded\n", VMCI_MODULE_NAME);
- }
-
- hostDeviceInit = FALSE;
- }
-
- VMCI_SharedCleanup();
-}
-
-
-module_init(vmci_init);
-module_exit(vmci_exit);
-MODULE_DEVICE_TABLE(pci, vmci_ids);
-
-module_param_named(disable_host, vmci_disable_host, bool, 0);
-MODULE_PARM_DESC(disable_host, "Disable driver host personality - (default=0)");
-
-module_param_named(disable_guest, vmci_disable_guest, bool, 0);
-MODULE_PARM_DESC(disable_guest, "Disable driver guest personality - (default=0)");
-
-module_param_named(disable_msi, vmci_disable_msi, bool, 0);
-MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)");
-
-module_param_named(disable_msix, vmci_disable_msix, bool, 0);
-MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default="
- __stringify(VMCI_DISABLE_MSIX) ")");
-
-MODULE_AUTHOR("VMware, Inc.");
-MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface (VMCI).");
-MODULE_VERSION(VMCI_DRIVER_VERSION_STRING);
-MODULE_LICENSE("GPL v2");
-/*
- * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
- * with them and mark their kernel modules as externally supported via a
- * change to the module header. If this isn't done, the module will not load
- * by default (i.e., neither mkinitrd nor modprobe will accept it).
- */
-MODULE_INFO(supported, "external");
diff --git a/modules/linux/vmci/linux/vmciKernelIf.c b/modules/linux/vmci/linux/vmciKernelIf.c
deleted file mode 100644
index a51bef8..0000000
--- a/modules/linux/vmci/linux/vmciKernelIf.c
+++ /dev/null
@@ -1,2170 +0,0 @@
-/*********************************************************
- * Copyright (C) 2007 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
- *
- *********************************************************/
-
-/*
- * vmciKernelIf.c --
- *
- * This file implements defines and helper functions for VMCI
- * host _and_ guest kernel code. This is the linux specific
- * implementation.
- */
-
-/* Must come before any kernel header file */
-#include "driver-config.h"
-
-#if !defined(linux) || defined(VMKERNEL)
-#error "Wrong platform."
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-# error "Linux kernels before 2.6.9 are not supported."
-#endif
-
-#include <linux/mm.h> /* For vmalloc_to_page() and get_user_pages()*/
-#include <linux/pagemap.h> /* For page_cache_release() */
-#include <linux/socket.h> /* For memcpy_{to,from}iovec(). */
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-
-#include "compat_highmem.h"
-#include "compat_interrupt.h"
-#include "compat_mm.h"
-#include "compat_module.h"
-#include "compat_page.h"
-#include "compat_pci.h"
-#include "compat_sched.h"
-#include "compat_semaphore.h"
-#include "compat_slab.h"
-#include "compat_spinlock.h"
-#include "compat_version.h"
-#include "compat_workqueue.h"
-
-#include "vm_assert.h"
-#include "vm_basic_types.h"
-#include "vmci_iocontrols.h"
-#include "vmci_kernel_if.h"
-#include "vmciQueue.h"
-#include "vmciQueuePair.h"
-
-
-/*
- * The Kernel specific component of the VMCIQueue structure.
- */
-
-struct VMCIQueueKernelIf {
- struct page **page;
- struct page **headerPage;
- void *va;
- VMCIMutex __mutex;
- VMCIMutex *mutex;
- Bool host;
- Bool isDataMapped;
- size_t numPages;
-};
-
-typedef struct VMCIDelayedWorkInfo {
- compat_work work;
- VMCIWorkFn *workFn;
- void *data;
-} VMCIDelayedWorkInfo;
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_InitLock
- *
- * Initializes the lock. Must be called before use.
- *
- * Results:
- * Always VMCI_SUCCESS.
- *
- * Side effects:
- * Thread can block.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCI_InitLock(VMCILock *lock, // IN:
- char *name, // IN: Unused on Linux
- VMCILockRank rank) // IN: Unused on Linux
-{
- spin_lock_init(lock);
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_CleanupLock
- *
- * Cleanup the lock. Must be called before deallocating lock.
- *
- * Results:
- * None
- *
- * Side effects:
- * Deletes kernel lock state
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_CleanupLock(VMCILock *lock)
-{
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_GrabLock
- *
- * Grabs the given lock. XXX Fill in specific lock requirements. XXX Move
- * locking code into hostif if VMCI stays in vmmon.
- *
- * Results:
- * None
- *
- * Side effects:
- * Thread can block.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_GrabLock(VMCILock *lock, // IN
- VMCILockFlags *flags) // OUT: used to restore irql on windows
-{
- spin_lock(lock);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_ReleaseLock
- *
- * Releases the given lock. XXX Move locking code into hostif if VMCI
- * stays in vmmon.
- *
- * Results:
- * None
- *
- * Side effects:
- * A thread blocked on this lock may wake up.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_ReleaseLock(VMCILock *lock, // IN
- VMCILockFlags flags) // IN
-{
- spin_unlock(lock);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_GrabLock_BH
- *
- * Grabs the given lock and for linux kernels disables bottom half execution.
- * This should be used with locks accessed both from bottom half/tasklet
- * contexts, ie. guestcall handlers, and from process contexts to avoid
- * deadlocks where the process has the lock and gets descheduled due to a
- * bh/tasklet coming in.
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_GrabLock_BH(VMCILock *lock, // IN
- VMCILockFlags *flags) // OUT: used to restore
-{
- spin_lock_bh(lock);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_ReleaseLock_BH
- *
- * Releases the given lock and for linux kernels reenables bottom half
- * execution.
- * This should be used with locks accessed both from bottom half/tasklet
- * contexts, ie. guestcall handlers, and from process contexts to avoid
- * deadlocks where the process has the lock and get descheduled due to a
- * bh/tasklet coming in.
- *
- * Results:
- * None
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_ReleaseLock_BH(VMCILock *lock, // IN
- VMCILockFlags flags) // IN
-{
- spin_unlock_bh(lock);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIHost_InitContext --
- *
- * Host-specific initialization of VMCI context state.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIHost_InitContext(VMCIHost *hostContext, // IN
- uintptr_t eventHnd) // IN: Unused
-{
- init_waitqueue_head(&hostContext->waitQueue);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIHost_ReleaseContext --
- *
- * Host-specific release of state allocated by
- * VMCIHost_InitContext.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIHost_ReleaseContext(VMCIHost *hostContext) // IN
-{
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIHost_SignalCall --
- *
- * Signal to userlevel that a VMCI call is waiting.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIHost_SignalCall(VMCIHost *hostContext) // IN
-{
- wake_up(&hostContext->waitQueue);
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIHost_WaitForCallLocked --
- *
- * Wait until a VMCI call is pending or the waiting thread is
- * interrupted. It is assumed that a lock is held prior to
- * calling this function. The lock will be released during the
- * wait. The correctnes of this funtion depends on that the same
- * lock is held when the call is signalled.
- *
- * Results:
- * TRUE on success
- * FALSE if the wait was interrupted.
- *
- * Side effects:
- * The call may block.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-VMCIHost_WaitForCallLocked(VMCIHost *hostContext, // IN
- VMCILock *lock, // IN
- VMCILockFlags *flags, // IN
- Bool useBH) // IN
-
-{
- DECLARE_WAITQUEUE(wait, current);
-
- /*
- * The thread must be added to the wait queue and have its state
- * changed while holding the lock - otherwise a signal may change
- * the state in between and have it overwritten causing a loss of
- * the event.
- */
-
- add_wait_queue(&hostContext->waitQueue, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- if (useBH) {
- VMCI_ReleaseLock_BH(lock, *flags);
- } else {
- VMCI_ReleaseLock(lock, *flags);
- }
-
- schedule();
-
- if (useBH) {
- VMCI_GrabLock_BH(lock, flags);
- } else {
- VMCI_GrabLock(lock, flags);
- }
-
- current->state = TASK_RUNNING;
-
- remove_wait_queue(&hostContext->waitQueue, &wait);
-
- if (signal_pending(current)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCIHost_ClearCall --
- *
- * Clear the pending call signal.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-VMCIHost_ClearCall(VMCIHost *hostContext) // IN
-{
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHost_CompareUser --
- *
- * Determines whether the two users are the same.
- *
- * Results:
- * VMCI_SUCCESS if equal, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int VMCIHost_CompareUser(VMCIHostUser *user1,
- VMCIHostUser *user2)
-{
- if (!user1 || !user2) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (*user1 == *user2) {
- return VMCI_SUCCESS;
- } else {
- return VMCI_ERROR_GENERIC;
- }
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCI_AllocKernelMem
- *
- * Allocate some kernel memory for the VMCI driver.
- *
- * Results:
- * The address allocated or NULL on error.
- *
- *
- * Side effects:
- * memory is malloced
- *----------------------------------------------------------------------
- */
-
-void *
-VMCI_AllocKernelMem(size_t size, int flags)
-{
- void *ptr;
-
- if ((flags & VMCI_MEMORY_ATOMIC) != 0) {
- ptr = kmalloc(size, GFP_ATOMIC);
- } else {
- ptr = kmalloc(size, GFP_KERNEL);
- }
-
- return ptr;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * VMCI_FreeKernelMem
- *
- * Free kernel memory allocated for the VMCI driver.
- *
- * Results:
- * None.
- *
- * Side effects:
- * memory is freed.
- *----------------------------------------------------------------------
- */
-
-void
-VMCI_FreeKernelMem(void *ptr, // IN:
- size_t size) // IN: Unused on Linux
-{
- kfree(ptr);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_CopyToUser --
- *
- * Copy memory to the user application from a kernel buffer. This
- * function may block, so don't call it while holding any kind of
- * lock.
- *
- * Results:
- * 0 on success.
- * Nonzero on failure.
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCI_CopyToUser(VA64 dst, // OUT: Destination user VA.
- const void *src, // IN: Source kernel VA.
- size_t len) // IN: Number of bytes to copy.
-{
- return copy_to_user(VMCIVA64ToPtr(dst), src, len) ? -EFAULT : 0;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_CopyFromUser --
- *
- * Copy memory from the user application to a kernel buffer. This
- * function may block, so don't call it while holding any kind of
- * lock.
- *
- * Results:
- * 0 on success.
- * Nonzero on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCI_CopyFromUser(void *dst, // OUT: Kernel VA
- VA64 src, // IN: User VA
- size_t len) // IN
-{
- return copy_from_user(dst, VMCIVA64ToPtr(src), len);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * VMCIDelayedWorkCB
- *
- * Called in a worker thread context.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-VMCIDelayedWorkCB(compat_work_arg work) // IN
-{
- VMCIDelayedWorkInfo *delayedWorkInfo;
-
- delayedWorkInfo = COMPAT_WORK_GET_DATA(work, VMCIDelayedWorkInfo, work);
- ASSERT(delayedWorkInfo);
- ASSERT(delayedWorkInfo->workFn);
-
- delayedWorkInfo->workFn(delayedWorkInfo->data);
-
- VMCI_FreeKernelMem(delayedWorkInfo, sizeof *delayedWorkInfo);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * VMCI_CanScheduleDelayedWork --
- *
- * Checks to see if the given platform supports delayed work callbacks.
- *
- * Results:
- * TRUE if it does. FALSE otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-VMCI_CanScheduleDelayedWork(void)
-{
- return TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * VMCI_ScheduleDelayedWork --
- *
- * Schedule the specified callback.
- *
- * Results:
- * Zero on success, error code otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-VMCI_ScheduleDelayedWork(VMCIWorkFn *workFn, // IN
- void *data) // IN
-{
- VMCIDelayedWorkInfo *delayedWorkInfo;
-
- ASSERT(workFn);
-
- delayedWorkInfo = VMCI_AllocKernelMem(sizeof *delayedWorkInfo,
- VMCI_MEMORY_ATOMIC);
- if (!delayedWorkInfo) {
- return VMCI_ERROR_NO_MEM;
- }
-
- delayedWorkInfo->workFn = workFn;
- delayedWorkInfo->data = data;
-
- COMPAT_INIT_WORK(&delayedWorkInfo->work, VMCIDelayedWorkCB,
- delayedWorkInfo);
-
- compat_schedule_work(&delayedWorkInfo->work);
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_CreateEvent --
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_CreateEvent(VMCIEvent *event) // IN:
-{
- init_waitqueue_head(event);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_DestroyEvent --
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_DestroyEvent(VMCIEvent *event) // IN:
-{
- /* Nothing to do. */
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_SignalEvent --
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_SignalEvent(VMCIEvent *event) // IN:
-{
- wake_up(event);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_WaitOnEvent --
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_WaitOnEvent(VMCIEvent *event, // IN:
- VMCIEventReleaseCB releaseCB, // IN:
- void *clientData) // IN:
-{
- /*
- * XXX Should this be a TASK_UNINTERRUPTIBLE wait? I'm leaving it
- * as it was for now.
- */
- VMCI_WaitOnEventInterruptible(event, releaseCB, clientData);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_WaitOnEventInterruptible --
- *
- * Results:
- * True if the wait was interrupted by a signal, false otherwise.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-VMCI_WaitOnEventInterruptible(VMCIEvent *event, // IN:
- VMCIEventReleaseCB releaseCB, // IN:
- void *clientData) // IN:
-{
- DECLARE_WAITQUEUE(wait, current);
-
- if (event == NULL || releaseCB == NULL) {
- return FALSE;
- }
-
- add_wait_queue(event, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- /*
- * Release the lock or other primitive that makes it possible for us to
- * put the current thread on the wait queue without missing the signal.
- * Ie. on Linux we need to put ourselves on the wait queue and set our
- * stateto TASK_INTERRUPTIBLE without another thread signalling us.
- * The releaseCB is used to synchronize this.
- */
- releaseCB(clientData);
-
- schedule();
- current->state = TASK_RUNNING;
- remove_wait_queue(event, &wait);
-
- return signal_pending(current);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMutex_Init --
- *
- * Initializes the mutex. Must be called before use.
- *
- * Results:
- * Success.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIMutex_Init(VMCIMutex *mutex, // IN
- char *name, // IN: Unused
- VMCILockRank rank) // IN: Unused
-{
- sema_init(mutex, 1);
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMutex_Destroy --
- *
- * Destroys the mutex. Does nothing on Linux.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIMutex_Destroy(VMCIMutex *mutex) // IN: Unused
-{
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMutex_Acquire --
- *
- * Acquires the mutex.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Thread may block.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIMutex_Acquire(VMCIMutex *mutex) // IN:
-{
- down(mutex);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMutex_Release --
- *
- * Releases the mutex.
- *
- * Results:
- * None.
- *
- * Side effects:
- * May wake up the thread blocking on this mutex.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIMutex_Release(VMCIMutex *mutex) // IN:
-{
- up(mutex);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_AllocQueue --
- *
- * Allocates kernel VA space of specified size, plus space for the
- * queue structure/kernel interface and the queue header. Allocates
- * physical pages for the queue data pages.
- *
- * PAGE m: VMCIQueueHeader (VMCIQueue->qHeader)
- * PAGE m+1: VMCIQueue
- * PAGE m+1+q: VMCIQueueKernelIf (VMCIQueue->kernelIf)
- * PAGE n-size: Data pages (VMCIQueue->kernelIf->page[])
- *
- * Results:
- * Pointer to the queue on success, NULL otherwise.
- *
- * Side effects:
- * Memory is allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-void *
-VMCI_AllocQueue(uint64 size, // IN: size of queue (not including header)
- uint32 flags) // IN: queuepair flags
-{
- uint64 i;
- VMCIQueue *queue;
- VMCIQueueHeader *qHeader;
- const uint64 numDataPages = CEILING(size, PAGE_SIZE);
- const uint queueSize =
- PAGE_SIZE +
- sizeof *queue + sizeof *(queue->kernelIf) +
- numDataPages * sizeof *(queue->kernelIf->page);
-
- /*
- * Size should be enforced by VMCIQPair_Alloc(), double-check here.
- * Allocating too much on Linux can cause the system to become
- * unresponsive, because we allocate page-by-page, and we allow the
- * system to wait for pages rather than fail.
- */
-
- if (size > VMCI_MAX_GUEST_QP_MEMORY) {
- ASSERT(FALSE);
- return NULL;
- }
-
- /*
- * If pinning is requested then double-check the size of the queue.
- * VMCIQPair_Alloc() will do this for the total queuepair size.
- */
-
- if ((flags & VMCI_QPFLAG_PINNED) && size > VMCI_MAX_PINNED_QP_MEMORY) {
- return NULL;
- }
-
- qHeader = (VMCIQueueHeader *)vmalloc(queueSize);
- if (!qHeader) {
- return NULL;
- }
-
- queue = (VMCIQueue *)((uint8 *)qHeader + PAGE_SIZE);
- queue->qHeader = qHeader;
- queue->savedHeader = NULL;
- queue->kernelIf = (VMCIQueueKernelIf *)((uint8 *)queue + sizeof *queue);
- queue->kernelIf->headerPage = NULL; // Unused in guest.
- queue->kernelIf->page = (struct page **)((uint8 *)queue->kernelIf +
- sizeof *(queue->kernelIf));
- queue->kernelIf->va = NULL;
- queue->kernelIf->host = FALSE;
- queue->kernelIf->isDataMapped = FALSE;
-
- for (i = 0; i < numDataPages; i++) {
- queue->kernelIf->page[i] = alloc_pages(GFP_KERNEL, 0);
- if (!queue->kernelIf->page[i]) {
- VMCI_FreeQueue(queue, i * PAGE_SIZE);
- return NULL;
- }
- }
-
- /*
- * alloc_pages() returns pinned PAs, but we need a permanent mapping to VA
- * if the caller has requested pinned queuepairs. Map all of them into
- * kernel VA now, for the lifetime of the queue. The page VAs will be
- * contiguous.
- */
-
- if (flags & VMCI_QPFLAG_PINNED) {
- queue->kernelIf->va = vmap(queue->kernelIf->page, numDataPages, VM_MAP,
- PAGE_KERNEL);
- if (NULL == queue->kernelIf->va) {
- VMCI_FreeQueue(queue, numDataPages * PAGE_SIZE);
- return NULL;
- }
- queue->kernelIf->isDataMapped = TRUE;
- }
-
- return (void *)queue;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_FreeQueue --
- *
- * Frees kernel VA space for a given queue and its queue header, and
- * frees physical data pages.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory is freed.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_FreeQueue(void *q, // IN:
- uint64 size) // IN: size of queue (not including header)
-{
- VMCIQueue *queue = q;
-
- if (queue) {
- uint64 i;
-
- if (queue->kernelIf->isDataMapped) {
- ASSERT(queue->kernelIf->va);
- vunmap(queue->kernelIf->va);
- queue->kernelIf->va = NULL;
- }
-
- ASSERT(NULL == queue->kernelIf->va);
-
- for (i = 0; i < CEILING(size, PAGE_SIZE); i++) {
- __free_page(queue->kernelIf->page[i]);
- }
- vfree(queue->qHeader);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_AllocPPNSet --
- *
- * Allocates two list of PPNs --- one for the pages in the produce queue,
- * and the other for the pages in the consume queue. Intializes the list
- * of PPNs with the page frame numbers of the KVA for the two queues (and
- * the queue headers).
- *
- * Results:
- * Success or failure.
- *
- * Side effects:
- * Memory may be allocated.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCI_AllocPPNSet(void *prodQ, // IN:
- uint64 numProducePages, // IN: for queue plus header
- void *consQ, // IN:
- uint64 numConsumePages, // IN: for queue plus header
- PPNSet *ppnSet) // OUT:
-{
- VMCIPpnList producePPNs;
- VMCIPpnList consumePPNs;
- VMCIQueue *produceQ = prodQ;
- VMCIQueue *consumeQ = consQ;
- uint64 i;
-
- if (!produceQ || !numProducePages || !consumeQ || !numConsumePages ||
- !ppnSet) {
- return VMCI_ERROR_INVALID_ARGS;
- }
-
- if (ppnSet->initialized) {
- return VMCI_ERROR_ALREADY_EXISTS;
- }
-
- producePPNs =
- VMCI_AllocKernelMem(numProducePages * sizeof *producePPNs,
- VMCI_MEMORY_NORMAL);
- if (!producePPNs) {
- return VMCI_ERROR_NO_MEM;
- }
-
- consumePPNs =
- VMCI_AllocKernelMem(numConsumePages * sizeof *consumePPNs,
- VMCI_MEMORY_NORMAL);
- if (!consumePPNs) {
- VMCI_FreeKernelMem(producePPNs, numProducePages * sizeof *producePPNs);
- return VMCI_ERROR_NO_MEM;
- }
-
- producePPNs[0] = page_to_pfn(vmalloc_to_page(produceQ->qHeader));
- for (i = 1; i < numProducePages; i++) {
- unsigned long pfn;
-
- producePPNs[i] = pfn = page_to_pfn(produceQ->kernelIf->page[i - 1]);
-
- /*
- * Fail allocation if PFN isn't supported by hypervisor.
- */
-
- if (sizeof pfn > sizeof *producePPNs &&
- pfn != producePPNs[i]) {
- goto ppnError;
- }
- }
- consumePPNs[0] = page_to_pfn(vmalloc_to_page(consumeQ->qHeader));
- for (i = 1; i < numConsumePages; i++) {
- unsigned long pfn;
-
- consumePPNs[i] = pfn = page_to_pfn(consumeQ->kernelIf->page[i - 1]);
-
- /*
- * Fail allocation if PFN isn't supported by hypervisor.
- */
-
- if (sizeof pfn > sizeof *consumePPNs &&
- pfn != consumePPNs[i]) {
- goto ppnError;
- }
- }
-
- ppnSet->numProducePages = numProducePages;
- ppnSet->numConsumePages = numConsumePages;
- ppnSet->producePPNs = producePPNs;
- ppnSet->consumePPNs = consumePPNs;
- ppnSet->initialized = TRUE;
- return VMCI_SUCCESS;
-
-ppnError:
- VMCI_FreeKernelMem(producePPNs, numProducePages * sizeof *producePPNs);
- VMCI_FreeKernelMem(consumePPNs, numConsumePages * sizeof *consumePPNs);
- return VMCI_ERROR_INVALID_ARGS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_FreePPNSet --
- *
- * Frees the two list of PPNs for a queue pair.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_FreePPNSet(PPNSet *ppnSet) // IN:
-{
- ASSERT(ppnSet);
- if (ppnSet->initialized) {
- /* Do not call these functions on NULL inputs. */
- ASSERT(ppnSet->producePPNs && ppnSet->consumePPNs);
- VMCI_FreeKernelMem(ppnSet->producePPNs,
- ppnSet->numProducePages * sizeof *ppnSet->producePPNs);
- VMCI_FreeKernelMem(ppnSet->consumePPNs,
- ppnSet->numConsumePages * sizeof *ppnSet->consumePPNs);
- }
- memset(ppnSet, 0, sizeof *ppnSet);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_PopulatePPNList --
- *
- * Populates the list of PPNs in the hypercall structure with the PPNS
- * of the produce queue and the consume queue.
- *
- * Results:
- * VMCI_SUCCESS.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCI_PopulatePPNList(uint8 *callBuf, // OUT:
- const PPNSet *ppnSet) // IN:
-{
- ASSERT(callBuf && ppnSet && ppnSet->initialized);
- memcpy(callBuf, ppnSet->producePPNs,
- ppnSet->numProducePages * sizeof *ppnSet->producePPNs);
- memcpy(callBuf + ppnSet->numProducePages * sizeof *ppnSet->producePPNs,
- ppnSet->consumePPNs,
- ppnSet->numConsumePages * sizeof *ppnSet->consumePPNs);
-
- return VMCI_SUCCESS;
-}
-
-
-#ifdef __KERNEL__
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * __VMCIMemcpyToQueue --
- *
- * Copies from a given buffer or iovector to a VMCI Queue. Uses
- * kmap()/kunmap() to dynamically map/unmap required portions of the queue
- * by traversing the offset -> page translation structure for the queue.
- * Assumes that offset + size does not wrap around in the queue.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-__VMCIMemcpyToQueue(VMCIQueue *queue, // OUT:
- uint64 queueOffset, // IN:
- const void *src, // IN:
- size_t size, // IN:
- Bool isIovec) // IN: if src is a struct iovec *
-{
- VMCIQueueKernelIf *kernelIf = queue->kernelIf;
- size_t bytesCopied = 0;
-
- while (bytesCopied < size) {
- uint64 pageIndex = (queueOffset + bytesCopied) / PAGE_SIZE;
- size_t pageOffset = (queueOffset + bytesCopied) & (PAGE_SIZE - 1);
- void *va;
- size_t toCopy;
-
- if (kernelIf->isDataMapped) {
- va = (void *)((uint8 *)kernelIf->va + (pageIndex * PAGE_SIZE));
- } else {
- va = kmap(kernelIf->page[pageIndex]);
- }
-
- ASSERT(va);
- if (size - bytesCopied > PAGE_SIZE - pageOffset) {
- /* Enough payload to fill up from this page. */
- toCopy = PAGE_SIZE - pageOffset;
- } else {
- toCopy = size - bytesCopied;
- }
-
- if (isIovec) {
- struct iovec *iov = (struct iovec *)src;
- int err;
-
- /* The iovec will track bytesCopied internally. */
- err = memcpy_fromiovec((uint8 *)va + pageOffset, iov, toCopy);
- if (err != 0) {
- if (!kernelIf->isDataMapped) {
- kunmap(kernelIf->page[pageIndex]);
- }
- return VMCI_ERROR_INVALID_ARGS;
- }
- } else {
- memcpy((uint8 *)va + pageOffset, (uint8 *)src + bytesCopied, toCopy);
- }
-
- bytesCopied += toCopy;
- if (!kernelIf->isDataMapped) {
- kunmap(kernelIf->page[pageIndex]);
- }
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * __VMCIMemcpyFromQueue --
- *
- * Copies to a given buffer or iovector from a VMCI Queue. Uses
- * kmap()/kunmap() to dynamically map/unmap required portions of the queue
- * by traversing the offset -> page translation structure for the queue.
- * Assumes that offset + size does not wrap around in the queue.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-__VMCIMemcpyFromQueue(void *dest, // OUT:
- const VMCIQueue *queue, // IN:
- uint64 queueOffset, // IN:
- size_t size, // IN:
- Bool isIovec) // IN: if dest is a struct iovec *
-{
- VMCIQueueKernelIf *kernelIf = queue->kernelIf;
- size_t bytesCopied = 0;
-
- while (bytesCopied < size) {
- uint64 pageIndex = (queueOffset + bytesCopied) / PAGE_SIZE;
- size_t pageOffset = (queueOffset + bytesCopied) & (PAGE_SIZE - 1);
- void *va;
- size_t toCopy;
-
- if (kernelIf->isDataMapped) {
- va = (void *)((uint8 *)kernelIf->va + (pageIndex * PAGE_SIZE));
- } else {
- va = kmap(kernelIf->page[pageIndex]);
- }
-
- ASSERT(va);
- if (size - bytesCopied > PAGE_SIZE - pageOffset) {
- /* Enough payload to fill up this page. */
- toCopy = PAGE_SIZE - pageOffset;
- } else {
- toCopy = size - bytesCopied;
- }
-
- if (isIovec) {
- struct iovec *iov = (struct iovec *)dest;
- int err;
-
- /* The iovec will track bytesCopied internally. */
- err = memcpy_toiovec(iov, (uint8 *)va + pageOffset, toCopy);
- if (err != 0) {
- if (!kernelIf->isDataMapped) {
- kunmap(kernelIf->page[pageIndex]);
- }
- return VMCI_ERROR_INVALID_ARGS;
- }
- } else {
- memcpy((uint8 *)dest + bytesCopied, (uint8 *)va + pageOffset, toCopy);
- }
-
- bytesCopied += toCopy;
- if (!kernelIf->isDataMapped) {
- kunmap(kernelIf->page[pageIndex]);
- }
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMemcpyToQueue --
- *
- * Copies from a given buffer to a VMCI Queue.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIMemcpyToQueue(VMCIQueue *queue, // OUT:
- uint64 queueOffset, // IN:
- const void *src, // IN:
- size_t srcOffset, // IN:
- size_t size, // IN:
- int bufType, // IN: Unused
- Bool canBlock) // IN: Unused
-{
- ASSERT(canBlock || !queue->kernelIf->host);
-
- return __VMCIMemcpyToQueue(queue, queueOffset,
- (uint8 *)src + srcOffset, size, FALSE);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMemcpyFromQueue --
- *
- * Copies to a given buffer from a VMCI Queue.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIMemcpyFromQueue(void *dest, // OUT:
- size_t destOffset, // IN:
- const VMCIQueue *queue, // IN:
- uint64 queueOffset, // IN:
- size_t size, // IN:
- int bufType, // IN: Unused
- Bool canBlock) // IN: Unused
-{
- ASSERT(canBlock || !queue->kernelIf->host);
-
- return __VMCIMemcpyFromQueue((uint8 *)dest + destOffset,
- queue, queueOffset, size, FALSE);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMemcpyToQueueLocal --
- *
- * Copies from a given buffer to a local VMCI queue. On Linux, this is the
- * same as a regular copy.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIMemcpyToQueueLocal(VMCIQueue *queue, // OUT
- uint64 queueOffset, // IN
- const void *src, // IN
- size_t srcOffset, // IN
- size_t size, // IN
- int bufType, // IN: Unused
- Bool canBlock) // IN: Unused
-{
- ASSERT(canBlock || !queue->kernelIf->host);
-
- return __VMCIMemcpyToQueue(queue, queueOffset,
- (uint8 *)src + srcOffset, size, FALSE);;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMemcpyFromQueueLocal --
- *
- * Copies to a given buffer from a VMCI Queue.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIMemcpyFromQueueLocal(void *dest, // OUT:
- size_t destOffset, // IN:
- const VMCIQueue *queue, // IN:
- uint64 queueOffset, // IN:
- size_t size, // IN:
- int bufType, // IN: Unused
- Bool canBlock) // IN: Unused
-{
- ASSERT(canBlock || !queue->kernelIf->host);
-
- return __VMCIMemcpyFromQueue((uint8 *)dest + destOffset,
- queue, queueOffset, size, FALSE);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * VMCIMemcpyToQueueV --
- *
- * Copies from a given iovec from a VMCI Queue.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-VMCIMemcpyToQueueV(VMCIQueue *queue, // OUT:
- uint64 queueOffset, // IN:
- const void *src, // IN: iovec
- size_t srcOffset, // IN: ignored
- size_t size, // IN:
- int bufType, // IN: Unused
- Bool canBlock) // IN: Unused
-{
- ASSERT(canBlock || !queue->kernelIf->host);
-
- /*
- * We ignore srcOffset because src is really a struct iovec * and will
- * maintain offset internally.
- */
- return __VMCIMemcpyToQueue(queue, queueOffset, src, size, TRUE);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * VMCIMemcpyFromQueueV --
- *
- * Copies to a given iovec from a VMCI Queue.
- *
- * Results:
- * Zero on success, negative error code on failure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-VMCIMemcpyFromQueueV(void *dest, // OUT: iovec
- size_t destOffset, // IN: ignored
- const VMCIQueue *queue, // IN:
- uint64 queueOffset, // IN:
- size_t size, // IN:
- int bufType, // IN: Unused
- Bool canBlock) // IN: Unused
-{
- ASSERT(canBlock || !queue->kernelIf->host);
-
- /*
- * We ignore destOffset because dest is really a struct iovec * and will
- * maintain offset internally.
- */
- return __VMCIMemcpyFromQueue(dest, queue, queueOffset, size, TRUE);
-}
-
-#endif
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIWellKnownID_AllowMap --
- *
- * Checks whether the calling context is allowed to register for the given
- * well known service ID. Currently returns FALSE if the service ID is
- * within the reserved range and VMCI_PRIVILEGE_FLAG_TRUSTED is not
- * provided as the input privilege flags. Otherwise returns TRUE.
- * XXX TODO access control based on host configuration information; this
- * will be platform specific implementation.
- *
- * Results:
- * Boolean value indicating access granted or denied.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-VMCIWellKnownID_AllowMap(VMCIId wellKnownID, // IN:
- VMCIPrivilegeFlags privFlags) // IN:
-{
- if (wellKnownID < VMCI_RESERVED_RESOURCE_ID_MAX &&
- !(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) {
- return FALSE;
- }
- return TRUE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHost_AllocQueue --
- *
- * Allocates kernel VA space of specified size plus space for the queue
- * and kernel interface. This is different from the guest queue allocator,
- * because we do not allocate our own queue header/data pages here but
- * share those of the guest.
- *
- * Results:
- * A pointer to an allocated and initialized VMCIQueue structure or NULL.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-VMCIQueue *
-VMCIHost_AllocQueue(uint64 size) // IN:
-{
- VMCIQueue *queue;
- const size_t numPages = CEILING(size, PAGE_SIZE) + 1;
- const size_t queueSize = sizeof *queue + sizeof *(queue->kernelIf);
- const size_t queuePageSize = numPages * sizeof *queue->kernelIf->page;
-
- queue = VMCI_AllocKernelMem(queueSize + queuePageSize, VMCI_MEMORY_NORMAL);
- if (queue) {
- queue->qHeader = NULL;
- queue->savedHeader = NULL;
- queue->kernelIf = (VMCIQueueKernelIf *)((uint8 *)queue + sizeof *queue);
- queue->kernelIf->host = TRUE;
- queue->kernelIf->mutex = NULL;
- queue->kernelIf->numPages = numPages;
- queue->kernelIf->headerPage = (struct page **)((uint8*)queue + queueSize);
- queue->kernelIf->page = &queue->kernelIf->headerPage[1];
- memset(queue->kernelIf->headerPage, 0,
- sizeof *queue->kernelIf->headerPage * queue->kernelIf->numPages);
- queue->kernelIf->va = NULL;
- queue->kernelIf->isDataMapped = FALSE;
- }
-
- return queue;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHost_FreeQueue --
- *
- * Frees kernel memory for a given queue (header plus translation
- * structure).
- *
- * Results:
- * None.
- *
- * Side effects:
- * Memory is freed.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIHost_FreeQueue(VMCIQueue *queue, // IN:
- uint64 queueSize) // IN:
-{
- if (queue) {
- const uint queueSize = sizeof *queue + sizeof *(queue->kernelIf);
- VMCI_FreeKernelMem(queue, queueSize);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_InitQueueMutex()
- *
- * Initialize the mutex for the pair of queues. This mutex is used to
- * protect the qHeader and the buffer from changing out from under any
- * users of either queue. Of course, it's only any good if the mutexes
- * are actually acquired. Queue structure must lie on non-paged memory
- * or we cannot guarantee access to the mutex.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-VMCI_InitQueueMutex(VMCIQueue *produceQ, // IN/OUT
- VMCIQueue *consumeQ) // IN/OUT
-{
- ASSERT(produceQ);
- ASSERT(consumeQ);
- ASSERT(produceQ->kernelIf);
- ASSERT(consumeQ->kernelIf);
-
- /*
- * Only the host queue has shared state - the guest queues do not
- * need to synchronize access using a queue mutex.
- */
-
- if (produceQ->kernelIf->host) {
- produceQ->kernelIf->mutex = &produceQ->kernelIf->__mutex;
- consumeQ->kernelIf->mutex = &produceQ->kernelIf->__mutex;
- sema_init(produceQ->kernelIf->mutex, 1);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_CleanupQueueMutex()
- *
- * Cleans up the mutex for the pair of queues.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-VMCI_CleanupQueueMutex(VMCIQueue *produceQ, // IN/OUT
- VMCIQueue *consumeQ) // IN/OUT
-{
- ASSERT(produceQ);
- ASSERT(consumeQ);
- ASSERT(produceQ->kernelIf);
- ASSERT(consumeQ->kernelIf);
-
- if (produceQ->kernelIf->host) {
- produceQ->kernelIf->mutex = NULL;
- consumeQ->kernelIf->mutex = NULL;
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_AcquireQueueMutex()
- *
- * Acquire the mutex for the queue. Note that the produceQ and
- * the consumeQ share a mutex. So, only one of the two need to
- * be passed in to this routine. Either will work just fine.
- *
- * Results:
- * VMCI_SUCCESS always.
- *
- * Side Effects:
- * May block the caller.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-VMCI_AcquireQueueMutex(VMCIQueue *queue, // IN
- Bool canBlock) // IN: Unused
-{
- ASSERT(queue);
- ASSERT(queue->kernelIf);
-
- if (queue->kernelIf->host) {
- ASSERT(canBlock);
- ASSERT(queue->kernelIf->mutex);
- down(queue->kernelIf->mutex);
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_ReleaseQueueMutex()
- *
- * Release the mutex for the queue. Note that the produceQ and
- * the consumeQ share a mutex. So, only one of the two need to
- * be passed in to this routine. Either will work just fine.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * May block the caller.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-VMCI_ReleaseQueueMutex(VMCIQueue *queue) // IN
-{
- ASSERT(queue);
- ASSERT(queue->kernelIf);
-
- if (queue->kernelIf->host) {
- ASSERT(queue->kernelIf->mutex);
- up(queue->kernelIf->mutex);
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_LockQueueHeader()
- *
- * Acquire a spinlock guarding the queue header. Note that the produceQ
- * and the consumeQ share the lock mutex. So, only one of the two need to
- * be passed in to this routine. Either will work just fine.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-VMCI_LockQueueHeader(VMCIQueue *queue) // IN
-{
- ASSERT(queue);
- ASSERT(queue->kernelIf);
- ASSERT(!queue->kernelIf->host);
-
- /*
- * We don't support non-blocking on the host right now, so we won't get
- * here for a host queue. And there's no lock required on the guest. So
- * this is a NOP.
- */
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_UnlockQueueHeader()
- *
- * Release the spinlock guarding the queue header.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
-
-void
-VMCI_UnlockQueueHeader(VMCIQueue *queue) // IN
-{
- ASSERT(queue);
- ASSERT(queue->kernelIf);
- ASSERT(!queue->kernelIf->host);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIReleasePageStorePages --
- *
- * Helper function to release pages in the PageStoreAttachInfo
- * previously obtained using get_user_pages.
- *
- * Results:
- * None.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static void
-VMCIReleasePages(struct page **pages, // IN
- uint64 numPages, // IN
- Bool dirty) // IN
-{
- int i;
-
- for (i = 0; i < numPages; i++) {
- ASSERT(pages[i]);
- if (dirty) {
- set_page_dirty(pages[i]);
- }
- page_cache_release(pages[i]);
- pages[i] = NULL;
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHost_RegisterUserMemory --
- *
- * Registers the specification of the user pages used for backing a queue
- * pair. Enough information to map in pages is stored in the OS specific
- * part of the VMCIQueue structure.
- *
- * Results:
- * VMCI_SUCCESS on sucess, negative error code on failure.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIHost_RegisterUserMemory(unsigned int index, // IN
- QueuePairPageStore *pageStore, // IN
- VMCIQueue *produceQ, // OUT
- VMCIQueue *consumeQ) // OUT
-{
- VA64 produceUVA;
- VA64 consumeUVA;
-
- ASSERT(index == 0);
- ASSERT(produceQ->kernelIf->headerPage && consumeQ->kernelIf->headerPage);
-
- /*
- * The new style and the old style mapping only differs in that we either
- * get a single or two UVAs, so we split the single UVA range at the
- * appropriate spot.
- */
-
- produceUVA = pageStore->pages;
- consumeUVA = pageStore->pages + produceQ->kernelIf->numPages * PAGE_SIZE;
- return VMCIHost_GetUserMemory(index, produceUVA, consumeUVA, produceQ, consumeQ);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHost_UnregisterUserMemory --
- *
- * Releases and removes the references to user pages stored in the attach
- * struct.
- *
- * Results:
- * None
- *
- * Side Effects:
- * Pages are released from the page cache and may become
- * swappable again.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIHost_UnregisterUserMemory(unsigned int index, // IN
- VMCIQueue *produceQ, // IN/OUT
- VMCIQueue *consumeQ) // IN/OUT
-{
- ASSERT(index == 0);
- ASSERT(produceQ->kernelIf);
- ASSERT(consumeQ->kernelIf);
- ASSERT(!produceQ->qHeader && !consumeQ->qHeader);
-
- VMCIReleasePages(produceQ->kernelIf->headerPage, produceQ->kernelIf->numPages, TRUE);
- memset(produceQ->kernelIf->headerPage, 0,
- sizeof *produceQ->kernelIf->headerPage * produceQ->kernelIf->numPages);
- VMCIReleasePages(consumeQ->kernelIf->headerPage, consumeQ->kernelIf->numPages, TRUE);
- memset(consumeQ->kernelIf->headerPage, 0,
- sizeof *consumeQ->kernelIf->headerPage * consumeQ->kernelIf->numPages);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHost_MapQueues --
- *
- * Once VMCIHost_RegisterUserMemory has been performed on a
- * queue, the queue pair headers can be mapped into the
- * kernel. Once mapped, they must be unmapped with
- * VMCIHost_UnmapQueues prior to calling
- * VMCIHost_UnregisterUserMemory.
- *
- * Results:
- * VMCI_SUCCESS if pages are mapped, appropriate error code otherwise.
- *
- * Side Effects:
- * Pages are pinned.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIHost_MapQueues(unsigned int index, // IN
- VMCIQueue *produceQ, // IN/OUT
- VMCIQueue *consumeQ, // IN/OUT
- uint32 flags) // UNUSED
-{
- int result;
-
- ASSERT(index == 0);
- if (!produceQ->qHeader || !consumeQ->qHeader) {
- struct page *headers[2];
-
- if (produceQ->qHeader != consumeQ->qHeader) {
- return VMCI_ERROR_QUEUEPAIR_MISMATCH;
- }
-
- if (produceQ->kernelIf->headerPage == NULL ||
- *produceQ->kernelIf->headerPage == NULL) {
- return VMCI_ERROR_UNAVAILABLE;
- }
-
- ASSERT(*produceQ->kernelIf->headerPage && *consumeQ->kernelIf->headerPage);
-
- headers[0] = *produceQ->kernelIf->headerPage;
- headers[1] = *consumeQ->kernelIf->headerPage;
-
- produceQ->qHeader = vmap(headers, 2, VM_MAP, PAGE_KERNEL);
- if (produceQ->qHeader != NULL) {
- consumeQ->qHeader =
- (VMCIQueueHeader *)((uint8 *)produceQ->qHeader + PAGE_SIZE);
- result = VMCI_SUCCESS;
- } else {
- Log("vmap failed\n");
- result = VMCI_ERROR_NO_MEM;
- }
- } else {
- result = VMCI_SUCCESS;
- }
-
- return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHost_UnmapQueues --
- *
- * Unmaps previously mapped queue pair headers from the kernel.
- *
- * Results:
- * VMCI_SUCCESS always.
- *
- * Side Effects:
- * Pages are unpinned.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIHost_UnmapQueues(unsigned int index, // IN
- VMCIGuestMemID gid, // IN
- VMCIQueue *produceQ, // IN/OUT
- VMCIQueue *consumeQ) // IN/OUT
-{
- ASSERT(index == 0);
- if (produceQ->qHeader) {
- ASSERT(consumeQ->qHeader);
-
- if (produceQ->qHeader < consumeQ->qHeader) {
- vunmap(produceQ->qHeader);
- } else {
- vunmap(consumeQ->qHeader);
- }
- produceQ->qHeader = NULL;
- consumeQ->qHeader = NULL;
- }
-
- return VMCI_SUCCESS;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHost_GetUserMemory --
- *
- *
- * Lock the user pages referenced by the {produce,consume}Buffer
- * struct into memory and populate the {produce,consume}Pages
- * arrays in the attach structure with them.
- *
- * Results:
- * VMCI_SUCCESS on sucess, negative error code on failure.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-VMCIHost_GetUserMemory(unsigned int index, // IN
- VA64 produceUVA, // IN
- VA64 consumeUVA, // IN
- VMCIQueue *produceQ, // OUT
- VMCIQueue *consumeQ) // OUT
-{
- int retval;
- int err = VMCI_SUCCESS;
-
- ASSERT(index == 0);
- down_write(&current->mm->mmap_sem);
- retval = get_user_pages(current,
- current->mm,
- (VA)produceUVA,
- produceQ->kernelIf->numPages,
- 1, 0,
- produceQ->kernelIf->headerPage,
- NULL);
- if (retval < produceQ->kernelIf->numPages) {
- Log("get_user_pages(produce) failed (retval=%d)\n", retval);
- VMCIReleasePages(produceQ->kernelIf->headerPage, retval, FALSE);
- err = VMCI_ERROR_NO_MEM;
- goto out;
- }
-
- retval = get_user_pages(current,
- current->mm,
- (VA)consumeUVA,
- consumeQ->kernelIf->numPages,
- 1, 0,
- consumeQ->kernelIf->headerPage,
- NULL);
- if (retval < consumeQ->kernelIf->numPages) {
- Log("get_user_pages(consume) failed (retval=%d)\n", retval);
- VMCIReleasePages(consumeQ->kernelIf->headerPage, retval, FALSE);
- VMCIReleasePages(produceQ->kernelIf->headerPage,
- produceQ->kernelIf->numPages, FALSE);
- err = VMCI_ERROR_NO_MEM;
- }
-
-out:
- up_write(&current->mm->mmap_sem);
-
- return err;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIHost_ReleaseUserMemory --
- * Release the reference to user pages stored in the attach
- * struct
- *
- * Results:
- * None
- *
- * Side Effects:
- * Pages are released from the page cache and may become
- * swappable again.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCIHost_ReleaseUserMemory(unsigned int index, // IN
- VMCIQueue *produceQ, // IN/OUT
- VMCIQueue *consumeQ) // IN/OUT
-{
- ASSERT(index == 0);
- ASSERT(produceQ->kernelIf->headerPage);
-
- VMCIHost_UnregisterUserMemory(index, produceQ, consumeQ);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCI_ReadPortBytes --
- *
- * Copy memory from an I/O port to kernel memory.
- *
- * Results:
- * No results.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-VMCI_ReadPortBytes(VMCIIoHandle handle, // IN: Unused
- VMCIIoPort port, // IN
- uint8 *buffer, // OUT
- size_t bufferLength) // IN
-{
- insb(port, buffer, bufferLength);
-}
diff --git a/modules/linux/vmci/linux/vmci_version.h b/modules/linux/vmci/linux/vmci_version.h
deleted file mode 100644
index 9bce229..0000000
--- a/modules/linux/vmci/linux/vmci_version.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*********************************************************
- * Copyright (C) 2007-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
- *
- *********************************************************/
-
-/*
- * vmci_version.h --
- *
- * Version definitions for the Linux vmci driver.
- */
-
-#ifndef _VMCI_VERSION_H_
-#define _VMCI_VERSION_H_
-
-#define VMCI_DRIVER_VERSION 9.5.17.0
-#define VMCI_DRIVER_VERSION_COMMAS 9,5,17,0
-#define VMCI_DRIVER_VERSION_STRING "9.5.17.0"
-
-#endif /* _VMCI_VERSION_H_ */
diff --git a/modules/linux/vmci/shared/pgtbl.h b/modules/linux/vmci/shared/pgtbl.h
deleted file mode 100644
index 0f0faee..0000000
--- a/modules/linux/vmci/shared/pgtbl.h
+++ /dev/null
@@ -1,377 +0,0 @@
-/*********************************************************
- * 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 __PGTBL_H__
-# define __PGTBL_H__
-
-
-#include <linux/highmem.h>
-
-#include "compat_pgtable.h"
-#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
-{
- if (pte_present(*pte) == 0) {
- return INVALID_MPN;
- }
- return pte_pfn(*pte);
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * 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_pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
-
- if (compat_pgd_present(*pgd) == 0) {
- return NULL;
- }
-
- pud = compat_pud_offset(pgd, 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 --
- *
- * 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
- * mpn on success
- *
- * Side effects:
- * None
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE MPN
-PgtblVa2MPNLocked(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) {
- MPN mpn = PgtblPte2MPN(pte);
- pte_unmap(pte);
- 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;
- }
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * PgtblVa2MPN --
- *
- * 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 int
-PgtblVa2MPN(VA addr) // IN
-{
- struct mm_struct *mm;
- MPN mpn;
-
- /* current->mm is NULL for kernel threads, so use active_mm. */
- mm = current->active_mm;
- if (compat_get_page_table_lock(mm)) {
- spin_lock(compat_get_page_table_lock(mm));
- }
- mpn = PgtblVa2MPNLocked(mm, addr);
- 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 int
-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__ */
diff --git a/modules/linux/vmci/shared/vmciQueue.h b/modules/linux/vmci/shared/vmciQueue.h
deleted file mode 100644
index 11225e7..0000000
--- a/modules/linux/vmci/shared/vmciQueue.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/*********************************************************
- * Copyright (C) 2010 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 _VMCI_QUEUE_H_
-#define _VMCI_QUEUE_H_
-
-/*
- *
- * vmciQueue.h --
- *
- * Defines the queue structure, and helper functions to enqueue and dequeue
- * items. XXX needs checksumming?
- */
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMX
-#define INCLUDE_ALLOW_VMK_MODULE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#if defined(SOLARIS) || defined(__APPLE__)
-# include <sys/uio.h>
-#endif
-
-#if defined VMKERNEL
-# include "vm_atomic.h"
-# include "return_status.h"
-# include "util_copy_dist.h"
-#endif
-
-
-/*
- * VMCIQueue
- *
- * This data type contains the information about a queue.
- *
- * There are two queues (hence, queue pairs) per transaction model between a
- * pair of end points, A & B. One queue is used by end point A to transmit
- * commands and responses to B. The other queue is used by B to transmit
- * commands and responses.
- *
- * VMCIQueueKernelIf is a per-OS defined Queue structure. It contains either a
- * direct pointer to the linear address of the buffer contents or a pointer to
- * structures which help the OS locate those data pages. See vmciKernelIf.c
- * for each platform for its definition.
- */
-
-typedef struct VMCIQueueKernelIf VMCIQueueKernelIf;
-
-typedef struct VMCIQueue {
- VMCIQueueHeader *qHeader;
- VMCIQueueHeader *savedHeader;
- VMCIQueueKernelIf *kernelIf;
-} VMCIQueue;
-
-
-/*
- * ESX uses a buffer type for the memcpy functions. Currently, none
- * of the hosted products use such a field. And, to keep the function
- * definitions simple, we use a define to declare the type parameter.
- */
-
-#ifdef VMKERNEL
-#define BUF_TYPE Util_BufferType
-#else
-#define BUF_TYPE int
-#endif
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMemcpy{To,From}QueueFunc() prototypes. Functions of these
- * types are passed around to enqueue and dequeue routines. Note that
- * often the functions passed are simply wrappers around memcpy
- * itself.
- *
- * Note: In order for the memcpy typedefs to be compatible with the VMKernel,
- * there's an unused last parameter for the hosted side. In
- * ESX, that parameter holds a buffer type.
- *
- *-----------------------------------------------------------------------------
- */
-typedef int VMCIMemcpyToQueueFunc(VMCIQueue *queue, uint64 queueOffset,
- const void *src, size_t srcOffset,
- size_t size, BUF_TYPE bufType,
- Bool canBlock);
-typedef int VMCIMemcpyFromQueueFunc(void *dest, size_t destOffset,
- const VMCIQueue *queue, uint64 queueOffset,
- size_t size, BUF_TYPE bufType,
- Bool canBlock);
-
-
-#if defined(_WIN32) && defined(WINNT_DDK)
-/*
- * Windows needs iovec for the V functions. We use an MDL for the actual
- * buffers, but we also have an offset that comes from WSK_BUF.
- */
-typedef struct iovec {
- PMDL mdl; // List of memory descriptors.
- ULONG offset; // Base offset.
-};
-#endif // _WIN32 && WINNT_DDK
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIMemcpy{To,From}Queue[V][Local]() prototypes
- *
- * Note that these routines are NOT SAFE to call on a host end-point
- * until the guest end of the queue pair has attached -AND-
- * SetPageStore(). The VMX crosstalk device will issue the
- * SetPageStore() on behalf of the guest when the guest creates a
- * QueuePair or attaches to one created by the host. So, if the guest
- * notifies the host that it's attached then the queue is safe to use.
- * Also, if the host registers notification of the connection of the
- * guest, then it will only receive that notification when the guest
- * has issued the SetPageStore() call and not before (when the guest
- * had attached).
- *
- *-----------------------------------------------------------------------------
- */
-
-int VMCIMemcpyToQueue(VMCIQueue *queue, uint64 queueOffset, const void *src,
- size_t srcOffset, size_t size, BUF_TYPE bufType,
- Bool canBlock);
-int VMCIMemcpyFromQueue(void *dest, size_t destOffset, const VMCIQueue *queue,
- uint64 queueOffset, size_t size, BUF_TYPE bufType,
- Bool canBlock);
-
-int VMCIMemcpyToQueueLocal(VMCIQueue *queue, uint64 queueOffset, const void *src,
- size_t srcOffset, size_t size, BUF_TYPE bufType,
- Bool canBlock);
-int VMCIMemcpyFromQueueLocal(void *dest, size_t destOffset, const VMCIQueue *queue,
- uint64 queueOffset, size_t size, BUF_TYPE bufType,
- Bool canBlock);
-
-#if defined VMKERNEL || defined (SOLARIS) || \
- (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \
- (defined(__linux__) && defined(__KERNEL__)) || \
- (defined(_WIN32) && defined(WINNT_DDK))
-int VMCIMemcpyToQueueV(VMCIQueue *queue, uint64 queueOffset, const void *src,
- size_t srcOffset, size_t size, BUF_TYPE bufType,
- Bool canBlock);
-int VMCIMemcpyFromQueueV(void *dest, size_t destOffset, const VMCIQueue *queue,
- uint64 queueOffset, size_t size, BUF_TYPE bufType,
- Bool canBlock);
-# if defined(VMKERNEL)
-int VMCIMemcpyToQueueVLocal(VMCIQueue *queue, uint64 queueOffset,
- const void *src, size_t srcOffset, size_t size,
- BUF_TYPE bufType, Bool canBlock);
-int VMCIMemcpyFromQueueVLocal(void *dest, size_t destOffset,
- const VMCIQueue *queue, uint64 queueOffset,
- size_t size, BUF_TYPE bufType, Bool canBlock);
-# else
-/*
- * For non-vmkernel platforms, the local versions are identical to the
- * non-local ones.
- */
-
-static INLINE int
-VMCIMemcpyToQueueVLocal(VMCIQueue *queue, // IN/OUT
- uint64 queueOffset, // IN
- const void *src, // IN: iovec
- size_t srcOffset, // IN
- size_t size, // IN
- BUF_TYPE bufType, // IN
- Bool canBlock) // IN
-{
- return VMCIMemcpyToQueueV(queue, queueOffset, src, srcOffset, size, bufType,
- canBlock);
-}
-
-static INLINE int
-VMCIMemcpyFromQueueVLocal(void *dest, // IN/OUT: iovec
- size_t destOffset, // IN
- const VMCIQueue *queue, // IN
- uint64 queueOffset, // IN
- size_t size, // IN
- BUF_TYPE bufType, // IN
- Bool canBlock) // IN
-{
- return VMCIMemcpyFromQueueV(dest, destOffset, queue, queueOffset, size, bufType,
- canBlock);
-}
-# endif /* !VMKERNEL */
-#endif /* Does the O/S support iovec? */
-
-
-#endif /* !_VMCI_QUEUE_H_ */
-
diff --git a/modules/linux/vmci/shared/vmci_handle_array.h b/modules/linux/vmci/shared/vmci_handle_array.h
deleted file mode 100644
index b31ab82..0000000
--- a/modules/linux/vmci/shared/vmci_handle_array.h
+++ /dev/null
@@ -1,374 +0,0 @@
-/*********************************************************
- * 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
- * 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
- *
- *********************************************************/
-
-/*
- * vmci_handle_array.h --
- *
- * Simple dynamic array.
- */
-
-#ifndef _VMCI_HANDLE_ARRAY_H_
-#define _VMCI_HANDLE_ARRAY_H_
-
-#define INCLUDE_ALLOW_VMMON
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMCORE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_kernel_if.h"
-#include "vmware.h"
-
-#include "vmci_defs.h"
-#include "vm_assert.h"
-#ifdef VMKERNEL
-#include "vm_libc.h"
-#endif // VMKERNEL
-
-#ifdef SOLARIS
-#include <sys/ddi.h>
-#include <sys/kmem.h>
-#include <sys/types.h>
-#include <sys/systm.h>
-#endif
-
-#define VMCI_HANDLE_ARRAY_DEFAULT_SIZE 4
-
-typedef struct VMCIHandleArray {
- uint32 capacity;
- uint32 size;
- VMCIHandle entries[1];
-} VMCIHandleArray;
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_Create --
- *
- * Results:
- * Array if successful, NULL if not.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE VMCIHandleArray *
-VMCIHandleArray_Create(uint32 capacity)
-{
- VMCIHandleArray *array;
-
- if (capacity == 0) {
- capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE;
- }
-
- array = (VMCIHandleArray *)VMCI_AllocKernelMem(sizeof array->capacity +
- sizeof array->size +
- capacity * sizeof(VMCIHandle),
- VMCI_MEMORY_NONPAGED |
- VMCI_MEMORY_ATOMIC);
- if (array == NULL) {
- return NULL;
- }
- array->capacity = capacity;
- array->size = 0;
-
- return array;
-}
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_Destroy --
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIHandleArray_Destroy(VMCIHandleArray *array)
-{
- VMCI_FreeKernelMem(array,
- sizeof array->capacity + sizeof array->size +
- array->capacity * sizeof(VMCIHandle));
-}
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_AppendEntry --
- *
- * Results:
- * None.
- *
- * Side effects:
- * Array may be reallocated.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIHandleArray_AppendEntry(VMCIHandleArray **arrayPtr,
- VMCIHandle handle)
-{
- VMCIHandleArray *array;
-
- ASSERT(arrayPtr && *arrayPtr);
- array = *arrayPtr;
-
- if (UNLIKELY(array->size >= array->capacity)) {
- /* reallocate. */
- uint32 arraySize = sizeof array->capacity + sizeof array->size +
- array->capacity * sizeof(VMCIHandle);
- VMCIHandleArray *newArray = (VMCIHandleArray *)
- VMCI_AllocKernelMem(arraySize + array->capacity * sizeof(VMCIHandle),
- VMCI_MEMORY_NONPAGED | VMCI_MEMORY_ATOMIC);
- if (newArray == NULL) {
- return;
- }
- memcpy(newArray, array, arraySize);
- newArray->capacity *= 2;
- VMCI_FreeKernelMem(array, arraySize);
- *arrayPtr = newArray;
- array = newArray;
- }
- array->entries[array->size] = handle;
- array->size++;
-}
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_RemoveEntry --
- *
- * Results:
- * Handle that was removed, VMCI_INVALID_HANDLE if entry not found.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE VMCIHandle
-VMCIHandleArray_RemoveEntry(VMCIHandleArray *array,
- VMCIHandle entryHandle)
-{
- uint32 i;
- VMCIHandle handle = VMCI_INVALID_HANDLE;
-
- ASSERT(array);
- for (i = 0; i < array->size; i++) {
- if (VMCI_HANDLE_EQUAL(array->entries[i], entryHandle)) {
- handle = array->entries[i];
- array->entries[i] = array->entries[array->size-1];
- array->entries[array->size-1] = VMCI_INVALID_HANDLE;
- array->size--;
- break;
- }
- }
-
- return handle;
-}
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_RemoveTail --
- *
- * Results:
- * Handle that was removed, VMCI_INVALID_HANDLE if array was empty.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE VMCIHandle
-VMCIHandleArray_RemoveTail(VMCIHandleArray *array)
-{
- VMCIHandle handle;
-
- if (array->size == 0) {
- return VMCI_INVALID_HANDLE;
- }
- handle = array->entries[array->size-1];
- array->entries[array->size-1] = VMCI_INVALID_HANDLE;
- array->size--;
-
- return handle;
-}
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_GetEntry --
- *
- * Results:
- * Handle at given index, VMCI_INVALID_HANDLE if invalid index.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE VMCIHandle
-VMCIHandleArray_GetEntry(const VMCIHandleArray *array,
- uint32 index)
-{
- ASSERT(array);
- if (UNLIKELY(index >= array->size)) {
- return VMCI_INVALID_HANDLE;
- }
-
- return array->entries[index];
-}
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_GetSize --
- *
- * Results:
- * Number of entries in array.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE uint32
-VMCIHandleArray_GetSize(const VMCIHandleArray *array)
-{
- ASSERT(array);
- return array->size;
-}
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_HasEntry --
- *
- * Results:
- * TRUE is entry exists in array, FALSE if not.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE Bool
-VMCIHandleArray_HasEntry(const VMCIHandleArray *array,
- VMCIHandle entryHandle)
-{
- uint32 i;
-
- ASSERT(array);
- for (i = 0; i < array->size; i++) {
- if (VMCI_HANDLE_EQUAL(array->entries[i], entryHandle)) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_GetCopy --
- *
- * Results:
- * Returns pointer to copy of array on success or NULL, if memory allocation
- * fails.
- *
- * Side effects:
- * Allocates nonpaged memory.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE VMCIHandleArray *
-VMCIHandleArray_GetCopy(const VMCIHandleArray *array)
-{
- VMCIHandleArray *arrayCopy;
-
- ASSERT(array);
-
- arrayCopy = (VMCIHandleArray *)VMCI_AllocKernelMem(sizeof array->capacity +
- sizeof array->size +
- array->size * sizeof(VMCIHandle),
- VMCI_MEMORY_NONPAGED |
- VMCI_MEMORY_ATOMIC);
- if (arrayCopy != NULL) {
- memcpy(&arrayCopy->size, &array->size,
- sizeof array->size + array->size * sizeof(VMCIHandle));
- arrayCopy->capacity = array->size;
- }
-
- return arrayCopy;
-}
-
-
-/*
- *-----------------------------------------------------------------------------------
- *
- * VMCIHandleArray_GetHandles --
- *
- * Results:
- * NULL if the array is empty. Otherwise, a pointer to the array
- * of VMCI handles in the handle array.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------------
- */
-
-static INLINE VMCIHandle *
-VMCIHandleArray_GetHandles(VMCIHandleArray *array) // IN
-{
- ASSERT(array);
-
- if (array->size) {
- return array->entries;
- } else {
- return NULL;
- }
-}
-
-#endif // _VMCI_HANDLE_ARRAY_H_
diff --git a/modules/linux/vmci/shared/vmci_page_channel.h b/modules/linux/vmci/shared/vmci_page_channel.h
deleted file mode 100644
index 22e9406..0000000
--- a/modules/linux/vmci/shared/vmci_page_channel.h
+++ /dev/null
@@ -1,733 +0,0 @@
-/*********************************************************
- * Copyright (C) 2011-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
- *
- *********************************************************/
-
-/*
- * vmci_page_channel.h
- *
- * vPageChannel structure and functions.
- */
-
-#ifndef _VMCI_PAGE_CHANNEL_H_
-#define _VMCI_PAGE_CHANNEL_H_
-
-#define INCLUDE_ALLOW_MODULE
-#define INCLUDE_ALLOW_VMK_MODULE
-#define INCLUDE_ALLOW_VMKERNEL
-#include "includeCheck.h"
-
-#include "vmci_defs.h"
-#include "vmci_call_defs.h"
-
-/** \cond PRIVATE */
-#define VPAGECHANNEL_MAX_TX_BUF_SIZE (1 << 14)
-#define VPAGECHANNEL_MAX_PAGES_PER_TX_BUFFER \
- (VPAGECHANNEL_MAX_TX_BUF_SIZE / PAGE_SIZE + 1)
-/** \endcond */
-
-/**
- * \brief Get a pointer to the elements in a packet.
- *
- * Returns a pointer to the elements at the end of a page channel packet.
- *
- * \see VPageChannelElem
- * \see VPageChannelPacket
- */
-
-#define VPAGECHANNEL_PACKET_ELEMS(packet) \
- (VPageChannelElem *)((char *)(packet) + \
- sizeof(VPageChannelPacket) + \
- packet->msgLen)
-
-/**
- * \brief Get a pointer to the message in a packet.
- *
- * Returns a pointer to the message embedded in a page channel packet.
- *
- * \see VPageChannelPacket
- */
-
-#define VPAGECHANNEL_PACKET_MESSAGE(packet) \
- (char *)((char *)(packet) + sizeof(VPageChannelPacket))
-
-/**
- * \brief Notify client directly, and do not read packets.
- *
- * This flag indicates that the channel should invoke the client's receive
- * callback directly when any packets are available. If not specified, then
- * when a notification is received, packets are read from the channel and the
- * callback invoked for each one separately.
- *
- * \note Not applicable to VMKernel.
- *
- * \see VPageChannel_CreateInVM()
- */
-
-#define VPAGECHANNEL_FLAGS_NOTIFY_ONLY 0x1
-
-/**
- * \brief Invoke client's receive callback in delayed context.
- *
- * This flag indicates that all callbacks run in a delayed context, and the
- * caller and callback are allowed to block. If not specified, then callbacks
- * run in interrupt context and the channel will not block, and the caller
- * is not allowed to block.
- *
- * \note Not applicable to VMKernel.
- *
- * \see VPageChannel_CreateInVM()
- */
-
-#define VPAGECHANNEL_FLAGS_RECV_DELAYED 0x2
-
-/**
- * \brief Send from an atomic context.
- *
- * This flag indicates that the client wishes to call Send() from an atomic
- * context and that the channel should not block. If the channel is not
- * allowed to block, then the channel's pages are permanently mapped and
- * pinned. Note that this will limit the total size of the channel to
- * VMCI_MAX_PINNED_QP_MEMORY.
- *
- * \note Not applicable to VMKernel.
- *
- * \see VPageChannel_CreateInVM()
- */
-
-#define VPAGECHANNEL_FLAGS_SEND_WHILE_ATOMIC 0x4
-
-/**
- * \brief An element describing a data range.
- *
- * Describes a data range, starting at a base address and for a given
- * length, i.e., an element of a scatter-gather list. Indicates physical
- * address for the guest and machine address for hypervisor. Can be passed
- * via packets or buffers.
- *
- * \note Structure is packed.
- *
- * \see VPageChannelPacket
- * \see VPageChanelBuffer
- */
-
-typedef
-#include "vmware_pack_begin.h"
-struct VPageChannelElem {
- union {
- /** \brief Physical address for guest. */
- uint64 pa;
-
- /** \brief Machine address for hypervisor. */
- uint64 ma;
- };
-
- /** \brief Length of range. */
- uint32 le;
-}
-#include "vmware_pack_end.h"
-VPageChannelElem;
-
-/**
- * \brief Page channel page types.
- *
- * The various types of page channel packets.
- *
- * \see VPageChannelPacket
- */
-typedef enum {
- /** \brief Data packet. */
- VPCPacket_Data = 1,
-
- /** \brief Completion notification, from hypervisor to guest. */
- VPCPacket_Completion_Notify,
-
- /** \cond PRIVATE */
- /** \brief Connect to hypervisor, internal. */
- VPCPacket_GuestConnect,
-
- /** \brief Complete connection handshake, internal. */
- VPCPacket_HyperConnect,
-
- /** \brief Request buffers, internal. */
- VPCPacket_RequestBuffer,
-
- /** \brief Set buffers, internal. */
- VPCPacket_SetRecvBuffer,
-
- /** \brief Hypervisor channel disconnect, internal. */
- VPCPacket_HyperDisconnect,
-
- /** \brief Guest channel ACK hypervisor disconnect, internal. */
- VPCPacket_GuestDisconnect,
- /** \endcond */
-} VPageChannelPacketType;
-
-/**
- * \brief Page channel packet structure.
- *
- * A packet structure for passing control/data between guest and hypervisor.
- * Can optionally contain a message and also a number of elements.
- *
- * \note Structure is packed.
- *
- * \see VPageChannelPacketType
- */
-typedef
-#include "vmware_pack_begin.h"
-struct VPageChannelPacket {
- /** \brief Type of packet. */
- VPageChannelPacketType type;
-
- /** \brief Length of optional message. */
- uint32 msgLen;
-
- /** \brief Number of optional elements in packet. */
- uint32 numElems;
-
- /** \brief Followed by msgLen of message and numElems VPageChannelElem. */
-}
-#include "vmware_pack_end.h"
-VPageChannelPacket;
-
-/**
- * \brief Page channel buffer structure.
- *
- * A buffer of elements (a scatter-gather list).
- *
- * \note Structure is packed.
- *
- * \see VPageChannelElem
- */
-
-typedef
-#include "vmware_pack_begin.h"
-struct VPageChannelBuffer {
- /** \brief Number of elements. */
- uint32 numElems;
-
- /** \brief First element. */
- VPageChannelElem elems[1];
-
- /** \brief Followed by numElems - 1 of VPageChannelElem. */
-}
-#include "vmware_pack_end.h"
-VPageChannelBuffer;
-
-/** \cond PRIVATE */
-typedef
-#include "vmware_pack_begin.h"
-struct VPageChannelGuestConnectMessage {
-
- /** \brief Guest channel's datagram handle for control channel. */
- VMCIHandle dgHandle;
-
- /** \brief Guest channel's queuepair handle. */
- VMCIHandle qpHandle;
-
- /** \brief Size of producer queue in queuepair in bytes. */
- uint64 produceQSize;
-
- /** \brief Size of consumer queue in queuepair in bytes. */
- uint64 consumeQSize;
-
- /** \brief Guest channel's doorbell handle. */
- VMCIHandle doorbellHandle;
-}
-#include "vmware_pack_end.h"
-VPageChannelGuestConnectMessage;
-
-typedef
-#include "vmware_pack_begin.h"
-struct VPageChannelHyperConnectMessage {
- /** \brief Hypervisor's doorbell handle. */
- VMCIHandle doorbellHandle;
-}
-#include "vmware_pack_end.h"
-VPageChannelHyperConnectMessage;
-/** \endcond PRIVATE */
-
-/** \cond PRIVATE */
-typedef enum VPageChannelState {
- VPCState_Free = 0,
- VPCState_Unconnected,
- VPCState_Connecting,
- VPCState_Connected,
- VPCState_Disconnecting,
- VPCState_Disconnected,
-} VPageChannelState;
-/** \endcond PRIVATE */
-
-/**
- * \brief Opaque page channel type.
- */
-
-struct VPageChannel;
-typedef struct VPageChannel VPageChannel;
-
-/**
- * \brief Client receive callback type.
- *
- * Type of receive callback, invoked when there are data packets in the
- * channel. The client provides a callback with this type to
- * VPageChannel_CreateInVM(). If VPAGECHANNEL_FLAGS_NOTIFY_ONLY is specified
- * in the channel creation flags, then \c packet is \c NULL; otherwise,
- * \c packet points to a channel packet.
- *
- * \see VPageChannel_CreateInVM()
- * \see VPageChannelPacket
- */
-
-typedef void (*VPageChannelRecvCB)(void *clientData,
- VPageChannelPacket *packet);
-
-
-#if !defined(VMKERNEL)
-
-/**
- * \brief Client element allocation callback type.
- *
- * Type of element allocation callback, invoked when the channel needs
- * elements. The client provides a callback of this type to
- * VPageChannel_CreateInVM().
- *
- * \see VPageChannel_CreateInVM()
- * \see VPageChannelElem
- * \see VPageChannelFreeElemFn
- */
-
-typedef int (*VPageChannelAllocElemFn)(void *clientData,
- VPageChannelElem *elems,
- int numElems);
-
-/**
- * \brief Client element release callback type.
- *
- * Type of element release callback, invoked when the channel releases
- * elements. The client provides a callback of this type to
- * VPageChannel_CreateInVM().
- *
- * \see VPageChannel_CreateInVM()
- * \see VPageChannelElem
- * \see VPageChannelAllocElemFn
- */
-
-typedef void (*VPageChannelFreeElemFn)(void *clientData,
- VPageChannelElem *elems,
- int numElems);
-
-/*
- ************************************************************************
- * VPageChannel_CreateInVM */ /**
- *
- * \brief Create guest page channel.
- *
- * Creates a page channel in the guest. The channel should be released
- * with VPageChannel_Destroy().
- *
- * \note Only applicable in the guest.
- *
- * \see VPageChannel_CreateInVMK()
- * \see VPageChannel_Destroy()
- *
- * \param[out] channel Pointer to a newly constructed page
- * channel if successful.
- * \param[in] resourceId Resource ID on which the channel should
- * register its control channel.
- * \param[in] peerResourceId Resource ID of peer's control channel.
- * \param[in] produceQSize Size of producer queue in queuepair in
- * bytes.
- * \param[in] consumeQSize Size of consumer queue in queuepair in
- * bytes.
- * \param[in] flags Channel flags.
- * \param[in] recvCB Client's receive callback.
- * \param[in] clientRecvData Client data for client's receive
- * callback.
- * \param[in] elemAlloc Element allocation callback for
- * allocating page ranges (scatter-gather
- * elements).
- * \param[in] allocClientData Client data for element allocation
- * callback.
- * \param[in] elemFree Element release callback for elements.
- * \param[in] freeClientData Client data for element release
- * callback.
- * \param[in] defRecvBufs Default number of elements sent to
- * hypervisor channel.
- * \param[in] maxRecvBufs Maximum number of elements that can be
- * sent to the hypervisor channel.
- *
- * \retval VMCI_SUCCESS Creation succeeded, \c *channel contains
- * a pointer to a valid channel.
- * \retval other Failure.
- *
- ************************************************************************
- */
-
-int VPageChannel_CreateInVM(VPageChannel **channel,
- VMCIId resourceId,
- VMCIId peerResourceId,
- uint64 produceQSize,
- uint64 consumeQSize,
- uint32 flags,
- VPageChannelRecvCB recvCB,
- void *clientRecvData,
- VPageChannelAllocElemFn elemAlloc,
- void *allocClientData,
- VPageChannelFreeElemFn elemFree,
- void *freeClientData,
- int defRecvBufs,
- int maxRecvBufs);
-
-#else // VMKERNEL
-
-/**
- * \brief Type of VM memory access off callback.
- *
- * This callback is invoked when the memory of the VM containing the peer
- * endpoint becomes inaccessible, for example due to a crash. When this
- * occurs, the client should unmap any guest pages and cleanup any state.
- * This callback runs in a blockable context. The client is not allowed to
- * call VPageChannel_Destroy() from inside the callback, or it will deadlock,
- * since that function will wait for the callback to complete.
- *
- * \note Only applicable on VMKernel.
- *
- * \see VPageChannel_CreateInVMK()
- */
-
-typedef void (*VPageChannelMemAccessOffCB)(void *clientData);
-
-/*
- ************************************************************************
- * VPageChannel_CreateInVMK */ /**
- *
- * \brief Create a page channel in VMKernel.
- *
- * Creates a page channel. The channel should be released with
- * VPageChannel_Destroy().
- *
- * \note Only applicable on VMKernel.
- *
- * \see VPageChannel_CreateInVM()
- * \see VPageChannel_Destroy()
- *
- * \param[out] channel Pointer to a newly constructed page
- * channel if successful.
- * \param[in] resourceId Resource ID on which to register
- * control channel.
- * \param[in] recvCB Client's receive callback.
- * \param[in] clientRecvData Client data for receive callback.
- * \param[in] memAccessOffCB Client's mem access off callback.
- * \param[in] memAccessOffData Client data for mem access off.
- *
- * \retval VMCI_SUCCESS Creation succeeded, \c *channel
- * contains a pointer to a valid channel.
- * \retval other Failure.
- *
- ***********************************************************************
- */
-
-int VPageChannel_CreateInVMK(VPageChannel **channel,
- VMCIId resourceId,
- VPageChannelRecvCB recvCB,
- void *clientRecvData,
- VPageChannelMemAccessOffCB memAccessOffCB,
- void *memAccessOffData);
-
-/*
- ************************************************************************
- * VPageChannel_ReserveBuffers */ /**
- *
- * \brief Reserve guest elements.
- *
- * Reserve sufficient guest elements to cover the given length. The
- * buffers can then be posted to the guest. This allocates both the
- * buffer and the elements within the buffer.
- *
- * \note Only applicable on VMKernel.
- *
- * \see VPageChannel_ReleaseBuffers()
- *
- * \param[in] channel Page channel.
- * \param[in] dataLen Length to reserve in bytes.
- * \param[out] buffer Pointer to a buffer containing elements to cover
- * the given length if successful.
- *
- * \retval VMCI_SUCCESS Reservation succeeded, \c *buffer contains
- * a pointer to a valid buffer.
- * \retval other Failure.
- *
- ************************************************************************
- */
-
-int VPageChannel_ReserveBuffers(VPageChannel *channel,
- size_t dataLen,
- VPageChannelBuffer **buffer);
-
-/*
- ************************************************************************
- * VPageChannel_ReleaseBuffers */ /**
- *
- * \brief Release guest elements.
- *
- * \note Only applicable on VMKernel.
- *
- * \see VPageChannel_ReserveBuffers()
- *
- * Release guest elements previous reserved with
- * VPageChannel_ReserveBuffers(). If the buffers were sent to the guest,
- * then only the buffer itself should be released, i.e.,
- * \c returnToFreePool should be \c FALSE; the guest will release the
- * buffers on completion. Otherwise, if for some reason they are not
- * sent after reserving them, then \c returnToFreePool should be set to
- * \c TRUE.
- *
- * \param[in] channel Page channel.
- * \param[in] buffer Buffer to be released.
- * \param[in] returnToFreePool If \c TRUE, then release the elements
- * of the buffer along with the buffer
- * itself. If \c FALSE, then release only
- * the buffer pointer itself.
- *
- ************************************************************************
- */
-
-void VPageChannel_ReleaseBuffers(VPageChannel *channel,
- VPageChannelBuffer *buffer,
- Bool returnToFreePool);
-
-/*
- ************************************************************************
- * VPageChannel_CompletionNotify */ /**
- *
- * \brief Notify channel of completion.
- *
- * This function is called when the client is finished using the elements
- * (scatter-gather list) of a packet. This will generated a notification
- * to the guest to pass ownership of the buffers back to the guest. This
- * can also be used to read back the data from the hypervisor and send
- * it to the guest.
- *
- * \note Only applicable on VMKernel.
- *
- * \see VPageChannel_ReserveBuffers
- *
- * \param[in] channel Channel on which I/O is complete.
- * \param[in] message Optional message to send to guest.
- * \param[in] len Length of optional message.
- * \param[in] buffer Buffer used for I/O.
- *
- ************************************************************************
- */
-
-int VPageChannel_CompletionNotify(VPageChannel *channel,
- char *message,
- int len,
- VPageChannelBuffer *buffer);
-
-/*
- ************************************************************************
- * VPageChannel_MapToMa */ /**
- *
- * \brief Map guest PA in an element to a list of MAs.
- *
- * Map a guest physical address to a list of hypervisor machine
- * addresses.
- *
- * \note Only applicable on VMKernel.
- *
- * \param[in] channel Channel on which to map.
- * \param[in] paElem Guest's physical address.
- * \param[out] maElems Hypervisor machine addresses.
- * \param[in] numElems Max number of hypervisor elements.
- *
- * \retval elems Number of mapped elements.
- *
- ************************************************************************
- */
-
-int VPageChannel_MapToMa(VPageChannel *channel,
- VPageChannelElem paElem,
- VPageChannelElem *maElems,
- uint32 numElems);
-
-/*
- ************************************************************************
- * VPageChannel_UnmapMa */ /**
- *
- * \brief Unmap MA for a buffer.
- *
- * Unmap hypervisor machine addresses referring to a guest physical
- * addresses.
- *
- * \note Only applicable on VMKernel.
- *
- * \see VPageChannel_MapToMa
- *
- * \param[in] channel Channel for which to unmap.
- * \param[in] buffer Buffer containing elements to unmap.
- * \param[in] numElems Number of elements to unmap.
- *
- * \retval 0 Unmap successful.
- * \retval -1 World not found for channel.
- *
- ************************************************************************
- */
-
-int VPageChannel_UnmapMa(VPageChannel *channel,
- VPageChannelBuffer *buffer,
- int numElems);
-
-#endif // VMKERNEL
-
-/*
- ************************************************************************
- * VPageChannel_Destroy */ /**
- *
- * \brief Destroy the given channel.
- *
- * Destroy the given channel. This will disconnect from the peer
- * channel (if connected) and release all resources.
- *
- * \see VPageChannel_CreateInVMK
- * \see VPageChannel_CreateInVM
- *
- * \param[in] channel The channel to be destroyed.
- *
- ************************************************************************
- */
-
-void VPageChannel_Destroy(VPageChannel *channel);
-
-/*
- ************************************************************************
- * VPageChannel_Send */ /**
- *
- * \brief Send a packet to the channel's peer.
- *
- * Send a packet to the channel's peer. A message and a number of
- * elements may optionally be sent. If the send is successful, the
- * elements are owned by the peer and only the buffer itself should
- * be released, but not the elements within. If the send fails, the
- * client should release the buffer and the elements.
- *
- * \see VPageChannel_SendPacket
- *
- * \param[in] channel Channel on which to send.
- * \param[in] type Type of packet to send.
- * \param[in] message Optional message to send.
- * \param[in] len Length of optional message.
- * \param[in] buffer Buffer (of elements) to send.
- *
- * \retval VMCI_SUCCESS Packet successfully sent, buffer elements
- * owned by peer.
- * \retval other Failure to send, client should release
- * elements.
- *
- ************************************************************************
- */
-
-int VPageChannel_Send(VPageChannel *channel,
- VPageChannelPacketType type,
- char *message,
- int len,
- VPageChannelBuffer *buffer);
-
-/*
- ************************************************************************
- * VPageChannel_SendPacket */ /**
- *
- * \brief Send the given packet to the channel's peer.
- *
- * Send a client-constructed packet to the channel's peer. If the
- * send is successful, any elements in the packet are owned by the
- * peer. Otherwise, the client retains ownership.
- *
- * \see VPageChannel_Send
- *
- * \param[in] channel Channel on which to send.
- * \param[in] packet Packet to be sent.
- *
- * \retval VMCI_SUCCESS Packet successfully sent, buffer elements
- * owned by peer.
- * \retval other Failure to send, client should release
- * elements.
- *
- ************************************************************************
- */
-
-int VPageChannel_SendPacket(VPageChannel *channel,
- VPageChannelPacket *packet);
-
-/*
- ************************************************************************
- * VPageChannel_PollRecvQ */ /**
- *
- * \brief Poll the channel's receive queue for packets.
- *
- * Poll the channel's receive queue for packets from the peer. If any
- * packets are available, the channel's receive callback will be invoked.
- *
- * \param[in] channel Channel to poll.
- *
- ************************************************************************
- */
-
-void VPageChannel_PollRecvQ(VPageChannel *channel);
-
-/*
- ************************************************************************
- * VPageChannel_BufferLen */ /**
- *
- * \brief Determine the length of a packet.
- *
- * Determine the length of the given packet in bytes.
- *
- * \param[in] packet Packet for which length is to be determined.
- *
- * \retval bytes Size of the packet in bytes.
- *
- ************************************************************************
- */
-
-static INLINE size_t
-VPageChannelPacket_BufferLen(VPageChannelPacket *packet) // IN
-{
- size_t len, i;
- VPageChannelElem *elems;
-
- ASSERT(packet);
-
- len = 0;
- elems = VPAGECHANNEL_PACKET_ELEMS(packet);
- for (i = 0; i < packet->numElems; i++) {
- len += elems[i].le;
- }
-
- return len;
-}
-
-/** \cond PRIVATE */
-#if defined(linux) && !defined(VMKERNEL)
-#include "compat_pci.h"
-#define vmci_pci_map_page(_pg, _off, _sz, _dir) \
- pci_map_page(NULL, (_pg), (_off), (_sz), (_dir))
-#define vmci_pci_unmap_page(_dma, _sz, _dir) \
- pci_unmap_page(NULL, (_dma), (_sz), (_dir))
-#endif // linux && !VMKERNEL
-/** \endcond PRIVATE */
-
-#endif // _VMCI_PACKET_H_
diff --git a/modules/linux/vmhgfs/file.c b/modules/linux/vmhgfs/file.c
index 1033984..db62070 100644
--- a/modules/linux/vmhgfs/file.c
+++ b/modules/linux/vmhgfs/file.c
@@ -25,6 +25,7 @@
/* Must come before any kernel header file. */
#include "driver-config.h"
+#include <linux/aio.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/signal.h>
diff --git a/modules/linux/vmsync/sync.c b/modules/linux/vmsync/sync.c
index d05ccad..73baf8b 100644
--- a/modules/linux/vmsync/sync.c
+++ b/modules/linux/vmsync/sync.c
@@ -162,7 +162,7 @@ VmSyncThawDevices(void *_state) // IN
cancel_delayed_work(&state->thawTask);
list_for_each_safe(cur, tmp, &state->devices) {
dev = list_entry(cur, VmSyncBlockDevice, list);
- if (dev->sb != NULL && dev->sb->s_frozen != SB_UNFROZEN) {
+ if (dev->sb != NULL && dev->sb->s_writers.frozen != SB_UNFROZEN) {
thaw_bdev(dev->bdev, dev->sb);
atomic_dec(&gFreezeCount);
}
@@ -237,7 +237,7 @@ VmSyncAddPath(const VmSyncState *state, // IN
* the superblock is already frozen.
*/
if (inode->i_sb->s_bdev == NULL ||
- inode->i_sb->s_frozen != SB_UNFROZEN) {
+ inode->i_sb->s_writers.frozen != SB_UNFROZEN) {
result = (inode->i_sb->s_bdev == NULL) ? -EINVAL : -EALREADY;
compat_path_release(&nd);
goto exit;
@@ -303,7 +303,7 @@ VmSyncFreezeDevices(VmSyncState *state, // IN
const char __user *userPaths) // IN
{
int result = 0;
- char *paths;
+ struct filename *paths;
char *currPath;
char *nextSep;
struct list_head *cur, *tmp;
@@ -328,7 +328,8 @@ VmSyncFreezeDevices(VmSyncState *state, // IN
/*
* First, try to add all paths to the list of paths to be frozen.
*/
- currPath = paths;
+ currPath = __getname();
+ strcpy(currPath, paths->name);
do {
nextSep = strchr(currPath, ':');
if (nextSep != NULL) {
@@ -347,6 +348,7 @@ VmSyncFreezeDevices(VmSyncState *state, // IN
}
currPath = nextSep + 1;
} while (nextSep != NULL);
+ __putname(currPath);
/*
* If adding all the requested paths worked, then freeze them.
@@ -371,6 +373,8 @@ VmSyncFreezeDevices(VmSyncState *state, // IN
compat_mutex_unlock(&state->lock);
compat_mutex_unlock(&gFreezeLock);
+ __putname(paths);
+
if (result == 0) {
compat_schedule_delayed_work(&state->thawTask, VMSYNC_THAW_TASK_DELAY);
}
@@ -670,9 +674,10 @@ init_module(void)
}
/* Create /proc/driver/vmware-sync */
- controlProcEntry = create_proc_entry("driver/vmware-sync",
- S_IFREG | S_IRUSR | S_IRGRP | S_IROTH,
- NULL);
+ controlProcEntry = proc_create("driver/vmware-sync",
+ S_IFREG | S_IRUSR | S_IRGRP | S_IROTH,
+ NULL,
+ &VmSyncFileOps);
if (!controlProcEntry) {
printk(KERN_ERR "vmsync: could not create /proc/driver/vmware-sync\n");
kmem_cache_destroy(gSyncStateCache);
@@ -680,7 +685,6 @@ init_module(void)
return -EINVAL;
}
- controlProcEntry->proc_fops = &VmSyncFileOps;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment