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