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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/promif_impl.h> 30 #include <sys/machsystm.h> 31 #include <sys/lpad.h> 32 #include <sys/vmsystm.h> 33 #include <sys/prom_plat.h> 34 #include <sys/ldoms.h> 35 #include <sys/kobj.h> 36 #include <sys/reboot.h> 37 #include <sys/hypervisor_api.h> 38 #include <sys/mdesc.h> 39 #include <sys/mach_descrip.h> 40 41 #ifndef _KMDB 42 static processorid_t cif_cpu; 43 static struct translation *cif_prom_trans; 44 static size_t cif_prom_ntrans; 45 46 int cif_cpu_mp_ready; 47 int (*prom_cif_handler)(void *) = NULL; 48 #endif 49 50 #ifdef DEBUG 51 uint_t cif_debug; 52 #endif /* DEBUG */ 53 54 extern int (*cif_handler)(void *); 55 56 typedef struct { 57 char *name; 58 cif_func_t func; 59 } cif_callback_t; 60 61 static cif_callback_t cb_table[] = { 62 { "getprop", promif_getprop }, 63 { "getproplen", promif_getproplen }, 64 { "nextprop", promif_nextprop }, 65 { "peer", promif_nextnode }, 66 { "child", promif_childnode }, 67 { "parent", promif_parentnode }, 68 { "enter", promif_enter_mon }, 69 { "exit", promif_exit_to_mon }, 70 { "boot", promif_reboot }, 71 { "write", promif_write }, 72 { "read", promif_read }, 73 { "interpret", promif_interpret }, 74 { "finddevice", promif_finddevice }, 75 { "instance-to-package", promif_instance_to_package }, 76 #ifndef _KMDB 77 { "setprop", promif_setprop }, 78 { "test", promif_test }, 79 { "instance-to-path", promif_instance_to_path }, 80 { "SUNW,power-off", promif_power_off }, 81 { "SUNW,asr-list-keys-len", promif_asr_list_keys_len }, 82 { "SUNW,asr-list-keys", promif_asr_list_keys }, 83 { "SUNW,asr-export-len", promif_asr_export_len }, 84 { "SUNW,asr-export", promif_asr_export }, 85 { "SUNW,set-security-key", promif_set_security_key }, 86 { "SUNW,get-security-key", promif_get_security_key }, 87 { "SUNW,start-cpu-by-cpuid", promif_start_cpu }, 88 { "SUNW,set-trap-table", promif_set_mmfsa_traptable }, 89 { "SUNW,set-sun4v-api-version", promif_set_sun4v_api_version }, 90 { "SUNW,get-sun4v-api-version", promif_get_sun4v_api_version }, 91 #endif 92 { NULL, NULL } 93 }; 94 95 cif_func_t 96 promif_find_cif_callback(char *opname) 97 { 98 cif_callback_t *cb; 99 100 if (opname == NULL) 101 return (NULL); 102 103 for (cb = cb_table; cb->name; cb++) { 104 if (prom_strcmp(cb->name, opname) == 0) 105 break; 106 } 107 108 return (cb->func); 109 } 110 111 static int 112 kern_cif_handler(void *p) 113 { 114 cell_t *ci = (cell_t *)p; 115 char *opname; 116 cif_func_t func; 117 int rv; 118 119 ASSERT(cif_handler == kern_cif_handler); 120 121 #ifndef _KMDB 122 cif_cpu = getprocessorid(); 123 #endif 124 125 opname = p1275_cell2ptr(ci[0]); 126 127 /* lookup the callback for the desired operation */ 128 func = promif_find_cif_callback(opname); 129 130 if (func == NULL) { 131 #ifdef _KMDB 132 prom_fatal_error("sun4v unsupported CIFs\n"); 133 #else 134 cmn_err(CE_CONT, "!sun4v unsupported CIF: %s\n", opname); 135 return (-1); 136 #endif 137 } 138 139 /* callback found, execute it */ 140 rv = func(p); 141 142 #ifndef _KMDB 143 cif_cpu = -1; 144 #endif 145 146 return (rv); 147 } 148 149 #ifdef _KMDB 150 151 void 152 cif_init(char *pgmname, caddr_t root, ihandle_t in, ihandle_t out, 153 phandle_t pin, phandle_t pout, pnode_t chosen, pnode_t options) 154 { 155 /* initialize pointer to a copy of OBP device tree */ 156 promif_stree_setroot(root); 157 158 promif_set_nodes(chosen, options); 159 160 /* initialize io parameters */ 161 promif_io_init(in, out, pin, pout); 162 163 /* 164 * Switch CIF handler to the kernel. 165 */ 166 if (pgmname != NULL) 167 prom_init(pgmname, (void *)kern_cif_handler); 168 else 169 cif_handler = kern_cif_handler; 170 } 171 172 #else 173 174 static void cache_prom_data(void); 175 176 /* 177 * This function returns 1 if the current thread is executing in 178 * the CIF and 0 otherwise. This is useful information to know 179 * since code that implements CIF handlers can assume that it has 180 * gone through the kern_preprom() entry point, implying it is 181 * running single threaded, has preemption disabled, etc. 182 */ 183 int 184 promif_in_cif(void) 185 { 186 int mycpuid = getprocessorid(); 187 188 return ((cif_cpu == mycpuid) ? 1 : 0); 189 } 190 191 /* 192 * Check that all cpus in the MD are within range (< NCPU). Attempt 193 * to stop any that aren't. 194 */ 195 static void 196 cif_check_cpus(void) 197 { 198 md_t *mdp; 199 mde_cookie_t rootnode; 200 size_t listsz; 201 int i; 202 mde_cookie_t *listp = NULL; 203 int num_nodes; 204 uint64_t cpuid; 205 int status; 206 207 mdp = md_get_handle(); 208 ASSERT(mdp); 209 210 rootnode = md_root_node(mdp); 211 ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); 212 213 num_nodes = md_node_count(mdp); 214 ASSERT(num_nodes > 0); 215 216 listsz = num_nodes * sizeof (mde_cookie_t); 217 listp = kmem_zalloc(listsz, KM_SLEEP); 218 219 num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"), 220 md_find_name(mdp, "fwd"), listp); 221 222 if (num_nodes <= 0) 223 goto done; 224 225 for (i = 0; i < num_nodes; i++) { 226 if (md_get_prop_val(mdp, listp[i], "id", &cpuid)) { 227 cmn_err(CE_WARN, "cif_check_cpus: " 228 "CPU instance %d has no 'id' property", i); 229 continue; 230 } 231 232 mutex_enter(&cpu_lock); 233 234 if (cpuid >= NCPU) { 235 status = stopcpu_bycpuid(cpuid); 236 if (status != 0 && status != ENOTSUP) 237 cmn_err(CE_PANIC, "failed to stop cpu %lu (%d)", 238 cpuid, status); 239 } 240 241 mutex_exit(&cpu_lock); 242 } 243 244 done: 245 kmem_free(listp, listsz); 246 } 247 248 void 249 cif_init(void) 250 { 251 void (*kmdb_cb)(void); 252 uint64_t rtba; 253 uint64_t rv; 254 255 /* 256 * Check if domaining is enabled. If not, do not 257 * initialize the kernel CIF handler. 258 */ 259 if (!(domaining_capabilities & DOMAINING_ENABLED)) 260 return; 261 262 /* 263 * Cache PROM data that is needed later, e.g. a shadow 264 * copy of the device tree, IO mappings, etc. 265 */ 266 cache_prom_data(); 267 268 /* 269 * Prepare to take over the get/set of environmental variables. 270 */ 271 promif_prop_init(); 272 273 /* 274 * Switch CIF handler to the kernel. 275 */ 276 prom_cif_handler = cif_handler; 277 278 promif_preprom(); 279 cif_handler = kern_cif_handler; 280 281 /* 282 * Take over rtba for the boot CPU. The rtba for 283 * all other CPUs are set as they enter the system. 284 */ 285 rtba = va_to_pa(&trap_table); 286 if ((rv = hv_cpu_set_rtba(&rtba)) != H_EOK) 287 panic("hv_cpu_set_rtba failed: %ld\n", rv); 288 289 promif_postprom(); 290 291 /* 292 * If the system has been booted with kmdb we need kmdb to 293 * use the kernel cif handler instead of the PROM cif handler. 294 */ 295 if (boothowto & RB_KMDB) { 296 kmdb_cb = (void (*)(void))modlookup("misc/kmdbmod", 297 "kctl_switch_promif"); 298 ASSERT(kmdb_cb != NULL); 299 (*kmdb_cb)(); 300 } 301 302 cif_check_cpus(); 303 } 304 305 static void 306 cache_prom_data(void) 307 { 308 /* initialize copy of OBP device tree */ 309 promif_stree_init(); 310 311 /* initialize io parameters */ 312 promif_io_init(); 313 } 314 315 #endif /* _KMDB */ 316