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