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