/* **********************************************************
 * Copyright 1998 - 2009 VMware, Inc.  All rights reserved.
 * **********************************************************/

/*
 * @VMKAPIMOD_LICENSE@
 */

/*
 ***********************************************************************
 * Module                                                         */ /**
 * \defgroup Module Kernel Module Management
 *
 * @{
 ***********************************************************************
 */

#ifndef _VMKAPI_MODULE_H_
#define _VMKAPI_MODULE_H_

/** \cond never */
#ifndef VMK_HEADER_INCLUDED_FROM_VMKAPI_H
#error This vmkapi file should never be included directly but only via vmkapi.h
#endif
/** \endcond never */

#include "vmkapi_module_int.h"
#include "vmkapi_module_ns.h"

/**
 * \brief Module stack element.
 */
typedef struct vmk_ModInfoStack {
   /** \brief Module ID. */
   vmk_ModuleID modID;

   /** \brief Module function called. */
   void     *mod_fn;

   /** \brief Return address of caller. */
   void     *pushRA;

   /** \brief Next module stack element. */
   struct vmk_ModInfoStack *oldStack;
} vmk_ModInfoStack;

/**
 * \brief Guaranteed invalid module ID.
 */
#define VMK_INVALID_MODULE_ID    ((vmk_uint32)-1)

/**
 * \brief Module ID for vmkernel itself.
 */
#define VMK_VMKERNEL_MODULE_ID   0

/**
 * \brief VMware proprietary code
 */
#define VMK_MODULE_LICENSE_VMWARE	"VMware"
/**
 * \brief GPLv2
 */
#define VMK_MODULE_LICENSE_GPLV2	"GPLv2"
/**
 * \brief BSD compatibile license
 */
#define VMK_MODULE_LICENSE_BSD		"BSD"

/*
 ***********************************************************************
 * VMK_MODPARAM_NAMED --                                          */ /**
 *
 * \ingroup Module
 *
 * \brief Define a parameter set by the user during module load.
 *
 * \param[in] name   Name of the parameter.
 * \param[in] var    Name of variable to store parameter value.
 * \param[in] type   Type of the variable.
 * \param[in] desc   String describing the variable.
 *
 ***********************************************************************
 */
#define VMK_MODPARAM_NAMED(name, var, type, desc)	\
   __VMK_MODPARAM_NAMED(name, var, type);		\
   __VMK_MODPARAM_DESC(name, desc)

/*
 ***********************************************************************
 * VMK_MODPARAM --                                                */ /**
 *
 * \ingroup Module
 * \brief Define a parameter set by the user during module load.
 *
 * \note This macro relies on having a variable with the same name
 *       as the parameter.  If your variable has a different name
 *       than the parameter name, use VMK_MODPARAM_NAMED.
 *
 * \param[in] name   Name of the parameter and variable.
 * \param[in] type   Type of the variable.
 * \param[in] desc   String describing the variable.
 *
 ***********************************************************************
 */
#define VMK_MODPARAM(name, type, desc) \
   VMK_MODPARAM_NAMED(name, name, type, desc)

/*
 ***********************************************************************
 * VMK_MODPARAM_ARRAY_NAMED --                                    */ /**
 *
 * \ingroup Module
 *
 * \brief Define an array parameter that can be set by the user during
 *        module load.
 *
 * \param[in] name   Name of parameter.
 * \param[in] var    Name of array variable.
 * \param[in] type   Type of array elements.
 * \param[in] nump   Variable to store count of set elements.
 * \param[in] desc   String describing the variable.
 *
 ***********************************************************************
 */
#define VMK_MODPARAM_ARRAY_NAMED(name, var, type, nump, desc)	\
  __VMK_MODPARAM_ARRAY_NAMED(name, var, type, nump);	        \
  __VMK_MODPARAM_DESC(name, desc)

/*
 ***********************************************************************
 * VMK_MODPARAM_ARRAY --                                          */ /**
 *
 * \ingroup Module
 *
 * \brief Define an array parameter that can be set by the user during
 *        module load.
 *
 * \note This macro relies on having a variable with the same name
 *       as the parameter. If your variable has a different name
 *       than the parameter name, use VMK_MODPARAM_NAMED.
 *
 * \param[in] name   Name of parameter and variable.
 * \param[in] type   Type of array elements.
 * \param[in] nump   Variable to store count of set elements.
 * \param[in] desc   String describing the variable.
 *
 ***********************************************************************
 */
#define VMK_MODPARAM_ARRAY(name, type, nump, desc) \
     VMK_MODPARAM_ARRAY_NAMED(name, name, type, nump, desc)

/*
 ***********************************************************************
 * VMK_MODPARAM_STRING_NAMED --                                   */ /**
 *
 * \ingroup Module
 * \brief Define an string parameter that can be set by the user
 *        during module load.
 *
 * \note This creates a copy of the string; your variable must be an
 *       array of sufficient size to hold the copy.  If you do not
 *       need to modify the string consider using a charp type.
 *
 * \param[in] name      Name of parameter.
 * \param[in] string    Variable name for the string copy.
 * \param[in] len       Maximum length of string.
 * \param[in] desc      String describing the variable.
 *
 ***********************************************************************
 */
#define VMK_MODPARAM_STRING_NAMED(name, string, len, desc)	\
   __VMK_MODPARAM_STRING_NAMED(name, string, len);		\
   __VMK_MODPARAM_DESC(name, desc)

/*
 ***********************************************************************
 * VMK_MODPARAM_STRING --                                         */ /**
 *
 * \ingroup Module
 * \brief Define an string parameter that can be set by the user
 *        during module load.
 *
 * \note This creates a copy of the string; your variable must be an
 *       array of sufficient size to hold the copy.  If you do not
 *       need to modify the string consider using a charp type.
 *
 * \param[in] name   Name of parameter and char array variable.
 * \param[in] len    Maximum length of string.
 * \param[in] desc   String describing the variable.
 *
 ***********************************************************************
 */
#define VMK_MODPARAM_STRING(name, len, desc) \
   VMK_MODPARAM_STRING_NAMED(name, name, len, desc)

/*
 ***********************************************************************
 * VMK_VERSION_INFO --                                            */ /**
 *
 * \ingroup Module
 * \brief Free-form string parameter describing version, build,
 *        etc. information.
 *
 * \param[in] string    A string to be embedded as version information.
 *
 ***********************************************************************
 */
#define VMK_VERSION_INFO(string) \
   __VMK_VERSION_INFO(string)

/*
 ***********************************************************************
 * VMK_LICENSE_INFO --                                            */ /**
 *
 * \ingroup Module
 * \brief A predefined string describing the license this module is
 *        released under.
 *
 * This macro adds a license string to the module. The license string
 * determines symbol binding rules. For instance, a module released under
 * a non-GPL license can only bind to symbols exported by non-GPL modules,
 * but it can not bind to symbols provided by GPL modules. A module
 * released under a GPL license can bind to symbols exported by GPL and
 * non-GPL modules.
 *
 * \note This macro should only be used if you release your code under
 *       a license described by the predefined license strings such as
 *       VMK_MODULE_LICENSE_*, otherwise please use macro
 *       VMK_THIRD_PARTY_LICENSE_INFO.
 *
 * \param[in] string  A string to be embedded as the license type. Only
 *                    the predefined license strings such as
 *                    VMK_MODULE_LICENSE_* are acceptable. The use of
 *                    other license strings may cause the module to
 *                    fail to load.
 *
 ***********************************************************************
 */
#define VMK_LICENSE_INFO(string) \
   __VMK_LICENSE_INFO(string)

/*
 ***********************************************************************
 * VMK_THIRD_PARTY_LICENSE_INFO --                                */ /**
 *
 * \ingroup Module
 * \brief A string describing the license this module is released
 *        under.
 *
 * This macro adds a license string to the module. The license string
 * determines symbol binding rules. A module released under a third
 * party license can only bind to symbols exported by non-GPL modules.
 *
 * \note This macro should be used if you release your code under
 *       a license that is not covered by the predefined license strings
 *       such as VMK_MODULE_LICENSE_*, e.g., under your company's
 *       license.
 *
 * \note This macro accepts any provided string as a valid license
 *       string, in contrast to macro VMK_LICENSE_INFO which only
 *       accepts predefined license strings.
 *
 * \param[in] string  A string to be embedded as the license type. The
 *                    predefined license strings as VMK_MODULE_LICENSE_*
 *                    should not be used with this macro.
 *
 ***********************************************************************
 */
#define VMK_THIRD_PARTY_LICENSE_INFO(string) \
   __VMK_LICENSE_INFO(__VMK_MODULE_LICENSE_THIRD_PARTY ":" string)

/*
 ***********************************************************************
 * vmk_ModuleRegister --                                          */ /**
 *
 * \ingroup Module
 * \brief Register a module with the VMKernel
 *
 * \pre The module shall not call any VMKernel function before this
 *      function has been invoked and has returned.
 *
 * \note A module should make a successful call to this function only
 *       once inside its initalization function, else undefined
 *       behavior may occur.
 *
 * \note  This function may block.
 *
 * \param[out] id                The address of a variable to store
 *                               the module's module ID handle.
 * \param[in] vmkApiModRevision  The module version for compatability
 *                               checks.
 *
 ***********************************************************************
 */
VMK_ReturnStatus vmk_ModuleRegister(
   vmk_ModuleID *id,
   vmk_uint32 vmkApiModRevision);

/*
 ***********************************************************************
 * vmk_ModuleUnregister --                                        */ /**
 *
 * \ingroup Module
 * \brief Unregister a module with the VMKernel
 *
 * \pre The module shall not have any VMKernel call in progress at
 *      the time this function is invoked, nor initiate any VMKernel
 *      call after it has been invoked.
 *
 * \note The module ID handle will be invalid after the success of
 *       this call and should not be used again.
 *
 * \note  This function may block.
 *
 * \param[in] id  The module ID handle to unregister.
 *
 ***********************************************************************
 */
VMK_ReturnStatus vmk_ModuleUnregister(
   vmk_ModuleID id);

/*
 ***********************************************************************
 * vmk_ModuleSetHeapID --                                         */ /**
 *
 * \ingroup Module
 * \brief Set a module's default heap
 *
 * Any vmkapi call that does not take an explicit heap that also has
 * a side effect of allocating storage will use the heap passed to this
 * function.
 *
 * \note  This function will not block.
 *
 * \pre The default heap may only be assigned once.  Subsequent
 *      assignments will be ignored.
 *
 ***********************************************************************
 */
void vmk_ModuleSetHeapID(
   vmk_ModuleID module,
   vmk_HeapID heap);

/*
 ***********************************************************************
 * vmk_ModuleGetHeapID --                                         */ /**
 *
 * \ingroup Module
 * \brief Query a module's default heap
 *
 * \note  This function will not block.
 *
 * \return The calling module's current default heap.
 * \retval VMK_INVALID_HEAP_ID The module has no default heap.
 *
 ***********************************************************************
 */
vmk_HeapID vmk_ModuleGetHeapID(
   vmk_ModuleID module);

/*
 ***********************************************************************
 * vmk_ModuleGetID --                                             */ /**
 *
 * \ingroup Module
 * \brief Get the identifier of the VMKernel module
 *
 * \note  This function will not block.
 *
 * \param[in] moduleName   Name of the module to find.
 *
 * \return The module ID of the module with the specified name.
 * \retval VMK_INVALID_MODULE_ID    No module with the specified name
 *                                  was found.
 *
 ***********************************************************************
 */
vmk_ModuleID vmk_ModuleGetID(
   const char *moduleName);


/*
 ***********************************************************************
 * vmk_ModuleGetName --                                           */ /**
 *
 * \ingroup Module
 * \brief Get the name associated with a module.
 *
 * \note  This function will not block.
 *
 * \note This call will return an error when called to retrieve the
 *       name of a module that has not yet returned from the module
 *       init function.
 *
 * \param[in]  module      The module ID to query.
 * \param[out] moduleName  A character buffer large enough to hold the
 *                         module name including the terminating nul.
 * \param[in]  len         The length of the character buffer in bytes.
 *
 * \retval VMK_NOT_FOUND   The module ID was not found.
 * \retval VMK_BAD_PARAM   The buffer isn't large enough to hold
 *                         the module's string name.
 *
 ***********************************************************************
 */
VMK_ReturnStatus vmk_ModuleGetName(
   vmk_ModuleID module,
   char *moduleName,
   vmk_ByteCountSmall len);

/*
 ***********************************************************************
 * vmk_ModuleGetDebugID --                                        */ /**
 *
 * \ingroup Module
 * \brief Convert a vmk_ModuleID to a 64-bit integer representation.
 *        This should not be used be used for anything other than a
 *        short-hand in debugging output.
 *
 * \note  This function will not block.
 *
 * \param[in] module    The module id.
 *
 ***********************************************************************
 */
vmk_uint64 vmk_ModuleGetDebugID(vmk_ModuleID module);

/*
 ***********************************************************************
 * vmk_ModuleIncUseCount --                                       */ /**
 *
 * \ingroup Module
 * \brief Increment a module's reference count
 *
 * \note  This function will not block.
 *
 * Any attempt to remove the module with \c vmkload_mod -u will fail
 * while the module's reference count is non nul.
 *
 * \param[in] module    Module to increment the reference count for.
 *
 * \retval VMK_OK                   The reference count was successfully
 *                                  incremented
 * \retval VMK_NOT_FOUND            The module doesn't exist
 * \retval VMK_MODULE_NOT_LOADED    The module is being unloaded
 *
 ***********************************************************************
 */
VMK_ReturnStatus vmk_ModuleIncUseCount(
   vmk_ModuleID module);

/*
 ***********************************************************************
 * vmk_ModuleDecUseCount --                                       */ /**
 *
 * \ingroup Module
 * \brief Decrement a module's reference count.
 *
 * \note  This function will not block.
 *
 * \param[in] module    Module to decrement the reference count for.
 *
 * \retval VMK_OK                   The reference count was successfully
 *                                  decremented.
 * \retval VMK_NOT_FOUND            The module doesn't exist.
 * \retval VMK_MODULE_NOT_LOADED    The module is being unloaded.
 *
 ***********************************************************************
 */
VMK_ReturnStatus vmk_ModuleDecUseCount(
   vmk_ModuleID module);

/*
 ***********************************************************************
 * vmk_ModulePushId --                                            */ /**
 *
 * \ingroup Module
 * \brief Push moduleID onto module tracking stack before an
 *        inter-module call.
 *
 * \note  This function will not block.
 *
 * \deprecated This call should no longer be called directly as it is
 *             likely to go away in a future release.
 *
 * \param[in] moduleID     Module ID from which the inter-module call
 *                         is to be made.
 * \param[in] function     Address of the inter-module function call
 * \param[in] modStack     Pointer to a vmk_ModInfoStack struct,
 *                         preferrably on the stack.
 *
 * \retval VMK_OK                   The moduleID was sucessfully pushed
 *                                  onto the module stack
 * \retval VMK_MODULE_NOT_LOADED    Module was not found
 *
 ***********************************************************************
 */
VMK_ReturnStatus vmk_ModulePushId(
    vmk_ModuleID moduleID,
    void *function,
    vmk_ModInfoStack *modStack);

/*
 ***********************************************************************
 * vmk_ModulePopId --                                             */ /**
 *
 * \ingroup Module
 * \brief Pop moduleID off of module tracking stack after an
 *        inter-module call.
 *
 * \note  This function will not block.
 *
 * \deprecated This call should no longer be called directly as it is
 *             likely to go away in a future release.
 *
 ***********************************************************************
 */
void vmk_ModulePopId(void);

/*
 ***********************************************************************
 * vmk_ModuleStackTop --                                          */ /**
 *
 * \ingroup Module
 * \brief Get the latest moduleID pushed onto the module tracking stack.
 *
 * \note  This function will not block.
 *
 * \retval The moduleID at the top of the module tracking stack.
 *
 ***********************************************************************
 */
vmk_ModuleID vmk_ModuleStackTop(void);


/*
 ***********************************************************************
 * VMKAPI_MODULE_CALL --                                          */ /**
 *
 * \ingroup Module
 * \brief Macro wrapper for inter-module calls that return a value.
 *
 * This wrapper should always be used when calling into another module
 * so that vmkernel can properly track resources associated with
 * a call.
 *
 * \param[in]     moduleID       moduleID of the calling module.
 * \param[out]    returnValue    Variable to hold the return value from
 *                               the called function.
 * \param[in]     function       Inter-module function call to be
 *                               invoked.
 * \param[in,out] args           Arguments to pass to the inter-module
 *                               function call.
 *
 ***********************************************************************
 */
#define VMKAPI_MODULE_CALL(moduleID, returnValue, function, args...)    	\
do {                                                                    	\
    vmk_ModInfoStack modStack;						\
    vmk_ModulePushId(moduleID, function, &modStack) ;                   \
    VMK_DEBUG_ONLY(vmk_Bool intsEnabledOnEntry = vmk_CPUHasIntsEnabled();)      \
    returnValue = (function)(args);                                     	\
    VMK_DEBUG_ONLY(                                                             \
        if (intsEnabledOnEntry != vmk_CPUHasIntsEnabled()) {                    \
            vmk_Panic("Function %p in module %d %sabled interrupts",            \
                 function, moduleID, intsEnabledOnEntry ? "dis" : "en");        \
        }                                                                       \
    )                                                                           \
    vmk_ModulePopId();                                                  	\
} while(0)

/*
 ***********************************************************************
 * VMKAPI_MODULE_CALL_VOID --                                     */ /**
 *
 * \ingroup Module
 * \brief Macro wrapper for inter-module calls that do not return
 *        a value.
 *
 * This wrapper should always be used when calling into another module
 * so that vmkernel can properly track resources associated with
 * a call.
 *
 * \param[in]     moduleID    moduleID of the calling module
 * \param[in]     function    Inter-module function call to be invoked
 * \param[in,out] args        Arguments to pass to the inter-module
 *                            function call
 *
 ***********************************************************************
 */
#define VMKAPI_MODULE_CALL_VOID(moduleID, function, args...)    		\
do {                                                            		\
    vmk_ModInfoStack modStack;					\
    vmk_ModulePushId(moduleID, function, &modStack);            \
    VMK_DEBUG_ONLY(vmk_Bool intsEnabledOnEntry = vmk_CPUHasIntsEnabled();)      \
    (function)(args);                                           		\
    VMK_DEBUG_ONLY(                                                             \
        if (intsEnabledOnEntry != vmk_CPUHasIntsEnabled()) {                    \
            vmk_Panic("Function %p in module %d %sabled interrupts",            \
                 function, moduleID, intsEnabledOnEntry ? "dis" : "en");        \
        }                                                                       \
    )                                                                           \
    vmk_ModulePopId();                                          		\
} while(0)

/*
 ***********************************************************************
 * VMK_MODULE_EXPORT_SYMBOL --                                    */ /**
 *
 * \ingroup Module
 * \brief Mark a symbol as exported
 *
 * Mark the given symbol as exported (and hence available for other
 * modules to find/call) within the name-space and version of the
 * current module (as specified by VMK_NAMESPACE_PROVIDES())
 *
 * \note Although exported symbols are encapsulated within the modules
 * provided name-space, exported symbols are required to have a
 * globally unique name.  This is because there are no restrictions on
 * what combinations of name-spaces any given module may request,
 * leading to potential unresolvable collisions if a module requested
 * two name-spaces that provided the same symbol.
 *
 * \param[in] symname    The symbol to export.
 *
 ***********************************************************************
 */
#define VMK_MODULE_EXPORT_SYMBOL(symname)     \
   __VMK_MODULE_EXPORT_SYMBOL(symname)

/*
 ***********************************************************************
 * VMK_MODULE_EXPORT_SYMBOL_ALIASED --                            */ /**
 *
 * \ingroup Module
 * \brief Re-export a symbol under an aliased name
 *
 * Re-export the given original symbol "symname" as "alias" within the
 * name-space and version of the current module (as specified by
 * VMK_NAMESPACE_PROVIDES()).  "symname" must be either:
 *
 * - an internal global (i.e. not static) symbol of the current
 *   module, or
 * - be present by virtue of being exported by another module, and the
 *   current module must contain the correct VMK_NAMESPACE_REQUIRED()
 *   invocation such that the original symbol can be found.
 *
 * "alias" must be globally unqiue.
 *
 * \note Calls via this alias incur no overheads, as referencing the
 * alias results in the function address of the original symbol.
 *
 * \param[in] symname    The symbol to export.
 * \param[in] alias      The publicly exported name
 *
 ***********************************************************************
 */
#define VMK_MODULE_EXPORT_SYMBOL_ALIASED(symname, alias)    \
   __VMK_MODULE_EXPORT_SYMBOL_ALIASED(symname, alias)

/*
 ***********************************************************************
 * VMK_MODULE_EXPORT_ALIAS --                                     */ /**
 *
 * \ingroup Module
 * \brief Re-export an already exported symbol
 *
 * Re-export the given original symbol "symname" within the name-space
 * and version of the current module (as specified by
 * VMK_NAMESPACE_PROVIDES()).  The original symbol must be present by
 * virtue of being exported by another module, and the current module
 * must contain the correct VMK_NAMESPACE_REQUIRED() invocation such
 * that the original symbol can be found.
 *
 * \note Calls via this alias incur no overheads, as referencing the
 * alias results in the function address of the original symbol.
 *
 * \param[in] symname    The name of the original symbol to re-export
 *
 ***********************************************************************
 */
#define VMK_MODULE_EXPORT_ALIAS(symname) \
   __VMK_MODULE_EXPORT_SYMBOL_ALIASED(symname, symname)

/*
 ***********************************************************************
 * VMK_NAMESPACE_REQUIRED --                                      */ /**
 *
 * \ingroup Module
 * \brief Mark this module as requiring a name-space at a given version
 *
 * Mark the module as requiring a name-space "namespace" at "version".
 * There is no limit on the number of name-spaces a module may require.
 *
 * \note The namespace and version parameters may not contain the
 *       restricted character VMK_NS_VER_SEPARATOR. Including this
 *       character may cause the module to fail to load.
 *
 * \param[in] namespace  The name-space
 * \param[in] version    The version of this name-space
 *
 ***********************************************************************
 */
#define VMK_NAMESPACE_REQUIRED(namespace, version) \
   __VMK_NAMESPACE_REQUIRED(namespace, version)

/*
 ***********************************************************************
 * VMK_NAMESPACE_PROIVDES --                                      */ /**
 *
 * \ingroup Module
 * \brief Mark this module as providing a name-space at a given version
 *
 * Mark the module as providing a name-space "namespace" at "version".
 * Each module may provide only one name-space.
 *
 * \note The namespace and version parameters may not contain the
 *       restricted character VMK_NS_VER_SEPARATOR. Including this
 *       character may cause the module to fail to load.
 *
 * \param[in] namespace  The name-space
 * \param[in] version    The version of this name-space
 *
 ***********************************************************************
 */
#define VMK_NAMESPACE_PROVIDES(namespace, version) \
   __VMK_NAMESPACE_PROVIDES(namespace, version)

#endif /* _VMKAPI_MODULE_H_ */
/** @} */