DDI_MODOPEN(9F)         Kernel Functions for Drivers         DDI_MODOPEN(9F)
NAME
       ddi_modopen, ddi_modsym, ddi_modclose - dynamically-loaded kernel
       module functions
SYNOPSIS
       #include <sys/modctl.h>       
ddi_modhandle_t ddi_modopen(
const char*modname, 
int mode,            
int *errnop);       
void *ddi_modsym(
ddi_modhandle_t handle, 
const char *symname,            
int *errnop);       
int ddi_modclose(
ddi_modhandle_t handle);
INTERFACE LEVEL
       illumos DDI specific (illumos DDI).
PARAMETERS
       modname                  The name of the dynamically-loaded kernel module (file) to
                  be opened. The 
modname string is of the form:
                    "[
namespace/[
dirspace/]]
modulename"
                  Each "
namespace/" directory along the standard kernel
                  moddir/
module-path path (
system(5)) is searched to locate
                  the module. If "
namespace/" is not specified, "misc/" is
                  assumed. If "
dirspace" is specified, then "
namespace/"
                  must be explicitly provided.       
mode                  Currently, 
KRTLD_MODE_FIRST.       
errnop                  Pointer to 
errno returned on error, if 
NULL then no
                  additional error information is available.       
handle                  Opaque handle returned from 
ddi_modopen(), invalidated by                  
ddi_modclose().       
symname                  Symbol's name as a character string.
DESCRIPTION
       The function prototypes for 
ddi_modopen(), 
ddi_modsym(), and       
ddi_modclose() are modeled after the userland 
libdl(3LIB),       
dlopen(3C), 
dlsym(3C), and 
dlclose(3C) interfaces, however not all
       userland features are available and the kernel symbol resolution is
       different. The 
dlerror(3C) interface is not appropriate for the
       kernel environment, so the new 
errnop return argument was added for       
ddi_modopen() and 
ddi_modsym().
       The 
ddi_modopen() function makes a dynamically-loaded kernel module
       named by "modname" available to a running kernel. 
ddi_modopen()       returns a handle that the caller can use on subsequent calls to       
ddi_modsym() and 
ddi_modclose(). The value of this handle should not
       be interpreted in any way by the caller.
       The 
ddi_modopen() interface works best as a dynamic component/object
       plug-in mechanism when targeting kernel "misc" modules that contain a
       single "struct modlmisc" module linkage, however non-"misc" modules
       and modules with multiple linkage structures can also be targeted.
       There are two different symbol resolution search orders associated
       with the 
ddi_modopen() function: one search order to resolve symbols
       during the load of the targeted module, another search order o
       resolve 
ddi_modsym() calls against the handle returned by       
ddi_modopen(). To resolve symbols during module load, the standard
       kernel module load search order is used; to resolve symbols during
       module "A" load, the order is as follows:
         A -> A's _depends_on -> unix -> unix's _depends_on
       A single-level, left-to-right search in 
_depends_on (or the "ld -N"
       alternative) modules occurs. For 
UNIX on 
Intel, 
_depends_on is
       "genunix dtracestubs". The 
ddi_modsym() search is limited to the
       module directly associated with the handle.
       The 
ddi_modopen() function increments the reference count on the
       named kernel module. Upon the first load of a module, the 
_init(9E)       initialization code in the module is called; 
ddi_modopen() does not
       return until 
_init completes.
       The 
ddi_modsym() function allows a caller to obtain the address of a
       symbol that is defined within a module. The 
handle argument is a
       valid 
ddi_modhandle_t as returned by 
ddi_modopen(), the 
symname       argument is the symbol's name as a character string. The special
       handle values supported by 
ddi_modsym(9F) are not supported.
       The 
ddi_modclose() function decrements the reference count of the
       kernel module associated with the specified handle. After the       
ddi_modclose() function is called, all 
ddi_modsym() resolutions
       obtained (either directly or indirectly) using the now closed 
handle       are invalid; further use of these resolutions can cause undefined
       behavior (that is, may lead to a panic). When the last 
ddi_modclose()       of a module occurs, and there are no further references to the
       module, the module 
_fini(9E) entry point may be called. If 
_fini       returns success then the module may be unloaded.
RETURN VALUES
       The 
ddi_modopen() function returns a handle to the dynamically-loaded
       kernel module. The 
ddi_modopen() function returns 
NULL if the module
       cannot be found, the object cannot be relocated, or an error occurs
       during the process of resolving and relocating its symbolic
       references.
       The 
ddi_modsym() function returns 
NULL if the 
symname symbol cannot
       be found directly within the module associated with the 
handle.
       If the 
handle was not referenced, 
ddi_modclose() returns 0. If the       
handle is invalid, 
ddi_modclose() may return a non-zero value.
       When either 
ddi_modopen() or 
ddi_modsym() return 
NULL, additional       
errno information related to the failure is returned in 
*errnop if it
       is not 
NULL.
CONTEXT
       ddi_modopen() can be called from user context only.
EXAMPLES
       Example 1: Coding a Dynamically Loaded Kernel Module
       The following example shows code to dynamically load and call a
       "
test" interface in a module called "
dltest". The "
test" interface
       then adds one to its integer argument.
         ddi_modhandle_t modh;
         int             (*test)(int);
         int             i = 0;
         int             errno;
         ---%<---
         /* dynamically load "dltest" kernel 'misc' module */
         modh = ddi_modopen("dltest", KRTLD_MODE_FIRST, &errno);
         if (modh == NULL)
                  goto fail;      /* failed to open dltest module */
         test = (int (*)())ddi_modsym(modh, "test", &errno);
         if (test == NULL) {
                 (void) ddi_modclose(modh);
                 goto fail;      /* failed to find "test" interface */
         }
         /* invoke test interface and verify result */
         i = (*test)(0);
         ASSERT(i == 1);
         (void) ddi_modclose(modh);
         ---%<---
       The implementation of the "dltest" "misc" module is as follows:
         #include <sys/modctl.h>
         static dltest_add = 0;
         /* define the module linkage */
         static struct modlmisc          modlmisc = {&mod_miscops, "dltest"};
         static struct modlinkage        modlinkage = {
                 MODREV_1, (void *)&modmisc, NULL
         };
         int
         _init(void)
         {
                 int     i;
                 dltest_add = 1;                 /* initialization */
                 if ((i = mod_install(&modlinkage)) != 0)
                         dltest_add = -1;        /* un-initialization */
                 return (i);
         }
         int
         _fini()
         {
                 int     i;
                 if ((i = mod_remove(&modlinkage)) == 0)
                                 dltest_add = -1;        /* un-initialization */
                 return (i);
         }
         int
         _info(struct modinfo *modinfop)
         {
                 return (mod_info(&modlinkage, modinfop));
         }
         /* "test" interface */
         int
         test(int i)
         {
                 return (i + dltest_add);
         }
       Example 2: Dynamically Accessing a Kernel Module within a Drive
       The following example shows driver code to dynamically load into the
       kernel a module constructed via the 
elfwrap(1) utility and containing
       firmware intended for download to a device. The "
start" and "
end"
       pointers provide the addresses of the beginning of the data and first
       byte beyond the data.
         ddi_modhandle_t modp;
         char *data_startp, *data_endp;
         size_t nbytes;
         int rv;
         modp = ddi_modopen("firmware-rev1.2a", KRTLD_MODE_FIRST, &rv);
         data_startp = (char *)ddi_modsym(modp, "fw-rev1.2a_start", &rv);
         data_endp = (char *)ddi_modsym(modp, "fw-rev1.2a_end", &rv);
         nbytes = data_endp - data_startp;
         rv = ddi_modclose(modp);
SEE ALSO
       elfwrap(1), 
dlclose(3C), 
dlopen(3C), 
dlsym(3C), 
libdl(3LIB),       
system(5), 
boot(8), 
modload(8), 
_fini(9E), 
_info(9E), 
_init(9E)       Writing Device DriversWARNINGS
       A 
system(5) forceload must be established for modules targeted by       
ddi_modopen() by code involved in the mount of root on "bootdev"
       during machine 
boot(8).
                               August 22, 2023               DDI_MODOPEN(9F)