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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 2000 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <strings.h>
33 
34 #include <fcode/private.h>
35 #include <fcode/log.h>
36 
37 #include <fcdriver/fcdriver.h>
38 
39 static device_t *builtin_driver_device;
40 
41 static int
is_device_builtin_package(fcode_env_t * env,device_t * d)42 is_device_builtin_package(fcode_env_t *env, device_t *d)
43 {
44 	return (d == builtin_driver_device);
45 }
46 
47 static char *dropin_name;
48 
49 /*
50  * do-builtin-dropin  ( -- )
51  * Convoluted name just in case someone has "do-dropin" word in Fcode.
52  * Somewhat different from do-dropin in OBP, as we just load the Fcode, we
53  * don't do a byte-load.
54  */
55 static void
do_builtin_dropin(fcode_env_t * env)56 do_builtin_dropin(fcode_env_t *env)
57 {
58 	fc_cell_t len, result;
59 	char *buf;
60 	int error;
61 	static char func_name[] = "do-builtin-dropin";
62 	extern int check_fcode_header(char *, uchar_t *, int);
63 
64 	if (dropin_name == NULL) {
65 		log_message(MSG_ERROR, "%s: dropin_name not set\n", func_name);
66 		return;
67 	}
68 	debug_msg(DEBUG_FIND_FCODE, "%s: '%s'\n", func_name, dropin_name);
69 	error = fc_run_priv(env->private, "sunos,get-fcode-size", 1, 1,
70 	    fc_ptr2cell(dropin_name), &len);
71 	if (error)
72 		return;
73 	if (len == 0) {
74 		log_message(MSG_WARN, "%s: '%s' zero length Fcode\n",
75 		    func_name, dropin_name);
76 		return;
77 	}
78 	buf = MALLOC(len);
79 	error = fc_run_priv(env->private, "sunos,get-fcode", 3, 1,
80 	    fc_ptr2cell(dropin_name), fc_ptr2cell(buf), len, &result);
81 	if (error) {
82 		FREE(buf);
83 		return;
84 	}
85 
86 	if (check_fcode_header(dropin_name, (uchar_t *)buf, len) == 0)
87 		log_message(MSG_WARN, "%s: '%s' fcode header NOT OK\n",
88 		    func_name, dropin_name);
89 
90 	debug_msg(DEBUG_FIND_FCODE,
91 	    "%s: '%s' doing byte-load len: %x\n", func_name, dropin_name,
92 	    (int)len);
93 	PUSH(DS, (fstack_t)buf);
94 	PUSH(DS, 1);
95 	byte_load(env);
96 }
97 
98 static void
do_builtin_file(fcode_env_t * env)99 do_builtin_file(fcode_env_t *env)
100 {
101 	char *fname;
102 	static char func_name[] = "do-builtin-file";
103 	fstack_t d;
104 
105 	if (dropin_name == NULL) {
106 		log_message(MSG_ERROR, "%s: dropin_name not set\n", func_name);
107 		return;
108 	}
109 	debug_msg(DEBUG_FIND_FCODE, "%s: '%s'\n", func_name, dropin_name);
110 	push_a_string(env, dropin_name);
111 	load_file(env);
112 	d = POP(DS);
113 	if (d) {
114 		debug_msg(DEBUG_FIND_FCODE, "%s: byte-load '%s'\n", func_name,
115 		    dropin_name);
116 		PUSH(DS, 1);
117 		byte_load(env);
118 	} else
119 		debug_msg(DEBUG_FIND_FCODE, "%s: load_file '%s' FAIL\n",
120 		    func_name, dropin_name);
121 }
122 
123 /*
124  * We need to lookup the builtin name via an FC_RUN_PRIV call to make sure
125  * the builtin exists.  If it exists, then we need to leave the xt of
126  * do-builtin-dropin on the stack and remember the name for do-dropin.  This is
127  * extremely convoluted because we can't a priori populate
128  * SUNW,builtin-drivers.
129  */
130 static void
builtin_driver_method_hook(fcode_env_t * env)131 builtin_driver_method_hook(fcode_env_t *env)
132 {
133 	device_t *device;
134 	char *method, *path;
135 	fc_cell_t len;
136 	fstack_t d;
137 	int error;
138 	static char func_name[] = "builtin-driver-method-hook";
139 
140 	d = POP(DS);
141 	CONVERT_PHANDLE(env, device, d);
142 	if (!is_device_builtin_package(env, device)) {
143 		PUSH(DS, d);
144 		PUSH(DS, FALSE);
145 		return;
146 	}
147 
148 	method = pop_a_string(env, NULL);
149 
150 	/*
151 	 * Check for file in filesystem.  If it exists, we'll just try to do
152 	 * a do-dropin-file.
153 	 */
154 	if ((path = search_for_fcode_file(env, method)) != NULL) {
155 		debug_msg(DEBUG_FIND_FCODE, "%s: '%s' file: '%s'\n", func_name,
156 		    method, path);
157 		if (dropin_name) {
158 			FREE(dropin_name);
159 		}
160 		dropin_name = STRDUP(path);
161 		push_a_string(env, "do-builtin-file");
162 		dollar_find(env);
163 		return;
164 	}
165 
166 	error = fc_run_priv(env->private, "sunos,get-fcode-size", 1, 1,
167 	    fc_ptr2cell(method), &len);
168 	if (error || len == 0) {
169 		if (len == 0)
170 			debug_msg(DEBUG_FIND_FCODE, "%s: '%s' NOT FOUND\n",
171 			    func_name, method);
172 		push_a_string(env, method);
173 		PUSH(DS, d);
174 		PUSH(DS, FALSE);
175 	} else {
176 		debug_msg(DEBUG_FIND_FCODE, "%s: '%s' FOUND len: %x\n",
177 		    func_name, method, (int)len);
178 		if (dropin_name) {
179 			FREE(dropin_name);
180 		}
181 		dropin_name = STRDUP(method);
182 		push_a_string(env, "do-builtin-dropin");
183 		dollar_find(env);
184 	}
185 }
186 
187 void
make_a_node(fcode_env_t * env,char * name,int finish)188 make_a_node(fcode_env_t *env, char *name, int finish)
189 {
190 	new_device(env);
191 	push_a_string(env, name);
192 	device_name(env);
193 	if (finish)
194 		finish_device(env);
195 }
196 
197 void
install_package_nodes(fcode_env_t * env)198 install_package_nodes(fcode_env_t *env)
199 {
200 	MYSELF = open_instance_chain(env, env->root_node, 0);
201 	if (MYSELF != NULL) {
202 		make_a_node(env, "packages", 0);
203 		make_a_node(env, "disk-label", 0);
204 		finish_device(env);
205 		make_a_node(env, "SUNW,builtin-drivers", 0);
206 		builtin_driver_device = env->current_device;
207 		finish_device(env);
208 		finish_device(env);
209 		close_instance_chain(env, MYSELF, 0);
210 		device_end(env);
211 		MYSELF = 0;
212 	}
213 }
214 
215 /*
216  * find-builtin-driver  ( str len -- xt true | false )
217  */
218 void
find_builtin_driver(fcode_env_t * env)219 find_builtin_driver(fcode_env_t *env)
220 {
221 	fstack_t d;
222 
223 	CHECK_DEPTH(env, 2, "find-builtin-driver");
224 	push_a_string(env, "SUNW,builtin-drivers");
225 	find_package(env);
226 	d = POP(DS);
227 	if (d) {
228 		find_method(env);
229 	} else {
230 		two_drop(env);
231 		PUSH(DS, FALSE);
232 	}
233 }
234 
235 void
exec_builtin_driver(fcode_env_t * env)236 exec_builtin_driver(fcode_env_t *env)
237 {
238 	fstack_t d;
239 	char *method, *path, *buf;
240 	fc_cell_t len, result;
241 	int error;
242 	static char func_name[] = "exec-builtin-driver";
243 	extern int check_fcode_header(char *, uchar_t *, int);
244 
245 	CHECK_DEPTH(env, 2, func_name);
246 	method = pop_a_string(env, NULL);
247 
248 	/*
249 	 * Check for file in filesystem.  If it exists, we'll just try to do
250 	 * a do-dropin-file.
251 	 */
252 	if ((path = search_for_fcode_file(env, method)) != NULL) {
253 		push_a_string(env, path);
254 		load_file(env);
255 		return;
256 	}
257 
258 	error = fc_run_priv(env->private, "sunos,get-fcode-size", 1, 1,
259 	    fc_ptr2cell(method), &len);
260 	if (error || len == 0) {
261 		if (len == 0)
262 			debug_msg(DEBUG_FIND_FCODE, "%s: '%s' NOT FOUND\n",
263 			    func_name, method);
264 		PUSH(DS, 0);
265 		return;
266 	}
267 	debug_msg(DEBUG_FIND_FCODE, "%s: '%s' FOUND len: %x\n",
268 	    func_name, method, (int)len);
269 	buf = MALLOC(len);
270 	error = fc_run_priv(env->private, "sunos,get-fcode", 3, 1,
271 	    fc_ptr2cell(method), fc_ptr2cell(buf), len, &result);
272 	if (error) {
273 		FREE(buf);
274 		PUSH(DS, 0);
275 		return;
276 	}
277 
278 	if (check_fcode_header(dropin_name, (uchar_t *)buf, len) == 0)
279 		log_message(MSG_WARN, "%s: '%s' fcode header NOT OK\n",
280 		    func_name, method);
281 
282 	debug_msg(DEBUG_FIND_FCODE, "%s: '%s' dropin Fcode: 0x%p/0x%x\n",
283 	    func_name, method, buf, (int)len);
284 	PUSH(DS, (fstack_t)buf);
285 	PUSH(DS, len);
286 }
287 
288 #pragma init(_init)
289 
290 static void
_init(void)291 _init(void)
292 {
293 	extern void set_find_method_hook(fcode_env_t *,
294 	    void (*)(fcode_env_t *));
295 	fcode_env_t *env = initial_env;
296 	fstack_t d;
297 
298 	ASSERT(env);
299 	NOTICE;
300 
301 	set_find_method_hook(env, builtin_driver_method_hook);
302 
303 	FORTH(0,	"install-package-nodes",	install_package_nodes);
304 	FORTH(0,	"find-builtin-driver",		find_builtin_driver);
305 	FORTH(0,	"exec-builtin-driver",		exec_builtin_driver);
306 	FORTH(0,	"builtin-driver-method-hook",
307 	    builtin_driver_method_hook);
308 	FORTH(0,	"do-builtin-dropin",		do_builtin_dropin);
309 	FORTH(0,	"do-builtin-file",		do_builtin_file);
310 }
311