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
38static fc_cell_t
39fc_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
63static void
64fc_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
88static int
89check_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
102static void
103rlfetch(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
113static void
114rlstore(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
127static void
128rwfetch(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
138static void
139rwstore(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
152void
153rbfetch(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
164static void
165rbstore(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 */
181static void
182rxfetch(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 */
198static void
199rxstore(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
213static void
214lpeek(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
231static void
232lpoke(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
244static void
245wpeek(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
262static void
263wpoke(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
275static void
276cpeek(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
293static void
294cpoke(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 */
309static void
310fcd_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 */
322static void
323fcd_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 */
335static void
336fcd_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 */
348static void
349fcd_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 */
361static void
362fcd_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 */
374static void
375fcd_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 */
387static void
388fcd_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 */
400static void
401fcd_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 */
413static void
414fcd_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
431static void
432fcd_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
460char *
461get_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
478static void
479local_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
496static char *mac_addr;
497static int mac_addr_is_valid;
498
499void
500set_mac_address(char *macaddr)
501{
502	mac_addr_is_valid = 1;
503	memcpy(mac_addr, macaddr, MAC_ADDR_SIZE);
504}
505
506void
507push_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 */
516static void
517local_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 */
536static void
537mac_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 */
566static int diag_mode_is_valid = 0;
567static int diag_mode = 0;
568
569void
570set_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
578void
579push_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 */
587static void
588diagnostic_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
613static 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