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