/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright 2016 Joyent, Inc.
*/
#include <sys/ddi_impldefs.h>
#include <vm/seg_kmem.h>
#include <sys/sysmacros.h>
#include <sys/ddidevmap.h>
#ifdef __xpv
#include <sys/hypervisor.h>
#endif
/* total max memory which can be alloced with ioctl interface */
int *rval);
void **result);
xsvc_open, /* cb_open */
xsvc_close, /* cb_close */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
xsvc_ioctl, /* cb_ioctl */
xsvc_devmap, /* cb_devmap */
NULL, /* cb_mmap */
NULL, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
NULL, /* cb_stream */
};
DEVO_REV, /* devo_rev */
0, /* devo_refcnt */
xsvc_getinfo, /* devo_getinfo */
nulldev, /* devo_identify */
nulldev, /* devo_probe */
xsvc_attach, /* devo_attach */
xsvc_detach, /* devo_detach */
nodev, /* devo_reset */
&xsvc_cb_ops, /* devo_cb_ops */
NULL, /* devo_bus_ops */
NULL, /* power */
ddi_quiesce_not_needed, /* quiesce */
};
&mod_driverops, /* Type of module. This one is a driver */
"xsvc driver", /* Name of the module. */
&xsvc_dev_ops, /* driver ops */
};
(void *) &xsvc_modldrv,
};
xsvc_mem_t **mp);
static int xsvc_mnode_key_compare(const void *q, const void *e);
void *xsvc_statep;
};
NULL,
};
/*
* _init()
*
*/
int
_init(void)
{
int err;
if (err != 0) {
return (err);
}
if (err != 0) {
return (err);
}
return (0);
}
/*
* _info()
*
*/
int
{
}
/*
* _fini()
*
*/
int
_fini(void)
{
int err;
if (err != 0) {
return (err);
}
return (0);
}
/*
* xsvc_attach()
*
*/
static int
{
int maxallocmem;
int instance;
int err;
switch (cmd) {
case DDI_ATTACH:
break;
case DDI_RESUME:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
if (err != DDI_SUCCESS) {
return (DDI_FAILURE);
}
}
/* Initialize allocation count */
state->xs_currently_alloced = 0;
/* create the minor node (for the ioctl) */
0);
if (err != DDI_SUCCESS) {
goto attachfail_minor_node;
}
/*
* the maxallocmem property will override the default (xsvc_max_memory).
* This is the maximum total memory the ioctl will allow to be alloced.
*/
if (maxallocmem >= 0) {
}
/* Initialize list of memory allocs */
/* Report that driver was loaded */
return (DDI_SUCCESS);
return (err);
}
/*
* xsvc_detach()
*
*/
static int
{
int instance;
return (DDI_FAILURE);
}
switch (cmd) {
case DDI_DETACH:
break;
case DDI_SUSPEND:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
/* Free any memory on list */
}
/* remove list */
return (DDI_SUCCESS);
}
/*
* xsvc_getinfo()
*
*/
/*ARGSUSED*/
static int
{
int instance;
int err;
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
return (DDI_FAILURE);
}
err = DDI_SUCCESS;
break;
case DDI_INFO_DEVT2INSTANCE:
err = DDI_SUCCESS;
break;
default:
err = DDI_FAILURE;
break;
}
return (err);
}
/*
* xsvc_open()
*
*/
/*ARGSUSED*/
static int
{
int instance;
return (ENXIO);
}
return (0);
}
/*
* xsvc_close()
*
*/
/*ARGSUSED*/
static int
{
return (0);
}
/*
* xsvc_ioctl()
*
*/
/*ARGSUSED*/
static int
{
int instance;
int err;
if (err != 0) {
return (EPERM);
}
if (instance == -1) {
return (EBADF);
}
return (EBADF);
}
switch (cmd) {
case XSVC_ALLOC_MEM:
break;
case XSVC_FREE_MEM:
break;
case XSVC_FLUSH_MEM:
break;
default:
}
return (err);
}
/*
* xsvc_ioctl_alloc_memory()
*
*/
static int
{
int err;
int i;
/* Copy in the params, then get the size and key */
mode);
if (err != 0) {
return (EFAULT);
}
} else {
if (err != 0) {
return (EFAULT);
}
}
/*
* make sure this doesn't put us over the maximum allowed to be
* allocated
*/
return (EAGAIN);
}
/* get state to track this memory */
if (err != 0) {
return (err);
}
/* allocate and bind the memory */
/* Finish converting params */
} else {
}
if (err != DDI_SUCCESS) {
goto allocfail_alloc_handle;
}
/* don't sleep here so we don't get stuck in contig alloc */
if (err != DDI_SUCCESS) {
goto allocfail_alloc_mem;
}
if (err != DDI_DMA_MAPPED) {
goto allocfail_bind;
}
/* return sgl */
for (i = 0; i < mp->xm_cookie_count; i++) {
sizeof (xsvc_mloc_32), mode);
if (err != 0) {
goto allocfail_copyout;
}
} else {
mode);
if (err != 0) {
goto allocfail_copyout;
}
}
}
/* set the last sgl entry to 0 to indicate cookie count */
mode);
if (err != 0) {
goto allocfail_copyout;
}
} else {
if (err != 0) {
goto allocfail_copyout;
}
}
return (0);
return (err);
}
/*
* xsvc_ioctl_flush_memory()
*
*/
static int
{
int err;
mode);
if (err != 0) {
return (EFAULT);
}
} else {
if (err != 0) {
return (EFAULT);
}
}
/* find the memory */
return (EINVAL);
}
return (0);
}
/*
* xsvc_ioctl_free_memory()
*
*/
static int
{
int err;
mode);
if (err != 0) {
return (EFAULT);
}
} else {
if (err != 0) {
return (EFAULT);
}
}
/* find the memory */
return (EINVAL);
}
return (0);
}
/*
* xsvc_mem_alloc()
*
*/
static int
{
}
return (0);
}
/*
* xsvc_mem_free()
*
*/
static void
{
}
}
/*
* xsvc_mem_lookup()
*
*/
static xsvc_mem_t *
{
} else {
}
return (mp);
}
/*
* xsvc_mnode_key_compare()
*
*/
static int
xsvc_mnode_key_compare(const void *q, const void *e)
{
n1 = (xsvc_mnode_t *)q;
n2 = (xsvc_mnode_t *)e;
return (-1);
return (1);
} else {
return (0);
}
}
/*
* xsvc_devmap()
*
*/
/*ARGSUSED*/
static int
{
int instance;
int err;
int i;
return (ENXIO);
}
/*
* On 64-bit kernels, if we have a 32-bit application doing a mmap(),
* smmap32 will sign extend the offset. We need to undo that since
* we are passed a physical address in off, not a offset.
*/
#if defined(__amd64)
}
#endif
#ifdef __xpv
/*
* this some later when there is a good reason.
*/
if (!DOMAIN_IS_INITDOMAIN(xen_info)) {
return (-1);
}
/* we will always treat this as a foreign MFN */
#else
#endif
/* always work with whole pages */
/*
* if this is memory we're trying to map into user space, we first
* need to map the PFNs into KVA, then build up a umem cookie, and
* finally do a umem_setup to map it in.
*/
if (pf_is_memory(pfn)) {
return (-1);
}
for (i = 0; i < npages; i++) {
/*
* Preemptively check for panic conditions from
* hat_devload and error out instead.
*/
err = DDI_FAILURE;
npages = i;
goto devmapfail_cookie_alloc;
}
pfn++;
}
if (err != 0) {
goto devmapfail_cookie_alloc;
}
goto devmapfail_umem_setup;
}
/*
* If this is not memory (or a foreign MFN in i86xpv), go through
* devmem_setup.
*/
} else {
return (err);
}
}
return (0);
for (i = 0; i < npages; i++) {
}
return (err);
}
/*
* xsvc_umem_cookie_alloc()
*
* allocate a umem cookie to be used in devmap_umem_setup using KVA already
* allocated.
*/
int
{
if (umem_cookiep == NULL) {
return (-1);
}
return (0);
}
/*
* xsvc_umem_cookie_free()
*
*/
static void
{
}
/*
* xsvc_devmap_map()
*
*/
/*ARGSUSED*/
static int
{
int instance;
return (ENXIO);
}
/* This driver only supports MAP_SHARED, not MAP_PRIVATE */
if (flags & MAP_PRIVATE) {
return (EINVAL);
}
return (0);
}
/*
* xsvc_devmap_dup()
*
* keep a reference count for forks so we don't unmap if we have multiple
* mappings.
*/
/*ARGSUSED*/
static int
void **new_pvtp)
{
return (ENOMEM);
}
cp->cook_refcnt++;
return (0);
}
/*
* xsvc_devmap_unmap()
*
* This routine is only call if we were mapping in memory in xsvc_devmap().
* i.e. we only pass in xsvc_callbk to devmap_umem_setup if pf_is_memory()
* was true. It would have been nice if devmap_callback_ctl had an args param.
* We wouldn't have had to look into the devmap_handle and into the umem
* cookie.
*/
/*ARGSUSED*/
static void
void **new_pvtp2)
{
int i;
/* peek into the umem cookie to figure out what we need to free up */
ncp->cook_refcnt++;
}
ncp->cook_refcnt++;
}
cp->cook_refcnt--;
if (cp->cook_refcnt == 0) {
/*
* free up the umem cookie, then unmap all the pages what we
* mapped in during devmap, then free up the kva space.
*/
for (i = 0; i < npages; i++) {
}
}
}