1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 
  28 /*
  29  * A simple wrapper around the balloon kernel thread to allow userland
  30  * programs access to the balloon status.
  31  */
  32 
  33 #include <sys/types.h>
  34 #include <sys/file.h>
  35 #include <sys/errno.h>
  36 #include <sys/open.h>
  37 #include <sys/cred.h>
  38 #include <sys/conf.h>
  39 #include <sys/stat.h>
  40 #include <sys/modctl.h>
  41 #include <sys/ddi.h>
  42 #include <sys/sunddi.h>
  43 #include <sys/hypervisor.h>
  44 #include <sys/sysmacros.h>
  45 #include <sys/balloon_impl.h>
  46 
  47 static dev_info_t *balloon_devi;
  48 
  49 /*ARGSUSED*/
  50 static int
  51 balloon_getinfo(dev_info_t *devi, ddi_info_cmd_t cmd, void *arg, void **result)
  52 {
  53         if (getminor((dev_t)arg) != BALLOON_MINOR)
  54                 return (DDI_FAILURE);
  55 
  56         switch (cmd) {
  57         case DDI_INFO_DEVT2DEVINFO:
  58                 *result = balloon_devi;
  59                 break;
  60         case DDI_INFO_DEVT2INSTANCE:
  61                 *result = 0;
  62                 break;
  63         default:
  64                 return (DDI_FAILURE);
  65         }
  66 
  67         return (DDI_SUCCESS);
  68 }
  69 
  70 static int
  71 balloon_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
  72 {
  73         if (cmd != DDI_ATTACH)
  74                 return (DDI_FAILURE);
  75 
  76         if (ddi_create_minor_node(devi, ddi_get_name(devi), S_IFCHR,
  77             ddi_get_instance(devi), DDI_PSEUDO, 0) != DDI_SUCCESS)
  78                 return (DDI_FAILURE);
  79 
  80         balloon_devi = devi;
  81         ddi_report_dev(devi);
  82         return (DDI_SUCCESS);
  83 }
  84 
  85 static int
  86 balloon_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
  87 {
  88         if (cmd != DDI_DETACH)
  89                 return (DDI_FAILURE);
  90         ddi_remove_minor_node(devi, NULL);
  91         balloon_devi = NULL;
  92         return (DDI_SUCCESS);
  93 }
  94 
  95 /*ARGSUSED1*/
  96 static int
  97 balloon_open(dev_t *dev, int flag, int otyp, cred_t *cr)
  98 {
  99         return (getminor(*dev) == BALLOON_MINOR ? 0 : ENXIO);
 100 }
 101 
 102 /*
 103  * When asked for one of the balloon values, we simply query the balloon thread.
 104  */
 105 /*ARGSUSED*/
 106 static int
 107 balloon_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr,
 108     int *rval_p)
 109 {
 110         int rval = 0;
 111         size_t value;
 112 
 113         switch (cmd) {
 114         case BLN_IOCTL_CURRENT:
 115         case BLN_IOCTL_TARGET:
 116         case BLN_IOCTL_LOW:
 117         case BLN_IOCTL_HIGH:
 118         case BLN_IOCTL_LIMIT:
 119                 value = balloon_values(cmd);
 120                 if (ddi_copyout((void *)&value, (void *)arg, sizeof (value),
 121                     mode))
 122                         return (EFAULT);
 123                 break;
 124         default:
 125                 rval = EINVAL;
 126                 break;
 127         }
 128         return (rval);
 129 }
 130 
 131 static struct cb_ops balloon_cb_ops = {
 132         balloon_open,
 133         nulldev,        /* close */
 134         nodev,          /* strategy */
 135         nodev,          /* print */
 136         nodev,          /* dump */
 137         nodev,          /* read */
 138         nodev,          /* write */
 139         balloon_ioctl,  /* ioctl */
 140         nodev,          /* devmap */
 141         nodev,          /* mmap */
 142         nodev,          /* segmap */
 143         nochpoll,       /* poll */
 144         ddi_prop_op,
 145         NULL,
 146         D_64BIT | D_MP,
 147         CB_REV,
 148         NULL,
 149         NULL
 150 };
 151 
 152 static struct dev_ops balloon_dv_ops = {
 153         DEVO_REV,
 154         0,
 155         balloon_getinfo,
 156         nulldev,                /* identify */
 157         nulldev,                /* probe */
 158         balloon_attach,
 159         balloon_detach,
 160         nodev,                  /* reset */
 161         &balloon_cb_ops,
 162         NULL,                   /* struct bus_ops */
 163         NULL,                   /* power */
 164         ddi_quiesce_not_needed,         /* quiesce */
 165 };
 166 
 167 static struct modldrv modldrv = {
 168         &mod_driverops,
 169         "balloon driver",
 170         &balloon_dv_ops
 171 };
 172 
 173 static struct modlinkage modl = {
 174         MODREV_1,
 175         {
 176                 (void *)&modldrv,
 177                 NULL            /* null termination */
 178         }
 179 };
 180 
 181 int
 182 _init(void)
 183 {
 184         return (mod_install(&modl));
 185 }
 186 
 187 int
 188 _fini(void)
 189 {
 190         return (mod_remove(&modl));
 191 }
 192 
 193 int
 194 _info(struct modinfo *modinfo)
 195 {
 196         return (mod_info(&modl, modinfo));
 197 }