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