Home | History | Annotate | Download | only in promif
      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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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