xref: /titanic_50/usr/src/lib/efcode/fcdriver/misc.c (revision 60b08185ce63023f22fd6b2ed0db8c0d119b2023)
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 2005 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 <stdio.h>
30 #include <stdlib.h>
31 #include <strings.h>
32 
33 #include <fcode/private.h>
34 #include <fcode/log.h>
35 
36 #include <fcdriver/fcdriver.h>
37 
38 static fc_cell_t
39 fc_reg_read(fcode_env_t *env, char *service, fstack_t virt, int *errp)
40 {
41 	fc_cell_t virtaddr, data;
42 	int error, nin;
43 
44 	if (!is_mcookie(virt))
45 		forth_abort(env, "fc_reg_read: bad mcookie: 0x%x\n", virt);
46 
47 	virtaddr = mcookie_to_addr(virt);
48 
49 	/* Supress fc_run_priv error msgs on peeks */
50 	nin = ((errp == NULL) ? 1 : (1 | FCRP_NOERROR));
51 
52 	error = fc_run_priv(env->private, service, nin, 1, virtaddr, &data);
53 	if (errp)
54 		/* Don't report error on peeks */
55 		*errp = error;
56 	else if (error) {
57 		forth_abort(env, "fc_read_reg: ERROR: cookie: %llx"
58 		    " virt: %llx\n", (uint64_t)virt, (uint64_t)virtaddr);
59 	}
60 	return (data);
61 }
62 
63 static void
64 fc_reg_write(fcode_env_t *env, char *service, fstack_t virt, fc_cell_t data,
65     int *errp)
66 {
67 	fc_cell_t virtaddr;
68 	int error, nin;
69 
70 	if (!is_mcookie(virt))
71 		forth_abort(env, "fc_reg_write: bad mcookie: 0x%x\n", virt);
72 
73 	virtaddr = mcookie_to_addr(virt);
74 
75 	/* Supress fc_run_priv error msgs on pokes */
76 	nin = ((errp == NULL) ? 2 : (2 | FCRP_NOERROR));
77 
78 	error = fc_run_priv(env->private, service, nin, 0, virtaddr, data);
79 	if (errp)
80 		/* Don't report error on pokes */
81 		*errp = error;
82 	else if (error) {
83 		forth_abort(env, "fc_write_reg: ERROR: cookie: %llx"
84 		    " virt: %llx\n", (uint64_t)virt, (uint64_t)virtaddr);
85 	}
86 }
87 
88 static int
89 check_address_abuse(fcode_env_t *env, fstack_t addr, char *type,
90     int want_mcookie, void (*alt)(fcode_env_t *))
91 {
92 	if (is_mcookie(addr) != want_mcookie) {
93 		debug_msg(DEBUG_ADDR_ABUSE, "Warning: %s to %s address: %llx\n",
94 		    type, want_mcookie ? "unmapped" : "mapped",
95 		    (uint64_t)addr);
96 		(*alt)(env);
97 		return (1);
98 	}
99 	return (0);
100 }
101 
102 static void
103 rlfetch(fcode_env_t *env)
104 {
105 	fstack_t p;
106 
107 	CHECK_DEPTH(env, 1, "rl@");
108 	p = TOS;
109 	if (!check_address_abuse(env, p, "rl@", 1, lfetch))
110 		TOS = (lforth_t)fc_reg_read(env, "rl@", p, NULL);
111 }
112 
113 static void
114 rlstore(fcode_env_t *env)
115 {
116 	fstack_t p, d;
117 
118 	CHECK_DEPTH(env, 2, "rl!");
119 	p = TOS;
120 	if (!check_address_abuse(env, p, "rl!", 1, lstore)) {
121 		p = POP(DS);
122 		d = POP(DS);
123 		fc_reg_write(env, "rl!", p, d, NULL);
124 	}
125 }
126 
127 static void
128 rwfetch(fcode_env_t *env)
129 {
130 	fstack_t p;
131 
132 	CHECK_DEPTH(env, 1, "rw@");
133 	p = TOS;
134 	if (!check_address_abuse(env, p, "rw@", 1, wfetch))
135 		TOS = (wforth_t)fc_reg_read(env, "rw@", p, NULL);
136 }
137 
138 static void
139 rwstore(fcode_env_t *env)
140 {
141 	fstack_t p, d;
142 
143 	CHECK_DEPTH(env, 2, "rw!");
144 	p = TOS;
145 	if (!check_address_abuse(env, p, "rw!", 1, wstore)) {
146 		p = POP(DS);
147 		d = POP(DS);
148 		fc_reg_write(env, "rw!", p, d, NULL);
149 	}
150 }
151 
152 void
153 rbfetch(fcode_env_t *env)
154 {
155 	fstack_t p;
156 
157 	CHECK_DEPTH(env, 1, "rb@");
158 	p = TOS;
159 	if (!check_address_abuse(env, p, "rb@", 1, cfetch)) {
160 		TOS = (uchar_t)fc_reg_read(env, "rb@", p, NULL);
161 	}
162 }
163 
164 static void
165 rbstore(fcode_env_t *env)
166 {
167 	fstack_t	p, d;
168 
169 	CHECK_DEPTH(env, 2, "rb!");
170 	p = TOS;
171 	if (!check_address_abuse(env, p, "rb!", 1, cstore)) {
172 		p = POP(DS);
173 		d = POP(DS);
174 		fc_reg_write(env, "rb!", p, d, NULL);
175 	}
176 }
177 
178 /*
179  * rx@        ( xa -- xv )
180  */
181 static void
182 rxfetch(fcode_env_t *env)
183 {
184 	fstack_t p;
185 	xforth_t x;
186 
187 	CHECK_DEPTH(env, 1, "rx@");
188 	p = TOS;
189 	if (!check_address_abuse(env, p, "rx@", 1, xfetch)) {
190 		p = POP(DS);
191 		push_xforth(env, (xforth_t)fc_reg_read(env, "rx@", p, NULL));
192 	}
193 }
194 
195 /*
196  * rx!        ( xv xa -- )
197  */
198 static void
199 rxstore(fcode_env_t *env)
200 {
201 	fstack_t p;
202 	xforth_t d;
203 
204 	CHECK_DEPTH(env, 2, "rx!");
205 	p = TOS;
206 	if (!check_address_abuse(env, p, "rx!", 1, xstore)) {
207 		p = POP(DS);
208 		d = pop_xforth(env);
209 		fc_reg_write(env, "rx!", p, d, NULL);
210 	}
211 }
212 
213 static void
214 lpeek(fcode_env_t *env)
215 {
216 	fstack_t p;
217 	lforth_t r;
218 	int error;
219 
220 	CHECK_DEPTH(env, 1, "lpeek");
221 	p = POP(DS);
222 	r = (lforth_t)fc_reg_read(env, "rl@", p, &error);
223 	if (error)
224 		PUSH(DS, FALSE);
225 	else {
226 		PUSH(DS, r);
227 		PUSH(DS, TRUE);
228 	}
229 }
230 
231 static void
232 lpoke(fcode_env_t *env)
233 {
234 	fstack_t p, d;
235 	int error;
236 
237 	CHECK_DEPTH(env, 2, "lpoke");
238 	p = POP(DS);
239 	d = POP(DS);
240 	fc_reg_write(env, "rl!", p, d, &error);
241 	PUSH(DS, error ? FALSE : TRUE);
242 }
243 
244 static void
245 wpeek(fcode_env_t *env)
246 {
247 	fstack_t p;
248 	int error;
249 	wforth_t r;
250 
251 	CHECK_DEPTH(env, 1, "wpeek");
252 	p = POP(DS);
253 	r = (wforth_t)fc_reg_read(env, "rw@", p, &error);
254 	if (error)
255 		PUSH(DS, FALSE);
256 	else {
257 		PUSH(DS, r);
258 		PUSH(DS, TRUE);
259 	}
260 }
261 
262 static void
263 wpoke(fcode_env_t *env)
264 {
265 	fstack_t p, d;
266 	int error;
267 
268 	CHECK_DEPTH(env, 2, "wpoke");
269 	p = POP(DS);
270 	d = POP(DS);
271 	fc_reg_write(env, "rw!", p, d, &error);
272 	PUSH(DS, error ? FALSE : TRUE);
273 }
274 
275 static void
276 cpeek(fcode_env_t *env)
277 {
278 	fstack_t	p;
279 	uchar_t r;
280 	int error;
281 
282 	CHECK_DEPTH(env, 1, "cpeek");
283 	p = POP(DS);
284 	r = (uchar_t)fc_reg_read(env, "rb@", p, &error);
285 	if (error)
286 		PUSH(DS, FALSE);
287 	else {
288 		PUSH(DS, r);
289 		PUSH(DS, TRUE);
290 	}
291 }
292 
293 static void
294 cpoke(fcode_env_t *env)
295 {
296 	fstack_t	p, d;
297 	int error;
298 
299 	CHECK_DEPTH(env, 2, "cpoke");
300 	p = POP(DS);
301 	d = POP(DS);
302 	fc_reg_write(env, "rb!", p, d, &error);
303 	PUSH(DS, error ? FALSE : TRUE);
304 }
305 
306 /*
307  * fcdriver version of cfetch, replaces base 'c@'
308  */
309 static void
310 fcd_cfetch(fcode_env_t *env)
311 {
312 	fstack_t addr = TOS;
313 
314 	CHECK_DEPTH(env, 1, "c@");
315 	if (!check_address_abuse(env, addr, "c@", 0, rbfetch))
316 		cfetch(env);
317 }
318 
319 /*
320  * fcdriver version of cstore, replaces base 'c!'
321  */
322 static void
323 fcd_cstore(fcode_env_t *env)
324 {
325 	fstack_t addr = TOS;
326 
327 	CHECK_DEPTH(env, 2, "c!");
328 	if (!check_address_abuse(env, addr, "c!", 0, rbstore))
329 		cstore(env);
330 }
331 
332 /*
333  * fcdriver version of wfetch, replaces base 'w@'
334  */
335 static void
336 fcd_wfetch(fcode_env_t *env)
337 {
338 	fstack_t addr = TOS;
339 
340 	CHECK_DEPTH(env, 1, "w@");
341 	if (!check_address_abuse(env, addr, "w@", 0, rwfetch))
342 		wfetch(env);
343 }
344 
345 /*
346  * fcdriver version of wstore, replaces base 'w!'
347  */
348 static void
349 fcd_wstore(fcode_env_t *env)
350 {
351 	fstack_t addr = TOS;
352 
353 	CHECK_DEPTH(env, 2, "w!");
354 	if (!check_address_abuse(env, addr, "w!", 0, rwstore))
355 		wstore(env);
356 }
357 
358 /*
359  * fcdriver version of lfetch, replaces base 'l@'
360  */
361 static void
362 fcd_lfetch(fcode_env_t *env)
363 {
364 	fstack_t addr = TOS;
365 
366 	CHECK_DEPTH(env, 1, "l@");
367 	if (!check_address_abuse(env, addr, "l@", 0, rlfetch))
368 		lfetch(env);
369 }
370 
371 /*
372  * fcdriver version of lstore, replaces base 'l!'
373  */
374 static void
375 fcd_lstore(fcode_env_t *env)
376 {
377 	fstack_t addr = TOS;
378 
379 	CHECK_DEPTH(env, 2, "l!");
380 	if (!check_address_abuse(env, addr, "l!", 0, rlstore))
381 		lstore(env);
382 }
383 
384 /*
385  * fcdriver version of xfetch, replaces base 'x@'
386  */
387 static void
388 fcd_xfetch(fcode_env_t *env)
389 {
390 	fstack_t addr = TOS;
391 
392 	CHECK_DEPTH(env, 1, "x@");
393 	if (!check_address_abuse(env, addr, "x@", 0, rxfetch))
394 		xfetch(env);
395 }
396 
397 /*
398  * fcdriver version of xstore, replaces base 'x!'
399  */
400 static void
401 fcd_xstore(fcode_env_t *env)
402 {
403 	fstack_t addr = TOS;
404 
405 	CHECK_DEPTH(env, 2, "x!");
406 	if (!check_address_abuse(env, addr, "x!", 0, rxstore))
407 		xstore(env);
408 }
409 
410 /*
411  * fcdriver version of move, replaces base 'move'
412  */
413 static void
414 fcd_move(fcode_env_t *env)
415 {
416 	size_t len;
417 	uchar_t *destaddr, *srcaddr;
418 
419 	CHECK_DEPTH(env, 3, "move");
420 	len = POP(DS);
421 	destaddr = ((uchar_t *)POP(DS));
422 	srcaddr = ((uchar_t *)POP(DS));
423 	for (; len > 0; len--, srcaddr++, destaddr++) {
424 		PUSH(DS, (fstack_t)srcaddr);
425 		fcd_cfetch(env);
426 		PUSH(DS, (fstack_t)destaddr);
427 		fcd_cstore(env);
428 	}
429 }
430 
431 static void
432 fcd_comp(fcode_env_t *env)
433 {
434 	char *str1, *str2, byte1, byte2;
435 	size_t len;
436 
437 	CHECK_DEPTH(env, 3, "comp");
438 	len  = (size_t)POP(DS);
439 	str1 = (char *)POP(DS);
440 	str2 = (char *)POP(DS);
441 	for (; len > 0; len--, str1++, str2++) {
442 		PUSH(DS, (fstack_t)str1);
443 		fcd_cfetch(env);
444 		byte1 = POP(DS);
445 		PUSH(DS, (fstack_t)str2);
446 		fcd_cfetch(env);
447 		byte2 = POP(DS);
448 		if (byte1 > byte2) {
449 			PUSH(DS, -1);
450 			return;
451 		}
452 		if (byte1 < byte2) {
453 			PUSH(DS, 1);
454 			return;
455 		}
456 	}
457 	PUSH(DS, 0);
458 }
459 
460 char *
461 get_eeprom_value(fcode_env_t *env, char *name)
462 {
463 	FILE *fd;
464 	char buf[80], *p;
465 
466 	sprintf(buf, "eeprom '%s'", name);
467 	if ((fd = popen(buf, "r")) == NULL)
468 		return (NULL);
469 	fgets(buf, sizeof (buf), fd);
470 	pclose(fd);
471 	if ((p = strchr(buf, '\n')) != NULL)
472 		*p = '\0';
473 	if ((p = strchr(buf, '=')) != NULL)
474 		return (p + 1);
475 	return (NULL);
476 }
477 
478 static void
479 local_mac_address(fcode_env_t *env)
480 {
481 	char *mac_str;
482 	int mac_value;
483 
484 	mac_str = get_eeprom_value(env, "local-mac-address?");
485 	if (mac_str != NULL && strcmp(mac_str, "true") == 0)
486 		mac_value = TRUE;
487 	else
488 		mac_value = FALSE;
489 	PUSH(DS, mac_value);
490 }
491 
492 /*
493  * Allow for programmatic over-ride of 'mac-address'
494  */
495 #define	MAC_ADDR_SIZE	6
496 static char *mac_addr;
497 static int mac_addr_is_valid;
498 
499 void
500 set_mac_address(char *macaddr)
501 {
502 	mac_addr_is_valid = 1;
503 	memcpy(mac_addr, macaddr, MAC_ADDR_SIZE);
504 }
505 
506 void
507 push_mac_address(fcode_env_t *env)
508 {
509 	PUSH(DS, (fstack_t)mac_addr);
510 	PUSH(DS, MAC_ADDR_SIZE);
511 }
512 
513 /*
514  * Does driver call to get this.
515  */
516 static void
517 local_ether_addr(fcode_env_t *env)
518 {
519 	static fc_cell_t *mac_add;
520 	int error;
521 
522 	mac_add = MALLOC(sizeof (fc_cell_t) * 2);
523 	error = fc_run_priv(env->private, "local-ether-addr", 0, 2, &mac_add[0],
524 	    &mac_add[1]);
525 	if (error) {
526 		bzero(mac_add, sizeof (mac_add));
527 	}
528 
529 	PUSH(DS, (fstack_t)&mac_add[0]);
530 	PUSH(DS, 6);
531 }
532 
533 /*
534  * 'mac-address' - complicated by 'local-mac-address' stuff.
535  */
536 static void
537 mac_address(fcode_env_t *env)
538 {
539 	fstack_t d;
540 
541 	if (mac_addr_is_valid) {
542 		push_mac_address(env);
543 		return;
544 	}
545 
546 	/*
547 	 * From here, we essentially re-implement OBP's 'mac-address' word.
548 	 * on some platforms, this may need to be re-implemented.
549 	 */
550 	local_mac_address(env);
551 	d = POP(DS);
552 	if (d) {
553 		push_a_string(env, "local-mac-address");
554 		get_inherited_prop(env);
555 		d = POP(DS);
556 		if (d == FALSE && TOS == 6)
557 			return;
558 		two_drop(env);
559 	}
560 	local_ether_addr(env);
561 }
562 
563 /*
564  * Allow for the programmatic setting of diagnostic-mode?
565  */
566 static int diag_mode_is_valid = 0;
567 static int diag_mode = 0;
568 
569 void
570 set_diagnostic_mode(fcode_env_t *env)
571 {
572 	fstack_t d = POP(DS);
573 
574 	diag_mode = d;
575 	diag_mode_is_valid = 1;
576 }
577 
578 void
579 push_diagnostic_mode(fcode_env_t *env)
580 {
581 	PUSH(DS, (fstack_t)diag_mode);
582 }
583 
584 /*
585  * 'diagnostic-mode?' - diagnostic-mode? is equivalent to NVRAM 'diag-switch?'
586  */
587 static void
588 diagnostic_mode(fcode_env_t *env)
589 {
590 	char *diag_str;
591 	int diag_value;
592 
593 	if (!diag_mode_is_valid) {
594 		diag_str = get_eeprom_value(env, "diag-switch?");
595 		if (diag_str != NULL && strcmp(diag_str, "false") == 0)
596 			diag_value = FALSE;
597 		else
598 			diag_value = TRUE;
599 		PUSH(DS, diag_value);
600 		set_diagnostic_mode(env);
601 	}
602 
603 	push_diagnostic_mode(env);
604 }
605 
606 /*
607  * May need to implement other memory-access Fcodes here (depending upon
608  * abuse), like fill, comp, +!, etc., etc.
609  */
610 
611 #pragma init(_init)
612 
613 static void
614 _init(void)
615 {
616 	fcode_env_t *env = initial_env;
617 
618 	mac_addr = MALLOC(MAC_ADDR_SIZE);
619 
620 	ASSERT(env);
621 	NOTICE;
622 
623 	ANSI(0x06e, 0,		"l@",			fcd_lfetch);
624 	ANSI(0x06f, 0,		"w@",			fcd_wfetch);
625 	ANSI(0x071, 0,		"c@",			fcd_cfetch);
626 	ANSI(0x073, 0,		"l!",			fcd_lstore);
627 	ANSI(0x074, 0,		"w!",			fcd_wstore);
628 	ANSI(0x075, 0,		"c!",			fcd_cstore);
629 	ANSI(0x078, 0,		"move",			fcd_move);
630 	ANSI(0x07a, 0,		"comp",			fcd_comp);
631 
632 	ANSI(0x120, 0,		"diagnostic-mode?",	diagnostic_mode);
633 
634 	ANSI(0x1a4, 0,		"mac-address",		mac_address);
635 
636 	P1275(0x220, 0,		"cpeek",		cpeek);
637 	P1275(0x221, 0,		"wpeek",		wpeek);
638 	P1275(0x222, 0,		"lpeek",		lpeek);
639 	P1275(0x223, 0,		"cpoke",		cpoke);
640 	P1275(0x224, 0,		"wpoke",		wpoke);
641 	P1275(0x225, 0,		"lpoke",		lpoke);
642 
643 	P1275(0x230, 0,		"rb@",			rbfetch);
644 	P1275(0x231, 0,		"rb!",			rbstore);
645 	P1275(0x232, 0,		"rw@",			rwfetch);
646 	P1275(0x233, 0,		"rw!",			rwstore);
647 	P1275(0x234, 0,		"rl@",			rlfetch);
648 	P1275(0x235, 0,		"rl!",			rlstore);
649 
650 	P1275(0x246,	0,	"x@",			fcd_xfetch);
651 	P1275(0x247,	0,	"x!",			fcd_xstore);
652 
653 	P1275(0x22e,	0,	"rx@",			rxfetch);
654 	P1275(0x22f,	0,	"rx!",			rxstore);
655 	FORTH(0,		"set-diagnostic-mode",	set_diagnostic_mode);
656 	FORTH(0,		"local-mac-address?",	local_mac_address);
657 	FORTH(0,		"local-ether-addr",	local_ether_addr);
658 }
659