Home Files
Adminer
Execute Command
PHP Eval
Symlink
File Upload
Owner :
www-data
PHP Version
5.6.40-0+deb8u12
Disk Space
40.98 GB
Server Addr
19-www4
Your IP
10.10.10.40
Edit File
File:
vmci-only/ 0000755 0000000 0000000 00000000000 11573422251 011473 5 ustar root root vmci-only/shared/ 0000755 0000000 0000000 00000000000 11573422251 012741 5 ustar root root vmci-only/shared/compat_interrupt.h 0000444 0000000 0000000 00000003573 11573420431 016515 0 ustar root root /********************************************************* * Copyright (C) 2003 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_INTERRUPT_H__ # define __COMPAT_INTERRUPT_H__ #include <linux/interrupt.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 69) /* * We cannot just define irqreturn_t, as some 2.4.x kernels have * typedef void irqreturn_t; for "increasing" backward compatibility. */ typedef void compat_irqreturn_t; #define COMPAT_IRQ_NONE #define COMPAT_IRQ_HANDLED #define COMPAT_IRQ_RETVAL(x) #else typedef irqreturn_t compat_irqreturn_t; #define COMPAT_IRQ_NONE IRQ_NONE #define COMPAT_IRQ_HANDLED IRQ_HANDLED #define COMPAT_IRQ_RETVAL(x) IRQ_RETVAL(x) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) #define COMPAT_IRQF_DISABLED SA_INTERRUPT #define COMPAT_IRQF_SHARED SA_SHIRQ #else #define COMPAT_IRQF_DISABLED IRQF_DISABLED #define COMPAT_IRQF_SHARED IRQF_SHARED #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) #define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp, struct pt_regs *regs) #else #define COMPAT_IRQ_HANDLER_ARGS(irq, devp) (int irq, void *devp) #endif #endif /* __COMPAT_INTERRUPT_H__ */ vmci-only/shared/compat_scsi.h 0000444 0000000 0000000 00000003024 11573420431 015411 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_SCSI_H__ # define __COMPAT_SCSI_H__ /* The scsi_bufflen() API appeared somewhere in time --hpreg */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) # define scsi_bufflen(cmd) ((cmd)->request_bufflen) # define scsi_sg_count(cmd) ((cmd)->use_sg) # define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer) # define scsi_set_resid(cmd, _resid) ((cmd)->resid = _resid) #endif /* * Using scsi_sglist to access the request buffer looks strange * so instead we define this macro. What happened is later kernel * put all SCSI data in sglists, since it simplifies passing buffers */ #define scsi_request_buffer(cmd) scsi_sglist(cmd) #endif /* __COMPAT_SCSI_H__ */ vmci-only/shared/compat_pci.h 0000444 0000000 0000000 00000042504 11573420431 015231 0 ustar root root /********************************************************* * Copyright (C) 1999 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ /* * compat_pci.h: PCI compatibility wrappers. */ #ifndef __COMPAT_PCI_H__ #define __COMPAT_PCI_H__ #include "compat_ioport.h" #include <linux/pci.h> #ifndef KERNEL_2_1 # include <linux/bios32.h> #endif #if KERNEL_VERSION(2, 6, 6) <= LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) # ifndef DMA_BIT_MASK # define DMA_BIT_MASK(n) DMA_##n##BIT_MASK # endif #endif /* 2.0.x has useless struct pci_dev; remap it to our own */ #ifndef KERNEL_2_1 #define pci_dev vmw_pci_driver_instance #endif /* 2.0/2.2 does not have pci driver API */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) struct vmw_pci_driver_instance { struct vmw_pci_driver_instance *next; void *driver_data; struct pci_driver *pcidrv; #ifdef KERNEL_2_1 struct pci_dev *pcidev; #else unsigned char bus; unsigned char devfn; unsigned int irq; #endif }; #endif /* 2.0 has pcibios_* calls only... We have to provide pci_* compatible wrappers. */ #ifndef KERNEL_2_1 static inline int pci_read_config_byte(struct pci_dev *pdev, // IN: PCI slot unsigned char where, // IN: Byte to read u8 *value) // OUT: Value read { return pcibios_read_config_byte(pdev->bus, pdev->devfn, where, value); } static inline int pci_read_config_dword(struct pci_dev *pdev, // IN: PCI slot unsigned char where, // IN: Dword to read u32 *value) // OUT: Value read { return pcibios_read_config_dword(pdev->bus, pdev->devfn, where, value); } static inline int pci_write_config_dword(struct pci_dev *pdev, // IN: PCI slot unsigned char where, // IN: Dword to write u32 value) // IN: Value to write { return pcibios_write_config_dword(pdev->bus, pdev->devfn, where, value); } #endif /* *----------------------------------------------------------------------------- * * compat_pci_name -- * * Return human readable PCI slot name. Note that some implementations * return a pointer to the static storage, so returned value may be * overwritten by subsequent calls to this function. * * Results: * Returns pointer to the string with slot name. * * Side effects: * None. * *----------------------------------------------------------------------------- */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22) #define compat_pci_name(pdev) pci_name(pdev) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) #define compat_pci_name(pdev) (pdev)->slot_name #elif defined(KERNEL_2_1) static inline const char* compat_pci_name(struct pci_dev* pdev) { static char slot_name[12]; sprintf(slot_name, "%02X:%02X.%X", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return slot_name; } #else static inline const char* compat_pci_name(struct pci_dev* pdev) { static char slot_name[12]; sprintf(slot_name, "%02X:%02X.%X", pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); return slot_name; } #endif /* pci_resource_start comes in 4 flavors - 2.0, 2.2, early 2.3, 2.4+ */ #ifndef KERNEL_2_1 static inline unsigned long compat_pci_resource_start(struct pci_dev *pdev, unsigned int index) { u32 addr; if (pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + index * 4, &addr)) { printk(KERN_ERR "Unable to read base address %u from PCI slot %s!\n", index, compat_pci_name(pdev)); return ~0UL; } if (addr & PCI_BASE_ADDRESS_SPACE) { return addr & PCI_BASE_ADDRESS_IO_MASK; } else { return addr & PCI_BASE_ADDRESS_MEM_MASK; } } #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 1) # define compat_pci_resource_start(dev, index) \ (((dev)->base_address[index] & PCI_BASE_ADDRESS_SPACE) \ ? ((dev)->base_address[index] & PCI_BASE_ADDRESS_IO_MASK) \ : ((dev)->base_address[index] & PCI_BASE_ADDRESS_MEM_MASK)) #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43) # define compat_pci_resource_start(dev, index) \ ((dev)->resource[index].start) #else # define compat_pci_resource_start(dev, index) \ pci_resource_start(dev, index) #endif /* since 2.3.15, a new set of s/w res flags IORESOURCE_ is introduced, * we fake them by returning either IORESOURCE_{IO, MEM} prior to 2.3.15 since * this is what compat_pci_request_region uses */ #ifndef KERNEL_2_1 static inline unsigned long compat_pci_resource_flags(struct pci_dev *pdev, unsigned int index) { u32 addr; if (pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0 + index * 4, &addr)) { printk(KERN_ERR "Unable to read base address %u from PCI slot %s!\n", index, compat_pci_name(pdev)); return ~0UL; } if (addr & PCI_BASE_ADDRESS_SPACE) { return IORESOURCE_IO; } else { return IORESOURCE_MEM; } } #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 1) # define compat_pci_resource_flags(dev, index) \ (((dev)->base_address[index] & PCI_BASE_ADDRESS_SPACE) \ ? IORESOURCE_IO: IORESOURCE_MEM) #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 15) /* IORESOURCE_xxx appeared in 2.3.15 and is set in resource[].flags */ # define compat_pci_resource_flags(dev, index) ((dev)->resource[index].flags) #else # define compat_pci_resource_flags(dev, index) pci_resource_flags(dev, index) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) static inline unsigned long compat_pci_resource_len(struct pci_dev *pdev, // IN unsigned int index) // IN { u32 addr, mask; unsigned char reg = PCI_BASE_ADDRESS_0 + index * 4; if (pci_read_config_dword(pdev, reg, &addr) || addr == 0xFFFFFFFF) { return 0; } pci_write_config_dword(pdev, reg, 0xFFFFFFFF); pci_read_config_dword(pdev, reg, &mask); pci_write_config_dword(pdev, reg, addr); if (mask == 0 || mask == 0xFFFFFFFF) { return 0; } if (addr & PCI_BASE_ADDRESS_SPACE) { return 65536 - (mask & PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); } else { return -(mask & PCI_BASE_ADDRESS_MEM_MASK); } } #else #define compat_pci_resource_len(dev, index) pci_resource_len(dev, index) #endif /* pci_request_region appears in 2.4.20 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) static inline int compat_pci_request_region(struct pci_dev *pdev, int bar, char *name) { if (compat_pci_resource_len(pdev, bar) == 0) { return 0; } if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_IO) { if (!compat_request_region(compat_pci_resource_start(pdev, bar), compat_pci_resource_len(pdev, bar), name)) { return -EBUSY; } } else if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { if (!compat_request_mem_region(compat_pci_resource_start(pdev, bar), compat_pci_resource_len(pdev, bar), name)) { return -EBUSY; } } return 0; } static inline void compat_pci_release_region(struct pci_dev *pdev, int bar) { if (compat_pci_resource_len(pdev, bar) != 0) { if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_IO) { release_region(compat_pci_resource_start(pdev, bar), compat_pci_resource_len(pdev, bar)); } else if (compat_pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { compat_release_mem_region(compat_pci_resource_start(pdev, bar), compat_pci_resource_len(pdev, bar)); } } } #else #define compat_pci_request_region(pdev, bar, name) pci_request_region(pdev, bar, name) #define compat_pci_release_region(pdev, bar) pci_release_region(pdev, bar) #endif /* pci_request_regions appeears in 2.4.3 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) static inline int compat_pci_request_regions(struct pci_dev *pdev, char *name) { int i; for (i = 0; i < 6; i++) { if (compat_pci_request_region(pdev, i, name)) { goto release; } } return 0; release: while (--i >= 0) { compat_pci_release_region(pdev, i); } return -EBUSY; } static inline void compat_pci_release_regions(struct pci_dev *pdev) { int i; for (i = 0; i < 6; i++) { compat_pci_release_region(pdev, i); } } #else #define compat_pci_request_regions(pdev, name) pci_request_regions(pdev, name) #define compat_pci_release_regions(pdev) pci_release_regions(pdev) #endif /* pci_enable_device is available since 2.4.0 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) #define compat_pci_enable_device(pdev) (0) #else #define compat_pci_enable_device(pdev) pci_enable_device(pdev) #endif /* pci_set_master is available since 2.2.0 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) #define compat_pci_set_master(pdev) (0) #else #define compat_pci_set_master(pdev) pci_set_master(pdev) #endif /* pci_disable_device is available since 2.4.4 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 4) #define compat_pci_disable_device(pdev) do {} while (0) #else #define compat_pci_disable_device(pdev) pci_disable_device(pdev) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) /* * Devices supported by particular pci driver. While 2.4+ kernels * can do match on subsystem and class too, we support match on * vendor/device IDs only. */ struct pci_device_id { unsigned int vendor, device; unsigned long driver_data; }; #define PCI_DEVICE(vend, dev) .vendor = (vend), .device = (dev) /* PCI driver */ struct pci_driver { const char *name; const struct pci_device_id *id_table; int (*probe)(struct pci_dev* dev, const struct pci_device_id* id); void (*remove)(struct pci_dev* dev); }; /* * Note that this is static variable. Maybe everything below should be in * separate compat_pci.c file, but currently only user of this file is vmxnet, * and vmxnet has only one file, so it is fine. Also with vmxnet all * functions below are called just once, so difference between 'inline' and * separate compat_pci.c should be very small. */ static struct vmw_pci_driver_instance *pci_driver_instances = NULL; #ifdef KERNEL_2_1 #define vmw_pci_device(instance) (instance)->pcidev #else #define vmw_pci_device(instance) (instance) #endif /* *----------------------------------------------------------------------------- * * pci_register_driver -- * * Create driver instances for all matching PCI devices in the box. * * Results: * Returns 0 for success, negative error value for failure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static inline int pci_register_driver(struct pci_driver *drv) { const struct pci_device_id *chipID; for (chipID = drv->id_table; chipID->vendor; chipID++) { #ifdef KERNEL_2_1 struct pci_dev *pdev; for (pdev = NULL; (pdev = pci_find_device(chipID->vendor, chipID->device, pdev)) != NULL; ) { #else int adapter; unsigned char bus, devfn, irq; for (adapter = 0; pcibios_find_device(chipID->vendor, chipID->device, adapter, &bus, &devfn) == 0; adapter++) { #endif struct vmw_pci_driver_instance *pdi; int err; pdi = kmalloc(sizeof *pdi, GFP_KERNEL); if (!pdi) { printk(KERN_ERR "Not enough memory.\n"); break; } pdi->pcidrv = drv; #ifdef KERNEL_2_1 pdi->pcidev = pdev; #else pdi->bus = bus; pdi->devfn = devfn; if (pci_read_config_byte(pdi, PCI_INTERRUPT_LINE, &irq)) { pdi->irq = -1; } else { pdi->irq = irq; } #endif pdi->driver_data = NULL; pdi->next = pci_driver_instances; pci_driver_instances = pdi; err = drv->probe(vmw_pci_device(pdi), chipID); if (err) { pci_driver_instances = pdi->next; kfree(pdi); } } } return 0; } /* *----------------------------------------------------------------------------- * * compat_pci_unregister_driver -- * * Shut down PCI driver - unbind all device instances from driver. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static inline void pci_unregister_driver(struct pci_driver *drv) { struct vmw_pci_driver_instance **ppdi; ppdi = &pci_driver_instances; while (1) { struct vmw_pci_driver_instance *pdi = *ppdi; if (!pdi) { break; } if (pdi->pcidrv == drv) { drv->remove(vmw_pci_device(pdi)); *ppdi = pdi->next; kfree(pdi); } else { ppdi = &pdi->next; } } } #else /* provide PCI_DEVICE for early 2.4.x kernels */ #ifndef PCI_DEVICE #define PCI_DEVICE(vend, dev) .vendor = (vend), .device = (dev), \ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID #endif #endif /* provide dummy MODULE_DEVICE_TABLE for 2.0/2.2 */ #ifndef MODULE_DEVICE_TABLE #define MODULE_DEVICE_TABLE(bus, devices) #endif /* *----------------------------------------------------------------------------- * * pci_set_drvdata -- * * Set per-device driver's private data. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ /* *----------------------------------------------------------------------------- * * pci_get_drvdata -- * * Retrieve per-device driver's private data. * * Results: * per-device driver's data previously set by pci_set_drvdata, * or NULL on failure. * * Side effects: * None. * *----------------------------------------------------------------------------- */ #ifndef KERNEL_2_1 /* 2.0.x is simple, we have driver_data directly in pci_dev */ #define pci_set_drvdata(pdev, data) do { (pdev)->driver_data = (data); } while (0) #define pci_get_drvdata(pdev) (pdev)->driver_data #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) /* 2.2.x is trickier, we have to find driver instance first */ static inline void pci_set_drvdata(struct pci_dev *pdev, void* data) { struct vmw_pci_driver_instance *pdi; for (pdi = pci_driver_instances; pdi; pdi = pdi->next) { if (pdi->pcidev == pdev) { pdi->driver_data = data; return; } } printk(KERN_ERR "pci_set_drvdata issued for unknown device %p\n", pdev); } static inline void * pci_get_drvdata(struct pci_dev *pdev) { struct vmw_pci_driver_instance *pdi; for (pdi = pci_driver_instances; pdi; pdi = pdi->next) { if (pdi->pcidev == pdev) { return pdi->driver_data; } } printk(KERN_ERR "pci_get_drvdata issued for unknown device %p\n", pdev); return NULL; } #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48) # define PCI_DMA_BIDIRECTIONAL 0 # define PCI_DMA_TODEVICE 1 # define PCI_DMA_FROMDEVICE 2 # define PCI_DMA_NONE 3 #endif /* * Power Management related compat wrappers. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) # define compat_pci_save_state(pdev) pci_save_state((pdev), NULL) # define compat_pci_restore_state(pdev) pci_restore_state((pdev), NULL) #else # define compat_pci_save_state(pdev) pci_save_state((pdev)) # define compat_pci_restore_state(pdev) pci_restore_state((pdev)) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) # define pm_message_t u32 # define compat_pci_choose_state(pdev, state) (state) # define PCI_D0 0 # define PCI_D3hot 3 #else # define compat_pci_choose_state(pdev, state) pci_choose_state((pdev), (state)) #endif /* 2.6.14 changed the PCI shutdown callback */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) # define COMPAT_PCI_SHUTDOWN(func) .driver = { .shutdown = (func), } # define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct device *(var)) # define COMPAT_PCI_TO_DEV(dev) (to_pci_dev(dev)) #else # define COMPAT_PCI_SHUTDOWN(func) .shutdown = (func) # define COMPAT_PCI_DECLARE_SHUTDOWN(func, var) (func)(struct pci_dev *(var)) # define COMPAT_PCI_TO_DEV(dev) (dev) #endif /* 2.6.26 introduced the device_set_wakeup_enable() function */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) # define compat_device_set_wakeup_enable(dev, val) do{}while(0) #else # define compat_device_set_wakeup_enable(dev, val) \ device_set_wakeup_enable(dev, val) #endif #endif /* __COMPAT_PCI_H__ */ vmci-only/shared/compat_statfs.h 0000444 0000000 0000000 00000002306 11573420431 015756 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __COMPAT_STATFS_H__ # define __COMPAT_STATFS_H__ /* vfs.h simply include statfs.h, but it knows what directory statfs.h is in. */ #include <linux/vfs.h> /* 2.5.74 renamed struct statfs to kstatfs. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 74) #define compat_kstatfs kstatfs #else #define compat_kstatfs statfs #endif #endif /* __COMPAT_STATFS_H__ */ vmci-only/shared/kernelStubs.h 0000444 0000000 0000000 00000011372 11573420377 015424 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * kernelStubs.h * * KernelStubs implements some userspace library functions in terms * of kernel functions to allow library userspace code to be used in a * kernel. */ #ifndef __KERNELSTUBS_H__ #define __KERNELSTUBS_H__ #ifdef linux # ifndef __KERNEL__ # error "__KERNEL__ is not defined" # endif # include "driver-config.h" // Must be included before any other header files # include "vm_basic_types.h" # include <linux/kernel.h> # include <linux/string.h> #elif defined(_WIN32) # include "vm_basic_types.h" # include <ntddk.h> /* kernel memory APIs */ # include <stdio.h> /* for _vsnprintf, vsprintf */ # include <stdarg.h> /* for va_start stuff */ # include <stdlib.h> /* for min macro. */ # include "vm_assert.h" /* Our assert macros */ #elif defined(__FreeBSD__) # include "vm_basic_types.h" # ifndef _KERNEL # error "_KERNEL is not defined" # endif # include <sys/types.h> # include <sys/malloc.h> # include <sys/param.h> # include <sys/kernel.h> # include <machine/stdarg.h> # include <sys/libkern.h> # include "vm_assert.h" #elif defined(__APPLE__) # include "vm_basic_types.h" # ifndef KERNEL # error "KERNEL is not defined" # endif # include <stdarg.h> # include <string.h> # elif defined(sun) # include "vm_basic_types.h" # include <sys/types.h> # include <sys/varargs.h> #endif /* * Function Prototypes */ #if defined(linux) || defined(__APPLE__) || defined (sun) # ifdef linux /* if (linux) { */ char *strdup(const char *source); # endif /* Shared between Linux and Apple kernel stubs. */ void *malloc(size_t size); void free(void *mem); void *calloc(size_t num, size_t len); void *realloc(void *ptr, size_t newSize); #elif defined(_WIN32) /* } else if (_WIN32) { */ #if (_WIN32_WINNT == 0x0400) /* The following declarations are missing on NT4. */ typedef unsigned int UINT_PTR; typedef unsigned int SIZE_T; /* No free with tag availaible on NT4 kernel! */ #define KRNL_STUBS_FREE(P,T) ExFreePool((P)) #else /* _WIN32_WINNT */ #define KRNL_STUBS_FREE(P,T) ExFreePoolWithTag((P),(T)) /* Win 2K and later useful kernel function, documented but not declared! */ NTKERNELAPI VOID ExFreePoolWithTag(IN PVOID P, IN ULONG Tag); #endif /* _WIN32_WINNT */ #elif defined(__FreeBSD__) /* } else if (FreeBSD) { */ /* Kernel memory on FreeBSD is tagged for statistics and sanity checking. */ MALLOC_DECLARE(M_VMWARE_TEMP); /* * On FreeBSD, the general memory allocator for both userland and the kernel is named * malloc, but the kernel malloc() takes more arguments. The following alias & macros * work around this, to provide the standard malloc() API for userspace code that is * being used in the kernel. */ # undef malloc static INLINE void * __compat_malloc(unsigned long size, struct malloc_type *type, int flags) { return malloc(size, type, flags); } # define malloc(size) __compat_malloc(size, M_VMWARE_TEMP, M_NOWAIT) # define calloc(count, size) __compat_malloc((count) * (size), \ M_VMWARE_TEMP, M_NOWAIT|M_ZERO) # define realloc(buf, size) realloc(buf, size, M_VMWARE_TEMP, M_NOWAIT) # define free(buf) free(buf, M_VMWARE_TEMP) # define strchr(s,c) index(s,c) # define strrchr(s,c) rindex(s,c) #endif /* } */ /* * Stub functions we provide. */ void Panic(const char *fmt, ...); char *Str_Strcpy(char *buf, const char *src, size_t maxSize); int Str_Vsnprintf(char *str, size_t size, const char *format, va_list arguments); char *Str_Vasprintf(size_t *length, const char *format, va_list arguments); char *Str_Asprintf(size_t *length, const char *Format, ...); /* * Functions the driver must implement for the stubs. */ EXTERN void Debug(const char *fmt, ...); #endif /* __KERNELSTUBS_H__ */ vmci-only/shared/includeCheck.h 0000444 0000000 0000000 00000007353 11573420432 015500 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * includeCheck.h -- * * Restrict include file use. * * In every .h file, define one or more of these * * INCLUDE_ALLOW_VMX * INCLUDE_ALLOW_USERLEVEL * INCLUDE_ALLOW_VMCORE * INCLUDE_ALLOW_MODULE * INCLUDE_ALLOW_VMKERNEL * INCLUDE_ALLOW_DISTRIBUTE * INCLUDE_ALLOW_VMK_MODULE * INCLUDE_ALLOW_VMKDRIVERS * INCLUDE_ALLOW_VMIROM * * Then include this file. * * Any file that has INCLUDE_ALLOW_DISTRIBUTE defined will potentially * be distributed in source form along with GPLed code. Ensure * that this is acceptable. */ /* * Declare a VMCORE-only variable to help classify object * files. The variable goes in the common block and does * not create multiple definition link-time conflicts. */ #if defined VMCORE && defined VMX86_DEVEL && defined VMX86_DEBUG && \ defined linux && !defined MODULE && \ !defined COMPILED_WITH_VMCORE #define COMPILED_WITH_VMCORE compiled_with_vmcore #ifdef ASM .comm compiled_with_vmcore, 0 #else asm(".comm compiled_with_vmcore, 0"); #endif /* ASM */ #endif #if defined VMCORE && \ !(defined VMX86_VMX || defined VMM || \ defined MONITOR_APP || defined VMMON) #error "Makefile problem: VMCORE without VMX86_VMX or \ VMM or MONITOR_APP or MODULE." #endif #if defined VMCORE && !defined INCLUDE_ALLOW_VMCORE #error "The surrounding include file is not allowed in vmcore." #endif #undef INCLUDE_ALLOW_VMCORE #if defined VMX86_VMX && !defined VMCORE && \ !(defined INCLUDE_ALLOW_VMX || defined INCLUDE_ALLOW_USERLEVEL) #error "The surrounding include file is not allowed in the VMX." #endif #undef INCLUDE_ALLOW_VMX #if defined USERLEVEL && !defined VMX86_VMX && !defined VMCORE && \ !defined INCLUDE_ALLOW_USERLEVEL #error "The surrounding include file is not allowed at userlevel." #endif #undef INCLUDE_ALLOW_USERLEVEL #if defined MODULE && !defined VMKERNEL_MODULE && \ !defined VMMON && !defined INCLUDE_ALLOW_MODULE #error "The surrounding include file is not allowed in driver modules." #endif #undef INCLUDE_ALLOW_MODULE #if defined VMMON && !defined INCLUDE_ALLOW_VMMON #error "The surrounding include file is not allowed in vmmon." #endif #undef INCLUDE_ALLOW_VMMON #if defined VMKERNEL && !defined INCLUDE_ALLOW_VMKERNEL #error "The surrounding include file is not allowed in the vmkernel." #endif #undef INCLUDE_ALLOW_VMKERNEL #if defined GPLED_CODE && !defined INCLUDE_ALLOW_DISTRIBUTE #error "The surrounding include file is not allowed in GPL code." #endif #undef INCLUDE_ALLOW_DISTRIBUTE #if defined VMKERNEL_MODULE && !defined VMKERNEL && \ !defined INCLUDE_ALLOW_VMK_MODULE && !defined INCLUDE_ALLOW_VMKDRIVERS #error "The surrounding include file is not allowed in vmkernel modules." #endif #undef INCLUDE_ALLOW_VMK_MODULE #undef INCLUDE_ALLOW_VMKDRIVERS #if defined VMIROM && ! defined INCLUDE_ALLOW_VMIROM #error "The surrounding include file is not allowed in vmirom." #endif #undef INCLUDE_ALLOW_VMIROM vmci-only/shared/vmci_kernel_if.h 0000444 0000000 0000000 00000032600 11573420432 016064 0 ustar root root /********************************************************* * 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_kernel_if.h -- * * This file defines helper functions for VMCI host _and_ guest * kernel code. It must work for Windows, Mac OS, vmkernel, Linux and * Solaris kernels, i.e. using defines where necessary. */ #ifndef _VMCI_KERNEL_IF_H_ #define _VMCI_KERNEL_IF_H_ #if !defined(linux) && !defined(_WIN32) && !defined(__APPLE__) && \ !defined(VMKERNEL) && !defined(SOLARIS) #error "Platform not supported." #endif #if defined(_WIN32) #include <ntddk.h> #endif #if defined(linux) && !defined(VMKERNEL) # include <linux/wait.h> # include "compat_version.h" # include "compat_spinlock.h" # include "compat_semaphore.h" #endif // linux #ifdef __APPLE__ # include <IOKit/IOLib.h> #include <mach/task.h> #include <mach/semaphore.h> #endif #ifdef VMKERNEL #include "splock.h" #include "semaphore_ext.h" #include "vmkapi.h" #endif #ifdef SOLARIS # include <sys/mutex.h> # include <sys/poll.h> # include <sys/semaphore.h> # include <sys/kmem.h> #endif #include "vm_basic_types.h" #include "vmci_defs.h" #if defined(__APPLE__) # include "dbllnklst.h" #endif /* Flags for specifying memory type. */ #define VMCI_MEMORY_NORMAL 0x0 #define VMCI_MEMORY_ATOMIC 0x1 #define VMCI_MEMORY_NONPAGED 0x2 /* Platform specific type definitions. */ #if defined(VMKERNEL) # define VMCI_EXPORT_SYMBOL(_SYMBOL) VMK_MODULE_EXPORT_SYMBOL(_SYMBOL); #elif defined(linux) # define VMCI_EXPORT_SYMBOL(_symbol) EXPORT_SYMBOL(_symbol); #elif defined(__APPLE__) # define VMCI_EXPORT_SYMBOL(_symbol) __attribute__((visibility("default"))) #else # define VMCI_EXPORT_SYMBOL(_symbol) #endif #if defined(VMKERNEL) typedef SP_SpinLock VMCILock; typedef SP_IRQL VMCILockFlags; typedef Semaphore VMCIEvent; typedef Semaphore VMCIMutex; typedef World_ID VMCIHostVmID; #elif defined(linux) typedef spinlock_t VMCILock; typedef unsigned long VMCILockFlags; typedef wait_queue_head_t VMCIEvent; typedef struct semaphore VMCIMutex; typedef PPN *VMCIPpnList; /* List of PPNs in produce/consume queue. */ #elif defined(__APPLE__) typedef IOLock *VMCILock; typedef unsigned long VMCILockFlags; typedef struct { IOLock *lock; DblLnkLst_Links waiters; int buffered; } VMCIEvent; typedef IOLock *VMCIMutex; typedef void *VMCIPpnList; /* Actually a pointer to the C++ Object IOMemoryDescriptor */ #elif defined(_WIN32) typedef KSPIN_LOCK VMCILock; typedef KIRQL VMCILockFlags; typedef KEVENT VMCIEvent; typedef FAST_MUTEX VMCIMutex; typedef PMDL VMCIPpnList; /* MDL to map the produce/consume queue. */ #elif defined(SOLARIS) typedef kmutex_t VMCILock; typedef unsigned long VMCILockFlags; typedef ksema_t VMCIEvent; typedef kmutex_t VMCIMutex; typedef PPN *VMCIPpnList; /* List of PPNs in produce/consume queue. */ #endif // VMKERNEL /* Callback needed for correctly waiting on events. */ typedef int (*VMCIEventReleaseCB)(void *clientData); /* * The VMCI locks use a ranking scheme similar to the one used by * vmkernel. While holding a lock L1 with rank R1, only locks with * rank higher than R1 may be grabbed. The available ranks for VMCI * locks are (in descending order): * - VMCI_LOCK_RANK_HIGH_BH : to be used for locks grabbed while executing * in a bottom half and not held while grabbing other locks. * - VMCI_LOCK_RANK_MIDDLE_BH : to be for locks grabbed while executing in a * bottom half and held while grabbing locks of rank VMCI_LOCK_RANK_HIGH_BH. * - VMCI_LOCK_RANK_LOW_BH : to be for locks grabbed while executing in a * bottom half and held while grabbing locks of rank * VMCI_LOCK_RANK_MIDDLE_BH. * - VMCI_LOCK_RANK_HIGHEST : to be used for locks that are not held while * grabbing other locks except system locks with higher ranks and bottom * half locks. * - VMCI_LOCK_RANK_HIGHER : to be used for locks that are held while * grabbing locks of rank VMCI_LOCK_RANK_HIGHEST or higher. * - VMCI_LOCK_RANK_HIGH : to be used for locks that are held while * grabbing locks of rank VMCI_LOCK_RANK_HIGHER or higher. This is * the highest lock rank used by core VMCI services * - VMCI_LOCK_RANK_MIDDLE : to be used for locks that are held while * grabbing locks of rank VMCI_LOCK_RANK_HIGH or higher. * - VMCI_LOCK_RANK_LOW : to be used for locks that are held while * grabbing locks of rank VMCI_LOCK_RANK_MIDDLE or higher. * - VMCI_LOCK_RANK_LOWEST : to be used for locks that are held while * grabbing locks of rank VMCI_LOCK_RANK_LOW or higher. */ #ifdef VMKERNEL typedef SP_Rank VMCILockRank; #define VMCI_LOCK_RANK_HIGH_BH SP_RANK_IRQ_LEAF #define VMCI_LOCK_RANK_MIDDLE_BH (SP_RANK_IRQ_LEAF-1) #define VMCI_LOCK_RANK_LOW_BH SP_RANK_IRQ_LOWEST #define VMCI_LOCK_RANK_HIGHEST SP_RANK_SHM_MGR-1 #else typedef unsigned long VMCILockRank; #define VMCI_LOCK_RANK_HIGHER_BH 0x8000 #define VMCI_LOCK_RANK_HIGH_BH 0x4000 #define VMCI_LOCK_RANK_MIDDLE_BH 0x2000 #define VMCI_LOCK_RANK_LOW_BH 0x1000 #define VMCI_LOCK_RANK_HIGHEST 0x0fff #endif // VMKERNEL #define VMCI_LOCK_RANK_HIGHER (VMCI_LOCK_RANK_HIGHEST-1) #define VMCI_LOCK_RANK_HIGH (VMCI_LOCK_RANK_HIGHER-1) #define VMCI_LOCK_RANK_MIDDLE_HIGH (VMCI_LOCK_RANK_HIGH-1) #define VMCI_LOCK_RANK_MIDDLE (VMCI_LOCK_RANK_MIDDLE_HIGH-1) #define VMCI_LOCK_RANK_MIDDLE_LOW (VMCI_LOCK_RANK_MIDDLE-1) #define VMCI_LOCK_RANK_LOW (VMCI_LOCK_RANK_MIDDLE_LOW-1) #define VMCI_LOCK_RANK_LOWEST (VMCI_LOCK_RANK_LOW-1) /* * In vmkernel, we try to reduce the amount of memory mapped into the * virtual address space by only mapping the memory of buffered * datagrams when copying from and to the guest. In other OSes, * regular kernel memory is used. VMCIBuffer is used to reference * possibly unmapped memory. */ #ifdef VMKERNEL typedef MPN VMCIBuffer; #define VMCI_BUFFER_INVALID INVALID_MPN #else typedef void * VMCIBuffer; #define VMCI_BUFFER_INVALID NULL #endif /* * Host specific struct used for signalling. */ typedef struct VMCIHost { #if defined(VMKERNEL) World_ID vmmWorldID[2]; /* * First one is the active one and the second * one is shadow world during FSR. */ #elif defined(linux) wait_queue_head_t waitQueue; #elif defined(__APPLE__) struct Socket *socket; /* vmci Socket object on Mac OS. */ #elif defined(_WIN32) KEVENT *callEvent; /* Ptr to userlevel event used when signalling * new pending guestcalls in kernel. */ #elif defined(SOLARIS) struct pollhead pollhead; /* Per datagram handle pollhead structure to * be treated as a black-box. None of its * fields should be referenced. */ #endif } VMCIHost; void VMCI_InitLock(VMCILock *lock, char *name, VMCILockRank rank); void VMCI_CleanupLock(VMCILock *lock); void VMCI_GrabLock(VMCILock *lock, VMCILockFlags *flags); void VMCI_ReleaseLock(VMCILock *lock, VMCILockFlags flags); void VMCI_GrabLock_BH(VMCILock *lock, VMCILockFlags *flags); void VMCI_ReleaseLock_BH(VMCILock *lock, VMCILockFlags flags); void VMCIHost_InitContext(VMCIHost *hostContext, uintptr_t eventHnd); void VMCIHost_ReleaseContext(VMCIHost *hostContext); void VMCIHost_SignalCall(VMCIHost *hostContext); void VMCIHost_ClearCall(VMCIHost *hostContext); Bool VMCIHost_WaitForCallLocked(VMCIHost *hostContext, VMCILock *lock, VMCILockFlags *flags, Bool useBH); #ifdef VMKERNEL int VMCIHost_ContextToHostVmID(VMCIHost *hostContext, VMCIHostVmID *hostVmID); void VMCIHost_SetActiveHnd(VMCIHost *hostContext, uintptr_t eventHnd); Bool VMCIHost_RemoveHnd(VMCIHost *hostContext, uintptr_t eventHnd); Bool VMCIHost_IsActiveHnd(VMCIHost *hostContext, uintptr_t eventHnd); void VMCIHost_SetInactiveHnd(VMCIHost *hostContext, uintptr_t eventHnd); uint32 VMCIHost_NumHnds(VMCIHost *hostContext); uintptr_t VMCIHost_GetActiveHnd(VMCIHost *hostContext); void VMCIHost_SignalBitmap(VMCIHost *hostContext); #endif void *VMCI_AllocKernelMem(size_t size, int flags); void VMCI_FreeKernelMem(void *ptr, size_t size); VMCIBuffer VMCI_AllocBuffer(size_t size, int flags); void *VMCI_MapBuffer(VMCIBuffer buf); void VMCI_ReleaseBuffer(void *ptr); void VMCI_FreeBuffer(VMCIBuffer buf, size_t size); #ifdef SOLARIS int VMCI_CopyToUser(VA64 dst, const void *src, size_t len, int mode); #else int VMCI_CopyToUser(VA64 dst, const void *src, size_t len); /* * Don't need the following for guests, hence no Solaris code for this * function. */ Bool VMCIWellKnownID_AllowMap(VMCIId wellKnownID, VMCIPrivilegeFlags privFlags); #endif void VMCI_CreateEvent(VMCIEvent *event); void VMCI_DestroyEvent(VMCIEvent *event); void VMCI_SignalEvent(VMCIEvent *event); void VMCI_WaitOnEvent(VMCIEvent *event, VMCIEventReleaseCB releaseCB, void *clientData); #if (defined(__APPLE__) || defined(__linux__) || defined(_WIN32)) && !defined(VMKERNEL) Bool VMCI_WaitOnEventInterruptible(VMCIEvent *event, VMCIEventReleaseCB releaseCB, void *clientData); #endif #if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \ defined(__APPLE__) || defined(SOLARIS)) int VMCI_CopyFromUser(void *dst, VA64 src, size_t len); #endif typedef void (VMCIWorkFn)(void *data); Bool VMCI_CanScheduleDelayedWork(void); int VMCI_ScheduleDelayedWork(VMCIWorkFn *workFn, void *data); int VMCIMutex_Init(VMCIMutex *mutex); void VMCIMutex_Destroy(VMCIMutex *mutex); void VMCIMutex_Acquire(VMCIMutex *mutex); void VMCIMutex_Release(VMCIMutex *mutex); #if defined(SOLARIS) || defined(_WIN32) int VMCIKernelIf_Init(void); void VMCIKernelIf_Exit(void); #endif // SOLARIS || _WIN32 #if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \ defined(SOLARIS) || defined(__APPLE__)) void *VMCI_AllocQueue(uint64 size); void VMCI_FreeQueue(void *q, uint64 size); typedef struct PPNSet { uint64 numProducePages; uint64 numConsumePages; VMCIPpnList producePPNs; VMCIPpnList consumePPNs; Bool initialized; } PPNSet; int VMCI_AllocPPNSet(void *produceQ, uint64 numProducePages, void *consumeQ, uint64 numConsumePages, PPNSet *ppnSet); void VMCI_FreePPNSet(PPNSet *ppnSet); int VMCI_PopulatePPNList(uint8 *callBuf, const PPNSet *ppnSet); #endif struct VMCIQueue; #if !defined(VMX86_TOOLS) #if !defined(VMKERNEL) struct PageStoreAttachInfo; struct VMCIQueue *VMCIHost_AllocQueue(uint64 queueSize); void VMCIHost_FreeQueue(struct VMCIQueue *queue, uint64 queueSize); int VMCIHost_GetUserMemory(struct PageStoreAttachInfo *attach, struct VMCIQueue *produceQ, struct VMCIQueue *detachQ); void VMCIHost_ReleaseUserMemory(struct PageStoreAttachInfo *attach, struct VMCIQueue *produceQ, struct VMCIQueue *detachQ); #endif // VMKERNEL #ifdef _WIN32 /* * Special routine used on the Windows platform to save a queue when * its backing memory goes away. */ void VMCIHost_SaveProduceQ(struct PageStoreAttachInfo *attach, struct VMCIQueue *produceQ, struct VMCIQueue *detachQ, const uint64 produceQSize); #endif // _WIN32 #endif // !VMX86_TOOLS #ifdef _WIN32 void VMCI_InitQueueMutex(struct VMCIQueue *produceQ, struct VMCIQueue *consumeQ); void VMCI_AcquireQueueMutex(struct VMCIQueue *queue); void VMCI_ReleaseQueueMutex(struct VMCIQueue *queue); Bool VMCI_EnqueueToDevNull(struct VMCIQueue *queue); int VMCI_ConvertToLocalQueue(struct VMCIQueue *queueInfo, struct VMCIQueue *otherQueueInfo, uint64 size, Bool keepContent, void **oldQueue); void VMCI_RevertToNonLocalQueue(struct VMCIQueue *queueInfo, void *nonLocalQueue, uint64 size); void VMCI_FreeQueueBuffer(void *queue, uint64 size); void VMCI_DeviceShutdownBegin(void); void VMCI_DeviceShutdownEnd(void); Bool VMCI_DeviceShutdown(void); #else // _WIN32 # define VMCI_InitQueueMutex(_pq, _cq) # define VMCI_AcquireQueueMutex(_q) # define VMCI_ReleaseQueueMutex(_q) # define VMCI_EnqueueToDevNull(_q) FALSE # define VMCI_ConvertToLocalQueue(_pq, _cq, _s, _oq, _kc) VMCI_ERROR_UNAVAILABLE # define VMCI_RevertToNonLocalQueue(_q, _nlq, _s) # define VMCI_FreeQueueBuffer(_q, _s) # define VMCI_DeviceShutdown() FALSE #endif // !_WIN32 #endif // _VMCI_KERNEL_IF_H_ vmci-only/shared/driverLog.h 0000444 0000000 0000000 00000002232 11573420431 015042 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * driverLog.h -- * * Logging functions for Linux kernel modules. */ #ifndef __DRIVERLOG_H__ #define __DRIVERLOG_H__ /* * The definitions of Warning(), Log(), and Panic() come from vm_assert.h for * consistency. */ #include "vm_assert.h" void DriverLog_Init(const char *prefix); #endif /* __DRIVERLOG_H__ */ vmci-only/shared/community_source.h 0000444 0000000 0000000 00000003742 11573420432 016521 0 ustar root root /********************************************************* * Copyright (C) 2009 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 * *********************************************************/ /* * community_source.h -- * * Macros for excluding source code from community. */ #ifndef _COMMUNITY_SOURCE_H_ #define _COMMUNITY_SOURCE_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMIROM #include "includeCheck.h" /* * Convenience macro for COMMUNITY_SOURCE */ #undef EXCLUDE_COMMUNITY_SOURCE #ifdef COMMUNITY_SOURCE #define EXCLUDE_COMMUNITY_SOURCE(x) #else #define EXCLUDE_COMMUNITY_SOURCE(x) x #endif #undef COMMUNITY_SOURCE_AMD_SECRET #if !defined(COMMUNITY_SOURCE) || defined(AMD_SOURCE) /* * It's ok to include AMD_SECRET source code for non-Community Source, * or for drops directed at AMD. */ #define COMMUNITY_SOURCE_AMD_SECRET #endif #undef COMMUNITY_SOURCE_INTEL_SECRET #if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE) /* * It's ok to include INTEL_SECRET source code for non-Community Source, * or for drops directed at Intel. */ #define COMMUNITY_SOURCE_INTEL_SECRET #endif #endif vmci-only/shared/circList.h 0000444 0000000 0000000 00000023667 11573420427 014705 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * circList.h -- * * macros, prototypes and struct definitions for double-linked * circular lists. */ #ifndef _CIRCLIST_H_ #define _CIRCLIST_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include "vmware.h" typedef struct ListItem { struct ListItem *prev; struct ListItem *next; } ListItem; /* A list with no elements is a null pointer. */ #define LIST_ITEM_DEF(name) \ ListItem * name = NULL #define LIST_EMPTY(l) ((l) == NULL) /* initialize list item */ #define INIT_LIST_ITEM(p) \ do { \ (p)->prev = (p)->next = (p); \ } while (0) /* check if initialized */ #define IS_LIST_ITEM_INITIALIZED(li) \ (((li) == (li)->prev) && ((li) == (li)->next)) /* return first element in the list */ #define LIST_FIRST(l) (l) #define LIST_FIRST_CHK(l) (l) /* return last element in the list */ #define LIST_LAST(l) ((l)->prev) #define LIST_LAST_CHK(l) (LIST_EMPTY(l) ? NULL : LIST_LAST(l)) /* * LIST_CONTAINER - get the struct for this entry (like list_entry) * @ptr: the &struct ListItem pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list struct within the struct. */ #define LIST_CONTAINER(ptr, type, member) \ ((type *)((char *)(ptr) - offsetof(type, member))) /* * delete item from the list */ #define LIST_DEL DelListItem /* * link two lists together */ #define LIST_SPLICE SpliceLists /* * Split a list into two lists */ #define LIST_SPLIT SplitLists /* * Add item to front of stack. List pointer points to new head. */ #define LIST_PUSH PushListItem /* * Add item at back of queue. List pointer only changes if list was empty. */ #define LIST_QUEUE QueueListItem /* * Get the list size. */ #define LIST_SIZE GetListSize /* * LIST_SCAN_FROM scans the list from "from" up until "until". * The loop variable p should not be destroyed in the process. * "from" is an element in the list where to start scanning. * "until" is the element where search should stop. * member is the field to use for the search - either "next" or "prev". */ #define LIST_SCAN_FROM(p, from, until, member) \ for (p = (from); (p) != NULL; \ (p) = (((p)->member == (until)) ? NULL : (p)->member)) /* scan the entire list (non-destructively) */ #define LIST_SCAN(p, l) \ LIST_SCAN_FROM(p, LIST_FIRST(l), LIST_FIRST(l), next) /* scan a list backward from last element to first (non-destructively) */ #define LIST_SCAN_BACK(p, l) \ LIST_SCAN_FROM(p, LIST_LAST_CHK(l), LIST_LAST(l), prev) /* scan the entire list where loop element may be destroyed */ #define LIST_SCAN_SAFE(p, pn, l) \ if (!LIST_EMPTY(l)) \ for (p = (l), (pn) = NextListItem(p, l); (p) != NULL; \ (p) = (pn), (pn) = NextListItem(p, l)) /* scan the entire list backwards where loop element may be destroyed */ #define LIST_SCAN_BACK_SAFE(p, pn, l) \ if (!LIST_EMPTY(l)) \ for (p = LIST_LAST(l), (pn) = PrevListItem(p, l); (p) != NULL; \ (p) = (pn), (pn) = PrevListItem(p, l)) /* function definitions */ /* *---------------------------------------------------------------------- * * NextListItem -- * * Returns the next member of a doubly linked list, or NULL if last. * Assumes: p is member of the list headed by head. * * Result: * If head or p is NULL, return NULL. Otherwise, * next list member (or null if last). * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE ListItem * NextListItem(ListItem *p, // IN ListItem *head) // IN { if (head == NULL || p == NULL) { return NULL; } /* both p and head are non-null */ p = p->next; return p == head ? NULL : p; } /* *---------------------------------------------------------------------- * * PrevListItem -- * * Returns the prev member of a doubly linked list, or NULL if first. * Assumes: p is member of the list headed by head. * * Result: * If head or prev is NULL, return NULL. Otherwise, * prev list member (or null if first). * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE ListItem * PrevListItem(ListItem *p, // IN ListItem *head) // IN { if (head == NULL || p == NULL) { return NULL; } /* both p and head are non-null */ return p == head ? NULL : p->prev; } /* *---------------------------------------------------------------------- * * DelListItem -- * * Deletes a member of a doubly linked list, possibly modifies the * list header itself. * Assumes neither p nor headp is null and p is a member of *headp. * * Result: * None * * Side effects: * Modifies *headp. * *---------------------------------------------------------------------- */ static INLINE void DelListItem(ListItem *p, // IN ListItem **headp) // IN/OUT { ListItem *next; ASSERT(p); ASSERT(headp); next = p->next; if (p == next) { *headp = NULL; } else { next->prev = p->prev; p->prev->next = next; if (*headp == p) { *headp = next; } } } /* *---------------------------------------------------------------------- * * QueueListItem -- * * Adds a new member to the back of a doubly linked list (queue) * Assumes neither p nor headp is null and p is not a member of *headp. * * Result: * None * * Side effects: * Modifies *headp. * *---------------------------------------------------------------------- */ static INLINE void QueueListItem(ListItem *p, // IN ListItem **headp) // IN/OUT { ListItem *head; head = *headp; if (LIST_EMPTY(head)) { INIT_LIST_ITEM(p); *headp = p; } else { p->prev = head->prev; p->next = head; p->prev->next = p; head->prev = p; } } /* *---------------------------------------------------------------------- * * PushListItem -- * * Adds a new member to the front of a doubly linked list (stack) * Assumes neither p nor headp is null and p is not a member of *headp. * * Result: * None * * Side effects: * Modifies *headp. * *---------------------------------------------------------------------- */ static INLINE void PushListItem(ListItem *p, // IN ListItem **headp) // IN/OUT { QueueListItem(p, headp); *headp = p; } /* *---------------------------------------------------------------------- * * SpliceLists -- * * Make a single list {l1 l2} from {l1} and {l2} and return it. * It is okay for one or both lists to be NULL. * No checking is done. It is assumed that l1 and l2 are two * distinct lists. * * Result: * A list { l1 l2 }. * * Side effects: * Modifies l1 and l2 list pointers. * *---------------------------------------------------------------------- */ static INLINE ListItem * SpliceLists(ListItem *l1, // IN ListItem *l2) // IN { ListItem *l1Last, *l2Last; if (LIST_EMPTY(l1)) { return l2; } if (LIST_EMPTY(l2)) { return l1; } l1Last = l1->prev; /* last elem of l1 */ l2Last = l2->prev; /* last elem of l2 */ /* * l1 -> ... -> l1Last l2 -> ... l2Last */ l1Last->next = l2; l2->prev = l1Last; l1->prev = l2Last; l2Last->next = l1; return l1; } /* *---------------------------------------------------------------------- * * SplitLists -- * * Make a list l = {l1 l2} into two separate lists {l1} and {l2}, where: * l = { ... x -> p -> ... } split into: * l1 = { ... -> x } * l2 = { p -> ... } * Assumes neither p nor l is null and p is a member of l. * If p is the first element of l, then l1 will be NULL. * * Result: * None. * * Side effects: * Sets *l1p and *l2p to the resulting two lists. * Modifies l's pointers. * *---------------------------------------------------------------------- */ static INLINE void SplitLists(ListItem *p, // IN ListItem *l, // IN ListItem **l1p, // OUT ListItem **l2p) // OUT { ListItem *last; if (p == LIST_FIRST(l)) { /* first element */ *l1p = NULL; *l2p = l; return; } last = l->prev; *l1p = l; p->prev->next = l; l->prev = p->prev; *l2p = p; p->prev = last; last->next = p; } /* *---------------------------------------------------------------------- * * GetListSize -- * * Return the number of items in the list. * * Result: * The number of items in the list. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE int GetListSize(ListItem *head) // IN { ListItem *li; int ret = 0; LIST_SCAN(li, head) { ret++; } return ret; } #endif /* _CIRCLIST_H_ */ vmci-only/shared/vmci_infrastructure.h 0000444 0000000 0000000 00000010001 11573420432 017175 0 ustar root root /********************************************************* * 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_infrastructure.h -- * * This file implements the VMCI infrastructure. */ #ifndef _VMCI_INFRASTRUCTURE_H_ #define _VMCI_INFRASTRUCTURE_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #include "includeCheck.h" #include "vmware.h" #include "vmci_defs.h" typedef enum { VMCIOBJ_VMX_VM = 10, VMCIOBJ_CONTEXT, VMCIOBJ_PROCESS, VMCIOBJ_DATAGRAM_PROCESS, VMCIOBJ_SOCKET, VMCIOBJ_NOT_SET, } VMCIObjType; /* For storing VMCI structures in file handles. */ typedef struct VMCIObj { void *ptr; VMCIObjType type; } VMCIObj; /* Guestcalls currently support a maximum of 8 uint64 arguments. */ #define VMCI_GUESTCALL_MAX_ARGS_SIZE 64 /* * Structure used for checkpointing the doorbell mappings. It is * written to the checkpoint as is, so changing this structure will * break checkpoint compatibility. */ typedef struct VMCIDoorbellCptState { VMCIHandle handle; uint64 bitmapIdx; } VMCIDoorbellCptState; /* Used to determine what checkpoint state to get and set. */ #define VMCI_NOTIFICATION_CPT_STATE 0x1 #define VMCI_WELLKNOWN_CPT_STATE 0x2 #define VMCI_DG_OUT_STATE 0x3 #define VMCI_DG_IN_STATE 0x4 #define VMCI_DG_IN_SIZE_STATE 0x5 #define VMCI_DOORBELL_CPT_STATE 0x6 /* Used to control the VMCI device in the vmkernel */ #define VMCI_DEV_RESET 0x01 #define VMCI_DEV_QP_RESET 0x02 // DEPRECATED #define VMCI_DEV_QUIESCE 0x03 #define VMCI_DEV_UNQUIESCE 0x04 #define VMCI_DEV_QP_BREAK_SHARING 0x05 // DEPRECATED #define VMCI_DEV_RESTORE_SYNC 0x06 #define VMCI_DEV_BMASTER_OFF 0x07 /* *------------------------------------------------------------------------- * * VMCI_Hash -- * * Hash function used by the Simple Datagram API. Based on the djb2 * hash function by Dan Bernstein. * * Result: * Returns guest call size. * * Side effects: * None. * *------------------------------------------------------------------------- */ static INLINE int VMCI_Hash(VMCIHandle handle, // IN unsigned size) // IN { unsigned i; int hash = 5381; const uint64 handleValue = QWORD(handle.resource, handle.context); for (i = 0; i < sizeof handle; i++) { hash = ((hash << 5) + hash) + (uint8)(handleValue >> (i * 8)); } return hash & (size - 1); } /* *------------------------------------------------------------------------- * * VMCI_HashId -- * * Hash function used by the Simple Datagram API. Hashes only a VMCI id * (not the full VMCI handle) Based on the djb2 * hash function by Dan Bernstein. * * Result: * Returns guest call size. * * Side effects: * None. * *------------------------------------------------------------------------- */ static INLINE int VMCI_HashId(VMCIId id, // IN unsigned size) // IN { unsigned i; int hash = 5381; for (i = 0; i < sizeof id; i++) { hash = ((hash << 5) + hash) + (uint8)(id >> (i * 8)); } return hash & (size - 1); } #endif // _VMCI_INFRASTRUCTURE_H_ vmci-only/shared/vmware_pack_begin.h 0000444 0000000 0000000 00000002444 11573420432 016556 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmware_pack_begin.h -- * * Begin of structure packing. See vmware_pack_init.h for details. * * Note that we do not use the following construct in this include file, * because we want to emit the code every time the file is included --hpreg * * #ifndef foo * # define foo * ... * #endif * */ #include "vmware_pack_init.h" #ifdef _MSC_VER # pragma pack(push, 1) #elif __GNUC__ #else # error Compiler packing... #endif vmci-only/shared/compat_init.h 0000444 0000000 0000000 00000002355 11573420431 015421 0 ustar root root /********************************************************* * Copyright (C) 1999 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ /* * compat_init.h: Initialization compatibility wrappers. */ #ifndef __COMPAT_INIT_H__ #define __COMPAT_INIT_H__ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) #include <linux/init.h> #endif #ifndef module_init #define module_init(x) int init_module(void) { return x(); } #endif #ifndef module_exit #define module_exit(x) void cleanup_module(void) { x(); } #endif #endif /* __COMPAT_INIT_H__ */ vmci-only/shared/compat_dcache.h 0000444 0000000 0000000 00000004004 11573420431 015656 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __COMPAT_DCACHE_H__ # define __COMPAT_DCACHE_H__ #include <linux/dcache.h> /* * per-dentry locking was born in 2.5.62. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 62) #define compat_lock_dentry(dentry) spin_lock(&dentry->d_lock) #define compat_unlock_dentry(dentry) spin_unlock(&dentry->d_lock) #else #define compat_lock_dentry(dentry) do {} while (0) #define compat_unlock_dentry(dentry) do {} while (0) #endif /* * d_alloc_name was born in 2.6.10. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) #define compat_d_alloc_name(parent, s) d_alloc_name(parent, s) #else #define compat_d_alloc_name(parent, s) \ ({ \ struct qstr q; \ q.name = s; \ q.len = strlen(s); \ q.hash = full_name_hash(q.name, q.len); \ d_alloc(parent, &q); \ }) #endif #endif /* __COMPAT_DCACHE_H__ */ vmci-only/shared/compat_highmem.h 0000444 0000000 0000000 00000002557 11573420431 016100 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_HIGHMEM_H__ # define __COMPAT_HIGHMEM_H__ /* * BIGMEM (4 GB) support appeared in 2.3.16: kmap() API added * HIGHMEM (4 GB + 64 GB) support appeared in 2.3.23: kmap() API modified * In 2.3.27, kmap() API modified again * * --hpreg */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 27) # include <linux/highmem.h> #else /* For page_address --hpreg */ # include <linux/pagemap.h> # define kmap(_page) (void*)page_address(_page) # define kunmap(_page) #endif #endif /* __COMPAT_HIGHMEM_H__ */ vmci-only/shared/compat_mm.h 0000444 0000000 0000000 00000010207 11573420431 015062 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_MM_H__ # define __COMPAT_MM_H__ #include <linux/mm.h> /* The get_page() API appeared in 2.3.7 --hpreg */ /* Sometime during development it became function instead of macro --petr */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) && !defined(get_page) # define get_page(_page) atomic_inc(&(_page)->count) /* The __free_page() API is exported in 2.1.67 --hpreg */ # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 67) # define put_page __free_page # else # include "compat_page.h" # define page_to_phys(_page) (page_to_pfn(_page) << PAGE_SHIFT) # define put_page(_page) free_page(page_to_phys(_page)) # endif #endif /* page_count() is 2.4.0 invention. Unfortunately unavailable in some RedHat * kernels (for example 2.4.21-4-RHEL3). */ /* It is function since 2.6.0, and hopefully RedHat will not play silly games * with mm_inline.h again... */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(page_count) # define page_count(page) atomic_read(&(page)->count) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) # define compat_vm_pgoff(vma) ((vma)->vm_offset >> PAGE_SHIFT) static inline unsigned long compat_do_mmap_pgoff(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flag, unsigned long pgoff) { unsigned long ret = -EINVAL; if (pgoff < 1 << (32 - PAGE_SHIFT)) { ret = do_mmap(file, addr, len, prot, flag, pgoff << PAGE_SHIFT); } return ret; } #else # define compat_vm_pgoff(vma) (vma)->vm_pgoff # ifdef VMW_SKAS_MMAP # define compat_do_mmap_pgoff(f, a, l, p, g, o) \ do_mmap_pgoff(current->mm, f, a, l, p, g, o) # else # define compat_do_mmap_pgoff(f, a, l, p, g, o) \ do_mmap_pgoff(f, a, l, p, g, o) # endif #endif /* 2.2.x uses 0 instead of some define */ #ifndef NOPAGE_SIGBUS #define NOPAGE_SIGBUS (0) #endif /* 2.2.x does not have HIGHMEM support */ #ifndef GFP_HIGHUSER #define GFP_HIGHUSER (GFP_USER) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) #include "compat_page.h" static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) { unsigned long addr; addr = __get_free_pages(gfp_mask, order); if (!addr) { return NULL; } return virt_to_page(addr); } #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) #endif /* * In 2.4.14, the logic behind the UnlockPage macro was moved to the * unlock_page() function. Later (in 2.5.12), the UnlockPage macro was removed * altogether, and nowadays everyone uses unlock_page(). */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 14) #define compat_unlock_page(page) UnlockPage(page) #else #define compat_unlock_page(page) unlock_page(page) #endif /* * In 2.4.10, vmtruncate was changed from returning void to returning int. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) #define compat_vmtruncate(inode, size) \ ({ \ int result = 0; \ vmtruncate(inode, size); \ result; \ }) #else #define compat_vmtruncate(inode, size) vmtruncate(inode, size) #endif #endif /* __COMPAT_MM_H__ */ vmci-only/shared/compat_pgtable.h 0000444 0000000 0000000 00000011044 11573420431 016067 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_PGTABLE_H__ # define __COMPAT_PGTABLE_H__ #if defined(CONFIG_PARAVIRT) && defined(CONFIG_HIGHPTE) # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) # include <asm/paravirt.h> # undef paravirt_map_pt_hook # define paravirt_map_pt_hook(type, va, pfn) do {} while (0) # endif #endif #include <asm/pgtable.h> /* pte_page() API modified in 2.3.23 to return a struct page * --hpreg */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 23) # define compat_pte_page pte_page #else # include "compat_page.h" # define compat_pte_page(_pte) virt_to_page(pte_page(_pte)) #endif /* Appeared in 2.5.5 --hpreg */ #ifndef pte_offset_map /* Appeared in SuSE 8.0's 2.4.18 --hpreg */ # ifdef pte_offset_atomic # define pte_offset_map pte_offset_atomic # define pte_unmap pte_kunmap # else # define pte_offset_map pte_offset # define pte_unmap(_pte) # endif #endif /* Appeared in 2.5.74-mmX --petr */ #ifndef pmd_offset_map # define pmd_offset_map(pgd, address) pmd_offset(pgd, address) # define pmd_unmap(pmd) #endif /* * Appeared in 2.6.10-rc2-mm1. Older kernels did L4 page tables as * part of pgd_offset, or they did not have L4 page tables at all. * In 2.6.11 pml4 -> pgd -> pmd -> pte hierarchy was replaced by * pgd -> pud -> pmd -> pte hierarchy. */ #ifdef PUD_MASK # define compat_pgd_offset(mm, address) pgd_offset(mm, address) # define compat_pgd_present(pgd) pgd_present(pgd) # define compat_pud_offset(pgd, address) pud_offset(pgd, address) # define compat_pud_present(pud) pud_present(pud) typedef pgd_t compat_pgd_t; typedef pud_t compat_pud_t; #elif defined(pml4_offset) # define compat_pgd_offset(mm, address) pml4_offset(mm, address) # define compat_pgd_present(pml4) pml4_present(pml4) # define compat_pud_offset(pml4, address) pml4_pgd_offset(pml4, address) # define compat_pud_present(pgd) pgd_present(pgd) typedef pml4_t compat_pgd_t; typedef pgd_t compat_pud_t; #else # define compat_pgd_offset(mm, address) pgd_offset(mm, address) # define compat_pgd_present(pgd) pgd_present(pgd) # define compat_pud_offset(pgd, address) (pgd) # define compat_pud_present(pud) (1) typedef pgd_t compat_pgd_t; typedef pgd_t compat_pud_t; #endif #define compat_pgd_offset_k(mm, address) pgd_offset_k(address) /* Introduced somewhere in 2.6.0, + backported to some 2.4 RedHat kernels */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pte_pfn) # define pte_pfn(pte) page_to_pfn(compat_pte_page(pte)) #endif /* A page_table_lock field is added to struct mm_struct in 2.3.10 --hpreg */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 10) # define compat_get_page_table_lock(_mm) (&(_mm)->page_table_lock) #else # define compat_get_page_table_lock(_mm) NULL #endif /* * Define VM_PAGE_KERNEL_EXEC for vmapping executable pages. * * On ia32 PAGE_KERNEL_EXEC was introduced in 2.6.8.1. Unfortunately it accesses * __PAGE_KERNEL_EXEC which is not exported for modules. So we use * __PAGE_KERNEL and just cut _PAGE_NX bit from it. * * For ia32 kernels before 2.6.8.1 we use PAGE_KERNEL directly, these kernels * do not have noexec support. * * On x86-64 situation is a bit better: they always supported noexec, but * before 2.6.8.1 flag was named PAGE_KERNEL_EXECUTABLE, and it was renamed * to PAGE_KERNEL_EXEC when ia32 got noexec too (see above). */ #ifdef CONFIG_X86 #ifdef _PAGE_NX #define VM_PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL & ~_PAGE_NX) #else #define VM_PAGE_KERNEL_EXEC PAGE_KERNEL #endif #else #ifdef PAGE_KERNEL_EXECUTABLE #define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXECUTABLE #else #define VM_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC #endif #endif #endif /* __COMPAT_PGTABLE_H__ */ vmci-only/shared/compat_sock.h 0000444 0000000 0000000 00000006002 11573420431 015406 0 ustar root root /********************************************************* * Copyright (C) 2003 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_SOCK_H__ # define __COMPAT_SOCK_H__ #include <linux/stddef.h> /* for NULL */ #include <net/sock.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) static inline wait_queue_head_t *sk_sleep(struct sock *sk) { return sk->sk_sleep; } #endif /* * Prior to 2.6.24, there was no sock network namespace member. In 2.6.26, it * was hidden behind accessor functions so that its behavior could vary * depending on the value of CONFIG_NET_NS. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) # define compat_sock_net(sk) sock_net(sk) #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) # define compat_sock_net(sk) sk->sk_net #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) #ifndef CONFIG_FILTER # define sk_filter(sk, skb, needlock) 0 #endif /* Taken from 2.6.16's sock.h and modified for macro. */ # define compat_sk_receive_skb(sk, skb, nested) \ ({ \ int rc = NET_RX_SUCCESS; \ \ if (sk_filter(sk, skb, 0)) { \ kfree_skb(skb); \ } else { \ skb->dev = NULL; \ bh_lock_sock(sk); \ if (!sock_owned_by_user(sk)) { \ rc = (sk)->sk_backlog_rcv(sk, skb); \ } else { \ sk_add_backlog(sk, skb); \ } \ bh_unlock_sock(sk); \ } \ \ sock_put(sk); \ rc; \ }) #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) # define compat_sk_receive_skb(sk, skb, nested) sk_receive_skb(sk, skb) #else # define compat_sk_receive_skb(sk, skb, nested) sk_receive_skb(sk, skb, nested) #endif #endif /* __COMPAT_SOCK_H__ */ vmci-only/shared/vmware.h 0000444 0000000 0000000 00000003502 11573420432 014410 0 ustar root root /********************************************************* * Copyright (C) 2003 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ /* * vmware.h -- * * Standard include file for VMware source code. */ #ifndef _VMWARE_H_ #define _VMWARE_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #include "includeCheck.h" #include "vm_basic_types.h" #include "vm_basic_defs.h" #include "vm_assert.h" /* * Global error codes. Currently used internally, but may be exported * to customers one day, like VM_E_XXX in vmcontrol_constants.h */ typedef enum VMwareStatus { VMWARE_STATUS_SUCCESS, /* success */ VMWARE_STATUS_ERROR, /* generic error */ VMWARE_STATUS_NOMEM, /* generic memory allocation error */ VMWARE_STATUS_INSUFFICIENT_RESOURCES, /* internal or system resource limit exceeded */ VMWARE_STATUS_INVALID_ARGS /* invalid arguments */ } VMwareStatus; #define VMWARE_SUCCESS(s) ((s) == VMWARE_STATUS_SUCCESS) #endif // ifndef _VMWARE_H_ vmci-only/shared/compat_version.h 0000444 0000000 0000000 00000005720 11573420431 016142 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __COMPAT_VERSION_H__ # define __COMPAT_VERSION_H__ #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_DISTRIBUTE #include "includeCheck.h" #ifndef __linux__ # error "linux-version.h" #endif #include <linux/version.h> #ifndef KERNEL_VERSION # error KERNEL_VERSION macro is not defined, environment is busted #endif /* * Distinguish relevant classes of Linux kernels. * * The convention is that version X defines all * the KERNEL_Y symbols where Y <= X. * * XXX Do not add more definitions here. This way of doing things does not * scale, and we are going to phase it out soon --hpreg */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0) # define KERNEL_2_1 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) # define KERNEL_2_2 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 1) # define KERNEL_2_3_1 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 15) /* new networking */ # define KERNEL_2_3_15 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) /* new procfs */ # define KERNEL_2_3_25 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29) /* even newer procfs */ # define KERNEL_2_3_29 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 43) /* softnet changes */ # define KERNEL_2_3_43 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 47) /* more softnet changes */ # define KERNEL_2_3_47 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 99) /* name in netdevice struct is array and not pointer */ # define KERNEL_2_3_99 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) /* New 'owner' member at the beginning of struct file_operations */ # define KERNEL_2_4_0 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) /* New netif_rx_ni() --hpreg */ # define KERNEL_2_4_8 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 2) /* New kdev_t, major()/minor() API --hpreg */ # define KERNEL_2_5_2 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) /* New sk_alloc(), pte_offset_map()/pte_unmap() --hpreg */ # define KERNEL_2_5_5 #endif #endif /* __COMPAT_VERSION_H__ */ vmci-only/shared/vmci_defs.h 0000444 0000000 0000000 00000056600 11573420432 015055 0 ustar root root /********************************************************* * Copyright (C) 2005-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_DEF_H_ #define _VMCI_DEF_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMMEXT #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #include "includeCheck.h" #include "vm_basic_types.h" #include "vm_atomic.h" #include "vm_assert.h" /* Register offsets. */ #define VMCI_STATUS_ADDR 0x00 #define VMCI_CONTROL_ADDR 0x04 #define VMCI_ICR_ADDR 0x08 #define VMCI_IMR_ADDR 0x0c #define VMCI_DATA_OUT_ADDR 0x10 #define VMCI_DATA_IN_ADDR 0x14 #define VMCI_CAPS_ADDR 0x18 #define VMCI_RESULT_LOW_ADDR 0x1c #define VMCI_RESULT_HIGH_ADDR 0x20 /* Max number of devices. */ #define VMCI_MAX_DEVICES 1 /* Status register bits. */ #define VMCI_STATUS_INT_ON 0x1 /* Control register bits. */ #define VMCI_CONTROL_RESET 0x1 #define VMCI_CONTROL_INT_ENABLE 0x2 #define VMCI_CONTROL_INT_DISABLE 0x4 /* Capabilities register bits. */ #define VMCI_CAPS_HYPERCALL 0x1 #define VMCI_CAPS_GUESTCALL 0x2 #define VMCI_CAPS_DATAGRAM 0x4 #define VMCI_CAPS_NOTIFICATIONS 0x8 /* Interrupt Cause register bits. */ #define VMCI_ICR_DATAGRAM 0x1 #define VMCI_ICR_NOTIFICATION 0x2 /* Interrupt Mask register bits. */ #define VMCI_IMR_DATAGRAM 0x1 #define VMCI_IMR_NOTIFICATION 0x2 /* Interrupt type. */ typedef enum VMCIIntrType { VMCI_INTR_TYPE_INTX = 0, VMCI_INTR_TYPE_MSI = 1, VMCI_INTR_TYPE_MSIX = 2 } VMCIIntrType; /* * Maximum MSI/MSI-X interrupt vectors in the device. */ #define VMCI_MAX_INTRS 2 /* * Supported interrupt vectors. There is one for each ICR value above, * but here they indicate the position in the vector array/message ID. */ #define VMCI_INTR_DATAGRAM 0 #define VMCI_INTR_NOTIFICATION 1 /* * A single VMCI device has an upper limit of 128MB on the amount of * memory that can be used for queue pairs. */ #define VMCI_MAX_GUEST_QP_MEMORY (128 * 1024 * 1024) /* * We have a fixed set of resource IDs available in the VMX. * This allows us to have a very simple implementation since we statically * know how many will create datagram handles. If a new caller arrives and * we have run out of slots we can manually increment the maximum size of * available resource IDs. */ typedef uint32 VMCI_Resource; /* VMCI reserved hypervisor datagram resource IDs. */ #define VMCI_RESOURCES_QUERY 0 #define VMCI_GET_CONTEXT_ID 1 #define VMCI_SET_NOTIFY_BITMAP 2 #define VMCI_DOORBELL_LINK 3 #define VMCI_DOORBELL_UNLINK 4 #define VMCI_DOORBELL_NOTIFY 5 #define VMCI_DATAGRAM_REQUEST_MAP 6 #define VMCI_DATAGRAM_REMOVE_MAP 7 #define VMCI_EVENT_SUBSCRIBE 8 #define VMCI_EVENT_UNSUBSCRIBE 9 #define VMCI_QUEUEPAIR_ALLOC 10 #define VMCI_QUEUEPAIR_DETACH 11 /* * VMCI_VSOCK_VMX_LOOKUP was assigned to 12 for Fusion 3.0/3.1, * WS 7.0/7.1 and ESX 4.1 */ #define VMCI_HGFS_TRANSPORT 13 #define VMCI_RESOURCE_MAX 14 /* VMCI Ids. */ typedef uint32 VMCIId; typedef struct VMCIHandle { VMCIId context; VMCIId resource; } VMCIHandle; static INLINE VMCIHandle VMCI_MAKE_HANDLE(VMCIId cid, VMCIId rid) { VMCIHandle h; h.context = cid; h.resource = rid; return h; } /* *---------------------------------------------------------------------- * * VMCI_HANDLE_TO_UINT64 -- * * Helper for VMCI handle to uint64 conversion. * * Results: * The uint64 value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE uint64 VMCI_HANDLE_TO_UINT64(VMCIHandle handle) // IN: { uint64 handle64; handle64 = handle.context; handle64 <<= 32; handle64 |= handle.resource; return handle64; } /* *---------------------------------------------------------------------- * * VMCI_UINT64_TO_HANDLE -- * * Helper for uint64 to VMCI handle conversion. * * Results: * The VMCI handle value. * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE VMCIHandle VMCI_UINT64_TO_HANDLE(uint64 handle64) // IN: { VMCIId context = (VMCIId)(handle64 >> 32); VMCIId resource = (VMCIId)handle64; return VMCI_MAKE_HANDLE(context, resource); } #define VMCI_HANDLE_TO_CONTEXT_ID(_handle) ((_handle).context) #define VMCI_HANDLE_TO_RESOURCE_ID(_handle) ((_handle).resource) #define VMCI_HANDLE_EQUAL(_h1, _h2) ((_h1).context == (_h2).context && \ (_h1).resource == (_h2).resource) #define VMCI_INVALID_ID 0xFFFFFFFF static const VMCIHandle VMCI_INVALID_HANDLE = {VMCI_INVALID_ID, VMCI_INVALID_ID}; #define VMCI_HANDLE_INVALID(_handle) \ VMCI_HANDLE_EQUAL((_handle), VMCI_INVALID_HANDLE) /* * The below defines can be used to send anonymous requests. * This also indicates that no response is expected. */ #define VMCI_ANON_SRC_CONTEXT_ID VMCI_INVALID_ID #define VMCI_ANON_SRC_RESOURCE_ID VMCI_INVALID_ID #define VMCI_ANON_SRC_HANDLE VMCI_MAKE_HANDLE(VMCI_ANON_SRC_CONTEXT_ID, \ VMCI_ANON_SRC_RESOURCE_ID) /* The lowest 16 context ids are reserved for internal use. */ #define VMCI_RESERVED_CID_LIMIT 16 /* * Hypervisor context id, used for calling into hypervisor * supplied services from the VM. */ #define VMCI_HYPERVISOR_CONTEXT_ID 0 /* * Well-known context id, a logical context that contains * a set of well-known services. */ #define VMCI_WELL_KNOWN_CONTEXT_ID 1 /* Todo: Change host context id to dynamic/random id. */ #define VMCI_HOST_CONTEXT_ID 2 /* * The VMCI_CONTEXT_RESOURCE_ID is used together with VMCI_MAKE_HANDLE to make * handles that refer to a specific context. */ #define VMCI_CONTEXT_RESOURCE_ID 0 /* *----------------------------------------------------------------------------- * * VMCI error codes. * *----------------------------------------------------------------------------- */ #define VMCI_SUCCESS_QUEUEPAIR_ATTACH 5 #define VMCI_SUCCESS_QUEUEPAIR_CREATE 4 #define VMCI_SUCCESS_LAST_DETACH 3 #define VMCI_SUCCESS_ACCESS_GRANTED 2 #define VMCI_SUCCESS_ENTRY_DEAD 1 #define VMCI_SUCCESS 0LL #define VMCI_ERROR_INVALID_RESOURCE (-1) #define VMCI_ERROR_INVALID_ARGS (-2) #define VMCI_ERROR_NO_MEM (-3) #define VMCI_ERROR_DATAGRAM_FAILED (-4) #define VMCI_ERROR_MORE_DATA (-5) #define VMCI_ERROR_NO_MORE_DATAGRAMS (-6) #define VMCI_ERROR_NO_ACCESS (-7) #define VMCI_ERROR_NO_HANDLE (-8) #define VMCI_ERROR_DUPLICATE_ENTRY (-9) #define VMCI_ERROR_DST_UNREACHABLE (-10) #define VMCI_ERROR_PAYLOAD_TOO_LARGE (-11) #define VMCI_ERROR_INVALID_PRIV (-12) #define VMCI_ERROR_GENERIC (-13) #define VMCI_ERROR_PAGE_ALREADY_SHARED (-14) #define VMCI_ERROR_CANNOT_SHARE_PAGE (-15) #define VMCI_ERROR_CANNOT_UNSHARE_PAGE (-16) #define VMCI_ERROR_NO_PROCESS (-17) #define VMCI_ERROR_NO_DATAGRAM (-18) #define VMCI_ERROR_NO_RESOURCES (-19) #define VMCI_ERROR_UNAVAILABLE (-20) #define VMCI_ERROR_NOT_FOUND (-21) #define VMCI_ERROR_ALREADY_EXISTS (-22) #define VMCI_ERROR_NOT_PAGE_ALIGNED (-23) #define VMCI_ERROR_INVALID_SIZE (-24) #define VMCI_ERROR_REGION_ALREADY_SHARED (-25) #define VMCI_ERROR_TIMEOUT (-26) #define VMCI_ERROR_DATAGRAM_INCOMPLETE (-27) #define VMCI_ERROR_INCORRECT_IRQL (-28) #define VMCI_ERROR_EVENT_UNKNOWN (-29) #define VMCI_ERROR_OBSOLETE (-30) #define VMCI_ERROR_QUEUEPAIR_MISMATCH (-31) #define VMCI_ERROR_QUEUEPAIR_NOTSET (-32) #define VMCI_ERROR_QUEUEPAIR_NOTOWNER (-33) #define VMCI_ERROR_QUEUEPAIR_NOTATTACHED (-34) #define VMCI_ERROR_QUEUEPAIR_NOSPACE (-35) #define VMCI_ERROR_QUEUEPAIR_NODATA (-36) #define VMCI_ERROR_BUSMEM_INVALIDATION (-37) #define VMCI_ERROR_MODULE_NOT_LOADED (-38) #define VMCI_ERROR_DEVICE_NOT_FOUND (-39) /* VMCI clients should return error code withing this range */ #define VMCI_ERROR_CLIENT_MIN (-500) #define VMCI_ERROR_CLIENT_MAX (-550) /* Internal error codes. */ #define VMCI_SHAREDMEM_ERROR_BAD_CONTEXT (-1000) #define VMCI_PATH_MAX 256 /* VMCI reserved events. */ typedef uint32 VMCI_Event; #define VMCI_EVENT_CTX_ID_UPDATE 0 #define VMCI_EVENT_CTX_REMOVED 1 #define VMCI_EVENT_QP_RESUMED 2 #define VMCI_EVENT_QP_PEER_ATTACH 3 #define VMCI_EVENT_QP_PEER_DETACH 4 #define VMCI_EVENT_MAX 5 /* Reserved guest datagram resource ids. */ #define VMCI_EVENT_HANDLER 0 /* VMCI privileges. */ typedef enum VMCIResourcePrivilegeType { VMCI_PRIV_CH_PRIV, VMCI_PRIV_DESTROY_RESOURCE, VMCI_PRIV_ASSIGN_CLIENT, VMCI_PRIV_DG_CREATE, VMCI_PRIV_DG_SEND, VMCI_PRIV_NOTIFY, VMCI_NUM_PRIVILEGES, } VMCIResourcePrivilegeType; /* * VMCI coarse-grained privileges (per context or host * process/endpoint. An entity with the restricted flag is only * allowed to interact with the hypervisor and trusted entities. */ typedef uint32 VMCIPrivilegeFlags; #define VMCI_PRIVILEGE_FLAG_RESTRICTED 0x01 #define VMCI_PRIVILEGE_FLAG_TRUSTED 0x02 #define VMCI_PRIVILEGE_ALL_FLAGS (VMCI_PRIVILEGE_FLAG_RESTRICTED | \ VMCI_PRIVILEGE_FLAG_TRUSTED) #define VMCI_NO_PRIVILEGE_FLAGS 0x00 #define VMCI_DEFAULT_PROC_PRIVILEGE_FLAGS VMCI_NO_PRIVILEGE_FLAGS #define VMCI_LEAST_PRIVILEGE_FLAGS VMCI_PRIVILEGE_FLAG_RESTRICTED #define VMCI_MAX_PRIVILEGE_FLAGS VMCI_PRIVILEGE_FLAG_TRUSTED /* VMCI Discovery Service. */ /* Well-known handle to the discovery service. */ #define VMCI_DS_RESOURCE_ID 1 /* Reserved resource ID for discovery service. */ #define VMCI_DS_HANDLE VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, \ VMCI_DS_RESOURCE_ID) #define VMCI_DS_CONTEXT VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, \ VMCI_CONTEXT_RESOURCE_ID) /* Maximum length of a DS message. */ #define VMCI_DS_MAX_MSG_SIZE 300 /* Command actions. */ #define VMCI_DS_ACTION_LOOKUP 0 #define VMCI_DS_ACTION_REGISTER 1 #define VMCI_DS_ACTION_UNREGISTER 2 /* Defines wire-protocol format for a request send to the DS from a context. */ typedef struct VMCIDsRequestHeader { int32 action; int32 msgid; VMCIHandle handle; int32 nameLen; char name[1]; } VMCIDsRequestHeader; /* Defines the wire-protocol format for a request send from the DS to a context. */ typedef struct VMCIDsReplyHeader { int32 msgid; int32 code; VMCIHandle handle; int32 msgLen; int8 msg[1]; } VMCIDsReplyHeader; #define VMCI_PUBLIC_GROUP_NAME "vmci public group" /* 0 through VMCI_RESERVED_RESOURCE_ID_MAX are reserved. */ #define VMCI_RESERVED_RESOURCE_ID_MAX 1023 #define VMCI_DOMAIN_NAME_MAXLEN 32 #define VMCI_LGPFX "VMCI: " /* * VMCIQueueHeader * * A Queue cannot stand by itself as designed. Each Queue's header * contains a pointer into itself (the producerTail) and into its peer * (consumerHead). The reason for the separation is one of * accessibility: Each end-point can modify two things: where the next * location to enqueue is within its produceQ (producerTail); and * where the next dequeue location is in its consumeQ (consumerHead). * * An end-point cannot modify the pointers of its peer (guest to * guest; NOTE that in the host both queue headers are mapped r/w). * But, each end-point needs read access to both Queue header * structures in order to determine how much space is used (or left) * in the Queue. This is because for an end-point to know how full * its produceQ is, it needs to use the consumerHead that points into * the produceQ but -that- consumerHead is in the Queue header for * that end-points consumeQ. * * Thoroughly confused? Sorry. * * producerTail: the point to enqueue new entrants. When you approach * a line in a store, for example, you walk up to the tail. * * consumerHead: the point in the queue from which the next element is * dequeued. In other words, who is next in line is he who is at the * head of the line. * * Also, producerTail points to an empty byte in the Queue, whereas * consumerHead points to a valid byte of data (unless producerTail == * consumerHead in which case consumerHead does not point to a valid * byte of data). * * For a queue of buffer 'size' bytes, the tail and head pointers will be in * the range [0, size-1]. * * If produceQHeader->producerTail == consumeQHeader->consumerHead * then the produceQ is empty. */ typedef struct VMCIQueueHeader { /* All fields are 64bit and aligned. */ VMCIHandle handle; /* Identifier. */ Atomic_uint64 producerTail; /* Offset in this queue. */ Atomic_uint64 consumerHead; /* Offset in peer queue. */ } VMCIQueueHeader; /* * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair * size to be less than 4GB, and use 32bit atomic operations on the head and * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which * is an atomic read-modify-write. This will cause traces to fire when a 32bit * consumer tries to read the producer's tail pointer, for example, because the * consumer has read-only access to the producer's tail pointer. * * We provide the following macros to invoke 32bit or 64bit atomic operations * based on the architecture the code is being compiled on. */ /* Architecture independent maximum queue size. */ #define QP_MAX_QUEUE_SIZE_ARCH_ANY CONST64U(0xffffffff) #ifdef __x86_64__ # define QP_MAX_QUEUE_SIZE_ARCH CONST64U(0xffffffffffffffff) # define QPAtomic_ReadOffset(x) Atomic_Read64(x) # define QPAtomic_WriteOffset(x, y) Atomic_Write64(x, y) #else /* * Wrappers below are being used to call Atomic_Read32 because of the * 'type punned' compilation warning received when Atomic_Read32 is * called with a Atomic_uint64 pointer typecasted to Atomic_uint32 * pointer from QPAtomic_ReadOffset. Ditto with QPAtomic_WriteOffset. */ static INLINE uint32 TypeSafe_Atomic_Read32(void *var) // IN: { return Atomic_Read32((Atomic_uint32 *)(var)); } static INLINE void TypeSafe_Atomic_Write32(void *var, uint32 val) // IN: { Atomic_Write32((Atomic_uint32 *)(var), (uint32)(val)); } # define QP_MAX_QUEUE_SIZE_ARCH CONST64U(0xffffffff) # define QPAtomic_ReadOffset(x) TypeSafe_Atomic_Read32((void *)(x)) # define QPAtomic_WriteOffset(x, y) \ TypeSafe_Atomic_Write32((void *)(x), (uint32)(y)) #endif /* __x86_64__ */ /* *----------------------------------------------------------------------------- * * QPAddPointer -- * * Helper to add a given offset to a head or tail pointer. Wraps the value * of the pointer around the max size of the queue. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void QPAddPointer(Atomic_uint64 *var, // IN: size_t add, // IN: uint64 size) // IN: { uint64 newVal = QPAtomic_ReadOffset(var); if (newVal >= size - add) { newVal -= size; } newVal += add; QPAtomic_WriteOffset(var, newVal); } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_ProducerTail() -- * * Helper routine to get the Producer Tail from the supplied queue. * * Results: * The contents of the queue's producer tail. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint64 VMCIQueueHeader_ProducerTail(const VMCIQueueHeader *qHeader) // IN: { VMCIQueueHeader *qh = (VMCIQueueHeader *)qHeader; return QPAtomic_ReadOffset(&qh->producerTail); } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_ConsumerHead() -- * * Helper routine to get the Consumer Head from the supplied queue. * * Results: * The contents of the queue's consumer tail. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint64 VMCIQueueHeader_ConsumerHead(const VMCIQueueHeader *qHeader) // IN: { VMCIQueueHeader *qh = (VMCIQueueHeader *)qHeader; return QPAtomic_ReadOffset(&qh->consumerHead); } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_AddProducerTail() -- * * Helper routine to increment the Producer Tail. Fundamentally, * QPAddPointer() is used to manipulate the tail itself. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void VMCIQueueHeader_AddProducerTail(VMCIQueueHeader *qHeader, // IN/OUT: size_t add, // IN: uint64 queueSize) // IN: { QPAddPointer(&qHeader->producerTail, add, queueSize); } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_AddConsumerHead() -- * * Helper routine to increment the Consumer Head. Fundamentally, * QPAddPointer() is used to manipulate the head itself. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void VMCIQueueHeader_AddConsumerHead(VMCIQueueHeader *qHeader, // IN/OUT: size_t add, // IN: uint64 queueSize) // IN: { QPAddPointer(&qHeader->consumerHead, add, queueSize); } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_CheckAlignment -- * * Checks if the given queue is aligned to page boundary. Returns TRUE if * the alignment is good. * * Results: * TRUE or FALSE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE Bool VMCIQueueHeader_CheckAlignment(const VMCIQueueHeader *qHeader) // IN: { uintptr_t hdr, offset; hdr = (uintptr_t) qHeader; offset = hdr & (PAGE_SIZE -1); return offset == 0; } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_GetPointers -- * * Helper routine for getting the head and the tail pointer for a queue. * Both the VMCIQueues are needed to get both the pointers for one queue. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void VMCIQueueHeader_GetPointers(const VMCIQueueHeader *produceQHeader, // IN: const VMCIQueueHeader *consumeQHeader, // IN: uint64 *producerTail, // OUT: uint64 *consumerHead) // OUT: { if (producerTail) { *producerTail = VMCIQueueHeader_ProducerTail(produceQHeader); } if (consumerHead) { *consumerHead = VMCIQueueHeader_ConsumerHead(consumeQHeader); } } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_ResetPointers -- * * Reset the tail pointer (of "this" queue) and the head pointer (of * "peer" queue). * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void VMCIQueueHeader_ResetPointers(VMCIQueueHeader *qHeader) // IN/OUT: { QPAtomic_WriteOffset(&qHeader->producerTail, CONST64U(0)); QPAtomic_WriteOffset(&qHeader->consumerHead, CONST64U(0)); } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_Init -- * * Initializes a queue's state (head & tail pointers). * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void VMCIQueueHeader_Init(VMCIQueueHeader *qHeader, // IN/OUT: const VMCIHandle handle) // IN: { qHeader->handle = handle; VMCIQueueHeader_ResetPointers(qHeader); } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_FreeSpace -- * * Finds available free space in a produce queue to enqueue more * data or reports an error if queue pair corruption is detected. * * Results: * Free space size in bytes or an error code. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE int64 VMCIQueueHeader_FreeSpace(const VMCIQueueHeader *produceQHeader, // IN: const VMCIQueueHeader *consumeQHeader, // IN: const uint64 produceQSize) // IN: { uint64 tail; uint64 head; uint64 freeSpace; tail = VMCIQueueHeader_ProducerTail(produceQHeader); head = VMCIQueueHeader_ConsumerHead(consumeQHeader); if (tail >= produceQSize || head >= produceQSize) { return VMCI_ERROR_INVALID_SIZE; } /* * Deduct 1 to avoid tail becoming equal to head which causes ambiguity. If * head and tail are equal it means that the queue is empty. */ if (tail >= head) { freeSpace = produceQSize - (tail - head) - 1; } else { freeSpace = head - tail - 1; } return freeSpace; } /* *----------------------------------------------------------------------------- * * VMCIQueueHeader_BufReady -- * * VMCIQueueHeader_FreeSpace() does all the heavy lifting of * determing the number of free bytes in a Queue. This routine, * then subtracts that size from the full size of the Queue so * the caller knows how many bytes are ready to be dequeued. * * Results: * On success, available data size in bytes (up to MAX_INT64). * On failure, appropriate error code. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE int64 VMCIQueueHeader_BufReady(const VMCIQueueHeader *consumeQHeader, // IN: const VMCIQueueHeader *produceQHeader, // IN: const uint64 consumeQSize) // IN: { int64 freeSpace; freeSpace = VMCIQueueHeader_FreeSpace(consumeQHeader, produceQHeader, consumeQSize); if (freeSpace < VMCI_SUCCESS) { return freeSpace; } else { return consumeQSize - freeSpace - 1; } } #endif vmci-only/shared/vmci_call_defs.h 0000444 0000000 0000000 00000020613 11573420432 016043 0 ustar root root /********************************************************* * Copyright (C) 2006-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 * *********************************************************/ #ifndef _VMCI_CALL_DEFS_H_ #define _VMCI_CALL_DEFS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKMOD #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #include "includeCheck.h" #include "vm_basic_types.h" #include "vmci_defs.h" /* * All structs here are an integral size of their largest member, ie. a struct * with at least one 8-byte member will have a size that is an integral of 8. * A struct which has a largest member of size 4 will have a size that is an * integral of 4. This is because Windows CL enforces this rule. 32 bit gcc * doesn't e.g. 32 bit gcc can misalign an 8 byte member if it is preceeded by * a 4 byte member. */ /* * Base struct for vmci datagrams. */ typedef struct VMCIDatagram { VMCIHandle dst; VMCIHandle src; uint64 payloadSize; } VMCIDatagram; /* * Second flag is for creating a well-known handle instead of a per context * handle. Next flag is for deferring datagram delivery, so that the * datagram callback is invoked in a delayed context (not interrupt context). */ #define VMCI_FLAG_DG_NONE 0 #define VMCI_FLAG_WELLKNOWN_DG_HND 0x1 #define VMCI_FLAG_ANYCID_DG_HND 0x2 #define VMCI_FLAG_DG_DELAYED_CB 0x4 /* Event callback should fire in a delayed context (not interrupt context.) */ #define VMCI_FLAG_EVENT_NONE 0 #define VMCI_FLAG_EVENT_DELAYED_CB 0x1 /* * Maximum supported size of a VMCI datagram for routable datagrams. * Datagrams going to the hypervisor are allowed to be larger. */ #define VMCI_MAX_DG_SIZE (17 * 4096) #define VMCI_MAX_DG_PAYLOAD_SIZE (VMCI_MAX_DG_SIZE - sizeof(VMCIDatagram)) #define VMCI_DG_PAYLOAD(_dg) (void *)((char *)(_dg) + sizeof(VMCIDatagram)) #define VMCI_DG_HEADERSIZE sizeof(VMCIDatagram) #define VMCI_DG_SIZE(_dg) (VMCI_DG_HEADERSIZE + (size_t)(_dg)->payloadSize) #define VMCI_DG_SIZE_ALIGNED(_dg) ((VMCI_DG_SIZE(_dg) + 7) & (size_t)CONST64U(0xfffffffffffffff8)) #define VMCI_MAX_DATAGRAM_QUEUE_SIZE (VMCI_MAX_DG_SIZE * 2) /* * Struct for sending VMCI_DATAGRAM_REQUEST_MAP and VMCI_DATAGRAM_REMOVE_MAP * datagrams. Struct size is 32 bytes. All fields in struct are aligned to * their natural alignment. */ typedef struct VMCIDatagramWellKnownMapMsg { VMCIDatagram hdr; VMCIId wellKnownID; uint32 _pad; } VMCIDatagramWellKnownMapMsg; /* * Struct used for querying, via VMCI_RESOURCES_QUERY, the availability of * hypervisor resources. * Struct size is 16 bytes. All fields in struct are aligned to their natural * alignment. */ typedef struct VMCIResourcesQueryHdr { VMCIDatagram hdr; uint32 numResources; uint32 _padding; } VMCIResourcesQueryHdr; /* * Convenience struct for negotiating vectors. Must match layout of * VMCIResourceQueryHdr minus the VMCIDatagram header. */ typedef struct VMCIResourcesQueryMsg { uint32 numResources; uint32 _padding; VMCI_Resource resources[1]; } VMCIResourcesQueryMsg; /* * The maximum number of resources that can be queried using * VMCI_RESOURCE_QUERY is 31, as the result is encoded in the lower 31 * bits of a positive return value. Negative values are reserved for * errors. */ #define VMCI_RESOURCE_QUERY_MAX_NUM 31 /* Maximum size for the VMCI_RESOURCE_QUERY request. */ #define VMCI_RESOURCE_QUERY_MAX_SIZE sizeof(VMCIResourcesQueryHdr) \ + VMCI_RESOURCE_QUERY_MAX_NUM * sizeof(VMCI_Resource) /* * Struct used for setting the notification bitmap. All fields in * struct are aligned to their natural alignment. */ typedef struct VMCINotifyBitmapSetMsg { VMCIDatagram hdr; PPN bitmapPPN; uint32 _pad; } VMCINotifyBitmapSetMsg; /* * Struct used for linking a doorbell handle with an index in the * notify bitmap. All fields in struct are aligned to their natural * alignment. */ typedef struct VMCIDoorbellLinkMsg { VMCIDatagram hdr; VMCIHandle handle; uint64 notifyIdx; } VMCIDoorbellLinkMsg; /* * Struct used for unlinking a doorbell handle from an index in the * notify bitmap. All fields in struct are aligned to their natural * alignment. */ typedef struct VMCIDoorbellUnlinkMsg { VMCIDatagram hdr; VMCIHandle handle; } VMCIDoorbellUnlinkMsg; /* * Struct used for generating a notification on a doorbell handle. All * fields in struct are aligned to their natural alignment. */ typedef struct VMCIDoorbellNotifyMsg { VMCIDatagram hdr; VMCIHandle handle; } VMCIDoorbellNotifyMsg; /* * This struct is used to contain data for events. Size of this struct is a * multiple of 8 bytes, and all fields are aligned to their natural alignment. */ typedef struct VMCI_EventData { VMCI_Event event; /* 4 bytes. */ uint32 _pad; /* * Event payload is put here. */ } VMCI_EventData; /* Callback needed for correctly waiting on events. */ typedef int (*VMCIDatagramRecvCB)(void *clientData, // IN: client data for handler VMCIDatagram *msg); // IN: /* * We use the following inline function to access the payload data associated * with an event data. */ static INLINE void * VMCIEventDataPayload(VMCI_EventData *evData) // IN: { return (void *)((char *)evData + sizeof *evData); } /* * Define the different VMCI_EVENT payload data types here. All structs must * be a multiple of 8 bytes, and fields must be aligned to their natural * alignment. */ typedef struct VMCIEventPayload_Context { VMCIId contextID; /* 4 bytes. */ uint32 _pad; } VMCIEventPayload_Context; typedef struct VMCIEventPayload_QP { VMCIHandle handle; /* QueuePair handle. */ VMCIId peerId; /* Context id of attaching/detaching VM. */ uint32 _pad; } VMCIEventPayload_QP; /* * We define the following struct to get the size of the maximum event data * the hypervisor may send to the guest. If adding a new event payload type * above, add it to the following struct too (inside the union). */ typedef struct VMCIEventData_Max { VMCI_EventData eventData; union { VMCIEventPayload_Context contextPayload; VMCIEventPayload_QP qpPayload; } evDataPayload; } VMCIEventData_Max; /* * Struct used for VMCI_EVENT_SUBSCRIBE/UNSUBSCRIBE and VMCI_EVENT_HANDLER * messages. Struct size is 32 bytes. All fields in struct are aligned to * their natural alignment. */ typedef struct VMCIEventMsg { VMCIDatagram hdr; VMCI_EventData eventData; /* Has event type and payload. */ /* * Payload gets put here. */ } VMCIEventMsg; /* * We use the following inline function to access the payload data associated * with an event message. */ static INLINE void * VMCIEventMsgPayload(VMCIEventMsg *eMsg) // IN: { return VMCIEventDataPayload(&eMsg->eventData); } /* Flags for VMCI QueuePair API. */ #define VMCI_QPFLAG_ATTACH_ONLY 0x1 /* Fail alloc if QP not created by peer. */ #define VMCI_QPFLAG_LOCAL 0x2 /* Only allow attaches from local context. */ /* Update the following (bitwise OR flags) while adding new flags. */ #define VMCI_QP_ALL_FLAGS (VMCI_QPFLAG_ATTACH_ONLY | VMCI_QPFLAG_LOCAL) /* * Structs used for QueuePair alloc and detach messages. We align fields of * these structs to 64bit boundaries. */ typedef struct VMCIQueuePairAllocMsg { VMCIDatagram hdr; VMCIHandle handle; VMCIId peer; /* 32bit field. */ uint32 flags; uint64 produceSize; uint64 consumeSize; uint64 numPPNs; /* List of PPNs placed here. */ } VMCIQueuePairAllocMsg; typedef struct VMCIQueuePairDetachMsg { VMCIDatagram hdr; VMCIHandle handle; } VMCIQueuePairDetachMsg; #endif vmci-only/shared/vm_basic_defs.h 0000444 0000000 0000000 00000034257 11573420432 015706 0 ustar root root /********************************************************* * Copyright (C) 2003-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 * *********************************************************/ /* * vm_basic_defs.h -- * * Standard macros for VMware source code. */ #ifndef _VM_BASIC_DEFS_H_ #define _VM_BASIC_DEFS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMIROM #include "includeCheck.h" #include "vm_basic_types.h" // For INLINE. /* Checks for FreeBSD, filtering out VMKERNEL. */ #define __IS_FREEBSD__ (!defined(VMKERNEL) && defined(__FreeBSD__)) #define __IS_FREEBSD_VER__(ver) (__IS_FREEBSD__ && __FreeBSD_version >= (ver)) #if defined _WIN32 && defined USERLEVEL #include <stddef.h> /* * We redefine offsetof macro from stddef; make * sure that it's already defined before we do that. */ #include <windows.h> // for Sleep() and LOWORD() etc. #undef GetFreeSpace // Unpollute preprocessor namespace. #endif /* * Simple macros */ #if (defined __APPLE__ || defined __FreeBSD__) && \ (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__) # include <stddef.h> #else // XXX the _WIN32 one matches that of VC++, to prevent redefinition warning // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings #ifndef offsetof #ifdef _WIN32 #define offsetof(s,m) (size_t)&(((s *)0)->m) #else #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #endif #endif #endif // __APPLE__ #ifndef ARRAYSIZE #define ARRAYSIZE(a) (sizeof (a) / sizeof *(a)) #endif #ifndef MIN #define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) #endif /* The Solaris 9 cross-compiler complains about these not being used */ #ifndef sun static INLINE int Min(int a, int b) { return a < b ? a : b; } #endif #ifndef MAX #define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) #endif #ifndef sun static INLINE int Max(int a, int b) { return a > b ? a : b; } #endif #define ROUNDUP(x,y) (((x) + (y) - 1) / (y) * (y)) #define ROUNDDOWN(x,y) ((x) / (y) * (y)) #define ROUNDUPBITS(x, bits) (((uintptr_t) (x) + MASK(bits)) & ~MASK(bits)) #define ROUNDDOWNBITS(x, bits) ((uintptr_t) (x) & ~MASK(bits)) #define CEILING(x, y) (((x) + (y) - 1) / (y)) #if defined __APPLE__ #include <machine/param.h> #undef MASK #endif /* * The MASK macro behaves badly when given negative numbers or numbers larger * than the highest order bit number (e.g. 32 on a 32-bit machine) as an * argument. The range 0..31 is safe. */ #define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */ #define DWORD_ALIGN(x) ((((x) + 3) >> 2) << 2) #define QWORD_ALIGN(x) ((((x) + 7) >> 3) << 3) #define IMPLIES(a,b) (!(a) || (b)) /* * Not everybody (e.g., the monitor) has NULL */ #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endif /* * Token concatenation * * The C preprocessor doesn't prescan arguments when they are * concatenated or stringified. So we need extra levels of * indirection to convince the preprocessor to expand its * arguments. */ #define CONC(x, y) x##y #define XCONC(x, y) CONC(x, y) #define XXCONC(x, y) XCONC(x, y) #define MAKESTR(x) #x #define XSTR(x) MAKESTR(x) /* * Wide versions of string constants. */ #define WSTR_(X) L ## X #define WSTR(X) WSTR_(X) /* * Page operations * * It has been suggested that these definitions belong elsewhere * (like x86types.h). However, I deem them common enough * (since even regular user-level programs may want to do * page-based memory manipulation) to be here. * -- edward */ #ifndef PAGE_SHIFT // { #if defined VM_I386 #define PAGE_SHIFT 12 #elif defined __APPLE__ #define PAGE_SHIFT 12 #elif defined __arm__ #define PAGE_SHIFT 12 #else #error #endif #endif // } #ifndef PAGE_SIZE #define PAGE_SIZE (1<<PAGE_SHIFT) #endif #ifndef PAGE_MASK #define PAGE_MASK (PAGE_SIZE - 1) #endif #ifndef PAGE_OFFSET #define PAGE_OFFSET(_addr) ((uintptr_t)(_addr)&(PAGE_SIZE-1)) #endif #ifndef VM_PAGE_BASE #define VM_PAGE_BASE(_addr) ((_addr)&~(PAGE_SIZE-1)) #endif #ifndef VM_PAGES_SPANNED #define VM_PAGES_SPANNED(_addr, _size) \ ((((_addr) & (PAGE_SIZE - 1)) + (_size) + (PAGE_SIZE - 1)) >> PAGE_SHIFT) #endif #ifndef BYTES_2_PAGES #define BYTES_2_PAGES(_nbytes) ((_nbytes) >> PAGE_SHIFT) #endif #ifndef PAGES_2_BYTES #define PAGES_2_BYTES(_npages) (((uint64)(_npages)) << PAGE_SHIFT) #endif #ifndef MBYTES_2_PAGES #define MBYTES_2_PAGES(_nbytes) ((_nbytes) << (20 - PAGE_SHIFT)) #endif #ifndef PAGES_2_MBYTES #define PAGES_2_MBYTES(_npages) ((_npages) >> (20 - PAGE_SHIFT)) #endif #ifndef BYTES_2_MBYTES #define BYTES_2_MBYTES(_nbytes) ((_nbytes) >> 20) #endif #ifndef MBYTES_2_BYTES #define MBYTES_2_BYTES(_nbytes) ((uint64)(_nbytes) << 20) #endif #ifndef VM_PAE_LARGE_PAGE_SHIFT #define VM_PAE_LARGE_PAGE_SHIFT 21 #endif #ifndef VM_PAE_LARGE_PAGE_SIZE #define VM_PAE_LARGE_PAGE_SIZE (1 << VM_PAE_LARGE_PAGE_SHIFT) #endif #ifndef VM_PAE_LARGE_PAGE_MASK #define VM_PAE_LARGE_PAGE_MASK (VM_PAE_LARGE_PAGE_SIZE - 1) #endif #ifndef VM_PAE_LARGE_2_SMALL_PAGES #define VM_PAE_LARGE_2_SMALL_PAGES (BYTES_2_PAGES(VM_PAE_LARGE_PAGE_SIZE)) #endif #ifndef NR_MPNS_PER_PAGE #define NR_MPNS_PER_PAGE (PAGE_SIZE / sizeof(MPN)) #endif /* * Word operations */ #ifndef LOWORD #define LOWORD(_dw) ((_dw) & 0xffff) #endif #ifndef HIWORD #define HIWORD(_dw) (((_dw) >> 16) & 0xffff) #endif #ifndef LOBYTE #define LOBYTE(_w) ((_w) & 0xff) #endif #ifndef HIBYTE #define HIBYTE(_w) (((_w) >> 8) & 0xff) #endif #define HIDWORD(_qw) ((uint32)((_qw) >> 32)) #define LODWORD(_qw) ((uint32)(_qw)) #define QWORD(_hi, _lo) ((((uint64)(_hi)) << 32) | ((uint32)(_lo))) /* * Deposit a field _src at _pos bits from the right, * with a length of _len, into the integer _target. */ #define DEPOSIT_BITS(_src,_pos,_len,_target) { \ unsigned mask = ((1 << _len) - 1); \ unsigned shiftedmask = ((1 << _len) - 1) << _pos; \ _target = (_target & ~shiftedmask) | ((_src & mask) << _pos); \ } /* * Get return address. */ #ifdef _MSC_VER #ifdef __cplusplus extern "C" #endif void *_ReturnAddress(void); #pragma intrinsic(_ReturnAddress) #define GetReturnAddress() _ReturnAddress() #elif __GNUC__ #define GetReturnAddress() __builtin_return_address(0) #endif #ifdef __GNUC__ #ifndef sun static INLINE_SINGLE_CALLER uintptr_t GetFrameAddr(void) { uintptr_t bp; #if !(__GNUC__ == 4 && (__GNUC_MINOR__ == 0 || __GNUC_MINOR__ == 1)) bp = (uintptr_t)__builtin_frame_address(0); #else /* * We use this assembly hack due to a bug discovered in gcc 4.1.1. * The bug was fixed in 4.2.0; assume it originated with 4.0. * PR147638, PR554369. */ __asm__ __volatile__( # if defined(VM_X86_64) "movq %%rbp, %0\n" # else "movl %%ebp, %0\n" # endif : "=g" (bp)); #endif return bp; } /* * Returns the frame pointer of the calling function. * Equivalent to __builtin_frame_address(1). */ static INLINE_SINGLE_CALLER uintptr_t GetCallerFrameAddr(void) { return *(uintptr_t*)GetFrameAddr(); } #endif // sun #endif // __GNUC__ /* * Data prefetch was added in gcc 3.1.1 * http://www.gnu.org/software/gcc/gcc-3.1/changes.html */ #ifdef __GNUC__ # if ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 1) || \ (__GNUC__ == 3 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 1)) # define PREFETCH_R(var) __builtin_prefetch((var), 0 /* read */, \ 3 /* high temporal locality */) # define PREFETCH_W(var) __builtin_prefetch((var), 1 /* write */, \ 3 /* high temporal locality */) # else # define PREFETCH_R(var) ((void)(var)) # define PREFETCH_W(var) ((void)(var)) # endif #endif /* __GNUC__ */ #ifdef USERLEVEL // { /* * Note this might be a problem on NT b/c while sched_yield guarantees it * moves you to the end of your priority list, Sleep(0) offers no such * guarantee. Bummer. --Jeremy. */ #if defined(N_PLAT_NLM) /* We do not have YIELD() as we do not need it yet... */ #elif defined(_WIN32) # define YIELD() Sleep(0) #else # include <sched.h> // For sched_yield. Don't ask. --Jeremy. # define YIELD() sched_yield() #endif /* * Standardize some Posix names on Windows. */ #ifdef _WIN32 // { #define snprintf _snprintf #define strtok_r strtok_s #if (_MSC_VER < 1500) #define vsnprintf _vsnprintf #endif typedef int uid_t; typedef int gid_t; static INLINE void sleep(unsigned int sec) { Sleep(sec * 1000); } static INLINE void usleep(unsigned long usec) { Sleep(CEILING(usec, 1000)); } typedef int pid_t; #define F_OK 0 #define X_OK 1 #define W_OK 2 #define R_OK 4 #endif // } /* * Macro for username comparison. */ #ifdef _WIN32 // { #define USERCMP(x,y) Str_Strcasecmp(x,y) #else #define USERCMP(x,y) strcmp(x,y) #endif // } #endif // } #ifndef va_copy #ifdef _WIN32 /* * Windows needs va_copy. This works for both 32 and 64-bit Windows * based on inspection of how varags.h from the Visual C CRTL is * implemented. (Future versions of the RTL may break this). */ #define va_copy(dest, src) ((dest) = (src)) #elif defined(__APPLE__) && defined(KERNEL) #include "availabilityMacOS.h" #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 // The Mac OS 10.5 kernel SDK defines va_copy in stdarg.h. #include <stdarg.h> #else /* * The Mac OS 10.4 kernel SDK needs va_copy. Based on inspection of * stdarg.h from the MacOSX10.4u.sdk kernel framework, this should * work. */ #define va_copy(dest, src) ((dest) = (src)) #endif // MAC_OS_X_VERSION_MIN_REQUIRED #elif defined(__GNUC__) && (__GNUC__ < 3) /* * Old versions of gcc recognize __va_copy, but not va_copy. */ #define va_copy(dest, src) __va_copy(dest, src) #endif // _WIN32 #endif // va_copy /* * This one is outside USERLEVEL because it's used by * files compiled into the Windows hgfs driver or the display * driver. */ #ifdef _WIN32 #define PATH_MAX 256 #ifndef strcasecmp #define strcasecmp(_s1,_s2) _stricmp((_s1),(_s2)) #endif #ifndef strncasecmp #define strncasecmp(_s1,_s2,_n) _strnicmp((_s1),(_s2),(_n)) #endif #endif #if defined __linux__ && !defined __KERNEL__ && !defined MODULE && \ !defined VMM && !defined FROBOS #include <features.h> #if __GLIBC_PREREQ(2, 1) && !defined GLIBC_VERSION_21 #define GLIBC_VERSION_21 #endif #if __GLIBC_PREREQ(2, 2) && !defined GLIBC_VERSION_22 #define GLIBC_VERSION_22 #endif #if __GLIBC_PREREQ(2, 3) && !defined GLIBC_VERSION_23 #define GLIBC_VERSION_23 #endif #if __GLIBC_PREREQ(2, 4) && !defined GLIBC_VERSION_24 #define GLIBC_VERSION_24 #endif #if __GLIBC_PREREQ(2, 5) && !defined GLIBC_VERSION_25 #define GLIBC_VERSION_25 #endif #endif /* * Convenience macros and definitions. Can often be used instead of #ifdef. */ #undef DEBUG_ONLY #ifdef VMX86_DEBUG #define vmx86_debug 1 #define DEBUG_ONLY(x) x #else #define vmx86_debug 0 #define DEBUG_ONLY(x) #endif #ifdef VMX86_STATS #define vmx86_stats 1 #define STATS_ONLY(x) x #else #define vmx86_stats 0 #define STATS_ONLY(x) #endif #ifdef VMX86_DEVEL #define vmx86_devel 1 #define DEVEL_ONLY(x) x #else #define vmx86_devel 0 #define DEVEL_ONLY(x) #endif #ifdef VMX86_LOG #define vmx86_log 1 #define LOG_ONLY(x) x #else #define vmx86_log 0 #define LOG_ONLY(x) #endif #ifdef VMX86_SERVER #define vmx86_server 1 #define SERVER_ONLY(x) x #define HOSTED_ONLY(x) #else #define vmx86_server 0 #define SERVER_ONLY(x) #define HOSTED_ONLY(x) x #endif #ifdef VMX86_WGS #define vmx86_wgs 1 #define WGS_ONLY(x) x #else #define vmx86_wgs 0 #define WGS_ONLY(x) #endif #ifdef VMKERNEL #define vmkernel 1 #define VMKERNEL_ONLY(x) x #else #define vmkernel 0 #define VMKERNEL_ONLY(x) #endif #ifdef _WIN32 #define WIN32_ONLY(x) x #define POSIX_ONLY(x) #else #define WIN32_ONLY(x) #define POSIX_ONLY(x) x #endif #ifdef __linux__ #define LINUX_ONLY(x) x #else #define LINUX_ONLY(x) #endif #ifdef __APPLE__ #define vmx86_apple 1 #define APPLE_ONLY(x) x #else #define vmx86_apple 0 #define APPLE_ONLY(x) #endif #ifdef VMM #define VMM_ONLY(x) x #define USER_ONLY(x) #else #define VMM_ONLY(x) #define USER_ONLY(x) x #endif /* VMVISOR ifdef only allowed in the vmkernel */ #ifdef VMKERNEL #ifdef VMVISOR #define vmvisor 1 #define VMVISOR_ONLY(x) x #else #define vmvisor 0 #define VMVISOR_ONLY(x) #endif #endif #ifdef _WIN32 #define VMW_INVALID_HANDLE INVALID_HANDLE_VALUE #else #define VMW_INVALID_HANDLE (-1LL) #endif #ifdef _WIN32 #define fsync(fd) _commit(fd) #define fileno(f) _fileno(f) #else #endif /* * Debug output macros for Windows drivers (the Eng variant is for * display/printer drivers only. */ #ifdef _WIN32 #ifndef USES_OLD_WINDDK #if defined(VMX86_LOG) #define WinDrvPrint(arg, ...) DbgPrint(arg, __VA_ARGS__) #define WinDrvEngPrint(arg, ...) EngDbgPrint(arg, __VA_ARGS__) #else #define WinDrvPrint(arg, ...) #define WinDrvEngPrint(arg, ...) #endif #endif #endif // _WIN32 #ifdef HOSTED_LG_PG #define hosted_lg_pg 1 #else #define hosted_lg_pg 0 #endif /* * Use to initialize cbSize for this structure to preserve < Vista * compatibility. */ #define NONCLIENTMETRICSINFO_V1_SIZE CCSIZEOF_STRUCT(NONCLIENTMETRICS, \ lfMessageFont) #endif // ifndef _VM_BASIC_DEFS_H_ vmci-only/shared/kernelStubsLinux.c 0000444 0000000 0000000 00000022635 11573420377 016443 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * kernelStubsLinux.c * * This file contains implementations of common userspace functions in terms * that the Linux kernel can understand. */ /* Must come before any kernel header file */ #include "driver-config.h" #include "kernelStubs.h" #include "compat_kernel.h" #include "compat_page.h" #include "compat_sched.h" #include <linux/slab.h> #include "vm_assert.h" /* *----------------------------------------------------------------------------- * * Panic -- * * Prints the debug message and stops the system. * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ void Panic(const char *fmt, ...) // IN { va_list args; char *result; va_start(args, fmt); result = Str_Vasprintf(NULL, fmt, args); va_end(args); if (result) { printk(KERN_EMERG "%s", result); } BUG(); while (1); // Avoid compiler warning. } /* *---------------------------------------------------------------------- * * Str_Strcpy-- * * Wrapper for strcpy that checks for buffer overruns. * * Results: * Same as strcpy. * * Side effects: * None. * *---------------------------------------------------------------------- */ char * Str_Strcpy(char *buf, // OUT const char *src, // IN size_t maxSize) // IN { unsigned int *stack = (unsigned int *)&buf; size_t len; len = strlen(src); if (len >= maxSize) { Panic("%s:%d Buffer too small 0x%x\n", __FILE__,__LINE__, stack[-1]); } return memcpy(buf, src, len + 1); } /* *---------------------------------------------------------------------- * * Str_Vsnprintf -- * * Compatability wrapper b/w different libc versions * * Results: * int - number of bytes written (not including NULL terminate character), * -1 on overflow (insufficient space for NULL terminate is considered * overflow) * * NB: on overflow the buffer WILL be null terminated * * Side effects: * None * *---------------------------------------------------------------------- */ int Str_Vsnprintf(char *str, // OUT size_t size, // IN const char *format, // IN va_list arguments) // IN { int retval; retval = vsnprintf(str, size, format, arguments); /* * Linux glibc 2.0.x returns -1 and null terminates (which we shouldn't * be linking against), but glibc 2.1.x follows c99 and returns * characters that would have been written. */ if (retval >= size) { return -1; } return retval; } /* *----------------------------------------------------------------------------- * * Str_Vasprintf -- * * Allocate and format a string, using the GNU libc way to specify the * format (i.e. optionally allow the use of positional parameters) * * Results: * The allocated string on success (if 'length' is not NULL, *length * is set to the length of the allocated string) * NULL on failure * * Side effects: * None * *----------------------------------------------------------------------------- */ char * Str_Vasprintf(size_t *length, // OUT const char *format, // IN va_list arguments) // IN { /* * Simple implementation of Str_Vasprintf when userlevel libraries are not * available (e.g. for use in drivers). We just fallback to vsnprintf, * doubling if we didn't have enough space. */ unsigned int bufSize; char *buf; int retval; bufSize = strlen(format); buf = NULL; do { /* * Initial allocation of strlen(format) * 2. Should this be tunable? * XXX Yes, this could overflow and spin forever when you get near 2GB * allocations. I don't care. --rrdharan */ va_list args2; bufSize *= 2; buf = realloc(buf, bufSize); if (!buf) { return NULL; } va_copy(args2, arguments); retval = Str_Vsnprintf(buf, bufSize, format, args2); va_end(args2); } while (retval == -1); if (length) { *length = retval; } /* * Try to trim the buffer here to save memory? */ return buf; } /* *----------------------------------------------------------------------------- * * Str_Asprintf -- * * Same as Str_Vasprintf(), but parameters are passed inline --hpreg * * Results: * Same as Str_Vasprintf() * * Side effects: * Same as Str_Vasprintf() * *----------------------------------------------------------------------------- */ char * Str_Asprintf(size_t *length, // OUT const char *format, // IN ...) // IN { va_list arguments; char *result; va_start(arguments, format); result = Str_Vasprintf(length, format, arguments); va_end(arguments); return result; } /* *----------------------------------------------------------------------------- * * strdup -- * * Duplicates a string. * * Results: * A pointer to memory containing the duplicated string or NULL if no * memory was available. * * Side effects: * None * *----------------------------------------------------------------------------- */ char * strdup(const char *source) // IN { char *target = NULL; if (source) { /* * We call our special implementation of malloc() because the users of * strdup() will call free(), and that'll decrement the pointer before * freeing it. Thus, we need to make sure that the allocated block * also stores the block length before the block itself (see malloc() * below). */ unsigned int len = strlen(source); target = malloc(len + 1); if (target) { memcpy(target, source, len + 1); } } return target; } /* *---------------------------------------------------------------------------- * * malloc -- * * Allocate memory using kmalloc. There is no realloc * equivalent, so we roll our own by padding each allocation with * 4 (or 8 for 64 bit guests) extra bytes to store the block length. * * Results: * Pointer to driver heap memory, offset by 4 (or 8) * bytes from the real block pointer. * * Side effects: * None. * *---------------------------------------------------------------------------- */ void * malloc(size_t size) // IN { size_t *ptr; ptr = kmalloc(size + sizeof size, GFP_KERNEL); if (ptr) { *ptr++ = size; } return ptr; } /* *--------------------------------------------------------------------------- * * free -- * * Free memory allocated by a previous call to malloc, calloc or realloc. * * Results: * None. * * Side effects: * Calls kfree to free the real (base) pointer. * *--------------------------------------------------------------------------- */ void free(void *mem) // IN { if (mem) { size_t *dataPtr = (size_t *)mem; kfree(--dataPtr); } } /* *---------------------------------------------------------------------------- * * calloc -- * * Malloc and zero. * * Results: * Pointer to driver heap memory (see malloc, above). * * Side effects: * None. * *---------------------------------------------------------------------------- */ void * calloc(size_t num, // IN size_t len) // IN { size_t size; void *ptr; size = num * len; ptr = malloc(size); if (ptr) { memset(ptr, 0, size); } return ptr; } /* *---------------------------------------------------------------------------- * * realloc -- * * Since the driver heap has no realloc equivalent, we have to roll our * own. Fortunately, we can retrieve the block size of every block we * hand out since we stashed it at allocation time (see malloc above). * * Results: * Pointer to memory block valid for 'newSize' bytes, or NULL if * allocation failed. * * Side effects: * Could copy memory around. * *---------------------------------------------------------------------------- */ void * realloc(void* ptr, // IN size_t newSize) // IN { void *newPtr; size_t *dataPtr; size_t length, lenUsed; dataPtr = (size_t *)ptr; length = ptr ? dataPtr[-1] : 0; if (newSize == 0) { if (ptr) { free(ptr); newPtr = NULL; } else { newPtr = malloc(newSize); } } else if (newSize == length) { newPtr = ptr; } else if ((newPtr = malloc(newSize))) { if (length < newSize) { lenUsed = length; } else { lenUsed = newSize; } memcpy(newPtr, ptr, lenUsed); free(ptr); } return newPtr; } vmci-only/shared/compat_workqueue.h 0000444 0000000 0000000 00000014314 11573420431 016503 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __COMPAT_WORKQUEUE_H__ # define __COMPAT_WORKQUEUE_H__ #include <linux/kernel.h> #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) # include <linux/workqueue.h> #endif /* * * Work queues and delayed work queues. * * Prior to 2.5.41, the notion of work queues did not exist. Taskqueues are * used for work queues and timers are used for delayed work queues. * * After 2.6.20, normal work structs ("work_struct") and delayed work * ("delayed_work") structs were separated so that the work_struct could be * slimmed down. The interface was also changed such that the address of the * work_struct itself is passed in as the argument to the work function. This * requires that one embed the work struct in the larger struct containing the * information necessary to complete the work and use container_of() to obtain * the address of the containing structure. * * Users of these macros should embed a compat_work or compat_delayed_work in * a larger structure, then specify the larger structure as the _data argument * for the initialization functions, specify the work function to take * a compat_work_arg or compat_delayed_work_arg, then use the appropriate * _GET_DATA macro to obtain the reference to the structure passed in as _data. * An example is below. * * * typedef struct WorkData { * int data; * compat_work work; * } WorkData; * * * void * WorkFunc(compat_work_arg data) * { * WorkData *workData = COMPAT_WORK_GET_DATA(data, WorkData, work); * * ... * } * * * { * WorkData *workData = kmalloc(sizeof *workData, GFP_EXAMPLE); * if (!workData) { * return -ENOMEM; * } * * COMPAT_INIT_WORK(&workData->work, WorkFunc, workData); * compat_schedule_work(&workData->work); * } */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 41) /* { */ typedef struct tq_struct compat_work; typedef struct compat_delayed_work { struct tq_struct work; struct timer_list timer; } compat_delayed_work; typedef void * compat_work_arg; typedef void * compat_delayed_work_arg; /* * Delayed work queues need to run at some point in the future in process * context, but task queues don't support delaying the task one is scheduling. * Timers allow us to delay the execution of our work queue until the future, * but timer handlers run in bottom-half context. As such, we use both a timer * and task queue and use the timer handler below to schedule the task in * process context immediately. The timer lets us delay execution, and the * task queue lets us run in process context. * * Note that this is similar to how delayed_work is implemented with work * queues in later kernel versions. */ static inline void __compat_delayed_work_timer(unsigned long arg) { compat_delayed_work *dwork = (compat_delayed_work *)arg; if (dwork) { schedule_task(&dwork->work); } } # define COMPAT_INIT_WORK(_work, _func, _data) \ INIT_LIST_HEAD(&(_work)->list); \ (_work)->sync = 0; \ (_work)->routine = _func; \ (_work)->data = _data # define COMPAT_INIT_DELAYED_WORK(_work, _func, _data) \ COMPAT_INIT_WORK(&(_work)->work, _func, _data); \ init_timer(&(_work)->timer); \ (_work)->timer.expires = 0; \ (_work)->timer.function = __compat_delayed_work_timer; \ (_work)->timer.data = (unsigned long)_work # define compat_schedule_work(_work) \ schedule_task(_work) # define compat_schedule_delayed_work(_work, _delay) \ (_work)->timer.expires = jiffies + _delay; \ add_timer(&(_work)->timer) # define COMPAT_WORK_GET_DATA(_p, _type, _member) \ (_type *)(_p) # define COMPAT_DELAYED_WORK_GET_DATA(_p, _type, _member) \ (_type *)(_p) #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) /* } { */ typedef struct work_struct compat_work; typedef struct work_struct compat_delayed_work; typedef void * compat_work_arg; typedef void * compat_delayed_work_arg; # define COMPAT_INIT_WORK(_work, _func, _data) \ INIT_WORK(_work, _func, _data) # define COMPAT_INIT_DELAYED_WORK(_work, _func, _data) \ INIT_WORK(_work, _func, _data) # define compat_schedule_work(_work) \ schedule_work(_work) # define compat_schedule_delayed_work(_work, _delay) \ schedule_delayed_work(_work, _delay) # define COMPAT_WORK_GET_DATA(_p, _type, _member) \ (_type *)(_p) # define COMPAT_DELAYED_WORK_GET_DATA(_p, _type, _member) \ (_type *)(_p) #else /* } Linux >= 2.6.20 { */ typedef struct work_struct compat_work; typedef struct delayed_work compat_delayed_work; typedef struct work_struct * compat_work_arg; typedef struct work_struct * compat_delayed_work_arg; # define COMPAT_INIT_WORK(_work, _func, _data) \ INIT_WORK(_work, _func) # define COMPAT_INIT_DELAYED_WORK(_work, _func, _data) \ INIT_DELAYED_WORK(_work, _func) # define compat_schedule_work(_work) \ schedule_work(_work) # define compat_schedule_delayed_work(_work, _delay) \ schedule_delayed_work(_work, _delay) # define COMPAT_WORK_GET_DATA(_p, _type, _member) \ container_of(_p, _type, _member) # define COMPAT_DELAYED_WORK_GET_DATA(_p, _type, _member) \ container_of(_p, _type, _member.work) #endif /* } */ #endif /* __COMPAT_WORKQUEUE_H__ */ vmci-only/shared/compat_page.h 0000444 0000000 0000000 00000004663 11573420431 015376 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_PAGE_H__ # define __COMPAT_PAGE_H__ #include <linux/mm.h> #include <asm/page.h> /* The pfn_to_page() API appeared in 2.5.14 and changed to function during 2.6.x */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(pfn_to_page) # define pfn_to_page(_pfn) (mem_map + (_pfn)) # define page_to_pfn(_page) ((_page) - mem_map) #endif /* The virt_to_page() API appeared in 2.4.0 --hpreg */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) && !defined(virt_to_page) # define virt_to_page(_kvAddr) pfn_to_page(MAP_NR(_kvAddr)) #endif /* * The get_order() API appeared at some point in 2.3.x, and was then backported * in 2.2.17-21mdk and in the stock 2.2.18. Because we can only detect its * definition through makefile tricks, we provide our own for now --hpreg */ static inline int compat_get_order(unsigned long size) // IN { int order; size = (size - 1) >> (PAGE_SHIFT - 1); order = -1; do { size >>= 1; order++; } while (size); return order; } /* * BUG() was added to <asm/page.h> in 2.2.18, and was moved to <asm/bug.h> * in 2.5.58. * * XXX: Technically, this belongs in some sort of "compat_asm_page.h" file, but * since our compatibility wrappers don't distinguish between <asm/xxx.h> and * <linux/xxx.h>, putting it here is reasonable. */ #ifndef BUG #define BUG() do { \ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ __asm__ __volatile__(".byte 0x0f,0x0b"); \ } while (0) #endif #endif /* __COMPAT_PAGE_H__ */ vmci-only/shared/compat_module.h 0000444 0000000 0000000 00000004372 11573420431 015744 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * compat_module.h -- */ #ifndef __COMPAT_MODULE_H__ # define __COMPAT_MODULE_H__ #include <linux/module.h> /* * Modules wishing to use the GPL license are required to include a * MODULE_LICENSE definition in their module source as of 2.4.10. */ #ifndef MODULE_LICENSE #define MODULE_LICENSE(license) #endif /* * To make use of our own home-brewed MODULE_INFO, we need macros to * concatenate two expressions to "__mod_", and and to convert an * expression into a string. I'm sure we've got these in our codebase, * but I'd rather not introduce such a dependency in a compat header. */ #ifndef __module_cat #define __module_cat_1(a, b) __mod_ ## a ## b #define __module_cat(a, b) __module_cat_1(a, b) #endif #ifndef __stringify #define __stringify_1(x) #x #define __stringify(x) __stringify_1(x) #endif /* * MODULE_INFO was born in 2.5.69. */ #ifndef MODULE_INFO #define MODULE_INFO(tag, info) \ static const char __module_cat(tag, __LINE__)[] \ __attribute__((section(".modinfo"), unused)) = __stringify(tag) "=" info #endif /* * MODULE_VERSION was born in 2.6.4. The earlier form appends a long "\0xxx" * string to the module's version, but that was removed in 2.6.10, so we'll * ignore it in our wrapper. */ #ifndef MODULE_VERSION #define MODULE_VERSION(_version) MODULE_INFO(version, _version) #endif #endif /* __COMPAT_MODULE_H__ */ vmci-only/shared/driverLog.c 0000444 0000000 0000000 00000011112 11573420431 015032 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * driverLog.c -- * * Common logging functions for Linux kernel modules. */ #include "driver-config.h" #include "compat_kernel.h" #include "compat_sched.h" #include <asm/current.h> #include "driverLog.h" #define LINUXLOG_BUFFER_SIZE 1024 static const char *driverLogPrefix = ""; /* * vsnprintf was born in 2.4.10. Fall back on vsprintf if we're * an older kernel. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) # define vsnprintf(str, size, fmt, args) vsprintf(str, fmt, args) #endif /* *---------------------------------------------------------------------------- * * DriverLog_Init -- * * Initializes the Linux logging. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ void DriverLog_Init(const char *prefix) // IN { driverLogPrefix = prefix ? prefix : ""; } /* *---------------------------------------------------------------------- * * DriverLogPrint -- * * Log error message from a Linux module. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void DriverLogPrint(const char *level, // IN: KERN_* constant const char *fmt, // IN: error format string va_list args) // IN: arguments for format string { static char staticBuf[LINUXLOG_BUFFER_SIZE]; char stackBuf[128]; va_list args2; const char *buf; /* * By default, use a small buffer on the stack (thread safe). If it is too * small, fall back to a larger static buffer (not thread safe). */ va_copy(args2, args); if (vsnprintf(stackBuf, sizeof stackBuf, fmt, args2) < sizeof stackBuf) { buf = stackBuf; } else { vsnprintf(staticBuf, sizeof staticBuf, fmt, args); buf = staticBuf; } va_end(args2); printk("%s%s[%d]: %s", level, driverLogPrefix, current->pid, buf); } /* *---------------------------------------------------------------------- * * Warning -- * * Warning messages from kernel module: logged into kernel log * as warnings. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Warning(const char *fmt, ...) // IN: warning format string { va_list args; va_start(args, fmt); DriverLogPrint(KERN_WARNING, fmt, args); va_end(args); } /* *---------------------------------------------------------------------- * * Log -- * * Log messages from kernel module: logged into kernel log * as debug information. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void Log(const char *fmt, ...) // IN: log format string { va_list args; /* * Use the kernel log with at least a KERN_DEBUG level * so it doesn't garbage the screen at (re)boot time on RedHat 6.0. */ va_start(args, fmt); DriverLogPrint(KERN_DEBUG, fmt, args); va_end(args); } /* *---------------------------------------------------------------------- * * Panic -- * * ASSERTION failures and Panics from kernel module get here. * Message is logged to the kernel log and on console. * * Results: * None. * * Side effects: * Never returns * *---------------------------------------------------------------------- */ void Panic(const char *fmt, ...) // IN: panic format string { va_list args; va_start(args, fmt); DriverLogPrint(KERN_EMERG, fmt, args); va_end(args); #ifdef BUG BUG(); #else /* Should die with %cs unwritable, or at least with page fault. */ asm volatile("movb $0, %cs:(0)"); #endif while (1); } vmci-only/shared/compat_mutex.h 0000444 0000000 0000000 00000003475 11573420431 015624 0 ustar root root /********************************************************* * Copyright (C) 2009 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_MUTEX_H__ # define __COMPAT_MUTEX_H__ /* Blocking mutexes were introduced in 2.6.16. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) #include "compat_semaphore.h" typedef struct semaphore compat_mutex_t; # define compat_define_mutex(_mx) DECLARE_MUTEX(_mx) # define compat_mutex_init(_mx) init_MUTEX(_mx) # define compat_mutex_lock(_mx) down(_mx) # define compat_mutex_lock_interruptible(_mx) down_interruptible(_mx) # define compat_mutex_unlock(_mx) up(_mx) #else #include <linux/mutex.h> typedef struct mutex compat_mutex_t; # define compat_define_mutex(_mx) DEFINE_MUTEX(_mx) # define compat_mutex_init(_mx) mutex_init(_mx) # define compat_mutex_lock(_mx) mutex_lock(_mx) # define compat_mutex_lock_interruptible(_mx) mutex_lock_interruptible(_mx) # define compat_mutex_unlock(_mx) mutex_unlock(_mx) #endif #endif /* __COMPAT_MUTEX_H__ */ vmci-only/shared/vmciKernelAPI2.h 0000444 0000000 0000000 00000004131 11573420432 015621 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciKernelAPI2.h -- * * Kernel API (v2) exported from the VMCI host and guest drivers. */ #ifndef __VMCI_KERNELAPI_2_H__ #define __VMCI_KERNELAPI_2_H__ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include "vmciKernelAPI1.h" /* Define version 2. */ #undef VMCI_KERNEL_API_VERSION #define VMCI_KERNEL_API_VERSION_2 2 #define VMCI_KERNEL_API_VERSION VMCI_KERNEL_API_VERSION_2 /* VMCI Doorbell API. */ #define VMCI_FLAG_DELAYED_CB 0x01 typedef void (*VMCICallback)(void *clientData); int VMCIDoorbell_Create(VMCIHandle *handle, uint32 flags, VMCIPrivilegeFlags privFlags, VMCICallback notifyCB, void *clientData); int VMCIDoorbell_Destroy(VMCIHandle handle); int VMCIDoorbell_Notify(VMCIHandle handle, VMCIPrivilegeFlags privFlags); /* Typedefs for all of the above, used by the IOCTLs and the kernel library. */ typedef int (VMCIDoorbell_CreateFct)(VMCIHandle *, uint32, VMCIPrivilegeFlags, VMCICallback, void *); typedef int (VMCIDoorbell_DestroyFct)(VMCIHandle); typedef int (VMCIDoorbell_NotifyFct)(VMCIHandle, VMCIPrivilegeFlags); #endif /* !__VMCI_KERNELAPI_2_H__ */ vmci-only/shared/vm_basic_asm.h 0000444 0000000 0000000 00000043307 11573420432 015541 0 ustar root root /********************************************************* * Copyright (C) 2003 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ /* * vm_basic_asm.h * * Basic asm macros * * ARM not implemented. */ #ifndef _VM_BASIC_ASM_H_ #define _VM_BASIC_ASM_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMIROM #include "includeCheck.h" #include "vm_basic_types.h" #if defined VM_X86_64 #include "vm_basic_asm_x86_64.h" #elif defined __i386__ #include "vm_basic_asm_x86.h" #endif /* * x86-64 windows doesn't support inline asm so we have to use these * intrinsic functions defined in the compiler. Not all of these are well * documented. There is an array in the compiler dll (c1.dll) which has * an array of the names of all the intrinsics minus the leading * underscore. Searching around in the ntddk.h file can also be helpful. * * The declarations for the intrinsic functions were taken from the DDK. * Our declarations must match the ddk's otherwise the 64-bit c++ compiler * will complain about second linkage of the intrinsic functions. * We define the intrinsic using the basic types corresponding to the * Windows typedefs. This avoids having to include windows header files * to get to the windows types. */ #ifdef _MSC_VER #ifdef __cplusplus extern "C" { #endif /* * It seems x86 & x86-64 windows still implements these intrinsic * functions. The documentation for the x86-64 suggest the * __inbyte/__outbyte intrinsics eventhough the _in/_out work fine and * __inbyte/__outbyte aren't supported on x86. */ int _inp(unsigned short); unsigned short _inpw(unsigned short); unsigned long _inpd(unsigned short); int _outp(unsigned short, int); unsigned short _outpw(unsigned short, unsigned short); unsigned long _outpd(uint16, unsigned long); #pragma intrinsic(_inp, _inpw, _inpd, _outp, _outpw, _outpw, _outpd) /* * Prevents compiler from re-ordering reads, writes and reads&writes. * These functions do not add any instructions thus only affect * the compiler ordering. * * See: * `Lockless Programming Considerations for Xbox 360 and Microsoft Windows' * http://msdn.microsoft.com/en-us/library/bb310595(VS.85).aspx */ void _ReadBarrier(void); void _WriteBarrier(void); void _ReadWriteBarrier(void); #pragma intrinsic(_ReadBarrier, _WriteBarrier, _ReadWriteBarrier) #ifdef VM_X86_64 /* * intrinsic functions only supported by x86-64 windows as of 2k3sp1 */ unsigned __int64 __rdtsc(void); void __stosw(unsigned short *, unsigned short, size_t); void __stosd(unsigned long *, unsigned long, size_t); void _mm_pause(void); #pragma intrinsic(__rdtsc, __stosw, __stosd, _mm_pause) unsigned char _BitScanForward64(unsigned long *, unsigned __int64); unsigned char _BitScanReverse64(unsigned long *, unsigned __int64); #pragma intrinsic(_BitScanForward64, _BitScanReverse64) #endif /* VM_X86_64 */ unsigned char _BitScanForward(unsigned long *, unsigned long); unsigned char _BitScanReverse(unsigned long *, unsigned long); #pragma intrinsic(_BitScanForward, _BitScanReverse) #ifdef __cplusplus } #endif #endif /* _MSC_VER */ #ifdef __GNUC__ // { #if defined(__i386__) || defined(__x86_64__) // Only on x86* /* * Checked against the Intel manual and GCC --hpreg * * volatile because reading from port can modify the state of the underlying * hardware. * * Note: The undocumented %z construct doesn't work (internal compiler error) * with gcc-2.95.1 */ #define __GCC_IN(s, type, name) \ static INLINE type \ name(uint16 port) \ { \ type val; \ \ __asm__ __volatile__( \ "in" #s " %w1, %0" \ : "=a" (val) \ : "Nd" (port) \ ); \ \ return val; \ } __GCC_IN(b, uint8, INB) __GCC_IN(w, uint16, INW) __GCC_IN(l, uint32, IN32) /* * Checked against the Intel manual and GCC --hpreg * * Note: The undocumented %z construct doesn't work (internal compiler error) * with gcc-2.95.1 */ #define __GCC_OUT(s, s2, port, val) do { \ __asm__( \ "out" #s " %" #s2 "1, %w0" \ : \ : "Nd" (port), "a" (val) \ ); \ } while (0) #define OUTB(port, val) __GCC_OUT(b, b, port, val) #define OUTW(port, val) __GCC_OUT(w, w, port, val) #define OUT32(port, val) __GCC_OUT(l, , port, val) #define GET_CURRENT_EIP(_eip) \ __asm__ __volatile("call 0\n\tpopl %0" : "=r" (_eip): ); #endif // x86* #elif defined(_MSC_VER) // } { static INLINE uint8 INB(uint16 port) { return (uint8)_inp(port); } static INLINE void OUTB(uint16 port, uint8 value) { _outp(port, value); } static INLINE uint16 INW(uint16 port) { return _inpw(port); } static INLINE void OUTW(uint16 port, uint16 value) { _outpw(port, value); } static INLINE uint32 IN32(uint16 port) { return _inpd(port); } static INLINE void OUT32(uint16 port, uint32 value) { _outpd(port, value); } #ifndef VM_X86_64 #ifdef NEAR #undef NEAR #endif #define GET_CURRENT_EIP(_eip) do { \ __asm call NEAR PTR $+5 \ __asm pop eax \ __asm mov _eip, eax \ } while (0) #endif // VM_X86_64 #else // } { #error #endif // } /* Sequence recommended by Intel for the Pentium 4. */ #define INTEL_MICROCODE_VERSION() ( \ __SET_MSR(MSR_BIOS_SIGN_ID, 0), \ __GET_EAX_FROM_CPUID(1), \ __GET_MSR(MSR_BIOS_SIGN_ID)) /* * Locate most and least significant bit set functions. Use our own name * space to avoid namespace collisions. The new names follow a pattern, * <prefix><size><option>, where: * * <prefix> is [lm]ssb (least/most significant bit set) * <size> is size of the argument: 32 (32-bit), 64 (64-bit) or Ptr (pointer) * <option> is for alternative versions of the functions * * NAME FUNCTION BITS FUNC(0) *----- -------- ---- ------- * lssb32_0 LSB set (uint32) 0..31 -1 * mssb32_0 MSB set (uint32) 0..31 -1 * lssb64_0 LSB set (uint64) 0..63 -1 * mssb64_0 MSB set (uint64) 0..63 -1 * lssbPtr_0 LSB set (uintptr_t;32-bit) 0..31 -1 * lssbPtr_0 LSB set (uintptr_t;64-bit) 0..63 -1 * mssbPtr_0 MSB set (uintptr_t;32-bit) 0..31 -1 * mssbPtr_0 MSB set (uintptr_t;64-bit) 0..63 -1 * lssbPtr LSB set (uintptr_t;32-bit) 1..32 0 * lssbPtr LSB set (uintptr_t;64-bit) 1..64 0 * mssbPtr MSB set (uintptr_t;32-bit) 1..32 0 * mssbPtr MSB set (uintptr_t;64-bit) 1..64 0 * lssb32 LSB set (uint32) 1..32 0 * mssb32 MSB set (uint32) 1..32 0 * lssb64 LSB set (uint64) 1..64 0 * mssb64 MSB set (uint64) 1..64 0 */ #if defined(_MSC_VER) static INLINE int lssb32_0(const uint32 value) { unsigned long idx; if (UNLIKELY(value == 0)) { return -1; } _BitScanForward(&idx, (unsigned long) value); return idx; } static INLINE int mssb32_0(const uint32 value) { unsigned long idx; if (UNLIKELY(value == 0)) { return -1; } _BitScanReverse(&idx, (unsigned long) value); return idx; } static INLINE int lssb64_0(const uint64 value) { if (UNLIKELY(value == 0)) { return -1; } else { #if defined(VM_X86_64) unsigned long idx; _BitScanForward64(&idx, (unsigned __int64) value); return idx; #else /* The coding was chosen to minimize conditionals and operations */ int lowFirstBit = lssb32_0((uint32) value); if (lowFirstBit == -1) { lowFirstBit = lssb32_0((uint32) (value >> 32)); if (lowFirstBit != -1) { return lowFirstBit + 32; } } return lowFirstBit; #endif } } static INLINE int mssb64_0(const uint64 value) { if (UNLIKELY(value == 0)) { return -1; } else { #if defined(VM_X86_64) unsigned long idx; _BitScanReverse64(&idx, (unsigned __int64) value); return idx; #else /* The coding was chosen to minimize conditionals and operations */ if (value > 0xFFFFFFFFULL) { return 32 + mssb32_0((uint32) (value >> 32)); } return mssb32_0((uint32) value); #endif } } #endif #if defined(__GNUC__) #if defined(__i386__) || defined(__x86_64__) // Only on x86* #define USE_ARCH_X86_CUSTOM #endif static INLINE int lssb32_0(uint32 value) { #if defined(USE_ARCH_X86_CUSTOM) if (UNLIKELY(value == 0)) { return -1; } else { int pos; __asm__ __volatile__("bsfl %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); return pos; } #else return __builtin_ffs(value) - 1; #endif } static INLINE int mssb32_0(uint32 value) { if (UNLIKELY(value == 0)) { return -1; } else { int pos; #if defined(USE_ARCH_X86_CUSTOM) __asm__ __volatile__("bsrl %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); #else pos = 32 - __builtin_clz(value) - 1; #endif return pos; } } static INLINE int lssb64_0(const uint64 value) { #if defined(USE_ARCH_X86_CUSTOM) if (UNLIKELY(value == 0)) { return -1; } else { intptr_t pos; #if defined(VM_X86_64) __asm__ __volatile__("bsf %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); #else /* The coding was chosen to minimize conditionals and operations */ pos = lssb32_0((uint32) value); if (pos == -1) { pos = lssb32_0((uint32) (value >> 32)); if (pos != -1) { return pos + 32; } } #endif return pos; } #else return __builtin_ffsll(value) - 1; #endif } static INLINE int mssb64_0(const uint64 value) { if (UNLIKELY(value == 0)) { return -1; } else { intptr_t pos; #if defined(USE_ARCH_X86_CUSTOM) #if defined(VM_X86_64) __asm__ __volatile__("bsr %1, %0\n" : "=r" (pos) : "rm" (value) : "cc"); #else /* The coding was chosen to minimize conditionals and operations */ if (value > 0xFFFFFFFFULL) { pos = 32 + mssb32_0((uint32) (value >> 32)); } else { pos = mssb32_0((uint32) value); } #endif #else pos = 64 - __builtin_clzll(value) - 1; #endif return pos; } } #if defined(USE_ARCH_X86_CUSTOM) #undef USE_ARCH_X86_CUSTOM #endif #endif static INLINE int lssbPtr_0(const uintptr_t value) { #if defined(VM_X86_64) return lssb64_0((uint64) value); #else return lssb32_0((uint32) value); #endif } static INLINE int lssbPtr(const uintptr_t value) { return lssbPtr_0(value) + 1; } static INLINE int mssbPtr_0(const uintptr_t value) { #if defined(VM_X86_64) return mssb64_0((uint64) value); #else return mssb32_0((uint32) value); #endif } static INLINE int mssbPtr(const uintptr_t value) { return mssbPtr_0(value) + 1; } static INLINE int lssb32(const uint32 value) { return lssb32_0(value) + 1; } static INLINE int mssb32(const uint32 value) { return mssb32_0(value) + 1; } static INLINE int lssb64(const uint64 value) { return lssb64_0(value) + 1; } static INLINE int mssb64(const uint64 value) { return mssb64_0(value) + 1; } #ifdef __GNUC__ #if defined(__i386__) || defined(__x86_64__) static INLINE void * uint16set(void *dst, uint16 val, size_t count) { int dummy0; int dummy1; __asm__ __volatile__("\t" "cld" "\n\t" "rep ; stosw" "\n" : "=c" (dummy0), "=D" (dummy1) : "0" (count), "1" (dst), "a" (val) : "memory", "cc" ); return dst; } static INLINE void * uint32set(void *dst, uint32 val, size_t count) { int dummy0; int dummy1; __asm__ __volatile__("\t" "cld" "\n\t" "rep ; stosl" "\n" : "=c" (dummy0), "=D" (dummy1) : "0" (count), "1" (dst), "a" (val) : "memory", "cc" ); return dst; } #else /* unknown system: rely on C to write */ static INLINE void * uint16set(void *dst, uint16 val, size_t count) { size_t i; for (i = 0; i < count; i++) { ((uint16 *) dst)[i] = val; } return dst; } static INLINE void * uint32set(void *dst, uint32 val, size_t count) { size_t i; for (i = 0; i < count; i++) { ((uint32 *) dst)[i] = val; } return dst; } #endif // defined(__i386__) || defined(__x86_64__) #elif defined(_MSC_VER) static INLINE void * uint16set(void *dst, uint16 val, size_t count) { #ifdef VM_X86_64 __stosw((uint16*)dst, val, count); #else __asm { pushf; mov ax, val; mov ecx, count; mov edi, dst; cld; rep stosw; popf; } #endif return dst; } static INLINE void * uint32set(void *dst, uint32 val, size_t count) { #ifdef VM_X86_64 __stosd((unsigned long*)dst, (unsigned long)val, count); #else __asm { pushf; mov eax, val; mov ecx, count; mov edi, dst; cld; rep stosd; popf; } #endif return dst; } #else #error "No compiler defined for uint*set" #endif /* *----------------------------------------------------------------------------- * * Bswap16 -- * * Swap the 2 bytes of "v" as follows: 32 -> 23. * *----------------------------------------------------------------------------- */ static INLINE uint16 Bswap16(uint16 v) { return ((v >> 8) & 0x00ff) | ((v << 8) & 0xff00); } /* *----------------------------------------------------------------------------- * * Bswap32 -- * * Swap the 4 bytes of "v" as follows: 3210 -> 0123. * *----------------------------------------------------------------------------- */ static INLINE uint32 Bswap32(uint32 v) // IN { #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) // { /* Checked against the Intel manual and GCC. --hpreg */ __asm__( "bswap %0" : "=r" (v) : "0" (v) ); return v; #else // } { return (v >> 24) | ((v >> 8) & 0xFF00) | ((v & 0xFF00) << 8) | (v << 24) ; #endif // } } #define Bswap Bswap32 /* *----------------------------------------------------------------------------- * * Bswap64 -- * * Swap the 8 bytes of "v" as follows: 76543210 -> 01234567. * *----------------------------------------------------------------------------- */ static INLINE uint64 Bswap64(uint64 v) // IN { return ((uint64)Bswap((uint32)v) << 32) | Bswap((uint32)(v >> 32)); } #if defined(__i386__) || defined(__x86_64__) /* * COMPILER_MEM_BARRIER prevents the compiler from re-ordering memory * references accross the barrier. NOTE: It does not generate any * instruction, so the CPU is free to do whatever it wants to... */ #ifdef __GNUC__ // { #define COMPILER_MEM_BARRIER() __asm__ __volatile__ ("": : :"memory") #define COMPILER_READ_BARRIER() COMPILER_MEM_BARRIER() #define COMPILER_WRITE_BARRIER() COMPILER_MEM_BARRIER() #elif defined(_MSC_VER) #define COMPILER_MEM_BARRIER() _ReadWriteBarrier() #define COMPILER_READ_BARRIER() _ReadBarrier() #define COMPILER_WRITE_BARRIER() _WriteBarrier() #endif // } /* * PAUSE is a P4 instruction that improves spinlock power+performance; * on non-P4 IA32 systems, the encoding is interpreted as a REPZ-NOP. * Use volatile to avoid NOP removal. */ static INLINE void PAUSE(void) #ifdef __GNUC__ { __asm__ __volatile__( "pause" :); } #elif defined(_MSC_VER) #ifdef VM_X86_64 { _mm_pause(); } #else /* VM_X86_64 */ #pragma warning( disable : 4035) { __asm _emit 0xf3 __asm _emit 0x90 } #pragma warning (default: 4035) #endif /* VM_X86_64 */ #else /* __GNUC__ */ #error No compiler defined for PAUSE #endif /* * Checked against the Intel manual and GCC --hpreg * * volatile because the tsc always changes without the compiler knowing it. */ static INLINE uint64 RDTSC(void) #ifdef __GNUC__ { #ifdef VM_X86_64 uint64 tscLow; uint64 tscHigh; __asm__ __volatile__( "rdtsc" : "=a" (tscLow), "=d" (tscHigh) ); return tscHigh << 32 | tscLow; #else uint64 tim; __asm__ __volatile__( "rdtsc" : "=A" (tim) ); return tim; #endif } #elif defined(_MSC_VER) #ifdef VM_X86_64 { return __rdtsc(); } #else #pragma warning( disable : 4035) { __asm _emit 0x0f __asm _emit 0x31 } #pragma warning (default: 4035) #endif /* VM_X86_64 */ #else /* __GNUC__ */ #error No compiler defined for RDTSC #endif /* __GNUC__ */ /* *----------------------------------------------------------------------------- * * DEBUGBREAK -- * * Does an int3 for MSVC / GCC. This is a macro to make sure int3 is * always inlined. * *----------------------------------------------------------------------------- */ #ifdef _MSC_VER #define DEBUGBREAK() __debugbreak() #else #define DEBUGBREAK() __asm__ (" int $3 ") #endif #endif // defined(__i386__) || defined(__x86_64__) #endif // _VM_BASIC_ASM_H_ vmci-only/shared/x86cpuid.h 0000644 0000000 0000000 00000154636 11573420432 014602 0 ustar root root /********************************************************* * Copyright (C) 1998-2008 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef _X86CPUID_H_ #define _X86CPUID_H_ /* http://www.sandpile.org/ia32/cpuid.htm */ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMX #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMMON #include "includeCheck.h" #include "vm_basic_types.h" #include "community_source.h" #include "x86vendor.h" /* * The linux kernel's ptrace.h stupidly defines the bare * EAX/EBX/ECX/EDX, which wrecks havoc with our preprocessor tricks. */ #undef EAX #undef EBX #undef ECX #undef EDX typedef struct CPUIDRegs { uint32 eax, ebx, ecx, edx; } CPUIDRegs; typedef union CPUIDRegsUnion { uint32 array[4]; CPUIDRegs regs; } CPUIDRegsUnion; /* * Results of calling cpuid(eax, ecx) on all host logical CPU. */ #ifdef _MSC_VER #pragma warning (disable :4200) // non-std extension: zero-sized array in struct #endif typedef #include "vmware_pack_begin.h" struct CPUIDReply { /* * Unique host logical CPU identifier. It does not change across queries, so * we use it to correlate the replies of multiple queries. */ uint64 tag; // OUT CPUIDRegs regs; // OUT } #include "vmware_pack_end.h" CPUIDReply; typedef #include "vmware_pack_begin.h" struct CPUIDQuery { uint32 eax; // IN uint32 ecx; // IN uint32 numLogicalCPUs; // IN/OUT CPUIDReply logicalCPUs[0]; // OUT } #include "vmware_pack_end.h" CPUIDQuery; /* * CPUID levels the monitor caches and ones that are not cached, but * have fields defined below (short name and actual value). * * The first parameter defines whether the level has its default masks * generated from the values in this file. Any level which is marked * as FALSE here *must* have all monitor support types set to NA. A * static assert in lib/cpuidcompat/cpuidcompat.c will check this. */ #define CPUID_CACHED_LEVELS \ CPUIDLEVEL(TRUE, 0, 0) \ CPUIDLEVEL(TRUE, 1, 1) \ CPUIDLEVEL(FALSE, 5, 5) \ CPUIDLEVEL(TRUE, 7, 7) \ CPUIDLEVEL(TRUE, D, 0xD) \ CPUIDLEVEL(FALSE,400, 0x40000000) \ CPUIDLEVEL(FALSE,410, 0x40000010) \ CPUIDLEVEL(FALSE, 80, 0x80000000) \ CPUIDLEVEL(TRUE, 81, 0x80000001) \ CPUIDLEVEL(FALSE, 87, 0x80000007) \ CPUIDLEVEL(FALSE, 88, 0x80000008) \ CPUIDLEVEL(TRUE, 8A, 0x8000000A) #define CPUID_UNCACHED_LEVELS \ CPUIDLEVEL(FALSE, 4, 4) \ CPUIDLEVEL(FALSE, 6, 6) \ CPUIDLEVEL(FALSE, A, 0xA) \ CPUIDLEVEL(FALSE, B, 0xB) \ CPUIDLEVEL(FALSE, 85, 0x80000005) \ CPUIDLEVEL(FALSE, 86, 0x80000006) \ CPUIDLEVEL(FALSE, 819, 0x80000019) \ CPUIDLEVEL(FALSE, 81A, 0x8000001A) \ CPUIDLEVEL(FALSE, 81B, 0x8000001B) \ CPUIDLEVEL(FALSE, 81C, 0x8000001C) \ CPUIDLEVEL(FALSE, 81D, 0x8000001D) \ CPUIDLEVEL(FALSE, 81E, 0x8000001E) #define CPUID_ALL_LEVELS \ CPUID_CACHED_LEVELS \ CPUID_UNCACHED_LEVELS /* Define cached CPUID levels in the form: CPUID_LEVEL_<ShortName> */ typedef enum { #define CPUIDLEVEL(t, s, v) CPUID_LEVEL_##s, CPUID_CACHED_LEVELS #undef CPUIDLEVEL CPUID_NUM_CACHED_LEVELS } CpuidCachedLevel; /* SVM CPUID feature leaf */ #define CPUID_SVM_FEATURES 0x8000000a /* * CPUID result registers */ #define CPUID_REGS \ CPUIDREG(EAX, eax) \ CPUIDREG(EBX, ebx) \ CPUIDREG(ECX, ecx) \ CPUIDREG(EDX, edx) typedef enum { #define CPUIDREG(uc, lc) CPUID_REG_##uc, CPUID_REGS #undef CPUIDREG CPUID_NUM_REGS } CpuidReg; #define CPUID_INTEL_VENDOR_STRING "GenuntelineI" #define CPUID_AMD_VENDOR_STRING "AuthcAMDenti" #define CPUID_CYRIX_VENDOR_STRING "CyriteadxIns" #define CPUID_VIA_VENDOR_STRING "CentaulsaurH" #define CPUID_HYPERV_HYPERVISOR_VENDOR_STRING "Microsoft Hv" #define CPUID_KVM_HYPERVISOR_VENDOR_STRING "KVMKVMKVM\0\0\0" #define CPUID_VMWARE_HYPERVISOR_VENDOR_STRING "VMwareVMware" #define CPUID_XEN_HYPERVISOR_VENDOR_STRING "XenVMMXenVMM" #define CPUID_INTEL_VENDOR_STRING_FIXED "GenuineIntel" #define CPUID_AMD_VENDOR_STRING_FIXED "AuthenticAMD" #define CPUID_CYRIX_VENDOR_STRING_FIXED "CyrixInstead" #define CPUID_VIA_VENDOR_STRING_FIXED "CentaurHauls" /* * FIELDDEF can be defined to process the CPUID information provided * in the following CPUID_FIELD_DATA macro. The first parameter is * the CPUID level of the feature (must be defined in * CPUID_ALL_LEVELS, above. The second parameter is the CPUID result * register in which the field is returned (defined in CPUID_REGS). * The third field is the vendor(s) this feature applies to. "COMMON" * means all vendors apply. UNKNOWN may not be used here. The fourth * and fifth parameters are the bit position of the field and the * width, respectively. The sixth is the text name of the field. * * The seventh parameters specifies the monitor support * characteristics for this field. The value must be a valid * CpuidFieldSupported value (omitting CPUID_FIELD_SUPPORT_ for * convenience). The meaning of those values are described below. * * The eighth parameter describes whether the feature is capable of * being used by usermode code (TRUE), or just CPL0 kernel code * (FALSE). * * FIELDDEFA takes a ninth parameter: the name used when generating * accessor functions in lib/public/cpuidInfoFuncs.h. * * FLAGDEF/FLAGDEFA is defined identically to fields, but their * accessors are more appropriate for 1-bit flags, and compile-time * asserts enforce that the size is 1 bit wide. */ /* * CpuidFieldSupported is made up of the following values: * * NO: A feature/field that IS NOT SUPPORTED by the monitor. Even * if the host supports this feature, we will never expose it to * the guest. * * YES: A feature/field that IS SUPPORTED by the monitor. If the * host supports this feature, we will expose it to the guest. If * not, then we will not set the feature. * * ANY: A feature/field that IS ALWAYS SUPPORTED by the monitor. * Even if the host does not support the feature, the monitor can * expose the feature to the guest. * * NA: Only legal for levels not masked/tested by default (see * above for this definition). Such fields must always be marked * as NA. * * These distinctions, when combined with the feature's CPL3 * properties can be translated into a common CPUID mask string as * follows: * * NO + CPL3 --> "R" (Reserved). We don't support the feature, * but we can't properly hide this from applications when using * direct execution or HV with apps that do try/catch/fail, so we * must still perform compatibility checks. * * NO + !CPL3 --> "0" (Masked). We can hide this from the guest. * * YES --> "H" (Host). We support the feature, so show it to the * guest if the host has the feature. * * ANY/NA --> "X" (Ignore). By default, don't perform checks for * this feature bit. Per-GOS masks may choose to set this bit in * the guest. (e.g. the APIC feature bit is always set to 1.) * * See lib/cpuidcompat/cpuidcompat.c for any possible overrides to * these defaults. */ typedef enum { CPUID_FIELD_SUPPORTED_NO, CPUID_FIELD_SUPPORTED_YES, CPUID_FIELD_SUPPORTED_ANY, CPUID_FIELD_SUPPORTED_NA, CPUID_NUM_FIELD_SUPPORTEDS } CpuidFieldSupported; #define CPUID_1_ECX_29 #define CPUID_1_ECX_30 #define CPUID_7_EBX_0 #define CPUID_7_EBX_7 #define CPUID_7_EBX_9 /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_0 \ FIELDDEF( 0, EAX, COMMON, 0, 32, NUMLEVELS, ANY, FALSE) \ FIELDDEF( 0, EBX, COMMON, 0, 32, VENDOR1, YES, TRUE) \ FIELDDEF( 0, ECX, COMMON, 0, 32, VENDOR3, YES, TRUE) \ FIELDDEF( 0, EDX, COMMON, 0, 32, VENDOR2, YES, TRUE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_1 \ FIELDDEFA( 1, EAX, COMMON, 0, 4, STEPPING, ANY, FALSE, STEPPING) \ FIELDDEFA( 1, EAX, COMMON, 4, 4, MODEL, ANY, FALSE, MODEL) \ FIELDDEFA( 1, EAX, COMMON, 8, 4, FAMILY, YES, FALSE, FAMILY) \ FIELDDEF( 1, EAX, COMMON, 12, 2, TYPE, ANY, FALSE) \ FIELDDEFA( 1, EAX, COMMON, 16, 4, EXTMODEL, ANY, FALSE, EXT_MODEL) \ FIELDDEFA( 1, EAX, COMMON, 20, 8, EXTFAMILY, YES, FALSE, EXT_FAMILY) \ FIELDDEF( 1, EBX, COMMON, 0, 8, BRAND_ID, ANY, FALSE) \ FIELDDEF( 1, EBX, COMMON, 8, 8, CLFL_SIZE, ANY, FALSE) \ FIELDDEFA( 1, EBX, COMMON, 16, 8, LCPU_COUNT, ANY, FALSE, LCPU_COUNT) \ FIELDDEFA( 1, EBX, COMMON, 24, 8, APICID, ANY, FALSE, APICID) \ FLAGDEFA( 1, ECX, COMMON, 0, 1, SSE3, YES, TRUE, SSE3) \ FLAGDEFA( 1, ECX, COMMON, 1, 1, PCLMULQDQ, YES, TRUE, PCLMULQDQ) \ FLAGDEF( 1, ECX, INTEL, 2, 1, NDA2, NO, FALSE) \ FLAGDEFA( 1, ECX, COMMON, 3, 1, MWAIT, ANY, FALSE, MWAIT) \ FLAGDEFA( 1, ECX, INTEL, 4, 1, DSCPL, NO, FALSE, DSCPL) \ FLAGDEFA( 1, ECX, INTEL, 5, 1, VMX, YES, FALSE, VMX) \ FLAGDEF( 1, ECX, VIA, 5, 1, VMX, YES, FALSE) \ FLAGDEF( 1, ECX, INTEL, 6, 1, SMX, NO, FALSE) \ FLAGDEF( 1, ECX, INTEL, 7, 1, EST, NO, FALSE) \ FLAGDEF( 1, ECX, INTEL, 8, 1, TM2, NO, FALSE) \ FLAGDEFA( 1, ECX, COMMON, 9, 1, SSSE3, YES, TRUE, SSSE3) \ FLAGDEF( 1, ECX, INTEL, 10, 1, HTCACHE, NO, FALSE) \ FLAGDEF( 1, ECX, INTEL, 11, 1, NDA11, NO, FALSE) \ FLAGDEFA( 1, ECX, COMMON, 12, 1, FMA, YES, TRUE, FMA) \ FLAGDEFA( 1, ECX, COMMON, 13, 1, CMPX16, YES, TRUE, CMPX16) \ FLAGDEF( 1, ECX, INTEL, 14, 1, xPPR, NO, FALSE) \ FLAGDEF( 1, ECX, INTEL, 15, 1, PERF_MSR, NO, FALSE) \ FLAGDEF( 1, ECX, INTEL, 17, 1, PCID, NO, FALSE) \ FLAGDEF( 1, ECX, INTEL, 18, 1, DCA, NO, FALSE) \ FLAGDEFA( 1, ECX, COMMON, 19, 1, SSE41, YES, TRUE, SSE41) \ FLAGDEFA( 1, ECX, COMMON, 20, 1, SSE42, YES, TRUE, SSE42) \ FLAGDEF( 1, ECX, INTEL, 21, 1, X2APIC, NO, FALSE) \ FLAGDEFA( 1, ECX, INTEL, 22, 1, MOVBE, YES, TRUE, MOVBE) \ FLAGDEFA( 1, ECX, COMMON, 23, 1, POPCNT, YES, TRUE, POPCNT) \ FLAGDEFA( 1, ECX, COMMON, 25, 1, AES, YES, TRUE, AES) \ FLAGDEFA( 1, ECX, COMMON, 26, 1, XSAVE, YES, FALSE, XSAVE) \ FLAGDEFA( 1, ECX, COMMON, 27, 1, OSXSAVE, ANY, FALSE, OSXSAVE) \ FLAGDEFA( 1, ECX, COMMON, 28, 1, AVX, YES, FALSE, AVX) \ CPUID_1_ECX_29 \ CPUID_1_ECX_30 \ FLAGDEFA( 1, ECX, COMMON, 31, 1, HYPERVISOR, ANY, FALSE, HYPERVISOR)\ FLAGDEFA( 1, EDX, COMMON, 0, 1, FPU, YES, TRUE, FPU) \ FLAGDEFA( 1, EDX, COMMON, 1, 1, VME, YES, FALSE, VME) \ FLAGDEF( 1, EDX, COMMON, 2, 1, DBGE, YES, FALSE) \ FLAGDEF( 1, EDX, COMMON, 3, 1, PGSZE, YES, FALSE) \ FLAGDEFA( 1, EDX, COMMON, 4, 1, TSC, YES, TRUE, TSC) \ FLAGDEF( 1, EDX, COMMON, 5, 1, MSR, YES, FALSE) \ FLAGDEFA( 1, EDX, COMMON, 6, 1, PAE, YES, FALSE, PAE) \ FLAGDEF( 1, EDX, COMMON, 7, 1, MCK, YES, FALSE) \ FLAGDEF( 1, EDX, COMMON, 8, 1, CPMX, YES, TRUE) \ FLAGDEFA( 1, EDX, COMMON, 9, 1, APIC, ANY, FALSE, APIC) \ FLAGDEFA( 1, EDX, COMMON, 11, 1, SEP, YES, TRUE, SEP) \ FLAGDEFA( 1, EDX, COMMON, 12, 1, MTRR, YES, FALSE, MTRR) \ FLAGDEFA( 1, EDX, COMMON, 13, 1, PGE, YES, FALSE, PGE) \ FLAGDEFA( 1, EDX, COMMON, 14, 1, MCA, YES, FALSE, MCA) \ FLAGDEFA( 1, EDX, COMMON, 15, 1, CMOV, YES, TRUE, CMOV) \ FLAGDEFA( 1, EDX, COMMON, 16, 1, PAT, YES, FALSE, PAT) \ FLAGDEF( 1, EDX, COMMON, 17, 1, 36PG, YES, FALSE) \ FLAGDEF( 1, EDX, INTEL, 18, 1, PSN, YES, FALSE) \ FLAGDEFA( 1, EDX, COMMON, 19, 1, CLFL, YES, TRUE, CLFL) \ FLAGDEF( 1, EDX, INTEL, 21, 1, DTES, YES, FALSE) \ FLAGDEF( 1, EDX, INTEL, 22, 1, ACPI, YES, FALSE) \ FLAGDEFA( 1, EDX, COMMON, 23, 1, MMX, YES, TRUE, MMX) \ FLAGDEFA( 1, EDX, COMMON, 24, 1, FXSAVE, YES, TRUE, FXSAVE) \ FLAGDEFA( 1, EDX, COMMON, 25, 1, SSE, YES, TRUE, SSE) \ FLAGDEFA( 1, EDX, COMMON, 26, 1, SSE2, YES, TRUE, SSE2) \ FLAGDEF( 1, EDX, INTEL, 27, 1, SS, YES, FALSE) \ FLAGDEFA( 1, EDX, COMMON, 28, 1, HT, ANY, FALSE, HT) \ FLAGDEF( 1, EDX, INTEL, 29, 1, TM, NO, FALSE) \ FLAGDEF( 1, EDX, INTEL, 30, 1, IA64, NO, FALSE) \ FLAGDEF( 1, EDX, INTEL, 31, 1, PBE, NO, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_4 \ FIELDDEF( 4, EAX, INTEL, 0, 5, CACHE_TYPE, NA, FALSE) \ FIELDDEF( 4, EAX, INTEL, 5, 3, CACHE_LEVEL, NA, FALSE) \ FLAGDEF( 4, EAX, INTEL, 8, 1, CACHE_SELF_INIT, NA, FALSE) \ FLAGDEF( 4, EAX, INTEL, 9, 1, CACHE_FULLY_ASSOC, NA, FALSE) \ FIELDDEF( 4, EAX, INTEL, 14, 12, CACHE_NUMHT_SHARING, NA, FALSE) \ FIELDDEFA( 4, EAX, INTEL, 26, 6, CORE_COUNT, NA, FALSE, INTEL_CORE_COUNT) \ FIELDDEF( 4, EBX, INTEL, 0, 12, CACHE_LINE, NA, FALSE) \ FIELDDEF( 4, EBX, INTEL, 12, 10, CACHE_PART, NA, FALSE) \ FIELDDEF( 4, EBX, INTEL, 22, 10, CACHE_WAYS, NA, FALSE) \ FIELDDEF( 4, ECX, INTEL, 0, 32, CACHE_SETS, NA, FALSE) \ FLAGDEF( 4, EDX, INTEL, 0, 1, CACHE_WBINVD_NOT_GUARANTEED, NA, FALSE) \ FLAGDEF( 4, EDX, INTEL, 1, 1, CACHE_IS_INCLUSIVE, NA, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_5 \ FIELDDEFA( 5, EAX, COMMON, 0, 16, MWAIT_MIN_SIZE, NA, FALSE, MWAIT_MIN_SIZE) \ FIELDDEFA( 5, EBX, COMMON, 0, 16, MWAIT_MAX_SIZE, NA, FALSE, MWAIT_MAX_SIZE) \ FLAGDEF( 5, ECX, COMMON, 0, 1, MWAIT_EXTENSIONS, NA, FALSE) \ FLAGDEFA( 5, ECX, COMMON, 1, 1, MWAIT_INTR_BREAK, NA, FALSE, MWAIT_INTR_BREAK) \ FIELDDEF( 5, EDX, INTEL, 0, 4, MWAIT_C0_SUBSTATE, NA, FALSE) \ FIELDDEF( 5, EDX, INTEL, 4, 4, MWAIT_C1_SUBSTATE, NA, FALSE) \ FIELDDEF( 5, EDX, INTEL, 8, 4, MWAIT_C2_SUBSTATE, NA, FALSE) \ FIELDDEF( 5, EDX, INTEL, 12, 4, MWAIT_C3_SUBSTATE, NA, FALSE) \ FIELDDEF( 5, EDX, INTEL, 16, 4, MWAIT_C4_SUBSTATE, NA, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_6 \ FLAGDEF( 6, EAX, INTEL, 0, 1, THERMAL_SENSOR, NA, FALSE) \ FLAGDEF( 6, EAX, INTEL, 1, 1, TURBO_MODE, NA, FALSE) \ FLAGDEF( 6, EAX, INTEL, 2, 1, APIC_INVARIANT, NA, FALSE) \ FIELDDEF( 6, EBX, INTEL, 0, 4, NUM_INTR_THRESHOLDS, NA, FALSE) \ FLAGDEF( 6, ECX, INTEL, 0, 1, HW_COORD_FEEDBACK, NA, FALSE) \ FLAGDEF( 6, ECX, INTEL, 3, 1, ENERGY_PERF_BIAS, NA, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_7 \ CPUID_7_EBX_0 \ CPUID_7_EBX_7 \ CPUID_7_EBX_9 /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_A \ FIELDDEFA( A, EAX, INTEL, 0, 8, PMC_VERSION, NA, FALSE, PMC_VERSION) \ FIELDDEFA( A, EAX, INTEL, 8, 8, NUM_PMCS, NA, FALSE, NUM_PMCS) \ FIELDDEF( A, EAX, INTEL, 16, 8, PMC_BIT_WIDTH, NA, FALSE) \ FIELDDEFA( A, EAX, INTEL, 24, 8, PMC_EBX_LENGTH, NA, FALSE, PMC_EBX_LENGTH) \ FLAGDEF( A, EBX, INTEL, 0, 1, PMC_CORE_CYCLE, NA, FALSE) \ FLAGDEF( A, EBX, INTEL, 1, 1, PMC_INSTR_RETIRED, NA, FALSE) \ FLAGDEF( A, EBX, INTEL, 2, 1, PMC_REF_CYCLES, NA, FALSE) \ FLAGDEF( A, EBX, INTEL, 3, 1, PMC_LAST_LVL_CREF, NA, FALSE) \ FLAGDEF( A, EBX, INTEL, 4, 1, PMC_LAST_LVL_CMISS, NA, FALSE) \ FLAGDEF( A, EBX, INTEL, 5, 1, PMC_BR_INST_RETIRED, NA, FALSE) \ FLAGDEF( A, EBX, INTEL, 6, 1, PMC_BR_MISS_RETIRED, NA, FALSE) \ FIELDDEF( A, EDX, INTEL, 0, 5, PMC_FIXED_NUM, NA, FALSE) \ FIELDDEF( A, EDX, INTEL, 5, 8, PMC_FIXED_SIZE, NA, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_B \ FIELDDEF( B, EAX, INTEL, 0, 5, MASK_WIDTH, NA, FALSE) \ FIELDDEF( B, EBX, INTEL, 0, 16, CPUS_SHARING_LEVEL, NA, FALSE) \ FIELDDEF( B, ECX, INTEL, 0, 8, LEVEL_NUMBER, NA, FALSE) \ FIELDDEF( B, ECX, INTEL, 8, 8, LEVEL_TYPE, NA, FALSE) \ FIELDDEF( B, EDX, INTEL, 0, 32, X2APIC_ID, NA, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_D \ FLAGDEFA( D, EAX, COMMON, 0, 1, XCR0_MASTER_LEGACY_FP, YES, FALSE, XCR0_MASTER_LEGACY_FP) \ FLAGDEFA( D, EAX, COMMON, 1, 1, XCR0_MASTER_SSE, YES, FALSE, XCR0_MASTER_SSE) \ FLAGDEFA( D, EAX, COMMON, 2, 1, XCR0_MASTER_YMM_H, YES, FALSE, XCR0_MASTER_YMM_H) \ FIELDDEF( D, EAX, COMMON, 3, 29, XCR0_MASTER_LOWER, NO, FALSE) \ FIELDDEF( D, EBX, COMMON, 0, 32, XSAVE_ENABLED_SIZE, ANY, FALSE) \ FIELDDEFA( D, ECX, COMMON, 0, 32, XSAVE_MAX_SIZE, YES, FALSE, XSAVE_MAX_SIZE) \ FIELDDEF( D, EDX, COMMON, 0, 32, XCR0_MASTER_UPPER, NO, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_400 \ FIELDDEF(400, EAX, COMMON, 0, 32, NUM_HYP_LEVELS, NA, FALSE) \ FIELDDEF(400, EBX, COMMON, 0, 32, HYPERVISOR1, NA, FALSE) \ FIELDDEF(400, ECX, COMMON, 0, 32, HYPERVISOR2, NA, FALSE) \ FIELDDEF(400, EDX, COMMON, 0, 32, HYPERVISOR3, NA, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_410 \ FIELDDEF(410, EAX, COMMON, 0, 32, TSC_HZ, NA, FALSE) \ FIELDDEF(410, EBX, COMMON, 0, 32, ACPIBUS_HZ, NA, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_80 \ FIELDDEF( 80, EAX, COMMON, 0, 32, NUM_EXT_LEVELS, NA, FALSE) \ FIELDDEF( 80, EBX, AMD, 0, 32, AMD_VENDOR1, NA, FALSE) \ FIELDDEF( 80, ECX, AMD, 0, 32, AMD_VENDOR3, NA, FALSE) \ FIELDDEF( 80, EDX, AMD, 0, 32, AMD_VENDOR2, NA, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_81 \ FIELDDEF( 81, EAX, INTEL, 0, 32, UNKNOWN81EAX, ANY, FALSE) \ FIELDDEF( 81, EAX, AMD, 0, 4, STEPPING, ANY, FALSE) \ FIELDDEF( 81, EAX, AMD, 4, 4, MODEL, ANY, FALSE) \ FIELDDEF( 81, EAX, AMD, 8, 4, FAMILY, ANY, FALSE) \ FIELDDEF( 81, EAX, AMD, 12, 2, TYPE, ANY, FALSE) \ FIELDDEF( 81, EAX, AMD, 16, 4, EXTMODEL, ANY, FALSE) \ FIELDDEF( 81, EAX, AMD, 20, 8, EXTFAMILY, ANY, FALSE) \ FIELDDEF( 81, EBX, INTEL, 0, 32, UNKNOWN81EBX, ANY, FALSE) \ FIELDDEF( 81, EBX, AMD, 0, 16, BRAND_ID, ANY, FALSE) \ FIELDDEF( 81, EBX, AMD, 16, 16, UNDEF, ANY, FALSE) \ FLAGDEFA( 81, ECX, COMMON, 0, 1, LAHF, YES, TRUE, LAHF64) \ FLAGDEFA( 81, ECX, AMD, 1, 1, CMPLEGACY, NO, FALSE, CMPLEGACY) \ FLAGDEFA( 81, ECX, AMD, 2, 1, SVM, YES, FALSE, SVM) \ FLAGDEFA( 81, ECX, AMD, 3, 1, EXTAPICSPC, YES, FALSE, EXTAPICSPC) \ FLAGDEFA( 81, ECX, AMD, 4, 1, CR8AVAIL, NO, FALSE, CR8AVAIL) \ FLAGDEFA( 81, ECX, AMD, 5, 1, ABM, YES, TRUE, ABM) \ FLAGDEFA( 81, ECX, AMD, 6, 1, SSE4A, YES, TRUE, SSE4A) \ FLAGDEF( 81, ECX, AMD, 7, 1, MISALIGNED_SSE, YES, TRUE) \ FLAGDEFA( 81, ECX, AMD, 8, 1, 3DNPREFETCH, YES, TRUE, 3DNPREFETCH) \ FLAGDEFA( 81, ECX, AMD, 9, 1, OSVW, ANY, FALSE, OSVW) \ FLAGDEF( 81, ECX, AMD, 10, 1, IBS, NO, FALSE) \ FLAGDEFA( 81, ECX, AMD, 11, 1, XOP, YES, TRUE, XOP) \ FLAGDEF( 81, ECX, AMD, 12, 1, SKINIT, NO, FALSE) \ FLAGDEF( 81, ECX, AMD, 13, 1, WATCHDOG, NO, FALSE) \ FLAGDEF( 81, ECX, AMD, 15, 1, LWP, NO, FALSE) \ FLAGDEFA( 81, ECX, AMD, 16, 1, FMA4, YES, TRUE, FMA4) \ FLAGDEF( 81, ECX, AMD, 19, 1, NODEID, NO, FALSE) \ FLAGDEF( 81, ECX, AMD, 22, 1, TOPOLOGY, NO, FALSE) \ FLAGDEF( 81, EDX, AMD, 0, 1, FPU, YES, TRUE) \ FLAGDEF( 81, EDX, AMD, 1, 1, VME, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 2, 1, DBGE, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 3, 1, PGSZE, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 4, 1, TSC, YES, TRUE) \ FLAGDEF( 81, EDX, AMD, 5, 1, MSR, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 6, 1, PAE, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 7, 1, MCK, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 8, 1, CPMX, YES, TRUE) \ FLAGDEF( 81, EDX, AMD, 9, 1, APIC, ANY, FALSE) \ FLAGDEFA( 81, EDX, COMMON, 11, 1, SYSC, ANY, TRUE, SYSC) \ FLAGDEF( 81, EDX, AMD, 12, 1, MTRR, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 13, 1, PGE, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 14, 1, MCA, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 15, 1, CMOV, YES, TRUE) \ FLAGDEF( 81, EDX, AMD, 16, 1, PAT, YES, FALSE) \ FLAGDEF( 81, EDX, AMD, 17, 1, 36PG, YES, FALSE) \ FLAGDEFA( 81, EDX, COMMON, 20, 1, NX, YES, FALSE, NX) \ FLAGDEFA( 81, EDX, AMD, 22, 1, MMXEXT, YES, TRUE, MMXEXT) \ FLAGDEF( 81, EDX, AMD, 23, 1, MMX, YES, TRUE) \ FLAGDEF( 81, EDX, AMD, 24, 1, FXSAVE, YES, TRUE) \ FLAGDEFA( 81, EDX, AMD, 25, 1, FFXSR, YES, FALSE, FFXSR) \ FLAGDEF( 81, EDX, COMMON, 26, 1, PDPE1GB, NO, FALSE) \ FLAGDEFA( 81, EDX, COMMON, 27, 1, RDTSCP, YES, TRUE, RDTSCP) \ FLAGDEFA( 81, EDX, COMMON, 29, 1, LM, YES, FALSE, LM) \ FLAGDEFA( 81, EDX, AMD, 30, 1, 3DNOWPLUS, YES, TRUE, 3DNOWPLUS) \ FLAGDEFA( 81, EDX, AMD, 31, 1, 3DNOW, YES, TRUE, 3DNOW) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_8x \ FIELDDEF( 85, EAX, AMD, 0, 8, ITLB_ENTRIES_2M4M_PGS, NA, FALSE) \ FIELDDEF( 85, EAX, AMD, 8, 8, ITLB_ASSOC_2M4M_PGS, NA, FALSE) \ FIELDDEF( 85, EAX, AMD, 16, 8, DTLB_ENTRIES_2M4M_PGS, NA, FALSE) \ FIELDDEF( 85, EAX, AMD, 24, 8, DTLB_ASSOC_2M4M_PGS, NA, FALSE) \ FIELDDEF( 85, EBX, AMD, 0, 8, ITLB_ENTRIES_4K_PGS, NA, FALSE) \ FIELDDEF( 85, EBX, AMD, 8, 8, ITLB_ASSOC_4K_PGS, NA, FALSE) \ FIELDDEF( 85, EBX, AMD, 16, 8, DTLB_ENTRIES_4K_PGS, NA, FALSE) \ FIELDDEF( 85, EBX, AMD, 24, 8, DTLB_ASSOC_4K_PGS, NA, FALSE) \ FIELDDEF( 85, ECX, AMD, 0, 8, L1_DCACHE_LINE_SIZE, NA, FALSE) \ FIELDDEF( 85, ECX, AMD, 8, 8, L1_DCACHE_LINES_PER_TAG, NA, FALSE) \ FIELDDEF( 85, ECX, AMD, 16, 8, L1_DCACHE_ASSOC, NA, FALSE) \ FIELDDEF( 85, ECX, AMD, 24, 8, L1_DCACHE_SIZE, NA, FALSE) \ FIELDDEF( 85, EDX, AMD, 0, 8, L1_ICACHE_LINE_SIZE, NA, FALSE) \ FIELDDEF( 85, EDX, AMD, 8, 8, L1_ICACHE_LINES_PER_TAG, NA, FALSE) \ FIELDDEF( 85, EDX, AMD, 16, 8, L1_ICACHE_ASSOC, NA, FALSE) \ FIELDDEF( 85, EDX, AMD, 24, 8, L1_ICACHE_SIZE, NA, FALSE) \ FIELDDEF( 86, EAX, AMD, 0, 12, L2_ITLB_ENTRIES_2M4M_PGS, NA, FALSE) \ FIELDDEF( 86, EAX, AMD, 12, 4, L2_ITLB_ASSOC_2M4M_PGS, NA, FALSE) \ FIELDDEF( 86, EAX, AMD, 16, 12, L2_DTLB_ENTRIES_2M4M_PGS, NA, FALSE) \ FIELDDEF( 86, EAX, AMD, 28, 4, L2_DTLB_ASSOC_2M4M_PGS, NA, FALSE) \ FIELDDEF( 86, EBX, AMD, 0, 12, L2_ITLB_ENTRIES_4K_PGS, NA, FALSE) \ FIELDDEF( 86, EBX, AMD, 12, 4, L2_ITLB_ASSOC_4K_PGS, NA, FALSE) \ FIELDDEF( 86, EBX, AMD, 16, 12, L2_DTLB_ENTRIES_4K_PGS, NA, FALSE) \ FIELDDEF( 86, EBX, AMD, 28, 4, L2_DTLB_ASSOC_4K_PGS,NA, FALSE) \ FIELDDEF( 86, ECX, AMD, 0, 8, L2CACHE_LINE, NA, FALSE) \ FIELDDEF( 86, ECX, AMD, 8, 4, L2CACHE_LINE_PER_TAG,NA, FALSE) \ FIELDDEF( 86, ECX, AMD, 12, 4, L2CACHE_WAYS, NA, FALSE) \ FIELDDEF( 86, ECX, AMD, 16, 16, L2CACHE_SIZE, NA, FALSE) \ FIELDDEF( 86, EDX, AMD, 0, 8, L3CACHE_LINE, NA, FALSE) \ FIELDDEF( 86, EDX, AMD, 8, 4, L3CACHE_LINE_PER_TAG,NA, FALSE) \ FIELDDEF( 86, EDX, AMD, 12, 4, L3CACHE_WAYS, NA, FALSE) \ FIELDDEF( 86, EDX, AMD, 18, 14, L3CACHE_SIZE, NA, FALSE) \ FLAGDEF( 87, EDX, AMD, 0, 1, TS, NA, FALSE) \ FLAGDEF( 87, EDX, AMD, 1, 1, FID, NA, FALSE) \ FLAGDEF( 87, EDX, AMD, 2, 1, VID, NA, FALSE) \ FLAGDEF( 87, EDX, AMD, 3, 1, TTP, NA, FALSE) \ FLAGDEF( 87, EDX, AMD, 4, 1, TM, NA, FALSE) \ FLAGDEF( 87, EDX, AMD, 5, 1, STC, NA, FALSE) \ FLAGDEF( 87, EDX, AMD, 6, 1, 100MHZSTEPS, NA, FALSE) \ FLAGDEF( 87, EDX, AMD, 7, 1, HWPSTATE, NA, FALSE) \ FLAGDEF( 87, EDX, COMMON, 8, 1, TSC_INVARIANT, NA, FALSE) \ FLAGDEF( 87, EDX, COMMON, 9, 1, CORE_PERF_BOOST, NA, FALSE) \ FIELDDEFA(88, EAX, COMMON, 0, 8, PHYSBITS, NA, FALSE, PHYS_BITS) \ FIELDDEFA(88, EAX, COMMON, 8, 8, VIRTBITS, NA, FALSE, VIRT_BITS) \ FIELDDEF( 88, EAX, COMMON, 16, 8, GUEST_PHYS_ADDR_SZ, NA, FALSE) \ FIELDDEFA(88, ECX, AMD, 0, 8, CORE_COUNT, NA, FALSE, AMD_CORE_COUNT) \ FIELDDEFA(88, ECX, AMD, 12, 4, APICID_COREID_SIZE, NA, FALSE, AMD_APICID_COREID_SIZE) \ FIELDDEFA(8A, EAX, AMD, 0, 8, SVM_REVISION, YES, FALSE, SVM_REVISION) \ FLAGDEF( 8A, EAX, AMD, 8, 1, SVM_HYPERVISOR, NO, FALSE) \ FIELDDEF( 8A, EAX, AMD, 9, 23, SVMEAX_RSVD, NO, FALSE) \ FIELDDEFA(8A, EBX, AMD, 0, 32, SVM_N_ASIDS, YES, FALSE, SVM_NUM_ASIDS) \ FIELDDEF( 8A, ECX, AMD, 0, 32, SVMECX_RSVD, NO, FALSE) \ FLAGDEFA( 8A, EDX, AMD, 0, 1, SVM_NP, YES, FALSE, NPT) \ FLAGDEF( 8A, EDX, AMD, 1, 1, SVM_LBR, NO, FALSE) \ FLAGDEF( 8A, EDX, AMD, 2, 1, SVM_LOCK, NO, FALSE) \ FLAGDEF( 8A, EDX, AMD, 3, 1, SVM_NRIP, YES, FALSE) \ FLAGDEF( 8A, EDX, AMD, 4, 1, SVM_TSC_RATE_MSR, NO, FALSE) \ FLAGDEF( 8A, EDX, AMD, 5, 1, SVM_VMCB_CLEAN, YES, FALSE) \ FLAGDEF( 8A, EDX, AMD, 6, 1, SVM_FLUSH_BY_ASID, YES, FALSE) \ FLAGDEFA( 8A, EDX, AMD, 7, 1, SVM_DECODE_ASSISTS, YES, FALSE, SVM_DECODE_ASSISTS) \ FIELDDEF( 8A, EDX, AMD, 8, 2, SVMEDX_RSVD0, NO, FALSE) \ FLAGDEFA( 8A, EDX, AMD, 10, 1, SVM_PAUSE_FILTER, NO, FALSE, PAUSE_FILTER) \ FLAGDEF( 8A, EDX, AMD, 11, 1, SVMEDX_RSVD1, NO, FALSE) \ FLAGDEF( 8A, EDX, AMD, 12, 1, SVM_PAUSE_THRESHOLD, NO, FALSE) \ FIELDDEF( 8A, EDX, AMD, 13, 19, SVMEDX_RSVD2, NO, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_81x \ FIELDDEF(819, EAX, AMD, 0, 12, L1_ITLB_ENTRIES_1G_PGS, NA, FALSE) \ FIELDDEF(819, EAX, AMD, 12, 4, L1_ITLB_ASSOC_1G_PGS, NA, FALSE) \ FIELDDEF(819, EAX, AMD, 16, 12, L1_DTLB_ENTRIES_1G_PGS, NA, FALSE) \ FIELDDEF(819, EAX, AMD, 28, 4, L1_DTLB_ASSOC_1G_PGS, NA, FALSE) \ FIELDDEF(819, EBX, AMD, 0, 12, L2_ITLB_ENTRIES_1G_PGS, NA, FALSE) \ FIELDDEF(819, EBX, AMD, 12, 4, L2_ITLB_ASSOC_1G_PGS, NA, FALSE) \ FIELDDEF(819, EBX, AMD, 16, 12, L2_DTLB_ENTRIES_1G_PGS, NA, FALSE) \ FIELDDEF(819, EBX, AMD, 28, 4, L2_DTLB_ASSOC_1G_PGS, NA, FALSE) \ FLAGDEF( 81A, EAX, AMD, 0, 1, FP128, NA, FALSE) \ FLAGDEF( 81A, EAX, AMD, 1, 1, MOVU, NA, FALSE) \ FLAGDEF( 81B, EAX, AMD, 0, 1, IBS_FFV, NA, FALSE) \ FLAGDEF( 81B, EAX, AMD, 1, 1, IBS_FETCHSAM, NA, FALSE) \ FLAGDEF( 81B, EAX, AMD, 2, 1, IBS_OPSAM, NA, FALSE) \ FLAGDEF( 81B, EAX, AMD, 3, 1, RW_OPCOUNT, NA, FALSE) \ FLAGDEF( 81B, EAX, AMD, 4, 1, OPCOUNT, NA, FALSE) \ FLAGDEF( 81B, EAX, AMD, 5, 1, BRANCH_TARGET_ADDR, NA, FALSE) \ FLAGDEF( 81B, EAX, AMD, 6, 1, OPCOUNT_EXT, NA, FALSE) \ FLAGDEF( 81B, EAX, AMD, 7, 1, RIP_INVALID_CHECK, NA, FALSE) \ FLAGDEF( 81C, EAX, AMD, 0, 1, LWP_AVAIL, NA, FALSE) \ FLAGDEF( 81C, EAX, AMD, 1, 1, LWP_VAL_AVAIL, NA, FALSE) \ FLAGDEF( 81C, EAX, AMD, 2, 1, LWP_IRE_AVAIL, NA, FALSE) \ FLAGDEF( 81C, EAX, AMD, 3, 1, LWP_BRE_AVAIL, NA, FALSE) \ FLAGDEF( 81C, EAX, AMD, 4, 1, LWP_DME_AVAIL, NA, FALSE) \ FLAGDEF( 81C, EAX, AMD, 5, 1, LWP_CNH_AVAIL, NA, FALSE) \ FLAGDEF( 81C, EAX, AMD, 6, 1, LWP_RNH_AVAIL, NA, FALSE) \ FLAGDEF( 81C, EAX, AMD, 31, 1, LWP_INT_AVAIL, NA, FALSE) \ FIELDDEF(81C, EBX, AMD, 0, 8, LWP_CB_SIZE, NA, FALSE) \ FIELDDEF(81C, EBX, AMD, 8, 8, LWP_EVENT_SIZE, NA, FALSE) \ FIELDDEF(81C, EBX, AMD, 16, 8, LWP_MAX_EVENTS, NA, FALSE) \ FIELDDEF(81C, EBX, AMD, 24, 8, LWP_EVENT_OFFSET, NA, FALSE) \ FIELDDEF(81C, ECX, AMD, 0, 4, LWP_LATENCY_MAX, NA, FALSE) \ FLAGDEF( 81C, ECX, AMD, 5, 1, LWP_DATA_ADDR_VALID, NA, FALSE) \ FIELDDEF(81C, ECX, AMD, 6, 3, LWP_LATENCY_ROUND, NA, FALSE) \ FIELDDEF(81C, ECX, AMD, 9, 7, LWP_VERSION, NA, FALSE) \ FIELDDEF(81C, ECX, AMD, 16, 8, LWP_MIN_BUF_SIZE, NA, FALSE) \ FLAGDEF( 81C, ECX, AMD, 28, 1, LWP_BRANCH_PRED, NA, FALSE) \ FLAGDEF( 81C, ECX, AMD, 29, 1, LWP_IP_FILTERING, NA, FALSE) \ FLAGDEF( 81C, ECX, AMD, 30, 1, LWP_CACHE_LEVEL, NA, FALSE) \ FLAGDEF( 81C, ECX, AMD, 31, 1, LWP_CACHE_LATENCY, NA, FALSE) \ FLAGDEF( 81C, EDX, AMD, 0, 1, LWP_SUPPORTED, NA, FALSE) \ FLAGDEF( 81C, EDX, AMD, 1, 1, LWP_VAL_SUPPORTED, NA, FALSE) \ FLAGDEF( 81C, EDX, AMD, 2, 1, LWP_IRE_SUPPORTED, NA, FALSE) \ FLAGDEF( 81C, EDX, AMD, 3, 1, LWP_BRE_SUPPORTED, NA, FALSE) \ FLAGDEF( 81C, EDX, AMD, 4, 1, LWP_DME_SUPPORTED, NA, FALSE) \ FLAGDEF( 81C, EDX, AMD, 5, 1, LWP_CNH_SUPPORTED, NA, FALSE) \ FLAGDEF( 81C, EDX, AMD, 6, 1, LWP_RNH_SUPPORTED, NA, FALSE) \ FLAGDEF( 81C, EDX, AMD, 31, 1, LWP_INT_SUPPORTED, NA, FALSE) \ FIELDDEFA( 81D,EAX, AMD, 0, 5, CACHE_TYPE, NA, FALSE, AMD_CACHE_TYPE) \ FIELDDEFA( 81D,EAX, AMD, 5, 3, CACHE_LEVEL, NA, FALSE, AMD_CACHE_LEVEL) \ FLAGDEF( 81D, EAX, AMD, 8, 1, CACHE_SELF_INIT, NA, FALSE) \ FLAGDEF( 81D, EAX, AMD, 9, 1, CACHE_FULLY_ASSOC, NA, FALSE) \ FIELDDEFA(81D, EAX, AMD, 14, 12, NUM_SHARING_CACHE, NA, FALSE, AMD_NUM_SHARING_CACHE) \ FIELDDEF(81D, EBX, AMD, 0, 12, CACHE_LINE_SIZE, NA, FALSE) \ FIELDDEF(81D, EBX, AMD, 12, 10, CACHE_PHYS_PARTITIONS, NA, FALSE) \ FIELDDEFA(81D,EBX, AMD, 22, 10, CACHE_WAYS, NA, FALSE, AMD_CACHE_WAYS) \ FIELDDEF(81D, ECX, AMD, 0, 32, CACHE_NUM_SETS, NA, FALSE) \ FLAGDEF( 81D, EDX, AMD, 0, 1, CACHE_WBINVD, NA, FALSE) \ FLAGDEF( 81D, EDX, AMD, 1, 1, CACHE_INCLUSIVE, NA, FALSE) \ FIELDDEF(81E, EAX, AMD, 0, 32, EXTENDED_APICID, NA, FALSE) \ FIELDDEF(81E, EBX, AMD, 0, 8, COMPUTE_UNIT_ID, NA, FALSE) \ FIELDDEFA(81E, EBX, AMD, 8, 2, CORES_PER_COMPUTE_UNIT, NA, FALSE, AMD_CORES_PER_COMPUTE_UNIT) \ FIELDDEF(81E, ECX, AMD, 0, 8, NODEID, NA, FALSE) \ FIELDDEFA( 81E,ECX, AMD, 8, 3, NODES_PER_PKG, NA, FALSE, AMD_NODES_PER_PKG) #define INTEL_CPUID_FIELD_DATA #define AMD_CPUID_FIELD_DATA #define CPUID_FIELD_DATA \ CPUID_FIELD_DATA_LEVEL_0 \ CPUID_FIELD_DATA_LEVEL_1 \ CPUID_FIELD_DATA_LEVEL_4 \ CPUID_FIELD_DATA_LEVEL_5 \ CPUID_FIELD_DATA_LEVEL_6 \ CPUID_FIELD_DATA_LEVEL_7 \ CPUID_FIELD_DATA_LEVEL_A \ CPUID_FIELD_DATA_LEVEL_B \ CPUID_FIELD_DATA_LEVEL_D \ CPUID_FIELD_DATA_LEVEL_400 \ CPUID_FIELD_DATA_LEVEL_410 \ CPUID_FIELD_DATA_LEVEL_80 \ CPUID_FIELD_DATA_LEVEL_81 \ CPUID_FIELD_DATA_LEVEL_8x \ CPUID_FIELD_DATA_LEVEL_81x \ INTEL_CPUID_FIELD_DATA \ AMD_CPUID_FIELD_DATA /* * Define all field and flag values as an enum. The result is a full * set of values taken from the table above in the form: * * CPUID_FEATURE_<vendor>_ID<level><reg>_<name> == mask for feature * CPUID_<vendor>_ID<level><reg>_<name>_MASK == mask for field * CPUID_<vendor>_ID<level><reg>_<name>_SHIFT == offset of field * * e.g. - CPUID_FEATURE_COMMON_ID1EDX_FPU = 0x1 * - CPUID_COMMON_ID88EAX_VIRTBITS_MASK = 0xff00 * - CPUID_COMMON_ID88EAX_VIRTBITS_SHIFT = 8 * * Note: The FEATURE/MASK definitions must use some gymnastics to get * around a warning when shifting left by 32. */ #define VMW_BIT_MASK(shift) (((1 << (shift - 1)) << 1) - 1) #define FIELDDEF(lvl, reg, vend, bitpos, size, name, s, c3) \ CPUID_##vend##_ID##lvl##reg##_##name##_SHIFT = bitpos, \ CPUID_##vend##_ID##lvl##reg##_##name##_MASK = \ VMW_BIT_MASK(size) << bitpos, \ CPUID_FEATURE_##vend##_ID##lvl##reg##_##name = \ CPUID_##vend##_ID##lvl##reg##_##name##_MASK, /* Before simplifying this take a look at bug 293638... */ #define FIELDDEFA(lvl, reg, vend, bitpos, size, name, s, c3, f) \ CPUID_##vend##_ID##lvl##reg##_##name##_SHIFT = bitpos, \ CPUID_##vend##_ID##lvl##reg##_##name##_MASK = \ VMW_BIT_MASK(size) << bitpos, \ CPUID_FEATURE_##vend##_ID##lvl##reg##_##name = \ CPUID_##vend##_ID##lvl##reg##_##name##_MASK, #define FLAGDEFA FIELDDEFA #define FLAGDEF FIELDDEF enum { /* Define data for every CPUID field we have */ CPUID_FIELD_DATA }; #undef VMW_BIT_MASK #undef FIELDDEF #undef FLAGDEF #undef FIELDDEFA #undef FLAGDEFA /* Level D subleaf 1 eax XSAVEOPT */ #define CPUID_COMMON_IDDsub1EAX_XSAVEOPT 1 /* * Legal CPUID config file mask characters. For a description of the * cpuid masking system, please see: * * http://vmweb.vmware.com/~mts/cgi-bin/view.cgi/Apps/CpuMigrationChecks */ #define CPUID_MASK_HIDE_CHR '0' #define CPUID_MASK_HIDE_STR "0" #define CPUID_MASK_FORCE_CHR '1' #define CPUID_MASK_FORCE_STR "1" #define CPUID_MASK_PASS_CHR '-' #define CPUID_MASK_PASS_STR "-" #define CPUID_MASK_TRUE_CHR 'T' #define CPUID_MASK_TRUE_STR "T" #define CPUID_MASK_FALSE_CHR 'F' #define CPUID_MASK_FALSE_STR "F" #define CPUID_MASK_IGNORE_CHR 'X' #define CPUID_MASK_IGNORE_STR "X" #define CPUID_MASK_HOST_CHR 'H' #define CPUID_MASK_HOST_STR "H" #define CPUID_MASK_RSVD_CHR 'R' #define CPUID_MASK_RSVD_STR "R" #define CPUID_MASK_INSTALL_CHR 'I' #define CPUID_MASK_INSTALL_STR "I" /* * When LM is disabled, we overlay the following masks onto the * guest's default masks. Any level that is not defined below should * be treated as all "-"s */ #define CPT_ID1ECX_LM_DISABLED "----:----:----:----:--0-:----:----:----" #define CPT_ID81EDX_LM_DISABLED "--0-:----:----:----:----:----:----:----" #define CPT_ID81ECX_LM_DISABLED "----:----:----:----:----:----:----:---0" #define CPT_GET_LM_DISABLED_MASK(lvl, reg) \ ((lvl == 1 && reg == CPUID_REG_ECX) ? CPT_ID1ECX_LM_DISABLED : \ (lvl == 0x80000001 && reg == CPUID_REG_ECX) ? CPT_ID81ECX_LM_DISABLED : \ (lvl == 0x80000001 && reg == CPUID_REG_EDX) ? CPT_ID81EDX_LM_DISABLED : \ NULL) /* * Macro to define GET and SET functions for various common CPUID * fields. To create function for a new field, simply name it (CPUID_ * and CPUID_SET_ are automatically prepended), and list the field * name that it needs to use. */ #define FIELD_FUNC(name, field) \ static INLINE uint32 CPUID_##name(uint32 reg) \ { \ return (reg & field##_MASK) >> field##_SHIFT; \ } \ static INLINE void CPUID_SET_##name(uint32 *reg, uint32 val) \ { \ *reg = (*reg & ~field##_MASK) | (val << field##_SHIFT); \ } FIELD_FUNC(STEPPING, CPUID_COMMON_ID1EAX_STEPPING) FIELD_FUNC(MODEL, CPUID_COMMON_ID1EAX_MODEL) FIELD_FUNC(FAMILY, CPUID_COMMON_ID1EAX_FAMILY) FIELD_FUNC(TYPE, CPUID_COMMON_ID1EAX_TYPE) FIELD_FUNC(EXTENDED_MODEL, CPUID_COMMON_ID1EAX_EXTMODEL) FIELD_FUNC(EXTENDED_FAMILY, CPUID_COMMON_ID1EAX_EXTFAMILY) FIELD_FUNC(LCPU_COUNT, CPUID_COMMON_ID1EBX_LCPU_COUNT) FIELD_FUNC(APICID, CPUID_COMMON_ID1EBX_APICID) FIELD_FUNC(PA_BITS, CPUID_COMMON_ID88EAX_PHYSBITS) FIELD_FUNC(VIRT_BITS, CPUID_COMMON_ID88EAX_VIRTBITS) FIELD_FUNC(SVM_REVISION, CPUID_AMD_ID8AEAX_SVM_REVISION) FIELD_FUNC(SVM_N_ASIDS, CPUID_AMD_ID8AEBX_SVM_N_ASIDS) FIELD_FUNC(CACHE_TYPE, CPUID_INTEL_ID4EAX_CACHE_TYPE) FIELD_FUNC(INTEL_CORE_COUNT, CPUID_INTEL_ID4EAX_CORE_COUNT) FIELD_FUNC(AMD_CORE_COUNT, CPUID_AMD_ID88ECX_CORE_COUNT) FIELD_FUNC(AMD_APICID_COREID_SIZE, CPUID_AMD_ID88ECX_APICID_COREID_SIZE) FIELD_FUNC(AMD_EXTAPICSPC, CPUID_AMD_ID81ECX_EXTAPICSPC) FIELD_FUNC(NUM_PMCS, CPUID_INTEL_IDAEAX_NUM_PMCS) FIELD_FUNC(MWAIT_MIN_SIZE, CPUID_COMMON_ID5EAX_MWAIT_MIN_SIZE) FIELD_FUNC(MWAIT_MAX_SIZE, CPUID_COMMON_ID5EBX_MWAIT_MAX_SIZE) FIELD_FUNC(MWAIT_C0_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C0_SUBSTATE) FIELD_FUNC(MWAIT_C1_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C1_SUBSTATE) FIELD_FUNC(MWAIT_C2_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C2_SUBSTATE) FIELD_FUNC(MWAIT_C3_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C3_SUBSTATE) FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE) FIELD_FUNC(TOPOLOGY_MASK_WIDTH, CPUID_INTEL_IDBEAX_MASK_WIDTH) FIELD_FUNC(TOPOLOGY_CPUS_SHARING_LEVEL, CPUID_INTEL_IDBEBX_CPUS_SHARING_LEVEL) FIELD_FUNC(TOPOLOGY_LEVEL_NUMBER, CPUID_INTEL_IDBECX_LEVEL_NUMBER) FIELD_FUNC(TOPOLOGY_LEVEL_TYPE, CPUID_INTEL_IDBECX_LEVEL_TYPE) FIELD_FUNC(TOPOLOGY_X2APIC_ID, CPUID_INTEL_IDBEDX_X2APIC_ID) FIELD_FUNC(AMD_CACHE_TYPE, CPUID_AMD_ID81DEAX_CACHE_TYPE) FIELD_FUNC(AMD_CACHE_LEVEL, CPUID_AMD_ID81DEAX_CACHE_LEVEL) FIELD_FUNC(AMD_CACHE_WAYS, CPUID_AMD_ID81DEBX_CACHE_WAYS) FIELD_FUNC(AMD_NODES_PER_PKG, CPUID_AMD_ID81EECX_NODES_PER_PKG) FIELD_FUNC(AMD_NUM_SHARING_CACHE, CPUID_AMD_ID81DEAX_NUM_SHARING_CACHE) FIELD_FUNC(AMD_CORES_PER_COMPUTE_UNIT, CPUID_AMD_ID81EEBX_CORES_PER_COMPUTE_UNIT) #undef FIELD_FUNC /* * Definitions of various fields' values and more complicated * macros/functions for reading cpuid fields. */ #define CPUID_FAMILY_EXTENDED 15 /* Effective Intel CPU Families */ #define CPUID_FAMILY_486 4 #define CPUID_FAMILY_P5 5 #define CPUID_FAMILY_P6 6 #define CPUID_FAMILY_P4 15 /* Effective AMD CPU Families */ #define CPUID_FAMILY_5x86 4 #define CPUID_FAMILY_K5 5 #define CPUID_FAMILY_K6 5 #define CPUID_FAMILY_K7 6 #define CPUID_FAMILY_K8 15 #define CPUID_FAMILY_K8L 16 #define CPUID_FAMILY_K8MOBILE 17 #define CPUID_FAMILY_LLANO 18 #define CPUID_FAMILY_BOBCAT 20 #define CPUID_FAMILY_BULLDOZER 21 /* Effective VIA CPU Families */ #define CPUID_FAMILY_C7 6 /* Intel model information */ #define CPUID_MODEL_PPRO 1 #define CPUID_MODEL_PII_03 3 #define CPUID_MODEL_PII_05 5 #define CPUID_MODEL_CELERON_06 6 #define CPUID_MODEL_PM_09 9 #define CPUID_MODEL_PM_0D 13 #define CPUID_MODEL_PM_0E 14 // Yonah / Sossaman #define CPUID_MODEL_CORE_0F 15 // Conroe / Merom #define CPUID_MODEL_CORE_17 0x17 // Penryn #define CPUID_MODEL_NEHALEM_1A 0x1a // Nehalem / Gainestown #define CPUID_MODEL_ATOM_1C 0x1c // Silverthorne / Diamondville #define CPUID_MODEL_CORE_1D 0x1d // Dunnington #define CPUID_MODEL_NEHALEM_1E 0x1e // Lynnfield #define CPUID_MODEL_NEHALEM_1F 0x1f // Havendale #define CPUID_MODEL_NEHALEM_25 0x25 // Westmere / Clarkdale #define CPUID_MODEL_SANDYBRIDGE_2A 0x2a // Sandybridge (desktop/mobile) #define CPUID_MODEL_SANDYBRIDGE_2D 0x2d // Sandybridge-EP #define CPUID_MODEL_NEHALEM_2C 0x2c // Westmere-EP #define CPUID_MODEL_NEHALEM_2E 0x2e // Nehalem-EX #define CPUID_MODEL_NEHALEM_2F 0x2f // Westmere-EX #define CPUID_MODEL_PIII_07 7 #define CPUID_MODEL_PIII_08 8 #define CPUID_MODEL_PIII_0A 10 /* AMD model information */ #define CPUID_MODEL_BARCELONA_02 0x02 // Barcelona (both Opteron & Phenom kind) /* VIA model information */ #define CPUID_MODEL_NANO 15 // Isaiah /* *---------------------------------------------------------------------- * * CPUID_IsVendor{AMD,Intel,VIA} -- * * Determines if the vendor string in cpuid id0 is from {AMD,Intel,VIA}. * * Results: * True iff vendor string is CPUID_{AMD,INTEL,VIA}_VENDOR_STRING * * Side effects: * None. * *---------------------------------------------------------------------- */ static INLINE Bool CPUID_IsRawVendor(CPUIDRegs *id0, const char* vendor) { // hard to get strcmp() in some environments, so do it in the raw return (id0->ebx == *(const uint32 *) (vendor + 0) && id0->ecx == *(const uint32 *) (vendor + 4) && id0->edx == *(const uint32 *) (vendor + 8)); } static INLINE Bool CPUID_IsVendorAMD(CPUIDRegs *id0) { return CPUID_IsRawVendor(id0, CPUID_AMD_VENDOR_STRING); } static INLINE Bool CPUID_IsVendorIntel(CPUIDRegs *id0) { return CPUID_IsRawVendor(id0, CPUID_INTEL_VENDOR_STRING); } static INLINE Bool CPUID_IsVendorVIA(CPUIDRegs *id0) { return CPUID_IsRawVendor(id0, CPUID_VIA_VENDOR_STRING); } static INLINE uint32 CPUID_EFFECTIVE_FAMILY(uint32 v) /* %eax from CPUID with %eax=1. */ { return CPUID_FAMILY(v) + (CPUID_FAMILY(v) == CPUID_FAMILY_EXTENDED ? CPUID_EXTENDED_FAMILY(v) : 0); } /* Normally only used when FAMILY==CPUID_FAMILY_EXTENDED, but Intel is * now using the extended model field for FAMILY==CPUID_FAMILY_P6 to * refer to the newer Core2 CPUs */ static INLINE uint32 CPUID_EFFECTIVE_MODEL(uint32 v) /* %eax from CPUID with %eax=1. */ { return CPUID_MODEL(v) + (CPUID_EXTENDED_MODEL(v) << 4); } /* * Notice that CPUID families for Intel and AMD overlap. The following macros * should only be used AFTER the manufacturer has been established (through * the use of CPUID standard function 0). */ static INLINE Bool CPUID_FAMILY_IS_486(uint32 eax) { return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_486; } static INLINE Bool CPUID_FAMILY_IS_P5(uint32 eax) { return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_P5; } static INLINE Bool CPUID_FAMILY_IS_P6(uint32 eax) { return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_P6; } static INLINE Bool CPUID_FAMILY_IS_PENTIUM4(uint32 eax) { return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_P4; } /* * Intel Pentium M processors are Yonah/Sossaman or an older P-M */ static INLINE Bool CPUID_UARCH_IS_PENTIUM_M(uint32 v) // IN: %eax from CPUID with %eax=1. { /* Assumes the CPU manufacturer is Intel. */ return CPUID_FAMILY_IS_P6(v) && (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_09 || CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_0D || CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_0E); } /* * Intel Core processors are Merom, Conroe, Woodcrest, Clovertown, * Penryn, Dunnington, Kentsfield, Yorktown, Harpertown, ........ */ static INLINE Bool CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1. { uint32 model = CPUID_EFFECTIVE_MODEL(v); /* Assumes the CPU manufacturer is Intel. */ return CPUID_FAMILY_IS_P6(v) && model >= CPUID_MODEL_CORE_0F && (model < CPUID_MODEL_NEHALEM_1A || model == CPUID_MODEL_CORE_1D); } /* * Intel Nehalem processors are: Nehalem, Gainestown, Lynnfield, Clarkdale. */ static INLINE Bool CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1. { /* Assumes the CPU manufacturer is Intel. */ uint32 effectiveModel = CPUID_EFFECTIVE_MODEL(v); return CPUID_FAMILY_IS_P6(v) && (effectiveModel == CPUID_MODEL_NEHALEM_1A || effectiveModel == CPUID_MODEL_NEHALEM_1E || effectiveModel == CPUID_MODEL_NEHALEM_1F || effectiveModel == CPUID_MODEL_NEHALEM_25 || effectiveModel == CPUID_MODEL_NEHALEM_2C || effectiveModel == CPUID_MODEL_NEHALEM_2E || effectiveModel == CPUID_MODEL_NEHALEM_2F); } static INLINE Bool CPUID_UARCH_IS_SANDYBRIDGE(uint32 v) // IN: %eax from CPUID with %eax=1. { /* Assumes the CPU manufacturer is Intel. */ uint32 effectiveModel = CPUID_EFFECTIVE_MODEL(v); return CPUID_FAMILY_IS_P6(v) && (effectiveModel == CPUID_MODEL_SANDYBRIDGE_2A || effectiveModel == CPUID_MODEL_SANDYBRIDGE_2D); } static INLINE Bool CPUID_FAMILY_IS_K7(uint32 eax) { return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_K7; } static INLINE Bool CPUID_FAMILY_IS_K8(uint32 eax) { return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_K8; } static INLINE Bool CPUID_FAMILY_IS_K8EXT(uint32 eax) { /* * We check for this pattern often enough that it's * worth a separate function, for syntactic sugar. */ return CPUID_FAMILY_IS_K8(eax) && CPUID_EXTENDED_MODEL(eax) != 0; } static INLINE Bool CPUID_FAMILY_IS_K8L(uint32 eax) { return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_K8L || CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_LLANO; } static INLINE Bool CPUID_FAMILY_IS_K8MOBILE(uint32 eax) { /* Essentially a K8 (not K8L) part, but with mobile features. */ return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_K8MOBILE; } static INLINE Bool CPUID_FAMILY_IS_K8STAR(uint32 eax) { /* * Read function name as "K8*", as in wildcard. * Matches K8 or K8L or K8MOBILE */ return CPUID_FAMILY_IS_K8(eax) || CPUID_FAMILY_IS_K8L(eax) || CPUID_FAMILY_IS_K8MOBILE(eax); } static INLINE Bool CPUID_FAMILY_IS_BOBCAT(uint32 eax) { return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_BOBCAT; } static INLINE Bool CPUID_FAMILY_IS_BULLDOZER(uint32 eax) { return CPUID_EFFECTIVE_FAMILY(eax) == CPUID_FAMILY_BULLDOZER; } /* * AMD Barcelona (of either Opteron or Phenom kind). */ static INLINE Bool CPUID_MODEL_IS_BARCELONA(uint32 v) // IN: %eax from CPUID with %eax=1. { /* Assumes the CPU manufacturer is AMD. */ return CPUID_EFFECTIVE_FAMILY(v) == CPUID_FAMILY_K8L && CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_BARCELONA_02; } #define CPUID_TYPE_PRIMARY 0 #define CPUID_TYPE_OVERDRIVE 1 #define CPUID_TYPE_SECONDARY 2 #define CPUID_INTEL_ID4EAX_CACHE_TYPE_NULL 0 #define CPUID_INTEL_ID4EAX_CACHE_TYPE_DATA 1 #define CPUID_INTEL_ID4EAX_CACHE_TYPE_INST 2 #define CPUID_INTEL_ID4EAX_CACHE_TYPE_UNIF 3 #define CPUID_INTEL_ID4EAX_CACHE_SELF_INIT 0x00000100 #define CPUID_INTEL_ID4EAX_CACHE_FULLY_ASSOC 0x00000200 #define CPUID_INTEL_IDBECX_LEVEL_TYPE_INVALID 0 #define CPUID_INTEL_IDBECX_LEVEL_TYPE_SMT 1 #define CPUID_INTEL_IDBECX_LEVEL_TYPE_CORE 2 /* * For certain AMD processors, an lfence instruction is necessary at various * places to ensure ordering. */ static INLINE Bool CPUID_VendorRequiresFence(CpuidVendor vendor) { return vendor == CPUID_VENDOR_AMD; } static INLINE Bool CPUID_VersionRequiresFence(uint32 version) { return CPUID_EFFECTIVE_FAMILY(version) == CPUID_FAMILY_K8 && CPUID_EFFECTIVE_MODEL(version) < 0x40; } static INLINE Bool CPUID_ID0RequiresFence(CPUIDRegs *id0) { if (id0->eax == 0) { return FALSE; } return CPUID_IsVendorAMD(id0); } static INLINE Bool CPUID_ID1RequiresFence(CPUIDRegs *id1) { return CPUID_VersionRequiresFence(id1->eax); } static INLINE Bool CPUID_RequiresFence(CpuidVendor vendor, // IN uint32 version) // IN: %eax from CPUID with %eax=1. { return CPUID_VendorRequiresFence(vendor) && CPUID_VersionRequiresFence(version); } /* * The following low-level functions compute the number of * cores per cpu. They should be used cautiously because * they do not necessarily work on all types of CPUs. * High-level functions that are correct for all CPUs are * available elsewhere: see lib/cpuidInfo/cpuidInfo.c. */ static INLINE uint32 CPUID_IntelCoresPerPackage(uint32 v) /* %eax from CPUID with %eax=4 and %ecx=0. */ { // Note: This is not guaranteed to work on older Intel CPUs. return 1 + CPUID_INTEL_CORE_COUNT(v); } static INLINE uint32 CPUID_AMDCoresPerPackage(uint32 v) /* %ecx from CPUID with %eax=0x80000008. */ { // Note: This is not guaranteed to work on older AMD CPUs. return 1 + CPUID_AMD_CORE_COUNT(v); } /* * Hypervisor CPUID space is 0x400000XX. */ static INLINE Bool CPUID_IsHypervisorLevel(uint32 level) { return (level & 0xffffff00) == 0x40000000; } #endif vmci-only/shared/autoconf/ 0000755 0000000 0000000 00000000000 11573422251 014557 5 ustar root root vmci-only/shared/autoconf/netif_num_params.c 0000444 0000000 0000000 00000003352 11573420431 020251 0 ustar root root /********************************************************* * Copyright (C) 2009 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ /* * Detect whether netif_rx_complete (and netif_rx_schedule) take a single * napi_struct argument. The foundation was laid whith introducing Generic * Receive Offload infrastructure but dropping unneeded net_device argument * did not happen till few commits later so we can't simply test for presence * of NETIF_F_GRO. * * Test succeeds if netif_rx_complete takes dev & napi arguments, or if it * takes dev argument only (kernels before 2.6.24). Test fails if netif_rx_complete * takes only single napi argument. */ #include "compat_version.h" #include "compat_autoconf.h" #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) # error This compile test intentionally fails. #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) #include <linux/netdevice.h> #ifdef NETIF_F_GRO void test_netif_rx_complete(struct net_device *dev, struct napi_struct *napi) { netif_rx_complete(dev, napi); } #endif #endif vmci-only/shared/autoconf/cachector.c 0000444 0000000 0000000 00000003270 11573420431 016654 0 ustar root root /********************************************************* * 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 * *********************************************************/ #include "compat_version.h" #include "compat_autoconf.h" /* * Between 2.6.23 and 2.6.24-rc1 ctor prototype was changed from * ctor(ptr, cache, flags) to ctor(cache, ptr). Unfortunately there * is no typedef for ctor, so we have to redefine kmem_cache_create * to find out ctor prototype. This assumes that kmem_cache_create * takes 5 arguments and not 6 - that change occured between * 2.6.22 and 2.6.23-rc1. If prototype matches, then this is old * kernel. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) #error "This test intentionally fails on 2.6.24 and newer kernels." #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) #include <linux/slab.h> struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, unsigned long, void (*)(void *, struct kmem_cache *, unsigned long)); #endif vmci-only/shared/autoconf/skas1.c 0000444 0000000 0000000 00000002353 11573420431 015744 0 ustar root root /********************************************************* * Copyright (C) 2004 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU 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 * *********************************************************/ /* * SKAS patch adds 'struct mm *mm' as first argument to do_mmap_pgoff. * This patch never hit mainstream kernel. */ #include <linux/mm.h> unsigned long check_do_mmap_pgoff(struct mm_struct *mm, struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flag, unsigned long pgoff) { return do_mmap_pgoff(mm, file, addr, len, prot, flag, pgoff); } vmci-only/shared/autoconf/cachecreate.c 0000444 0000000 0000000 00000003210 11573420431 017142 0 ustar root root /********************************************************* * 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 * *********************************************************/ #include "compat_version.h" #include "compat_autoconf.h" /* * All kernels before 2.6.22 take 6 arguments. All kernels since * 2.6.23-rc1 take 5 arguments. Only kernels between 2.6.22 and * 2.6.23-rc1 are questionable - we could ignore them if we wanted, * nobody cares about them even now. But unfortunately RedHat is * re-releasing 2.6.X-rc kernels under 2.6.(X-1) name, so they * are releasing 2.6.23-rc1 as 2.6.22-5055-something, so we have * to do autodetection for them. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) /* Success... */ #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) #error "This test intentionally fails on 2.6.23 and newer kernels." #else #include <linux/slab.h> struct kmem_cache *kmemtest(void) { return kmem_cache_create("test", 12, 0, 0, NULL, NULL); } #endif vmci-only/shared/autoconf/inode1.c 0000444 0000000 0000000 00000002703 11573420431 016100 0 ustar root root /********************************************************* * 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 * *********************************************************/ #include "compat_version.h" #include "compat_autoconf.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) #include <linux/fs.h> #include <linux/stddef.h> /* NULL */ /* * After 2.6.18, inodes were "slimmed". This involved removing the union * that encapsulates inode private data (and using i_private instead), as well * as removing i_blksize. Red Hat backported this behavior into a 2.6.17 * kernel. * * This test will fail on a kernel with such a patch. */ void test(void) { struct inode inode; inode.u.generic_ip = NULL; } #else #error "This test intentionally fails on 2.6.20 and newer kernels." #endif vmci-only/shared/autoconf/geninclude.c 0000444 0000000 0000000 00000002321 11573420431 017032 0 ustar root root /********************************************************* * Copyright (C) 2003 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #include "compat_version.h" #include "compat_autoconf.h" #ifdef CONFIG_X86_VOYAGER APATH/mach-voyager #endif #ifdef CONFIG_X86_VISWS APATH/mach-visws #endif #ifdef CONFIG_X86_NUMAQ APATH/mach-numaq #endif #ifdef CONFIG_X86_BIGSMP APATH/mach-bigsmp #endif #ifdef CONFIG_X86_SUMMIT APATH/mach-summit #endif #ifdef CONFIG_X86_GENERICARCH APATH/mach-generic #endif APATH/mach-default vmci-only/shared/autoconf/netcreate_num_params.c 0000444 0000000 0000000 00000003160 11573420431 021113 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * During 2.6.33 merge window net_proto_ops->create() method was changed - * a new 'kern' field, signalling whether socket is being created by kernel * or userspace application, was added to it. Unfortunately, some * distributions, such as RHEL 6, have backported the change to earlier * kernels, so we can't rely solely on kernel version to determine number of * arguments. */ #include "compat_version.h" #include "compat_autoconf.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) # error This compile test intentionally fails. #else #include <linux/net.h> static int TestCreate(struct net *net, struct socket *sock, int protocol, int kern) { return 0; } struct net_proto_family testFamily = { .create = TestCreate, }; #endif vmci-only/shared/autoconf/getsb1.c 0000444 0000000 0000000 00000003076 11573420431 016112 0 ustar root root /********************************************************* * 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 * *********************************************************/ #include "compat_version.h" #include "compat_autoconf.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) #include <linux/fs.h> /* * Around 2.6.18, a pointer to a vfsmount was added to get_sb. Red Hat * backported this behavior into a 2.6.17 kernel. * * This test will fail on a kernel with such a patch. */ static struct super_block * LinuxDriverGetSb(struct file_system_type *fs_type, int flags, const char *dev_name, void *rawData) { return 0; } struct file_system_type fs_type = { .get_sb = LinuxDriverGetSb }; #else #error "This test intentionally fails on 2.6.19 or newer kernels." #endif vmci-only/shared/autoconf/filldir1.c 0000444 0000000 0000000 00000003260 11573420431 016426 0 ustar root root /********************************************************* * 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 * *********************************************************/ #include "compat_version.h" #include "compat_autoconf.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) #include <linux/fs.h> #include <linux/types.h> /* loff_t */ #include <linux/stddef.h> /* NULL */ /* * After 2.6.18, filldir and statfs were changed to send 64-bit inode * numbers to user space. Red Hat backported this behavior into a 2.6.17 * kernel. * * This test will fail on a kernel with such a patch. */ static int LinuxDriverFilldir(void *buf, const char *name, int namelen, loff_t offset, ino_t ino, unsigned int d_type) { return 0; } void test(void) { vfs_readdir(NULL, LinuxDriverFilldir, NULL); } #else #error "This test intentionally fails on 2.6.20 and newer kernels." #endif vmci-only/shared/autoconf/statfs1.c 0000444 0000000 0000000 00000002671 11573420431 016312 0 ustar root root /********************************************************* * 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 * *********************************************************/ #include "compat_version.h" #include "compat_autoconf.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) #include <linux/fs.h> /* * Around 2.6.18, the super_block pointer in statfs was changed to a dentry * pointer. Red Hat backported this behavior into a 2.6.17 kernel. * * This test will fail on a kernel with such a patch. */ static int LinuxDriverStatFs(struct super_block *sb, struct kstatfs *stat) { return 0; } struct super_operations super_ops = { .statfs = LinuxDriverStatFs }; #else #error "This test intentionally fails on 2.6.19 and newer kernels." #endif vmci-only/shared/autoconf/skblin.c 0000444 0000000 0000000 00000002572 11573420431 016207 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * Detect whether skb_linearize takes one or two arguments. */ #include "compat_version.h" #include "compat_autoconf.h" #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17) /* * Since 2.6.18 all kernels have single-argument skb_linearize. For * older kernels use autodetection. Not using autodetection on newer * kernels saves us from compile failure on some post 2.6.18 kernels * which do not have selfcontained skbuff.h. */ #include <linux/skbuff.h> int test_skb_linearize(struct sk_buff *skb) { return skb_linearize(skb); } #endif vmci-only/shared/autoconf/cachector1.c 0000444 0000000 0000000 00000003075 11573420431 016740 0 ustar root root /********************************************************* * Copyright (C) 2008 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #include "compat_version.h" #include "compat_autoconf.h" /* * Between 2.6.27-rc1 and 2.6.27-rc2 ctor prototype was changed from * ctor(cache, ptr) to ctor(ptr). Unfortunately there * is no typedef for ctor, so we have to redefine kmem_cache_create * to find out ctor prototype. If prototype matches, then this is old * kernel. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) #error "This test intentionally fails on 2.6.28 and newer kernels." #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) #include <linux/slab.h> struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, unsigned long, void (*)(struct kmem_cache *, void *)); #endif vmci-only/shared/vm_basic_asm_x86.h 0000444 0000000 0000000 00000042706 11573420432 016250 0 ustar root root /********************************************************* * Copyright (C) 1998-2003 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ /* * vm_basic_asm_x86.h * * Basic IA32 asm macros */ #ifndef _VM_BASIC_ASM_X86_H_ #define _VM_BASIC_ASM_X86_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMIROM #include "includeCheck.h" #ifdef VM_X86_64 /* * The gcc inline asm uses the "A" constraint which differs in 32 & 64 * bit mode. 32 bit means eax and edx, 64 means rax or rdx. */ #error "x86-64 not supported" #endif /* * FXSAVE/FXRSTOR * save/restore SIMD/MMX fpu state * * The pointer passed in must be 16-byte aligned. * * Intel and AMD processors behave differently w.r.t. fxsave/fxrstor. Intel * processors unconditionally save the exception pointer state (instruction * ptr., data ptr., and error instruction opcode). FXSAVE_ES1 and FXRSTOR_ES1 * work correctly for Intel processors. * * AMD processors only save the exception pointer state if ES=1. This leads to a * security hole whereby one process/VM can inspect the state of another process * VM. The AMD recommended workaround involves clobbering the exception pointer * state unconditionally, and this is implemented in FXRSTOR_AMD_ES0. Note that * FXSAVE_ES1 will only save the exception pointer state for AMD processors if * ES=1. * * The workaround (FXRSTOR_AMD_ES0) only costs 1 cycle more than just doing an * fxrstor, on both AMD Opteron and Intel Core CPUs. */ #if defined(__GNUC__) static INLINE void FXSAVE_ES1(uint8 *save) { __asm__ __volatile__ ("fxsave %0\n" : "=m" (*save) : : "memory"); } static INLINE void FXRSTOR_ES1(const uint8 *load) { __asm__ __volatile__ ("fxrstor %0\n" : : "m" (*load) : "memory"); } static INLINE void FXRSTOR_AMD_ES0(const uint8 *load) { uint64 dummy = 0; __asm__ __volatile__ ("fnstsw %%ax \n" // Grab x87 ES bit "bt $7,%%ax \n" // Test ES bit "jnc 1f \n" // Jump if ES=0 "fnclex \n" // ES=1. Clear it so fild doesn't trap "1: \n" "ffree %%st(7) \n" // Clear tag bit - avoid poss. stack overflow "fildl %0 \n" // Dummy Load from "safe address" changes all // x87 exception pointers. "fxrstor %1 \n" : : "m" (dummy), "m" (*load) : "ax", "memory"); } #endif /* __GNUC__ */ /* * XSAVE/XRSTOR * save/restore GSSE/SIMD/MMX fpu state * * The pointer passed in must be 64-byte aligned. * See above comment for more information. */ #if defined(__GNUC__) && (defined(VMM) || defined(VMKERNEL) || defined(FROBOS)) static INLINE void XSAVE_ES1(uint8 *save, uint64 mask) { #if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1 __asm__ __volatile__ ( ".byte 0x0f, 0xae, 0x21 \n" : : "c" (save), "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #else __asm__ __volatile__ ( "xsave %0 \n" : "=m" (*save) : "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #endif } static INLINE void XRSTOR_ES1(const uint8 *load, uint64 mask) { #if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1 __asm__ __volatile__ ( ".byte 0x0f, 0xae, 0x29 \n" : : "c" (load), "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #else __asm__ __volatile__ ( "xrstor %0 \n" : : "m" (*load), "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #endif } static INLINE void XRSTOR_AMD_ES0(const uint8 *load, uint64 mask) { uint64 dummy = 0; __asm__ __volatile__ ("fnstsw %%ax \n" // Grab x87 ES bit "bt $7,%%ax \n" // Test ES bit "jnc 1f \n" // Jump if ES=0 "fnclex \n" // ES=1. Clear it so fild doesn't trap "1: \n" "ffree %%st(7) \n" // Clear tag bit - avoid poss. stack overflow "fildl %0 \n" // Dummy Load from "safe address" changes all // x87 exception pointers. "mov %%ebx, %%eax \n" #if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1 ".byte 0x0f, 0xae, 0x29 \n" : : "m" (dummy), "c" (load), "b" ((uint32)mask), "d" ((uint32)(mask >> 32)) #else "xrstor %1 \n" : : "m" (dummy), "m" (*load), "b" ((uint32)mask), "d" ((uint32)(mask >> 32)) #endif : "eax", "memory"); } #endif /* __GNUC__ */ /* *----------------------------------------------------------------------------- * * Div643232 -- * * Unsigned integer division: * The dividend is 64-bit wide * The divisor is 32-bit wide * The quotient is 32-bit wide * * Use this function if you are certain that: * o Either the quotient will fit in 32 bits, * o Or your code is ready to handle a #DE exception indicating overflow. * If that is not the case, then use Div643264(). --hpreg * * Results: * Quotient and remainder * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(__GNUC__) static INLINE void Div643232(uint64 dividend, // IN uint32 divisor, // IN uint32 *quotient, // OUT uint32 *remainder) // OUT { /* Checked against the Intel manual and GCC --hpreg */ __asm__( "divl %4" : "=a" (*quotient), "=d" (*remainder) : "0" ((uint32)dividend), "1" ((uint32)(dividend >> 32)), "rm" (divisor) : "cc" ); } #elif defined _MSC_VER static INLINE void Div643232(uint64 dividend, // IN uint32 divisor, // IN uint32 *quotient, // OUT uint32 *remainder) // OUT { /* Written and tested by mann, checked by dbudko and hpreg */ __asm { mov eax, DWORD PTR [dividend] mov edx, DWORD PTR [dividend+4] div DWORD PTR [divisor] mov edi, DWORD PTR [quotient] mov [edi], eax mov edi, DWORD PTR [remainder] mov [edi], edx } } #else #error No compiler defined for Div643232 #endif #if defined(__GNUC__) /* *----------------------------------------------------------------------------- * * Div643264 -- * * Unsigned integer division: * The dividend is 64-bit wide * The divisor is 32-bit wide * The quotient is 64-bit wide --hpreg * * Results: * Quotient and remainder * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Div643264(uint64 dividend, // IN uint32 divisor, // IN uint64 *quotient, // OUT uint32 *remainder) // OUT { uint32 hQuotient; uint32 lQuotient; /* Checked against the Intel manual and GCC --hpreg */ __asm__( "divl %5" "\n\t" "movl %%eax, %0" "\n\t" "movl %4, %%eax" "\n\t" "divl %5" : "=&rm" (hQuotient), "=a" (lQuotient), "=d" (*remainder) : "1" ((uint32)(dividend >> 32)), "g" ((uint32)dividend), "rm" (divisor), "2" (0) : "cc" ); *quotient = (uint64)hQuotient << 32 | lQuotient; } #endif /* *----------------------------------------------------------------------------- * * Mul64x3264 -- * * Unsigned integer by fixed point multiplication: * Unsigned 64-bit integer multiplicand. * Unsigned 32-bit fixed point multiplier, represented as * multiplier >> shift, where shift < 64. * Unsigned 64-bit integer product. * * Implementation: * Multiply 64x32 bits to yield a full 96-bit product. * Shift right by shift. * Return the low-order 64 bits of the result. * * Result: * Product * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(__GNUC__) static INLINE uint64 Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) { uint64 result; uint32 tmp1, tmp2; // ASSERT(shift >= 0 && shift < 64); /* * Written and tested by mann, improved with suggestions by hpreg. * * The main improvement over the previous version is that the test * of shift against 32 is moved out of the asm and into C code. * This lets the compiler delete the test and one of the * alternative code sequences in the case where shift is a * constant. It also lets us use the best code sequence in each * alternative, rather than a compromise. The downside is that in * the non-constant case, this version takes slightly more code * space. * * Note on the constraints: We don't really want multiplicand to * start in %edx:%eax as the =A constraint dictates; in fact, we'd * prefer any *other* two registers. But gcc doesn't have * constraint syntax for any other register pair, and trying to * constrain ((uint32) multiplicand) to one place and (multiplicand * >> 32) to another generates *really* bad code -- gcc is just not * smart enough, at least in the version we are currently using. */ if (shift < 32) { __asm__("mov %%eax, %2 \n\t" // Save lo(multiplicand) in tmp2 "mov %%edx, %%eax \n\t" // Get hi(multiplicand) "mull %4 \n\t" // p2 = hi(multiplicand) * multiplier "xchg %%eax, %2 \n\t" // Save lo(p2) in tmp2, get lo(multiplicand) "mov %%edx, %1 \n\t" // Save hi(p2) in tmp1 "mull %4 \n\t" // p1 = lo(multiplicand) * multiplier "addl %2, %%edx \n\t" // hi(p1) += lo(p2) "adcl $0, %1 \n\t" // hi(p2) += carry from previous step "shrdl %%edx, %%eax \n\t" // result = hi(p2):hi(p1):lo(p1) >> shift "shrdl %1, %%edx" : "=A" (result), "=&r" (tmp1), // use in shrdl requires it to be a register "=&r" (tmp2) // could be "=&rm" but "m" is slower : "0" (multiplicand), "rm" (multiplier), "c" (shift) : "cc" ); } else { __asm__("mov %%edx, %2 \n\t" // Save hi(multiplicand) in tmp2 "mull %4 \n\t" // p1 = lo(multiplicand) * multiplier "mov %%edx, %1 \n\t" // Save hi(p1) in tmp1 "mov %2, %%eax \n\t" // Discard lo(p1), get hi(multiplicand) "mull %4 \n\t" // p2 = hi(multiplicand) * multiplier "addl %1, %%eax \n\t" // lo(p2) += hi(p1) "adcl $0, %%edx \n\t" // hi(p2) += carry from previous step "shrdl %%edx, %%eax \n\t" // result = p2 >> (shift & 31) "shrl %%cl, %%edx" : "=A" (result), "=&r" (tmp1), // could be "=&rm" but "m" is slower "=&r" (tmp2) // could be "=&rm" but "m" is slower : "0" (multiplicand), "rm" (multiplier), "c" (shift) : "cc" ); } return result; } #elif defined _MSC_VER #pragma warning(disable: 4035) static INLINE uint64 Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) { // ASSERT(shift >= 0 && shift < 64); /* Written and tested by mann, checked by dbudko and hpreg */ __asm { mov eax, DWORD PTR [multiplicand+4] // Get hi(multiplicand) mul DWORD PTR [multiplier] // p2 = hi(multiplicand) * multiplier mov ecx, eax // Save lo(p2) mov ebx, edx // Save hi(p2) mov eax, DWORD PTR [multiplicand] // Get lo(multiplicand) mul DWORD PTR [multiplier+0] // p1 = lo(multiplicand) * multiplier add edx, ecx // hi(p1) += lo(p2) adc ebx, 0 // hi(p2) += carry from previous step mov ecx, DWORD PTR [shift] // Get shift cmp ecx, 32 // shift < 32? jl SHORT l2 // Go if so mov eax, edx // result = hi(p2):hi(p1) >> (shift & 31) mov edx, ebx shrd eax, edx, cl shr edx, cl jmp SHORT l3 l2: shrd eax, edx, cl // result = hi(p2):hi(p1):lo(p1) >> shift shrd edx, ebx, cl l3: } // return with result in edx:eax } #pragma warning(default: 4035) #else #error No compiler defined for Mul64x3264 #endif /* *----------------------------------------------------------------------------- * * Muls64x32s64 -- * * Signed integer by fixed point multiplication: * Signed 64-bit integer multiplicand. * Unsigned 32-bit fixed point multiplier, represented as * multiplier >> shift, where shift < 64. * Signed 64-bit integer product. * * Implementation: * Multiply 64x32 bits to yield a full 96-bit product. * Shift right by the location of the binary point. * Return the low-order 64 bits of the result. * * Result: * Product * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(__GNUC__) static INLINE int64 Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) { int64 result; uint32 tmp1, tmp2; // ASSERT(shift >= 0 && shift < 64); /* Written and tested by mann, checked by dbudko and hpreg */ /* XXX hpreg suggested some improvements that we haven't converged on yet */ __asm__("mov %%eax, %2\n\t" // Save lo(multiplicand) "mov %%edx, %%eax\n\t" // Get hi(multiplicand) "test %%eax, %%eax\n\t" // Check sign of multiplicand "jl 0f\n\t" // Go if negative "mull %4\n\t" // p2 = hi(multiplicand) * multiplier "jmp 1f\n" "0:\n\t" "mull %4\n\t" // p2 = hi(multiplicand) * multiplier "sub %4, %%edx\n" // hi(p2) += -1 * multiplier "1:\n\t" "xchg %%eax, %2\n\t" // Save lo(p2), get lo(multiplicand) "mov %%edx, %1\n\t" // Save hi(p2) "mull %4\n\t" // p1 = lo(multiplicand) * multiplier "addl %2, %%edx\n\t" // hi(p1) += lo(p2) "adcl $0, %1\n\t" // hi(p2) += carry from previous step "cmpl $32, %%ecx\n\t" // shift < 32? "jl 2f\n\t" // Go if so "mov %%edx, %%eax\n\t" // result = hi(p2):hi(p1) >> (shift & 31) "mov %1, %%edx\n\t" "shrdl %%edx, %%eax\n\t" "sarl %%cl, %%edx\n\t" "jmp 3f\n" "2:\n\t" "shrdl %%edx, %%eax\n\t" // result = hi(p2):hi(p1):lo(p1) >> shift "shrdl %1, %%edx\n" "3:\n\t" : "=A" (result), "=&r" (tmp1), "=&rm" (tmp2) : "0" (multiplicand), "rm" (multiplier), "c" (shift) : "cc"); return result; } #elif defined _MSC_VER #pragma warning(disable: 4035) static INLINE int64 Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) { //ASSERT(shift >= 0 && shift < 64); /* Written and tested by mann, checked by dbudko and hpreg */ __asm { mov eax, DWORD PTR [multiplicand+4] // Get hi(multiplicand) test eax, eax // Check sign of multiplicand jl SHORT l0 // Go if negative mul DWORD PTR [multiplier] // p2 = hi(multiplicand) * multiplier jmp SHORT l1 l0: mul DWORD PTR [multiplier] // p2 = hi(multiplicand) * multiplier sub edx, DWORD PTR [multiplier] // hi(p2) += -1 * multiplier l1: mov ecx, eax // Save lo(p2) mov ebx, edx // Save hi(p2) mov eax, DWORD PTR [multiplicand] // Get lo(multiplicand) mul DWORD PTR [multiplier] // p1 = lo(multiplicand) * multiplier add edx, ecx // hi(p1) += lo(p2) adc ebx, 0 // hi(p2) += carry from previous step mov ecx, DWORD PTR [shift] // Get shift cmp ecx, 32 // shift < 32? jl SHORT l2 // Go if so mov eax, edx // result = hi(p2):hi(p1) >> (shift & 31) mov edx, ebx shrd eax, edx, cl sar edx, cl jmp SHORT l3 l2: shrd eax, edx, cl // result = hi(p2):hi(p1):lo(p1) << shift shrd edx, ebx, cl l3: } // return with result in edx:eax } #pragma warning(default: 4035) #else #error No compiler defined for Muls64x32s64 #endif #endif vmci-only/shared/compat_skbuff.h 0000444 0000000 0000000 00000015575 11573420431 015746 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __COMPAT_SKBUFF_H__ # define __COMPAT_SKBUFF_H__ #include <linux/skbuff.h> /* * When transition from mac/nh/h to skb_* accessors was made, also SKB_WITH_OVERHEAD * was introduced. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) || \ (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 21) && defined(SKB_WITH_OVERHEAD)) #define compat_skb_mac_header(skb) skb_mac_header(skb) #define compat_skb_network_header(skb) skb_network_header(skb) #define compat_skb_network_offset(skb) skb_network_offset(skb) #define compat_skb_transport_header(skb) skb_transport_header(skb) #define compat_skb_transport_offset(skb) skb_transport_offset(skb) #define compat_skb_network_header_len(skb) skb_network_header_len(skb) #define compat_skb_tail_pointer(skb) skb_tail_pointer(skb) #define compat_skb_end_pointer(skb) skb_end_pointer(skb) #define compat_skb_ip_header(skb) ((struct iphdr *)skb_network_header(skb)) #define compat_skb_ipv6_header(skb) ((struct ipv6hdr *)skb_network_header(skb)) #define compat_skb_tcp_header(skb) ((struct tcphdr *)skb_transport_header(skb)) #define compat_skb_reset_mac_header(skb) skb_reset_mac_header(skb) #define compat_skb_reset_network_header(skb) skb_reset_network_header(skb) #define compat_skb_reset_transport_header(skb) skb_reset_transport_header(skb) #define compat_skb_set_network_header(skb, off) skb_set_network_header(skb, off) #define compat_skb_set_transport_header(skb, off) skb_set_transport_header(skb, off) #else #define compat_skb_mac_header(skb) (skb)->mac.raw #define compat_skb_network_header(skb) (skb)->nh.raw #define compat_skb_network_offset(skb) ((skb)->nh.raw - (skb)->data) #define compat_skb_transport_header(skb) (skb)->h.raw #define compat_skb_transport_offset(skb) ((skb)->h.raw - (skb)->data) #define compat_skb_network_header_len(skb) ((skb)->h.raw - (skb)->nh.raw) #define compat_skb_tail_pointer(skb) (skb)->tail #define compat_skb_end_pointer(skb) (skb)->end #define compat_skb_ip_header(skb) (skb)->nh.iph #define compat_skb_ipv6_header(skb) (skb)->nh.ipv6h #define compat_skb_tcp_header(skb) (skb)->h.th #define compat_skb_reset_mac_header(skb) ((skb)->mac.raw = (skb)->data) #define compat_skb_reset_network_header(skb) ((skb)->nh.raw = (skb)->data) #define compat_skb_reset_transport_header(skb) ((skb)->h.raw = (skb)->data) #define compat_skb_set_network_header(skb, off) ((skb)->nh.raw = (skb)->data + (off)) #define compat_skb_set_transport_header(skb, off) ((skb)->h.raw = (skb)->data + (off)) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) || defined(VMW_SKB_LINEARIZE_2618) # define compat_skb_linearize(skb) skb_linearize((skb)) #else # if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 0) # define compat_skb_linearize(skb) __skb_linearize((skb), GFP_ATOMIC) # elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) # define compat_skb_linearize(skb) skb_linearize((skb), GFP_ATOMIC) # else static inline int compat_skb_linearize(struct sk_buff *skb) { return 0; } # endif #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) #define compat_skb_csum_offset(skb) (skb)->csum_offset #else #define compat_skb_csum_offset(skb) (skb)->csum #endif /* * Note that compat_skb_csum_start() has semantic different from kernel's csum_start: * kernel's skb->csum_start is offset between start of checksummed area and start of * complete skb buffer, while our compat_skb_csum_start(skb) is offset from start * of packet itself. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) #define compat_skb_csum_start(skb) ((skb)->csum_start - skb_headroom(skb)) #else #define compat_skb_csum_start(skb) compat_skb_transport_offset(skb) #endif #if defined(NETIF_F_GSO) /* 2.6.18 and upwards */ #define compat_skb_mss(skb) (skb_shinfo(skb)->gso_size) #else #define compat_skb_mss(skb) (skb_shinfo(skb)->tso_size) #endif /* used by both received pkts and outgoing ones */ #define VM_CHECKSUM_UNNECESSARY CHECKSUM_UNNECESSARY /* csum status of received pkts */ #if defined(CHECKSUM_COMPLETE) # define VM_RX_CHECKSUM_PARTIAL CHECKSUM_COMPLETE #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW) # define VM_RX_CHECKSUM_PARTIAL CHECKSUM_HW #else # define VM_RX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL #endif /* csum status of outgoing pkts */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && defined(CHECKSUM_HW) # define VM_TX_CHECKSUM_PARTIAL CHECKSUM_HW #else # define VM_TX_CHECKSUM_PARTIAL CHECKSUM_PARTIAL #endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)) # define compat_kfree_skb(skb, type) kfree_skb(skb, type) # define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb, type) # define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb, type) # define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb, type) #else # define compat_kfree_skb(skb, type) kfree_skb(skb) # define compat_dev_kfree_skb(skb, type) dev_kfree_skb(skb) # if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43)) # define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb(skb) # define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb(skb) # else # define compat_dev_kfree_skb_any(skb, type) dev_kfree_skb_any(skb) # define compat_dev_kfree_skb_irq(skb, type) dev_kfree_skb_irq(skb) # endif #endif #ifndef NET_IP_ALIGN # define COMPAT_NET_IP_ALIGN 2 #else # define COMPAT_NET_IP_ALIGN NET_IP_ALIGN #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) # define compat_skb_headlen(skb) skb_headlen(skb) # define compat_pskb_may_pull(skb, len) pskb_may_pull(skb, len) # define compat_skb_is_nonlinear(skb) skb_is_nonlinear(skb) #else # define compat_skb_headlen(skb) (skb)->len # define compat_pskb_may_pull(skb, len) 1 # define compat_skb_is_nonlinear(skb) 0 #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) # define compat_skb_header_cloned(skb) skb_header_cloned(skb) #else # define compat_skb_header_cloned(skb) 0 #endif #endif /* __COMPAT_SKBUFF_H__ */ vmci-only/shared/compat_uaccess.h 0000444 0000000 0000000 00000006062 11573420431 016103 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_UACCESS_H__ # define __COMPAT_UACCESS_H__ /* User space access functions moved in 2.1.7 to asm/uaccess.h --hpreg */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 7) # include <asm/uaccess.h> #else # include <asm/segment.h> #endif /* get_user() API modified in 2.1.4 to take 2 arguments --hpreg */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 4) # define compat_get_user get_user #else /* * We assign 0 to the variable in case of failure to prevent "`_var' might be * used uninitialized in this function" compiler warnings. I think it is OK, * because the hardware-based version in newer kernels probably has the same * semantics and does not guarantee that the value of _var will not be * modified, should the access fail --hpreg */ # define compat_get_user(_var, _uvAddr) ({ \ int _status; \ \ _status = verify_area(VERIFY_READ, _uvAddr, sizeof(*(_uvAddr))); \ if (_status == 0) { \ (_var) = get_user(_uvAddr); \ } else { \ (_var) = 0; \ } \ _status; \ }) #endif /* * The copy_from_user() API appeared in 2.1.4 * * The emulation is not perfect here, but it is conservative: on failure, we * always return the total size, instead of the potentially smaller faulty * size --hpreg * * Since 2.5.55 copy_from_user() is no longer macro. */ #if !defined(copy_from_user) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) # define copy_from_user(_to, _from, _size) ( \ verify_area(VERIFY_READ, _from, _size) \ ? (_size) \ : (memcpy_fromfs(_to, _from, _size), 0) \ ) # define copy_to_user(_to, _from, _size) ( \ verify_area(VERIFY_WRITE, _to, _size) \ ? (_size) \ : (memcpy_tofs(_to, _from, _size), 0) \ ) #endif #endif /* __COMPAT_UACCESS_H__ */ vmci-only/shared/vm_atomic.h 0000444 0000000 0000000 00000210515 11573420432 015071 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vm_atomic.h -- * * Atomic power * * Note: Only partially tested on ARM processors: Works for View Open * Client, which shouldn't have threads. * * In ARM, GCC intrinsics (__sync*) compile but might not * work, while MS intrinsics (_Interlocked*) do not compile, * and ARM has no equivalent to the "lock" instruction prior to * ARMv6; the current ARM target is ARMv5. According to glibc * documentation, ARMv5 cannot have atomic code in user space. * Instead a Linux system call to kernel code referenced in * entry-armv.S is used to achieve atomic functions. See bug * 478054 for details. */ #ifndef _ATOMIC_H_ #define _ATOMIC_H_ //#define FAKE_ATOMIC /* defined if true atomic not needed */ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMIROM #include "includeCheck.h" #include "vm_basic_types.h" /* Basic atomic type: 32 bits */ typedef struct Atomic_uint32 { volatile uint32 value; } Atomic_uint32; /* Basic atomic type: 64 bits */ typedef struct Atomic_uint64 { volatile uint64 value; } Atomic_uint64 ALIGNED(8); #ifdef __arm__ #ifdef __GNUC__ EXTERN Atomic_uint32 atomicLocked64bit; #ifndef FAKE_ATOMIC /* * Definitions for kernel function call which attempts an * atomic exchange, returning 0 only upon success. * The code actually called is put in memory by the kernel, * and is in fact what the kernel uses for this atomic * instruction. This does not work for Linux versions * before 2.6 or (obviously) for non-Linux implementations. * For other implementations on ARMv6 and up, use * LDREX/SUBS/STREXEQ/LDRNE/ADDS/BNE spin-lock; for pre-ARMv6, * use SWP-based spin-lock. */ #if !defined(__linux__) #define __kernel_cmpxchg(x, y, z) _fn__kernel_cmpxchgNotImplementedOnNonLinuxARM #else typedef int (__kernel_cmpxchg_t)(uint32 oldVal, uint32 newVal, volatile uint32 *mem); #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) #endif #endif // FAKE_ATOMIC #endif // __GNUC__ #endif // __arm__ /* * Prototypes for msft atomics. These are defined & inlined by the * compiler so no function definition is needed. The prototypes are * needed for c++. Since amd64 compiler doesn't support inline asm we * have to use these. Unfortunately, we still have to use some inline asm * for the 32 bit code since the and/or/xor implementations didn't show up * untill xp or 2k3. * * The declarations for the intrinsic functions were taken from ntddk.h * in the DDK. The declarations must match otherwise the 64-bit c++ * compiler will complain about second linkage of the intrinsic functions. * We define the intrinsic using the basic types corresponding to the * Windows typedefs. This avoids having to include windows header files * to get to the windows types. */ #if defined(_MSC_VER) && _MSC_VER >= 1310 #ifdef __cplusplus extern "C" { #endif long _InterlockedExchange(long volatile*, long); long _InterlockedCompareExchange(long volatile*, long, long); long _InterlockedExchangeAdd(long volatile*, long); long _InterlockedDecrement(long volatile*); long _InterlockedIncrement(long volatile*); #pragma intrinsic(_InterlockedExchange, _InterlockedCompareExchange) #pragma intrinsic(_InterlockedExchangeAdd, _InterlockedDecrement) #pragma intrinsic(_InterlockedIncrement) #if defined(VM_X86_64) long _InterlockedAnd(long volatile*, long); __int64 _InterlockedAnd64(__int64 volatile*, __int64); long _InterlockedOr(long volatile*, long); __int64 _InterlockedOr64(__int64 volatile*, __int64); long _InterlockedXor(long volatile*, long); __int64 _InterlockedXor64(__int64 volatile*, __int64); __int64 _InterlockedExchangeAdd64(__int64 volatile*, __int64); __int64 _InterlockedIncrement64(__int64 volatile*); __int64 _InterlockedDecrement64(__int64 volatile*); __int64 _InterlockedExchange64(__int64 volatile*, __int64); __int64 _InterlockedCompareExchange64(__int64 volatile*, __int64, __int64); #if !defined(_WIN64) #pragma intrinsic(_InterlockedAnd, _InterlockedAnd64) #pragma intrinsic(_InterlockedOr, _InterlockedOr64) #pragma intrinsic(_InterlockedXor, _InterlockedXor64) #pragma intrinsic(_InterlockedExchangeAdd64, _InterlockedIncrement64) #pragma intrinsic(_InterlockedDecrement64, _InterlockedExchange64) #pragma intrinsic(_InterlockedCompareExchange64) #endif /* !_WIN64 */ #endif /* __x86_64__ */ #ifdef __cplusplus } #endif #endif /* _MSC_VER */ /* Convert a volatile uint32 to Atomic_uint32. */ static INLINE Atomic_uint32 * Atomic_VolatileToAtomic(volatile uint32 *var) { return (Atomic_uint32 *)var; } /* Convert a volatile uint64 to Atomic_uint64. */ static INLINE Atomic_uint64 * Atomic_VolatileToAtomic64(volatile uint64 *var) { return (Atomic_uint64 *)var; } /* *----------------------------------------------------------------------------- * * Atomic_Init, Atomic_SetFence, AtomicUseFence -- * * Determine whether an lfence intruction is executed after * every locked instruction. * * Certain AMD processors have a bug (see bug 107024) that * requires an lfence after every locked instruction. * * The global variable AtomicUseFence controls whether lfence * is used (see AtomicEpilogue). * * Atomic_SetFence sets AtomicUseFence to the given value. * * Atomic_Init computes and sets AtomicUseFence. * It does not take into account the number of processors. * * The rationale for all this complexity is that Atomic_Init * is the easy-to-use interface. It can be called a number * of times cheaply, and does not depend on other libraries. * However, because the number of CPUs is difficult to compute, * it does without it and always assumes there are more than one. * * For programs that care or have special requirements, * Atomic_SetFence can be called directly, in addition to Atomic_Init. * It overrides the effect of Atomic_Init, and can be called * before, after, or between calls to Atomic_Init. * *----------------------------------------------------------------------------- */ // The freebsd assembler doesn't know the lfence instruction #if defined(__GNUC__) && \ __GNUC__ >= 3 && \ (defined(__VMKERNEL__) || !defined(__FreeBSD__)) && \ (!defined(MODULE) || defined(__VMKERNEL_MODULE__)) && \ !defined(__APPLE__) && \ (defined(__i386__) || defined(__x86_64__)) /* PR136775 */ #define ATOMIC_USE_FENCE #endif #if defined(VMATOMIC_IMPORT_DLLDATA) VMX86_EXTERN_DATA Bool AtomicUseFence; #else EXTERN Bool AtomicUseFence; #endif EXTERN Bool atomicFenceInitialized; void AtomicInitFence(void); static INLINE void Atomic_Init(void) { #ifdef ATOMIC_USE_FENCE if (!atomicFenceInitialized) { AtomicInitFence(); } #endif } static INLINE void Atomic_SetFence(Bool fenceAfterLock) /* IN: TRUE to enable lfence */ /* FALSE to disable. */ { AtomicUseFence = fenceAfterLock; #if defined(__VMKERNEL__) extern void Atomic_SetFenceVMKAPI(Bool fenceAfterLock); Atomic_SetFenceVMKAPI(fenceAfterLock); #endif atomicFenceInitialized = TRUE; } /* Conditionally execute fence after interlocked instruction. */ static INLINE void AtomicEpilogue(void) { #ifdef ATOMIC_USE_FENCE #ifdef VMM /* The monitor conditionally patches out the lfence when not needed.*/ /* Construct a MonitorPatchTextEntry in the .patchtext section. */ asm volatile ("1:\n\t" "lfence\n\t" "2:\n\t" ".pushsection .patchtext\n\t" ".quad 1b\n\t" ".quad 2b\n\t" ".popsection\n\t" ::: "memory"); #else if (UNLIKELY(AtomicUseFence)) { asm volatile ("lfence" ::: "memory"); } #endif #endif } /* * All the assembly code is tricky and written conservatively. * For example, to make sure gcc won't introduce copies, * we force the addressing mode like this: * * "xchgl %0, (%1)" * : "=r" (val) * : "r" (&var->value), * "0" (val) * : "memory" * * - edward * * Actually - turns out that gcc never generates memory aliases (it * still does generate register aliases though), so we can be a bit * more agressive with the memory constraints. The code above can be * modified like this: * * "xchgl %0, %1" * : "=r" (val), * "=m" (var->value), * : "0" (val), * "1" (var->value) * * The advantages are that gcc can use whatever addressing mode it * likes to access the memory value, and that we dont have to use a * way-too-generic "memory" clobber as there is now an explicit * declaration that var->value is modified. * * see also /usr/include/asm/atomic.h to convince yourself this is a * valid optimization. * * - walken */ /* *----------------------------------------------------------------------------- * * Atomic_Read -- * * Read * * Results: * The value of the atomic variable. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_Read(Atomic_uint32 const *var) // IN { return var->value; } #define Atomic_Read32 Atomic_Read /* *----------------------------------------------------------------------------- * * Atomic_Write -- * * Write * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Write(Atomic_uint32 *var, // IN uint32 val) // IN { var->value = val; } #define Atomic_Write32 Atomic_Write /* *----------------------------------------------------------------------------- * * Atomic_ReadWrite -- * * Read followed by write * * Results: * The value of the atomic variable before the write. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_ReadWrite(Atomic_uint32 *var, // IN uint32 val) // IN { #ifdef FAKE_ATOMIC uint32 retval = var->value; var->value = val; return retval; #elif defined(__GNUC__) #ifdef __arm__ register uint32 retval; register volatile uint32 *mem = &(var->value); /* XXX - ARMv5 only: for ARMv6, use LDREX/STREX/CMP/BEQ spin-lock */ __asm__ __volatile__("swp %0, %1, [%2]" : "=&r,&r" (retval) : "r,0" (val), "r,r" (mem) : "memory"); return retval; #else // __arm__ (assume x86*) /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "xchgl %0, %1" # if VM_ASM_PLUS : "=r" (val), "+m" (var->value) : "0" (val) # else : "=r" (val), "=m" (var->value) : "0" (val), "1" (var->value) # endif ); AtomicEpilogue(); return val; #endif // __arm__ #elif defined _MSC_VER #if _MSC_VER >= 1310 return _InterlockedExchange((long *)&var->value, (long)val); #else #pragma warning(push) #pragma warning(disable : 4035) // disable no-return warning { __asm mov eax, val __asm mov ebx, var __asm xchg [ebx]Atomic_uint32.value, eax // eax is the return value, this is documented to work - edward } #pragma warning(pop) #endif #else #error No compiler defined for Atomic_ReadWrite #endif } #define Atomic_ReadWrite32 Atomic_ReadWrite /* *----------------------------------------------------------------------------- * * Atomic_ReadIfEqualWrite -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * Results: * The value of the atomic variable before the write. * * Side effects: * The variable may be modified. * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_ReadIfEqualWrite(Atomic_uint32 *var, // IN uint32 oldVal, // IN uint32 newVal) // IN { #ifdef FAKE_ATOMIC uint32 readVal = var->value; if (oldVal == readVal) { var->value = newVal; } return oldVal; #elif defined(__GNUC__) #ifdef __arm__ uint32 readVal; register volatile uint32 *mem = &(var->value); // loop until var not oldVal or var successfully replaced when var oldVal do { readVal = Atomic_Read(var); if (oldVal != readVal) { return readVal; } } while (__kernel_cmpxchg(oldVal, newVal, mem) != 0); return oldVal; // success #else // __arm__ (assume x86*) uint32 val; /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; cmpxchgl %2, %1" # if VM_ASM_PLUS : "=a" (val), "+m" (var->value) : "r" (newVal), "0" (oldVal) # else : "=a" (val), "=m" (var->value) : "r" (newVal), "0" (oldVal) /* * "1" (var->value): results in inconsistent constraints on gcc 2.7.2.3 * when compiling enterprise-2.2.17-14-RH7.0-update. * The constraint has been commented out for now. We may consider doing * this systematically, but we need to be sure it is the right thing to * do. However, it is also possible that the offending use of this asm * function will be removed in the near future in which case we may * decide to reintroduce the constraint instead. hpreg & agesen. */ # endif : "cc" ); AtomicEpilogue(); return val; #endif // __arm__ #elif defined _MSC_VER #if _MSC_VER >= 1310 return _InterlockedCompareExchange((long *)&var->value, (long)newVal, (long)oldVal); #else #pragma warning(push) #pragma warning(disable : 4035) // disable no-return warning { __asm mov eax, oldVal __asm mov ebx, var __asm mov ecx, newVal __asm lock cmpxchg [ebx]Atomic_uint32.value, ecx // eax is the return value, this is documented to work - edward } #pragma warning(pop) #endif #else #error No compiler defined for Atomic_ReadIfEqualWrite #endif } #define Atomic_ReadIfEqualWrite32 Atomic_ReadIfEqualWrite #if defined(__x86_64__) /* *----------------------------------------------------------------------------- * * Atomic_ReadIfEqualWrite64 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * Results: * The value of the atomic variable before the write. * * Side effects: * The variable may be modified. * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadIfEqualWrite64(Atomic_uint64 *var, // IN uint64 oldVal, // IN uint64 newVal) // IN { #if defined(__GNUC__) uint64 val; /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; cmpxchgq %2, %1" : "=a" (val), "+m" (var->value) : "r" (newVal), "0" (oldVal) : "cc" ); AtomicEpilogue(); return val; #elif defined _MSC_VER return _InterlockedCompareExchange64((__int64 *)&var->value, (__int64)newVal, (__int64)oldVal); #else #error No compiler defined for Atomic_ReadIfEqualWrite64 #endif } #endif /* *----------------------------------------------------------------------------- * * Atomic_And -- * * Atomic read, bitwise AND with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_And(Atomic_uint32 *var, // IN uint32 val) // IN { #ifdef FAKE_ATOMIC var->value &= val; #elif defined(__GNUC__) #ifdef __arm__ /* same as Atomic_FetchAndAnd without return value */ uint32 res; register volatile uint32 *mem = &(var->value); do { res = Atomic_Read(var); } while (__kernel_cmpxchg(res, res & val, mem) != 0); #else // __arm__ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; andl %1, %0" # if VM_ASM_PLUS : "+m" (var->value) : "ri" (val) # else : "=m" (var->value) : "ri" (val), "0" (var->value) # endif : "cc" ); AtomicEpilogue(); #endif // __arm__ #elif defined _MSC_VER #if defined(__x86_64__) _InterlockedAnd((long *)&var->value, (long)val); #else __asm mov eax, val __asm mov ebx, var __asm lock and [ebx]Atomic_uint32.value, eax #endif #else #error No compiler defined for Atomic_And #endif } #define Atomic_And32 Atomic_And /* *----------------------------------------------------------------------------- * * Atomic_Or -- * * Atomic read, bitwise OR with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Or(Atomic_uint32 *var, // IN uint32 val) // IN { #ifdef FAKE_ATOMIC var->value |= val; #elif defined(__GNUC__) #ifdef __arm__ /* same as Atomic_FetchAndOr without return value */ uint32 res; register volatile uint32 *mem = &(var->value); do { res = Atomic_Read(var); } while (__kernel_cmpxchg(res, res | val, mem) != 0); #else // __arm__ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; orl %1, %0" # if VM_ASM_PLUS : "+m" (var->value) : "ri" (val) # else : "=m" (var->value) : "ri" (val), "0" (var->value) # endif : "cc" ); AtomicEpilogue(); #endif // __arm__ #elif defined _MSC_VER #if defined(__x86_64__) _InterlockedOr((long *)&var->value, (long)val); #else __asm mov eax, val __asm mov ebx, var __asm lock or [ebx]Atomic_uint32.value, eax #endif #else #error No compiler defined for Atomic_Or #endif } #define Atomic_Or32 Atomic_Or /* *----------------------------------------------------------------------------- * * Atomic_Xor -- * * Atomic read, bitwise XOR with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Xor(Atomic_uint32 *var, // IN uint32 val) // IN { #ifdef FAKE_ATOMIC var->value ^= val; #elif defined(__GNUC__) #ifdef __arm__ uint32 res; register volatile uint32 *mem = &(var->value); do { res = Atomic_Read(var); } while (__kernel_cmpxchg(res, res ^ val, mem) != 0); #else // __arm__ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; xorl %1, %0" # if VM_ASM_PLUS : "+m" (var->value) : "ri" (val) # else : "=m" (var->value) : "ri" (val), "0" (var->value) # endif : "cc" ); AtomicEpilogue(); #endif // __arm__ #elif defined _MSC_VER #if defined(__x86_64__) _InterlockedXor((long *)&var->value, (long)val); #else __asm mov eax, val __asm mov ebx, var __asm lock xor [ebx]Atomic_uint32.value, eax #endif #else #error No compiler defined for Atomic_Xor #endif } #define Atomic_Xor32 Atomic_Xor #if defined(__x86_64__) /* *----------------------------------------------------------------------------- * * Atomic_Xor64 -- * * Atomic read, bitwise XOR with a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Xor64(Atomic_uint64 *var, // IN uint64 val) // IN { #if defined(__GNUC__) /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; xorq %1, %0" : "+m" (var->value) : "ri" (val) : "cc" ); AtomicEpilogue(); #elif defined _MSC_VER _InterlockedXor64((__int64 *)&var->value, (__int64)val); #else #error No compiler defined for Atomic_Xor64 #endif } #endif /* *----------------------------------------------------------------------------- * * Atomic_Add -- * * Atomic read, add a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Add(Atomic_uint32 *var, // IN uint32 val) // IN { #ifdef FAKE_ATOMIC var->value += val; #elif defined(__GNUC__) #ifdef __arm__ /* same as Atomic_FetchAndAddUnfenced without return value */ uint32 res; register volatile uint32 *mem = &(var->value); do { res = Atomic_Read(var); } while (__kernel_cmpxchg(res, res + val, mem) != 0); #else // __arm__ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; addl %1, %0" # if VM_ASM_PLUS : "+m" (var->value) : "ri" (val) # else : "=m" (var->value) : "ri" (val), "0" (var->value) # endif : "cc" ); AtomicEpilogue(); #endif // __arm__ #elif defined _MSC_VER #if _MSC_VER >= 1310 _InterlockedExchangeAdd((long *)&var->value, (long)val); #else __asm mov eax, val __asm mov ebx, var __asm lock add [ebx]Atomic_uint32.value, eax #endif #else #error No compiler defined for Atomic_Add #endif } #define Atomic_Add32 Atomic_Add #if defined(__x86_64__) /* *----------------------------------------------------------------------------- * * Atomic_Add64 -- * * Atomic read, add a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Add64(Atomic_uint64 *var, // IN uint64 val) // IN { #if defined(__GNUC__) /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; addq %1, %0" : "+m" (var->value) : "ri" (val) : "cc" ); AtomicEpilogue(); #elif defined _MSC_VER _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val); #else #error No compiler defined for Atomic_Add64 #endif } #endif /* *----------------------------------------------------------------------------- * * Atomic_Sub -- * * Atomic read, subtract a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Sub(Atomic_uint32 *var, // IN uint32 val) // IN { #ifdef FAKE_ATOMIC var->value -= val; #elif defined(__GNUC__) #ifdef __arm__ uint32 res; register volatile uint32 *mem = &(var->value); do { res = Atomic_Read(var); } while (__kernel_cmpxchg(res, res - val, mem) != 0); #else // __arm__ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; subl %1, %0" # if VM_ASM_PLUS : "+m" (var->value) : "ri" (val) # else : "=m" (var->value) : "ri" (val), "0" (var->value) # endif : "cc" ); AtomicEpilogue(); #endif // __arm__ #elif defined _MSC_VER #if _MSC_VER >= 1310 _InterlockedExchangeAdd((long *)&var->value, (long)-val); #else __asm mov eax, val __asm mov ebx, var __asm lock sub [ebx]Atomic_uint32.value, eax #endif #else #error No compiler defined for Atomic_Sub #endif } #define Atomic_Sub32 Atomic_Sub #if defined(__x86_64__) /* *----------------------------------------------------------------------------- * * Atomic_Sub64 -- * * Atomic read, subtract a value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Sub64(Atomic_uint64 *var, // IN uint64 val) // IN { #ifdef __GNUC__ /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; subq %1, %0" : "+m" (var->value) : "ri" (val) : "cc" ); AtomicEpilogue(); #elif defined _MSC_VER _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)-val); #else #error No compiler defined for Atomic_Sub64 #endif } #endif /* *----------------------------------------------------------------------------- * * Atomic_Inc -- * * Atomic read, increment, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Inc(Atomic_uint32 *var) // IN { #ifdef __GNUC__ #ifdef __arm__ /* just use Atomic_Add */ Atomic_Add(var, 1); #else // __arm__ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; incl %0" # if VM_ASM_PLUS : "+m" (var->value) : # else : "=m" (var->value) : "0" (var->value) # endif : "cc" ); AtomicEpilogue(); #endif // __arm__ #elif defined _MSC_VER #if _MSC_VER >= 1310 _InterlockedIncrement((long *)&var->value); #else __asm mov ebx, var __asm lock inc [ebx]Atomic_uint32.value #endif #else #error No compiler defined for Atomic_Inc #endif } #define Atomic_Inc32 Atomic_Inc /* *----------------------------------------------------------------------------- * * Atomic_Dec -- * * Atomic read, decrement, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Dec(Atomic_uint32 *var) // IN { #ifdef __GNUC__ #ifdef __arm__ /* just use Atomic_Sub */ Atomic_Sub(var, 1); #else // __arm__ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( "lock; decl %0" # if VM_ASM_PLUS : "+m" (var->value) : # else : "=m" (var->value) : "0" (var->value) # endif : "cc" ); AtomicEpilogue(); #endif // __arm__ #elif defined _MSC_VER #if _MSC_VER >= 1310 _InterlockedDecrement((long *)&var->value); #else __asm mov ebx, var __asm lock dec [ebx]Atomic_uint32.value #endif #else #error No compiler defined for Atomic_Dec #endif } #define Atomic_Dec32 Atomic_Dec /* * Note that the technique below can be used to implement ReadX(), where X is * an arbitrary mathematical function. */ /* *----------------------------------------------------------------------------- * * Atomic_FetchAndOr -- * * Atomic read (returned), bitwise OR with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_FetchAndOr(Atomic_uint32 *var, // IN uint32 val) // IN { uint32 res; #if defined(__arm__) && !defined(FAKE_ATOMIC) register volatile uint32 *mem = &(var->value); do { res = Atomic_Read(var); } while (__kernel_cmpxchg(res, res | val, mem) != 0); #else do { res = Atomic_Read(var); } while (res != Atomic_ReadIfEqualWrite(var, res, res | val)); #endif return res; } /* *----------------------------------------------------------------------------- * * Atomic_FetchAndAnd -- * * Atomic read (returned), bitwise And with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_FetchAndAnd(Atomic_uint32 *var, // IN uint32 val) // IN { uint32 res; #if defined(__arm__) && !defined(FAKE_ATOMIC) register volatile uint32 *mem = &(var->value); do { res = Atomic_Read(var); } while (__kernel_cmpxchg(res, res & val, mem) != 0); #else do { res = Atomic_Read(var); } while (res != Atomic_ReadIfEqualWrite(var, res, res & val)); #endif return res; } #define Atomic_ReadOr32 Atomic_FetchAndOr #if defined(__x86_64__) /* *----------------------------------------------------------------------------- * * Atomic_ReadOr64 -- * * Atomic read (returned), bitwise OR with a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadOr64(Atomic_uint64 *var, // IN uint64 val) // IN { uint64 res; do { res = var->value; } while (res != Atomic_ReadIfEqualWrite64(var, res, res | val)); return res; } #endif /* *----------------------------------------------------------------------------- * * Atomic_FetchAndAddUnfenced -- * * Atomic read (returned), add a value, write. * * If you have to implement FetchAndAdd() on an architecture other than * x86 or x86-64, you might want to consider doing something similar to * Atomic_FetchAndOr(). * * The "Unfenced" version of Atomic_FetchAndInc never executes * "lfence" after the interlocked operation. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_FetchAndAddUnfenced(Atomic_uint32 *var, // IN uint32 val) // IN { #ifdef FAKE_ATOMIC uint32 res = var->value; var->value = res + val; return res; #elif defined(__GNUC__) #ifdef __arm__ uint32 res; register volatile uint32 *mem = &(var->value); do { res = Atomic_Read(var); } while (__kernel_cmpxchg(res, res + val, mem) != 0); return res; #else // __arm__ /* Checked against the Intel manual and GCC --walken */ __asm__ __volatile__( # if VM_ASM_PLUS "lock; xaddl %0, %1" : "=r" (val), "+m" (var->value) : "0" (val) : "cc" # else "lock; xaddl %0, (%1)" : "=r" (val) : "r" (&var->value), "0" (val) : "cc", "memory" # endif ); return val; #endif // __arm__ #elif defined _MSC_VER #if _MSC_VER >= 1310 return _InterlockedExchangeAdd((long *)&var->value, (long)val); #else #pragma warning(push) #pragma warning(disable : 4035) // disable no-return warning { __asm mov eax, val __asm mov ebx, var __asm lock xadd [ebx]Atomic_uint32.value, eax } #pragma warning(pop) #endif #else #error No compiler defined for Atomic_FetchAndAdd #endif } #define Atomic_ReadAdd32 Atomic_FetchAndAdd /* *----------------------------------------------------------------------------- * * Atomic_FetchAndAdd -- * * Atomic read (returned), add a value, write. * * If you have to implement FetchAndAdd() on an architecture other than * x86 or x86-64, you might want to consider doing something similar to * Atomic_FetchAndOr(). * * Unlike "Unfenced" version, this one may execute the "lfence" after * interlocked operation. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_FetchAndAdd(Atomic_uint32 *var, // IN uint32 val) // IN { #if defined(__GNUC__) && !defined(__arm__) val = Atomic_FetchAndAddUnfenced(var, val); AtomicEpilogue(); return val; #else return Atomic_FetchAndAddUnfenced(var, val); #endif } #if defined(__x86_64__) /* *----------------------------------------------------------------------------- * * Atomic_ReadAdd64 -- * * Atomic read (returned), add a value, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadAdd64(Atomic_uint64 *var, // IN uint64 val) // IN { #if defined(__GNUC__) /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; xaddq %0, %1" : "=r" (val), "+m" (var->value) : "0" (val) : "cc" ); AtomicEpilogue(); return val; #elif defined _MSC_VER return _InterlockedExchangeAdd64((__int64 *)&var->value, (__int64)val); #else #error No compiler defined for Atomic_ReadAdd64 #endif } #endif /* *----------------------------------------------------------------------------- * * Atomic_FetchAndInc -- * * Atomic read (returned), increment, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_FetchAndInc(Atomic_uint32 *var) // IN { return Atomic_FetchAndAdd(var, 1); } #define Atomic_ReadInc32 Atomic_FetchAndInc #if defined(__x86_64__) /* *----------------------------------------------------------------------------- * * Atomic_ReadInc64 -- * * Atomic read (returned), increment, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadInc64(Atomic_uint64 *var) // IN { return Atomic_ReadAdd64(var, 1); } #endif /* *----------------------------------------------------------------------------- * * Atomic_FetchAndDec -- * * Atomic read (returned), decrement, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint32 Atomic_FetchAndDec(Atomic_uint32 *var) // IN { return Atomic_FetchAndAdd(var, (uint32)-1); } #define Atomic_ReadDec32 Atomic_FetchAndDec #if defined(__x86_64__) /* *----------------------------------------------------------------------------- * * Atomic_ReadDec64 -- * * Atomic read (returned), decrement, write. * * Results: * The value of the variable before the operation. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadDec64(Atomic_uint64 *var) // IN { return Atomic_ReadAdd64(var, CONST64U(-1)); } #endif #ifdef VMKERNEL /* *----------------------------------------------------------------------------- * * CMPXCHG1B -- * * Compare and exchange a single byte. * * Results: * The value read from ptr. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint8 CMPXCHG1B(volatile uint8 *ptr, // IN uint8 oldVal, // IN uint8 newVal) // IN { uint8 val; __asm__ __volatile__("lock; cmpxchgb %b2, %1" : "=a" (val), "+m" (*ptr) : "r" (newVal), "0" (oldVal) : "cc"); return val; } #endif /* * Usage of this helper struct is strictly reserved to the following * function. --hpreg */ typedef struct { uint32 lowValue; uint32 highValue; } S_uint64; /* *----------------------------------------------------------------------------- * * Atomic_CMPXCHG64 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * XXX: Ensure that if this function is to be inlined by gcc, it is * compiled with -fno-strict-aliasing. Otherwise it will break. * Unfortunately we know that gcc 2.95.3 (used to build the FreeBSD 3.2 * Tools) does not honor -fno-strict-aliasing. As a workaround, we avoid * inlining the function entirely for versions of gcc under 3.0. * * Results: * TRUE if equal, FALSE if not equal * * Side effects: * None * *----------------------------------------------------------------------------- */ #ifdef __arm__ #define Atomic_CMPXCHG64(x, y, z) _fnAtomic_CMPXCHG64_NotImplementedOnARM #else // __arm__ #if defined(__GNUC__) && __GNUC__ < 3 static Bool #else static INLINE Bool #endif Atomic_CMPXCHG64(Atomic_uint64 *var, // IN/OUT uint64 const *oldVal, // IN uint64 const *newVal) // IN { #ifdef FAKE_ATOMIC uint64 readVal = var->value; if (*oldVal == readVal) { var->value = *newVal; } return (*oldVal == readVal); #elif defined(__GNUC__) Bool equal; /* Checked against the Intel manual and GCC --walken */ #if defined(__x86_64__) uint64 dummy; __asm__ __volatile__( "lock; cmpxchgq %3, %0" "\n\t" "sete %1" : "+m" (*var), "=qm" (equal), "=a" (dummy) : "r" (*newVal), "2" (*oldVal) : "cc" ); #else /* 32-bit version */ int dummy1, dummy2; # if defined __PIC__ /* * Rules for __asm__ statements in __PIC__ code * -------------------------------------------- * * The compiler uses %ebx for __PIC__ code, so an __asm__ statement cannot * clobber %ebx. The __asm__ statement can temporarily modify %ebx, but _for * each parameter that is used while %ebx is temporarily modified_: * * 1) The constraint cannot be "m", because the memory location the compiler * chooses could then be relative to %ebx. * * 2) The constraint cannot be a register class which contains %ebx (such as * "r" or "q"), because the register the compiler chooses could then be * %ebx. (This happens when compiling the Fusion UI with gcc 4.2.1, Apple * build 5577.) * * For that reason alone, the __asm__ statement should keep the regions * where it temporarily modifies %ebx as small as possible. */ # if __GNUC__ < 3 // Part of #188541 - for RHL 6.2 etc. __asm__ __volatile__( "xchg %%ebx, %6" "\n\t" "mov 4(%%ebx), %%ecx" "\n\t" "mov (%%ebx), %%ebx" "\n\t" "lock; cmpxchg8b (%3)" "\n\t" "xchg %%ebx, %6" "\n\t" "sete %0" : "=a" (equal), "=d" (dummy2), "=D" (dummy1) : /* * See the "Rules for __asm__ statements in __PIC__ code" above: %3 * must use a register class which does not contain %ebx. */ "S" (var), "0" (((S_uint64 const *)oldVal)->lowValue), "1" (((S_uint64 const *)oldVal)->highValue), "D" (newVal) : "ecx", "cc", "memory" ); # else __asm__ __volatile__( "xchgl %%ebx, %6" "\n\t" "lock; cmpxchg8b (%3)" "\n\t" "xchgl %%ebx, %6" "\n\t" "sete %0" : "=qm,qm" (equal), "=a,a" (dummy1), "=d,d" (dummy2) : /* * See the "Rules for __asm__ statements in __PIC__ code" above: %3 * must use a register class which does not contain %ebx. * "a"/"c"/"d" are already used, so we are left with either "S" or "D". */ "S,D" (var), "1,1" (((S_uint64 const *)oldVal)->lowValue), "2,2" (((S_uint64 const *)oldVal)->highValue), // %6 cannot use "m": 'newVal' is read-only. "r,r" (((S_uint64 const *)newVal)->lowValue), "c,c" (((S_uint64 const *)newVal)->highValue) : "cc", "memory" ); # endif # else __asm__ __volatile__( "lock; cmpxchg8b %0" "\n\t" "sete %1" # if VM_ASM_PLUS : "+m" (*var), # else : "=m" (*var), # endif "=qm" (equal), "=a" (dummy1), "=d" (dummy2) : "2" (((S_uint64 const *)oldVal)->lowValue), "3" (((S_uint64 const *)oldVal)->highValue), "b" (((S_uint64 const *)newVal)->lowValue), "c" (((S_uint64 const *)newVal)->highValue) : "cc" ); # endif #endif /* 32-bit version */ AtomicEpilogue(); return equal; #elif defined _MSC_VER #if defined(__x86_64__) return (__int64)*oldVal == _InterlockedCompareExchange64((__int64 *)&var->value, (__int64)*newVal, (__int64)*oldVal); #else #pragma warning(push) #pragma warning(disable : 4035) // disable no-return warning { __asm mov esi, var __asm mov edx, oldVal __asm mov ecx, newVal __asm mov eax, [edx]S_uint64.lowValue __asm mov edx, [edx]S_uint64.highValue __asm mov ebx, [ecx]S_uint64.lowValue __asm mov ecx, [ecx]S_uint64.highValue __asm lock cmpxchg8b [esi] __asm sete al __asm movzx eax, al // eax is the return value, this is documented to work - edward } #pragma warning(pop) #endif #else #error No compiler defined for Atomic_CMPXCHG64 #endif } #endif // __arm__ /* *----------------------------------------------------------------------------- * * Atomic_CMPXCHG32 -- * * Compare exchange: Read variable, if equal to oldVal, write newVal * * Results: * TRUE if equal, FALSE if not equal * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Atomic_CMPXCHG32(Atomic_uint32 *var, // IN/OUT uint32 oldVal, // IN uint32 newVal) // IN { #ifdef FAKE_ATOMIC uint32 readVal = var->value; if (oldVal == readVal) { var->value = newVal; } return (oldVal == readVal); #elif defined(__GNUC__) #ifdef __arm__ register volatile uint32 *mem = &(var->value); return !__kernel_cmpxchg(oldVal, newVal, mem); #else // __arm__ Bool equal; uint32 dummy; __asm__ __volatile__( "lock; cmpxchgl %3, %0" "\n\t" "sete %1" # if VM_ASM_PLUS : "+m" (*var), "=qm" (equal), "=a" (dummy) : "r" (newVal), "2" (oldVal) # else : "=m" (*var), "=qm" (equal), "=a" (dummy) : /*"0" (*var), */ "r" (newVal), "2" (oldVal) # endif : "cc" ); AtomicEpilogue(); return equal; #endif // __arm__ #else // defined(__GNUC__) return (Atomic_ReadIfEqualWrite(var, oldVal, newVal) == oldVal); #endif // defined(__GNUC__) } #ifdef __arm__ #define Atomic_Read64(x) _fnAtomic_Read64_NotImplementedOnARM #define Atomic_FetchAndAdd64(x,y) _fnAtomic_FetchAndAdd64_NotImplementedOnARM #define Atomic_FetchAndInc64(x) _fnAtomic_FetchAndInc64_NotImplementedOnARM #define Atomic_FetchAndDec64(x) _fnAtomic_FetchAndDec64_NotImplementedOnARM #define Atomic_Inc64(x) _fnAtomic_Inc64_NotImplementedOnARM #define Atomic_Dec64(x) _fnAtomic_Dec64_NotImplementedOnARM #define Atomic_ReadWrite64(x,y) _fnAtomic_ReadWrite64_NotImplementedOnARM #define Atomic_Write64(x,y) _fnAtomic_Write64_NotImplementedOnARM #define Atomic_And64(x) _fnAtomic_And64_NotImplementedOnARM #define Atomic_Or64(x) _fnAtomic_Or64_NotImplementedOnARM #else // __arm__ /* *----------------------------------------------------------------------------- * * Atomic_Read64 -- * * Read and return. * * Results: * The value of the atomic variable. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_Read64(Atomic_uint64 const *var) // IN { #if defined(FAKE_ATOMIC) return var->value; #elif defined(__GNUC__) && defined(__x86_64__) uint64 value; /* * We have no evidence that suggests GCC will split this read into * two move instructions. However, we prefer to be defensive in * light of errors seen in Atomic_Write64. */ __asm__ __volatile__( "movq %1, %0" : "=r" (value) : "m" (var->value) ); return value; #elif defined(__GNUC__) && defined(__i386__) uint64 value; /* * Since cmpxchg8b will replace the contents of EDX:EAX with the * value in memory if there is no match, we need only execute the * instruction once in order to atomically read 64 bits from * memory. The only constraint is that ECX:EBX must have the same * value as EDX:EAX so that if the comparison succeeds. We * intentionally don't tell gcc that we are using ebx and ecx as we * don't modify them and do not care what value they store. */ __asm__ __volatile__( "mov %%ebx, %%eax" "\n\t" "mov %%ecx, %%edx" "\n\t" "lock; cmpxchg8b %1" : "=&A" (value) : "m" (*var) : "cc" ); AtomicEpilogue(); return value; #elif defined (_MSC_VER) && defined(__x86_64__) /* * Microsoft docs guarantee "Simple reads and writes to properly * aligned 64-bit variables are atomic on 64-bit Windows." * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx * * XXX Verify that value is properly aligned. Bug 61315. */ return var->value; #elif defined (_MSC_VER) && defined(__i386__) # pragma warning(push) # pragma warning(disable : 4035) // disable no-return warning { __asm mov ecx, var __asm mov edx, ecx __asm mov eax, ebx __asm lock cmpxchg8b [ecx] // edx:eax is the return value; this is documented to work. --mann } # pragma warning(pop) #else # error No compiler defined for Atomic_Read64 #endif } /* *---------------------------------------------------------------------- * * Atomic_FetchAndAdd64 -- * * Atomically adds a 64-bit integer to another * * Results: * Returns the old value just prior to the addition * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint64 Atomic_FetchAndAdd64(Atomic_uint64 *var, // IN/OUT uint64 addend) // IN { uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal + addend; } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); return oldVal; } /* *---------------------------------------------------------------------- * * Atomic_FetchAndInc64 -- * * Atomically increments a 64-bit integer * * Results: * Returns the old value just prior to incrementing * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint64 Atomic_FetchAndInc64(Atomic_uint64 *var) // IN/OUT { return Atomic_FetchAndAdd64(var, 1); } /* *---------------------------------------------------------------------- * * Atomic_FetchAndDec64 -- * * Atomically decrements a 64-bit integer * * Results: * Returns the old value just prior to decrementing * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE uint64 Atomic_FetchAndDec64(Atomic_uint64 *var) // IN/OUT { uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal - 1; } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); return oldVal; } /* *----------------------------------------------------------------------------- * * Atomic_Inc64 -- * * Atomic read, increment, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Inc64(Atomic_uint64 *var) // IN { #if !defined(__x86_64__) Atomic_FetchAndInc64(var); #elif defined(__GNUC__) /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; incq %0" : "+m" (var->value) : : "cc" ); AtomicEpilogue(); #elif defined _MSC_VER _InterlockedIncrement64((__int64 *)&var->value); #else #error No compiler defined for Atomic_Inc64 #endif } /* *----------------------------------------------------------------------------- * * Atomic_Dec64 -- * * Atomic read, decrement, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Dec64(Atomic_uint64 *var) // IN { #if !defined(__x86_64__) Atomic_FetchAndDec64(var); #elif defined(__GNUC__) /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; decq %0" : "+m" (var->value) : : "cc" ); AtomicEpilogue(); #elif defined _MSC_VER _InterlockedDecrement64((__int64 *)&var->value); #else #error No compiler defined for Atomic_Dec64 #endif } /* *----------------------------------------------------------------------------- * * Atomic_ReadWrite64 -- * * Read followed by write * * Results: * The value of the atomic variable before the write. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE uint64 Atomic_ReadWrite64(Atomic_uint64 *var, // IN uint64 val) // IN { #if defined(__x86_64__) #if defined(__GNUC__) /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "xchgq %0, %1" : "=r" (val), "+m" (var->value) : "0" (val) ); AtomicEpilogue(); return val; #elif defined _MSC_VER return _InterlockedExchange64((__int64 *)&var->value, (__int64)val); #else #error No compiler defined for Atomic_ReadWrite64 #endif #else uint64 oldVal; do { oldVal = var->value; } while (!Atomic_CMPXCHG64(var, &oldVal, &val)); return oldVal; #endif } /* *----------------------------------------------------------------------------- * * Atomic_Write64 -- * * Write * * Results: * None. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Write64(Atomic_uint64 *var, // IN uint64 val) // IN { #if defined(__x86_64__) #if defined(__GNUC__) /* * There is no move instruction for 64-bit immediate to memory, so unless * the immediate value fits in 32-bit (i.e. can be sign-extended), GCC * breaks the assignment into two movl instructions. The code below forces * GCC to load the immediate value into a register first. */ __asm__ __volatile__( "movq %1, %0" : "=m" (var->value) : "r" (val) ); #elif defined _MSC_VER /* * Microsoft docs guarantee "Simple reads and writes to properly aligned * 64-bit variables are atomic on 64-bit Windows." * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx * * XXX Verify that value is properly aligned. Bug 61315. */ var->value = val; #else #error No compiler defined for Atomic_Write64 #endif #else /* defined(__x86_64__) */ (void)Atomic_ReadWrite64(var, val); #endif } /* *----------------------------------------------------------------------------- * * Atomic_Or64 -- * * Atomic read, bitwise OR with a 64-bit value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_Or64(Atomic_uint64 *var, // IN uint64 val) // IN { #if defined(__x86_64__) #if defined(__GNUC__) /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; orq %1, %0" : "+m" (var->value) : "ri" (val) : "cc" ); AtomicEpilogue(); #elif defined _MSC_VER _InterlockedOr64((__int64 *)&var->value, (__int64)val); #else #error No compiler defined for Atomic_Or64 #endif #else // __x86_64__ uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal | val; } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); #endif } /* *----------------------------------------------------------------------------- * * Atomic_And64 -- * * Atomic read, bitwise AND with a 64-bit value, write. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_And64(Atomic_uint64 *var, // IN uint64 val) // IN { #if defined(__x86_64__) #if defined(__GNUC__) /* Checked against the AMD manual and GCC --hpreg */ __asm__ __volatile__( "lock; andq %1, %0" : "+m" (var->value) : "ri" (val) : "cc" ); AtomicEpilogue(); #elif defined _MSC_VER _InterlockedAnd64((__int64 *)&var->value, (__int64)val); #else #error No compiler defined for Atomic_And64 #endif #else // __x86_64__ uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal & val; } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); #endif } #endif // __arm__ /* *----------------------------------------------------------------------------- * * Atomic_SetBit64 -- * * Atomic read, set bit N, and write. * Be careful: if bit is in a register (not in an immediate), then it * can specify a bit offset above 63 or even a negative offset. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_SetBit64(Atomic_uint64 *var, // IN/OUT uint64 bit) // IN { #if defined(__x86_64__) #if defined(__GNUC__) __asm__ __volatile__( "lock; bts %1, %0" : "+m" (var->value) : "ri" (bit) : "cc" ); AtomicEpilogue(); #elif defined _MSC_VER uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal | (CONST64U(1) << bit); } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); #else #error No compiler defined for Atomic_SetBit64 #endif #else // __x86_64__ uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal | (CONST64U(1) << bit); } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); #endif } /* *----------------------------------------------------------------------------- * * Atomic_ClearBit64 -- * * Atomic read, clear bit N, and write. * Be careful: if bit is in a register (not in an immediate), then it * can specify a bit offset above 63 or even a negative offset. * * Results: * None * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void Atomic_ClearBit64(Atomic_uint64 *var, // IN/OUT uint64 bit) // IN { #if defined(__x86_64__) #if defined(__GNUC__) __asm__ __volatile__( "lock; btr %1, %0" : "+m" (var->value) : "ri" (bit) : "cc" ); AtomicEpilogue(); #elif defined _MSC_VER uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal & ~(CONST64U(1) << bit); } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); #else #error No compiler defined for Atomic_ClearBit64 #endif #else // __x86_64__ uint64 oldVal; uint64 newVal; do { oldVal = var->value; newVal = oldVal & ~(CONST64U(1) << bit); } while (!Atomic_CMPXCHG64(var, &oldVal, &newVal)); #endif } /* *----------------------------------------------------------------------------- * * Atomic_TestBit64 -- * * Read a bit. * Be careful: if bit is in a register (not in an immediate), then it * can specify a bit offset above 63 or even a negative offset. * * Results: * TRUE if the tested bit was set; else FALSE. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE Bool Atomic_TestBit64(Atomic_uint64 *var, // IN uint64 bit) // IN { #if defined(__x86_64__) #if defined(__GNUC__) Bool out = FALSE; __asm__ __volatile__( "bt %2, %1; setc %0" : "=rm"(out) : "m" (var->value), "ri" (bit) : "cc" ); return out; #elif defined _MSC_VER return (var->value & (CONST64U(1) << bit)) != 0; #else #error No compiler defined for Atomic_TestBit64 #endif #else // __x86_64__ return (var->value & (CONST64U(1) << bit)) != 0; #endif } /* * Template code for the Atomic_<name> type and its operators. * * The cast argument is an intermediate type cast to make some * compilers stop complaining about casting uint32 <-> void *, * even though we only do it in the 32-bit case so they are always * the same size. So for val of type uint32, instead of * (void *)val, we have (void *)(uintptr_t)val. * The specific problem case is the Windows ddk compiler * (as used by the SVGA driver). -- edward */ #define MAKE_ATOMIC_TYPE(name, size, in, out, cast) \ typedef Atomic_uint ## size Atomic_ ## name; \ \ \ static INLINE void \ AtomicAssertOnCompile ## name(void) \ { \ enum { AssertOnCompileMisused = 8 * sizeof (in) == size \ && 8 * sizeof (out) == size \ && 8 * sizeof (cast) == size \ ? 1 : -1 }; \ typedef char AssertOnCompileFailed[AssertOnCompileMisused]; \ } \ \ \ static INLINE out \ Atomic_Read ## name(Atomic_ ## name const *var) \ { \ return (out)(cast)Atomic_Read ## size(var); \ } \ \ \ static INLINE void \ Atomic_Write ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Write ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE out \ Atomic_ReadWrite ## name(Atomic_ ## name *var, \ in val) \ { \ return (out)(cast)Atomic_ReadWrite ## size(var, \ (uint ## size)(cast)val); \ } \ \ \ static INLINE out \ Atomic_ReadIfEqualWrite ## name(Atomic_ ## name *var, \ in oldVal, \ in newVal) \ { \ return (out)(cast)Atomic_ReadIfEqualWrite ## size(var, \ (uint ## size)(cast)oldVal, (uint ## size)(cast)newVal); \ } \ \ \ static INLINE void \ Atomic_And ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_And ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Or ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Or ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Xor ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Xor ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Add ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Add ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Sub ## name(Atomic_ ## name *var, \ in val) \ { \ Atomic_Sub ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE void \ Atomic_Inc ## name(Atomic_ ## name *var) \ { \ Atomic_Inc ## size(var); \ } \ \ \ static INLINE void \ Atomic_Dec ## name(Atomic_ ## name *var) \ { \ Atomic_Dec ## size(var); \ } \ \ \ static INLINE out \ Atomic_ReadOr ## name(Atomic_ ## name *var, \ in val) \ { \ return (out)(cast)Atomic_ReadOr ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE out \ Atomic_ReadAdd ## name(Atomic_ ## name *var, \ in val) \ { \ return (out)(cast)Atomic_ReadAdd ## size(var, (uint ## size)(cast)val); \ } \ \ \ static INLINE out \ Atomic_ReadInc ## name(Atomic_ ## name *var) \ { \ return (out)(cast)Atomic_ReadInc ## size(var); \ } \ \ \ static INLINE out \ Atomic_ReadDec ## name(Atomic_ ## name *var) \ { \ return (out)(cast)Atomic_ReadDec ## size(var); \ } /* * Since we use a macro to generate these definitions, it is hard to look for * them. So DO NOT REMOVE THIS COMMENT and keep it up-to-date. --hpreg * * Atomic_Ptr * Atomic_ReadPtr -- * Atomic_WritePtr -- * Atomic_ReadWritePtr -- * Atomic_ReadIfEqualWritePtr -- * Atomic_AndPtr -- * Atomic_OrPtr -- * Atomic_XorPtr -- * Atomic_AddPtr -- * Atomic_SubPtr -- * Atomic_IncPtr -- * Atomic_DecPtr -- * Atomic_ReadOrPtr -- * Atomic_ReadAddPtr -- * Atomic_ReadIncPtr -- * Atomic_ReadDecPtr -- * * Atomic_Int * Atomic_ReadInt -- * Atomic_WriteInt -- * Atomic_ReadWriteInt -- * Atomic_ReadIfEqualWriteInt -- * Atomic_AndInt -- * Atomic_OrInt -- * Atomic_XorInt -- * Atomic_AddInt -- * Atomic_SubInt -- * Atomic_IncInt -- * Atomic_DecInt -- * Atomic_ReadOrInt -- * Atomic_ReadAddInt -- * Atomic_ReadIncInt -- * Atomic_ReadDecInt -- */ #if defined(__x86_64__) MAKE_ATOMIC_TYPE(Ptr, 64, void const *, void *, uintptr_t) #else MAKE_ATOMIC_TYPE(Ptr, 32, void const *, void *, uintptr_t) #endif MAKE_ATOMIC_TYPE(Int, 32, int, int, int) /* *----------------------------------------------------------------------------- * * Atomic_MFence -- * * Implements mfence in terms of a lock xor. The reason for implementing * our own mfence is that not all of our supported cpus have an assembly * mfence (P3, Athlon). We put it here to avoid duplicating code which is * also why it is prefixed with "Atomic_". * * Results: * None. * * Side effects: * Cause loads and stores prior to this to be globally * visible. * *----------------------------------------------------------------------------- */ static INLINE void Atomic_MFence(void) { Atomic_uint32 fence; Atomic_Xor(&fence, 0x1); } #endif // ifndef _ATOMIC_H_ vmci-only/shared/compat_ioport.h 0000444 0000000 0000000 00000004041 11573420431 015764 0 ustar root root /********************************************************* * Copyright (C) 2003 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_IOPORT_H__ # define __COMPAT_IOPORT_H__ #include <linux/ioport.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) static inline void * compat_request_region(unsigned long start, unsigned long len, const char *name) { if (check_region(start, len)) { return NULL; } request_region(start, len, name); return (void*)1; } #else #define compat_request_region(start, len, name) request_region(start, len, name) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 7) /* mmap io support starts from 2.3.7, fail the call for kernel prior to that */ static inline void * compat_request_mem_region(unsigned long start, unsigned long len, const char *name) { return NULL; } static inline void compat_release_mem_region(unsigned long start, unsigned long len) { return; } #else #define compat_request_mem_region(start, len, name) request_mem_region(start, len, name) #define compat_release_mem_region(start, len) release_mem_region(start, len) #endif /* these two macro defs are needed by compat_pci_request_region */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 15) # define IORESOURCE_IO 0x00000100 # define IORESOURCE_MEM 0x00000200 #endif #endif /* __COMPAT_IOPORT_H__ */ vmci-only/shared/compat_slab.h 0000444 0000000 0000000 00000006653 11573420431 015404 0 ustar root root /********************************************************* * Copyright (C) 2005 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_SLAB_H__ # define __COMPAT_SLAB_H__ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 0) # include <linux/slab.h> #else # include <linux/malloc.h> #endif /* * Before 2.6.20, kmem_cache_t was the accepted way to refer to a kmem_cache * structure. Prior to 2.6.15, this structure was called kmem_cache_s, and * afterwards it was renamed to kmem_cache. Here we keep things simple and use * the accepted typedef until it became deprecated, at which point we switch * over to the kmem_cache name. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) # define compat_kmem_cache struct kmem_cache #else # define compat_kmem_cache kmem_cache_t #endif /* * Up to 2.6.22 kmem_cache_create has 6 arguments - name, size, alignment, flags, * constructor, and destructor. Then for some time kernel was asserting that * destructor is NULL, and since 2.6.23-pre1 kmem_cache_create takes only 5 * arguments - destructor is gone. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) || defined(VMW_KMEMCR_HAS_DTOR) #define compat_kmem_cache_create(name, size, align, flags, ctor) \ kmem_cache_create(name, size, align, flags, ctor, NULL) #else #define compat_kmem_cache_create(name, size, align, flags, ctor) \ kmem_cache_create(name, size, align, flags, ctor) #endif /* * Up to 2.6.23 kmem_cache constructor has three arguments - pointer to block to * prepare (aka "this"), from which cache it came, and some unused flags. After * 2.6.23 flags were removed, and order of "this" and cache parameters was swapped... * Since 2.6.27-rc2 everything is different again, and ctor has only one argument. * * HAS_3_ARGS has precedence over HAS_2_ARGS if both are defined. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) && !defined(VMW_KMEMCR_CTOR_HAS_3_ARGS) # define VMW_KMEMCR_CTOR_HAS_3_ARGS #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) && !defined(VMW_KMEMCR_CTOR_HAS_2_ARGS) # define VMW_KMEMCR_CTOR_HAS_2_ARGS #endif #if defined(VMW_KMEMCR_CTOR_HAS_3_ARGS) typedef void compat_kmem_cache_ctor(void *, compat_kmem_cache *, unsigned long); #define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg, \ compat_kmem_cache *cache, \ unsigned long flags #elif defined(VMW_KMEMCR_CTOR_HAS_2_ARGS) typedef void compat_kmem_cache_ctor(compat_kmem_cache *, void *); #define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) compat_kmem_cache *cache, \ void *arg #else typedef void compat_kmem_cache_ctor(void *); #define COMPAT_KMEM_CACHE_CTOR_ARGS(arg) void *arg #endif #endif /* __COMPAT_SLAB_H__ */ vmci-only/shared/compat_pci_mapping.h 0000444 0000000 0000000 00000004741 11573420431 016745 0 ustar root root /********************************************************* * Copyright (C) 2008 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_PCI_MAPPING_H__ #define __COMPAT_PCI_MAPPING_H__ #include <asm/types.h> #include <asm/io.h> #include <linux/pci.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,41) typedef u32 dma_addr_t; static __inline__ int get_order(unsigned long size) { int order; size = (size - 1) >> (PAGE_SHIFT - 1); order = -1; do { size >>= 1; order++; } while (size); return order; } static inline void * compat_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { void *ptr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)); if (ptr) { memset(ptr, 0, size); *dma_handle = virt_to_phys(ptr); } return ptr; } static inline void compat_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { free_pages((unsigned long)vaddr, get_order(size)); } static inline dma_addr_t compat_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) { return virt_to_phys(ptr); } static inline void compat_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { } #else #define compat_pci_alloc_consistent(hwdev, size, dma_handle) \ pci_alloc_consistent(hwdev, size, dma_handle) #define compat_pci_free_consistent(hwdev, size, vaddr, dma_handle) \ pci_free_consistent(hwdev, size, vaddr, dma_handle) #define compat_pci_map_single(hwdev, ptr, size, direction) \ pci_map_single(hwdev, ptr, size, direction) #define compat_pci_unmap_single(hwdev, dma_addr, size, direction) \ pci_unmap_single(hwdev, dma_addr, size, direction) #endif #endif vmci-only/shared/compat_spinlock.h 0000444 0000000 0000000 00000004606 11573420431 016301 0 ustar root root /********************************************************* * Copyright (C) 2005 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_SPINLOCK_H__ # define __COMPAT_SPINLOCK_H__ /* * The spin_lock() API appeared in 2.1.25 in asm/smp_lock.h * It moved in 2.1.30 to asm/spinlock.h * It moved again in 2.3.18 to linux/spinlock.h * * --hpreg */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 18) # include <linux/spinlock.h> #else # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 30) # include <asm/spinlock.h> # else typedef struct {} spinlock_t; # define spin_lock_init(lock) # define spin_lock(lock) # define spin_unlock(lock) # define spin_lock_irqsave(lock, flags) do { \ save_flags(flags); \ cli(); \ spin_lock(lock); \ } while (0) # define spin_unlock_irqrestore(lock, flags) do { \ spin_unlock(lock); \ restore_flags(flags); \ } while (0) # endif #endif /* * Preempt support was added during 2.5.x development cycle, and later * it was backported to 2.4.x. In 2.4.x backport these definitions * live in linux/spinlock.h, that's why we put them here (in 2.6.x they * are defined in linux/preempt.h which is included by linux/spinlock.h). */ #ifdef CONFIG_PREEMPT #define compat_preempt_disable() preempt_disable() #define compat_preempt_enable() preempt_enable() #else #define compat_preempt_disable() do { } while (0) #define compat_preempt_enable() do { } while (0) #endif #endif /* __COMPAT_SPINLOCK_H__ */ vmci-only/shared/vmware_pack_init.h 0000444 0000000 0000000 00000003644 11573420432 016440 0 ustar root root /********************************************************* * 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 __VMWARE_PACK_INIT_H__ # define __VMWARE_PACK_INIT_H__ /* * vmware_pack_init.h -- * * Platform-independent code to make the compiler pack (i.e. have them * occupy the smallest possible space) structure definitions. The following * constructs are known to work --hpreg * * #include "vmware_pack_begin.h" * struct foo { * ... * } * #include "vmware_pack_end.h" * ; * * typedef * #include "vmware_pack_begin.h" * struct foo { * ... * } * #include "vmware_pack_end.h" * foo; */ #ifdef _MSC_VER /* * MSVC 6.0 emits warning 4103 when the pack push and pop pragma pairing is * not balanced within 1 included file. That is annoying because our scheme * is based on the pairing being balanced between 2 included files. * * So we disable this warning, but this is safe because the compiler will also * emit warning 4161 when there is more pops than pushes within 1 main * file --hpreg */ # pragma warning(disable:4103) #elif __GNUC__ #else # error Compiler packing... #endif #endif /* __VMWARE_PACK_INIT_H__ */ vmci-only/shared/vm_device_version.h 0000444 0000000 0000000 00000022536 11573420432 016625 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef VM_DEVICE_VERSION_H #define VM_DEVICE_VERSION_H #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #ifdef _WIN32 #ifdef __MINGW32__ #include "initguid.h" #else #include "guiddef.h" #endif #endif /* LSILogic 53C1030 Parallel SCSI controller * LSILogic SAS1068 SAS controller */ #define PCI_VENDOR_ID_LSILOGIC 0x1000 #define PCI_DEVICE_ID_LSI53C1030 0x0030 #define PCI_DEVICE_ID_LSISAS1068 0x0054 /* Our own PCI IDs * VMware SVGA II (Unified VGA) * VMware SVGA (PCI Accelerator) * VMware vmxnet (Idealized NIC) * VMware vmxscsi (Abortive idealized SCSI controller) * VMware chipset (Subsystem ID for our motherboards) * VMware e1000 (Subsystem ID) * VMware vmxnet3 (Uniform Pass Through NIC) * VMware HD Audio codec * VMware HD Audio controller */ #define PCI_VENDOR_ID_VMWARE 0x15AD #define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 #define PCI_DEVICE_ID_VMWARE_SVGA 0x0710 #define PCI_DEVICE_ID_VMWARE_NET 0x0720 #define PCI_DEVICE_ID_VMWARE_SCSI 0x0730 #define PCI_DEVICE_ID_VMWARE_VMCI 0x0740 #define PCI_DEVICE_ID_VMWARE_CHIPSET 0x1976 #define PCI_DEVICE_ID_VMWARE_82545EM 0x0750 /* single port */ #define PCI_DEVICE_ID_VMWARE_82546EB 0x0760 /* dual port */ #define PCI_DEVICE_ID_VMWARE_EHCI 0x0770 #define PCI_DEVICE_ID_VMWARE_UHCI 0x0774 #define PCI_DEVICE_ID_VMWARE_XHCI 0x0778 #define PCI_DEVICE_ID_VMWARE_1394 0x0780 #define PCI_DEVICE_ID_VMWARE_BRIDGE 0x0790 #define PCI_DEVICE_ID_VMWARE_ROOTPORT 0x07A0 #define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0 #define PCI_DEVICE_ID_VMWARE_VMXWIFI 0x07B8 #define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 #define PCI_DEVICE_ID_VMWARE_82574 0x07D0 #define PCI_DEVICE_ID_VMWARE_HDAUDIO_CODEC 0x1975 #define PCI_DEVICE_ID_VMWARE_HDAUDIO_CONTROLLER 0x1977 /* The hypervisor device might grow. Please leave room * for 7 more subfunctions. */ #define PCI_DEVICE_ID_VMWARE_HYPER 0x0800 #define PCI_DEVICE_ID_VMWARE_VMI 0x0801 #define PCI_DEVICE_VMI_CLASS 0x05 #define PCI_DEVICE_VMI_SUBCLASS 0x80 #define PCI_DEVICE_VMI_INTERFACE 0x00 #define PCI_DEVICE_VMI_REVISION 0x01 /* From linux/pci_ids.h: * AMD Lance Ethernet controller * BusLogic SCSI controller * Ensoniq ES1371 sound controller */ #define PCI_VENDOR_ID_AMD 0x1022 #define PCI_DEVICE_ID_AMD_VLANCE 0x2000 #define PCI_VENDOR_ID_BUSLOGIC 0x104B #define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 #define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040 #define PCI_VENDOR_ID_ENSONIQ 0x1274 #define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 /* From linux/pci_ids.h: * Intel 82439TX (430 HX North Bridge) * Intel 82371AB (PIIX4 South Bridge) * Intel 82443BX (440 BX North Bridge and AGP Bridge) * Intel 82545EM (e1000, server adapter, single port) * Intel 82546EB (e1000, server adapter, dual port) * Intel HECI (as embedded in ich9m) */ #define PCI_VENDOR_ID_INTEL 0x8086 #define PCI_DEVICE_ID_INTEL_82439TX 0x7100 #define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 #define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 #define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 #define PCI_DEVICE_ID_INTEL_82371AB 0x7111 #define PCI_DEVICE_ID_INTEL_82443BX 0x7190 #define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191 #define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 /* Used when no AGP support */ #define PCI_DEVICE_ID_INTEL_82545EM 0x100f #define PCI_DEVICE_ID_INTEL_82546EB 0x1010 #define PCI_DEVICE_ID_INTEL_82574 0x10d3 #define PCI_DEVICE_ID_INTEL_82574_APPLE 0x10f6 #define PCI_DEVICE_ID_INTEL_HECI 0x2a74 #define E1000E_PCI_DEVICE_ID_CONFIG_STR "e1000e.pci.deviceID" #define E1000E_PCI_SUB_VENDOR_ID_CONFIG_STR "e1000e.pci.subVendorID" #define E1000E_PCI_SUB_DEVICE_ID_CONFIG_STR "e1000e.pci.subDeviceID" /* * Intel HD Audio controller and Realtek ALC885 codec. */ #define PCI_DEVICE_ID_INTEL_631XESB_632XESB 0x269a #define PCI_VENDOR_ID_REALTEK 0x10ec #define PCI_DEVICE_ID_REALTEK_ALC885 0x0885 /* * Fresco Logic xHCI (USB 3.0) Controller */ #define PCI_VENDOR_ID_FRESCO 0x1B73 #define PCI_DEVICE_ID_FRESCO_FL1000 0x1000 // Original 1-port chip #define PCI_DEVICE_ID_FRESCO_FL1009 0x1009 // New 2-port chip (Driver 3.0.98+) #define PCI_DEVICE_ID_FRESCO_FL1400 0x1400 // Unknown (4-port? Dev hardware?) /* * NEC/Renesas xHCI (USB 3.0) Controller */ #define PCI_VENDOR_ID_NEC 0x1033 #define PCI_DEVICE_ID_NEC_UPD720200 0x0194 #define PCI_REVISION_NEC_UPD720200 0x03 #define PCI_FIRMWARE_NEC_UPD720200 0x3015 /************* Strings for IDE Identity Fields **************************/ #define VIDE_ID_SERIAL_STR "00000000000000000001" /* Must be 20 Bytes */ #define VIDE_ID_FIRMWARE_STR "00000001" /* Must be 8 Bytes */ /* No longer than 40 Bytes */ #define VIDE_ATA_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE Hard Drive" #define VIDE_ATAPI_MODEL_STR PRODUCT_GENERIC_NAME " Virtual IDE CDROM Drive" #define ATAPI_VENDOR_ID "NECVMWar" /* Must be 8 Bytes */ #define ATAPI_PRODUCT_ID PRODUCT_GENERIC_NAME " IDE CDROM" /* Must be 16 Bytes */ #define ATAPI_REV_LEVEL "1.00" /* Must be 4 Bytes */ #define IDE_NUM_INTERFACES 2 /* support for two interfaces */ #define IDE_DRIVES_PER_IF 2 /************* Strings for SCSI Identity Fields **************************/ #define SCSI_DISK_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI Hard Drive" #define SCSI_DISK_VENDOR_NAME COMPANY_NAME #define SCSI_DISK_REV_LEVEL "1.0" #define SCSI_CDROM_MODEL_STR PRODUCT_GENERIC_NAME " Virtual SCSI CDROM Drive" #define SCSI_CDROM_VENDOR_NAME COMPANY_NAME #define SCSI_CDROM_REV_LEVEL "1.0" /************* SCSI implementation limits ********************************/ #define SCSI_MAX_CONTROLLERS 4 // Need more than 1 for MSCS clustering #define SCSI_MAX_DEVICES 16 // BT-958 emulates only 16 #define PVSCSI_MAX_DEVICES 255 // 255 (including the controller) /* * VSCSI_BV_INTS is the number of uint32's needed for a bit vector * to cover all scsi devices per target. */ #define VSCSI_BV_INTS CEILING(PVSCSI_MAX_DEVICES, 8 * sizeof (uint32)) #define SCSI_IDE_CHANNEL SCSI_MAX_CONTROLLERS #define SCSI_IDE_HOSTED_CHANNEL (SCSI_MAX_CONTROLLERS + 1) #define SCSI_MAX_CHANNELS (SCSI_MAX_CONTROLLERS + 2) /************* Strings for the VESA BIOS Identity Fields *****************/ #define VBE_OEM_STRING COMPANY_NAME " SVGA" #define VBE_VENDOR_NAME COMPANY_NAME #define VBE_PRODUCT_NAME PRODUCT_GENERIC_NAME /************* PCI implementation limits ********************************/ #define PCI_MAX_BRIDGES 15 /************* Ethernet implementation limits ***************************/ #define MAX_ETHERNET_CARDS 10 /********************** Floppy limits ***********************************/ #define MAX_FLOPPY_DRIVES 2 /************* PCI Passthrough implementation limits ********************/ #define MAX_PCI_PASSTHRU_DEVICES 6 /************* USB implementation limits ********************************/ #define MAX_USB_DEVICES_PER_HOST_CONTROLLER 127 /************* Strings for Host USB Driver *******************************/ #ifdef _WIN32 /* * Globally unique ID for the VMware device interface. Define INITGUID before including * this header file to instantiate the variable. */ DEFINE_GUID(GUID_DEVICE_INTERFACE_VMWARE_USB_DEVICES, 0x2da1fe75, 0xaab3, 0x4d2c, 0xac, 0xdf, 0x39, 0x8, 0x8c, 0xad, 0xa6, 0x65); /* * Globally unique ID for the VMware device setup class. */ DEFINE_GUID(GUID_CLASS_VMWARE_USB_DEVICES, 0x3b3e62a5, 0x3556, 0x4d7e, 0xad, 0xad, 0xf5, 0xfa, 0x3a, 0x71, 0x2b, 0x56); /* * This string defines the device ID string of a VMware USB device. * The format is USB\Vid_XXXX&Pid_YYYY, where XXXX and YYYY are the * hexadecimal representations of the vendor and product ids, respectively. * * The official vendor ID for VMware, Inc. is 0x0E0F. * The product id for USB generic devices is 0x0001. */ #define USB_VMWARE_DEVICE_ID_WIDE L"USB\\Vid_0E0F&Pid_0001" #define USB_DEVICE_ID_LENGTH (sizeof(USB_VMWARE_DEVICE_ID_WIDE) / sizeof(WCHAR)) #ifdef UNICODE #define USB_PNP_SETUP_CLASS_NAME L"VMwareUSBDevices" #define USB_PNP_DRIVER_NAME L"vmusb" #else #define USB_PNP_SETUP_CLASS_NAME "VMwareUSBDevices" #define USB_PNP_DRIVER_NAME "vmusb" #endif #endif #endif /* VM_DEVICE_VERSION_H */ vmci-only/shared/compat_semaphore.h 0000444 0000000 0000000 00000003142 11573420431 016434 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_SEMAPHORE_H__ # define __COMPAT_SEMAPHORE_H__ /* <= 2.6.25 have asm only, 2.6.26 has both, and 2.6.27-rc2+ has linux only. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) # include <asm/semaphore.h> #else # include <linux/semaphore.h> #endif /* * The init_MUTEX_LOCKED() API appeared in 2.2.18, and is also in * 2.2.17-21mdk --hpreg */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) #ifndef init_MUTEX_LOCKED #define init_MUTEX_LOCKED(_sem) *(_sem) = MUTEX_LOCKED #endif #ifndef DECLARE_MUTEX #define DECLARE_MUTEX(name) struct semaphore name = MUTEX #endif #ifndef DECLARE_MUTEX_LOCKED #define DECLARE_MUTEX_LOCKED(name) struct semaphore name = MUTEX_LOCKED #endif #endif #endif /* __COMPAT_SEMAPHORE_H__ */ vmci-only/shared/backdoor_def.h 0000444 0000000 0000000 00000017377 11573420432 015530 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * backdoor_def.h -- * * This contains backdoor defines that can be included from * an assembly language file. */ #ifndef _BACKDOOR_DEF_H_ #define _BACKDOOR_DEF_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" /* * If you want to add a new low-level backdoor call for a guest userland * application, please consider using the GuestRpc mechanism instead. --hpreg */ #define BDOOR_MAGIC 0x564D5868 /* Low-bandwidth backdoor port. --hpreg */ #define BDOOR_PORT 0x5658 #define BDOOR_CMD_GETMHZ 1 /* * BDOOR_CMD_APMFUNCTION is used by: * * o The FrobOS code, which instead should either program the virtual chipset * (like the new BIOS code does, matthias offered to implement that), or not * use any VM-specific code (which requires that we correctly implement * "power off on CLI HLT" for SMP VMs, boris offered to implement that) * * o The old BIOS code, which will soon be jettisoned * * --hpreg */ #define BDOOR_CMD_APMFUNCTION 2 #define BDOOR_CMD_GETDISKGEO 3 #define BDOOR_CMD_GETPTRLOCATION 4 #define BDOOR_CMD_SETPTRLOCATION 5 #define BDOOR_CMD_GETSELLENGTH 6 #define BDOOR_CMD_GETNEXTPIECE 7 #define BDOOR_CMD_SETSELLENGTH 8 #define BDOOR_CMD_SETNEXTPIECE 9 #define BDOOR_CMD_GETVERSION 10 #define BDOOR_CMD_GETDEVICELISTELEMENT 11 #define BDOOR_CMD_TOGGLEDEVICE 12 #define BDOOR_CMD_GETGUIOPTIONS 13 #define BDOOR_CMD_SETGUIOPTIONS 14 #define BDOOR_CMD_GETSCREENSIZE 15 #define BDOOR_CMD_MONITOR_CONTROL 16 #define BDOOR_CMD_GETHWVERSION 17 #define BDOOR_CMD_OSNOTFOUND 18 #define BDOOR_CMD_GETUUID 19 #define BDOOR_CMD_GETMEMSIZE 20 #define BDOOR_CMD_HOSTCOPY 21 /* Devel only */ #define BDOOR_CMD_SERVICE_VM 22 /* Unused, never shipped, prototype only */ #define BDOOR_CMD_GETTIME 23 /* Deprecated. Use GETTIMEFULL. */ #define BDOOR_CMD_STOPCATCHUP 24 #define BDOOR_CMD_PUTCHR 25 /* Devel only */ #define BDOOR_CMD_ENABLE_MSG 26 /* Devel only */ #define BDOOR_CMD_GOTO_TCL 27 /* Devel only */ #define BDOOR_CMD_INITPCIOPROM 28 #define BDOOR_CMD_INT13 29 #define BDOOR_CMD_MESSAGE 30 #define BDOOR_CMD_RSVD0 31 #define BDOOR_CMD_RSVD1 32 #define BDOOR_CMD_RSVD2 33 #define BDOOR_CMD_ISACPIDISABLED 34 #define BDOOR_CMD_TOE 35 /* Not in use */ #define BDOOR_CMD_ISMOUSEABSOLUTE 36 #define BDOOR_CMD_PATCH_SMBIOS_STRUCTS 37 #define BDOOR_CMD_MAPMEM 38 /* Devel only */ #define BDOOR_CMD_ABSPOINTER_DATA 39 #define BDOOR_CMD_ABSPOINTER_STATUS 40 #define BDOOR_CMD_ABSPOINTER_COMMAND 41 #define BDOOR_CMD_TIMER_SPONGE 42 /* Not supported anymore */ #define BDOOR_CMD_PATCH_ACPI_TABLES 43 /* Catch-all to allow synchronous tests */ #define BDOOR_CMD_DEVEL_FAKEHARDWARE 44 /* Debug only - needed in beta */ #define BDOOR_CMD_GETHZ 45 #define BDOOR_CMD_GETTIMEFULL 46 #define BDOOR_CMD_STATELOGGER 47 #define BDOOR_CMD_CHECKFORCEBIOSSETUP 48 #define BDOOR_CMD_LAZYTIMEREMULATION 49 #define BDOOR_CMD_BIOSBBS 50 #define BDOOR_CMD_VASSERT 51 #define BDOOR_CMD_ISGOSDARWIN 52 #define BDOOR_CMD_DEBUGEVENT 53 #define BDOOR_CMD_OSNOTMACOSXSERVER 54 #define BDOOR_CMD_GETTIMEFULL_WITH_LAG 55 #define BDOOR_CMD_ACPI_HOTPLUG_DEVICE 56 #define BDOOR_CMD_ACPI_HOTPLUG_MEMORY 57 #define BDOOR_CMD_ACPI_HOTPLUG_CBRET 58 #define BDOOR_CMD_GET_HOST_VIDEO_MODES 59 /* Not in use */ #define BDOOR_CMD_ACPI_HOTPLUG_CPU 60 #define BDOOR_CMD_USB_HOTPLUG_MOUSE 61 /* Not in use */ #define BDOOR_CMD_XPMODE 62 #define BDOOR_CMD_NESTING_CONTROL 63 #define BDOOR_CMD_FIRMWARE_INIT 64 #define BDOOR_CMD_FIRMWARE_ACPI_SERVICES 65 # define BDOOR_CMD_FAS_GET_TABLE_SIZE 0 # define BDOOR_CMD_FAS_GET_TABLE_DATA 1 # define BDOOR_CMD_FAS_GET_PLATFORM_NAME 2 # define BDOOR_CMD_FAS_GET_PCIE_OSC_MASK 3 #define BDOOR_CMD_SENDPSHAREHINTS 66 #define BDOOR_CMD_ENABLE_USB_MOUSE 67 #define BDOOR_CMD_GET_VCPU_INFO 68 # define BDOOR_CMD_VCPU_SLC64 0 # define BDOOR_CMD_VCPU_SYNC_VTSCS 1 # define BDOOR_CMD_VCPU_HV_REPLAY_OK 2 # define BDOOR_CMD_VCPU_RESERVED 31 #define BDOOR_CMD_EFI_SERIALCON_CONFIG 69 #define BDOOR_CMD_BUG328986 70 #define BDOOR_CMD_FIRMWARE_ERROR 71 # define BDOOR_CMD_FE_INSUFFICIENT_MEM 0 # define BDOOR_CMD_FE_EXCEPTION 1 #define BDOOR_CMD_MAX 72 /* * IMPORTANT NOTE: When modifying the behavior of an existing backdoor command, * you must adhere to the semantics expected by the oldest Tools who use that * command. Specifically, do not alter the way in which the command modifies * the registers. Otherwise backwards compatibility will suffer. */ /* Processing mode for guest pshare hints (SENDPSHAREHINTS cmd) */ #define BDOOR_PSHARE_HINTS_ASYNC 0 #define BDOOR_PSHARE_HINTS_SYNC 1 #define BDOOR_PSHARE_HINTS_TYPE(ecx) (((ecx) >> 16) & 0x1) /* Version of backdoor pshare hints protocol */ #define BDOOR_PSHARE_HINTS_VERSION 1 #define BDOOR_PSHARE_HINTS_VER(ecx) (((ecx) >> 17) & 0x7f) /* Task applied to backdoor pshare hints */ #define BDOOR_PSHARE_HINTS_CMD_SHARE 0 #define BDOOR_PSHARE_HINTS_CMD_DROP 1 #define BDOOR_PSHARE_HINTS_CMD(ecx) (((ecx) >> 24) & 0x1) /* Nesting control operations */ #define NESTING_CONTROL_RESTRICT_BACKDOOR 0 #define NESTING_CONTROL_OPEN_BACKDOOR 1 #define NESTING_CONTROL_QUERY 2 #define NESTING_CONTROL_MAX 2 /* High-bandwidth backdoor port. --hpreg */ #define BDOORHB_PORT 0x5659 #define BDOORHB_CMD_MESSAGE 0 #define BDOORHB_CMD_VASSERT 1 #define BDOORHB_CMD_MAX 2 /* * There is another backdoor which allows access to certain TSC-related * values using otherwise illegal PMC indices when the pseudo_perfctr * control flag is set. */ #define BDOOR_PMC_HW_TSC 0x10000 #define BDOOR_PMC_REAL_NS 0x10001 #define BDOOR_PMC_APPARENT_NS 0x10002 #define BDOOR_PMC_PSEUDO_TSC 0x10003 #define IS_BDOOR_PMC(index) (((index) | 3) == 0x10003) #define BDOOR_CMD(ecx) ((ecx) & 0xffff) #ifdef VMM /* *---------------------------------------------------------------------- * * Backdoor_CmdRequiresFullyValidVCPU -- * * A few backdoor commands require the full VCPU to be valid * (including GDTR, IDTR, TR and LDTR). The rest get read/write * access to GPRs and read access to Segment registers (selectors). * * Result: * True iff VECX contains a command that require the full VCPU to * be valid. * *---------------------------------------------------------------------- */ static INLINE Bool Backdoor_CmdRequiresFullyValidVCPU(unsigned cmd) { return cmd == BDOOR_CMD_RSVD0 || cmd == BDOOR_CMD_RSVD1 || cmd == BDOOR_CMD_RSVD2; } #endif #endif vmci-only/shared/compat_string.h 0000444 0000000 0000000 00000003563 11573420431 015766 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __COMPAT_STRING_H__ # define __COMPAT_STRING_H__ #include <linux/string.h> /* * kstrdup was born in 2.6.13. This implementation is almost identical to the * one found there. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) #define compat_kstrdup(s, gfp) kstrdup(s, gfp) #else #define compat_kstrdup(s, gfp) \ ({ \ size_t len; \ char *buf; \ len = strlen(s) + 1; \ buf = kmalloc(len, gfp); \ memcpy(buf, s, len); \ buf; \ }) #endif #endif /* __COMPAT_STRING_H__ */ vmci-only/shared/x86cpuid_asm.h 0000444 0000000 0000000 00000022267 11573420432 015432 0 ustar root root /********************************************************* * Copyright (C) 2003-2009 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 * *********************************************************/ /* * x86cpuid_asm.h * * CPUID-related assembly functions. */ #ifndef _X86CPUID_ASM_H_ #define _X86CPUID_ASM_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #include "vm_basic_asm.h" #include "x86cpuid.h" /* * x86-64 windows doesn't support inline asm so we have to use these * intrinsic functions defined in the compiler. Not all of these are well * documented. There is an array in the compiler dll (c1.dll) which has * an array of the names of all the intrinsics minus the leading * underscore. Searching around in the ntddk.h file can also be helpful. * * The declarations for the intrinsic functions were taken from the DDK. * Our declarations must match the ddk's otherwise the 64-bit c++ compiler * will complain about second linkage of the intrinsic functions. * We define the intrinsic using the basic types corresponding to the * Windows typedefs. This avoids having to include windows header files * to get to the windows types. */ #ifdef _MSC_VER #ifdef __cplusplus extern "C" { #endif #ifdef VM_X86_64 /* * intrinsic functions only supported by x86-64 windows as of 2k3sp1 */ void __cpuid(unsigned int*, unsigned int); #pragma intrinsic(__cpuid) #endif /* VM_X86_64 */ #ifdef __cplusplus } #endif #endif /* _MSC_VER */ #ifdef __GNUC__ // { /* * Checked against the Intel manual and GCC --hpreg * * Need __volatile__ and "memory" since CPUID has a synchronizing effect. * The CPUID may also change at runtime (APIC flag, etc). * */ /* * %ebx is reserved on i386 PIC. Apple's gcc-5493 (gcc 4.0) compiling * for x86_64 incorrectly errors out saying %ebx is reserved. This is * Apple bug 7304232. */ #if vm_x86_64 ? (defined __APPLE_CC__ && __APPLE_CC__ == 5493) : defined __PIC__ #if vm_x86_64 /* * Note that this generates movq %rbx,%rbx; cpuid; xchgq %rbx,%rbx ... * Unfortunately Apple's assembler does not have .ifnes, and I cannot * figure out how to do that with .if. If we ever enable this code * on other 64bit systems, both movq & xchgq should be surrounded by * .ifnes \"%%rbx\", \"%q1\" & .endif */ #define VM_CPUID_BLOCK "movq %%rbx, %q1\n\t" \ "cpuid\n\t" \ "xchgq %%rbx, %q1\n\t" #define VM_EBX_OUT(reg) "=&r"(reg) #else #define VM_CPUID_BLOCK "movl %%ebx, %1\n\t" \ "cpuid\n\t" \ "xchgl %%ebx, %1\n\t" #define VM_EBX_OUT(reg) "=&rm"(reg) #endif #else #define VM_CPUID_BLOCK "cpuid" #define VM_EBX_OUT(reg) "=b"(reg) #endif static INLINE void __GET_CPUID(int eax, // IN CPUIDRegs *regs) // OUT { __asm__ __volatile__( VM_CPUID_BLOCK : "=a" (regs->eax), VM_EBX_OUT(regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) : "a" (eax) : "memory" ); } static INLINE void __GET_CPUID2(int eax, // IN int ecx, // IN CPUIDRegs *regs) // OUT { __asm__ __volatile__( VM_CPUID_BLOCK : "=a" (regs->eax), VM_EBX_OUT(regs->ebx), "=c" (regs->ecx), "=d" (regs->edx) : "a" (eax), "c" (ecx) : "memory" ); } static INLINE uint32 __GET_EAX_FROM_CPUID(int eax) // IN { uint32 ebx; __asm__ __volatile__( VM_CPUID_BLOCK : "=a" (eax), VM_EBX_OUT(ebx) : "a" (eax) : "memory", "%ecx", "%edx" ); return eax; } static INLINE uint32 __GET_EBX_FROM_CPUID(int eax) // IN { uint32 ebx; __asm__ __volatile__( VM_CPUID_BLOCK : "=a" (eax), VM_EBX_OUT(ebx) : "a" (eax) : "memory", "%ecx", "%edx" ); return ebx; } static INLINE uint32 __GET_ECX_FROM_CPUID(int eax) // IN { uint32 ecx; uint32 ebx; __asm__ __volatile__( VM_CPUID_BLOCK : "=a" (eax), VM_EBX_OUT(ebx), "=c" (ecx) : "a" (eax) : "memory", "%edx" ); return ecx; } static INLINE uint32 __GET_EDX_FROM_CPUID(int eax) // IN { uint32 edx; uint32 ebx; __asm__ __volatile__( VM_CPUID_BLOCK : "=a" (eax), VM_EBX_OUT(ebx), "=d" (edx) : "a" (eax) : "memory", "%ecx" ); return edx; } static INLINE uint32 __GET_EAX_FROM_CPUID4(int ecx) // IN { uint32 eax; uint32 ebx; __asm__ __volatile__( VM_CPUID_BLOCK : "=a" (eax), VM_EBX_OUT(ebx), "=c" (ecx) : "a" (4), "c" (ecx) : "memory", "%edx" ); return eax; } #undef VM_CPUID_BLOCK #undef VM_EBX_OUT #elif defined(_MSC_VER) // } { static INLINE void __GET_CPUID(int input, CPUIDRegs *regs) { #ifdef VM_X86_64 __cpuid((unsigned int *)regs, input); #else __asm push esi __asm push ebx __asm push ecx __asm push edx __asm mov eax, input __asm mov esi, regs __asm _emit 0x0f __asm _emit 0xa2 __asm mov 0x0[esi], eax __asm mov 0x4[esi], ebx __asm mov 0x8[esi], ecx __asm mov 0xC[esi], edx __asm pop edx __asm pop ecx __asm pop ebx __asm pop esi #endif } #ifdef VM_X86_64 /* * No inline assembly in Win64. Implemented in bora/lib/user in * cpuidMasm64.asm. */ extern void __GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs); #else // VM_X86_64 static INLINE void __GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs) { __asm push esi __asm push ebx __asm push ecx __asm push edx __asm mov eax, inputEax __asm mov ecx, inputEcx __asm mov esi, regs __asm _emit 0x0f __asm _emit 0xa2 __asm mov 0x0[esi], eax __asm mov 0x4[esi], ebx __asm mov 0x8[esi], ecx __asm mov 0xC[esi], edx __asm pop edx __asm pop ecx __asm pop ebx __asm pop esi } #endif static INLINE uint32 __GET_EAX_FROM_CPUID(int input) { #ifdef VM_X86_64 CPUIDRegs regs; __cpuid((unsigned int *)®s, input); return regs.eax; #else uint32 output; //NOT_TESTED(); __asm push ebx __asm push ecx __asm push edx __asm mov eax, input __asm _emit 0x0f __asm _emit 0xa2 __asm mov output, eax __asm pop edx __asm pop ecx __asm pop ebx return output; #endif } static INLINE uint32 __GET_EBX_FROM_CPUID(int input) { #ifdef VM_X86_64 CPUIDRegs regs; __cpuid((unsigned int *)®s, input); return regs.ebx; #else uint32 output; //NOT_TESTED(); __asm push ebx __asm push ecx __asm push edx __asm mov eax, input __asm _emit 0x0f __asm _emit 0xa2 __asm mov output, ebx __asm pop edx __asm pop ecx __asm pop ebx return output; #endif } static INLINE uint32 __GET_ECX_FROM_CPUID(int input) { #ifdef VM_X86_64 CPUIDRegs regs; __cpuid((unsigned int *)®s, input); return regs.ecx; #else uint32 output; //NOT_TESTED(); __asm push ebx __asm push ecx __asm push edx __asm mov eax, input __asm _emit 0x0f __asm _emit 0xa2 __asm mov output, ecx __asm pop edx __asm pop ecx __asm pop ebx return output; #endif } static INLINE uint32 __GET_EDX_FROM_CPUID(int input) { #ifdef VM_X86_64 CPUIDRegs regs; __cpuid((unsigned int *)®s, input); return regs.edx; #else uint32 output; //NOT_TESTED(); __asm push ebx __asm push ecx __asm push edx __asm mov eax, input __asm _emit 0x0f __asm _emit 0xa2 __asm mov output, edx __asm pop edx __asm pop ecx __asm pop ebx return output; #endif } #ifdef VM_X86_64 /* * No inline assembly in Win64. Implemented in bora/lib/user in * cpuidMasm64.asm. */ extern uint32 __GET_EAX_FROM_CPUID4(int inputEcx); #else // VM_X86_64 static INLINE uint32 __GET_EAX_FROM_CPUID4(int inputEcx) { uint32 output; //NOT_TESTED(); __asm push ebx __asm push ecx __asm push edx __asm mov eax, 4 __asm mov ecx, inputEcx __asm _emit 0x0f __asm _emit 0xa2 __asm mov output, eax __asm pop edx __asm pop ecx __asm pop ebx return output; } #endif // VM_X86_64 #else // } #error #endif #define CPUID_FOR_SIDE_EFFECTS() ((void)__GET_EAX_FROM_CPUID(0)) static INLINE void __GET_CPUID4(int inputEcx, CPUIDRegs *regs) { __GET_CPUID2(4, inputEcx, regs); } /* The first parameter is used as an rvalue and then as an lvalue. */ #define GET_CPUID(_ax, _bx, _cx, _dx) { \ CPUIDRegs regs; \ __GET_CPUID(_ax, ®s); \ _ax = regs.eax; \ _bx = regs.ebx; \ _cx = regs.ecx; \ _dx = regs.edx; \ } #endif vmci-only/shared/vm_basic_math.h 0000444 0000000 0000000 00000003773 11573420432 015715 0 ustar root root /********************************************************* * Copyright (C) 2008 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ /* * vm_basic_math.h -- * * Standard mathematical macros for VMware source code. */ #ifndef _VM_BASIC_MATH_H_ #define _VM_BASIC_MATH_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMIROM #include "includeCheck.h" #include "vm_basic_types.h" // For INLINE. #include "vm_basic_asm.h" // For Div64... static INLINE uint32 RatioOf(uint32 numer1, uint32 numer2, uint32 denom) { uint64 numer = (uint64)numer1 * numer2; /* Calculate "(numer1 * numer2) / denom" avoiding round-off errors. */ #if defined(VMM) || !(defined(__i386__) || defined(__x86_64__)) return numer / denom; #else uint32 ratio; uint32 unused; Div643232(numer, denom, &ratio, &unused); return ratio; #endif } static INLINE uint32 ExponentialAvg(uint32 avg, uint32 value, uint32 gainNumer, uint32 gainDenom) { uint32 term1 = gainNumer * avg; uint32 term2 = (gainDenom - gainNumer) * value; return (term1 + term2) / gainDenom; } #endif // ifndef _VM_BASIC_MATH_H_ vmci-only/shared/vmciKernelAPI.h 0000444 0000000 0000000 00000002410 11573420432 015535 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciKernelAPI.h -- * * Kernel API (current) exported from the VMCI host and guest drivers. */ #ifndef __VMCI_KERNELAPI_H__ #define __VMCI_KERNELAPI_H__ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" /* With this file you always get the latest version. */ #include "vmciKernelAPI1.h" #include "vmciKernelAPI2.h" #endif /* !__VMCI_KERNELAPI_H__ */ vmci-only/shared/compat_cred.h 0000444 0000000 0000000 00000002560 11573420431 015371 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_CRED_H__ # define __COMPAT_CRED_H__ /* * Include linux/cred.h via linux/sched.h - it is not nice, but * as cpp does not have #ifexist... */ #include <linux/sched.h> #if !defined(current_fsuid) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) #define current_uid() (current->uid) #define current_euid() (current->euid) #define current_fsuid() (current->fsuid) #define current_gid() (current->gid) #define current_egid() (current->egid) #define current_fsgid() (current->fsgid) #endif #endif /* __COMPAT_CRED_H__ */ vmci-only/shared/vm_basic_asm_x86_64.h 0000444 0000000 0000000 00000027312 11573420432 016555 0 ustar root root /********************************************************* * Copyright (C) 1998-2004 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU 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_basic_asm_x86_64.h * * Basic x86_64 asm macros. */ #ifndef _VM_BASIC_ASM_X86_64_H_ #define _VM_BASIC_ASM_X86_64_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #include "includeCheck.h" #ifndef VM_X86_64 #error "This file is x86-64 only!" #endif #ifdef _MSC_VER #ifdef __cplusplus extern "C" { #endif uint64 _umul128(uint64 multiplier, uint64 multiplicand, uint64 *highProduct); int64 _mul128(int64 multiplier, int64 multiplicand, int64 *highProduct); uint64 __shiftright128(uint64 lowPart, uint64 highPart, uint8 shift); #ifdef __cplusplus } #endif #pragma intrinsic(_umul128, _mul128, __shiftright128) #endif // _MSC_VER /* * FXSAVE/FXRSTOR * save/restore SIMD/MMX fpu state * * The pointer passed in must be 16-byte aligned. * * Intel and AMD processors behave differently w.r.t. fxsave/fxrstor. Intel * processors unconditionally save the exception pointer state (instruction * ptr., data ptr., and error instruction opcode). FXSAVE_ES1 and FXRSTOR_ES1 * work correctly for Intel processors. * * AMD processors only save the exception pointer state if ES=1. This leads to a * security hole whereby one process/VM can inspect the state of another process * VM. The AMD recommended workaround involves clobbering the exception pointer * state unconditionally, and this is implemented in FXRSTOR_AMD_ES0. Note that * FXSAVE_ES1 will only save the exception pointer state for AMD processors if * ES=1. * * The workaround (FXRSTOR_AMD_ES0) only costs 1 cycle more than just doing an * fxrstor, on both AMD Opteron and Intel Core CPUs. */ #if defined(__GNUC__) static INLINE void FXSAVE_ES1(uint8 *save) { __asm__ __volatile__ ("fxsaveq %0 \n" : "=m" (*save) : : "memory"); } static INLINE void FXSAVE_COMPAT_ES1(uint8 *save) { __asm__ __volatile__ ("fxsave %0 \n" : "=m" (*save) : : "memory"); } static INLINE void FXRSTOR_ES1(const uint8 *load) { __asm__ __volatile__ ("fxrstorq %0 \n" : : "m" (*load) : "memory"); } static INLINE void FXRSTOR_COMPAT_ES1(const uint8 *load) { __asm__ __volatile__ ("fxrstor %0 \n" : : "m" (*load) : "memory"); } static INLINE void FXRSTOR_AMD_ES0(const uint8 *load) { uint64 dummy = 0; __asm__ __volatile__ ("fnstsw %%ax \n" // Grab x87 ES bit "bt $7,%%ax \n" // Test ES bit "jnc 1f \n" // Jump if ES=0 "fnclex \n" // ES=1. Clear it so fild doesn't trap "1: \n" "ffree %%st(7) \n" // Clear tag bit - avoid poss. stack overflow "fildl %0 \n" // Dummy Load from "safe address" changes all // x87 exception pointers. "fxrstorq %1 \n" : : "m" (dummy), "m" (*load) : "ax", "memory"); } #endif /* __GNUC__ */ /* * XSAVE/XRSTOR * save/restore GSSE/SIMD/MMX fpu state * * The pointer passed in must be 64-byte aligned. * See above comment for more information. */ #if defined(__GNUC__) && (defined(VMM) || defined(VMKERNEL) || defined(FROBOS)) static INLINE void XSAVE_ES1(uint8 *save, uint64 mask) { #if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1 __asm__ __volatile__ ( ".byte 0x48, 0x0f, 0xae, 0x21 \n" : : "c" (save), "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #else __asm__ __volatile__ ( "xsaveq %0 \n" : "=m" (*save) : "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #endif } static INLINE void XSAVE_COMPAT_ES1(uint8 *save, uint64 mask) { #if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1 __asm__ __volatile__ ( ".byte 0x0f, 0xae, 0x21 \n" : : "c" (save), "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #else __asm__ __volatile__ ( "xsave %0 \n" : "=m" (*save) : "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #endif } static INLINE void XRSTOR_ES1(const uint8 *load, uint64 mask) { #if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1 __asm__ __volatile__ ( ".byte 0x48, 0x0f, 0xae, 0x29 \n" : : "c" (load), "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #else __asm__ __volatile__ ( "xrstorq %0 \n" : : "m" (*load), "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #endif } static INLINE void XRSTOR_COMPAT_ES1(const uint8 *load, uint64 mask) { #if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1 __asm__ __volatile__ ( ".byte 0x0f, 0xae, 0x29 \n" : : "c" (load), "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #else __asm__ __volatile__ ( "xrstor %0 \n" : : "m" (*load), "a" ((uint32)mask), "d" ((uint32)(mask >> 32)) : "memory"); #endif } static INLINE void XRSTOR_AMD_ES0(const uint8 *load, uint64 mask) { uint64 dummy = 0; __asm__ __volatile__ ("fnstsw %%ax \n" // Grab x87 ES bit "bt $7,%%ax \n" // Test ES bit "jnc 1f \n" // Jump if ES=0 "fnclex \n" // ES=1. Clear it so fild doesn't trap "1: \n" "ffree %%st(7) \n" // Clear tag bit - avoid poss. stack overflow "fildl %0 \n" // Dummy Load from "safe address" changes all // x87 exception pointers. "mov %%ebx, %%eax \n" #if __GNUC__ < 4 || __GNUC__ == 4 && __GNUC_MINOR__ == 1 ".byte 0x48, 0x0f, 0xae, 0x29 \n" : : "m" (dummy), "c" (load), "b" ((uint32)mask), "d" ((uint32)(mask >> 32)) #else "xrstorq %1 \n" : : "m" (dummy), "m" (*load), "b" ((uint32)mask), "d" ((uint32)(mask >> 32)) #endif : "eax", "memory"); } #endif /* __GNUC__ */ /* *----------------------------------------------------------------------------- * * Mul64x3264 -- * * Unsigned integer by fixed point multiplication: * result = multiplicand * multiplier >> shift * * Unsigned 64-bit integer multiplicand. * Unsigned 32-bit fixed point multiplier, represented as * multiplier >> shift, where shift < 64. * Unsigned 64-bit integer product. * * Implementation: * Multiply 64x64 bits to yield a full 128-bit product. * Shift result in RDX:RAX right by "shift". * Return the low-order 64 bits of the above. * * Result: * Product * *----------------------------------------------------------------------------- */ #if defined(__GNUC__) static INLINE uint64 Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) { uint64 result, dummy; const uint64 multiplier64 = multiplier; __asm__("mulq %3 \n\t" "shrdq %1, %0 \n\t" : "=a" (result), "=d" (dummy) : "0" (multiplier64), "rm" (multiplicand), "c" (shift) : "cc"); return result; } #elif defined(_MSC_VER) static INLINE uint64 Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift) { uint64 tmplo, tmphi; tmplo = _umul128(multiplicand, multiplier, &tmphi); return __shiftright128(tmplo, tmphi, (uint8) shift); } #endif /* *----------------------------------------------------------------------------- * * Muls64x32s64 -- * * Signed integer by fixed point multiplication: * result = multiplicand * multiplier >> shift * * Signed 64-bit integer multiplicand. * Unsigned 32-bit fixed point multiplier, represented as * multiplier >> shift, where shift < 64. * Signed 64-bit integer product. * * Implementation: * Multiply 64x64 bits to yield a full 128-bit product. * Shift result in RDX:RAX right by "shift". * Return the low-order 64 bits of the above. * * Note: using an unsigned shift instruction is correct because * shift < 64 and we return only the low 64 bits of the shifted * result. * * Result: * Product * *----------------------------------------------------------------------------- */ #if defined(__GNUC__) static inline int64 Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) { int64 result, dummy; const int64 multiplier64 = multiplier; __asm__("imulq %3 \n\t" "shrdq %1, %0 \n\t" : "=a" (result), "=d" (dummy) : "0" (multiplier64), "rm" (multiplicand), "c" (shift) : "cc"); return result; } #elif defined(_MSC_VER) static INLINE int64 Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift) { int64 tmplo, tmphi; tmplo = _mul128(multiplicand, multiplier, &tmphi); return __shiftright128(tmplo, tmphi, (uint8) shift); } #endif #if defined(__GNUC__) static INLINE void * uint64set(void *dst, uint64 val, uint64 count) { int dummy0; int dummy1; __asm__ __volatile__("\t" "cld" "\n\t" "rep ; stosq" "\n" : "=c" (dummy0), "=D" (dummy1) : "0" (count), "1" (dst), "a" (val) : "memory", "cc"); return dst; } #endif /* *----------------------------------------------------------------------------- * * Div643232 -- * * Unsigned integer division: * The dividend is 64-bit wide * The divisor is 32-bit wide * The quotient is 32-bit wide * * Use this function if you are certain that the quotient will fit in 32 bits, * If that is not the case, a #DE exception was generated in 32-bit version, * but not in this 64-bit version. So please be careful. * * Results: * Quotient and remainder * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(__GNUC__) || defined(_MSC_VER) static INLINE void Div643232(uint64 dividend, // IN uint32 divisor, // IN uint32 *quotient, // OUT uint32 *remainder) // OUT { *quotient = (uint32)(dividend / divisor); *remainder = (uint32)(dividend % divisor); } #endif /* *----------------------------------------------------------------------------- * * Div643264 -- * * Unsigned integer division: * The dividend is 64-bit wide * The divisor is 32-bit wide * The quotient is 64-bit wide * * Results: * Quotient and remainder * * Side effects: * None * *----------------------------------------------------------------------------- */ #if defined(__GNUC__) static INLINE void Div643264(uint64 dividend, // IN uint32 divisor, // IN uint64 *quotient, // OUT uint32 *remainder) // OUT { *quotient = dividend / divisor; *remainder = dividend % divisor; } #endif #endif // _VM_BASIC_ASM_X86_64_H_ vmci-only/shared/compat_netdevice.h 0000444 0000000 0000000 00000023566 11573420431 016433 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_NETDEVICE_H__ # define __COMPAT_NETDEVICE_H__ #include <linux/skbuff.h> #include <linux/rtnetlink.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> /* * The enet_statistics structure moved from linux/if_ether.h to * linux/netdevice.h and is renamed net_device_stats in 2.1.25 --hpreg */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 25) # include <linux/if_ether.h> # define net_device_stats enet_statistics #endif /* The netif_rx_ni() API appeared in 2.4.8 --hpreg */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 8) # define netif_rx_ni netif_rx #endif /* The device struct was renamed net_device in 2.3.14 --hpreg */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14) # define net_device device #endif /* * SET_MODULE_OWNER appeared sometime during 2.3.x. It was setting * dev->owner = THIS_MODULE until 2.5.70, where netdevice refcounting * was completely changed. SET_MODULE_OWNER was nop for whole * 2.6.x series, and finally disappeared in 2.6.24. * * MOD_xxx_USE_COUNT wrappers are here, as they must be mutually * exclusive with SET_MODULE_OWNER call. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) # define COMPAT_SET_MODULE_OWNER(dev) do {} while (0) # define COMPAT_NETDEV_MOD_INC_USE_COUNT MOD_INC_USE_COUNT # define COMPAT_NETDEV_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT #else # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) # define COMPAT_SET_MODULE_OWNER(dev) SET_MODULE_OWNER(dev) # else # define COMPAT_SET_MODULE_OWNER(dev) do {} while (0) # endif # define COMPAT_NETDEV_MOD_INC_USE_COUNT do {} while (0) # define COMPAT_NETDEV_MOD_DEC_USE_COUNT do {} while (0) #endif /* * SET_NETDEV_DEV appeared sometime during 2.5.x, and later was * crossported to various 2.4.x kernels (as dummy macro). */ #ifdef SET_NETDEV_DEV # define COMPAT_SET_NETDEV_DEV(dev, pdev) SET_NETDEV_DEV(dev, pdev) #else # define COMPAT_SET_NETDEV_DEV(dev, pdev) do {} while (0) #endif /* * Build alloc_etherdev API on the top of init_etherdev. For 2.0.x kernels * we must provide dummy init method, otherwise register_netdev does * nothing. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) int vmware_dummy_init(struct net_device *dev) { return 0; } #endif static inline struct net_device* compat_alloc_etherdev(int priv_size) { struct net_device* dev; int size = sizeof *dev + priv_size; /* * The name is dynamically allocated before 2.4.0, but * is an embedded array in later kernels. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) size += sizeof("ethXXXXXXX"); #endif dev = kmalloc(size, GFP_KERNEL); if (dev) { memset(dev, 0, size); if (priv_size) { dev->priv = dev + 1; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) dev->name = (char *)(dev + 1) + priv_size; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) dev->init = vmware_dummy_init; #endif if (init_etherdev(dev, 0) != dev) { kfree(dev); dev = NULL; } } return dev; } #else #define compat_alloc_etherdev(sz) alloc_etherdev(sz) #endif /* * alloc_netdev and free_netdev are there since 2.4.23. Their use is mandatory * since 2.6.24. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23) static inline struct net_device * compat_alloc_netdev(int priv_size, const char *mask, void (*setup)(struct net_device *)) { struct net_device *dev; int netdev_size = sizeof *dev; int alloc_size; # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) netdev_size += IFNAMSIZ; # endif alloc_size = netdev_size + priv_size; dev = kmalloc(alloc_size, GFP_KERNEL); if (dev) { memset(dev, 0, alloc_size); dev->priv = (char*)dev + netdev_size; setup(dev); # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) dev->name = (char*)(dev + 1); # endif strcpy(dev->name, mask); } return dev; } # define compat_free_netdev(dev) kfree(dev) #else # define compat_alloc_netdev(size, mask, setup) alloc_netdev(size, mask, setup) # define compat_free_netdev(dev) free_netdev(dev) #endif /* netdev_priv() appeared in 2.6.3 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3) # define compat_netdev_priv(netdev) (netdev)->priv #else # define compat_netdev_priv(netdev) netdev_priv(netdev) #endif /* * All compat_* business is good but when we can we should just provide * missing implementation to ease upstreaming task. */ #ifndef HAVE_ALLOC_NETDEV #define alloc_netdev(sz, name, setup) compat_alloc_netdev(sz, name, setup) #define alloc_etherdev(sz) compat_alloc_etherdev(sz) #endif #ifndef HAVE_FREE_NETDEV #define free_netdev(dev) kfree(dev) #endif #ifndef HAVE_NETDEV_PRIV #define netdev_priv(dev) ((dev)->priv) #endif #if defined(NETDEV_TX_OK) # define COMPAT_NETDEV_TX_OK NETDEV_TX_OK # define COMPAT_NETDEV_TX_BUSY NETDEV_TX_BUSY #else # define COMPAT_NETDEV_TX_OK 0 # define COMPAT_NETDEV_TX_BUSY 1 #endif #ifndef HAVE_NETIF_QUEUE static inline void netif_start_queue(struct device *dev) { clear_bit(0, &dev->tbusy); } static inline void netif_stop_queue(struct device *dev) { set_bit(0, &dev->tbusy); } static inline int netif_queue_stopped(struct device *dev) { return test_bit(0, &dev->tbusy); } static inline void netif_wake_queue(struct device *dev) { clear_bit(0, &dev->tbusy); mark_bh(NET_BH); } static inline int netif_running(struct device *dev) { return dev->start == 0; } static inline int netif_carrier_ok(struct device *dev) { return 1; } static inline void netif_carrier_on(struct device *dev) { } static inline void netif_carrier_off(struct device *dev) { } #endif /* Keep compat_* defines for now */ #define compat_netif_start_queue(dev) netif_start_queue(dev) #define compat_netif_stop_queue(dev) netif_stop_queue(dev) #define compat_netif_queue_stopped(dev) netif_queue_stopped(dev) #define compat_netif_wake_queue(dev) netif_wake_queue(dev) #define compat_netif_running(dev) netif_running(dev) #define compat_netif_carrier_ok(dev) netif_carrier_ok(dev) #define compat_netif_carrier_on(dev) netif_carrier_on(dev) #define compat_netif_carrier_off(dev) netif_carrier_off(dev) /* unregister_netdevice_notifier was not safe prior to 2.6.17 */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17) && \ !defined(ATOMIC_NOTIFIER_INIT) /* pre 2.6.17 and not patched */ static inline int compat_unregister_netdevice_notifier(struct notifier_block *nb) { int err; rtnl_lock(); err = unregister_netdevice_notifier(nb); rtnl_unlock(); return err; } #else /* post 2.6.17 or patched */ #define compat_unregister_netdevice_notifier(_nb) \ unregister_netdevice_notifier(_nb); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) # define compat_netif_napi_add(dev, napi, poll, quota) \ netif_napi_add(dev, napi, poll, quota) # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) || \ defined VMW_NETIF_SINGLE_NAPI_PARM # define compat_napi_complete(dev, napi) napi_complete(napi) # define compat_napi_schedule(dev, napi) napi_schedule(napi) # else # define compat_napi_complete(dev, napi) netif_rx_complete(dev, napi) # define compat_napi_schedule(dev, napi) netif_rx_schedule(dev, napi) # endif # define compat_napi_enable(dev, napi) napi_enable(napi) # define compat_napi_disable(dev, napi) napi_disable(napi) #else # define compat_napi_complete(dev, napi) netif_rx_complete(dev) # define compat_napi_schedule(dev, napi) netif_rx_schedule(dev) # define compat_napi_enable(dev, napi) netif_poll_enable(dev) # define compat_napi_disable(dev, napi) netif_poll_disable(dev) /* RedHat ported GRO to 2.6.18 bringing new napi_struct with it */ # if defined NETIF_F_GRO # define compat_netif_napi_add(netdev, napi, pollcb, quota) \ do { \ (netdev)->poll = (pollcb); \ (netdev)->weight = (quota);\ (napi)->dev = (netdev); \ } while (0) # else struct napi_struct { int dummy; }; # define compat_netif_napi_add(dev, napi, pollcb, quota) \ do { \ (dev)->poll = (pollcb); \ (dev)->weight = (quota);\ } while (0) # endif #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) # define compat_netif_tx_lock(dev) netif_tx_lock(dev) # define compat_netif_tx_unlock(dev) netif_tx_unlock(dev) #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) # define compat_netif_tx_lock(dev) spin_lock(&dev->xmit_lock) # define compat_netif_tx_unlock(dev) spin_unlock(&dev->xmit_lock) #else /* Vendor backporting (SLES 10) has muddled the tx_lock situation. Pick whichever * of the above works for you. */ # define compat_netif_tx_lock(dev) do {} while (0) # define compat_netif_tx_unlock(dev) do {} while (0) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) # define COMPAT_VLAN_GROUP_ARRAY_LEN VLAN_N_VID #else # define COMPAT_VLAN_GROUP_ARRAY_LEN VLAN_GROUP_ARRAY_LEN #endif #endif /* __COMPAT_NETDEVICE_H__ */ vmci-only/shared/driver-config.h 0000444 0000000 0000000 00000004212 11573420431 015643 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * Sets the proper defines from the Linux header files * * This file must be included before the inclusion of any kernel header file, * with the exception of linux/autoconf.h and linux/version.h --hpreg */ #ifndef __VMX_CONFIG_H__ #define __VMX_CONFIG_H__ #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_MODULE #include "includeCheck.h" #include "compat_version.h" #include "compat_autoconf.h" /* * We rely on Kernel Module support. Check here. */ #ifndef CONFIG_MODULES # error "No Module support in this kernel. Please configure with CONFIG_MODULES" #endif /* * 2.2 kernels still use __SMP__ (derived from CONFIG_SMP * in the main Makefile), so we do it here. */ #ifdef CONFIG_SMP # define __SMP__ 1 #endif #if defined(CONFIG_MODVERSIONS) && defined(KERNEL_2_1) # if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) /* * MODVERSIONS might be already defined when using kernel's Makefiles. */ # ifndef MODVERSIONS # define MODVERSIONS # endif # include <linux/modversions.h> # endif #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) /* * Force the uintptr_t definition to come from linux/types.h instead of vm_basic_types.h. */ # include <linux/types.h> # define _STDINT_H 1 #endif #ifndef __KERNEL__ # define __KERNEL__ #endif #endif vmci-only/shared/compat_page-flags.h 0000444 0000000 0000000 00000005037 11573420431 016464 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __COMPAT_PAGE_FLAGS_H__ # define __COMPAT_PAGE_FLAGS_H__ /* No page-flags.h prior to 2.5.12. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 12) # include <linux/page-flags.h> #endif /* * The pgoff_t type was introduced in 2.5.20, but we'll look for it by * definition since it's more convenient. Note that we want to avoid a * situation where, in the future, a #define is changed to a typedef, * so if pgoff_t is not defined in some future kernel, we won't define it. */ #if !defined(pgoff_t) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) #define pgoff_t unsigned long #endif /* * set_page_writeback() was introduced in 2.6.6. Prior to that, callers were * using the SetPageWriteback() macro directly, so that's what we'll use. * Prior to 2.5.12, the writeback bit didn't exist, so we don't need to do * anything. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 12) #define compat_set_page_writeback(page) #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6) #define compat_set_page_writeback(page) SetPageWriteback(page) #else #define compat_set_page_writeback(page) set_page_writeback(page) #endif /* * end_page_writeback() was introduced in 2.5.12. Prior to that, it looks like * there was no page writeback bit, and everything the function accomplished * was done by unlock_page(), so we'll define it out. * * Note that we could just #define end_page_writeback to nothing and avoid * needing the compat_ prefix, but this is more complete with respect to * compat_set_page_writeback. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 12) #define compat_end_page_writeback(page) #else #define compat_end_page_writeback(page) end_page_writeback(page) #endif #endif /* __COMPAT_PAGE_FLAGS_H__ */ vmci-only/shared/guest_msg_def.h 0000444 0000000 0000000 00000005642 11573420432 015731 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * guest_msg_def.h -- * * Second layer of the internal communication channel between guest * applications and vmware * */ #ifndef _GUEST_MSG_DEF_H_ #define _GUEST_MSG_DEF_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" /* Basic request types */ typedef enum { MESSAGE_TYPE_OPEN, MESSAGE_TYPE_SENDSIZE, MESSAGE_TYPE_SENDPAYLOAD, MESSAGE_TYPE_RECVSIZE, MESSAGE_TYPE_RECVPAYLOAD, MESSAGE_TYPE_RECVSTATUS, MESSAGE_TYPE_CLOSE, } MessageType; /* Reply statuses */ /* The basic request succeeded */ #define MESSAGE_STATUS_SUCCESS 0x0001 /* vmware has a message available for its party */ #define MESSAGE_STATUS_DORECV 0x0002 /* The channel has been closed */ #define MESSAGE_STATUS_CLOSED 0x0004 /* vmware removed the message before the party fetched it */ #define MESSAGE_STATUS_UNSENT 0x0008 /* A checkpoint occurred */ #define MESSAGE_STATUS_CPT 0x0010 /* An underlying device is powering off */ #define MESSAGE_STATUS_POWEROFF 0x0020 /* vmware has detected a timeout on the channel */ #define MESSAGE_STATUS_TIMEOUT 0x0040 /* vmware supports high-bandwidth for sending and receiving the payload */ #define MESSAGE_STATUS_HB 0x0080 /* * This mask defines the status bits that the guest is allowed to set; * we use this to mask out all other bits when receiving the status * from the guest. Otherwise, the guest can manipulate VMX state by * setting status bits that are only supposed to be changed by the * VMX. See bug 45385. */ #define MESSAGE_STATUS_GUEST_MASK MESSAGE_STATUS_SUCCESS /* * Max number of channels. * Unfortunately this has to be public because the monitor part * of the backdoor needs it for its trivial-case optimization. [greg] */ #define GUESTMSG_MAX_CHANNEL 8 /* Flags to open a channel. --hpreg */ #define GUESTMSG_FLAG_COOKIE 0x80000000 #define GUESTMSG_FLAG_ALL GUESTMSG_FLAG_COOKIE /* * Maximum size of incoming message. This is to prevent denial of host service * attacks from guest applications. */ #define GUESTMSG_MAX_IN_SIZE (64 * 1024) #endif /* _GUEST_MSG_DEF_H_ */ vmci-only/shared/vmware_pack_end.h 0000444 0000000 0000000 00000002470 11573420432 016237 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmware_pack_end.h -- * * End of structure packing. See vmware_pack_init.h for details. * * Note that we do not use the following construct in this include file, * because we want to emit the code every time the file is included --hpreg * * #ifndef foo * # define foo * ... * #endif * */ #include "vmware_pack_init.h" #ifdef _MSC_VER # pragma pack(pop) #elif __GNUC__ __attribute__((__packed__)) #else # error Compiler packing... #endif vmci-only/shared/compat_sched.h 0000444 0000000 0000000 00000024236 11573420431 015546 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_SCHED_H__ # define __COMPAT_SCHED_H__ #include <linux/sched.h> /* CLONE_KERNEL available in 2.5.35 and higher. */ #ifndef CLONE_KERNEL #define CLONE_KERNEL CLONE_FILES | CLONE_FS | CLONE_SIGHAND #endif /* TASK_COMM_LEN become available in 2.6.11. */ #ifndef TASK_COMM_LEN #define TASK_COMM_LEN 16 #endif /* The capable() API appeared in 2.1.92 --hpreg */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 1, 92) # define capable(_capability) suser() #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 0) # define need_resched() need_resched #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) # define need_resched() (current->need_resched) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 3) # define cond_resched() (need_resched() ? schedule() : (void) 0) #endif /* Oh well. We need yield... Happy us! */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 20) # ifdef __x86_64__ # define compat_yield() there_is_nothing_like_yield() # else # include <linux/unistd.h> # include <linux/kernel.h> /* * Used by _syscallX macros. Note that this is global variable, so * do not rely on its contents too much. As exit() is only function * we use, and we never check return value from exit(), we have * no problem... */ extern int errno; /* * compat_exit() provides an access to the exit() function. It must * be named compat_exit(), as exit() (with different signature) is * provided by x86-64, arm and other (but not by i386). */ # define __NR_compat_yield __NR_sched_yield static inline _syscall0(int, compat_yield); # endif #else # define compat_yield() yield() #endif /* * Since 2.5.34 there are two methods to enumerate tasks: * for_each_process(p) { ... } which enumerates only tasks and * do_each_thread(g,t) { ... } while_each_thread(g,t) which enumerates * also threads even if they share same pid. */ #ifndef for_each_process # define for_each_process(p) for_each_task(p) #endif #ifndef do_each_thread # define do_each_thread(g, t) for_each_task(g) { t = g; do # define while_each_thread(g, t) while (0) } #endif /* * Lock for signal mask is moving target... */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 40) && defined(CLONE_PID) /* 2.4.x without NPTL patches or early 2.5.x */ #define compat_sigmask_lock sigmask_lock #define compat_dequeue_signal_current(siginfo_ptr) \ dequeue_signal(¤t->blocked, (siginfo_ptr)) #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 60) && !defined(INIT_SIGHAND) /* RedHat's 2.4.x with first version of NPTL support, or 2.5.40 to 2.5.59 */ #define compat_sigmask_lock sig->siglock #define compat_dequeue_signal_current(siginfo_ptr) \ dequeue_signal(¤t->blocked, (siginfo_ptr)) #else /* RedHat's 2.4.x with second version of NPTL support, or 2.5.60+. */ #define compat_sigmask_lock sighand->siglock #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) #define compat_dequeue_signal_current(siginfo_ptr) \ dequeue_signal(¤t->blocked, (siginfo_ptr)) #else #define compat_dequeue_signal_current(siginfo_ptr) \ dequeue_signal(current, ¤t->blocked, (siginfo_ptr)) #endif #endif /* * recalc_sigpending() had task argument in the past */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 29) && defined(CLONE_PID) /* 2.4.x without NPTL patches or early 2.5.x */ #define compat_recalc_sigpending() recalc_sigpending(current) #else /* RedHat's 2.4.x with NPTL support, or 2.5.29+ */ #define compat_recalc_sigpending() recalc_sigpending() #endif /* * reparent_to_init() was introduced in 2.4.8. In 2.5.38 (or possibly * earlier, but later than 2.5.31) a call to it was added into * daemonize(), so compat_daemonize no longer needs to call it. * * In 2.4.x kernels reparent_to_init() forgets to do correct refcounting * on current->user. It is better to count one too many than one too few... */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 38) #define compat_reparent_to_init() do { \ reparent_to_init(); \ atomic_inc(¤t->user->__count); \ } while (0) #else #define compat_reparent_to_init() do {} while (0) #endif /* * daemonize appeared in 2.2.18. Except 2.2.17-4-RH7.0, which has it too. * Fortunately 2.2.17-4-RH7.0 uses versioned symbols, so we can check * its existence with defined(). */ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18)) && !defined(daemonize) static inline void daemonize(void) { struct fs_struct *fs; exit_mm(current); current->session = 1; current->pgrp = 1; exit_fs(current); fs = init_task.fs; current->fs = fs; atomic_inc(&fs->count); } #endif /* * flush_signals acquires sighand->siglock since 2.5.61... Verify RH's kernels! */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) #define compat_flush_signals(task) do { \ spin_lock_irq(&task->compat_sigmask_lock); \ flush_signals(task); \ spin_unlock_irq(&task->compat_sigmask_lock); \ } while (0) #else #define compat_flush_signals(task) flush_signals(task) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) #define compat_allow_signal(signr) do { \ spin_lock_irq(¤t->compat_sigmask_lock); \ sigdelset(¤t->blocked, signr); \ compat_recalc_sigpending(); \ spin_unlock_irq(¤t->compat_sigmask_lock); \ } while (0) #else #define compat_allow_signal(signr) allow_signal(signr) #endif /* * daemonize can set process name since 2.5.61. Prior to 2.5.61, daemonize * didn't block signals on our behalf. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 61) #define compat_daemonize(x...) \ ({ \ /* Beware! No snprintf here, so verify arguments! */ \ sprintf(current->comm, x); \ \ /* Block all signals. */ \ spin_lock_irq(¤t->compat_sigmask_lock); \ sigfillset(¤t->blocked); \ compat_recalc_sigpending(); \ spin_unlock_irq(¤t->compat_sigmask_lock); \ compat_flush_signals(current); \ \ daemonize(); \ compat_reparent_to_init(); \ }) #else #define compat_daemonize(x...) daemonize(x) #endif /* * try to freeze a process. For kernels 2.6.11 or newer, we know how to choose * the interface. The problem is that the oldest interface, introduced in * 2.5.18, was backported to 2.4.x kernels. So if we're older than 2.6.11, * we'll decide what to do based on whether or not swsusp was configured * for the kernel. For kernels 2.6.20 and newer, we'll also need to include * freezer.h since the try_to_freeze definition was pulled out of sched.h. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) #include <linux/freezer.h> #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) || defined(VMW_TL10S64_WORKAROUND) #define compat_try_to_freeze() try_to_freeze() #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11) #define compat_try_to_freeze() try_to_freeze(PF_FREEZE) #elif defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_SOFTWARE_SUSPEND2) #include "compat_mm.h" #include <linux/errno.h> #include <linux/suspend.h> static inline int compat_try_to_freeze(void) { if (current->flags & PF_FREEZE) { refrigerator(PF_FREEZE); return 1; } else { return 0; } } #else static inline int compat_try_to_freeze(void) { return 0; } #endif /* * As of 2.6.23-rc1, kernel threads are no longer freezable by * default. Instead, kernel threads that need to be frozen must opt-in * by calling set_freezable() as soon as the thread is created. */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) #define compat_set_freezable() do { set_freezable(); } while (0) #else #define compat_set_freezable() do {} while (0) #endif /* * Around 2.6.27 kernel stopped sending signals to kernel * threads being frozen, instead threads have to check * freezing() or use wait_event_freezable(). Unfortunately * wait_event_freezable() completely hides the fact that * thread was frozen from calling code and sometimes we do * want to know that. */ #ifdef PF_FREEZER_NOSIG #define compat_wait_check_freezing() freezing(current) #else #define compat_wait_check_freezing() (0) #endif /* * Since 2.6.27-rc2 kill_proc() is gone... Replacement (GPL-only!) * API is available since 2.6.19. Use them from 2.6.27-rc1 up. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) typedef int compat_pid; #define compat_find_get_pid(pid) (pid) #define compat_put_pid(pid) do { } while (0) #define compat_kill_pid(pid, sig, flag) kill_proc(pid, sig, flag) #else typedef struct pid * compat_pid; #define compat_find_get_pid(pid) find_get_pid(pid) #define compat_put_pid(pid) put_pid(pid) #define compat_kill_pid(pid, sig, flag) kill_pid(pid, sig, flag) #endif #endif /* __COMPAT_SCHED_H__ */ vmci-only/shared/vmci_iocontrols.h 0000444 0000000 0000000 00000056501 11573420432 016327 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmci_iocontrols.h * * The VMCI driver io controls. */ #ifndef _VMCI_IOCONTROLS_H_ #define _VMCI_IOCONTROLS_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" #include "vm_assert.h" #include "vmci_defs.h" #if defined(_WIN32) && defined(WINNT_DDK) /* We need to expose the API through an IOCTL on Windows. Use latest API. */ #include "vmciKernelAPI.h" #endif // _WIN32 && WINNT_DDK /* *----------------------------------------------------------------------------- * * VMCIVA64ToPtr -- * * Convert a VA64 to a pointer. * * Results: * Virtual address. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE void * VMCIVA64ToPtr(VA64 va64) // IN { #ifdef VM_X86_64 ASSERT_ON_COMPILE(sizeof (void *) == 8); #else ASSERT_ON_COMPILE(sizeof (void *) == 4); // Check that nothing of value will be lost. ASSERT(!(va64 >> 32)); #endif return (void *)(uintptr_t)va64; } /* *----------------------------------------------------------------------------- * * VMCIPtrToVA64 -- * * Convert a pointer to a VA64. * * Results: * Virtual address. * * Side effects: * None * *----------------------------------------------------------------------------- */ static INLINE VA64 VMCIPtrToVA64(void const *ptr) // IN { ASSERT_ON_COMPILE(sizeof ptr <= sizeof (VA64)); return (VA64)(uintptr_t)ptr; } /* * Driver version. * * Increment major version when you make an incompatible change. * Compatibility goes both ways (old driver with new executable * as well as new driver with old executable). */ #define VMCI_VERSION_SHIFT_WIDTH 16 /* Never change this. */ #define VMCI_MAKE_VERSION(_major, _minor) ((_major) << \ VMCI_VERSION_SHIFT_WIDTH | \ (uint16) (_minor)) #define VMCI_VERSION_MAJOR(v) ((uint32) (v) >> VMCI_VERSION_SHIFT_WIDTH) #define VMCI_VERSION_MINOR(v) ((uint16) (v)) /* * VMCI_VERSION is always the current version. Subsequently listed * versions are ways of detecting previous versions of the connecting * application (i.e., VMX). * * VMCI_VERSION_HOSTQP: This version introduced host end point support * for hosted products. * * VMCI_VERSION_PREHOSTQP: This is the version prior to the adoption of * support for host end-points. * * VMCI_VERSION_PREVERS2: This fictional version number is intended to * represent the version of a VMX which doesn't call into the driver * with ioctl VERSION2 and thus doesn't establish its version with the * driver. */ #define VMCI_VERSION VMCI_VERSION_NOTIFY #define VMCI_VERSION_NOTIFY VMCI_MAKE_VERSION(10, 0) #define VMCI_VERSION_HOSTQP VMCI_MAKE_VERSION(9, 0) #define VMCI_VERSION_PREHOSTQP VMCI_MAKE_VERSION(8, 0) #define VMCI_VERSION_PREVERS2 VMCI_MAKE_VERSION(1, 0) #if defined(__linux__) || defined(SOLARIS) || defined(VMKERNEL) /* * Linux defines _IO* macros, but the core kernel code ignore the encoded * ioctl value. It is up to individual drivers to decode the value (for * example to look at the size of a structure to determine which version * of a specific command should be used) or not (which is what we * currently do, so right now the ioctl value for a given command is the * command itself). * * Hence, we just define the IOCTL_VMCI_foo values directly, with no * intermediate IOCTLCMD_ representation. */ # define IOCTLCMD(_cmd) IOCTL_VMCI_ ## _cmd #elif defined (__APPLE__) #include <sys/ioccom.h> #define IOCTLCMD(_cmd) IOCTL_VMCI_ ## _cmd #define IOCTLCMD_I(_cmd, _type) \ IOCTL_VMCI_MACOS_ ## _cmd = _IOW('V', IOCTL_VMCI_ ## _cmd, _type) #define IOCTLCMD_O(_cmd, _type) \ IOCTL_VMCI_MACOS_ ## _cmd = _IOR('V', IOCTL_VMCI_ ## _cmd, _type) #define IOCTLCMD_IO(_cmd, _type) \ IOCTL_VMCI_MACOS_ ## _cmd = _IOWR('V', IOCTL_VMCI_ ## _cmd, _type) #else // if defined(__linux__) /* * On platforms other than Linux, IOCTLCMD_foo values are just numbers, and * we build the IOCTL_VMCI_foo values around these using platform-specific * format for encoding arguments and sizes. */ # define IOCTLCMD(_cmd) IOCTLCMD_VMCI_ ## _cmd #endif enum IOCTLCmd_VMCI { /* * We need to bracket the range of values used for ioctls, because x86_64 * Linux forces us to explicitly register ioctl handlers by value for * handling 32 bit ioctl syscalls. Hence FIRST and LAST. Pick something * for FIRST that doesn't collide with vmmon (2001+). */ #if defined(__linux__) IOCTLCMD(FIRST) = 1951, #else /* Start at 0. */ IOCTLCMD(FIRST), #endif IOCTLCMD(VERSION) = IOCTLCMD(FIRST), /* BEGIN VMCI */ IOCTLCMD(INIT_CONTEXT), IOCTLCMD(CREATE_PROCESS), IOCTLCMD(CREATE_DATAGRAM_PROCESS), /* * The following two used to be for shared memory. They are now unused and * and are reserved for future use. They will fail if issued. */ IOCTLCMD(RESERVED1), IOCTLCMD(RESERVED2), /* * The follwoing two were also used to be for shared memory. An old * WS6 user-mode client might try to use them with the new driver, * but since we ensure that only contexts created by VMX'en of the * appropriate version (VMCI_VERSION_NOTIFY) or higher use this * ioctl, everything is fine. */ IOCTLCMD(NOTIFY_RESOURCE), IOCTLCMD(NOTIFICATIONS_RECEIVE), IOCTLCMD(VERSION2), IOCTLCMD(QUEUEPAIR_ALLOC), IOCTLCMD(QUEUEPAIR_SETPAGEFILE), IOCTLCMD(QUEUEPAIR_DETACH), IOCTLCMD(DATAGRAM_SEND), IOCTLCMD(DATAGRAM_RECEIVE), IOCTLCMD(DATAGRAM_REQUEST_MAP), IOCTLCMD(DATAGRAM_REMOVE_MAP), IOCTLCMD(CTX_ADD_NOTIFICATION), IOCTLCMD(CTX_REMOVE_NOTIFICATION), IOCTLCMD(CTX_GET_CPT_STATE), IOCTLCMD(CTX_SET_CPT_STATE), IOCTLCMD(GET_CONTEXT_ID), /* END VMCI */ /* * BEGIN VMCI SOCKETS * * We mark the end of the vmci commands and the start of the vmci sockets * commands since they are used in separate modules on Linux. * */ IOCTLCMD(LAST), IOCTLCMD(SOCKETS_FIRST) = IOCTLCMD(LAST), IOCTLCMD(SOCKETS_ACCEPT) = IOCTLCMD(SOCKETS_FIRST), IOCTLCMD(SOCKETS_BIND), /* * This used to be for close() on Windows and MacOS, which is now * redundant (since we now use real handles). It is now used instead for * sending private symbols to the MacOS driver. */ IOCTLCMD(SOCKETS_SET_SYMBOLS), IOCTLCMD(SOCKETS_CONNECT), /* * The next two values are public (vmci_sockets.h) and cannot be changed. * That means the number of values above these cannot be changed either * unless the base index (specified below) is updated accordingly. */ IOCTLCMD(SOCKETS_GET_AF_VALUE), IOCTLCMD(SOCKETS_GET_LOCAL_CID), IOCTLCMD(SOCKETS_GET_SOCK_NAME), IOCTLCMD(SOCKETS_GET_SOCK_OPT), IOCTLCMD(SOCKETS_GET_VM_BY_NAME), IOCTLCMD(SOCKETS_IOCTL), IOCTLCMD(SOCKETS_LISTEN), IOCTLCMD(SOCKETS_RECV), IOCTLCMD(SOCKETS_RECV_FROM), IOCTLCMD(SOCKETS_SELECT), IOCTLCMD(SOCKETS_SEND), IOCTLCMD(SOCKETS_SEND_TO), IOCTLCMD(SOCKETS_SET_SOCK_OPT), IOCTLCMD(SOCKETS_SHUTDOWN), IOCTLCMD(SOCKETS_SOCKET), /* 1990 on Linux. */ /* END VMCI SOCKETS */ /* * We reserve a range of 4 ioctls for VMCI Sockets to grow. We cannot * reserve many ioctls here since we are close to overlapping with vmmon * ioctls. Define a meta-ioctl if running out of this binary space. */ // Must be last. IOCTLCMD(SOCKETS_LAST) = IOCTLCMD(SOCKETS_SOCKET) + 4, /* 1994 on Linux. */ /* * The VSockets ioctls occupy the block above. We define a new range of * VMCI ioctls to maintain binary compatibility between the user land and * the kernel driver. Careful, vmmon ioctls start from 2001, so this means * we can add only 4 new VMCI ioctls. Define a meta-ioctl if running out of * this binary space. */ IOCTLCMD(FIRST2), IOCTLCMD(SET_NOTIFY) = IOCTLCMD(FIRST2), /* 1995 on Linux. */ IOCTLCMD(LAST2), }; #if defined (__APPLE__) /* * The size of this must match the size of VSockIoctlPrivSyms in * modules/vsock/common/vsockIoctl.h. */ #include "vmware_pack_begin.h" struct IOCTLCmd_VMCIMacOS_PrivSyms { char data[304]; } #include "vmware_pack_end.h" ; enum IOCTLCmd_VMCIMacOS { IOCTLCMD_I(SOCKETS_SET_SYMBOLS, struct IOCTLCmd_VMCIMacOS_PrivSyms), IOCTLCMD_O(SOCKETS_GET_AF_VALUE, int), IOCTLCMD_O(SOCKETS_GET_LOCAL_CID, unsigned int), }; #endif // __APPLE__ #if defined _WIN32 /* * Windows VMCI ioctl definitions. */ /* * The first is the device name in user-mode. The next two are for registering * or opening the device in kernel-mode, and are always in UNICODE. */ #define VMCI_DEVICE_NAME TEXT("\\\\.\\VMCI") #define VMCI_DEVICE_NAME_NT L"\\??\\VMCI" #define VMCI_DEVICE_NAME_PATH L"\\Device\\vmci" #define VMCI_DEVICE_LINK_PATH L"\\DosDevices\\vmci" /* These values cannot be changed since some of the ioctl values are public. */ #define FILE_DEVICE_VMCI 0x8103 #define VMCI_IOCTL_BASE_INDEX 0x801 #define VMCIIOCTL_BUFFERED(name) \ CTL_CODE(FILE_DEVICE_VMCI, \ VMCI_IOCTL_BASE_INDEX + IOCTLCMD_VMCI_ ## name, \ METHOD_BUFFERED, \ FILE_ANY_ACCESS) #define VMCIIOCTL_NEITHER(name) \ CTL_CODE(FILE_DEVICE_VMCI, \ VMCI_IOCTL_BASE_INDEX + IOCTLCMD_VMCI_ ## name, \ METHOD_NEITHER, \ FILE_ANY_ACCESS) enum IOCTLCmd_VMCIWin32 { IOCTLCMD(DEVICE_GET) = IOCTLCMD(LAST2) + 1, IOCTLCMD(SOCKETS_SERVICE_GET), }; #define IOCTL_VMCI_VERSION VMCIIOCTL_BUFFERED(VERSION) /* BEGIN VMCI */ #define IOCTL_VMCI_INIT_CONTEXT \ VMCIIOCTL_BUFFERED(INIT_CONTEXT) #define IOCTL_VMCI_CREATE_PROCESS \ VMCIIOCTL_BUFFERED(CREATE_PROCESS) #define IOCTL_VMCI_CREATE_DATAGRAM_PROCESS \ VMCIIOCTL_BUFFERED(CREATE_DATAGRAM_PROCESS) #define IOCTL_VMCI_HYPERCALL \ VMCIIOCTL_BUFFERED(HYPERCALL) #define IOCTL_VMCI_CREATE_DATAGRAM_HANDLE \ VMCIIOCTL_BUFFERED(CREATE_DATAGRAM_HANDLE) #define IOCTL_VMCI_DESTROY_DATAGRAM_HANDLE \ VMCIIOCTL_BUFFERED(DESTROY_DATAGRAM_HANDLE) #define IOCTL_VMCI_NOTIFY_RESOURCE \ VMCIIOCTL_BUFFERED(NOTIFY_RESOURCE) #define IOCTL_VMCI_NOTIFICATIONS_RECEIVE \ VMCIIOCTL_BUFFERED(NOTIFICATIONS_RECEIVE) #define IOCTL_VMCI_VERSION2 \ VMCIIOCTL_BUFFERED(VERSION2) #define IOCTL_VMCI_QUEUEPAIR_ALLOC \ VMCIIOCTL_BUFFERED(QUEUEPAIR_ALLOC) #define IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE \ VMCIIOCTL_BUFFERED(QUEUEPAIR_SETPAGEFILE) #define IOCTL_VMCI_QUEUEPAIR_DETACH \ VMCIIOCTL_BUFFERED(QUEUEPAIR_DETACH) #define IOCTL_VMCI_DATAGRAM_SEND \ VMCIIOCTL_BUFFERED(DATAGRAM_SEND) #define IOCTL_VMCI_DATAGRAM_RECEIVE \ VMCIIOCTL_NEITHER(DATAGRAM_RECEIVE) #define IOCTL_VMCI_DATAGRAM_REQUEST_MAP \ VMCIIOCTL_BUFFERED(DATAGRAM_REQUEST_MAP) #define IOCTL_VMCI_DATAGRAM_REMOVE_MAP \ VMCIIOCTL_BUFFERED(DATAGRAM_REMOVE_MAP) #define IOCTL_VMCI_CTX_ADD_NOTIFICATION \ VMCIIOCTL_BUFFERED(CTX_ADD_NOTIFICATION) #define IOCTL_VMCI_CTX_REMOVE_NOTIFICATION \ VMCIIOCTL_BUFFERED(CTX_REMOVE_NOTIFICATION) #define IOCTL_VMCI_CTX_GET_CPT_STATE \ VMCIIOCTL_BUFFERED(CTX_GET_CPT_STATE) #define IOCTL_VMCI_CTX_SET_CPT_STATE \ VMCIIOCTL_BUFFERED(CTX_SET_CPT_STATE) #define IOCTL_VMCI_GET_CONTEXT_ID \ VMCIIOCTL_BUFFERED(GET_CONTEXT_ID) #define IOCTL_VMCI_DEVICE_GET \ VMCIIOCTL_BUFFERED(DEVICE_GET) /* END VMCI */ /* BEGIN VMCI SOCKETS */ #define IOCTL_VMCI_SOCKETS_ACCEPT \ VMCIIOCTL_BUFFERED(SOCKETS_ACCEPT) #define IOCTL_VMCI_SOCKETS_BIND \ VMCIIOCTL_BUFFERED(SOCKETS_BIND) #define IOCTL_VMCI_SOCKETS_CLOSE \ VMCIIOCTL_BUFFERED(SOCKETS_CLOSE) #define IOCTL_VMCI_SOCKETS_CONNECT \ VMCIIOCTL_BUFFERED(SOCKETS_CONNECT) #define IOCTL_VMCI_SOCKETS_GET_AF_VALUE \ VMCIIOCTL_BUFFERED(SOCKETS_GET_AF_VALUE) #define IOCTL_VMCI_SOCKETS_GET_LOCAL_CID \ VMCIIOCTL_BUFFERED(SOCKETS_GET_LOCAL_CID) #define IOCTL_VMCI_SOCKETS_GET_SOCK_NAME \ VMCIIOCTL_BUFFERED(SOCKETS_GET_SOCK_NAME) #define IOCTL_VMCI_SOCKETS_GET_SOCK_OPT \ VMCIIOCTL_BUFFERED(SOCKETS_GET_SOCK_OPT) #define IOCTL_VMCI_SOCKETS_GET_VM_BY_NAME \ VMCIIOCTL_BUFFERED(SOCKETS_GET_VM_BY_NAME) #define IOCTL_VMCI_SOCKETS_IOCTL \ VMCIIOCTL_BUFFERED(SOCKETS_IOCTL) #define IOCTL_VMCI_SOCKETS_LISTEN \ VMCIIOCTL_BUFFERED(SOCKETS_LISTEN) #define IOCTL_VMCI_SOCKETS_RECV_FROM \ VMCIIOCTL_BUFFERED(SOCKETS_RECV_FROM) #define IOCTL_VMCI_SOCKETS_SELECT \ VMCIIOCTL_BUFFERED(SOCKETS_SELECT) #define IOCTL_VMCI_SOCKETS_SEND_TO \ VMCIIOCTL_BUFFERED(SOCKETS_SEND_TO) #define IOCTL_VMCI_SOCKETS_SET_SOCK_OPT \ VMCIIOCTL_BUFFERED(SOCKETS_SET_SOCK_OPT) #define IOCTL_VMCI_SOCKETS_SHUTDOWN \ VMCIIOCTL_BUFFERED(SOCKETS_SHUTDOWN) #define IOCTL_VMCI_SOCKETS_SERVICE_GET \ VMCIIOCTL_BUFFERED(SOCKETS_SERVICE_GET) /* END VMCI SOCKETS */ #endif // _WIN32 /* * VMCI driver initialization. This block can also be used to * pass initial group membership etc. */ typedef struct VMCIInitBlock { VMCIId cid; VMCIPrivilegeFlags flags; #ifdef _WIN32 uint64 event; /* Handle for signalling vmci calls on windows. */ #endif // _WIN32 } VMCIInitBlock; typedef struct VMCISharedMemInfo { VMCIHandle handle; uint32 size; uint32 result; VA64 va; /* Currently only used in the guest. */ char pageFileName[VMCI_PATH_MAX]; } VMCISharedMemInfo; typedef struct VMCIQueuePairAllocInfo { VMCIHandle handle; VMCIId peer; uint32 flags; uint64 produceSize; uint64 consumeSize; #if !defined(VMX86_SERVER) && !defined(VMKERNEL) VA64 producePageFile; /* User VA. */ VA64 consumePageFile; /* User VA. */ uint64 producePageFileSize; /* Size of the file name array. */ uint64 consumePageFileSize; /* Size of the file name array. */ #else PPN * PPNs; uint64 numPPNs; #endif int32 result; uint32 _pad; } VMCIQueuePairAllocInfo; /* * For backwards compatibility, here is a version of the * VMCIQueuePairPageFileInfo before host support end-points was added. * Note that the current version of that structure requires VMX to * pass down the VA of the mapped file. Before host support was added * there was nothing of the sort. So, when the driver sees the ioctl * with a parameter that is the sizeof * VMCIQueuePairPageFileInfo_NoHostQP then it can infer that the version * of VMX running can't attach to host end points because it doesn't * provide the VA of the mapped files. * * The Linux driver doesn't get an indication of the size of the * structure passed down from user space. So, to fix a long standing * but unfiled bug, the _pad field has been renamed to version. * Existing versions of VMX always initialize the PageFileInfo * structure so that _pad, er, version is set to 0. * * A version value of 1 indicates that the size of the structure has * been increased to include two UVA's: produceUVA and consumeUVA. * These UVA's are of the mmap()'d queue contents backing files. * * In addition, if when VMX is sending down the * VMCIQueuePairPageFileInfo structure it gets an error then it will * try again with the _NoHostQP version of the file to see if an older * VMCI kernel module is running. */ typedef struct VMCIQueuePairPageFileInfo_NoHostQP { VMCIHandle handle; VA64 producePageFile; /* User VA. */ VA64 consumePageFile; /* User VA. */ uint64 producePageFileSize; /* Size of the file name array. */ uint64 consumePageFileSize; /* Size of the file name array. */ int32 result; uint32 version; /* Was _pad. Must be 0. */ } VMCIQueuePairPageFileInfo_NoHostQP; typedef struct VMCIQueuePairPageFileInfo { VMCIHandle handle; #if !defined(VMX86_SERVER) && !defined(VMKERNEL) VA64 producePageFile; /* User VA. */ VA64 consumePageFile; /* User VA. */ uint64 producePageFileSize; /* Size of the file name array. */ uint64 consumePageFileSize; /* Size of the file name array. */ #endif int32 result; uint32 version; /* Was _pad. */ VA64 produceVA; /* User VA of the mapped file. */ VA64 consumeVA; /* User VA of the mapped file. */ } VMCIQueuePairPageFileInfo; typedef struct VMCIQueuePairDetachInfo { VMCIHandle handle; int32 result; uint32 _pad; } VMCIQueuePairDetachInfo; typedef struct VMCIDatagramSendRecvInfo { VA64 addr; uint32 len; int32 result; } VMCIDatagramSendRecvInfo; /* Used to create datagram endpoints in guest or host userlevel. */ typedef struct VMCIDatagramCreateProcessInfo { VMCIId resourceID; uint32 flags; #ifdef _WIN32 int eventHnd; #else int _unused; #endif int result; // result of handle create operation VMCIHandle handle; // handle if successfull } VMCIDatagramCreateProcessInfo; /* Used to add/remove well-known datagram mappings. */ typedef struct VMCIDatagramMapInfo { VMCIId wellKnownID; int result; } VMCIDatagramMapInfo; /* Used to add/remove remote context notifications. */ typedef struct VMCINotifyAddRemoveInfo { VMCIId remoteCID; int result; } VMCINotifyAddRemoveInfo; /* Used to set/get current context's checkpoint state. */ typedef struct VMCICptBufInfo { VA64 cptBuf; uint32 cptType; uint32 bufSize; int32 result; uint32 _pad; } VMCICptBufInfo; /* Used to pass notify flag's address to the host driver. */ typedef struct VMCISetNotifyInfo { VA64 notifyUVA; int32 result; uint32 _pad; } VMCISetNotifyInfo; #define VMCI_NOTIFY_RESOURCE_QUEUE_PAIR 0 #define VMCI_NOTIFY_RESOURCE_DOOR_BELL 1 #define VMCI_NOTIFY_RESOURCE_ACTION_NOTIFY 0 #define VMCI_NOTIFY_RESOURCE_ACTION_CREATE 1 #define VMCI_NOTIFY_RESOURCE_ACTION_DESTROY 2 /* * Used to create and destroy doorbells, and generate a notification * for a doorbell or queue pair. */ typedef struct VMCINotifyResourceInfo { VMCIHandle handle; uint16 resource; uint16 action; int32 result; } VMCINotifyResourceInfo; /* * Used to recieve pending notifications for doorbells and queue * pairs. */ typedef struct VMCINotificationReceiveInfo { VA64 dbHandleBufUVA; uint64 dbHandleBufSize; VA64 qpHandleBufUVA; uint64 qpHandleBufSize; int32 result; uint32 _pad; } VMCINotificationReceiveInfo; #if defined(_WIN32) && defined(WINNT_DDK) /* * Used on Windows to expose the API calls that are no longer exported. This * is kernel-mode only, and both sides will have the same bitness, so we can * use pointers directly. */ /* Version 1. */ typedef struct VMCIDeviceGetInfoVer1 { VMCI_DeviceReleaseFct *deviceRelease; VMCIDatagram_CreateHndFct *dgramCreateHnd; VMCIDatagram_CreateHndPrivFct *dgramCreateHndPriv; VMCIDatagram_DestroyHndFct *dgramDestroyHnd; VMCIDatagram_SendFct *dgramSend; VMCI_GetContextIDFct *getContextId; VMCI_VersionFct *version; VMCIEvent_SubscribeFct *eventSubscribe; VMCIEvent_UnsubscribeFct *eventUnsubscribe; VMCIQPair_AllocFct *qpairAlloc; VMCIQPair_DetachFct *qpairDetach; VMCIQPair_GetProduceIndexesFct *qpairGetProduceIndexes; VMCIQPair_GetConsumeIndexesFct *qpairGetConsumeIndexes; VMCIQPair_ProduceFreeSpaceFct *qpairProduceFreeSpace; VMCIQPair_ProduceBufReadyFct *qpairProduceBufReady; VMCIQPair_ConsumeFreeSpaceFct *qpairConsumeFreeSpace; VMCIQPair_ConsumeBufReadyFct *qpairConsumeBufReady; VMCIQPair_EnqueueFct *qpairEnqueue; VMCIQPair_DequeueFct *qpairDequeue; VMCIQPair_PeekFct *qpairPeek; VMCIQPair_EnqueueVFct *qpairEnqueueV; VMCIQPair_DequeueVFct *qpairDequeueV; VMCIQPair_PeekVFct *qpairPeekV; } VMCIDeviceGetInfoVer1; /* Version 2. */ typedef struct VMCIDeviceGetInfoVer2 { VMCIDoorbell_CreateFct *doorbellCreate; VMCIDoorbell_DestroyFct *doorbellDestroy; VMCIDoorbell_NotifyFct *doorbellNotify; } VMCIDeviceGetInfoVer2; typedef struct VMCIDeviceGetInfoHdr { /* Requested API version on input, supported version on output. */ uint32 apiVersion; } VMCIDeviceGetInfoHdr; /* Combination of all versions. */ typedef struct VMCIDeviceGetInfo { VMCIDeviceGetInfoHdr hdr; VMCIDeviceGetInfoVer1 ver1; VMCIDeviceGetInfoVer2 ver2; } VMCIDeviceGetInfo; #endif // _WIN32 && WINNT_DDK #ifdef __APPLE__ /* * Mac OS ioctl definitions. * * Mac OS defines _IO* macros, and the core kernel code uses the size encoded * in the ioctl value to copy the memory back and forth (depending on the * direction encoded in the ioctl value) between the user and kernel address * spaces. * See iocontrolsMacOS.h for details on how this is done. We use sockets only * for vmci. */ #include <sys/ioccom.h> enum VMCrossTalkSockOpt { VMCI_SO_VERSION = 0, VMCI_SO_CONTEXT = IOCTL_VMCI_INIT_CONTEXT, VMCI_SO_PROCESS = IOCTL_VMCI_CREATE_PROCESS, VMCI_SO_DATAGRAM_PROCESS = IOCTL_VMCI_CREATE_DATAGRAM_PROCESS, VMCI_SO_NOTIFY_RESOURCE = IOCTL_VMCI_NOTIFY_RESOURCE, VMCI_SO_NOTIFICATIONS_RECEIVE = IOCTL_VMCI_NOTIFICATIONS_RECEIVE, VMCI_SO_VERSION2 = IOCTL_VMCI_VERSION2, VMCI_SO_QUEUEPAIR_ALLOC = IOCTL_VMCI_QUEUEPAIR_ALLOC, VMCI_SO_QUEUEPAIR_SETPAGEFILE = IOCTL_VMCI_QUEUEPAIR_SETPAGEFILE, VMCI_SO_QUEUEPAIR_DETACH = IOCTL_VMCI_QUEUEPAIR_DETACH, VMCI_SO_DATAGRAM_SEND = IOCTL_VMCI_DATAGRAM_SEND, VMCI_SO_DATAGRAM_RECEIVE = IOCTL_VMCI_DATAGRAM_RECEIVE, VMCI_SO_DATAGRAM_REQUEST_MAP = IOCTL_VMCI_DATAGRAM_REQUEST_MAP, VMCI_SO_DATAGRAM_REMOVE_MAP = IOCTL_VMCI_DATAGRAM_REMOVE_MAP, VMCI_SO_CTX_ADD_NOTIFICATION = IOCTL_VMCI_CTX_ADD_NOTIFICATION, VMCI_SO_CTX_REMOVE_NOTIFICATION = IOCTL_VMCI_CTX_REMOVE_NOTIFICATION, VMCI_SO_CTX_GET_CPT_STATE = IOCTL_VMCI_CTX_GET_CPT_STATE, VMCI_SO_CTX_SET_CPT_STATE = IOCTL_VMCI_CTX_SET_CPT_STATE, VMCI_SO_GET_CONTEXT_ID = IOCTL_VMCI_GET_CONTEXT_ID, VMCI_SO_USERFD, }; # define VMCI_MACOS_HOST_DEVICE_BASE "com.vmware.kext.vmci" # ifdef VMX86_DEVEL # define VMCI_MACOS_HOST_DEVICE VMCI_MACOS_HOST_DEVICE_BASE ".devel" # else # define VMCI_MACOS_HOST_DEVICE VMCI_MACOS_HOST_DEVICE_BASE # endif #endif /* Clean up helper macros */ #undef IOCTLCMD #endif // ifndef _VMCI_IOCONTROLS_H_ vmci-only/shared/compat_pagemap.h 0000444 0000000 0000000 00000002535 11573420431 016070 0 ustar root root /********************************************************* * Copyright (C) 2009 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_PAGEMAP_H__ # define __COMPAT_PAGEMAP_H__ #include <linux/pagemap.h> /* * AOP_FLAG_NOFS was defined in the same changeset that * grab_cache_page_write_begin() was introduced. */ #ifdef AOP_FLAG_NOFS #define compat_grab_cache_page_write_begin(mapping, index, flags) \ grab_cache_page_write_begin((mapping), (index), (flags)) #else #define compat_grab_cache_page_write_begin(mapping, index, flags) \ __grab_cache_page((mapping), (index)); #endif #endif /* __COMPAT_PAGEMAP_H__ */ vmci-only/shared/vm_basic_types.h 0000444 0000000 0000000 00000061152 11573420432 016123 0 ustar root root /********************************************************* * Copyright (C) 1998-2009 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_basic_types.h -- * * basic data types. */ #ifndef _VM_BASIC_TYPES_H_ #define _VM_BASIC_TYPES_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMIROM #include "includeCheck.h" /* STRICT ANSI means the Xserver build and X defines Bool differently. */ #if !defined(__STRICT_ANSI__) || defined(__FreeBSD__) || defined(__MINGW32__) typedef char Bool; #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #define IsBool(x) (((x) & ~1) == 0) #define IsBool2(x, y) ((((x) | (y)) & ~1) == 0) /* * Macros __i386__ and __ia64 are intrinsically defined by GCC */ #if defined _MSC_VER && defined _M_X64 # define __x86_64__ #elif defined _MSC_VER && defined _M_IX86 # define __i386__ #endif #ifdef __i386__ #define VM_I386 #endif #ifdef __x86_64__ #define VM_X86_64 #define VM_I386 #define vm_x86_64 (1) #else #define vm_x86_64 (0) #endif #ifdef _MSC_VER #pragma warning (3 :4505) // unreferenced local function #pragma warning (disable :4018) // signed/unsigned mismatch #pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied #pragma warning (disable :4305) // truncation from 'const int' to 'short' #pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char' #pragma warning (disable :4267) // truncation of 'size_t' #pragma warning (disable :4146) // unary minus operator applied to unsigned type, result still unsigned #pragma warning (disable :4142) // benign redefinition of type #endif #if defined(__APPLE__) || defined(HAVE_STDINT_H) /* * TODO: This is a C99 standard header. We should be able to test for * #if __STDC_VERSION__ >= 199901L, but that breaks the Netware build * (which doesn't have stdint.h). */ #include <stdint.h> typedef uint64_t uint64; typedef int64_t int64; typedef uint32_t uint32; typedef int32_t int32; typedef uint16_t uint16; typedef int16_t int16; typedef uint8_t uint8; typedef int8_t int8; /* * Note: C does not specify whether char is signed or unsigned, and * both gcc and msvc implement processor-specific signedness. With * three types: * typeof(char) != typeof(signed char) != typeof(unsigned char) * * Be careful here, because gcc (4.0.1 and others) likes to warn about * conversions between signed char * and char *. */ #else /* !HAVE_STDINT_H */ #ifdef _MSC_VER typedef unsigned __int64 uint64; typedef signed __int64 int64; #elif __GNUC__ /* The Xserver source compiles with -ansi -pendantic */ # if !defined(__STRICT_ANSI__) || defined(__FreeBSD__) # if defined(VM_X86_64) typedef unsigned long uint64; typedef long int64; # else typedef unsigned long long uint64; typedef long long int64; # endif # endif #else # error - Need compiler define for int64/uint64 #endif /* _MSC_VER */ typedef unsigned int uint32; typedef unsigned short uint16; typedef unsigned char uint8; typedef int int32; typedef short int16; typedef signed char int8; #endif /* HAVE_STDINT_H */ /* * FreeBSD (for the tools build) unconditionally defines these in * sys/inttypes.h so don't redefine them if this file has already * been included. [greg] * * This applies to Solaris as well. */ /* * Before trying to do the includes based on OS defines, see if we can use * feature-based defines to get as much functionality as possible */ #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif #ifdef HAVE_SYS_INTTYPES_H #include <sys/inttypes.h> #endif #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif #ifdef __FreeBSD__ #include <sys/param.h> /* For __FreeBSD_version */ #endif #if !defined(USING_AUTOCONF) # if defined(__FreeBSD__) || defined(sun) # ifdef KLD_MODULE # include <sys/types.h> # else # if __FreeBSD_version >= 500043 # if !defined(VMKERNEL) # include <inttypes.h> # endif # include <sys/types.h> # else # include <sys/inttypes.h> # endif # endif # elif defined __APPLE__ # if KERNEL # include <sys/unistd.h> # include <sys/types.h> /* mostly for size_t */ # include <stdint.h> # else # include <unistd.h> # include <inttypes.h> # include <stdlib.h> # include <stdint.h> # endif # else # if !defined(__intptr_t_defined) && !defined(intptr_t) # ifdef VM_I386 # define __intptr_t_defined # ifdef VM_X86_64 typedef int64 intptr_t; # else typedef int32 intptr_t; # endif # elif defined(__arm__) typedef int32 intptr_t; # endif # endif # ifndef _STDINT_H # ifdef VM_I386 # ifdef VM_X86_64 typedef uint64 uintptr_t; # else typedef uint32 uintptr_t; # endif # elif defined(__arm__) typedef uint32 uintptr_t; # endif # endif # endif #endif /* * Time * XXX These should be cleaned up. -- edward */ typedef int64 VmTimeType; /* Time in microseconds */ typedef int64 VmTimeRealClock; /* Real clock kept in microseconds */ typedef int64 VmTimeVirtualClock; /* Virtual Clock kept in CPU cycles */ /* * Printf format specifiers for size_t and 64-bit number. * Use them like this: * printf("%"FMT64"d\n", big); * * FMTH is for handles/fds. */ #ifdef _MSC_VER #define FMT64 "I64" #ifdef VM_X86_64 #define FMTSZ "I64" #define FMTPD "I64" #define FMTH "I64" #else #define FMTSZ "I" #define FMTPD "I" #define FMTH "I" #endif #elif defined __APPLE__ /* Mac OS hosts use the same formatters for 32- and 64-bit. */ #define FMT64 "ll" #if KERNEL #define FMTSZ "l" #else #define FMTSZ "z" #endif #define FMTPD "l" #define FMTH "" #elif __GNUC__ #define FMTH "" #if defined(N_PLAT_NLM) || defined(sun) || \ (defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5)) /* * Why (__FreeBSD__ + 0)? See bug 141008. * Yes, we really need to test both (__FreeBSD__ + 0) and * ((__FreeBSD__ + 0) < 5). No, we can't remove "+ 0" from * ((__FreeBSD__ + 0) < 5). */ #ifdef VM_X86_64 #define FMTSZ "l" #define FMTPD "l" #else #define FMTSZ "" #define FMTPD "" #endif #elif defined(__linux__) \ || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \ || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \ || (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L) /* BSD, Linux */ #define FMTSZ "z" #if defined(VM_X86_64) #define FMTPD "l" #else #define FMTPD "" #endif #else /* Systems with a pre-C99 libc */ #define FMTSZ "Z" #ifdef VM_X86_64 #define FMTPD "l" #else #define FMTPD "" #endif #endif #ifdef VM_X86_64 #define FMT64 "l" #elif defined(sun) || defined(__FreeBSD__) #define FMT64 "ll" #else #define FMT64 "L" #endif #else #error - Need compiler define for FMT64 and FMTSZ #endif /* * Suffix for 64-bit constants. Use it like this: * CONST64(0x7fffffffffffffff) for signed or * CONST64U(0x7fffffffffffffff) for unsigned. * * 2004.08.30(thutt): * The vmcore/asm64/gen* programs are compiled as 32-bit * applications, but must handle 64 bit constants. If the * 64-bit-constant defining macros are already defined, the * definition will not be overwritten. */ #if !defined(CONST64) || !defined(CONST64U) #ifdef _MSC_VER #define CONST64(c) c##I64 #define CONST64U(c) c##uI64 #elif defined __APPLE__ #define CONST64(c) c##LL #define CONST64U(c) c##uLL #elif __GNUC__ #ifdef VM_X86_64 #define CONST64(c) c##L #define CONST64U(c) c##uL #else #define CONST64(c) c##LL #define CONST64U(c) c##uLL #endif #else #error - Need compiler define for CONST64 #endif #endif /* * Use CONST3264/CONST3264U if you want a constant to be * treated as a 32-bit number on 32-bit compiles and * a 64-bit number on 64-bit compiles. Useful in the case * of shifts, like (CONST3264U(1) << x), where x could be * more than 31 on a 64-bit compile. */ #ifdef VM_X86_64 #define CONST3264(a) CONST64(a) #define CONST3264U(a) CONST64U(a) #else #define CONST3264(a) (a) #define CONST3264U(a) (a) #endif #define MIN_INT8 ((int8)0x80) #define MAX_INT8 ((int8)0x7f) #define MIN_UINT8 ((uint8)0) #define MAX_UINT8 ((uint8)0xff) #define MIN_INT16 ((int16)0x8000) #define MAX_INT16 ((int16)0x7fff) #define MIN_UINT16 ((uint16)0) #define MAX_UINT16 ((uint16)0xffff) #define MIN_INT32 ((int32)0x80000000) #define MAX_INT32 ((int32)0x7fffffff) #define MIN_UINT32 ((uint32)0) #define MAX_UINT32 ((uint32)0xffffffff) #define MIN_INT64 (CONST64(0x8000000000000000)) #define MAX_INT64 (CONST64(0x7fffffffffffffff)) #define MIN_UINT64 (CONST64U(0)) #define MAX_UINT64 (CONST64U(0xffffffffffffffff)) typedef uint8 *TCA; /* Pointer into TC (usually). */ /* * Type big enough to hold an integer between 0..100 */ typedef uint8 Percent; #define AsPercent(v) ((Percent)(v)) #define CHOOSE_PERCENT AsPercent(101) typedef uintptr_t VA; typedef uintptr_t VPN; typedef uint64 PA; typedef uint32 PPN; typedef uint64 PhysMemOff; typedef uint64 PhysMemSize; /* The Xserver source compiles with -ansi -pendantic */ #ifndef __STRICT_ANSI__ typedef uint64 BA; #endif typedef uint32 BPN; typedef uint32 PageNum; typedef unsigned MemHandle; typedef int32 World_ID; /* !! do not alter the definition of INVALID_WORLD_ID without ensuring * that the values defined in both bora/public/vm_basic_types.h and * lib/vprobe/vm_basic_types.h are the same. Additionally, the definition * of VMK_INVALID_WORLD_ID in vmkapi_world.h also must be defined with * the same value */ #define INVALID_WORLD_ID ((World_ID)0) typedef World_ID User_CartelID; #define INVALID_CARTEL_ID INVALID_WORLD_ID typedef User_CartelID User_SessionID; #define INVALID_SESSION_ID INVALID_CARTEL_ID typedef User_CartelID User_CartelGroupID; #define INVALID_CARTELGROUP_ID INVALID_CARTEL_ID typedef uint32 Worldlet_ID; #define INVALID_WORLDLET_ID ((Worldlet_ID)-1) /* The Xserver source compiles with -ansi -pendantic */ #ifndef __STRICT_ANSI__ typedef uint64 MA; typedef uint32 MPN; #endif /* * This type should be used for variables that contain sector * position/quantity. */ typedef uint64 SectorType; /* * Linear address */ typedef uintptr_t LA; typedef uintptr_t LPN; #define LA_2_LPN(_la) ((_la) >> PAGE_SHIFT) #define LPN_2_LA(_lpn) ((_lpn) << PAGE_SHIFT) #define LAST_LPN ((((LA) 1) << (8 * sizeof(LA) - PAGE_SHIFT)) - 1) #define LAST_LPN32 ((((LA32)1) << (8 * sizeof(LA32) - PAGE_SHIFT)) - 1) #define LAST_LPN64 ((((LA64)1) << (8 * sizeof(LA64) - PAGE_SHIFT)) - 1) /* Valid bits in a LPN. */ #define LPN_MASK LAST_LPN #define LPN_MASK32 LAST_LPN32 #define LPN_MASK64 LAST_LPN64 /* * On 64 bit platform, address and page number types default * to 64 bit. When we need to represent a 32 bit address, we use * types defined below. * * On 32 bit platform, the following types are the same as the * default types. */ typedef uint32 VA32; typedef uint32 VPN32; typedef uint32 LA32; typedef uint32 LPN32; typedef uint32 PA32; typedef uint32 PPN32; typedef uint32 MA32; typedef uint32 MPN32; /* * On 64 bit platform, the following types are the same as the * default types. */ typedef uint64 VA64; typedef uint64 VPN64; typedef uint64 LA64; typedef uint64 LPN64; typedef uint64 PA64; typedef uint64 PPN64; typedef uint64 MA64; typedef uint64 MPN64; /* * VA typedefs for user world apps. */ typedef VA32 UserVA32; typedef VA64 UserVA64; typedef UserVA64 UserVAConst; /* Userspace ptr to data that we may only read. */ typedef UserVA32 UserVA32Const; /* Userspace ptr to data that we may only read. */ typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */ #ifdef VMKERNEL typedef UserVA64 UserVA; #else typedef void * UserVA; #endif /* * Maximal possible PPN value (errors too) that PhysMem can handle. * Must be at least as large as MAX_PPN which is the maximum PPN * for any region other than buserror. */ #define PHYSMEM_MAX_PPN ((PPN)0xffffffff) #define MAX_PPN ((PPN)0x1fffffff) /* Maximal observable PPN value. */ #define INVALID_PPN ((PPN)0xffffffff) #define INVALID_BPN ((BPN)0x1fffffff) #define RESERVED_MPN ((MPN) 0) #define INVALID_MPN ((MPN)-1) #define MEMREF_MPN ((MPN)-2) #define RELEASED_MPN ((MPN)-3) #define MAX_MPN ((MPN)0x7fffffff) /* 43 bits of address space. */ #define INVALID_LPN ((LPN)-1) #define INVALID_VPN ((VPN)-1) #define INVALID_LPN64 ((LPN64)-1) #define INVALID_PAGENUM ((PageNum)-1) /* * Format modifier for printing VA, LA, and VPN. * Use them like this: Log("%#"FMTLA"x\n", laddr) */ #if defined(VMM) || defined(FROBOS64) || vm_x86_64 || defined __APPLE__ # define FMTLA "l" # define FMTVA "l" # define FMTVPN "l" #else # define FMTLA "" # define FMTVA "" # define FMTVPN "" #endif #ifndef EXTERN #define EXTERN extern #endif #define CONST const #ifndef INLINE # ifdef _MSC_VER # define INLINE __inline # else # define INLINE inline # endif #endif /* * Annotation for data that may be exported into a DLL and used by other * apps that load that DLL and import the data. */ #if defined(_WIN32) && defined(VMX86_IMPORT_DLLDATA) # define VMX86_EXTERN_DATA extern __declspec(dllimport) #else // !_WIN32 # define VMX86_EXTERN_DATA extern #endif #if defined(_WIN32) && !defined(VMX86_NO_THREADS) #define THREADSPECIFIC __declspec(thread) #else #define THREADSPECIFIC #endif /* * Due to the wonderful "registry redirection" feature introduced in * 64-bit Windows, if you access any key under HKLM\Software in 64-bit * code, you need to open/create/delete that key with * VMKEY_WOW64_32KEY if you want a consistent view with 32-bit code. */ #ifdef _WIN32 #ifdef _WIN64 #define VMW_KEY_WOW64_32KEY KEY_WOW64_32KEY #else #define VMW_KEY_WOW64_32KEY 0x0 #endif #endif /* * Consider the following reasons functions are inlined: * * 1) inlined for performance reasons * 2) inlined because it's a single-use function * * Functions which meet only condition 2 should be marked with this * inline macro; It is not critical to be inlined (but there is a * code-space & runtime savings by doing so), so when other callers * are added the inline-ness should be removed. */ #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) /* * Starting at version 3.3, gcc does not always inline functions marked * 'inline' (it depends on their size). To force gcc to do so, one must use the * extra __always_inline__ attribute. */ # define INLINE_SINGLE_CALLER INLINE __attribute__((__always_inline__)) #else # define INLINE_SINGLE_CALLER INLINE #endif /* * Used when a hard guaranteed of no inlining is needed. Very few * instances need this since the absence of INLINE is a good hint * that gcc will not do inlining. */ #if defined(__GNUC__) && defined(VMM) #define ABSOLUTELY_NOINLINE __attribute__((__noinline__)) #endif /* * Attributes placed on function declarations to tell the compiler * that the function never returns. */ #ifdef _MSC_VER #define NORETURN __declspec(noreturn) #elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9) #define NORETURN __attribute__((__noreturn__)) #else #define NORETURN #endif /* * GCC 3.2 inline asm needs the + constraint for input/ouput memory operands. * Older GCCs don't know about it --hpreg */ #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2) # define VM_ASM_PLUS 1 #else # define VM_ASM_PLUS 0 #endif /* * Branch prediction hints: * LIKELY(exp) - Expression exp is likely TRUE. * UNLIKELY(exp) - Expression exp is likely FALSE. * Usage example: * if (LIKELY(excCode == EXC_NONE)) { * or * if (UNLIKELY(REAL_MODE(vc))) { * * We know how to predict branches on gcc3 and later (hopefully), * all others we don't so we do nothing. */ #if (__GNUC__ >= 3) /* * gcc3 uses __builtin_expect() to inform the compiler of an expected value. * We use this to inform the static branch predictor. The '!!' in LIKELY * will convert any !=0 to a 1. */ #define LIKELY(_exp) __builtin_expect(!!(_exp), 1) #define UNLIKELY(_exp) __builtin_expect((_exp), 0) #else #define LIKELY(_exp) (_exp) #define UNLIKELY(_exp) (_exp) #endif /* * GCC's argument checking for printf-like functions * This is conditional until we have replaced all `"%x", void *' * with `"0x%08x", (uint32) void *'. Note that %p prints different things * on different platforms. Argument checking is enabled for the * vmkernel, which has already been cleansed. * * fmtPos is the position of the format string argument, beginning at 1 * varPos is the position of the variable argument, beginning at 1 */ #if defined(__GNUC__) # define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos))) #else # define PRINTF_DECL(fmtPos, varPos) #endif #if defined(__GNUC__) # define SCANF_DECL(fmtPos, varPos) __attribute__((__format__(__scanf__, fmtPos, varPos))) #else # define SCANF_DECL(fmtPos, varPos) #endif /* * UNUSED_PARAM should surround the parameter name and type declaration, * e.g. "int MyFunction(int var1, UNUSED_PARAM(int var2))" * */ #ifndef UNUSED_PARAM # if defined(__GNUC__) # define UNUSED_PARAM(_parm) _parm __attribute__((__unused__)) # else # define UNUSED_PARAM(_parm) _parm # endif #endif /* * REGPARM defaults to REGPARM3; i.e., a request that gcc * put the first three arguments in registers. (It is fine * if the function has fewer than three arguments.) Gcc only. * Syntactically, put REGPARM where you'd put INLINE or NORETURN. * * Note that 64-bit code already puts the first six arguments in * registers, so these attributes are only useful for 32-bit code. */ #if defined(__GNUC__) # define REGPARM0 __attribute__((regparm(0))) # define REGPARM1 __attribute__((regparm(1))) # define REGPARM2 __attribute__((regparm(2))) # define REGPARM3 __attribute__((regparm(3))) # define REGPARM REGPARM3 #else # define REGPARM0 # define REGPARM1 # define REGPARM2 # define REGPARM3 # define REGPARM #endif /* * ALIGNED specifies minimum alignment in "n" bytes. */ #ifdef __GNUC__ #define ALIGNED(n) __attribute__((__aligned__(n))) #else #define ALIGNED(n) #endif /* * __func__ is a stringified function name that is part of the C99 standard. The block * below defines __func__ on older systems where the compiler does not support that * macro. */ #if defined(__GNUC__) \ && ((__GNUC__ == 2 && __GNUC_MINOR < 96) \ || (__GNUC__ < 2)) # define __func__ __FUNCTION__ #endif /* * Once upon a time, this was used to silence compiler warnings that * get generated when the compiler thinks that a function returns * when it is marked noreturn. Don't do it. Use NOT_REACHED(). */ #define INFINITE_LOOP() do { } while (1) /* * On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_ * is defined. Use the same logic here so we don't define it twice. [greg] */ #ifdef __FreeBSD__ # ifdef _BSD_SIZE_T_ # undef _BSD_SIZE_T_ # ifdef VM_I386 # ifdef VM_X86_64 typedef uint64 size_t; # else typedef uint32 size_t; # endif # endif /* VM_I386 */ # endif # ifdef _BSD_SSIZE_T_ # undef _BSD_SSIZE_T_ # ifdef VM_I386 # ifdef VM_X86_64 typedef int64 ssize_t; # else typedef int32 ssize_t; # endif # endif /* VM_I386 */ # endif #else # ifndef _SIZE_T # ifdef VM_I386 # define _SIZE_T # ifdef VM_X86_64 typedef uint64 size_t; # else typedef uint32 size_t; # endif # elif defined(__arm__) # define _SIZE_T typedef uint32 size_t; # endif # endif # if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(_SSIZE_T_) && \ !defined(ssize_t) && !defined(__ssize_t_defined) && \ !defined(_SSIZE_T_DECLARED) # ifdef VM_I386 # define _SSIZE_T # define __ssize_t_defined # define _SSIZE_T_DECLARED # ifdef VM_X86_64 typedef int64 ssize_t; # else typedef int32 ssize_t; # endif # elif defined(__arm__) # define _SSIZE_T # define __ssize_t_defined # define _SSIZE_T_DECLARED typedef int32 ssize_t; # endif # endif #endif /* * Format modifier for printing pid_t. On sun the pid_t is a ulong, but on * Linux it's an int. * Use this like this: printf("The pid is %"FMTPID".\n", pid); */ #ifdef sun # ifdef VM_X86_64 # define FMTPID "d" # else # define FMTPID "lu" # endif #else # define FMTPID "d" #endif /* * Format modifier for printing uid_t. On Solaris 10 and earlier, uid_t * is a ulong, but on other platforms it's an unsigned int. * Use this like this: printf("The uid is %"FMTUID".\n", uid); */ #if defined(sun) && !defined(SOL11) # ifdef VM_X86_64 # define FMTUID "u" # else # define FMTUID "lu" # endif #else # define FMTUID "u" #endif /* * Format modifier for printing mode_t. On sun the mode_t is a ulong, but on * Linux it's an int. * Use this like this: printf("The mode is %"FMTMODE".\n", mode); */ #ifdef sun # ifdef VM_X86_64 # define FMTMODE "o" # else # define FMTMODE "lo" # endif #else # define FMTMODE "o" #endif /* * Format modifier for printing time_t. Most platforms define a time_t to be * a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed * size quantity. Refer to the definition of FMTSZ to see why we need silly * preprocessor arithmetic. * Use this like this: printf("The mode is %"FMTTIME".\n", time); */ #if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5) # define FMTTIME FMTSZ"d" #else # if defined(_MSC_VER) # ifndef _SAFETIME_H_ # if (_MSC_VER < 1400) || defined(_USE_32BIT_TIME_T) # define FMTTIME "ld" # else # define FMTTIME FMT64"d" # endif # else # ifndef FMTTIME # error "safetime.h did not define FMTTIME" # endif # endif # else # define FMTTIME "ld" # endif #endif #ifdef __APPLE__ /* * Format specifier for all these annoying types such as {S,U}Int32 * which are 'long' in 32-bit builds * and 'int' in 64-bit builds. */ # ifdef __LP64__ # define FMTLI "" # else # define FMTLI "l" # endif /* * Format specifier for all these annoying types such as NS[U]Integer * which are 'int' in 32-bit builds * and 'long' in 64-bit builds. */ # ifdef __LP64__ # define FMTIL "l" # else # define FMTIL "" # endif #endif /* * Define MXSemaHandle here so both vmmon and vmx see this definition. */ #ifdef _WIN32 typedef uintptr_t MXSemaHandle; #else typedef int MXSemaHandle; #endif /* * Define type for poll device handles. */ typedef int64 PollDevHandle; /* * Define the utf16_t type. */ #if defined(_WIN32) && defined(_NATIVE_WCHAR_T_DEFINED) typedef wchar_t utf16_t; #else typedef uint16 utf16_t; #endif /* * Define for point and rectangle types. Defined here so they * can be used by other externally facing headers in bora/public. */ typedef struct VMPoint { int x, y; } VMPoint; #if defined _WIN32 && defined USERLEVEL struct tagRECT; typedef struct tagRECT VMRect; #else typedef struct VMRect { int left; int top; int right; int bottom; } VMRect; #endif /* * ranked locks "everywhere" */ typedef uint32 MX_Rank; #endif /* _VM_BASIC_TYPES_H_ */ vmci-only/shared/compat_timer.h 0000444 0000000 0000000 00000006551 11573420431 015600 0 ustar root root /********************************************************* * Copyright (C) 2002 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_TIMER_H__ # define __COMPAT_TIMER_H__ /* * The del_timer_sync() API appeared in 2.3.43 * It became reliable in 2.4.0-test3 * * --hpreg */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) # define compat_del_timer_sync(timer) del_timer_sync(timer) #else # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43) /* 2.3.43 removed asm/softirq.h's reference to bh_base. */ # include <linux/interrupt.h> # endif # include <asm/softirq.h> static inline int compat_del_timer_sync(struct timer_list *timer) // IN { int wasPending; start_bh_atomic(); wasPending = del_timer(timer); end_bh_atomic(); return wasPending; } #endif /* * The msleep_interruptible() API appeared in 2.6.9. * It is based on the msleep() API, which appeared in 2.4.29. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) # include <linux/delay.h> # define compat_msleep_interruptible(msecs) msleep_interruptible(msecs) # define compat_msleep(msecs) msleep(msecs) #else # include <linux/sched.h> /* * msecs_to_jiffies appeared in 2.6.7. For earlier kernels, * fall back to slow-case code (we don't use this operation * enough to need the performance). */ # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 7) # define msecs_to_jiffies(msecs) (((msecs) * HZ + 999) / 1000) # endif /* * set_current_state appeared in 2.2.18. */ # if LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) # define set_current_state(a) do { current->state = (a); } while(0) # endif static inline void compat_msleep_interruptible(unsigned long msecs) // IN { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(msecs_to_jiffies(msecs) + 1); } static inline void compat_msleep(unsigned long msecs) // IN { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(msecs_to_jiffies(msecs) + 1); } #endif /* * There is init_timer_deferrable() since 2.6.22. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) # define compat_init_timer_deferrable(timer) init_timer_deferrable(timer) #else # define compat_init_timer_deferrable(timer) init_timer(timer) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) static inline void compat_setup_timer(struct timer_list * timer, void (*function)(unsigned long), unsigned long data) { timer->function = function; timer->data = data; init_timer(timer); } #else # define compat_setup_timer(timer, function, data) \ setup_timer(timer, function, data) #endif #endif /* __COMPAT_TIMER_H__ */ vmci-only/shared/compat_fs.h 0000444 0000000 0000000 00000023312 11573420431 015062 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __COMPAT_FS_H__ # define __COMPAT_FS_H__ #include <linux/fs.h> /* * 2.6.5+ kernels define FS_BINARY_MOUNTDATA. Since it didn't exist and * wasn't used prior, it's safe to define it to zero. */ #ifndef FS_BINARY_MOUNTDATA #define FS_BINARY_MOUNTDATA 0 #endif /* * MAX_LFS_FILESIZE wasn't defined until 2.5.4. */ #ifndef MAX_LFS_FILESIZE # include <linux/pagemap.h> # if BITS_PER_LONG == 32 # define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG - 1)) - 1) # elif BITS_PER_LONG == 64 # define MAX_LFS_FILESIZE 0x7fffffffffffffffUL # endif #endif /* * sendfile as a VFS op was born in 2.5.30. Unfortunately, it also changed * signatures, first in 2.5.47, then again in 2.5.70, then again in 2.6.8. * Luckily, the 2.6.8+ signature is the same as the 2.5.47 signature. And * as of 2.6.23-rc1 sendfile is gone, replaced by splice_read... * * Let's not support sendfile from 2.5.30 to 2.5.47, because the 2.5.30 * signature is much different and file_send_actor isn't externed. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) #define VMW_SENDFILE_NONE #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 8) #define VMW_SENDFILE_NEW #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70) #define VMW_SENDFILE_OLD #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 47) #define VMW_SENDFILE_NEW #else #define VMW_SENDFILE_NONE #endif /* * splice_read is there since 2.6.17, but let's avoid 2.6.17-rcX kernels... * After all nobody is using splice system call until 2.6.23 using it to * implement sendfile. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) #define VMW_SPLICE_READ 1 #endif /* * Filesystems wishing to use generic page cache read/write routines are * supposed to implement aio_read and aio_write (calling into * generic_file_aio_read() and generic_file_aio_write() if necessary). * * The VFS exports do_sync_read() and do_sync_write() as the "new" * generic_file_read() and generic_file_write(), but filesystems need not * actually implement read and write- the VFS will automatically call * do_sync_write() and do_sync_read() when applications invoke the standard * read() and write() system calls. * * In 2.6.19, generic_file_read() and generic_file_write() were removed, * necessitating this change. AIO dates as far back as 2.5.42, but the API has * changed over time, so for simplicity, we'll only enable it from 2.6.19 and * on. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) # define VMW_USE_AIO #endif /* * The alloc_inode and destroy_inode VFS ops didn't exist prior to 2.4.21. * Without these functions, file systems can't embed inodes. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 21) # define VMW_EMBED_INODE #endif /* * iget() was removed from the VFS as of 2.6.25-rc1. The replacement for iget() * is iget_locked() which was added in 2.5.17. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 17) # define VMW_USE_IGET_LOCKED #endif /* * parent_ino was born in 2.5.5. For older kernels, let's use 2.5.5 * implementation. It uses the dcache lock which is OK because per-dentry * locking appeared after 2.5.5. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) #define compat_parent_ino(dentry) parent_ino(dentry) #else #define compat_parent_ino(dentry) \ ({ \ ino_t res; \ spin_lock(&dcache_lock); \ res = dentry->d_parent->d_inode->i_ino; \ spin_unlock(&dcache_lock); \ res; \ }) #endif /* * putname changed to __putname in 2.6.6. */ #define compat___getname() __getname() #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 6) #define compat___putname(name) putname(name) #else #define compat___putname(name) __putname(name) #endif /* * inc_nlink, drop_nlink, and clear_nlink were added in 2.6.19. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) #define compat_inc_nlink(inode) ((inode)->i_nlink++) #define compat_drop_nlink(inode) ((inode)->i_nlink--) #define compat_clear_nlink(inode) ((inode)->i_nlink = 0) #else #define compat_inc_nlink(inode) inc_nlink(inode) #define compat_drop_nlink(inode) drop_nlink(inode) #define compat_clear_nlink(inode) clear_nlink(inode) #endif /* * i_size_write and i_size_read were introduced in 2.6.0-test1 * (though we'll look for them as of 2.6.1). They employ slightly different * locking in order to guarantee atomicity, depending on the length of a long, * whether the kernel is SMP, or whether the kernel is preemptible. Prior to * i_size_write and i_size_read, there was no such locking, so that's the * behavior we'll emulate. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 1) #define compat_i_size_read(inode) ((inode)->i_size) #define compat_i_size_write(inode, size) ((inode)->i_size = size) #else #define compat_i_size_read(inode) i_size_read(inode) #define compat_i_size_write(inode, size) i_size_write(inode, size) #endif /* * filemap_fdatawrite was introduced in 2.5.12. Prior to that, modules used * filemap_fdatasync instead. In 2.4.18, both filemap_fdatawrite and * filemap_fdatawait began returning status codes. Prior to that, they were * void functions, so we'll just have them return 0. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 18) #define compat_filemap_fdatawrite(mapping) \ ({ \ int result = 0; \ filemap_fdatasync(mapping); \ result; \ }) #define compat_filemap_fdatawait(mapping) \ ({ \ int result = 0; \ filemap_fdatawait(mapping); \ result; \ }) #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 12) #define compat_filemap_fdatawrite(mapping) filemap_fdatasync(mapping) #define compat_filemap_fdatawait(mapping) filemap_fdatawait(mapping) #else #define compat_filemap_fdatawrite(mapping) filemap_fdatawrite(mapping) #define compat_filemap_fdatawait(mapping) filemap_fdatawait(mapping) #endif /* * filemap_write_and_wait was introduced in 2.6.6 and exported for module use * in 2.6.16. It's really just a simple wrapper around filemap_fdatawrite and * and filemap_fdatawait, which initiates a flush of all dirty pages, then * waits for the pages to flush. The implementation here is a simplified form * of the one found in 2.6.20-rc3. * * Unfortunately, it just isn't possible to implement this prior to 2.4.5, when * neither filemap_fdatawait nor filemap_fdatasync were exported for module * use. So we'll define it out and hope for the best. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 5) #define compat_filemap_write_and_wait(mapping) #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) #define compat_filemap_write_and_wait(mapping) \ ({ \ int result = 0; \ if (mapping->nrpages) { \ result = compat_filemap_fdatawrite(mapping); \ if (result != -EIO) { \ int result2 = compat_filemap_fdatawait(mapping); \ if (!result) { \ result = result2; \ } \ } \ } \ result; \ }) #else #define compat_filemap_write_and_wait(mapping) filemap_write_and_wait(mapping) #endif /* * invalidate_remote_inode was introduced in 2.6.0-test5. Prior to that, * filesystems wishing to invalidate pages belonging to an inode called * invalidate_inode_pages. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) #define compat_invalidate_remote_inode(inode) invalidate_inode_pages(inode) #else #define compat_invalidate_remote_inode(inode) invalidate_remote_inode(inode) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) #define VMW_FSYNC_OLD #endif #endif /* __COMPAT_FS_H__ */ vmci-only/shared/backdoor_types.h 0000444 0000000 0000000 00000006727 11573420432 016133 0 ustar root root /********************************************************* * Copyright (C) 1999 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ /* * backdoor_types.h -- * * Type definitions for backdoor interaction code. */ #ifndef _BACKDOOR_TYPES_H_ #define _BACKDOOR_TYPES_H_ #ifndef VM_I386 #error The backdoor protocol is only supported on x86 architectures. #endif /* * These #defines are intended for defining register structs as part of * existing named unions. If the union should encapsulate the register * (and nothing else), use DECLARE_REG_NAMED_STRUCT defined below. */ #define DECLARE_REG32_STRUCT \ struct { \ uint16 low; \ uint16 high; \ } halfs; \ uint32 word #define DECLARE_REG64_STRUCT \ DECLARE_REG32_STRUCT; \ struct { \ uint32 low; \ uint32 high; \ } words; \ uint64 quad #ifndef VM_X86_64 #define DECLARE_REG_STRUCT DECLARE_REG32_STRUCT #else #define DECLARE_REG_STRUCT DECLARE_REG64_STRUCT #endif #define DECLARE_REG_NAMED_STRUCT(_r) \ union { DECLARE_REG_STRUCT; } _r /* * Some of the registers are expressed by semantic name, because if they were * expressed as register structs declared above, we could only address them * by fixed size (half-word, word, quad, etc.) instead of by varying size * (size_t, uintptr_t). * * To be cleaner, these registers are expressed ONLY by semantic name, * rather than by a union of the semantic name and a register struct. */ typedef union { struct { DECLARE_REG_NAMED_STRUCT(ax); size_t size; /* Register bx. */ DECLARE_REG_NAMED_STRUCT(cx); DECLARE_REG_NAMED_STRUCT(dx); DECLARE_REG_NAMED_STRUCT(si); DECLARE_REG_NAMED_STRUCT(di); } in; struct { DECLARE_REG_NAMED_STRUCT(ax); DECLARE_REG_NAMED_STRUCT(bx); DECLARE_REG_NAMED_STRUCT(cx); DECLARE_REG_NAMED_STRUCT(dx); DECLARE_REG_NAMED_STRUCT(si); DECLARE_REG_NAMED_STRUCT(di); } out; } Backdoor_proto; typedef union { struct { DECLARE_REG_NAMED_STRUCT(ax); DECLARE_REG_NAMED_STRUCT(bx); size_t size; /* Register cx. */ DECLARE_REG_NAMED_STRUCT(dx); uintptr_t srcAddr; /* Register si. */ uintptr_t dstAddr; /* Register di. */ DECLARE_REG_NAMED_STRUCT(bp); } in; struct { DECLARE_REG_NAMED_STRUCT(ax); DECLARE_REG_NAMED_STRUCT(bx); DECLARE_REG_NAMED_STRUCT(cx); DECLARE_REG_NAMED_STRUCT(dx); DECLARE_REG_NAMED_STRUCT(si); DECLARE_REG_NAMED_STRUCT(di); DECLARE_REG_NAMED_STRUCT(bp); } out; } Backdoor_proto_hb; MY_ASSERTS(BACKDOOR_STRUCT_SIZES, ASSERT_ON_COMPILE(sizeof(Backdoor_proto) == 6 * sizeof(uintptr_t)); ASSERT_ON_COMPILE(sizeof(Backdoor_proto_hb) == 7 * sizeof(uintptr_t)); ) #undef DECLARE_REG_STRUCT #endif /* _BACKDOOR_TYPES_H_ */ vmci-only/shared/compat_kernel.h 0000444 0000000 0000000 00000002735 11573420431 015740 0 ustar root root /********************************************************* * Copyright (C) 2004 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_KERNEL_H__ # define __COMPAT_KERNEL_H__ #include <asm/unistd.h> #include <linux/kernel.h> /* * container_of was introduced in 2.5.28 but it's easier to check like this. */ #ifndef container_of #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #endif /* * vsnprintf became available in 2.4.10. For older kernels, just fall back on * vsprintf. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10) #define vsnprintf(str, size, fmt, args) vsprintf(str, fmt, args) #endif #endif /* __COMPAT_KERNEL_H__ */ vmci-only/shared/vmciKernelAPI1.h 0000444 0000000 0000000 00000016003 11573420432 015621 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciKernelAPI1.h -- * * Kernel API (v1) exported from the VMCI host and guest drivers. */ #ifndef __VMCI_KERNELAPI_1_H__ #define __VMCI_KERNELAPI_1_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" /* VMCI module namespace on vmkernel. */ #define MOD_VMCI_NAMESPACE "com.vmware.vmci" /* Define version 1. */ #undef VMCI_KERNEL_API_VERSION #define VMCI_KERNEL_API_VERSION_1 1 #define VMCI_KERNEL_API_VERSION VMCI_KERNEL_API_VERSION_1 /* Macros to operate on the driver version number. */ #define VMCI_MAJOR_VERSION(v) (((v) >> 16) & 0xffff) #define VMCI_MINOR_VERSION(v) ((v) & 0xffff) /* VMCI Device Usage API. */ Bool VMCI_DeviceGet(uint32 *apiVersion); void VMCI_DeviceRelease(void); /* VMCI Datagram API. */ int VMCIDatagram_CreateHnd(VMCIId resourceID, uint32 flags, VMCIDatagramRecvCB recvCB, void *clientData, VMCIHandle *outHandle); int VMCIDatagram_CreateHndPriv(VMCIId resourceID, uint32 flags, VMCIPrivilegeFlags privFlags, VMCIDatagramRecvCB recvCB, void *clientData, VMCIHandle *outHandle); int VMCIDatagram_DestroyHnd(VMCIHandle handle); int VMCIDatagram_Send(VMCIDatagram *msg); /* VMCI Utility API. */ VMCIId VMCI_GetContextID(void); uint32 VMCI_Version(void); int VMCI_ContextID2HostVmID(VMCIId contextID, void *hostVmID, size_t hostVmIDLen); /* VMCI Event API. */ typedef void (*VMCI_EventCB)(VMCIId subID, VMCI_EventData *ed, void *clientData); int VMCIEvent_Subscribe(VMCI_Event event, uint32 flags, VMCI_EventCB callback, void *callbackData, VMCIId *subID); int VMCIEvent_Unsubscribe(VMCIId subID); /* VMCI Context API */ VMCIPrivilegeFlags VMCIContext_GetPrivFlags(VMCIId contextID); /* VMCI Discovery Service API. */ int VMCIDs_Lookup(const char *name, VMCIHandle *out); /* VMCI Queue Pair API. */ typedef struct VMCIQPair VMCIQPair; int VMCIQPair_Alloc(VMCIQPair **qpair, VMCIHandle *handle, uint64 produceQSize, uint64 consumeQSize, VMCIId peer, uint32 flags, VMCIPrivilegeFlags privFlags); int VMCIQPair_Detach(VMCIQPair **qpair); int VMCIQPair_GetProduceIndexes(const VMCIQPair *qpair, uint64 *producerTail, uint64 *consumerHead); int VMCIQPair_GetConsumeIndexes(const VMCIQPair *qpair, uint64 *consumerTail, uint64 *producerHead); int64 VMCIQPair_ProduceFreeSpace(const VMCIQPair *qpair); int64 VMCIQPair_ProduceBufReady(const VMCIQPair *qpair); int64 VMCIQPair_ConsumeFreeSpace(const VMCIQPair *qpair); int64 VMCIQPair_ConsumeBufReady(const VMCIQPair *qpair); ssize_t VMCIQPair_Enqueue(VMCIQPair *qpair, const void *buf, size_t bufSize, int mode); ssize_t VMCIQPair_Dequeue(VMCIQPair *qpair, void *buf, size_t bufSize, int mode); ssize_t VMCIQPair_Peek(VMCIQPair *qpair, void *buf, size_t bufSize, int mode); #if defined (SOLARIS) || (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ (defined(__linux__) && defined(__KERNEL__)) || \ (defined(_WIN32) && defined(WINNT_DDK)) /* * Environments that support struct iovec */ ssize_t VMCIQPair_EnqueueV(VMCIQPair *qpair, void *iov, size_t iovSize, int mode); ssize_t VMCIQPair_DequeueV(VMCIQPair *qpair, void *iov, size_t iovSize, int mode); ssize_t VMCIQPair_PeekV(VMCIQPair *qpair, void *iov, size_t iovSize, int mode); #endif /* Systems that support struct iovec */ /* Typedefs for all of the above, used by the IOCTLs and the kernel library. */ typedef void (VMCI_DeviceReleaseFct)(void); typedef int (VMCIDatagram_CreateHndFct)(VMCIId, uint32, VMCIDatagramRecvCB, void *, VMCIHandle *); typedef int (VMCIDatagram_CreateHndPrivFct)(VMCIId, uint32, VMCIPrivilegeFlags, VMCIDatagramRecvCB, void *, VMCIHandle *); typedef int (VMCIDatagram_DestroyHndFct)(VMCIHandle); typedef int (VMCIDatagram_SendFct)(VMCIDatagram *); typedef VMCIId (VMCI_GetContextIDFct)(void); typedef uint32 (VMCI_VersionFct)(void); typedef int (VMCIEvent_SubscribeFct)(VMCI_Event, uint32, VMCI_EventCB, void *, VMCIId *); typedef int (VMCIEvent_UnsubscribeFct)(VMCIId); typedef int (VMCIQPair_AllocFct)(VMCIQPair **, VMCIHandle *, uint64, uint64, VMCIId, uint32, VMCIPrivilegeFlags); typedef int (VMCIQPair_DetachFct)(VMCIQPair **); typedef int (VMCIQPair_GetProduceIndexesFct)(const VMCIQPair *, uint64 *, uint64 *); typedef int (VMCIQPair_GetConsumeIndexesFct)(const VMCIQPair *, uint64 *, uint64 *); typedef int64 (VMCIQPair_ProduceFreeSpaceFct)(const VMCIQPair *); typedef int64 (VMCIQPair_ProduceBufReadyFct)(const VMCIQPair *); typedef int64 (VMCIQPair_ConsumeFreeSpaceFct)(const VMCIQPair *); typedef int64 (VMCIQPair_ConsumeBufReadyFct)(const VMCIQPair *); typedef ssize_t (VMCIQPair_EnqueueFct)(VMCIQPair *, const void *, size_t, int); typedef ssize_t (VMCIQPair_DequeueFct)(VMCIQPair *, void *, size_t, int); typedef ssize_t (VMCIQPair_PeekFct)(VMCIQPair *, void *, size_t, int); typedef ssize_t (VMCIQPair_EnqueueVFct)(VMCIQPair *qpair, void *, size_t, int); typedef ssize_t (VMCIQPair_DequeueVFct)(VMCIQPair *qpair, void *, size_t, int); typedef ssize_t (VMCIQPair_PeekVFct)(VMCIQPair *qpair, void *, size_t, int); #endif /* !__VMCI_KERNELAPI_1_H__ */ vmci-only/shared/compat_autoconf.h 0000444 0000000 0000000 00000002600 11573420431 016265 0 ustar root root /********************************************************* * Copyright (C) 2009 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 and no later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *********************************************************/ #ifndef __COMPAT_AUTOCONF_H__ # define __COMPAT_AUTOCONF_H__ #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_DISTRIBUTE #include "includeCheck.h" #ifndef LINUX_VERSION_CODE # error "Include compat_version.h before compat_autoconf.h" #endif /* autoconf.h moved from linux/autoconf.h to generated/autoconf.h in 2.6.33-rc1. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) # include <linux/autoconf.h> #else # include <generated/autoconf.h> #endif #endif /* __COMPAT_AUTOCONF_H__ */ vmci-only/shared/compat_ethtool.h 0000444 0000000 0000000 00000003306 11573420431 016131 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef _COMPAT_ETHTOOL_H #define _COMPAT_ETHTOOL_H /* * ethtool is a userspace utility for getting and setting ethernet device * settings. Kernel support for it was first published in 2.4.0-test11, but * only in 2.4.15 were the ethtool_value struct and the ETHTOOL_GLINK ioctl * added to ethtool.h (together, because the ETHTOOL_GLINK ioctl expects a * single value response). * * Likewise, ioctls for getting and setting TSO were published in 2.4.22. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) # include <linux/ethtool.h> # ifndef ETHTOOL_GLINK # define ETHTOOL_GLINK 0x0a typedef struct { __u32 cmd; __u32 data; } compat_ethtool_value; # else typedef struct ethtool_value compat_ethtool_value; # endif # ifndef ETHTOOL_GTSO # define ETHTOOL_GTSO 0x1E # define ETHTOOL_STSO 0x1F # endif #endif #endif /* _COMPAT_ETHTOOL_H */ vmci-only/shared/dbllnklst.h 0000444 0000000 0000000 00000013044 11573420427 015106 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * dbllnklst.h -- * * Double linked lists */ #ifndef _DBLLNKLST_H_ #define _DBLLNKLST_H_ #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" #include "vm_basic_types.h" #define DblLnkLst_OffsetOf(type, field) ((intptr_t)&((type *)0)->field) #define DblLnkLst_Container(addr, type, field) \ ((type *)((char *)(addr) - DblLnkLst_OffsetOf(type, field))) #define DblLnkLst_ForEach(curr, head) \ for (curr = (head)->next; curr != (head); curr = (curr)->next) /* Safe from list element removal within loop body. */ #define DblLnkLst_ForEachSafe(curr, nextElem, head) \ for (curr = (head)->next, nextElem = (curr)->next; \ curr != (head); \ curr = nextElem, nextElem = (curr)->next) typedef struct DblLnkLst_Links { struct DblLnkLst_Links *prev; struct DblLnkLst_Links *next; } DblLnkLst_Links; /* * Functions * * DblLnkLst_LinkFirst and DblLnkLst_LinkLast are specific * to anchored lists. The rest are for both circular and * anchored lists. */ /* *---------------------------------------------------------------------- * * DblLnkLst_Init -- * * Initialize a member of a doubly linked list * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_Init(DblLnkLst_Links *l) // IN { l->prev = l->next = l; } /* *---------------------------------------------------------------------- * * DblLnkLst_Link -- * * Merge two doubly linked lists into one * * The operation is commutative * The operation is inversible (its inverse is DblLnkLst_Unlink) * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_Link(DblLnkLst_Links *l1, // IN DblLnkLst_Links *l2) // IN { DblLnkLst_Links *tmp; (tmp = l1->prev)->next = l2; (l1->prev = l2->prev)->next = l1; l2->prev = tmp ; } /* *---------------------------------------------------------------------- * * DblLnkLst_Unlink -- * * Split one doubly linked list into two * * No check is performed: the caller must ensure that both members * belong to the same doubly linked list * * The operation is commutative * The operation is inversible (its inverse is DblLnkLst_Link) * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_Unlink(DblLnkLst_Links *l1, // IN DblLnkLst_Links *l2) // IN { DblLnkLst_Links *tmp; tmp = l1->prev ; (l1->prev = l2->prev)->next = l1; (l2->prev = tmp )->next = l2; } /* *---------------------------------------------------------------------- * * DblLnkLst_Unlink1 -- * * Unlink an element from its list. * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_Unlink1(DblLnkLst_Links *l) // IN { DblLnkLst_Unlink(l, l->next); } /* *---------------------------------------------------------------------------- * * DblLnkLst_IsLinked -- * * Determines whether an element is linked with any other elements. * * Results: * TRUE if link is linked, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------------- */ static INLINE Bool DblLnkLst_IsLinked(DblLnkLst_Links const *l) // IN { /* * A DblLnkLst_Links is either linked to itself (not linked) or linked to * other elements in a list (linked). */ return l->prev != l; } /* *---------------------------------------------------------------------- * * DblLnkLst_LinkFirst -- * * Insert 'l' at the beginning of the list anchored at 'head' * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_LinkFirst(DblLnkLst_Links *head, // IN DblLnkLst_Links *l) // IN { DblLnkLst_Link(head->next, l); } /* *---------------------------------------------------------------------- * * DblLnkLst_LinkLast -- * * Insert 'l' at the end of the list anchored at 'head' * * Result * None * * Side effects: * None * *---------------------------------------------------------------------- */ static INLINE void DblLnkLst_LinkLast(DblLnkLst_Links *head, // IN DblLnkLst_Links *l) // IN { DblLnkLst_Link(head, l); } #endif /* _DBLLNKLST_H_ */ vmci-only/shared/vm_assert.h 0000444 0000000 0000000 00000026413 11573420432 015120 0 ustar root root /********************************************************* * Copyright (C) 1998-2004 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU 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_assert.h -- * * The basic assertion facility for all VMware code. * * For proper use, see * http://vmweb.vmware.com/~mts/WebSite/guide/programming/asserts.html */ #ifndef _VM_ASSERT_H_ #define _VM_ASSERT_H_ #define INCLUDE_ALLOW_USERLEVEL #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_VMMON #define INCLUDE_ALLOW_VMKERNEL #define INCLUDE_ALLOW_VMKDRIVERS #define INCLUDE_ALLOW_VMK_MODULE #define INCLUDE_ALLOW_DISTRIBUTE #define INCLUDE_ALLOW_VMCORE #define INCLUDE_ALLOW_VMIROM #include "includeCheck.h" // XXX not necessary except some places include vm_assert.h improperly #include "vm_basic_types.h" #include "vm_basic_defs.h" /* * XXX old file code */ #ifdef FILECODEINT #error "Don't define FILECODEINT. It is obsolete." #endif #ifdef FILECODE #error "Don't define FILECODE. It is obsolete." #endif /* * Panic and log functions */ EXTERN void Log(const char *fmt, ...) PRINTF_DECL(1, 2); EXTERN void Warning(const char *fmt, ...) PRINTF_DECL(1, 2); EXTERN NORETURN void Panic(const char *fmt, ...) PRINTF_DECL(1, 2); EXTERN void LogThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3); EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...) PRINTF_DECL(2, 3); /* DB family: messages which are parsed by logfile database system */ #define WarningDB Warning #define LogDB Log #define WarningThrottledDB WarningThrottled #define LogThrottledDB LogThrottled /* * Stress testing: redefine ASSERT_IFNOT() to taste */ #ifndef ASSERT_IFNOT /* * PR 271512: When compiling with gcc, catch assignments inside an ASSERT. * * 'UNLIKELY' is defined with __builtin_expect, which does not warn when * passed an assignment (gcc bug 36050). To get around this, we put 'cond' * in an 'if' statement and make sure it never gets executed by putting * that inside of 'if (0)'. We use gcc's statement expression syntax to * make ASSERT an expression because some code uses it that way. * * Since statement expression syntax is a gcc extension and since it's * not clear if this is a problem with other compilers, the ASSERT * definition was not changed for them. Using a bare 'cond' with the * ternary operator may provide a solution. */ #ifdef __GNUC__ #define ASSERT_IFNOT(cond, panic) \ ({if (UNLIKELY(!(cond))) { panic; if (0) { if (cond) { ; } } } (void)0;}) #else #define ASSERT_IFNOT(cond, panic) \ (UNLIKELY(!(cond)) ? (panic) : (void)0) #endif #endif /* * Assert, panic, and log macros * * Some of these are redefined below undef !VMX86_DEBUG. * ASSERT() is special cased because of interaction with Windows DDK. */ #if defined VMX86_DEBUG || defined ASSERT_ALWAYS_AVAILABLE #undef ASSERT #define ASSERT(cond) \ ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertAssert)) #endif #define ASSERT_BUG(bug, cond) \ ASSERT_IFNOT(cond, _ASSERT_PANIC_BUG(bug, AssertAssert)) #define ASSERT_BUG_DEBUGONLY(bug, cond) ASSERT_BUG(bug, cond) #define PANIC() _ASSERT_PANIC(AssertPanic) #define PANIC_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertPanic) #define ASSERT_NOT_IMPLEMENTED(cond) \ ASSERT_IFNOT(cond, NOT_IMPLEMENTED()) #define ASSERT_NOT_IMPLEMENTED_BUG(bug, cond) \ ASSERT_IFNOT(cond, NOT_IMPLEMENTED_BUG(bug)) #define NOT_IMPLEMENTED() _ASSERT_PANIC(AssertNotImplemented) #define NOT_IMPLEMENTED_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertNotImplemented) #define NOT_REACHED() _ASSERT_PANIC(AssertNotReached) #define NOT_REACHED_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertNotReached) #define ASSERT_MEM_ALLOC(cond) \ ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertMemAlloc)) #ifdef VMX86_DEVEL #define ASSERT_LENGTH(real, expected) \ ASSERT_IFNOT((real) == (expected), \ Panic(AssertLengthFmt, __FILE__, __LINE__, real, expected)) #else #define ASSERT_LENGTH(real, expected) ASSERT((real) == (expected)) #endif #ifdef VMX86_DEVEL #define ASSERT_DEVEL(cond) ASSERT(cond) #else #define ASSERT_DEVEL(cond) ((void) 0) #endif #define ASSERT_NO_INTERRUPTS() ASSERT(!INTERRUPTS_ENABLED()) #define ASSERT_HAS_INTERRUPTS() ASSERT(INTERRUPTS_ENABLED()) #define ASSERT_LOG_UNEXPECTED(bug, cond) \ (UNLIKELY(!(cond)) ? LOG_UNEXPECTED(bug) : 0) #ifdef VMX86_DEVEL #define LOG_UNEXPECTED(bug) \ Warning(AssertUnexpectedFmt, __FILE__, __LINE__, bug) #else #define LOG_UNEXPECTED(bug) \ Log(AssertUnexpectedFmt, __FILE__, __LINE__, bug) #endif #define ASSERT_NOT_TESTED(cond) (UNLIKELY(!(cond)) ? NOT_TESTED() : 0) #ifdef VMX86_DEVEL #define NOT_TESTED() Warning(AssertNotTestedFmt, __FILE__, __LINE__) #else #define NOT_TESTED() Log(AssertNotTestedFmt, __FILE__, __LINE__) #endif #define NOT_TESTED_ONCE() \ do { \ static Bool alreadyPrinted = FALSE; \ if (UNLIKELY(!alreadyPrinted)) { \ alreadyPrinted = TRUE; \ NOT_TESTED(); \ } \ } while (0) #define NOT_TESTED_1024() \ do { \ static uint16 count = 0; \ if (UNLIKELY(count == 0)) { NOT_TESTED(); } \ count = (count + 1) & 1023; \ } while (0) #define LOG_ONCE(_s) \ do { \ static Bool logged = FALSE; \ if (!logged) { \ Log _s; \ logged = TRUE; \ } \ } while (0) /* * Redefine macros that are only in debug versions */ #if !defined VMX86_DEBUG && !defined ASSERT_ALWAYS_AVAILABLE // { #undef ASSERT #define ASSERT(cond) ((void) 0) #undef ASSERT_BUG_DEBUGONLY #define ASSERT_BUG_DEBUGONLY(bug, cond) ((void) 0) #undef ASSERT_LENGTH #define ASSERT_LENGTH(real, expected) ((void) 0) /* * Expand NOT_REACHED() as appropriate for each situation. * * Mainly, we want the compiler to infer the same control-flow * information as it would from Panic(). Otherwise, different * compilation options will lead to different control-flow-derived * errors, causing some make targets to fail while others succeed. * * VC++ has the __assume() built-in function which we don't trust * (see bug 43485); gcc has no such construct; we just panic in * userlevel code. The monitor doesn't want to pay the size penalty * (measured at 212 bytes for the release vmm for a minimal infinite * loop; panic would cost even more) so it does without and lives * with the inconsistency. */ #ifdef VMM #undef NOT_REACHED #define NOT_REACHED() ((void) 0) #else // keep debug definition #endif #undef ASSERT_LOG_UNEXPECTED #define ASSERT_LOG_UNEXPECTED(bug, cond) ((void) 0) #undef LOG_UNEXPECTED #define LOG_UNEXPECTED(bug) ((void) 0) #undef ASSERT_NOT_TESTED #define ASSERT_NOT_TESTED(cond) ((void) 0) #undef NOT_TESTED #define NOT_TESTED() ((void) 0) #undef NOT_TESTED_ONCE #define NOT_TESTED_ONCE() ((void) 0) #undef NOT_TESTED_1024 #define NOT_TESTED_1024() ((void) 0) #endif // !VMX86_DEBUG } /* * Compile-time assertions. * * ASSERT_ON_COMPILE does not use the common * switch (0) { case 0: case (e): ; } trick because some compilers (e.g. MSVC) * generate code for it. * * The implementation uses both enum and typedef because the typedef alone is * insufficient; gcc allows arrays to be declared with non-constant expressions * (even in typedefs, where it makes no sense). */ #define ASSERT_ON_COMPILE(e) \ do { \ enum { AssertOnCompileMisused = ((e) ? 1 : -1) }; \ typedef char AssertOnCompileFailed[AssertOnCompileMisused]; \ } while (0) /* * To put an ASSERT_ON_COMPILE() outside a function, wrap it * in MY_ASSERTS(). The first parameter must be unique in * each .c file where it appears. For example, * * MY_ASSERTS(FS3_INT, * ASSERT_ON_COMPILE(sizeof(FS3_DiskLock) == 128); * ASSERT_ON_COMPILE(sizeof(FS3_DiskLockReserved) == DISK_BLOCK_SIZE); * ASSERT_ON_COMPILE(sizeof(FS3_DiskBlock) == DISK_BLOCK_SIZE); * ASSERT_ON_COMPILE(sizeof(Hardware_DMIUUID) == 16); * ) * * Caution: ASSERT() within MY_ASSERTS() is silently ignored. * The same goes for anything else not evaluated at compile time. */ #define MY_ASSERTS(name, assertions) \ static INLINE void name(void) { \ assertions \ } /* * Internal macros, functions, and strings * * The monitor wants to save space at call sites, so it has specialized * functions for each situation. User level wants to save on implementation * so it uses generic functions. */ #if !defined VMM || defined MONITOR_APP // { #if defined VMKERNEL // vmkernel Panic() function does not want a trailing newline. #define _ASSERT_PANIC(name) \ Panic(_##name##Fmt, __FILE__, __LINE__) #define _ASSERT_PANIC_BUG(bug, name) \ Panic(_##name##Fmt " bugNr=%d", __FILE__, __LINE__, bug) #else /* !VMKERNEL */ #define _ASSERT_PANIC(name) \ Panic(_##name##Fmt "\n", __FILE__, __LINE__) #define _ASSERT_PANIC_BUG(bug, name) \ Panic(_##name##Fmt " bugNr=%d\n", __FILE__, __LINE__, bug) #endif /* VMKERNEL */ #define AssertLengthFmt _AssertLengthFmt #define AssertUnexpectedFmt _AssertUnexpectedFmt #define AssertNotTestedFmt _AssertNotTestedFmt #endif // } // these don't have newline so a bug can be tacked on #define _AssertPanicFmt "PANIC %s:%d" #define _AssertAssertFmt "ASSERT %s:%d" #define _AssertNotImplementedFmt "NOT_IMPLEMENTED %s:%d" #define _AssertNotReachedFmt "NOT_REACHED %s:%d" #define _AssertMemAllocFmt "MEM_ALLOC %s:%d" // these are complete formats with newline #define _AssertLengthFmt "LENGTH %s:%d r=%#x e=%#x\n" #define _AssertUnexpectedFmt "UNEXPECTED %s:%d bugNr=%d\n" #define _AssertNotTestedFmt "NOT_TESTED %s:%d\n" #endif /* ifndef _VM_ASSERT_H_ */ vmci-only/shared/compat_namei.h 0000444 0000000 0000000 00000004106 11573420431 015543 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __COMPAT_NAMEI_H__ # define __COMPAT_NAMEI_H__ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 18) #include <linux/namei.h> #endif /* * In 2.6.25-rc2, dentry and mount objects were removed from the nameidata * struct. They were both replaced with a struct path. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) #define compat_vmw_nd_to_dentry(nd) (nd).path.dentry #else #define compat_vmw_nd_to_dentry(nd) (nd).dentry #endif /* In 2.6.25-rc2, path_release(&nd) was replaced with path_put(&nd.path). */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) #define compat_path_release(nd) path_put(&(nd)->path) #else #define compat_path_release(nd) path_release(nd) #endif /* path_lookup was exported in 2.4.25 */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25) #define compat_path_lookup(path, flags, nd) path_lookup(path, flags, nd) #else #define compat_path_lookup(path, flags, nd) \ ({ \ int ret = 0; \ if (path_init(path, flags, nd)) { \ ret = path_walk(path, nd); \ } \ ret; \ }) #endif #endif /* __COMPAT_NAMEI_H__ */ vmci-only/vmciKernelIf.c 0000444 0000000 0000000 00000122512 11573420431 014214 0 ustar root root /********************************************************* * 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/wait.h> #include <linux/vmalloc.h> #include "compat_module.h" #include "compat_version.h" #include "compat_sched.h" #include "compat_workqueue.h" #include "compat_interrupt.h" #include "compat_spinlock.h" #include "compat_slab.h" #include "compat_semaphore.h" #include "compat_page.h" #include "compat_mm.h" #include "compat_highmem.h" #include "vm_basic_types.h" #include "vm_assert.h" #include "vmci_kernel_if.h" #ifndef VMX86_TOOLS # include "vmciQueuePair.h" #endif #include "vmciQueue.h" #include "vmci_iocontrols.h" /* * The Kernel specific component of the VMCIQueue structure. */ #if defined VMX86_TOOLS struct VMCIQueueKernelIf { struct page *page[0]; }; #else struct VMCIQueueKernelIf { struct page **page; }; #endif typedef struct VMCIDelayedWorkInfo { compat_work work; VMCIWorkFn *workFn; void *data; } VMCIDelayedWorkInfo; /* *----------------------------------------------------------------------------- * * VMCI_InitLock * * Initializes the lock. Must be called before use. * * Results: * None * * Side effects: * Thread can block. * *----------------------------------------------------------------------------- */ void VMCI_InitLock(VMCILock *lock, // IN: char *name, // IN: Unused on Linux VMCILockRank rank) // IN: Unused on Linux { spin_lock_init(lock); } /* *----------------------------------------------------------------------------- * * 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 { } /* *---------------------------------------------------------------------- * * 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_AllocBuffer * * Allocate some kernel memory for the VMCI driver. The memory is * not guaranteed to have a mapping in the virtual address * space. Use VMCI_MapBuffer to get a VA mapping for the memory. * * Results: * A reference to the allocated memory or VMCI_BUFFER_INVALID * on error. * * * Side effects: * memory is allocated. *---------------------------------------------------------------------- */ VMCIBuffer VMCI_AllocBuffer(size_t size, int flags) { return VMCI_AllocKernelMem(size, flags); } /* *---------------------------------------------------------------------- * * VMCI_MapBuffer * * Ensures that the kernel memory allocated with VMCI_AllocBuffer * has a mapping in the virtual address space. * * Results: * None. * * Side effects: * virtual address mapping of kernel memory is established. *---------------------------------------------------------------------- */ void * VMCI_MapBuffer(VMCIBuffer buf) { return buf; } /* *---------------------------------------------------------------------- * * VMCI_ReleaseBuffer * * Releases the VA mapping of kernel memory allocated with * VMCI_AllocBuffer. * * Results: * None. * * Side effects: * virtual address mapping of kernel memory is released. *---------------------------------------------------------------------- */ void VMCI_ReleaseBuffer(void *ptr) // IN: The VA of the mapped memory { } /* *---------------------------------------------------------------------- * * VMCI_FreeBuffer * * Free temporary kernel memory allocated for the VMCI driver. * * Results: * None. * * Side effects: * memory is freed. *---------------------------------------------------------------------- */ void VMCI_FreeBuffer(VMCIBuffer buf, // IN: size_t size) // IN: Unused on Linux { VMCI_FreeKernelMem(buf, size); } /* *----------------------------------------------------------------------------- * * 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: { 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); } #ifdef VMX86_TOOLS /* *----------------------------------------------------------------------------- * * 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) { uint64 i; VMCIQueue *queue; VMCIQueueHeader *qHeader; const uint64 numDataPages = CEILING(size, PAGE_SIZE); const uint queueSize = PAGE_SIZE + sizeof *queue + numDataPages * sizeof queue->kernelIf->page[0]; /* * 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; } qHeader = (VMCIQueueHeader *)vmalloc(queueSize); if (!qHeader) { return NULL; } queue = (VMCIQueue *)((uint8 *)qHeader + PAGE_SIZE); queue->qHeader = qHeader; queue->kernelIf = (VMCIQueueKernelIf *)((uint8 *)queue + sizeof *queue); for (i = 0; i < numDataPages; i++) { queue->kernelIf->page[i] = alloc_pages(GFP_KERNEL, 0); if (!queue->kernelIf->page[i]) { while (i) { __free_page(queue->kernelIf->page[--i]); } vfree(qHeader); return NULL; } } 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; 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; } #endif #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 = kmap(kernelIf->page[pageIndex]); size_t toCopy; 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) { kunmap(kernelIf->page[pageIndex]); return VMCI_ERROR_INVALID_ARGS; } } else { memcpy((uint8 *)va + pageOffset, (uint8 *)src + bytesCopied, toCopy); } bytesCopied += toCopy; 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 = kmap(kernelIf->page[pageIndex]); size_t toCopy; 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) { kunmap(kernelIf->page[pageIndex]); return VMCI_ERROR_INVALID_ARGS; } } else { memcpy((uint8 *)dest + bytesCopied, (uint8 *)va + pageOffset, toCopy); } bytesCopied += toCopy; 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 { 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 { 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: ignored { /* * 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: ignored { /* * 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; } #ifndef VMX86_TOOLS /* *----------------------------------------------------------------------------- * * 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 uint queueSize = sizeof *queue + sizeof *(queue->kernelIf); queue = VMCI_AllocKernelMem(queueSize, VMCI_MEMORY_NORMAL); if (queue) { queue->qHeader = NULL; queue->kernelIf = (VMCIQueueKernelIf *)((uint8 *)queue + sizeof *queue); } 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); } } /* *----------------------------------------------------------------------------- * * 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(PageStoreAttachInfo *attach, // IN/OUT VMCIQueue *produceQ, // OUT VMCIQueue *consumeQ) // OUT { int retval; int err = VMCI_SUCCESS; attach->producePages = VMCI_AllocKernelMem(attach->numProducePages * sizeof attach->producePages[0], VMCI_MEMORY_NORMAL); if (attach->producePages == NULL) { return VMCI_ERROR_NO_MEM; } attach->consumePages = VMCI_AllocKernelMem(attach->numConsumePages * sizeof attach->consumePages[0], VMCI_MEMORY_NORMAL); if (attach->consumePages == NULL) { err = VMCI_ERROR_NO_MEM; goto errorDealloc; } down_write(¤t->mm->mmap_sem); retval = get_user_pages(current, current->mm, (VA)attach->produceBuffer, attach->numProducePages, 1, 0, attach->producePages, NULL); if (retval < attach->numProducePages) { Log("get_user_pages(produce) failed: %d\n", retval); if (retval > 0) { int i; for (i = 0; i < retval; i++) { page_cache_release(attach->producePages[i]); } } err = VMCI_ERROR_NO_MEM; goto out; } retval = get_user_pages(current, current->mm, (VA)attach->consumeBuffer, attach->numConsumePages, 1, 0, attach->consumePages, NULL); if (retval < attach->numConsumePages) { int i; Log("get_user_pages(consume) failed: %d\n", retval); if (retval > 0) { for (i = 0; i < retval; i++) { page_cache_release(attach->consumePages[i]); } } for (i = 0; i < attach->numProducePages; i++) { page_cache_release(attach->producePages[i]); } err = VMCI_ERROR_NO_MEM; } if (err == VMCI_SUCCESS) { produceQ->qHeader = kmap(attach->producePages[0]); produceQ->kernelIf->page = &attach->producePages[1]; consumeQ->qHeader = kmap(attach->consumePages[0]); consumeQ->kernelIf->page = &attach->consumePages[1]; } out: up_write(¤t->mm->mmap_sem); errorDealloc: if (err < VMCI_SUCCESS) { if (attach->producePages != NULL) { VMCI_FreeKernelMem(attach->producePages, attach->numProducePages * sizeof attach->producePages[0]); } if (attach->consumePages != NULL) { VMCI_FreeKernelMem(attach->consumePages, attach->numConsumePages * sizeof attach->consumePages[0]); } } 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(PageStoreAttachInfo *attach, // IN/OUT VMCIQueue *produceQ, // OUT VMCIQueue *consumeQ) // OUT { int i; ASSERT(attach->producePages); ASSERT(attach->consumePages); kunmap(attach->producePages[0]); kunmap(attach->consumePages[0]); for (i = 0; i < attach->numProducePages; i++) { ASSERT(attach->producePages[i]); set_page_dirty(attach->producePages[i]); page_cache_release(attach->producePages[i]); } for (i = 0; i < attach->numConsumePages; i++) { ASSERT(attach->consumePages[i]); set_page_dirty(attach->consumePages[i]); page_cache_release(attach->consumePages[i]); } VMCI_FreeKernelMem(attach->producePages, attach->numProducePages * sizeof attach->producePages[0]); VMCI_FreeKernelMem(attach->consumePages, attach->numConsumePages * sizeof attach->consumePages[0]); } #endif /* Host only code */ vmci-only/vmciGuestKernelIf.h 0000444 0000000 0000000 00000003546 11573420371 015241 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciGuestKernelIf.h -- * * This file defines OS encapsulation helper functions that are * needed only in VMCI guest kernel code. It must work for * windows, solaris and linux kernel, ie. using defines * where necessary. */ #ifndef _VMCI_GUEST_KERNEL_IF_H_ #define _VMCI_GUEST_KERNEL_IF_H_ #if defined(_WIN32) #include <ntddk.h> #endif #ifdef SOLARIS # include <sys/ddi.h> # include <sys/sunddi.h> # include <sys/types.h> #endif #include "vm_basic_types.h" #include "vmci_defs.h" #if defined(linux) typedef unsigned short int VMCIIoPort; typedef int VMCIIoHandle; #elif defined(_WIN32) typedef PUCHAR VMCIIoPort; typedef int VMCIIoHandle; #elif defined(SOLARIS) typedef uint8_t * VMCIIoPort; typedef ddi_acc_handle_t VMCIIoHandle; #elif defined(__APPLE__) typedef unsigned short int VMCIIoPort; typedef void *VMCIIoHandle; #endif // VMKERNEL void VMCI_ReadPortBytes(VMCIIoHandle handle, VMCIIoPort port, uint8 *buffer, size_t bufferLength); #endif // _VMCI_GUEST_KERNEL_IF_H_ vmci-only/vmciDatagram.c 0000444 0000000 0000000 00000074262 11573420371 014250 0 ustar root root /********************************************************* * 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.c -- * * Simple Datagram API for the guest driver. */ #ifdef __linux__ # include "driver-config.h" # define EXPORT_SYMTAB # include <linux/module.h> # include "compat_kernel.h" # include "compat_pci.h" #elif defined(_WIN32) # include <ntddk.h> #elif defined(SOLARIS) # include <sys/ddi.h> # include <sys/sunddi.h> #elif defined(__APPLE__) #else # error "Platform not support by VMCI datagram API." #endif // linux #define LGPFX "VMCIDatagram: " #include "vmci_kernel_if.h" #include "vm_basic_types.h" #include "vm_assert.h" #include "vmci_defs.h" #include "vmci_infrastructure.h" #include "vmciInt.h" #include "vmciUtil.h" #include "vmciDatagram.h" #include "vmciCommonInt.h" #include "vmciKernelAPI.h" typedef struct DatagramHashEntry { struct DatagramHashEntry *next; int refCount; VMCIHandle handle; uint32 flags; Bool runDelayed; VMCIDatagramRecvCB recvCB; void *clientData; VMCIEvent destroyEvent; } DatagramHashEntry; #define HASH_TABLE_SIZE 64 #define VMCI_HASHRESOURCE(handle, size) \ VMCI_HashId(VMCI_HANDLE_TO_RESOURCE_ID(handle), (size)) /* * Hash table containing all the datagram handles for this VM. It is * synchronized using a single lock but we should consider making it more * fine grained, e.g. a per bucket lock or per set of buckets' lock. */ typedef struct DatagramHashTable { VMCILock lock; DatagramHashEntry *entries[HASH_TABLE_SIZE]; } DatagramHashTable; typedef struct VMCIDelayedDatagramInfo { DatagramHashEntry *entry; VMCIDatagram msg; } VMCIDelayedDatagramInfo; static int DatagramReleaseCB(void *clientData); static int DatagramHashAddEntry(DatagramHashEntry *entry, VMCIId contextID); static int DatagramHashRemoveEntry(VMCIHandle handle); static DatagramHashEntry *DatagramHashGetEntry(VMCIHandle handle); static DatagramHashEntry *DatagramHashGetEntryAnyCid(VMCIHandle handle); static void DatagramHashReleaseEntry(DatagramHashEntry *entry); static Bool DatagramHandleUniqueLockedAnyCid(VMCIHandle handle); static int DatagramProcessNotify(void *clientData, VMCIDatagram *msg); DatagramHashTable hashTable; /* *------------------------------------------------------------------------------ * * DatagramReleaseCB -- * * Callback to release the datagram entry reference. It is called by the * VMCI_WaitOnEvent function before it blocks. * * Result: * None. * *------------------------------------------------------------------------------ */ static int DatagramReleaseCB(void *clientData) { DatagramHashEntry *entry = (DatagramHashEntry *)clientData; ASSERT(entry); DatagramHashReleaseEntry(entry); return 0; } /* *------------------------------------------------------------------------- * * DatagramHashAddEntry -- * Given a datagram handle entry, adds it to the hashtable of datagram * entries. Allocates a resource id iff the handle of the given entry * is an invalid one. 0 through VMCI_RESERVED_RESOURCE_ID_MAX are * reserved resource ids. * * Result: * VMCI_SUCCESS if added, error if not. * *------------------------------------------------------------------------- */ static int DatagramHashAddEntry(DatagramHashEntry *entry, // IN: VMCIId contextID) // IN: { int idx; VMCILockFlags flags; static VMCIId datagramRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1; ASSERT(entry); VMCI_GrabLock_BH(&hashTable.lock, &flags); /* Do not allow addition of a new handle if the device is being shutdown. */ if (VMCI_DeviceShutdown()) { VMCI_ReleaseLock_BH(&hashTable.lock, flags); return VMCI_ERROR_DEVICE_NOT_FOUND; } if (!VMCI_HANDLE_INVALID(entry->handle) && !DatagramHandleUniqueLockedAnyCid(entry->handle)) { VMCI_ReleaseLock_BH(&hashTable.lock, flags); return VMCI_ERROR_DUPLICATE_ENTRY; } else if (VMCI_HANDLE_INVALID(entry->handle)) { VMCIId oldRID = datagramRID; VMCIHandle handle; Bool foundRID = FALSE; /* * Generate a unique datagram 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, datagramRID); foundRID = DatagramHandleUniqueLockedAnyCid(handle); datagramRID++; if (UNLIKELY(!datagramRID)) { /* * Skip the reserved rids. */ datagramRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1; } } while (!foundRID && datagramRID != oldRID); if (LIKELY(foundRID)) { entry->handle = handle; } else { /* * We wrapped around --- no rids were free. */ ASSERT(datagramRID == oldRID); VMCI_ReleaseLock_BH(&hashTable.lock, flags); return VMCI_ERROR_NO_HANDLE; } } ASSERT(!VMCI_HANDLE_INVALID(entry->handle)); idx = VMCI_HASHRESOURCE(entry->handle, HASH_TABLE_SIZE); /* New entry is added to top/front of hash bucket. */ entry->refCount++; entry->next = hashTable.entries[idx]; hashTable.entries[idx] = entry; VMCI_ReleaseLock_BH(&hashTable.lock, flags); return VMCI_SUCCESS; } /* *------------------------------------------------------------------------- * * DatagramHashRemoveEntry -- * * Result: * VMCI_SUCCESS if removed, VMCI_ERROR_NO_HANDLE if not found. * *------------------------------------------------------------------------- */ static int DatagramHashRemoveEntry(VMCIHandle handle) { int result = VMCI_ERROR_NOT_FOUND; VMCILockFlags flags; DatagramHashEntry *prev, *cur; int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE); prev = NULL; VMCI_GrabLock_BH(&hashTable.lock, &flags); cur = hashTable.entries[idx]; while (TRUE) { if (cur == NULL) { break; } if (VMCI_HANDLE_EQUAL(cur->handle, handle)) { /* Remove entry and break. */ if (prev) { prev->next = cur->next; } else { hashTable.entries[idx] = cur->next; } cur->refCount--; /* * We know that DestroyHnd still has a reference so refCount must be * at least 1. */ ASSERT(cur->refCount > 0); result = VMCI_SUCCESS; break; } prev = cur; cur = cur->next; } VMCI_ReleaseLock_BH(&hashTable.lock, flags); return result; } /* *------------------------------------------------------------------------- * * DatagramHashGetEntry -- * * Gets the given datagram hashtable entry based on handle lookup. * * Result: * Datagram hash entry if found. NULL otherwise. * *------------------------------------------------------------------------- */ static DatagramHashEntry * DatagramHashGetEntry(VMCIHandle handle) // IN { VMCILockFlags flags; DatagramHashEntry *cur; int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE); VMCI_GrabLock_BH(&hashTable.lock, &flags); for (cur = hashTable.entries[idx]; cur != NULL; cur = cur->next) { if (VMCI_HANDLE_EQUAL(cur->handle, handle)) { cur->refCount++; break; } } VMCI_ReleaseLock_BH(&hashTable.lock, flags); return cur; } /* *------------------------------------------------------------------------- * * DatagramHashGetEntryAnyCid -- * * Gets the given datagram hashtable entry based on handle lookup. * Will match "any" or specific cid. * * Result: * Datagram hash entry if found. NULL otherwise. * *------------------------------------------------------------------------- */ static DatagramHashEntry * DatagramHashGetEntryAnyCid(VMCIHandle handle) // IN { VMCILockFlags flags; DatagramHashEntry *cur; int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE); VMCI_GrabLock_BH(&hashTable.lock, &flags); for (cur = hashTable.entries[idx]; cur != NULL; cur = cur->next) { if (VMCI_HANDLE_TO_RESOURCE_ID(cur->handle) == VMCI_HANDLE_TO_RESOURCE_ID(handle)) { if (VMCI_HANDLE_TO_CONTEXT_ID(cur->handle) == VMCI_INVALID_ID || VMCI_HANDLE_TO_CONTEXT_ID(cur->handle) == VMCI_HANDLE_TO_CONTEXT_ID(handle)) { cur->refCount++; break; } } } VMCI_ReleaseLock_BH(&hashTable.lock, flags); return cur; } /* *------------------------------------------------------------------------- * * DatagramHashReleaseEntry -- * * Drops a reference to the current hash entry. If this is the last * reference then the entry is freed. * * Result: * None. * *------------------------------------------------------------------------- */ static void DatagramHashReleaseEntry(DatagramHashEntry *entry) // IN { VMCILockFlags flags; VMCI_GrabLock_BH(&hashTable.lock, &flags); entry->refCount--; /* Check if this is last reference and signal the destroy event if so. */ if (entry->refCount == 0) { VMCI_SignalEvent(&entry->destroyEvent); } VMCI_ReleaseLock_BH(&hashTable.lock, flags); } /* *------------------------------------------------------------------------------ * * DatagramHandleUniqueLockedAnyCid -- * * Checks whether the resource id (with any context id) is already in the * hash table. * Assumes that the caller has the hash table lock. * * Result: * TRUE if the handle is unique. FALSE otherwise. * *------------------------------------------------------------------------------ */ static Bool DatagramHandleUniqueLockedAnyCid(VMCIHandle handle) // IN { Bool unique = TRUE; DatagramHashEntry *entry; int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE); entry = hashTable.entries[idx]; while (entry) { if (VMCI_HANDLE_TO_RESOURCE_ID(entry->handle) == VMCI_HANDLE_TO_RESOURCE_ID(handle)) { unique = FALSE; break; } entry = entry->next; } return unique; } /* *----------------------------------------------------------------------------- * * VMCIDatagram_CreateHnd -- * * Creates a datagram endpoint and returns a handle to it. * * Results: * Returns handle if success, negative errno value otherwise. * * Side effects: * Datagram endpoint is created both in guest and on host. * *----------------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCIDatagram_CreateHnd) int VMCIDatagram_CreateHnd(VMCIId resourceID, // IN uint32 flags, // IN VMCIDatagramRecvCB recvCB, // IN void *clientData, // IN VMCIHandle *outHandle) // OUT { int result; DatagramHashEntry *entry; VMCIHandle handle; VMCIId contextID; if (!recvCB || !outHandle) { return VMCI_ERROR_INVALID_ARGS; } if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0) { contextID = VMCI_INVALID_ID; } else { contextID = VMCI_GetContextID(); /* Validate contextID. */ if (contextID == VMCI_INVALID_ID) { return VMCI_ERROR_NO_RESOURCES; } } if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) { VMCIDatagramWellKnownMapMsg wkMsg; if (resourceID == VMCI_INVALID_ID) { return VMCI_ERROR_INVALID_ARGS; } wkMsg.hdr.dst.context = VMCI_HYPERVISOR_CONTEXT_ID; wkMsg.hdr.dst.resource = VMCI_DATAGRAM_REQUEST_MAP; wkMsg.hdr.src = VMCI_ANON_SRC_HANDLE; wkMsg.hdr.payloadSize = sizeof wkMsg - VMCI_DG_HEADERSIZE; wkMsg.wellKnownID = resourceID; result = VMCI_SendDatagram((VMCIDatagram *)&wkMsg); if (result < VMCI_SUCCESS) { VMCI_DEBUG_LOG(4, (LGPFX"Failed to reserve wellknown id %d, " "error %d.\n", resourceID, result)); return result; } handle = VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, resourceID); } else { if (resourceID == VMCI_INVALID_ID) { handle = VMCI_INVALID_HANDLE; } else { handle = VMCI_MAKE_HANDLE(contextID, resourceID); } } /* Update local datastructure. */ entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED); if (entry == NULL) { 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->handle = handle; entry->flags = flags; entry->recvCB = recvCB; entry->clientData = clientData; entry->refCount = 0; VMCI_CreateEvent(&entry->destroyEvent); result = DatagramHashAddEntry(entry, contextID); if (result != VMCI_SUCCESS) { VMCI_DEBUG_LOG(4, (LGPFX"Failed to add new entry, err 0x%x.\n", result)); VMCI_DestroyEvent(&entry->destroyEvent); VMCI_FreeKernelMem(entry, sizeof *entry); return result; } ASSERT(!VMCI_HANDLE_INVALID(entry->handle)); *outHandle = entry->handle; return VMCI_SUCCESS; } /* *----------------------------------------------------------------------------- * * VMCIDatagram_CreateHndPriv -- * * API provided for compatibility with the host vmci API. This function * doesn't ever succeed since you can't ask for elevated privileges from * the guest. Use VMCIDatagram_CreateHnd instead. * * Results: * Returns a negative error. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCIDatagram_CreateHndPriv) int VMCIDatagram_CreateHndPriv(VMCIId resourceID, // IN: uint32 flags, // IN: VMCIPrivilegeFlags privFlags, // IN: VMCIDatagramRecvCB recvCB, // IN: void *clientData, // IN: VMCIHandle *outHandle) // OUT: { return VMCI_ERROR_NO_ACCESS; } /* *----------------------------------------------------------------------------- * * VMCIDatagram_DestroyHnd -- * * Destroys a handle. * * Results: * VMCI_SUCCESS or error code. * * Side effects: * Host and guest state is cleaned up. * *----------------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCIDatagram_DestroyHnd) int VMCIDatagram_DestroyHnd(VMCIHandle handle) // IN { DatagramHashEntry *entry = DatagramHashGetEntry(handle); if (entry == NULL) { return VMCI_ERROR_NOT_FOUND; } DatagramHashRemoveEntry(entry->handle); /* * We wait for destroyEvent to be signalled. The resource is released * as part of the wait. */ VMCI_WaitOnEvent(&entry->destroyEvent, DatagramReleaseCB, entry); if ((entry->flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) { int result; VMCIDatagramWellKnownMapMsg wkMsg; wkMsg.hdr.dst.context = VMCI_HYPERVISOR_CONTEXT_ID; wkMsg.hdr.dst.resource = VMCI_DATAGRAM_REMOVE_MAP; wkMsg.hdr.src = VMCI_ANON_SRC_HANDLE; wkMsg.hdr.payloadSize = sizeof wkMsg - VMCI_DG_HEADERSIZE; wkMsg.wellKnownID = entry->handle.resource; result = VMCI_SendDatagram((VMCIDatagram *)&wkMsg); if (result < VMCI_SUCCESS) { VMCI_WARNING((LGPFX"Failed to remove well-known mapping for " "resource %d.\n", entry->handle.resource)); } } /* We know we are now holding the last reference so we can free the entry. */ VMCI_DestroyEvent(&entry->destroyEvent); VMCI_FreeKernelMem(entry, sizeof *entry); return VMCI_SUCCESS; } /* *----------------------------------------------------------------------------- * * VMCIDatagram_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(VMCIDatagram_Send) int VMCIDatagram_Send(VMCIDatagram *msg) // IN { uint32 retval; DatagramHashEntry *entry; VMCIId contextId; if (msg == NULL) { VMCI_DEBUG_LOG(4, (LGPFX"Invalid datagram.\n")); return VMCI_ERROR_INVALID_ARGS; } if (VMCI_DG_SIZE(msg) > VMCI_MAX_DG_SIZE) { VMCI_DEBUG_LOG(4, (LGPFX"Payload size %"FMT64"u too big to send.\n", msg->payloadSize)); return VMCI_ERROR_INVALID_ARGS; } /* Check srcHandle exists otherwise fail. */ entry = DatagramHashGetEntry(msg->src); if (entry == NULL) { VMCI_DEBUG_LOG(4, (LGPFX"Couldn't find handle 0x%x:0x%x.\n", msg->src.context, msg->src.resource)); return VMCI_ERROR_INVALID_ARGS; } contextId = VMCI_HANDLE_TO_CONTEXT_ID(msg->src); if (contextId == VMCI_INVALID_ID) { msg->src = VMCI_MAKE_HANDLE(VMCI_GetContextID(), VMCI_HANDLE_TO_RESOURCE_ID(msg->src)); } retval = VMCI_SendDatagram(msg); DatagramHashReleaseEntry(entry); return retval; } /* *----------------------------------------------------------------------------- * * VMCIDatagramDelayedDispatchCB -- * * Calls the specified callback in a delayed context. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void VMCIDatagramDelayedDispatchCB(void *data) // IN { VMCIDelayedDatagramInfo *dgInfo = (VMCIDelayedDatagramInfo *)data; ASSERT(data); dgInfo->entry->recvCB(dgInfo->entry->clientData, &dgInfo->msg); DatagramHashReleaseEntry(dgInfo->entry); VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dgInfo->msg.payloadSize); } /* *----------------------------------------------------------------------------- * * VMCIDatagram_Dispatch -- * * Forwards the datagram to the corresponding entry's callback. This will * defer the datagram if requested by the client, so that the callback * is invoked in a delayed context. * * Results: * VMCI_SUCCESS on success, error code if not. * * Side effects: * None. * *----------------------------------------------------------------------------- */ int VMCIDatagram_Dispatch(VMCIId contextID, // IN: unused VMCIDatagram *msg) // IN { int32 err = VMCI_SUCCESS; DatagramHashEntry *entry; ASSERT(msg); entry = DatagramHashGetEntryAnyCid(msg->dst); if (entry == NULL) { VMCI_DEBUG_LOG(4, (LGPFX"destination handle 0x%x:0x%x doesn't exist.\n", msg->dst.context, msg->dst.resource)); return VMCI_ERROR_NO_HANDLE; } if (!entry->recvCB) { VMCI_WARNING((LGPFX"no handle callback for handle 0x%x:0x%x payload of " "size %"FMT64"d.\n", msg->dst.context, msg->dst.resource, msg->payloadSize)); goto out; } if (entry->runDelayed) { VMCIDelayedDatagramInfo *dgInfo; dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)msg->payloadSize, VMCI_MEMORY_ATOMIC | VMCI_MEMORY_NONPAGED); if (NULL == dgInfo) { err = VMCI_ERROR_NO_MEM; goto out; } dgInfo->entry = entry; memcpy(&dgInfo->msg, msg, VMCI_DG_SIZE(msg)); err = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo); if (VMCI_SUCCESS == err) { return err; } VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)msg->payloadSize); } else { entry->recvCB(entry->clientData, msg); } out: DatagramHashReleaseEntry(entry); return err; } /* *----------------------------------------------------------------------------- * * VMCIDatagram_Init -- * * Register guest call handlers. * * Results: * None * * Side effects: * None. * *----------------------------------------------------------------------------- */ void VMCIDatagram_Init(void) { int i; VMCI_InitLock(&hashTable.lock, "VMCIDatagramHashtable", VMCI_LOCK_RANK_MIDDLE_BH); for (i = 0; i < HASH_TABLE_SIZE; i++) { hashTable.entries[i] = NULL; } } /* *----------------------------------------------------------------------------- * * 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; } /* *----------------------------------------------------------------------------- * * 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) { VMCILockFlags flags; VMCI_GrabLock_BH(&hashTable.lock, &flags); VMCI_ReleaseLock_BH(&hashTable.lock, flags); } /* *----------------------------------------------------------------------------- * * DatagramProcessNotify -- * * Callback to send a notificaton to a vmci process. Creates datagram * copy and signals the process. * * Results: * VMCI_SUCCESS on success, appropriate error code otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int DatagramProcessNotify(void *clientData, // IN: VMCIDatagram *msg) // IN: { VMCIDatagramProcess *dgmProc = (VMCIDatagramProcess *) clientData; size_t dgmSize; VMCIDatagram *dgm; DatagramQueueEntry *dqEntry; VMCILockFlags flags; ASSERT(dgmProc != NULL && msg != NULL); dgmSize = VMCI_DG_SIZE(msg); ASSERT(dgmSize <= VMCI_MAX_DG_SIZE); dgm = VMCI_AllocKernelMem(dgmSize, VMCI_MEMORY_NONPAGED | VMCI_MEMORY_ATOMIC); if (!dgm) { VMCI_WARNING((LGPFX"Failed to allocate datagram of size %d bytes.\n", (uint32)dgmSize)); return VMCI_ERROR_NO_MEM; } memcpy(dgm, msg, dgmSize); /* Allocate datagram queue entry and add it to the target fd's queue. */ dqEntry = VMCI_AllocKernelMem(sizeof *dqEntry, VMCI_MEMORY_NONPAGED | VMCI_MEMORY_ATOMIC); if (dqEntry == NULL) { VMCI_FreeKernelMem(dgm, dgmSize); VMCI_WARNING((LGPFX"Failed to allocate memory for process datagram.\n")); return VMCI_ERROR_NO_MEM; } dqEntry->dg = dgm; VMCI_GrabLock_BH(&dgmProc->datagramQueueLock, &flags); if (dgmProc->datagramQueueSize + dgmSize >= VMCI_MAX_DATAGRAM_QUEUE_SIZE) { VMCI_ReleaseLock_BH(&dgmProc->datagramQueueLock, flags); VMCI_FreeKernelMem(dgm, dgmSize); VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry); VMCI_LOG((LGPFX"Datagram process receive queue is full.\n")); return VMCI_ERROR_NO_RESOURCES; } LIST_QUEUE(&dqEntry->listItem, &dgmProc->datagramQueue); dgmProc->pendingDatagrams++; dgmProc->datagramQueueSize += dgmSize; #ifdef SOLARIS /* * Release the lock here for Solaris. Otherwise, a deadlock * may occur since pollwakeup(9F) (invoked from VMCIHost_SignalCall) * and poll_common (invoked from poll(2)) try to grab a common lock. * The man pages of pollwakeup(9F) and chpoll(9E) talk about this. */ VMCI_ReleaseLock_BH(&dgmProc->datagramQueueLock, flags); #endif VMCIHost_SignalCall(&dgmProc->host); #ifndef SOLARIS /* For platforms other than Solaris, release the lock here. */ VMCI_ReleaseLock_BH(&dgmProc->datagramQueueLock, flags); #endif VMCI_DEBUG_LOG(10, (LGPFX"Sent datagram with resource id %d and size %u.\n", msg->dst.resource, (uint32)dgmSize)); /* dqEntry and dgm are freed when user reads call.. */ return VMCI_SUCCESS; } /* *---------------------------------------------------------------------- * * VMCIDatagramProcess_Create -- * * Creates a new VMCIDatagramProcess object. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int VMCIDatagramProcess_Create(VMCIDatagramProcess **outDgmProc, // OUT: VMCIDatagramCreateProcessInfo *createInfo, // IN: uintptr_t eventHnd) // IN: { VMCIDatagramProcess *dgmProc; ASSERT(createInfo); ASSERT(outDgmProc); dgmProc = VMCI_AllocKernelMem(sizeof *dgmProc, VMCI_MEMORY_NONPAGED); if (dgmProc == NULL) { return VMCI_ERROR_NO_MEM; } VMCI_InitLock(&dgmProc->datagramQueueLock, "VMCIDgmProc", VMCI_LOCK_RANK_MIDDLE_BH); VMCIHost_InitContext(&dgmProc->host, eventHnd); dgmProc->pendingDatagrams = 0; dgmProc->datagramQueueSize = 0; dgmProc->datagramQueue = NULL; /* * We pass the result and corresponding handle to user level via the * createInfo. */ createInfo->result = VMCIDatagram_CreateHnd(createInfo->resourceID, createInfo->flags, DatagramProcessNotify, (void *)dgmProc, &dgmProc->handle); if (createInfo->result < VMCI_SUCCESS) { VMCI_FreeKernelMem(dgmProc, sizeof *dgmProc); return createInfo->result; } createInfo->handle = dgmProc->handle; *outDgmProc = dgmProc; return VMCI_SUCCESS; } /* *---------------------------------------------------------------------- * * VMCIDatagramProcess_Destroy -- * * Destroys a VMCIDatagramProcess object. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void VMCIDatagramProcess_Destroy(VMCIDatagramProcess *dgmProc) // IN: { ListItem *curr, *next; DatagramQueueEntry *dqEntry; VMCILockFlags flags; if (!dgmProc) { return; } if (!VMCI_HANDLE_EQUAL(dgmProc->handle, VMCI_INVALID_HANDLE)) { /* * We block in destroy so we know that there can be no more * callbacks to DatagramProcessNotifyCB when we return from * this call. */ VMCIDatagram_DestroyHnd(dgmProc->handle); dgmProc->handle = VMCI_INVALID_HANDLE; } /* Flush dgmProc's call queue. */ VMCI_GrabLock_BH(&dgmProc->datagramQueueLock, &flags); LIST_SCAN_SAFE(curr, next, dgmProc->datagramQueue) { dqEntry = LIST_CONTAINER(curr, DatagramQueueEntry, listItem); LIST_DEL(curr, &dgmProc->datagramQueue); ASSERT(dqEntry && dqEntry->dg); VMCI_FreeKernelMem(dqEntry->dg, VMCI_DG_SIZE(dqEntry->dg)); VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry); } VMCI_ReleaseLock_BH(&dgmProc->datagramQueueLock, flags); VMCIHost_ReleaseContext(&dgmProc->host); VMCI_CleanupLock(&dgmProc->datagramQueueLock); VMCI_FreeKernelMem(dgmProc, sizeof *dgmProc); } /* *---------------------------------------------------------------------- * * VMCIDatagramProcess_ReadCall -- * * Dequeues the next guest call and returns it to user level. * * Results: * 0 on success, appropriate error code otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int VMCIDatagramProcess_ReadCall(VMCIDatagramProcess *dgmProc, // IN: size_t maxSize, // IN: max size of dg VMCIDatagram **dg) // OUT: { DatagramQueueEntry *dqEntry; ListItem *listItem; VMCILockFlags flags; ASSERT(dgmProc); ASSERT(dg); /* Dequeue the next dgmProc datagram queue entry. */ VMCI_GrabLock_BH(&dgmProc->datagramQueueLock, &flags); /* * Currently, we do not support blocking read of datagrams on Mac and * Solaris. XXX: This will go away soon. */ #if defined(SOLARIS) || defined(__APPLE__) if (dgmProc->pendingDatagrams == 0) { VMCIHost_ClearCall(&dgmProc->host); VMCI_ReleaseLock_BH(&dgmProc->datagramQueueLock, flags); VMCI_DEBUG_LOG(4, (LGPFX"No datagrams pending.\n")); return VMCI_ERROR_NO_MORE_DATAGRAMS; } #else while (dgmProc->pendingDatagrams == 0) { VMCIHost_ClearCall(&dgmProc->host); if (!VMCIHost_WaitForCallLocked(&dgmProc->host, &dgmProc->datagramQueueLock, &flags, TRUE)) { VMCI_ReleaseLock_BH(&dgmProc->datagramQueueLock, flags); VMCI_DEBUG_LOG(4, (LGPFX"Blocking read of datagram interrupted.\n")); return VMCI_ERROR_NO_MORE_DATAGRAMS; } } #endif listItem = LIST_FIRST(dgmProc->datagramQueue); ASSERT (listItem != NULL); dqEntry = LIST_CONTAINER(listItem, DatagramQueueEntry, listItem); ASSERT(dqEntry->dg); /* Check the size of the userland buffer. */ if (maxSize < VMCI_DG_SIZE(dqEntry->dg)) { VMCI_ReleaseLock_BH(&dgmProc->datagramQueueLock, flags); VMCI_DEBUG_LOG(4, (LGPFX"Caller's buffer is too small.\n")); return VMCI_ERROR_NO_MEM; } LIST_DEL(listItem, &dgmProc->datagramQueue); dgmProc->pendingDatagrams--; dgmProc->datagramQueueSize -= VMCI_DG_SIZE(dqEntry->dg); if (dgmProc->pendingDatagrams == 0) { VMCIHost_ClearCall(&dgmProc->host); } VMCI_ReleaseLock_BH(&dgmProc->datagramQueueLock, flags); *dg = dqEntry->dg; VMCI_FreeKernelMem(dqEntry, sizeof *dqEntry); return VMCI_SUCCESS; } vmci-only/vmciNotifications.h 0000444 0000000 0000000 00000003106 11573420371 015333 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciNotifications.h -- * * VMCI notifications API for OS device drivers. */ #ifndef _VMCI_NOTIFICATIONS_H_ #define _VMCI_NOTIFICATIONS_H_ #include "vm_basic_types.h" #include "vmci_defs.h" #include "vmciKernelAPI.h" void VMCINotifications_Init(void); void VMCINotifications_Exit(void); void VMCINotifications_Sync(void); Bool VMCI_RegisterNotificationBitmap(PPN bitmapPPN); void VMCI_ScanNotificationBitmap(uint8 *bitmap); int VMCINotificationRegister(VMCIHandle *handle, Bool doorbell, uint32 flags, VMCICallback notifyCB, void *callbackData); int VMCINotificationUnregister(VMCIHandle handle, Bool doorbell); void VMCINotifications_Hibernate(Bool enterHibernation); #endif /* !_VMCI_NOTIFICATIONS_H_ */ vmci-only/vmciEvent.h 0000444 0000000 0000000 00000002562 11573420371 013610 0 ustar root root /********************************************************* * 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" void VMCIEvent_Init(void); void VMCIEvent_Exit(void); void VMCIEvent_Sync(void); int VMCIEvent_Dispatch(VMCIDatagram *msg); #ifdef VMX86_TOOLS Bool VMCIEvent_CheckHostCapabilities(void); #endif #endif //__VMCI_EVENT_H__ vmci-only/vmciQueuePairInt.h 0000444 0000000 0000000 00000003361 11573420371 015100 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciQueuePairInt.h -- * * Helper function declarations for VMCI QueuePair API. */ #ifndef _VMCI_QUEUE_PAIR_INT_H_ #define _VMCI_QUEUE_PAIR_INT_H_ #include "vmci_defs.h" #include "vmciQueue.h" void VMCIQueuePair_Init(void); void VMCIQueuePair_Exit(void); void VMCIQueuePair_Sync(void); int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ, uint64 produceSize, VMCIQueue **consumeQ, uint64 consumeSize, VMCIId peer, uint32 flags); int VMCIQueuePair_AllocPriv(VMCIHandle *handle, VMCIQueue **produceQ, uint64 produceSize, VMCIQueue **consumeQ, uint64 consumeSize, VMCIId peer, uint32 flags, VMCIPrivilegeFlags privFlags); int VMCIQueuePair_Detach(VMCIHandle handle); void VMCIQueuePair_Convert(Bool toLocal, Bool deviceReset); #endif /* !_VMCI_QUEUE_PAIR_INT_H_ */ vmci-only/Makefile.kernel 0000444 0000000 0000000 00000004051 11573420371 014411 0 ustar root root #!/usr/bin/make -f ########################################################## # Copyright (C) 2005 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 vmci Makefile to be distributed externally #### INCLUDE += -I. EXTRA_CFLAGS := $(CC_OPTS) $(INCLUDE) EXTRA_CFLAGS += -DVMX86_TOOLS obj-m += $(DRIVER).o $(DRIVER)-y := $(subst $(SRCROOT)/, , $(patsubst %.c, %.o, $(wildcard $(SRCROOT)/*.c))) # # Compile the common sources from the shared directory. # STUBS := kernelStubsLinux.o $(DRIVER)-y += $(STUBS) VMCI_PATH := $(shell cd $(SRCROOT) && pwd) ifdef OVT_SOURCE_DIR STUBS_PATH := $(OVT_SOURCE_DIR)/modules/linux/shared else STUBS_PATH := $(VMCI_PATH)/shared endif $(addprefix $(VMCI_PATH)/,$(STUBS)): $(VMCI_PATH)/%.o: $(STUBS_PATH)/%.c $(Q)$(rule_cc_o_c) clean: rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \ Modules.symvers Module.markers modules.order \ $(foreach dir,./,$(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 vmci-only/vmciQueuePair.c 0000444 0000000 0000000 00000113672 11573420371 014427 0 ustar root root /********************************************************* * 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.c -- * * Implements the VMCI QueuePair API. */ #ifdef __linux__ # include "driver-config.h" # include <asm/page.h> # include <linux/module.h> #elif defined(_WIN32) # include <wdm.h> #elif defined(__APPLE__) # include <IOKit/IOLib.h> #endif /* __linux__ */ #include "vm_assert.h" #include "vm_atomic.h" #include "vmci_handle_array.h" #include "vmci_kernel_if.h" #include "vmciEvent.h" #include "vmciInt.h" #include "vmciKernelAPI.h" #include "vmciQueuePairInt.h" #include "vmciUtil.h" #include "circList.h" #define LGPFX "VMCIQueuePair: " typedef struct QueuePairEntry { VMCIHandle handle; VMCIId peer; uint32 flags; uint64 produceSize; uint64 consumeSize; uint64 numPPNs; PPNSet ppnSet; void *produceQ; void *consumeQ; uint32 refCount; Bool hibernateFailure; ListItem listItem; } QueuePairEntry; typedef struct QueuePairList { ListItem *head; Atomic_uint32 hibernate; VMCIMutex mutex; } QueuePairList; static QueuePairList queuePairList; static VMCIHandleArray *hibernateFailedList; static VMCILock hibernateFailedListLock; static QueuePairEntry *QueuePairList_FindEntry(VMCIHandle handle); static void QueuePairList_AddEntry(QueuePairEntry *entry); static void QueuePairList_RemoveEntry(QueuePairEntry *entry); static QueuePairEntry *QueuePairList_GetHead(void); static QueuePairEntry *QueuePairEntryCreate(VMCIHandle handle, VMCIId peer, uint32 flags, uint64 produceSize, uint64 consumeSize, void *produceQ, void *consumeQ); static void QueuePairEntryDestroy(QueuePairEntry *entry); static int VMCIQueuePairAlloc_HyperCall(const QueuePairEntry *entry); static int VMCIQueuePairAllocHelper(VMCIHandle *handle, VMCIQueue **produceQ, uint64 produceSize, VMCIQueue **consumeQ, uint64 consumeSize, VMCIId peer, uint32 flags); static int VMCIQueuePairDetachHelper(VMCIHandle handle); static int VMCIQueuePairDetachHyperCall(VMCIHandle handle); static int QueuePairNotifyPeerLocal(Bool attach, VMCIHandle handle); static void VMCIQPMarkHibernateFailed(QueuePairEntry *entry); static void VMCIQPUnmarkHibernateFailed(QueuePairEntry *entry); /* *----------------------------------------------------------------------------- * * QueuePairLock_Init -- * * Creates the lock protecting the QueuePair list. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void QueuePairLock_Init(void) { VMCIMutex_Init(&queuePairList.mutex); } /* *----------------------------------------------------------------------------- * * QueuePairLock_Destroy -- * * Destroys the lock protecting the QueuePair list. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void QueuePairLock_Destroy(void) { VMCIMutex_Destroy(&queuePairList.mutex); /* No-op on Linux and Windows. */ } /* *----------------------------------------------------------------------------- * * QueuePairList_Lock -- * * Acquires the lock protecting the QueuePair list. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void QueuePairList_Lock(void) { VMCIMutex_Acquire(&queuePairList.mutex); } /* *----------------------------------------------------------------------------- * * QueuePairList_Unlock -- * * Releases the lock protecting the QueuePair list. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static INLINE void QueuePairList_Unlock(void) { VMCIMutex_Release(&queuePairList.mutex); } /* *----------------------------------------------------------------------------- * * VMCIQueuePair_Init -- * * Initalizes QueuePair data structure state. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void VMCIQueuePair_Init(void) { queuePairList.head = NULL; Atomic_Write(&queuePairList.hibernate, 0); QueuePairLock_Init(); hibernateFailedList = VMCIHandleArray_Create(0); /* * The lock rank must be lower than subscriberLock in vmciEvent, * since we hold the hibernateFailedListLock while generating * detach events. */ VMCI_InitLock(&hibernateFailedListLock, "VMCIQPHibernateFailed", VMCI_LOCK_RANK_MIDDLE_BH); } /* *----------------------------------------------------------------------------- * * VMCIQueuePair_Exit -- * * Destroys all QueuePairs. Makes hypercalls to detach from QueuePairs. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void VMCIQueuePair_Exit(void) { QueuePairEntry *entry; QueuePairList_Lock(); while ((entry = QueuePairList_GetHead())) { /* * Don't make a hypercall for local QueuePairs. */ if (!(entry->flags & VMCI_QPFLAG_LOCAL)) { 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 entry->handle; detachMsg.handle = entry->handle; (void)VMCI_SendDatagram((VMCIDatagram *)&detachMsg); } /* * We cannot fail the exit, so let's reset refCount. */ entry->refCount = 0; QueuePairList_RemoveEntry(entry); QueuePairEntryDestroy(entry); } Atomic_Write(&queuePairList.hibernate, 0); QueuePairList_Unlock(); QueuePairLock_Destroy(); VMCI_CleanupLock(&hibernateFailedListLock); VMCIHandleArray_Destroy(hibernateFailedList); } /* *----------------------------------------------------------------------------- * * VMCIQueuePair_Sync -- * * Use this as a synchronization point when setting globals, for example, * during device shutdown. * * Results: * TRUE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void VMCIQueuePair_Sync(void) { QueuePairList_Lock(); QueuePairList_Unlock(); } /* *----------------------------------------------------------------------------- * * QueuePairList_FindEntry -- * * Searches the list of QueuePairs to find if an entry already exists. * Assumes that the lock on the list is held. * * Results: * Pointer to the entry if it exists, NULL otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static QueuePairEntry * QueuePairList_FindEntry(VMCIHandle handle) // IN: { ListItem *next; if (VMCI_HANDLE_INVALID(handle)) { return NULL; } LIST_SCAN(next, queuePairList.head) { QueuePairEntry *entry = LIST_CONTAINER(next, QueuePairEntry, listItem); if (VMCI_HANDLE_EQUAL(entry->handle, handle)) { return entry; } } return NULL; } /* *----------------------------------------------------------------------------- * * QueuePairList_AddEntry -- * * Appends a QueuePair entry to the list. Assumes that the lock on the * list is held. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void QueuePairList_AddEntry(QueuePairEntry *entry) // IN: { if (entry) { LIST_QUEUE(&entry->listItem, &queuePairList.head); } } /* *----------------------------------------------------------------------------- * * QueuePairList_RemoveEntry -- * * Removes a QueuePair entry from the list. Assumes that the lock on the * list is held. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void QueuePairList_RemoveEntry(QueuePairEntry *entry) // IN: { if (entry) { LIST_DEL(&entry->listItem, &queuePairList.head); } } /* *----------------------------------------------------------------------------- * * 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(void) { ListItem *first = LIST_FIRST(queuePairList.head); if (first) { QueuePairEntry *entry = LIST_CONTAINER(first, QueuePairEntry, listItem); return entry; } return NULL; } /* *----------------------------------------------------------------------------- * * VMCIQueuePair_Alloc -- * * Allocates a VMCI QueuePair. Only checks validity of input arguments. * Real work is done in the OS-specific helper routine. * * Results: * Success or failure. * * Side effects: * Memory is allocated. * *----------------------------------------------------------------------------- */ 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: { ASSERT_ON_COMPILE(sizeof(VMCIQueueHeader) <= PAGE_SIZE); return VMCIQueuePair_AllocPriv(handle, produceQ, produceSize, consumeQ, consumeSize, peer, flags, VMCI_NO_PRIVILEGE_FLAGS); } /* *----------------------------------------------------------------------------- * * VMCIQueuePair_AllocPriv -- * * Provided for compatibility with the host API. Always returns an error * since requesting privileges from the guest is not allowed. Use * VMCIQueuePair_Alloc instead. * * Results: * An error. * * Side effects: * None. * *----------------------------------------------------------------------------- */ int VMCIQueuePair_AllocPriv(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: { if (privFlags != VMCI_NO_PRIVILEGE_FLAGS) { return VMCI_ERROR_NO_ACCESS; } if (!handle || !produceQ || !consumeQ || (!produceSize && !consumeSize) || (flags & ~VMCI_QP_ALL_FLAGS)) { return VMCI_ERROR_INVALID_ARGS; } return VMCIQueuePairAllocHelper(handle, produceQ, produceSize, consumeQ, consumeSize, peer, flags); } /* *----------------------------------------------------------------------------- * * VMCIQueuePair_Detach -- * * Detaches from a VMCI QueuePair. Only checks validity of input argument. * Real work is done in the OS-specific helper routine. * * Results: * Success or failure. * * Side effects: * Memory is freed. * *----------------------------------------------------------------------------- */ int VMCIQueuePair_Detach(VMCIHandle handle) // IN: { if (VMCI_HANDLE_INVALID(handle)) { return VMCI_ERROR_INVALID_ARGS; } return VMCIQueuePairDetachHelper(handle); } /* *----------------------------------------------------------------------------- * * QueuePairEntryCreate -- * * Allocates and initializes a QueuePairEntry 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 lock is held by the caller. * * Results: * Pointer to structure intialized. * * Side effects: * None. * *----------------------------------------------------------------------------- */ QueuePairEntry * QueuePairEntryCreate(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; QueuePairEntry *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_GetContextID(); 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 = QueuePairList_FindEntry(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(handle) == NULL); entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NORMAL); if (entry) { entry->handle = handle; entry->peer = peer; entry->flags = flags; entry->produceSize = produceSize; entry->consumeSize = consumeSize; entry->numPPNs = numPPNs; memset(&entry->ppnSet, 0, sizeof entry->ppnSet); entry->produceQ = produceQ; entry->consumeQ = consumeQ; entry->refCount = 0; INIT_LIST_ITEM(&entry->listItem); } return entry; } /* *----------------------------------------------------------------------------- * * QueuePairEntryDestroy -- * * Frees a QueuePairEntry structure. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void QueuePairEntryDestroy(QueuePairEntry *entry) // IN: { ASSERT(entry); ASSERT(entry->refCount == 0); VMCI_FreePPNSet(&entry->ppnSet); VMCI_FreeQueue(entry->produceQ, entry->produceSize); VMCI_FreeQueue(entry->consumeQ, entry->consumeSize); VMCI_FreeKernelMem(entry, sizeof *entry); } /* *----------------------------------------------------------------------------- * * VMCIQueuePairAlloc_HyperCall -- * * Helper to make a QueuePairAlloc hypercall. * * Results: * Result of the hypercall. * * Side effects: * Memory is allocated & freed. * *----------------------------------------------------------------------------- */ int VMCIQueuePairAlloc_HyperCall(const QueuePairEntry *entry) // IN: { VMCIQueuePairAllocMsg *allocMsg; size_t msgSize; int result; if (!entry || entry->numPPNs <= 2) { return VMCI_ERROR_INVALID_ARGS; } ASSERT(!(entry->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->handle; allocMsg->peer = entry->peer; allocMsg->flags = entry->flags; allocMsg->produceSize = entry->produceSize; allocMsg->consumeSize = entry->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; } /* *----------------------------------------------------------------------------- * * VMCIQueuePairAllocHelper -- * * Helper for VMCI QueuePairAlloc. Allocates physical pages for the * QueuePair. Makes OS dependent calls through generic wrappers. * * Results: * Success or failure. * * Side effects: * Memory is allocated. * *----------------------------------------------------------------------------- */ static int VMCIQueuePairAllocHelper(VMCIHandle *handle, // IN/OUT: VMCIQueue **produceQ, // OUT: uint64 produceSize, // IN: VMCIQueue **consumeQ, // OUT: uint64 consumeSize, // IN: VMCIId peer, // IN: uint32 flags) // 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; QueuePairEntry *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)); QueuePairList_Lock(); /* Do not allow alloc/attach if the device is being shutdown. */ if (VMCI_DeviceShutdown()) { result = VMCI_ERROR_DEVICE_NOT_FOUND; goto error; } if ((Atomic_Read(&queuePairList.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 = QueuePairList_FindEntry(*handle))) { if (queuePairEntry->flags & VMCI_QPFLAG_LOCAL) { /* Local attach case. */ if (queuePairEntry->refCount > 1) { VMCI_DEBUG_LOG(4, (LGPFX"Error attempting to attach more than " "once.\n")); result = VMCI_ERROR_UNAVAILABLE; goto errorKeepEntry; } if (queuePairEntry->produceSize != consumeSize || queuePairEntry->consumeSize != produceSize || queuePairEntry->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); if (!myProduceQ) { VMCI_WARNING((LGPFX"Error allocating pages for produce queue.\n")); result = VMCI_ERROR_NO_MEM; goto error; } myConsumeQ = VMCI_AllocQueue(consumeSize); if (!myConsumeQ) { VMCI_WARNING((LGPFX"Error allocating pages for consume queue.\n")); result = VMCI_ERROR_NO_MEM; goto error; } queuePairEntry = QueuePairEntryCreate(*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->flags & VMCI_QPFLAG_LOCAL) { /* Local create case. */ VMCIId contextId = VMCI_GetContextID(); /* * 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->handle.context != contextId || (queuePairEntry->peer != VMCI_INVALID_ID && queuePairEntry->peer != contextId)) { result = VMCI_ERROR_NO_ACCESS; goto error; } if (queuePairEntry->flags & VMCI_QPFLAG_ATTACH_ONLY) { result = VMCI_ERROR_NOT_FOUND; goto error; } } else { result = VMCIQueuePairAlloc_HyperCall(queuePairEntry); if (result < VMCI_SUCCESS) { VMCI_WARNING((LGPFX"VMCIQueuePairAlloc_HyperCall result = %d.\n", result)); goto error; } } VMCI_InitQueueMutex((VMCIQueue *)myProduceQ, (VMCIQueue *)myConsumeQ); QueuePairList_AddEntry(queuePairEntry); out: queuePairEntry->refCount++; *handle = queuePairEntry->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->flags & VMCI_QPFLAG_LOCAL) && queuePairEntry->refCount == 1) { VMCIQueueHeader_Init((*produceQ)->qHeader, *handle); VMCIQueueHeader_Init((*consumeQ)->qHeader, *handle); } QueuePairList_Unlock(); return VMCI_SUCCESS; error: QueuePairList_Unlock(); if (queuePairEntry) { /* The queues will be freed inside the destroy routine. */ QueuePairEntryDestroy(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->refCount > 0); QueuePairList_Unlock(); return result; } /* *----------------------------------------------------------------------------- * * VMCIQueuePairDetachHyperCall -- * * Helper to make a QueuePairDetach hypercall. * * 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); } /* *----------------------------------------------------------------------------- * * VMCIQueuePairDetachHelper -- * * Helper for VMCI QueuePair detach interface on Linux. Frees the physical * pages for the QueuePair. * * Results: * Success or failure. * * Side effects: * Memory may be freed. * *----------------------------------------------------------------------------- */ static int VMCIQueuePairDetachHelper(VMCIHandle handle) // IN: { int result; QueuePairEntry *entry; uint32 refCount; ASSERT(!VMCI_HANDLE_INVALID(handle)); QueuePairList_Lock(); entry = QueuePairList_FindEntry(handle); if (!entry) { QueuePairList_Unlock(); return VMCI_ERROR_NOT_FOUND; } ASSERT(entry->refCount >= 1); if (entry->flags & VMCI_QPFLAG_LOCAL) { result = VMCI_SUCCESS; if (entry->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->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?). */ QueuePairList_Unlock(); 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->refCount--; if (entry->refCount == 0) { QueuePairList_RemoveEntry(entry); } /* If we didn't remove the entry, this could change once we unlock. */ refCount = entry ? entry->refCount : 0xffffffff; /* * Value does not matter, silence the * compiler. */ QueuePairList_Unlock(); if (refCount == 0) { QueuePairEntryDestroy(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; contextId = VMCI_GetContextID(); 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 lock held. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void VMCIQPMarkHibernateFailed(QueuePairEntry *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->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(QueuePairEntry *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->handle; entry->hibernateFailure = FALSE; VMCI_GrabLock_BH(&hibernateFailedListLock, &flags); VMCIHandleArray_RemoveEntry(hibernateFailedList, handle); VMCI_ReleaseLock_BH(&hibernateFailedListLock, flags); } /* *---------------------------------------------------------------------------- * * VMCIQueuePair_Convert -- * * Queue pairs 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 VMCIQueuePair_Convert(Bool toLocal, // IN Bool deviceReset) // IN { if (toLocal) { ListItem *next; QueuePairList_Lock(); LIST_SCAN(next, queuePairList.head) { QueuePairEntry *entry = LIST_CONTAINER(next, QueuePairEntry, listItem); if (!(entry->flags & VMCI_QPFLAG_LOCAL)) { VMCIQueue *prodQ; VMCIQueue *consQ; void *oldProdQ; void *oldConsQ; int result; prodQ = (VMCIQueue *)entry->produceQ; consQ = (VMCIQueue *)entry->consumeQ; oldConsQ = oldProdQ = NULL; VMCI_AcquireQueueMutex(prodQ); result = VMCI_ConvertToLocalQueue(consQ, prodQ, entry->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->handle.context, entry->handle.resource, result)); VMCI_ReleaseQueueMutex(prodQ); VMCIQPMarkHibernateFailed(entry); continue; } result = VMCI_ConvertToLocalQueue(prodQ, consQ, entry->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->handle.context, entry->handle.resource, result)); VMCI_RevertToNonLocalQueue(consQ, oldConsQ, entry->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->handle); if (result < VMCI_SUCCESS) { VMCI_WARNING((LGPFX"Hibernate failed to detach from handle " "%x:%x\n", entry->handle.context, entry->handle.resource)); VMCI_RevertToNonLocalQueue(consQ, oldConsQ, entry->consumeSize); VMCI_RevertToNonLocalQueue(prodQ, oldProdQ, entry->produceSize); VMCI_ReleaseQueueMutex(prodQ); VMCIQPMarkHibernateFailed(entry); continue; } entry->flags |= VMCI_QPFLAG_LOCAL; VMCI_ReleaseQueueMutex(prodQ); VMCI_FreeQueueBuffer(oldProdQ, entry->produceSize); VMCI_FreeQueueBuffer(oldConsQ, entry->consumeSize); QueuePairNotifyPeerLocal(FALSE, entry->handle); } } Atomic_Write(&queuePairList.hibernate, 1); QueuePairList_Unlock(); } 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(&queuePairList.hibernate, 0); } } vmci-only/vmciProcess.h 0000444 0000000 0000000 00000002650 11573420371 014143 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciProcess.h -- * * Process code for the Linux guest driver */ #ifndef __VMCI_PROCESS_H__ #define __VMCI_PROCESS_H__ #define INCLUDE_ALLOW_MODULE #include "includeCheck.h" #include "vm_basic_types.h" #include "vmci_defs.h" #include "vmci_handle_array.h" typedef struct VMCIProcess VMCIProcess; void VMCIProcess_Init(void); void VMCIProcess_Exit(void); Bool VMCIProcess_CheckHostCapabilities(void); int VMCIProcess_Create(VMCIProcess **outProcess); void VMCIProcess_Destroy(VMCIProcess *process); VMCIProcess *VMCIProcess_Get(VMCIId processID); #endif //__VMCI_PROCESS_H__ vmci-only/vmciInt.h 0000444 0000000 0000000 00000003124 11573420371 013254 0 ustar root root /********************************************************* * 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 * *********************************************************/ #ifndef __VMCI_INT_H__ #define __VMCI_INT_H__ #define INCLUDE_ALLOW_MODULE #include "includeCheck.h" #include "vm_basic_types.h" #include "vmci_call_defs.h" #include "vmciProcess.h" #define DODEBUGLOG(...) printk(KERN_DEBUG __VA_ARGS__) #define DOLOG(...) printk(KERN_INFO __VA_ARGS__) #define DOWARNING(...) printk(KERN_WARNING __VA_ARGS__) #ifdef VMCI_DEBUG # define VMCI_DEBUG_LOG(_level, _args) DODEBUGLOG _args #else # define VMCI_DEBUG_LOG(_level, _args) #endif // VMCI_DEBUG #define VMCI_LOG(_args) DOLOG _args #define VMCI_WARNING(_args) DOWARNING _args /* * Called by common code, hence the different naming convention. * XXX Should be in vmci.h. */ int VMCI_SendDatagram(VMCIDatagram *dg); Bool VMCI_DeviceEnabled(void); #endif /* __VMCIINT_H__ */ vmci-only/vmciEvent.c 0000444 0000000 0000000 00000045421 11573420371 013604 0 ustar root root /********************************************************* * 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. */ #if defined(__linux__) && !defined(VMKERNEL) # include "driver-config.h" # include "compat_kernel.h" # include "compat_module.h" #endif // __linux__ #include "vmci_kernel_if.h" #include "vmci_defs.h" #include "vmci_infrastructure.h" #include "vmciEvent.h" #include "vmciKernelAPI.h" #ifdef VMX86_TOOLS # include "vmciInt.h" # include "vmciUtil.h" #elif defined(VMKERNEL) # include "vmciVmkInt.h" # include "vm_libc.h" # include "helper_ext.h" # include "vmciDriver.h" #else # include "vmciDriver.h" #endif #include "circList.h" /* Must come after vmciVmkInt.h. */ #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; ListItem subscriberListItem; } VMCISubscription; typedef struct VMCISubscriptionItem { ListItem listItem; VMCISubscription sub; } VMCISubscriptionItem; 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); /* * In the guest, VMCI events are dispatched from interrupt context, so * the locks need to be bottom half safe. In the host kernel, this * isn't so, and regular locks are used instead. */ #ifdef VMX86_TOOLS #define VMCIEventInitLock(_lock, _name) VMCI_InitLock(_lock, _name, VMCI_LOCK_RANK_HIGHER_BH) #define VMCIEventGrabLock(_lock, _flags) VMCI_GrabLock_BH(_lock, _flags) #define VMCIEventReleaseLock(_lock, _flags) VMCI_ReleaseLock_BH(_lock, _flags) #else #define VMCIEventInitLock(_lock, _name) VMCI_InitLock(_lock, _name, VMCI_LOCK_RANK_HIGHER) #define VMCIEventGrabLock(_lock, _flags) VMCI_GrabLock(_lock, _flags) #define VMCIEventReleaseLock(_lock, _flags) VMCI_ReleaseLock(_lock, _flags) #endif static ListItem *subscriberArray[VMCI_EVENT_MAX] = {NULL}; static VMCILock subscriberLock; typedef struct VMCIDelayedEventInfo { VMCISubscription *sub; uint8 eventPayload[sizeof(VMCIEventData_Max)]; } VMCIDelayedEventInfo; /* *---------------------------------------------------------------------- * * VMCIEvent_Init -- * * General init code. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void VMCIEvent_Init(void) { VMCIEventInitLock(&subscriberLock, "VMCIEventSubscriberLock"); } /* *---------------------------------------------------------------------- * * VMCIEvent_Exit -- * * General exit code. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void VMCIEvent_Exit(void) { ListItem *iter, *iter2; VMCI_Event e; /* We free all memory at exit. */ for (e = 0; e < VMCI_EVENT_MAX; e++) { LIST_SCAN_SAFE(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 = LIST_CONTAINER(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; VMCIEventGrabLock(&subscriberLock, &lockFlags); VMCIEventReleaseLock(&subscriberLock, lockFlags); } #ifdef VMX86_TOOLS /* *----------------------------------------------------------------------------- * * 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; } #endif /* *----------------------------------------------------------------------------- * * 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); VMCIEventGrabLock(&subscriberLock, &flags); VMCIEventRelease(sub); VMCIEventReleaseLock(&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 { ListItem *iter; VMCI_Event e; for (e = 0; e < VMCI_EVENT_MAX; e++) { LIST_SCAN(iter, subscriberArray[e]) { VMCISubscription *cur = LIST_CONTAINER(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); VMCIEventGrabLock(&subscriberLock, &flags); VMCIEventRelease(sub); VMCIEventReleaseLock(&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; ListItem *iter; VMCILockFlags flags; ASSERT(eventMsg); VMCIEventGrabLock(&subscriberLock, &flags); LIST_SCAN(iter, subscriberArray[eventMsg->eventData.event]) { VMCI_EventData *ed; VMCISubscription *cur = LIST_CONTAINER(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 { 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); } } out: VMCIEventReleaseLock(&subscriberLock, flags); 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 (eventMsg->eventData.event >= VMCI_EVENT_MAX) { 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 (event >= VMCI_EVENT_MAX || callback == NULL) { VMCI_DEBUG_LOG(4, (LGPFX"Failed to subscribe to event %d cb %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. */ 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; VMCIEventGrabLock(&subscriberLock, &lockFlags); /* Do not allow a new subscription if the device is being shutdown. */ if (VMCI_DeviceShutdown()) { result = VMCI_ERROR_DEVICE_NOT_FOUND; 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); LIST_QUEUE(&sub->subscriberListItem, &subscriberArray[event]); result = VMCI_SUCCESS; } else { result = VMCI_ERROR_NO_RESOURCES; } exit: VMCIEventReleaseLock(&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; VMCIEventGrabLock(&subscriberLock, &flags); s = VMCIEventFind(subID); if (s != NULL) { VMCIEventRelease(s); LIST_DEL(&s->subscriberListItem, &subscriberArray[s->event]); } VMCIEventReleaseLock(&subscriberLock, flags); if (s != NULL) { VMCI_WaitOnEvent(&s->destroyEvent, EventReleaseCB, s); VMCI_DestroyEvent(&s->destroyEvent); } return s; } /* *---------------------------------------------------------------------- * * VMCIEvent_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(VMCIEvent_Subscribe) int VMCIEvent_Subscribe(VMCI_Event event, // IN uint32 flags, // IN VMCI_EventCB callback, // IN void *callbackData, // IN VMCIId *subscriptionID) // OUT { int retval; VMCISubscription *s = NULL; if (subscriptionID == NULL) { VMCI_DEBUG_LOG(4, (LGPFX"Invalid arguments.\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; } /* *---------------------------------------------------------------------- * * VMCIEvent_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(VMCIEvent_Unsubscribe) int VMCIEvent_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; } vmci-only/vmciGuestKernelIf.c 0000444 0000000 0000000 00000003445 11573420371 015232 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciGuestKernelIf.c -- * * This file implements guest only OS helper functions for VMCI. * 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 #include <linux/moduleparam.h> #include "compat_version.h" #include "compat_pci.h" #include "vm_basic_types.h" #include "vmciGuestKernelIf.h" /* *----------------------------------------------------------------------------- * * 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); } vmci-only/Makefile 0000644 0000000 0000000 00000010427 11573420431 013135 0 ustar root root #!/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 HEADER_DIR = /lib/modules/$(VM_UNAME)/build/include BUILD_DIR = $(HEADER_DIR)/.. DRIVER := vmci PRODUCT := tools # 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: vmci-only/vmciQueue.h 0000444 0000000 0000000 00000012614 11573420432 013610 0 ustar root root /********************************************************* * 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; 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); typedef int VMCIMemcpyFromQueueFunc(void *dest, size_t destOffset, const VMCIQueue *queue, uint64 queueOffset, size_t size, BUF_TYPE bufType); #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]() 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); int VMCIMemcpyFromQueue(void *dest, size_t destOffset, const VMCIQueue *queue, uint64 queueOffset, size_t size, BUF_TYPE bufType); #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); int VMCIMemcpyFromQueueV(void *dest, size_t destOffset, const VMCIQueue *queue, uint64 queueOffset, size_t size, BUF_TYPE bufType); #endif /* Does the O/S support iovec? */ #endif /* !_VMCI_QUEUE_H_ */ vmci-only/vmciUtil.h 0000444 0000000 0000000 00000003311 11573420371 013435 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciUtil.h -- * * Helper functions. */ #ifndef __VMCI_UTIL_H__ #define __VMCI_UTIL_H__ #define INCLUDE_ALLOW_MODULE #include "includeCheck.h" #include "vmciGuestKernelIf.h" #include "vmci_infrastructure.h" #define VMCI_MAJOR_VERSION_NUMBER 1 #define VMCI_MINOR_VERSION_NUMBER 0 #define VMCI_VERSION_NUMBER \ ((VMCI_MAJOR_VERSION_NUMBER << 16) | (VMCI_MINOR_VERSION_NUMBER)) typedef struct VMCIGuestDeviceHandle { void *obj; VMCIObjType objType; } VMCIGuestDeviceHandle; void VMCIUtil_Init(void); void VMCIUtil_Exit(void); Bool VMCIUtil_CheckHostCapabilities(void); Bool VMCI_CheckHostCapabilities(void); Bool VMCI_InInterrupt(void); void VMCI_ReadDatagramsFromPort(VMCIIoHandle ioHandle, VMCIIoPort dgInPort, uint8 *dgInBuffer, size_t dgInBufferSize); Bool VMCI_DeviceInUse(void); #endif //__VMCI_UTIL_H__ vmci-only/vmciQPair.c 0000444 0000000 0000000 00000071751 11573420431 013541 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * 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. */ /* Must come before any kernel header file. */ #if defined(__linux__) && !defined(VMKERNEL) # include "driver-config.h" # include "compat_module.h" #endif #include "vmci_kernel_if.h" #include "vm_assert.h" #include "vmci_handle_array.h" #include "vmci_defs.h" #ifndef VMKERNEL # include "circList.h" #endif #if defined VMKERNEL || !defined VMX86_TOOLS # include "vmciQueuePair.h" #else # include "vmciGuestKernelIf.h" # include "vmciQueuePairInt.h" #endif #include "vmciKernelAPI.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; }; #define VMCI_QPAIR_NO_QUEUE(_qp) (!(_qp)->produceQ->qHeader || \ !(_qp)->consumeQ->qHeader) /* *----------------------------------------------------------------------------- * * VMCIQPair_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(VMCIQPair_Alloc) int VMCIQPair_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; /* * 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; } myQPair = VMCI_AllocKernelMem(sizeof *myQPair, VMCI_MEMORY_NONPAGED); if (!myQPair) { return VMCI_ERROR_NO_MEM; } memset(myQPair, 0, sizeof *myQPair); myQPair->produceQSize = produceQSize; myQPair->consumeQSize = consumeQSize; myQPair->peer = peer; myQPair->flags = flags; myQPair->privFlags = privFlags; retval = VMCIQueuePair_AllocPriv(handle, &myQPair->produceQ, myQPair->produceQSize, &myQPair->consumeQ, myQPair->consumeQSize, myQPair->peer, myQPair->flags, myQPair->privFlags); if (retval < VMCI_SUCCESS) { VMCI_FreeKernelMem(myQPair, sizeof *myQPair); return retval; } *qpair = myQPair; myQPair->handle = *handle; return retval; } /* *----------------------------------------------------------------------------- * * VMCIQPair_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(VMCIQPair_Detach) int VMCIQPair_Detach(VMCIQPair **qpair) // IN/OUT { int result; VMCIQPair *oldQPair; if (!qpair || !(*qpair)) { return VMCI_ERROR_INVALID_ARGS; } oldQPair = *qpair; result = VMCIQueuePair_Detach(oldQPair->handle); /* * 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. */ memset(oldQPair, 0, sizeof *oldQPair); oldQPair->handle = VMCI_INVALID_HANDLE; oldQPair->peer = VMCI_INVALID_ID; VMCI_FreeKernelMem(oldQPair, sizeof *oldQPair); *qpair = NULL; return result; } /* * "Windows blocking call." * * Note that on the Windows platform, kernel module clients may * block when calling into any these rouintes. The reason is * that a mutex has to be acquired in order to view/modify the * VMCIQueue structure fields: pointers, handle, and buffer data. * However, other platforms don't require the acquisition of a * mutex and thus don't block. */ /* *----------------------------------------------------------------------------- * * VMCIQPair_Lock -- * * Helper routine that will lock the QPair before subsequent operations. * * Results: * None. * * Side effects: * Windows blocking call. * *----------------------------------------------------------------------------- */ static INLINE void VMCIQPairLock(const VMCIQPair *qpair) // IN { #if !defined VMX86_VMX VMCI_AcquireQueueMutex(qpair->produceQ); #endif } /* *----------------------------------------------------------------------------- * * VMCIQPair_Unlock -- * * 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 VMCI_ReleaseQueueMutex(qpair->produceQ); #endif } /* *----------------------------------------------------------------------------- * * VMCIQPair_GetProduceIndexes -- * * 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(VMCIQPair_GetProduceIndexes) int VMCIQPair_GetProduceIndexes(const VMCIQPair *qpair, // IN uint64 *producerTail, // OUT uint64 *consumerHead) // OUT { int result; if (!qpair) { return VMCI_ERROR_INVALID_ARGS; } VMCIQPairLock(qpair); if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) { result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED; } else { VMCIQueueHeader_GetPointers(qpair->produceQ->qHeader, qpair->consumeQ->qHeader, producerTail, consumerHead); result = VMCI_SUCCESS; } VMCIQPairUnlock(qpair); if (result == VMCI_SUCCESS && ((producerTail && *producerTail >= qpair->produceQSize) || (consumerHead && *consumerHead >= qpair->produceQSize))) { return VMCI_ERROR_INVALID_SIZE; } return result; } /* *----------------------------------------------------------------------------- * * VMCIQPair_GetConsumeIndexes -- * * 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(VMCIQPair_GetConsumeIndexes) int VMCIQPair_GetConsumeIndexes(const VMCIQPair *qpair, // IN uint64 *consumerTail, // OUT uint64 *producerHead) // OUT { int result; if (!qpair) { return VMCI_ERROR_INVALID_ARGS; } VMCIQPairLock(qpair); if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) { result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED; } else { VMCIQueueHeader_GetPointers(qpair->consumeQ->qHeader, qpair->produceQ->qHeader, consumerTail, producerHead); result = VMCI_SUCCESS; } VMCIQPairUnlock(qpair); if (result == VMCI_SUCCESS && ((consumerTail && *consumerTail >= qpair->consumeQSize) || (producerHead && *producerHead >= qpair->consumeQSize))) { return VMCI_ERROR_INVALID_SIZE; } return result; } /* *----------------------------------------------------------------------------- * * VMCIQPair_ProduceFreeSpace -- * * 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(VMCIQPair_ProduceFreeSpace) int64 VMCIQPair_ProduceFreeSpace(const VMCIQPair *qpair) // IN { int64 result; if (!qpair) { return VMCI_ERROR_INVALID_ARGS; } VMCIQPairLock(qpair); if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) { result = 0; } else { result = VMCIQueueHeader_FreeSpace(qpair->produceQ->qHeader, qpair->consumeQ->qHeader, qpair->produceQSize); } VMCIQPairUnlock(qpair); return result; } /* *----------------------------------------------------------------------------- * * VMCIQPair_ConsumeFreeSpace -- * * 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(VMCIQPair_ConsumeFreeSpace) int64 VMCIQPair_ConsumeFreeSpace(const VMCIQPair *qpair) // IN { int64 result; if (!qpair) { return VMCI_ERROR_INVALID_ARGS; } VMCIQPairLock(qpair); if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) { result = 0; } else { result = VMCIQueueHeader_FreeSpace(qpair->consumeQ->qHeader, qpair->produceQ->qHeader, qpair->consumeQSize); } VMCIQPairUnlock(qpair); return result; } /* *----------------------------------------------------------------------------- * * VMCIQPair_ProduceBufReady -- * * 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(VMCIQPair_ProduceBufReady) int64 VMCIQPair_ProduceBufReady(const VMCIQPair *qpair) // IN { int64 result; if (!qpair) { return VMCI_ERROR_INVALID_ARGS; } VMCIQPairLock(qpair); if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) { result = 0; } else { result = VMCIQueueHeader_BufReady(qpair->produceQ->qHeader, qpair->consumeQ->qHeader, qpair->produceQSize); } VMCIQPairUnlock(qpair); return result; } /* *----------------------------------------------------------------------------- * * VMCIQPair_ConsumeBufReady -- * * 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(VMCIQPair_ConsumeBufReady) int64 VMCIQPair_ConsumeBufReady(const VMCIQPair *qpair) // IN { int64 result; if (!qpair) { return VMCI_ERROR_INVALID_ARGS; } VMCIQPairLock(qpair); if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) { result = 0; } else { result = VMCIQueueHeader_BufReady(qpair->consumeQ->qHeader, qpair->produceQ->qHeader, qpair->consumeQSize); } VMCIQPairUnlock(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 INLINE ssize_t EnqueueLocked(VMCIQueue *produceQ, // IN const VMCIQueue *consumeQ, // IN const uint64 produceQSize, // IN const void *buf, // IN size_t bufSize, // IN int bufType, // IN VMCIMemcpyToQueueFunc memcpyToQueue) // IN { int64 freeSpace; uint64 tail; size_t written; ssize_t result; #if !defined VMX86_VMX if (UNLIKELY(VMCI_EnqueueToDevNull(produceQ))) { return (ssize_t) bufSize; } if (UNLIKELY(!produceQ->qHeader || !consumeQ->qHeader)) { return VMCI_ERROR_QUEUEPAIR_NOTATTACHED; } #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); } else { /* Tail pointer wraps around. */ const size_t tmp = (size_t)(produceQSize - tail); result = memcpyToQueue(produceQ, tail, buf, 0, tmp, bufType); if (result >= VMCI_SUCCESS) { result = memcpyToQueue(produceQ, 0, buf, tmp, written - tmp, bufType); } } 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 INLINE ssize_t DequeueLocked(VMCIQueue *produceQ, // IN const VMCIQueue *consumeQ, // IN const uint64 consumeQSize, // IN void *buf, // IN size_t bufSize, // IN int bufType, // IN VMCIMemcpyFromQueueFunc memcpyFromQueue, // IN Bool updateConsumer) // IN { int64 bufReady; uint64 head; size_t read; ssize_t result; #if !defined VMX86_TOOLS && !defined VMX86_VMX if (UNLIKELY(!produceQ->qHeader || !consumeQ->qHeader)) { return VMCI_ERROR_QUEUEPAIR_NODATA; } #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); } else { /* Head pointer wraps around. */ const size_t tmp = (size_t)(consumeQSize - head); result = memcpyFromQueue(buf, 0, consumeQ, head, tmp, bufType); if (result >= VMCI_SUCCESS) { result = memcpyFromQueue(buf, tmp, consumeQ, 0, read - tmp, bufType); } } if (result < VMCI_SUCCESS) { return result; } if (updateConsumer) { VMCIQueueHeader_AddConsumerHead(produceQ->qHeader, read, consumeQSize); } return read; } /* *----------------------------------------------------------------------------- * * VMCIQPair_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(VMCIQPair_Enqueue) ssize_t VMCIQPair_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; } VMCIQPairLock(qpair); result = EnqueueLocked(qpair->produceQ, qpair->consumeQ, qpair->produceQSize, buf, bufSize, bufType, VMCIMemcpyToQueue); VMCIQPairUnlock(qpair); return result; } /* *----------------------------------------------------------------------------- * * VMCIQPair_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(VMCIQPair_Dequeue) ssize_t VMCIQPair_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; } VMCIQPairLock(qpair); result = DequeueLocked(qpair->produceQ, qpair->consumeQ, qpair->consumeQSize, buf, bufSize, bufType, VMCIMemcpyFromQueue, TRUE); VMCIQPairUnlock(qpair); return result; } /* *----------------------------------------------------------------------------- * * VMCIQPair_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(VMCIQPair_Peek) ssize_t VMCIQPair_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; } VMCIQPairLock(qpair); result = DequeueLocked(qpair->produceQ, qpair->consumeQ, qpair->consumeQSize, buf, bufSize, bufType, VMCIMemcpyFromQueue, FALSE); VMCIQPairUnlock(qpair); return result; } #if defined (SOLARIS) || (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \ (defined(__linux__) && defined(__KERNEL__)) || \ (defined(_WIN32) && defined(WINNT_DDK)) /* *----------------------------------------------------------------------------- * * VMCIQPair_EnqueueV -- * * 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(VMCIQPair_EnqueueV) ssize_t VMCIQPair_EnqueueV(VMCIQPair *qpair, // IN void *iov, // IN size_t iovSize, // IN int bufType) // IN { ssize_t result; if (!qpair || !iov) { return VMCI_ERROR_INVALID_ARGS; } VMCIQPairLock(qpair); result = EnqueueLocked(qpair->produceQ, qpair->consumeQ, qpair->produceQSize, iov, iovSize, bufType, VMCIMemcpyToQueueV); VMCIQPairUnlock(qpair); return result; } /* *----------------------------------------------------------------------------- * * VMCIQPair_DequeueV -- * * 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(VMCIQPair_DequeueV) ssize_t VMCIQPair_DequeueV(VMCIQPair *qpair, // IN void *iov, // IN size_t iovSize, // IN int bufType) // IN { ssize_t result; VMCIQPairLock(qpair); if (!qpair || !iov) { return VMCI_ERROR_INVALID_ARGS; } result = DequeueLocked(qpair->produceQ, qpair->consumeQ, qpair->consumeQSize, iov, iovSize, bufType, VMCIMemcpyFromQueueV, TRUE); VMCIQPairUnlock(qpair); return result; } /* *----------------------------------------------------------------------------- * * VMCIQPair_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(VMCIQPair_PeekV) ssize_t VMCIQPair_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; } VMCIQPairLock(qpair); result = DequeueLocked(qpair->produceQ, qpair->consumeQ, qpair->consumeQSize, iov, iovSize, bufType, VMCIMemcpyFromQueueV, FALSE); VMCIQPairUnlock(qpair); return result; } #endif /* Systems that support struct iovec */ vmci-only/vmciCommonInt.h 0000444 0000000 0000000 00000003321 11573420371 014424 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciCommonInt.h -- * * Struct definitions for VMCI internal common code. */ #ifndef _VMCI_COMMONINT_H_ #define _VMCI_COMMONINT_H_ #define INCLUDE_ALLOW_MODULE #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" #include "circList.h" struct DatagramQueueEntry { ListItem listItem; /* For queuing. */ VMCIDatagram *dg; /* Pending datagram. */ }; struct VMCIProcess { ListItem listItem; /* For global process list. */ VMCIId pid; /* Process id. */ }; struct VMCIDatagramProcess { VMCILock datagramQueueLock; VMCIHandle handle; VMCIHost host; uint32 pendingDatagrams; size_t datagramQueueSize; ListItem *datagramQueue; }; #endif /* _VMCI_COMMONINT_H_ */ vmci-only/vmci_handle_array.h 0000444 0000000 0000000 00000021601 11573420432 015310 0 ustar root root /********************************************************* * 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); 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_ vmci-only/COPYING 0000444 0000000 0000000 00000043103 11573420420 012521 0 ustar root root 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. vmci-only/vmciProcess.c 0000444 0000000 0000000 00000011504 11573420371 014134 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciProcess.c -- * * VMCI Process code for guest driver. */ #ifdef __linux__ # include "driver-config.h" # define EXPORT_SYMTAB # include <linux/module.h> # include "compat_kernel.h" # include "compat_pci.h" #endif // __linux__ #include "vmci_kernel_if.h" #include "vmci_defs.h" #include "vmciInt.h" #include "vmciProcess.h" #include "vmciDatagram.h" #include "vmci_infrastructure.h" #include "circList.h" #include "vmciUtil.h" #include "vmciCommonInt.h" static ListItem *processList = NULL; static VMCILock processLock; /* *---------------------------------------------------------------------- * * VMCIProcess_Init -- * * General init code. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void VMCIProcess_Init(void) { VMCI_InitLock(&processLock, "VMCIProcessListLock", VMCI_LOCK_RANK_HIGH); } /* *---------------------------------------------------------------------- * * VMCIProcess_Exit -- * * General init code. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void VMCIProcess_Exit(void) { VMCI_CleanupLock(&processLock); } /* *----------------------------------------------------------------------------- * * VMCIProcess_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 VMCIProcess_CheckHostCapabilities(void) { /* VMCIProcess does not require any hypercalls. */ return TRUE; } /* *---------------------------------------------------------------------- * * VMCIProcess_Create -- * * Creates a new VMCI process. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ int VMCIProcess_Create(VMCIProcess **outProcess) // IN { VMCIProcess *process; VMCILockFlags flags; process = VMCI_AllocKernelMem(sizeof *process, VMCI_MEMORY_NONPAGED); if (process == NULL) { return VMCI_ERROR_NO_MEM; } process->pid = (VMCIId)(uintptr_t)process >> 1; VMCI_GrabLock(&processLock, &flags); LIST_QUEUE(&process->listItem, &processList); VMCI_ReleaseLock(&processLock, flags); *outProcess = process; return 0; } /* *---------------------------------------------------------------------- * * VMCIProcess_Destroy -- * * Destroys a VMCI process. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void VMCIProcess_Destroy(VMCIProcess *process) { VMCILockFlags flags; /* Dequeue process. */ VMCI_GrabLock(&processLock, &flags); LIST_DEL(&process->listItem, &processList); VMCI_ReleaseLock(&processLock, flags); VMCI_FreeKernelMem(process, sizeof *process); } /* *---------------------------------------------------------------------- * * VMCIProcess_Get -- * * Get the process corresponding to the pid. * * Results: * VMCI process on success, NULL otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ VMCIProcess * VMCIProcess_Get(VMCIId processID) // IN { VMCIProcess *process = NULL; ListItem *next; VMCILockFlags flags; VMCI_GrabLock(&processLock, &flags); if (processList == NULL) { goto out; } LIST_SCAN(next, processList) { process = LIST_CONTAINER(next, VMCIProcess, listItem); if (process->pid == processID) { break; } } out: VMCI_ReleaseLock(&processLock, flags); return (process && process->pid == processID) ? process : NULL; } vmci-only/pgtbl.h 0000444 0000000 0000000 00000022326 11573420431 012755 0 ustar root root /********************************************************* * 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 "compat_highmem.h" #include "compat_pgtable.h" #include "compat_spinlock.h" #include "compat_page.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 11) # define compat_active_mm mm #else # define compat_active_mm active_mm #endif /* *----------------------------------------------------------------------------- * * 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->compat_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; MPN mpn; mm = current->compat_active_mm; 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; struct page *page; mm = current->compat_active_mm; 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__ */ vmci-only/vmciNotifications.c 0000444 0000000 0000000 00000100552 11573420371 015331 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciNotifications.c -- * * Implementation of the VMCI notifications registration and * delivery, and the related doorbell API for the guest driver. */ #ifdef __linux__ # include "driver-config.h" # include "compat_kernel.h" # include "compat_module.h" #endif // linux #include "vmci_kernel_if.h" #include "vm_basic_types.h" #include "vm_assert.h" #include "vmciKernelAPI.h" #include "vmci_defs.h" #include "vmci_call_defs.h" #include "vmciInt.h" #include "vmciUtil.h" #include "circList.h" #define LGPFX "VMCINotifications: " #if !defined(SOLARIS) && !defined(__APPLE__) /* * The VMCI Notify hash table provides two mappings: * 1) one maps a given notification index in the bitmap to the * entries, giving the set of handlers registered for that * index. This is mainly used for firing handlers for a given * bitmap index. * 2) the other maps a handle and a resource (doorbell/queuepair) * to the entry (used to check for duplicates and delete the * entry) */ #define HASH_TABLE_SIZE 64 #define VMCI_NOTIF_HASH(val) VMCI_HashId(val, HASH_TABLE_SIZE) typedef struct VMCINotifyHashEntry { uint32 idx; // Bitmap index VMCIHandle handle; Bool doorbell; Bool runDelayed; VMCICallback notifyCB; void *callbackData; VMCIEvent destroyEvent; int refCount; ListItem handleListItem; ListItem idxListItem; } VMCINotifyHashEntry; typedef struct VMCINotifyHashTable { VMCILock lock; ListItem *entriesByIdx[HASH_TABLE_SIZE]; ListItem *entriesByHandle[HASH_TABLE_SIZE]; } VMCINotifyHashTable; static int VMCINotifyHashAddEntry(VMCINotifyHashEntry *entry); static void VMCINotifyHashSetEntryCallback(VMCINotifyHashEntry *entry, VMCICallback notifyCB); static VMCINotifyHashEntry *VMCINotifyHashRemoveEntry(VMCIHandle handle, Bool doorbell); static int VMCINotifyReleaseCB(void *clientData); static void VMCINotifyHashReleaseEntry(VMCINotifyHashEntry *entry); static VMCINotifyHashEntry *VMCINotifyHashFindByIdx(uint32 idx, uint32 *hashBucket); static VMCINotifyHashEntry *VMCINotifyHashFindByHandle(VMCIHandle handle, Bool doorbell, uint32 *hashBucket); static void VMCINotifyDelayedDispatchCB(void *data); static void VMCINotifyHashFireEntries(uint32 notifyIdx); static int LinkNotificationHypercall(VMCIHandle handle, Bool doorbell, uint32 notifyIdx); static int UnlinkNotificationHypercall(VMCIHandle handle, Bool doorbell); /* * The VMCI notify hash table keeps track of currently registered * notifications. */ static VMCINotifyHashTable vmciNotifyHT; /* * 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; /* * lastNotifyIdxReleased is a one entry cache used to by the index * allocation. */ static uint32 lastNotifyIdxReleased = PAGE_SIZE; /* *---------------------------------------------------------------------- * * VMCINotifications_Init -- * * General init code. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void VMCINotifications_Init(void) { memset(vmciNotifyHT.entriesByIdx, 0, ARRAY_SIZE(vmciNotifyHT.entriesByIdx)); memset(vmciNotifyHT.entriesByHandle, 0, ARRAY_SIZE(vmciNotifyHT.entriesByHandle)); VMCI_InitLock(&vmciNotifyHT.lock, "VMCINotifyHashLock", VMCI_LOCK_RANK_HIGHER_BH); return; } /* *---------------------------------------------------------------------- * * VMCINotifications_Exit -- * * General exit code. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void VMCINotifications_Exit(void) { uint32 bucket; ListItem *iter, *iter2; for (bucket = 0; bucket < HASH_TABLE_SIZE; bucket++) { LIST_SCAN_SAFE(iter, iter2, vmciNotifyHT.entriesByIdx[bucket]) { VMCINotifyHashEntry *cur; /* * We should never get here because all notifications 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 = LIST_CONTAINER(iter, VMCINotifyHashEntry, idxListItem); VMCI_FreeKernelMem(cur, sizeof *cur); } } VMCI_CleanupLock(&vmciNotifyHT.lock); } /* *----------------------------------------------------------------------------- * * VMCINotifications_Sync -- * * Use this as a synchronization point when setting globals, for example, * during device shutdown. * * Results: * TRUE. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void VMCINotifications_Sync(void) { VMCILockFlags flags; VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); } /* *---------------------------------------------------------------------- * * VMCINotifications_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 VMCINotifications_Hibernate(Bool enterHibernate) // IN { VMCILockFlags flags; uint32 bucket; ListItem *iter; if (enterHibernate) { /* * Nothing to do when entering hibernation. */ return; } VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); for (bucket = 0; bucket < HASH_TABLE_SIZE; bucket++) { LIST_SCAN(iter, vmciNotifyHT.entriesByIdx[bucket]) { VMCINotifyHashEntry *cur; int result; cur = LIST_CONTAINER(iter, VMCINotifyHashEntry, idxListItem); result = LinkNotificationHypercall(cur->handle, cur->doorbell, 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", cur->handle.context, cur->handle.resource, cur->doorbell ? "doorbell" : "queue pair", result)); } } } VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); } /* *------------------------------------------------------------------------- * * VMCINotifyHashAddEntry -- * * Given a notification entry, adds it to the hashtable of * notifications. * * Result: * VMCI_SUCCESS on success, appropriate error code otherwise. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int VMCINotifyHashAddEntry(VMCINotifyHashEntry *entry) // IN { VMCILockFlags flags; uint32 bucket; uint32 newNotifyIdx; int result; static VMCIId notifyRID = 0; ASSERT(entry); VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); /* Do not allow addition of a new handle if the device is being shutdown. */ if (VMCI_DeviceShutdown()) { result = VMCI_ERROR_DEVICE_NOT_FOUND; goto out; } if (VMCI_HANDLE_INVALID(entry->handle)) { VMCIHandle newHandle; VMCIId oldRID = notifyRID; Bool found; do { newHandle = VMCI_MAKE_HANDLE(VMCI_GetContextID(), notifyRID); notifyRID++; found = VMCINotifyHashFindByHandle(newHandle, entry->doorbell, NULL) != NULL; } while(found && oldRID != notifyRID); if (UNLIKELY(found)) { /* * We went full circle and still didn't find a free handle. */ result = VMCI_ERROR_NO_HANDLE; goto out; } entry->handle = newHandle; } else if (VMCI_GetContextID() != entry->handle.context) { /* * The context id passed down should either be invalid or * the context id of the guest. */ result = VMCI_ERROR_INVALID_ARGS; goto out; } if (VMCINotifyHashFindByHandle(entry->handle, entry->doorbell, &bucket)) { result = VMCI_ERROR_ALREADY_EXISTS; goto out; } LIST_QUEUE(&entry->handleListItem, &vmciNotifyHT.entriesByHandle[bucket]); /* * 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 withing 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 && !VMCINotifyHashFindByIdx(lastNotifyIdxReleased, NULL)) { newNotifyIdx = lastNotifyIdxReleased; lastNotifyIdxReleased = PAGE_SIZE; } else { Bool reused = FALSE; newNotifyIdx = lastNotifyIdxReserved; if (notifyIdxCount + 1 < maxNotifyIdx) { do { if (!VMCINotifyHashFindByIdx(newNotifyIdx, NULL)) { reused = TRUE; break; } newNotifyIdx = (newNotifyIdx + 1) % maxNotifyIdx; } while(newNotifyIdx != lastNotifyIdxReleased); } if (!reused) { newNotifyIdx = maxNotifyIdx; maxNotifyIdx++; } } } else { newNotifyIdx = (lastNotifyIdxReserved + 1) % PAGE_SIZE; } lastNotifyIdxReserved = newNotifyIdx; notifyIdxCount++; bucket = VMCI_NOTIF_HASH(newNotifyIdx); entry->refCount++; entry->idx = newNotifyIdx; LIST_QUEUE(&entry->idxListItem, &vmciNotifyHT.entriesByIdx[bucket]); result = VMCI_SUCCESS; out: VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); return result; } /* *------------------------------------------------------------------------- * * VMCINotifyHashSetEntryCallback -- * * Sets the notify callback of the given entry. Once the callback * has been set, it may start firing. * * Result: * None. * * Side effects: * None. * *------------------------------------------------------------------------- */ static void VMCINotifyHashSetEntryCallback(VMCINotifyHashEntry *entry, // IN VMCICallback notifyCB) // IN { VMCILockFlags flags; ASSERT(entry && notifyCB); VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); entry->notifyCB = notifyCB; VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); } /* *------------------------------------------------------------------------- * * VMCINotifyHashRemoveEntry -- * * Removes the entry identified by the handle of the given * resource type from the hash table. * * Result: * Pointer to entry if removed, NULL if not found. * * Side effects: * None. * *------------------------------------------------------------------------- */ static VMCINotifyHashEntry * VMCINotifyHashRemoveEntry(VMCIHandle handle, // IN Bool doorbell) // IN { VMCILockFlags flags; VMCINotifyHashEntry *entry; uint32 bucket; VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); entry = VMCINotifyHashFindByHandle(handle, doorbell, &bucket); if (entry) { ASSERT(entry->refCount > 0); LIST_DEL(&entry->handleListItem, &vmciNotifyHT.entriesByHandle[bucket]); bucket = VMCI_NOTIF_HASH(entry->idx); LIST_DEL(&entry->idxListItem, &vmciNotifyHT.entriesByIdx[bucket]); 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 && !VMCINotifyHashFindByIdx(maxNotifyIdx - 1, NULL)) { maxNotifyIdx--; } } lastNotifyIdxReleased = entry->idx; } VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); return entry; } /* *------------------------------------------------------------------------------ * * VMCINotifyReleaseCB -- * * Callback to release the notification entry reference. It is * called by the VMCI_WaitOnEvent function before it blocks. * * Result: * 0. * * Side effects: * Releases hash entry (see below). * *------------------------------------------------------------------------------ */ static int VMCINotifyReleaseCB(void *clientData) // IN { VMCINotifyHashEntry *entry = (VMCINotifyHashEntry *)clientData; ASSERT(entry); VMCINotifyHashReleaseEntry(entry); return 0; } /* *------------------------------------------------------------------------- * * VMCINotifyHashReleaseEntry -- * * Drops a reference to the current hash entry. If this is the last * reference then the entry is freed. * * Result: * None. * * Side effects: * May signal event. * *------------------------------------------------------------------------- */ static void VMCINotifyHashReleaseEntry(VMCINotifyHashEntry *entry) // IN { VMCILockFlags flags; VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); entry->refCount--; /* * Check if this is last reference and signal the destroy event if * so. */ if (entry->refCount == 0) { VMCI_SignalEvent(&entry->destroyEvent); } VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); } /* *----------------------------------------------------------------------------- * * VMCINotifyHashFindByIdx -- * * Find hash entry by bitmap index. Assumes lock is * held. Regardless of whether an entry was found, the bucket that * the entry would have been in is returned in hashBucket (if * valid). * * Results: * Entry if found, NULL if not. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static VMCINotifyHashEntry * VMCINotifyHashFindByIdx(uint32 idx, // IN uint32 *hashBucket) // IN/OUT: hash value for idx { ListItem *iter; uint32 bucket = VMCI_NOTIF_HASH(idx); if (hashBucket) { *hashBucket = bucket; } LIST_SCAN(iter, vmciNotifyHT.entriesByIdx[bucket]) { VMCINotifyHashEntry *cur = LIST_CONTAINER(iter, VMCINotifyHashEntry, idxListItem); if (cur->idx == idx) { return cur; } } return NULL; } /* *----------------------------------------------------------------------------- * * VMCINotifyHashFindByHandle -- * * Find hash entry by handle and resoruce. Assumes lock is * held. Regardless of whether an entry was found, the bucket that * the entry would have been in is returned in hashBucket (if * valid). * * Results: * Entry if found, NULL if not. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static VMCINotifyHashEntry * VMCINotifyHashFindByHandle(VMCIHandle handle, // IN Bool doorbell, // IN uint32 *hashBucket) // IN/OUT: hash value for handle { ListItem *iter; uint32 bucket = VMCI_NOTIF_HASH(handle.resource); if (hashBucket) { *hashBucket = bucket; } LIST_SCAN(iter, vmciNotifyHT.entriesByHandle[bucket]) { VMCINotifyHashEntry *cur = LIST_CONTAINER(iter, VMCINotifyHashEntry, handleListItem); if (VMCI_HANDLE_EQUAL(cur->handle, handle) && cur->doorbell == doorbell) { return cur; } } return NULL; } /* *----------------------------------------------------------------------------- * * VMCINotifyDelayedDispatchCB -- * * Calls the specified callback in a delayed context. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void VMCINotifyDelayedDispatchCB(void *data) // IN { VMCINotifyHashEntry *entry = (VMCINotifyHashEntry *)data; ASSERT(data); entry->notifyCB(entry->callbackData); VMCINotifyHashReleaseEntry(entry); } /* *------------------------------------------------------------------------- * * VMCINotifyHashFireEntries -- * * 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 VMCINotifyHashFireEntries(uint32 notifyIdx) // IN { VMCILockFlags flags; ListItem *iter; int bucket = VMCI_NOTIF_HASH(notifyIdx); VMCI_GrabLock_BH(&vmciNotifyHT.lock, &flags); LIST_SCAN(iter, vmciNotifyHT.entriesByIdx[bucket]) { VMCINotifyHashEntry *cur = LIST_CONTAINER(iter, VMCINotifyHashEntry, idxListItem); if (cur->idx == notifyIdx && cur->notifyCB) { if (cur->runDelayed) { int err; cur->refCount++; err = VMCI_ScheduleDelayedWork(VMCINotifyDelayedDispatchCB, cur); if (err != VMCI_SUCCESS) { cur->refCount--; goto out; } } else { cur->notifyCB(cur->callbackData); } } } out: VMCI_ReleaseLock_BH(&vmciNotifyHT.lock, flags); } /* *---------------------------------------------------------------------- * * LinkNotificationHypercall -- * * 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 LinkNotificationHypercall(VMCIHandle handle, // IN Bool doorbell, // IN uint32 notifyIdx) // IN { VMCIDoorbellLinkMsg linkMsg; int result; VMCIId resourceID; ASSERT(!VMCI_HANDLE_INVALID(handle)); if (doorbell) { 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; result = VMCI_SendDatagram((VMCIDatagram *)&linkMsg); return result; } /* *---------------------------------------------------------------------- * * UnlinkNotificationHypercall -- * * 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 UnlinkNotificationHypercall(VMCIHandle handle, // IN Bool doorbell) // IN { VMCIDoorbellUnlinkMsg unlinkMsg; int result; VMCIId resourceID; ASSERT(!VMCI_HANDLE_INVALID(handle)); if (doorbell) { 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; result = VMCI_SendDatagram((VMCIDatagram *)&unlinkMsg); return result; } /* *----------------------------------------------------------------------------- * * VMCINotificationRegister -- * * Links a resource with an index in the notification bitmap. * * Results: * VMCI_SUCCESS on success, appropriate error code otherwise. * * Side effects: * Notification state is created both in guest and on host. * *----------------------------------------------------------------------------- */ int VMCINotificationRegister(VMCIHandle *handle, // IN Bool doorbell, // IN uint32 flags, // IN VMCICallback notifyCB, // IN void *callbackData) // IN { int result; VMCINotifyHashEntry *entry; if (!notifyCB || !handle) { return VMCI_ERROR_INVALID_ARGS; } entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_NONPAGED); if (entry == NULL) { return VMCI_ERROR_NO_MEM; } entry->runDelayed = (flags & VMCI_FLAG_DELAYED_CB) ? TRUE : FALSE; if (entry->runDelayed && !VMCI_CanScheduleDelayedWork()) { VMCI_FreeKernelMem(entry, sizeof *entry); return VMCI_ERROR_INVALID_ARGS; } /* * Reserve an index in the notification bitmap. */ entry->handle = *handle; entry->doorbell = doorbell; entry->notifyCB = NULL; // Wait with this until link is established in hypervisor entry->callbackData = callbackData; entry->refCount = 0; result = VMCINotifyHashAddEntry(entry); if (result != VMCI_SUCCESS) { VMCI_FreeKernelMem(entry, sizeof *entry); return result; } VMCI_CreateEvent(&entry->destroyEvent); result = LinkNotificationHypercall(entry->handle, doorbell, entry->idx); if (result != VMCI_SUCCESS) { VMCI_DEBUG_LOG(4, (LGPFX"Failed to link handle 0x%x:0x%x of resource %s " "to index (error: %d).\n", entry->handle.context, entry->handle.resource, entry->doorbell ? "doorbell" : "queue pair", result)); VMCINotifyHashRemoveEntry(entry->handle, entry->doorbell); VMCI_DestroyEvent(&entry->destroyEvent); VMCI_FreeKernelMem(entry, sizeof *entry); } else { /* * When the handle is set, the notification callback may start * to fire. Since flags in the notification bitmap can be * shared, a given callback may fire immediately. */ VMCINotifyHashSetEntryCallback(entry, notifyCB); *handle = entry->handle; } return result; } /* *----------------------------------------------------------------------------- * * VMCINotificationUnregister -- * * Unregisters a notification previously created through * VMCINotificationRegister. This function may block. The call * always succeeds if the notification exists. * * Results: * VMCI_SUCCESS if success, VMCI_ERROR_NOT_FOUND otherwise. * * Side effects: * Notification state is destroyed both in guest and hypervisor. * *----------------------------------------------------------------------------- */ int VMCINotificationUnregister(VMCIHandle handle, // IN Bool doorbell) // IN { VMCINotifyHashEntry *entry; int result; entry = VMCINotifyHashRemoveEntry(handle, doorbell); if (!entry) { return VMCI_ERROR_NOT_FOUND; } VMCI_WaitOnEvent(&entry->destroyEvent, VMCINotifyReleaseCB, entry); VMCI_DestroyEvent(&entry->destroyEvent); VMCI_FreeKernelMem(entry, sizeof *entry); result = UnlinkNotificationHypercall(handle, doorbell); if (result != VMCI_SUCCESS) { /* * 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", doorbell ? "doorbell" : "queuepair", handle.context, handle.resource, result)); } return VMCI_SUCCESS; } /* *----------------------------------------------------------------------------- * * VMCI_RegisterNotificationBitmap -- * * 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 the bitmap is registered successfully with the device, FALSE * otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ Bool VMCI_RegisterNotificationBitmap(PPN bitmapPPN) // IN { VMCINotifyBitmapSetMsg bitmapSetMsg; int result; 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"VMCINotifications: Failed to register PPN %u as " "notification bitmap (error: %d).\n", bitmapPPN, result)); return FALSE; } return TRUE; } /* *----------------------------------------------------------------------------- * * 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) // IN { size_t idx; for (idx = 0; idx < maxNotifyIdx; idx++) { if (bitmap[idx] & 0x1) { bitmap[idx] &= ~1; VMCINotifyHashFireEntries(idx); } } } /* *----------------------------------------------------------------------------- * * VMCIDoorbell_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 in interrupt context (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(VMCIDoorbell_Create) int VMCIDoorbell_Create(VMCIHandle *handle, // IN uint32 flags, // IN VMCIPrivilegeFlags privFlags, // IN: Unused in guest VMCICallback notifyCB, // IN void *clientData) // IN { if (!handle || !notifyCB || flags & ~VMCI_FLAG_DELAYED_CB) { return VMCI_ERROR_INVALID_ARGS; } if (privFlags & ~VMCI_LEAST_PRIVILEGE_FLAGS) { return VMCI_ERROR_NO_ACCESS; } return VMCINotificationRegister(handle, TRUE, flags, notifyCB, clientData); } /* *----------------------------------------------------------------------------- * * VMCIDoorbell_Destroy -- * * Destroys a doorbell previously created with * VMCIDoorbell_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(VMCIDoorbell_Destroy) int VMCIDoorbell_Destroy(VMCIHandle handle) // IN { if (VMCI_HANDLE_INVALID(handle)) { return VMCI_ERROR_INVALID_ARGS; } return VMCINotificationUnregister(handle, TRUE); } /* *----------------------------------------------------------------------------- * * VMCIDoorbell_Notify -- * * Generates a notification on the doorbell identified by the * handle. * * Results: * VMCI_SUCCESS on success, appropriate error code otherwise. * * Side effects: * May do a hypercall. * *----------------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCIDoorbell_Notify) int VMCIDoorbell_Notify(VMCIHandle handle, // IN VMCIPrivilegeFlags privFlags) // IN: Unused in guest { VMCIDoorbellNotifyMsg notifyMsg; int result; if (VMCI_HANDLE_INVALID(handle)) { return VMCI_ERROR_INVALID_ARGS; } if (privFlags & ~VMCI_LEAST_PRIVILEGE_FLAGS) { return VMCI_ERROR_NO_ACCESS; } 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; result = VMCI_SendDatagram((VMCIDatagram *)¬ifyMsg); return result; } #else // defined(SOLARIS) || defined(__APPLE__) /* *----------------------------------------------------------------------------- * * VMCIDoorbell_Create/VMCIDoorbell_Destroy/VMCIDoorbell_Notify -- * * 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, // I 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; } #endif vmci-only/vmciDatagram.h 0000444 0000000 0000000 00000003546 11573420371 014252 0 ustar root root /********************************************************* * 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 -- * * Simple Datagram API for the Linux guest driver. */ #ifndef __VMCI_DATAGRAM_H__ #define __VMCI_DATAGRAM_H__ #define INCLUDE_ALLOW_MODULE #include "includeCheck.h" #include "vmci_defs.h" #include "vmci_call_defs.h" #include "vmci_kernel_if.h" #include "vmci_infrastructure.h" #include "vmci_iocontrols.h" typedef struct DatagramQueueEntry DatagramQueueEntry; typedef struct VMCIDatagramProcess VMCIDatagramProcess; void VMCIDatagram_Init(void); void VMCIDatagram_Sync(void); Bool VMCIDatagram_CheckHostCapabilities(void); int VMCIDatagram_Dispatch(VMCIId contextID, VMCIDatagram *msg); int VMCIDatagramProcess_Create(VMCIDatagramProcess **outDgmProc, VMCIDatagramCreateProcessInfo *createInfo, uintptr_t eventHnd); void VMCIDatagramProcess_Destroy(VMCIDatagramProcess *dgmProc); int VMCIDatagramProcess_ReadCall(VMCIDatagramProcess *dgmProc, size_t maxSize, VMCIDatagram **dg); #endif //__VMCI_DATAGRAM_H__ vmci-only/vmci_drv.c 0000644 0000000 0000000 00000101041 11573420371 013446 0 ustar root root /********************************************************* * Copyright (C) 2005 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.c -- * * Linux guest driver for the VMCI device. */ #include "driver-config.h" #include <linux/moduleparam.h> #include <linux/poll.h> #include "compat_kernel.h" #include "compat_module.h" #include "compat_pci.h" #include "compat_init.h" #include "compat_ioport.h" #include "compat_interrupt.h" #include "compat_page.h" #include "compat_mutex.h" #include "vm_basic_types.h" #include "vm_device_version.h" #include "kernelStubs.h" #include "vmci_iocontrols.h" #include "vmci_defs.h" #include "vmciInt.h" #include "vmci_infrastructure.h" #include "vmciDatagram.h" #include "vmciProcess.h" #include "vmciUtil.h" #include "vmciEvent.h" #include "vmciNotifications.h" #include "vmciQueuePairInt.h" #include "vmci_version.h" #include "vmciCommonInt.h" #define LGPFX "VMCI: " #define VMCI_DEVICE_MINOR_NUM 0 /* 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 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; } vmci_device; 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 int vmci_open(struct inode *inode, struct file *file); static int vmci_close(struct inode *inode, struct file *file); static long vmci_ioctl(struct file *file, unsigned int cmd, unsigned long arg); #if !defined(HAVE_UNLOCKED_IOCTL) static int vmci_legacy_ioctl(struct inode *dummy, struct file *file, unsigned int cmd, unsigned long arg); #endif static unsigned int vmci_poll(struct file *file, poll_table *wait); #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); static const struct pci_device_id vmci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_VMCI), }, { 0 }, }; static struct file_operations vmci_ops = { .owner = THIS_MODULE, .open = vmci_open, .release = vmci_close, #ifdef HAVE_UNLOCKED_IOCTL .unlocked_ioctl = vmci_ioctl, #else .ioctl = vmci_legacy_ioctl, #endif #ifdef HAVE_COMPAT_IOCTL .compat_ioctl = vmci_ioctl, #endif .poll = vmci_poll, }; static struct pci_driver vmci_driver = { .name = "vmci", .id_table = vmci_ids, .probe = vmci_probe_device, .remove = __devexit_p(vmci_remove_device), }; static vmci_device vmci_dev; /* We dynamically request the device major number at init time. */ static int device_major_nr = 0; static int vmci_disable_msi; static int 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; /* *----------------------------------------------------------------------------- * * vmci_init -- * * Initialization, called by Linux when the module is loaded. * * Results: * Returns 0 for success, negative errno value otherwise. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int __init vmci_init(void) { int err; /* Initialize 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; data_buffer = vmalloc(data_buffer_size); if (!data_buffer) { return -ENOMEM; } /* Register device node ops. */ err = register_chrdev(0, "vmci", &vmci_ops); if (err < 0) { printk(KERN_ERR "Unable to register vmci device\n"); goto err_free_mem; } device_major_nr = err; printk("VMCI: Major device number is: %d\n", device_major_nr); /* This should be last to make sure we are done initializing. */ err = pci_register_driver(&vmci_driver); if (err < 0) { goto err_unregister_chrdev; } return 0; err_unregister_chrdev: unregister_chrdev(device_major_nr, "vmci"); err_free_mem: vfree(data_buffer); return err; } /* *----------------------------------------------------------------------------- * * vmci_exit -- * * Cleanup, called by Linux when the module is unloaded. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void __exit vmci_exit(void) { pci_unregister_driver(&vmci_driver); unregister_chrdev(device_major_nr, "vmci"); vfree(data_buffer); } /* *----------------------------------------------------------------------------- * * 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 __devinit 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 = compat_pci_enable_device(pdev); if (result) { printk(KERN_ERR "Cannot VMCI device %s: error %d\n", compat_pci_name(pdev), result); return result; } compat_pci_set_master(pdev); /* To enable QueuePair functionality. */ ioaddr = compat_pci_resource_start(pdev, 0); ioaddr_size = compat_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", compat_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; /* * 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 unlock; } } /* 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 for * event init. 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). */ VMCIProcess_Init(); VMCIDatagram_Init(); VMCIEvent_Init(); VMCIUtil_Init(); VMCINotifications_Init(); VMCIQueuePair_Init(); /* * 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"); 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: VMCIQueuePair_Exit(); VMCINotifications_Exit(); VMCIUtil_Exit(); VMCIEvent_Exit(); VMCIProcess_Exit(); 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); } unlock: compat_mutex_unlock(&vmci_dev.lock); release: if (notification_bitmap) { vfree(notification_bitmap); } release_region(ioaddr, ioaddr_size); pci_disable: compat_pci_disable_device(pdev); return -EBUSY; } /* *----------------------------------------------------------------------------- * * vmci_remove_device -- * * Cleanup, called for each device on unload. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static void __devexit vmci_remove_device(struct pci_dev* pdev) { struct vmci_device *dev = pci_get_drvdata(pdev); printk(KERN_INFO "Removing vmci device\n"); VMCIQueuePair_Exit(); // XXX Todo add exit/cleanup functions for util, sm, dg, and resource apis. VMCIUtil_Exit(); VMCIEvent_Exit(); //VMCIDatagram_Exit(); VMCIProcess_Exit(); compat_mutex_lock(&dev->lock); 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; VMCINotifications_Exit(); if (notification_bitmap) { vfree(notification_bitmap); } printk(KERN_INFO "Unregistered vmci device.\n"); compat_mutex_unlock(&dev->lock); compat_pci_disable_device(pdev); } /* *----------------------------------------------------------------------------- * * vmci_open -- * * Open device. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int vmci_open(struct inode *inode, // IN struct file *file) // IN { VMCIGuestDeviceHandle *devHndl; int errcode; printk(KERN_INFO "Opening vmci device\n"); if (MINOR(inode->i_rdev) != VMCI_DEVICE_MINOR_NUM) { return -ENODEV; } compat_mutex_lock(&vmci_dev.lock); if (!vmci_dev.enabled) { printk(KERN_INFO "Received open on uninitialized vmci device.\n"); errcode = -ENODEV; goto unlock; } /* Do open ... */ devHndl = VMCI_AllocKernelMem(sizeof *devHndl, VMCI_MEMORY_NORMAL); if (!devHndl) { printk(KERN_INFO "Failed to create device obj when opening device.\n"); errcode = -ENOMEM; goto unlock; } devHndl->obj = NULL; devHndl->objType = VMCIOBJ_NOT_SET; file->private_data = devHndl; compat_mutex_unlock(&vmci_dev.lock); return 0; unlock: compat_mutex_unlock(&vmci_dev.lock); return errcode; } /* *----------------------------------------------------------------------------- * * vmci_close -- * * Close device. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int vmci_close(struct inode *inode, // IN struct file *file) // IN { VMCIGuestDeviceHandle *devHndl = (VMCIGuestDeviceHandle *) file->private_data; if (devHndl) { if (devHndl->objType == VMCIOBJ_PROCESS) { VMCIProcess_Destroy((VMCIProcess *) devHndl->obj); } else if (devHndl->objType == VMCIOBJ_DATAGRAM_PROCESS) { VMCIDatagramProcess_Destroy((VMCIDatagramProcess *) devHndl->obj); } VMCI_FreeKernelMem(devHndl, sizeof *devHndl); file->private_data = NULL; } return 0; } /* *----------------------------------------------------------------------------- * * vmci_ioctl -- * * IOCTL interface to device. * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static long vmci_ioctl(struct file *file, // IN unsigned int cmd, // IN unsigned long arg) // IN { #ifndef VMX86_DEVEL return -ENOTTY; #else int retval; VMCIGuestDeviceHandle *devHndl = file->private_data; if (devHndl == NULL) { return -EINVAL; } compat_mutex_lock(&vmci_dev.lock); /* * When adding new ioctls make sure that their data structures are same * for i386 and x86_64 architectures, as this handler is used for both ia32 * and x86_64 ioctls. */ switch (cmd) { case IOCTL_VMCI_CREATE_PROCESS: { if (devHndl->objType != VMCIOBJ_NOT_SET) { printk("VMCI: Received IOCTLCMD_VMCI_CREATE_PROCESS on " "initialized handle.\n"); retval = -EINVAL; break; } ASSERT(!devHndl->obj); retval = VMCIProcess_Create((VMCIProcess **) &devHndl->obj); if (retval != 0) { printk("VMCI: Failed to create process.\n"); break; } devHndl->objType = VMCIOBJ_PROCESS; break; } case IOCTL_VMCI_CREATE_DATAGRAM_PROCESS: { VMCIDatagramCreateProcessInfo createInfo; VMCIDatagramProcess *dgmProc; if (devHndl->objType != VMCIOBJ_NOT_SET) { printk("VMCI: Received IOCTLCMD_VMCI_CREATE_DATAGRAM_PROCESS on " "initialized handle.\n"); retval = -EINVAL; break; } ASSERT(!devHndl->obj); retval = copy_from_user(&createInfo, (void *)arg, sizeof createInfo); if (retval != 0) { printk("VMCI: Error getting datagram create info, %d.\n", retval); retval = -EFAULT; break; } if (VMCIDatagramProcess_Create(&dgmProc, &createInfo, 0 /* Unused */) < VMCI_SUCCESS) { retval = -EINVAL; break; } retval = copy_to_user((void *)arg, &createInfo, sizeof createInfo); if (retval != 0) { VMCIDatagramProcess_Destroy(dgmProc); printk("VMCI: Failed to create datagram process.\n"); retval = -EFAULT; break; } devHndl->obj = dgmProc; devHndl->objType = VMCIOBJ_DATAGRAM_PROCESS; break; } case IOCTL_VMCI_DATAGRAM_SEND: { VMCIDatagramSendRecvInfo sendInfo; VMCIDatagram *dg; if (devHndl->objType != VMCIOBJ_DATAGRAM_PROCESS) { printk("VMCI: Ioctl %d only valid for process datagram handle.\n", cmd); retval = -EINVAL; break; } retval = copy_from_user(&sendInfo, (void *) arg, sizeof sendInfo); if (retval) { printk("VMCI: copy_from_user failed.\n"); retval = -EFAULT; break; } if (sendInfo.len > VMCI_MAX_DG_SIZE) { printk("VMCI: datagram size too big.\n"); retval = -EINVAL; break; } dg = VMCI_AllocKernelMem(sendInfo.len, VMCI_MEMORY_NORMAL); if (dg == NULL) { printk("VMCI: Cannot allocate memory to dispatch datagram.\n"); retval = -ENOMEM; break; } retval = copy_from_user(dg, (char *)(VA)sendInfo.addr, sendInfo.len); if (retval != 0) { printk("VMCI: Error getting datagram: %d\n", retval); VMCI_FreeKernelMem(dg, sendInfo.len); retval = -EFAULT; break; } DEBUG_ONLY(printk("VMCI: Datagram dst handle 0x%x:0x%x, src handle " "0x%x:0x%x, payload size %"FMT64"u.\n", dg->dst.context, dg->dst.resource, dg->src.context, dg->src.resource, dg->payloadSize)); sendInfo.result = VMCIDatagram_Send(dg); VMCI_FreeKernelMem(dg, sendInfo.len); retval = copy_to_user((void *)arg, &sendInfo, sizeof sendInfo); break; } case IOCTL_VMCI_DATAGRAM_RECEIVE: { VMCIDatagramSendRecvInfo recvInfo; VMCIDatagram *dg = NULL; if (devHndl->objType != VMCIOBJ_DATAGRAM_PROCESS) { printk("VMCI: Ioctl %d only valid for process datagram handle.\n", cmd); retval = -EINVAL; break; } retval = copy_from_user(&recvInfo, (void *) arg, sizeof recvInfo); if (retval) { printk("VMCI: copy_from_user failed.\n"); retval = -EFAULT; break; } ASSERT(devHndl->obj); recvInfo.result = VMCIDatagramProcess_ReadCall((VMCIDatagramProcess *)devHndl->obj, recvInfo.len, &dg); if (recvInfo.result < VMCI_SUCCESS) { retval = -EINVAL; break; } 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 *)arg, &recvInfo, sizeof recvInfo); break; } case IOCTL_VMCI_GET_CONTEXT_ID: { VMCIId cid = VMCI_GetContextID(); retval = copy_to_user((void *)arg, &cid, sizeof cid); break; } default: printk(KERN_DEBUG "vmci_ioctl(): unknown ioctl 0x%x.\n", cmd); retval = -EINVAL; break; } compat_mutex_unlock(&vmci_dev.lock); return retval; #endif } #if !defined(HAVE_UNLOCKED_IOCTL) /* *----------------------------------------------------------------------------- * * vmci_legacy_ioctl -- * * IOCTL interface for kernels that do not have unlocked_ioctl. * * Results: * Negative error code, or per-ioctl result. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static int vmci_legacy_ioctl(struct inode *inode, // IN: unused struct file *filp, // IN: u_int iocmd, // IN: unsigned long ioarg) // IN: { return vmci_ioctl(filp, iocmd, ioarg); } #endif /* *----------------------------------------------------------------------------- * * vmci_poll -- * * vmci poll function * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ static unsigned int vmci_poll(struct file *file, // IN poll_table *wait) // IN { VMCILockFlags flags; unsigned int mask = 0; VMCIGuestDeviceHandle *devHndl = (VMCIGuestDeviceHandle *) file->private_data; /* * Check for call to this VMCI process. */ if (!devHndl) { return mask; } if (devHndl->objType == VMCIOBJ_DATAGRAM_PROCESS) { VMCIDatagramProcess *dgmProc = (VMCIDatagramProcess *) devHndl->obj; ASSERT(dgmProc); if (wait != NULL) { poll_wait(file, &dgmProc->host.waitQueue, wait); } VMCI_GrabLock_BH(&dgmProc->datagramQueueLock, &flags); if (dgmProc->pendingDatagrams > 0) { mask = POLLIN; } VMCI_ReleaseLock_BH(&dgmProc->datagramQueueLock, flags); } return mask; } /* *----------------------------------------------------------------------------- * * 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) { Bool retval; compat_mutex_lock(&vmci_dev.lock); retval = vmci_dev.enabled; compat_mutex_unlock(&vmci_dev.lock); return retval; } /* *----------------------------------------------------------------------------- * * 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; } /* * 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); } module_init(vmci_init); module_exit(vmci_exit); MODULE_DEVICE_TABLE(pci, vmci_ids); 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 information. */ MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface"); 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"); vmci-only/vmciUtil.c 0000444 0000000 0000000 00000040513 11573420371 013435 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciUtil.c * * Small utility function for allocating kernel memory and copying data. * */ #ifdef __linux__ # include "driver-config.h" # define EXPORT_SYMTAB # include <linux/module.h> # include "compat_kernel.h" # include "compat_slab.h" # include "compat_interrupt.h" #elif defined(_WIN32) # ifndef WINNT_DDK # error This file only works with the NT ddk # endif // WINNT_DDK # include <ntddk.h> #elif defined(SOLARIS) # include <sys/ddi.h> # include <sys/sunddi.h> # include <sys/disp.h> #elif defined(__APPLE__) # include <IOKit/IOLib.h> #else #error "platform not supported." #endif //linux #define LGPFX "VMCIUtil: " #include "vmware.h" #include "vm_atomic.h" #include "vmci_defs.h" #include "vmci_kernel_if.h" #include "vmciGuestKernelIf.h" #include "vmciInt.h" #include "vmciProcess.h" #include "vmciDatagram.h" #include "vmciUtil.h" #include "vmciEvent.h" #include "vmciKernelAPI.h" static void VMCIUtilCidUpdate(VMCIId subID, VMCI_EventData *eventData, void *clientData); static VMCIId ctxUpdateSubID = VMCI_INVALID_ID; static Atomic_uint32 vmContextID = { VMCI_INVALID_ID }; static Atomic_uint32 vmciClientCount; /* *----------------------------------------------------------------------------- * * 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 (VMCIEvent_Subscribe(VMCI_EVENT_CTX_ID_UPDATE, VMCI_FLAG_EVENT_NONE, VMCIUtilCidUpdate, NULL, &ctxUpdateSubID) < VMCI_SUCCESS) { VMCI_WARNING((LGPFX"Failed to subscribe to event %d.\n", VMCI_EVENT_CTX_ID_UPDATE)); } } /* *----------------------------------------------------------------------------- * * VMCIUtil_Exit -- * * Cleanup * * Results: * None. * * Side effects: * None. * *----------------------------------------------------------------------------- */ void VMCIUtil_Exit(void) { if (VMCIEvent_Unsubscribe(ctxUpdateSubID) < VMCI_SUCCESS) { VMCI_WARNING((LGPFX"Failed to unsubscribe to event %d with " "subscriber id %d.\n", VMCI_EVENT_CTX_ID_UPDATE, ctxUpdateSubID)); } } /* *----------------------------------------------------------------------------- * * 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_WARNING((LGPFX"Invalid subscriber id. %d.\n", subID)); return; } if (eventData == NULL || evPayload->contextID == VMCI_INVALID_ID) { VMCI_WARNING((LGPFX"Invalid event data.\n")); return; } VMCI_LOG((LGPFX"Updating context id from 0x%x to 0x%x on event %d.\n", Atomic_Read(&vmContextID), evPayload->contextID, eventData->event)); Atomic_Write(&vmContextID, evPayload->contextID); } /* *----------------------------------------------------------------------------- * * 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 Bool VMCIUtil_CheckHostCapabilities(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_GetContextID -- * * Returns the context id. * * Results: * Context id. * * Side effects: * None. * *----------------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCI_GetContextID) VMCIId VMCI_GetContextID(void) { 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); } /* *----------------------------------------------------------------------------- * * 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 &= VMCIProcess_CheckHostCapabilities(); result &= VMCIDatagram_CheckHostCapabilities(); result &= VMCIUtil_CheckHostCapabilities(); VMCI_LOG((LGPFX"Host capability check: %s\n", result ? "PASSED" : "FAILED")); return result; } /* *---------------------------------------------------------------------- * * VMCI_Version -- * * Returns the version of the VMCI guest driver. * * Results: * Returns a version number. * * Side effects: * None. * *---------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCI_Version) uint32 VMCI_Version() { return VMCI_VERSION_NUMBER; } /* *---------------------------------------------------------------------- * * VMCI_InInterrupt -- * * Determines if we are running in tasklet/dispatch level or above. * * Results: * TRUE if tasklet/dispatch or above, FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ Bool VMCI_InInterrupt() { #if defined(_WIN32) return KeGetCurrentIrql() >= DISPATCH_LEVEL; #elif defined(__linux__) return in_interrupt(); #elif defined(SOLARIS) return servicing_interrupt(); /* servicing_interrupt is not part of DDI. */ #elif defined(__APPLE__) /* * All interrupt servicing is handled by IOKit functions, by the time the IOService * interrupt handler is called we're no longer in an interrupt dispatch level. */ return false; #endif // } /* *---------------------------------------------------------------------- * * VMCI_DeviceGet -- * * 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_DeviceGet) Bool VMCI_DeviceGet(uint32 *apiVersion) { Atomic_Inc32(&vmciClientCount); if (*apiVersion > VMCI_KERNEL_API_VERSION) { *apiVersion = VMCI_KERNEL_API_VERSION; goto release; } if (!VMCI_DeviceEnabled()) { goto release; } if (VMCI_DeviceShutdown()) { goto release; } return TRUE; release: Atomic_Dec32(&vmciClientCount); return FALSE; } /* *---------------------------------------------------------------------- * * VMCI_DeviceRelease -- * * Indicates that the caller is done using the VMCI device. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCI_DeviceRelease) void VMCI_DeviceRelease(void) { Atomic_Dec32(&vmciClientCount); } /* *---------------------------------------------------------------------- * * VMCI_DeviceInUse -- * * Report whether the device is in-use by a client. * * Results: * TRUE if the device is in-use (reference count greater than zero), * FALSE otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ Bool VMCI_DeviceInUse(void) { return Atomic_Read32(&vmciClientCount) > 0 ? TRUE : FALSE; } /* *---------------------------------------------------------------------- * * 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_Dispatch(dg->src.context, dg); } if (result < VMCI_SUCCESS) { VMCI_DEBUG_LOG(4, (LGPFX"Datagram with resource %d failed with " "err %x.\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 of size %u.\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; } } } /* *---------------------------------------------------------------------- * * VMCIContext_GetPrivFlags -- * * Provided for compatibility with the host VMCI API. * * Results: * Always returns VMCI_NO_PRIVILEGE_FLAGS. * * Side effects: * None. * *---------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCIContext_GetPrivFlags) VMCIPrivilegeFlags VMCIContext_GetPrivFlags(VMCIId contextID) // IN { return VMCI_NO_PRIVILEGE_FLAGS; } /* *---------------------------------------------------------------------- * * VMCI_ContextID2HostVmID -- * * Provided for compatibility with the host VMCI API. * * Results: * Returns VMCI_ERROR_UNAVAILABLE. * * Side effects: * None. * *---------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCI_ContextID2HostVmID) int VMCI_ContextID2HostVmID(VMCIId contextID, // IN void *hostVmID, // OUT size_t hostVmIDLen) // IN { return VMCI_ERROR_UNAVAILABLE; } vmci-only/vmciGuestDs.c 0000444 0000000 0000000 00000015674 11573420371 014110 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmciGuestDs.c * * Implements the client-access API to the VMCI discovery service in * the guest kernel. * */ #ifdef __linux__ # include "driver-config.h" # define EXPORT_SYMTAB # include <linux/module.h> # include "compat_kernel.h" # include "compat_pci.h" #elif defined(_WIN32) # include <ntddk.h> #elif defined(SOLARIS) # include <sys/ddi.h> # include <sys/sunddi.h> #elif defined(__APPLE__) # include <IOKit/IOLib.h> #else # error "Platform not support by VMCI datagram API." #endif // linux #include "vm_basic_types.h" #include "vm_atomic.h" #include "vm_assert.h" #include "vmci_defs.h" #include "vmci_kernel_if.h" #include "vmci_infrastructure.h" #include "vmciInt.h" #include "vmciUtil.h" #include "vmciDatagram.h" #include "vmciKernelAPI.h" static Atomic_uint32 MsgIdCounter = { 0 }; typedef struct VMCIDsRecvData { VMCIHost context; VMCILock lock; int status; uint8 buffer[VMCI_DS_MAX_MSG_SIZE]; } VMCIDsRecvData; static int VMCIDsDoCall(int action, const char *name, VMCIHandle handle, VMCIHandle *handleOut); static int VMCIDsRecvCB(void *clientData, struct VMCIDatagram *msg); /* *------------------------------------------------------------------------- * * VMCIDs_Lookup -- * * Look up a handle in the VMCI discovery service based on * the given name. * * Results: * Error code. 0 if success. * * Side effects: * None. * *------------------------------------------------------------------------- */ VMCI_EXPORT_SYMBOL(VMCIDs_Lookup) int VMCIDs_Lookup(const char *name, // IN VMCIHandle *out) // { return VMCIDsDoCall(VMCI_DS_ACTION_LOOKUP, name, VMCI_INVALID_HANDLE, out); } /* *------------------------------------------------------------------------- * * VMCIDsDoCall -- * * Serialize a call into the CDS wire-format, send it across * the VMCI device, wait for a response, and return * the results. * * Results: * Error code. 0 if success. * * Side effects: * None. * *------------------------------------------------------------------------- */ static int VMCIDsDoCall(int action, // IN const char *name, // IN VMCIHandle handle, // IN: For the "register" action VMCIHandle *handleOut) // OUT: For the "lookup" action { int8 *sendBuffer = NULL; const size_t sendBufferSize = VMCI_DS_MAX_MSG_SIZE + sizeof(VMCIDatagram); int nameLen, requestSize, res; uint32 savedMsgIdCounter; VMCIDsReplyHeader *reply; VMCIHandle dsHandle = VMCI_INVALID_HANDLE; VMCIDsRecvData *recvData = NULL; VMCIDatagram *dgram; VMCIDsRequestHeader *request; VMCILockFlags flags; nameLen = strlen(name); if (nameLen + sizeof *request > sendBufferSize) { res = VMCI_ERROR_INVALID_ARGS; goto out; } sendBuffer = VMCI_AllocKernelMem(sendBufferSize, VMCI_MEMORY_NONPAGED); if (sendBuffer == NULL) { res = VMCI_ERROR_NO_MEM; goto out; } recvData = VMCI_AllocKernelMem(sizeof *recvData, VMCI_MEMORY_NONPAGED); if (recvData == NULL) { res = VMCI_ERROR_NO_MEM; goto out; } VMCIHost_InitContext(&recvData->context, (uintptr_t) recvData); VMCI_InitLock(&recvData->lock, "VMCIDsRecvHandler", VMCI_LOCK_RANK_MIDDLE_BH); savedMsgIdCounter = Atomic_FetchAndInc(&MsgIdCounter); dgram = (VMCIDatagram *) sendBuffer; request = (VMCIDsRequestHeader *) (sendBuffer + sizeof *dgram); /* Serialize request. */ request->action = action; request->msgid = savedMsgIdCounter; request->handle = handle; request->nameLen = nameLen; memcpy(request->name, name, nameLen + 1); requestSize = sizeof *request + nameLen; if (VMCIDatagram_CreateHnd(VMCI_INVALID_ID, 0, VMCIDsRecvCB, recvData, &dsHandle) != VMCI_SUCCESS) { res = VMCI_ERROR_NO_HANDLE; goto out; } dgram->dst = VMCI_DS_HANDLE; dgram->src = dsHandle; dgram->payloadSize = requestSize; /* Send the datagram to CDS. */ res = VMCIDatagram_Send(dgram); if (res <= 0) { goto out; } /* Block here waiting for the reply */ VMCI_GrabLock_BH(&recvData->lock, &flags); VMCIHost_WaitForCallLocked(&recvData->context, &recvData->lock, &flags, TRUE); VMCI_ReleaseLock_BH(&recvData->lock, flags); if (recvData->status != VMCI_SUCCESS) { res = recvData->status; goto out; } reply = (VMCIDsReplyHeader *) recvData->buffer; /* Check that the msgid matches what we expect. */ if (reply->msgid != savedMsgIdCounter) { res = VMCI_ERROR_GENERIC; goto out; } if (handleOut != NULL) { *handleOut = reply->handle; } res = reply->code; out: if (!VMCI_HANDLE_EQUAL(dsHandle, VMCI_INVALID_HANDLE)) { VMCIDatagram_DestroyHnd(dsHandle); } if (recvData) { VMCI_CleanupLock(&recvData->lock); VMCIHost_ReleaseContext(&recvData->context); VMCI_FreeKernelMem(recvData, sizeof *recvData); } if (sendBuffer) { VMCI_FreeKernelMem(sendBuffer, sendBufferSize); } return res; } /* *----------------------------------------------------------------------------- * * VMCIDsRecvCB -- * * Receive callback for the Discovery Service query datagram * handle. * * Results: * If the received payload is not larger than the MAX, it is * copied into clientData. * * Side effects: * Signals the thread waiting for the reply. * *----------------------------------------------------------------------------- */ static int VMCIDsRecvCB(void *clientData, // IN: client data for handler struct VMCIDatagram *msg) // IN { VMCIDsRecvData *recvData = clientData; VMCILockFlags flags; ASSERT(msg->payloadSize <= VMCI_DS_MAX_MSG_SIZE); if (msg->payloadSize <= VMCI_DS_MAX_MSG_SIZE) { memcpy(recvData->buffer, VMCI_DG_PAYLOAD(msg), (size_t)msg->payloadSize); recvData->status = VMCI_SUCCESS; } else { recvData->status = VMCI_ERROR_PAYLOAD_TOO_LARGE; } VMCI_GrabLock_BH(&recvData->lock, &flags); VMCIHost_SignalCall(&recvData->context); VMCI_ReleaseLock_BH(&recvData->lock, flags); return 0; } vmci-only/vmci_version.h 0000444 0000000 0000000 00000002200 11573420371 014340 0 ustar root root /********************************************************* * 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 * *********************************************************/ /* * vmci_version.h -- * * Version definitions for the Linux vmci driver. */ #ifndef _VMCI_VERSION_H_ #define _VMCI_VERSION_H_ #define VMCI_DRIVER_VERSION 9.0.3.0 #define VMCI_DRIVER_VERSION_COMMAS 9,0,3,0 #define VMCI_DRIVER_VERSION_STRING "9.0.3.0" #endif /* _VMCI_VERSION_H_ */