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