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