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 2006 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_boot_prop_read(char *pname, char *prop_buf, int buf_len)
48 {
49 	int len;
50 	struct bootops *ops = kctl.kctl_boot_ops;
51 
52 	len = BOP_GETPROPLEN(ops, pname);
53 	if (len > 0 && len <= buf_len) {
54 		(void) BOP_GETPROP(ops, pname, (void *)prop_buf);
55 		return (1);
56 	}
57 
58 	return (0);
59 }
60 
61 static int
62 kctl_ddi_prop_read(char *pname, char *prop_buf, int buf_len)
63 {
64 	dev_info_t *dip = ddi_root_node();
65 	char *val;
66 	int ret = 0;
67 
68 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
69 	    DDI_PROP_DONTPASS, pname, &val) != DDI_SUCCESS)
70 		return (0);
71 
72 	if (strlen(val) < buf_len) {
73 		(void) strcpy(prop_buf, val);
74 		ret = 1;
75 	}
76 
77 	ddi_prop_free(val);
78 	return (ret);
79 }
80 
81 /*
82  * We don't have any property-walking routines, so we have to specifically
83  * query and thus have guilty knowledge of the properties that the
84  * debugger wants to see.
85  *
86  * Here actually we only support four console properties:
87  *     input-device, output-device, ttya-mode, ttyb-mode.
88  */
89 #define	KCTL_PROPNV_NENT		4
90 
91 static kmdb_auxv_nv_t *
92 kctl_pcache_create(int *nprops)
93 {
94 	int (*preader)(char *, char *, int);
95 	kmdb_auxv_nv_t *pnv;
96 	size_t psz = sizeof (kmdb_auxv_nv_t) * KCTL_PROPNV_NENT;
97 
98 	if (kctl.kctl_boot_loaded) {
99 		preader = kctl_boot_prop_read;
100 	} else {
101 		preader = kctl_ddi_prop_read;
102 	}
103 
104 	pnv = kobj_alloc(psz, KM_WAIT);
105 
106 	(void) strcpy((&pnv[0])->kanv_name, "input-device");
107 	(void) strcpy((&pnv[1])->kanv_name, "output-device");
108 	(void) strcpy((&pnv[2])->kanv_name, "ttya-mode");
109 	(void) strcpy((&pnv[3])->kanv_name, "ttyb-mode");
110 
111 	/*
112 	 * console is defined by "console" property, with
113 	 * fallback on the old "input-device" property.
114 	 */
115 	(void) strcpy((&pnv[0])->kanv_val, "text");	/* default to screen */
116 	if (!preader("console", (&pnv[0])->kanv_val,
117 	    sizeof ((&pnv[0])->kanv_val)))
118 		(void) preader("input-device", (&pnv[0])->kanv_val,
119 		    sizeof ((&pnv[0])->kanv_val));
120 
121 	if (strcmp((&pnv[0])->kanv_val, "ttya") == 0 ||
122 	    strcmp((&pnv[0])->kanv_val, "ttyb") == 0) {
123 		(void) strcpy((&pnv[1])->kanv_val, (&pnv[0])->kanv_val);
124 	} else {
125 		(void) strcpy((&pnv[0])->kanv_val, "keyboard");
126 		(void) strcpy((&pnv[1])->kanv_val, "screen");
127 	}
128 
129 	if (!preader((&pnv[2])->kanv_name, (&pnv[2])->kanv_val,
130 	    sizeof ((&pnv[2])->kanv_val)))
131 		(void) strcpy((&pnv[2])->kanv_val, "9600,8,n,1,-");
132 
133 	if (!preader((&pnv[3])->kanv_name, (&pnv[3])->kanv_val,
134 	    sizeof ((&pnv[3])->kanv_val)))
135 		(void) strcpy((&pnv[3])->kanv_val, "9600,8,n,1,-");
136 
137 	*nprops = KCTL_PROPNV_NENT;
138 	return (pnv);
139 }
140 
141 static void
142 kctl_pcache_destroy(kmdb_auxv_nv_t *pnv)
143 {
144 	kobj_free(pnv, sizeof (kmdb_auxv_nv_t) * KCTL_PROPNV_NENT);
145 }
146 
147 /*ARGSUSED*/
148 static void
149 kctl_cpu_init(void)
150 {
151 }
152 
153 void
154 kctl_auxv_init_isadep(kmdb_auxv_t *kav, void *romp)
155 {
156 	kav->kav_pcache = kctl_pcache_create(&kav->kav_nprops);
157 	kav->kav_romp = romp;
158 }
159 
160 void
161 kctl_auxv_fini_isadep(kmdb_auxv_t *kav)
162 {
163 	if (kav->kav_pcache != NULL)
164 		kctl_pcache_destroy(kav->kav_pcache);
165 }
166 
167 int
168 kctl_preactivate_isadep(void)
169 {
170 	return (0);
171 }
172 
173 /*ARGSUSED*/
174 int
175 kctl_activate_isadep(kdi_debugvec_t *dvec)
176 {
177 	dvec->dv_kctl_cpu_init = kctl_cpu_init;
178 	dvec->dv_kctl_vmready = hat_kdi_init;
179 
180 	if (!kctl.kctl_boot_loaded)
181 		hat_kdi_init();
182 
183 	return (0);
184 }
185 
186 void
187 kctl_depreactivate_isadep(void)
188 {
189 }
190 
191 void
192 kctl_deactivate_isadep(void)
193 {
194 	hat_kdi_fini();
195 }
196 
197 #if defined(__amd64)
198 void *
199 kctl_boot_tmpinit(void)
200 {
201 	/*
202 	 * Many common kernel functions assume that GSBASE has been initialized,
203 	 * and fail horribly if it hasn't.  We'll install a pointer to a dummy
204 	 * cpu_t for use during our initialization.
205 	 */
206 	cpu_t *old = (cpu_t *)rdmsr(MSR_AMD_GSBASE);
207 
208 	wrmsr(MSR_AMD_GSBASE, (uint64_t)kobj_zalloc(sizeof (cpu_t), KM_TMP));
209 	return (old);
210 }
211 
212 void
213 kctl_boot_tmpfini(void *old)
214 {
215 	wrmsr(MSR_AMD_GSBASE, (uint64_t)old);
216 }
217 
218 #else
219 
220 void *
221 kctl_boot_tmpinit(void)
222 {
223 	/*
224 	 * Many common kernel functions assume that %gs has been initialized,
225 	 * and fail horribly if it hasn't.  Boot has reserved a descriptor for
226 	 * us (GS_GDT) in its GDT, a descriptor which we'll use to describe our
227 	 * dummy cpu_t.  We then set %gs to refer to this descriptor.
228 	 */
229 	cpu_t *cpu = kobj_zalloc(sizeof (cpu_t), KM_TMP);
230 	uintptr_t old;
231 	desctbr_t bgdt;
232 	user_desc_t *gsdesc;
233 
234 	rd_gdtr(&bgdt);
235 	gsdesc = (user_desc_t *)(bgdt.dtr_base + GS_GDT);
236 
237 	USEGD_SETBASE(gsdesc, (uintptr_t)cpu);
238 	USEGD_SETLIMIT(gsdesc, sizeof (cpu_t));
239 
240 	old = getgs();
241 	setgs(GS_GDT);
242 
243 	return ((void *)old);
244 }
245 
246 void
247 kctl_boot_tmpfini(void *old)
248 {
249 	setgs((uintptr_t)old);
250 }
251 #endif
252