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 39 #ifndef _KMDB 40 static processorid_t cif_cpu; 41 static struct translation *cif_prom_trans; 42 static size_t cif_prom_ntrans; 43 44 int cif_cpu_mp_ready; 45 int (*prom_cif_handler)(void *) = NULL; 46 #endif 47 48 #ifdef DEBUG 49 uint_t cif_debug; 50 #endif /* DEBUG */ 51 52 extern int (*cif_handler)(void *); 53 54 typedef struct { 55 char *name; 56 cif_func_t func; 57 } cif_callback_t; 58 59 static cif_callback_t cb_table[] = { 60 { "getprop", promif_getprop }, 61 { "getproplen", promif_getproplen }, 62 { "nextprop", promif_nextprop }, 63 { "peer", promif_nextnode }, 64 { "child", promif_childnode }, 65 { "parent", promif_parentnode }, 66 { "enter", promif_enter_mon }, 67 { "exit", promif_exit_to_mon }, 68 { "boot", promif_reboot }, 69 { "write", promif_write }, 70 { "read", promif_read }, 71 { "interpret", promif_interpret }, 72 { "finddevice", promif_finddevice }, 73 { "instance-to-package", promif_instance_to_package }, 74 #ifndef _KMDB 75 { "setprop", promif_setprop }, 76 { "test", promif_test }, 77 { "instance-to-path", promif_instance_to_path }, 78 { "SUNW,power-off", promif_power_off }, 79 { "SUNW,asr-list-keys-len", promif_asr_list_keys_len }, 80 { "SUNW,asr-list-keys", promif_asr_list_keys }, 81 { "SUNW,asr-export-len", promif_asr_export_len }, 82 { "SUNW,asr-export", promif_asr_export }, 83 { "SUNW,set-security-key", promif_set_security_key }, 84 { "SUNW,get-security-key", promif_get_security_key }, 85 { "SUNW,start-cpu-by-cpuid", promif_start_cpu }, 86 { "SUNW,set-trap-table", promif_set_mmfsa_traptable }, 87 { "SUNW,set-sun4v-api-version", promif_set_sun4v_api_version }, 88 { "SUNW,get-sun4v-api-version", promif_get_sun4v_api_version }, 89 #endif 90 { NULL, NULL } 91 }; 92 93 cif_func_t 94 promif_find_cif_callback(char *opname) 95 { 96 cif_callback_t *cb; 97 98 if (opname == NULL) 99 return (NULL); 100 101 for (cb = cb_table; cb->name; cb++) { 102 if (prom_strcmp(cb->name, opname) == 0) 103 break; 104 } 105 106 return (cb->func); 107 } 108 109 static int 110 kern_cif_handler(void *p) 111 { 112 cell_t *ci = (cell_t *)p; 113 char *opname; 114 cif_func_t func; 115 int rv; 116 117 ASSERT(cif_handler == kern_cif_handler); 118 119 #ifndef _KMDB 120 cif_cpu = getprocessorid(); 121 #endif 122 123 opname = p1275_cell2ptr(ci[0]); 124 125 /* lookup the callback for the desired operation */ 126 func = promif_find_cif_callback(opname); 127 128 if (func == NULL) { 129 #ifdef _KMDB 130 prom_fatal_error("sun4v unsupported CIFs\n"); 131 #else 132 cmn_err(CE_CONT, "!sun4v unsupported CIF: %s\n", opname); 133 return (-1); 134 #endif 135 } 136 137 /* callback found, execute it */ 138 rv = func(p); 139 140 #ifndef _KMDB 141 cif_cpu = -1; 142 #endif 143 144 return (rv); 145 } 146 147 #ifdef _KMDB 148 149 void 150 cif_init(char *pgmname, caddr_t root, ihandle_t in, ihandle_t out, 151 phandle_t pin, phandle_t pout, pnode_t chosen, pnode_t options) 152 { 153 /* initialize pointer to a copy of OBP device tree */ 154 promif_stree_setroot(root); 155 156 promif_set_nodes(chosen, options); 157 158 /* initialize io parameters */ 159 promif_io_init(in, out, pin, pout); 160 161 /* 162 * Switch CIF handler to the kernel. 163 */ 164 if (pgmname != NULL) 165 prom_init(pgmname, (void *)kern_cif_handler); 166 else 167 cif_handler = kern_cif_handler; 168 } 169 170 #else 171 172 static void cache_prom_data(void); 173 174 /* 175 * This function returns 1 if the current thread is executing in 176 * the CIF and 0 otherwise. This is useful information to know 177 * since code that implements CIF handlers can assume that it has 178 * gone through the kern_preprom() entry point, implying it is 179 * running single threaded, has preemption disabled, etc. 180 */ 181 int 182 promif_in_cif(void) 183 { 184 int mycpuid = getprocessorid(); 185 186 return ((cif_cpu == mycpuid) ? 1 : 0); 187 } 188 189 void 190 cif_init(void) 191 { 192 void (*kmdb_cb)(void); 193 uint64_t rtba; 194 uint64_t rv; 195 196 /* 197 * Check if domaining is enabled. If not, do not 198 * initialize the kernel CIF handler. 199 */ 200 if (!domaining_enabled) 201 return; 202 203 /* 204 * Cache PROM data that is needed later, e.g. a shadow 205 * copy of the device tree, IO mappings, etc. 206 */ 207 cache_prom_data(); 208 209 /* 210 * Prepare to take over the get/set of environmental variables. 211 */ 212 promif_prop_init(); 213 214 /* 215 * Switch CIF handler to the kernel. 216 */ 217 prom_cif_handler = cif_handler; 218 219 promif_preprom(); 220 cif_handler = kern_cif_handler; 221 222 /* 223 * Take over rtba for the boot CPU. The rtba for 224 * all other CPUs are set as they enter the system. 225 */ 226 rtba = va_to_pa(&trap_table); 227 if ((rv = hv_cpu_set_rtba(&rtba)) != H_EOK) 228 panic("hv_cpu_set_rtba failed: %ld\n", rv); 229 230 promif_postprom(); 231 232 /* 233 * If the system has been booted with kmdb we need kmdb to 234 * use the kernel cif handler instead of the PROM cif handler. 235 */ 236 if (boothowto & RB_KMDB) { 237 kmdb_cb = (void (*)(void))modlookup("misc/kmdbmod", 238 "kctl_switch_promif"); 239 ASSERT(kmdb_cb != NULL); 240 (*kmdb_cb)(); 241 } 242 } 243 244 static void 245 cache_prom_data(void) 246 { 247 /* initialize copy of OBP device tree */ 248 promif_stree_init(); 249 250 /* initialize io parameters */ 251 promif_io_init(); 252 } 253 254 255 /* 256 * Platform-specific actions to be taken when all cpus are running 257 * in the OS. 258 */ 259 void 260 cpu_mp_init(void) 261 { 262 if (!domaining_enabled) 263 return; 264 265 cif_cpu_mp_ready = 1; 266 } 267 268 #endif /* _KMDB */ 269