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