xref: /illumos-gate/usr/src/uts/common/kmdb/kdrv.c (revision 734b6a94890be549309b21156f8ed6d4561cac51)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * The driver portion of kmdb, which manages /dev/kmdb and passes requests along
31  * to the kmdb misc module (kmdbmod).
32  */
33 
34 #include <sys/conf.h>
35 #include <sys/stat.h>
36 #include <sys/modctl.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/open.h>
40 #include <sys/kobj.h>
41 #include <sys/kdi.h>
42 #include <sys/policy.h>
43 #include <sys/kobj_impl.h>
44 #include <sys/kmdb.h>
45 #include <sys/sysmacros.h>
46 
47 #define	KDRV_CFG_MAXLEN		2048
48 
49 static dev_info_t 		*kdrv_dip;
50 
51 /*ARGSUSED*/
52 static int
53 kdrv_open(dev_t *dev, int openflags, int otyp, cred_t *credp)
54 {
55 	if (otyp != OTYP_CHR)
56 		return (EINVAL);
57 
58 	if (secpolicy_kmdb(credp) != 0)
59 		return (EPERM);
60 
61 	return (0);
62 }
63 
64 /*ARGSUSED*/
65 static int
66 kdrv_close(dev_t dev, int openflags, int otyp, cred_t *credp)
67 {
68 	return (0);
69 }
70 
71 typedef struct kdrv_flags_map {
72 	const char *fm_name;
73 	int fm_defval;
74 	uint_t fm_flag;
75 } kdrv_flags_map_t;
76 
77 static const kdrv_flags_map_t kdrv_flags_map[] = {
78 	{ "kmdb-auto-entry", 1, KMDB_F_AUTO_ENTRY },
79 	{ "kmdb-trap-noswitch", 0, KMDB_F_TRAP_NOSWITCH },
80 	{ "kmdb-driver-debug", 0, KMDB_F_DRV_DEBUG },
81 	{ NULL }
82 };
83 
84 static int
85 kdrv_activate(intptr_t arg)
86 {
87 	uint_t flags;
88 	size_t memsz;
89 	char *cfg;
90 	size_t got;
91 	int i, rc;
92 
93 	memsz = ddi_prop_get_int(DDI_DEV_T_ANY, kdrv_dip,
94 	    DDI_PROP_DONTPASS, "kmdb-memseg-size", 0);
95 
96 	for (flags = 0, i = 0; kdrv_flags_map[i].fm_name != NULL; i++) {
97 		const kdrv_flags_map_t *fm = &kdrv_flags_map[i];
98 		if (ddi_prop_get_int(DDI_DEV_T_ANY, kdrv_dip, DDI_PROP_DONTPASS,
99 		    (char *)fm->fm_name, fm->fm_defval))
100 			flags |= fm->fm_flag;
101 	}
102 
103 	cfg = kmem_alloc(KDRV_CFG_MAXLEN, KM_SLEEP);
104 
105 	if ((rc = copyinstr((caddr_t)arg, cfg, KDRV_CFG_MAXLEN, &got)) != 0) {
106 		kmem_free(cfg, KDRV_CFG_MAXLEN);
107 		return (rc == ENAMETOOLONG ? E2BIG : EFAULT);
108 	}
109 
110 	rc = kctl_modload_activate(memsz, cfg, flags);
111 
112 	kmem_free(cfg, KDRV_CFG_MAXLEN);
113 
114 	return (rc);
115 }
116 
117 static int
118 kdrv_deactivate(void)
119 {
120 	return (kctl_deactivate());
121 }
122 
123 /*ARGSUSED*/
124 static int
125 kdrv_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, cred_t *credp,
126     int *rvalp)
127 {
128 	switch (cmd) {
129 	case KMDB_IOC_START:
130 		return (kdrv_activate(arg));
131 
132 	case KMDB_IOC_STOP:
133 		return (kdrv_deactivate());
134 
135 	default:
136 		return (EINVAL);
137 	}
138 }
139 
140 /*ARGSUSED*/
141 static int
142 kdrv_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
143 {
144 	int error = DDI_SUCCESS;
145 
146 	switch (infocmd) {
147 	case DDI_INFO_DEVT2DEVINFO:
148 		*result = kdrv_dip;
149 		break;
150 	case DDI_INFO_DEVT2INSTANCE:
151 		*result = (void *)(uintptr_t)getminor((dev_t)arg);
152 		break;
153 	default:
154 		*result = NULL;
155 		error = DDI_FAILURE;
156 	}
157 
158 	return (error);
159 }
160 
161 static int
162 kdrv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
163 {
164 	if (cmd != DDI_ATTACH)
165 		return (DDI_FAILURE);
166 
167 	if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR,
168 	    ddi_get_instance(dip), DDI_PSEUDO, 0) != DDI_SUCCESS)
169 		return (DDI_FAILURE);
170 
171 	kdrv_dip = dip;
172 
173 	if (kctl_attach(dip) != 0)
174 		return (DDI_FAILURE);
175 
176 	return (DDI_SUCCESS);
177 }
178 
179 static int
180 kdrv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
181 {
182 	if (cmd != DDI_DETACH)
183 		return (DDI_FAILURE);
184 
185 	if (kctl_detach() == EBUSY)
186 		return (DDI_FAILURE);
187 
188 	ddi_remove_minor_node(dip, NULL);
189 
190 	return (DDI_SUCCESS);
191 }
192 
193 static struct cb_ops kdrv_cb_ops = {
194 	kdrv_open,
195 	kdrv_close,
196 	nodev,			/* not a block driver	*/
197 	nodev,			/* no print routine	*/
198 	nodev,			/* no dump routine	*/
199 	nodev,			/* no read routine	*/
200 	nodev,			/* no write routine	*/
201 	kdrv_ioctl,
202 	nodev,			/* no devmap routine	*/
203 	nodev,			/* no mmap routine	*/
204 	nodev,			/* no segmap routine	*/
205 	nochpoll,		/* no chpoll routine	*/
206 	ddi_prop_op,
207 	0,			/* not a STREAMS driver	*/
208 	D_NEW | D_MP,		/* safe for multi-thread/multi-processor */
209 };
210 
211 static struct dev_ops kdrv_ops = {
212 	DEVO_REV,		/* devo_rev */
213 	0,			/* devo_refcnt */
214 	kdrv_getinfo,		/* devo_getinfo */
215 	nulldev,		/* devo_identify */
216 	nulldev,		/* devo_probe */
217 	kdrv_attach,		/* devo_attach */
218 	kdrv_detach,		/* devo_detach */
219 	nodev,			/* devo_reset */
220 	&kdrv_cb_ops,		/* devo_cb_ops */
221 	(struct bus_ops *)0,	/* devo_bus_ops */
222 	NULL,			/* devo_power */
223 };
224 
225 static struct modldrv modldrv = {
226 	&mod_driverops,
227 	"kmdb driver %I%",
228 	&kdrv_ops
229 };
230 
231 static struct modlinkage modlinkage = {
232 	MODREV_1,
233 	(void *)&modldrv,
234 	NULL
235 };
236 
237 int
238 _init(void)
239 {
240 	return (mod_install(&modlinkage));
241 }
242 
243 int
244 _info(struct modinfo *modinfop)
245 {
246 	return (mod_info(&modlinkage, modinfop));
247 }
248 
249 int
250 _fini(void)
251 {
252 	return (mod_remove(&modlinkage));
253 }
254