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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/promif_impl.h>
28 #include <sys/machsystm.h>
29 #include <sys/lpad.h>
30 #include <sys/vmsystm.h>
31 #include <sys/prom_plat.h>
32 #include <sys/ldoms.h>
33 #include <sys/kobj.h>
34 #include <sys/reboot.h>
35 #include <sys/hypervisor_api.h>
36 #include <sys/mdesc.h>
37 #include <sys/mach_descrip.h>
38 #include <sys/cpu_module.h>
39 #include <vm/seg_kmem.h>
40
41 #ifndef _KMDB
42 #include <sys/pte.h>
43 #include <vm/hat_sfmmu.h>
44 #include <sys/memlist_impl.h>
45
46 static processorid_t cif_cpu;
47 static struct translation *cif_prom_trans;
48 static size_t cif_prom_ntrans;
49
50 int cif_cpu_mp_ready;
51 int (*prom_cif_handler)(void *) = NULL;
52
53 extern struct memlist *phys_avail;
54 extern struct vnode promvp;
55 extern void kdi_tlb_page_unlock(caddr_t, int);
56
57 #define COMBINE(hi, lo) (((uint64_t)(uint32_t)(hi) << 32) | (uint32_t)(lo))
58 #define OFW_PT_START_ADDR 0xfffffffc00000000 /* OBP PT start */
59 #define OFW_PT_END_ADDR 0xffffffffffffffff /* OBP PT end */
60
61 #define PROM_ADDR(a) (((a) >= OFW_START_ADDR && (a) <= OFW_END_ADDR) || \
62 ((a) >= OFW_PT_START_ADDR && (a) <= OFW_PT_END_ADDR))
63 #endif
64
65 #ifdef DEBUG
66 uint_t cif_debug;
67 int prom_free_debug;
68 #define PMFREE_DEBUG(args...) if (prom_free_debug) printf(args)
69 #else
70 #define PMFREE_DEBUG(args...)
71 #endif
72
73 extern int (*cif_handler)(void *);
74
75 typedef struct {
76 char *name;
77 cif_func_t func;
78 } cif_callback_t;
79
80 static cif_callback_t cb_table[] = {
81 { "getprop", promif_getprop },
82 { "getproplen", promif_getproplen },
83 { "nextprop", promif_nextprop },
84 { "peer", promif_nextnode },
85 { "child", promif_childnode },
86 { "parent", promif_parentnode },
87 { "enter", promif_enter_mon },
88 { "exit", promif_exit_to_mon },
89 { "boot", promif_reboot },
90 { "write", promif_write },
91 { "read", promif_read },
92 { "interpret", promif_interpret },
93 { "finddevice", promif_finddevice },
94 { "instance-to-package", promif_instance_to_package },
95 #ifndef _KMDB
96 { "setprop", promif_setprop },
97 { "test", promif_test },
98 { "instance-to-path", promif_instance_to_path },
99 { "SUNW,power-off", promif_power_off },
100 { "SUNW,asr-list-keys-len", promif_asr_list_keys_len },
101 { "SUNW,asr-list-keys", promif_asr_list_keys },
102 { "SUNW,asr-export-len", promif_asr_export_len },
103 { "SUNW,asr-export", promif_asr_export },
104 { "SUNW,set-security-key", promif_set_security_key },
105 { "SUNW,get-security-key", promif_get_security_key },
106 { "SUNW,start-cpu-by-cpuid", promif_start_cpu },
107 { "SUNW,set-trap-table", promif_set_mmfsa_traptable },
108 { "SUNW,set-sun4v-api-version", promif_set_sun4v_api_version },
109 { "SUNW,get-sun4v-api-version", promif_get_sun4v_api_version },
110 #endif
111 { NULL, NULL }
112 };
113
114 cif_func_t
promif_find_cif_callback(char * opname)115 promif_find_cif_callback(char *opname)
116 {
117 cif_callback_t *cb;
118
119 if (opname == NULL)
120 return (NULL);
121
122 for (cb = cb_table; cb->name; cb++) {
123 if (prom_strcmp(cb->name, opname) == 0)
124 break;
125 }
126
127 return (cb->func);
128 }
129
130 static int
kern_cif_handler(void * p)131 kern_cif_handler(void *p)
132 {
133 cell_t *ci = (cell_t *)p;
134 char *opname;
135 cif_func_t func;
136 int rv;
137
138 ASSERT(cif_handler == kern_cif_handler);
139
140 #ifndef _KMDB
141 cif_cpu = getprocessorid();
142 #endif
143
144 opname = p1275_cell2ptr(ci[0]);
145
146 /* lookup the callback for the desired operation */
147 func = promif_find_cif_callback(opname);
148
149 if (func == NULL) {
150 #ifdef _KMDB
151 prom_fatal_error("sun4v unsupported CIFs\n");
152 #else
153 cmn_err(CE_CONT, "!sun4v unsupported CIF: %s\n", opname);
154 return (-1);
155 #endif
156 }
157
158 /* callback found, execute it */
159 rv = func(p);
160
161 #ifndef _KMDB
162 cif_cpu = -1;
163 #endif
164
165 return (rv);
166 }
167
168 #ifdef _KMDB
169
170 void
cif_init(char * pgmname,caddr_t root,ihandle_t in,ihandle_t out,phandle_t pin,phandle_t pout,pnode_t chosen,pnode_t options)171 cif_init(char *pgmname, caddr_t root, ihandle_t in, ihandle_t out,
172 phandle_t pin, phandle_t pout, pnode_t chosen, pnode_t options)
173 {
174 /* initialize pointer to a copy of OBP device tree */
175 promif_stree_setroot(root);
176
177 promif_set_nodes(chosen, options);
178
179 /* initialize io parameters */
180 promif_io_init(in, out, pin, pout);
181
182 /*
183 * Switch CIF handler to the kernel.
184 */
185 if (pgmname != NULL)
186 prom_init(pgmname, (void *)kern_cif_handler);
187 else
188 cif_handler = kern_cif_handler;
189 }
190
191 #else
192
193 static struct translation *
read_prom_mappings(size_t * ntransp)194 read_prom_mappings(size_t *ntransp)
195 {
196 char *prop = "translations";
197 pnode_t node;
198 size_t translen;
199 ihandle_t immu;
200 struct translation *transroot;
201
202 *ntransp = 0;
203
204 /*
205 * the "translations" property is associated with the mmu node
206 */
207 if ((immu = prom_mmu_ihandle()) == (ihandle_t)-1) {
208 PMFREE_DEBUG("no mmu ihandle");
209 return (NULL);
210 }
211 node = (pnode_t)prom_getphandle(immu);
212 if (node == OBP_NONODE || node == OBP_BADNODE) {
213 PMFREE_DEBUG("no mmu node");
214 return (NULL);
215 }
216
217 if ((translen = prom_getproplen(node, prop)) == -1) {
218 PMFREE_DEBUG("no translations property");
219 return (NULL);
220 }
221 transroot = (struct translation *)kmem_zalloc(translen, KM_SLEEP);
222
223 if (prom_getprop(node, prop, (caddr_t)transroot) == -1) {
224 PMFREE_DEBUG("translations getprop failed");
225 kmem_free(transroot, translen);
226 return (NULL);
227 }
228 *ntransp = translen / sizeof (*transroot);
229
230 return (transroot);
231 }
232
233 static void
unmap_prom_mappings(struct translation * transroot,size_t ntransroot)234 unmap_prom_mappings(struct translation *transroot, size_t ntransroot)
235 {
236 int i, j, rv;
237 int npgs, nunmapped, nfreed, nskipped, nskipped_io;
238 char *p;
239 tte_t tte;
240 pfn_t pfn;
241 page_t *pp;
242 uint64_t vaddr;
243 struct translation *promt;
244 cpuset_t other_cpus;
245
246 /*
247 * During startup isa_list is allocated in OBP address space
248 * so it needs to be re-allocated in kernel address space
249 * before OBP memory is unmapped.
250 *
251 * see cpu_setup_common().
252 */
253 p = kmem_zalloc(strlen(isa_list) + 1, KM_SLEEP);
254 (void) strcpy(p, isa_list);
255 isa_list = p;
256
257 nfreed = 0;
258 nunmapped = 0;
259 nskipped = 0;
260 nskipped_io = 0;
261
262 for (i = 0, promt = transroot; i < ntransroot; i++, promt++) {
263 ASSERT(promt->tte_hi != 0);
264 ASSERT32(promt->virt_hi == 0 && promt->size_hi == 0);
265
266 vaddr = COMBINE(promt->virt_hi, promt->virt_lo);
267
268 if (!PROM_ADDR(vaddr)) {
269 nskipped++;
270 continue;
271 }
272
273 npgs = mmu_btopr(COMBINE(promt->size_hi, promt->size_lo));
274
275 if (npgs > 1) {
276 PMFREE_DEBUG("large trans vaddr=0x%lx, npgs=%d\n",
277 vaddr, npgs);
278 }
279 for (j = 0; j < npgs; j++) {
280
281 pfn = sfmmu_vatopfn((caddr_t)vaddr, KHATID, &tte);
282
283 if (pfn == PFN_INVALID) {
284 tte.tte_inthi = promt->tte_hi;
285 tte.tte_intlo = promt->tte_lo;
286 pfn = TTE_TO_PFN((caddr_t)COMBINE(
287 promt->virt_hi, promt->virt_lo), &tte);
288 PMFREE_DEBUG(
289 "no mapping for vaddr=0x%lx (opfn=0x%lx)\n",
290 vaddr, pfn);
291 break;
292 }
293 ASSERT(!TTE_IS_LOCKED(&tte));
294 ASSERT(TTE_IS_8K(&tte));
295
296 /*
297 * Unload the current mapping for the pfn and
298 * if it is the last mapping for a memory page,
299 * free the page.
300 */
301 PMFREE_DEBUG("unmap vaddr=0x%lx pfn=0x%lx", vaddr, pfn);
302
303 hat_unload(kas.a_hat, (caddr_t)vaddr, PAGESIZE,
304 HAT_UNLOAD_UNLOCK);
305
306 if (pf_is_memory(pfn)) {
307 pp = page_numtopp_nolock(pfn);
308 PMFREE_DEBUG(" pp=0x%p", (void *)pp);
309 ASSERT(pp);
310 ASSERT(PAGE_EXCL(pp));
311 ASSERT(PP_ISNORELOC(pp));
312 ASSERT(!PP_ISFREE(pp));
313 ASSERT(page_find(&promvp, pfn));
314 ASSERT(page_get_pagecnt(pp->p_szc) == 1);
315
316 if (pp->p_mapping) {
317 PMFREE_DEBUG(" skip\n");
318 } else {
319 PP_CLRNORELOC(pp);
320 page_destroy(pp, 0);
321 memlist_write_lock();
322 rv = memlist_add_span(pfn << PAGESHIFT,
323 PAGESIZE, &phys_avail);
324 ASSERT(rv == MEML_SPANOP_OK);
325 memlist_write_unlock();
326 PMFREE_DEBUG(" free\n");
327 nfreed++;
328 }
329 } else {
330 nskipped_io++;
331 PMFREE_DEBUG(" skip IO\n");
332 }
333 nunmapped++;
334 vaddr += PAGESIZE;
335 }
336 }
337
338 if (transroot) {
339 PMFREE_DEBUG(
340 "nunmapped=%d nfreed=%d nskipped=%d nskipped_io=%d\n",
341 nunmapped, nfreed, nskipped, nskipped_io);
342 kmem_free(transroot, ntransroot * sizeof (*transroot));
343 }
344
345 /*
346 * Unload OBP permanent mappings.
347 */
348 kdi_tlb_page_unlock((caddr_t)OFW_START_ADDR, 1);
349 kpreempt_disable();
350 other_cpus = cpu_ready_set;
351 CPUSET_DEL(other_cpus, CPU->cpu_id);
352 xt_some(other_cpus, vtag_unmap_perm_tl1, (uint64_t)OFW_START_ADDR,
353 KCONTEXT);
354 kpreempt_enable();
355 }
356
357 static void cache_prom_data(void);
358
359 /*
360 * This function returns 1 if the current thread is executing in
361 * the CIF and 0 otherwise. This is useful information to know
362 * since code that implements CIF handlers can assume that it has
363 * gone through the kern_preprom() entry point, implying it is
364 * running single threaded, has preemption disabled, etc.
365 */
366 int
promif_in_cif(void)367 promif_in_cif(void)
368 {
369 int mycpuid = getprocessorid();
370
371 return ((cif_cpu == mycpuid) ? 1 : 0);
372 }
373
374 /*
375 * Check that all cpus in the MD are within range (< NCPU). Attempt
376 * to stop any that aren't.
377 */
378 static void
cif_check_cpus(void)379 cif_check_cpus(void)
380 {
381 md_t *mdp;
382 mde_cookie_t rootnode;
383 size_t listsz;
384 int i;
385 mde_cookie_t *listp = NULL;
386 int num_nodes;
387 uint64_t cpuid;
388 int status;
389
390 mdp = md_get_handle();
391 ASSERT(mdp);
392
393 rootnode = md_root_node(mdp);
394 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
395
396 num_nodes = md_node_count(mdp);
397 ASSERT(num_nodes > 0);
398
399 listsz = num_nodes * sizeof (mde_cookie_t);
400 listp = kmem_zalloc(listsz, KM_SLEEP);
401
402 num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"),
403 md_find_name(mdp, "fwd"), listp);
404
405 if (num_nodes <= 0)
406 goto done;
407
408 for (i = 0; i < num_nodes; i++) {
409 if (md_get_prop_val(mdp, listp[i], "id", &cpuid)) {
410 cmn_err(CE_WARN, "cif_check_cpus: "
411 "CPU instance %d has no 'id' property", i);
412 continue;
413 }
414
415 mutex_enter(&cpu_lock);
416
417 if (cpuid >= NCPU) {
418 status = stopcpu_bycpuid(cpuid);
419 if (status != 0 && status != ENOTSUP)
420 cmn_err(CE_PANIC, "failed to stop cpu %lu (%d)",
421 cpuid, status);
422 }
423
424 mutex_exit(&cpu_lock);
425 }
426
427 done:
428 kmem_free(listp, listsz);
429 (void) md_fini_handle(mdp);
430 }
431
432 void
cif_init(void)433 cif_init(void)
434 {
435 void (*kmdb_cb)(void);
436 uint64_t rtba;
437 uint64_t rv;
438 size_t ntransroot;
439 struct translation *transroot;
440
441 /*
442 * Check if domaining is enabled. If not, do not
443 * initialize the kernel CIF handler.
444 */
445 if (!domaining_enabled())
446 return;
447
448 transroot = read_prom_mappings(&ntransroot);
449
450 /*
451 * Cache PROM data that is needed later, e.g. a shadow
452 * copy of the device tree, IO mappings, etc.
453 */
454 cache_prom_data();
455
456 /*
457 * Prepare to take over the get/set of environmental variables.
458 */
459 promif_prop_init();
460
461 /*
462 * Switch CIF handler to the kernel.
463 */
464 prom_cif_handler = cif_handler;
465
466 promif_preprom();
467 cif_handler = kern_cif_handler;
468
469 /*
470 * Take over rtba for the boot CPU. The rtba for
471 * all other CPUs are set as they enter the system.
472 */
473 rtba = va_to_pa(&trap_table);
474 if ((rv = hv_cpu_set_rtba(&rtba)) != H_EOK)
475 panic("hv_cpu_set_rtba failed: %ld\n", rv);
476
477 promif_postprom();
478
479 /*
480 * If the system has been booted with kmdb we need kmdb to
481 * use the kernel cif handler instead of the PROM cif handler.
482 */
483 if (boothowto & RB_KMDB) {
484 kmdb_cb = (void (*)(void))modlookup("misc/kmdbmod",
485 "kctl_switch_promif");
486 ASSERT(kmdb_cb != NULL);
487 (*kmdb_cb)();
488 }
489
490 cif_check_cpus();
491
492 if (transroot != NULL)
493 unmap_prom_mappings(transroot, ntransroot);
494 }
495
496 static void
cache_prom_data(void)497 cache_prom_data(void)
498 {
499 /* initialize copy of OBP device tree */
500 promif_stree_init();
501
502 /* initialize io parameters */
503 promif_io_init();
504 }
505
506 #endif /* _KMDB */
507