diff options
Diffstat (limited to 'usr/src/lib/efcode/fcdriver/misc.c')
-rw-r--r-- | usr/src/lib/efcode/fcdriver/misc.c | 659 |
1 files changed, 659 insertions, 0 deletions
diff --git a/usr/src/lib/efcode/fcdriver/misc.c b/usr/src/lib/efcode/fcdriver/misc.c new file mode 100644 index 0000000000..4e62b11e03 --- /dev/null +++ b/usr/src/lib/efcode/fcdriver/misc.c @@ -0,0 +1,659 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2000 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> + +#include <fcode/private.h> +#include <fcode/log.h> + +#include <fcdriver/fcdriver.h> + +static fc_cell_t +fc_reg_read(fcode_env_t *env, char *service, fstack_t virt, int *errp) +{ + fc_cell_t virtaddr, data; + int error, nin; + + if (!is_mcookie(virt)) + forth_abort(env, "fc_reg_read: bad mcookie: 0x%x\n", virt); + + virtaddr = mcookie_to_addr(virt); + + /* Supress fc_run_priv error msgs on peeks */ + nin = ((errp == NULL) ? 1 : (1 | FCRP_NOERROR)); + + error = fc_run_priv(env->private, service, nin, 1, virtaddr, &data); + if (errp) + /* Don't report error on peeks */ + *errp = error; + else if (error) { + log_message(MSG_ERROR, "fc_read_reg: ERROR: cookie: %llx" + " virt: %llx\n", (uint64_t)virt, (uint64_t)virtaddr); + data = 0; + } + return (data); +} + +static void +fc_reg_write(fcode_env_t *env, char *service, fstack_t virt, fc_cell_t data, + int *errp) +{ + fc_cell_t virtaddr; + int error, nin; + + if (!is_mcookie(virt)) + forth_abort(env, "fc_reg_write: bad mcookie: 0x%x\n", virt); + + virtaddr = mcookie_to_addr(virt); + + /* Supress fc_run_priv error msgs on pokes */ + nin = ((errp == NULL) ? 2 : (2 | FCRP_NOERROR)); + + error = fc_run_priv(env->private, service, nin, 0, virtaddr, data); + if (errp) + /* Don't report error on pokes */ + *errp = error; + else if (error) { + log_message(MSG_ERROR, "fc_write_reg: ERROR: cookie: %llx" + " virt: %llx\n", (uint64_t)virt, (uint64_t)virtaddr); + } +} + +static int +check_address_abuse(fcode_env_t *env, fstack_t addr, char *type, + int want_mcookie, void (*alt)(fcode_env_t *)) +{ + if (is_mcookie(addr) != want_mcookie) { + debug_msg(DEBUG_ADDR_ABUSE, "Warning: %s to %s address: %llx\n", + type, want_mcookie ? "unmapped" : "mapped", + (uint64_t)addr); + (*alt)(env); + return (1); + } + return (0); +} + +static void +rlfetch(fcode_env_t *env) +{ + fstack_t p; + + CHECK_DEPTH(env, 1, "rl@"); + p = TOS; + if (!check_address_abuse(env, p, "rl@", 1, lfetch)) + TOS = (lforth_t)fc_reg_read(env, "rl@", p, NULL); +} + +static void +rlstore(fcode_env_t *env) +{ + fstack_t p, d; + + CHECK_DEPTH(env, 2, "rl!"); + p = TOS; + if (!check_address_abuse(env, p, "rl!", 1, lstore)) { + p = POP(DS); + d = POP(DS); + fc_reg_write(env, "rl!", p, d, NULL); + } +} + +static void +rwfetch(fcode_env_t *env) +{ + fstack_t p; + + CHECK_DEPTH(env, 1, "rw@"); + p = TOS; + if (!check_address_abuse(env, p, "rw@", 1, wfetch)) + TOS = (wforth_t)fc_reg_read(env, "rw@", p, NULL); +} + +static void +rwstore(fcode_env_t *env) +{ + fstack_t p, d; + + CHECK_DEPTH(env, 2, "rw!"); + p = TOS; + if (!check_address_abuse(env, p, "rw!", 1, wstore)) { + p = POP(DS); + d = POP(DS); + fc_reg_write(env, "rw!", p, d, NULL); + } +} + +void +rbfetch(fcode_env_t *env) +{ + fstack_t p; + + CHECK_DEPTH(env, 1, "rb@"); + p = TOS; + if (!check_address_abuse(env, p, "rb@", 1, cfetch)) { + TOS = (uchar_t)fc_reg_read(env, "rb@", p, NULL); + } +} + +static void +rbstore(fcode_env_t *env) +{ + fstack_t p, d; + + CHECK_DEPTH(env, 2, "rb!"); + p = TOS; + if (!check_address_abuse(env, p, "rb!", 1, cstore)) { + p = POP(DS); + d = POP(DS); + fc_reg_write(env, "rb!", p, d, NULL); + } +} + +/* + * rx@ ( xa -- xv ) + */ +static void +rxfetch(fcode_env_t *env) +{ + fstack_t p; + xforth_t x; + + CHECK_DEPTH(env, 1, "rx@"); + p = TOS; + if (!check_address_abuse(env, p, "rx@", 1, xfetch)) { + p = POP(DS); + push_xforth(env, (xforth_t)fc_reg_read(env, "rx@", p, NULL)); + } +} + +/* + * rx! ( xv xa -- ) + */ +static void +rxstore(fcode_env_t *env) +{ + fstack_t p; + xforth_t d; + + CHECK_DEPTH(env, 2, "rx!"); + p = TOS; + if (!check_address_abuse(env, p, "rx!", 1, xstore)) { + p = POP(DS); + d = pop_xforth(env); + fc_reg_write(env, "rx!", p, d, NULL); + } +} + +static void +lpeek(fcode_env_t *env) +{ + fstack_t p; + lforth_t r; + int error; + + CHECK_DEPTH(env, 1, "lpeek"); + p = POP(DS); + r = (lforth_t)fc_reg_read(env, "rl@", p, &error); + if (error) + PUSH(DS, FALSE); + else { + PUSH(DS, r); + PUSH(DS, TRUE); + } +} + +static void +lpoke(fcode_env_t *env) +{ + fstack_t p, d; + int error; + + CHECK_DEPTH(env, 2, "lpoke"); + p = POP(DS); + d = POP(DS); + fc_reg_write(env, "rl!", p, d, &error); + PUSH(DS, error ? FALSE : TRUE); +} + +static void +wpeek(fcode_env_t *env) +{ + fstack_t p; + int error; + wforth_t r; + + CHECK_DEPTH(env, 1, "wpeek"); + p = POP(DS); + r = (wforth_t)fc_reg_read(env, "rw@", p, &error); + if (error) + PUSH(DS, FALSE); + else { + PUSH(DS, r); + PUSH(DS, TRUE); + } +} + +static void +wpoke(fcode_env_t *env) +{ + fstack_t p, d; + int error; + + CHECK_DEPTH(env, 2, "wpoke"); + p = POP(DS); + d = POP(DS); + fc_reg_write(env, "rw!", p, d, &error); + PUSH(DS, error ? FALSE : TRUE); +} + +static void +cpeek(fcode_env_t *env) +{ + fstack_t p; + uchar_t r; + int error; + + CHECK_DEPTH(env, 1, "cpeek"); + p = POP(DS); + r = (uchar_t)fc_reg_read(env, "rb@", p, &error); + if (error) + PUSH(DS, FALSE); + else { + PUSH(DS, r); + PUSH(DS, TRUE); + } +} + +static void +cpoke(fcode_env_t *env) +{ + fstack_t p, d; + int error; + + CHECK_DEPTH(env, 2, "cpoke"); + p = POP(DS); + d = POP(DS); + fc_reg_write(env, "rb!", p, d, &error); + PUSH(DS, error ? FALSE : TRUE); +} + +/* + * fcdriver version of cfetch, replaces base 'c@' + */ +static void +fcd_cfetch(fcode_env_t *env) +{ + fstack_t addr = TOS; + + CHECK_DEPTH(env, 1, "c@"); + if (!check_address_abuse(env, addr, "c@", 0, rbfetch)) + cfetch(env); +} + +/* + * fcdriver version of cstore, replaces base 'c!' + */ +static void +fcd_cstore(fcode_env_t *env) +{ + fstack_t addr = TOS; + + CHECK_DEPTH(env, 2, "c!"); + if (!check_address_abuse(env, addr, "c!", 0, rbstore)) + cstore(env); +} + +/* + * fcdriver version of wfetch, replaces base 'w@' + */ +static void +fcd_wfetch(fcode_env_t *env) +{ + fstack_t addr = TOS; + + CHECK_DEPTH(env, 1, "w@"); + if (!check_address_abuse(env, addr, "w@", 0, rwfetch)) + wfetch(env); +} + +/* + * fcdriver version of wstore, replaces base 'w!' + */ +static void +fcd_wstore(fcode_env_t *env) +{ + fstack_t addr = TOS; + + CHECK_DEPTH(env, 2, "w!"); + if (!check_address_abuse(env, addr, "w!", 0, rwstore)) + wstore(env); +} + +/* + * fcdriver version of lfetch, replaces base 'l@' + */ +static void +fcd_lfetch(fcode_env_t *env) +{ + fstack_t addr = TOS; + + CHECK_DEPTH(env, 1, "l@"); + if (!check_address_abuse(env, addr, "l@", 0, rlfetch)) + lfetch(env); +} + +/* + * fcdriver version of lstore, replaces base 'l!' + */ +static void +fcd_lstore(fcode_env_t *env) +{ + fstack_t addr = TOS; + + CHECK_DEPTH(env, 2, "l!"); + if (!check_address_abuse(env, addr, "l!", 0, rlstore)) + lstore(env); +} + +/* + * fcdriver version of xfetch, replaces base 'x@' + */ +static void +fcd_xfetch(fcode_env_t *env) +{ + fstack_t addr = TOS; + + CHECK_DEPTH(env, 1, "x@"); + if (!check_address_abuse(env, addr, "x@", 0, rxfetch)) + xfetch(env); +} + +/* + * fcdriver version of xstore, replaces base 'x!' + */ +static void +fcd_xstore(fcode_env_t *env) +{ + fstack_t addr = TOS; + + CHECK_DEPTH(env, 2, "x!"); + if (!check_address_abuse(env, addr, "x!", 0, rxstore)) + xstore(env); +} + +/* + * fcdriver version of move, replaces base 'move' + */ +static void +fcd_move(fcode_env_t *env) +{ + size_t len; + uchar_t *destaddr, *srcaddr; + + CHECK_DEPTH(env, 3, "move"); + len = POP(DS); + destaddr = ((uchar_t *)POP(DS)); + srcaddr = ((uchar_t *)POP(DS)); + for (; len > 0; len--, srcaddr++, destaddr++) { + PUSH(DS, (fstack_t)srcaddr); + fcd_cfetch(env); + PUSH(DS, (fstack_t)destaddr); + fcd_cstore(env); + } +} + +static void +fcd_comp(fcode_env_t *env) +{ + char *str1, *str2, byte1, byte2; + size_t len; + + CHECK_DEPTH(env, 3, "comp"); + len = (size_t)POP(DS); + str1 = (char *)POP(DS); + str2 = (char *)POP(DS); + for (; len > 0; len--, str1++, str2++) { + PUSH(DS, (fstack_t)str1); + fcd_cfetch(env); + byte1 = POP(DS); + PUSH(DS, (fstack_t)str2); + fcd_cfetch(env); + byte2 = POP(DS); + if (byte1 > byte2) { + PUSH(DS, -1); + return; + } + if (byte1 < byte2) { + PUSH(DS, 1); + return; + } + } + PUSH(DS, 0); +} + +char * +get_eeprom_value(fcode_env_t *env, char *name) +{ + FILE *fd; + char buf[80], *p; + + sprintf(buf, "eeprom '%s'", name); + if ((fd = popen(buf, "r")) == NULL) + return (NULL); + fgets(buf, sizeof (buf), fd); + pclose(fd); + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; + if ((p = strchr(buf, '=')) != NULL) + return (p + 1); + return (NULL); +} + +static void +local_mac_address(fcode_env_t *env) +{ + char *mac_str; + int mac_value; + + mac_str = get_eeprom_value(env, "local-mac-address?"); + if (mac_str != NULL && strcmp(mac_str, "true") == 0) + mac_value = TRUE; + else + mac_value = FALSE; + PUSH(DS, mac_value); +} + +/* + * Allow for programmatic over-ride of 'mac-address' + */ +#define MAC_ADDR_SIZE 6 +static char *mac_addr; +static int mac_addr_is_valid; + +void +set_mac_address(char *macaddr) +{ + mac_addr_is_valid = 1; + memcpy(mac_addr, macaddr, MAC_ADDR_SIZE); +} + +void +push_mac_address(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)mac_addr); + PUSH(DS, MAC_ADDR_SIZE); +} + +/* + * Does driver call to get this. + */ +static void +local_ether_addr(fcode_env_t *env) +{ + static fc_cell_t *mac_add; + int error; + + mac_add = MALLOC(sizeof (fc_cell_t) * 2); + error = fc_run_priv(env->private, "local-ether-addr", 0, 2, &mac_add[0], + &mac_add[1]); + if (error) { + bzero(mac_add, sizeof (mac_add)); + } + + PUSH(DS, (fstack_t)&mac_add[0]); + PUSH(DS, 6); +} + +/* + * 'mac-address' - complicated by 'local-mac-address' stuff. + */ +static void +mac_address(fcode_env_t *env) +{ + fstack_t d; + + if (mac_addr_is_valid) { + push_mac_address(env); + return; + } + + /* + * From here, we essentially re-implement OBP's 'mac-address' word. + * on some platforms, this may need to be re-implemented. + */ + local_mac_address(env); + d = POP(DS); + if (d) { + push_a_string(env, "local-mac-address"); + get_inherited_prop(env); + d = POP(DS); + if (d == FALSE && TOS == 6) + return; + two_drop(env); + } + local_ether_addr(env); +} + +/* + * Allow for the programmatic setting of diagnostic-mode? + */ +static int diag_mode_is_valid = 0; +static int diag_mode = 0; + +void +set_diagnostic_mode(fcode_env_t *env) +{ + fstack_t d = POP(DS); + + diag_mode = d; + diag_mode_is_valid = 1; +} + +void +push_diagnostic_mode(fcode_env_t *env) +{ + PUSH(DS, (fstack_t)diag_mode); +} + +/* + * 'diagnostic-mode?' - diagnostic-mode? is equivalent to NVRAM 'diag-switch?' + */ +static void +diagnostic_mode(fcode_env_t *env) +{ + char *diag_str; + int diag_value; + + if (!diag_mode_is_valid) { + diag_str = get_eeprom_value(env, "diag-switch?"); + if (diag_str != NULL && strcmp(diag_str, "false") == 0) + diag_value = FALSE; + else + diag_value = TRUE; + PUSH(DS, diag_value); + set_diagnostic_mode(env); + } + + push_diagnostic_mode(env); +} + +/* + * May need to implement other memory-access Fcodes here (depending upon + * abuse), like fill, comp, +!, etc., etc. + */ + +#pragma init(_init) + +static void +_init(void) +{ + fcode_env_t *env = initial_env; + + mac_addr = MALLOC(MAC_ADDR_SIZE); + + ASSERT(env); + NOTICE; + + ANSI(0x06e, 0, "l@", fcd_lfetch); + ANSI(0x06f, 0, "w@", fcd_wfetch); + ANSI(0x071, 0, "c@", fcd_cfetch); + ANSI(0x073, 0, "l!", fcd_lstore); + ANSI(0x074, 0, "w!", fcd_wstore); + ANSI(0x075, 0, "c!", fcd_cstore); + ANSI(0x078, 0, "move", fcd_move); + ANSI(0x07a, 0, "comp", fcd_comp); + + ANSI(0x120, 0, "diagnostic-mode?", diagnostic_mode); + + ANSI(0x1a4, 0, "mac-address", mac_address); + + P1275(0x220, 0, "cpeek", cpeek); + P1275(0x221, 0, "wpeek", wpeek); + P1275(0x222, 0, "lpeek", lpeek); + P1275(0x223, 0, "cpoke", cpoke); + P1275(0x224, 0, "wpoke", wpoke); + P1275(0x225, 0, "lpoke", lpoke); + + P1275(0x230, 0, "rb@", rbfetch); + P1275(0x231, 0, "rb!", rbstore); + P1275(0x232, 0, "rw@", rwfetch); + P1275(0x233, 0, "rw!", rwstore); + P1275(0x234, 0, "rl@", rlfetch); + P1275(0x235, 0, "rl!", rlstore); + + P1275(0x246, 0, "x@", fcd_xfetch); + P1275(0x247, 0, "x!", fcd_xstore); + + P1275(0x22e, 0, "rx@", rxfetch); + P1275(0x22f, 0, "rx!", rxstore); + FORTH(0, "set-diagnostic-mode", set_diagnostic_mode); + FORTH(0, "local-mac-address?", local_mac_address); + FORTH(0, "local-ether-addr", local_ether_addr); +} |