xref: /illumos-gate/usr/src/uts/sun4v/promif/promif_emul.c (revision f808c858fa61e7769218966759510a8b1190dfcf)
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