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 <sys/types.h> 30 #include <sys/cpr.h> 31 #include <sys/promimpl.h> 32 #include <sys/privregs.h> 33 #include <sys/stack.h> 34 #include <sys/cpuvar.h> 35 #include "cprboot.h" 36 37 38 #define TIMEOUT_MSECS 1000 39 40 41 /* 42 * globals 43 */ 44 int cpr_test_mode; 45 csu_md_t mdinfo; 46 caddr_t tmp_stack; 47 uint_t cb_mid; 48 uint_t cb_clock_freq; 49 uint_t cpu_delay; 50 51 52 /* 53 * file scope 54 */ 55 typedef void (*tlb_func_t)(int, caddr_t, tte_t *); 56 static uint_t mdlen; 57 static cpuset_t slave_set; 58 static int has_scbc; 59 60 61 /* 62 * check machdep desc and cpr_machdep info 63 * 64 * sets globals: 65 * mdinfo 66 * mdlen 67 */ 68 int 69 cb_check_machdep(void) 70 { 71 uint16_t wst32, wst64; 72 char *fmt, *str; 73 cmd_t cmach; 74 75 str = "cb_check_machdep"; 76 CB_VPRINTF((ent_fmt, str, entry)); 77 78 /* 79 * get machdep desc and set length of prom words 80 */ 81 SF_DCOPY(cmach); 82 if (cmach.md_magic != CPR_MACHDEP_MAGIC) { 83 prom_printf("%s: bad machdep magic 0x%x, expect 0x%x\n", 84 str, cmach.md_magic, CPR_MACHDEP_MAGIC); 85 return (ERR); 86 } 87 mdlen = cmach.md_size - sizeof (csu_md_t); 88 89 /* 90 * get machep info, check for valid stack bias and wstate 91 */ 92 SF_DCOPY(mdinfo); 93 fmt = "found bad statefile data: %s (0x%x), expect 0x%x or 0x%x\n"; 94 if (mdinfo.ksb != 0x0 && mdinfo.ksb != V9BIAS64) { 95 prom_printf(fmt, "stack bias", mdinfo.ksb, 0, V9BIAS64); 96 return (ERR); 97 } 98 wst32 = WSTATE(WSTATE_U32, WSTATE_K32); 99 wst64 = WSTATE(WSTATE_U32, WSTATE_K64); 100 if (mdinfo.kwstate != wst32 && mdinfo.kwstate != wst64) { 101 prom_printf(fmt, "wstate", mdinfo.kwstate, wst32, wst64); 102 return (ERR); 103 } 104 105 return (0); 106 } 107 108 109 /* 110 * interpret saved prom words 111 */ 112 int 113 cb_interpret(void) 114 { 115 int bytes, wlen, s; 116 char minibuf[60]; 117 char *words; 118 119 CB_VENTRY(cb_interpret); 120 121 /* 122 * The variable length machdep section for sun4u consists of 123 * a sequence of null-terminated strings stored contiguously. 124 * 125 * The first string defines Forth words which help the prom 126 * handle kernel translations. 127 * 128 * The second string defines Forth words required by kadb to 129 * interface with the prom when a trap is taken. 130 */ 131 words = SF_DATA(); 132 bytes = mdlen; 133 while (bytes) { 134 wlen = prom_strlen(words) + 1; /* include the null */ 135 if (verbose) { 136 s = sizeof (minibuf) - 4; 137 (void) prom_strncpy(minibuf, words, s); 138 if (wlen > s) 139 (void) prom_strcpy(&minibuf[s], "..."); 140 prom_printf(" interpret \"%s\"\n", minibuf); 141 } 142 prom_interpret(words, 0, 0, 0, 0, 0); 143 words += wlen; 144 bytes -= wlen; 145 } 146 147 /* advance past prom words */ 148 SF_ADV(mdlen); 149 150 return (0); 151 } 152 153 154 /* 155 * write dtlb/itlb entries 156 */ 157 static void 158 restore_tlb(struct sun4u_tlb *utp, int cpu_id) 159 { 160 struct sun4u_tlb *tail; 161 tlb_func_t tfunc; 162 caddr_t virt; 163 char tname; 164 165 if (utp == mdinfo.dtte) { 166 tfunc = set_dtlb_entry; 167 tname = 'd'; 168 } else if (utp == mdinfo.itte) { 169 tfunc = set_itlb_entry; 170 tname = 'i'; 171 } 172 173 for (tail = utp + CPR_MAX_TLB; utp < tail; utp++) { 174 if (utp->va_tag == NULL) 175 continue; 176 virt = (caddr_t)utp->va_tag; 177 (*tfunc)(utp->index, virt, &utp->tte); 178 if (verbose || CPR_DBG(4)) { 179 prom_printf(" cpu_id %d: write %ctlb " 180 "(index %x, virt 0x%lx, size 0x%x)\n", 181 cpu_id, tname, utp->index, utp->va_tag, 182 TTEBYTES(utp->tte.tte_size)); 183 } 184 } 185 } 186 187 188 /* 189 * install locked tlb entries for the kernel and cpr module; 190 * also sets up the tmp stack 191 */ 192 int 193 cb_ksetup(void) 194 { 195 CB_VENTRY(cb_ksetup); 196 197 restore_tlb(mdinfo.dtte, cb_mid); 198 restore_tlb(mdinfo.itte, cb_mid); 199 tmp_stack = (caddr_t)(mdinfo.tmp_stack + mdinfo.tmp_stacksize); 200 201 return (0); 202 } 203 204 205 static void 206 cb_park_err(int cpu_id) 207 { 208 prom_printf("\ncpu_id %d did not stop!...\n", cpu_id); 209 cb_exit_to_mon(); 210 } 211 212 213 /* 214 * local copy of an older interface for OBP revs < 4.6 215 */ 216 static int 217 cb_prom_stop_self(void) 218 { 219 cell_t ci[3]; 220 221 ci[0] = p1275_ptr2cell("SUNW,stop-self"); /* Service name */ 222 ci[1] = (cell_t)0; /* #argument cells */ 223 ci[2] = (cell_t)0; /* #result cells */ 224 (void) p1275_cif_handler(&ci); /* Do NOT lock */ 225 return (0); 226 } 227 228 229 /* 230 * install locked tlb entries and spin or park in a prom idle-loop 231 */ 232 void 233 slave_init(int cpu_id) 234 { 235 restore_tlb(mdinfo.dtte, cpu_id); 236 restore_tlb(mdinfo.itte, cpu_id); 237 CPUSET_ADD(slave_set, cpu_id); 238 membar_stld(); 239 if (has_scbc) { 240 /* just spin, master will park this cpu */ 241 /* CONSTCOND */ 242 while (1); 243 } else { 244 (void) cb_prom_stop_self(); 245 cb_park_err(cpu_id); 246 } 247 } 248 249 250 /* 251 * when any cpu is started, they naturally rely on the prom for all 252 * text/data translations until switching to the kernel trap table. 253 * to jump back into the cpr module and to restart slave cpus, cprboot 254 * needs to reinstall translations for the nucleus and some cpr pages. 255 * 256 * the easy method is creating one set of global translations available 257 * to all cpus with prom_map(); unfortunately, a 4MB "map" request will 258 * allocate and overwrite a few pages, and these are often kernel pages 259 * that were just restored. 260 * 261 * to solve the "map" problem, all cpus install their own set of locked 262 * tlb entries to translate the nucleus and parts of the cpr module; 263 * after all cpus have switched to kernel traps, any of these locked 264 * tlb entries for pages outside the nucleus will be cleared. 265 */ 266 int 267 cb_mpsetup(void) 268 { 269 struct sun4u_cpu_info *scip, *tail; 270 int timeout, ncpu; 271 char *str, *intf; 272 273 intf = "SUNW,stop-cpu-by-cpuid"; 274 has_scbc = (prom_test(intf) == 0); 275 CB_VPRINTF(("\n\"%s\" test %d\n", intf, has_scbc)); 276 277 str = "cb_mp_setup"; 278 CB_VPRINTF((ent_fmt, str, entry)); 279 280 /* 281 * launch any slave cpus from the .sci array into cprboot text 282 * and wait about a second for them to checkin with slave_set 283 */ 284 ncpu = 0; 285 CPUSET_ZERO(slave_set); 286 for (scip = mdinfo.sci, tail = scip + NCPU; scip < tail; scip++) { 287 if (scip->node == 0 || scip->cpu_id == cb_mid) 288 continue; 289 (void) prom_startcpu(scip->node, 290 (caddr_t)cpu_launch, scip->cpu_id); 291 292 for (timeout = TIMEOUT_MSECS; timeout; timeout--) { 293 if (CPU_IN_SET(slave_set, scip->cpu_id)) 294 break; 295 cb_usec_wait(MILLISEC); 296 } 297 298 if (timeout == 0) { 299 prom_printf("\n%s: cpu did not start, " 300 "cpu_id %d, node 0x%x\n", 301 prog, scip->cpu_id, scip->node); 302 return (ERR); 303 } 304 305 if (has_scbc && prom_stopcpu_bycpuid(scip->cpu_id)) 306 cb_park_err(scip->cpu_id); 307 308 ncpu++; 309 } 310 311 if (verbose && ncpu) 312 prom_printf("\n%s: slave cpu count: %d\n", str, ncpu); 313 314 return (0); 315 } 316