15084Sjohnlev /*
25084Sjohnlev * CDDL HEADER START
35084Sjohnlev *
45084Sjohnlev * The contents of this file are subject to the terms of the
55084Sjohnlev * Common Development and Distribution License (the "License").
65084Sjohnlev * You may not use this file except in compliance with the License.
75084Sjohnlev *
85084Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95084Sjohnlev * or http://www.opensolaris.org/os/licensing.
105084Sjohnlev * See the License for the specific language governing permissions
115084Sjohnlev * and limitations under the License.
125084Sjohnlev *
135084Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each
145084Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155084Sjohnlev * If applicable, add the following below this CDDL HEADER, with the
165084Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying
175084Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner]
185084Sjohnlev *
195084Sjohnlev * CDDL HEADER END
205084Sjohnlev */
215084Sjohnlev
225084Sjohnlev /*
23*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
245084Sjohnlev * Use is subject to license terms.
255084Sjohnlev */
265084Sjohnlev
275084Sjohnlev
285084Sjohnlev /*
295084Sjohnlev * A simple wrapper around the balloon kernel thread to allow userland
305084Sjohnlev * programs access to the balloon status.
315084Sjohnlev */
325084Sjohnlev
335084Sjohnlev #include <sys/types.h>
345084Sjohnlev #include <sys/file.h>
355084Sjohnlev #include <sys/errno.h>
365084Sjohnlev #include <sys/open.h>
375084Sjohnlev #include <sys/cred.h>
385084Sjohnlev #include <sys/conf.h>
395084Sjohnlev #include <sys/stat.h>
405084Sjohnlev #include <sys/modctl.h>
415084Sjohnlev #include <sys/ddi.h>
425084Sjohnlev #include <sys/sunddi.h>
435084Sjohnlev #include <sys/hypervisor.h>
445084Sjohnlev #include <sys/sysmacros.h>
455084Sjohnlev #include <sys/balloon_impl.h>
465084Sjohnlev
475084Sjohnlev static dev_info_t *balloon_devi;
485084Sjohnlev
495084Sjohnlev /*ARGSUSED*/
505084Sjohnlev static int
balloon_getinfo(dev_info_t * devi,ddi_info_cmd_t cmd,void * arg,void ** result)515084Sjohnlev balloon_getinfo(dev_info_t *devi, ddi_info_cmd_t cmd, void *arg, void **result)
525084Sjohnlev {
535084Sjohnlev if (getminor((dev_t)arg) != BALLOON_MINOR)
545084Sjohnlev return (DDI_FAILURE);
555084Sjohnlev
565084Sjohnlev switch (cmd) {
575084Sjohnlev case DDI_INFO_DEVT2DEVINFO:
585084Sjohnlev *result = balloon_devi;
595084Sjohnlev break;
605084Sjohnlev case DDI_INFO_DEVT2INSTANCE:
615084Sjohnlev *result = 0;
625084Sjohnlev break;
635084Sjohnlev default:
645084Sjohnlev return (DDI_FAILURE);
655084Sjohnlev }
665084Sjohnlev
675084Sjohnlev return (DDI_SUCCESS);
685084Sjohnlev }
695084Sjohnlev
705084Sjohnlev static int
balloon_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)715084Sjohnlev balloon_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
725084Sjohnlev {
735084Sjohnlev if (cmd != DDI_ATTACH)
745084Sjohnlev return (DDI_FAILURE);
755084Sjohnlev
765084Sjohnlev if (ddi_create_minor_node(devi, ddi_get_name(devi), S_IFCHR,
775084Sjohnlev ddi_get_instance(devi), DDI_PSEUDO, 0) != DDI_SUCCESS)
785084Sjohnlev return (DDI_FAILURE);
795084Sjohnlev
805084Sjohnlev balloon_devi = devi;
815084Sjohnlev ddi_report_dev(devi);
825084Sjohnlev return (DDI_SUCCESS);
835084Sjohnlev }
845084Sjohnlev
855084Sjohnlev static int
balloon_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)865084Sjohnlev balloon_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
875084Sjohnlev {
885084Sjohnlev if (cmd != DDI_DETACH)
895084Sjohnlev return (DDI_FAILURE);
905084Sjohnlev ddi_remove_minor_node(devi, NULL);
915084Sjohnlev balloon_devi = NULL;
925084Sjohnlev return (DDI_SUCCESS);
935084Sjohnlev }
945084Sjohnlev
955084Sjohnlev /*ARGSUSED1*/
965084Sjohnlev static int
balloon_open(dev_t * dev,int flag,int otyp,cred_t * cr)975084Sjohnlev balloon_open(dev_t *dev, int flag, int otyp, cred_t *cr)
985084Sjohnlev {
995084Sjohnlev return (getminor(*dev) == BALLOON_MINOR ? 0 : ENXIO);
1005084Sjohnlev }
1015084Sjohnlev
1025084Sjohnlev /*
1035084Sjohnlev * When asked for one of the balloon values, we simply query the balloon thread.
1045084Sjohnlev */
1055084Sjohnlev /*ARGSUSED*/
1065084Sjohnlev static int
balloon_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval_p)1075084Sjohnlev balloon_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr,
1085084Sjohnlev int *rval_p)
1095084Sjohnlev {
1105084Sjohnlev int rval = 0;
1115084Sjohnlev size_t value;
1125084Sjohnlev
1135084Sjohnlev switch (cmd) {
1145084Sjohnlev case BLN_IOCTL_CURRENT:
1155084Sjohnlev case BLN_IOCTL_TARGET:
1165084Sjohnlev case BLN_IOCTL_LOW:
1175084Sjohnlev case BLN_IOCTL_HIGH:
1185084Sjohnlev case BLN_IOCTL_LIMIT:
1195084Sjohnlev value = balloon_values(cmd);
1205084Sjohnlev if (ddi_copyout((void *)&value, (void *)arg, sizeof (value),
1215084Sjohnlev mode))
1225084Sjohnlev return (EFAULT);
1235084Sjohnlev break;
1245084Sjohnlev default:
1255084Sjohnlev rval = EINVAL;
1265084Sjohnlev break;
1275084Sjohnlev }
1285084Sjohnlev return (rval);
1295084Sjohnlev }
1305084Sjohnlev
1315084Sjohnlev static struct cb_ops balloon_cb_ops = {
1325084Sjohnlev balloon_open,
1335084Sjohnlev nulldev, /* close */
1345084Sjohnlev nodev, /* strategy */
1355084Sjohnlev nodev, /* print */
1365084Sjohnlev nodev, /* dump */
1375084Sjohnlev nodev, /* read */
1385084Sjohnlev nodev, /* write */
1395084Sjohnlev balloon_ioctl, /* ioctl */
1405084Sjohnlev nodev, /* devmap */
1415084Sjohnlev nodev, /* mmap */
1425084Sjohnlev nodev, /* segmap */
1435084Sjohnlev nochpoll, /* poll */
1445084Sjohnlev ddi_prop_op,
1455084Sjohnlev NULL,
1465084Sjohnlev D_64BIT | D_MP,
1475084Sjohnlev CB_REV,
1485084Sjohnlev NULL,
1495084Sjohnlev NULL
1505084Sjohnlev };
1515084Sjohnlev
1525084Sjohnlev static struct dev_ops balloon_dv_ops = {
1535084Sjohnlev DEVO_REV,
1545084Sjohnlev 0,
1555084Sjohnlev balloon_getinfo,
156*7656SSherry.Moore@Sun.COM nulldev, /* identify */
157*7656SSherry.Moore@Sun.COM nulldev, /* probe */
1585084Sjohnlev balloon_attach,
1595084Sjohnlev balloon_detach,
160*7656SSherry.Moore@Sun.COM nodev, /* reset */
1615084Sjohnlev &balloon_cb_ops,
162*7656SSherry.Moore@Sun.COM NULL, /* struct bus_ops */
163*7656SSherry.Moore@Sun.COM NULL, /* power */
164*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
1655084Sjohnlev };
1665084Sjohnlev
1675084Sjohnlev static struct modldrv modldrv = {
1685084Sjohnlev &mod_driverops,
169*7656SSherry.Moore@Sun.COM "balloon driver",
1705084Sjohnlev &balloon_dv_ops
1715084Sjohnlev };
1725084Sjohnlev
1735084Sjohnlev static struct modlinkage modl = {
1745084Sjohnlev MODREV_1,
1755084Sjohnlev {
1765084Sjohnlev (void *)&modldrv,
1775084Sjohnlev NULL /* null termination */
1785084Sjohnlev }
1795084Sjohnlev };
1805084Sjohnlev
1815084Sjohnlev int
_init(void)1825084Sjohnlev _init(void)
1835084Sjohnlev {
1845084Sjohnlev return (mod_install(&modl));
1855084Sjohnlev }
1865084Sjohnlev
1875084Sjohnlev int
_fini(void)1885084Sjohnlev _fini(void)
1895084Sjohnlev {
1905084Sjohnlev return (mod_remove(&modl));
1915084Sjohnlev }
1925084Sjohnlev
1935084Sjohnlev int
_info(struct modinfo * modinfo)1945084Sjohnlev _info(struct modinfo *modinfo)
1955084Sjohnlev {
1965084Sjohnlev return (mod_info(&modl, modinfo));
1975084Sjohnlev }
198