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