xref: /illumos-gate/usr/src/cmd/mdb/intel/kmdb/kctl/kctl_isadep.c (revision 7f7322febbcfe774b7270abc3b191c094bfcc517)
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 2005 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 #include <kmdb/kmdb_auxv.h>
30 #include <kmdb/kctl/kctl.h>
31 
32 #include <sys/bootconf.h>
33 #include <sys/kobj.h>
34 #include <sys/kobj_impl.h>
35 #include <sys/cpuvar.h>
36 #include <sys/kdi_impl.h>
37 #include <sys/x86_archext.h>
38 #include <sys/controlregs.h>
39 #include <sys/archsystm.h>
40 
41 #if defined(__i386)
42 /* Copied from stand/i386/sys/bootdef.h */
43 #define	GS_GDT		0x38	/* dummy cpu_t pointer descriptor	*/
44 #endif
45 
46 static int
47 kctl_ddi_prop_read(kmdb_auxv_nv_t *nv, char *pname, void *arg)
48 {
49 	dev_info_t *dip = arg;
50 	char *val;
51 
52 	if (strlen(pname) >= sizeof (nv->kanv_name)) {
53 		cmn_err(CE_WARN, "ignoring boot property %s: name too long\n",
54 		    pname);
55 		return (0);
56 	}
57 
58 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
59 	    DDI_PROP_DONTPASS, pname, &val) != DDI_SUCCESS)
60 		return (NULL);
61 
62 	if (strlen(val) >= sizeof (nv->kanv_val)) {
63 		cmn_err(CE_WARN, "ignoring boot property %s: value too long\n",
64 		    pname);
65 		return (0);
66 	}
67 
68 	strcpy(nv->kanv_name, pname);
69 	strcpy(nv->kanv_val, val);
70 
71 	ddi_prop_free(val);
72 
73 	return (1);
74 }
75 
76 /*ARGSUSED*/
77 static int
78 cons_type(void)
79 {
80 #define	CONS_STR_BUFLEN 10
81 	static int cons_type = -1;
82 	char cons_str[CONS_STR_BUFLEN];
83 	int len;
84 	struct bootops *ops = kctl.kctl_boot_ops;
85 
86 	if (cons_type != -1)
87 		return (cons_type);
88 	cons_type = 0;	/* default to screen */
89 
90 	len = BOP_GETPROPLEN(ops, "console");
91 	if (len > 0 && len <= CONS_STR_BUFLEN) {
92 		(void) BOP_GETPROP(ops, "console", (void *)cons_str);
93 		if (strncmp(cons_str, "ttya", 4) == 0)
94 			cons_type = 1;
95 		else if (strncmp(cons_str, "ttyb", 4) == 0)
96 			cons_type = 2;
97 	}
98 
99 	return (cons_type);
100 }
101 
102 /*
103  * fake prom properties, assuming the properties being read are
104  * input-device, output-device, ttya-mode, ttyb-mode.
105  */
106 /*ARGSUSED*/
107 static int
108 kctl_boot_prop_read(kmdb_auxv_nv_t *nv, char *pname, void *arg)
109 {
110 	if (strcmp(pname, "ttya-mode") == 0 ||
111 	    strcmp(pname, "ttyb-mode") == 0) {
112 		(void) strcpy(nv->kanv_val, "9600,8,n,1,-");
113 		return (0);
114 	}
115 
116 	if (strcmp(pname, "input-device") != 0 &&
117 	    strcmp(pname, "output-device") != 0)
118 		return (0);
119 
120 	strcpy(nv->kanv_name, pname);
121 	switch (cons_type()) {
122 	case 0:
123 		if (strcmp(pname, "input-device") == 0)
124 			(void) strcpy(nv->kanv_val, "keyboard");
125 		else
126 			(void) strcpy(nv->kanv_val, "screen");
127 		break;
128 	case 1:
129 		(void) strcpy(nv->kanv_val, "ttya");
130 		break;
131 	case 2:
132 		(void) strcpy(nv->kanv_val, "ttyb");
133 		break;
134 	}
135 
136 	return (1);
137 }
138 
139 static int
140 kctl_props_get(char *pname, kmdb_auxv_nv_t *valnv,
141     kmdb_auxv_nv_t *modenv, int (*preader)(kmdb_auxv_nv_t *, char *, void *),
142     void *arg)
143 {
144 #ifdef __amd64
145 	/*
146 	 * The current implementation of the amd64 shim layer doesn't support
147 	 * the use of the BOP_* calls with stack-allocated buffers.
148 	 */
149 	static
150 #endif
151 	char modepname[25];
152 
153 	if (!preader(valnv, pname, arg))
154 		return (0);
155 
156 	if (*valnv->kanv_val == '/')
157 		return (1);
158 
159 	snprintf(modepname, sizeof (modepname), "%s-mode", valnv->kanv_val);
160 
161 	return (preader(modenv, modepname, arg) ? 2 : 1);
162 }
163 
164 /*
165  * We don't have any property-walking routines, so we have to specifically
166  * query and thus have guilty knowledge of the properties that the
167  * debugger wants to see.
168  */
169 #define	KCTL_PROPNV_NENT		4
170 
171 static kmdb_auxv_nv_t *
172 kctl_pcache_create(int *nprops)
173 {
174 	int (*preader)(kmdb_auxv_nv_t *, char *, void *);
175 	kmdb_auxv_nv_t *pnv;
176 	size_t psz = sizeof (kmdb_auxv_nv_t) * KCTL_PROPNV_NENT;
177 	void *arg;
178 	int np = 0;
179 
180 	if (kctl.kctl_boot_loaded) {
181 		preader = kctl_boot_prop_read;
182 		arg = NULL;
183 	} else {
184 		preader = kctl_ddi_prop_read;
185 		arg = ddi_find_devinfo("options", -1, 0);
186 	}
187 
188 	pnv = kobj_alloc(psz, KM_WAIT);
189 
190 	np += kctl_props_get("input-device", &pnv[np], &pnv[np + 1], preader,
191 	    arg);
192 	np += kctl_props_get("output-device", &pnv[np], &pnv[np + 1], preader,
193 	    arg);
194 
195 	*nprops = np;
196 	return (pnv);
197 }
198 
199 static void
200 kctl_pcache_destroy(kmdb_auxv_nv_t *pnv)
201 {
202 	kobj_free(pnv, sizeof (kmdb_auxv_nv_t) * KCTL_PROPNV_NENT);
203 }
204 
205 /*ARGSUSED*/
206 static void
207 kctl_cpu_init(void)
208 {
209 }
210 
211 void
212 kctl_auxv_init_isadep(kmdb_auxv_t *kav, void *romp)
213 {
214 	kav->kav_pcache = kctl_pcache_create(&kav->kav_nprops);
215 	kav->kav_romp = romp;
216 }
217 
218 void
219 kctl_auxv_fini_isadep(kmdb_auxv_t *kav)
220 {
221 	if (kav->kav_pcache != NULL)
222 		kctl_pcache_destroy(kav->kav_pcache);
223 }
224 
225 int
226 kctl_preactivate_isadep(void)
227 {
228 	return (0);
229 }
230 
231 /*ARGSUSED*/
232 int
233 kctl_activate_isadep(kdi_debugvec_t *dvec)
234 {
235 	dvec->dv_kctl_cpu_init = kctl_cpu_init;
236 	dvec->dv_kctl_vmready = hat_kdi_init;
237 
238 	if (!kctl.kctl_boot_loaded)
239 		hat_kdi_init();
240 
241 	return (0);
242 }
243 
244 void
245 kctl_depreactivate_isadep(void)
246 {
247 }
248 
249 void
250 kctl_deactivate_isadep(void)
251 {
252 	hat_kdi_fini();
253 }
254 
255 #if defined(__amd64)
256 void *
257 kctl_boot_tmpinit(void)
258 {
259 	/*
260 	 * Many common kernel functions assume that GSBASE has been initialized,
261 	 * and fail horribly if it hasn't.  We'll install a pointer to a dummy
262 	 * cpu_t for use during our initialization.
263 	 */
264 	cpu_t *old = (cpu_t *)rdmsr(MSR_AMD_GSBASE);
265 
266 	wrmsr(MSR_AMD_GSBASE, (uint64_t)kobj_zalloc(sizeof (cpu_t), KM_TMP));
267 	return (old);
268 }
269 
270 void
271 kctl_boot_tmpfini(void *old)
272 {
273 	wrmsr(MSR_AMD_GSBASE, (uint64_t)old);
274 }
275 
276 #else
277 
278 void *
279 kctl_boot_tmpinit(void)
280 {
281 	/*
282 	 * Many common kernel functions assume that %gs has been initialized,
283 	 * and fail horribly if it hasn't.  Boot has reserved a descriptor for
284 	 * us (GS_GDT) in its GDT, a descriptor which we'll use to describe our
285 	 * dummy cpu_t.  We then set %gs to refer to this descriptor.
286 	 */
287 	cpu_t *cpu = kobj_zalloc(sizeof (cpu_t), KM_TMP);
288 	uintptr_t old;
289 	desctbr_t bgdt;
290 	user_desc_t *gsdesc;
291 
292 	rd_gdtr(&bgdt);
293 	gsdesc = (user_desc_t *)(bgdt.dtr_base + GS_GDT);
294 
295 	USEGD_SETBASE(gsdesc, (uintptr_t)cpu);
296 	USEGD_SETLIMIT(gsdesc, sizeof (cpu_t));
297 
298 	old = getgs();
299 	setgs(GS_GDT);
300 
301 	return ((void *)old);
302 }
303 
304 void
305 kctl_boot_tmpfini(void *old)
306 {
307 	setgs((uintptr_t)old);
308 }
309 #endif
310