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
fc_reg_read(fcode_env_t * env,char * service,fstack_t virt,int * errp)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
fc_reg_write(fcode_env_t * env,char * service,fstack_t virt,fc_cell_t data,int * errp)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
check_address_abuse(fcode_env_t * env,fstack_t addr,char * type,int want_mcookie,void (* alt)(fcode_env_t *))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
rlfetch(fcode_env_t * env)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
rlstore(fcode_env_t * env)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
rwfetch(fcode_env_t * env)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
rwstore(fcode_env_t * env)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
rbfetch(fcode_env_t * env)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
rbstore(fcode_env_t * env)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
rxfetch(fcode_env_t * env)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
rxstore(fcode_env_t * env)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
lpeek(fcode_env_t * env)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
lpoke(fcode_env_t * env)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
wpeek(fcode_env_t * env)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
wpoke(fcode_env_t * env)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
cpeek(fcode_env_t * env)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
cpoke(fcode_env_t * env)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
fcd_cfetch(fcode_env_t * env)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
fcd_cstore(fcode_env_t * env)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
fcd_wfetch(fcode_env_t * env)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
fcd_wstore(fcode_env_t * env)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
fcd_lfetch(fcode_env_t * env)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
fcd_lstore(fcode_env_t * env)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
fcd_xfetch(fcode_env_t * env)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
fcd_xstore(fcode_env_t * env)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
fcd_move(fcode_env_t * env)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
fcd_comp(fcode_env_t * env)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 *
get_eeprom_value(fcode_env_t * env,char * name)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
local_mac_address(fcode_env_t * env)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
set_mac_address(char * macaddr)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
push_mac_address(fcode_env_t * env)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
local_ether_addr(fcode_env_t * env)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
mac_address(fcode_env_t * env)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
set_diagnostic_mode(fcode_env_t * env)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
push_diagnostic_mode(fcode_env_t * env)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
diagnostic_mode(fcode_env_t * env)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
_init(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