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