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
cb_check_machdep(void)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
cb_interpret(void)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
restore_tlb(struct sun4u_tlb * utp,int cpu_id)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
cb_ksetup(void)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
cb_park_err(int cpu_id)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
cb_prom_stop_self(void)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
slave_init(int cpu_id)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
cb_mpsetup(void)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