diff options
285 files changed, 83325 insertions, 0 deletions
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. @@ -0,0 +1,24 @@ + Micromonitor Embedded System Boot Monitor + + This package contains code primarily developed at + Bell Laboratories, Alcatel-Lucent Technologies + (http:http://www.alcatel-lucent.com/). + + This software contains code derived from the Freebsd project + (https://www.freebsd.org/). + + The compression/decomppresion support is provided by the Zlib + project (www.zlib.net). + + Some files from both Freebsd and Zlib have been modified + to build in the Micromonitor environment. + + Some port/cpu/device-specific files are from Mike Kelly + Cogent Computer Systems (http://www.cogcomp.com). + + An SMC ethernet driver from Jay Monkman + (www.lopingdog.com). + + Some improvements to original JFFS2 code from Bill Gatliff + (www.billgatliff.com). + @@ -0,0 +1,51 @@ +This is the top-level of the MicroMonitor source tree. + +There are three main directories: +umon_main: + This is the common code reusable on various targets as the core + of MicroMonitor's functionality. +umon_ports: + This directory contains the public ports of MicroMonitor. Each + subdirectory contains the makefile and target-specific code for + one uMon port. +umon_apps: + This code provides a few different application examples for use + after the bootmonitor is built and running on your target. The + best place to go there is umon_apps/demo. This directory contains + the source and makefile that support building a basic application + for any target supported by MicroMonitor. + +For a quick introduction refer to: + http://www.umonfw.com/docs/white_paper.pdf +For a lot more than you'll ever care to read about it refer to: + http://www.umonfw.com/docs/umon_user_manual.pdf +OR... + +To get started, refer to umon_main/README. + +----------------------------------------------------------------------- + +Re-release of Micromonitor (aka uMon) under the Apache 2.0 license... + +Starting with the original umon1.19 code I referred to + +http://www.apache.org/dev/apply-license.html#new + +to do what was necessary to re-release a new smaller version of the +uMon code under the Apache 2.0 license. This was originally motivated +by a request from a GSOC (Google Summer of Code) student wanting to +port uMon to the BeagleBone Black board as an alternative bootloader +for use by the RTEMS embedded operating system. + +I copied http://www.apache.org/licenses/LICENSE-2.0.txt +to this local LICENSE file. + +I started with https://www.apache.org/licenses/example-NOTICE.txt +to create an appropriate NOTICE file. + +This README file was last modified on Mar 28, 2015. + +Primary contact: +Ed Sutter ed.sutter@alcatel-lucent.com + +----------------------------------------------------------------------- diff --git a/apps/common/cli.h b/apps/common/cli.h new file mode 100644 index 0000000..6384816 --- /dev/null +++ b/apps/common/cli.h @@ -0,0 +1,123 @@ +/* cli.h: + * Header file for Command Line Interface related stuff. + * + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Note1: the majority of this code was edited with 4-space tabs. + * Note2: as more and more contributions are accepted, the term "author" + * is becoming a mis-representation of credit. + * + * Original author: Ed Sutter + * Email: esutter@lucent.com + * Phone: 908-582-2351 + */ +#ifndef _cli_h +#define _cli_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* Command table structure used by the monitor: + */ +struct monCommand { + char *name; /* Name of command seen by user. */ + int (*func)(int,char **); /* Called when command is invoked. */ + char **helptxt; /* Help text (see notes below). */ + long flags; /* Single-bit flags for various uses */ + /* (see the CMDFLAG_XXX macros). */ +}; + +#ifdef __cplusplus +} +#endif + +/* Bits currently assigned to command flags used in the monCommand + * structure... + */ +#define CMDFLAG_NOMONRC 1 + +/* Maximum size of a command line: + */ +#ifndef CMDLINESIZE +#define CMDLINESIZE 128 +#endif + +/* Maximum number of arguments in a command line: + */ +#define ARGCNT 24 + +/* Definitions for docommand() return values: + * + * Note that the CMD_SUCCESS, CMD_FAILURE and CMD_PARAM_ERROR are return + * values used by the local command code also. The remaining errors + * (CMD_LINE_ERROR, CMD_ULVL_DENIED and CMD_NOT_FOUND) are used only by + # the docommand() function. + * + * CMD_SUCCESS: + * Everything worked ok. + * CMD_FAILURE: + * Command parameters were valid, but command itself failed for some other + * reason. The docommand() function does not print a message here, it + * is assumed that the error message was printed by the local function. + * CMD_PARAM_ERROR: + * Command line did not parse properly. Control was passed to a + * local command function, but argument syntax caused it to choke. + * In this case docommand() will print out the generic CLI syntax error + * message. + * CMD_LINE_ERROR: + * Command line itself was invalid. Too many args, invalid shell var + * syntax, etc.. Somekind of command line error prior to checking for + * the command name-to-function match. + * CMD_ULVL_DENIED: + * Command's user level is higher than current user level, so access + * is denied. + * CMD_NOT_FOUND: + * Since these same return values are used for each command function + * plus the docommand() function, this error indicates that docommand() + * could not even find the command in the command table. + * CMD_MONRC_DENIED: + * The command cannot execute because it is considered illegal + * when run from within the monrc file. + */ +#define CMD_SUCCESS 0 +#define CMD_FAILURE -1 +#define CMD_PARAM_ERROR -2 +#define CMD_LINE_ERROR -3 +#define CMD_ULVL_DENIED -4 +#define CMD_NOT_FOUND -5 +#define CMD_MONRC_DENIED -6 + +/* Notes on help text array: + * The monitor's CLI processor assumes that every command's help text + * array abides by a few basic rules... + * First of all, it assumes that every array has AT LEAST two strings. + * The first string in the array of strings is assumed to be a one-line + * abstract describing the command. + * The second string in the array of strings is assumed to be a usage + * message that describes the syntax of the arguments needed by the command. + * If this second string is an empty string (""), the docommand() prints out + * a generic usage string indicating that there are no options or arguements + * to apply to the command. + * All remaining lines are formatted based on the needs of the individual + * command and the final string is a null pointer to let the CLI processor + * know where the end is. + * Following is an example help text array... + * + * char *HelpHelp[] = { + * "Display command set", + * "-[d] [commandname]", + * "Options:", + * " -d list commands and descriptions", + * 0, + * }; + * + */ +#endif diff --git a/apps/common/crt0_arm.S b/apps/common/crt0_arm.S new file mode 100644 index 0000000..6e49597 --- /dev/null +++ b/apps/common/crt0_arm.S @@ -0,0 +1,13 @@ +#include "cfg.h" + + .extern AppStack + .extern Cstart + .global start + + /* Set stack pointer to end of AppStack and jump to Cstart: + */ +start: + ldr sp, =(AppStack + APPSTACKSIZE - 4) + +jump_to_c: + bl Cstart diff --git a/apps/common/crt0_bfin.S b/apps/common/crt0_bfin.S new file mode 100644 index 0000000..dda3a82 --- /dev/null +++ b/apps/common/crt0_bfin.S @@ -0,0 +1,34 @@ +#include "cfg.h" + + .extern _AppStack + .extern _Cstart + .global start + + .text + +start: + /* Clear all DAG registers: + */ + R0 = 0 + I0 = R0 + I1 = R0 + I2 = R0 + I3 = R0 + L0 = R0 + L1 = R0 + L2 = R0 + L3 = R0 + B0 = R0 + B1 = R0 + B2 = R0 + B3 = R0 + M0 = R0 + M1 = R0 + M2 = R0 + M3 = R0 + LC0 = R0; + LC1 = R0; + + sp.h = _AppStack+(APPSTACKSIZE-32) + sp.l = _AppStack+(APPSTACKSIZE-32) + jump _Cstart diff --git a/apps/common/crt0_cf.S b/apps/common/crt0_cf.S new file mode 100644 index 0000000..929c7ce --- /dev/null +++ b/apps/common/crt0_cf.S @@ -0,0 +1,11 @@ +#include "cfg.h" + + .extern AppStack + .extern Cstart + .global start + + .text + +start: + move.l #AppStack+(APPSTACKSIZE-32),%sp + jsr Cstart diff --git a/apps/common/crt0_mb.S b/apps/common/crt0_mb.S new file mode 100644 index 0000000..9894b9a --- /dev/null +++ b/apps/common/crt0_mb.S @@ -0,0 +1,14 @@ +#include "cfg.h" + + .extern AppStack + .extern Cstart + .global start + + /* Set stack pointer to end of AppStack and jump to Cstart: + */ +start: + addi r1, r0, AppStack + addi r1, r1, (APPSTACKSIZE-16) + +jump_to_c: + brai Cstart diff --git a/apps/common/crt0_mips.s b/apps/common/crt0_mips.s new file mode 100644 index 0000000..a4e4a4e --- /dev/null +++ b/apps/common/crt0_mips.s @@ -0,0 +1,25 @@ +#include "cfg.h" + +#define sp $29 +#define k0 $26 +#define KSEG_MSK 0xE0000000 +#define K0BASE 0x80000000 +#define KSEG1A(reg) \ + and reg, ~KSEG_MSK; \ + or reg, K1BASE; + + .extern AppStack + .global start + + .text + .set noreorder + +start: + la sp, AppStack + addiu sp, APPSTACKSIZE + addiu sp, -4*4 + +goToC: + la k0,Cstart + j k0 + nop diff --git a/apps/common/crt0_ppc.S b/apps/common/crt0_ppc.S new file mode 100644 index 0000000..80ef3db --- /dev/null +++ b/apps/common/crt0_ppc.S @@ -0,0 +1,16 @@ +#include "cfg.h" +#define sp 1 +#define r0 0 +#define r7 7 + + .extern AppStack + .extern Cstart + .globl start + +start: + lis sp, (AppStack+(APPSTACKSIZE-4))@h + addi sp, sp, (AppStack+(APPSTACKSIZE-4))@l + addi r7, r0, -8 + and sp, sp, r7 /* 8-byte aligned (EABI spec) */ + ba Cstart + nop diff --git a/apps/common/cygprof.c b/apps/common/cygprof.c new file mode 100644 index 0000000..b10bff2 --- /dev/null +++ b/apps/common/cygprof.c @@ -0,0 +1,26 @@ +/* This file supports the GCC option '-finstrument-functions' to + * insert per-function entry and exit calls... + * Every function that is recompiled with that option on will call + * __cyg_profile_func_enter() at the entrypoint and __cyg_profile_func_exit() + * at the exitpoint. + * This can be an extremely powerful capability for diagnosing various + * problems with system because it provides a trace of all functions + * executed. The disadvantage is time and space (minor detail)! + */ +int cyg_prof_on; + +void +__cyg_profile_func_enter (void *this_fn, void *call_site) +{ + if (cyg_prof_on) { + mon_memtrace("IN: %x %x\n", this_fn, call_site); + } +} + +void +__cyg_profile_func_exit (void *this_fn, void *call_site) +{ + if (cyg_prof_on) { + mon_memtrace("OUT: %x %x\n", this_fn, call_site); + } +} diff --git a/apps/common/monlib.c b/apps/common/monlib.c new file mode 100644 index 0000000..33c05e4 --- /dev/null +++ b/apps/common/monlib.c @@ -0,0 +1,1115 @@ +/* monlib.c: + * This file is part of the monitor code, but it is actually linked into + * the application. It is built with (but not linked with) the monitor, + * then the monlib.o file is linked with the application. + * The only requirement on the application is that it know where the address + * of the monCom function is in the monitor's space. + * The monCom function will be accessible in some "well-known" way (processor + * and platform dependent) so that this will not be a problem. + * + * This monlib.c file is a replacement for the older mechanism that was + * a bit more error-prone... A table of function pointers existed at some + * well-known location in the monitor, and the content of that table was + * assumed to also be "well-known". This new version only assumes that the + * pointer to monCom is well-known; everything else will work based on the + * fact that the monitor and application will share the monlib.h header + * file. + * + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Note1: the majority of this code was edited with 4-space tabs. + * Note2: as more and more contributions are accepted, the term "author" + * is becoming a mis-representation of credit. + * + * Original author: Ed Sutter + * Email: esutter@lucent.com + * Phone: 908-582-2351 + */ +#include "monlib.h" + +static int (*_tfsseek)(int,int,int); +static int (*_tfsgetline)(int,char *,int); +static int (*_tfsipmod)(char *,char *,int,int); +static int (*_tfsinit)(void); +static int (*_tfsadd)(char *,char *,char *,unsigned char *,int); +static int (*_tfsunlink)(char *); +static int (*_tfsrun)(char **,int); +static int (*_tfsread)(int,char *,int); +static int (*_tfswrite)(int,char *,int); +static int (*_tfsopen)(char *,long,char *); +static int (*_tfsclose)(int,char *); +static int (*_printf)(); +static int (*_cprintf)(); +static int (*_sprintf)(); +static int (*_monrestart)(int); +static int (*_rputchar)(unsigned char c); +static int (*_getchar)(void); +static int (*_gotachar)(void); +static int (*_getbytes)(char *,int,int); +static int (*_addcommand)(struct monCommand *,char *); +static int (*_docommand)(char *,int); +static int (*_getline)(char *,int,int); +static int (*_tfsfstat)(char *,struct tfshdr *); +static int (*_tfseof)(int); +static int (*_decompress)(char *,int,char *); +static int (*_tfstruncate)(int,long); +static int (*_heapextend)(char *,int); +static int (*_tfslink)(char *,char *); +static int (*_pcicfgwrite)(int,int,int,int,int,unsigned long); +static int (*_i2cwrite)(int,int,unsigned char *,int); +static int (*_i2cread)(int,int,unsigned char *,int); +static int (*_flashwrite)(char *,char *,int); +static int (*_flasherase)(int); +static int (*_flashinfo)(int,int *,char **); +static int (*_flashoverride)(void *,int,int); +static int (*_sendenet)(char *,int); +static int (*_recvenet)(char *,int); +static int (*_printpkt)(char *,int,int); +static int (*_setenv)(char *,char *); +static int (*_watchdog)(void); +static int (*_timeofday)(int,void *); +static int (*_montimer)(int cmd, void *arg); + +static char *(*_getenv)(char *); +static char *(*_version)(void); +static char *(*_getenvp)(void); +#ifdef MALLOC_DEBUG +static char *(*_malloc)(int,char *,int); +static char *(*_realloc)(char *buf,int,char *,int); +#else +static char *(*_malloc)(int); +static char *(*_realloc)(char *,int); +#endif +static char *(*_getsym)(char *,char *,int); + +static void (*_intsrestore)(unsigned long); +static void (*_appexit)(int); +static void (*_free)(char *); +static void (*_getargv)(int *,char ***); +static void (*_profiler)(void *); +static void (*_bbc)(char *,int); +static void (*_memtrace)(); +static void (*_appwarmstart)(unsigned long); +static void (*_mondelay)(long); +static void (*_printmem)(char *,int,int); + +static long (*_tfsctrl)(int,long,long); +static long (*_tfstell)(int); +static long (*_portcmd)(int,void *); + +static struct tfshdr *(*_tfsnext)(struct tfshdr *); +static struct tfshdr *(*_tfsstat)(char *); + +static unsigned long (*_i2cctrl)(int,int,unsigned long,unsigned long); +static unsigned long (*_pcicfgread)(int,int,int,int,int); +static unsigned long (*_pcictrl)(int,int,unsigned long,unsigned long); +static unsigned long (*_crc32)(unsigned char *,unsigned long); +static unsigned long (*_intsoff)(void); +static unsigned long (*_assign_handler)(long,unsigned long,unsigned long); + +static unsigned short (*_xcrc16)(unsigned char *,unsigned long); + + +static void (*_monlock)(void); +static void (*_monunlock)(void); +static int (*_moncom)(int,void *,void *, void *); + +/************************************************************************** + * + * The following macros support the default monitor lock/unlock mechanism when + * they point to monLock and monUnlock. If something other than the default + * is to be used, then simply redefine them here. Refer to the monitor + * app note that discusses multi-tasking access to the monitor API for more + * information. + * + * TFS_MONLOCK/UNLOCK: + * Lock/unlock for functions that access TFS flash space: + */ +#define TFS_MONLOCK monLock +#define TFS_MONUNLOCK monUnlock + +/* ENV_MONLOCK/UNLOCK: + * Lock/unlock for functions that access monitor shell variables: + */ +#define ENV_MONLOCK monLock +#define ENV_MONUNLOCK monUnlock + +/* CONSOLE_MONLOCK/UNLOCK: + * Lock/unlock for functions in the monitor that deal with console output. + */ +#define CONSOLE_MONLOCK monLock +#define CONSOLE_MONUNLOCK monUnlock + +/* HEAP_MONLOCK/UNLOCK: + * Lock/unlock for functions in the monitor that deal with the heap. + */ +#define HEAP_MONLOCK monLock +#define HEAP_MONUNLOCK monUnlock + +/* BLOCKING_MONLOCK/UNLOCK: + * Lock/unlock for functions in the monitor that block waiting for + * console input. + */ +#define BLOCKING_MONLOCK monLock +#define BLOCKING_MONUNLOCK monUnlock + +/* GENERIC_MONLOCK/UNLOCK: + * Lock/unlock for all functions not covered by the above macros. + */ +#define GENERIC_MONLOCK monLock +#define GENERIC_MONUNLOCK monUnlock + +/************************************************************************** + * + * monConnect(): + * This must be the first call by the application code to talk to the + * monitor. It is expecting three incoming function pointers: + * + * mon: Points to the monitor's _moncom function; + * This is a "well-known" address because the monitor and + * application code (two separately linked binaries) must + * know it. + * lock: Points to a function in the application code that will be + * used by the monitor as a lock-out function (some kind of + * semaphore in the application). + * unlock: Points to a function in the application code that will be + * used by the monitor as an un-lock-out function (undo whatever + * lock-out mechanism was done by lock). + */ +int +monConnect(int (*mon)(int,void *,void *,void *), + void (*lock)(void), void (*unlock)(void)) +{ + int rc = 0; + + /* Assign incoming lock and unlock functions... */ + _monlock = lock; + _monunlock = unlock; + + /* If the mon pointer is non-zero, then make the mon_ connections... */ + if (mon) { + + _moncom = mon; + + /* Make the connections between "mon_" functions that are */ + /* symbolically accessible by the application and the corresponding */ + /* functions that exists in the monitor. */ + rc += _moncom(GETMONFUNC_PUTCHAR,&_rputchar,0,0); + rc += _moncom(GETMONFUNC_GETCHAR,&_getchar,0,0); + rc += _moncom(GETMONFUNC_GOTACHAR,&_gotachar,0,0); + rc += _moncom(GETMONFUNC_GETBYTES,&_getbytes,0,0); + rc += _moncom(GETMONFUNC_PRINTF,&_printf,0,0); + rc += _moncom(GETMONFUNC_CPRINTF,&_cprintf,0,0); + rc += _moncom(GETMONFUNC_SPRINTF,&_sprintf,0,0); + rc += _moncom(GETMONFUNC_RESTART,&_monrestart,0,0); + rc += _moncom(GETMONFUNC_GETENV,&_getenv,0,0); + rc += _moncom(GETMONFUNC_SETENV,&_setenv,0,0); + rc += _moncom(GETMONFUNC_TFSINIT,&_tfsinit,0,0); + rc += _moncom(GETMONFUNC_TFSADD,&_tfsadd,0,0); + rc += _moncom(GETMONFUNC_TFSUNLINK,&_tfsunlink,0,0); + rc += _moncom(GETMONFUNC_TFSRUN,&_tfsrun,0,0); + rc += _moncom(GETMONFUNC_TFSNEXT,&_tfsnext,0,0); + rc += _moncom(GETMONFUNC_TFSSTAT,&_tfsstat,0,0); + rc += _moncom(GETMONFUNC_TFSREAD,&_tfsread,0,0); + rc += _moncom(GETMONFUNC_TFSWRITE,&_tfswrite,0,0); + rc += _moncom(GETMONFUNC_TFSOPEN,&_tfsopen,0,0); + rc += _moncom(GETMONFUNC_TFSCLOSE,&_tfsclose,0,0); + rc += _moncom(GETMONFUNC_TFSSEEK,&_tfsseek,0,0); + rc += _moncom(GETMONFUNC_TFSGETLINE,&_tfsgetline,0,0); + rc += _moncom(GETMONFUNC_TFSIPMOD,&_tfsipmod,0,0); + rc += _moncom(GETMONFUNC_TFSCTRL,&_tfsctrl,0,0); + rc += _moncom(GETMONFUNC_ADDCOMMAND,&_addcommand,0,0); + rc += _moncom(GETMONFUNC_DOCOMMAND,&_docommand,0,0); + rc += _moncom(GETMONFUNC_GETARGV,&_getargv,0,0); + rc += _moncom(GETMONFUNC_CRC16,&_xcrc16,0,0); + rc += _moncom(GETMONFUNC_CRC32,&_crc32,0,0); + rc += _moncom(GETMONFUNC_INTSOFF,&_intsoff,0,0); + rc += _moncom(GETMONFUNC_INTSRESTORE,&_intsrestore,0,0); + rc += _moncom(GETMONFUNC_APPEXIT,&_appexit,0,0); + rc += _moncom(GETMONFUNC_MALLOC,&_malloc,0,0); + rc += _moncom(GETMONFUNC_FREE,&_free,0,0); + rc += _moncom(GETMONFUNC_GETLINE,&_getline,0,0); + rc += _moncom(GETMONFUNC_TFSFSTAT,&_tfsfstat,0,0); + rc += _moncom(GETMONFUNC_TFSEOF,&_tfseof,0,0); + rc += _moncom(GETMONFUNC_DECOMPRESS,&_decompress,0,0); + rc += _moncom(GETMONFUNC_TFSTRUNCATE,&_tfstruncate,0,0); + rc += _moncom(GETMONFUNC_HEAPXTEND,&_heapextend,0,0); + rc += _moncom(GETMONFUNC_PROFILER,&_profiler,0,0); + rc += _moncom(GETMONFUNC_TFSLINK,&_tfslink,0,0); + rc += _moncom(GETMONFUNC_BBC,&_bbc,0,0); + rc += _moncom(GETMONFUNC_MEMTRACE,&_memtrace,0,0); + rc += _moncom(GETMONFUNC_TFSTELL,&_tfstell,0,0); + rc += _moncom(GETMONFUNC_VERSION,&_version,0,0); + rc += _moncom(GETMONFUNC_WARMSTART,&_appwarmstart,0,0); + rc += _moncom(GETMONFUNC_PCICFGREAD,&_pcicfgread,0,0); + rc += _moncom(GETMONFUNC_PCICFGWRITE,&_pcicfgwrite,0,0); + rc += _moncom(GETMONFUNC_PCICONTROL,&_pcictrl,0,0); + rc += _moncom(GETMONFUNC_I2CREAD,&_i2cread,0,0); + rc += _moncom(GETMONFUNC_I2CWRITE,&_i2cwrite,0,0); + rc += _moncom(GETMONFUNC_I2CCONTROL,&_i2cctrl,0,0); + rc += _moncom(GETMONFUNC_MONDELAY,&_mondelay,0,0); + rc += _moncom(GETMONFUNC_GETENVP,&_getenvp,0,0); + rc += _moncom(GETMONFUNC_REALLOC,&_realloc,0,0); + rc += _moncom(GETMONFUNC_SENDENETPKT,&_sendenet,0,0); + rc += _moncom(GETMONFUNC_RECVENETPKT,&_recvenet,0,0); + rc += _moncom(GETMONFUNC_GETSYM,&_getsym,0,0); + rc += _moncom(GETMONFUNC_PRINTPKT,&_printpkt,0,0); + rc += _moncom(GETMONFUNC_FLASHWRITE,&_flashwrite,0,0); + rc += _moncom(GETMONFUNC_FLASHERASE,&_flasherase,0,0); + rc += _moncom(GETMONFUNC_FLASHINFO,&_flashinfo,0,0); + rc += _moncom(GETMONFUNC_ASSIGNHDLR,&_assign_handler,0,0); + rc += _moncom(GETMONFUNC_WATCHDOG,&_watchdog,0,0); + rc += _moncom(GETMONFUNC_PRINTMEM,&_printmem,0,0); + rc += _moncom(GETMONFUNC_PORTCMD,&_portcmd,0,0); + rc += _moncom(GETMONFUNC_TIMEOFDAY,&_timeofday,0,0); + rc += _moncom(GETMONFUNC_TIMER,&_montimer,0,0); + rc += _moncom(GETMONFUNC_FLASHOVRRD,&_flashoverride,0,0); + } + return(rc); +} + +/* ignorelock: + * Used as a back-door to disable the monLock()/monUnlock() stuff. + * This is useful if the application CLI falls through to the monitor's + * CLI and you are using the "call" command in the monitor to execute some + * function that has a mon_xxx function in it. In this case, the fact that + * the application has fallen through to the monitor means that the lock + * is already active, so when the function tries to call some other mon_xxx + * function it won't be able to because of the lock already being set. + * + * With these functions in the application space, the user can do the + * following: + * call %DisableLock + * call %Func_with_monXXX_in_it + * call %EnableLock + * + * Note that this is NOT to be used by application code, it is simply a + * back-door mechanism to allow "call" from the CLI to invoke functions + * that have mon_XXX functionality in them. + */ +static int ignorelock = 0; + +void +DisableMonLock(void) +{ + ignorelock = 2; +} + +void +EnableMonLock(void) +{ + ignorelock = 0; +} + +/* monLock() & monUnlock(): + * Used by all of the wrapper functions below this point to call + * the function pointed to by _monlock & _monunlock function pointers + * (if set). + * These functions must test both the function pointer and the state + * of the ignorelock variable. The function DisableMonLock() sets the + * ignorelock variable to 2 because it is being executed through "call" + * which means that the lock is active. + */ +static void +monLock() +{ + if (_monlock) { + switch(ignorelock) { + case 1: + break; + case 2: + ignorelock--; + break; + default: + _monlock(); + break; + } + } +} + +static void +monUnlock() +{ + if (_monunlock) { + switch(ignorelock) { + case 1: + break; + case 2: + ignorelock--; + default: + _monunlock(); + break; + } + } +} + +int +mon_com(int cmd, void *arg1, void *arg2, void *arg3) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _moncom(cmd,arg1,arg2,arg3); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_putchar(char c) +{ + int ret; + + CONSOLE_MONLOCK(); + ret = _rputchar(c); + CONSOLE_MONUNLOCK(); + return(ret); +} + +int +mon_getchar(void) +{ + int ret; + + BLOCKING_MONLOCK(); + ret = _getchar(); + BLOCKING_MONUNLOCK(); + return(ret); +} + +int +mon_gotachar(void) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _gotachar(); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_getbytes(char *buf,int cnt,int block) +{ + int ret; + + BLOCKING_MONLOCK(); + ret = _getbytes(buf,cnt,block); + BLOCKING_MONUNLOCK(); + return(ret); +} + +int +mon_printf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +char *fmt; +int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12; +{ + int ret; + + CONSOLE_MONLOCK(); + ret = _printf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); + CONSOLE_MONUNLOCK(); + return(ret); +} + +int +mon_cprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +char *fmt; +int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12; +{ + int ret; + + CONSOLE_MONLOCK(); + ret = _cprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); + CONSOLE_MONUNLOCK(); + return(ret); +} + +int +mon_sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +char *fmt, *buf; +int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12; +{ + int ret; + + GENERIC_MONLOCK(); + ret = _sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_restart(int val) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _monrestart(val); + GENERIC_MONUNLOCK(); + return(ret); +} + +char * +mon_getenvp(void) +{ + char *ret; + + ENV_MONLOCK(); + ret = _getenvp(); + ENV_MONUNLOCK(); + return(ret); +} + +char * +mon_getenv(char *name) +{ + char *ret; + + ENV_MONLOCK(); + ret = _getenv(name); + ENV_MONUNLOCK(); + return(ret); +} + +int +mon_setenv(char *name,char *val) +{ + int ret; + + ENV_MONLOCK(); + ret = _setenv(name,val); + ENV_MONUNLOCK(); + return(ret); +} + +char * +mon_getsym(char *name,char *buf, int bufsize) +{ + char *ret; + + ENV_MONLOCK(); + ret = _getsym(name,buf,bufsize); + ENV_MONUNLOCK(); + return(ret); +} + +int +mon_tfsinit(void) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsinit(); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsadd(char *name, char *info, char *flags, unsigned char *src, int size) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsadd(name,info,flags,src,size); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfslink(char *src, char *target) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfslink(src,target); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsunlink(char *name) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsunlink(name); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsrun(char **name,int verbose) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsrun(name,verbose); + TFS_MONUNLOCK(); + return(ret); +} + +struct tfshdr * +mon_tfsnext(struct tfshdr *fp) +{ + struct tfshdr *ret; + + TFS_MONLOCK(); + ret = _tfsnext(fp); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfstruncate(int tfd, long len) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfstruncate(tfd,len); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfseof(int tfd) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfseof(tfd); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsfstat(char *name, struct tfshdr *fp) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsfstat(name,fp); + TFS_MONUNLOCK(); + return(ret); +} + +struct tfshdr * +mon_tfsstat(char *name) +{ + struct tfshdr *ret; + + TFS_MONLOCK(); + ret = _tfsstat(name); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsread(int fd, char *buf, int cnt) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsread(fd,buf,cnt); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfswrite(int fd, char *buf, int cnt) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfswrite(fd,buf,cnt); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsopen(char *file,long flagmode,char *buf) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsopen(file,flagmode,buf); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsclose(int fd,char *info) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsclose(fd,info); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsseek(int fd, int offset, int whence) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsseek(fd,offset,whence); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsgetline(int fd,char *bp,int max) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsgetline(fd,bp,max); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsipmod(char *name,char *buf,int offset,int size) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsipmod(name,buf,offset,size); + TFS_MONUNLOCK(); + return(ret); +} + +long +mon_tfsctrl(int rqst,long arg1,long arg2) +{ + long ret; + + TFS_MONLOCK(); + ret = _tfsctrl(rqst,arg1,arg2); + TFS_MONUNLOCK(); + return(ret); +} + +long +mon_tfstell(int fd) +{ + long ret; + + TFS_MONLOCK(); + ret = _tfstell(fd); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_addcommand(struct monCommand *cmdlist, char *cmdlvl) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _addcommand(cmdlist,cmdlvl); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_docommand(char *cmdline,int verbose) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _docommand(cmdline,verbose); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_getargv(int *argc,char ***argv) +{ + GENERIC_MONLOCK(); + _getargv(argc,argv); + GENERIC_MONUNLOCK(); +} + +unsigned short +mon_xcrc16(char *buf,long nbytes) +{ + unsigned short ret; + + GENERIC_MONLOCK(); + ret = _xcrc16((unsigned char *)buf,nbytes); + GENERIC_MONUNLOCK(); + return(ret); +} + +unsigned long +mon_intsoff(void) +{ + unsigned long ret; + + GENERIC_MONLOCK(); + ret = _intsoff(); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_intsrestore(unsigned long msr) +{ + GENERIC_MONLOCK(); + _intsrestore(msr); + GENERIC_MONUNLOCK(); +} + +void +mon_appexit(int val) +{ + GENERIC_MONLOCK(); + _appexit(val); + GENERIC_MONUNLOCK(); +} + +#ifdef MALLOC_DEBUG +char * +mon_malloc(int size,char *fname,int fline) +{ + char *ret; + + HEAP_MONLOCK(); + ret = _malloc(size,fname,fline); + HEAP_MONUNLOCK(); + return(ret); +} + +char * +mon_realloc(char *buf, int size, char *fname, int fline) +{ + char *ret; + + HEAP_MONLOCK(); + ret = _realloc(buf,size, fname, fline); + HEAP_MONUNLOCK(); + return(ret); +} +#else +char * +mon_malloc(int size) +{ + char *ret; + + HEAP_MONLOCK(); + ret = _malloc(size); + HEAP_MONUNLOCK(); + return(ret); +} + +char * +mon_realloc(char *buf, int size) +{ + char *ret; + + HEAP_MONLOCK(); + ret = _realloc(buf,size); + HEAP_MONUNLOCK(); + return(ret); +} +#endif + +void +mon_free(char *cp) +{ + HEAP_MONLOCK(); + _free(cp); + HEAP_MONUNLOCK(); +} + +int +mon_getline(char *buf,int max,int ledit) +{ + int ret; + + BLOCKING_MONLOCK(); + ret = _getline(buf,max,ledit); + BLOCKING_MONUNLOCK(); + return(ret); +} + +int +mon_decompress(char *src,int srcsize,char *dest) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _decompress(src,srcsize,dest); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_heapextend(char *base,int size) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _heapextend(base,size); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_bbc(char *filename, int lineno) +{ + _bbc(filename, lineno); +} + +void +mon_profiler(void *pdata) +{ + _profiler(pdata); +} + +void +mon_memtrace(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +char *fmt; +int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12; +{ + _memtrace(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); +} + +char * +mon_version(void) +{ + char *ret; + + GENERIC_MONLOCK(); + ret = _version(); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_warmstart(unsigned long mask) +{ + GENERIC_MONLOCK(); + _appwarmstart(mask); + GENERIC_MONUNLOCK(); +} + +int +mon_pcicfgwrite(int interface,int bus,int dev,int func,int reg, + unsigned long val) +{ + int retval; + + GENERIC_MONLOCK(); + retval = _pcicfgwrite(interface,bus,dev,func,reg,val); + GENERIC_MONUNLOCK(); + return(retval); +} + +unsigned long +mon_pcicfgread(int interface,int bus,int dev, int func,int reg) +{ + unsigned long retval; + + GENERIC_MONLOCK(); + retval = _pcicfgread(interface,bus,dev,func,reg); + GENERIC_MONUNLOCK(); + return(retval); +} + +unsigned long +mon_pcictrl(int interface, int cmd, unsigned long arg1, unsigned long arg2) +{ + unsigned long val; + + GENERIC_MONLOCK(); + val = _pcictrl(interface,cmd,arg1,arg2); + GENERIC_MONUNLOCK(); + return(val); +} + +unsigned long +mon_i2cctrl(int interface, int cmd, unsigned long arg1, unsigned long arg2) +{ + unsigned long val; + + GENERIC_MONLOCK(); + val = _i2cctrl(interface,cmd,arg1,arg2); + GENERIC_MONUNLOCK(); + return(val); +} + +int +mon_i2cwrite(int interface, int bigaddr, unsigned char *data, int len) +{ + int val; + + GENERIC_MONLOCK(); + val = _i2cwrite(interface,bigaddr,data,len); + GENERIC_MONUNLOCK(); + return(val); +} + +int +mon_i2cread(int interface, int bigaddr, unsigned char *data, int len) +{ + int val; + + GENERIC_MONLOCK(); + val = _i2cread(interface,bigaddr,data,len); + GENERIC_MONUNLOCK(); + return(val); +} + +void +mon_delay(long msec) +{ + GENERIC_MONLOCK(); + _mondelay(msec); + GENERIC_MONUNLOCK(); +} + +int +mon_timer(int cmd, void *arg) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _montimer(cmd, arg); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_sendenetpkt(char *pkt,int size) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _sendenet(pkt,size); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_recvenetpkt(char *pkt,int size) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _recvenet(pkt,size); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_printpkt(char *buf,int size, int incoming) +{ + GENERIC_MONLOCK(); + _printpkt(buf,size,incoming); + GENERIC_MONUNLOCK(); +} + +int +mon_flashoverride(void *flashinfo,int get,int bank) +{ + int ret; + + TFS_MONLOCK(); + ret = _flashoverride(flashinfo,get,bank); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_flashwrite(char *dest,char *src,int bytecnt) +{ + int ret; + + TFS_MONLOCK(); + ret = _flashwrite(dest,src,bytecnt); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_flasherase(int snum) +{ + int ret; + + TFS_MONLOCK(); + ret = _flasherase(snum); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_flashinfo(int snum, int *size, char **base) +{ + int ret; + + TFS_MONLOCK(); + ret = _flashinfo(snum,size,base); + TFS_MONUNLOCK(); + return(ret); +} + +unsigned long +mon_assignhandler(long hnum, unsigned long arg1, unsigned long arg2) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _assign_handler(hnum,arg1,arg2); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_watchdog(void) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _watchdog(); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_printmem(char *mem, int size, int ascii) +{ + GENERIC_MONLOCK(); + _printmem(mem,size,ascii); + GENERIC_MONUNLOCK(); +} + +long +mon_portcmd(int cmd, void *arg) +{ + long ret; + + GENERIC_MONLOCK(); + ret = _portcmd(cmd,arg); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_timeofday(int cmd, void *arg) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _timeofday(cmd,arg); + GENERIC_MONUNLOCK(); + return(ret); +} diff --git a/apps/common/monlib.h b/apps/common/monlib.h new file mode 100644 index 0000000..10e37f4 --- /dev/null +++ b/apps/common/monlib.h @@ -0,0 +1,239 @@ +/* monlib.h: + * This header file is used by both the monitor and the application that + * may reside on top of the monitor. + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Note1: the majority of this code was edited with 4-space tabs. + * Note2: as more and more contributions are accepted, the term "author" + * is becoming a mis-representation of credit. + * + * Original author: Ed Sutter + * Email: esutter@lucent.com + * Phone: 908-582-2351 + */ +#ifndef _MONLIB_H_ +#define _MONLIB_H_ + +#include "tfs.h" +#include "cli.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +extern int monConnect(int (*monptr)(int,void *,void *,void *), + void (*lock)(void),void (*unlock)(void)); +extern void mon_getargv(int *argc,char ***argv); +extern void mon_intsrestore(unsigned long oldval); +extern void mon_appexit(int exit_value); +extern void mon_free(char *buffer); +extern void mon_profiler(void *pdata); +extern void mon_bbc(char *filename, int linenum); +extern void mon_warmstart(unsigned long mask); +extern void mon_delay(long msec); +extern void mon_printpkt(char *buf, int size, int incoming); +extern void mon_printmem(char *mem, int size, int ascii); + + +extern int mon_com(int cmd,void *arg1,void *arg2,void *arg3); +extern int mon_timer(int cmd, void * arg); +extern int mon_setenv(char *varname,char *value); +extern int mon_putchar(char c); +extern int mon_getchar(void); +extern int mon_gotachar(void); +extern int mon_getbytes(char *buf,int count,int block); +extern int mon_restart(int restart_value); +extern int mon_tfsinit(void); +extern int mon_tfsunlink(char *filename); +extern int mon_tfslink(char *source, char *target); +extern int mon_tfsrun(char **arglist,int verbosity); +extern int mon_tfsfstat(char *filename,struct tfshdr *tfp); +extern int mon_tfseof(int file_descriptor); +extern int mon_tfstruncate(int file_descriptor,long length); +extern int mon_tfsread(int file_descriptor,char *buffer,int size); +extern int mon_tfswrite(int file_descriptor,char *buffer,int size); +extern int mon_tfsopen(char *filename,long mode,char *buffer); +extern int mon_tfsclose(int file_descriptor,char *info); +extern int mon_tfsseek(int file_descriptor,int offset,int whence); +extern int mon_tfsgetline(int file_descriptor,char *buffer,int bufsize); +extern int mon_tfsipmod(char *name,char *buffer,int offset,int size); +extern int mon_addcommand(struct monCommand *command_list,char *); +extern int mon_docommand(char *cmdline,int verbosity); +extern int mon_getline(char *buffer,int max,int ledit); +extern int mon_decompress(char *src,int srcsize,char *dest); +extern int mon_heapextend(char *base,int size); +extern int mon_pcicfgwrite(int interface,int bus,int dev,int func,int reg, + unsigned long val); +extern int mon_tfsadd(char *filename, char *info, char *flags, + unsigned char *src, int size); +extern int mon_i2cwrite(int interface, int bigaddr, unsigned char *data, + int len); +extern int mon_i2cread(int interface, int bigaddr, unsigned char *data, + int len); +extern int mon_sendenetpkt(char *pkt, int len); +extern int mon_recvenetpkt(char *pkt, int len); +extern int mon_flashoverride(void *flashinfo, int get, int bank); +extern int mon_flasherase(int snum); +extern int mon_flashwrite(char *dest,char *src, int bytecnt); +extern int mon_flashinfo(int snum,int *size, char **base); +extern int mon_watchdog(void); +extern int mon_timeofday(int cmd, void *arg); + +extern char *mon_getsym(char *symname, char *buf, int bufsize); +extern char *mon_getenv(char *varname); +extern char *mon_getenvp(void); +extern char *mon_version(void); +#ifdef MALLOC_DEBUG +extern char *mon_malloc(int size,char *file, int line); +extern char *mon_realloc(char *buf,int size,char *file, int line); +#else +extern char *mon_malloc(int size); +extern char *mon_realloc(char *buf,int size); +#endif + +extern long mon_tfsctrl(int command,long arg1,long arg2); +extern long mon_tfstell(int file_descriptor); +extern long mon_portcmd(int cmd, void *arg); + +extern unsigned short mon_xcrc16(char *buffer,long length); + +extern unsigned long mon_intsoff(void); + +extern unsigned long mon_pcicfgread(int interface,int bus,int dev, + int func,int reg); + +extern unsigned long mon_pcictrl(int interface, int cmd, + unsigned long arg1, unsigned long arg2); + +extern unsigned long mon_i2cctrl(int interface, int cmd, + unsigned long arg1, unsigned long arg2); + +extern unsigned long mon_assignhandler(long hnum, + unsigned long arg1,unsigned long arg2); + +extern struct tfshdr *mon_tfsnext(struct tfshdr *tfp); +extern struct tfshdr *mon_tfsstat(char *filename); + +#if SHOWVARARGS +extern void mon_memtrace(char *fmt, ...); +extern int mon_printf(char *fmt, ...); +extern int mon_cprintf(char *fmt, ...); +extern int mon_sprintf(char *,char *fmt, ...); +#else +extern void mon_memtrace(); +extern int mon_printf(); +extern int mon_cprintf(); +extern int mon_sprintf(); +#endif + +#ifdef __cplusplus +} +#endif + + +/* defines used by monConnect(): + */ +#define GETMONFUNC_PUTCHAR 1 +#define GETMONFUNC_GETCHAR 2 +#define GETMONFUNC_GOTACHAR 3 +#define GETMONFUNC_GETBYTES 4 +#define GETMONFUNC_PRINTF 5 +#define GETMONFUNC_CPRINTF 6 +#define GETMONFUNC_SPRINTF 7 +#define GETMONFUNC_RESTART 8 +#define GETMONFUNC_GETENV 9 +#define GETMONFUNC_SETENV 10 +#define GETMONFUNC_TFSINIT 11 +#define GETMONFUNC_TFSADD 12 +#define GETMONFUNC_TFSUNLINK 13 +#define GETMONFUNC_TFSRUN 14 +#define GETMONFUNC_TFSNEXT 15 +#define GETMONFUNC_TFSSTAT 16 +#define GETMONFUNC_TFSREAD 17 +#define GETMONFUNC_TFSWRITE 18 +#define GETMONFUNC_TFSOPEN 19 +#define GETMONFUNC_TFSCLOSE 20 +#define GETMONFUNC_TFSSEEK 21 +#define GETMONFUNC_TFSGETLINE 22 +#define GETMONFUNC_TFSIPMOD 23 +#define GETMONFUNC_TFSCTRL 24 +#define GETMONFUNC_ADDCOMMAND 25 +#define GETMONFUNC_DOCOMMAND 26 +#define GETMONFUNC_GETARGV 27 +#define GETMONFUNC_CRC16 28 +#define GETMONFUNC_CRC32 29 +#define GETMONFUNC_PIOGET 30 /* NA (removed as of 1.0) */ +#define GETMONFUNC_PIOSET 31 /* NA (removed as of 1.0) */ +#define GETMONFUNC_PIOCLR 32 /* NA (removed as of 1.0) */ +#define GETMONFUNC_INTSOFF 33 +#define GETMONFUNC_INTSRESTORE 34 +#define GETMONFUNC_APPEXIT 35 +#define GETMONFUNC_MALLOC 36 +#define GETMONFUNC_FREE 37 +#define GETMONFUNC_GETLINE 38 +#define GETMONFUNC_TFSFSTAT 39 +#define GETMONFUNC_TFSEOF 40 +#define GETMONFUNC_DECOMPRESS 41 +#define GETMONFUNC_TFSTRUNCATE 42 +#define GETMONFUNC_HEAPXTEND 43 +#define GETMONFUNC_PROFILER 44 +#define GETMONFUNC_TFSLINK 45 +#define GETMONFUNC_BBC 46 +#define GETMONFUNC_MEMTRACE 47 +#define GETMONFUNC_TFSTELL 48 +#define GETMONFUNC_VERSION 49 +#define GETMONFUNC_WARMSTART 50 +#define GETMONFUNC_PCICFGREAD 51 +#define GETMONFUNC_PCICFGWRITE 52 +#define GETMONFUNC_PCICONTROL 53 +#define GETMONFUNC_I2CREAD 54 +#define GETMONFUNC_I2CWRITE 55 +#define GETMONFUNC_I2CCONTROL 56 +#define GETMONFUNC_MONDELAY 57 +#define GETMONFUNC_GETENVP 58 +#define GETMONFUNC_REALLOC 59 +#define GETMONFUNC_SENDENETPKT 60 +#define GETMONFUNC_RECVENETPKT 61 +#define GETMONFUNC_GETSYM 62 +#define GETMONFUNC_PRINTPKT 63 +#define GETMONFUNC_FLASHWRITE 64 +#define GETMONFUNC_FLASHERASE 65 +#define GETMONFUNC_FLASHINFO 66 +#define GETMONFUNC_ASSIGNHDLR 67 +#define GETMONFUNC_WATCHDOG 68 +#define GETMONFUNC_PRINTMEM 69 +#define GETMONFUNC_PORTCMD 70 +#define GETMONFUNC_TIMEOFDAY 71 +#define GETMONFUNC_TIMER 72 +#define GETMONFUNC_FLASHOVRRD 73 + +#define CACHEFTYPE_DFLUSH 200 +#define CACHEFTYPE_IINVALIDATE 201 + +#define CHARFUNC_PUTCHAR 300 +#define CHARFUNC_GETCHAR 301 +#define CHARFUNC_GOTACHAR 302 +#define CHARFUNC_RAWMODEON 303 +#define CHARFUNC_RAWMODEOFF 304 + +#define ASSIGNFUNC_GETUSERLEVEL 400 + + +/* Defines used by mon_warmstart(): + */ +#define WARMSTART_IOINIT 0x00000001 +#define WARMSTART_BSSINIT 0x00000002 +#define WARMSTART_RUNMONRC 0x00000004 +#define WARMSTART_MONHEADER 0x00000008 +#define WARMSTART_TFSAUTOBOOT 0x00000010 +#define WARMSTART_BOARDINFO 0x00000020 +#define WARMSTART_ALL 0xffffffff +#endif diff --git a/apps/common/tfs.h b/apps/common/tfs.h new file mode 100644 index 0000000..f83d518 --- /dev/null +++ b/apps/common/tfs.h @@ -0,0 +1,187 @@ +/* tfs.h: + * Header file for TFS transactions, used by both application and monitor. + * + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Note1: the majority of this code was edited with 4-space tabs. + * Note2: as more and more contributions are accepted, the term "author" + * is becoming a mis-representation of credit. + * + * Original author: Ed Sutter + * Email: esutter@lucent.com + * Phone: 908-582-2351 + */ +#ifndef _tfs_h +#define _tfs_h + +#define TFSINFOSIZE 23 /* Max size of info string (mod4-1). */ + +#ifndef TFSNAMESIZE /* This specifies the maximum size of a file */ +#define TFSNAMESIZE 23 /* name that can be used in TFS. */ +#endif /* This MUST be some value mod4 - 1. */ + +#ifndef TFS_CHANGELOG_FILE /* Information used for change-log */ +#define TFS_CHANGELOG_SIZE 0 /* facility within tfs. */ +#define TFS_CHANGELOG_FILE ".tfschlog" +#endif + +#ifndef SYMFILE /* This specifies the default filename */ +#define SYMFILE "symtbl" /* used by the monitor for the symbol */ +#endif /* table. */ + +#define MINUSRLEVEL 0 /* Minimum user level supported. */ +#define MAXUSRLEVEL 3 /* Maximum user level supported. */ + +#ifndef TFS_RESERVED +#define TFS_RESERVED 4 /* Number of "reserved" entries (ulong) */ +#endif /* in the TFS header. */ + + +/* Flags: */ +#define TFS_EXEC 0x00000001 /* 'e': Executable script. */ +#define TFS_BRUN 0x00000002 /* 'b': To be executed at boot. */ +#define TFS_QRYBRUN 0x00000004 /* 'B': To be executed at boot if */ + /* query passes. */ +#define TFS_SYMLINK 0x00000008 /* 'l': Symbolic link file. */ +#define TFS_EBIN 0x00000010 /* 'E': Executable binary (coff/elf/a.out). */ +#define TFS_CPRS 0x00000040 /* 'c': File is compressed. */ +#define TFS_IPMOD 0x00000080 /* 'i': File is in-place modifiable. */ +#define TFS_UNREAD 0x00000100 /* 'u': File is not even readable if the */ + /* user-level requirement is not met; */ + /* else, it is read-only. */ +#define TFS_ULVLMSK 0x00000600 /* User level mask defines 4 access levels: */ +#define TFS_ULVL0 0x00000000 /* '0' level 0 */ +#define TFS_ULVL1 0x00000200 /* '1' level 1 */ +#define TFS_ULVL2 0x00000400 /* '2' level 2 */ +#define TFS_ULVL3 0x00000600 /* '3' level 3 */ +#define TFS_NSTALE 0x00000800 /* File is NOT stale, invisible to user. + * When this bit is clear, the file is + * considered stale (see notes in tfsadd()). + * See notes in tfsclose() for this. + */ +#define TFS_ACTIVE 0x00008000 /* Used to indicate that file is not deleted. */ + +#define TFS_ULVLMAX TFS_ULVL3 +#define TFS_USRLVL(f) ((f->flags & TFS_ULVLMSK) >> 9) + +/* Open modes */ +#define TFS_RDONLY 0x00010000 /* File is opened for reading. */ +#define TFS_CREATE 0x00020000 /* File is to be created. Error if file */ + /* with the same name already exists. */ +#define TFS_APPEND 0x00040000 /* Append to existing file. If OR'ed */ + /* with TFS_CREATE, then create if */ + /* necessary. */ +#define TFS_ALLFFS 0x00080000 /* File is created with all FFs. */ +#define TFS_CREATERM 0x00100000 /* File is to be created. If file with */ + /* same name already exists, then allow */ + /* tfsadd() to remove it if necessary. */ + +/* The function tfsrunrc() will search through the current file set and */ +/* if the file defined by TFS_RCFILE exists, it will be executed. */ +/* If this file exists, it will NOT be run by tfsrunboot(). */ +#define TFS_RCFILE "monrc" + +/* Requests that can be made to tfsctrl(): */ +#define TFS_ERRMSG 1 +#define TFS_MEMUSE 2 +#define TFS_MEMDEAD 3 +#define TFS_DEFRAG 4 +#define TFS_TELL 5 +#define TFS_UNOPEN 7 +#define TFS_FATOB 8 +#define TFS_FBTOA 9 +#define TFS_MEMAVAIL 10 +#define TFS_TIMEFUNCS 11 +#define TFS_DOCOMMAND 12 +#define TFS_INITDEV 13 +#define TFS_CHECKDEV 14 +#define TFS_DEFRAGDEV 15 +#define TFS_DEFRAGOFF 16 +#define TFS_DEFRAGON 17 +#define TFS_HEADROOM 18 +#define TFS_FCOUNT 19 + +/* struct tfshdr: + * It is in FLASH as part of the file system to record the attributes of + * the file at the time of creation. + */ +struct tfshdr { + unsigned short hdrsize; /* Size of this header. */ + unsigned short hdrvrsn; /* Header version #. */ + long filsize; /* Size of the file. */ + long flags; /* Flags describing the file. */ + unsigned long filcrc; /* 32 bit CRC of file. */ + unsigned long hdrcrc; /* 32 bit CRC of the header. */ + unsigned long modtime; /* Time when file was last modified. */ + struct tfshdr *next; /* Pointer to next file in list. */ + char name[TFSNAMESIZE+1]; /* Name of file. */ + char info[TFSINFOSIZE+1]; /* Miscellaneous info field. */ +#if TFS_RESERVED + unsigned long rsvd[TFS_RESERVED]; +#endif +}; + +#define TFSHDRSIZ sizeof(struct tfshdr) + +/* TFS error returns. */ +#define TFS_OKAY 0 +#define TFSERR_NOFILE -1 +#define TFSERR_NOSLOT -2 +#define TFSERR_EOF -3 +#define TFSERR_BADARG -4 +#define TFSERR_NOTEXEC -5 +#define TFSERR_BADCRC -6 +#define TFSERR_FILEEXISTS -7 +#define TFSERR_FLASHFAILURE -8 +#define TFSERR_WRITEMAX -9 +#define TFSERR_RDONLY -10 +#define TFSERR_BADFD -11 +#define TFSERR_BADHDR -12 +#define TFSERR_CORRUPT -13 +#define TFSERR_MEMFAIL -14 +#define TFSERR_NOTIPMOD -16 +#define TFSERR_MUTEXFAILURE -17 +#define TFSERR_FLASHFULL -18 +#define TFSERR_USERDENIED -19 +#define TFSERR_NAMETOOBIG -20 +#define TFSERR_FILEINUSE -21 +#define TFSERR_NOTCPRS -22 +#define TFSERR_NOTAVAILABLE -23 +#define TFSERR_BADFLAG -24 +#define TFSERR_CLEANOFF -25 +#define TFSERR_FLAKEYSOURCE -26 +#define TFSERR_BADEXTENSION -27 +#define TFSERR_MIN -100 + +/* TFS seek options. */ +#define TFS_BEGIN 1 +#define TFS_CURRENT 2 +#define TFS_END 3 + +/* Macros: */ +#define TFS_DELETED(fp) (!((fp)->flags & TFS_ACTIVE)) +#define TFS_FILEEXISTS(fp) ((fp)->flags & TFS_ACTIVE) +#define TFS_ISCPRS(fp) ((fp)->flags & TFS_CPRS) +#define TFS_ISEXEC(fp) ((fp)->flags & TFS_EXEC) +#define TFS_ISBOOT(fp) ((fp)->flags & TFS_BRUN) +#define TFS_ISLINK(fp) ((fp)->flags & TFS_SYMLINK) +#define TFS_STALE(fp) (!((fp)->flags & TFS_NSTALE)) +#define TFS_FLAGS(fp) ((fp)->flags) +#define TFS_NAME(fp) ((fp)->name) +#define TFS_SIZE(fp) ((fp)->filsize) +#define TFS_TIME(fp) ((fp)->modtime) +#define TFS_INFO(fp) ((fp)->info) +#define TFS_NEXT(fp) ((fp)->next) +#define TFS_CRC(fp) ((fp)->filcrc) +#define TFS_ENTRY(fp) ((fp)->entry) +#define TFS_BASE(fp) ((char *)(fp)+(fp)->hdrsize) + +typedef struct tfshdr TFILE; +#endif diff --git a/apps/common/timer.h b/apps/common/timer.h new file mode 100755 index 0000000..e48ba52 --- /dev/null +++ b/apps/common/timer.h @@ -0,0 +1,46 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +struct elapsed_tmr { + unsigned long start; // Start value of elapsed timeout. + unsigned long tmrval; // Running timer value + // (used by elapsed timeout) + unsigned long currenttmrval; // Current timer value + // (not used by elapsed timeout) + unsigned long tpm; // Ticks per millisecond + + unsigned long elapsed_low; + unsigned long elapsed_high; + + unsigned long timeout_low; + unsigned long timeout_high; + + unsigned long tmrflags; +}; + +/* Timer flags: + */ +#define HWTMR_ENABLED (1 << 0) +#define TIMEOUT_OCCURRED (1 << 1) + +/* Timer macros: + */ +#define HWRTMR_IS_ENABLED(tmr) \ + ((tmr)->tmrflags & HWTMR_ENABLED) + +#define ELAPSED_TIMEOUT(tmr) \ + ((tmr)->tmrflags & TIMEOUT_OCCURRED) + +/* uMon API timer commands: + */ +#define TIMER_START 1 +#define TIMER_ELAPSED 2 +#define TIMER_QUERY 3 + +extern unsigned long target_timer(void); +extern void startElapsedTimer(struct elapsed_tmr *tmr,long timeout); +extern int msecElapsed(struct elapsed_tmr *tmr); +extern unsigned long msecRemaining(struct elapsed_tmr *tmr); +extern int monTimer(int cmd, void *arg); + +#endif diff --git a/apps/demo/README b/apps/demo/README new file mode 100644 index 0000000..69018dd --- /dev/null +++ b/apps/demo/README @@ -0,0 +1,7 @@ +This directory contains source and makefile to build a small +uMon-resident application that creates it's own stack area and +also provides a few umon-ish demonstrations (particularly a +stack trace demo). + +Refer to makefile for details on how to build for various CPU architectures +and target configurations. diff --git a/apps/demo/bashrc b/apps/demo/bashrc new file mode 100644 index 0000000..d6f9ebe --- /dev/null +++ b/apps/demo/bashrc @@ -0,0 +1,8 @@ +export PS1=uMonDemo: +export EDITOR=vi +export TITLE="MicroMonitor Demo Application" +export UMONTOP=../../umon_main +export HOME=`pwd` +unset TERM +. $UMONTOP/host/bin/umon_setup +export TARGET_IP=192.168.1.110 diff --git a/apps/demo/cfg.h b/apps/demo/cfg.h new file mode 100644 index 0000000..de4f34c --- /dev/null +++ b/apps/demo/cfg.h @@ -0,0 +1 @@ +#define APPSTACKSIZE 0x2000 diff --git a/apps/demo/main.c b/apps/demo/main.c new file mode 100644 index 0000000..d74a2d3 --- /dev/null +++ b/apps/demo/main.c @@ -0,0 +1,250 @@ +/* + * This file is a simple example of an application that could be run + * on top of the monitor. + * + * Cstart(): + * The Cstart() function depends on the setting of MONCOMPTR in config.h. + * It demonstrates the use of monConnect and the first mon_XXX function + * typically called by an application, mon_getargv(). + * + * main(): + * The main() function demonstrates argument processing (thanks to + * the call to mon_getargv() in start()), environment variables and + * a simple use of TFS to dump the content of an ASCII file. + * Also, if the first argument is "strace_demo", then the strace_demo() + * function is called. Refer to strace.c for details. + */ + +#include <string.h> +#include <stdlib.h> +#include "monlib.h" +#include "tfs.h" +#include "cfg.h" +#include "timer.h" + +unsigned long AppStack[APPSTACKSIZE/4]; + +extern void strace_demo(void); + +void +hitakey(void) +{ + while(!mon_gotachar()); + mon_getchar(); +} + +/* timer_demo(): + * This function assumes that the underlying monitor has a relatively + * new uMon API hook call mon_timer(). + * This demo shows how to do a few different elapsed timer operations + * using the API. + */ +void +timer_demo(void) +{ + struct elapsed_tmr tmr; + unsigned long starttime, endtime; + + /* Here are a few different ways (using the uMon API) to wait for + * three seconds... + * + * First make sure the underlying monitor has a Hardware-based + * timer. If it doesn't then this is worthless. + */ + mon_timer(TIMER_QUERY,&tmr); + if ((HWRTMR_IS_ENABLED(&tmr)) == 0) { + mon_printf("This monitor doesn't have INCLUDE_HWTMR configured\n"); + return; + } + + mon_printf("Timer demo ready to start, hit a key to continue\n"); + hitakey(); + + /***************************************************************** + * + * The first one, also the simplest, but least versatile is to just + * use mon_delay(). The mon_delay function just takes the number + * of milliseconds you want to wait, and uses the underlying hardware + * to busy wait on that duration... + */ + mon_printf("1. Wait for 3 seconds...\n"); + mon_delay(3000); + mon_printf("1. Done, hit a key to continue\n"); + hitakey(); + + /***************************************************************** + * + * The second one, allows the user to specify the elapsed time + * (in milliseconds), then allows the user to poll waiting for that + * time to expire. Meanwhile, the application can do other things + * while it waits. + */ + mon_printf("2. Wait for 3 seconds...\n"); + tmr.start = 3000; + mon_timer(TIMER_START,&tmr); + while(mon_timer(TIMER_ELAPSED,&tmr) == 0) { + /* Do whatever you like here. */ + } + mon_printf("2. Done, hit a key to continue\n"); + hitakey(); + + /***************************************************************** + * + * The third method, uses the granularity of the hardware clock + * and the returned value of "ticks-per-millisecond". It provides + * the most versatility (without actually knowing the details of + * the hardware clock), but requires the most work. Note that we + * have to deal with the possiblity of 32-bit timer value wrap. + */ + mon_printf("3. Wait for 3 seconds...\n"); + mon_timer(TIMER_QUERY,&tmr); + starttime = tmr.currenttmrval; + endtime = starttime + 3000 * tmr.tpm; + if (endtime < starttime) { + do { + mon_timer(TIMER_QUERY,&tmr); + } while(tmr.currenttmrval > starttime); + do { + mon_timer(TIMER_QUERY,&tmr); + } while(tmr.currenttmrval < endtime); + } + else { + do { + mon_timer(TIMER_QUERY,&tmr); + } while((tmr.currenttmrval > starttime) && + (tmr.currenttmrval < endtime)); + } + + mon_printf("3. Done, hit a key to continue\n"); + while(!mon_gotachar()); + + mon_printf("Timer demo done\n"); + mon_appexit(1); +} + +/* Global variables added just to be able to use this + * app to demonstrate hookup with gdb... + */ +int argtot; +long apprambase; + +int +main(int argc,char *argv[]) +{ + int i, tfd; + char line[80], *ab, *filename; + + argtot = argc; + + /* If argument count is greater than one, then dump out the + * set of CLI arguments... + */ + if (argc > 1) { + if ((argc == 2) && (strcmp(argv[1],"strace_demo") == 0)) + strace_demo(); + + if ((argc == 2) && (strcmp(argv[1],"timer") == 0)) + timer_demo(); + + mon_printf("Argument list...\n"); + for(i=0;i<argc;i++) { + mon_printf(" arg[%d]: %s\n",i,argv[i]); + if (strcmp(argv[i],"match") == 0) + mon_printf("got a match!\n"); + } + } + + /* Using the content of the shell variable APPRAMBASE, dump the + * memory starting at that location... + */ + ab = mon_getenv("APPRAMBASE"); + if (ab) { + char *addr = (char *)strtoul(ab,0,0); + apprambase = strtoul(ab,0,0); + + mon_printf("Dumping memory at 0x%lx...\n",addr); + mon_printmem(addr,128,1); + } + + filename = "monrc"; + + /* If the 'monrc' file exists, the assume it is ASCII and dump it + * line by line... + */ + if (mon_tfsstat(filename)) { + mon_printf("Dumping content of '%s'...\n",filename); + + tfd = mon_tfsopen(filename,TFS_RDONLY,0); + if (tfd >= 0) { + while(mon_tfsgetline(tfd,line,sizeof(line))) + mon_printf("%s",line); + mon_tfsclose(tfd,0); + } + else { + mon_printf("TFS error: %s\n", + (char *)mon_tfsctrl(TFS_ERRMSG,tfd,0)); + } + } + else { + mon_printf("File '%s' not found\n",filename); + } + return(0); +} + +void +__gccmain() +{ +} + +int +Cstart(void) +{ + char **argv; + int argc; + + /* Connect the application to the monitor. This must be done + * prior to the application making any other attempts to use the + * "mon_" functions provided by the monitor. + */ + monConnect((int(*)())(*(unsigned long *)MONCOMPTR),(void *)0,(void *)0); + + /* When the monitor starts up an application, it stores the argument + * list internally. The call to mon_getargv() retrieves the arg list + * for use by this application... + */ + mon_getargv(&argc,&argv); + + /* Call main, then exit to monitor. + */ + main(argc,argv); + + mon_appexit(0); + + /* Won't get here. */ + return(0); +} + +/* CstartAlt(): + * Demonstrates the use of the "call -a" command in uMon. + * For example, if for some reason you wanted to do this... + * Load the application then load the symtbl file using + * "make TARGET_IP=1.2.3.4 sym", then issue these commands: + * + * tfs -v ld app + * call -a %CstartAlt one two three + * + * The "call -a" command in uMon correctly sets up the function + * call parameters so that the following function would see 4 + * arguments (including arg0), with argv[1] thru argv[3] being + * pointers to each of the number strings (i.e. "one", "two", "three") + * and argv[0] being the ascii-coded-hex address of the function + * CstartAlt. + */ +int +CstartAlt(int argc, char *argv[]) +{ + monConnect((int(*)())(*(unsigned long *)MONCOMPTR),(void *)0,(void *)0); + main(argc,argv); + mon_appexit(0); + return(0); +} diff --git a/apps/demo/makefile b/apps/demo/makefile new file mode 100644 index 0000000..549bf86 --- /dev/null +++ b/apps/demo/makefile @@ -0,0 +1,229 @@ +########################################################################## +# +# Basic, target/architecture independent makefile for building an +# application that runs on its own stack. +# +# NOTE: +# This is a template, and may need modification for different sites. +# +# The application code in main.c provides a target-independent example +# of hooking up an application to a target running MicroMonitor. +# Also, there is a self-induced exception branch (see strace_demo.c) +# that can be invoked to force the application to take an exception. +# The purpose of this is to allow the user to then use the monitor's +# 'strace' command to see the function nesting that occurred prior to +# the exception. This requires that the symbol table also be on-board. +# To walk through this example, establish the site-dependent information +# specified below, then execute "make" to build the image, and then +# "make dld sym" to install it (and a symbol table) on the target. +# +# Site dependent information: +# Adjust these values based on your system configuration. +# ARCH: +# Set ARCH to one of the accepted CPU architectures (i.e. MIPS +# PPC, ARM, BLACKFIN, COLDFIRE, MICROBLAZE). +# MONCOMPTR: +# Set MONCOMPTR to the output of 'echo $MONCOMPTR' on your target. +# APPRAMBASE: +# Set APPRAMBASE to the output of 'echo $APPRAMBASE' on your target. +# TARGET_IP: +# Set TARGET_IP to the IP address of your target. +# +ARCH = ARM +MONCOMPTR = 12345 +APPRAMBASE = 12345 +TARGET_IP = + +########################################################################## +# +# There should be no need to change anything below this point if +# building for the csb350, csb472, csb337 or csb360... +# +APPNAME = app +NM = $(TOOL_PREFIX)-nm +AR = $(TOOL_PREFIX)-ar +LD = $(TOOL_PREFIX)-ld +ASM = $(TOOL_PREFIX)-as +CC = $(TOOL_PREFIX)-gcc +COMMON = ../common +STRIP = $(TOOL_PREFIX)-strip +OBJCOPY = $(TOOL_PREFIX)-objcopy +OBJDUMP = $(TOOL_PREFIX)-objdump +LIBGCC = `$(CC) --print-libgcc-file-name` +LIBDIR = $(LIBGCC:/libgcc.a=) +LIBPATH = +COMMON_CFLAGS = -I $(COMMON) -fno-builtin -Wall + +ifeq ($(ARCH),MIPS) +TOOL_PREFIX := mips-elf +CFLAGS := $(COMMON_CFLAGS) -G 0 -march=r4600 -mips3 -mno-abicalls \ + -fno-pic -c -g -O2 -EB -I . +CRT0 := crt0_mips.o +CPU := -D CPU_IS_MIPS=1 +endif + +ifeq ($(ARCH),PPC) +TOOL_PREFIX := ppc-elf +CFLAGS := $(COMMON_CFLAGS) -mno-sdata -msoft-float \ + -c -O -g -I. +CRT0 := crt0_ppc.o +CPU := -D CPU_IS_PPC=1 +LIBGCC = `$(CC) --print-file-name=nof/libgcc.a` +endif + +ifeq ($(ARCH),ARM) +TOOL_PREFIX := arm-elf +CFLAGS := $(COMMON_CFLAGS) -mcpu=arm1136j-s -fno-omit-frame-pointer \ + -c -O -g -I. +CRT0 := crt0_arm.o +CPU := -D CPU_IS_ARM=1 +endif + +ifeq ($(ARCH),BLACKFIN) +TOOL_PREFIX := bfin-elf +CFLAGS := $(COMMON_CFLAGS) -mcsync-anomaly -c -O -g -I. +CRT0 := crt0_bfin.o +CPU := -D CPU_IS_BFIN=1 +endif + +ifeq ($(ARCH),MICROBLAZE) +TOOL_PREFIX := C:/EDK/gnu/microblaze/nt/bin/mb +LIBPATH := -L C:/xilinx/els_stuff/projects/avnet_spartan3_devkit/microblaze_0/lib +CFLAGS := $(COMMON_CFLAGS) -mno-xl-soft-mul -c -O -g -I. +CRT0 := crt0_mb.o +CPU := -D CPU_IS_MICROBLAZE=1 +endif + +ifeq ($(ARCH),COLDFIRE) +TOOL_PREFIX := m68k-elf +CFLAGS := $(COMMON_CFLAGS) -msoft-float -m5200 -g -c -I. +CRT0 := crt0_cf.o +CPU := -D CPU_IS_68K=1 +#LIBGCC = `$(CC) -m5200 --print-libgcc-file-name` +LIBGCC = /usr/lib/gcc-lib/m68k-elf/3.2/m5200/libgcc.a -L /usr/m68k-elf/lib/m5200 +endif + +OBJS=$(CRT0) main.o strace.o monlib.o + +##### +# +# $(APPNAME): +# Top level target builds the application. +# +$(APPNAME): varcheck $(OBJS) makefile + echo tools: $(TOOL_PREFIX) + $(LD) -e start -o $(APPNAME) -Ttext $(APPRAMBASE) $(OBJS) $(LIBPATH) -lc $(LIBGCC) + $(NM) --numeric-sort $(APPNAME) >$(APPNAME).sym + $(OBJDUMP) --source --disassemble $(APPNAME) > $(APPNAME).dis + $(STRIP) $(APPNAME) + +##### +# +# Variable checks: +# Verify that the necessary variables have been set on the make +# command line. +# +varcheck: +ifndef ARCH + @echo Must specify ARCH=XXX on command line. + @exit 1 +endif +ifndef TOOL_PREFIX + @echo Invalid ARCH specification. Use PPC, ARM, MIPS, BLACKFIN or COLDFIRE. + @exit 1 +endif +ifeq ($(TOOL_PREFIX),-) + @echo Invalid ARCH specification. Use PPC, ARM, MIPS, BLACKFIN or COLDFIRE. + @exit 1 +endif +ifndef MONCOMPTR + @echo Must specify MONCOMPTR=XXX on command line. + @exit 1 +endif +ifndef APPRAMBASE + @echo Must specify APPRAMBASE=XXX on command line. + @exit 1 +endif + +targetipcheck: +ifndef TARGET_IP + @echo Must specify TARGET_IP=IPADDRESS on command line. + @exit 1 +endif + + +##### +# +# Objects: +# +crt0_68k.o: $(COMMON)/crt0_68k.S + $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_68k.S + +crt0_arm.o: $(COMMON)/crt0_arm.S + $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_arm.S + +crt0_bfin.o: $(COMMON)/crt0_bfin.S + $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_bfin.S + +crt0_mips.o: $(COMMON)/crt0_mips.S + $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_mips.S + +crt0_mb.o: $(COMMON)/crt0_mb.S + $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_mb.S + +crt0_ppc.o: $(COMMON)/crt0_ppc.S + $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_ppc.S + +crt0_sh2.o: $(COMMON)/crt0_sh2.S + $(CC) $(CFLAGS) -o $@ $(COMMON)/crt0_sh2.S + +main.o: main.c + $(CC) $(CFLAGS) -D MONCOMPTR=$(MONCOMPTR) -o $@ main.c + +monlib.o: $(COMMON)/monlib.c + $(CC) $(CFLAGS) -o $@ $(COMMON)/monlib.c + +strace.o: strace.c + $(CC) $(CFLAGS) $(CPU) -o $@ strace.c + +##### +# +# clean: +# Remove all files created by this make. +# +clean: + rm -f *.o $(APPNAME) $(APPNAME).ezip $(APPNAME).sym $(APPNAME).dis symtbl + +##### +# +# sym: +# Create and download the symbol table file that can be used by uMon +# with this application... +# +sym: targetipcheck + @if ! test -f $(APPNAME).sym; then echo Must build $(APPNAME) first; exit 1; fi + monsym -p0x $(APPNAME).sym >symtbl + ttftp $(TARGET_IP) put symtbl + + + +##### +# +# dld: +# Use the ttftp tool (supplied with MicroMonitor) to download the +# application to the target. +# +dld: targetipcheck + @if ! test -f $(APPNAME); then echo Must build $(APPNAME) first; exit 1; fi + ttftp $(TARGET_IP) put $(APPNAME) $(APPNAME),E + +##### +# +# zdld: +# Compress the elf file using the 'elf' tool (supplied with MicroMonitor) +# The output of this is "$(APPNAME).ezip", then download that compressed file. +# +zdld: targetipcheck + @if ! test -f $(APPNAME); then echo Must build $(APPNAME) first; exit 1; fi + elf -z6 $(APPNAME) + ttftp $(TARGET_IP) put $(APPNAME).ezip $(APPNAME),Ec diff --git a/apps/demo/strace.c b/apps/demo/strace.c new file mode 100644 index 0000000..a2fcb0f --- /dev/null +++ b/apps/demo/strace.c @@ -0,0 +1,100 @@ +/* strace.c: + * This file provides a simple, self-induced exception that can + * be caught by MicroMonitor. After catching the exception, the + * monitor will not attempt any automatic restart because the + * NO_EXCEPTION_RESTART shell variable is set at the top of + * strace_demo() below (typically this environment variable would + * be set during development in the monrc file). + * + * After the exception has completed, at the uMON> prompt type the + * "strace" command. Assuming your monitor is built with INCLUDE_STRACE + * set (refer to config.h for your monitor's port), then the output + * should be something like this... + * + * 1: uMON>app strace_demo + * 2: strace_demo + * 3: func1 + * 4: func2 + * 5: func3 exception now! + * 6: + * 7: EXCEPTION: 'Syscall' + * 8: Occurred near 0xa0051240 (within func3) + * 9: + * 10: uMON>strace + * 11: 0xa0051240: func3() + 0x1c + * 12: 0xa0051284: func2() + 0x28 + * 13: 0xa00512b4: func1() + 0x1c + * 14: 0xa00512f4: strace_demo() + 0x30 + * 15: 0xa00511d0: main() + 0x1b4 + * 16: 0xa005120c: Cstart() + 0x34 + * 17: + * 18: uMON> + * + * Line 1 : shows the invocation of the application 'app'. + * Lines 2-5 : show the output of the strace.c mon_printf calls. + * Lines 7-8 : show uMon catching the exception. + * Line 10 : shows the invocation of the 'strace' command. + * Lines 11-16 : show the output of strace giving the user the exact + * call-stack that caused the exception. + + * Note1: + * The strace facility (INCLUDE_STRACE in config.h) in the + * monitor requires that the symbol table facility (INCLUDE_SYMTBL in + * the config.h file) also be enabled. + * Note2: + * Depending on the version of GCC you're using, you may have to specify + * -fno-omit-frame-pointer on the command line; otherwise the stack trace + * function will not work properly. + */ +#include "monlib.h" + +#if CPU_IS_MIPS +#define EXCEPTION() asm("syscall 99"); /* System call */ +#elif CPU_IS_68K +#define EXCEPTION() asm("trap #3"); /* Trap */ +#elif CPU_IS_SH +#define EXCEPTION() asm("trap #3"); /* Trap */ +#elif CPU_IS_BFIN +#define EXCEPTION() asm("excpt 5"); /* Force exception */ +#elif CPU_IS_MICROBLAZE +#define EXCEPTION() asm("bralid r15,8"); /* User exception */ +#elif CPU_IS_PPC +#define EXCEPTION() asm("sc"); /* System call */ +#elif CPU_IS_ARM +#define EXCEPTION() asm("swi"); /* Software interrupt */ +#else +#error: Must specify CPU type for exception demo. +#endif + +int +func3(int i) +{ + mon_printf("func3 exception now!\n"); + EXCEPTION(); + return(i+5); +} + +int +func2(int i) +{ + mon_printf("func2\n"); + func3(i+3); + return(99); +} + +int +func1(void) +{ + mon_printf("func1\n"); + func2(3); + return(88); +} + +int +strace_demo(void) +{ + mon_printf("strace_demo\n"); + mon_setenv("NO_EXCEPTION_RESTART","TRUE"); + func1(); + return(77); +} diff --git a/main/common/alttfsdevtbl.S b/main/common/alttfsdevtbl.S new file mode 100644 index 0000000..1e198b8 --- /dev/null +++ b/main/common/alttfsdevtbl.S @@ -0,0 +1,67 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * alttfsdevtbl.S: + * + * The use of alt_tfsdevtbl_base within uMon allows the "tfs cfg" + * command to be used by versions of uMon that are relocated to + * RAM. This applies to the "ramtst" build for a given port, + * but more importantly, it applies to those ports that have to + * relocate themselves to RAM just to successfully boot. + * + * The reason this is needed is because this block of empty flash + * is placed at a fixed location in the memory space (usually + * next to moncomptr and etheradd) so that other non-flash-based + * versions can find this location through a tag in the linker + * map file. That tag must be set to point to the physical location + * at which alt_tfsdevtbl_base is placed (similar to etheradd). + * + * So, when building with the following line in config.h... + * + * #define TFS_ALTDEVTBL_BASE &alt_tfsdevtbl_base + * + * the linker map file used by any run-from-ram version of that + * port must contain the tag that initializes this base address + * something like this (where ALTTFSDEVTBLBASE is replaced by + * some fixed address)... + * + * alt_tfsdevtbl_base = ALTTFSDEVTBLBASE; + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + + .global alt_tfsdevtbl_base + + .balign 0x10 + +alt_tfsdevtbl_base: + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +alt_tfsdevtbl_end: diff --git a/main/common/aout.h b/main/common/aout.h new file mode 100644 index 0000000..e90160b --- /dev/null +++ b/main/common/aout.h @@ -0,0 +1,53 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * aout.h: + * + * Header file for the AOUT file format used by TFS. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _AOUT_H_ +#define _AOUT_H_ + +struct exec { + unsigned short a_mid; + unsigned short a_magic; + unsigned long a_text; /* Size of text segment in bytes */ + unsigned long a_data; /* Size of data segment in bytes */ + unsigned long a_bss; /* Size of bss segment in bytes */ + unsigned long a_syms; /* Size of symbol table in bytes */ + unsigned long a_entry; /* Entry point address */ + unsigned long a_trsize; /* Size of text relocation table */ + unsigned long a_drsize; /* Size of data relocation table */ +}; + +struct relocation_info { + int r_address; + ulong r_info; +}; + +/* Fields within r_info: */ +#define SYMNUM_MSK 0xffffff00 +#define PCREL_MSK 0x00000080 +#define LENGTH_MSK 0x00000060 +#define EXTERN_MSK 0x00000010 +#endif diff --git a/main/common/arp.c b/main/common/arp.c new file mode 100644 index 0000000..0c8d762 --- /dev/null +++ b/main/common/arp.c @@ -0,0 +1,650 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * arp.c: + * This code supports some basic arp/rarp stuff. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_ETHERNET +#include "endian.h" +#include "genlib.h" +#include "ether.h" +#include "stddefs.h" +#include "cli.h" +#include "timer.h" + +static void ArpFlush(void); +static void ArpShow(char *); +static void llas(char *); +static int ArpStore(uchar *,uchar *); +static int IpIsOnThisNet(uchar *); + +static unsigned long probeIP; +static char probeAbort; + +/* Constants used by Dynamic IPV4 Local-Link Address setup... + * (see RFC 3927) + */ +#define PROBE_WAIT 1000 /* (msec) */ +#define PROBE_NUM 3 +#define PROBE_MIN 1000 /* (msec) */ +#define PROBE_MAX 2000 /* (msec) */ +#define ANNOUNCE_WAIT 2000 /* (msec) */ +#define ANNOUNCE_NUM 2 +#define ANNOUNCE_INTERVAL 2000 /* (msec) */ +#define MAX_CONFLICTS 10 +#define RATE_LIMIT_INTERVAL 60000 /* (msec) */ +#define DEFEND_INTERVAL 10000 /* (msec) */ + +/* arpcache[]: + * Used to store the most recent set of IP-to-MAC address correlations. + */ +struct arpcache { + uchar ip[4]; + uchar ether[6]; +} ArpCache[SIZEOFARPCACHE]; + +/* ArpIdx & ArpTot: + * Used for keeping track of current arp cache content. + */ +int ArpIdx, ArpTot; + +/* ArpStore(): + * Called with binary ip and ethernet addresses. + * It will store that set away in the cache. + */ +int +ArpStore(uchar *ip,uchar *ether) +{ + if (EtherFromCache(ip)) + return(0); + if (ArpIdx >= SIZEOFARPCACHE) + ArpIdx=0; + memcpy((char *)ArpCache[ArpIdx].ip,(char *)ip,4); + memcpy((char *)ArpCache[ArpIdx].ether,(char *)ether,6); + ArpIdx++; + ArpTot++; + return(0); +} + +/* EtherFromCache(): + * Called with a binary (4-byte) ip address. If a match is found + * in the cache, return a pointer to that ethernet address; else + * return NULL. + */ +uchar * +EtherFromCache(uchar *ip) +{ + int i; + + for(i=0;i<SIZEOFARPCACHE;i++) { + if (!memcmp((char *)ArpCache[i].ip, (char *)ip,4)) + return(ArpCache[i].ether); + } + return(0); +} + +void +ArpFlush(void) +{ + int i; + + for(i=0;i<SIZEOFARPCACHE;i++) { + memset((char *)ArpCache[i].ip,0,4); + memset((char *)ArpCache[i].ether,0,6); + } + ArpIdx = ArpTot = 0; +} + +/* ArpShow(): + * Dump the content of the current arp cache. + */ +void +ArpShow(char *ip) +{ + struct arpcache *ap, *end; + + if (ArpTot < SIZEOFARPCACHE) + end = &ArpCache[ArpTot]; + else + end = &ArpCache[SIZEOFARPCACHE]; + + for (ap=ArpCache;ap<end;ap++) { + if ((!ip) || (!memcmp((char *)ip, (char *)ap->ip,4))) { + printf("%02x:%02x:%02x:%02x:%02x:%02x = ", + ap->ether[0], ap->ether[1], ap->ether[2], ap->ether[3], + ap->ether[4], ap->ether[5]); + printf("%d.%d.%d.%d\n", + ap->ip[0], ap->ip[1], ap->ip[2], ap->ip[3]); + } + } +} + +/* SendArpResp(): + * Called in response to an ARP REQUEST. The incoming ethernet + * header pointer points to the memory area that contains the incoming + * ethernet packet that this function is called in response to. + * In other words, it is used to fill the majority of the response + * packet fields. + */ +int +SendArpResp(struct ether_header *re) +{ + struct ether_header *te; + struct arphdr *ta, *ra; + + te = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&(te->ether_shost), (char *)BinEnetAddr,6); + memcpy((char *)&(te->ether_dhost),(char *)&(re->ether_shost),6); + te->ether_type = ecs(ETHERTYPE_ARP); + + ta = (struct arphdr *) (te + 1); + ra = (struct arphdr *) (re + 1); + ta->hardware = ra->hardware; + ta->protocol = ra->protocol; + ta->hlen = ra->hlen; + ta->plen = ra->plen; + ta->operation = ARP_RESPONSE; + memcpy((char *)ta->senderha, (char *)BinEnetAddr,6); + memcpy((char *)ta->senderia, (char *)ra->targetia,4); + memcpy((char *)ta->targetha, (char *)ra->senderha,6); + memcpy((char *)ta->targetia, (char *)ra->senderia,4); + self_ecs(ta->hardware); + self_ecs(ta->protocol); + self_ecs(ta->operation); + sendBuffer(ARPSIZE); + return(0); +} + +/* SendArpRequest(): + * If 'probe' is non-zero, then the request is an arp-probe. + * Refer to RFC3927 for more on that. + */ +static int +SendArpRequest(uchar *ip, int probe) +{ + struct ether_header *te; + struct arphdr *ta; + + /* Populate the ethernet header: */ + te = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&(te->ether_shost), (char *)BinEnetAddr,6); + memcpy((char *)&(te->ether_dhost), (char *)BroadcastAddr,6); + te->ether_type = ecs(ETHERTYPE_ARP); + + /* Populate the arp header: */ + ta = (struct arphdr *) (te + 1); + ta->hardware = ecs(1); /* 1 for ethernet */ + ta->protocol = ecs(ETHERTYPE_IP); + ta->hlen = 6; /* Length of hdware (ethernet) address */ + ta->plen = 4; /* Length of protocol (ip) address */ + ta->operation = ecs(ARP_REQUEST); + memcpy((char *)ta->senderha, (char *)BinEnetAddr,6); + if (probe) { + memset((char *)ta->senderia,0,4); + memset((char *)ta->targetha,0,6); + } + else { + memcpy((char *)ta->senderia, (char *)BinIpAddr,4); + memcpy((char *)ta->targetha, (char *)BroadcastAddr,6); + } + memcpy((char *)ta->targetia, (char *)ip,4); + sendBuffer(ARPSIZE); + return(0); +} + +/* GetBinNetMask(): + * Return a subnet mask in binary form. + * Since this function needs a netmask, if NETMASK is not set, then + * it uses the default based on the upper 3 bits of the IP address + * (refer to TCP/IP Illustrated Volume 1 Pg8 for details). + */ +void +GetBinNetMask(uchar *binnetmask) +{ + char *nm; + + nm = getenv("NETMASK"); + if (!nm) { + memset((char *)binnetmask,0xff,4); + if ((BinIpAddr[0] & 0xe0) == 0xc0) { /* Class C */ + binnetmask[3] = 0; + } + else if ((BinIpAddr[0] & 0xc0) == 0x80) { /* Class B */ + binnetmask[3] = 0; + binnetmask[2] = 0; + } + else if ((BinIpAddr[0] & 0x80) == 0x00) { /* Class A */ + binnetmask[3] = 0; + binnetmask[2] = 0; + binnetmask[1] = 0; + } + } + else + IpToBin(nm,binnetmask); +} + +/* IpIsOnThisNet(): + * Return 1 if the incoming ip is on this subnet; else 0. + * For each bit in the netmask that is set to 1... + * If the corresponding bits in the incoming IP and this board's IP + * do not match, return 0; else return 1. + */ +int +IpIsOnThisNet(uchar *ip) +{ + int i; + uchar binnetmask[8]; + + GetBinNetMask(binnetmask); + + for(i=0;i<4;i++) { + if ((ip[i] & binnetmask[i]) != (BinIpAddr[i] & binnetmask[i])) { + return(0); + } + } + return(1); +} + +/* Arp(): + * If no args, just dump the arp cache. + * If arg is present, then assume it to be an ip address. + * Check the arp cache for the presence of that ip<->correlation, if + * present, print it; else issue and arp request for that IP and wait + * for a response. + */ + +char *ArpHelp[] = { + "Address resolution protocol", + "-[flps:v] [IP]", +#if INCLUDE_VERBOSEHELP + " -f flush cache", + " -l dynamic config using link-local arp probe", + " -p proxy arp", + " -s{eadr} store eadr/IP into cache", +#if INCLUDE_ETHERVERBOSE + " -v verbose", +#endif +#endif + 0, +}; + +int +Arp(int argc,char *argv[]) +{ + int opt, proxyarp, llad; + char binip[8], binether[8], *storeether; + + llad = proxyarp = 0; + storeether = (char *)0; + while ((opt=getopt(argc,argv,"flps:v")) != -1) { + switch(opt) { + case 'f': /* Flush current arp cache */ + ArpFlush(); + break; + case 'l': /* Dynamic ip-config using link-local addressing */ + llad = 1; /* (refer to RFC 3927) */ + break; + case 's': /* Store specified IP/MAC combination in arp cache. */ + storeether = optarg; + break; + case 'p': /* Assume gateway will run proxy arp */ + proxyarp = 1; + break; +#if INCLUDE_ETHERVERBOSE + case 'v': /* Enable verbosity for ARP. */ + EtherVerbose |= SHOW_ARP; + break; +#endif + default: + return(CMD_PARAM_ERROR); + } + } + + /* If llad flag is set, then we do a dynamic configuration using the + * link-local protocol as described in RFC 3927... + */ + if (llad) { + char buf[32]; + struct elapsed_tmr tmr; + int i, retry, conflicts, psval; + +#if INCLUDE_DHCPBOOT + dhcpDisable(); +#endif + probeAbort = retry = conflicts = 0; + + /* Use MAC address to establish a uniformly selected pseudo random + * value between 0 and 1000... + */ + psval = (BinEnetAddr[5] * 4); + + monDelay(psval); + + if (argc == (optind+1)) + IpToBin((char *)argv[optind],(unsigned char *)&probeIP); + else + llas((char *)&probeIP); + +nextllas: + SendArpRequest((uchar *)&probeIP,1); + startElapsedTimer(&tmr,ANNOUNCE_WAIT); + while(!msecElapsed(&tmr)) { + if (probeAbort) { + llas((char *)&probeIP); + probeAbort = retry = 0; + monDelay(psval + PROBE_MIN); + goto nextllas; + } + if (EtherFromCache((uchar *)&probeIP)) { + if (++conflicts > MAX_CONFLICTS) + monDelay(RATE_LIMIT_INTERVAL); + else + monDelay(psval + PROBE_MIN); + if (++retry == PROBE_NUM) { + llas((char *)&probeIP); + retry = 0; + } + goto nextllas; + } + pollethernet(); + } + /* If we're here, then we found an IP address that is not being + * used on the local subnet... + */ + setenv("IPADD",IpToString(probeIP,buf)); + setenv("NETMASK","255.255.0.0"); + setenv("GIPADD",0); +#if INCLUDE_ETHERVERBOSE + EthernetStartup(EtherVerbose,0); +#else + EthernetStartup(0,0); +#endif + for(i=0;i<ANNOUNCE_NUM;i++) { + SendArpRequest(BinIpAddr,0); + monDelay(ANNOUNCE_INTERVAL); + } + } + else if (argc == (optind+1)) { + IpToBin((char *)argv[optind],(unsigned char *)binip); + if (storeether) { + EtherToBin((char *)storeether, (unsigned char *)binether); + ArpStore((unsigned char *)binip,(unsigned char *)binether); + } + else { + if (ArpEther((unsigned char *)binip,(unsigned char *)0,proxyarp)) + ArpShow(binip); + } + } + else + ArpShow(0); +#if INCLUDE_ETHERVERBOSE + EtherVerbose &= ~ SHOW_ARP; +#endif + return(CMD_SUCCESS); +} + +/* ArpEther(): + * Retrieve the ethernet address that corresponds to the incoming IP + * address. First check the local ArpCache[], then if not found issue + * an ARP request... If the incoming IP is on this net, then issue the + * request for the MAC address of that IP; otherwise, issue the request + * for this net's GATEWAY. + */ +uchar * +ArpEther(uchar *binip, uchar *ecpy, int proxyarp) +{ + char *gip; + struct elapsed_tmr tmr; + uchar gbinip[8], *Ip, *ep; + int timeoutsecs, retry; + + if (!EtherIsActive) { + printf("Ethernet disabled\n"); + return(0); + } + + /* First check local cache. If found, return with pointer to MAC. */ + ep = EtherFromCache(binip); + if (ep) { + if (ecpy) { + memcpy((char *)ecpy, (char *)ep,6); + ep = ecpy; + } + return(ep); + } + + retry = 0; + RetransmitDelay(DELAY_INIT_ARP); + while(1) { + /* If IP is not on this net, then get the GATEWAY IP address. */ + if (!proxyarp && !IpIsOnThisNet(binip)) { + gip = getenv("GIPADD"); + if (gip) { + IpToBin(gip,gbinip); + if (!IpIsOnThisNet(gbinip)) { + printf("GIPADD/IPADD subnet confusion.\n"); + return(0); + } + ep = EtherFromCache(gbinip); + if (ep) { + if (ecpy) { + memcpy((char *)ecpy, (char *)ep,6); + ep = ecpy; + } + return(ep); + } + SendArpRequest(gbinip,0); + Ip = gbinip; + } + else { + SendArpRequest(binip,0); + Ip = binip; + } + } + else { + SendArpRequest(binip,0); + Ip = binip; + } + if (retry) { + printf(" ARP Retry #%d (%d.%d.%d.%d)\n",retry, + binip[0],binip[1],binip[2],binip[3]); + } + + /* Now that the request has been issued, wait for a while to see if + * the ARP cache is loaded with the result of the request. + */ + timeoutsecs = RetransmitDelay(DELAY_OR_TIMEOUT_RETURN); + if (timeoutsecs == RETRANSMISSION_TIMEOUT) + break; + startElapsedTimer(&tmr,timeoutsecs*1000); + while(!msecElapsed(&tmr)) { + ep = EtherFromCache(Ip); + if (ep) + break; + + pollethernet(); + } + if (ep) { + if (ecpy) { + memcpy((char *)ecpy, (char *)ep,6); + ep = ecpy; + } + return(ep); + } + RetransmitDelay(DELAY_INCREMENT); + retry++; + } +#if INCLUDE_ETHERVERBOSE + if ((EtherVerbose & SHOW_ARP) && (retry)) + printf(" ARP giving up\n"); +#endif + return(0); +} + +/* processRARP(); + * Called by the fundamental ethernet driver code to process a RARP + * request. + */ +int +processRARP(struct ether_header *ehdr,ushort size) +{ + struct arphdr *arpp; + + arpp = (struct arphdr *)(ehdr+1); + self_ecs(arpp->hardware); + self_ecs(arpp->protocol); + self_ecs(arpp->operation); + + switch(arpp->operation) { + case RARP_RESPONSE: + if (!memcmp((char *)arpp->targetha, (char *)BinEnetAddr,6)) { +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_ARP) { + printf(" RARP Response from %d.%d.%d.%d\n", + arpp->senderia[0],arpp->senderia[1], + arpp->senderia[2],arpp->senderia[3]); + printf(" MY IP: from %d.%d.%d.%d\n", + arpp->targetia[0],arpp->targetia[1], + arpp->targetia[2],arpp->targetia[3]); + } +#endif + memcpy((char *)BinIpAddr, (char *)arpp->targetia,6); + } + break; + case RARP_REQUEST: + break; + default: + printf(" Invalid RARP operation: 0x%x\n",arpp->operation); + return(-1); + } + return(0); +} + +/* processARP(); + * Called by the fundamental ethernet driver code to process a ARP + * request. + */ +char * +processARP(struct ether_header *ehdr,ushort size) +{ + struct arphdr *arpp; + + arpp = (struct arphdr *)(ehdr+1); + self_ecs(arpp->hardware); + self_ecs(arpp->protocol); + self_ecs(arpp->operation); + + /* If the sender IP address is all zeroes, then assume this is + * an arp probe. If we are currently doing a probe, and the + * address we are probing matches the target IP address of this + * probe, then set a flag that will abort the current probe. + */ + if ((arpp->senderia[0] == 0) && (arpp->senderia[1] == 0) && + (arpp->senderia[2] == 0) && (arpp->senderia[3] == 0)) { + if (memcmp((char *)arpp->targetia,(char *)&probeIP,4) == 0) + probeAbort = 1; + } + + switch(arpp->operation) { + case ARP_REQUEST: + if (!memcmp((char *)arpp->targetia, (char *)BinIpAddr,4)) { + ArpStore(arpp->senderia,arpp->senderha); + SendArpResp(ehdr); + } + break; + case ARP_RESPONSE: + if (!memcmp((char *)arpp->targetia, (char *)BinIpAddr,4)) { + if (!memcmp((char *)arpp->targetia,(char *)arpp->senderia,4)) + printf("WARNING: IP %s may be in use on network\n",IPadd); + + ArpStore(arpp->senderia,arpp->senderha); + } + break; + default: + printf(" Invalid ARP operation: 0x%x\n",arpp->operation); + printPkt(ehdr,(int)size,ETHER_INCOMING); + return((char *)0); + } + return((char *)(arpp + 1)); +} + +/* sendGratuitousARP(): + * As defined in RFC 3220... + * + * An ARP packet sent by a node in order to spontaneously + * cause other nodes to update an entry in their ARP cache. + * + * Issue a "gratuitous ARP" (RFC 3220) for two reasons... + * - make sure no other host is already using this IP address. + * - cause other devices on cable to update their arp cache. + */ +void +sendGratuitousArp(void) +{ + SendArpRequest(BinIpAddr,0); +} + +/* llas(): + * Link local address selection. + * Referring to sec 2.1 of RFC3927, select an address using a pseudo-random + * number generator to assign a number in the range from + * 169.254.1.0 (0xa9fe0100) thru 169.254.254.255 (0xa9fefeff). + * To do this, we run a 32-bit CRC on the 6-byte MAC address, then add the + * least significant 8 bits of that value to the base of the address + * range. Each successive time this function is called, then increment + * by the least significant 4 bits of the LSB of the MAC. + */ +#define LLAD_BEGIN 0xa9fe0100 +#define LLAD_END 0xa9fefeff + +static void +llas(char *ipptr) +{ + static char beenhere; + static unsigned long llad; + unsigned long pseudorandval, tmp; + + if (beenhere == 0) { + pseudorandval = crc32(BinEnetAddr,6); + llad = LLAD_BEGIN + (pseudorandval & 0xff); + } + else { + pseudorandval = (unsigned long)(BinEnetAddr[5] & 0xf); + llad += pseudorandval; + if (llad >= LLAD_END) + llad = LLAD_BEGIN + pseudorandval + beenhere; + } + beenhere++; + + printf("LLAD: %d.%d.%d.%d\n", + (llad & 0xff000000) >> 24, (llad & 0xff0000) >> 16, + (llad & 0xff00) >> 8, (llad & 0xff)); + + tmp = ecl(llad); + + if (ipptr) + memcpy(ipptr,(char *)&tmp,4); +} + +#endif diff --git a/main/common/bits.h b/main/common/bits.h new file mode 100644 index 0000000..3caffa3 --- /dev/null +++ b/main/common/bits.h @@ -0,0 +1,67 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * bits.h + * + * This file contains the Bit position defines for ease of use + * + * Contributed by: Michael Kelly, Cogent Computers Systems, Inc. + * + */ + +#ifndef _BITS_H_ +#define _BITS_H_ +/* + * Bit position defines + */ +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +#endif diff --git a/main/common/bmem.h b/main/common/bmem.h new file mode 100644 index 0000000..ec891fa --- /dev/null +++ b/main/common/bmem.h @@ -0,0 +1,38 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * bmem.h + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +struct bmem { + int id; + char *name; + int pgsize; + int spsize; + int ppb; + int btot; + int (*bmemerase)(int bkno, int verbose); + int (*bmemread)(char *dest, int bkno, int pgno, int size, int verbose); + int (*bmemwrite)(char *src, int bkno, int pgno, int size, int verbose); +}; + +extern struct bmem bmemtbl[]; diff --git a/main/common/boardinfo.c b/main/common/boardinfo.c new file mode 100644 index 0000000..f1ea412 --- /dev/null +++ b/main/common/boardinfo.c @@ -0,0 +1,320 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * boardinfo.c: + * + * When the boot monitor is updated (using newmon), only the sectors that + * are used by the monitor are re-written. If a sector in the flash is + * not being used by TFS, and is not being used by the monitor, then the + * strategy of the code in this file may be useful... + * + * The monrc file is used by the monitor to store various initialization + * parameters. At a minimum (on systems with ethernet), this will include + * an IP address, MAC address, Gateway IP address and Network Mask. It + * may also include some board/target-specific information. This is convenient + * because it is a file that can be updated on a per-board basis; however, + * the convenience can also be a pain in the butt. The user can easily + * modify the monrc file and change the IP address and MAC address (things + * that are usually not changed very often, especially the MAC address). + * To make some of this stuff a bit less convenient to change, these + * values (strings) can be put into some other portion of flash that is + * not used by the monitor or TFS. Hence, even if TFS is initialized or + * the monitor is updated, this information will remain in place. + * + * This file, in conjunction with a target-specific table called + * boardinfotbl[] supports the ability to store this data in a sector + * that is not being used by TFS or the monitor binary. When the target + * first comes up, it will check to see if this space is erased. If yes, + * then it will query the user for values to be loaded and they will then + * be stored away in a sector of flash that is not used by TFS or uMon. + * They will become shell variables at startup, and will not be changeable + * unless that sector is manually erased. + * + * Note that an inefficiency of this is that it assumes it has a sector + * dedicated to it. This "inefficiency" however; is what makes it less + * likely to be mistakenly erased. + * + * Following is an example boardinfotbl[]... + * + extern unsigned char etheraddr[], boardtag[]; + + struct boardinfo boardinfotbl[] = { + { etheraddr, 32, "ETHERADD", (char *)0, "MAC addr" }, + { boardtag, 32, "BOARDTAG", (char *)0, "Board tag" }, + { 0,0,0,0 } + }; + + * + * The externs "etheraddr" and "boardtag" are actually pointers into some + * portion of the flash sector that is to be used for this storage. These + * values can be placed in the linker map file or be hard-coded addresses + * in this file. + * + * Then, in config.h, the following two definitions must be established... + * + + #define BOARDINFO_SECTOR 7 + #define BOARDINFO_BUFMAX 32 + + * + * The value assigned to BOARDINFO_SECTOR is the sector number that is + * used for the storage and BOARDINFO_BUFMAX is the size of buf[] within + * the BoardInfoInit function below. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "genlib.h" +#include "boardinfo.h" +#include "cli.h" + +#if INCLUDE_FLASH & INCLUDE_BOARDINFO + +#ifdef BOARDINFO_DEBUG +#define BINFOPRINT(a) printf a +#else +#define BINFOPRINT(a) +#endif + +/* boardinfo_error: + * Set if there was any kind of read error from the board info structure. + */ +int boardinfo_error; + +void +BoardInfoInit(void) +{ + short len; + ushort crc; + struct boardinfo *bip; + int maxpromptsize, erased; + struct boardinfoverify *bipv; + uchar buf[BOARDINFO_BUFMAX]; + char c, snum[8], prfmt[16], *prefill; + + sprintf(snum,"%d",BOARDINFO_SECTOR); + + /* Step through each bip entry and see if the data area is either + * empty or the crc16 passed. If either is true, then allow + * If every entry in the board-information area is either empty + * or the crc test passes, we can just return... + */ + erased = 0; + maxpromptsize = 0; + boardinfo_error = 0; + bip = boardinfotbl; + while((bip->array) && (!boardinfo_error)) { + BINFOPRINT(("Boardinfo item: %s (%s)",bip->varname,bip->prompt)); + if (bip->array[0] != 0xff) { + BINFOPRINT((" not")); + bipv = (struct boardinfoverify *)&bip->array[bip->size-BIVSIZE]; + + /* If len and crc are set, then use those fields to sanity + * check the data... + */ + if ((bipv->len != 0xffff) && (bipv->crc16 != 0xffff)) { + if ((bipv->len > bip->size) || + (xcrc16(bip->array,bipv->len) != bipv->crc16)) { + boardinfo_error = 1; + } + } + } + else + erased++; + BINFOPRINT((" erased\n")); + + /* Gather data to determine the largest prompt... */ + len = strlen(bip->prompt); + if (len > maxpromptsize) + maxpromptsize = len; + bip++; + } + + /* If there was no error, and the board info area is not erased, + * we return here assuming the data is valid. + */ + if ((boardinfo_error == 0) && (erased == 0)) { + sectorProtect(snum,1); + return; + } + + /* If there was some kind of error reading any of the fields in the + * board-info area, then either return or clear the error and interact + * with the user to re-load the data... + */ + if (boardinfo_error != 0) { +#ifdef BOARDINFO_REENTER_ON_ERROR + printf("\nError reading board-info data, re-enter data..."); + boardinfo_error = 0; +#else + printf("\nError reading board-info data in sector %d.\n", + BOARDINFO_SECTOR); + return; +#endif + } + + sprintf(prfmt,"%%%ds : ",maxpromptsize); + + printf("%s: board information field initialization...\n",PLATFORM_NAME); + + /* Un-protect the sector used for board information... + */ + sectorProtect(snum,0); + + do { + /* Erase the sector used for board information... + */ + if (AppFlashErase(BOARDINFO_SECTOR) < 0) { + boardinfo_error = 1; + break; + } + + /* Step through each entry in the boardinfo table and query + * the user for input to be stored... + */ + bip = boardinfotbl; + while(bip->array) { + bipv = (struct boardinfoverify *)&bip->array[bip->size-BIVSIZE]; + + if (bip->def) + prefill = bip->def; + else + prefill = 0; + + printf(prfmt,bip->prompt); + len = 0; + if (getline_p((char *)buf,bip->size-BIVSIZE,0,prefill) != 0) { + len = strlen(buf)+1; + if (AppFlashWrite(bip->array,buf,len) < 0) { + boardinfo_error = 1; + break; + } + crc = xcrc16(buf,len); + } + if (len) { + if (AppFlashWrite((uchar *)(&bipv->len), + (uchar *)&len,sizeof(len)) < 0) { + boardinfo_error = 1; + break; + } + if (AppFlashWrite((uchar *)(&bipv->crc16), + (uchar *)&crc,sizeof(crc)) < 0) { + boardinfo_error = 1; + break; + } + } + bip++; + } + if (boardinfo_error) + break; + + bip = boardinfotbl; + printf("\nNew system settings:\n\n"); + while(bip->array) { +#ifdef BOARDINFO_SHOW_RAW + printMem(bip->array,bip->size,1); +#else + printf("%24s: %s\n",bip->prompt, + bip->array[0] == 0xff ? "" : (char *)bip->array); +#endif + bip++; + } + putstr("\nHit ENTER to accept, any other key to re-enter..."); + c = getchar(); + putchar('\n'); + + } while((c != '\r') && (c != '\n')); + + sectorProtect(snum,1); +} + +void +BoardInfoEnvInit(void) +{ + struct boardinfo *bip; + + /* If an error was detected by BoardInfoInit() then we don't + * want to do any environmental initialization here... + */ + if (boardinfo_error != 0) { + printf("Board info environment not initialized\n"); + return; + } + + bip = boardinfotbl; + while(bip->array) { + if ((bip->varname) && (bip->array[0] != 0xff)) + setenv(bip->varname,bip->array); + bip++; + } +} + +/* BoardInfoVar(): + * Return 1 if the incoming variable name is a variable + * that is established by the BoardInfo facility; else zero. + */ +int +BoardInfoVar(char *varname) +{ + struct boardinfo *bip; + + bip = boardinfotbl; + while(bip->array) { + if (strcmp(varname,bip->varname) == 0) + return(1); + bip++; + } + return(0); +} + +char *BinfoHelp[] = { + "Dump board-specific information", + "", +#if INCLUDE_VERBOSEHELP +#endif + 0, +}; + +int +BinfoCmd(int argc, char *argv[]) +{ + int i; + char *array; + struct boardinfo *bip; + + i = 1; + bip = boardinfotbl; + printf("Boardinfo sector: %d\n",BOARDINFO_SECTOR); + printf(" # ADDRESS VALUE VARNAME DESCRIPTION\n"); + while(bip->array) { + if (bip->array[0] == 0xff) + array = "-empty-"; + else + array = bip->array; + printf(" %2d: 0x%08lx %-18s %-15s %s\n",i, + (long)bip->array,array,bip->varname,bip->prompt); + bip++; + i++; + } + return(CMD_SUCCESS); +} +#endif diff --git a/main/common/boardinfo.h b/main/common/boardinfo.h new file mode 100644 index 0000000..8a690b3 --- /dev/null +++ b/main/common/boardinfo.h @@ -0,0 +1,56 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * boardinfo.h: + * + * Structures and data used by boardinfo facility. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _BOARDINFO_H_ +#define _BOARDINFO_H_ + +struct boardinfo { + unsigned char *array; + short size; + char *varname; + char *def; + char *prompt; +}; + +struct boardinfoverify { + unsigned short len; + unsigned short crc16; +}; + +#define BISIZE sizeof(struct boardinfo) +#define BIVSIZE sizeof(struct boardinfoverify) + +/* boardinfotbl[]: + * If the "boardinfo" facility in the monitor is to be used, then + * this table must be included in the target-specific portion of + * the monitor build. + */ +extern struct boardinfo boardinfotbl[]; + +extern void BoardInfoInit(void), BoardInfoEnvInit(void); +extern int BoardInfoVar(char *); +#endif diff --git a/main/common/cache.c b/main/common/cache.c new file mode 100644 index 0000000..5f230bf --- /dev/null +++ b/main/common/cache.c @@ -0,0 +1,119 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * cache.c: + * This code is the front-end to CPU-specific code that may or may not + * support basic I & D cache operations. Various facilities in the + * monitor call the wrapper functions below for carrying out cpu-specific + * cache operations. This code provides that wrapper allowing the other + * portions of the monitor to be unaware of what the specific CPU actually + * supports. + * + * The cacheInit() function must be called at monitor startup, then + * cacheInit() calls cacheInitForTarget(), a function that must be provided + * by the target-specific code to fill in the CPU-specific functionality. + * This function should establish the cache as it is to be used in + * the monitor (typically i-cache enabled, d-cache disabled), plus, if + * applicable, the dcacheFlush and icacheInvalidate function pointers should + * be initialized to CPU-specific functions that match the API... + * + * int (*dcacheDisable)(void); + * int (*icacheDisable)(void); + * int (*dcacheFlush)(char *base,int size); + * int (*icacheInvalidate)(char *base, int size); + * + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "genlib.h" +#include "cache.h" + +int (*dcacheFlush)(char *,int), (*icacheInvalidate)(char *, int); +int (*dcacheDisable)(void), (*icacheDisable)(void); + +/* flushDcache(): + * Flush the address range specified, or if address and size are both + * zero, flush the entire D-Cache. + */ +int +flushDcache(char *addr, int size) +{ + /* The dcacheFlush function pointer should be initialized in the + * port-specific function "cacheInitForTarget". + */ + if (dcacheFlush) + return(dcacheFlush(addr,size)); + return(0); +} + +/* disableDcache(): + * Disable data cache. + */ +int +disableDcache(void) +{ + /* The dcacheDisable function pointer should be initialized in the + * port-specific function "cacheInitForTarget". + */ + if (dcacheDisable) + return(dcacheDisable()); + return(0); +} + +/* invalidateIcache(): + * Invalidate the address range specified, or if address and size are both + * zero, invalidate the entire I-Cache. + */ +int +invalidateIcache(char *addr, int size) +{ + /* The icacheInvalidate function pointer should be initialized in the + * port-specific function "cacheInitForTarget". + */ + if (icacheInvalidate) + return(icacheInvalidate(addr,size)); + return(0); +} + +/* disableIcache(): + * Disable instruction cache. + */ +int +disableIcache(void) +{ + /* The icacheDisable function pointer should be initialized in the + * port-specific function "cacheInitForTarget". + */ + if (icacheDisable) + return(icacheDisable()); + return(0); +} + +int +cacheInit() +{ + dcacheDisable = (int(*)(void))0; + icacheDisable = (int(*)(void))0; + dcacheFlush = (int(*)(char *,int))0; + icacheInvalidate = (int(*)(char *,int))0; + cacheInitForTarget(); /* Target-specific initialization. */ + return(0); +} diff --git a/main/common/cache.h b/main/common/cache.h new file mode 100644 index 0000000..a7733ee --- /dev/null +++ b/main/common/cache.h @@ -0,0 +1,66 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * cache.h: + * + * Refer to cache.c for comments. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _CACHE_H_ +#define _CACHE_H_ + +/* dcacheFlush, icacheInvalidate, dcacheDisable & icacheDisable: + * Function pointers that should be initialized by target-specific code + * to point to target-specific functions that can be accessed by the + * generic monitor source. + */ +extern int (*dcacheFlush)(char *,int), (*icacheInvalidate)(char *,int); +extern int (*dcacheDisable)(void), (*icacheDisable)(void); + +/* flushDcache(): + * Wrapper function for the target-specific d-cache flushing operation + * (if one is appropriate). If addr and size are both zero, then flush + * the entire D-cache. + */ +extern int flushDcache(char *addr, int size); + +/* invalidateIcache(): + * Wrapper function for the target-specific i-cache invalidation operation + * (if one is appropriate). If addr and size are both zero, then invalidate + * the entire I-cache. + */ +extern int invalidateIcache(char *addr, int size); + +/* disableDcache() & disableIcache(): + * Wrapper functions to call target-specific cache disable functions + * (if available). + */ +extern int disableDcache(void); +extern int disableIcache(void); + +/* cacheInit(): + * Called at startup. This function calls cacheInitForTarget() which + * establishes the cache configuration and initializes the above + * function pointers (if applicable). + */ +extern int cacheInit(void); +#endif diff --git a/main/common/cast.c b/main/common/cast.c new file mode 100644 index 0000000..0bab527 --- /dev/null +++ b/main/common/cast.c @@ -0,0 +1,412 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * cast.c: + * + * The cast command is used in the monitor to cast or overlay a structure + * onto a block of memory to display that memory in the format specified + * by the structure. The structure definition is found in the file + * "structfile" in TFS. Valid types within structfile are + * char, char.c, char.x, short, short.x, long, long.x and struct name. + * Default format is decimal. The '.x' extension tells cast to print + * in hex and the '.c' extension tells cast to print the actual character. + * + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "tfs.h" +#include "tfsprivate.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" +#include "cli.h" + +#if INCLUDE_CAST + +static ulong memAddr; +static int castDepth; + +#define OPEN_BRACE '{' +#define CLOSE_BRACE '}' + +#define STRUCT_SEARCH 1 +#define STRUCT_DISPLAY 2 +#define STRUCT_ALLDONE 3 +#define STRUCT_ERROR 4 + +#define STRUCT_SHOWPAD (1<<0) +#define STRUCT_SHOWADD (1<<1) +#define STRUCT_VERBOSE (1<<2) + + +#define STRUCTFILE "structfile" + +struct mbrinfo { + char *type; + char *format; + int size; + int mode; +}; + +struct mbrinfo mbrinfotbl[] = { + { "char", "%d", 1 }, /* decimal */ + { "char.x", "0x%02x", 1 }, /* hex */ + { "char.c", "%c", 1 }, /* character */ + { "short", "%d", 2 }, /* decimal */ + { "short.x", "0x%04x", 2 }, /* hex */ + { "long", "%ld", 4 }, /* decimal */ + { "long.x", "0x%08lx", 4 }, /* hex */ + { 0,0,0 } +}; + +/* castIndent(): + * Used to insert initial whitespace based on the depth of the + * structure nesting. + */ +void +castIndent(void) +{ + int i; + + for(i=0;i<castDepth;i++) + printf(" "); +} + +/* strAddr(): + * Called by showStruct(). It will populate the incoming buffer pointer + * with either NULL or the ascii-hex representation of the current address + * pointer. + */ +char * +strAddr(long flags, char *buf) +{ + if (flags & STRUCT_SHOWADD) + sprintf(buf,"0x%08lx: ",memAddr); + else + buf[0] = 0; + return(buf); +} + +/* showStruct(): + * The workhorse of cast. This function parses the structfile looking for + * the structure type; then it attempts to display the memory block that + * begins at memAddr as if it was the structure. Note that there is no + * pre-processing done to verify valid syntax of the structure definition. + */ +int +showStruct(int tfd,long flags,char *structtype,char *structname,char *linkname) +{ + struct mbrinfo *mptr; + ulong curpos, nextlink; + int i, state, snl, retval, tblsize; + char line[96], addrstr[16], format[64]; + char *cp, *eol, *type, *eotype, *name, *bracket, *eoname, tmp; + + type = (char *)0; + retval = nextlink = 0; + curpos = tfsctrl(TFS_TELL,tfd,0); + tfsseek(tfd,0,TFS_BEGIN); + castIndent(); + if (structname) + printf("struct %s %s:\n",structtype,structname); + else + printf("struct %s @0x%lx:\n",structtype,memAddr); + castDepth++; + + state = STRUCT_SEARCH; + snl = strlen(structtype); + + while(1) { + if (tfsgetline(tfd,line,sizeof(line)-1) == 0) { + printf("Structure definition '%s' not found\n",structtype); + break; + } + if ((line[0] == '\r') || (line[0] == '\n')) /* empty line? */ + continue; + + eol = strpbrk(line,";#\r\n"); + if (eol) + *eol = 0; + + if (state == STRUCT_SEARCH) { + if (!strncmp(line,"struct",6)) { + cp = line+6; + while(isspace(*cp)) + cp++; + if (!strncmp(cp,structtype,snl)) { + cp += snl; + while(isspace(*cp)) + cp++; + if (*cp == OPEN_BRACE) + state = STRUCT_DISPLAY; + else { + retval = -1; + break; + } + } + } + } + else if (state == STRUCT_DISPLAY) { + type = line; + while(isspace(*type)) + type++; + + if (*type == CLOSE_BRACE) { + state = STRUCT_ALLDONE; + break; + } + + eotype = type; + while(!isspace(*eotype)) + eotype++; + *eotype = 0; + name = eotype+1; + while(isspace(*name)) + name++; + bracket = strchr(name,'['); + if (bracket) + tblsize = atoi(bracket+1); + else + tblsize = 1; + + if (*name == '*') { + castIndent(); + printf("%s%-8s %s: ",strAddr(flags,addrstr),type,name); + if (!strcmp(type,"char.c")) + printf("\"%s\"\n",*(char **)memAddr); + else + printf("0x%lx\n",*(ulong *)memAddr); + memAddr += 4; + continue; + } + mptr = mbrinfotbl; + while(mptr->type) { + if (!strcmp(type,mptr->type)) { + castIndent(); + eoname = name; + while(!isspace(*eoname)) + eoname++; + tmp = *eoname; + *eoname = 0; + + if (bracket) { + if (!strcmp(type,"char.c")) { + printf("%s%-8s %s: ", + strAddr(flags,addrstr),mptr->type,name); + cp = (char *)memAddr; + for(i=0;i<tblsize && isprint(*cp);i++) + printf("%c",*cp++); + printf("\n"); + } + else + printf("%s%-8s %s\n", + strAddr(flags,addrstr),mptr->type,name); + memAddr += mptr->size * tblsize; + } + else { + sprintf(format,"%s%-8s %%s: %s\n", + strAddr(flags,addrstr),mptr->type,mptr->format); + switch(mptr->size) { + case 1: + printf(format,name,*(uchar *)memAddr); + break; + case 2: + printf(format,name,*(ushort *)memAddr); + break; + case 4: + printf(format,name,*(ulong *)memAddr); + break; + } + memAddr += mptr->size; + } + *eoname = tmp; + break; + } + mptr++; + } + if (!(mptr->type)) { + int padsize; + char *subtype, *subname, *eossn; + + if (!strcmp(type,"struct")) { + subtype = eotype+1; + while(isspace(*subtype)) + subtype++; + subname = subtype; + while(!isspace(*subname)) + subname++; + *subname = 0; + + subname++; + while(isspace(*subname)) + subname++; + eossn = subname; + while(!isspace(*eossn)) + eossn++; + *eossn = 0; + if (*subname == '*') { + castIndent(); + printf("%s%s %s %s: 0x%08lx\n",strAddr(flags,addrstr), + type,subtype,subname,*(ulong *)memAddr); + if (linkname) { + if (!strcmp(linkname,subname+1)) + nextlink = *(ulong *)memAddr; + } + memAddr += 4; + } + else { + for (i=0;i<tblsize;i++) { + if (bracket) + sprintf(bracket+1,"%d]",i); + if (showStruct(tfd,flags,subtype,subname,0) < 0) { + state = STRUCT_ALLDONE; + goto done; + } + } + } + } + else if (!strncmp(type,"pad[",4)) { + padsize = atoi(type+4); + if (flags & STRUCT_SHOWPAD) { + castIndent(); + printf("%spad[%d]\n",strAddr(flags,addrstr),padsize); + } + memAddr += padsize; + } + else { + retval = -1; + break; + } + } + } + else { + state = STRUCT_ERROR; + break; + } + } +done: + + switch(state) { + case STRUCT_SEARCH: + printf("struct %s not found\n",structtype); + retval = -1; + break; + case STRUCT_DISPLAY: + printf("invalid member type: %s\n",type); + retval = -1; + break; + case STRUCT_ERROR: + printf("unknown error\n"); + retval = -1; + break; + } + tfsseek(tfd,curpos,TFS_BEGIN); + if (linkname) + memAddr = nextlink; + castDepth--; + return(retval); +} + +char *CastHelp[] = { + "Cast a structure definition across data in memory.", + "-[al:n:pt:] {struct type} {address}", +#if INCLUDE_VERBOSEHELP + "Options:", + " -a show addresses", + " -l{linkname}", + " -n{structname}", + " -p show padding", + " -t{tablename}", +#endif + 0, +}; + +int +Cast(int argc,char *argv[]) +{ + long flags; + int opt, tfd, index; + char *structtype, *structfile, *tablename, *linkname, *name; + + flags = 0; + name = (char *)0; + linkname = (char *)0; + tablename = (char *)0; + while((opt=getopt(argc,argv,"apl:n:t:")) != -1) { + switch(opt) { + case 'a': + flags |= STRUCT_SHOWADD; + break; + case 'l': + linkname = optarg; + break; + case 'n': + name = optarg; + break; + case 'p': + flags |= STRUCT_SHOWPAD; + break; + case 't': + tablename = optarg; + break; + default: + return(CMD_PARAM_ERROR); + } + } + if (argc != optind + 2) + return(CMD_PARAM_ERROR); + + structtype = argv[optind]; + memAddr = strtoul(argv[optind+1],0,0); + + /* Start by detecting the presence of a structure definition file... */ + structfile = getenv("STRUCTFILE"); + if (!structfile) + structfile = STRUCTFILE; + + tfd = tfsopen(structfile,TFS_RDONLY,0); + if (tfd < 0) { + printf("Structure definition file '%s' not found\n",structfile); + return(CMD_FAILURE); + } + + index = 0; + do { + castDepth = 0; + showStruct(tfd,flags,structtype,name,linkname); + index++; + if (linkname) + printf("Link #%d = 0x%lx\n",index,memAddr); + if (tablename || linkname) { + if (askuser("next?")) { + if (tablename) + printf("%s[%d]:\n",tablename,index); + } + else + tablename = linkname = (char *)0; + } + } while(tablename || linkname); + + tfsclose(tfd,0); + return(CMD_SUCCESS); +} +#endif diff --git a/main/common/cf.c b/main/common/cf.c new file mode 100644 index 0000000..a0cbcd9 --- /dev/null +++ b/main/common/cf.c @@ -0,0 +1,207 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * cf.c: + * This code is the user interface portion of the cf (compact flash) + * command for uMon. + * This command is intended to be the "interface" portion of some + * other command (for example "fatfs"). Refer to the discussion in + * fatfs.c for more details. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#if INCLUDE_CF +#include "stddefs.h" +#include "genlib.h" +#include "cli.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "cf.h" + + +char *CfHelp[] = { + "Compact Flash Interface", + "[options] {operation} [args]...", +#if INCLUDE_VERBOSEHELP + "", + "Options:", + " -v enable verbosity", + "", + "Operations:", + " init [prefix]", + " read {dest} {blk} {blktot}", + " write {blk} {src} {blktot}", +#endif + 0 +}; + +static int cfInum; /* Interface number: to support multiple CF interfaces. + * Typically this will always be zero. + */ + +int +CfCmd(int argc, char *argv[]) +{ + char *cmd, *buf, *prefix, varname[16]; + int opt, verbose, cfret, blknum, blkcnt; + + verbose = 0; + while ((opt=getopt(argc,argv,"i:r:w:v")) != -1) { + switch(opt) { + case 'i': + cfInum = atoi(optarg); /* sticky */ + break; + case 'v': + verbose = 1; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc < optind + 1) + return(CMD_PARAM_ERROR); + + cmd = argv[optind]; + + if (strcmp(cmd,"init") == 0) { + if (argc != optind+2) + return(CMD_PARAM_ERROR); + + prefix = argv[optind+1]; + if (strlen(prefix)+4 > sizeof(varname)) { + printf("prefix %s too long\n",prefix); + return(CMD_PARAM_ERROR); + } + + cfret = cfInit(cfInum,verbose); + if (cfret < 0) { + printf("cfInit returned %d\n",cfret); + return(CMD_FAILURE); + } + + sprintf(varname,"%s_RD",prefix); + shell_sprintf(varname,"0x%lx",(long)cfRead); + + sprintf(varname,"%s_WR",prefix); + shell_sprintf(varname,"0x%lx",(long)cfWrite); + + shell_sprintf("CF_BLKSIZ","0x%lx",CF_BLKSIZE); + + if (verbose) { + printf("read: 0x%lx, write: 0x%lx, blksiz: 0x%lx\n", + (long)cfRead,(long)cfWrite,(long)CF_BLKSIZE,verbose); + } + } + else if (strcmp(cmd,"read") == 0) { + if (argc != optind+4) + return(CMD_PARAM_ERROR); + + buf = (char *)strtoul(argv[optind+1],0,0); + blknum = strtoul(argv[optind+2],0,0); + blkcnt = strtoul(argv[optind+3],0,0); + + cfret = cfRead(cfInum,buf,blknum,blkcnt,verbose); + if (cfret < 0) { + printf("cfRead returned %d\n",cfret); + return(CMD_FAILURE); + } + } + else if (strcmp(cmd,"write") == 0) { + if (argc != optind+4) + return(CMD_PARAM_ERROR); + buf = (char *)strtoul(argv[optind+1],0,0); + blknum = strtoul(argv[optind+2],0,0); + blkcnt = strtoul(argv[optind+3],0,0); + + cfret = cfWrite(cfInum,buf,blknum,blkcnt,verbose); + if (cfret < 0) { + printf("cfWrite returned %d\n",cfret); + return(CMD_FAILURE); + } + } + else { + printf("cf op <%s> not found\n",cmd); + return(CMD_FAILURE); + } + + return(CMD_SUCCESS); +} + +#ifdef INCLUDE_CF_DUMMY_FUNCS +/* This code is included here just for simulating the CF + * interface (temporarily if a real one isn't ready. In a real system, + * the INCLUDE_CF_DUMMY_FUNCS definition would be off. + */ + +int +cfInit(int interface, int verbose) +{ + if (interface != 0) { + if (verbose) + printf("cfInit bad interface %d\n",interface); + return(-1); + } + + return(0); +} + +int +cfRead(int interface, char *buf, int blk, int blkcnt, int verbose) +{ + char *from; + int size; + + if (interface != 0) { + if (verbose) + printf("cfRead bad interface %d\n",interface); + return(-1); + } + + from = (char *)(blk * CF_BLKSIZE); + size = blkcnt * CF_BLKSIZE; + memcpy(buf,from,size); + return(0); +} + +int +cfWrite(int interface, char *buf, int blk, int blkcnt, int verbose) +{ + char *to; + int size; + + if (interface != 0) { + if (verbose) + printf("cfWrite bad interface %d\n",interface); + return(-1); + } + + to = (char *)(blk * CF_BLKSIZE); + size = blkcnt * CF_BLKSIZE; + memcpy(to,buf,size); + return(0); +} + +#endif + +#endif diff --git a/main/common/cf.h b/main/common/cf.h new file mode 100644 index 0000000..64fbff7 --- /dev/null +++ b/main/common/cf.h @@ -0,0 +1,39 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * cf.h: + * + * Header file supporting compact flash command. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#ifndef CF_BLKSIZE +#define CF_BLKSIZE 512 +#endif + + +/* These two functions must be supplied by the port-specific code. + */ +int cfInit(int interface,int verbose); +int cfRead(int interface,char *buf,int bknum,int bkcnt,int verbose); +int cfWrite(int interface,char *buf,int bknum,int bkcnt,int verbose); + diff --git a/main/common/chario.c b/main/common/chario.c new file mode 100644 index 0000000..fb8fbae --- /dev/null +++ b/main/common/chario.c @@ -0,0 +1,543 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * chario.c: + * This code supports some basic character io functionality. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "timer.h" +#include "ether.h" +#include "fbi.h" + +#define CTLC 0x03 /* control-c */ + +int rawmode, ConsoleBaudRate; + +/* extWatchDog(): + * This function pointer is used by the application to override the + * monitor's configured watchdog functionality. Refer to config.h + * in umon_ports/template for more information on the WATCHDOG macro. + */ +#ifdef WATCHDOG_ENABLED +int (*remoteWatchDog)(void); +#endif + +/* remotexxxx() function pointers: + * These function pointers provide the application with the ability to + * override the monitor's default putchar/getchar/gotachar functions. + * See comments above InitRemoteIO() function below for more info. + */ +int (*remoterawon)(void); +int (*remoterawoff)(void); +int (*remoteputchar)(int); +int (*remotegetchar)(void); +int (*remotegotachar)(void); + +static char console_echo_off; + +/* console_echo(): + * Enable/disable the output of the console... + */ +void +console_echo(int enable) +{ + if (enable) + console_echo_off = 0; + else + console_echo_off = 1; +} + +/* putchar(): + * Output a character to the stdout RS232 port. + * If console_echo_off is set, then we DON'T send the + * character to the console. + */ +int +putchar(char c) +{ + /* If the remoteputchar function pointer is non-zero, then we + * assume that the default putchar function has been overridden + * by some overlaying application using mon_com(CHARFUNC_PUTCHAR,), + * so we use that redefined function instead... + */ + if (remoteputchar) { + remoteputchar(c); + return((int)c); + } + + if (rawmode) { + if (!console_echo_off) + target_putchar(c); + fbi_putchar(c); + return((int)c); + } + + /* If redirection is active, the redirect the character to a file + * in TFS. Note that if INCLUDE_REDIRECT is 0, then this function + * is NULL (see genlib.h). + */ + RedirectCharacter(c); + + /* Call the target-specific function that puts the character out on + * the console port (precede '\n' with '\r'). + * For each call to target_putchar(), call SendIPMonChar so that if + * this output is generated by moncmd, it will be sent back to the + * moncmd client. Note that if INCLUDE_ETHERNET is 0, then the + * function SendIPMonChar is NULL (see ether.h). + */ + if (c == '\n') { + SendIPMonChar('\r',0); + fbi_putchar('\r'); + if (!console_echo_off) + target_putchar('\r'); + } + SendIPMonChar(c,0); + if (!console_echo_off) + target_putchar(c); + fbi_putchar(c); + WATCHDOG_MACRO; + return((int)c); +} + +int +getchar(void) +{ + /* If the remotegetchar function pointer is non-zero, then we + * assume that the default getchar function has been overridden + * by some overlaying application using mon_com(CHARFUNC_GETCHAR,), + * so we use that redefined function instead... + */ + if (remotegetchar) + return(remotegetchar()); + + while(!gotachar()) { + /* While waiting for an incoming character, call pollethernet() + * to process any incoming packets. Note that if INCLUDE_ETHERNET + * is 0 in config.h, then this function is NULL (see ether.h). + */ + WATCHDOG_MACRO; + pollethernet(); + } + + return(target_getchar()); +} + +int +gotachar(void) +{ + /* If the remotegotachar function pointer is non-zero, then we + * assume that the default gotachar function has been overridden + * by some overlaying application using mon_com(CHARFUNC_GOTACHAR,), + * so we use that redefined function instead... + */ + if (remotegotachar) + return(remotegotachar()); + + fbi_cursor(); + WATCHDOG_MACRO; + return(target_gotachar()); +} + +/* flush_console_out(): + * Call this function to wait for the console UART to flush all outgoing + * characters. Note that this function has a timeout in the loop. + */ +void +flush_console_out(void) +{ + int timeout = 0; + + if (remoteputchar) + return; + + while(timeout++ < 50000) { + if (target_console_empty()) { + monDelay(10); + break; + } + } +} + +/* flush_console_in(void): + * While there is input queued up from the console, + * flush it to the bit bucket... + */ +void +flush_console_in(void) +{ + while(gotachar()) + getchar(); +} + + +/* rawon() & rawoff(): + * Used primarily by xmodem. When xmodem runs, it must be assured that + * the interface is in RAW mode. For the case of the monitor alone, it + * will always be in a raw mode. These functions are primarily for use + * when an application has re-loaded the serial driver and may have put + * it in a non-raw mode. The mon_com() calls CHARFUNC_RAWMODEON and + * CHARFUNC_RAWMODEOFF establish these pointers. + */ +void +rawon(void) +{ + if (remoterawon) + remoterawon(); + rawmode = 1; +} + +void +rawoff(void) +{ + if (remoterawoff) + remoterawoff(); + rawmode = 0; +} + +/* puts() & putstr(): + * Two string-output functions. + * puts: normal "puts" as is available in standard c libs. + * putstr: same as "puts", but no ending newline. + */ + +void +putstr(char *string) +{ + while(*string) { + putchar(*string); + string++; + } +} + +void +puts(char *string) +{ + putstr(string); + putchar('\n'); +} + + +/* getfullline(): + * Basic line retrieval; but with a few options... + * This function is accessed through the getline_xx functions + * below. + * Args... + * buf: pointer to buffer to be used to place the incoming characters. + * max: size of the buffer. + * ledit: if set, then allow the line-editor to be used if ESC is input. + * timeout: if positive, then after 'timeout' number of seconds waiting + * per character, giveup. + * if negative, then after 'timeout' number of seconds waiting + * total, giveup. + * if zero, then wait forever. + * prefill: if set, prefill the buffer with that string and show the user. + * echo: if set, characters are echoed as they are entered. + */ +int +getfullline(char *buf,int max,int ledit, int timeout,char *prefill, int echo) +{ + char *base; + struct elapsed_tmr tmr; + static unsigned char crlf; + int tot, idx, cumulativetimeout; + + cumulativetimeout = 0; + tot = idx = 0; + base = buf; + max -= 1; /* Make sure there is space for the null terminator. */ + + if (prefill) { + strcpy(base,prefill); + tot = strlen(prefill); + putstr(prefill); + buf += tot; + idx = tot; + } + + /* If the timeout parameter is negative, then assume that this is + * to be run with a cumulative timeout rather than a timeout that + * is re-started after each character... + */ + if (timeout < 0) { + cumulativetimeout = 1; + timeout = abs(timeout); + } + + for(;idx<max;idx++) { + if (timeout > 0) { + startElapsedTimer(&tmr,timeout); + while(!msecElapsed(&tmr)) { + if (gotachar()) + break; + pollethernet(); + } + if (cumulativetimeout) + timeout = msecRemaining(&tmr); + + if (ELAPSED_TIMEOUT(&tmr)) { + *buf = 0; + return(-1); /* Return negative to indicate timeout */ + } + } + if (cumulativetimeout && timeout == 0) { + *buf = 0; + return(-1); + } + + *buf = (char)getchar(); + + if (getenv("CLI_HEXOUT")) + printf("<%02x>",*buf); + + if (!*buf) { + idx--; + continue; + } +#if INCLUDE_LINEEDIT + if ((*buf == 0x1b) && (ledit)) { + (void)line_edit(base); + break; + } + else +#endif + { + if ((*buf == '\r') || (*buf == '\n')) { + if ((crlf) && (*buf != crlf)) { + crlf = 0; + continue; + } + puts("\r"); + crlf = *buf; + *buf = 0; + break; + } + if (*buf == '\b' || *buf == 0x7f) { + if (tot) { + idx -= 2; + buf--; + tot--; + if (echo) + putstr("\b \b"); + } + } + else if (*buf == CTLC) { + puts("^C"); + *base = 0; + return(0); + } + else { + if (echo) + putchar(*buf); + tot++; + buf++; + } + crlf = 0; + } + } + if (idx == max) { + printf((char *)"\007\nInput too long (exceeds %d bytes).\n",max); + *buf = 0; + return(0); + } +#if INCLUDE_LINEEDIT + if (ledit) + historylog(base); +#endif + return(strlen(base)); +} + +int +getline(char *buf, int max, int ledit) +{ + return(getfullline(buf,max,ledit,0,0,1)); +} + +int +getline_t(char *buf, int max, int timeout) +{ + return(getfullline(buf,max,0,timeout,0,1)); +} + +int +getline_p(char *buf, int max, int ledit, char *prefill) +{ + return(getfullline(buf,max,ledit,0,prefill,1)); +} + +/* getpass(): + */ +#if INCLUDE_USRLVL +char * +getpass(char *prompt,char *buf,int max, int timeout) +{ + putstr(prompt); + if (getfullline(buf,max,0,timeout*1000,0,0) == -1) + putchar('\n'); + return(buf); +} +#endif + +/* getbytes(): + * Similar to gets() except that the caller specifies the number + * of characters and whether or not to block. + * If the copy to the buffer fails, abort and return the current + * count. + */ + +int +getbytes(char *buf,int cnt,int block) +{ + int i; + volatile char *bp; + char c; + + bp = (volatile char *)buf; + + for(i=0;i<cnt;i++) { + if (!block && !gotachar()) + break; + c = (char)getchar(); + *bp = c; + if (*bp != c) + break; + bp++; + } + return(i); +} + +/* getbytes_t(): + * Similar to getbytes() except that the caller specifies the allowed + * timeout between two consecutive bytes received. + * If the copy to the buffer fails, or timeout occures, abort and return + * the current count. + */ + +int +getbytes_t(char *buf,int cnt,int timeout) +{ + int i; + struct elapsed_tmr tmr; + volatile char *bp; + char c; + + bp = (volatile char *)buf; + + for(i=0;i<cnt;i++) { + if (!gotachar()) { + startElapsedTimer(&tmr,timeout); + while(!gotachar() && !msecElapsed(&tmr)); + if (!gotachar()) + break; + } + c = (char)getchar(); + *bp = c; + if (*bp != c) + break; + bp++; + } + return(i); +} + +int +putbytes(char *buf, int cnt) +{ + char *end; + + end = buf + cnt; + + while(buf < end) { + putchar(*buf++); + } + return(cnt); +} + +int +askuser(char *msg) +{ + int yes, len; + +#if INCLUDE_MONCMD + /* If command was issued from UDP (i.e. moncmd), then + * immediately return 1... + */ + if (IPMonCmdActive) + return(1); +#endif + + putstr(msg); + len = strlen(msg); + switch((char)getchar()) { + case ' ': + case 'y': + case '\r': + case '\n': + yes = 1; + break; + default: + yes = 0; + break; + } + while(len) { + putstr("\b \b"); + len--; + } + return(yes); +} + +int +More(void) +{ + return(askuser((char *)"more?")); +} + +int +hitakey(void) +{ + return(askuser((char *)"hit any key to continue...")); +} + +/* RemoteIO functions: + * The idea of "remote io" is to allow the monitor commands to still + * run when the application has taken over the system. The monitor's + * connection to the serial port is a simple polled interface. When + * the application comes up, it is very likely that it will overlay a + * new driver onto the serial port. If this happens, and the user at + * the console interface of the application wants to execute a monitor + * command, then the monitor's putchar/getchar/gotachar functions must + * use functions that are part of the application. These remote io + * function pointers, if set, will point to those functions. + */ + +void +InitRemoteIO(void) +{ + /* Null out the remote put/getchar functions. */ + remoterawon = 0; + remoterawoff = 0; + remoteputchar = 0; + remotegetchar = 0; + remotegotachar = 0; +} diff --git a/main/common/cli.h b/main/common/cli.h new file mode 100644 index 0000000..9b661c6 --- /dev/null +++ b/main/common/cli.h @@ -0,0 +1,130 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * cli.h: + * + * Header file for Command Line Interface related stuff. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _CLI_H_ +#define _CLI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Command table structure used by the monitor: + */ +struct monCommand { + char *name; /* Name of command seen by user. */ + int (*func)(int,char **); /* Called when command is invoked. */ + char **helptxt; /* Help text (see notes below). */ + long flags; /* Single-bit flags for various uses */ + /* (see the CMDFLAG_XXX macros). */ +}; + +#ifdef __cplusplus +} +#endif + +/* Bits currently assigned to command flags used in the monCommand + * structure... + */ +#define CMDFLAG_NOMONRC 1 + +/* Maximum size of a command line: + */ +#ifndef CMDLINESIZE +#define CMDLINESIZE 256 +#endif + +/* Maximum number of arguments in a command line: + */ +#define ARGCNT 24 + +/* Definitions for docommand() return values: + * + * Note that the CMD_SUCCESS, CMD_FAILURE and CMD_PARAM_ERROR are return + * values used by the local command code also. The remaining errors + * (CMD_LINE_ERROR, CMD_ULVL_DENIED and CMD_NOT_FOUND) are used only by + # the docommand() function. + * + * CMD_SUCCESS: + * Everything worked ok. + * CMD_FAILURE: + * Command parameters were valid, but command itself failed for some other + * reason. The docommand() function does not print a message here, it + * is assumed that the error message was printed by the local function. + * CMD_PARAM_ERROR: + * Command line did not parse properly. Control was passed to a + * local command function, but argument syntax caused it to choke. + * In this case docommand() will print out the generic CLI syntax error + * message. + * CMD_LINE_ERROR: + * Command line itself was invalid. Too many args, invalid shell var + * syntax, etc.. Somekind of command line error prior to checking for + * the command name-to-function match. + * CMD_ULVL_DENIED: + * Command's user level is higher than current user level, so access + * is denied. + * CMD_NOT_FOUND: + * Since these same return values are used for each command function + * plus the docommand() function, this error indicates that docommand() + * could not even find the command in the command table. + * CMD_MONRC_DENIED: + * The command cannot execute because it is considered illegal + * when run from within the monrc file. + */ +#define CMD_SUCCESS 0 +#define CMD_FAILURE -1 +#define CMD_PARAM_ERROR -2 +#define CMD_LINE_ERROR -3 +#define CMD_ULVL_DENIED -4 +#define CMD_NOT_FOUND -5 +#define CMD_MONRC_DENIED -6 + +/* Notes on help text array: + * The monitor's CLI processor assumes that every command's help text + * array abides by a few basic rules... + * First of all, it assumes that every array has AT LEAST two strings. + * The first string in the array of strings is assumed to be a one-line + * abstract describing the command. + * The second string in the array of strings is assumed to be a usage + * message that describes the syntax of the arguments needed by the command. + * If this second string is an empty string (""), the docommand() prints out + * a generic usage string indicating that there are no options or arguements + * to apply to the command. + * All remaining lines are formatted based on the needs of the individual + * command and the final string is a null pointer to let the CLI processor + * know where the end is. + * Following is an example help text array... + * + * char *HelpHelp[] = { + * "Display command set", + * "-[d] [commandname]", + * "Options:", + * " -d list commands and descriptions", + * 0, + * }; + * + */ +#endif diff --git a/main/common/cmdtbl.c b/main/common/cmdtbl.c new file mode 100644 index 0000000..e2010c0 --- /dev/null +++ b/main/common/cmdtbl.c @@ -0,0 +1,484 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * cmdtbl.c: + * This is the command table used by the monitor. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "cli.h" +#include "genlib.h" +#include "xcmddcl.h" + +#define ULVLCMD "ulvl" + +#if INCLUDE_MEMCMDS +#define INCLUDE_PM 1 +#define INCLUDE_DM 1 +#define INCLUDE_FM 1 +#define INCLUDE_CM 1 +#define INCLUDE_SM 1 +#define INCLUDE_MT 1 +#endif + +extern int Arp(int, char **); +extern int BbcCmd(int, char **); +extern int BinfoCmd(int, char **); +extern int BmemCmd(int, char **); +extern int Call(int, char **); +extern int Cast(int, char **); +extern int Cm(int, char **); +extern int CfCmd(int, char **); +extern int Dis(int, char **); +extern int Dm(int, char **); +extern int Dhcp(int, char **); +extern int DnsCmd(int, char **); +extern int Echo(int, char **); +extern int Edit(int, char **); +extern int Ether(int, char **); +extern int Exit(int, char **); +extern int FatfsCmd(int, char **); +extern int FbiCmd(int, char **); +extern int FlashCmd(int, char **); +extern int Fm(int, char **); +extern int Gdb(int, char **); +extern int Goto(int, char **); +extern int Gosub(int, char **); +extern int Heap(int, char **); +extern int Help(int, char **); +extern int History(int, char **); +extern int Icmp(int, char **); +extern int Ide(int, char **); +extern int I2cCmd(int, char **); +extern int If(int, char **); +extern int Igmp(int, char **); +extern int Item(int, char **); +extern int Jffs2Cmd(int, char **); +extern int Mt(int, char **); +extern int MtraceCmd(int, char **); +extern int Pm(int, char **); +extern int Prof(int, char **); +extern int Read(int, char **); +extern int Reg(int, char **); +extern int Reset(int, char **); +extern int Return(int, char **); +extern int SdCmd(int, char **); +extern int Set(int, char **); +extern int Sleep(int, char **); +extern int Sm(int, char **); +extern int SpifCmd(int, char **); +extern int Strace(int, char **); +extern int StructCmd(int, char **); +extern int SyslogCmd(int, char **); +extern int Tfs(int, char **); +extern int Tftp(int, char **); +extern int TsiCmd(int, char **); +extern int Ulvl(int, char **); +extern int Unzip(int, char **); +extern int Version(int, char **); +extern int WhatCmd(int, char **); +extern int Xmodem(int, char **); + +extern char *ArpHelp[]; +extern char *BbcHelp[]; +extern char *BinfoHelp[]; +extern char *BmemHelp[]; +extern char *CallHelp[]; +extern char *CastHelp[]; +extern char *CfHelp[]; +extern char *CmHelp[]; +extern char *DisHelp[]; +extern char *DhcpHelp[]; +extern char *DmHelp[]; +extern char *DnsHelp[]; +extern char *EchoHelp[]; +extern char *EditHelp[]; +extern char *EtherHelp[]; +extern char *ExitHelp[]; +extern char *FatfsHelp[]; +extern char *FbiHelp[]; +extern char *FlashHelp[]; +extern char *FmHelp[]; +extern char *GdbHelp[]; +extern char *GosubHelp[]; +extern char *GotoHelp[]; +extern char *HelpHelp[]; +extern char *HeapHelp[]; +extern char *HistoryHelp[]; +extern char *IcmpHelp[]; +extern char *IdeHelp[]; +extern char *I2cHelp[]; +extern char *IfHelp[]; +extern char *IgmpHelp[]; +extern char *ItemHelp[]; +extern char *Jffs2Help[]; +extern char *MtHelp[]; +extern char *MtraceHelp[]; +extern char *PmHelp[]; +extern char *ProfHelp[]; +extern char *ReadHelp[]; +extern char *RegHelp[]; +extern char *ResetHelp[]; +extern char *ReturnHelp[]; +extern char *SdHelp[]; +extern char *SetHelp[]; +extern char *SleepHelp[]; +extern char *SmHelp[]; +extern char *SpifHelp[]; +extern char *StraceHelp[]; +extern char *StructHelp[]; +extern char *SyslogHelp[]; +extern char *TfsHelp[]; +extern char *TftpHelp[]; +extern char *TsiHelp[]; +extern char *UlvlHelp[]; +extern char *UnzipHelp[]; +extern char *VersionHelp[]; +extern char *WhatHelp[]; +extern char *XmodemHelp[]; + +struct monCommand cmdlist[] = { +#if INCLUDE_ETHERNET + { "arp", Arp, ArpHelp, CMDFLAG_NOMONRC }, +#endif +#if INCLUDE_BBC + { "bbc", BbcCmd, BbcHelp, 0 }, +#endif +#if INCLUDE_BMEM + { "bmem", BmemCmd, BmemHelp, 0 }, +#endif +#if INCLUDE_BOARDINFO + { "brdinfo", BinfoCmd, BinfoHelp, 0 }, +#endif + { "call", Call, CallHelp, CMDFLAG_NOMONRC }, +#if INCLUDE_CAST + { "cast", Cast, CastHelp, 0 }, +#endif +#if INCLUDE_CF + { "cf", CfCmd, CfHelp, 0 }, +#endif +#if INCLUDE_CM + { "cm", Cm, CmHelp, 0 }, +#endif +#if INCLUDE_DHCPBOOT + { "dhcp", Dhcp, DhcpHelp, CMDFLAG_NOMONRC }, +#endif +#if INCLUDE_DISASSEMBLER + { "dis", Dis, DisHelp, 0 }, +#endif +#if INCLUDE_DM + { "dm", Dm, DmHelp, 0 }, +#endif +#if INCLUDE_DNS + { "dns", DnsCmd, DnsHelp, 0 }, +#endif +#if INCLUDE_TFSSCRIPT + { "echo", Echo, EchoHelp, 0 }, +#endif +#if INCLUDE_EDIT + { "edit", Edit, EditHelp, 0 }, +#endif +#if INCLUDE_ETHERNET + { "ether", Ether, EtherHelp, CMDFLAG_NOMONRC }, +#endif +#if INCLUDE_TFSSCRIPT + { "exit", Exit, ExitHelp, 0 }, +#endif +#if INCLUDE_FATFS + { "fatfs", FatfsCmd, FatfsHelp, 0 }, +#endif +#if INCLUDE_FBI + { "fbi", FbiCmd, FbiHelp, 0 }, +#endif +#if INCLUDE_FLASH + { "flash", FlashCmd, FlashHelp, 0 }, +#endif +#if INCLUDE_FM + { "fm", Fm, FmHelp, 0 }, +#endif + +#if INCLUDE_GDB + { "gdb", Gdb, GdbHelp, CMDFLAG_NOMONRC }, +#endif + +#if INCLUDE_TFSSCRIPT + { "gosub", Gosub, GosubHelp, 0 }, + { "goto", Goto, GotoHelp, 0 }, +#endif + +#if INCLUDE_MALLOC + { "heap", Heap, HeapHelp, 0 }, +#endif + + { "help", Help, HelpHelp, 0 }, + { "?", Help, HelpHelp, 0 }, + +#if INCLUDE_LINEEDIT + { "history", History, HistoryHelp, 0 }, +#endif + +#if INCLUDE_I2C + { "i2c", I2cCmd, I2cHelp, 0 }, +#endif + +#if INCLUDE_ICMP + { "icmp", Icmp, IcmpHelp, CMDFLAG_NOMONRC }, +#endif + +#if INCLUDE_IDE + { "ide", Ide, IdeHelp, CMDFLAG_NOMONRC }, +#endif + +#if INCLUDE_IGMP + { "igmp", Igmp, IgmpHelp, CMDFLAG_NOMONRC }, +#endif + +#if INCLUDE_TFSSCRIPT + { "if", If, IfHelp, 0 }, +#endif + +#if INCLUDE_TFSSCRIPT + { "item", Item, ItemHelp, 0 }, +#endif + +#if INCLUDE_JFFS2 + { "jffs2", Jffs2Cmd, Jffs2Help, 0 }, +#endif + +#if INCLUDE_MT + { "mt", Mt, MtHelp, 0 }, +#endif + +#if INCLUDE_MEMTRACE + { "mtrace", MtraceCmd, MtraceHelp, 0 }, +#endif + +#if INCLUDE_PM + { "pm", Pm, PmHelp, 0 }, +#endif + +#if INCLUDE_PROFILER + { "prof", Prof, ProfHelp, 0 }, +#endif + +#if INCLUDE_TFSSCRIPT + { "read", Read, ReadHelp, 0 }, +#endif + +#if INCLUDE_STRACE + { "reg", Reg, RegHelp, 0 }, +#endif + + { "reset", Reset, ResetHelp, 0 }, + +#if INCLUDE_TFSSCRIPT + { "return", Return, ReturnHelp, 0 }, +#endif +#if INCLUDE_SD + { "sd", SdCmd, SdHelp, 0 }, +#endif + + { "set", Set, SetHelp, 0 }, + +#if INCLUDE_TFSSCRIPT + { "sleep", Sleep, SleepHelp, 0 }, +#endif + +#if INCLUDE_SM + { "sm", Sm, SmHelp, 0 }, +#endif + +#if INCLUDE_SPIF + { "spif", SpifCmd, SpifHelp, 0 }, +#endif + +#if INCLUDE_STRACE + { "strace", Strace, StraceHelp, 0 }, +#endif + +#if INCLUDE_STRUCT + { "struct", StructCmd, StructHelp, 0 }, +#endif + +#if INCLUDE_SYSLOG + { "syslog", SyslogCmd, SyslogHelp, CMDFLAG_NOMONRC }, +#endif + +#if INCLUDE_USRLVL + { ULVLCMD, Ulvl, UlvlHelp, 0 }, +#endif + +#if INCLUDE_TFTP + { "tftp", Tftp, TftpHelp, CMDFLAG_NOMONRC }, +#endif + +#if INCLUDE_TFSCLI + { "tfs", Tfs, TfsHelp, 0 }, +#endif + +#if INCLUDE_TSI + { "tsi", TsiCmd, TsiHelp, 0 }, +#endif + +#if INCLUDE_UNZIP + { "unzip", Unzip, UnzipHelp, 0 }, +#endif + +#if INCLUDE_XMODEM + { "xmodem", Xmodem, XmodemHelp, 0 }, +#endif + + { "version", Version, VersionHelp, 0 }, + +#if INCLUDE_TFS + { "what", WhatCmd, WhatHelp, 0 }, +#endif + +#include "xcmdtbl.h" /* For non-generic commands that are */ + /* specific to a particular target. */ + { 0,0,0,0 }, +}; + +#if INCLUDE_USRLVL + +/* cmdUlvl[]: + * This table stores one char per command that contains that command's + * user level. The default user level of all commands is 0, but can + * be re-defined by the ulvl -c command. + */ +char cmdUlvl[(sizeof(cmdlist)/sizeof(struct monCommand))]; + +/* setCmdUlvl(): + * The incoming string is a command name followed by a comma and a user + * level (ranging from 0 thru 4). + * Return 0 if pass, 1 if new level was user-level rejected, -1 if error. + */ +int +setCmdUlvl(char *cmdlvl, int verbose) +{ + extern char *appcmdUlvl; + extern struct monCommand *appCmdlist; + struct monCommand *cptr; + int newlevel, idx, pass, doall; + char *comma, *lvlptr, buffer[32], *cmdandlevel; + + /* Make a copy of the incoming string so that we can + * modify it... + */ + if (strlen(cmdlvl) > (sizeof(buffer)-1)) + goto showerr; + + strcpy(buffer,cmdlvl); + cmdandlevel = buffer; + + /* First verify that the comma is in the string... */ + comma = strchr(cmdandlevel,','); + if (!comma) + goto showerr; + + /* Retrieve and verify the new level to be assigned... + * If the level value is the string "off", then we assign a level + * value that is greater than MAXUSRLEVEL so that the command is + * essentially disabled as a built-in. + */ + if (strcmp(comma+1,"off") == 0) { + newlevel = MAXUSRLEVEL+1; + } + else { + newlevel = atoi(comma+1); + if ((newlevel < MINUSRLEVEL) || (newlevel > MAXUSRLEVEL)) + goto showerr; + } + + *comma = 0; + + /* Don't allow adjustment of the ulvl command itself. It must be + * able to run as user level 0 all the time... + */ + if (!strcmp(cmdandlevel,ULVLCMD)) { + printf("Can't adjust '%s' user level.\n",ULVLCMD); + return(-1); + } + + if (appCmdlist) { + pass = 0; + cptr = appCmdlist; + lvlptr = appcmdUlvl; + } + else { + pass = 1; + cptr = cmdlist; + lvlptr = cmdUlvl; + } + + /* If the command string is "ALL" then we set all commands + * to the requested level. + */ + if (!strcmp(cmdandlevel,"ALL")) + doall = 1; + else + doall = 0; + + while(pass < 2) { + if ((cptr == cmdlist) && (cmdandlevel[0] == '_')) + cmdandlevel++; + + /* Find the command in the table that is to be adjusted... */ + for(idx=0;cptr->name;cptr++,idx++) { + if (doall || (!strcmp(cmdandlevel,cptr->name))) { + /* Even with doall set, we don't want to touch + * the ULVLCMD level... + */ + if (doall && !strcmp(cptr->name,ULVLCMD)) + continue; + + /* If the command's user level is to be lowered, then the + * current monitor userlevel must be at least as high as the + * command's current user level... + */ + if ((newlevel < lvlptr[idx]) && (getUsrLvl() < lvlptr[idx])) { + if (verbose) + printf("User-level access denied: %s\n",cmdandlevel); + return(1); + } + lvlptr[idx] = newlevel; + if (!doall) + return(0); + } + } + cptr = cmdlist; + lvlptr = cmdUlvl; + pass++; + } + + if (doall) + return(0); + +showerr: + if (verbose) + printf("Input error: %s\n",cmdlvl); + return(-1); +} + +#endif diff --git a/main/common/coff.h b/main/common/coff.h new file mode 100644 index 0000000..f324e73 --- /dev/null +++ b/main/common/coff.h @@ -0,0 +1,114 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * coff.h: + * + * Header file used for the COFF file format of TFS. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _COFF_H_ +#define _COFF_H_ + +/* File header... */ +struct filehdr { + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + long f_timdat; /* time & date stamp */ + long f_symptr; /* file pointer to symtab */ + long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ +}; + +#define FILHDR struct filehdr +#define FILHSZ sizeof(FILHDR) +#define F_EXEC 0000002 + +/* Optional header... */ +struct aouthdr { + short magic; + short vstamp; /* version stamp */ + long tsize; /* text size in bytes, padded to FW + bdry */ + long dsize; /* initialized data " " */ + long bsize; /* uninitialized data " " */ + long entry; /* entry pt. */ + long text_start; /* base of text used for this file */ + long data_start; /* base of data used for this file */ +}; + +#define AOUTHDR struct aouthdr +#define AOUTHSZ sizeof(AOUTHDR) + +struct scnhdr { + char s_name[8]; /* section name */ + long s_paddr; /* physical address */ + long s_vaddr; /* virtual address */ + long s_size; /* section size */ + long s_scnptr; /* file ptr to raw data for section */ + long s_relptr; /* file ptr to relocation */ + long s_lnnoptr; /* file ptr to line numbers */ + unsigned short s_nreloc; /* number of relocation entries */ + unsigned short s_nlnno; /* number of line number entries */ + long s_flags; /* flags */ +}; + +#define SCNHDR struct scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/* + * The low 4 bits of s_flags is used as a section "type" + */ + +#define STYP_REG 0x00 /* "regular" section: + allocated, relocated, loaded */ +#define STYP_DSECT 0x01 /* "dummy" section: + not allocated, relocated, + not loaded */ +#define STYP_NOLOAD 0x02 /* "noload" section: + allocated, relocated, + not loaded */ +#define STYP_GROUP 0x04 /* "grouped" section: + formed of input sections */ +#define STYP_PAD 0x08 /* "padding" section: + not allocated, not relocated, + loaded */ +#define STYP_COPY 0x10 /* "copy" section: + for decision function used + by field update; not + allocated, not relocated, + loaded; reloc & lineno + entries processed normally */ +#define STYP_TEXT 0x20 /* section contains text only */ +#define STYP_DATA 0x40 /* section contains data only */ +#define STYP_BSS 0x80 /* section contains bss only */ +#define STYP_INFO 0x0200 +#define STYP_LIT 0x8020 +#define STYP_ABS 0x4000 +#define STYP_BSSREG 0x1200 +#define STYP_ENVIR 0x2200 + +#define ISLOADABLE(flags) \ + (flags & (STYP_ABS | STYP_TEXT | STYP_LIT | STYP_DATA)) +#define ISBSS(flags) (flags & (STYP_BSS)) +#define ISTEXT(flags) (flags & (STYP_TEXT)) +#endif diff --git a/main/common/cstart.c b/main/common/cstart.c new file mode 100644 index 0000000..260c9b3 --- /dev/null +++ b/main/common/cstart.c @@ -0,0 +1,148 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * cstart.c: + * This is the first 'C' code exececuted by the processor after a reset if + * the monitor is built to boot and copy itself into RAM. + * + * This 2-stage monitor is done with two distinct images. + * The first image (the real "boot" image) includes this cstart() code + * in place of normal start(). The make process generates the umon.c file + * included below. This file is essentially a C-array that consists of + * the binary image (second image) of a version of the monitor that is + * built to run out of RAM. The value of UMON_RAMBASE is the base address + * of this image and the value of UMON_START is the entry point into this + * image. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "cpu.h" + +#ifdef ROM_MONSTACKSIZE +ulong MonStack[ROM_MONSTACKSIZE/4]; +#endif + +/* The umon.c file is simply an array that contains the monitor + * image and the necessary information needed to do the copy. + */ +#include "umon.c" + +char * +memcpy(char *to,char *from,int count) +{ + char *to_copy, *end; + + to_copy = to; + + /* If count is greater than 8, get fancy, else just do byte-copy... */ + if (count > 8) { + /* Attempt to optimize the transfer here... */ + if (((int)to & 3) && ((int)from & 3)) { + /* If from and to pointers are both unaligned to the + * same degree then we can do a few char copies to get them + * 4-byte aligned and then do a lot of 4-byte aligned copies. + */ + if (((int)to & 3) == ((int)from & 3)) { + while((int)to & 3) { + *to++ = *from++; + count--; + } + } + /* If from and to pointers are both odd, but different, then + * we can increment them both by 1 and do a bunch of 2-byte + * aligned copies... + */ + else if (((int)to & 1) && ((int)from & 1)) { + *to++ = *from++; + count--; + } + } + + /* If both pointers are now 4-byte aligned or 2-byte aligned, + * take advantage of that here... + */ + if (!((int)to & 3) && !((int)from & 3)) { + end = to + (count & ~3); + count = count & 3; + while(to < end) { + *(ulong *)to = *(ulong *)from; + from += 4; + to += 4; + } + } + else if (!((int)to & 1) && !((int)from & 1)) { + end = to + (count & ~1); + count = count & 1; + while(to < end) { + *(ushort *)to = *(ushort *)from; + from += 2; + to += 2; + } + } + } + + if (count) { + end = to + count; + while(to < end) + *to++ = *from++; + } + return(to_copy); +} + +void +cstart(void) +{ + register long *lp1, *lp2, *end2; + void (*entry)(); + + entry = (void(*)())UMON_START; + + /* Copy image from boot flash to RAM, then verify the copy. + * If it worked, then jump into that space; else reset and start + * over (not much else can be done!). + */ + memcpy((char *)UMON_RAMBASE,(char *)umon,(int)sizeof(umon)); + + /* Verify the copy... + */ + lp1 = (long *)UMON_RAMBASE; + lp2 = (long *)umon; + end2 = lp2 + (int)sizeof(umon)/sizeof(long); + while(lp2 < end2) { + if (*lp1 != *lp2) { +#ifdef CSTART_ERROR_FUNCTION + extern void CSTART_ERROR_FUNCTION(); + + CSTART_ERROR_FUNCTION(lp1,*lp1,*lp2); +#endif +#ifdef INLINE_RESETFUNC + INLINE_RESETFUNC(); +#else + entry = RESETFUNC(); +#endif + break; + } + lp1++; lp2++; + } + entry(); +} diff --git a/main/common/dallasdate.c b/main/common/dallasdate.c new file mode 100644 index 0000000..31af955 --- /dev/null +++ b/main/common/dallasdate.c @@ -0,0 +1,362 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * dallasdate.c: + * + * Code to support the DALLAS DS1743W Timekeeping RAM plus the hooks to + * allow TFS to timestamp files. The function tfsTimeEnable() must be + * called to setup the connection between TFS and the DS1743W. + * + * Applicable to DS1743W and DS1746WP. Probably also works with other + * Dallas timekeepers, but the above two are the only ones I've tested + * it with. This code is assumed to be compiled with the DATEREGBASE + * value defined elsewhere. This value is the address at which the code + * is to access the 8-byte register map that contains the time/date + * information. + * + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "cli.h" + +#ifndef DATEREGBASE +#error DATEREGBASE not defined +#endif + +#define WRITE 0x80 /* part of 'cent' member */ +#define READ 0x40 /* part of 'cent' member */ +#define FT 0x40 /* part of 'wday' member */ +#define OSC_OFF 0x80 /* part of 'sec' member */ + +/* Masks for various portions of the time/date... */ +#define YEAR10_MASK 0xf0 +#define MONTH10_MASK 0x10 +#define DATE10_MASK 0x30 +#define DAY10_MASK 0x00 +#define HOUR10_MASK 0x30 +#define MINUTE10_MASK 0x70 +#define SECOND10_MASK 0x70 +#define CENTURY10_MASK 0x30 +#define YEAR_MASK 0x0f /* Year is 0-99 */ +#define MONTH_MASK 0x0f /* Month is 1-12 */ +#define DATE_MASK 0x0f /* Date is 1-31 */ +#define DAY_MASK 0x07 /* Day is 1-7 */ +#define HOUR_MASK 0x0f /* Hour is 0-23 */ +#define MINUTE_MASK 0x0f /* Minutes is 0-59 */ +#define SECOND_MASK 0x0f /* Seconds is 0-59 */ +#define CENTURY_MASK 0x0f /* Century is 0-39 */ + +struct dsdate { + uchar cent; /* B7=W, B6=R, B5-4=10cent, B3-0=cent (00-39) */ + uchar sec; /* B7=OSC; B6-4=10secs; B3-0=sec (0-59) */ + uchar min; /* B6-4=10mins; B3-0=min (0-59) */ + uchar hour; /* B4-5=10hour; B3-0=hour (0-23) */ + uchar wday; /* B6=FT B2-0=day (1-7) */ + uchar mday; /* B4-5=10date; B3-0=date (1-31) */ + uchar month; /* B4=10mo; B3-0=month (1-12) */ + uchar year; /* MS-nibble=10Year; LS-nibble=year (0-99) */ +}; + +#define DS1743REGS ((struct dsdate *)DATEREGBASE) +#define DS_century (DS1743REGS->cent) +#define DS_second (DS1743REGS->sec) +#define DS_minute (DS1743REGS->min) +#define DS_hour (DS1743REGS->hour) +#define DS_wday (DS1743REGS->wday) +#define DS_mday (DS1743REGS->mday) +#define DS_month (DS1743REGS->month) +#define DS_year (DS1743REGS->year) + +#define SECONDS_IN_DAY 86400 + +static char +DaysInMonth[] = { + 31, 28, 31, 30, 31, 30, /* Jan, Feb, Mar, Apr, May, Jun */ + 31, 31, 30, 31, 30, 31 /* Jul, Aug, Sep, Oct, Nov, Dec */ +}; + +/* rangecheck(): + Return 0 if value is outside the range of high and low; else 1. +*/ +static int +rangecheck(int value, char *name, int low, int high) +{ + if ((value < low) || (value > high)) { + printf("%s outside valid range of %d - %d\n", + name,low,high); + return(0); + } + return(1); +} + +/* to_dsdatefmt(): + * Take an incoming integer and convert it to the dallas time date + * format using a 10-multiplier for the upper nibble. + */ +static unsigned char +to_dsdatefmt(int value) +{ + int tens; + + tens = 0; + while (value >= 10) { + tens++; + value -= 10; + } + return((tens << 4) | value); +} + +static int +from_dsdatefmt(unsigned char value, unsigned char mask10) +{ + int newvalue; + + newvalue = value & 0x0f; + newvalue += 10 * ((value & mask10) >> 4); + return(newvalue); +} + +int +showDate(int center) +{ + int (*pfunc)(char *, ...); + int day, date, month, year, hour, minute, second, century; + + DS_century |= READ; /* Set READ bit */ + + century = from_dsdatefmt(DS_century,CENTURY10_MASK); + second = from_dsdatefmt(DS_second,SECOND10_MASK); + minute = from_dsdatefmt(DS_minute,MINUTE10_MASK); + hour = from_dsdatefmt(DS_hour,HOUR10_MASK); + day = from_dsdatefmt(DS_wday,DAY10_MASK); + date = from_dsdatefmt(DS_mday,DATE10_MASK); + month = from_dsdatefmt(DS_month,MONTH10_MASK); + year = (((DS_year & 0xf0) >> 4) * 10) + (DS_year & 0x0f); + + DS_century &= ~READ; /* Clear READ bit */ + + if (center) + pfunc = cprintf; + else + pfunc = printf; + + pfunc("%02d/%02d/%02d%02d @ %02d:%02d:%02d\n", + month,date,century,year,hour,minute,second); + + return(0); +} + +#if INCLUDE_TFS + +static int +YearIsLeap(int year) +{ + if (year % 4) /* if year not divisible by 4... */ + return(0); /* it's not leap */ + if (year < 1582) /* all years divisible by 4 were */ + return(1); /* leap prior to 1582 */ + if (year % 100) /* if year divisible by 4, */ + return(1); /* but not by 100, it's leap */ + if (year % 400) /* if year divisible by 100, */ + return(0); /* but not by 400, it's not leap */ + else + return(1); /* if divisible by 400, it's leap */ +} + +/* GetAtime(): + * Build a string based on the incoming long value as described in + * GetLtime()... + * Used by TFS to keep track of file time. + */ +static char * +GetAtime(long tval, char *buf, int bsize) +{ + int year; /* Actual year */ + int doy; /* Day of year */ + int sid; /* Seconds in day */ + int leapyear; /* Set if year is leap */ + int month, hour, minute; + + if ((bsize < 18) || (tval == TIME_UNDEFINED)) { + *buf = 0; + return(buf); + } + + /* Break down the basic bitfields: */ + year = 2000 + ((tval >> 26) & 0x3f); + leapyear = YearIsLeap(year); + doy = ((tval >> 17) & 0x1ff); + sid = tval & 0x1ffff; + + /* Now build the date from the bit fields: */ + hour = sid / 3600; + sid -= (hour*3600); + minute = sid/60; + sid -= (minute*60); + + month = 0; + while(doy > DaysInMonth[month]) { + doy -= DaysInMonth[month]; + if ((month == 1) && (leapyear)) + doy--; + month++; + } + sprintf(buf,"%02d/%02d/%02d@%02d:%02d:%02d", + month+1,doy,year,hour,minute,sid); + return(buf); +} + +/* GetLtime(): + * Build a long with the following format.... + * + * B31-26 year since 2000 (0-127 yep, this breaks in 2128) + * B25-17 day of year (1-365) + * B16-0 seconds in day (0-86400) + * + * Used by TFS to keep track of file time. + */ +static long +GetLtime(void) +{ + long tval; + int year, month, mday, seconds, doy, leapyear; + + DS_century |= READ; /* Set READ bit */ + + year = from_dsdatefmt(DS_year,YEAR10_MASK); /* 00=2000 */ + month = from_dsdatefmt(DS_month,MONTH10_MASK)-1; /* 0-11 */ + mday = from_dsdatefmt(DS_mday,DATE10_MASK); /* 1-31 */ + leapyear = YearIsLeap(year+2000); + + if ((month > 11) || (month < 0) || (mday < 1) || (mday > 31)) + return(TIME_UNDEFINED); + + /* Determine current day of year... */ + doy = mday; + while(month > 0) { + doy += DaysInMonth[month-1]; + if ((month == 1) && leapyear) + doy++; + month--; + } + + /* Determine current second of day... */ + seconds = (from_dsdatefmt(DS_hour,HOUR10_MASK) * 3600); + seconds += (from_dsdatefmt(DS_minute,MINUTE10_MASK) * 60); + seconds += from_dsdatefmt(DS_second,SECOND10_MASK); + + DS_century &= ~READ; /* Clear READ bit */ + + tval = (((year & 0x3f) << 26) | + ((doy & 0x1ff) << 17) | + (seconds & 0x1ffff)); + return(tval); +} + +/* tfsTimeEnable(): + * Hook the file timestamping in TFS to the DS1743 device... + */ +void +tfsTimeEnable(void) +{ + tfsctrl(TFS_TIMEFUNCS,(long)GetLtime,(long)GetAtime); +} +#endif + +char *DateHelp[] = { + "Display (mm/dd/yyyy@hh:mm:ss) or modify time and date.", + "[{day date month year hour min sec}]", +#if INCLUDE_VERBOSEHELP + "Where...", + " day: 1-7 (sun=1)", + " date: 1-31", + " month: 1-12", + " year: 0-3899", + " hour: 0-23", + " min: 0-59", + " sec: 0-59", + "Note: 'date off' disables the oscillator", +#endif + 0 +}; + +int +Date(int argc,char *argv[]) +{ + int day, date, month, year, hour, minute, second, century, rngchk; + + if (argc == 1) { + if (DS_second & OSC_OFF) + printf("Warning: oscillator disabled.\n"); + showDate(0); + return(CMD_SUCCESS); + } + else if ((argc == 2) && !strcmp(argv[1],"off")) { + DS_century |= WRITE; /* Disable the oscillator */ + DS_second = OSC_OFF; /* to save battery life. */ + DS_century &= ~WRITE; + return(CMD_SUCCESS); + } + else if (argc != 8) + return(CMD_PARAM_ERROR); + + day = atoi(argv[1]); + date = atoi(argv[2]); + month = atoi(argv[3]); + year = atoi(argv[4]); + hour = atoi(argv[5]); + minute = atoi(argv[6]); + second = atoi(argv[7]); + + rngchk = 0; + rngchk += rangecheck(day,"day",1,7); + rngchk += rangecheck(date,"date",1,31); + rngchk += rangecheck(month,"month",1,12); + rngchk += rangecheck(year,"year",0,3899); + rngchk += rangecheck(hour,"hour",0,23); + rngchk += rangecheck(minute,"minute",0,59); + rngchk += rangecheck(second,"second",0,59); + + if (rngchk != 7) + return(CMD_PARAM_ERROR); + + DS_century = WRITE; /* Set WRITE bit */ + DS_second = to_dsdatefmt(second) & ~OSC_OFF; + DS_minute = to_dsdatefmt(minute); + DS_hour = to_dsdatefmt(hour); + DS_wday = day; + DS_mday = to_dsdatefmt(date); + DS_month = to_dsdatefmt(month); + century = year / 100; + year = year % 100; + DS_year = to_dsdatefmt(year); + DS_century = (to_dsdatefmt(century)&(CENTURY_MASK|CENTURY10_MASK))|WRITE; + + DS_century &= ~WRITE; /* Clear WRITE bit */ + return(CMD_SUCCESS); +} + + diff --git a/main/common/date.c b/main/common/date.c new file mode 100644 index 0000000..f7d56b0 --- /dev/null +++ b/main/common/date.c @@ -0,0 +1,160 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * date.c: + * + * A command front-end and utilities for time-of-day-clock hardware. + * Some of this is taken from the older file dallasdate.c which *should* + * be moved to the dev directory (if not already there). + * This code expects a few HW-specific functions to be available... + * + * getTimeAndDate(struct todinfo *); + * setTimeAndDate(struct todinfo *); + * + * If setTimeAndDate() is passed '0', then it is this code's attempt + * to disable the TOD oscillator (to reduce battery drain). + * + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "genlib.h" +#include "cli.h" +#include "date.h" + +/* rangecheck(): + Return 0 if value is outside the range of high and low; else 1. +*/ +static int +rangecheck(int value, char *name, int low, int high) +{ + if ((value < low) || (value > high)) { + printf("%s outside valid range of %d - %d\n", + name,low,high); + return(0); + } + return(1); +} + +int +showDate(int center) +{ + int (*pfunc)(char *, ...); + struct todinfo now; + + getTimeAndDate(&now); + + if (center) + pfunc = cprintf; + else + pfunc = printf; + + pfunc("%02d/%02d/%04d @ %02d:%02d:%02d\n", + now.month,now.date,now.year, + now.hour,now.minute,now.second); + + return(0); +} + +char *DateHelp[] = { + "Display (mm/dd/yyyy@hh:mm:ss) or modify time and date.", + "[{day date month year hour min sec}]", +#if INCLUDE_VERBOSEHELP + "Where...", + " day: 1-7 (sun=1)", + " date: 1-31", + " month: 1-12", + " year: full number (i.e. 2006)", + " hour: 0-23", + " min: 0-59", + " sec: 0-59", + "Note: 'date off' disables the oscillator (if HW supports this)", +#endif + 0 +}; + +int +DateCmd(int argc,char *argv[]) +{ + int rngchk; + struct todinfo now; + + if (argc == 1) { + showDate(0); + return(CMD_SUCCESS); + } + else if ((argc == 2) && !strcmp(argv[1],"off")) { + if (setTimeAndDate(0) < 0) { + printf("Clock can't be disabled\n"); + return(CMD_FAILURE); + } + return(CMD_SUCCESS); + } + else if (argc != 8) + return(CMD_PARAM_ERROR); + + now.day = (char)atoi(argv[1]); + now.date = (char)atoi(argv[2]); + now.month = (char)atoi(argv[3]); + now.year = atoi(argv[4]); + now.hour = (char)atoi(argv[5]); + now.minute = (char)atoi(argv[6]); + now.second = (char)atoi(argv[7]); + + rngchk = 0; + rngchk += rangecheck(now.day,"day",1,7); + rngchk += rangecheck(now.date,"date",1,31); + rngchk += rangecheck(now.month,"month",1,12); + rngchk += rangecheck(now.year,"year",0,9999); + rngchk += rangecheck(now.hour,"hour",0,23); + rngchk += rangecheck(now.minute,"minute",0,59); + rngchk += rangecheck(now.second,"second",0,59); + + if (rngchk != 7) + return(CMD_PARAM_ERROR); + + setTimeAndDate(&now); + return(CMD_SUCCESS); +} + +int +timeofday(int cmd, void *arg) +{ + int rc; + struct todinfo *now; + + rc = 0; + now = (struct todinfo *)arg; + + switch(cmd) { + case TOD_ON: + case TOD_OFF: + break; + case TOD_SET: + rc = setTimeAndDate(now); + break; + case TOD_GET: + rc = getTimeAndDate(now); + break; + } + return(rc); +} diff --git a/main/common/date.h b/main/common/date.h new file mode 100644 index 0000000..1f39ee0 --- /dev/null +++ b/main/common/date.h @@ -0,0 +1,46 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * date.h + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +struct todinfo { + char day; /* 1-7 (sun = 1) */ + char date; /* 1-31 */ + char month; /* 1-12 */ + char hour; /* 0-23 */ + char minute; /* 0-59 */ + char second; /* 0-59 */ + short year; /* full number (i.e. 2006) */ +}; + +extern int showDate(int center); +extern int timeofday(int cmd, void *arg); +extern int setTimeAndDate(struct todinfo *now); +extern int getTimeAndDate(struct todinfo *now); + +/* #defines used by the uMon API mon_timeofday()... + */ +#define TOD_ON 1 +#define TOD_OFF 2 +#define TOD_SET 3 +#define TOD_GET 4 diff --git a/main/common/devices.c b/main/common/devices.c new file mode 100644 index 0000000..134c21c --- /dev/null +++ b/main/common/devices.c @@ -0,0 +1,149 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * devices.c: + * + * This code provides the monitor with the ability to treat the peripherals + * as an entry in a device table so that each device can be accessed through + * read, write, ioctl, init, open and close. + * The device table header file is defined as part of the target-specific + * code and contains all of the target-specific device entries. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "devtbl.h" +#include "devices.h" +#include "genlib.h" +#include "stddefs.h" + +/* devtbldump(): + * Dump the contents of the device table. + */ +void +devtbldump() +{ + int i; + + /* Dump the device table and add an asterisk next to the console device. */ + for(i=0;i<DEVTOT;i++) { + printf("Dev %d: %s%s\n",i,devtbl[i].name, + ConsoleDevice == i ? " (console)" : ""); + } +} + +/* isbaddev(): + * Return the result of a basic range check of the device number. + */ +int +isbaddev(int dev) +{ + if ((dev < 0) || (dev >= DEVTOT)) { + printf("Invalid device: %d\n",dev); + return(1); + } + return(0); +} + +/* Upper half device driver interfaces: */ + +int +init(int dev,ulong arg) +{ + if (isbaddev(dev) || !devtbl[dev].init) + return(-1); + return (devtbl[dev].init(arg)); +} + +int +open(int dev,ulong arg1,ulong arg2) +{ + if (isbaddev(dev) || !devtbl[dev].open) + return(-1); + return (devtbl[dev].open(arg1,arg2)); +} + +int +close(int dev) +{ + if (isbaddev(dev) || !devtbl[dev].close) + return(-1); + return (devtbl[dev].close(dev)); +} + +int +ioctl(int dev,int func,ulong data1,ulong data2) +{ + if (isbaddev(dev) || !devtbl[dev].ctrl) + return(-1); + return (devtbl[dev].ctrl(func,data1,data2)); +} + +int +read(int dev,char *buf,int cnt) +{ + if (isbaddev(dev) || !devtbl[dev].read) + return(-1); + return (devtbl[dev].read(buf,cnt)); +} + +int +write(int dev,char *buf,int cnt) +{ + if (isbaddev(dev) || !devtbl[dev].read) + return(-1); + return (devtbl[dev].write(buf,cnt)); +} + +/* devInit(): + * Step through the device table and execute each devices' initialization + * function (if any). If any device initialization fails, print out an + * error message and immediately branch to the montor's command loop. + * Since it is through this point that the monitor's UARTs are first + * initialized, we pass in a baudrate that is then handed to each of the + * device initialization routines (although it is only used by serial + * devices). + */ +int +devInit(int baud) +{ + int fd; + + if (baud == 0) + baud = ConsoleBaudRate; + + /* Keep track of the last baud rate, so that it can be used if the + * incoming baudrate is NULL. + */ + ConsoleBaudRate = baud; + + fd = 0; + for(fd=0;fd<DEVTOT;fd++) + { + /* If device table does not have an init function, skip over it. */ + if (!devtbl[fd].init) + continue; + if (devtbl[fd].init((ulong)baud) != 0) { + printf("devInit() <%s> FAILED\n",devtbl[fd].name); + CommandLoop(); + } + } + return(0); +} diff --git a/main/common/devices.h b/main/common/devices.h new file mode 100644 index 0000000..62f7e8f --- /dev/null +++ b/main/common/devices.h @@ -0,0 +1,65 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * devices.h + * + * device structure: + * This structure defines the basic information needed for device + * control. The table of devices is initialized at compile time + * with each device assigned an integer device descriptor. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _DEVICES_H_ +#define _DEVICES_H_ + +struct device { + int (*init)(unsigned long); + int (*ctrl)(int,unsigned long,unsigned long); + int (*open)(unsigned long,unsigned long); + int (*close)(int); + int (*read)(char *,int); + int (*write)(char *,int); + char *name; +}; + +extern struct device devtbl[]; + +/* Generic driver functions: */ +extern int open(int, unsigned long, unsigned long); +extern int close(int); +extern int read(int, char *, int); +extern int write(int, char *, int); +extern int init(int, unsigned long); +extern int ioctl(int, int, unsigned long, unsigned long); +extern int devInit(int); +extern int isbaddev(int); +extern void devtbldump(void); + +/* Common ioctl definitions: */ +#define INIT 1 +#define GOTACHAR 2 +#define SETBAUD 3 + +#define nodriver 0 + +extern int ConsoleDevice; +#endif diff --git a/main/common/dhcp_00.c b/main/common/dhcp_00.c new file mode 100644 index 0000000..8a9d7ca --- /dev/null +++ b/main/common/dhcp_00.c @@ -0,0 +1,259 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * dhcp_00.c: + * + * This file contains the functions that are called from dhcpboot.c if the + * the default DHCP interaction is to be done by the monitor. Whenever a + * new dhcp_XX.c file is created, this file should be used as the template. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#include "cpuio.h" +#include "ether.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "genlib.h" +#include "endian.h" +#include "stddefs.h" + +#if INCLUDE_DHCPBOOT + +/* ValidDHCPOffer(): + * Target issued the DISCOVER, the incoming packet is the server's + * OFFER reply. If the DHCPOFFRFLTR shell variable is not present, then + * return 1 indicating acceptance of the offer. If the DHCPOFFRFLTR variable + * exists, then use its content to determine if the offer should be accepted... + * + * Shell variable syntax: + * + * DHCP_FIELD_IDENTIFIER,EXPECTED_STRING + * + * where DHCP_FIELD_IDENTIFIER can be... + * BFN bootfile name + * SHN server-host name + * VSO### vendor-specific option number (options encapsulated within + * the Vendor-Specific Information (#43) option) + * SSO### site-specific option number (range 128-254) + * + * For example: + * 1... + * if DHCPOFFRFLTR contains "BFN,abcfile" + * then the offer will only be accepted if the bootfile specified by the + * dhcp server contains the string "abcfile". + * 2... + * if DHCPOFFRFLTR contains "SHN,a_host_name" + * then the offer will only be accepted if the server-hostname specified + * by the dhcp server contains the string "a_host_name". + * 3... + * if DHCPOFFRFLTR contains "VSO18,some_String" + * then the offer will only be accepted if the server returns vendor- + * specific option # 18 and it contains the string "some_String". + * + * Note that "containing the string" means that the string specified in + * the DHCPOFFRFLTR shell variable can be the entire string or a sub-string + * within the server's response. + */ +int +ValidDHCPOffer(struct dhcphdr *dhdr) +{ + char *var; + int offeraccepted, badsyntax; + + /* If no DHCPOFFRFLTR var, accept the offer... */ + var = getenv("DHCPOFFRFLTR"); + if (!var) + return(1); + + /* Start off by assuming acceptance... */ + badsyntax = 0; + offeraccepted = 1; + + /* Now process the DHCPOFFRFLTR variable and incoming dhcp data, + * and clear the offeraccepted (or set badsyntax) flag if necessary... + */ + + if (!strncmp(var,"BFN,",4)) { + if (!strstr((char *)dhdr->bootfile,var+4)) + offeraccepted = 0; + } + else if (!strncmp(var,"SHN,",4)) { + if (!strstr((char *)dhdr->server_hostname,var+4)) + offeraccepted = 0; + } + else if ((!strncmp(var,"SSO",3)) || (!strncmp(var,"VSO",3))) { + int optno; + ulong cookie; + char *comma, *optval, *vso; + + optno = atoi(var+3); + comma = strchr(var,','); + memcpy((char *)&cookie,(char *)&dhdr->magic_cookie,4); + if (cookie != ecl(STANDARD_MAGIC_COOKIE)) + offeraccepted = 0; + else if (!comma) + badsyntax = 1; + else if (var[0] == 'S') { + if ((optno < 128) || (optno > 254)) + badsyntax = 1; + else { + optval = (char *)DhcpGetOption(optno,(unsigned char *)(dhdr+1)); + if (!optval) + offeraccepted = 0; + else { + if (!strstr(optval+2,comma+1)) + offeraccepted = 0; + } + } + } + else if (var[0] == 'V') { + if ((optno < 0) || (optno > 254)) + badsyntax = 1; + else { + vso = (char *)DhcpGetOption(DHCPOPT_VENDORSPECIFICINFO, + (uchar *)dhdr+1); + if (!vso) + offeraccepted = 0; + else { + optval = (char *)DhcpGetOption(optno,(unsigned char *)vso+2); + if (!optval) + offeraccepted = 0; + else { + if (!strstr(optval+2,comma+1)) + offeraccepted = 0; + } + } + } + } + } + else { + badsyntax = 1; + } + if (badsyntax) { + printf("Bad DHCPOFFRFLTR syntax.\n"); + offeraccepted = 0; + } + return(offeraccepted); +} + +/* DhcpVendorSpecific(): + * Process any vendor specific data from the incoming header. + */ +void +DhcpVendorSpecific(struct dhcphdr *dhdr) +{ + return; /* Obviously, the default is no processing. */ +} + +/* printDhcpVSopt(): + * Input is the option, the option length and the pointer to the options. + * Print the option. + */ +int +printDhcpVSopt(int vsopt, int vsoptlen, char *options) +{ + return(0); +} + +/* buildDhcpHdr(): + * Called by dhcpboot.c to allow application-specific header stuff to + * be added to header. Return 0 if generic stuff in dhcpboot.c is to be + * used; else return 1 and the calling code will assume this function is + * dealing with it (see dhcpboot.c for basic idea). + */ +int +buildDhcpHdr(struct dhcphdr *dhdr) +{ + return(0); +} + +/* DhcpBootpLoadVSA(): + * Called by DhcpBootpDone to store an ascii-coded-hex copy of the + * vendor-specific-area (BOOTP) or options (DHCP) in the shell variable + * DHCPVSA. + */ +void +DhcpBootpLoadVSA(uchar *vsabin, int vsize) +{ + int i; + uchar *cp, *vsaacx; + + /* If after the transaction has completed, the RLYAGNT is */ + /* set, but GIPADD is not set, copy RLYAGNT to GIPADD... */ + if (!getenv("GIPADD") && getenv("RLYAGNT")) + setenv("GIPADD",getenv("RLYAGNT")); + + /* Since the VSA (bootp) or options list (DHCP) can be large, + * This code looks for the presence of the DHCPVSA shell variable + * as an indication as to whether or not this data should be stored + * in the DHCPVSA variable... + * If the variable is present, then this code will load the DHCPVSA + * shell variable; else it just returns here. + * Note that it doesn't matter what the content of DHCPVSA is, as + * long as it is present, so just loading it with "TRUE" in monrc + * will be sufficient to tell this logic to load the variable with + * the data. + */ + if (!getenv("DHCPVSA")) + return; + + /* If allocation succeeds, then copy BOOTP VendorSpecificArea to the */ + /* DHCPVSA shell variable. Copy it as ascii-coded hex */ + vsaacx = (uchar *)malloc((vsize*2)+4); + if (vsaacx) { + cp = vsaacx; + for(i=0;i<vsize;i++,cp+=2) + sprintf((char *)cp,"%02x", vsabin[i]); + *cp = 0; + setenv("DHCPVSA", (char *)vsaacx); + free((char *)vsaacx); + } + else + printf("DHCPVSA space allocation failed\n"); +} + + +/* DhcpBootpDone(): + * Called at the end of the Bootp or Dhcp transaction. + * Input... + * bootp: 1 if BOOTP; else DHCP. + * dhdr: pointer to dhcp or bootp header. + * vsize: size of vendor specific area (for bootp this is fixed at 64, + * but for dhcp it is variable). + */ +void +DhcpBootpDone(int bootp, struct dhcphdr *dhdr, int vsize) +{ + if (bootp) { + struct bootphdr *bhdr; + + bhdr = (struct bootphdr *)dhdr; + DhcpBootpLoadVSA(bhdr->vsa,vsize); + } + else { + DhcpBootpLoadVSA((uchar *)&dhdr->magic_cookie,vsize); + } + return; +} + +#endif diff --git a/main/common/dhcp_01.c b/main/common/dhcp_01.c new file mode 100644 index 0000000..afd7fa0 --- /dev/null +++ b/main/common/dhcp_01.c @@ -0,0 +1,246 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * dhcp_01.c: + * This is the PPA-specific code used for Videotron Market trial. + * It was built from the dhcp_00.c DHCP-extension template file. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#include "cpuio.h" +#include "ether.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "genlib.h" +#include "stddefs.h" + +/* Vendor specific option definitions: */ +#define VS_PROXYIP 1 +#define VS_PHONENUM 2 +#define VS_CODER 3 +#define VS_PPADHCPSRVR 4 +#define VS_MINNETDELAY 5 +#define VS_MAXNETDELAY 6 +#define VS_APPINFO 7 +#define VS_CODERCTL 8 +#define VS_NAMEVAL 99 + +#define PPADHCPSRVR_STR "PPADHCPSRVR" + +/* ValidDHCPOffer(): + * Target issued the DISCOVER, the incoming packet is the server's + * OFFER reply. If the offer contains the vendor specific + * VS_PPADHCPSRVR option and the string within that + * option is correct, then accept the offer; by issuing a request. + */ +ValidDHCPOffer(struct dhcphdr *dhdr) +{ + uchar *op, *op1; + + op = op1 = 0; + op1 = DhcpGetOption(DHCPOPT_VENDORSPECIFICINFO,dhdr+1); + if (op1) { + op = DhcpGetOption(VS_PPADHCPSRVR,op1+2); + } + if (op) { + if (!strncmp(op+2,PPADHCPSRVR_STR,sizeof(PPADHCPSRVR_STR)-1)) { + return(1); + } + } + return(0); +} + +/* buildDhcpHdr(): + * Called by dhcpboot.c to allow application-specific header stuff to + * be added to header. Return 0 if generic stuff in dhcpboot.c is to be + * used; else return 1 and the calling code will assume this function is + * dealing with it (see dhcpboot.c for basic idea). + */ +int +buildDhcpHdr(struct dhcphdr *dhcpdata) +{ + return(0); +} + +/* DhcpBootpDone(): + * Called at the end of the Bootp or Dhcp transaction. + * Input... + * bootp: 1 if BOOTP; else DHCP. + * dhdr: pointer to dhcp or bootp header. + * vsize: size of vendor specific area (for bootp this is fixed at 64, + * but for dhcp it is variable). + */ +void +DhcpBootpDone(int bootp, struct dhcphdr *dhdr, int vsize) +{ + return; +} + +void +SetPPAOption(type,op1,varname) +int type; +uchar *op1; +char *varname; +{ + uchar *op, tmp; + + op = DhcpGetOption(type,op1+2); + if (op) { + tmp = op[*(op+1)+2]; + op[*(op+1)+2] = 0; + DhcpSetEnv(varname,op+2); + op[*(op+1)+2] = tmp; + } +} + +/* DhcpVendorSpecific(): + * Process vendor specific stuff within the incoming dhcp header. + */ +DhcpVendorSpecific(struct dhcphdr *dhdr) +{ + ulong ip; + uchar *op, *op1, buf[16], tmp; + + op = op1 = 0; + op1 = DhcpGetOption(DHCPOPT_VENDORSPECIFICINFO,dhdr+1); + if (op1) { + /* Get PROXY_IP and BPROXY_IP (optionally): */ + op = DhcpGetOption(VS_PROXYIP,op1+2); + if (op) { + memcpy(&ip,op+2,4); + DhcpSetEnv("PROXY_IP",IpToString(ip,buf)); + if (*(op+1) == 8) { + memcpy(&ip,op+6,4); + DhcpSetEnv("BPROXY_IP",IpToString(ip,buf)); + } + } + + /* Get PPA phone numbers (1 or 2). */ + op = DhcpGetOption(VS_PHONENUM,op1+2); + if (op) { + char *space; + tmp = op[*(op+1)+2]; + op[*(op+1)+2] = 0; + space = strchr(op+2,' '); + if (space) { + *space = 0; + DhcpSetEnv("LINE0_NUMBER",op+2); + DhcpSetEnv("LINE1_NUMBER",space+1); + *space = ' '; + } + else + DhcpSetEnv("LINE0_NUMBER",op+2); + op[*(op+1)+2] = tmp; + } + + /* Set Coder type: */ + SetPPAOption(VS_CODER,op1,"CODER"); + + /* Set Coder control: */ + SetPPAOption(VS_CODERCTL,op1,"CODERCTL"); + + /* Set minimum network delay setting: */ + SetPPAOption(VS_MINNETDELAY,op1,"MIN_NET_DELAY"); + + /* Set maximum network delay setting: */ + SetPPAOption(VS_MAXNETDELAY,op1,"MAX_NET_DELAY"); + + /* Set appinfo: */ + SetPPAOption(VS_APPINFO,op1,"APPINFO"); + } + + /* Check for VS_NAMEVAL here... + * If the Vendor-Specific-Information is present, and within that + * information there is a sub-option of VS_NAMEVAL, + * then consider the content of that sub-option to be one or more + * strings (separated by a comma) of the format "VARNAME=VALUE". + * This is used to allow the DHCP server to configure shell variables + * into the environment prior to the monitor turning over control to + * the application. + * Two examples of VS_NAMEVAL strings: + * First, just one name-value combination... + * VARNAME=VALUE + * Second, a multiple name-value combination... + * VARNAME=VALUE,VAR1=ABC,IP=1.2.3.4 + */ + + op = op1 = 0; + op1 = DhcpGetOption(DHCPOPT_VENDORSPECIFICINFO,dhdr+1); + if (op1) + op = DhcpGetOption(VS_NAMEVAL,op1+2); + if (op) { + int len; + uchar *end, tmp; + uchar *name, *value, *eqsign, *comma, *base; + + op++; + len = (int)*op++; + base = op; + tmp = base[len]; + base[len] = 0; + end = base + len; + while (op < end) { + eqsign = (uchar *)strchr(op,'='); + if (!eqsign) + break; + name = op; + *eqsign = 0; + value = eqsign+1; + comma = (uchar *)strchr(value,','); + if (comma) { + *comma = 0; + op = comma+1; + } + else + op = end; + DhcpSetEnv(name,value); + *eqsign = '='; + *comma = ','; + } + base[len] = tmp; + } +} + +int +printDhcpVSopt(int vsopt, int vsoptlen, char *options) +{ + switch(vsopt) { + case VS_PROXYIP: + for(i=0;i<vsoptlen;i++) + printf("%d ",(unsigned int)*options++); + break; + case VS_CODER: + case VS_NAMEVAL: + case VS_MINNETDELAY: + case VS_MAXNETDELAY: + case VS_PPADHCPSRVR: + case VS_PHONENUM: + case VS_APPINFO: + for(i=0;i<vsoptlen;i++) + printf("%c",*options++); + break; + default: + return(0); + } + return(1); +} diff --git a/main/common/dhcp_02.c b/main/common/dhcp_02.c new file mode 100644 index 0000000..1fb0cdc --- /dev/null +++ b/main/common/dhcp_02.c @@ -0,0 +1,89 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * dhcp_02.c: + * + * This is the PPA-specific code used for Time-Warner Market. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpuio.h" +#include "ether.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "genlib.h" +#include "stddefs.h" + +/* ValidDHCPOffer(): + * Target issued the DISCOVER, the incoming packet is the server's + * OFFER reply. If the offer contains the string PPADHCPSRVR in the + * bootfile string, then accept the offer (return 1); else reject it. + */ +ValidDHCPOffer(struct dhcphdr *dhdr) +{ + if (strcmp(dhdr->bootfile,"PPADHCPSRVR")) + return(0); + return(1); +} + +/* buildDhcpHdr(): + * Called by dhcpboot.c to allow application-specific header stuff to + * be added to header. Return 0 if generic stuff in dhcpboot.c is to be + * used; else return 1 and the calling code will assume this function is + * dealing with it (see dhcpboot.c for basic idea). + */ +int +buildDhcpHdr(struct dhcphdr *dhcpdata) +{ + return(0); +} + +/* DhcpBootpDone(): + * Called at the end of the Bootp or Dhcp transaction. + * Input... + * bootp: 1 if BOOTP; else DHCP. + * dhdr: pointer to dhcp or bootp header. + * vsize: size of vendor specific area (for bootp this is fixed at 64, + * but for dhcp it is variable). + */ +void +DhcpBootpDone(int bootp, struct dhcphdr *dhdr, int vsize) +{ + return; +} + +/* DhcpVendorSpecific(): + * Process vendor specific stuff within the incoming dhcp header. + */ +void +DhcpVendorSpecific(struct dhcphdr *dhdr) +{ +} + +/* printDhcpVSopt(): + * Print vendor specific stuff within the incoming dhcp header. + */ +int +printDhcpVSopt(int vsopt, int vsoptlen, char *options) +{ + return(0); +} diff --git a/main/common/dhcp_03.c b/main/common/dhcp_03.c new file mode 100644 index 0000000..2f8566c --- /dev/null +++ b/main/common/dhcp_03.c @@ -0,0 +1,101 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * dhcp_03.c: + * + * This is the PPA-specific code used for PATHSTAR. PATHSTAR uses BOOTP + * and has their own proprietary string in the vendor-specific-area. + * This code loads that string into the BOOTPVSA shell variable. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#include "cpuio.h" +#include "ether.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "genlib.h" +#include "stddefs.h" + +/* ValidDHCPOffer(): + Target issued the DISCOVER, the incoming packet is the server's + OFFER reply. +*/ +ValidDHCPOffer(struct dhcphdr *dhdr) +{ + return(1); +} + +/* buildDhcpHdr(): + Called by dhcpboot.c to allow application-specific header stuff to + be added to header. Return 0 if generic stuff in dhcpboot.c is to be + used; else return 1 and the calling code will assume this function is + dealing with it (see dhcpboot.c for basic idea). +*/ +int +buildDhcpHdr(struct dhcphdr *dhcpdata) +{ + return(0); +} + +/* DhcpBootpDone(): + Called at the end of the Bootp or Dhcp transaction. + Input... + bootp: 1 if BOOTP; else DHCP. + dhdr: pointer to dhcp or bootp header. + vsize: size of vendor specific area (for bootp this is fixed at 64, + but for dhcp it is variable). +*/ +void +DhcpBootpDone(int bootp, struct dhcphdr *dhdr, int vsize) +{ + if (bootp) { + ulong cookie; + struct bootphdr *bhdr; + char bootpvsa[65], *vp; + + bhdr = (struct bootphdr *)dhdr; + memcpy(&cookie,bhdr->vsa,4); + if (cookie != STANDARD_MAGIC_COOKIE) { + memcpy(bootpvsa,bhdr->vsa,64); + bootpvsa[64] = 0; + setenv("BOOTPVSA",bootpvsa); + } + } +} + +/* DhcpVendorSpecific(): + Process vendor specific stuff within the incoming dhcp header. +*/ +void +DhcpVendorSpecific(struct dhcphdr *dhdr) +{ +} + +/* printDhcpVSopt(): + Print vendor specific stuff within the incoming dhcp header. +*/ +int +printDhcpVSopt(int vsopt, int vsoptlen, char *options) +{ + return(0); +} diff --git a/main/common/dhcpboot.c b/main/common/dhcpboot.c new file mode 100644 index 0000000..e0ded6a --- /dev/null +++ b/main/common/dhcpboot.c @@ -0,0 +1,1328 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * dhcpboot.c: + * + * This code implements a subset of the DHCP client protocol. + * Based on RFC2131 spec, the "automatic allocation" mode, in which DHCP + * assigns a permanent IP address to a client, is the only mode supported. + * + * The idea is that the monitor boots up, and if IPADD is set to DHCP, then + * DHCP is used to populate shell variables with a server-supplied IP + * address, NetMask and Gateway IP address. Then, when the application + * is launched (probably via TFS), it can retrieve the content of those + * shell variables for use by the application. + * + * Sequence of events for this limited implementation of DHCP... + * Client issues a DHCP_DISCOVER, server responds with a DHCP_OFFER, + * client issues a DHCP_REQUEST and server responds with a DHCP_ACK. + * DISCOVER: request by the client to broadcast the fact that it is looking + * for a DHCP server. + * OFFER: reply from the server when it receives a DISCOVER request from + * a client. The offer may contain all the information that the DHCP + * client needs to bootup, but this is dependent on the configuration of + * the server. + * REQUEST: request by the client for the server (now known because an OFFER + * was received) to send it the information it needs. + * ACK: reply from the server with the information requested. + * + * NOTE: this file contains a generic DHCP client supporting "automatic + * allocation mode" (infinite lease time). There are several different + * application-specific enhancements that can be added and hopefully + * they have been isolated through the use of the dhcp_00.c file. + * I've attempted to isolate as much of the non-generic code to + * the file dhcp_XX.c (where dhcp_00.c is the default code). If non-default + * code is necessary, then limit the changes to a new dhcp_XX.c file. This + * will allow the code in this file to stay generic; hence, the user of this + * code will be able to accept monitor upgrades without the need to touch + * this file. The makefile must link in some additional dhcp_XX.c file + * (default is dhcp_00.c). Bottom line... there should be no need to modify + * this file for application-specific stuff; if there is, please let me know. + * + * NOTE1: the shell variable IPADD can also be set to DHCPV or DHCPv to + * enable different levels of verbosity during DHCP transactions... 'V' + * is full DHCP verbosity and 'v' only prints the DhcpSetEnv() calls. + * + * NOTE2: this file supports DHCP and BOOTP. Most of the function names + * refer to DHCP even though their functionality is shared by both DHCP + * and BOOTP. This is because I wrote this originally for DHCP, then added + * the hooks for BOOTP... Bottom line: don't let the names confuse you! + * + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#include "endian.h" +#include "cpuio.h" +#include "ether.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "genlib.h" +#include "stddefs.h" +#include "cli.h" +#include "timer.h" + +int DHCPStartup(short), BOOTPStartup(short); +int DhcpSetEnv(char *,char *); +int SendDHCPDiscover(int,short); +void dhcpDumpVsa(void), printDhcpOptions(uchar *); + +unsigned short DHCPState; + +#if INCLUDE_DHCPBOOT + +static struct elapsed_tmr dhcpTmr; +static int DHCPCommandIssued; +static ulong DHCPTransactionId; + +/* Variables used for DHCP Class ID specification: */ +static char *DHCPClassId; +static int DHCPClassIdSize; + +/* Variables used for DHCP Client ID specification: */ +static char DHCPClientId[32]; +static int DHCPClientIdSize, DHCPClientIdType; + +/* Variables used for setting up a DHCP Parameter Request List: */ +static uchar DHCPRequestList[32]; +static int DHCPRqstListSize; + +/* Variable to keep track of elapsed seconds since DHCP started: */ +static short DHCPElapsedSecs; + +char *DhcpHelp[] = { + "Issue a DHCP discover", + "-[brvV] [vsa]", +#if INCLUDE_VERBOSEHELP + "Options...", + " -b use bootp", + " -r retry", + " -v|V verbosity", +#endif + 0, +}; + +int +Dhcp(int argc,char *argv[]) +{ + int opt, bootp; + + bootp = 0; + DHCPCommandIssued = 1; + while ((opt=getopt(argc,argv,"brvV")) != -1) { + switch(opt) { + case 'b': + bootp = 1; + break; + case 'r': + DHCPCommandIssued = 0; + break; +#if INCLUDE_ETHERVERBOSE + case 'v': + EtherVerbose = SHOW_DHCP; + break; + case 'V': + EtherVerbose = DHCP_VERBOSE; + break; +#endif + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc == optind+1) { + if (!strcmp(argv[optind],"vsa")) { + dhcpDumpVsa(); + return(CMD_SUCCESS); + } + else + return(CMD_PARAM_ERROR); + } + else if (argc != optind) + return(CMD_PARAM_ERROR); + + startElapsedTimer(&dhcpTmr,RetransmitDelay(DELAY_INIT_DHCP)*1000); + + if (bootp) { + DHCPState = BOOTPSTATE_INITIALIZE; + if (DHCPCommandIssued) + BOOTPStartup(0); + } + else { + DHCPState = DHCPSTATE_INITIALIZE; + if (DHCPCommandIssued) + DHCPStartup(0); + } + return(CMD_SUCCESS); +} + +/* dhcpDumpVsa(): + * Simply dump the content of the VSA shell variable in DHCP format. + * The variable content is stored in ascii and must be converted to binary + * prior to calling printDhcpOptions(). + */ +void +dhcpDumpVsa(void) +{ + int i; + char tmp[3], *vsa_b, *vsa_a, len; + + vsa_a = getenv("DHCPVSA"); + if ((!vsa_a) || (!strcmp(vsa_a,"TRUE"))) + return; + len = strlen(vsa_a); + vsa_b = malloc(len); + if (!vsa_b) + return; + + len >>= 1; + tmp[2] = 0; + for(i=0;i<len;i++) { + tmp[0] = *vsa_a++; + tmp[1] = *vsa_a++; + vsa_b[i] = (char)strtol(tmp,0,16); + } + /* First 4 bytes of DHCPVSA is the cookie, so skip over that. */ + printDhcpOptions((unsigned char *)vsa_b+4); + free(vsa_b); +} + +void +dhcpDisable() +{ + DHCPState = DHCPSTATE_NOTUSED; +} + +/* DHCPStartup(): + * This function is called at the point in which the ethernet interface is + * started if, and only if, the IPADD shell variable is set to DHCP. + * In older version of DHCP, the default was to use "LUCENT.PPA.1.1" as + * the default vcid. Now it is only used if specified in the shell variable + * DHCPCLASSID. The same strategy applies to DHCPCLIENTID. +*/ +int +DHCPStartup(short seconds) +{ + char *id, *colon, *rlist; + +#if !INCLUDE_TFTP + printf("WARNING: DHCP can't load bootfile, TFTP not built into monitor.\n"); +#endif + + /* The format of DHCPCLASSID is simply a string of characters. */ + id = getenv("DHCPCLASSID"); + if (id) + DHCPClassId = id; + else + DHCPClassId = ""; + DHCPClassIdSize = strlen(DHCPClassId); + + /* The format of DHCPCLIENTID is "TYPE:ClientID" where 'TYPE is a + * decimal number ranging from 1-255 used as the "type" portion of + * the option, and ClientID is a string of ascii-coded hex pairs + * that are converted to binary and used as the client identifier. + */ + id = getenv("DHCPCLIENTID"); + if (id) { + colon = strchr(id,':'); + if ((colon) && (!(strlen(colon+1) & 1))) { + DHCPClientIdType = atoi(id); + colon++; + for(DHCPClientIdSize=0;*colon;DHCPClientIdSize++) { + uchar tmp; + + tmp = colon[2]; + colon[2] = 0; + DHCPClientId[DHCPClientIdSize] = (uchar)strtol(colon,0,16); + colon[2] = tmp; + colon+=2; + } + } + } + else + DHCPClientIdSize = 0; + + /* The format of DHCPRQSTLIST is #:#:#:#:# where each '#' is a decimal + * number representing a parameter to be requested via the Parameter + * Request List option... + */ + rlist = getenv("DHCPRQSTLIST"); + if (rlist) { + DHCPRqstListSize = 0; + colon = rlist; + while(*colon) { + if (*colon++ == ':') + DHCPRqstListSize++; + } + if (DHCPRqstListSize > sizeof(DHCPRequestList)) { + printf("DHCPRQSTLIST too big.\n"); + DHCPRqstListSize = 0; + } + else { + char *rqst; + + DHCPRqstListSize = 0; + rqst = rlist; + while(1) { + DHCPRequestList[DHCPRqstListSize++] = strtol(rqst,&colon,0); + if (*colon != ':') + break; + rqst = colon+1; + } + DHCPRequestList[DHCPRqstListSize] = 0; + } + } + else + DHCPRqstListSize = 0; + + return(SendDHCPDiscover(0,seconds)); +} + +int +BOOTPStartup(short seconds) +{ + return(SendDHCPDiscover(1,seconds)); +} + +uchar * +dhcpLoadShellVarOpts(uchar *options) +{ + if (DHCPClassIdSize) { + *options++ = DHCPOPT_CLASSID; + *options++ = DHCPClassIdSize; + memcpy((char *)options, (char *)DHCPClassId, DHCPClassIdSize); + options += DHCPClassIdSize; + } + if (DHCPClientIdSize) { + *options++ = DHCPOPT_CLIENTID; + *options++ = DHCPClientIdSize+1; + *options++ = DHCPClientIdType; + memcpy((char *)options, (char *)DHCPClientId, DHCPClientIdSize); + options += DHCPClientIdSize; + } + if (DHCPRqstListSize) { + *options++ = DHCPOPT_PARMRQSTLIST; + *options++ = DHCPRqstListSize; + memcpy((char *)options, (char *)DHCPRequestList, DHCPRqstListSize); + options += DHCPRqstListSize; + } + return(options); +} + +/* SendDHCPDiscover() + * The DHCPDISCOVER is issued as an ethernet broadcast. IF the bootp + * flag is non-zero then just do a bootp request (a subset of the + * DHCPDISCOVER stuff). + */ +int +SendDHCPDiscover(int bootp,short seconds) +{ + struct dhcphdr *dhcpdata; + struct bootphdr *bootpdata; + struct ether_header *te; + struct ip *ti; + struct Udphdr *tu; + ushort uh_ulen; + int optlen; + char *dhcpflags; + ulong cookie; + uchar *dhcpOptions, *dhcpOptionsBase; + + /* Retrieve an ethernet buffer from the driver and populate the + * ethernet level of packet: + */ + te = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&te->ether_shost, (char *)BinEnetAddr,6); + memcpy((char *)&te->ether_dhost, (char *)BroadcastAddr,6); + te->ether_type = ecs(ETHERTYPE_IP); + + /* Move to the IP portion of the packet and populate it appropriately: */ + ti = (struct ip *) (te + 1); + ti->ip_vhl = IP_HDR_VER_LEN; + ti->ip_tos = 0; + ti->ip_id = 0; + ti->ip_off = ecs(0x4000); /* No fragmentation allowed */ + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memset((char *)&ti->ip_src.s_addr,0,4); + memset((char *)&ti->ip_dst.s_addr,0xff,4); + + /* Now udp... */ + tu = (struct Udphdr *) (ti + 1); + tu->uh_sport = ecs(DhcpClientPort); + tu->uh_dport = ecs(DhcpServerPort); + + /* First the stuff that is the same for BOOTP or DHCP... */ + bootpdata = (struct bootphdr *)(tu+1); + dhcpdata = (struct dhcphdr *)(tu+1); + dhcpdata->op = DHCPBOOTP_REQUEST; + dhcpdata->htype = 1; + dhcpdata->hlen = 6; + dhcpdata->hops = 0; + dhcpdata->seconds = ecs(seconds); + memset((char *)dhcpdata->bootfile,0,sizeof(dhcpdata->bootfile)); + memset((char *)dhcpdata->server_hostname,0,sizeof(dhcpdata->server_hostname)); + + /* For the first DHCPDISCOVER issued, establish a transaction id based + * on a crc32 of the mac address. For each DHCPDISCOVER after that, + * just increment. + */ + if (!DHCPTransactionId) + DHCPTransactionId = crc32(BinEnetAddr,6); + else + DHCPTransactionId++; + + memcpy((char *)&dhcpdata->transaction_id,(char *)&DHCPTransactionId,4); + memset((char *)&dhcpdata->client_ip,0,4); + memset((char *)&dhcpdata->your_ip,0,4); + memset((char *)&dhcpdata->server_ip,0,4); + memset((char *)&dhcpdata->router_ip,0,4); + memcpy((char *)dhcpdata->client_macaddr, (char *)BinEnetAddr,6); + dhcpflags = getenv("DHCPFLAGS"); + if (dhcpflags) /* 0x8000 is the only bit used currently. */ + dhcpdata->flags = (ushort)strtoul(dhcpflags,0,0); + else + dhcpdata->flags = 0; + + self_ecs(dhcpdata->flags); + + /* Finally, the DHCP or BOOTP specific stuff... + * Based on RFC1534 (Interoperation Between DHCP and BOOTP), any message + * received by a DHCP server that contains a 'DHCP_MESSAGETYPE' option + * is assumed to have been sent by a DHCP client. A message without the + * DHCP_MESSAGETYPE option is assumed to have been sent by a BOOTP + * client. + */ + uh_ulen = optlen = 0; + if (bootp) { + memset((char *)bootpdata->vsa,0,sizeof(bootpdata->vsa)); + uh_ulen = sizeof(struct Udphdr) + sizeof(struct bootphdr); + tu->uh_ulen = ecs(uh_ulen); + } + else { + if (!buildDhcpHdr(dhcpdata)) { + /* The cookie should only be loaded at the start of the + * vendor specific area if vendor-specific options are present. + */ + cookie = ecl(STANDARD_MAGIC_COOKIE); + memcpy((char *)&dhcpdata->magic_cookie,(char *)&cookie,4); + dhcpOptionsBase = (uchar *)(dhcpdata+1); + dhcpOptions = dhcpOptionsBase; + *dhcpOptions++ = DHCPOPT_MESSAGETYPE; + *dhcpOptions++ = 1; + *dhcpOptions++ = DHCPDISCOVER; + dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions); + *dhcpOptions++ = 0xff; + + /* Calculate ip and udp lengths after all DHCP options are loaded + * so that the size is easily computed based on the value of the + * dhcpOptions pointer. Apparently, the minimum size of the + * options space is 64 bytes, we determined this simply because + * the DHCP server we are using complains if the size is smaller. + * Also, NULL out the space that is added to get a minimum option + * size of 64 bytes, + */ + optlen = dhcpOptions - dhcpOptionsBase; + if (optlen < 64) { + memset((char *)dhcpOptions,0,64-optlen); + optlen = 64; + } + uh_ulen = sizeof(struct Udphdr)+sizeof(struct dhcphdr)+optlen; + tu->uh_ulen = ecs(uh_ulen); + } + } + ti->ip_len = ecs((sizeof(struct ip) + uh_ulen)); + + ipChksum(ti); /* Compute checksum of ip hdr */ + udpChksum(ti); /* Compute UDP checksum */ + + if (bootp) { + DHCPState = BOOTPSTATE_REQUEST; + sendBuffer(BOOTPSIZE); + } + else { + DHCPState = DHCPSTATE_SELECT; + sendBuffer(DHCPSIZE+optlen); + } +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_DHCP) + printf(" %s startup (%d elapsed secs)\n", + bootp ? "BOOTP" : "DHCP",seconds); +#endif + return(0); +} + +/* SendDHCPRequest() + * The DHCP request is broadcast back with the "server identifier" option + * set to indicate which server has been selected (in case more than one + * has offered). + */ +int +SendDHCPRequest(struct dhcphdr *dhdr) +{ + uchar *op; + struct dhcphdr *dhcpdata; + struct ether_header *te; + struct ip *ti; + struct Udphdr *tu; + int optlen; + uchar *dhcpOptions, *dhcpOptionsBase; + ushort uh_ulen; + ulong cookie; + + te = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&te->ether_shost, (char *)BinEnetAddr,6); + memcpy((char *)&te->ether_dhost, (char *)BroadcastAddr,6); + te->ether_type = ecs(ETHERTYPE_IP); + + ti = (struct ip *) (te + 1); + ti->ip_vhl = IP_HDR_VER_LEN; + ti->ip_tos = 0; + ti->ip_id = 0; + ti->ip_off = ecs(IP_DONTFRAG); /* No fragmentation allowed */ + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memset((char *)&ti->ip_src.s_addr,0,4); + memset((char *)&ti->ip_dst.s_addr,0xff,4); + + tu = (struct Udphdr *) (ti + 1); + tu->uh_sport = ecs(DhcpClientPort); + tu->uh_dport = ecs(DhcpServerPort); + + dhcpdata = (struct dhcphdr *)(tu+1); + dhcpdata->op = DHCPBOOTP_REQUEST; + dhcpdata->htype = 1; + dhcpdata->hlen = 6; + dhcpdata->hops = 0; + dhcpdata->seconds = ecs(DHCPElapsedSecs); + /* Use the same xid for the request as was used for the discover... + * (rfc2131 section 4.4.1) + */ + memcpy((char *)&dhcpdata->transaction_id,(char *)&dhdr->transaction_id,4); + + dhcpdata->flags = dhdr->flags; + memset((char *)&dhcpdata->client_ip,0,4); + memcpy((char *)&dhcpdata->your_ip,(char *)&dhdr->your_ip,4); + memset((char *)&dhcpdata->server_ip,0,4); + memset((char *)&dhcpdata->router_ip,0,4); + cookie = ecl(STANDARD_MAGIC_COOKIE); + memcpy((char *)&dhcpdata->magic_cookie,(char *)&cookie,4); + memcpy((char *)dhcpdata->client_macaddr, (char *)BinEnetAddr,6); + + dhcpOptionsBase = (uchar *)(dhcpdata+1); + dhcpOptions = dhcpOptionsBase; + *dhcpOptions++ = DHCPOPT_MESSAGETYPE; + *dhcpOptions++ = 1; + *dhcpOptions++ = DHCPREQUEST; + + *dhcpOptions++ = DHCPOPT_SERVERID; /* Server id ID */ + *dhcpOptions++ = 4; + op = DhcpGetOption(DHCPOPT_SERVERID,(uchar *)(dhdr+1)); + if (op) + memcpy((char *)dhcpOptions, (char *)op+2,4); + else + memset((char *)dhcpOptions, (char)0,4); + dhcpOptions+=4; + + *dhcpOptions++ = DHCPOPT_REQUESTEDIP; /* Requested IP */ + *dhcpOptions++ = 4; + memcpy((char *)dhcpOptions,(char *)&dhdr->your_ip,4); + dhcpOptions += 4; + dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions); + *dhcpOptions++ = 0xff; + + /* See note in SendDHCPDiscover() regarding the computation of the + * ip and udp lengths. + */ + optlen = dhcpOptions - dhcpOptionsBase; + if (optlen < 64) + optlen = 64; + uh_ulen = sizeof(struct Udphdr) + sizeof(struct dhcphdr) + optlen; + tu->uh_ulen = ecs(uh_ulen); + ti->ip_len = ecs((sizeof(struct ip) + uh_ulen)); + + ipChksum(ti); /* Compute checksum of ip hdr */ + udpChksum(ti); /* Compute UDP checksum */ + + DHCPState = DHCPSTATE_REQUEST; + sendBuffer(DHCPSIZE+optlen); + return(0); +} + +/* randomDhcpStartupDelay(): + * Randomize the startup for DHCP/BOOTP (see RFC2131 Sec 4.4.1)... + * Return a value between 1 and 10 based on the last 4 bits of the + * board's MAC address. + * The presence of the DHCPSTARTUPDELAY shell variable overrides + * this random value. + */ +int +randomDhcpStartupDelay(void) +{ + char *env; + int randomsec; + + env = getenv("DHCPSTARTUPDELAY"); + if (env) { + randomsec = (int)strtol(env,0,0); + } + else { + randomsec = (BinEnetAddr[5] & 0xf); + if (randomsec > 10) + randomsec -= 7; + else if (randomsec == 0) + randomsec = 10; + } + return(randomsec); +} + +/* dhcpStateCheck(): + * Called by pollethernet() to monitor the progress of DHCPState. + * The retry rate is "almost" what is specified in the RFC... + * Refer to the RetransmitDelay() function for details. + * + * Regarding timing... + * The DHCP startup may be running without an accurate measure of elapsed + * time. The value of LoopsPerMillisecond is used as an approximation of + * the number of times this function must be called for one second to + * pass (dependent on network traffic, etc...). RetransmitDelay() is + * called to retrieve the number of seconds that must elapse prior to + * retransmitting the last DHCP message. The static variables in this + * function are used to keep track of that timeout. + */ +void +dhcpStateCheck(void) +{ + int delaysecs; + + /* If the DHCP command has been issued, it is assumed that the script + * is handling retries... + */ + if (DHCPCommandIssued) + return; + + /* Return, restart or fall through; depending on DHCPState... */ + switch(DHCPState) { + case DHCPSTATE_NOTUSED: + case BOOTPSTATE_COMPLETE: + case DHCPSTATE_BOUND: + return; + case DHCPSTATE_RESTART: + DHCPStartup(0); + return; + case BOOTPSTATE_RESTART: + BOOTPStartup(0); + return; + case DHCPSTATE_INITIALIZE: + case BOOTPSTATE_INITIALIZE: + delaysecs = randomDhcpStartupDelay(); + startElapsedTimer(&dhcpTmr,delaysecs * 1000); +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_DHCP) + printf("\nDHCP/BOOTP %d sec startup delay...\n",delaysecs); +#endif + if (DHCPState & BOOTP_MODE) + DHCPState = BOOTPSTATE_INITDELAY; + else + DHCPState = DHCPSTATE_INITDELAY; + return; + case DHCPSTATE_INITDELAY: + case BOOTPSTATE_INITDELAY: + if (msecElapsed(&dhcpTmr) || (gotachar())) { + DHCPElapsedSecs = 0; + startElapsedTimer(&dhcpTmr, + RetransmitDelay(DELAY_INIT_DHCP)*1000); + if (DHCPState & BOOTP_MODE) + BOOTPStartup(0); + else + DHCPStartup(0); + } + return; + default: + break; + } + + if (msecElapsed(&dhcpTmr)) { + int lastdelay; + + lastdelay = RetransmitDelay(DELAY_RETURN); + delaysecs = RetransmitDelay(DELAY_INCREMENT); + + if (delaysecs != RETRANSMISSION_TIMEOUT) { + DHCPElapsedSecs += delaysecs; + startElapsedTimer(&dhcpTmr,delaysecs*1000); + + if (DHCPState & BOOTP_MODE) + BOOTPStartup(DHCPElapsedSecs); + else + DHCPStartup(DHCPElapsedSecs); +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_DHCP) + printf(" DHCP/BOOTP retry (%d secs)\n",lastdelay); +#endif + } + else { +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_DHCP) + printf(" DHCP/BOOTP giving up\n"); +#endif + } + } +} + +/* xidCheck(): + * Common function used for DHCP and BOOTP to verify incoming transaction + * id... + */ +int +xidCheck(char *id,int bootp) +{ + if (memcmp(id,(char *)&DHCPTransactionId,4)) { +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_DHCP) { + printf("%s ignored: unexpected transaction id.\n", + bootp ? "BOOTP":"DHCP"); + } +#endif + return(-1); + } + return(0); +} + +int +loadBootFile(int bootp) +{ +#if INCLUDE_TFTP + ulong addr; + char bfile[TFSNAMESIZE+TFSINFOSIZE+32]; + char *tfsfile, *bootfile, *tftpsrvr, *flags, *info; + + /* If the DHCPDONTBOOT variable is present, then don't put + * the file in TFS and don't run it. Just complete the TFTP + * transfer, and allow the user to deal with the downloaded + * data using APPRAMBASE and TFTPGET shell variables (probably + * through some boot script). + */ + if (getenv("DHCPDONTBOOT")) + tfsfile = (char *)0; + else + tfsfile = bfile; + + /* If both bootfile and server-ip are specified, then boot it. + * The name of the file must contain information that tells the monitor + * what type of file it is, so the first 'comma' extension is used as + * the flag field (if it is a valid flag set) and the second 'comma' + * extension is used as the info field. + */ + bootfile = getenv("BOOTFILE"); + tftpsrvr = getenv("BOOTSRVR"); + + if (bootfile && tftpsrvr) { + int tftpworked; + + addr = getAppRamStart(); + info = ""; + flags = "e"; + strncpy(bfile,bootfile,sizeof(bfile)); + + if (tfsfile) { + char *icomma, *fcomma; + + fcomma = strchr(bfile,','); + if (fcomma) { + icomma = strchr(fcomma+1,','); + if (icomma) { + *icomma = 0; + info = icomma+1; + } + *fcomma = 0; + if (tfsctrl(TFS_FATOB,(long)(fcomma+1),0) != 0) + flags = fcomma+1; + } + } + + /* Since we are about to transition to TFTP, match TFTP's + * verbosity to the verbosity currently set for DHCP... + */ +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_DHCP) + EtherVerbose |= SHOW_TFTP_STATE; +#endif + + /* If the TFTP transfer succeeds, attempt to run the boot file; + * if the TFTP transfer fails, then re-initialize the tftp state + * and set the DHCP state such that dhcpStateCheck() will + * cause the handshake to start over again... + */ + tftpworked = tftpGet(addr,tftpsrvr,"octet",bfile,tfsfile,flags,info); + if (tftpworked) { +#if INCLUDE_ETHERVERBOSE + EtherVerbose = 0; +#endif + if (tfsfile) { + int err; + char *argv[2]; + + argv[0] = bfile; + argv[1] = 0; + err = tfsrun(argv,0); + if (err != TFS_OKAY) + printf("DHCP-invoked tfsrun(%s) failed: %s\n", + bfile,tfserrmsg(err)); + } + } + else { + tftpInit(); + RetransmitDelay(DELAY_INIT_TFTP); +#if INCLUDE_ETHERVERBOSE + EtherVerbose &= ~SHOW_TFTP_STATE; +#endif + if (bootp) + DHCPState = BOOTPSTATE_RESTART; + else + DHCPState = DHCPSTATE_RESTART; + } + } +#if INCLUDE_ETHERVERBOSE + else + EtherVerbose &= ~(SHOW_DHCP|DHCP_VERBOSE); +#endif +#endif + return(0); +} + +/* processBOOTP(): + * A subset of processDHCP(). + * We get here from processDHCP, because it detects that the current + * value of DHCPState is BOOTPSTATE_REQUEST. + */ +int +processBOOTP(struct ether_header *ehdr,ushort size) +{ + struct ip *ihdr; + struct Udphdr *uhdr; + struct bootphdr *bhdr; + ulong ip, temp_ip, cookie; + uchar buf[16], *op; + +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_HEX) + printMem((uchar *)ehdr,size,EtherVerbose & SHOW_ASCII); +#endif + + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); + bhdr = (struct bootphdr *)(uhdr+1); + + /* Verify incoming transaction id matches the previous outgoing value: */ + if (xidCheck((char *)&bhdr->transaction_id,1) < 0) + return(-1); + + /* If bootfile is nonzero, store it into BOOTFILE shell var: */ + if (bhdr->bootfile[0]) + DhcpSetEnv("BOOTFILE", (char *)bhdr->bootfile); + + /* Assign IP "server_ip" to the BOOTSRVR shell var (if non-zero): */ + memcpy((char *)&temp_ip,(char *)&bhdr->server_ip,4); + if (temp_ip) + DhcpSetEnv("BOOTSRVR",(char *)IpToString(temp_ip,(char *)buf)); + + /* Assign IP "router_ip" to the RLYAGNT shell var (if non-zero): */ + memcpy((char *)&temp_ip,(char *)&bhdr->router_ip,4); + if (temp_ip) + DhcpSetEnv("RLYAGNT",(char *)IpToString(temp_ip,(char *)buf)); + + /* Assign IP address loaded in "your_ip" to the IPADD shell var: */ + memcpy((char *)BinIpAddr,(char *)&bhdr->your_ip,4); + memcpy((char *)&temp_ip,(char *)&bhdr->your_ip,4); + DhcpSetEnv("IPADD",(char *)IpToString(temp_ip,(char *)buf)); + + /* If STANDARD_MAGIC_COOKIE exists, then process options... */ + memcpy((char *)&cookie,(char *)bhdr->vsa,4); + if (cookie == ecl(STANDARD_MAGIC_COOKIE)) { + /* Assign subnet mask option to NETMASK shell var (if found): */ + op = DhcpGetOption(DHCPOPT_SUBNETMASK,&bhdr->vsa[4]); + if (op) { + memcpy((char *)&ip,(char *)op+2,4); + DhcpSetEnv("NETMASK",(char *)IpToString(ip,(char *)buf)); + } + /* Assign first router option to GIPADD shell var (if found): */ + /* (the router option can have multiple entries, and they are */ + /* supposed to be in order of preference, so use the first one) */ + op = DhcpGetOption(DHCPOPT_ROUTER,&bhdr->vsa[4]); + if (op) { + memcpy((char *)&ip, (char *)op+2,4); + DhcpSetEnv("GIPADD",(char *)IpToString(ip,(char *)buf)); + } + } + + DhcpBootpDone(1,(struct dhcphdr *)bhdr, + size - ((int)((int)&bhdr->vsa - (int)ehdr))); + + DHCPState = BOOTPSTATE_COMPLETE; + + /* Call loadBootFile() which will then kick off a tftp client + * transfer if both BOOTFILE and BOOTSRVR shell variables are + * loaded; otherwise, we are done. + */ + loadBootFile(1); + + return(0); +} + +int +processDHCP(struct ether_header *ehdr,ushort size) +{ + struct ip *ihdr; + struct Udphdr *uhdr; + struct dhcphdr *dhdr; + uchar buf[16], *op, msgtype; + ulong ip, temp_ip, leasetime; + + if (DHCPState == BOOTPSTATE_REQUEST) + return(processBOOTP(ehdr,size)); + +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_HEX) + printMem((uchar *)ehdr,size,EtherVerbose & SHOW_ASCII); +#endif + + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); + dhdr = (struct dhcphdr *)(uhdr+1); + + /* Verify incoming transaction id matches the previous outgoing value: */ + if (xidCheck((char *)&dhdr->transaction_id,0) < 0) + return(-1); + + op = DhcpGetOption(DHCPOPT_MESSAGETYPE,(uchar *)(dhdr+1)); + if (op) + msgtype = *(op+2); + else + msgtype = DHCPUNKNOWN; + + if ((DHCPState == DHCPSTATE_SELECT) && (msgtype == DHCPOFFER)) { + /* Target issued the DISCOVER, the incoming packet is the server's + * OFFER reply. The function "ValidDHCPOffer() will return + * non-zero if the request is to be sent. + */ + if (ValidDHCPOffer(dhdr)) + SendDHCPRequest(dhdr); +#if INCLUDE_ETHERVERBOSE + else if (EtherVerbose & SHOW_DHCP) { + char ip[4]; + memcpy(ip,(char *)&ihdr->ip_src,4); + printf(" DHCP offer from %d.%d.%d.%d ignored\n", + ip[0],ip[1],ip[2],ip[3]); + } +#endif + } + else if ((DHCPState == DHCPSTATE_REQUEST) && (msgtype == DHCPACK)) { + ulong cookie; + uchar ipsrc[4]; + + /* Target issued the REQUEST, the incoming packet is the server's + * ACK reply. We're done so load the environment now. + */ + memcpy((char *)ipsrc,(char *)&ihdr->ip_src,4); + shell_sprintf("DHCPOFFERFROM","%d.%d.%d.%d", + ipsrc[0],ipsrc[1],ipsrc[2],ipsrc[3]); + + /* If bootfile is nonzero, store it into BOOTFILE shell var: */ + if (dhdr->bootfile[0]) + DhcpSetEnv("BOOTFILE",(char *)dhdr->bootfile); + + /* Assign IP "server_ip" to the BOOTSRVR shell var (if non-zero): */ + memcpy((char *)&temp_ip,(char *)&dhdr->server_ip,4); + if (temp_ip) + DhcpSetEnv("BOOTSRVR",(char *)IpToString(temp_ip,(char *)buf)); + + /* Assign IP "router_ip" to the RLYAGNT shell var (if non-zero): */ + memcpy((char *)&temp_ip,(char *)&dhdr->router_ip,4); + if (temp_ip) + DhcpSetEnv("RLYAGNT",(char *)IpToString(temp_ip,(char *)buf)); + + /* Assign IP address loaded in "your_ip" to the IPADD shell var: */ + memcpy((char *)BinIpAddr,(char *)&dhdr->your_ip,4); + memcpy((char *)&temp_ip,(char *)&dhdr->your_ip,4); + DhcpSetEnv("IPADD",IpToString(temp_ip,(char *)buf)); + + op = DhcpGetOption(DHCPOPT_ROOTPATH,(uchar *)(dhdr+1)); + if (op) + DhcpSetEnv("ROOTPATH",(char *)op+2); + + /* If STANDARD_MAGIC_COOKIE exists, process options... */ + memcpy((char *)&cookie,(char *)&dhdr->magic_cookie,4); + if (cookie == ecl(STANDARD_MAGIC_COOKIE)) { + /* Assign subnet mask to NETMASK shell var (if found): */ + op = DhcpGetOption(DHCPOPT_SUBNETMASK,(uchar *)(dhdr+1)); + if (op) { + memcpy((char *)&ip,(char *)op+2,4); + DhcpSetEnv("NETMASK",(char *)IpToString(ip,(char *)buf)); + } + + /* Assign Hostname to HOSTNAME shell var (if found): */ + op = DhcpGetOption(DHCPOPT_HOSTNAME,(uchar *)(dhdr+1)); + if (op) { + char tmpnam[64]; + int optlen = *(op+1); + + if (optlen < sizeof(tmpnam)-1) { + memset(tmpnam,0,sizeof(tmpnam)); + memcpy(tmpnam,(char *)(op+2),optlen); + DhcpSetEnv("HOSTNAME",tmpnam); + } + } + + /* Assign gateway IP to GIPADD shell var (if found): + * (the router option can have multiple entries, and they are + * supposed to be in order of preference, so use the first one). + */ + op = DhcpGetOption(DHCPOPT_ROUTER,(uchar *)(dhdr+1)); + if (op) { + memcpy((char *)&ip,(char *)op+2,4); + DhcpSetEnv("GIPADD",(char *)IpToString(ip,(char *)buf)); + } + /* Process DHCPOPT_LEASETIME option as follows... + * If not set, assume infinite and clear DHCPLEASETIME shellvar. + * If set, then look for the presence of the DHCPLEASETIME shell + * variable and use it as a minimum. If the incoming value is + * >= what is in the shell variable, accept it and load the shell + * variable with this value. If incoming lease time is less than + * what is stored in DHCPLEASETIME, ignore the request. + * If DHCPLEASETIME is not set, then just load the incoming lease + * into the DHCPLEASETIME shell variable and accept the offer. + */ + op = DhcpGetOption(DHCPOPT_LEASETIME,(uchar *)(dhdr+1)); + if (op) { + memcpy((char *)&leasetime,(char *)op+2,4); + leasetime = ecl(leasetime); + if (getenv("DHCPLEASETIME")) { + ulong minleasetime; + minleasetime = strtol(getenv("DHCPLEASETIME"),0,0); + if (leasetime < minleasetime) { + printf("DHCP: incoming lease time 0x%lx too small.\n", + leasetime); + return(-1); + } + } + sprintf((char *)buf,"0x%lx",leasetime); + setenv("DHCPLEASETIME",(char *)buf); + } + else + setenv("DHCPLEASETIME",(char *)0); + } + + /* Check for vendor specific stuff... */ + DhcpVendorSpecific(dhdr); + + DhcpBootpDone(0,dhdr, + size - ((int)((int)&dhdr->magic_cookie - (int)ehdr))); + + DHCPState = DHCPSTATE_BOUND; + + /* Call loadBootFile() which will then kick off a tftp client + * transfer if both BOOTFILE and BOOTSRVR shell variables are + * loaded; otherwise, we are done. + */ + loadBootFile(0); + } + return(0); +} + +char * +DHCPop(int op) +{ + switch(op) { + case DHCPBOOTP_REQUEST: + return("REQUEST"); + case DHCPBOOTP_REPLY: + return("REPLY"); + default: + return("???"); + } +} + +char * +DHCPmsgtype(int msg) +{ + char *type; + + switch(msg) { + case DHCPDISCOVER: + type = "DISCOVER"; + break; + case DHCPOFFER: + type = "OFFER"; + break; + case DHCPREQUEST: + type = "REQUEST"; + break; + case DHCPDECLINE: + type = "DECLINE"; + break; + case DHCPACK: + type = "ACK"; + break; + case DHCPNACK: + type = "NACK"; + break; + case DHCPRELEASE: + type = "RELEASE"; + break; + case DHCPINFORM: + type = "INFORM"; + break; + case DHCPFORCERENEW: + type = "FORCERENEW"; + break; + case DHCPLEASEQUERY: + type = "LEASEQUERY"; + break; + case DHCPLEASEUNASSIGNED: + type = "LEASEUNASSIGNED"; + break; + case DHCPLEASEUNKNOWN: + type = "LEASEUNKNOWN"; + break; + case DHCPLEASEACTIVE: + type = "LEASEACTIVE"; + break; + default: + type = "???"; + break; + } + return(type); +} + +/* printDhcpOptions(): + * Verbosely display the DHCP options pointed to by the incoming + * options pointer. + */ +void +printDhcpOptions(uchar *options) +{ + int i, safety, opt, optlen; + + safety = 0; + while(*options != 0xff) { + if (safety++ > 10000) { + printf("Aborting, overflow likely\n"); + break; + } + opt = (int)*options++; + if (opt == 0) /* padding */ + continue; + printf(" option %3d: ",opt); + optlen = (int)*options++; + if (opt==DHCPOPT_MESSAGETYPE) { + printf("DHCP_%s",DHCPmsgtype(*options++)); + } + else if ((opt < DHCPOPT_HOSTNAME) || + (opt == DHCPOPT_BROADCASTADDRESS) || + (opt == DHCPOPT_REQUESTEDIP) || + (opt == DHCPOPT_SERVERID) || + (opt == DHCPOPT_NISSERVER)) { + for(i=0;i<optlen;i++) + printf("%d ",*options++); + } + else if ((opt == DHCPOPT_NISDOMAINNAME) || (opt == DHCPOPT_CLASSID)) { + for(i=0;i<optlen;i++) + printf("%c",*options++); + } + else if (opt == DHCPOPT_CLIENTID) { + printf("%d 0x",(int)*options++); + for(i=1;i<optlen;i++) + printf("%02x",*options++); + } + else { + printf("0x"); + for(i=0;i<optlen;i++) + printf("%02x",*options++); + } + printf("\n"); + } +} + +/* printDhcp(): + * Try to format the DHCP stuff... + */ +void +printDhcp(struct Udphdr *p) +{ + struct dhcphdr *d; + uchar *client_ip, *your_ip, *server_ip, *router_ip; + ulong cookie, xid; + + d = (struct dhcphdr *)(p+1); + + client_ip = (uchar *)&(d->client_ip); + your_ip = (uchar *)&(d->your_ip); + server_ip = (uchar *)&(d->server_ip); + router_ip = (uchar *)&(d->router_ip); + memcpy((char *)&xid,(char *)&d->transaction_id,4); + /* xid = ecl(xid) */ + + printf(" DHCP: sport dport ulen sum\n"); + printf(" %4d %4d %4d %4d\n", + ecs(p->uh_sport), ecs(p->uh_dport), ecs(p->uh_ulen),ecs(p->uh_sum)); + printf(" op = %s, htype = %d, hlen = %d, hops = %d\n", + DHCPop(d->op),d->htype,d->hlen,d->hops); + printf(" seconds = %d, flags = 0x%x, xid= 0x%lx\n", + ecs(d->seconds),ecs(d->flags),xid); + printf(" client_macaddr = %02x:%02x:%02x:%02x:%02x:%02x\n", + d->client_macaddr[0], d->client_macaddr[1], + d->client_macaddr[2], d->client_macaddr[3], + d->client_macaddr[4], d->client_macaddr[5]); + printf(" client_ip = %d.%d.%d.%d\n", + client_ip[0],client_ip[1],client_ip[2],client_ip[3]); + printf(" your_ip = %d.%d.%d.%d\n", + your_ip[0],your_ip[1],your_ip[2],your_ip[3]); + printf(" server_ip = %d.%d.%d.%d\n", + server_ip[0],server_ip[1],server_ip[2],server_ip[3]); + printf(" router_ip = %d.%d.%d.%d\n", + router_ip[0],router_ip[1],router_ip[2],router_ip[3]); + if (d->bootfile[0]) + printf(" bootfile: %s\n", d->bootfile); + if (d->server_hostname[0]) + printf(" server_hostname: %s\n", d->server_hostname); + + /* If STANDARD_MAGIC_COOKIE doesn't exist, then don't process options... */ + memcpy((char *)&cookie,(char *)&d->magic_cookie,4); + if (cookie != ecl(STANDARD_MAGIC_COOKIE)) + return; + + printDhcpOptions((uchar *)(d+1)); +} + +/* DhcpGetOption(): + * Based on the incoming option pointer and a specified option value, + * search through the options list for the value and return a pointer + * to that option. + */ +uchar * +DhcpGetOption(unsigned char optval,unsigned char *options) +{ + int safety; + + safety = 0; + while(*options != 0xff) { + if (safety++ > 1000) + break; + if (*options == 0) { /* Skip over padding. */ + options++; + continue; + } + if (*options == optval) + return(options); + options += ((*(options+1)) + 2); + } + return((uchar *)0); +} + +int +DhcpSetEnv(char *name,char *value) +{ +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_DHCP) + printf(" Dhcp/Bootp SetEnv: %s = %s\n",name,value); +#endif + return(setenv(name,value)); +} + +int +DhcpIPCheck(char *ipadd) +{ + char verbose; + + if (!memcmp(ipadd,"DHCP",4)) { + verbose = ipadd[4]; + DHCPState = DHCPSTATE_INITIALIZE; + } + else if (!memcmp(ipadd,"BOOTP",5)) { + verbose = ipadd[5]; + DHCPState = BOOTPSTATE_INITIALIZE; + } + else { + if (IpToBin(ipadd,BinIpAddr) < 0) { + verbose = 0; + DHCPState = BOOTPSTATE_INITIALIZE; + } + else { + DHCPState = DHCPSTATE_NOTUSED; + return(0); + } + } + + BinIpAddr[0] = 0; + BinIpAddr[1] = 0; + BinIpAddr[2] = 0; + BinIpAddr[3] = 0; +#if INCLUDE_ETHERVERBOSE + if (verbose == 'V') + EtherVerbose = DHCP_VERBOSE; + else if (verbose == 'v') + EtherVerbose = SHOW_DHCP; +#endif + return(0); +} + +char * +dhcpStringState(int state) +{ + switch(state) { + case DHCPSTATE_INITIALIZE: + return("DHCP_INITIALIZE"); + case DHCPSTATE_SELECT: + return("DHCP_SELECT"); + case DHCPSTATE_REQUEST: + return("DHCP_REQUEST"); + case DHCPSTATE_BOUND: + return("DHCP_BOUND"); + case DHCPSTATE_RENEW: + return("DHCP_RENEW"); + case DHCPSTATE_REBIND: + return("DHCP_REBIND"); + case DHCPSTATE_NOTUSED: + return("DHCP_NOTUSED"); + case DHCPSTATE_RESTART: + return("DHCP_RESTART"); + case BOOTPSTATE_INITIALIZE: + return("BOOTP_INITIALIZE"); + case BOOTPSTATE_REQUEST: + return("BOOTP_REQUEST"); + case BOOTPSTATE_RESTART: + return("BOOTP_RESTART"); + case BOOTPSTATE_COMPLETE: + return("BOOTP_COMPLETE"); + default: + return("???"); + } +} + +void +ShowDhcpStats() +{ + printf("Current DHCP State: %s\n",dhcpStringState(DHCPState)); +} + +#endif diff --git a/main/common/dns.c b/main/common/dns.c new file mode 100755 index 0000000..8947289 --- /dev/null +++ b/main/common/dns.c @@ -0,0 +1,760 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * dns.c: + * + * This file implements a basic DNS client and some form of a multicast-DNS + * reponder. The functionality provides the basic ability to retrieve an IP + * address from a domain name. + * Refer to RFC 1035 section 4.1 for the packet format. + * + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_DNS +#include "endian.h" +#include "genlib.h" +#include "stddefs.h" +#include "ether.h" +#include "cli.h" +#include "timer.h" + +const char mDNSIp[] = { 224, 0, 0, 251 }; +const char mDNSMac[] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfb }; + +char * dnsErrStr(int errno); + +short DnsPort; +static unsigned short dnsId; +static unsigned long dnsIP; +static char dnsErrno, dnsWaiting, dnsCacheInitialized; +static struct dnscache hostnames[MAX_CACHED_HOSTNAMES]; + +/* ip_to_bin... + * Essentially identical to IpToBin() in ethernet.c, but without + * the error message. + */ +int +ip_to_bin(char *ascii,uchar *binary) +{ + int i, digit; + char *acpy; + + acpy = ascii; + for(i=0;i<4;i++) { + digit = (int)strtol(acpy,&acpy,10); + if (((i != 3) && (*acpy++ != '.')) || + ((i == 3) && (*acpy != 0)) || + (digit < 0) || (digit > 255)) { + return(-1); + } + binary[i] = (uchar)digit; + } + return(0); +} + + +/* getHostAddr(): + * This function is a simplified version of gethostbyname(). + * Given a domain name, this function will first query a + * locally maintained cache then, if not found there, it will + * issue a DNS query to retrieve the hosts IP address. + */ +unsigned long +getHostAddr(char *hostname) +{ + short port; + struct ip *ipp; + struct Udphdr *udpp; + struct dnshdr *dnsp; + struct elapsed_tmr tmr; + struct ether_header *enetp; + uchar binenet[8], *enetaddr; + unsigned long srvrip, binip; + char *pp, *np, *srvrname, *dot; + int i, namelen, pktsize, ip_len; + + /* First check to see if the incoming host name is simply a + * decimal-dot-formatted IP address. If it is, then just + * convert it to a 32-bit long and return here... + */ + if (ip_to_bin(hostname,(uchar *)&binip) == 0) + return(binip); + + if (!dnsCacheInitialized) + dnsCacheInit(); + + dnsErrno = DNSERR_NULL; + + /* First try to find the hostname in our local cache... + */ + for(i=0;i<MAX_CACHED_HOSTNAMES;i++) { + if (strcmp(hostnames[i].name,hostname) == 0) + return(hostnames[i].addr); + } + + /* If not in the cache, we query the network. First look + * for a DNSSRVR defined in the environment. If found, use + * it; else, use IP broadcast. + */ + + /* See if this is a mDNS request... + */ + if (strstr(hostname,".local")) { + DnsPort = port = DNSMCAST_PORT; + srvrip = htonl(DNSMCAST_IP); + memcpy((char *)binenet,(char *)mDNSMac,sizeof(mDNSMac)); + enetaddr = binenet; + } + else { + port = IPPORT_DNS; + DnsPort = port+1; + srvrname = getenv("DNSSRVR"); + if (srvrname == (char *)0) + srvrip = 0xffffffff; + else { + if (IpToBin(srvrname,(uchar *)&srvrip) < 0) + return(0); + } + + /* Get the ethernet address for the IP: + */ + enetaddr = ArpEther((uchar *)&srvrip,binenet,0); + if (!enetaddr) { + printf("ARP failed for 0x%x\n",srvrip); + return(0); + } + } + + /* Retrieve an ethernet buffer from the driver and populate the + * ethernet level of packet: + */ + enetp = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&enetp->ether_shost,(char *)BinEnetAddr,6); + memcpy((char *)&enetp->ether_dhost,(char *)binenet,6); + enetp->ether_type = htons(ETHERTYPE_IP); + + /* Move to the IP portion of the packet and populate it + * appropriately: + */ + ipp = (struct ip *) (enetp + 1); + ipp->ip_vhl = IP_HDR_VER_LEN; + ipp->ip_tos = 0; + ipp->ip_id = ipId(); + ipp->ip_off = 0; + ipp->ip_ttl = UDP_TTL; + ipp->ip_p = IP_UDP; + memcpy((char *)&ipp->ip_src.s_addr,(char *)BinIpAddr,4); + memcpy((char *)&ipp->ip_dst.s_addr,(char *)&srvrip,4); + + /* Now UDP... + */ + udpp = (struct Udphdr *) (ipp + 1); + udpp->uh_sport = htons(DnsPort); + udpp->uh_dport = htons(port); + + /* Finally, the DNS data ... + */ + dnsp = (struct dnshdr *)(udpp+1); + + /* Build the message. This query supports a single internet + * host-address question. + * + * Fixed header... + */ + dnsId = ipId(); + dnsp->id = htons(dnsId); /* Unique id */ + dnsp->param = 0; /* Parameter field */ + dnsp->num_questions = htons(1); /* # of questions */ + dnsp->num_answers = 0; /* # of answers */ + dnsp->num_authority = 0; /* # of authority */ + dnsp->num_additional = 0; /* # of additional */ + + /* The formatted name list.. + * Each name is preceded by a single-byte length, so for our + * query, the list is "LNNNLNNNLNNN0", where... + * 'L' is the single-byte length of the name. + * 'NN..N' is variable-lenght domain. + * '0' is the length of the next name in the list; hence, + * indicating the end of the list. + * + * For each '.' (dot) in the hostname, there is a + * LNNN pair. + */ + pp = (char *)dnsp->question; + np = (char *)hostname; + namelen = strlen(hostname); + do { + dot = strchr(np,'.'); + if (dot) { + *pp++ = dot-np; + memcpy(pp,np,dot-np); + pp += (dot-np); + np = dot + 1; + } + else { + *pp++ = strlen(np); + strcpy(pp,np); + } + } while(dot); + + + /* Since the size of the name can be arbitrary (not aligned), + * we must populate the TYPE and CLASS fields one byte at + * a time... + */ + pp += (strlen(np) + 1); + *pp++ = 0; + *pp++ = 1; /* type = 'A' (host address) */ + *pp++ = 0; + *pp = 1; /* class = 'IN' (the internet) */ + + /* Send the DNS query: + * Total message size is... + * FIXED_HDR_SIZE + NAME_SIZE + TYPE_SIZE + CLASS_SIZE + (NAMELEN_SIZE*2) + * where... + * FIXED_HDR_SIZE = 12 + * NAME_SIZE = strlen(hostname) = namelen + * TYPE_SIZE = sizeof(short) = 2 + * CLASS_SIZE = sizeof(short) = 2 + * NAMELEN_SIZE = sizeof(char) = 1 + * + * There are 2 name lengths. The first one is the size of the host + * name we are querying for and the second one is zero (indicating no + * more names in the list). + * So, the total length of the packet is <namelen + 18>. + */ + + pktsize = namelen+18; + ip_len = sizeof(struct ip) + sizeof(struct Udphdr) + pktsize; + ipp->ip_len = htons(ip_len); + udpp->uh_ulen = htons((ushort)(ip_len - sizeof(struct ip))); + + ipChksum(ipp); /* Compute csum of ip hdr */ + udpChksum(ipp); /* Compute UDP checksum */ + +// printf("Sending DNS rqst id=%04x (%d %d)\n",dnsId,pktsize,ip_len); + + dnsWaiting = 1; + sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + pktsize); + + /* Wait for 3 seconds for a response... + */ + startElapsedTimer(&tmr,3000); + while(!msecElapsed(&tmr)) { + if (dnsErrno != DNSERR_NULL) + break; + pollethernet(); + } + if (dnsErrno == DNSERR_COMPLETE) { + dnsCacheAdd(hostname,dnsIP); + shell_sprintf("DNSIP","%d.%d.%d.%d", + IP1(dnsIP),IP2(dnsIP),IP3(dnsIP), IP4(dnsIP)); + return(dnsIP); + } + else { + if (dnsErrno == DNSERR_NULL) + printf("DNS attempt timeout\n"); + else + printf("DNSErr: %s\n",dnsErrStr((int)dnsErrno)); + setenv("DNSIP",0); + } + return(0); +} + +/* Note two different processDNS/processMCASTDNS functions... + * processDNS() provides the necessary code to deal with responses + * that we should expect to get as a result of issuing a dns request. + * processMCASTDNS() provides the necessary code to deal with requests + * from other machines querying for our hostname/ip info. + */ + +/* processDNS(): + * This function provides the recieving half of the DNS query above. + */ +int +processDNS(struct ether_header *ehdr,ushort size) +{ + int i; + char *pp; + struct ip *ihdr; + struct Udphdr *uhdr; + struct dnshdr *dhdr; + unsigned short rtype, qtot, atot; + + if (dnsWaiting == 0) + return(0); + + dnsWaiting = 0; + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); + dhdr = (struct dnshdr *)(uhdr + 1); + +// printf("DNS: (%d)\n",size); +// printf(" dnsid: %04x\n",htons(dhdr->id)); +// printf(" param: %04x\n",htons(dhdr->param)); +// printf(" quest: %04x\n",htons(dhdr->num_questions)); +// printf(" answe: %04x\n",htons(dhdr->num_answers)); +// printf(" autho: %04x\n",htons(dhdr->num_authority)); +// printf(" addit: %04x\n",htons(dhdr->num_additional)); +// printMem(dhdr->question, size - UDPSIZE - IPSIZE - ETHERSIZE - 12,1); + + /* Verify the DNS response... + */ + if ((htons(dhdr->param) & 0x8000) == 0) { /* response? */ + dnsErrno = DNSERR_NOTARESPONSE; + return(0); + } + if (htons(dhdr->id) != dnsId) { /* correct id? */ + dnsErrno = DNSERR_BADRESPID; + return(0); + } + if ((rtype = (htons(dhdr->param) & 0xf)) != 0) { /* response normal? */ + switch(rtype) { + case 1: + dnsErrno = DNSERR_FORMATERR; + break; + case 2: + dnsErrno = DNSERR_SRVRFAILURE; + break; + case 3: + dnsErrno = DNSERR_NAMENOEXIST; + break; + default: + dnsErrno = DNSERR_BADRESPTYPE; + break; + } + return(0); + } + qtot = htons(dhdr->num_questions); + if ((atot = htons(dhdr->num_answers)) < 1) { /* answer count >= 1? */ + dnsErrno = DNSERR_BADANSWRCOUNT; + return(0); + } + + /* At this point we can assume that the received packet format + * is ok. Now we need to parse the packet for the "answer" to + * our query... + */ + + /* Set 'pp' to point to the start of the question list. + * There should only be one question in the response. + */ + pp = (char *)&dhdr->question; + + /* Skip over the questions: + */ + for(i=0;i<qtot;i++) { + while(*pp) /* while 'L' is nonzero */ + pp += (*pp + 1); + pp += 5; /* Account for last 'L' plus TYPE/CLASS */ + } + + /* The 'pp' pointer is now pointing a list of resource records that + * correspond to the answer list. It is from this list that we + * must retrieve the information we are looking for... + */ + + for(i=0;i<atot;i++) { + unsigned short type, len; + + /* The first portion of the record is the resource domain name + * and it may be literal string (a 1-octet count followed by + * characters that make up the name) or a pointer to a literal + * string. + */ + if ((*pp & 0xc0) == 0xc0) { /* compressed? (section 4.1.4 RFC1035) */ + pp += 2; + } + else { + while(*pp) /* while 'L' is nonzero */ + pp += (*pp + 1); + pp += 1; + } + memcpy((char *)&type,pp,2); + type = htons(type); + pp += 8; + memcpy((char *)&len,pp,2); + len = htons(len); + if ((type == TYPE_A) && (len == 4)) { + pp += 2; + memcpy((char *)&dnsIP,pp,4); + dnsIP = htonl(dnsIP); + } + else + pp += (len+2); + } + dnsErrno = DNSERR_COMPLETE; + return(0); +} + +/* processMCASTDNS(): + * If we're here, then we've received a request over the Multi-cast + * DNS address for some host name. If the hostname in this request + * matches this board's hostname, then return this board's IP address. + * If the shell variable HOSTNAME isn't set, then just return immediately. + */ +int +processMCASTDNS(struct ether_header *ehdr,ushort size) +{ + int l1, ql = 0; + struct ip *ihdr; + char *pp, *myname; + struct Udphdr *uhdr; + struct dnshdr *dhdr; + + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)(ihdr + 1); + dhdr = (struct dnshdr *)(uhdr + 1); + + // If this message is DNS response, branch to processDNS()... + if ((htons(dhdr->param) & 0x8000) == 0x8000) { + processDNS(ehdr,size); + return(0); + } + + if ((myname = getenv("HOSTNAME")) == 0) + return(0); + + // If this isn't a normal query type, return... + if ((htons(dhdr->param) & 0xf) != 0) + return(0); + + // If there isn't exactly 1 question, return... + if (htons(dhdr->num_questions) != 1) + return(0); + + /* At this point we can assume that the received packet format + * is ok. Now we need to parse the packet for the "question"... + */ + + /* Set 'pp' to point to the start of the question list. + */ + pp = (char *)dhdr->question; + l1 = *pp; + while(*pp) { + ql += *pp; + ql++; + pp += (*pp + 1); + } + + /* If the name in the question matches our hostname, then send a + * reply... + * + * Referring to top of pg 20 of the document + * http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt... + * + * Multicast DNS responses MUST be sent to UDP port 5353 on the + * 224.0.0.251 multicast address. + */ + if ((l1 == strlen(myname)) && + (memcmp(myname,(char *)&dhdr->question[1],l1) == 0)) { + struct ip *ti, *ri; + struct Udphdr *tu, *ru; + struct ether_header *te; + struct dnshdr *td; + short type, class; + long ttl; + struct elapsed_tmr tmr; + + te = EtherCopy(ehdr); + ti = (struct ip *) (te + 1); + ri = (struct ip *) (ehdr + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ti->ip_id = ri->ip_id; + ti->ip_off = ri->ip_off; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)mDNSIp, + sizeof(struct in_addr)); + + tu = (struct Udphdr *) (ti + 1); + ru = (struct Udphdr *) (ri + 1); + tu->uh_sport = ru->uh_dport; + tu->uh_dport = htons(DNSMCAST_PORT); + + td = (struct dnshdr *)(tu+1); + + /* Flags: */ + td->id = dhdr->id; + td->param = htons(0x8400); + td->num_questions = 0; + td->num_answers = htons(1); + td->num_authority = 0; + td->num_additional = 0; + + /* Answers: */ + pp = (char *)td->question; + memcpy(pp,(char *)dhdr->question,ql+1); + pp += (ql+1); + + type = htons(TYPE_A); + memcpy(pp,(char *)&type,2); + pp += 2; + + class = htons(CLASS_IN); + memcpy(pp,(char *)&class,2); + pp += 2; + + ttl = htonl(900); + memcpy(pp,(char *)&ttl,4); + pp += 4; + + *pp++ = 0; /* 2-byte length of address */ + *pp++ = 4; + memcpy(pp,(char *)BinIpAddr,4); + + tu->uh_ulen = ecs((UDPSIZE + 27 + ql)); + ti->ip_len = ecs((UDPSIZE + 27 + ql + sizeof(struct ip))); + + ipChksum(ti); /* Compute checksum of ip hdr */ + udpChksum(ti); /* Compute UDP checksum */ + + /* Delay for some random time between 20-120msec... + */ + startElapsedTimer(&tmr,20 + (BinEnetAddr[5] & 0x3f)); + while(!msecElapsed(&tmr)); + + sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + 27 + ql); + } + return(0); +} + +/* DNS Cache utilities: + */ +void +dnsCacheInit(void) +{ + int i; + + for(i=0;i<MAX_CACHED_HOSTNAMES;i++) { + hostnames[i].idx = 0; + hostnames[i].addr = 0; + hostnames[i].name[0] = 0; + } + dnsCacheInitialized = 1; +} + +int +dnsCacheDump(void) +{ + int i, tot; + struct dnscache *hnp; + + tot = 0; + hnp = hostnames; + for(i=0;i<MAX_CACHED_HOSTNAMES;i++,hnp++) { + if (hnp->addr) { + printf("%3d %30s: %d.%d.%d.%d\n",hnp->idx,hnp->name, IP1(hnp->addr), + IP2(hnp->addr), IP3(hnp->addr), IP4(hnp->addr)); + tot++; + } + } + return(tot); +} + +int +dnsCacheAdd(char *name, unsigned long inaddr) +{ + int i, li, lowest; + struct dnscache *hnp; + static int idx = 0; + + if (!dnsCacheInitialized) + dnsCacheInit(); + + /* Validate incoming name size: + */ + if ((strlen(name) >= MAX_HOSTNAME_SIZE) || (inaddr == 0)) + return(-1); + + lowest = 0x70000000; + + /* First look for an empty slot... + */ + hnp = hostnames; + li = MAX_CACHED_HOSTNAMES; + for(i=0;i<MAX_CACHED_HOSTNAMES;i++,hnp++) { + if (hnp->addr == 0) { + strcpy(hnp->name,name); + hnp->addr = inaddr; + hnp->idx = idx++; + return(1); + } + else { + if (hnp->idx < lowest) { + lowest = hnp->idx; + li = i; + } + } + } + + if (i == MAX_CACHED_HOSTNAMES) + return(-1); + + /* If all slots are filled, use the slot that had the + * the lowest idx value (this would be the oldest entry)... + */ + hnp = &hostnames[li]; + strcpy(hnp->name,name); + hnp->addr = inaddr; + hnp->idx = idx++; + return(1); +} + +int +dnsCacheDelAddr(unsigned long addr) +{ + int i; + + if (!dnsCacheInitialized) { + dnsCacheInit(); + return(0); + } + + for(i=0;i<MAX_CACHED_HOSTNAMES;i++) { + if (hostnames[i].addr == addr) { + hostnames[i].name[0] = 0; + hostnames[i].addr = 0; + return(1); + } + } + return(0); +} + +int +dnsCacheDelName(char *name) +{ + int i; + + if (!dnsCacheInitialized) { + dnsCacheInit(); + return(0); + } + + for(i=0;i<MAX_CACHED_HOSTNAMES;i++) { + if (strcmp(hostnames[i].name,name) == 0) { + hostnames[i].name[0] = 0; + hostnames[i].addr = 0; + return(1); + } + } + return(0); +} + +struct dnserr dnsErrTbl[] = { + { DNSERR_NOSRVR, "no dns server" }, + { DNSERR_SOCKETFAIL, "socket fail" }, + { DNSERR_FORMATERR, "format error" }, + { DNSERR_SRVRFAILURE, "server error" }, + { DNSERR_NAMENOEXIST, "no name exists" }, + { DNSERR_BADRESPTYPE, "bad dns server response" }, + { DNSERR_BADQSTNCOUNT, "bad question count" }, + { DNSERR_BADANSWRCOUNT, "bad answer count" }, + { DNSERR_NOTARESPONSE, "replay not a dns response" }, + { DNSERR_BADRESPID, "bad dns response id" }, + + /* Must be last entry in table: */ + { DNSERR_NULL, "no error" } +}; + +char * +dnsErrStr(int errno) +{ + struct dnserr *dep; + + dep = dnsErrTbl; + while(dep->errno != DNSERR_NULL) { + if (dep->errno == errno) + return(dep->errstr); + dep++; + } + return("invalid dns errno"); +} + +char *DnsHelp[] = { + "DNS Client", + "{hostname} | {cmd args}", + " Valid cmd values:", + " add {name} {ip}", + " cache {dump | init}", + " mdns {on | off}", + " del {name}", + 0, +}; + +int +DnsCmd(int argc, char *argv[]) +{ + unsigned long addr; + + if (argc == 2) { + if ((addr = getHostAddr(argv[1])) != 0) { + printf("%s: %d.%d.%d.%d\n",argv[1], + IP1(dnsIP),IP2(dnsIP),IP3(dnsIP), IP4(dnsIP)); + } + } + else if (argc == 3) { + if (strcmp(argv[1],"cache") == 0) { + if (strcmp(argv[2],"dump") == 0) + dnsCacheDump(); + else if (strcmp(argv[2],"init") == 0) + dnsCacheInit(); + else + return(CMD_PARAM_ERROR); + } + else if (strcmp(argv[1],"mdns") == 0) { + extern void enableMulticastReception(void); + extern void disableMulticastReception(void); + + if (strcmp(argv[2],"on") == 0) + enableMulticastReception(); + else if (strcmp(argv[2],"off") == 0) + disableMulticastReception(); + else + return(CMD_PARAM_ERROR); + } + else if (strcmp(argv[1],"del") == 0) { + dnsCacheDelName(argv[2]); + } + else + return(CMD_PARAM_ERROR); + } + else if (argc == 4) { + if (strcmp(argv[1],"add") == 0) { + if (IpToBin(argv[3],(uchar *)&addr) < 0) + return(CMD_FAILURE); + dnsCacheAdd(argv[2],addr); + } + else + return(CMD_PARAM_ERROR); + } + else + return(CMD_PARAM_ERROR); + + return(CMD_SUCCESS); +} + +#endif diff --git a/main/common/docmd.c b/main/common/docmd.c new file mode 100644 index 0000000..49a2190 --- /dev/null +++ b/main/common/docmd.c @@ -0,0 +1,940 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * docmd: + * This code supports the command line interface (CLI) portion of the + * monitor. It is a table-driven CLI that uses the table in cmdtbl.c. + * A limited amount of "shell-like" capabilities are supported... + * shell variables, symbol-table lookup, command history, + * command line editiing, command output redirection, etc... + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "ether.h" +#include "cli.h" +#include "term.h" +#include <ctype.h> + +const char *__ctype_ptr; +const char *__ctype_ptr__; + +/* appCmdlist: + * This is a pointer to a list of commands that can be added to the + * monitor's list by the application using addcommand(). + */ +struct monCommand *appCmdlist; +char *appcmdUlvl; + +extern struct monCommand cmdlist[]; +extern char cmdUlvl[]; + +void +showusage(struct monCommand *cmdptr) +{ + char *usage; + + usage = cmdptr->helptxt[1]; + printf("Usage: %s %s\n", + cmdptr->name,*usage ? usage : "(no args/opts)"); +} + +void +paramerr(struct monCommand *cmdptr) +{ + printf("Command parameter error...\n"); + showusage(cmdptr); +} + +int +addcommand(struct monCommand *cmdlist, char *cmdlvl) +{ + appCmdlist = cmdlist; +#if INCLUDE_USRLVL + appcmdUlvl = cmdlvl; +#endif + return(0); +} + +#if INCLUDE_SHELLVARS + +char * +shellsym_chk(char type, char *string,int *size,char *buf,int bufsize) +{ + char *p1, *p2, varname[CMDLINESIZE], *val; + + p1 = string; + p2 = varname; + /* If incoming check is for a symbol, we apply a somewhat more + * flexible syntax check for the symbol name... + */ + if (type == '%') { + while(*p1 && (*p1 != '}') && (*p1 != ' ') && (*p1 != '\t')) + *p2++ = *p1++; + } + else { + while(1) { + if (((*p1 >= '0') && (*p1 <= '9')) || + ((*p1 >= 'a') && (*p1 <= 'z')) || + ((*p1 >= 'A') && (*p1 <= 'Z')) || + (*p1 == '_')) { + *p2++ = *p1++; + } + else + break; + } + } + *p2 = '\0'; + + if (type == '%') + val = getsym(varname,buf,bufsize); + else + val = getenv(varname); + + if ((val) && (size)) + *size = strlen(varname); + + return(val); +} + +/* braceimbalance(): + * Return non-zero (the index into the src string at the point of the + * imbalance) if the incoming string does not have a balanced set + * of braces; else return 0. + */ +static int +braceimbalance(char *src, int *idx, int *ndp) +{ + int bnest; + char *base; + + bnest = 0; + base = src; + while((*src) && (bnest >= 0)) { + if (((*src == '$') || (*src == '%')) && (*(src+1) == '{')) { + bnest++; + src++; + } + else if (*src == '}') { + if (bnest) + bnest--; + } + else if (*src == '{') { + *ndp += 1; /* Indicate that there is a brace with no '$' prefix */ + } + else if (*src == '\\') { + if ((*(src+1) == '$') || (*(src+1) == '%') || + (*(src+1) == '\\') || + (*(src+1) == '{') || (*(src+1) == '}')) { + src++; + } + } + src++; + } + + /* If there is a '{}' mismatch, bnest will be non-zero... */ + *idx = src - base - 1; + return(bnest); +} + +/* processprefixes(): + * Process the '$' for shell variables and '%' for symbols. + * Look for the last '$' (or '%') in the incoming string and attempt to + * make a shell variable (or symbol) substitution. Return 0 if no '$' + * (or '%') is found. Note that '$' and '%' are processed interchangeably + * to support symbols and shell variables in the same way. + */ +static int +processprefixes(char *src) +{ + int namesize, srclen; + char *varname, *value; + char buf[CMDLINESIZE], buf1[CMDLINESIZE]; + + + srclen = strlen(src); + + while(*src) { + if (((*src == '$') || (*src == '%')) && (*(src-1) != '\\')) { + varname = src+1; + value = shellsym_chk(*src,varname,&namesize,buf1,sizeof(buf1)); + if (value) { + if (((srclen - namesize) + strlen(value)) >= CMDLINESIZE) { + printf("Cmd line expansion overflow\n"); + return(-1); + } + if ((*value == '$') && + (strncmp(value+1,varname,strlen(value+1)) == 0)) + return(0); + strcpy(buf,varname+namesize); + sprintf(varname-1,"%s%s",value,buf); + return(1); + } + } + src++; + } + return(0); +} + +/* processbraces(): + * Look into the incoming string for the deepest set of braces and + * substitute that with the value stored in the corresponding shell + * variable. Return 1 if a set of braces was processed; else 0 indicating + * that all braces have been processed. Return -1 if there is some kind + * of processing error (buffer overflow). + */ +static int +processbraces(char *src) +{ + int namesize, srclen, result, opentot; + char *cp1, *cp2, *varname, *value, type; + char buf[CMDLINESIZE], buf1[CMDLINESIZE], buf2[CMDLINESIZE]; + + type = 0; + opentot = 0; + varname = src; + srclen = strlen(src); + + while(*src) { + if (((*src == '$') || (*src == '%')) && (*(src+1) == '{')) { + opentot++; + type = *src; + varname = src+2; + src++; + } + else if ((*src == '}') && (opentot)) { + cp1 = varname; + cp2 = buf1; + while(cp1 < src) + *cp2++ = *cp1++; + *cp2 = 0; + while((result = processprefixes(buf1)) == 1); + if (result == -1) + return(-1); + + strcpy(buf,src); + sprintf(varname,"%s%s",buf1,buf); + value = shellsym_chk(type,varname,&namesize,buf2,sizeof(buf2)); + /* If the shellvar or symbol exists, replace it; else remove it. */ + if (value) { + if (((srclen-(namesize+3))+strlen(value)+1) > CMDLINESIZE) { + printf("Cmd line expansion overflow\n"); + return(-1); + } + strcpy(buf1,varname+namesize+1); + sprintf(varname-2,"%s%s",value,buf1); + } + else { + strcpy(varname-2,src+1); + } + return(1); + } + else if (*src == '\\') { + if ((*(src+1) == '$') || (*(src+1) == '%') || + (*(src+1) == '\\') || + (*(src+1) == '{') || (*(src+1) == '}')) { + src++; + } + } + else if ((isspace(*src)) && (opentot)) { + printf("Cmd line expansion error\n"); + return(-1); + } + src++; + } + return(0); +} + +/* expandshellvars(): + * Passed a string that is to be expanded with all shell variables converted. + * This function supports variables of type $VARNAME and ${VARNAME}. + * It also allows variables to be embedded within variables. For example... + * ${VAR${NAME}} will be a 2-pass expansion in which ${NAME} is evaluated + * and then ${VARXXX} (where XXX is whatever was in variable NAME) is + * processed. + */ +static int +expandshellvars(char *newstring) +{ + char *cp; + int result, cno, ndp; + + /* Verify that there is a balanced set of braces in the incoming + * string... + */ + ndp = 0; + if (braceimbalance(newstring,&cno,&ndp)) { + printf("Brace imbalance @ %d%s.\n", + cno,ndp ? " ({ missing $ or %)" : ""); + return(-1); + } + + /* Process the variable names within braces... */ + while((result = processbraces(newstring)) == 1); + if (result == -1) + return(-1); + + /* Process dollar signs (left-most first)... */ + while((result = processprefixes(newstring)) == 1); + if (result == -1) + return(-1); + + /* Cleanup any remaining "\{", "\}" or "\$" strings... */ + cp = newstring+1; + while(*cp) { + if (*cp == '{' || *cp == '}' || *cp == '$' || *cp == '%') { + if (*(cp-1) == '\\') { + strcpy(cp-1,cp); + cp -= 2; + } + } + cp++; + } + return(0); +} +#else +static int +expandshellvars(char *newstring) +{ + return(0); +} +#endif + + +/* tokenize(): + * Take the incoming string and create an argv[] array from that. The + * incoming string is assumed to be writeable. The argv[] array is simple + * a set of pointers into that string, where the whitespace delimited + * character sets are each NULL terminated. + */ +int +tokenize(char *string,char *argv[]) +{ + int argc, done; + + /* Null out the incoming argv array. */ + for(argc=0;argc<ARGCNT;argc++) + argv[argc] = (char *)0; + + argc = 0; + while(1) { + while ((*string == ' ') || (*string == '\t')) + string++; + if (*string == 0) + break; + argv[argc] = string; + while ((*string != ' ') && (*string != '\t')) { + if ((*string == '\\') && (*(string+1) == '"')) { + strcpy(string,string+1); + } + else if (*string == '"') { + strcpy(string,string+1); + while(*string != '"') { + if ((*string == '\\') && (*(string+1) == '"')) + strcpy(string,string+1); + if (*string == 0) + return(-1); + string++; + } + strcpy(string,string+1); + continue; + } + if (*string == 0) + break; + string++; + } + if (*string == 0) + done = 1; + else { + done = 0; + *string++ = 0; + } + argc++; + if (done) + break; + if (argc >= ARGCNT) { + argc = -1; + break; + } + } + return(argc); +} + +/* showhelp(): + * Called by Help() when it is time to print out some verbosity level of + * a command's help text. + * if... + * verbose == 2, then print all the help text; + * verbose == 1, then print the command name and abstract; + * verbose == 0, then print only the command name; + */ +int +showhelp(struct monCommand *list,int index,int verbose) +{ + char **hp; + struct monCommand *cptr = &list[index]; + +#if INCLUDE_USRLVL + char *lvltbl = 0; + + /* Get command list in sync with user-level table: + */ + if (list == cmdlist) + lvltbl = cmdUlvl; + else if (list == appCmdlist) + lvltbl = appcmdUlvl; + else + return(-1); + + /* Verify user level: + */ + if ((lvltbl[index] > getUsrLvl())) + return(0); +#endif + + if (verbose == 2) { + printf("%s\n", cptr->helptxt[0]); + showusage(cptr); + + hp = &cptr->helptxt[2]; + while(*hp) + printf("%s\n",*hp++); + +#if INCLUDE_USRLVL + printf("\nRequired user level: %d\n",lvltbl[index]); +#endif + } + else if (verbose == 1) { +#if INCLUDE_USRLVL + printf(" %-12s %d %s\n", cptr->name, lvltbl[index],cptr->helptxt[0]); +#else + printf(" %-12s %s\n", cptr->name, cptr->helptxt[0]); +#endif + } + else { + printf("%-12s",cptr->name); + } + return(1); +} + +/* Command list headers can be defined in config.h or just + * omitted... + */ +#ifndef APP_CMDLIST_HEADER +#define APP_CMDLIST_HEADER "\nApplication-Installed Command Set:" +#endif + +#ifndef MON_CMDLIST_HEADER +#define MON_CMDLIST_HEADER "\nMicro-Monitor Command Set:" +#endif + +/* Help(): + * This command displays each commands help text. + * The help text is assumed to be formatted as an array of strings + * where... + * the first string is the command description; + * the second string is command usage; + * and all remaining strings up to the NULL are just printable text. + */ +char *HelpHelp[] = { + "Display command set", + "-[di] [commandname]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -d list commands and descriptions", + " -i configuration info", +#endif + 0, +}; + +int +Help(int argc,char *argv[]) +{ + char *cp; + char *args[2]; + struct monCommand *cptr, *acptr; + int j, i, foundit, opt, descriptions, info; + + descriptions = info = 0; + while((opt=getopt(argc,argv,"di")) != -1) { + switch(opt) { + case 'd': + descriptions = 1; + break; + case 'i': + info = 1; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (info) { + monHeader(0); + stkusage(); + printf("Moncomptr: 0x%08lx\n",(long)&moncomptr); +#if INCLUDE_ETHERNET + printf("Etheradd_ptr: 0x%08lx\n",(long)etheraddr); +#endif +#if INCLUDE_TFS +#ifdef TFS_ALTDEVTBL_BASE + if (alt_tfsdevtbl != (struct tfsdev *)0xffffffff) + printf("AltTFSdevtbl: 0x%08lx\n",(long)alt_tfsdevtbl); +#endif +#endif +#if INCLUDE_TERM + { + int row, col; + if (term_getsize(&row,&col) != -1) + printf("ROW/COL: %d/%d\n",row,col); + } +#endif + + return(CMD_SUCCESS); + } + + cptr = cmdlist; + if (argc == optind) { + foundit = 1; + if (descriptions) { + if (appCmdlist) { + printf("%s\n",APP_CMDLIST_HEADER); + acptr = appCmdlist; + for(i=0;acptr->name;acptr++,i++) + showhelp(appCmdlist,i,1); + } + printf("%s\n",MON_CMDLIST_HEADER); + while(cptr->name) { + showhelp(cmdlist,cptr-cmdlist,1); + cptr++; + } + putchar('\n'); + } + else { + i = 0; + if (appCmdlist) { + acptr = appCmdlist; + printf("%s\n",APP_CMDLIST_HEADER); + for(j=0;acptr->name;acptr++,j++) { + if (showhelp(appCmdlist,j,0)) { + if ((++i%6) == 0) + putchar('\n'); + } + } + putchar('\n'); + i = 0; + } + printf("%s\n",MON_CMDLIST_HEADER); + while(cptr->name) { + if (showhelp(cmdlist,cptr-cmdlist,0)) { + if ((++i%6) == 0) + putchar('\n'); + } + cptr++; + } + putchar('\n'); + } + } + else { + foundit = 0; + cp = argv[1]; + if (appCmdlist) { + acptr = appCmdlist; + for(i=0;acptr->name;acptr++,i++) { + if (strcmp(acptr->name,cp) == 0) { + foundit = showhelp(appCmdlist,i,2); + break; + } + } + } + if (!foundit) { + if (*cp == '_') + cp++; + while(cptr->name) { + if (strcmp(cptr->name,cp) == 0) { + foundit = showhelp(cmdlist,cptr-cmdlist,2); + break; + } + cptr++; + } + } + } + + if (!foundit) { + TFILE *tfp; + + /* If the command is not found in the command table, then see if + * it is an executable in TFS. If it is, run it with a single + * argument "help"... + */ + tfp = tfsstat(argv[1]); + if (tfp && (TFS_ISEXEC(tfp))) { + args[0] = argv[1]; + args[1] = argv[0]; + tfsrun(args,0); + } + else { + printf("\"%s\" not found\n",argv[1]); + return(CMD_FAILURE); + } + } + return(CMD_SUCCESS); +} + +#if INCLUDE_SHELLVARS +/* getPathEntry(): + * Copy the next path entry pointed to by 'path' into 'entry'. + */ +char * +getPathEntry(char *path, char *entry, int entrysize) +{ + int i; + char *base = entry; + + entrysize--; + + while(*path == ':') + path++; + + for(i=0;(i < entrysize) && (*path != ':') && (*path != 0); i++) + *entry++ = *path++; + + if (entry == base) + return(0); + + *entry++ = 0; + return(path); +} + +/* findPath(): + * If PATH is set, then step through each colon-delimited entry looking + * for a valid executable. + */ +int +findPath(char *name,char *fpath,int pathsize) +{ + int elen; + TFILE *tfp; + char *path; + char entry[TFSNAMESIZE+1]; + + if ((tfp = tfsstat(name))) + strcpy(fpath,name); + + if ((path = getenv("PATH"))) { + if ((*path == ':') && tfp) + return(1); + while((path = getPathEntry(path,entry,sizeof(entry)))) { + elen = strlen(entry); + if ((elen + strlen(name)) < (pathsize-1)) { + if (entry[elen-1] != '/') + strcat(entry,"/"); + strcat(entry,name); + if (tfsstat(entry)) { + strcpy(fpath,entry); + return(1); + } + } + } + } + if (tfp) + return(1); + return(0); +} +#else +int +findPath(char *name, char *fpath, int pathsize) +{ + if (tfsstat(name)) { + strcpy(fpath,name); + return(1); + } + return(0); +} +#endif + +/* fsCmdAlias(): + * Just allow "cat" to be used instead of "tfs cat" (for exammple)... + */ +char * +fsCmdAlias(char *cmdcpy, char *cmd, int cpysize) +{ +#if INCLUDE_TFS + if ((strlen(cmd) + 16) >= cpysize) { + strcpy(cmdcpy,cmd); + } + else if ((strncmp(cmd,"cat ",4) == 0) || + (strncmp(cmd,"ls",2) == 0) || + (strncmp(cmd,"rm ",3) == 0) || + (strncmp(cmd,"cp ",3) == 0) || + (strncmp(cmd,"ld ",3) == 0)) { + sprintf(cmdcpy,"tfs %s", cmd); + } + else + strcpy(cmdcpy,cmd); +#else + strcpy(cmdcpy,cmd); +#endif + return(cmdcpy); +} + +/* _docommand(): + * Called by docommand() (below) to process what it thinks is a + * single command. + * + * Assume the incoming string is a null terminated character string + * that is made up of whitespace delimited tokens that will be parsed + * into command line arguments. The first argument is the command name + * and all following arguments (if any) are specific to that command. + * If verbose is non-zero, print the list of arguments after tokenization. + */ +int +_docommand(char *cmdline,int verbose) +{ + int ret, argc, i, err; + struct monCommand *cmdptr, *cmdptrbase; + char *argv[ARGCNT], cmdcpy[CMDLINESIZE], path[TFSNAMESIZE+1]; +#if INCLUDE_USRLVL + char *ulvlptr = 0; +#endif + + cmdline = fsCmdAlias(cmdcpy,cmdline,CMDLINESIZE); + + /* Redirection check is done prior to shell variable expansion, so + * the code within RedirectionCheck() itself must deal with the '$' + * after the redirection arrow... + */ + if (RedirectionCheck(cmdline) == -1) + return(CMD_LINE_ERROR); + + /* If there are any instances if a dollar or percent sign within the + * command line, then expand any shell variables (or symbols) that may + * be present. + */ + if (strpbrk(cmdline,"$%")) { + if (expandshellvars(cmdline) < 0) + return(CMD_LINE_ERROR); + } + + /* Build argc/argv structure based on incoming command line. + */ + argc = tokenize(cmdline,argv); + if (argc == 0) + return(CMD_SUCCESS); /* Empty line is ok */ + if (argc < 0) { + printf("Command line error\n"); + return(CMD_LINE_ERROR); + } + + /* If verbosity is enabled, print the processed command line. + */ + if (verbose) { + for(i=0;i<argc;i++) + printf("%s ",argv[i]); + printf("\n"); + } + + /* Initialize static data used by getopt(). + */ + getoptinit(); + + /* At this point all CLI processing has been done. We've tokenized + * and converted shell variables where necessary. Now its time to + * scan through the command table(s) looking for a match between + * the first token of the incoming command string and a command name + * in the table(s). + * The monitor allows the application to insert a set of commands + * that will be in addition to the commands that are in the monitor's + * command list, this is done with the API function mon_addcommand() + * which ultimately calls the function addcommand() in this file. + * That function is handed a pointer to two tables: a command structure + * table and a user level table. + * If the application-supplied command table is present, then we scan + * through it first. This is done so that when we scan the monitor-owned + * command table, we can strip off a leading underscore to support the + * ability to have a command in each table (applcation-supplied and + * monitor built-ins) with the same name. + */ + if (appCmdlist) { + cmdptrbase = appCmdlist; +#if INCLUDE_USRLVL + ulvlptr = appcmdUlvl; +#endif + } + else { + cmdptrbase = cmdlist; +#if INCLUDE_USRLVL + ulvlptr = cmdUlvl; +#endif + } + + while(1) { + /* If we are processing the monitor-owned command table, then + * we want to eliminate the leading underscore of argv[0] (if + * there is one). + */ + if ((cmdptrbase == cmdlist) && (argv[0][0] == '_')) + strcpy(argv[0],&argv[0][1]); + + for(cmdptr = cmdptrbase; cmdptr->name; cmdptr++) { + if (strcmp(argv[0],cmdptr->name) == 0) + break; + } + if (cmdptr->name) { +#if INCLUDE_USRLVL + /* If command exists, but we are not at the required user + * level, then just pretend there was no command match... + */ + if (ulvlptr[cmdptr-cmdptrbase] > getUsrLvl()) + break; +#endif + /* Do not run this command if monrc is active and the + * NOMONRC flag bit is set for this command... + */ + if ((cmdptr->flags & CMDFLAG_NOMONRC) && tfsRunningMonrc()) { + printf("%s: illegal within monrc.\n",cmdptr->name); + return(CMD_MONRC_DENIED); + } + + /* Execute the command's function... + */ + ret = cmdptr->func(argc,argv); + + /* If command returns parameter error, then print the second + * string in that commands help text as the usage text. If + * the second string is a null pointer, then print a generic + * "no arguments" string as the usage message. + */ + if (ret == CMD_PARAM_ERROR) + paramerr(cmdptr); + + RedirectionCmdDone(); + return(ret); + } + if (cmdptrbase == cmdlist) + break; + + cmdptrbase = cmdlist; +#if INCLUDE_USRLVL + ulvlptr = cmdUlvl; +#endif + } + + /* If we get here, then the first token does not match on any of + * the command names in ether of the command tables. As a last + * resort, we look to see if the first token matches an executable + * file name in TFS. + */ + ret = CMD_NOT_FOUND; + + if (findPath(argv[0],path,sizeof(path))) { + argv[0] = path; + err = tfsrun(argv,0); + if (err == TFS_OKAY) + ret = CMD_SUCCESS; + else + printf("%s: %s\n",path,(char *)tfsctrl(TFS_ERRMSG,err,0)); + } + else { + printf("Command not found: %s\n",argv[0]); + } + RedirectionCmdDone(); + return(ret); +} + +/* docommand(): + * This is a relatively new (Jan 2006) front end to _docommand(). + * It deals with three things (two of which are new uMon command line + * capabilities): + * + * 1. Terminates the line at the sight of a poundsign (moved from + * original docommand() function). + * 2. Looks for the left arros ('<') at the end of the line and if + * found, it is used to indicate that the line should be repeated + * until interrupted. + * 3. Allow multiple, semicolon-delimited commands to be put on a + * single command line. + */ +int +docommand(char *line, int verbose) +{ + int ret, loop, len; + char *lp, *base, *backslash, cmdcpy[CMDLINESIZE]; + + loop = 0; + len = strlen(line); + if (len >= CMDLINESIZE) + return(CMD_LINE_ERROR); + + lp = line + len - 1; + if (*lp == '<') { + loop = 1; + *lp = 0; + } + +repeat: + backslash = 0; + lp = base = cmdcpy; + strcpy(lp,line); + + while (*lp) { + if (*lp == ';') { + if (backslash) { + strcpy(backslash,lp); + backslash = 0; + continue; + } + *lp = 0; + ret = _docommand(base,verbose); + *lp++ = ';'; + base = lp; + if (ret != CMD_SUCCESS) + return(ret); + continue; + } + if (*lp == '#') { + if (backslash) { + strcpy(backslash,lp); + backslash = 0; + continue; + } + *lp = 0; + loop = 0; + break; + } + if (*lp == '\\') { + backslash = lp; + lp++; + continue; + } + backslash = 0; + lp++; + } + ret = _docommand(base,verbose); + + if ((loop) && !gotachar()) + goto repeat; + + return(ret); +} diff --git a/main/common/edit.c b/main/common/edit.c new file mode 100644 index 0000000..3fb8b54 --- /dev/null +++ b/main/common/edit.c @@ -0,0 +1,722 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * edit.c: + * + * A simple buffer editor. It allows a user to pull a TFS file into RAM, + * make some "ed-like" modifications to the ASCII data and then write + * that data back to TFS. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_EDIT +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include <ctype.h> +#include "cli.h" + +extern char *file_line_edit(char *); +static int rmCR(char *,int); +static int gotoline(char *,char *,char **,char *,int); +static int searchfor(char *,char *,char **,char *); +static int whatlineisthis(char *,char *); +static int getrange(char *,int *,int *,char *,char *,char *); +static void lnprbuf(char *,char *,char *); +static void prbuf(char *,char *); +static void prlno(int,int); +static void deletelines(char *,int,char *,char **,char **); +static char *prline(char *,char *); +static char *skipwhite(char *); + +#define BREAK 1 +#define CONTINUE 2 +#define FALLTHROUGH 3 +#define INSERT 4 +#define COMMAND 5 +#define ESCAPE 0x1b + +#define ILCMAX 8 + +void +efree(int size, char *buffer) +{ + if (size != 0) + free(buffer); +} + +/* Help text while in the editor: */ +char *edithelp[] = { + "Editor commands:", + "d{LRNG} delete line", +#if INCLUDE_LINEEDIT + "e# edit line # (uses 'ksh/vi-like' command line editing)", +#endif + "i enter insert mode (use '.' to exit insert mode)", + "a enter append mode (use '.' to exit append mode)", + "j# join line '#' with line '#+1'", + "P[LRNG] print buffer with line numbers", + "p print buffer", + "q[fname] quit edit, write file", + "s[srchstr] goto line containing search string", + "x exit edit, do not write file", + "# goto line # (use '$' to go to last line)", + ".+/-# goto line relative to current position", + "", + "Where...", + "# represents a decimal number;", + "LRNG represents a line number or inclusive line range (# or #-#);", + 0, +}; + +/* Help text outside the editor: */ + +char *EditHelp[] = { + "Edit file or buffer", + "-[b:c:f:i:m:rs:t] [filename]", +#if INCLUDE_VERBOSEHELP + " -b {adr} specify buffer base address", + " -c {cmd} in-line command", + " -f {flgs} file flags (see tfs)", + " -i {info} file info (see tfs)", + " -m {size} specify allocation size for buffer", + " -r do not automatically remove carriage returns from file", + " -s {size} size of buffer", + " -t convert tabs to spaces", +#endif + 0, +}; + +int +Edit(int argc,char *argv[]) +{ + int i, opt, tfd, quit, mode, bsize; + char ln[CMDLINESIZE], *lp, *cp, *cp1, *filename, *flags, *info; + char *buffer, *bp; /* Buffer and pointer into buffer. */ + char *eob; /* Current EOF pointer (max distance between */ + /* bp and buffer). */ + char *inlinecmd[ILCMAX]; /* If non-NULL, it points to a list of */ + /* commands to be executed prior to going */ + /* into interactive mode. */ + int ilcidx; /* Index into in-line command table. */ + int len; /* Length of the incoming line. */ + int size; /* Size of buffer specified on command line. */ + int cmdtot; /* Running total of incoming lines. */ + int delcnt; /* Used by :d when a range is specified. */ + int noCR; /* Set by -r option to remove Carriage Returns */ + TFILE tstruct, *tfp; + + tfp = (TFILE *)0; + size = bsize = 0; + flags = filename = (char*)0; + buffer = (char *)getAppRamStart(); + info = (char *)0; + noCR = 1; + ilcidx = 0; + for(i=0;i<8;i++) + inlinecmd[i] = (char *)0; + + while ((opt = getopt(argc, argv, "b:c:f:i:m:rs:")) != -1) { + switch (opt) { + case 'b': + buffer = (char *)strtol(optarg,(char **)0,0); + break; + case 'c': + if (ilcidx < ILCMAX-1) + inlinecmd[ilcidx++] = optarg; + break; + case 'f': + flags = optarg; + break; + case 'i': + info = optarg; + break; + case 'm': + bsize = strtol(optarg,0,0); + break; + case 'r': + noCR = 0; + break; + case 's': + size = (int)strtol(optarg,(char **)0,0); + break; + default: + return (CMD_PARAM_ERROR); + } + } + + if (bsize != 0) { + buffer = malloc(bsize); + if (!buffer) + return(CMD_FAILURE); + } + + if (argc == optind+1) { + filename = argv[optind]; + if (tfsfstat(filename,&tstruct) != -1) { + tfp = &tstruct; + size = TFS_SIZE(tfp); + if ((bsize > 0) && (size > bsize)) { + printf("Allocation too small\n"); + efree(bsize,buffer); + return(CMD_FAILURE); + } + tfd = tfsopen(filename,TFS_RDONLY,0); + if (tfd < 0) { + printf("%s: %s\n",filename,(char *)tfsctrl(TFS_ERRMSG,tfd,0)); + efree(bsize,buffer); + return(CMD_FAILURE); + } + else { + tfsread(tfd,buffer,size); + tfsclose(tfd,0); + } + } + } + + if ((noCR) && (size != 0)) { + if ((buffer[size-1] != 0x0d) && (buffer[size-1] != 0x0a)) { + printf("EOF linefeed inserted.\n"); + buffer[size++] = 0x0a; + buffer[size] = 0; + } + size -= rmCR(buffer,size); + } + + bp = buffer; + eob = buffer + size; + + if (!ilcidx) + printf("Edit buffer = 0x%lx.\nType '?' for help\n",(ulong)buffer); + + quit = 0; + cmdtot = 0; + mode = COMMAND; + while(!quit) { + lp = ln; + if (ilcidx > cmdtot) + strcpy(ln,inlinecmd[cmdtot]); + else if (ilcidx) { /* If ILC command set doesn't terminate */ + /* the edit session, force it here. */ + efree(bsize,buffer); + return(CMD_SUCCESS); + } + else + getline(ln,CMDLINESIZE,0); + cmdtot++; + if (mode == INSERT) { + if (!strcmp(lp,".")) + mode = COMMAND; + else { + len = strlen(lp) + 1; + cp1 = eob + len; + cp = eob; + while(cp > bp) *--cp1 = *--cp; + while(*lp) *bp++ = *lp++; + *bp++ = '\n'; + eob += len; + } + continue; + } + if (!strcmp(ln,"x")) { /* Exit editor now. */ + efree(bsize,buffer); + return(CMD_SUCCESS); + } + else if (!strcmp(ln,"?")) { /* Display help info. */ + char **eh; + + eh = edithelp; + while(*eh) + printf("%s\n",*eh++); + } + else if (!strcmp(ln,"p")) /* Print buffer. */ + prbuf(buffer,eob); + else if (!strcmp(ln,"P")) /* Print buffer with lines. */ + lnprbuf(buffer,bp,eob); + else if (!strcmp(ln,"i")) /* Enter insert mode. */ + mode = INSERT; + else if (!strcmp(ln,"a")) { /* Enter insert mode at */ + mode = INSERT; /* next line */ + gotoline(".+1",buffer,&bp,eob,0); + } + else if (!strcmp(ln,"$")) { /* Goto last line. */ + gotoline(ln,buffer,&bp,eob,0); + gotoline(".-1",buffer,&bp,eob,1); + } + else if (isdigit(ln[0]) || (ln[0]=='.')) /* Goto line. */ + gotoline(ln,buffer,&bp,eob,1); + else if (ln[0] == 's') { /* Go to line containing string. */ + char *str; + str = skipwhite(&ln[1]); + if (!*str) + gotoline(".+1",buffer,&bp,eob,0); + searchfor(str,buffer,&bp,eob); + } +#if INCLUDE_LINEEDIT + else if (ln[0] == 'e') { + char *copy, *eoc, *cp2, crlf[2]; + int oldlnsize, newlnsize, toendsize; + + if (gotoline(&ln[1],buffer,&bp,eob,0) == -1) + continue; + copy = malloc(CMDLINESIZE); + if (!copy) + continue; + eoc = copy + CMDLINESIZE - 3; + cp = bp; + cp1 = copy; + oldlnsize = 0; + while ((*cp != 0x0a) && (*cp != 0x0d) && (cp1 != eoc)) { + if (*cp == '\t') /* Tabs are replaced with spaces to */ + *cp = ' '; /* eliminate whitespace confusion in */ + putchar(*cp); /* the line editor. */ + *cp1++ = *cp++; + oldlnsize++; + } + crlf[0] = *cp; + if (*cp != *(cp+1)) { + crlf[1] = *(cp+1); + if (*(cp+1) == 0x0a || *(cp+1) == 0x0d) + oldlnsize++; + } + else { + crlf[1] = 0; + } + oldlnsize++; + *cp1++ = ESCAPE; + *cp1 = 0; + if (file_line_edit(copy) != (char *)0) { + newlnsize = strlen(copy); + toendsize = eob - (bp+oldlnsize); + copy[newlnsize++] = crlf[0]; + if (crlf[1] == 0x0d || crlf[1] == 0x0a) + copy[newlnsize++] = crlf[1]; + copy[newlnsize] = 0; + if (oldlnsize == newlnsize) { + memcpy(bp,copy,newlnsize); + } + else if (oldlnsize > newlnsize) { + strcpy(bp,copy); + memcpy(bp+newlnsize,cp+1,toendsize); + } + else { + cp1 = eob-1; + cp2 = (char *)(eob+(newlnsize-oldlnsize)-1); + for(i=0;i<toendsize;i++) + *cp2-- = *cp1--; + memcpy(bp,copy,newlnsize); + } + eob -= oldlnsize; + eob += newlnsize; + } + free(copy); + } +#endif + else if (ln[0] == 'P') { + int range, first, last, currentline; + + range = getrange(&ln[1],&first,&last,buffer,bp,eob); + if (range > 0) { + char *bpcpy; + + bpcpy = bp; + gotoline(".",buffer,&bpcpy,eob,0); + currentline = whatlineisthis(buffer,bpcpy); + if (gotoline(&ln[1],buffer,&bpcpy,eob,0) == -1) + continue; + for(i=first;i<=last;i++) { + prlno(i,currentline); + bpcpy = prline(bpcpy,eob); + } + } + } + else if (ln[0] == 'j') { /* Join line specified with next line */ + char *tmpeob; + + if (gotoline(&ln[1],buffer,&bp,eob,0) == -1) + continue; + tmpeob=eob-1; + while(bp < tmpeob) { + if (*bp == '\n') { + memcpy(bp,bp+1,eob-bp); + eob--; + break; + } + bp++; + } + } + else if (ln[0] == 'd') { /* Delete line (or range of lines) */ + delcnt = getrange(&ln[1],0,0,buffer,bp,eob); + deletelines(&ln[1],delcnt,buffer,&bp,&eob); + } + else if (ln[0] == 'q') { /* Quit edit, if filename is present */ + lp = &ln[1]; /* use it. */ + lp = skipwhite(lp); + if (*lp) + filename = lp; + quit = 1; + } + else { + printf("huh?\n"); + } + } + + if (filename) { + int err; + char buf[16]; + + if (tfp) { + int link; + + /* If filename and TFS_NAME(tfp) differ, then we are editing + * a file through a symbolic link. If it is a link, then we + * use the info/flags/filename from the source file (using the + * file pointer and ignoring user input stuff). + */ + link = strcmp(filename,TFS_NAME(tfp)); + + if ((!flags) || (link)) + flags = (char *)tfsctrl(TFS_FBTOA,TFS_FLAGS(tfp),(long)buf); + if ((!info) || (link)) + info = TFS_INFO(tfp); + if (link) { + printf("Updating source file '%s' thru link '%s'\n", + TFS_NAME(tfp),filename); + filename = TFS_NAME(tfp); + } + } + if (!flags) + flags = (char *)0; + if (!info) + info = (char *)0; + err = tfsadd(filename,info,flags,(unsigned char *)buffer,eob-buffer); + if (err != TFS_OKAY) + printf("%s: %s\n",filename,(char *)tfsctrl(TFS_ERRMSG,err,0)); + } + efree(bsize,buffer); + return(CMD_SUCCESS); +} + +static void +lnprbuf(char *buffer,char *bp,char *eob) +{ + int lno, currentline; + + if (buffer == eob) + return; + + lno = 1; + currentline = whatlineisthis(buffer,bp); + prlno(lno++,currentline); + while(buffer < eob) { + putchar(*buffer); + if ((*buffer == '\n') && ((buffer + 1) != eob)) + prlno(lno++,currentline); + buffer++; + } +} + +static void +prlno(int lno,int currentline) +{ + char *fmt; + + if (lno == currentline) + fmt = ">%2d: "; + else + fmt = "%3d: "; + printf(fmt,lno); +} + +static void +prbuf(char *bp,char *eob) +{ + while(bp < eob) + putchar(*bp++); +} + +char * +prline(char *bp,char *eob) +{ + while(bp < eob) { + putchar(*bp); + if (*bp == '\n') + break; + bp++; + } + return(bp+1); +} + +/* searchfor(): + * Step through the buffer starting at 'bp' and search for a memory match + * with the incoming string pointed to by 'srch'. If not found, simply + * return after the entire buffer has been searched (wrap to start if + * necessary). If found, then adjust '*bp' to point to the beginning of + * of the line that contains the match. + */ +static int +searchfor(char *srch,char *buffer,char **bp,char *eob) +{ + static char *lastsrchstring; + char *startedhere, *tbp; + int len; + + tbp = *bp; + if (tbp < eob) + startedhere = *bp; + else + tbp = startedhere = buffer; + + if (*srch) { + len = strlen(srch); + if (lastsrchstring) + free(lastsrchstring); + lastsrchstring = malloc(len+1); + if (lastsrchstring) + strcpy(lastsrchstring,srch); + } + else if (lastsrchstring) { + len = strlen(lastsrchstring); + srch = lastsrchstring; + } + else + return(-1); + do { + if ((tbp + len) > eob) { + tbp = buffer; + } + else { + if (!memcmp(tbp,srch,len)) { + while(1) { + if (tbp <= buffer) { + *bp = buffer; + break; + } + if (*tbp == '\n') { + *bp = tbp+1; + break; + } + tbp--; + } + prline(*bp,eob); + return(0); + } + else + tbp++; + } + } while(tbp != startedhere); + printf("'%s' not found\n",srch); + return(-1); +} + +static int +gotoline(char *ln,char *buffer,char **bp,char *eob,int verbose) +{ + int lno, i, moveforward; + char *tbp, *base; + + base = buffer; + moveforward = 1; + + /* If destination line number is '.', assume you're already there. + * If the '.' is followed by a '+' or '-' then the following number + * is considered an offset from the current line instead of from the + * start of the buffer. + */ + if (ln[0] == '.') { + base = *bp; + if (ln[1] == '+') + lno = atoi(&ln[2]) + 1; + else if (ln[1] == '-') { + lno = atoi(&ln[2]) + 2; + moveforward = 0; + } + else + goto end; + } + else if (ln[0] == '$') { + lno = 99999999; + } + else + lno = atoi(ln); + + if (lno < 1) { + printf("Invalid line\n"); + return(-1); + } + + if (moveforward) { + for(tbp=base,i=1;i<lno&&tbp<eob;tbp++) + if (*tbp == '\n') i++; + if (tbp == eob) { + if (verbose) + printf("Pointer set to end of buffer.\n"); + /* If out of range, set pointer to end of buffer. */ + *bp = eob; + return(-1); + } + } + else { + for(tbp=base,i=1;i<lno&&tbp>=buffer;tbp--) + if (*tbp == '\n') i++; + if (tbp < buffer) { + if (verbose) + printf("Pointer set to start of buffer.\n"); + /* If out of range, set pointer to beginning of buffer. */ + *bp = buffer; + return(-1); + } + tbp+=2; + } + *bp = tbp; + +end: + if (verbose) { + printf("%3d: ",whatlineisthis(buffer,*bp)); + prline(*bp,eob); + } + return(0); +} + +static int +whatlineisthis(char *buffer,char *bp) +{ + int lno; + char *cp; + cp = buffer; + + lno = 1; + while(cp < bp) { + if (*cp == '\n') + lno++; + cp++; + } + return(lno); +} + +static int +getrange(char *cp,int *begin,int *end,char *buffer,char *bp,char *eob) +{ + char *dash; + int b, e, lastline, thisline; + + if (!*cp) + return(0); + + lastline = whatlineisthis(buffer,eob) - 1; + thisline = whatlineisthis(buffer,bp); + + if (*cp == '.') + b = thisline; + else + b = atoi(cp); + dash = strchr(cp,'-'); + if (dash) { + if (*(dash+1) == '$') + e = lastline; + else if (*(dash+1) == '.') + e = thisline; + else + e = atoi(dash+1); + } + else + e = b; + + if (e > lastline) + e = lastline; + if (begin) + *begin = b; + if (end) + *end = e; + if ((e <= 0) || (b <=0) || (e < b)) + printf("Bad range\n"); + return(e - b + 1); +} + +static void +deletelines(char *lp,int lcnt,char *buffer,char **bp,char **eob) +{ + char *cp, *cp1, *t_bp, *t_eob; + + if (lcnt <= 0) + return; + + t_bp = *bp; + t_eob = *eob; + + if (gotoline(lp,buffer,&t_bp,t_eob,0) == -1) + return; + cp = cp1 = t_bp; + while(lcnt>0) { + if (cp >= t_eob) { + printf("Pointer set to end of buffer.\n"); + break; + } + if (*cp == '\n') + lcnt--; + cp++; + } + while(cp != t_eob) + *cp1++ = *cp++; + + *eob = cp1; + *bp = t_bp; +} + +static char * +skipwhite(char *cp) +{ + while((*cp == ' ') || (*cp == '\t')) + cp++; + return(cp); +} + +/* rmCR(): + * Given the source and size of the buffer, remove all instances of 0x0d + * (carriage return) from the buffer. Return the number of CRs removed. +*/ +static int +rmCR(char *src,int size) +{ + int i; /* Index into src array. */ + int tot; /* Keep track of total # of 0x0d's removed. */ + int remaining; /* Keep track of how far to go. */ + + tot = 0; + remaining = size; + for (i=0;i<size;i++) { + remaining--; + if (src[i] == 0x0d) { + src[i] = 0; /* Make sure memory is writeable. */ + if (src[i] != 0) + continue; + memcpy(&src[i],&src[i+1],remaining); + tot++; + } + } + if (tot) + printf("Removed %d CRs\n",tot); + return(tot); +} + +#endif diff --git a/main/common/elf.h b/main/common/elf.h new file mode 100644 index 0000000..f8a69b2 --- /dev/null +++ b/main/common/elf.h @@ -0,0 +1,159 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * elf.h: + * + * Used to support ELF file format in TFS. + * The data in this header file is built primarily from information in + * the book "Understanding ELF Object Files and Debugging Tools" + * All page references in comments refer to that book. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#ifndef _ELF_H_ +#define _ELF_H_ + +typedef unsigned short Elf32_Half; +typedef unsigned long Elf32_Word; +typedef unsigned long Elf32_Addr; +typedef unsigned long Elf32_Off; + +/* Size of ELF identification field. */ +#define EI_NIDENT 16 + +/* e_type values... */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff + + +struct elf_fhdr { /* pg 12 */ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +}; + +#define ELFFHDR struct elf_fhdr + +/* sh_flags values... */ +#define SHF_WRITE 0x1 +#define SHF_ALLOC 0x2 +#define SHF_EXECINSTR 0x4 +#define SHF_MASKPROC 0xf0000000 + +/* sh_type values... */ +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7fffffff +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0x8fffffff + +struct elf_shdr { /* pg 19 */ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +}; + +#define ELFSHDR struct elf_shdr + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +struct elf_phdr { /* pg 42 */ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +}; + +#define ELFPHDR struct elf_phdr + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +#define SHN_UNDEF 0 + +struct elf_sym { + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +}; + +#endif diff --git a/main/common/endian.h b/main/common/endian.h new file mode 100644 index 0000000..36dede7 --- /dev/null +++ b/main/common/endian.h @@ -0,0 +1,68 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * endian.h: + * + * macros used for endian conversion. + * The intent is that the macros have nil effect on Big_Endian systems... + * + * ecs: endian-convert short + * ecl: endian-convert long + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _ENDIAN_H_ +#define _ENDIAN_H_ + +#ifdef CPU_LE +#define ecs(a) (((a & 0x00ff) << 8) | ((a & 0xff00) >> 8)) +#define ecl(a) (((a & 0x000000ff) << 24) | ((a & 0x0000ff00) << 8) | \ + ((a & 0x00ff0000) >> 8) | ((a & 0xff000000) >> 24)) +#define self_ecs(a) (a = ecs(a)) +#define self_ecl(a) (a = ecl(a)) +#define ntohl ecl +#define ntohs ecs +#define htonl ecl +#define htons ecs +#else +#ifdef CPU_BE +#define ecs(a) a +#define ecl(a) a +#define self_ecs(a) +#define self_ecl(a) +#define ntohl(a) a +#define ntohs(a) a +#define htonl(a) a +#define htons(a) a +#else +#error You need to define CPU_BE or CPU_LE in config.h! +#endif /* else ifdef CPU_BE */ +#endif /* ifdef CPU_LE */ + +/* just to be safe... + */ +#ifdef CPU_LE +#ifdef CPU_BE +#error You have both CPU_BE and CPU_LE defined. Pick one! +#endif +#endif + +#endif diff --git a/main/common/env.c b/main/common/env.c new file mode 100755 index 0000000..22a10fc --- /dev/null +++ b/main/common/env.c @@ -0,0 +1,858 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * env.c: + * Shell variable functions used to load or retrieve shell variable + * information from the shell variable table. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include <stdarg.h> +#include "config.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "ether.h" +#include "genlib.h" +#include "stddefs.h" +#include "cli.h" +#include "version.h" +#include "boardinfo.h" +#include "timer.h" + +#if INCLUDE_SHELLVARS + +char *whatplatform = "@(#)PLATFORM=" PLATFORM_NAME; + +#ifdef TARGET_ENV_SETUP +extern void TARGET_ENV_SETUP(void); +#endif + +#ifndef PROMPT +#define PROMPT "uMON>" +#endif + +int shell_print(void); +int envToExec(char *); +void clearenv(void); + +/* Structure used for the shell variables: */ +struct s_shell { + char *val; /* Value stored in shell variable */ + char *name; /* Name of shell variable */ + int vsize; /* Size of storage allocated for value */ + struct s_shell *next; +}; + +struct s_shell *shell_vars; + +/* If no malloc, then use locally defined env_alloc() and env_free()... + */ +#if INCLUDE_MALLOC + +#define env_alloc malloc +#define env_free free + +#else + +#define ENV_ALLOC_TOT 48 +#define ENV_ALLOC_SIZE (sizeof(struct s_shell)+8) + +struct env_space { + int inuse; + char space[ENV_ALLOC_SIZE]; +} envSpace[ENV_ALLOC_TOT]; + + +char * +env_alloc(int size) +{ + int i; + + if (size > ENV_ALLOC_SIZE) + return(0); + + for(i=0;i<ENV_ALLOC_TOT;i++) { + if (envSpace[i].inuse == 0) { + envSpace[i].inuse = 1; + memset(envSpace[i].space,0,ENV_ALLOC_SIZE); + return(envSpace[i].space); + } + } + return(0); +} + +void +env_free(char *space) +{ + int i; + + for(i=0;i<ENV_ALLOC_TOT;i++) { + if (envSpace[i].space == space) { + envSpace[i].inuse = 0; + break; + } + } + return; +} +#endif + +/* + * Set() + * + * Syntax: + * set var clears the variable 'var' + * set var value assign "value" to variable 'var' + * set -a var value AND 'var' with 'value' + * set -o var value OR 'var' with 'value' + * set -i var [value] increment 'var' by 'value' (or 1 if no value) + * set -d var [value] decrement 'var' by 'value' (or 1 if no value) + * set -x result of -i/-d is in hex + */ +char *SetHelp[] = { + "Shell variable operations", +#if INCLUDE_EE + "-[ab:cdef:iox] [varname[=expression]] [value]", +#else + "-[ab:cdef:iox] [varname] [value]", +#endif +#if INCLUDE_VERBOSEHELP + " -a AND var with value", + " -b set console baudrate", + " -c clear the environment", + " -d decrease var by value (or 1)", + " -e build an environ string", +#if INCLUDE_TFS + " -f{file} create script from environment", +#endif + " -i increase var by value (or 1)", + " -o OR var with value", + " -x result in hex (NA with expressions, use hex())", +#endif + 0, +}; + +#define SET_NOOP 0 +#define SET_INCR 1 +#define SET_DECR 2 +#define SET_OR 3 +#define SET_AND 4 + +int +Set(int argc,char *argv[]) +{ + char *envp, buf[CMDLINESIZE]; + int opt, decimal, setop, i; + + setop = SET_NOOP; + envp = (char *)0; + decimal = 1; + while((opt=getopt(argc,argv,"ab:cdef:iox")) != -1) { + switch(opt) { + case 'a': /* logical and */ + setop = SET_AND; + decimal = 0; + break; + case 'b': + ChangeConsoleBaudrate(atoi(optarg)); + return(CMD_SUCCESS); + case 'c': /* clear environment */ + clearenv(); + break; + case 'd': /* decrement */ + setop = SET_DECR; + break; + case 'e': + envp = getenvp(); + break; +#if INCLUDE_TFS + case 'f': /* build script from environment */ + envToExec(optarg); + return(0); +#endif + case 'i': /* increment */ + setop = SET_INCR; + break; + case 'o': /* logical or */ + setop = SET_OR; + decimal = 0; + break; + case 'x': + decimal = 0; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (!shell_vars) { + printf("No memory allocated for environment.\n"); + return(CMD_FAILURE); + } + + if (setop != SET_NOOP) { /* Do some operation on a shell variable */ + char *varval; + unsigned long value, opval; + + /* For -i & -d, if value is not specified, then assume 1. */ + if (argc == optind+1) { + if ((setop == SET_INCR) || (setop == SET_DECR)) + opval = 1; + else + return(CMD_PARAM_ERROR); + } + else if (argc == optind+2) + opval = strtoul(argv[optind+1],0,0); + else + return(CMD_PARAM_ERROR); + + varval = getenv(argv[optind]); + if (!varval) { + printf("%s: not found\n", argv[optind]); + return(CMD_FAILURE); + } + + value = strtoul(varval,(char **)0,0); + switch(setop) { + case SET_INCR: + value += opval; + break; + case SET_DECR: + value -= opval; + break; + case SET_AND: + value &= opval; + break; + case SET_OR: + value |= opval; + break; + } + if (decimal) + sprintf(buf,"%ld",value); + else + sprintf(buf,"0x%lx",value); + setenv(argv[optind],buf); + } + else if (argc == optind) { /* display all variables */ + shell_print(); + } + else if (argc == (optind+1)) { /* run EE or clear one var or set envp */ +#if INCLUDE_EE + switch(setEE(argv[optind])) { + case 1: + return(CMD_SUCCESS); + case -1: + return(CMD_FAILURE); + } +#endif + if (envp) + shell_sprintf(argv[optind],"0x%lx",(ulong)envp); + else + setenv(argv[optind],0); + } + else if (argc >= (optind+2)) { /* Set a specific variable */ + buf[0] = 0; + for(i=optind+1;i<argc;i++) { + if ((strlen(buf) + strlen(argv[i]) + 2) >= sizeof(buf)) { + printf("String too large\n"); + break; + } + strcat(buf,argv[i]); + if (i != (argc-1)) + strcat(buf," "); + } + if (!decimal) + shell_sprintf(argv[optind],"0x%lx",atoi(buf)); + else + setenv(argv[optind],buf); + } + else + return(CMD_PARAM_ERROR); + + return(CMD_SUCCESS); +} + +/* Shell variable support routines... + * The basic scheme is to malloc in the space needed for the variable + * name and the value of that variable. For each variable that + * exists there is one s_shell structure that is in the linked list. + * As shell variables are removed, their corresonding s_shell structure + * is NOT removed, but the data pointed to within the structure is + * freed. This keeps the linked list implementation extremely simple + * but maintains the versatility gained by using malloc for the + * variables instead of some limted set of static arrays. + */ + + +/* shell_alloc(): + * First scan through the entire list to see if the requested + * shell variable name already exists in the list; if it does, + * then just use the same s_shell entry but change the value. + * Also, if the new value fits in the same space as the older value, + * then just use the same memory space (don't do the free/malloc). + * If it doesn't, then scan through the list again. If there + * is one that has no variable assigned to it (name = 0), then + * use it for the new allocation. If all s_shell structures do + * have valid entries, then malloc a new s_shell structure and then + * place the new shell variable data in that structure. + */ + +static int +shell_alloc(char *name,char *value) +{ + int namelen, valuelen; + struct s_shell *sp; + + sp = shell_vars; + namelen = strlen(name); + valuelen = strlen(value); + while(1) { + if (sp->name == (char *)0) { + if (sp->next != (struct s_shell *)0) { + sp = sp->next; + continue; + } + else + break; + } + if (strcmp(sp->name,name) == 0) { + if (sp->vsize < valuelen+1) { /* If new value is smaller */ + env_free(sp->val); /* than the old value, then */ + sp->val = env_alloc(valuelen+1);/* don't re-allocate any */ + if (!sp->val) /* memory, just copy into */ + return(-1); /* the space used by the */ + sp->vsize = valuelen+1; /* previous value. */ + } + strcpy(sp->val,value); + return(0); + } + if (sp->next == (struct s_shell *)0) + break; + sp = sp->next; + } + sp = shell_vars; + while(1) { + if (sp->name == (char *)0) { + sp->name = env_alloc(namelen+1); + if (!sp->name) + return(-1); + strcpy(sp->name,name); + sp->val = env_alloc(valuelen+1); + if (!sp->val) + return(-1); + sp->vsize = valuelen+1; + strcpy(sp->val,value); + return(0); + } + if (sp->next != (struct s_shell *)0) + sp = sp->next; + else { + sp->next = (struct s_shell *)env_alloc(sizeof(struct s_shell)); + if (!sp->next) + return(-1); + sp = sp->next; + sp->name = env_alloc(namelen+1); + if (!sp->name) + return(-1); + strcpy(sp->name,name); + sp->val = env_alloc(valuelen+1); + if (!sp->val) + return(-1); + sp->vsize = valuelen+1; + strcpy(sp->val,value); + sp->next = (struct s_shell *)0; + return(0); + } + } +} + +/* shell_dealloc(): + * Remove the requested shell variable from the list. Return 0 if + * the variable was removed successfully, otherwise return -1. + */ +static int +shell_dealloc(char *name) +{ + struct s_shell *sp; + + sp = shell_vars; + while(1) { + if (sp->name == (char *)0) { + if (sp->next == (struct s_shell *)0) + return(-1); + else { + sp = sp->next; + continue; + } + } + if (strcmp(name,sp->name) == 0) { + env_free(sp->name); + env_free(sp->val); + sp->name = (char *)0; + sp->val = (char *)0; + return(0); + } + + if (sp->next == (struct s_shell *)0) + return(-1); + else + sp = sp->next; + } +} + +/* ConsoleBaudEnvSet(): + * Called by to load/reload the CONSOLEBAUD shell variable based on + * the content of the global variable 'ConsoleBaudRate'. + */ +void +ConsoleBaudEnvSet(void) +{ + char buf[16]; + + sprintf(buf,"%d",ConsoleBaudRate); + setenv("CONSOLEBAUD",buf); +} + +/* ShellVarInit(); + * Setup the shell_vars pointer appropriately for additional + * shell variable assignments that will be made through shell_alloc(). + */ +int +ShellVarInit() +{ + char buf[16]; + +#if !INCLUDE_MALLOC + memset((char *)&envSpace,0,sizeof(envSpace)); +#endif + + shell_vars = (struct s_shell *)env_alloc(sizeof(struct s_shell)); + if (!shell_vars) { + printf("No memory for environment initialization\n"); + return(-1); + } + shell_vars->next = (struct s_shell *)0; + shell_vars->name = (char *)0; + setenv("PROMPT",PROMPT); + sprintf(buf,"0x%lx",APPLICATION_RAMSTART); + setenv("APPRAMBASE",buf); + sprintf(buf,"0x%lx",BOOTROM_BASE); + setenv("BOOTROMBASE",buf); + setenv("PLATFORM",PLATFORM_NAME); + setenv("MONITORBUILT",monBuilt()); + shell_sprintf("MONCOMPTR","0x%lx",(ulong)&moncomptr); +#if INCLUDE_HWTMR + shell_sprintf("TARGETTIMER","0x%x",target_timer); + shell_sprintf("TICKSPERMSEC","0x%x",TIMER_TICKS_PER_MSEC); +#endif + + /* Support the ability to have additional target-specific + * shell variables initialized at startup... + */ +#ifdef TARGET_ENV_SETUP + TARGET_ENV_SETUP(); +#endif + + shell_sprintf("VERSION_MAJ","%d",MAJOR_VERSION); + shell_sprintf("VERSION_MIN","%d",MINOR_VERSION); + shell_sprintf("VERSION_TGT","%d",TARGET_VERSION); + return(0); +} + +/* getenv: + * Return the pointer to the value entry if the shell variable + * name is currently set; otherwise, return a null pointer. + */ +char * +getenv(char *name) +{ + register struct s_shell *sp; + + for(sp = shell_vars;sp != (struct s_shell *)0;sp = sp->next) { + if (sp->name != (char *)0) { + if (strcmp(sp->name,name) == 0) + return(sp->val); + } + } + return((char *)0); +} + +/* getenvp: + * Build an environment string consisting of all shell variables and + * their values concatenated into one string. The format is + * + * NAME=VALUE LF NAME=VALUE LF NAME=VALUE LF NULL + * + * with the limit in size being driven only by the space + * available on the heap. Note that this uses malloc, and it + * the responsibility of the caller to free the pointer when done. + */ +char * +getenvp(void) +{ + int size; + char *envp, *cp; + register struct s_shell *sp; + + size = 0; + + /* Get total size of the current environment vars */ + for(sp = shell_vars;sp != (struct s_shell *)0;sp = sp->next) { + if (sp->name != (char *)0) { + size += (strlen(sp->name) + strlen(sp->val) + 2); + } + } + if (size == 0) + return((char *)0); + + envp = env_alloc(size+1); /* leave room for final NULL */ + if (envp == 0) + return((char *)0); + + cp = envp; + for(sp = shell_vars;sp != (struct s_shell *)0;sp = sp->next) { + if (sp->name != (char *)0) + cp += sprintf(cp,"%s=%s\n",sp->name,sp->val); + } + *cp = 0; /* Append NULL after final separator */ + return(envp); +} + +/* clearenv(): + * Clear out the entire environment. + */ +void +clearenv(void) +{ + struct s_shell *sp; + + for(sp = shell_vars;sp != (struct s_shell *)0;sp = sp->next) { + if (sp->name != (char *)0) { + env_free(sp->name); + env_free(sp->val); + sp->name = (char *)0; + sp->val = (char *)0; + } + } +} + +/* setenv: + * Interface to shell_dealloc() and shell_alloc(). + */ +int +setenv(char *name,char *value) +{ + if (!shell_vars) + return(-1); + if ((value == (char *)0) || (*value == 0)) + return(shell_dealloc(name)); + else + return(shell_alloc(name,value)); +} + +/* shell_print(): + * Print out all of the current shell variables and their values. + */ +int +shell_print(void) +{ + int maxlen, len; + char format[8]; + register struct s_shell *sp; + + /* Before printing the list, pass through the list to determine the + * largest variable name. This is used to create a format string + * that is then passed to printf() when printing the list of + * name/value pairs. It guarantees that regardless of the length + * of the name, the format of the printed out put will be consistent + * for all variables. + */ + maxlen = 0; + sp = shell_vars; + while(1) { + if (sp->name) { + len = strlen(sp->name); + if (len > maxlen) + maxlen = len; + } + if (sp->next != (struct s_shell *)0) + sp = sp->next; + else + break; + } + sprintf(format,"%%%ds = ",maxlen+1); + + /* Now that we know the size of the largest variable, we can + * print the list cleanly... + */ + sp = shell_vars; + while(1) { + if (sp->name != (char *)0) { + printf(format, sp->name); + puts(sp->val); /* sp->val may overflow printf, so use puts */ + } + if (sp->next != (struct s_shell *)0) + sp = sp->next; + else + break; + } + return(0); +} + +/* shell_sprintf(): + * Simple way to turn a printf-like formatted string into a shell variable. + */ +int +shell_sprintf(char *varname, char *fmt, ...) +{ + int tot; + char buf[CMDLINESIZE]; + va_list argp; + + va_start(argp,fmt); + tot = vsnprintf(buf,CMDLINESIZE-1,fmt,argp); + va_end(argp); + setenv(varname,buf); + return(tot); +} + + +#if INCLUDE_TFS +/* validEnvToExecVar(): + * Return 1 if the variable should be included in the script + * generated by envToExec(); else return 0. + * Specifically... if the variable is generated internally + * then we don't want to include it in the script. + */ +int +validEnvToExecVar(char *varname) +{ + char **vp; + static char *invalid_varprefixes[] = { + "ARG", "TFS_PREFIX_", "TFS_START_", + "TFS_END_", "TFS_SPARE_", "TFS_SPARESZ_", + "TFS_SCNT_", "TFS_DEVINFO_", "FLASH_BASE_", + "FLASH_SCNT_", "FLASH_END_", + 0 + }; + static char *invalid_varnames[] = { + "APPRAMBASE", "BOOTROMBASE", "CMDSTAT", + "CONSOLEBAUD", "MALLOC", "MONCOMPTR", + "MONITORBUILT", "PLATFORM", "PROMPT", + "TFS_DEVTOT", "FLASH_DEVTOT", "PROMPT", + "VERSION_MAJ", "VERSION_MIN", "VERSION_TGT", + "MONCMD_SRCIP", "MONCMD_SRCPORT", +#if INCLUDE_HWTMR + "TARGETTIMER", "TICKSPERMSEC", +#endif + 0 + }; + + if (varname == 0) + return(0); + + if (strncmp(varname,"ARG",3) == 0) + return(0); + +#if INCLUDE_BOARDINFO + if (BoardInfoVar(varname)) + return(0); +#endif + + for(vp=invalid_varnames;*vp;vp++) { + if (!strcmp(varname,*vp)) + return(0); + } + for(vp=invalid_varprefixes;*vp;vp++) { + if (!strncmp(varname,*vp,strlen(*vp))) + return(0); + } + return(1); +} + +/* envToExec(): + Create a file of "set" commands that can be run to recreate the + current environment. + Changed Oct 2008 to eliminate use of getAppRamStart(). +*/ +int +envToExec(char *filename) +{ + int err, vartot, size, rc; + char *buf, *bp, *cp; + register struct s_shell *sp; + + sp = shell_vars; + vartot = size = rc = 0; + + /* First go through the list to see how much space we need + * to allocate... + */ + while(1) { + if (validEnvToExecVar(sp->name)) { + size += strlen(sp->name) + 6; + cp = sp->val; + while(*cp) { + if (*cp == '$') + size++; + size++; + cp++; + } + size += 3; + vartot++; + } + if (sp->next != (struct s_shell *)0) + sp = sp->next; + else + break; + } + if (size == 0) + return(0); + + /* Now that we know the space needed (stored in 'size' variable), + * allocate it and build the new file in that space, then use tfsadd() + * to create the file... + */ + vartot = 0; + sp = shell_vars; + buf = bp = (char *)env_alloc(size); + while(1) { + /* Note: if this code changes, then the code above that is used to + * allocate the buffer size may also need to change... + */ + if (validEnvToExecVar(sp->name)) { + bp += sprintf(bp,"set %s \"",sp->name); + cp = sp->val; + while(*cp) { + if (*cp == '$') + *bp++ = '\\'; + *bp++ = *cp++; + } + *bp++ = '\"'; + *bp++ = '\n'; + *bp = 0; + vartot++; + } + if (sp->next != (struct s_shell *)0) + sp = sp->next; + else + break; + } + if (vartot > 0) { + err = tfsadd(filename,"envsetup","e",(unsigned char *)buf,strlen(buf)); + if (err != TFS_OKAY) { + printf("%s: %s\n",filename,(char *)tfsctrl(TFS_ERRMSG,err,0)); + rc = -1; + } + } + env_free(buf); + return(rc); +} +#endif + +#else + +/* The 'set' command is part of the build even if INCLUDE_SHELLVARS + * is false. This allows the user to still access teh "set -b ###" + * facility for changing the baudrate. + */ +char *SetHelp[] = { + "Set baud", + "-[b:] (no args)", +#if INCLUDE_VERBOSEHELP + " -b set console baudrate", +#endif + 0, +}; + +int +Set(int argc,char *argv[]) +{ + int opt; + + while((opt=getopt(argc,argv,"b:")) != -1) { + switch(opt) { + case 'b': + ChangeConsoleBaudrate(atoi(optarg)); + return(CMD_SUCCESS); + break; + default: + return(CMD_PARAM_ERROR); + } + } + printf("Shell vars not included in build.\n"); + return(CMD_FAILURE); +} + +int +setenv(char *name,char *value) +{ + return(-1); +} + +char * +getenv(char *name) +{ + return(0); +} + +int +shell_sprintf(char *varname, char *fmt, ...) +{ + return(0); +} + +void +ConsoleBaudEnvSet(void) +{ +} + +char * +getenvp(void) +{ + return(0); +} + +#endif + +/* ChangeConsoleBaudrate(): + * Called to attempt to adjust the console baudrate. + * Support 2 special cases: + * if baud == 0, then just turn off console echo; + * if baud == 1, turn it back on. + */ +int +ChangeConsoleBaudrate(int baud) +{ + if (baud == 0) + console_echo(0); + else if (baud == 1) + console_echo(1); + else { + if (ConsoleBaudSet(baud) < 0) { + printf("Baud=%d failed\n",baud); + return(-1); + } + ConsoleBaudRate = baud; + ConsoleBaudEnvSet(); + } + return(0); +} + diff --git a/main/common/ether.h b/main/common/ether.h new file mode 100644 index 0000000..8fd470d --- /dev/null +++ b/main/common/ether.h @@ -0,0 +1,714 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * ether.h: + * + * This file is a single "contains-all" header file to support different + * components of ethernet/IP along with the peer and upper layer protocols + * like ICMP, UDP, TFTP, DHCP etc... + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#ifndef _ETHER_H_ +#define _ETHER_H_ + +#define __PACKED__ __attribute__ ((packed)) + +#ifndef INCLUDE_MONCMD +#define INCLUDE_MONCMD INCLUDE_ETHERNET +#endif + +#ifndef INCLUDE_ETHERVERBOSE +#define INCLUDE_ETHERVERBOSE INCLUDE_ETHERNET +#endif + +#ifndef INCLUDE_RARPIPASSIGN +#define INCLUDE_RARPIPASSIGN INCLUDE_ETHERNET +#endif + +/************************************************************************ + * + * Default MAC & IP addresses... + * + */ + +#ifndef DEFAULT_ETHERADD +#define DEFAULT_ETHERADD "00:00:00:00:00:00" +#endif + +#ifndef DEFAULT_IPADD +#define DEFAULT_IPADD "0.0.0.0" +#endif + +/************************************************************************ + * + * Retransmission delay stuff... + * + */ + +#define DELAY_INIT_ARP 1 +#define DELAY_INIT_DHCP 2 +#define DELAY_INIT_TFTP 3 +#define DELAY_INCREMENT 4 +#define DELAY_RETURN 5 +#define DELAY_OR_TIMEOUT_RETURN 6 +#define RETRANSMISSION_TIMEOUT -1 +#define RETRANSMISSION_ACTIVE 1 + +/************************************************************************ + * + * Ethernet stuff... + * + */ + +struct ether_addr { + unsigned char ether_addr_octet[6]; +} __PACKED__ ; + +struct ether_header { + struct ether_addr ether_dhost; + struct ether_addr ether_shost; + unsigned short ether_type; +} __PACKED__ ; +#define ETHERSIZE sizeof(struct ether_header) + +#define ETHERTYPE_PUP 0x0200 /* PUP protocol */ +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#define ETHERTYPE_ARP 0x0806 /* Addr resolution protocol */ +#define ETHERTYPE_REVARP 0x8035 /* Reverse ARP */ + +#define ETHER_MINPKT 64 + +/************************************************************************ + * + * ARP/RARP stuff... + * + */ + +#define SIZEOFARPCACHE 8 + +#define ARPSIZE (sizeof(struct ether_header) + sizeof(struct arphdr)) + +struct arphdr { + unsigned short hardware; /* 1 for ethernet */ + unsigned short protocol; + unsigned char hlen; + unsigned char plen; + unsigned short operation; + unsigned char senderha[6]; + unsigned char senderia[4]; + unsigned char targetha[6]; + unsigned char targetia[4]; +} __PACKED__ ; + +/* ARP/RARP operations:. */ +#define ARP_REQUEST 1 +#define ARP_RESPONSE 2 +#define RARP_REQUEST 3 +#define RARP_RESPONSE 4 + +/************************************************************************ + * + * IP stuff... + * + */ + +struct in_addr { + unsigned long s_addr; +} __PACKED__ ; + +#define getIP_V(x) ((x)>>4) +#define getIP_HL(x) ((x)&0xf) +#define IP_DONTFRAG 0x4000 /* dont fragment flag */ +#define IP_MOREFRAGS 0x2000 /* more fragments flag */ +#define IP_VER 0x4 +#define IP_HDR_LEN (sizeof(struct ip)>>2) +#define IP_HDR_VER_LEN ((IP_VER<<4)|IP_HDR_LEN) +#define IP_HLEN(ihdr) ((ihdr->ip_vhl&0x0f)<<2) + +struct ip { + unsigned char ip_vhl; /* version & header length */ + unsigned char ip_tos; /* type of service */ + short ip_len; /* total length */ + unsigned short ip_id; /* identification */ + short ip_off; /* fragment offset field */ + unsigned char ip_ttl; /* time to live */ + unsigned char ip_p; /* protocol */ + unsigned short ip_sum; /* checksum */ + struct in_addr ip_src; /* source address */ + struct in_addr ip_dst; /* dest address */ +} __PACKED__ ; +#define IPSIZE sizeof(struct ip) + +/* ip protocols */ +#define IP_IP 0 +#define IP_ICMP 1 +#define IP_IGMP 2 +#define IP_GGP 3 +#define IP_TCP 6 +#define IP_PUP 12 +#define IP_UDP 17 + +#define IP1(a) ((a & 0xff000000) >> 24) +#define IP2(a) ((a & 0xff0000) >> 16) +#define IP3(a) ((a & 0xff00) >> 8) +#define IP4(a) (a & 0xff) + +#define IP2LONG(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | d) + +/************************************************************************ + * + * ICMP stuff... + * + */ + +#define ICMP_UNREACHABLESIZE (sizeof(struct ether_header) + \ + sizeof(struct ip) + sizeof(struct icmp_unreachable_hdr) + datalen) +#define ICMP_TIMERQSTSIZE (sizeof(struct ether_header) + \ + sizeof(struct ip) + sizeof(struct icmp_time_hdr)) +#define ICMP_ECHORQSTSIZE (sizeof(struct ether_header) + \ + sizeof(struct ip) + sizeof(struct icmp_echo_hdr)) + +#define INVALID_TIMESTAMP 0xffffffff +#define NONSTANDARD_TIMESTAMP 0x80000000 + +/* ICMP protocol header. + */ +struct icmp_hdr { + unsigned char type; /* type of message */ + unsigned char code; /* type subcode */ + unsigned short cksum; /* ones complement cksum of struct */ +} __PACKED__ ; + +/* ICMP time request. + */ +struct icmp_time_hdr { + unsigned char type; /* type of message */ + unsigned char code; /* type subcode */ + unsigned short cksum; /* ones complement cksum of struct */ + unsigned short id; /* identifier */ + unsigned short seq; /* sequence number */ + unsigned long orig; /* originate timestamp */ + unsigned long recv; /* receive timestamp */ + unsigned long xmit; /* transmit timestamp */ +} __PACKED__ ; + +/* ICMP echo reply. + */ +struct icmp_echo_hdr { + unsigned char type; /* type of message */ + unsigned char code; /* type subcode */ + unsigned short cksum; /* ones complement cksum of struct */ + unsigned short id; /* identifier */ + unsigned short seq; /* sequence number */ +} __PACKED__ ; + +struct icmp_unreachable_hdr { + unsigned char type; /* type of message */ + unsigned char code; /* type subcode */ + unsigned short cksum; /* ones complement cksum of struct */ + unsigned short unused1; /* Is alway zero */ + unsigned short unused2; /* Is alway zero */ +} __PACKED__ ; + +/* ICMP types + */ +#define ICMP_ECHOREPLY 0 +#define ICMP_DESTUNREACHABLE 3 +#define ICMP_SOURCEQUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHOREQUEST 8 +#define ICMP_TIMEEXCEEDED 11 +#define ICMP_PARAMPROBLEM 12 +#define ICMP_TIMEREQUEST 13 +#define ICMP_TIMEREPLY 14 +#define ICMP_INFOREQUEST 15 +#define ICMP_INFOREPLY 16 +#define ICMP_ADDRMASKREQUEST 17 +#define ICMP_ADDRMASKREPLY 18 + +/* A few unreachable codes. + */ +#define ICMP_UNREACHABLE_PROTOCOL 2 +#define ICMP_UNREACHABLE_PORT 3 +#define ICMP_DEST_UNREACHABLE_MAX_CODE 12 + +/************************************************************************ + * + * UDP stuff... + * + */ + +/* UDP protocol header. + */ +struct Udphdr { + unsigned short uh_sport; /* source port */ + unsigned short uh_dport; /* destination port */ + unsigned short uh_ulen; /* udp length */ + unsigned short uh_sum; /* udp checksum */ +} __PACKED__ ; +#define UDPSIZE sizeof(struct Udphdr) + +/* UDP pseudo header. + */ +struct UdpPseudohdr { + struct in_addr ip_src; /* source address */ + struct in_addr ip_dst; /* dest address */ + unsigned char zero; /* fixed to zero */ + unsigned char proto; /* protocol */ + unsigned short ulen; /* udp length */ +} __PACKED__ ; + +#define UDP_OPEN 2 +#define UDP_DATA 3 +#define UDP_ACK 4 +#define UDP_TTL 0x3c + +/************************************************************************ + * + * IGMP stuff... + * + */ + +/* IGMP protocol header. + */ +struct Igmphdr { + unsigned char type; /* IGMP message type */ + unsigned char mrt; /* Max response time */ + unsigned short csum; /* Checksum of IGMP header */ + unsigned long group; /* Multicast group ip */ +} __PACKED__ ; + +#define IGMPSIZE sizeof(struct Igmphdr) + +#define IGMPTYPE_QUERY 0x11 +#define IGMPTYPE_REPORTV1 0x12 +#define IGMPTYPE_REPORTV2 0x16 +#define IGMPTYPE_JOIN IGMPTYPE_REPORTV2 +#define IGMPTYPE_LEAVE 0x17 + +#define ALL_HOSTS 0xe0000001 /* 224.0.0.1 */ +#define ALL_MULTICAST_ROUTERS 0xe0000002 /* 224.0.0.2 */ + +#define IGMP_JOINRQSTSIZE (sizeof(struct ether_header) + \ + sizeof(struct ip) + sizeof(long) + sizeof(struct Igmphdr)) + +/************************************************************************ + * + * TFTP stuff... + * + */ + +/* TFTP state values: + */ +#define TFTPOFF 0 +#define TFTPIDLE 1 +#define TFTPACTIVE 2 +#define TFTPERROR 3 +#define TFTPSENTRRQ 4 +#define TFTPTIMEOUT 5 +#define TFTPHOSTERROR 6 +#define TFTPSENTWRQ 7 + +/* TFTP opcode superset (see Stevens pg 466) + */ +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DAT 3 +#define TFTP_ACK 4 +#define TFTP_ERR 5 +#define TFTP_OACK 6 /* RFC2347: Option Acknowledgement opcode. */ + +/* TFTP is UDP port 69... (see Stevens pg 206) + */ +#define IPPORT_TFTP 69 +#define IPPORT_TFTPSRC 8888 + +#define TFTP_NETASCII_WRQ 1 +#define TFTP_NETASCII_RRQ 2 +#define TFTP_OCTET_WRQ 3 +#define TFTP_OCTET_RRQ 4 +#define TFTP_DATAMAX 512 +#define TFTP_PKTOVERHEAD (ETHERSIZE + IPSIZE + UDPSIZE) +#define TFTPACKSIZE (TFTP_PKTOVERHEAD + 4) + +/************************************************************************ + * + * DHCP stuff... + * See RFCs 2131 & 2132 for more details. + * Note that the values used for dhcpstate enum are based on the state + * diagram in 3rd Edition Comer pg 375. Plus a few more so that I can + * used the same enum for DHCP and BOOTP. + * + */ + +#define BOOTPSIZE (sizeof(struct ether_header) + sizeof(struct ip) + \ + sizeof(struct Udphdr) + sizeof(struct bootphdr)) + +#define DHCPSIZE (sizeof(struct ether_header) + sizeof(struct ip) + \ + sizeof(struct Udphdr) + sizeof(struct dhcphdr)) + +#define IPPORT_DHCP_SERVER 67 +#define IPPORT_DHCP_CLIENT 68 + +#define DHCPBOOTP_REQUEST 1 +#define DHCPBOOTP_REPLY 2 + +#define USE_NULL 0 +#define USE_DHCP 1 +#define USE_BOOTP 2 + +#define DHCP_VERBOSE (SHOW_DHCP|SHOW_INCOMING|SHOW_OUTGOING|SHOW_BROADCAST) + +/* DHCP Message types: + */ +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNACK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 +#define DHCPFORCERENEW 9 +#define DHCPLEASEQUERY 10 +#define DHCPLEASEUNASSIGNED 11 +#define DHCPLEASEUNKNOWN 12 +#define DHCPLEASEACTIVE 13 +#define DHCPUNKNOWN 99 + +/* DHCPState (short) values: (upper bit set = bootp) + */ +#define DHCPSTATE_INITIALIZE 0x0001 +#define DHCPSTATE_INITDELAY 0x0002 +#define DHCPSTATE_SELECT 0x0003 +#define DHCPSTATE_REQUEST 0x0004 +#define DHCPSTATE_BOUND 0x0005 +#define DHCPSTATE_RENEW 0x0006 +#define DHCPSTATE_REBIND 0x0007 +#define DHCPSTATE_NOTUSED 0x0008 +#define DHCPSTATE_RESTART 0x0009 +#define BOOTP_MODE 0x8000 +#define BOOTPSTATE_INITIALIZE 0x8001 +#define BOOTPSTATE_INITDELAY 0x8002 +#define BOOTPSTATE_REQUEST 0x8003 +#define BOOTPSTATE_RESTART 0x8004 +#define BOOTPSTATE_COMPLETE 0x8005 + +/* DHCP Options + */ +#define DHCPOPT_SUBNETMASK 1 +#define DHCPOPT_ROUTER 3 +#define DHCPOPT_HOSTNAME 12 +#define DHCPOPT_ROOTPATH 17 +#define DHCPOPT_BROADCASTADDRESS 28 +#define DHCPOPT_VENDORSPECIFICINFO 43 +#define DHCPOPT_REQUESTEDIP 50 +#define DHCPOPT_LEASETIME 51 +#define DHCPOPT_MESSAGETYPE 53 +#define DHCPOPT_SERVERID 54 +#define DHCPOPT_PARMRQSTLIST 55 +#define DHCPOPT_CLASSID 60 +#define DHCPOPT_CLIENTID 61 +#define DHCPOPT_NISDOMAINNAME 64 +#define DHCPOPT_NISSERVER 65 + +#define STANDARD_MAGIC_COOKIE 0x63825363 /* 99.130.83.99 */ + +struct dhcphdr { + unsigned char op; + unsigned char htype; + unsigned char hlen; + unsigned char hops; + unsigned long transaction_id; + unsigned short seconds; + unsigned short flags; + unsigned long client_ip; + unsigned long your_ip; + unsigned long server_ip; + unsigned long router_ip; + unsigned char client_macaddr[16]; + unsigned char server_hostname[64]; + unsigned char bootfile[128]; + unsigned long magic_cookie; + /* Dhcp options would start here */ +} __PACKED__ ; + +struct bootphdr { + unsigned char op; + unsigned char htype; + unsigned char hlen; + unsigned char hops; + unsigned long transaction_id; + unsigned short seconds; + unsigned short unused; + unsigned long client_ip; + unsigned long your_ip; + unsigned long server_ip; + unsigned long router_ip; + unsigned char client_macaddr[16]; + unsigned char server_hostname[64]; + unsigned char bootfile[128]; + unsigned char vsa[64]; +} __PACKED__ ; + +unsigned char *DhcpGetOption(unsigned char, unsigned char *); + +/************************************************************************ + * + * DNS stuff... + * + * The area of the dnshdr structure beginning with the question array + * is actually a variable sized area for four sections: + * question, answer, authority and additional information. + * For the monitor's implementation of DNS, it is simplified to need + * only the question section because we are only using this to do + * a standard DNS query (give a domain name to a server and wait for + * a response that has the IP address). + * So, for the sake of building a fixed size structure, we allocate a + * 64 byte question section and assume that no single domain name request + * will exceed that length. + * Note: first byte of domain name is the size. + * + * For MulticastDNS information I used... + * http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt + */ +#define MAX_DOMAIN_NAME_SIZE 63 + +struct dnshdr { + unsigned short id; + unsigned short param; + unsigned short num_questions; + unsigned short num_answers; + unsigned short num_authority; + unsigned short num_additional; + unsigned char question[MAX_DOMAIN_NAME_SIZE+1]; +} __PACKED__ ; + +#define IPPORT_DNS 53 +#define TYPE_A 1 +#define TYPE_CNAME 5 +#define CLASS_IN 1 + +/* DNS Error codes: + */ +#define DNSERR_NULL 0 +#define DNSERR_COMPLETE 1 +#define DNSERR_NOSRVR 2 +#define DNSERR_SOCKETFAIL 3 +#define DNSERR_FORMATERR 4 +#define DNSERR_SRVRFAILURE 5 +#define DNSERR_NAMENOEXIST 6 +#define DNSERR_BADRESPTYPE 7 +#define DNSERR_BADQSTNCOUNT 8 +#define DNSERR_BADANSWRCOUNT 9 +#define DNSERR_NOTARESPONSE 10 +#define DNSERR_BADRESPID 11 + +#define DNSMCAST_IP IP2LONG(224,0,0,251) +#define DNSMCAST_PORT 5353 + +/* DNS Buffer sizes: + */ +#define MAX_CACHED_HOSTNAMES 32 +#define MAX_HOSTNAME_SIZE 255 + +#define DNS_RETRY_MAX 5 +#define DNS_PKTBUF_SIZE 512 + +struct dnserr { + int errno; + char *errstr; +}; + +struct dnscache { + int idx; + unsigned long addr; + char name[MAX_HOSTNAME_SIZE+1]; +}; + +extern const char mDNSIp[]; + +/************************************************************************ + * + * TCP stuff... + * + */ + +struct tcphdr { + unsigned short sport; /* Source port */ + unsigned short dport; /* Source port */ + unsigned long seqno; /* Sequence number */ + unsigned long ackno; /* Acknowledgment number */ + unsigned short flags; /* Flags (lower 6 bits) */ + unsigned short windowsize; /* Window size */ + unsigned short tcpcsum; /* TCP checksum */ + unsigned short urgentptr; /* Urgent pointer */ +/* options (if any) & data (if any) follow */ +} __PACKED__ ; + +/* Masks for flags (made up of flag bits, reserved bits & header length): + */ +#define TCP_FLAGMASK 0x003F +#define TCP_RSVDMASK 0x0FC0 +#define TCP_HDRLENMASK 0xF000 +#define TCP_HLEN(tp) (((tp)->flags & TCP_HDRLENMASK) >> 10) + +/* Masks for flag bits within flags member: + */ +#define TCP_FINISH 0x0001 +#define TCP_SYNC 0x0002 +#define TCP_RESET 0x0004 +#define TCP_PUSH 0x0008 +#define TCP_ACK 0x0010 +#define TCP_URGENT 0x0020 + + +/************************************************************************ + * + * Miscellaneous... + * + */ + +/* Port that is used to issue monitor commands through ethernet. + */ +#define MONRESPSIZE (sizeof(struct ether_header) + sizeof(struct ip) + \ + sizeof(struct Udphdr) + idx) +#define IPPORT_MONCMD 777 +#define IPPORT_GDB 1234 + +/* Verbosity levels used by various ethernet layers: + */ +#define SHOW_INCOMING 0x00000001 +#define SHOW_OUTGOING 0x00000002 +#define SHOW_HEX 0x00000004 +#define SHOW_BROADCAST 0x00000008 +#define SHOW_TFTP_TICKER 0x00000010 +#define SHOW_DHCP 0x00000020 +#define SHOW_ARP 0x00000040 +#define SHOW_ASCII 0x00000080 +#define SHOW_BADCSUM 0x00000100 +#define SHOW_BADCSUMV 0x00000200 +#define SHOW_PHY 0x00000400 +#define SHOW_GDB 0x00000800 +#define SHOW_TFTP_STATE 0x00001000 +#define SHOW_DRIVER_DEBUG 0x00002000 +#define SHOW_ALL 0xffffffff + +#define ENET_DEBUG_ENABLED() (EtherVerbose & SHOW_DRIVER_DEBUG) + +#define ETHER_INCOMING 1 +#define ETHER_OUTGOING 2 + +extern char *Etheradd, *IPadd; +extern unsigned char etheraddr[], ipaddr[]; +extern unsigned short MoncmdPort, TftpPort, TftpSrcPort; +extern unsigned short DhcpClientPort, DhcpServerPort, DHCPState; +extern int EtherVerbose, IPMonCmdActive, EtherIsActive, EtherPollingOff; +extern unsigned char BinEnetAddr[], BinIpAddr[]; +extern unsigned char AllZeroAddr[], BroadcastAddr[]; +extern int EtherXFRAMECnt, EtherRFRAMECnt, EtherIPERRCnt, EtherUDPERRCnt; + +extern int getAddresses(void); +extern int IpToBin(char *,unsigned char *); +extern int EtherToBin(char *,unsigned char *); +extern char *extGetIpAdd(void), *extGetEtherAdd(void); +extern char *IpToString(unsigned long, char *); +extern char *EtherToString(unsigned char *,char *); +extern unsigned short ipId(void); +extern unsigned char *ArpEther(unsigned char *,unsigned char *,int); +extern unsigned char *getXmitBuffer(void); +extern unsigned char *EtherFromCache(unsigned char *); +extern void ipChksum(struct ip *), udpChksum(struct ip *); +extern void tcpChksum(struct ip *); +#if INCLUDE_ETHERVERBOSE +extern void printPkt(struct ether_header *,int,int); +#else +#define printPkt(a,b,c) +#endif +extern void DhcpBootpDone(int, struct dhcphdr *,int); +extern void DhcpVendorSpecific(struct dhcphdr *); +extern int sendBuffer(int); +extern struct ether_header *EtherCopy(struct ether_header *); +extern int ValidDHCPOffer(struct dhcphdr *); +extern int buildDhcpHdr(struct dhcphdr *); +extern int printDhcpVSopt(int,int,char *); +extern int RetransmitDelay(int); +extern int tftpGet(unsigned long,char *,char *,char *,char *,char *,char *); +extern void printDhcp(struct Udphdr *); +extern int printIp(struct ip*); +extern int printUdp(struct Udphdr *,char *); +extern int printIgmp(struct Igmphdr *,char *); +extern void processPACKET(struct ether_header *,unsigned short); +extern void processTCP(struct ether_header *,unsigned short); +extern int processTFTP(struct ether_header *,unsigned short); +extern int processICMP(struct ether_header *,unsigned short); +extern char *processARP(struct ether_header *,unsigned short); +extern int processDHCP(struct ether_header *,unsigned short); +extern int processRARP(struct ether_header *,unsigned short); +extern int processGDB(struct ether_header *,unsigned short); +extern int processDNS(struct ether_header *,unsigned short); +extern int processMCASTDNS(struct ether_header *,unsigned short); +extern int SendICMPUnreachable(struct ether_header *,unsigned char); +extern void enresetmmu(void), enreset(void); +extern void ShowEtherdevStats(void), ShowTftpStats(void), ShowDhcpStats(void); +extern void enablePromiscuousReception(void); +extern void disablePromiscuousReception(void); +extern int enselftest(int), polletherdev(void), EtherdevStartup(int); +extern void DisableEtherdev(void); +extern void tftpStateCheck(void), dhcpStateCheck(void); +extern int DhcpIPCheck(char *); +extern void dhcpDisable(void); +extern void tftpInit(void); +extern void disableBroadcastReception(void); +extern void enableBroadcastReception(void); +extern void sendGratuitousArp(void); + +extern unsigned long getHostAddr(char *); +extern int dnsCacheDelName(char *); +extern void dnsCacheInit(void); +extern int dnsCacheAdd(char *, unsigned long); +extern int dnsCacheDelAddr(unsigned long); +extern short DnsPort; + +#if INCLUDE_ETHERNET +extern int pollethernet(void); +extern int EthernetStartup(int,int); +#else +#define pollethernet() +#define EthernetStartup(a,b) +#endif + +#if INCLUDE_MONCMD +extern int SendIPMonChar(unsigned char,int); +#else +#define SendIPMonChar(a,b) +#endif + +extern int DisableEthernet(void); +extern void storeMac(int); +extern void GetBinNetMask(unsigned char *binnetmask); +extern int monSendEnetPkt(char *pkt, int cnt); +extern int monRecvEnetPkt(char *pkt, int cnt); +extern void AppPrintPkt(char *buf, int size, int incoming); + +#endif diff --git a/main/common/etheraddr.S b/main/common/etheraddr.S new file mode 100644 index 0000000..901d87e --- /dev/null +++ b/main/common/etheraddr.S @@ -0,0 +1,37 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * etheraddr.S: + * + * Provide space to allow a programmer to place an ascii + * string in this location as an optional point + * of storage for MAC ... + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + .global etheraddr + + .balign 0x10 + +etheraddr: + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff diff --git a/main/common/ethernet.c b/main/common/ethernet.c new file mode 100644 index 0000000..e24d0cd --- /dev/null +++ b/main/common/ethernet.c @@ -0,0 +1,1808 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * ethernet.c: + * + * This code supports most of the generic ethernet/IP/ARP/UDP stuff. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "endian.h" +#include "stddefs.h" +#include "genlib.h" + +#if INCLUDE_ETHERNET +#include "cpuio.h" +#include "ether.h" +#include "monflags.h" +#include "cli.h" +#include "timer.h" + +void ShowEthernetStats(void); + +#if INCLUDE_MONCMD +void executeMONCMD(void); +void processMONCMD(struct ether_header *,ushort); +int SendIPMonChar(uchar,int); +char IPMonCmdLine[CMDLINESIZE]; +int IPMonCmdVerbose; +int IPMonCmdActive; /* Set if MONCMD is in progress. */ +#endif + +#if INCLUDE_DHCPBOOT +#define dhcpStateCheck() dhcpStateCheck() +#define dhcpDisable() dhcpDisable() +#define ShowDhcpStats() ShowDhcpStats() +#else +#define dhcpStateCheck() +#define dhcpDisable() +#define ShowDhcpStats() +#endif + +#if INCLUDE_TFTP +#define tftpStateCheck() tftpStateCheck() +#define tftpInit() tftpInit() +#define ShowTftpStats() ShowTftpStats() +#else +#define tftpStateCheck() +#define tftpInit() +#define ShowTftpStats() +#endif + + +#if INCLUDE_ETHERVERBOSE +int EtherVerbose; /* Verbosity flag (see ether.h). */ +#endif + +char *Etheradd, *IPadd; /* Pointers to ascii addresses */ +uchar BinIpAddr[4]; /* Space for binary IP address */ +uchar BinEnetAddr[6]; /* Space for binary MAC address */ +int EtherPollingOff; /* Non-zero if ethernet polling is off. */ +int EtherIsActive; /* Non-zero if ethernet is up. */ +int EtherIPERRCnt; /* Number of IP errors detected. */ +int EtherUDPERRCnt; /* Number of UDP errors detected. */ +int EtherXFRAMECnt; /* Number of packets transmitted. */ +int EtherRFRAMECnt; /* Number of packets received. */ +int EtherPollNesting; /* Incremented when pollethernet() is called. */ +int MaxEtherPollNesting; /* High-warter mark of EtherPollNesting. */ +ushort UniqueIpId; +ulong IPMonCmdHdrBuf[(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct Udphdr) + 128)/(sizeof(ulong))]; +struct ether_header *IPMonCmdHdr; + +/* AppPktPtr & AppPktLen: + * These two values are used to allow the monitor's ethernet driver + * to easily (not necessarily most efficiently) hook up to an application + * that needs to be able to send and/or receive ethernet packets. + * Refer to discussion above monRecvEnetPkt(). + */ +char *AppPktPtr; +int AppPktLen; + +/* Ports used by the monitor have defaults, but can be redefined using + * shell variables: + */ +ushort MoncmdPort; /* shell var: MCMDPORT */ +ushort GdbPort; /* shell var: GDBPORT */ +ushort DhcpClientPort; /* shell var: DCLIPORT */ +ushort DhcpServerPort; /* shell var: DSRVPORT */ +ushort TftpPort; /* shell var: TFTPPORT */ +ushort TftpSrcPort; /* shell var: TFTPPORT */ + +uchar BroadcastAddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +uchar AllZeroAddr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +#if INCLUDE_ETHERVERBOSE +struct pinfo { + int pnum; + char *pname; +} protocols[] = { + { IP_IP, "IP" }, + { IP_ICMP, "ICMP" }, + { IP_IGMP, "IGMP" }, + { IP_GGP, "GGP" }, + { IP_TCP, "TCP" }, + { IP_PUP, "PUP" }, + { IP_UDP, "UDP" }, + { 0,0 }, +}; + +struct enet_verbosity { + char letter; + ulong flags; +} enet_verbose_tbl[] = { + { '0', 0 }, + { 'a', SHOW_ARP | SHOW_BROADCAST }, + { 'c', SHOW_BADCSUM }, + { 'C', SHOW_BADCSUM | SHOW_BADCSUMV }, + { 'd', SHOW_DHCP }, +#if INCLUDE_GDB + { 'g', SHOW_GDB }, +#endif + { 'i', SHOW_INCOMING }, + { 'I', SHOW_INCOMING | SHOW_BROADCAST }, + { 'o', SHOW_OUTGOING }, + { 'p', SHOW_PHY }, + { 't', SHOW_TFTP_STATE }, + { 'x', SHOW_HEX }, + { 'X', SHOW_HEX | SHOW_ASCII }, + { 0,0 } +}; + +int +SetEthernetVerbosity(char *letters) +{ + ulong verbose = 0; + struct enet_verbosity *evp = enet_verbose_tbl; + + while(*letters) { + evp = enet_verbose_tbl; + while(evp->letter) { + if (*letters == evp->letter) { + verbose |= evp->flags; + break; + } + evp++; + } + if (evp->letter == 0) { + printf("Invalid verbosity: '%c'\n",*letters); + return(CMD_PARAM_ERROR); + } + + letters++; + } + EtherVerbose = verbose; + return(CMD_SUCCESS); +} +#endif + +char *EtherHelp[] = { + "Ethernet interface", + "-[d:pt:v:V] {cmd} [cmd args]", +#if INCLUDE_VERBOSEHELP + "Options...", + " -d {1|0} driver debug mode (1=on)", + " -p {1|0} promiscuous mode (1=on)", + " -t self-test ethernet interface", +#if INCLUDE_ETHERVERBOSE + " -v {flgs} enable specific verbosity...", + " 0: turn off verbosity", + " a: enable ARP trace", + " c: print csum errmsg", + " C: dump csum errpkt", + " d: enable DHCP trace", +#if INCLUDE_GDB + " g: enable GDB trace", +#endif + " i: incoming packets (minus broadcast)", + " I: incoming packets (including broadcast)", + " o: outgoing packets", + " p: phy r/w accesses", + " t: enable TFTP trace", + " x: enable hex dump (requires i,I or o)", + " X: same as 'x' plus ascii", + " -V full verbosity (same as -v Iodtx)", +#endif + "", + "Commands...", + " {on | off | mac | stat | {print I|i|O pkt len} | {psnd addr len}}", +#endif + 0 +}; + + +int +Ether(int argc,char *argv[]) +{ + int opt; + + /* Automatically turn polling on if this command is issued. + */ + EtherPollingOff = 0; + + while ((opt=getopt(argc,argv,"d:p:s:tv:V")) != -1) { + switch(opt) { + case 'p': + if (*optarg == '1') + enablePromiscuousReception(); + else + disablePromiscuousReception(); + return(CMD_SUCCESS); + case 't': + if (EtherIsActive == 0) { + printf("Selftest requires active driver to run\n"); + return(CMD_FAILURE); + } + enselftest(1); + return(CMD_SUCCESS); +#if INCLUDE_ETHERVERBOSE + case 'd': + if (*optarg == '1') + EtherVerbose |= SHOW_DRIVER_DEBUG; + else + EtherVerbose &= ~SHOW_DRIVER_DEBUG; + return(CMD_SUCCESS); + case 'V': + EtherVerbose = SHOW_ALL; + return(CMD_SUCCESS); + case 'v': + return(SetEthernetVerbosity(optarg)); +#endif + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc <= optind) + return(CMD_SUCCESS); + + if (!strcmp(argv[optind],"off")) { + enreset(); + EtherIsActive = 0; + return(CMD_SUCCESS); + } +#if INCLUDE_ETHERVERBOSE + else if (!strcmp(argv[optind],"print")) { + if (argc == optind+4) { + int len, mode; + ulong overbose; + struct ether_header *pkt; + + overbose = EtherVerbose; + switch(argv[optind+1][0]) { + case 'O': + mode = ETHER_OUTGOING; + EtherVerbose = SHOW_ALL; + break; + case 'I': + mode = ETHER_INCOMING; + EtherVerbose = SHOW_ALL; + break; + case 'i': + mode = ETHER_INCOMING; + EtherVerbose = (SHOW_ALL & ~SHOW_BROADCAST); + break; + default: + return(CMD_PARAM_ERROR); + } + pkt = (struct ether_header *)strtol(argv[optind+2],0,0); + len = (int)strtol(argv[optind+3],0,0); + printPkt(pkt,len,mode); + EtherVerbose = overbose; + return(CMD_SUCCESS); + } + else + return(CMD_PARAM_ERROR); + } +#endif + else if (!strcmp(argv[optind],"mac")) { + storeMac(1); + return(CMD_SUCCESS); + } + else if (!strcmp(argv[optind],"psnd")) { + ulong addr, len; + uchar *buf; + addr = strtol(argv[optind+1],0,0); + len = strtol(argv[optind+2],0,0); + buf = getXmitBuffer(); + memcpy((char *)buf,(char *)addr,(int)len); + sendBuffer(len); + return(CMD_SUCCESS); + } + else if (!strcmp(argv[optind],"stat")) { + ShowEthernetStats(); + ShowEtherdevStats(); + ShowDhcpStats(); + ShowTftpStats(); + return(CMD_SUCCESS); + } + else if (strcmp(argv[optind],"on")) + return(CMD_PARAM_ERROR); + +#if INCLUDE_ETHERVERBOSE + EthernetStartup(EtherVerbose,0); +#else + EthernetStartup(0,0); +#endif + return(CMD_SUCCESS); +} + +void +ShowEthernetStats(void) +{ + printf("Ethernet interface currently %sabled.\n", + EtherIsActive ? "en" : "dis"); + printf("Transmitted frames: %d\n",EtherXFRAMECnt); + printf("Received frames: %d\n",EtherRFRAMECnt); + printf("IP hdr cksum errors: %d\n",EtherIPERRCnt); + printf("UDP pkt cksum errors: %d\n",EtherUDPERRCnt); + printf("Max pollethernet nest: %d\n",MaxEtherPollNesting); +} + +/* DisableEthernet(): + * Shut down the interface, and return the state of the + * interface prior to forcing the shut down. + */ +int +DisableEthernet(void) +{ + int eia; + + eia = EtherIsActive; + EtherIsActive = 0; +#if INCLUDE_MONCMD + IPMonCmdActive = 0; +#endif + DisableEtherdev(); + return(eia); +} + +/* EthernetWaitforLinkup(): + * If the ENET_LINK_IS_UP() macro is defined, then use it to poll + * the just-initialized ethernet link so that we don't return from + * this point until the port is active. + * Return: + * 0 if no macro is defined or poll is aborted + * 1 if link is up + * -1 if link is not up + */ +int +EthernetWaitforLinkup(void) +{ + int linkup = 0; + +#ifdef ENET_LINK_IS_UP +#ifndef LINKUP_TICK_MAX +#define LINKUP_TICK_MAX 15 +#endif + extern int ENET_LINK_IS_UP(void); + + int tick; + struct elapsed_tmr tmr; + + if (getenv("ETHERNET_NOWAIT")) + return(0); + + for(tick=0;tick<LINKUP_TICK_MAX;tick++) { + startElapsedTimer(&tmr,500); + while(1) { + if (gotachar()) + goto done; + + if (ENET_LINK_IS_UP()) { + linkup = 1; + goto done; + } + if(msecElapsed(&tmr)) { + if (tick == 0) { + tick++; + printf("Wait for enet link up (hit-a-key to abort) "); + } + else + putchar('.'); + break; + } + } + } + if (tick == LINKUP_TICK_MAX) { + linkup = -1; + printf(" give up."); + DisableEthernet(); + } + +done: + putchar('\n'); +#endif + + return(linkup); +} + +int +EthernetStartup(int verbose, int justreset) +{ + /* Initialize the retransmission delay calculator: */ + RetransmitDelay(DELAY_INIT_DHCP); + + EtherIPERRCnt = 0; + EtherXFRAMECnt = 0; + EtherRFRAMECnt = 0; + EtherUDPERRCnt = 0; +#if INCLUDE_MONCMD + IPMonCmdActive = 0; +#endif + EtherPollNesting = 0; + MaxEtherPollNesting = 0; + DHCPState = DHCPSTATE_NOTUSED; +#if INCLUDE_ETHERVERBOSE + if (getenv("ETHERNET_DEBUG")) + EtherVerbose |= SHOW_DRIVER_DEBUG; + else + EtherVerbose = 0; +#endif + + /* Setup all the IP addresses used by the monitor... */ + if (getAddresses() == -1) + return(-1); + + /* Call device specific startup code: */ + if (EtherdevStartup(verbose) < 0) + return(-1); + + /* Initialize some TFTP state... */ + tftpInit(); + +#if INCLUDE_DHCPBOOT + /* If EthernetStartup is called as a result of anything other than a + * target reset, don't startup any DHCP/BOOTP transaction... + */ + if (!justreset) + dhcpDisable(); +#endif + EtherIsActive = 1; + EtherPollingOff = 0; + + /* Wait for link up state before continuing... + */ + EthernetWaitforLinkup(); + + /* Issue a gratuitous ARP to let other devices on the net know we're + * here, and also to make sure some other device isn't already using + * the IP address that this target is using... + */ + sendGratuitousArp(); + + return(0); +} + +/* pollethernet(): + * Called at a few critical points in the monitor code to poll the + * ethernet device and keep track of the state of DHCP and TFTP. + */ +int +pollethernet(void) +{ + int pcnt; + + if ((!EtherIsActive) || EtherPollingOff || (EtherPollNesting > 4)) + return(0); + + EtherPollNesting++; + if (EtherPollNesting > MaxEtherPollNesting) + MaxEtherPollNesting = EtherPollNesting; + + pcnt = polletherdev(); +#if INCLUDE_MONCMD + if (IPMonCmdLine[0] != 0) + executeMONCMD(); +#endif + + dhcpStateCheck(); + tftpStateCheck(); + + EtherPollNesting--; + return(pcnt); +} + +/* getAddresses(): + * Try getting ether/ip addresses from environment. + * If not there, try getting them from some target-specific interface. + * If not there, then get them from raw flash. + * If not there, just use the hard-coded default. + * Also, load all port numbers from shell variables, else default. + * + * Discussion regarding etheraddr[]... + * The purpose of this array is to provide a point in flash that is + * initialized to 0xff by the code (see reset.s). This then allows some + * other mechanism (storeMAC() or bed of nails, etc..) to program this + * location to some non-0xff value. This allows the base monitor image to + * be common, but then be modified by other code or external hardware. + */ + +int +getAddresses(void) +{ + char *gdbPort, *dcliPort, *dsrvPort, *tftpPort; + + /* Set up port numbers: */ + gdbPort = getenv("GDBPORT"); + dcliPort = getenv("DCLIPORT"); + dsrvPort = getenv("DSRVPORT"); + tftpPort = getenv("TFTPPORT"); + +#if INCLUDE_MONCMD + { + char *mcmdPort = getenv("MCMDPORT"); + if (mcmdPort) + MoncmdPort = (ushort)strtol(mcmdPort,0,0); + else + MoncmdPort = IPPORT_MONCMD; + } +#endif + + if (gdbPort) + GdbPort = (ushort)strtol(gdbPort,0,0); + else + GdbPort = IPPORT_GDB; + if (dcliPort) + DhcpClientPort = (ushort)strtol(dcliPort,0,0); + else + DhcpClientPort = IPPORT_DHCP_CLIENT; + if (dsrvPort) + DhcpServerPort = (ushort)strtol(dsrvPort,0,0); + else + DhcpServerPort = IPPORT_DHCP_SERVER; + if (tftpPort) + TftpPort = (ushort)strtol(tftpPort,0,0); + else + TftpPort = IPPORT_TFTP; /* 69 */ + TftpSrcPort = IPPORT_TFTPSRC; /* 8888 */ + + /* Retrieve MAC address and store in shell variable ETHERADD... + * First see if the shell variable is already loaded. + * If not see if some target-specific interface has it. + * If not see if the the string is stored in raw flash (usually this + * storage is initialized in reset.s of the target-specific code). + * Finally, as a last resort, use the default set up in config.h. + */ + if (!(Etheradd = getenv("ETHERADD"))) { + if (!(Etheradd = extGetEtherAdd())) { +#if INCLUDE_FLASH + if (etheraddr[0] != 0xff) + Etheradd = (char *)etheraddr; + else +#endif + Etheradd = DEFAULT_ETHERADD; + } + setenv("ETHERADD",Etheradd); + } + + /* Apply the same logic as above to the IP address... */ + if (!(IPadd = getenv("IPADD"))) { + if (!(IPadd = extGetIpAdd())) + IPadd = DEFAULT_IPADD; + setenv("IPADD",IPadd); + } + + /* Convert addresses to binary: + */ + if (EtherToBin(Etheradd,BinEnetAddr) < 0) + return(-1); + + /* If the ethernet address is 0:0:0:0:0:0, then we + * return an error here so that the interface is not + * brought up. + */ + if (memcmp((char *)BinEnetAddr, (char *)AllZeroAddr,6) == 0) { + static int firsttime; + + if (firsttime == 0) { + printf("\nNULL MAC address, network interface disabled.\n"); + firsttime = 1; + } + return(-1); + } + +#if INCLUDE_DHCPBOOT + if (DhcpIPCheck(IPadd) == -1) + return(-1); +#else + if (IpToBin(IPadd,BinIpAddr) < 0) + return(-1); +#endif + /* Initialize a unique number based on MAC: */ + UniqueIpId = xcrc16(BinEnetAddr,6); + + return(0); +} + +/* processPACKET(): + * This is the top level of the message processing after a complete + * packet has been received over ethernet. It's all just a lot of + * parsing to determine whether the message is for this board's IP + * address (broadcast reception may be enabled), and the type of + * incoming protocol. Once that is determined, the packet is either + * processed (TFTP, DHCP, ARP, ICMP-ECHO, etc...) or discarded. + */ +void +processPACKET(struct ether_header *ehdr, ushort size) +{ + int i, udpdone; + ushort *datap, udpport; + ulong csum; + struct ip *ihdr; + struct Udphdr *uhdr; + + WATCHDOG_MACRO; + + /* If source MAC address is this board, then assume the MAC is in + * full-duplex mode and we received our own outgoing broadcast + * message (i.e. ignore it)... + */ + if (!memcmp((char *)&(ehdr->ether_shost),(char *)BinEnetAddr,6)) { + return; + } + + printPkt(ehdr,size,ETHER_INCOMING); + + /* AppPktPtr is used by monRecvEnetPkt() so that an application can + * use the monitor's ethernet driver. For more info, refer to notes + * above the monRecvEnetPkt() function. + */ + if (AppPktPtr) { + memcpy(AppPktPtr,(char *)ehdr,size > AppPktLen ? AppPktLen : size); + AppPktPtr = 0; + AppPktLen = size; + return; + } + + EtherRFRAMECnt++; + + if (ehdr->ether_type == ecs(ETHERTYPE_ARP)) { + processARP(ehdr,size); + return; + } + else if (ehdr->ether_type == ecs(ETHERTYPE_REVARP)) { + processRARP(ehdr,size); + return; + } + else if (ehdr->ether_type != ecs(ETHERTYPE_IP)) { + return; + } + + ihdr = (struct ip *) (ehdr + 1); + + /* If not version # 4, return now... */ + if (getIP_V(ihdr->ip_vhl) != 4) { + return; + } + +#if INCLUDE_RARPIPASSIGN + /* If destination MAC address matches ours, and our IP address is + * 0.0.0.0, and this is an ICMP request, then this may be a reverse + * ARP, so we allow this packet through... + * Note that this logic is only applicable if DHCP is NOT running. + */ + if (DHCPState == DHCPSTATE_NOTUSED) { + if (!memcmp((char *)&(ehdr->ether_dhost),(char *)BinEnetAddr,6) && + (BinIpAddr[0] == 0) && (BinIpAddr[1] == 0) && + (BinIpAddr[2] == 0) && (BinIpAddr[3] == 0) && + (ihdr->ip_p == IP_ICMP)) { + goto skipIPAddrFilter; + } + } +#endif + + /* IP address filtering: + * At this point, the only packets accepted are those destined for this + * board's IP address or broadcast to the subnet, plus DHCP, if active, + */ + if (memcmp((char *)&(ihdr->ip_dst),(char *)BinIpAddr,4)) { + long net_mask, sub_net_addr; + +#if INCLUDE_DNS + if (memcmp((char *)&(ihdr->ip_dst),(char *)mDNSIp,4)) { +#endif + GetBinNetMask( (uchar *) &net_mask ); + sub_net_addr = ihdr->ip_dst.s_addr & ~net_mask; /* x.x.x.255 */ + uhdr = (struct Udphdr *)(ihdr+1); + + if ( ihdr->ip_p != IP_UDP + || ecs(uhdr->uh_dport) != MoncmdPort + || sub_net_addr != ~net_mask ) { +#if INCLUDE_DHCPBOOT + if (DHCPState == DHCPSTATE_NOTUSED) + return; + if (ihdr->ip_p != IP_UDP) + return; + uhdr = (struct Udphdr *)(ihdr+1); + if (uhdr->uh_dport != ecs(DhcpClientPort)) { + return; + } +#else + return; +#endif + } +#if INCLUDE_DNS + } +#endif + } + +#if INCLUDE_RARPIPASSIGN +skipIPAddrFilter: +#endif + + /* Verify incoming IP header checksum... + * Refer to section 3.2 of TCP/IP Illustrated, Vol 1 for details. + */ + csum = 0; + datap = (ushort *) ihdr; + for (i=0;i<(sizeof(struct ip)/sizeof(ushort));i++,datap++) + csum += *datap; + csum = (csum & 0xffff) + (csum >> 16); + if (csum != 0xffff) { + EtherIPERRCnt++; +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_BADCSUM) { + printf("IP csum error: 0x%04x != 0xffff\n",(ushort)csum); + if (EtherVerbose & SHOW_BADCSUMV) { + int overbose = EtherVerbose; + + EtherVerbose = SHOW_ALL; + printPkt(ehdr,size,ETHER_INCOMING); + EtherVerbose = overbose; + } + } +#endif + return; + } + +#if INCLUDE_ICMP + if (ihdr->ip_p == IP_ICMP) { + processICMP(ehdr,size); + return; + } + else +#endif + if (ihdr->ip_p == IP_TCP) { + processTCP(ehdr,size); + return; + } + else if (ihdr->ip_p != IP_UDP) { + +#if INCLUDE_ICMP + SendICMPUnreachable(ehdr,ICMP_UNREACHABLE_PROTOCOL); +#endif +#if INCLUDE_ETHERVERBOSE + { + int j; + + if (!(EtherVerbose & SHOW_INCOMING)) + return; + for(j=0;protocols[j].pname;j++) { + if (ihdr->ip_p == protocols[j].pnum) { + printf("%s not supported\n", + protocols[j].pname); + return; + } + } + } +#endif + printf("<%02x> protocol unrecognized\n", ihdr->ip_p); + return; + } + + uhdr = (struct Udphdr *)(ihdr+1); + + /* If non-zero, verify incoming UDP packet checksum... + * Refer to section 11.3 of TCP/IP Illustrated, Vol 1 for details. + */ + if (uhdr->uh_sum) { + int len; + struct UdpPseudohdr pseudohdr; + + memcpy((char *)&pseudohdr.ip_src.s_addr,(char *)&ihdr->ip_src.s_addr,4); + memcpy((char *)&pseudohdr.ip_dst.s_addr,(char *)&ihdr->ip_dst.s_addr,4); + pseudohdr.zero = 0; + pseudohdr.proto = ihdr->ip_p; + pseudohdr.ulen = uhdr->uh_ulen; + + csum = 0; + datap = (ushort *) &pseudohdr; + for (i=0;i<(sizeof(struct UdpPseudohdr)/sizeof(ushort));i++) + csum += *datap++; + + /* If length is odd, pad and add one. */ + len = ecs(uhdr->uh_ulen); + if (len & 1) { + uchar *ucp; + ucp = (uchar *)uhdr; + ucp[len] = 0; + len++; + } + len >>= 1; + + datap = (ushort *) uhdr; + for (i=0;i<len;i++) + csum += *datap++; + csum = (csum & 0xffff) + (csum >> 16); + if (csum != 0xffff) { + EtherUDPERRCnt++; +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_BADCSUM) { + printf("UDP csum error: 0x%04x != 0xffff\n",(ushort)csum); + if (EtherVerbose & SHOW_BADCSUMV) { + int overbose = EtherVerbose; + + EtherVerbose = SHOW_ALL; + printPkt(ehdr,size,ETHER_INCOMING); + printf("pseudohdr.ip_src: 0x%08lx\n", + pseudohdr.ip_src.s_addr); + printf("pseudohdr.ip_dst: 0x%08lx\n", + pseudohdr.ip_dst.s_addr); + printf("pseudohdr.zero: 0x%02x\n", pseudohdr.zero); + printf("pseudohdr.proto: 0x%02x\n", pseudohdr.proto); + printf("pseudohdr.ulen: 0x%04x\n", pseudohdr.ulen); + EtherVerbose = overbose; + } + } +#endif + return; + } + } + udpport = ecs(uhdr->uh_dport); + udpdone = 0; + +#if INCLUDE_MONCMD + if (!udpdone && (udpport == MoncmdPort)) { + processMONCMD(ehdr,size); + udpdone = 1; + } +#endif +#if INCLUDE_DHCPBOOT + if (!udpdone && (udpport == DhcpClientPort)) { + processDHCP(ehdr,size); + udpdone = 1; + } +#endif +#if INCLUDE_TFTP + if (!udpdone && ((udpport == TftpPort) || (udpport == TftpSrcPort))) { + processTFTP(ehdr,size); + udpdone = 1; + } +#endif +#if INCLUDE_DNS + if (!udpdone && (udpport == DnsPort)) { + processDNS(ehdr,size); + udpdone = 1; + } + if (!udpdone && (ecl(ihdr->ip_dst.s_addr) == DNSMCAST_IP) && + (udpport == DNSMCAST_PORT)) { + processMCASTDNS(ehdr,size); + udpdone = 1; + } +#endif +#if INCLUDE_GDB + if (!udpdone && (udpport == GdbPort)) { + processGDB(ehdr,size); + udpdone = 1; + } +#endif + if (!udpdone) { +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_INCOMING) { + uchar *cp; + cp = (uchar *)&(ihdr->ip_src); + printf(" Unexpected IP pkt from %d.%d.%d.%d ", + cp[0],cp[1],cp[2],cp[3]); + printf("(sport=0x%x,dport=0x%x)\n", + ecs(uhdr->uh_sport),ecs(uhdr->uh_dport)); + } +#endif +#if INCLUDE_ICMP + SendICMPUnreachable(ehdr,ICMP_UNREACHABLE_PORT); +#endif + } +} + +#if INCLUDE_MONCMD +#define MONCMD_SRCIP_VARNAME "MONCMD_SRCIP" +#define MONCMD_SRCPORT_VARNAME "MONCMD_SRCPORT" + +/* processMONCMD(): + * This function is called as a result of receiving a packet on port + * 777. It will process the incoming packet as if it was an ASCII + * command destined for MicroMonitor's CLI. + * + * As of Aug 16, 2004, support for NETCAT is also in this function. + * Differentiating between netcat and moncmd is done by looking + * for the terminating newline character which is only present with + * netcat. For example: + * The following host command line: <netcat -u 135.222.140.72 777> + * puts the netcat user into an interactive mode with uMon so + * normal uMon commands can be issued through netcat (until interrupted). + * + * As of Aug 5, 2005, another change has been made to uMon's MONCMD + * server as a result of a bug reported by Leon Pollack. The change + * breaks up the processing of the incoming moncmd request into two + * parts processMONCMD() and executeMONCMD() (refer to CVS log for + * more details): + * + * 1. processMONCMD(): + * Retrieve the incoming message from the ethernet interface and + * store the message in a local buffer to be processed later. + * 2. executeMONCMD(): + * After the ethernet packet has been properly dequeued, then + * process the remote command appropriately. + */ + +void +processMONCMD(struct ether_header *ehdr,ushort size) +{ + int verbose = 0, doitnow = 0; + struct ip *ihdr; + struct Udphdr *uhdr; + char *moncmd; + uchar *src; + + if (size > sizeof(IPMonCmdHdrBuf)) + return; + + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)(ihdr + 1); + moncmd = (char *)(uhdr + 1); + memcpy((char *)IPMonCmdHdrBuf,(char *)ehdr,size); + IPMonCmdHdr = (struct ether_header *)&IPMonCmdHdrBuf; + src = (uchar *)&ihdr->ip_src; + + /* Keep track of who sent the most recent moncmd request: + */ + shell_sprintf(MONCMD_SRCIP_VARNAME,"%d.%d.%d.%d", + src[0],src[1],src[2],src[3]); + shell_sprintf(MONCMD_SRCPORT_VARNAME,"%d",ecs(uhdr->uh_sport)); + + if (!MFLAGS_NOMONCMDPRN()) { + printf("MONCMD (from %s): ",getenv(MONCMD_SRCIP_VARNAME)); + puts(moncmd); + verbose = 1; + } + + if (strlen(moncmd) >= (sizeof(IPMonCmdLine) - 2)) { + printf("MONCMD (from %s): too long\n",getenv(MONCMD_SRCIP_VARNAME)); + return; + } + + /* A leading '.' tells the moncmd server to execute the command now, + * not after the pollethernet queue has been emptied... + */ + if (*moncmd == '.') { + moncmd++; + doitnow = 1; + } + + strcpy(IPMonCmdLine+1,moncmd); + IPMonCmdLine[0] = '+'; + IPMonCmdVerbose = verbose; + + if (doitnow) + executeMONCMD(); +} + +void +executeMONCMD(void) +{ + char *ncnl; /* netcat newline */ + char *moncmd; + + /* Clear the initial '+' character so that this function is + * never executed multiple times because of calls to + * polletherdev() during the MONCMD transaction. + */ + IPMonCmdLine[0] = 0; + + /* If the first character of the incoming command is an '@', then + * the response is not sent back to the client... + */ + moncmd = IPMonCmdLine + 1; + if (*moncmd == '@') { + IPMonCmdActive = 0; + moncmd++; + } + else + IPMonCmdActive = 1; + + /* Added to support netcat... + */ + ncnl = strchr(moncmd,0x0a); + if (ncnl) + *ncnl = 0; + + docommand(moncmd,IPMonCmdVerbose); + + if (ncnl) + writeprompt(); + + if (IPMonCmdActive) { + SendIPMonChar(0,1); + IPMonCmdActive = 0; + } + + stkchk("Post-sendIPmonchar"); + if (!ncnl) + writeprompt(); + + IPMonCmdLine[0] = 0; +} + +int +SendIPMonChar(uchar c, int done) +{ + static int idx; + static char linebuf[128]; + int len, hdrlen; + struct ether_header *te; + struct ip *ti, *ri; + struct Udphdr *tu, *ru; + + if (!IPMonCmdActive) + return(0); + + /* Check for overflow and if detected, reset the buffer pointer... + */ + if (idx >= sizeof(linebuf)) + idx = 0; + + linebuf[idx++] = c; + + if ((idx < sizeof(linebuf)) && (!done) && (c != '\n')) + return(0); + + /* Once inside the meat of this function, clear the IPMonCmdActive flag + * to avoid recursion if an error message is to be printed by some + * called by this function... + */ + IPMonCmdActive = 0; + + hdrlen = sizeof(struct ip) + sizeof(struct Udphdr); + len = idx + hdrlen ; + + te = EtherCopy(IPMonCmdHdr); + + ti = (struct ip *) (te + 1); + ri = (struct ip *) (IPMonCmdHdr + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ti->ip_len = ecs(len); + ti->ip_id = ipId(); + ti->ip_off = ri->ip_off; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), + sizeof(struct in_addr)); + + tu = (struct Udphdr *) (ti + 1); + ru = (struct Udphdr *) (ri + 1); + tu->uh_sport = ru->uh_dport; + tu->uh_dport = ru->uh_sport; + tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + idx)); + memcpy((char *)(tu+1),linebuf,idx); + + ipChksum(ti); /* Compute checksum of ip hdr */ + udpChksum(ti); /* Compute UDP checksum */ + + sendBuffer(MONRESPSIZE); + idx = 0; + IPMonCmdActive = 1; + return(1); +} +#endif + +#if INCLUDE_ETHERVERBOSE +/* + * printPkt(ehdr,len) + */ +void +printPkt(struct ether_header *ehdr, int len, int direction) +{ + struct arphdr *arpp; + char *dir; + + /* Filter based on verbosity level... */ + switch(direction) { + case ETHER_INCOMING: + if (!(EtherVerbose & SHOW_INCOMING)) + return; + dir = "INCOMING"; + break; + case ETHER_OUTGOING: + if (!(EtherVerbose & SHOW_OUTGOING)) + return; + dir = "OUTGOING"; + break; + default: + printf("printPkt() direction error\n"); + dir = "???"; + break; + } + + /* If direction is incoming and SHOW_BROADCAST is not set, then */ + /* return here if the destination host is broadcast. */ + if ((direction == ETHER_INCOMING) && + (!(EtherVerbose & SHOW_BROADCAST)) && + (!memcmp((char *)ehdr->ether_dhost.ether_addr_octet,(char *)BroadcastAddr,6))) + return; + + printf("\n%s PACKET (%d bytes):\n",dir,len); + if (EtherVerbose & SHOW_HEX) + printMem((uchar *)ehdr,len,EtherVerbose & SHOW_ASCII); + printf(" Destination Host = %02x:%02x:%02x:%02x:%02x:%02x\n", + ehdr->ether_dhost.ether_addr_octet[0], + ehdr->ether_dhost.ether_addr_octet[1], + ehdr->ether_dhost.ether_addr_octet[2], + ehdr->ether_dhost.ether_addr_octet[3], + ehdr->ether_dhost.ether_addr_octet[4], + ehdr->ether_dhost.ether_addr_octet[5]); + + printf(" Source Host = %02x:%02x:%02x:%02x:%02x:%02x\n", + ehdr->ether_shost.ether_addr_octet[0], + ehdr->ether_shost.ether_addr_octet[1], + ehdr->ether_shost.ether_addr_octet[2], + ehdr->ether_shost.ether_addr_octet[3], + ehdr->ether_shost.ether_addr_octet[4], + ehdr->ether_shost.ether_addr_octet[5]); + + + switch (ehdr->ether_type) { + case ecs(ETHERTYPE_IP): + printIp((struct ip *)(ehdr+1)); + break; + case ecs(ETHERTYPE_PUP): + printf(" Type = PUP\n"); + break; + case ecs(ETHERTYPE_ARP): + arpp = (struct arphdr *)(ehdr+1); + printf(" Type = ARP %s from IP %d.%d.%d.%d to %d.%d.%d.%d)\n", + arpp->operation == ecs(ARP_RESPONSE) ? "RESPONSE" : "REQUEST", + arpp->senderia[0],arpp->senderia[1], + arpp->senderia[2],arpp->senderia[3], + arpp->targetia[0],arpp->targetia[1], + arpp->targetia[2],arpp->targetia[3]); + break; + case ecs(ETHERTYPE_REVARP): + printf(" Type = REVARP\n"); + break; + default: + printf(" Type = 0x%04x ???\n", ehdr->ether_type); + break; + } +} + +void +AppPrintPkt(char *buf, int size, int incoming) +{ + int overbose, mode; + + overbose = EtherVerbose; + if (incoming) { + EtherVerbose = SHOW_ALL & ~SHOW_OUTGOING; + mode = ETHER_INCOMING; + } + else { + EtherVerbose = SHOW_ALL & ~SHOW_INCOMING; + mode = ETHER_OUTGOING; + } + printPkt((struct ether_header *)buf,size,mode); + EtherVerbose = overbose; +} + +/* + * printIp(p) + */ +int +printIp(struct ip *ihdr) +{ + ushort ipoff; + struct ip *icpy; + int i, ipsize; + char *fragmented; + char buf[16], buf1[16], *payload; + ulong tmp[sizeof(struct ip)/2]; + + ipsize = ((ihdr->ip_vhl & 0x0f) << 2); + + /* Copy data to aligned memory space so printf doesn't crash. */ + memcpy((char *)tmp,(char *)ihdr,sizeof(struct ip)); + icpy = (struct ip *)tmp; + printf(" IP: vhl/tos len id offset ttl/proto csum\n"); + printf(" x%02x%02x x%04x x%04x x%04x x%02x%02x x%04x\n", + icpy->ip_vhl,icpy->ip_tos, ecs(icpy->ip_len), + ecs(icpy->ip_id), ecs(icpy->ip_off), + icpy->ip_ttl, icpy->ip_p, ecs(icpy->ip_sum)); + + printf(" src/dest: %s / %s\n", + IpToString(icpy->ip_src.s_addr,buf), + IpToString(icpy->ip_dst.s_addr,buf1)); + + /* Check for options... + */ + if (ipsize > sizeof(struct ip)) { + printf(" IP Options: x"); + for(i=sizeof(struct ip);i<ipsize;i++) + printf("%02x",((char *)ihdr)[i]); + printf("\n"); + } + + payload = (char *)ihdr; + payload += ipsize; + ipoff = ecs(icpy->ip_off); + + if (ipoff & 0x3fff) { + if (ipoff == IP_MOREFRAGS) + fragmented = " (first fragment)"; + else if ((ipoff & IP_MOREFRAGS) == 0) + fragmented = " (last fragment)"; + else + fragmented = " (fragment)"; + } + else + fragmented = ""; + + /* Only print the header info if this is not a fragment or if it + * is the first fragment... + */ + if ((ipoff == 0) || (ipoff == IP_MOREFRAGS) || (ipoff == IP_DONTFRAG)) { + if (icpy->ip_p == IP_UDP) { + printUdp((struct Udphdr *)payload,fragmented); + return(0); + } + else if (icpy->ip_p == IP_IGMP) { + printIgmp((struct Igmphdr *)payload,fragmented); + return(0); + } + } + + for(i=0;protocols[i].pname;i++) { + if (icpy->ip_p == protocols[i].pnum) { + printf(" Protocol: %s%s\n",protocols[i].pname,fragmented); + return(0); + } + } + printf(" <%02x>: unknown IP protocol%s\n", icpy->ip_p,fragmented); + return (1); +} + +/* + * printUdp(p) + */ +int +printUdp(struct Udphdr *p,char *fragmented) +{ + ushort dport, sport; + + dport = ecs(p->uh_dport); + sport = ecs(p->uh_sport); + +#if INCLUDE_DHCPBOOT + if ((dport == DhcpServerPort) || (dport == DhcpClientPort)) { + printDhcp(p); + return(0); + } +#endif + printf(" UDP: sport dport ulen sum%s\n",fragmented); + printf(" %4d %4d %4d %4d\n", + sport, dport, ecs(p->uh_ulen),ecs(p->uh_sum)); + return(0); +} + +/* + * printIgmp(p) + */ +int +printIgmp(struct Igmphdr *p,char *fragmented) +{ + uchar buf[16]; + + printf(" IGMP: type mrt csum group%s\n",fragmented); + printf(" x%02x x%02x x%04x %s\n", + p->type, p->mrt, p->csum, IpToString(p->group,(char *)buf)); + return(0); +} +#endif + +/* IpToString(): + * Incoming ascii pointer is assumed to be pointing to at least 16 + * characters of available space. Conversion from long to ascii is done + * and string is terminated with NULL. The ascii pointer is returned. + */ +char * +IpToString(ulong ipadd,char *ascii) +{ + uchar *cp; + + cp = (uchar *)&ipadd; + sprintf(ascii,"%d.%d.%d.%d", + (int)cp[0],(int)cp[1],(int)cp[2],(int)cp[3]); + return(ascii); +} + +char * +EtherToString(uchar *etheradd,char *ascii) +{ + sprintf(ascii,"%02x:%02x:%02x:%02x:%02x:%02x",(int)etheradd[0], + (int)etheradd[1],(int)etheradd[2],(int)etheradd[3], + (int)etheradd[4],(int)etheradd[5]); + return(ascii); +} + +/* ipChksum(): + * Compute the checksum of the incoming IP header. The size of + * the header is variable because of the possibility of there + * being options; hence, the size of the header is taken from + * the ip_vhl field instead of assuming sizeof(struct ip). + * The incoming pointer to an IP header is directly populated with + * the result. + */ +void +ipChksum(struct ip *ihdr) +{ + register int i, stot; + register ushort *sp; + register long csum; + + csum = 0; + ihdr->ip_sum = 0; + stot = (((ihdr->ip_vhl & 0x0f) << 2) / (int)sizeof(ushort)); + sp = (ushort *) ihdr; + for (i=0;i<stot;i++,sp++) { + csum += *sp; + if (csum & 0x80000000) + csum = (csum & 0xffff) + (csum >> 16); + } + while(csum >> 16) + csum = (csum & 0xffff) + (csum >> 16); + ihdr->ip_sum = ~csum; +} + +/* udpChksum(): + * Compute the checksum of the UDP packet. + * The incoming pointer is to an ip header, the udp header after that ip + * header is directly populated with the result. + * Got part of this code out of Steven's TCP/IP Illustrated Volume 2. + */ +void +udpChksum(struct ip *ihdr) +{ + register int i; + register ushort *datap; + register long sum; + int len; + struct Udphdr *uhdr; + struct UdpPseudohdr pseudohdr; + + uhdr = (struct Udphdr *)(ihdr+1); + uhdr->uh_sum = 0; + + /* Note that optionally, the checksum can be forced to zero here, + * so a return could replace the remaining code. + * That would be kinda dangerous, but it is an option according to + * the spec. + */ + + /* Start with the checksum of the pseudo header: + * Note that we have to use memcpy because we don't know if the incoming + * stream is aligned properly. + */ + memcpy((char *)&pseudohdr.ip_src.s_addr,(char *)&ihdr->ip_src.s_addr,4); + memcpy((char *)&pseudohdr.ip_dst.s_addr,(char *)&ihdr->ip_dst.s_addr,4); + pseudohdr.zero = 0; + pseudohdr.proto = ihdr->ip_p; + pseudohdr.ulen = uhdr->uh_ulen; + + /* Get checksum of pseudo header: */ + sum = 0; + datap = (ushort *) &pseudohdr; + for (i=0;i<(sizeof(struct UdpPseudohdr)/sizeof(ushort));i++) { + sum += *datap++; + if (sum & 0x80000000) + sum = (sum & 0xffff) + (sum >> 16); + } + + len = ecs(uhdr->uh_ulen); + datap = (ushort *) uhdr; + + /* If length is odd, pad with zero and add 1... */ + if (len & 1) { + uchar *ucp; + ucp = (uchar *)uhdr; + ucp[len] = 0; + len++; + } + + while(len) { + sum += *datap++; + if (sum & 0x80000000) + sum = (sum & 0xffff) + (sum >> 16); + len -= 2; + } + + while(sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + uhdr->uh_sum = ~sum; +} + +struct ether_header * +EtherCopy(struct ether_header *re) +{ + struct ether_header *te; + + te = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&(te->ether_shost),(char *)BinEnetAddr,6); + memcpy((char *)&(te->ether_dhost),(char *)&(re->ether_shost),6); + te->ether_type = re->ether_type; + return(te); +} + +ushort +ipId(void) +{ + return(++UniqueIpId); +} + + +/* getTuneup(): + * The DHCP, TFTP and ARP timeout & retry mechanism can be tuned based on + * the content of the shell variables DHCPRETRYTUNE, TFTPRETRYTUNE and + * ARPRETRYTUNE respectively. + * Return 0 if variable is not found, -1 if there is a detected error in + * the content of the shell variable; else 1 indicating that the three + * parameters have been loaded from the content of the shell variable. + */ +int +getTuneup(char *varname,int *rexmitdelay,int *giveupcount,int *rexmitdelaymax) +{ + char *vp, *colon1, *colon2; + + vp = getenv(varname); + if (!vp) + return(0); + colon1 = strchr(vp,':'); + if (colon1) { + colon2 = strchr(colon1+1,':'); + if (colon2) { + *rexmitdelay = (int)strtol(vp,0,0); + *giveupcount = (int)strtol(colon1+1,0,0); + *rexmitdelaymax = (int)strtol(colon2+1,0,0); + return(1); + } + } + printf("Syntax error in %s\n",varname); + return(-1); +} + +/* RetransmitDelay(): + * This function provides a common point for retransmission delay + * calculation. It is an implementation "similar" to the recommendation + * made in the RFC 2131 (DHCP) section 4.1 paragraph #8... + * + * The delay before the first retransmission is 4 seconds randomized by + * the value of a uniform random number chosen from the range -1 to +2. + * The delay before the next retransmission is 8 seconds randomized by + * the same number as previous randomization. Each subsequent retransmission + * delay is doubled up to a maximum of 66 seconds. Once a delay of 66 + * seconds is reached, return that value for 6 subsequent delay + * requests, then return RETRANSMISSION_TIMEOUT (-1) indicating that the + * requestor should give up. + * + * The value of randomdelta will be 2, 1, 0 or -1 depending on the target's + * IP address. + * + * The return values will be... + * 4+randomdelta, 8+randomdelta, 16+randomdelta, etc... up to 64+randomdelta. + * Then after returning 64+randomdelta 6 times, return RETRANSMISSION_TIMEOUT. + * + * NOTE: if DELAY_RETURN is the opcode, then RETRANSMISSION_TIMEOUT is + * never returned, once the max is reached, it is always the value + * returned; + * if DELAY_OR_TIMEOUT_RETURN is the opcode, then once maxoutcount + * reaches 6, RETRANSMISSION_TIMEOUT is returned. + * + * NOTE1: this function supports the ability to modify the above-discussed + * parameters. Start with DELAY_INIT_DHCP to set up the parameters + * discussed above; start with DELAY_INIT_XXXX for others. + */ +int +RetransmitDelay(int opcode) +{ + static int randomdelta; /* Used to slightly randomize the delay. + * Taken from the 2 least-significant-bits + * of the IP address (range = -1 to 2). + */ + static int rexmitdelay; /* Doubled each time DELAY_INCREMENT + * is called until it is greater than the + * value stored in rexmitdelaymax. + */ + static int rexmitdelaymax; /* See rexmitdelay. */ + static int maxoutcount; /* Number of times the returned delay has + * reached its max. + */ + static int giveupcount; /* Once maxoutcount reaches this value, we + * give up and return TIMEOUT. + */ + int rexmitstate; + + rexmitstate = RETRANSMISSION_ACTIVE; + switch(opcode) { + case DELAY_INIT_DHCP: + if (getTuneup("DHCPRETRYTUNE",&rexmitdelay, + &giveupcount,&rexmitdelaymax) <= 0) { + rexmitdelay = 4; + giveupcount = 6; + rexmitdelaymax = 64; + } + maxoutcount = 0; + randomdelta = (int)(BinIpAddr[3] & 3) - 1; + break; + case DELAY_INIT_TFTP: + if (getTuneup("TFTPRETRYTUNE",&rexmitdelay, + &giveupcount,&rexmitdelaymax) <= 0) { + rexmitdelay = 2; + giveupcount = 4; + rexmitdelaymax = 8; + } + maxoutcount = 0; + randomdelta = (int)(BinIpAddr[3] & 3) - 1; + break; + case DELAY_INIT_ARP: + if (getTuneup("ARPRETRYTUNE",&rexmitdelay, + &giveupcount,&rexmitdelaymax) <= 0) { + rexmitdelay = 1; + giveupcount = 0; + rexmitdelaymax = 4; + } + maxoutcount = 0; + randomdelta = 0; + break; + case DELAY_INCREMENT: + if (rexmitdelay < rexmitdelaymax) + rexmitdelay <<= 1; /* double it. */ + else + maxoutcount++; + + if (maxoutcount > giveupcount) + rexmitstate = RETRANSMISSION_TIMEOUT; + break; + case DELAY_OR_TIMEOUT_RETURN: + if (maxoutcount > giveupcount) + rexmitstate = RETRANSMISSION_TIMEOUT; + break; + case DELAY_RETURN: + break; + default: + printf("\007TimeoutAlgorithm error 0x%x.\n",opcode); + rexmitstate = RETRANSMISSION_TIMEOUT; + break; + } + if (rexmitstate == RETRANSMISSION_TIMEOUT) + return(RETRANSMISSION_TIMEOUT); + else + return(rexmitdelay+randomdelta); +} + +/* monSendEnetPkt() & monRecvEnetPkt(): + * These two functions allow the monitor to provide a primitive + * connect to the ethernet interface for an application (using + * mon_sendenetpkt() and mon_recvenetpkt()). + * + * Note: These are obviously not very sophisticated; however, they + * provide an immediate mechanism for LWIP to access the raw driver. + * without the application even being aware of the type of ethernet + * device. + */ +int +monSendEnetPkt(char *pkt, int pktlen) +{ + /* If pkt is zero and pktlen is either 0 or -1, we use this as a + * mechanism that changes uMon's ethernet polling state. This is + * necessary so that an application can use the monitor's API along + * with the monitor's hook to ethernet, but without having other + * hooks in uMon do any pollethernet() calls. + */ + if (pkt == 0) { + if (pktlen == 0) { + EtherPollingOff = 1; + return(0); + } + if (pktlen == -1) { + EtherPollingOff = 0; + return(0); + } + } + + /* Copy the incoming packet into a packet that has been allocated + * by the monitor's packet allocator for this ethernet device: + */ + memcpy((char *)getXmitBuffer(),(char *)pkt,pktlen); + sendBuffer(pktlen); + return(pktlen); +} + +int +monRecvEnetPkt(char *pkt, int pktlen) +{ + int pcnt, len; + + /* Prior to calling polletherdev(), this function sets up the globals + * AppPktPtr and AppPktLen so that if a packet is recived, and + * polletherdev() calls processPACKET(), the data will simply be + * copied to the requested buffer space instead of being processed + * by the monitor's packet handler (see the top of processPACKET() + * for the use of AppPktPtr & AppPktLen). + * + * NOTE: this assumes that the target-specific function polletherdev() + * will only process one packet per call. If it can process more than + * one per call, then packets will be lost here. + */ + AppPktPtr = pkt; + AppPktLen = pktlen; + pcnt = polletherdev(); + if (pcnt == 0) { + len = 0; + } + else { + if (pcnt > 1) + len = -AppPktLen; + else + len = AppPktLen; + } + AppPktPtr = 0; + return(len); +} + +#ifndef USE_ALT_STOREMAC + +/* storeMac(): + * This function can be called in system startup (after flash drivers + * are initialized) to give the user the opportunity to program a + * MAC address into the "etheraddr" block of flash in monitor space. + * This is only done if that space is erased (0xff), so only on the + * first pass will it be called. + * It is useful for monitors that want to exist without a monrc file, + * but should still have a MAC address. + * As of uMon_1.0, this function can also be called by the ether command. + */ +void +storeMac(int verbose) +{ +#if INCLUDE_FLASH + int snum, yes; + char macascii[24], prefill[24], buf[6]; + uchar *realetheraddr; +#ifdef TO_FLASH_ADDR + /* The address the program is linked to is not necessarily the + * physical address where flash operations can be performed on. + * A typical use could be that the program is linked to run in + * a cacheable region but writing to the flash can only be done + * in an uncached region. + * "config.h" is a good place to define the TO_FLASH_ADDR macro. + */ + realetheraddr = (uchar *)TO_FLASH_ADDR(etheraddr); +#else + realetheraddr = etheraddr; +#endif + + if (realetheraddr[0] != 0xff) { + if (verbose) + printf("MAC store abort: etheraddr[] contains data\n"); + return; + } + + /* If etheraddr[] is writeable (RAM), then assume that this + * function is being called as part of a RAM based temporary + * monitor; hence, no need to do it... + */ + realetheraddr[0] = 0; + monDelay(100); + if (realetheraddr[0] == 0) { + realetheraddr[0] = 0xff; + if (verbose) + printf("MAC store abort: etheraddr[] in RAM\n"); + return; + } + + /* Use whatever is in config.h as the default MAC address, + * then allow the user to override it with getline_p()... + */ + strcpy(prefill,DEFAULT_ETHERADD); + +#if INCLUDE_ETHERVERBOSE + printf("\nMAC address must be configured.\n"); + printf("The system's MAC address is a 6-digit, colon-delimited string\n"); + printf("(for example: 12:34:56:78:9a:bc). It must be unique for all\n"); + printf("ethernet controllers present on a given subnet. MAC addresses\n"); + printf("are often allocated by a product vendor to prevent duplication,\n"); + printf("and are frequently documented on decals or other materials\n"); + printf("provided with the product. The following prompt allows you\n"); + printf("to specify the MAC address for this device.\n"); + if (strlen(prefill) != 0) + printf("Use backspace if the printed default needs modification...\n"); + printf("\n"); +#endif + + do { + printf("Enter MAC address (xx:xx:xx:xx:xx:xx):\n"); + if (getline_p(macascii,sizeof(macascii),0,prefill) == 0) + return; + } while (EtherToBin((char *)macascii,(uchar *)buf) == -1); + + printf("Configuring '%s' as MAC address, ok?",macascii); + yes = askuser(" (y or n)"); + + putchar('\n'); + if (!yes) + return; + + if (addrtosector((uchar *)realetheraddr,&snum,0,0) < 0) + return; + + sprintf(buf,"%d",snum); + sectorProtect(buf,0); + AppFlashWrite((uchar *)realetheraddr,(uchar *)macascii,strlen(macascii)+1); + sectorProtect(buf,1); + + printf("MAC address burned in at 0x%lx\n",(long)realetheraddr); +#else + printf("Error: MAC storage requires flash driver\n"); +#endif +} +#endif + +#endif /* INCLUDE_ETHERNET */ + +/* EtherToBin(): + * Convert ascii MAC address string to binary. Note that this is outside + * the #if INCLUDE_ETHERNET because it is used by password.c. This correctly + * implies that if there is no ethernet interface, then we need a different + * solution for the password backdoor!. + */ +int +EtherToBin(char *ascii,uchar *binary) +{ + int i, digit; + char *acpy, *acpy1; + + acpy = ascii; + for(i=0;i<6;i++) { + digit = (int)strtol(acpy,&acpy1,16); + if (((i != 5) && (*acpy1++ != ':')) || + ((i == 5) && (*acpy1 != 0)) || + ((acpy1 - acpy) < 2) || + (digit < 0) || (digit > 255)) { + printf("Misformed ethernet addr at: 0x%lx\n",(long)ascii); + return(-1); + } + acpy = acpy1; + binary[i] = (uchar)digit; + } + return(0); +} + +int +IpToBin(char *ascii,uchar *binary) +{ + int i, digit; + char *acpy; + + acpy = ascii; + for(i=0;i<4;i++) { + digit = (int)strtol(acpy,&acpy,10); + if (((i != 3) && (*acpy++ != '.')) || + ((i == 3) && (*acpy != 0)) || + (digit < 0) || (digit > 255)) { + printf("Misformed IP addr at 0x%lx\n",(long)ascii); + return(-1); + } + binary[i] = (uchar)digit; + } + return(0); +} + diff --git a/main/common/fbi.c b/main/common/fbi.c new file mode 100755 index 0000000..583fb47 --- /dev/null +++ b/main/common/fbi.c @@ -0,0 +1,1728 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * fbi.c: + * + * Frame Buffer Interface... + * This file started out as a simple means to transfer a .bmp formatted + * file onto a framebuffer. It has since expanded into what I think is a + * pretty complete set of frame-buffer utilities to run in both pixel mode + * (for images) and console mode (for text). + * As of this writing, pixel mode allows the user to display raw frame-buffer + * images or 24-bit RGB .bmp formatted images. In console mode, the font + * rendering supports variable size fonts (using one font file) and console + * scrolling using a dual-buffer algorithm. + * + ***** + * + * Configuration: + * If you're hardware has a frame buffer interface (typically, this will be + * an LCD, but doesn't have to be), then do the following: + * + * - provide the basic initialization code for the framebuffer + * device: void fbdev_init(void), which will be called by uMon + * startup code automatically. + * + * - establish these three macros as per your device's specifications... + * PIXELS_PER_COL (height of framebuffer device) + * PIXELS_PER_ROW (height of framebuffer device) + * FRAME_BUFFER_BASE_ADDR (starting point of the frame-buffer memory) + * + * - establish one (and only one) of the following to be 1, with all + * others being 0: + * PIXFMT_IS_RGB565 + * PIXFMT_IS_RGB555 + * + * (as of this writing only 16-bit color depth RGB565/RGB555 has been + * tested). + * + * - set INCLUDE_FBI to 1 in the config.h file; + * - add font.c and fbi.c to the common files list in your makefile; + * - to support more efficient consolemode screen scrolling, optionally + * set FBDEV_SETSTART to the name of a function in the driver that + * when called, will re-establish the base address of the frame + * buffer memory using the 'addr' value provided. + * - the console mode feature includes a blinking cursor. To build without + * the cursor, add... + * #define FBI_NO_CURSOR + * to your config.h file. + * + ***** + * + * Startup: + * At startup, the target can come up in console mode or pixel mode + * based on the presence of a splash image. The function fbi_splash() + * is called and it will look for a few different filenames (see function + * below). If a splash image is found, it is dumped to the frame buffer + * and the system will start up in pixel mode. If a splash image is not + * found, then the system will come up in console mode, meaning that all + * characters typed at the serial port will be printed out the frame buffer + * device. + * + ***** + * + * Acknowledgements: + * I got the majority of my information regarding the format of the BMP + * file from Wikipedia (http://en.wikipedia.org/wiki/BMP_file_format). + * I got the basic idea for the scrolling algorithm out of code from + * one of Cogent's LCD drivers. Also, the file font.c has one font that + * I tediously created by hand (kinda ugly), and one that I got from Cogent. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#if INCLUDE_FBI +#include "cpuio.h" +#include "genlib.h" +#include "cli.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "warmstart.h" +#include "font.h" +#include "fbi.h" +#include "timer.h" + +/* FBI_DEBUG: + * Primarily used for debugging the fb_scroll() algorithm... + */ +//#define FBI_DEBUG + +#ifdef FBDEV_SETSTART +extern void FBDEV_SETSTART(long addr); +#endif + +/* PIXELS_PER_ROW, PIXELS_PER_COL and LCD_BUF_ADD are assumed to be + * defined in cpuio.h... + */ +#define SCREEN_WIDTH PIXELS_PER_ROW +#define SCREEN_HEIGHT PIXELS_PER_COL +#define FB_BASE ((unsigned long)FRAME_BUFFER_BASE_ADDR) + +#define RED(val) (char)((val & 0x00ff0000) >> 16) +#define GREEN(val) (char)((val & 0x0000ff00) >> 8) +#define BLUE(val) (char)((val & 0x000000ff)) + +#define FILLTYPE_BOX 1 +#define FILLTYPE_COLOR 2 + +#define BOX_XSIZE 10 +#define BOX_YSIZE 10 + +#define DEFAULT_FG_COLOR 0x00f0f0f0 +#define DEFAULT_BG_COLOR 0x00101010 + +#if PIXFMT_IS_RGB565 +#define fbtype unsigned short +#define FB_GRAY 0x632c +#define FB_WHITE 0xffff +#define FB_BLACK 0x0821 +#elif PIXFMT_IS_RGB555 +# warning: pixel format RGB555 not yet tested +#define fbtype unsigned short +#define FB_GRAY 0x318c +#define FB_WHITE 0xffff +#define FB_BLACK 0x0421 +#else +# error: unknown pixel format +#endif + +#define FB_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(fbtype)) +#define FB_END (FB_BASE + FB_SIZE) + +struct bmpstuff { + unsigned long size; + unsigned long offset; + unsigned long hdrsz; + unsigned long width; + unsigned long height; + unsigned short planes; + unsigned short bpp; + unsigned long cprs; + unsigned long rawsize; + unsigned long hrez; + unsigned long vrez; + unsigned long palettesiz; + unsigned long impcol; +}; + +/* Whenever color is represented where it will be stored in the frame buffer + * but also queriable by the user, we store the RGB value and the FBTYPE + * value because once converted to the FBTYPE, it doesn't necessarily + * convert directly back to the original RGB value it was derived from. + */ +struct fbicolor { + fbtype fbval; + long rgbval; +}; + +void fbi_cursor_clear(void); +void fbi_consolemode_enable(int enable, int fbinit); + +static struct bmpstuff bmpinfo; +static struct fbicolor font_fgcolor, font_bgcolor; +static int font_totalcharheight, font_totalcharwidth, font_linemodulo; +static int font_rowsperscreen, font_colsperscreen, font_scrolltot; +static int font_style, font_xscale, font_yscale, font_xpos, font_ypos; +static fbtype *fbi_cursorpos; +static char fbi_linewrap, fbi_cursorstate; +static char fbi_consolemode_enabled, font_initialized, font_is_opaque; + +/* ecl() & ecs: + * The .bmp file is inherently Windows/Intel-ish. As a result, all integers + * in that file are little endian. These functions automatically convert + * as needed... + * + * If this host is little endian, just return the value; else do the + * endian swap and return. + */ +unsigned long +ecl(unsigned long val) +{ + short tval = 1; + char *tp; + + tp = (char *)&tval; + if (*tp == 1) { + return(val); + } + else { + return((( val & 0x000000ff) << 24) | + ((val & 0x0000ff00) << 8) | + ((val & 0x00ff0000) >> 8) | + ((val & 0xff000000) >> 24)); + } +} + +unsigned short +ecs(unsigned short val) +{ + short tval = 1; + char *tp; + + tp = (char *)&tval; + if (*tp == 1) { + return(val); + } + else { + return(((val & 0x00ff) << 8) | ((val & 0xff00) >> 8)); + } +} + +/* rgb_to_fb() / fb_to_rgb(): + * Convert 24-bit RGB to (or from) whatever the frame buffer type is... + */ + +#if PIXFMT_IS_RGB565 +/* Assume incoming RGB values 8-bits each (24-bit RGB). + * Convert that to 16-bit RGB565 format (5-bit red, 6-bit grn, 5-bit blue). + */ +fbtype +rgb_to_fb(long rgb) +{ + char red, grn, blue; + + red = RED(rgb); + grn = GREEN(rgb); + blue = BLUE(rgb); + + return(((short)(red >> 3) << 11) | + ((short)(grn >> 2) << 5) | (short)(blue >> 3)); +} + +#elif PIXFMT_IS_RGB555 + +/* Assume incoming RGB values 8-bits each (24-bit RGB). + * Convert that to 16-bit RGB555 format (5-bit red, 5-bit grn, 5-bit blue). + * (NOT READY YET) + */ +fbtype +rgb_to_fb(long rgb) +{ + unsigned long red, green, blue; + + red = ((fbval & 0xf800) >> 11); + green = ((fbval & 0x07e0) >> 5); + blue = (fbval & 0x001f); + + return(((short)(red >> 3) << 10) | + ((short)(grn >> 5) << 5) | (short)(blue >> 3)); +} + +#endif + +/* fb_memset(): + * A version of memset that is written to efficiently populate the frame + * buffer with a value of type fbtype. The incoming total is assumed to + * be in fbtype units. + */ +void +fb_memset(fbtype *dest, fbtype val, int tot) +{ + /* If the size of a framebuffer element is half the size of a long, + * then we can double up the memory fill by populating one long value + * with two framebuffer fill values (one being shifted left 16)... + */ + if (sizeof(fbtype) == sizeof(unsigned long)/2) { + unsigned long l_val, *l_fp, *l_end; + + l_val = (unsigned long)val; + l_val <<= 16; + l_val |= (unsigned long)val; + l_fp = (unsigned long *)dest; + l_end = (unsigned long *)(dest+tot); + while(l_fp < l_end) + *l_fp++ = l_val; + + } + /* Otherwise, we just do an fbtype-oriented memset... + */ + else { + fbtype *end = dest+tot; + + while(dest < end) + *dest++ = val; + } +} + +void +fb_memcpy(fbtype *dest, fbtype *src, int tot) +{ + /* If the size of a framebuffer element is half the size of a long, + * then we can double up the memory fill by populating one long value + * with two framebuffer fill values (one being shifted left 16)... + */ + if (sizeof(fbtype) == sizeof(unsigned long)/2) { + unsigned long *l_dest, *l_src, *l_end; + + l_dest = (unsigned long *)dest; + l_src = (unsigned long *)src; + l_end = (unsigned long *)(dest+tot); + while(l_dest < l_end) + *l_dest++ = *l_src++; + + } + /* Otherwise, we just do an fbtype-oriented memcpy... + */ + else { + fbtype *end = dest+tot; + + while(dest < end) + *dest++ = *src++; + } +} + +void +font_defaults(void) +{ + struct font *fontp; + + if (font_initialized) + return; + + font_xpos = 0; + font_ypos = 0; + font_style = 1; + font_xscale = 1; + font_yscale = 1; + font_scrolltot = 0; + font_fgcolor.rgbval = DEFAULT_FG_COLOR; + font_fgcolor.fbval = rgb_to_fb(font_fgcolor.rgbval); + font_bgcolor.rgbval = DEFAULT_BG_COLOR; + font_bgcolor.fbval = rgb_to_fb(font_bgcolor.rgbval); + font_is_opaque = 1; + fbi_linewrap = 0; + fbi_cursorstate = 0; + fbi_cursorpos = 0; + + fontp = &font_styles[font_style]; + font_totalcharheight = ((fontp->height + fontp->above + fontp->below) * + font_yscale); + font_totalcharwidth = ((fontp->width + fontp->between) * font_xscale); + font_rowsperscreen = SCREEN_HEIGHT / font_totalcharheight; + font_colsperscreen = SCREEN_WIDTH / font_totalcharwidth; + font_linemodulo = SCREEN_HEIGHT % font_totalcharheight; + font_initialized = 1; +} + + +/* fb_scroll(): + * This could be done with a simple memory-to-memory transfer which copies + * row 2 to row 1, row 3 to row 2, etc... all the way down the screen. + * However, this would be *really* slow, so an alternative solution is + * used that takes advantage of the fact that we can adjust which portion + * of memory is looked at by the DMA engine connected to the device that is + * actually displaying the pixels (typically this will be an LCD). + * + * Consider the double buffer here, with the start of the second buffer + * being adjacent to the end of the first buffer... + * + * --------------------------- + * | -| * + * | | * + * | | * + * | | * + * ___| -|___ * + * | | + * | | + * | | + * | | + * | | + * --------------------------- + * + * For the sake of this discussion, assume each buffer deals with five + * lines of text. Also, initially the visible portion of the frame + * buffer aligns with the top buffer (note the asterisks to the right). + * As text is typed, each character is put into both buffers... + * + * --------------------------- + * | text for line 1 -| * + * | another line here | * + * | another line is here | * + * | this is the fourth line | * + * ___| and this is line five -|___ * + * | text for line 1 | + * | another line here | + * | another line is here | + * | this is the fourth line | + * | and this is line five | + * --------------------------- + * + * Up to this point, the viewing window has not changed. + * The next line of text is simply placed at the top of both of the + * buffers, just like a circular queue... + * + * --------------------------- + * | this is now line #6 | + * | another line here -| * + * | another line is here | * + * | this is the fourth line | * + * ___| and this is line five |___ * + * | this is now line #6 -| * + * | another line here | + * | another line is here | + * | this is the fourth line | + * | and this is line five | + * --------------------------- + * + * The only added trick now is that the viewing window is shifted down + * one row; thus, giving the appearance of a single line scroll, but without + * the memcpy overhead. + * Then, continuing with this, when the viewing window gets to the bottom + * of the second buffer as shown below... + * + * --------------------------- + * | this is now line #6 | + * | line seven | + * | this would be line 8 | + * | and nine... | + * ___| this is line ten |___ + * | this is now line #6 -| * + * | line seven | * + * | this would be line 8 | * + * | and nine... | * + * | this is line ten -| * + * --------------------------- + * + * the next "scroll" would simply put to one line from the top... + * + * --------------------------- + * | eleventh line now | + * | line seven -| * + * | this would be line 8 | * + * | and nine... | * + * ___| this is line ten |___ * + * | eleventh line now -| * + * | line seven | + * | this would be line 8 | + * | and nine... | + * | this is line ten | + * --------------------------- + * + * One 'gotcha' that I discovered (and fixed) with this algorithm is that + * it only works perfectly if the character height of the font divides + * evenly into the height of the visible frame. If this is not the case, + * then as the lines are scrolling, there will be a larger gap between + * one line and the next as each 'N' lines scroll by (where 'N' is the nuber + * of lines that can fit on the screen. + * To get around this problem, when the font is first established I determine + * what the modulo is between the character height and the screen height. + * Then for each character-oriented line generated I insert one extra pixel + * oriented line until the modulo reaches zero. This simply distributes the + * extra space across each of the lines and only one pixel (at most) of + * difference is visible. + * In short, the font_linemodulo value is the number of character-lines that + * need to have one additional pixel added to their height so that the final + * character-line is at the very bottom of the screen. + */ + +void +fb_erase_line(int lno) +{ + int linesize, linesize1; + fbtype *dest, *end, *dest1; +#ifdef FBI_DEBUG + int erasetype; +#endif + + linesize = SCREEN_WIDTH * font_totalcharheight; + + if (font_linemodulo == 0) { + dest = (fbtype *)(FB_BASE + (lno * linesize * sizeof(fbtype))); + end = dest + linesize; +#ifdef FBI_DEBUG + erasetype = 0; +#endif + } + else { + linesize1 = linesize + SCREEN_WIDTH; + + if (lno < font_linemodulo) { + dest = (fbtype *)(FB_BASE + (lno * linesize1 * sizeof(fbtype))); + end = dest + linesize1; +#ifdef FBI_DEBUG + erasetype = 1; +#endif + } + else if (lno == font_linemodulo) { + dest = (fbtype *)(FB_BASE + (lno * linesize1 * sizeof(fbtype))); + end = dest + linesize1; + end = dest + linesize; +#ifdef FBI_DEBUG + erasetype = 2; +#endif + } + else { + dest = (fbtype *)(FB_BASE + (font_linemodulo * linesize1 * sizeof(fbtype))); + dest += ((lno-font_linemodulo) * linesize); + end = dest + linesize; +#ifdef FBI_DEBUG + erasetype = 3; +#endif + } + } + + dest1 = dest + FB_SIZE/sizeof(fbtype); + fb_memset(dest,font_bgcolor.fbval,end-dest); +#ifdef FBDEV_SETSTART + fb_memset(dest1,font_bgcolor.fbval,end-dest); +#endif + +#ifdef FBI_DEBUG + if (!fbi_consolemode_enabled) /* don't print if console is enabled */ + printf("fb_erase_line_%d(%d)\n",erasetype,lno); +#endif + +} + +#ifdef FBDEV_SETSTART + +/* fb_scroll() + * Called each time a 'newline' character is put to the screen. + */ +void +fb_scroll(void) +{ + int adjust, next_ypos; + unsigned long fbstart; + + font_scrolltot++; + + if (font_ypos >= (font_rowsperscreen-1)) + next_ypos = 0; + else + next_ypos = font_ypos+1; + + if (font_scrolltot >= (font_rowsperscreen*2)) { + fb_erase_line(next_ypos); + + fbstart = (FB_BASE + + (SCREEN_WIDTH*font_totalcharheight * sizeof(fbtype))); + + if (font_linemodulo) + fbstart += SCREEN_WIDTH * sizeof(fbtype); + + FBDEV_SETSTART(fbstart); + +#ifdef FBI_DEBUG + if (!fbi_consolemode_enabled) { /* don't print if console is enabled */ + printf("fb_scroll_1: %d %d %d (fbstart=0x%lx)\n", + font_ypos,font_scrolltot,font_rowsperscreen,fbstart); + } +#endif + font_scrolltot = font_rowsperscreen; + } + else if (font_scrolltot >= font_rowsperscreen) { + int ldiff = font_scrolltot - font_rowsperscreen; + + fb_erase_line(ldiff); + + adjust = + (SCREEN_WIDTH * font_totalcharheight * sizeof(fbtype)); + + fbstart = (FB_BASE + ((ldiff+1) * adjust)); + + if (font_linemodulo) { + if (ldiff <= font_linemodulo) + fbstart += ldiff * (SCREEN_WIDTH * sizeof(fbtype)); + else + fbstart += font_linemodulo * (SCREEN_WIDTH * sizeof(fbtype)); + } + + FBDEV_SETSTART(fbstart); + +#ifdef FBI_DEBUG + if (!fbi_consolemode_enabled) { /* don't print if console is enabled */ + printf("fb_scroll_2: %d %d %d %d (fbstart=0x%lx)\n", + font_ypos,font_scrolltot,font_rowsperscreen,adjust,fbstart); + } +#endif + } + + font_ypos = next_ypos; +} + +#else + +void +fb_scroll(void) +{ + int i, tot; + struct font *fp; + fbtype *dest, *src; + + if (font_ypos >= (font_rowsperscreen-1)) { + /* Starting at the point in the frame buffer where the second line + * starts, copy that to the top of the frame buffer. Effectively + * moving every line below the first line up by one. + * Then clear the newly created bottom line. + * + * NOTE: this is the *slow* way. Ideally, the hardware has the ability + * to support the fbdev_setstart() functionality so the double-buffer + * algorithm (described above) can be used. + */ + fp = &font_styles[font_style]; + dest = (fbtype *)FB_BASE; + src = (fbtype *)FB_BASE + (SCREEN_WIDTH * font_totalcharheight); + + tot = ((FB_END - FB_BASE)/2) - (src - dest); + + for(i=0;i<tot;i++) + *dest++ = *src++; + + /* Clear the new bottom line... + */ + while(dest < (fbtype *)FB_END) + *dest++ = font_bgcolor.fbval; + } + else + font_ypos++; +} + +#endif + +/* fb_putchar(): + * Using the current font settings and frame buffer position, set the + * pixels that correspond to the incoming character 'inchar'. + * This function supports the double-buffer line scroll technique discussed + * above; hence, the use of fp1 & fp2 below. + */ +static void +fb_putchar(char inchar) +{ + struct font *fp; + int i, j, k; + char *bmppos; + unsigned char mask, endmask, fontchar; + fbtype *fp1, *fp2, *position, *start, *end; + + if (!font_initialized) + font_defaults(); + + fp = &font_styles[font_style]; + +#ifndef FBI_NO_CURSOR + fbi_cursor_clear(); +#endif + + if (inchar == '\r') { + font_xpos = 0; + return; + } + else if (inchar == '\n') { + fb_scroll(); + return; + } + else if (inchar == '\b') { + if (font_xpos > 0) { + font_xpos--; + fb_putchar(' '); + font_xpos--; + } + return; + } + + /* Chop at end of screen... + */ + if (font_xpos >= font_colsperscreen) { + if (fbi_linewrap) { + font_xpos = 0; + fb_scroll(); + } + else + return; + } + + position = start = (fbtype *)FB_BASE + + (font_ypos * font_totalcharheight * SCREEN_WIDTH) + + (font_xpos * font_totalcharwidth); + + if (font_ypos < font_linemodulo) { + position += font_ypos*SCREEN_WIDTH; + } + else { + position += font_linemodulo*SCREEN_WIDTH; + } + + bmppos = fp->bitmap + ((inchar - 0x20) * fp->height); + for(i=0;i<fp->above * font_yscale;i++) { + fp1 = (fbtype *)position; + fp2 = fp1 + FB_SIZE/2; + end = fp1 + (fp->width * font_xscale) + (fp->between * font_xscale); + while(fp1 < end) { + if (font_is_opaque) { + *fp1++ = font_bgcolor.fbval; + *fp2++ = font_bgcolor.fbval; + } + else { + fp1++; + fp2++; + } + } + position += SCREEN_WIDTH; + } + + /* Some fonts will only use the left-most 7 columns of pixels, so + * we support that here... + */ + if (fp->width == 7) + endmask = 1; + else + endmask = 0; + + for(i=0;i<fp->height;i++) { + fontchar = *bmppos++; + + for(k=0;k<font_yscale;k++) { + fp1 = (fbtype *)position; + fp2 = fp1 + FB_SIZE/2; + for(mask = 0x80; mask != endmask; mask >>= 1) { + if (fontchar & mask) { + for(j=0;j<font_xscale;j++) { + *fp1++ = font_fgcolor.fbval; + *fp2++ = font_fgcolor.fbval; + } + } + else if (font_is_opaque) { + for(j=0;j<font_xscale;j++) { + *fp1++ = font_bgcolor.fbval; + *fp2++ = font_bgcolor.fbval; + } + } + else { + for(j=0;j<font_xscale;j++) { + fp1++; + fp2++; + } + } + } + + end = fp1 + (fp->between * font_xscale); + while(fp1 < end) { + if (font_is_opaque) { + *fp1++ = font_bgcolor.fbval; + *fp2++ = font_bgcolor.fbval; + } + else { + fp1++; + fp2++; + } + } + position += SCREEN_WIDTH; + } + } + + for(i=0;i<fp->below*font_yscale;i++) { + fp1 = position; + fp2 = fp1 + FB_SIZE/2; + end = fp1 + (fp->width * font_xscale) + (fp->between * font_xscale); + while(fp1 < end) { + if (font_is_opaque) { + *fp1++ = font_bgcolor.fbval; + *fp2++ = font_bgcolor.fbval; + } + else { + fp1++; + fp2++; + } + } + position += SCREEN_WIDTH; + } + + font_xpos++; +} + +static int +fbi_puts(char *str) +{ + int tot, slash; + char nextchar; + + tot = slash = 0; + while(*str) { + if (slash) { + switch(*str) { + case 'n': + nextchar = '\n'; + break; + case 'r': + nextchar = '\r'; + break; + case 'b': + nextchar = '\b'; + break; + default: + tot++; + fb_putchar('\\'); + nextchar = *str; + break; + } + str++; + } + else { + if (*str == '\\') { + slash = 1; + str++; + continue; + } + nextchar = *str++; + } + tot++; + fb_putchar(nextchar); + slash = 0; + } + + return(tot); +} + +/* get_bmphdr_long(): + * Given an offset, copy 4 bytes of data to a temporary long + * value, then endian-swap if necessary. + */ +unsigned long +get_bmphdr_long(char *offset, char *msg, int verbose) +{ + unsigned long tmp1, tmp2; + + memcpy((char *)&tmp1,(char *)offset,4); + tmp2 = ecl(tmp1); + + if (verbose) + printf(" %-20s: %ld\n",msg,tmp2); + + return(tmp2); +} + +/* get_bmphdr_short(): + * Given an offset, copy 2 bytes of data to a temporary short + * value, then endian-swap if necessary. + */ +unsigned short +get_bmphdr_short(char *offset, char *msg, int verbose) +{ + unsigned short tmp1, tmp2; + + memcpy((char *)&tmp1,(char *)offset,2); + tmp2 = ecs(tmp1); + + if (verbose) + printf(" %-20s: %d\n",msg,tmp2); + + return(tmp2); +} + +/* get_bmpinfo(): + * Using the incoming base address as the pointer to the incoming data, + * return 1 if the data is not BMP formatted + * return 0 if the data is BMP formatted + * return -1 if the data is BMP formatted but something is not compatible + * with this tool + */ +int +get_bmpinfo(char *base, int verbose) +{ + if ((base[0] != 'B') || (base[1] != 'M')) { + return(1); + } + + /* Retrieve the .bmp file's header info... + */ + bmpinfo.size = get_bmphdr_long(base+2,"Size",verbose); + bmpinfo.offset = get_bmphdr_long(base+10,"Offset",verbose); + bmpinfo.hdrsz = get_bmphdr_long(base+14,"Hdrsize",verbose); + bmpinfo.width = get_bmphdr_long(base+18,"Width",verbose); + bmpinfo.height = get_bmphdr_long(base+22,"Height",verbose); + bmpinfo.planes = get_bmphdr_short(base+26,"Planes",verbose); + bmpinfo.bpp = get_bmphdr_short(base+28,"Bpp",verbose); + bmpinfo.cprs = get_bmphdr_long(base+30,"Cprs",verbose); + bmpinfo.rawsize = get_bmphdr_long(base+34,"RawSize",verbose); + bmpinfo.hrez = get_bmphdr_long(base+38,"Hrez",verbose); + bmpinfo.vrez = get_bmphdr_long(base+42,"Vrez",verbose); + bmpinfo.palettesiz = get_bmphdr_long(base+46,"Palettesiz",verbose); + bmpinfo.impcol = get_bmphdr_long(base+50,"Important colors",verbose); + + if (bmpinfo.cprs != 0) { + printf("Can't deal with non-zero compression method.\n"); + return(-1); + } + if (bmpinfo.bpp != 24) { + printf("BMP file pixel format is not 24 bits per pixel.\n"); + return(-1); + } + return(0); +} + +void +fbi_consolemode_enable(int enable, int fbinit) +{ + font_scrolltot = 0; + font_ypos = font_xpos = 0; + + if (enable) { + if (!font_initialized) + font_defaults(); + } + + if (fbinit) { + /* Regardless of whether we are enabling or disableing console + * mode we need to init the frame buffer. We fill it with with the + * same color that is used by the font's background. + * + * If FBDEV_SETSTART is defined, then we assume that we're + * using the double-buffer technique (described above) for + * scrolling; hence, we need to initialize twice the space... + */ +#ifdef FBDEV_SETSTART + fb_memset((fbtype *)FB_BASE,font_bgcolor.fbval, + ((FB_END-FB_BASE)/sizeof(fbtype))*2); + + FBDEV_SETSTART(FB_BASE); +#else + fb_memset((fbtype *)FB_BASE,font_bgcolor.fbval, + (FB_END-FB_BASE)/sizeof(fbtype)); +#endif + } + + fbi_consolemode_enabled = (char)enable; +} + +int +is_fbi_consolemode_enabled(void) +{ + if (fbi_consolemode_enabled) + return(1); + return(0); +} + +void +fillbox(int x_offset,int y_offset,int type,fbtype *dest_base,fbtype *src_base) +{ + int x, y, offset; + fbtype *src, *dest; + + offset = (y_offset * BOX_YSIZE * SCREEN_WIDTH) + (x_offset * BOX_XSIZE); + dest = dest_base + offset; + + if (type & FILLTYPE_COLOR) { + for(y=0;y<BOX_YSIZE;y++) { + for(x=0;x<BOX_XSIZE;x++) + dest[x] = *src_base; + + dest += SCREEN_WIDTH; + } + } + else { + src = src_base + offset; + + for(y=0;y<BOX_YSIZE;y++) { + for(x=0;x<BOX_XSIZE;x++) + dest[x] = src[x]; + + dest += SCREEN_WIDTH; + src += SCREEN_WIDTH; + } + } +} + +/* copypixel(): + * Copy the frame buffer data that corresponds to the specified x/y + * coordinate from one frame buffer block to another... + * Note, if filltype is FILLTYPE_COLOR, then we assume that 'frm' + * is pointing to a fixed color. + */ +void +copypixel(fbtype *to, fbtype *frm, int filltype, int x, int y) +{ + fbtype *dst, *src; + + dst = to + ((y * PIXELS_PER_ROW) + x); + + if (filltype & FILLTYPE_COLOR) + src = frm; + else + src = frm + ((y * PIXELS_PER_ROW) + x); + + *dst = *src; +} + +/* fillscreen(): + * Fill the screen from top to bottom in four scans, skipping around between + * each scan just to improve the effect. If 'box' is set, then the fill + * area is a 10x10 box; otherwise its a pixel. + */ +void +fillscreen(fbtype *to,fbtype *frm,int filltype, int delay) +{ + int x, y; + int xInit, yInit, xEnd, yEnd; + + yInit = xInit = 0; + xEnd = SCREEN_WIDTH; + yEnd = SCREEN_HEIGHT; + if (filltype & FILLTYPE_BOX) { + xEnd = xEnd/BOX_XSIZE; + yEnd = yEnd/BOX_YSIZE; + } + +repeat: + for(y=yInit;y<yEnd;y+=2) { + for(x=xInit;x<xEnd;x+=2) { + if (filltype & FILLTYPE_BOX) { + fillbox(x,y,filltype,to,frm); + if (delay) + monDelay(delay); + } + else if (filltype & FILLTYPE_COLOR) { + *(to + (y*SCREEN_WIDTH)+x) = *frm; + } + else { + *(to + (y*SCREEN_WIDTH)+x) = *(frm + (y*SCREEN_WIDTH)+x); + } + } + if (!(filltype & FILLTYPE_BOX)) { + if (delay) + monDelay(delay); + } + } + if ((xInit == 0) && (yInit == 0)) { + xInit = 1; yInit = 1; + goto repeat; + } + if ((xInit == 1) && (yInit == 1)) { + xInit = 0; yInit = 1; + goto repeat; + } + if ((xInit == 0) && (yInit == 1)) { + xInit = 1; yInit = 0; + goto repeat; + } + /* If FILTYPE_BOX is set and the boxsize is not evenly + * divided into the actual screen size, then we need to + * fill in the edges (right & bottom). + */ + if (filltype & FILLTYPE_BOX) { + int xmod, ymod; + + xmod = SCREEN_WIDTH % BOX_XSIZE; + ymod = SCREEN_HEIGHT % BOX_YSIZE; + if (xmod) { + for(y=0;y<SCREEN_HEIGHT;y++) { + for(x=SCREEN_WIDTH-xmod;x<SCREEN_WIDTH;x++) + copypixel(to,frm,filltype,x,y); + } + } + if (ymod) { + for(y=SCREEN_HEIGHT-ymod;y<SCREEN_HEIGHT;y++) { + for(x=0;x<SCREEN_WIDTH;x++) + copypixel(to,frm,filltype,x,y); + } + } + } +} + +void +fill_centerout(fbtype *to,fbtype *frm,int filltype, int delay) +{ + int i, j, x, y, row, col, maxcol, maxrow; + + x = SCREEN_WIDTH/2; + y = SCREEN_HEIGHT/2; + copypixel(to,frm,filltype,x,y); + for(i=0;x>=0 && y>=0;x--,y--,i+=2) { + for(j=0,row=y,col=x;j<i;j++,col++) + copypixel(to,frm,filltype,col,row); + maxcol = col; + maxrow = row; + for(j=0,row=y;j<i;j++,row++) + copypixel(to,frm,filltype,col,row); + for(j=0;j<i;j++,col--) + copypixel(to,frm,filltype,col,row); + for(j=0;j<i;j++,row--) + copypixel(to,frm,filltype,col,row); + } + if (x == -1) { + while(y >= 0) { + for(x=0;x<SCREEN_WIDTH;x++) { + copypixel(to,frm,filltype,x,y); + copypixel(to,frm,filltype,x,maxrow); + } + y--; maxrow++; + } + } + else if (y == -1) { + while(x >= 0) { + for(y=0;y<SCREEN_HEIGHT;y++) { + copypixel(to,frm,filltype,x,y); + copypixel(to,frm,filltype,maxcol,y); + } + x--; maxcol++; + } + } +} + +/* fb_setcolor(): + * Fill the frame buffer with the incoming RGB-24 formatted + * color value... + */ +void +fb_setcolor(long rgb, int transition_type) +{ + fbtype fillval, *to, *from; + + to = (fbtype *)FB_BASE; + from = &fillval; + fillval = rgb_to_fb(rgb); + + switch(transition_type) { + case 1: /* Pixel fill */ + fillscreen(to,from,FILLTYPE_COLOR,0); + break; + case 2: /* Box fill */ + fillscreen(to,from,FILLTYPE_BOX | FILLTYPE_COLOR,0); + break; + case 3: /* Center-out fill */ + fill_centerout(to,from,FILLTYPE_COLOR,0); + break; + default: /* Standard top-to-bottom fill */ + fb_memset(to,fillval,(FB_END-FB_BASE)/sizeof(fbtype)); + break; + } +} + +char *FbiHelp[] = { + "Frame buffer interface", + "-[d:f:o:t:v] {cmd} [args...]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -d ## delay the transition speed", + " -f RGB enable (and set) frame-buffer fill value", + " -o X,Y offset into frame buffer", + " -t ## apply transition when updating screen", + " (doesn't work with .bmp formated source data)", + " -v additive verbosity", + "", + "Commands:", + " color {rgb-value} # fill screen with specified color", + " consolemode {on|wrap|off} # enable/disable console mode", + " fb2file {filename} # copy frame-buffer to TFS file", + " fill {filename | hex_address} # fill screen with file or data", + " font {style} {xscale} {yscale} {fgcolor} {bgcolor}", + " print {text} # print to screen", + " setpixel {x} {y} {size} {color}", +#ifdef FBDEV_SETSTART + " setstart {hex address} # establish base address of frame buffer", +#endif +#endif + 0, +}; + +int +FbiCmd(int argc,char *argv[]) +{ + TFILE *tfp; + unsigned char *bmp; + unsigned long fill_rgb; + fbtype *fp, fill_fbvalue; + char *cmd, *arg1, fill_is_set, *base, *comma; + int x, y, widthadjust, transition_type; + int data_is_raw, transition_delay, rowsize, verbose, opt; + + if (!font_initialized) + font_defaults(); + + verbose = 0; + fill_rgb = 0; + fill_fbvalue = 0; + transition_delay = transition_type = fill_is_set = 0; + while((opt=getopt(argc,argv,"d:f:o:t:v")) != -1) { + switch(opt) { + case 'd': + transition_delay = (int)strtol(optarg,0,0); + break; + case 'f': + fill_is_set = 1; + fill_rgb = strtoul(optarg,0,0); + break; + case 'o': + comma = strchr(optarg,','); + if (!comma) + return(CMD_PARAM_ERROR); + font_xpos = strtol(optarg,0,0); + font_ypos = strtol(comma+1,0,0); + if ((font_xpos > SCREEN_WIDTH) || (font_ypos > SCREEN_HEIGHT)) { + printf("Offset out of range\n"); + return(CMD_FAILURE); + } + break; + case 't': + transition_type = atoi(optarg); + break; + case 'v': + verbose++; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc == optind) { + printf("Frame buffer info...\n"); + printf(" Base addr: 0x%lx\n",FB_BASE); + printf(" LCD width x height (pixels): %dx%d\n", + SCREEN_WIDTH,SCREEN_HEIGHT); +#if PIXFMT_IS_RGB565 + printf(" Pixel fmt: RGB565 (16 bits-per-pixel)\n"); +#elif PIXFMT_IS_RGB555 + printf(" Pixel fmt: RGB555 (16 bits-per-pixel)\n"); +#endif + printf("Font (style=%d)...\n",font_style); + printf(" Scale: x=%d, y=%d\n", font_xscale,font_yscale); + printf(" Color: fg=0x%06x, bg=0x%06x\n", + font_fgcolor.rgbval, font_bgcolor.rgbval); + printf(" Total per-char font height: %d, width: %d\n", + font_totalcharheight,font_totalcharwidth); + printf(" Total rows: %d (mod %d), cols: %d\n", + font_rowsperscreen, font_linemodulo, font_colsperscreen); + printf(" Current position: x=%d, y=%d\n",font_xpos,font_ypos); + + shell_sprintf("FBIBASE","0x%x",FB_BASE); + shell_sprintf("FBIROWS","%d",font_rowsperscreen); + shell_sprintf("FBICOLS","%d",font_colsperscreen); + return(CMD_SUCCESS); + } + if (argc < optind + 1) + return(CMD_FAILURE); + + cmd = argv[optind]; + arg1 = argv[optind+1]; + + if (strcmp(cmd,"fill") == 0) { + if (argc != (optind+2)) + return(CMD_PARAM_ERROR); + + if ((arg1[0] == '0') && (arg1[1] == 'x')) { + base = (char *)strtoul(arg1,0,0); + } + else { + if ((tfp = tfsstat(arg1)) == (TFILE *)0) { + printf("File '%s' not found\n",arg1); + return(1); + } + base = TFS_BASE(tfp); + } + + if ((data_is_raw = get_bmpinfo(base,verbose)) == -1) + return(CMD_FAILURE); + + if (fill_is_set) { + fill_fbvalue = rgb_to_fb(fill_rgb); + } + + /* If the input data is raw, then just copy it directly to the frame + * buffer memory space and be done. + * Note, the transition_type set up with the -t option only works when + * we're pushing in raw data... + */ + if (data_is_raw) { + fbtype *to = (fbtype *)FB_BASE; + fbtype *from = (fbtype *)base; + + switch(transition_type) { + case 1: /* Pixel fill */ + fillscreen(to,from,0,transition_delay); + break; + case 2: /* Box fill */ + fillscreen(to,from,FILLTYPE_BOX,transition_delay); + break; + case 3: /* Center-out fill */ + fill_centerout(to,from,0,transition_delay); + break; + default: /* Standard top-to-bottom fill */ + if (transition_delay) { + while(to < (fbtype *)FB_END) { + *to++ = *from++; + if (((int)to & 0x1ff) == 0x1ff) + monDelay(transition_delay); + } + } + else { + fb_memcpy(to,from,(fbtype *)FB_END-to); + } + } + return(CMD_SUCCESS); + } + + fp = (fbtype *)FB_BASE; + + /* Adust the starting point based on x & y offsets (if any)... + */ + fp += (font_ypos * SCREEN_WIDTH) + font_xpos; + + /* Each row of pixels is extended to a 4-byte boundary, filling + * with an unspecified value so that the next row will start on + * a multiple-of-four byte location in memory or in the file. + * This equation establishes a row size variable that is compliant + * with that rule. The equation is taken directly out of the + * wikipedia page mentioned at the top of this file. + * + * (n * width) + 31 + * rowsize = 4 * ( ---------------- ) + * 32 + * + * (where 'n' is the number of bits per pixel). + */ + rowsize = ((((24*bmpinfo.width) + 31)/32) * 4); + if (verbose > 1) + printf("rowsize: %d\n",rowsize); + + widthadjust = 0; + while ((bmpinfo.width * 3) % 4) { + widthadjust++; + bmpinfo.width++; + } + + if ((verbose > 1) && widthadjust) { + printf("%d-byte width adjustment: %ld -> %ld\n", + widthadjust, bmpinfo.width-widthadjust, bmpinfo.width); + } + + if (bmpinfo.rawsize == 0) { + bmpinfo.rawsize = (bmpinfo.height * bmpinfo.width) * 3; + } + else { + if ((verbose > 1) && + (bmpinfo.rawsize != (bmpinfo.height * bmpinfo.width) * 3)) { + printf("size off: %d %d\n", + bmpinfo.rawsize,(bmpinfo.height * bmpinfo.width) * 3); + } + } + + bmp = (unsigned char *)base + bmpinfo.offset + bmpinfo.rawsize; + + /* Below there are 4 distinct cases regarding the size of the .bmp + * image vs the size of the LCD screen... + * If the bitmap is larger than the LCD, then just fit the upper + * left corner of the bitmap into the LCD. + * If the LCD is larger than the bitmap, just put the bitmap in + * the upper left corner of the LCD and allow portions to be cut off. + * + * - Pixels are stored "upside-down" with respect to normal image raster + * scan order, starting in the lower left corner, going from left to + * right, and then row by row from the bottom to the top of the image. + * As a result, this code has to also deal with that. + */ + + if (bmpinfo.width > SCREEN_WIDTH) { + if (bmpinfo.height > SCREEN_HEIGHT) { + if (verbose > 2) + printf("case 1\n"); + for(y=0;y<SCREEN_HEIGHT;y++) { + volatile unsigned char *bp; + + bmp -= rowsize; + bp = bmp; + for(x=0;x<SCREEN_WIDTH;x++,fp++) { + *fp = ((short)(*bp++ & 0xf8) >> 3); // Blue + *fp |= ((short)(*bp++ & 0xfc) << 3); // Green + *fp |= ((short)(*bp++ & 0xf8) << 8); // Red + } + if (transition_delay) monDelay(transition_delay); + } + } + else { + if (verbose > 2) + printf("case 2\n"); + for(y=0;y<bmpinfo.height;y++) { + volatile unsigned char *bp; + + bmp -= rowsize; + bp = bmp; + for(x=0;x<SCREEN_WIDTH;x++,fp++) { + *fp = ((short)(*bp++ & 0xf8) >> 3); // Blue + *fp |= ((short)(*bp++ & 0xfc) << 3); // Green + *fp |= ((short)(*bp++ & 0xf8) << 8); // Red + } + if (transition_delay) monDelay(transition_delay); + } + if (fill_is_set) { + while(fp < (unsigned short *)FB_END) + *fp++ = fill_fbvalue; + } + } + } + else { + if (bmpinfo.height > SCREEN_HEIGHT) { + if (verbose > 2) + printf("case 3\n"); + for(y=0;y<SCREEN_HEIGHT;y++) { + volatile unsigned char *bp; + + bmp -= rowsize; + bp = bmp; + for(x=0;x<bmpinfo.width;x++,fp++) { + *fp = ((short)(*bp++ & 0xf8) >> 3); // Blue + *fp |= ((short)(*bp++ & 0xfc) << 3); // Green + *fp |= ((short)(*bp++ & 0xf8) << 8); // Red + } + if (fill_is_set) { + while(x++ < SCREEN_WIDTH) + *fp++ = fill_fbvalue; + } + else { + fp += (SCREEN_WIDTH - x); + } + if (transition_delay) monDelay(transition_delay); + } + } + else { + if (verbose > 2) + printf("case 4\n"); + for(y=0;y<bmpinfo.height;y++) { + volatile unsigned char *bp; + + bmp -= rowsize; + bp = bmp; + for(x=0;x<bmpinfo.width;x++,fp++) { + *fp = ((short)(*bp++ & 0xf8) >> 3); // Blue + *fp |= ((short)(*bp++ & 0xfc) << 3); // Green + *fp |= ((short)(*bp++ & 0xf8) << 8); // Red + } + if (fill_is_set) { + while(x++ < SCREEN_WIDTH) + *fp++ = fill_fbvalue; + } + else { + fp += (SCREEN_WIDTH - x); + } + if (transition_delay) monDelay(transition_delay); + } + if (fill_is_set) { + while(fp < (unsigned short *)FB_END) + *fp++ = fill_fbvalue; + } + } + } + } +#ifdef FBDEV_SETSTART + else if (strcmp(cmd,"setstart") == 0) { + if (argc != (optind+2)) + return(CMD_PARAM_ERROR); + + FBDEV_SETSTART(strtol(arg1,0,0)); + return(CMD_SUCCESS); + } +#endif + else if (strcmp(cmd,"color") == 0) { + if (argc != (optind+2)) + return(CMD_PARAM_ERROR); + + fb_setcolor(strtoul(arg1,0,0),transition_type); + return(CMD_SUCCESS); + } + else if (strcmp(cmd,"consolemode") == 0) { + if (argc == (optind+1)) { + printf("Consolemode currently %sabled\n", + fbi_consolemode_enabled ? "en" : "dis"); + return(CMD_SUCCESS); + } + + if (argc != (optind+2)) + return(CMD_PARAM_ERROR); + + if (strcmp(arg1,"on") == 0) { + fbi_consolemode_enable(1,1); + fbi_linewrap = 0; + } + else if (strcmp(arg1,"wrap") == 0) { + fbi_consolemode_enable(1,1); + fbi_linewrap = 1; + } + else if (strcmp(arg1,"off") == 0) { + fbi_consolemode_enable(0,1); + } + else { + return(CMD_PARAM_ERROR); + } + + return(CMD_SUCCESS); + } + else if (strcmp(cmd,"font") == 0) { + int newstyle; + struct font *fontp; + + if (argc != (optind+6)) + return(CMD_PARAM_ERROR); + + newstyle = atoi(argv[optind+1]); + if ((newstyle < 0) || (newstyle >= font_style_total())) { + printf("Invalid font style\n"); + return(CMD_FAILURE); + } + + font_style = newstyle; + font_xscale = atoi(argv[optind+2]); + font_yscale = atoi(argv[optind+3]); + if (strcmp(argv[optind+4],"--")) { + font_fgcolor.rgbval = strtol(argv[optind+4],0,0); + font_fgcolor.fbval = rgb_to_fb(font_fgcolor.rgbval); + } + + + if (strcmp(argv[optind+5],"transparent") == 0) { + font_is_opaque = 0; + } + else if (strcmp(argv[optind+5],"--")) { + font_is_opaque = 1; + font_bgcolor.rgbval = strtol(argv[optind+5],0,0); + font_bgcolor.fbval = rgb_to_fb(font_bgcolor.rgbval); + } + + + fontp = &font_styles[font_style]; + font_totalcharheight = ((fontp->height + fontp->above + fontp->below) * + font_yscale); + font_totalcharwidth = ((fontp->width + fontp->between) * font_xscale); + + font_rowsperscreen = SCREEN_HEIGHT / font_totalcharheight; + font_colsperscreen = SCREEN_WIDTH / font_totalcharwidth; + font_linemodulo = SCREEN_HEIGHT % font_totalcharheight; + + font_initialized = 1; + } + else if (strcmp(cmd,"setpixel") == 0) { + long color; + int x, y, xx, yy, width; + + if (argc != optind+5) + return(CMD_PARAM_ERROR); + + x = strtol(argv[optind+1],0,0); + y = strtol(argv[optind+2],0,0); + width = strtol(argv[optind+3],0,0); + color = strtol(argv[optind+4],0,0); + + for(xx = x-width;xx <= x+width;xx++) { + for(yy = y-width;yy <= y+width;yy++) + fbi_setpixel(xx,yy,color); + } + } + else if (strcmp(cmd,"print") == 0) { + if (argc != optind+2) + return(CMD_PARAM_ERROR); + + if (verbose) + printf("Print: <%s>\n",argv[optind+1]); + + fbi_puts(argv[optind+1]); + return(CMD_SUCCESS); + } + else if (strcmp(cmd,"fb2file") == 0) { + int err; + + if (argc != optind+2) + return(CMD_PARAM_ERROR); + + if (verbose) + printf("Copying frame buffer to '%s'...\n",arg1); + + err = tfsadd(arg1,0,0,(unsigned char *)FB_BASE,FB_SIZE); + if (err != TFS_OKAY) + printf("Failed: %s\n",(char *)tfsctrl(TFS_ERRMSG,err,0)); + return(CMD_SUCCESS); + } + else { + return(CMD_PARAM_ERROR); + } + + return(CMD_SUCCESS); +} + +/* fbi_putchar(): + * This is the external putchar available to other parts of the code. + */ +void +fbi_putchar(char c) +{ + if (!fbi_consolemode_enabled) + return; + + fb_putchar(c); +} + +#ifndef FBI_NO_CURSOR +void +fbi_cursor(void) +{ + static char beenhere; + static struct elapsed_tmr tmr; + + if (!fbi_consolemode_enabled) + return; + + if (!beenhere) { + startElapsedTimer(&tmr,500); + beenhere = 1; + return; + } + + if(msecElapsed(&tmr)) { + fbi_cursorpos = (fbtype *)FB_BASE + + (font_ypos * font_totalcharheight * SCREEN_WIDTH) + + (font_xpos * font_totalcharwidth); + + if (font_ypos < font_linemodulo) { + fbi_cursorpos += font_ypos*SCREEN_WIDTH; + } + else { + fbi_cursorpos += font_linemodulo*SCREEN_WIDTH; + } + fbi_cursorpos += (font_totalcharheight-3) * SCREEN_WIDTH; + if (fbi_cursorstate) { + fb_memset(fbi_cursorpos,font_bgcolor.fbval,font_totalcharwidth); +#ifdef FBDEV_SETSTART + fb_memset(fbi_cursorpos + FB_SIZE/sizeof(fbtype), + font_bgcolor.fbval,font_totalcharwidth); +#endif + fbi_cursorstate = 0; + } + else { + fb_memset(fbi_cursorpos,font_fgcolor.fbval,font_totalcharwidth); +#ifdef FBDEV_SETSTART + fb_memset(fbi_cursorpos + FB_SIZE/sizeof(fbtype), + font_fgcolor.fbval,font_totalcharwidth); +#endif + fbi_cursorstate = 1; + } + startElapsedTimer(&tmr,500); + } +} + +void +fbi_cursor_clear(void) +{ + if (fbi_cursorstate == 1) { + fb_memset(fbi_cursorpos,font_bgcolor.fbval,font_totalcharwidth); +#ifdef FBDEV_SETSTART + fb_memset(fbi_cursorpos + FB_SIZE/sizeof(fbtype), + font_bgcolor.fbval,font_totalcharwidth); +#endif + fbi_cursorstate = 0; + } +} +#endif + +/* fbi_splash(): + * This function should be called at system startup to push out a + * "splash screen" if the appropriate file is installed in TFS. + * The presence of this file also establishes the initial state of + * the console... + * If the file is present, then consolemode is disabled and the splash + * screen is displayed. If the file is not present, then just set + * up the system with consolemode enabled. + */ +void +fbi_splash(void) +{ + TFILE *tfp; + fbtype *fp; + +#if INCLUDE_UNZIP + tfp = tfsstat("splash.gz"); + if (tfp) { + decompress((char *)TFS_BASE(tfp),(int)TFS_SIZE(tfp),(char *)FB_BASE); + return; + } +#endif + + tfp = tfsstat("splash.bin"); + fp = (fbtype *)FB_BASE; + + if (tfp) { + fbtype *splash; + + splash = (fbtype *)TFS_BASE(tfp); + fb_memcpy(fp,splash,(fbtype *)FB_END-fp); + fbi_consolemode_enable(0,0); + } + else { + fbi_consolemode_enable(1,1); + } +} + +void +fbi_setpixel(int x, int y, long rgbcolor) +{ + fbtype *fbp; + + if (x > PIXELS_PER_ROW) + x = PIXELS_PER_ROW; + else if (x < 0) + x = 0; + if (y > PIXELS_PER_COL) + y = PIXELS_PER_COL; + else if (y < 0) + y = 0; + + fbp = (fbtype *)FB_BASE + ((y * PIXELS_PER_ROW) + x); + *fbp = rgb_to_fb(rgbcolor); +} + +#endif diff --git a/main/common/fbi.h b/main/common/fbi.h new file mode 100755 index 0000000..1cdb9e6 --- /dev/null +++ b/main/common/fbi.h @@ -0,0 +1,51 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * fbi.h: + * + * Frame Buffer Interface... + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" + +#if INCLUDE_FBI + +#define fbi_putchar(a) fbi_putchar(a) +extern void fbi_putchar(char c); + +#ifdef FBI_NO_CURSOR +#define fbi_cursor() +#else +#define fbi_cursor(a) fbi_cursor(a) +extern void fbi_cursor(void); +#endif + +#else + +#define fbi_putchar(a) +#define fbi_cursor() + +#endif + +extern void fbi_setpixel(int x, int y, long rgbcolor); +extern void fbi_splash(void); +extern void fbdev_init(void); diff --git a/main/common/flash.c b/main/common/flash.c new file mode 100755 index 0000000..9e01586 --- /dev/null +++ b/main/common/flash.c @@ -0,0 +1,1399 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * flash.c: + * + * This file contains the portions of the flash code that are device + * independent. Refer to the appropriate device sub-directory for the + * code that is specific to the flash device on the target. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "genlib.h" +#if INCLUDE_FLASH +#include "cpu.h" +#include "flash.h" +#include <ctype.h> +#include "stddefs.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "cli.h" + +extern struct flashdesc FlashNamId[]; + +int FlashTrace; +int FlashCurrentBank; +int sectortoaddr(int,int *,uchar **); + +#define SRANGE_ERROR -1 +#define SRANGE_SINGLE 1 +#define SRANGE_RANGE 2 +#define SRANGE_ALL 3 + +/* FlashProtectWindow: + * Must be set to allow any flash operation to be done on space assumed + * to be software protected. + */ +int FlashProtectWindow; + +/* FlashBank[]: + * This table contains all of the information that is needed to keep the + * flash code somewhat generic across multiple flash devices. + */ +struct flashinfo FlashBank[FLASHBANKS]; + +#ifdef DISABLE_INTERRUPTS_DURING_FLASHOPS +#define FLASH_INTSDECL unsigned long oints +#define FLASH_INTSOFF() oints = intsoff() +#define FLASH_INTSRESTORE(ival) intsrestore(oints) +#else +#define FLASH_INTSDECL +#define FLASH_INTSOFF() +#define FLASH_INTSRESTORE(ival) +#endif + +/* showlockop(): + * Return a string that verbosely represents the flash lock + * operation... + */ +char * +showlockop(int operation) +{ + switch(operation) { + case FLASH_LOCK: + return("lock"); + case FLASH_UNLOCK: + return("unlock"); + case FLASH_LOCKDWN: + return("lock_down"); + case FLASH_LOCKQRY: + return("lock_qry"); + case FLASH_LOCKABLE: + return("lockable"); + default: + return("???"); + } +} + +/* showflashtype(): + * Find a match between the incoming id and an entry in the FlashNamId[] + * table. The FlashNamId[] table is part of the device-specific code. + */ +int +showflashtype(ulong id, int showid) +{ + struct flashdesc *fdp; + + if (showid) + printf("Flash ID: 0x%lx\n",id); + + fdp = FlashNamId; + while(fdp->desc) { + if (id == fdp->id) { + printf("Device = %s\n",fdp->desc); + return(0); + } + fdp++; + } + if (id == FLASHRAM) { + printf("Device = FLASH-RAM\n"); + return(0); + } + printf("Flash id 0x%lx not recognized\n",id); + return(-1); +} + +void +showflashtotal(void) +{ +#if FLASHBANKS > 1 + printf("Total of %d banks (0-%d), current default bank: %d\n", + FLASHBANKS,FLASHBANKS-1,FlashCurrentBank); +#else + printf("Current flash bank: 0\n"); +#endif +} + +/* showflashinfo(): + * Dump information about specified flash device. + */ +int +showflashinfo(char *devrange) +{ + uchar *base; + struct sectorinfo *sp; + struct flashinfo *fdev; + char *range, varname[32]; + int first_sector_of_device, devtot; + int locksupported, sector, lastsector, hdrprinted; + + devtot = 0; + hdrprinted = 0; + lastsector = lastflashsector(); + + /* An incoming NULL range implies "any" sector... + */ + if (devrange == 0) { + showflashtotal(); + range = "any"; + } + else { + range = devrange; + } + + /* Loop through all sectors on all devices, picking only those + * sectors that fall in the specified range. + */ + for(sector = 0; sector <= lastsector; sector++) { + if (gotachar()) { + getchar(); + printf("<break>\n"); + break; + } + if (!inRange(range,sector)) + continue; + + if (!(fdev = snumtofdev(sector))) + return(-1); + + first_sector_of_device = fdev->sectors[0].snum; + + if (flashlock(first_sector_of_device,FLASH_LOCKABLE) > 0) + locksupported = 1; + else + locksupported = 0; + + /* If sector is first sector of a device, then print + * device info also... + */ + if ((sector == first_sector_of_device) && (!strcmp(range,"any"))) { + if (showflashtype(fdev->id,0) < 0) + return(-1); + printf(" Bank width : %d\n",fdev->width); + printf(" Sectors : %d\n",fdev->sectorcnt); + printf(" Base addr : 0x%08lx\n",(ulong)(fdev->base)); + hdrprinted = 0; + + if (devrange == 0) { + sprintf(varname,"FLASH_BASE_%d",devtot); + shell_sprintf(varname,"0x%lx",(ulong)(fdev->base)); + sprintf(varname,"FLASH_SCNT_%d",devtot); + shell_sprintf(varname,"%d",fdev->sectorcnt); + sprintf(varname,"FLASH_END_%d",devtot); + shell_sprintf(varname,"0x%lx",(ulong)(fdev->end)); + } + devtot++; + } + + if (!hdrprinted) { + printf(" Sctr TFS? Begin End Size %s %s%s", + "SWProt?", "Erased?", locksupported ? " Locked?\n" : "\n"); + hdrprinted = 1; + } + + sp = &fdev->sectors[sector - first_sector_of_device]; + sectortoaddr(sp->snum,0,&base); + if ((range == 0) || inRange(range,sp->snum)) { + printf(" %3d %c 0x%08lx 0x%08lx 0x%06lx %s %s ", + sp->snum, tfsspace((char *)base) ? '*' : ' ', + (ulong)(sp->begin), (ulong)(sp->end), sp->size, + sp->protected ? "yes" : " no", + flasherased(sp->begin,sp->end) ? "yes" : " no"); + if (locksupported) { + switch(flashlock(sp->snum,FLASH_LOCKQRY)) { + case -1: + printf("???"); + break; + case 1: + printf("yes"); + break; + case 0: + printf(" no"); + break; + } + } + printf("\n"); + } + } + + if (devrange == 0) + shell_sprintf("FLASH_DEVTOT","%d",devtot); + + return(0); +} + +#ifdef FLASH_COPY_TO_RAM + +/* flashopload(): + * Copy flash operation to ram space. + * Note that this function assumes that cache is disabled at this point. + * This is important because we are copying text into bss space and if + * cache was on, there could be a coherency problem. + */ +int +flashopload(ulong *begin,ulong *end,ulong *copy,int size) +{ + /* Some CPUs have 16bit opcodes and can only do aligned accesses. */ + unsigned short *sBegin = (unsigned short *)begin; + unsigned short *sEnd = (unsigned short *)end; + unsigned short *sCopy = (unsigned short *)copy; + + /* Verify space availability: */ + if (((int)end - (int)begin) >= size) { + printf("flashopload overflow ((0x%lx-0x%lx) > 0x%x)\n", + (ulong)end,(ulong)begin,size); + return(-1); + } + + /* Initially fill the copy space with 0xff so that the space + * remaining is viewable... + */ + memset((char *)copy,0xff,size); + + /* Copy function() to RAM, then verify: */ + while(sBegin < sEnd) { + *sCopy = *sBegin; + if (*sCopy++ != *sBegin++) { + printf("flashopload failed\n"); + return(-1); + } + } + + return(0); +} + +#endif + +/* flashtype(): + * Use the device-specific function pointer to call the routine + * relocated to RAM space. + */ +int +flashtype(struct flashinfo *fdev) +{ + return(fdev->fltype(fdev)); +} + +/* flasherase(): + * Use the device-specific function pointer to call the routine + * relocated to RAM space. + * Note that flasherase() is called with a sector number. The sector + * number is relative to the entire system, not just the particular device. + * This means that if there is more than one flash device in the system that + * the actual sector number (relative to the device) may not be the same + * value. This adjustment is made here so that the underlying code that is + * pumped into ram for execution does not have to be aware of this. + * Return... + * 1 if successful + * -1 if failure + * 0 if sector is protected or locked + */ +int +flasherase(int snum) +{ + uchar *tmp; + ulong *base, *end; + int size, rc, dev_snum; + struct flashinfo *fdev; + struct sectorinfo *sinfo; + + if (FlashTrace) + printf("flasherase(%d)\n",snum); + + if (!(fdev = snumtofdev(snum))) + return(-1); + + /* If the device type is RAM, the erase is a bit different... + */ + if (fdev->id == FLASHRAM) { + // Use 'tmp' here to eliminate a 3.4 toolset warning. + sectortoaddr(snum,&size,&tmp); + base = (ulong *)tmp; + end = base + (size/sizeof(long)); + while(base < end) { + *base = 0xffffffff; + if (*base != 0xffffffff) + return(-1); + base++; + } + return(1); + } + + /* If the sector is soft-protected or locked, return negative + * and print failure. If the sector is already erased, then + * there is no need to issue the device-specific erase algorithm. + */ + dev_snum = snum - fdev->sectors[0].snum; + sinfo = &fdev->sectors[dev_snum]; + if (!flasherased(sinfo->begin,sinfo->end)) { + if ((!FlashProtectWindow) && (sinfo->protected)) { + printf("Sector %d protected\n",snum); + return(0); + } + + if (flashlocked(snum,1)) + return(0); + + rc = fdev->flerase(fdev,dev_snum); + if (rc < 0) + return(rc); + } + return(1); +} + + +/* flashwrite(): + * Use the device-specific function pointer to call the routine + * relocated to RAM space. + * First make a few checks on the request, then write to flash if all + * checks succeed. + */ +int +flashwrite(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt) +{ + int j, lowsector, highsector, rc, first_sector_of_device; + register uchar *dp, *sp, *edp; + + if (FlashTrace) + printf("flashwrite(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt); + + if (fdev->id == FLASHRAM) { + uchar *sp, *dp, *end; + sp = src; + dp = dest; + end = dp+bytecnt; + while(dp < end) { + *dp = *sp; + if (*dp != *sp) + return(-1); + dp++; sp++; + } + return(0); + } + + dp = dest; + sp = src; + edp = (dest + bytecnt) - 1; + first_sector_of_device = fdev->sectors[0].snum; + + /* If outside the devices space, return failed.. */ + if ((edp < fdev->sectors[0].begin) || + (dp > fdev->sectors[fdev->sectorcnt-1].end)) { + printf("flashwrite() failed: dest out of flash range\n"); + return(-1); + } + + /* Make sure the destination is not within a protected sector */ + if (FlashProtectWindow == FLASH_PROTECT_WINDOW_CLOSED) { + + /* First determine the sectors that overlap with the + * flash space to be written... + */ + + lowsector = highsector = -1; + for(j=0;j<fdev->sectorcnt;j++) { + if ((dp >= fdev->sectors[j].begin) && + (dp <= fdev->sectors[j].end)) + lowsector = j; + } + for(j=0;j<fdev->sectorcnt;j++) { + if ((edp >= fdev->sectors[j].begin) && + (edp <= fdev->sectors[j].end)) + highsector = j; + } + if ((lowsector == -1) || (highsector == -1)) { + printf("flashwrite() failed: can't find sector\n"); + return(-1); + } + + /* Now that the range of affected sectors is known, + * verify that those sectors are not protected or locked... + */ + for(j=lowsector;j<=highsector;j++) { + if (fdev->sectors[j].protected) { + printf("flashwrite() failed: sector protected\n"); + return(-1); + } + if (flashlocked(j+first_sector_of_device,1)) + return(-1); + } + } + + /* Now make sure that there is no attempt to transition a bit + * in the affected range from 0 to 1... A flash write can only + * bring bits low (erase brings them high). + */ + while(dp < edp) { + if ((*dp & *sp) != *sp) { + printf("flashwrite(0x%lx) failed: bit 0->1 rqst denied.\n", + (long)dp); + return(-1); + } + dp++; + sp++; + WATCHDOG_MACRO; + } + rc = fdev->flwrite(fdev,dest,src,bytecnt); + if (rc < 0) + return(rc); + + /* Assuming everything else appears to have passed, make sure the + * source and destination addresses match... + */ + if (memcmp((char *)dest,(char *)src,(int)bytecnt) != 0) { + printf("flashwrite() post-verify failed.\n"); + return(-1); + } + return(0); +} + +/* flashewrite(): + * Use the device-specific function pointer to call the routine + * relocated to RAM space. + */ +int +flashewrite(uchar *dest,uchar *src,long bytecnt) +{ + int i; + struct flashinfo *fdev; + + if (FlashTrace) + printf("flashwrite(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt); + + if ((fdev = addrtobank(dest)) == 0) + return(-1); + + /* Source and destination addresses must be long-aligned. */ + if (((int)src & 3) || ((int)dest & 3)) + return(-1); + + /* If the protection window is closed, then verify that no protected + * sectors will be written over... + */ + if (FlashProtectWindow == FLASH_PROTECT_WINDOW_CLOSED) { + for (i=0;i<fdev->sectorcnt;i++) { + if((((uchar *)dest) > (fdev->sectors[i].end)) || + (((uchar *)dest+bytecnt) < (fdev->sectors[i].begin))) + continue; + else + if (fdev->sectors[i].protected) + return(-1); + } + } + return(fdev->flewrite(fdev,dest,src,bytecnt)); +} + +/* flashlock(): + Use a function pointer to call the routine relocated to RAM space. +*/ +int +flashlock(int snum,int operation) +{ + int dev_snum; + struct flashinfo *fdev; + + if (FlashTrace) + printf("flashlock(%d,%s)\n",snum,showlockop(operation)); + + fdev = snumtofdev(snum); + dev_snum = snum - fdev->sectors[0].snum; + return(fdev->fllock(fdev,dev_snum,operation)); +} + +int +flashlocked(int snum, int verbose) +{ + if ((flashlock(snum,FLASH_LOCKABLE) > 0) && + (flashlock(snum,FLASH_LOCKQRY) == 1)) { + if (verbose) + printf("Sector %d locked\n",snum); + return(1); + } + return(0); +} + +/* snumtofdev(): + * Return the flash device pointer that corresponds to the incoming + * sector number. + */ +struct flashinfo * +snumtofdev(int snum) +{ + int dev; + struct flashinfo *fbnk; + + fbnk = FlashBank; + for(dev=0;dev<FLASHBANKS;dev++,fbnk++) { + if ((snum >= fbnk->sectors[0].snum) && + (snum <= fbnk->sectors[fbnk->sectorcnt-1].snum)) + return(fbnk); + } + printf("snumtofdev(%d) failed\n",snum); + return(0); +} + +/* addrtosector(): + * Incoming address is translated to sector number, size of sector + * and base of sector. + * Return 0 if successful; else -1. + */ +int +addrtosector(uchar *addr,int *sector,int *size,uchar **base) +{ + struct flashinfo *fbnk; + struct sectorinfo *sinfo; + int dev, sec, i; + + sec = 0; + fbnk = FlashBank; + for(dev=0;dev<FLASHBANKS;dev++,fbnk++) { + for(i=0;i<fbnk->sectorcnt;i++,sec++) { + sinfo = &fbnk->sectors[i]; + if ((addr >= sinfo->begin) && (addr <= sinfo->end)) { + if (sector) { + *sector = sec; + } + if (base) { + *base = sinfo->begin; + } + if (size) { + *size = sinfo->size; + } + return(0); + } + } + } + printf("addrtosector(0x%lx) failed\n",(ulong)addr); + return(-1); +} + +/* addrtobank(): + * From the incoming address, return a pointer to the flash bank that + * this address is within. + */ +struct flashinfo * +addrtobank(uchar *addr) +{ + struct flashinfo *fbnk; + int dev; + + fbnk = FlashBank; + for(dev=0;dev<FLASHBANKS;dev++,fbnk++) { + if ((addr >= fbnk->base) && (addr <= fbnk->end)) + return(fbnk); + } + printf("addrtobank(0x%lx) failed\n",(ulong)addr); + return(0); +} + +int +sectortoaddr(int sector,int *size,uchar **base) +{ + struct flashinfo *fbnk; + struct sectorinfo *sinfo; + int dev, sec, i; + + sec = 0; + fbnk = FlashBank; + for(dev=0;dev<FLASHBANKS;dev++,fbnk++) { + for(i=0;i<fbnk->sectorcnt;i++,sec++) { + if (sec == sector) { + sinfo = &fbnk->sectors[i]; + if (base) *base = sinfo->begin; + if (size) *size = sinfo->size; + return(0); + } + } + } + printf("sectortoaddr(%d) failed\n",sector); + return(-1); +} + +/* InFlashSpace(): + * Return 1 if the block of memory is within flash space; + * else return 0. + */ +int +InFlashSpace(uchar *begin, int size) +{ + int dev; + uchar *end; + struct flashinfo *fbnk; + + end = begin+size; + fbnk = FlashBank; + for(dev=0;dev<FLASHBANKS;dev++,fbnk++) { + if (((begin >= fbnk->base) && (begin <= fbnk->end)) || + ((end >= fbnk->base) && (end <= fbnk->end))) + return(1); + } + return(0); +} + +/* flashbankinfo(): + * Based on the incoming bank number, return the beginning, end and + * number of sectors within that bank. + */ +int +flashbankinfo(int bank,uchar **begin,uchar **end,int *sectorcnt) +{ + struct flashinfo *fbnk; + + if (bank >= FLASHBANKS) + return(-1); + + fbnk = &FlashBank[bank]; + if (begin) + *begin = fbnk->base; + if (end) + *end = fbnk->end; + if (sectorcnt) + *sectorcnt = fbnk->sectorcnt; + return(0); +} + +/* lastlargesector(): + * Incoming bank number is used to populate the sector information + * (sector number, sector size and address) of the last large sector + * in the specified bank. + * * from_addr defines the search start address: + * * from_addr = 0 means start from the first sector; + * * from_addr MUST be sector aligned. + * * sectorcnt defines the numbers of contiguous sectors to search across; + * * sectorcnt = 0 means search to the last sector. + * Return 0 if successful; else -1. + */ +int +lastlargesector(int bank, uchar *from_addr, + int sectorcnt, int *sector, int *size, uchar **base) +{ + struct flashinfo *fbnk; + struct sectorinfo *sinfo; + uchar *largest_sbase; + int i, from_sector, to_sector, largest_ssize, largest_snum; + + if (bank >= FLASHBANKS) { + printf("lastlargesector(%d) failed\n",bank); + return(-1); + } + + fbnk = &FlashBank[bank]; + largest_ssize = 0; + largest_snum = 0; + largest_sbase = (uchar *)0; + + if (from_addr) { + if (addrtosector(from_addr, &from_sector, 0, 0) == -1) + return(-1); + if (fbnk->sectors[from_sector].begin != from_addr) { + printf("lastlargesector failed:\n" + " parameter from_addr (%0x08X) must be sector aligned\n", + from_addr); + return(-1); + } + } + else { + from_sector = 0; + } + + to_sector = from_sector + sectorcnt - 1; + if (to_sector > fbnk->sectorcnt - 1) { + to_sector = fbnk->sectorcnt - 1; + } + + //printf("from_addr = 0x%08X\n", from_addr); + //printf("from_sector = %d\n", from_sector); + //printf("to_sector = %d\n", to_sector); + + sinfo = &fbnk->sectors[from_sector]; + for(i=from_sector; i<=to_sector; i++, sinfo++) { + if (sinfo->size >= largest_ssize) { + largest_ssize = sinfo->size; + largest_snum = sinfo->snum; + largest_sbase = sinfo->begin; + } + } + + //printf("largest_sbase = 0x%08X\n", largest_sbase); + //printf("largest_snum = %d\n", largest_snum); + //printf("largest_ssize = 0x%08X\n", largest_ssize); + + if (sector) + *sector = largest_snum; + if (size) + *size = largest_ssize; + if (base) + *base = largest_sbase; + return(0); +} + +void +LowerFlashProtectWindow() +{ + if (FlashProtectWindow) + FlashProtectWindow--; +} + +/* AppFlashWrite(): + * Takes in a source, destination and byte count and converts that to + * the appropriate flashwrite() call. This function supports the possibility + * of having one write request span across multiple devices in contiguous + * memory space. + */ +int +AppFlashWrite(uchar *dest,uchar *src,long bytecnt) +{ + int ret; + FLASH_INTSDECL; + long tmpcnt; + struct flashinfo *fbnk; + + ret = 0; + while(bytecnt > 0) { + fbnk = addrtobank((uchar *)dest); + if (!fbnk) + return(-1); + + if ((dest + bytecnt) <= fbnk->end) + tmpcnt = bytecnt; + else + tmpcnt = (fbnk->end - dest) + 1; + + FLASH_INTSOFF(); + ret = flashwrite(fbnk,dest,src,tmpcnt); + FLASH_INTSRESTORE(); + if (ret < 0) { + printf("AppFlashWrite(0x%lx,0x%lx,%ld) failed (%d)\n", + (ulong)dest,(ulong)src,bytecnt,ret); + break; + } + src += tmpcnt; + dest += tmpcnt; + bytecnt -= tmpcnt; + } + return(ret); +} + +#if INCLUDE_FLASHREAD + +/* flashread(): + * Use the device-specific function pointer to call the routine + * relocated to RAM space. + * First make a few checks on the request, then read from flash + * if the checks succeed. + */ +int +flashread(struct flashinfo *fdev,uchar *dest,uchar *src,long bytecnt) +{ + int rc, first_sector_of_device; + register uchar *dp, *sp, *edp; + + if (FlashTrace) + printf("flashread(0x%lx,0x%lx,%ld)\n",(long)dest,(long)src,bytecnt); + + if (fdev->id == FLASHRAM) { + uchar *sp, *dp, *end; + sp = src; + dp = dest; + end = dp+bytecnt; + while(dp < end) { + *dp = *sp; + if (*dp != *sp) + return(-1); + dp++; sp++; + } + return(0); + } + + dp = dest; + sp = src; + edp = (dest + bytecnt) - 1; + first_sector_of_device = fdev->sectors[0].snum; + + /* If outside the devices space, return failed.. */ + if ((edp < fdev->sectors[0].begin) || + (dp > fdev->sectors[fdev->sectorcnt-1].end)) { + printf("flashread() failed: dest out of flash range\n"); + return(-1); + } + + rc = fdev->flread(fdev,dest,src,bytecnt); + if (rc < 0) + return(rc); + + /* Assuming everything else appears to have passed, make sure the + * source and destination addresses match... + */ + if (memcmp((char *)dest,(char *)src,(int)bytecnt) != 0) { + printf("flashread() post-verify failed.\n"); + return(-1); + } + return(0); +} + +/* AppFlashRead(): + * Takes in a source, destination and byte count and converts that to + * the appropriate flashwrite() call. This function supports the possibility + * of having one write request span across multiple devices in contiguous + * memory space. + */ +int +AppFlashRead(uchar *dest,uchar *src,long bytecnt) +{ + int ret; + FLASH_INTSDECL; + long tmpcnt; + struct flashinfo *fbnk; + + ret = 0; + while(bytecnt > 0) { + fbnk = addrtobank((uchar *)dest); + if (!fbnk) + return(-1); + + if ((dest + bytecnt) <= fbnk->end) + tmpcnt = bytecnt; + else + tmpcnt = (fbnk->end - dest) + 1; + + FLASH_INTSOFF(); + ret = flashread(fbnk,dest,src,tmpcnt); + FLASH_INTSRESTORE(); + if (ret < 0) { + printf("AppFlashRead(0x%lx,0x%lx,%ld) failed (%d)\n", + (ulong)dest,(ulong)src,bytecnt,ret); + break; + } + src += tmpcnt; + dest += tmpcnt; + bytecnt -= tmpcnt; + } + return(ret); +} +#endif + +int +lastflashsector(void) +{ + int lastsnum; + struct flashinfo *lastfbnk; + + lastfbnk = &FlashBank[FLASHBANKS-1]; + lastsnum = lastfbnk->sectors[lastfbnk->sectorcnt-1].snum; + return(lastsnum); +} + +int +AppFlashEraseAll() +{ + FLASH_INTSDECL; + int ret, snum, lastsnum; + + ret = 0; + FLASH_INTSOFF(); + + /* Loop through all sectors of all banks... + */ + lastsnum = lastflashsector(); + for(snum=0;snum<=lastsnum;snum++) { + WATCHDOG_MACRO; + ret = flasherase(snum); + if (ret <= 0) + break; + } + + FLASH_INTSRESTORE(); + return(ret); +} + +/* Erase the flash sector specified. */ +int +AppFlashErase(int snum) /* erase specified sector */ +{ + int ret; + FLASH_INTSDECL; + + FLASH_INTSOFF(); + ret = flasherase(snum); + FLASH_INTSRESTORE(); + return(ret); +} + +/* sectorProtect(): + * Set or clear (based on value of protect) the protected flag for the + * specified range of sectors... + * This supports incoming ranges that can be dash and/or comma delimited. + * For example a range can be "0", "0-3", or "0,2-4", etc... + */ +int +sectorProtect(char *range, int protect) +{ + struct flashinfo *fbnk; + int i, dev, snum; + + snum = 0; + for(dev = 0;dev < FLASHBANKS;dev++) { + fbnk = &FlashBank[dev]; + for(i = 0;i < fbnk->sectorcnt;i++,snum++) { + if ((range == 0) || (*range == 0) || inRange(range,snum)) + fbnk->sectors[i].protected = protect; + } + } + return(0); +} + +#ifdef FLASHRAM_BASE + +struct sectorinfo sinfoRAM[FLASHRAM_SECTORCOUNT]; + +/* FlashRamInit(): + * This monitor supports TFS space allocated across multiple flash devices + * that may not be in contiguous memory space. To allow RAM to be seen + * as a "flash-like" device to TFS, we set it up in sectors similar to + * those in a real flash device. + * Input... + * snum: All the "flash" space is broken up into individual sectors. + * This is the starting sector number that is to be used for + * the block of sectors within this RAM space. + * fbnk: Pointer to the structure that must be populated with the + * flash bank information. Usually this contains pointers to the + * functions that operate on the flash; but for RAM they aren't + * necessary. + * sinfo: Table populated with the characteristics (size, start, etc...) + * of each sector. + * ssizes: A table containing the size of each of the sectors. This is + * copied to the sinfo space. If this pointer is NULL, then + * this function sets all sector sizes to FLASHRAM_SECTORSIZE. + */ +int +FlashRamInit(int snum, int scnt, struct flashinfo *fbnk, + struct sectorinfo *sinfo, int *ssizes) +{ + int i; + uchar *begin; + + /* FLASHRAM_SECTORCOUNT (in config.h) must match the number of sectors + * allocated to the flash ram device in flashdev.c... + */ + if (scnt != FLASHRAM_SECTORCOUNT) + printf("Warning: flashram sector count inconsistency\n"); + + fbnk->id = FLASHRAM; /* Device id. */ + fbnk->base = (uchar *)FLASHRAM_BASE; /* Base address of bank. */ + fbnk->end = (uchar *)FLASHRAM_END; /* End address of bank. */ + fbnk->sectorcnt = scnt; /* Number of sectors. */ + fbnk->width = 1; /* Width (in bytes). */ + fbnk->fltype = FlashOpNotSupported; /* Flashtype() function. */ + fbnk->flerase = FlashOpNotSupported; /* Flasherase() function. */ + fbnk->flwrite = FlashOpNotSupported; /* Flashwrite() function. */ + fbnk->flewrite = FlashOpNotSupported; /* Flashewrite() function. */ + fbnk->fllock = FlashOpNotSupported; /* Flashlock() function. */ + fbnk->sectors = sinfo; /* Ptr to sector size table. */ + begin = fbnk->base; + for(i=0;i<fbnk->sectorcnt;i++,snum++) { + sinfo[i].snum = snum; + if (ssizes == 0) + sinfo[i].size = FLASHRAM_SECTORSIZE; + else + sinfo[i].size = ssizes[i]; + sinfo[i].begin = begin; + sinfo[i].end = sinfo[i].begin + sinfo[i].size - 1; + sinfo[i].protected = 0; + begin += sinfo[i].size; + } + + return(snum); +} +#endif + +char *FlashHelp[] = { + "Flash memory operations", + "{op} [args]", +#if INCLUDE_VERBOSEHELP + "Ops...", + " opw", + " init", + " type", + " bank [#]", + " prot {rnge}", + " info [rnge]", + " unprot {rnge}", + " lock {rnge}", + " unlock [rnge]", + " lockdwn {rnge}", + " erase {rnge}", + " trace {lvl}", + " write {dest} {src} {byte_cnt}", + " ewrite {dest} {src} {byte_cnt}", + "", + " rnge = range of affected sectors", + " Range syntax examples: <1> <1-5> <1,3,7> <all>", +#endif + 0, +}; + +/* FlashCmd(): + * Code that handles the user interface. See FlashHelp[] below for usage. + */ +int +FlashCmd(int argc,char *argv[]) +{ + int ret; + FLASH_INTSDECL; + ulong dest, src; + long bytecnt, rslt; + struct flashinfo *fbnk; + + FLASH_INTSOFF(); + + fbnk = &FlashBank[FlashCurrentBank]; + ret = CMD_SUCCESS; + + if (strcmp(argv[1],"init") == 0) + FlashInit(); + else if (strcmp(argv[1],"info") == 0) { + showflashinfo(argv[2]); + } + else if (strcmp(argv[1],"type") == 0) { + showflashtype((ulong)flashtype(fbnk),1); + } + else if (strcmp(argv[1],"trace") == 0) { + if (argc == 3) + FlashTrace = atoi(argv[2]); + else if (argc == 2) + printf("Flash trace lvl: %d\n",FlashTrace); + else + return(CMD_PARAM_ERROR); + } + else if (strcmp(argv[1],"bank") == 0) { + int tmpbank; + if (argc == 3) { + tmpbank = atoi(argv[2]); + if (tmpbank < FLASHBANKS) { + FlashCurrentBank = tmpbank; + } + else { + printf("Bank %d out of range\n",tmpbank); + return(CMD_PARAM_ERROR); + } + printf("Subsequent flash ops apply to bank %d\n", + FlashCurrentBank); + } + else { + showflashtotal(); + } + } + else if (strcmp(argv[1],"ewrite") == 0) { + if (argc == 5) { + dest = strtoul(argv[2],(char **)0,0); + src = strtoul(argv[3],(char **)0,0); + bytecnt = (long)strtoul(argv[4],(char **)0,0); + rslt = flashewrite((uchar *)dest,(uchar *)src,bytecnt); + if (rslt < 0) { + printf("ewrite failed (%ld)\n",rslt); + ret = CMD_FAILURE; + } + } + else + ret = CMD_PARAM_ERROR; + } + else if (!strcmp(argv[1],"write")) { + if (argc == 5) { + dest = strtoul(argv[2],(char **)0,0); + src = strtoul(argv[3],(char **)0,0); + bytecnt = (long)strtoul(argv[4],(char **)0,0); + rslt = AppFlashWrite((uchar *)dest,(uchar *)src,bytecnt); + if (rslt < 0) { + printf("Write failed (%ld)\n",rslt); + ret = CMD_FAILURE; + } + } + else + ret = CMD_PARAM_ERROR; + } +#if INCLUDE_FLASHREAD + else if (!strcmp(argv[1],"read")) { + if (argc == 5) { + dest = strtoul(argv[2],(char **)0,0); + src = strtoul(argv[3],(char **)0,0); + bytecnt = (long)strtoul(argv[4],(char **)0,0); + rslt = AppFlashRead((uchar *)dest,(uchar *)src,bytecnt); + if (rslt < 0) { + printf("Read failed (%ld)\n",rslt); + ret = CMD_FAILURE; + } + } + else + ret = CMD_PARAM_ERROR; + } +#endif + else if (!strcmp(argv[1],"opw")) { + if (getUsrLvl() != MAXUSRLEVEL) + printf("Must be user level %d\n",MAXUSRLEVEL); + else + FlashProtectWindow = 2; + } + else if (!strcmp(argv[1],"unprot")) { + if (argc != 3) + ret = CMD_PARAM_ERROR; + else + sectorProtect(argv[2],0); + } + else if (!strcmp(argv[1],"prot")) { + if (argc != 3) + ret = CMD_PARAM_ERROR; + else + sectorProtect(argv[2],1); + } + else if (!strcmp(argv[1],"erase")) { + if (argc != 3) { + ret = CMD_PARAM_ERROR; + } + else { + uchar *base; + int rc, snum, size, stot = 0; + + if (strncmp(argv[2],"0x",2) == 0) { + ulong begin, end; + char *dash = strchr(argv[2],'-'); + + begin = end = strtoul(argv[2],0,0); + if (dash) + end = strtoul(dash+1,0,0); + + while(begin <= end) { + if (addrtosector((uchar *)begin,&snum,&size,&base) < 0) + break; + begin = (ulong)base; + rc = flasherase(snum); + if (rc != 1) { + printf("Erase failed (%d)\n",rc); + ret = CMD_FAILURE; + break; + } + stot++; + begin += size; + } + } + else { + int last; + + last = lastflashsector(); + for(snum=0;snum<=last;snum++) { + int rc; + + if ((argv[2] == 0) || inRange(argv[2],snum)) { + ticktock(); + rc = flasherase(snum); + if (rc != 1) { + printf("Erase failed (%d)\n",rc); + ret = CMD_FAILURE; + break; + } + stot++; + } + } + } + printf("%d sectors erased\n",stot); + } + } + else if ((!strcmp(argv[1],"lock")) || (!strcmp(argv[1],"unlock")) || + (!strcmp(argv[1],"lockdwn"))) { + int operation, snum; + + if (!strcmp(argv[1],"lock")) + operation = FLASH_LOCK; + else if (!strcmp(argv[1],"unlock")) + operation = FLASH_UNLOCK; + else + operation = FLASH_LOCKDWN; + + if (argc == 2) { +#ifdef FLASH_PROTECT_RANGE + argv[2] = FLASH_PROTECT_RANGE; + argc = 3; + printf("Applying %s to sector(s) %s...\n",argv[1],argv[2]); +#else + printf("Monitor not built with specified protection range\n"); + ret = CMD_FAILURE; +#endif + } + + if (argc != 3) { + ret = CMD_PARAM_ERROR; + } + else { + int last; + struct flashinfo *fdev; + + last = lastflashsector(); + for(snum=0;snum<=last;snum++) { + if (inRange(argv[2],snum)) { + ticktock(); + if ((fdev = snumtofdev(snum)) == 0) { + ret = CMD_FAILURE; + break; + } + if (flashlock(fdev->sectors[0].snum,FLASH_LOCKABLE) <= 0) { + printf("Sector %d does not support %s\n",snum,argv[1]); + ret = CMD_FAILURE; + break; + } + rslt = flashlock(snum,operation); + if (rslt < 0) { + printf("%s failed (%ld) at sector %d\n", + argv[1],rslt,snum); + ret = CMD_FAILURE; + break; + } + } + } + } + } + else { + ret = CMD_PARAM_ERROR; + } + + FLASH_INTSRESTORE(); + return(ret); +} + +/* FlashOpOverride(): + * This function is used by monlib to provide the application with the + * ability to override the underlying flash operations with functions + * provided by the application. + * The finfo parameter is actually a flashinfo pointer; set void here + * to eliminate confusion when used with monlib.h and the application . + */ +int +FlashOpOverride(void *finfo, int get, int bank) +{ + char *src, *dst; + struct flashinfo *fdev; + + if ((!finfo) || (bank >= FLASHBANKS)) + return(-1); + + fdev = &FlashBank[bank]; + + if (get) { + src = (char *)fdev; + dst = (char *)finfo; + } + else { + src = (char *)finfo; + dst = (char *)fdev; + } + memcpy(dst,src,sizeof(struct flashinfo)); + return(0); +} + +int +FlashOpNotSupported(void) +{ + if (FlashTrace) + printf("flash operation not supported\n"); + + return(-1); +} + +/* Used as a placeholder for the flash drivers that don't + * support flash lock... + */ +int +FlashLockNotSupported(struct flashinfo *fdev,int snum,int operation) +{ + if (operation == FLASH_LOCKABLE) + return(0); + else + return(-1); +} + +#endif + +/* flasherased(): + * Return 1 if range of memory is all 0xff; else 0. + * Scan through the range of memory specified by begin-end (inclusive) + * looking for anything that is not 0xff. Do this in three sections so + * that the pointers can be 4-byte aligned for the bulk of the comparison + * range... + * The beginning steps through as a char pointer until aligned on a 4-byte + * boundary. Then do ulong * comparisons until the just before the end + * where we once again use char pointers to align on the last few + * non-aligned bytes (if any). + */ +int +flasherased(unsigned char *begin, unsigned char *end) +{ + unsigned long *lp, *lp1, ltmp; + + /* If begin is greater than end, the range is illegal. The only + * exception to this is the case where end may be zero. This is + * considered an exception because in cases where we are dealing + * with the last sector of a device that sits at the end of memory + * space, the end point will wrap. + */ + if ((begin > end) && (end != 0)) { + printf("flasherased(): bad range\n"); + return(0); + } + + /* Get pointers aligned so that we can do the bulk of the comparison + * with long pointers... + */ + while(((long)begin & 3) && (begin <= end)) { + if (*begin != 0xff) + return(0); + begin++; + } + if (begin > end) + return(1); + + lp = (unsigned long *)begin; + ltmp = (unsigned long)end; + ltmp &= ~3; + lp1 = (unsigned long *)ltmp; + + while(lp != lp1) { + if (*lp != 0xffffffff) + return(0); + lp++; + +#ifdef WATCHDOG_ENABLED + /* For each 64K through this loop, tickle the watchdog. + */ + if ((0xffff & (unsigned long)lp) == 0) { + WATCHDOG_MACRO; + } +#endif + } + if (lp > (unsigned long *)end) + return(1); + + begin = (unsigned char *)lp; + do { + if (*begin != 0xff) + return(0); + } while(begin++ != end); + return(*end == 0xff); +} + diff --git a/main/common/flash.h b/main/common/flash.h new file mode 100755 index 0000000..118f845 --- /dev/null +++ b/main/common/flash.h @@ -0,0 +1,125 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * flash.h: + * + * Device-independent macros and data structures used by flash driver. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _FLASH_H_ +#define _FLASH_H_ + +#define FLASH_PROTECT_WINDOW_CLOSED 0 +#define ALL_SECTORS -1 + +#ifndef FLASH_LOOP_TIMEOUT +#define FLASH_LOOP_TIMEOUT 1000000 +#endif + +#define FLASH_LOCK 1 +#define FLASH_UNLOCK 2 +#define FLASH_LOCKDWN 3 +#define FLASH_LOCKQRY 4 +#define FLASH_LOCKABLE 5 /* query driver for lock support */ + +/* Device ID used for ram that is "pretending" to be a flash bank. */ +#define FLASHRAM 0x9999 + +struct flashdesc { + unsigned long id; /* manufacturer & device id */ + char *desc; /* ascii string */ +}; + +struct sectorinfo { + long size; /* size of sector */ + int snum; /* number of sector (amongst possibly */ + /* several devices) */ + int protected; /* if set, sector is protected by window */ + unsigned char *begin; /* base address of sector */ + unsigned char *end; /* end address of sector */ +}; + +struct flashinfo { + unsigned long id; /* manufacturer & device id */ + unsigned char *base; /* base address of device */ + unsigned char *end; /* end address of device */ + int sectorcnt; /* number of sectors */ + int width; /* 1, 2, or 4 */ + int (*fltype)(struct flashinfo *); + int (*flerase)(struct flashinfo *, int); +#if INCLUDE_FLASHREAD + int (*flread)(struct flashinfo *,unsigned char *,\ + unsigned char *,long); +#endif + int (*flwrite)(struct flashinfo *,unsigned char *,\ + unsigned char *,long); + int (*flewrite)(struct flashinfo *,unsigned char *,\ + unsigned char *,long); + int (*fllock)(struct flashinfo *,int,int); + struct sectorinfo *sectors; +}; + +extern int FlashTrace; +extern int FlashProtectWindow; +extern int FlashCurrentBank; +extern struct flashinfo FlashBank[FLASHBANKS]; +extern int flashopload(unsigned long *begin,unsigned long *end, \ + unsigned long *copy,int size); + +extern int showflashtype(unsigned long, int); +extern int showflashinfo(char *); +extern int flashopload(unsigned long *,unsigned long *,unsigned long *,int); +extern int flashtype(struct flashinfo *); +extern int flasherase(int snum); +extern int flashwrite(struct flashinfo *,unsigned char *,unsigned char *,long); +extern int flashewrite(unsigned char *,unsigned char *,long); +extern int flasherased(unsigned char *,unsigned char *); +extern int flashlock(int, int); +extern int flashlocked(int, int); +extern int addrtosector(unsigned char *,int *,int *,unsigned char **); +extern struct flashinfo *snumtofdev(int); +extern struct flashinfo *addrtobank(unsigned char *); +extern int sectortoaddr(int,int *,unsigned char **); +extern int flashbankinfo(int,unsigned char **,unsigned char **,int *); +extern void LowerFlashProtectWindow(void); +extern int AppFlashWrite(unsigned char *,unsigned char *,long); +extern int AppFlashEraseAll(void); +extern int AppFlashErase(int); +extern int srange(char *,int *,int *); +extern int sectorProtect(char *,int); +extern int FlashOpNotSupported(void); +extern int FlashLockNotSupported(struct flashinfo *,int,int); +extern int lastlargesector(int,unsigned char *,int,int *,int *,unsigned char **); +extern int lastflashsector(void); +extern int FlashRamInit(int, int, struct flashinfo *,struct sectorinfo *,int *); +extern int InFlashSpace(unsigned char *begin, int size); +extern int FlashOpOverride(void *flashinfo,int get,int bank); + +#define NotAligned16(add) ((long)add & 1) +#define NotAligned32(add) ((long)add & 3) + +#ifdef FLASHRAM_BASE +extern int ramSectors[]; +extern struct sectorinfo sinfoRAM[]; +#endif + +#endif diff --git a/main/common/flashram.c b/main/common/flashram.c new file mode 100644 index 0000000..d2f0841 --- /dev/null +++ b/main/common/flashram.c @@ -0,0 +1,60 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * flashram.c + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" + +#ifdef FLASHRAM_BASE +/* As of Jan 2004, this module is no longer needed. + * I added an option to FlashRamInit() so that if the incoming sector + * size table is NULL, then all sectors are initialized to the same + * size. For cases where this table was used, the call to FlashRamInit + * should have the ssizes argument changed to zero. See FlashRamInit() + * for more on this. + */ +#if 0 +#include "flash.h" + +/* Generic Flash RAM configuration information... + * The assumption is a 16-element array (FLASHRAM_SECTORCOUNT = 16). + * + * This can be included in a monitor build if the build has + * a block of RAM dedicated to TFS file storage. If some other + * configuration is required, then copy this to target-specific space + * and modify a local version. + */ +int +ramSectors[FLASHRAM_SECTORCOUNT] = { + FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE, + FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE, + FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE, + FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE, + FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE, + FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE, + FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE, + FLASHRAM_SECTORSIZE, FLASHRAM_SECTORSIZE, +}; +#endif +#endif diff --git a/main/common/font.c b/main/common/font.c new file mode 100755 index 0000000..87d1df9 --- /dev/null +++ b/main/common/font.c @@ -0,0 +1,6751 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * font.c: + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * Contribution by: Mike Kelly (www.cogcomp.com) + * + */ + +#include "config.h" +#include "font.h" + +/* If none of the three fonts are defined in config.h, then we just + * default to using the 8x13 font (which is probably the only font + * really needed). + */ +#ifndef USE_FONT_8x12 +#ifndef USE_FONT_8x16 +#ifndef USE_FONT_8x13 +#define USE_FONT_8x13 +#endif +#endif +#endif + +#ifdef USE_FONT_8x12 +/* font: + * This is a homemade 8x12 pixel font. Crude at best. + * It uses the entire 8x12 space, does not put any fixed + * edge on the pixel. It therefore looks better if the + * font definition structure used with this font provide + * at least an 'above' and 'between' setting of 1. + */ +char font8x12[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // SPACE + 0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x38,0x00,0x38,0x38,0x00, // ! + 0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // " + 0x00,0x66,0x66,0xff,0xff,0x66,0x66,0xff,0xff,0x66,0x66,0x00, // # + 0x3c,0x7e,0xdb,0xdb,0xd8,0x7c,0x3e,0x1b,0xdb,0xdb,0x7e,0x3c, // $ + 0x00,0x61,0x63,0x06,0x0c,0x18,0x30,0x60,0xc6,0x86,0x00,0x00, // % + 0x00,0x00,0x00,0x18,0x18,0x7f,0xfe,0x18,0x18,0x00,0x00,0x00, // & + 0x18,0x18,0x30,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ' + 0x1e,0x1e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1e,0x1e, // ( + 0x78,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x78,0x78, // ) + 0x00,0x00,0x00,0x66,0x18,0x7f,0xfe,0x18,0x66,0x00,0x00,0x00, // * + 0x00,0x00,0x00,0x18,0x18,0x7f,0xfe,0x18,0x18,0x00,0x00,0x00, // + + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60, // , + 0x00,0x00,0x00,0x00,0x00,0x7e,0x7e,0x00,0x00,0x00,0x00,0x00, // - + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18, // . + 0x00,0x01,0x03,0x07,0x0e,0x1c,0x38,0x70,0xe0,0xc0,0x80,0x00, // / + + 0x3c,0x7e,0xc7,0xc7,0xcb,0xcb,0xd3,0xd3,0xe3,0xe3,0x7e,0x3c, // 0 + 0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x7e, // 1 + 0x7e,0xff,0xc3,0x03,0x07,0x1e,0x78,0xe0,0xc0,0xc0,0xff,0xff, // 2 + 0x7c,0xfe,0x03,0x03,0x03,0x7e,0x7e,0x03,0x03,0x03,0xfe,0x7c, // 3 + 0xc0,0xc0,0xc6,0xc6,0xc6,0xff,0xff,0x06,0x06,0x06,0x06,0x06, // 4 + 0xfe,0xff,0xc0,0xc0,0xfc,0x7e,0x03,0x03,0xc3,0xc3,0x7e,0x3c, // 5 + 0x3c,0x7e,0xc3,0xc0,0xc0,0xfc,0xfe,0xc3,0xc3,0xc3,0x7e,0x3c, // 6 + 0x7f,0xff,0x03,0x03,0x03,0x06,0x0c,0x18,0x30,0x60,0xc0,0xc0, // 7 + 0x3c,0x7e,0xc3,0xc3,0xc3,0x7e,0x7e,0xc3,0xc3,0xc3,0x7e,0x3c, // 8 + 0x3c,0x7e,0xc3,0xc3,0xc3,0x7f,0x3f,0x03,0x03,0x03,0x03,0x03, // 9 + + 0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00, // : + 0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x80,0x01, // ; + 0x01,0x02,0x04,0x08,0x10,0x20,0x20,0x10,0x08,0x04,0x02,0x01, // < + 0x00,0x00,0x00,0x7e,0x7e,0x00,0x00,0x7e,0x7e,0x00,0x00,0x00, // = + 0x80,0x40,0x20,0x10,0x08,0x04,0x04,0x08,0x10,0x20,0x40,0x80, // > + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ? + + 0x3c,0x7e,0xc3,0xcf,0xdf,0xdb,0xdb,0xdf,0xce,0xc0,0x7e,0x3c, // @ + 0x3c,0x7e,0x66,0xc3,0xc3,0xc3,0xff,0xff,0xc3,0xc3,0xc3,0xc3, // A + 0xfc,0xfe,0xc3,0xc3,0xc3,0xfe,0xfe,0xc3,0xc3,0xc3,0xfe,0xfc, // B + 0x3c,0x7e,0xe7,0xc3,0xc0,0xc0,0xc0,0xc0,0xc3,0xe7,0x7e,0x3c, // C + 0xfc,0xfe,0xc7,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc7,0xfe,0xfc, // D + 0xff,0xff,0xc0,0xc0,0xc0,0xfc,0xfc,0xc0,0xc0,0xc0,0xff,0xff, // E + 0xff,0xff,0xc0,0xc0,0xc0,0xfc,0xfc,0xc0,0xc0,0xc0,0xc0,0xc0, // F + 0x3c,0x7e,0xe3,0xc3,0xc0,0xc0,0xcf,0xcf,0xc3,0xe3,0x7f,0x3e, // G + 0xc3,0xc3,0xc3,0xc3,0xc3,0xff,0xff,0xc3,0xc3,0xc3,0xc3,0xc3, // H + 0xff,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0xff, // I + 0xff,0xff,0x0c,0x0c,0x0c,0x0c,0x0c,0xcc,0xcc,0xcc,0xfc,0x78, // J + 0xc3,0xc3,0xc7,0xce,0xdc,0xf8,0xf8,0xdc,0xce,0xc7,0xc3,0xc3, // K + 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xff,0xff, // L + 0xc3,0xe7,0xff,0xff,0xdb,0xdb,0xdb,0xdb,0xc3,0xc3,0xc3,0xc3, // M + 0xc3,0xe3,0xf3,0xfb,0xdf,0xcf,0xc7,0xc3,0xc3,0xc3,0xc3,0xc3, // N + 0x3c,0x7e,0x66,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x66,0x7e,0x3c, // O + 0xfc,0xfe,0xc3,0xc3,0xc3,0xfe,0xfc,0xc0,0xc0,0xc0,0xc0,0xc0, // P + 0x38,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7f,0x3b, // Q + 0xfc,0xfe,0xc3,0xc3,0xc3,0xfe,0xfc,0xce,0xc7,0xc3,0xc3,0xc3, // R + 0x3c,0x7e,0xc3,0xc3,0xc0,0x7c,0x3e,0x03,0xc3,0xc3,0x7e,0x3c, // S + 0xff,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // T + 0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xe7,0x7e,0x3c, // U + 0xc3,0xc3,0x66,0x66,0x66,0x66,0x66,0x66,0x7e,0x3c,0x3c,0x18, // V + 0xc3,0xc3,0xc3,0xc3,0xdb,0xdb,0xdb,0xdb,0xff,0xff,0xe7,0xc3, // W + 0xc3,0xc3,0xc3,0x66,0x3c,0x3c,0x66,0x66,0xc3,0xc3,0xc3,0xc3, // X + 0xc3,0xc3,0xe7,0x66,0x3c,0x3c,0x18,0x18,0x18,0x18,0x18,0x18, // Y + 0xff,0xff,0x03,0x07,0x0e,0x1c,0x38,0x70,0xe0,0xc0,0xff,0xff, // Z + + 0x1e,0x1e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1e,0x1e, // [ + 0x00,0x80,0xc0,0x60,0x30,0x18,0x0c,0x06,0x03,0x01,0x00,0x00, // BACKSLASH + 0x78,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x78,0x78, // ] + 0x00,0x18,0x66,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, // _ + + 0x30,0x30,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ` + 0x00,0x00,0x00,0x00,0x3e,0x63,0x03,0x3f,0x63,0x63,0x3f,0x01, // a + 0x00,0x60,0x60,0x60,0x7e,0x63,0x63,0x63,0x63,0x63,0x7e,0x00, // b + 0x00,0x00,0x00,0x00,0x3e,0x63,0x60,0x60,0x60,0x63,0x3e,0x00, // c + 0x00,0x03,0x03,0x03,0x3f,0x63,0x63,0x63,0x63,0x63,0x3f,0x00, // d + 0x00,0x00,0x00,0x00,0x3e,0x63,0x63,0x7f,0x60,0x63,0x3e,0x00, // e + 0x00,0x1e,0x33,0x33,0x30,0x30,0x78,0x30,0x30,0x30,0x30,0x00, // f + 0x00,0x00,0x00,0x00,0x3e,0x63,0x63,0x3f,0x03,0x03,0x63,0x3e, // g + 0x00,0x60,0x60,0x60,0x7e,0x63,0x63,0x63,0x63,0x63,0x63,0x00, // h + 0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0c,0x00, // i + 0x00,0x03,0x03,0x00,0x03,0x03,0x03,0x03,0x03,0x63,0x63,0x3e, // j + 0x00,0x60,0x60,0x66,0x6c,0x78,0x70,0x78,0x6c,0x66,0x66,0x00, // k + 0x00,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x00, // l + 0x00,0x00,0x00,0x00,0xe6,0xdb,0xdb,0xdb,0xdb,0xc3,0xc3,0x00, // m + 0x00,0x00,0x00,0x00,0x6e,0x73,0x63,0x63,0x63,0x63,0x63,0x00, // n + 0x00,0x00,0x00,0x00,0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00, // o + 0x00,0x00,0x00,0x00,0x7e,0x63,0x63,0x63,0x7e,0x60,0x60,0x60, // p + 0x00,0x00,0x00,0x00,0x7c,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x06, // q + 0x00,0x00,0x00,0x00,0x6e,0x73,0x63,0x60,0x60,0x60,0x60,0x00, // r + 0x00,0x00,0x00,0x00,0x3e,0x63,0x60,0x3e,0x03,0x63,0x3e,0x00, // s + 0x00,0x30,0x30,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x00, // t + 0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3a,0x00, // u + 0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00, // v + 0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xdb,0xdb,0xdb,0x66,0x00, // w + 0x00,0x00,0x00,0x00,0xc3,0x66,0x3c,0x18,0x3c,0x66,0xc3,0x00, // x + 0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x3f,0x03,0x03,0x63,0x3e, // y + 0x00,0x00,0x00,0x00,0x7f,0x06,0x0c,0x18,0x30,0x60,0x7f,0x00, // z + + 0x03,0x06,0x06,0x06,0x0c,0x18,0x0c,0x06,0x06,0x06,0x03,0x00, // { + 0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x18,0x18,0x18,0x18, // | + 0xc0,0x60,0x60,0x60,0x30,0x18,0x30,0x60,0x60,0x60,0xc0,0x00, // } + 0x00,0x00,0x61,0x92,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // +}; + +#endif + +#ifdef USE_FONT_8x16 + +char font8x16[] = { + +/* Character (0x20): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character ! (0x21): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | **** | + | **** | + | **** | + | **** | + | ** | + | ** | + | | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x3c, +0x3c, +0x3c, +0x3c, +0x18, +0x18, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +/* Character " (0x22): + ht=16, width=8 + +--------+ + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | * * | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x36, +0x36, +0x36, +0x36, +0x14, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character # (0x23): + ht=16, width=8 + +--------+ + | | + | | + | ** ** | + | ** ** | + | ** ** | + |******* | + | ** ** | + | ** ** | + |******* | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x6c, +0x6c, +0x6c, +0xfe, +0x6c, +0x6c, +0xfe, +0x6c, +0x6c, +0x6c, +0x00, +0x00, +0x00, +0x00, + +/* Character $ (0x24): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ***** | + |** ** | + |** | + | **** | + | **** | + | ** | + |** ** | + | ***** | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x18, +0x7c, +0xc6, +0xc0, +0x78, +0x3c, +0x06, +0xc6, +0x7c, +0x18, +0x18, +0x00, +0x00, + +/* Character % (0x25): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** * | + | ** ** | + | ** | + | ** | + | ** | + | ** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x62, +0x66, +0x0c, +0x18, +0x30, +0x66, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character & (0x26): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** ** | + | *** | + | ** | + | *** ** | + | ****** | + |** ** | + |** ** | + |** ** | + | *** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x38, +0x6c, +0x38, +0x30, +0x76, +0x7e, +0xcc, +0xcc, +0xcc, +0x76, +0x00, +0x00, +0x00, +0x00, + +/* Character ' (0x27): + ht=16, width=8 + +--------+ + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x0c, +0x0c, +0x0c, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character ( (0x28): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x0c, +0x18, +0x30, +0x30, +0x30, +0x30, +0x30, +0x30, +0x18, +0x0c, +0x00, +0x00, +0x00, +0x00, + +/* Character ) (0x29): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x30, +0x18, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x18, +0x30, +0x00, +0x00, +0x00, +0x00, + +/* Character * (0x2a): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** ** | + | *** | + |******* | + | *** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x6c, +0x38, +0xfe, +0x38, +0x6c, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character + (0x2b): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** | + | ** | + | ****** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x7e, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character , (0x2c): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x0c, +0x0c, +0x0c, +0x18, +0x00, +0x00, +0x00, + +/* Character - (0x2d): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + |******* | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character . (0x2e): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +/* Character / (0x2f): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | * | + | ** | + | ** | + | ** | + | ** | + | ** | + |** | + |* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x02, +0x06, +0x0c, +0x18, +0x30, +0x60, +0xc0, +0x80, +0x00, +0x00, +0x00, +0x00, + +/* Character 0 (0x30): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** *** | + |** **** | + |**** ** | + |*** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xce, +0xde, +0xf6, +0xe6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 1 (0x31): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x78, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x7e, +0x00, +0x00, +0x00, +0x00, + +/* Character 2 (0x32): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0x06, +0x0c, +0x18, +0x30, +0x60, +0xc6, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character 3 (0x33): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + | ** | + | ** | + | **** | + | ** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0x06, +0x06, +0x3c, +0x06, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 4 (0x34): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | *** | + | **** | + | ** ** | + |** ** | + |** ** | + |******* | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x0c, +0x1c, +0x3c, +0x6c, +0xcc, +0xcc, +0xfe, +0x0c, +0x0c, +0x1e, +0x00, +0x00, +0x00, +0x00, + +/* Character 5 (0x35): + ht=16, width=8 + +--------+ + | | + | | + |******* | + |** | + |** | + |** | + |****** | + | ** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0xc0, +0xc0, +0xc0, +0xfc, +0x06, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 6 (0x36): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** | + |** | + |****** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0xc0, +0xfc, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 7 (0x37): + ht=16, width=8 + +--------+ + | | + | | + |******* | + |** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0xc6, +0x06, +0x0c, +0x18, +0x30, +0x30, +0x30, +0x30, +0x30, +0x00, +0x00, +0x00, +0x00, + +/* Character 8 (0x38): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 9 (0x39): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + | ****** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0x7e, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character : (0x3a): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** | + | ** | + | | + | | + | ** | + | ** | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character ; (0x3b): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** | + | ** | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x00, +0x0c, +0x0c, +0x0c, +0x18, +0x00, +0x00, +0x00, + +/* Character < (0x3c): + ht=16, width=8 + +--------+ + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + |** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x0c, +0x18, +0x30, +0x60, +0xc0, +0x60, +0x30, +0x18, +0x0c, +0x00, +0x00, +0x00, +0x00, + +/* Character = (0x3d): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + |******* | + | | + |******* | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x00, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character > (0x3e): + ht=16, width=8 + +--------+ + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x60, +0x30, +0x18, +0x0c, +0x06, +0x0c, +0x18, +0x30, +0x60, +0x00, +0x00, +0x00, +0x00, + +/* Character ? (0x3f): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + | ** | + | ** | + | ** | + | ** | + | | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0x0c, +0x18, +0x18, +0x18, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +/* Character @ (0x40): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** **** | + |** **** | + |** **** | + |** *** | + |** | + | ****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xde, +0xde, +0xde, +0xdc, +0xc0, +0x7e, +0x00, +0x00, +0x00, +0x00, + +/* Character A (0x41): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** ** | + |** ** | + |** ** | + |** ** | + |******* | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x38, +0x6c, +0xc6, +0xc6, +0xc6, +0xfe, +0xc6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character B (0x42): + ht=16, width=8 + +--------+ + | | + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfc, +0x66, +0x66, +0x66, +0x7c, +0x66, +0x66, +0x66, +0x66, +0xfc, +0x00, +0x00, +0x00, +0x00, + +/* Character C (0x43): + ht=16, width=8 + +--------+ + | | + | | + | **** | + | ** ** | + |** * | + |** | + |** | + |** | + |** | + |** * | + | ** ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x3c, +0x66, +0xc2, +0xc0, +0xc0, +0xc0, +0xc0, +0xc2, +0x66, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character D (0x44): + ht=16, width=8 + +--------+ + | | + | | + |***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xf8, +0x6c, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x6c, +0xf8, +0x00, +0x00, +0x00, +0x00, + +/* Character E (0x45): + ht=16, width=8 + +--------+ + | | + | | + |******* | + | ** ** | + | ** | + | ** * | + | ***** | + | ** * | + | ** | + | ** | + | ** ** | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0x66, +0x60, +0x64, +0x7c, +0x64, +0x60, +0x60, +0x66, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character F (0x46): + ht=16, width=8 + +--------+ + | | + | | + |******* | + | ** ** | + | ** | + | ** * | + | ***** | + | ** * | + | ** | + | ** | + | ** | + |**** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0x66, +0x60, +0x64, +0x7c, +0x64, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, +0x00, + +/* Character G (0x47): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** | + |** | + |** | + |** *** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc0, +0xc0, +0xc0, +0xce, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character H (0x48): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |******* | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xfe, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character I (0x49): + ht=16, width=8 + +--------+ + | | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x3c, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character J (0x4a): + ht=16, width=8 + +--------+ + | | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + |** ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x3c, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xd8, +0xd8, +0x70, +0x00, +0x00, +0x00, +0x00, + +/* Character K (0x4b): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |**** | + |**** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xcc, +0xd8, +0xf0, +0xf0, +0xd8, +0xcc, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character L (0x4c): + ht=16, width=8 + +--------+ + | | + | | + |**** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** * | + | ** ** | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xf0, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x62, +0x66, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character M (0x4d): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |*** *** | + |*** *** | + |******* | + |** * ** | + |** * ** | + |** * ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xee, +0xee, +0xfe, +0xd6, +0xd6, +0xd6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character N (0x4e): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |*** ** | + |*** ** | + |**** ** | + |** **** | + |** *** | + |** *** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xe6, +0xe6, +0xf6, +0xde, +0xce, +0xce, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character O (0x4f): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character P (0x50): + ht=16, width=8 + +--------+ + | | + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | ** | + | ** | + | ** | + |**** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfc, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, +0x00, + +/* Character Q (0x51): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** * ** | + |** * ** | + | ***** | + | ** | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xd6, +0xd6, +0x7c, +0x06, +0x00, +0x00, +0x00, + +/* Character R (0x52): + ht=16, width=8 + +--------+ + | | + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | **** | + | ** ** | + | ** ** | + | ** ** | + |*** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfc, +0x66, +0x66, +0x66, +0x7c, +0x78, +0x6c, +0x66, +0x66, +0xe6, +0x00, +0x00, +0x00, +0x00, + +/* Character S (0x53): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** | + |** | + | *** | + | *** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0xc0, +0x70, +0x1c, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character T (0x54): + ht=16, width=8 + +--------+ + | | + | | + | ****** | + | * ** * | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7e, +0x5a, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character U (0x55): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character V (0x56): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ** ** | + | *** | + | * | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x10, +0x00, +0x00, +0x00, +0x00, + +/* Character W (0x57): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** * ** | + |** * ** | + |** * ** | + |******* | + |*** *** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xd6, +0xd6, +0xd6, +0xfe, +0xee, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character X (0x58): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + | ** ** | + | *** | + | *** | + | ** ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x38, +0x6c, +0xc6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character Y (0x59): + ht=16, width=8 + +--------+ + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character Z (0x5a): + ht=16, width=8 + +--------+ + | | + | | + |******* | + |** ** | + |* ** | + | ** | + | ** | + | ** | + | ** | + |** * | + |** ** | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0xc6, +0x86, +0x0c, +0x18, +0x30, +0x60, +0xc2, +0xc6, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character [ (0x5b): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character \ (0x5c): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + |* | + |** | + | ** | + | ** | + | ** | + | ** | + | ** | + | * | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x80, +0xc0, +0x60, +0x30, +0x18, +0x0c, +0x06, +0x02, +0x00, +0x00, +0x00, +0x00, + +/* Character ] (0x5d): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character ^ (0x5e): + ht=16, width=8 + +--------+ + | | + | * | + | *** | + | ** ** | + |** ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x10, +0x38, +0x6c, +0xc6, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character _ (0x5f): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + |********| + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0x00, +0x00, + +/* Character ` (0x60): + ht=16, width=8 + +--------+ + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x18, +0x18, +0x18, +0x0c, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character a (0x61): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | **** | + | ** | + | ***** | + |** ** | + |** ** | + |** *** | + | *** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x78, +0x0c, +0x7c, +0xcc, +0xcc, +0xdc, +0x76, +0x00, +0x00, +0x00, +0x00, + +/* Character b (0x62): + ht=16, width=8 + +--------+ + | | + | | + |*** | + | ** | + | ** | + | ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xe0, +0x60, +0x60, +0x7c, +0x66, +0x66, +0x66, +0x66, +0x66, +0xfc, +0x00, +0x00, +0x00, +0x00, + +/* Character c (0x63): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ***** | + |** ** | + |** | + |** | + |** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0xc0, +0xc0, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character d (0x64): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** | + | ** | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x1c, +0x0c, +0x0c, +0x7c, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0x7e, +0x00, +0x00, +0x00, +0x00, + +/* Character e (0x65): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ***** | + |** ** | + |** ** | + |******* | + |** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xfe, +0xc0, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character f (0x66): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** ** | + | ** | + | ** | + |****** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x1c, +0x36, +0x30, +0x30, +0xfc, +0x30, +0x30, +0x30, +0x30, +0x78, +0x00, +0x00, +0x00, +0x00, + +/* Character g (0x67): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | *** ** | + |** *** | + |** ** | + |** ** | + |** *** | + | *** ** | + | ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x76, +0xce, +0xc6, +0xc6, +0xce, +0x76, +0x06, +0xc6, +0x7c, +0x00, +0x00, + +/* Character h (0x68): + ht=16, width=8 + +--------+ + | | + | | + |*** | + | ** | + | ** | + | ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |*** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xe0, +0x60, +0x60, +0x7c, +0x66, +0x66, +0x66, +0x66, +0x66, +0xe6, +0x00, +0x00, +0x00, +0x00, + +/* Character i (0x69): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x18, +0x00, +0x38, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character j (0x6a): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + |** ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x1c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0xcc, +0xcc, +0x78, +0x00, +0x00, + +/* Character k (0x6b): + ht=16, width=8 + +--------+ + | | + | | + |*** | + | ** | + | ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | ** ** | + | ** ** | + |*** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xe0, +0x60, +0x60, +0x66, +0x66, +0x6c, +0x78, +0x6c, +0x66, +0xe6, +0x00, +0x00, +0x00, +0x00, + +/* Character l (0x6c): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x1c, +0x00, +0x00, +0x00, +0x00, + +/* Character m (0x6d): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** ** | + |******* | + |** * ** | + |** * ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x6c, +0xfe, +0xd6, +0xd6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character n (0x6e): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xdc, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x00, +0x00, +0x00, +0x00, + +/* Character o (0x6f): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character p (0x70): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | ** | + | ** | + |**** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xdc, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x60, +0x60, +0xf0, +0x00, +0x00, + +/* Character q (0x71): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | *** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | ** | + | ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x76, +0xcc, +0xcc, +0xcc, +0xcc, +0x7c, +0x0c, +0x0c, +0x1e, +0x00, +0x00, + +/* Character r (0x72): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** *** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + |**** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xdc, +0x66, +0x60, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, +0x00, + +/* Character s (0x73): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ***** | + |** ** | + |** | + | ***** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0x7c, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character t (0x74): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + |****** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x30, +0x30, +0x30, +0xfc, +0x30, +0x30, +0x30, +0x30, +0x36, +0x1c, +0x00, +0x00, +0x00, +0x00, + +/* Character u (0x75): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | *** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0x76, +0x00, +0x00, +0x00, +0x00, + +/* Character v (0x76): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + | ** ** | + | *** | + | * | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x10, +0x00, +0x00, +0x00, +0x00, + +/* Character w (0x77): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** * ** | + |** * ** | + |** * ** | + |******* | + | ** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0xd6, +0xd6, +0xd6, +0xfe, +0x6c, +0x00, +0x00, +0x00, +0x00, + +/* Character x (0x78): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + | ** ** | + | *** | + | ** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0x6c, +0x38, +0x6c, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character y (0x79): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** *** | + | *** ** | + | ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xce, +0x76, +0x06, +0xc6, +0x7c, +0x00, +0x00, + +/* Character z (0x7a): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |******* | + |* ** | + | ** | + | ** | + | ** | + | ** * | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x86, +0x0c, +0x18, +0x30, +0x62, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character { (0x7b): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** | + | ** | + | ** | + | *** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x0e, +0x18, +0x18, +0x18, +0x70, +0x18, +0x18, +0x18, +0x18, +0x0e, +0x00, +0x00, +0x00, +0x00, + +/* Character | (0x7c): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x18, +0x18, +0x18, +0x00, +0x18, +0x18, +0x18, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +/* Character } (0x7d): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** | + | ** | + | ** | + | *** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x70, +0x18, +0x18, +0x18, +0x0e, +0x18, +0x18, +0x18, +0x18, +0x70, +0x00, +0x00, +0x00, +0x00, + +/* Character ~ (0x7e): + ht=16, width=8 + +--------+ + | | + | | + | *** ** | + |** *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x76, +0xdc, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character (0x7f): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | * | + | *** | + | *** | + | ** ** | + | ** ** | + |******* | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x10, +0x38, +0x38, +0x6c, +0x6c, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, + +}; +#endif + +#ifdef USE_FONT_8x13 + +/* This is the same font as the above 8x16, but with the "empty" top + * and bottom edges removed. Two pixels at the bottom and one at the + * top. + * It is up to the font rendering engine to insert them based on the + * font style chosen. See the font table at the bottom of this file. + */ +char font8x13[] = { + +/* Character (0x20): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character ! (0x21): + ht=13, width=8 + +--------+ + | | + | ** | + | **** | + | **** | + | **** | + | **** | + | ** | + | ** | + | | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x18, +0x3c, +0x3c, +0x3c, +0x3c, +0x18, +0x18, +0x00, +0x18, +0x18, +0x00, +0x00, + +/* Character " (0x22): + ht=13, width=8 + +--------+ + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | * * | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x36, +0x36, +0x36, +0x36, +0x14, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character # (0x23): + ht=13, width=8 + +--------+ + | | + | ** ** | + | ** ** | + | ** ** | + |******* | + | ** ** | + | ** ** | + |******* | + | ** ** | + | ** ** | + | ** ** | + | | + | | + +--------+ */ +0x00, +0x6c, +0x6c, +0x6c, +0xfe, +0x6c, +0x6c, +0xfe, +0x6c, +0x6c, +0x6c, +0x00, +0x00, + +/* Character $ (0x24): + ht=13, width=8 + +--------+ + | | + | ** | + | ** | + | ***** | + |** ** | + |** | + | **** | + | **** | + | ** | + |** ** | + | ***** | + | ** | + | ** | + +--------+ */ +0x00, +0x18, +0x18, +0x7c, +0xc6, +0xc0, +0x78, +0x3c, +0x06, +0xc6, +0x7c, +0x18, +0x18, + +/* Character % (0x25): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ** * | + | ** ** | + | ** | + | ** | + | ** | + | ** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x62, +0x66, +0x0c, +0x18, +0x30, +0x66, +0xc6, +0x00, +0x00, + +/* Character & (0x26): + ht=13, width=8 + +--------+ + | | + | *** | + | ** ** | + | *** | + | ** | + | *** ** | + | ****** | + |** ** | + |** ** | + |** ** | + | *** ** | + | | + | | + +--------+ */ +0x00, +0x38, +0x6c, +0x38, +0x30, +0x76, +0x7e, +0xcc, +0xcc, +0xcc, +0x76, +0x00, +0x00, + +/* Character ' (0x27): + ht=13, width=8 + +--------+ + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x0c, +0x0c, +0x0c, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character ( (0x28): + ht=13, width=8 + +--------+ + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x0c, +0x18, +0x30, +0x30, +0x30, +0x30, +0x30, +0x30, +0x18, +0x0c, +0x00, +0x00, + +/* Character ) (0x29): + ht=13, width=8 + +--------+ + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x30, +0x18, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x18, +0x30, +0x00, +0x00, + +/* Character * (0x2a): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ** ** | + | *** | + |******* | + | *** | + | ** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x6c, +0x38, +0xfe, +0x38, +0x6c, +0x00, +0x00, +0x00, +0x00, + +/* Character + (0x2b): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ** | + | ** | + | ****** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x7e, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +/* Character , (0x2c): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x0c, +0x0c, +0x0c, +0x18, +0x00, + +/* Character - (0x2d): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + |******* | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character . (0x2e): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x00, +0x00, + +/* Character / (0x2f): + ht=13, width=8 + +--------+ + | | + | | + | | + | * | + | ** | + | ** | + | ** | + | ** | + | ** | + |** | + |* | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x02, +0x06, +0x0c, +0x18, +0x30, +0x60, +0xc0, +0x80, +0x00, +0x00, + +/* Character 0 (0x30): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** ** | + |** *** | + |** **** | + |**** ** | + |*** ** | + |** ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc6, +0xce, +0xde, +0xf6, +0xe6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, + +/* Character 1 (0x31): + ht=13, width=8 + +--------+ + | | + | ** | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | | + | | + +--------+ */ +0x00, +0x18, +0x78, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x7e, +0x00, +0x00, + +/* Character 2 (0x32): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + |******* | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc6, +0x06, +0x0c, +0x18, +0x30, +0x60, +0xc6, +0xfe, +0x00, +0x00, + +/* Character 3 (0x33): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + | ** | + | ** | + | **** | + | ** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0x06, +0x06, +0x3c, +0x06, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, + +/* Character 4 (0x34): + ht=13, width=8 + +--------+ + | | + | ** | + | *** | + | **** | + | ** ** | + |** ** | + |** ** | + |******* | + | ** | + | ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x0c, +0x1c, +0x3c, +0x6c, +0xcc, +0xcc, +0xfe, +0x0c, +0x0c, +0x1e, +0x00, +0x00, + +/* Character 5 (0x35): + ht=13, width=8 + +--------+ + | | + |******* | + |** | + |** | + |** | + |****** | + | ** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0xfe, +0xc0, +0xc0, +0xc0, +0xfc, +0x06, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, + +/* Character 6 (0x36): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** | + |** | + |****** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc0, +0xc0, +0xfc, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, + +/* Character 7 (0x37): + ht=13, width=8 + +--------+ + | | + |******* | + |** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0xfe, +0xc6, +0x06, +0x0c, +0x18, +0x30, +0x30, +0x30, +0x30, +0x30, +0x00, +0x00, + +/* Character 8 (0x38): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** ** | + |** ** | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, + +/* Character 9 (0x39): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + | ****** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0x7e, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, + +/* Character : (0x3a): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ** | + | ** | + | | + | | + | ** | + | ** | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x00, +0x00, + +/* Character ; (0x3b): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ** | + | ** | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x00, +0x0c, +0x0c, +0x0c, +0x18, +0x00, + +/* Character < (0x3c): + ht=13, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + |** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x0c, +0x18, +0x30, +0x60, +0xc0, +0x60, +0x30, +0x18, +0x0c, +0x00, +0x00, + +/* Character = (0x3d): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | | + |******* | + | | + |******* | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x00, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character > (0x3e): + ht=13, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x60, +0x30, +0x18, +0x0c, +0x06, +0x0c, +0x18, +0x30, +0x60, +0x00, +0x00, + +/* Character ? (0x3f): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** ** | + | ** | + | ** | + | ** | + | ** | + | | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc6, +0x0c, +0x18, +0x18, +0x18, +0x00, +0x18, +0x18, +0x00, +0x00, + +/* Character @ (0x40): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** **** | + |** **** | + |** **** | + |** *** | + |** | + | ****** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xde, +0xde, +0xde, +0xdc, +0xc0, +0x7e, +0x00, +0x00, + +/* Character A (0x41): + ht=13, width=8 + +--------+ + | | + | *** | + | ** ** | + |** ** | + |** ** | + |** ** | + |******* | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0x38, +0x6c, +0xc6, +0xc6, +0xc6, +0xfe, +0xc6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, + +/* Character B (0x42): + ht=13, width=8 + +--------+ + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |****** | + | | + | | + +--------+ */ +0x00, +0xfc, +0x66, +0x66, +0x66, +0x7c, +0x66, +0x66, +0x66, +0x66, +0xfc, +0x00, +0x00, + +/* Character C (0x43): + ht=13, width=8 + +--------+ + | | + | **** | + | ** ** | + |** * | + |** | + |** | + |** | + |** | + |** * | + | ** ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x3c, +0x66, +0xc2, +0xc0, +0xc0, +0xc0, +0xc0, +0xc2, +0x66, +0x3c, +0x00, +0x00, + +/* Character D (0x44): + ht=13, width=8 + +--------+ + | | + |***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |***** | + | | + | | + +--------+ */ +0x00, +0xf8, +0x6c, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x6c, +0xf8, +0x00, +0x00, + +/* Character E (0x45): + ht=13, width=8 + +--------+ + | | + |******* | + | ** ** | + | ** | + | ** * | + | ***** | + | ** * | + | ** | + | ** | + | ** ** | + |******* | + | | + | | + +--------+ */ +0x00, +0xfe, +0x66, +0x60, +0x64, +0x7c, +0x64, +0x60, +0x60, +0x66, +0xfe, +0x00, +0x00, + +/* Character F (0x46): + ht=13, width=8 + +--------+ + | | + |******* | + | ** ** | + | ** | + | ** * | + | ***** | + | ** * | + | ** | + | ** | + | ** | + |**** | + | | + | | + +--------+ */ +0x00, +0xfe, +0x66, +0x60, +0x64, +0x7c, +0x64, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, + +/* Character G (0x47): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** ** | + |** | + |** | + |** | + |** *** | + |** ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc6, +0xc0, +0xc0, +0xc0, +0xce, +0xc6, +0xc6, +0x7c, +0x00, +0x00, + +/* Character H (0x48): + ht=13, width=8 + +--------+ + | | + |** ** | + |** ** | + |** ** | + |** ** | + |******* | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xfe, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, + +/* Character I (0x49): + ht=13, width=8 + +--------+ + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x3c, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, + +/* Character J (0x4a): + ht=13, width=8 + +--------+ + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + |** ** | + | *** | + | | + | | + +--------+ */ +0x00, +0x3c, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xd8, +0xd8, +0x70, +0x00, +0x00, + +/* Character K (0x4b): + ht=13, width=8 + +--------+ + | | + |** ** | + |** ** | + |** ** | + |** ** | + |**** | + |**** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0xc6, +0xc6, +0xcc, +0xd8, +0xf0, +0xf0, +0xd8, +0xcc, +0xc6, +0xc6, +0x00, +0x00, + +/* Character L (0x4c): + ht=13, width=8 + +--------+ + | | + |**** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** * | + | ** ** | + |******* | + | | + | | + +--------+ */ +0x00, +0xf0, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x62, +0x66, +0xfe, +0x00, +0x00, + +/* Character M (0x4d): + ht=13, width=8 + +--------+ + | | + |** ** | + |** ** | + |*** *** | + |*** *** | + |******* | + |** * ** | + |** * ** | + |** * ** | + |** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0xc6, +0xc6, +0xee, +0xee, +0xfe, +0xd6, +0xd6, +0xd6, +0xc6, +0xc6, +0x00, +0x00, + +/* Character N (0x4e): + ht=13, width=8 + +--------+ + | | + |** ** | + |** ** | + |*** ** | + |*** ** | + |**** ** | + |** **** | + |** *** | + |** *** | + |** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0xc6, +0xc6, +0xe6, +0xe6, +0xf6, +0xde, +0xce, +0xce, +0xc6, +0xc6, +0x00, +0x00, + +/* Character O (0x4f): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, + +/* Character P (0x50): + ht=13, width=8 + +--------+ + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | ** | + | ** | + | ** | + |**** | + | | + | | + +--------+ */ +0x00, +0xfc, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, + +/* Character Q (0x51): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** * ** | + |** * ** | + | ***** | + | ** | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xd6, +0xd6, +0x7c, +0x06, +0x00, + +/* Character R (0x52): + ht=13, width=8 + +--------+ + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | **** | + | ** ** | + | ** ** | + | ** ** | + |*** ** | + | | + | | + +--------+ */ +0x00, +0xfc, +0x66, +0x66, +0x66, +0x7c, +0x78, +0x6c, +0x66, +0x66, +0xe6, +0x00, +0x00, + +/* Character S (0x53): + ht=13, width=8 + +--------+ + | | + | ***** | + |** ** | + |** | + |** | + | *** | + | *** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0xc6, +0xc0, +0xc0, +0x70, +0x1c, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, + +/* Character T (0x54): + ht=13, width=8 + +--------+ + | | + | ****** | + | * ** * | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x7e, +0x5a, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, + +/* Character U (0x55): + ht=13, width=8 + +--------+ + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, + +/* Character V (0x56): + ht=13, width=8 + +--------+ + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ** ** | + | *** | + | * | + | | + | | + +--------+ */ +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x10, +0x00, +0x00, + +/* Character W (0x57): + ht=13, width=8 + +--------+ + | | + |** ** | + |** ** | + |** ** | + |** * ** | + |** * ** | + |** * ** | + |******* | + |*** *** | + |** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0xc6, +0xc6, +0xc6, +0xd6, +0xd6, +0xd6, +0xfe, +0xee, +0xc6, +0xc6, +0x00, +0x00, + +/* Character X (0x58): + ht=13, width=8 + +--------+ + | | + |** ** | + |** ** | + |** ** | + | ** ** | + | *** | + | *** | + | ** ** | + |** ** | + |** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x38, +0x6c, +0xc6, +0xc6, +0xc6, +0x00, +0x00, + +/* Character Y (0x59): + ht=13, width=8 + +--------+ + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | ** | + | ** | + | ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, + +/* Character Z (0x5a): + ht=13, width=8 + +--------+ + | | + |******* | + |** ** | + |* ** | + | ** | + | ** | + | ** | + | ** | + |** * | + |** ** | + |******* | + | | + | | + +--------+ */ +0x00, +0xfe, +0xc6, +0x86, +0x0c, +0x18, +0x30, +0x60, +0xc2, +0xc6, +0xfe, +0x00, +0x00, + +/* Character [ (0x5b): + ht=13, width=8 + +--------+ + | | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x7c, +0x00, +0x00, + +/* Character \ (0x5c): + ht=13, width=8 + +--------+ + | | + | | + | | + |* | + |** | + | ** | + | ** | + | ** | + | ** | + | ** | + | * | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x80, +0xc0, +0x60, +0x30, +0x18, +0x0c, +0x06, +0x02, +0x00, +0x00, + +/* Character ] (0x5d): + ht=13, width=8 + +--------+ + | | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x7c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x7c, +0x00, +0x00, + +/* Character ^ (0x5e): + ht=13, width=8 + +--------+ + | * | + | *** | + | ** ** | + |** ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x10, +0x38, +0x6c, +0xc6, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character _ (0x5f): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + |********| + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, + +/* Character ` (0x60): + ht=13, width=8 + +--------+ + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x18, +0x18, +0x18, +0x0c, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character a (0x61): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | **** | + | ** | + | ***** | + |** ** | + |** ** | + |** *** | + | *** ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x78, +0x0c, +0x7c, +0xcc, +0xcc, +0xdc, +0x76, +0x00, +0x00, + +/* Character b (0x62): + ht=13, width=8 + +--------+ + | | + |*** | + | ** | + | ** | + | ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |****** | + | | + | | + +--------+ */ +0x00, +0xe0, +0x60, +0x60, +0x7c, +0x66, +0x66, +0x66, +0x66, +0x66, +0xfc, +0x00, +0x00, + +/* Character c (0x63): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ***** | + |** ** | + |** | + |** | + |** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0xc0, +0xc0, +0xc6, +0x7c, +0x00, +0x00, + +/* Character d (0x64): + ht=13, width=8 + +--------+ + | | + | *** | + | ** | + | ** | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ****** | + | | + | | + +--------+ */ +0x00, +0x1c, +0x0c, +0x0c, +0x7c, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0x7e, +0x00, +0x00, + +/* Character e (0x65): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ***** | + |** ** | + |** ** | + |******* | + |** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xfe, +0xc0, +0xc6, +0x7c, +0x00, +0x00, + +/* Character f (0x66): + ht=13, width=8 + +--------+ + | | + | *** | + | ** ** | + | ** | + | ** | + |****** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x1c, +0x36, +0x30, +0x30, +0xfc, +0x30, +0x30, +0x30, +0x30, +0x78, +0x00, +0x00, + +/* Character g (0x67): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | *** ** | + |** *** | + |** ** | + |** ** | + |** *** | + | *** ** | + | ** | + |** ** | + | ***** | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x76, +0xce, +0xc6, +0xc6, +0xce, +0x76, +0x06, +0xc6, +0x7c, + +/* Character h (0x68): + ht=13, width=8 + +--------+ + | | + |*** | + | ** | + | ** | + | ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |*** ** | + | | + | | + +--------+ */ +0x00, +0xe0, +0x60, +0x60, +0x7c, +0x66, +0x66, +0x66, +0x66, +0x66, +0xe6, +0x00, +0x00, + +/* Character i (0x69): + ht=13, width=8 + +--------+ + | | + | ** | + | ** | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x18, +0x18, +0x00, +0x38, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, + +/* Character j (0x6a): + ht=13, width=8 + +--------+ + | | + | ** | + | ** | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + |** ** | + | **** | + +--------+ */ +0x00, +0x0c, +0x0c, +0x00, +0x1c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0xcc, +0xcc, +0x78, + +/* Character k (0x6b): + ht=13, width=8 + +--------+ + | | + |*** | + | ** | + | ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | ** ** | + | ** ** | + |*** ** | + | | + | | + +--------+ */ +0x00, +0xe0, +0x60, +0x60, +0x66, +0x66, +0x6c, +0x78, +0x6c, +0x66, +0xe6, +0x00, +0x00, + +/* Character l (0x6c): + ht=13, width=8 + +--------+ + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + +--------+ */ +0x00, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x1c, +0x00, +0x00, + +/* Character m (0x6d): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ** ** | + |******* | + |** * ** | + |** * ** | + |** ** | + |** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x6c, +0xfe, +0xd6, +0xd6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, + +/* Character n (0x6e): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + |** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0xdc, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x00, +0x00, + +/* Character o (0x6f): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, + +/* Character p (0x70): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + |** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | ** | + | ** | + |**** | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0xdc, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x60, +0x60, +0xf0, + +/* Character q (0x71): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | *** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | ** | + | ** | + | **** | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x76, +0xcc, +0xcc, +0xcc, +0xcc, +0x7c, +0x0c, +0x0c, +0x1e, + +/* Character r (0x72): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + |** *** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + |**** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0xdc, +0x66, +0x60, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, + +/* Character s (0x73): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | ***** | + |** ** | + |** | + | ***** | + | ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0x7c, +0x06, +0xc6, +0x7c, +0x00, +0x00, + +/* Character t (0x74): + ht=13, width=8 + +--------+ + | | + | ** | + | ** | + | ** | + |****** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | *** | + | | + | | + +--------+ */ +0x00, +0x30, +0x30, +0x30, +0xfc, +0x30, +0x30, +0x30, +0x30, +0x36, +0x1c, +0x00, +0x00, + +/* Character u (0x75): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | *** ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0x76, +0x00, +0x00, + +/* Character v (0x76): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + | ** ** | + | *** | + | * | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x10, +0x00, +0x00, + +/* Character w (0x77): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + |** ** | + |** ** | + |** * ** | + |** * ** | + |** * ** | + |******* | + | ** ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0xd6, +0xd6, +0xd6, +0xfe, +0x6c, +0x00, +0x00, + +/* Character x (0x78): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + |** ** | + |** ** | + | ** ** | + | *** | + | ** ** | + |** ** | + |** ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0x6c, +0x38, +0x6c, +0xc6, +0xc6, +0x00, +0x00, + +/* Character y (0x79): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** *** | + | *** ** | + | ** | + |** ** | + | ***** | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xce, +0x76, +0x06, +0xc6, +0x7c, + +/* Character z (0x7a): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + |******* | + |* ** | + | ** | + | ** | + | ** | + | ** * | + |******* | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0xfe, +0x86, +0x0c, +0x18, +0x30, +0x62, +0xfe, +0x00, +0x00, + +/* Character { (0x7b): + ht=13, width=8 + +--------+ + | | + | *** | + | ** | + | ** | + | ** | + | *** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + +--------+ */ +0x00, +0x0e, +0x18, +0x18, +0x18, +0x70, +0x18, +0x18, +0x18, +0x18, +0x0e, +0x00, +0x00, + +/* Character | (0x7c): + ht=13, width=8 + +--------+ + | | + | ** | + | ** | + | ** | + | ** | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x18, +0x18, +0x18, +0x18, +0x00, +0x18, +0x18, +0x18, +0x18, +0x18, +0x00, +0x00, + +/* Character } (0x7d): + ht=13, width=8 + +--------+ + | | + | *** | + | ** | + | ** | + | ** | + | *** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + +--------+ */ +0x00, +0x70, +0x18, +0x18, +0x18, +0x0e, +0x18, +0x18, +0x18, +0x18, +0x70, +0x00, +0x00, + +/* Character ~ (0x7e): + ht=13, width=8 + +--------+ + | | + | *** ** | + |** *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x76, +0xdc, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character (0x7f): + ht=13, width=8 + +--------+ + | | + | | + | | + | | + | * | + | *** | + | *** | + | ** ** | + | ** ** | + |******* | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x10, +0x38, +0x38, +0x6c, +0x6c, +0xfe, +0x00, +0x00, +0x00, + +}; +#endif + +/* This table allows the font rendering engine (fbi_putchar() in fbi.c) + * to support some flexibility of spacing between and above/below + * characters. + */ +struct font font_styles[] = { + /* bitmap, width, height, above, below, between */ +#ifdef USE_FONT_8x16 + { font8x16, 7, 16, 0, 0, 0 }, + { font8x16, 8, 16, 0, 0, 0 }, + { font8x16, 8, 16, 0, 0, 1 }, + { font8x16, 8, 16, 0, 1, 0 }, + { font8x16, 8, 16, 0, 1, 1 }, + { font8x16, 8, 16, 1, 0, 0 }, + { font8x16, 8, 16, 1, 0, 1 }, + { font8x16, 8, 16, 1, 1, 0 }, + { font8x16, 8, 16, 1, 1, 1 }, +#endif +#ifdef USE_FONT_8x13 + { font8x13, 7, 13, 0, 0, 0 }, + { font8x13, 8, 13, 0, 0, 0 }, + { font8x13, 8, 13, 0, 0, 1 }, + { font8x13, 8, 13, 0, 1, 0 }, + { font8x13, 8, 13, 0, 1, 1 }, + { font8x13, 8, 13, 1, 0, 0 }, + { font8x13, 8, 13, 1, 0, 1 }, + { font8x13, 8, 13, 1, 1, 0 }, + { font8x13, 8, 13, 1, 1, 1 }, + { font8x13, 8, 13, 1, 2, 1 }, +#endif +#ifdef USE_FONT_8x12 + { font8x12, 8, 12, 0, 0, 0 }, + { font8x12, 8, 12, 0, 0, 1 }, + { font8x12, 8, 12, 0, 1, 0 }, + { font8x12, 8, 12, 0, 1, 1 }, + { font8x12, 8, 12, 1, 0, 0 }, + { font8x12, 8, 12, 1, 0, 1 }, + { font8x12, 8, 12, 1, 1, 0 }, + { font8x12, 8, 12, 1, 1, 1 }, +#endif +}; + +int +font_style_total(void) +{ + return(sizeof(font_styles)/sizeof(struct font)); +} diff --git a/main/common/font.h b/main/common/font.h new file mode 100755 index 0000000..c1fcd8f --- /dev/null +++ b/main/common/font.h @@ -0,0 +1,47 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * font.h + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +struct font { + char *bitmap; /* Pointer to font bitmap array. */ + int width; /* Width of font in array. */ + int height; /* Height of font in array. */ + int above; /* Number of pixels of empty space above. */ + int below; /* Number of pixels of empty space blow. */ + int between; /* Number of pixels of separation between each char. */ +}; + +extern char font8x12[]; +extern struct font font_styles[]; +extern int font_style_total(void); + +#define MAX_FONT_WIDTH 8 +#define MIN_FONT_WIDTH 8 + +#define FONT_WHITE 0x00ffffff +#define FONT_BLACK 0x00000000 +#define FONT_TRANSPARENT 0x01000000 +#define FONT_INVERT 0x02000000 + +#define OPAQUE_BACKGROUND(x) ((x & FONT_TRANSPARENT) == 0) diff --git a/main/common/gdb.c b/main/common/gdb.c new file mode 100644 index 0000000..74b8b5e --- /dev/null +++ b/main/common/gdb.c @@ -0,0 +1,686 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * gdb.c: + * + * The code in this file allows a gdb debugger on a host to connect to the + * monitor. It supports both serial and network (udp) connections. + * Note that this is only the cpu-independent portion of the GDB debug + * protocol. The following commands in gdb have been verified to work + * with this code: + * + * - target remote com1 + * - target remote udp:135.222.140.68:1234 + * - load and c + * - info registers + * - x/16x 0xff800000 + * - print varname + * + *I'm sure other commands work, but these are the ones I've tested. + * + * This interface was written from scratch. + * References used were: + * Bill Gatliff's ESP article and a description of the GDB Remote + * Serial Protocol I found at: + * http://developer/apple.com/documentation/DeveloperTools/gdb/gdb/gdb_32.htm + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "genlib.h" +#include "ether.h" +#include "stddefs.h" +#include "endian.h" +#include "cli.h" + +#if INCLUDE_GDB + +#include "gdbregs.c" /* CPU-specific register name table */ + +#define REGTBL_SIZE (sizeof(gdb_regtbl)/sizeof(char *)) + +#define GDBERR_NOHASH 1 /* no '#' in command */ +#define GDBERR_BADCSUM 2 /* bad checksum */ +#define GDBERR_GENERR 3 /* general confusion */ +#define GDBERR_BADXFMT 4 /* unexpected 'X' command format */ +#define GDBERR_RNUMOOR 5 /* register number out of range */ +#define GDBERR_NOSPACE 6 /* buffer not big enough for response */ + +/* gdbIbuf[]: + * Input buffer used for storage of the incoming command from + * the gdb debugger. + */ +#if INCLUDE_ETHERNET +static uchar gdbIbuf[512]; +#endif + +/* gdbRbuf[]: + * Response buffer used for the complete response destined + * for the gdb host. + */ +static uchar gdbRbuf[1024]; +static int gdbRlen; +static void (*gdbContinueFptr)(); + +/* gdbUdp: + * Set if the gdb interaction is via UDP, else zero. + * Obviously this code assumes there is no reentrancy to deal with. + */ +static int gdbUdp; + +/* gdbTrace(): + * This is a function pointer that is loaded with either printf + * or Mtrace... Use printf if gdb is running via UDP; else use + * printf. + */ +static int (*gdbTrace)(char *, ...); + +/* gdb_response(): + * Utility function used by the other response functions to format + * the complete response back to the gdb host. All interaction with + * the host is in ASCII. The response message is preceded by '+$' + * and and terminated with '#CC' where 'CC' is a checksum. + */ +int +gdb_response(char *line) +{ + uchar csum, *resp; + + csum = 0; + resp = gdbRbuf; + *resp++ = '$'; + while(*line) { + csum += *line; + *resp++ = *line++; + } + resp += sprintf((char *)resp,"#%02x",csum); + *resp = 0; + + /* If gdbUdp is clear, then we assume that the gdb host is tied + * to the target's serial port, so just use printf to send the + * response. + * If gdbUdp is set, then we assume the calling function will + * send the response (via ethernet). + */ + if (!gdbUdp) + printf((char *)gdbRbuf); + + gdbRlen = strlen((char *)gdbRbuf); + + if (gdbRlen < 128) + gdbTrace("GDB_RSP: %s\n",gdbRbuf); + else + gdbTrace("GDB_RSP: BIG\n"); + + return(gdbRlen); +} + +int +gdb_ok(void) +{ + return(gdb_response("OK")); +} + +int +gdb_sig(int signal) +{ + char buf[8]; + + sprintf(buf,"S%02d",signal); + return(gdb_response(buf)); +} + +int +gdb_err(int errno) +{ + char buf[8]; + + sprintf(buf,"E%02d",errno); + return(gdb_response(buf)); +} + +/* gdb_m(): + * GDB memory read command... + * Incoming command format is... + * + * mADDR,LEN#CC + * + * where: + * 'm' is the "memory read" request + * 'ADDR' is the address from which the data is to be read + * 'LEN' is the number of bytes to be read + * + */ +int +gdb_m(char *line) +{ + int len, i; + char *lp; + uchar *addr, *resp, buf[128]; + + addr = (uchar *)strtol(line+1,&lp,16); + len = (int)strtol(lp+1,0,16); + if (len) { + if (len*2 >= sizeof(buf)) { + gdb_err(GDBERR_NOSPACE); + } + else { + resp = buf; + for(i=0;i<len;i++,addr++) + resp += sprintf((char *)resp,"%02x",*addr); + gdb_response((char *)buf); + } + } + else + gdb_ok(); + return(0); +} + +/* gdb_M(): + * GDB memory write command... + * Incoming command format is... + * + * MADDR,LEN:DATA#CC + * + * where: + * 'M' is the "memory read" request + * 'ADDR' is the address from which the data is to be read + * 'LEN' is the number of bytes to be read + * 'DATA' is the ascii data + * + * STATUS: This function has been tested with m68k-elf-gdb (xtools) + * and appears to work ok. + */ +int +gdb_M(char *line) +{ + int len, i; + char *lp; + uchar *addr, buf[3]; + + addr = (uchar *)strtol(line+1,&lp,16); + len = (int)strtol(lp+1,&lp,16); + lp++; + + buf[2] = 0; + for(i=0;i<len;i++) { + buf[0] = *lp++; + buf[1] = *lp++; + *addr++ = (uchar)strtol((char *)buf,0,16); + } + gdb_ok(); + return(0); +} + +/* gdb_X(): + * Similar to gdb_M() except that the data is in binary. + * The characters '$', '#' and 0x7d are escaped using 0x7d. + */ +int +gdb_X(char *line) +{ + int len, i; + char *lp; + uchar *addr; + + addr = (uchar *)strtol(line+1,&lp,16); + len = (int)strtol(lp+1,&lp,16); + lp++; + + for(i=0;i<len;i++) { + if ((*lp == 0x7d) && + ((*(lp+1) == 0x03) || (*(lp+1) == 0x04) || (*(lp+1) == 0x5d))) { + *addr++ = *(lp+1) | 0x20; + lp += 2; + } + else + *addr++ = *lp++; + } + + gdb_ok(); + return(0); +} + +/* gdb_q(): + * Query. Not sure what this is for, but according to Gatliff's + * article, just do it... + */ +int +gdb_q(char *line) +{ + line++; + + if (strncmp(line,"Offsets",7) == 0) + return(gdb_response("Text=0;Data=0;Bss=0")); + else + return(gdb_ok()); +} + +/* gdb_g(): + * Get all registers. + * GDB at the host expects to see a buffer of ASCII-coded hex values + * with each register being 8-bytes (forming one 32-bit value). + * The order of these registers is defined by the table included + * in the file gdbregs.c above. + */ + +int +gdb_g(char *line) +{ + int i; + ulong reg; + char *resp, buf[(REGTBL_SIZE * 8) + 1]; + + resp = buf; + for(i=0;i<REGTBL_SIZE;i++) { + if (gdb_regtbl[i] != 0) + getreg(gdb_regtbl[i],®); + else + reg = 0; + self_ecl(reg); + resp += sprintf(resp,"%08lx",reg); + } + return(gdb_response(buf)); +} + +/* gdb_P(): + * Store to a register. + */ +int +gdb_P(char *line) +{ + char *lp; + int rnum; + ulong rval; + + line++; + rnum = strtol(line,&lp,16); + if (rnum >= REGTBL_SIZE) { + gdb_err(GDBERR_RNUMOOR); + return(-1); + } + lp++; + rval = strtol(lp,0,16); + self_ecl(rval); + putreg(gdb_regtbl[rnum],rval); + + gdb_ok(); + return(0); +} + +/* gdb_c(): + * This is the function that is called as a result of the 'c' (continue) + * command. + */ +int +gdb_c(char *line) +{ + ulong addr; + void (*func)(); + + line++; + if (*line == '#') + getreg(CPU_PC_REG,&addr); + else + addr = strtol(line,0,16); + + func = (void(*)())addr; + func(); + return(0); +} + +/* gdb_cmd(): + * First function called out of the monitor's command interpreter. It + * does a basic syntax verification and then passes parameters to the + * appropriate handler above. + * Incoming syntax is + * + * $ CMD # CSUM (of CMD) + * + * where: + * $ is the ascii '$' character (0x24) + * # is the ascii '#' character (0x23) + * CMD is some command line consisting of a command and arguments + * CSUM is the checksum of the characters in CMD + * + * for example: + * + * $m4015bc,2#5a + * + * Returns... + * 0 if command is not processed; + * 1 if command is processed; + * -1 if command is processed but has an error; + * + * If this code detects an error, then send an error code back to GDB. + * According to the article, there are no defined error codes in GDB so + * we will use the following... + * 1 indicates a missing '#' at the end of the incoming cmd string. + * 2 indicates a bad checksum calculation. + * 3 indicates some command processing error. + * 4 indicates bad 'X' command parsing. + */ +int +gdb_cmd(uchar *line) +{ + char *comma, *colon, *cp, *bp, buf[32]; + int len, clen, err, i; + uchar mycsum, incsum; + + gdbContinueFptr = (void(*)())0; + + /* If the command is 'X', then we have to treat it "special" because + * it contains binary data... + */ + if (line[1] == 'X') { + comma = strchr((char *)line,','); + colon = strchr((char *)line,':'); + if ((comma) && (colon)) { + bp = buf; + cp = (char *)line; + while(cp <= colon) + *bp++ = *cp++; + *bp = 0; + gdbTrace("GDB_CMD: '%s'\n",buf); + } + else { + gdbTrace("GDB_CMD: 'X'\n"); + gdb_err(GDBERR_BADXFMT); /* Unexpected 'X' command format */ + } + } + else if (line[0] == 0x03) { + gdbTrace("GDB_CTRLC\n"); + gdb_sig(2); + return(1); + } + else { + gdbTrace("GDB_CMD: '%s'\n",line); + len = strlen((char *)line); + + if (line[len-3] != '#') { + gdb_err(GDBERR_NOHASH); /* Missing ending '#' */ + return(-1); + } + + clen = len - 3; + mycsum = 0; + for(i=1;i<clen;i++) + mycsum += line[i]; + + incsum = (uchar)strtol((char *)line+len-2,(char **)0,16); + if (mycsum != incsum) { + gdb_err(GDBERR_BADCSUM); /* Checksum failure */ + return(-1); + } + } + + err = 0; + line++; + switch(*line) { + case 'm': /* Memory read */ + err = gdb_m((char *)line); + break; + case 'M': /* Memory write (Ascii-coded-hex) */ + err = gdb_M((char *)line); + break; + case 'X': /* Memory write (Binary) */ + err = gdb_X((char *)line); + break; + case 's': /* Step */ + gdb_response("S05"); + break; + case 'c': /* Continue */ + gdb_c((char *)line); + break; + case '?': /* Last signal */ + gdb_response("S05"); + break; + case 'g': /* get all registers */ + gdb_g((char *)line); + break; + case 'q': /* Query */ + gdb_q((char *)line); + break; + case 'P': /* PRR=HHHHHHHH... reg*/ + gdb_P((char *)line); + break; + case 'H': /* Thread */ + gdb_ok(); + break; + case 'k': /* Quit */ + gdb_ok(); + break; + default: /* Unknown... return empty response. */ + gdb_response(""); + break; + } + if (err) { + gdb_err(GDBERR_GENERR); /* Command processing error */ + } + return(1); +} + +/* Gdb(): + * This is the command at the CLI that allows the monitor to connect + * to a gdb debugger via the serial port. It currently assumes that + * the console port is the same port as is being used for the gdb + * connection. Eventually this needs to be modified to provide an + * option for the gdb protocol to run on some serial port other than + * the console. + * + * The connection command in gdb to connect to via serial port (PC) + * is: + * target remote com1 + */ +char *GdbHelp[] = { + "Enter gdb mode", + "(no options)", + 0, +}; + +int +Gdb(int argc, char *argv) +{ + int state, quit; + uchar *lp, c; + static uchar line[1024]; + + printf("Entering GDB mode, to exit manually type: '$k#00'\n"); + + lp = (uchar *)0; + quit = 0; + state = 0; + gdbUdp = 0; + gdbTrace = Mtrace; + while(!quit) { + c = getchar(); + switch(state) { + case 0: /* Wait for start of message */ + if (c == '$') { + lp = line; + *lp++ = c; + state = 1; + } + break; + case 1: + *lp++ = c; /* This is the command character */ + state = 2; + break; + case 2: + if (c == '#') { + state = 3; + *lp++ = c; + } + else { + *lp++ = c; + } + break; + case 3: + *lp++ = c; + state = 4; + break; + case 4: + *lp++ = c; + *lp = 0; + state = 0; + if (line[1] == 'k') + quit = 1; + gdb_cmd(line); + break; + default: + break; + } + } + putchar('\n'); + return(CMD_SUCCESS); +} + +#if INCLUDE_ETHERNET +/* processGDB(): + * This is the function that allows a remote gdb host to connect to + * the monitor with gdb at the udp level. The connection command in + * gdb to do this is: + * + * target remote udp:TARGET_IP:TARGET_PORT + */ +int +processGDB(struct ether_header *ehdr,ushort size) +{ + char *gdbp; + struct ip *ihdr, *ti, *ri; + struct Udphdr *uhdr, *tu, *ru; + struct ether_header *te; + + /* If SHOW_GDB is set (via ether -vg), then we dump the trace to + * the console; otherwise, we use mtrace. + */ +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_GDB) + gdbTrace = printf; + else +#endif + gdbTrace = Mtrace; + + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); + gdbp = (char *)(uhdr + 1); + size = ecs(uhdr->uh_ulen) - sizeof(struct Udphdr); + + /* Check for ACK/NAK here: + */ + if (size == 1) { + if ((*gdbp == '+') || (*gdbp == '-')) { + gdbTrace("GDB_%s\n",*gdbp == '+' ? "ACK" : "NAK"); + return(0); + } + } + + /* Copy the incoming udp payload (the gdb command) to gdbIbuf[] + * and NULL terminate it... + */ + memcpy((char *)gdbIbuf,(char *)gdbp,size); + gdbIbuf[size] = 0; + + /* Now that we've stored away the GDB command request, we + * initially respond with the GDB acknowledgement ('+')... + */ + te = EtherCopy(ehdr); + ti = (struct ip *) (te + 1); + ri = (struct ip *) (ehdr + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ti->ip_len = ecs((1 + (sizeof(struct ip) + sizeof(struct Udphdr)))); + ti->ip_id = ipId(); + ti->ip_off = ri->ip_off; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), + sizeof(struct in_addr)); + tu = (struct Udphdr *) (ti + 1); + ru = (struct Udphdr *) (ri + 1); + tu->uh_sport = ru->uh_dport; + tu->uh_dport = ru->uh_sport; + tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + 1)); + gdbp = (char *)(tu+1); + *gdbp = '+'; + + ipChksum(ti); /* Compute checksum of ip hdr */ + udpChksum(ti); /* Compute UDP checksum */ + + sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) + + sizeof(struct Udphdr) + 1); + + /* Wrap the processing of the incoming packet with a set/clear + * of the gdbUdp flag so that the other gdb code can act + * accordingly. + */ + gdbUdp = 1; + if (gdb_cmd(gdbIbuf) == 0) { + gdbUdp = 0; + return(0); + } + gdbUdp = 0; + + /* Add 1 to the gdbRlen to include the NULL termination. + */ + gdbRlen++; + + + /* The second respons is only done if gdb_cmd returns non-zero. + * It is the response to the gdb command issued by the debugger + * on the host. + */ + te = EtherCopy(ehdr); + ti = (struct ip *) (te + 1); + ri = (struct ip *) (ehdr + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ti->ip_len = ecs((gdbRlen + (sizeof(struct ip) + sizeof(struct Udphdr)))); + ti->ip_id = ipId(); + ti->ip_off = ri->ip_off; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&(ti->ip_src.s_addr),(char *)BinIpAddr, + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), + sizeof(struct in_addr)); + + tu = (struct Udphdr *) (ti + 1); + ru = (struct Udphdr *) (ri + 1); + tu->uh_sport = ru->uh_dport; + tu->uh_dport = ru->uh_sport; + tu->uh_ulen = ecs((ushort)(sizeof(struct Udphdr) + gdbRlen)); + memcpy((char *)(tu+1),(char *)gdbRbuf,gdbRlen); + + ipChksum(ti); /* Compute checksum of ip hdr */ + udpChksum(ti); /* Compute UDP checksum */ + + sendBuffer(sizeof(struct ether_header) + sizeof(struct ip) + + sizeof(struct Udphdr) + gdbRlen); + + return(1); +} +#endif + +#endif + diff --git a/main/common/genlib.h b/main/common/genlib.h new file mode 100644 index 0000000..c0338cd --- /dev/null +++ b/main/common/genlib.h @@ -0,0 +1,269 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * genlib.h: + * + * Header file for functions in genlib.c (and some others). + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _GENLIB_H_ +#define _GENLIB_H_ + +#include <stdarg.h> + +/* Some compilers consider sizeof() to be unsigned... */ +#define sizeof (int)sizeof + +extern int optind; +extern char *optarg; + +extern int abs(int); +extern int atoi(char *); +extern int memcmp(char *, char *, int); +extern int strcmp(char *, char *); +extern int strcasecmp(char *, char *); +extern int strncmp(char *, char *, int); +extern int strlen(char *); +extern int strspn(char *, char *); +extern int strcspn(char *, char *); +extern int getopt(int,char **,char *); +extern int s_memcpy(char *, char *, int, int, int); +extern int s_memset(unsigned char *,unsigned char,int,int,int); +extern char *memccpy(char *, char *, int, int); +extern char *memchr(char *, char, int); +extern char *memcpy(char *, char *, int); +extern void bcopy(char *, char *, int); +extern char *memset(char *, char, int); +extern char *strcat(char *, char *); +extern char *strchr(char *, char); +extern char *strstr(char *, char *); +extern char *strcpy(char *, char *); +extern char *strncat(char *, char *, int); +extern char *strncpy(char *, char *, int); +extern char *strpbrk(char *, char *); +extern char *strrchr(char *, char); +extern char *strtok(char *, char *); +extern char *strtolower(char *string); +extern char *strtoupper(char *string); +extern long strtol(char *, char **, int); +extern unsigned short swap2(unsigned short); +extern unsigned long swap4(unsigned long); +extern unsigned long strtoul(char *, char **, int); +extern void getoptinit(void); +extern void prstring(char *); +extern void prlong(long); +extern long lceil(long n, long to); +extern unsigned long ulceil(unsigned long n, unsigned long to); + +/* Included here, but not in genlib.c: */ +extern int target_gotachar(void), gotachar(void); +extern int target_getchar(void), getchar(void); +extern int target_putchar(char), putchar(char); +extern int target_console_empty(void); +extern int AddrToSym(int,unsigned long,char *,unsigned long *); +extern int printf(char *, ...); +extern int sprintf(char *, char *, ...); +extern int snprintf(char *, int, char *, ...); +extern int vsnprintf(char *, int, char *, va_list); +extern int cprintf(char *, ...); +extern int getbytes(char *,int,int); +extern int getbytes_t(char *,int,int); +extern int putbytes(char *,int); +extern int getUsrLvl(void); +extern int setenv(char *,char *); +extern int shell_sprintf(char *,char *fmt,...); +extern int getline(char *,int,int); +extern int getline_t(char *,int,int); +extern int getline_p(char *,int,int,char *); +extern int getfullline(char *buf,int max,int ledit,int timeout,\ + char *prefill, int echo); +extern int stkchk(char *); +extern int inRange(char *,int); +extern int More(void); +extern int validPassword(char *,int); +extern int newPasswordFile(void); +extern int extValidPassword(char *,int); +extern int setCmdUlvl(char *,int); +extern int askuser(char *); +extern int hitakey(void); +extern int getreg(char *,unsigned long *); +extern int putreg(char *,unsigned long); +extern int putargv(int,char *); +extern int addrtosector(unsigned char *,int *,int *,unsigned char **); +extern int AppFlashWrite(unsigned char *,unsigned char *,long); +extern int AppFlashErase(int); +extern int flushDcache(char *,int); +extern int invalidateIcache(char *,int); +extern int pollConsole(char *); +extern int sectortoaddr(int,int *,unsigned char **); +extern int sectorProtect(char *,int); +extern int FlashInit(void); +extern int cacheInit(void); +extern int pioget(char,int); +extern int extendHeap(char *,int); +extern int decompress(char *,int,char *); +extern int RedirectionCheck(char *); +extern int docommand(char *, int); +extern int SymFileFd(int); +extern int ShellVarInit(void); +extern int showDate(int); +extern int inUmonBssSpace(char *,char *); +extern int passwordFileExists(void); +extern int Mtrace(char *, ...); +extern int monWatchDog(void); +extern int ConsoleBaudSet(int); +extern int ChangeConsoleBaudrate(int); +extern int TextInRam(void); +extern int uMonInRam(void); +extern long portCmd(int, void *); +extern unsigned short xcrc16(unsigned char *buffer,unsigned long nbytes); +extern unsigned long crc32(unsigned char *,unsigned long); +extern unsigned long intsoff(void); +extern unsigned long getAppRamStart(void); +extern unsigned long assign_handler(long, unsigned long, unsigned long); +extern char *line_edit(char *); +#ifndef MALLOC_DEBUG +extern char *malloc(int); +extern char *realloc(char *,int); +#endif +extern char *getenvp(void); +extern char *getenv(char *); +extern char *getpass(char *,char *,int,int); +extern char *getsym(char *,char *,int); +extern char *monVersion(void); +extern char *monBuilt(void); +extern char *ExceptionType2String(int); +extern char *shellsym_chk(char,char *,int *,char *,int); +extern void stkusage(void); +extern void target_reset(void); +extern void flush_console_out(void); +extern void flush_console_in(void); +extern void initCPUio(void); +extern void historyinit(void); +extern void AppWarmStart(unsigned long mask); +extern void MtraceInit(char *,int); +extern void monrestart(int); +extern void historylog(char *); +extern void free(void *); +extern void puts(char *); +extern void putstr(char *); +extern void MonitorBuiltEnvSet(void); +extern void writeprompt(void); +extern void intsrestore(unsigned long); +extern void prascii(unsigned char *,int); +extern void cacheInitForTarget(void); +extern void exceptionAutoRestart(int); +extern void clrTmpMaxUsrLvl(int (*)(void)); +extern void *setTmpMaxUsrLvl(void); +extern void rawon(void), rawoff(void); +extern void monHeader(int); +extern void mstatshowcom(void); +extern void CommandLoop(void); +extern void flushRegtbl(void); + +extern void showregs(void), reginit(void); +extern void initUsrLvl(int); +extern void warmstart(int); +extern void coldstart(void); +extern void InitRemoteIO(void); +extern void appexit(int); +extern void pioset(char,int); +extern void pioclr(char,int); +extern void getargv(int *argc, char ***argv); +extern void init0(void), init1(void), init2(void), init3(void); +extern void EnableBreakInterrupt(void); +extern void DisableBreakInterrupt(void); +extern void ctxMON(void), ctxAPP(void); +extern void printMem(unsigned char *,int,int); +extern void monDelay(int); +extern void ticktock(void); +extern void atinit(void); +extern void umonBssInit(void); +extern void ConsoleBaudEnvSet(void); +extern void console_echo(int); +extern void LowerFlashProtectWindow(void); +#if INCLUDE_REDIRECT +extern void RedirectCharacter(char); +extern void RedirectionCmdDone(void); +#else +#define RedirectCharacter(c) +#define RedirectionCmdDone() +#endif + +extern double atof(const char *str); +extern double strtod(const char *str, char **endptr); + +extern unsigned long MonStack[]; +extern const unsigned long crc32tab[]; +extern unsigned short xcrc16tab[]; +extern char *Mtracebuf; +extern char ApplicationInfo[]; +extern unsigned long ExceptionAddr, LoopsPerMillisecond; +extern unsigned long APPLICATION_RAMSTART, BOOTROM_BASE; +extern int ConsoleDevice; +extern int ConsoleBaudRate; +extern int StateOfMonitor, AppExitStatus, ExceptionType; +extern int bss_start, bss_end, boot_base; +extern int (*remoterawon)(void), (*remoterawoff)(void); +extern int (*remoteputchar)(int), (*remotegetchar)(void); +extern int (*remotegotachar)(void); +extern int (*dcacheFlush)(char *,int), (*icacheInvalidate)(char *,int); +extern int (*extgetUsrLvl)(void); +extern int (*moncomptr)(int,void *, void *, void *); + +#define STACK_PREINIT_VAL 0x63636363 + +/* If the watchdog macro is defined, then we also define the + * WATCHDOG_ENABLED macro so that code can use #ifdef WATCHDOG_ENABLED + * or simply insert WATCHDOG_MACRO inline... + * This eliminates the need for the ifdef wrapper if no other code is + * included with the macro. + */ +#ifdef WATCHDOG_MACRO +extern int (*remoteWatchDog)(void); +#define WATCHDOG_ENABLED +#else +#define WATCHDOG_MACRO +#endif + +#endif + +#ifndef HUGE_VAL +#define HUGE_VAL (__builtin_huge_val()); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +typedef struct { + int quot; + int rem; +} div_t; + +typedef struct { + long int quot; + long int rem; +} ldiv_t; + +extern ldiv_t ldiv(long,long); +extern div_t div(int,int); diff --git a/main/common/i2c.c b/main/common/i2c.c new file mode 100644 index 0000000..3982fb0 --- /dev/null +++ b/main/common/i2c.c @@ -0,0 +1,159 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * i2c.c: + * + * This file contains all of the generic code to support a target + * with one or more I-Squared-C interface masters. + * It assumes that somewhere in target-specific space there are three + * i2c interface functions: i2cRead(), i2cWrite() and i2cCtrl(). + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cli.h" +#include "i2c.h" +#include "genlib.h" +#include "stddefs.h" + +int i2cVerbose; + +char *I2cHelp[] = { + "I-Squared-C Interface Access", + "[options] {init | show | read addr len | write addr data}", +#if INCLUDE_VERBOSEHELP + "Options:", + " -b burst", + " -i{##} interface", + " -w{data} pre-write data as part of read (uses repeated start)", + " -v verbose", +#endif + 0, +}; + +int +I2cCmd(int argc, char *argv[]) +{ + char *next; + uchar buf[256]; + int i, wtot, opt, interface, len, rslt, addr, burst, ret, rwctrl; + + rslt = 0; + wtot = 0; + burst = 0; + rwctrl = 0; + interface = 0; + i2cVerbose = 0; + ret = CMD_SUCCESS; + while ((opt=getopt(argc,argv,"bi:vw:")) != -1) { + switch(opt) { + case 'i': + interface = atoi(optarg); + break; + case 'b': + burst = 1; /* Do multiple accesses within one START/STOP */ + break; + case 'w': /* Pre-write in a read */ + burst = 1; + rwctrl = REPEATED_START; + for(wtot=1;wtot<sizeof(buf);wtot++) { + buf[wtot] = (uchar)strtol(optarg,&next,0); + if (*next == ',') + optarg = next+1; + else + break; + } + buf[0] = wtot; + break; + case 'v': + i2cVerbose = 1; + break; + default: + return(CMD_FAILURE); + } + } + + if (argc < (optind+1)) + return(CMD_PARAM_ERROR); + + if (strcmp(argv[optind],"read") == 0) { + if (argc != (optind+3)) + return(CMD_PARAM_ERROR); + addr = strtol(argv[optind+1],0,0); + len = strtol(argv[optind+2],0,0); + if (len > sizeof(buf)) + len = sizeof(buf); + if (burst) { + addr |= rwctrl; + rslt = i2cRead(interface,addr,buf,len); + } + else { + for(i=0;i<len;i++) { + rslt = i2cRead(interface,addr,buf+i,1); + if (rslt < 0) + break; + } + } + if (rslt < 0) { + printf("i2cRead = %d\n",rslt); + ret = CMD_FAILURE; + } + else + printMem(buf,len,1); + } + else if (strcmp(argv[optind],"write") == 0) { + if (rwctrl == REPEATED_START) { + printf("-w applies to read only\n"); + return(CMD_FAILURE); + } + if (argc < (optind+3)) + return(CMD_PARAM_ERROR); + addr = strtol(argv[optind+1],0,0); + for(len=0,i=optind+2;i<argc;i++,len++) + buf[len] = (uchar)strtol(argv[i],0,0); + + if (burst) { + rslt = i2cWrite(interface,addr,buf,len); + } + else { + for(i=0;i<len;i++) { + rslt = i2cWrite(interface,addr,buf+i,1); + if (rslt < 0) + break; + } + } + if (rslt < 0) { + printf("i2cWrite = %d\n",rslt); + ret = CMD_FAILURE; + } + } + else if (strcmp(argv[optind],"init") == 0) { + i2cCtrl(interface,I2CCTRL_INIT,0,0); + } + else if (strcmp(argv[optind],"show") == 0) { + i2cCtrl(interface,I2CCTRL_SHOW,0,0); + } + else + return(CMD_PARAM_ERROR); + + i2cVerbose = 0; + return(ret); +} diff --git a/main/common/i2c.h b/main/common/i2c.h new file mode 100644 index 0000000..e5f0f17 --- /dev/null +++ b/main/common/i2c.h @@ -0,0 +1,127 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * i2c.h: + * + * Header for I-Squared-C code. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _I2C_H_ +#define _I2C_H_ + +extern int i2cVerbose; + +/******************************************************************** + * + * Commands used by i2cCtrl(): + */ +#define I2CCTRL_INIT 1 +#define I2CCTRL_SHOW 2 +#define I2CCTRL_START 3 /* Send START condition */ +#define I2CCTRL_STOP 4 /* Send STOP condition */ +#define I2CCTRL_WADD 5 /* Send Write address */ +#define I2CCTRL_RADD 6 /* Send Read address */ +#define I2CCTRL_RDAT 7 /* Read data */ +#define I2CCTRL_WDAT 8 /* Write data */ +#define I2CCTRL_SACK 9 /* Send ACK */ +#define I2CCTRL_WACK 10 /* WaitFor ACK */ + +/******************************************************************** + * + * Upper bits of the bigaddr integer used for special case read/write + */ +#define REPEATED_START 0x40000000 +#define OMIT_STOP 0x20000000 + +/******************************************************************** + * + * Functions that must be provided from some target-specific code. + */ + + +/* i2cCtrl() + * Parameters: + * int interface- + * This parameter supports the case where the target hardware has more + * than one i2c controller. The interface number would correspond to + * one of potentially several different controllers. + * int cmd- + * Command to be carried out by the control function. + * ulong arg1- + * First command-specific argument. + * ulong arg2- + * Second command-specific argument. + */ +extern int i2cCtrl(int interface,int cmd,unsigned long arg1,unsigned long arg2); + +/* i2cRead() + * Parameters: + * int interface- + * See description under i2cCtrl. + * int bigaddr- + * The device address on the I2C bus. Referred to here as "big" because + * it is an "int" so it supports 10-bit addresses (if needed). + * uchar *data- + * Pointer to the data buffer into which the data is to be placed. + * int len- + * Number of bytes to be read from the I2C device. This must not be + * larger than the size of the data buffer. + * Return: + * int + * The function should return the number of bytes read. If everything + * went well, then the return value should equal the len parameter. + * Negative represents some failure. + */ +extern int i2cRead(int interface,int bigaddr,unsigned char *data,int len); + +/* i2cWrite() + * Parameters: + * int interface- + * See description under i2cCtrl. + * int bigaddr- + * See description under i2cRead. + * uchar *data- + * Buffer from which the data is to be taken and put into the specified + * I2C device. + * int len- + * Number of bytes to be written. + * Return: + * int + * The function should return the number of bytes written. If everything + * went well, then the return value should equal the len parameter. + * Negative represents some failure. + */ +extern int i2cWrite(int interface,int bigaddr,unsigned char *data,int len); + +/* i2cShow() + * Parameters: + * int interface- + * See description under i2cCtrl. + * Return: + * void + * The function should be part of target-specific code that simply + * prints out a list of the device names and their address on the + * I-Squared-C bus of the specfied interface. + */ +extern void i2cShow(int interface); + +#endif diff --git a/main/common/icmp.c b/main/common/icmp.c new file mode 100644 index 0000000..51b2c5a --- /dev/null +++ b/main/common/icmp.c @@ -0,0 +1,646 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * icmp.c: + * + * Support some basic ICMP stuff. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" + +#if INCLUDE_ETHERNET +#include "endian.h" +#include "genlib.h" +#include "ether.h" +#include "stddefs.h" +#include "cli.h" +#include "timer.h" + +#if INCLUDE_ICMP + +/* To reduce uMon footprint size, INCLUDE_ICMPTIME can be set to 0 in + * config.h if necessary... + */ +#ifndef INCLUDE_ICMPTIME +#define INCLUDE_ICMPTIME 1 +#endif + +#define MSECS_PER_HOUR 3600000 +#define MSECS_PER_MINUTE 60000 +#define MSECS_PER_SECOND 1000 + +#define ICMP_TIME_ID 0x1111 /* made these up. */ +#define ICMP_ECHO_ID 0x2222 +#define ICMP_ECHO_DATASIZE 26 + +#if INCLUDE_ICMPTIME +static ulong ICMPTimeStamp; +#endif + +static int CheckSrvrResolution; +ushort ICMPEchoReplyId, ICMPSeqNoRcvd; +int SendICMPRequest(uchar,uchar *,uchar *,ulong,ushort); + +int SendEchoResp(struct ether_header *); + +/* Destination unreachable codes: (3rd Edition Comer pg 129) */ +char *IcmpDestUnreachableCode[] = { + "Network unreachable", + "Host unreachable", + "Protocol unreachable", + "Port unreachable", + "Fragmentation needed and DF set", + "Source route failed", + "???", +}; + +char *IcmpHelp[] = { + "ICMP interface", + "-[c:d:f:rs:t:v:] {operation} [args]", +#if INCLUDE_VERBOSEHELP + "Options...", + " -c {#} echo count", + " -s {#} size of icmp-echo packet", + " -t {#} timeout (msec) to wait for response (default=2000)", + " -v {var} load result in shellvar 'var'", +#if INCLUDE_ICMPTIME + " -d {#} delta (hours) relative to GMT", + " -f {x|d} hex or decimal output (default is ascii)", + " -r check server resolution", + "Operations...", + " time {IP}", + " echo {IP}", + "Notes...", + " If '.ns' is appended to time, then time is non-standard.", + " The 'dfr' options are used by time, options 'cs' are used by echo.", +#endif +#endif + 0, +}; + +int +Icmp(int argc,char *argv[]) +{ + ushort seqno; + long size; + struct elapsed_tmr tmr; + int opt, count, timeout; + uchar binip[8], binenet[8]; + char *varname, *operation, *ipadd; +#if INCLUDE_ICMPTIME + uchar buf[32]; + char *nonstandard = "", format='a'; + int timestamp, hour, min, sec, gmt_delta=0; +#endif + + size = 0; + count = 1; + timeout = 2000; + varname = (char *)0; + CheckSrvrResolution = 0; + + while ((opt=getopt(argc,argv,"c:d:f:rs:t:v:")) != -1) { + switch(opt) { + case 'c': /* count used by ping */ + count = strtol(optarg,(char **)0,0); + break; +#if INCLUDE_ICMPTIME + case 'd': /* difference between this time zone and Greenwich */ + gmt_delta = strtol(optarg,(char **)0,0); + break; + case 'f': + format = *optarg; + break; + case 'r': + CheckSrvrResolution = 1; + break; +#endif + case 's': + size = strtol(optarg,(char **)0,0); + break; + case 't': + timeout = strtol(optarg,(char **)0,0); + break; + case 'v': + varname = optarg; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc == optind) + return(CMD_PARAM_ERROR); + + operation = argv[optind]; + ipadd = argv[optind+1]; + + /* If time or echo, do the common up-front stuff here... */ + if (!strcmp(operation,"time") || !strcmp(operation,"echo")) { + if (argc != optind + 2) + return(CMD_PARAM_ERROR); + + /* Convert IP address to binary: */ + if (IpToBin(ipadd,binip) < 0) + return(CMD_SUCCESS); + } + +#if INCLUDE_ICMPTIME + if (!strcmp(operation, "time")) { + + /* Get the ethernet address for the IP: */ + if (!ArpEther(binip,binenet,0)) { + printf("ARP failed for %s\n",ipadd); + return(CMD_FAILURE); + } + + ICMPTimeStamp = INVALID_TIMESTAMP; + SendICMPRequest(ICMP_TIMEREQUEST,binip,binenet,0,0); + + /* Limit the amount of time waiting for a response... */ + startElapsedTimer(&tmr,timeout); + while(msecElapsed(&tmr)) { + pollethernet(); + if (ICMPTimeStamp != INVALID_TIMESTAMP) + break; + } + if (ELAPSED_TIMEOUT(&tmr)) { + printf("No response\n"); + return(CMD_FAILURE); + } + + if (ICMPTimeStamp & NONSTANDARD_TIMESTAMP) { + ICMPTimeStamp &= ~NONSTANDARD_TIMESTAMP; + nonstandard = ".ns"; + } + + if (format == 'a') { + timestamp = ICMPTimeStamp + (gmt_delta*MSECS_PER_HOUR); + hour = timestamp/MSECS_PER_HOUR; + timestamp -= hour*MSECS_PER_HOUR; + min = timestamp/MSECS_PER_MINUTE; + timestamp -= min*MSECS_PER_MINUTE; + sec = timestamp/MSECS_PER_SECOND; + timestamp -= sec*MSECS_PER_SECOND; + sprintf((char *)buf,"%02d:%02d:%02d.%03d%s",hour,min,sec,timestamp, + nonstandard); + } + else if (format == 'x') + sprintf((char *)buf,"0x%lx%s",ICMPTimeStamp,nonstandard); + else if (format == 'd') + sprintf((char *)buf,"%ld%s",ICMPTimeStamp,nonstandard); + else + return(CMD_PARAM_ERROR); + if (varname) + setenv(varname,(char *)buf); + else if (!CheckSrvrResolution) + printf("%s\n",buf); + CheckSrvrResolution = 0; + } + else +#endif + if (!strcmp(operation, "echo")) { + seqno = 0; + while (count-- > 0) { + + /* Is this a self-ping? */ + if (memcmp((char *)binip,(char *)BinIpAddr,4) == 0) { + printf("Yes, I am alive!\n"); + break; + } + /* Get the ethernet address for the IP: */ + if (!ArpEther(binip,binenet,0)) { + printf("ARP failed for %s\n",ipadd); + if (varname) + setenv(varname,"NOANSWER"); + continue; + } + + ICMPEchoReplyId = 0; + SendICMPRequest(ICMP_ECHOREQUEST,binip,binenet,size,seqno); + + /* Limit the amount of time waiting for a response... */ + startElapsedTimer(&tmr,timeout); + while(!msecElapsed(&tmr)) { + pollethernet(); + if (ICMPEchoReplyId == ICMP_ECHO_ID) + break; + } + + if (ELAPSED_TIMEOUT(&tmr)) { + printf("no answer from %s\n",ipadd); + if (varname) + setenv(varname,"NOANSWER"); + } + else { + printf("%s is alive",ipadd); + if (count) { + printf(" icmp_seq=%d",ICMPSeqNoRcvd); + startElapsedTimer(&tmr,timeout); + while(!msecElapsed(&tmr)) + pollethernet(); + seqno++; + } + if (varname) + setenv(varname,"ALIVE"); + printf("\n"); + } + } + } + else + printf("Unrecognized ICMP op: %s\n",operation); + return(CMD_SUCCESS); +} + +int +processICMP(struct ether_header *ehdr,ushort size) +{ + struct ip *ipp; + struct icmp_hdr *icmpp; + int i; + + ipp = (struct ip *)(ehdr + 1); + + icmpp = (struct icmp_hdr *)((char *)ipp+IP_HLEN(ipp)); + if (icmpp->type == ICMP_ECHOREQUEST) { /* 3rdEd Comer pg 127 */ +#if INCLUDE_RARPIPASSIGN + /* If we're here and our IP address is 0.0.0.0, then the + * incoming packet's destination MAC address must have matched + * ours, so we assume (kinda dangerous) that we should assign + * this IP address to ourself... + * This capability allows a board to come up with a MAC address + * assigned, and IP set to 0.0.0.0, then the host can do + * arp -a IPADD MAC + * ping IPADD + * to assing IPADD to this board. + */ + if (DHCPState == DHCPSTATE_NOTUSED) { + if ((BinIpAddr[0] == 0) && (BinIpAddr[1] == 0) && + (BinIpAddr[2] == 0) && (BinIpAddr[3] == 0)) { + memcpy((char *)BinIpAddr,(char *)&(ipp->ip_dst),4); + printf("RARP IP Assignment: %d.%d.%d.%d\n", + BinIpAddr[0], BinIpAddr[1], + BinIpAddr[2], BinIpAddr[3]); + shell_sprintf("IPADD","%d.%d.%d.%d", + BinIpAddr[0], BinIpAddr[1], + BinIpAddr[2], BinIpAddr[3]); + } + } +#endif + SendEchoResp(ehdr); + return(0); + } + else if (icmpp->type == ICMP_ECHOREPLY) { + struct icmp_echo_hdr *icmpecho; + + icmpecho = (struct icmp_echo_hdr *)icmpp; + ICMPEchoReplyId = ecs(icmpecho->id); + ICMPSeqNoRcvd = ecs(icmpecho->seq); + } + else if (icmpp->type == ICMP_DESTUNREACHABLE) { /* 3rdEd Comer pg 129 */ +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_INCOMING) { + i = icmpp->code; + if ((i > 5) || (i < 0)) + i = 6; + printf(" ICMP: %s (code=%d)\n", + IcmpDestUnreachableCode[i],icmpp->code); + } +#endif + return(0); + } +#if INCLUDE_ICMPTIME + else if (icmpp->type == ICMP_TIMEREPLY) { + struct icmp_time_hdr *icmptime; + ulong orig, recv, xmit; + + icmptime = (struct icmp_time_hdr *)icmpp; + memcpy((char *)&orig,(char *)&icmptime->orig,4); + memcpy((char *)&recv,(char *)&icmptime->recv,4); + memcpy((char *)&xmit,(char *)&icmptime->xmit,4); + + ICMPSeqNoRcvd = icmptime->seq; +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_INCOMING) { + printf(" ICMP_TIMEREPLY: orig=0x%lx,recv=0x%lx,xmit=0x%lx\n", + orig,recv,xmit); + } +#endif + if (CheckSrvrResolution) { + static int ICMPTimeStampTbl[20]; + + if (icmptime->seq < 20) { + ICMPTimeStampTbl[icmptime->seq] = xmit; + SendICMPRequest(ICMP_TIMEREQUEST,(uchar *)&ipp->ip_src, + (uchar *)&ehdr->ether_shost,0,icmptime->seq+1); + } else { + + printf("TS00: %d\n",ICMPTimeStampTbl[0]); + for(i=1;i<20;i++) { + printf("TS%02d: %d (dlta=%d)\n",i, + ICMPTimeStampTbl[i], + ICMPTimeStampTbl[i]-ICMPTimeStampTbl[i-1]); + } + ICMPTimeStamp = xmit; + } + } + else { + ICMPTimeStamp = xmit; + } + } +#endif + else { +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_INCOMING) { + printf(" ICMPTYPE=%d\n",icmpp->type); + } +#endif + return(-1); + } + return(0); +} + +/* SendEchoResp(): + * Called in response to an ICMP ECHO REQUEST. Typically used as + * a response to a PING. + */ +int +SendEchoResp(struct ether_header *re) +{ + int i, icmp_len, datalen, oddlen; + ulong t; + ushort *sp, ip_len; + struct ether_header *te; + struct ip *ti, *ri; + struct icmp_echo_hdr *ticmp, *ricmp; + + ri = (struct ip *) (re + 1); + datalen = ecs(ri->ip_len) - ((ri->ip_vhl & 0x0f) * 4); + + te = EtherCopy(re); + ti = (struct ip *) (te + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ti->ip_len = ri->ip_len; + ti->ip_id = ipId(); + ti->ip_off = 0; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_ICMP; + memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr), + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), + sizeof(struct in_addr)); + + ticmp = (struct icmp_echo_hdr *) (ti + 1); + ricmp = (struct icmp_echo_hdr *) (ri + 1); + ticmp->type = ICMP_ECHOREPLY; + ticmp->code = 0; + ticmp->cksum = 0; + ticmp->id = ricmp->id; + ticmp->seq = ricmp->seq; + memcpy((char *)(ticmp+1),(char *)(ricmp+1),datalen-8); + + ip_len = ecs(ti->ip_len); + if (ip_len & 1) { /* If size is odd, temporarily bump up ip_len by */ + oddlen = 1; /* one and add append a null byte for csum. */ + ((char *)ti)[ip_len] = 0; + ip_len++; + } + else + oddlen = 0; + icmp_len = (ip_len - sizeof(struct ip))/2; + + ipChksum(ti); /* compute checksum of ip hdr: (3rd Edition Comer pg 100) */ + + /* compute checksum of icmp message: (3rd Edition Comer pg 126) */ + ticmp->cksum = 0; + sp = (ushort *) ticmp; + for (i=0,t=0;i<icmp_len;i++,sp++) + t += ecs(*sp); + t = (t & 0xffff) + (t >> 16); + ticmp->cksum = ~t; + + self_ecs(ticmp->cksum); + + if (oddlen) + ip_len--; + + sendBuffer(sizeof(struct ether_header) + ip_len); +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_OUTGOING) + printf(" Sent Echo Response\n"); +#endif + return(0); +} + +/* SendICMPRequest(): + * Currently supports ICMP_TIMEREQUEST and ICMP_ECHOREQUEST. + */ +int +SendICMPRequest(uchar type,uchar *binip,uchar *binenet, + ulong tmpval,ushort seq) +{ + ushort *sp; + uchar *data; + struct ip *ti; + int i, icmp_len; + struct ether_header *te; + struct icmp_time_hdr *ticmp; + ulong origtime, datasize, csum; + + datasize = ICMP_ECHO_DATASIZE; + + /* Retrieve an ethernet buffer from the driver and populate the */ + /* ethernet level of packet: */ + te = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&te->ether_shost,(char *)BinEnetAddr,6); + memcpy((char *)&te->ether_dhost,(char *)binenet,6); + te->ether_type = ecs(ETHERTYPE_IP); + + /* Move to the IP portion of the packet and populate it appropriately: */ + ti = (struct ip *) (te + 1); + ti->ip_vhl = IP_HDR_VER_LEN; + ti->ip_tos = 0; +#if INCLUDE_ICMPTIME + if (type == ICMP_TIMEREQUEST) { + origtime = tmpval; + ti->ip_len = sizeof(struct ip) + sizeof(struct icmp_time_hdr); + } + else +#endif + { + if (tmpval != 0) + datasize = tmpval; + ti->ip_len = sizeof(struct ip) + sizeof(struct icmp_echo_hdr) + + datasize; + } + + ti->ip_id = ipId(); + ti->ip_off = 0; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_ICMP; + memcpy((char *)&ti->ip_src.s_addr,(char *)BinIpAddr,4); + memcpy((char *)&ti->ip_dst.s_addr,(char *)binip,4); + + icmp_len = (ti->ip_len - sizeof(struct ip))/2; + self_ecs(ti->ip_len); + self_ecs(ti->ip_off); + self_ecs(ti->ip_id); + + ipChksum(ti); /* Compute csum of ip hdr */ + + /* Move to the ICMP portion of the packet and populate it appropriately: */ + ticmp = (struct icmp_time_hdr *)(ti+1); + ticmp->type = type; + ticmp->code = 0; + ticmp->seq = ecs(seq); +#if INCLUDE_ICMPTIME + if (type == ICMP_TIMEREQUEST) { + ticmp->id = ICMP_TIME_ID; + memcpy((char *)&ticmp->orig,(char *)&origtime,4); + memset((char *)&ticmp->recv,0,4); + memset((char *)&ticmp->xmit,0,4); + } else +#endif + { + ticmp->id = ICMP_ECHO_ID; + + /* Add 'datasize' bytes of data... */ + data = (uchar *)((struct icmp_echo_hdr *)ticmp+1); + for(i=0;i<datasize;i++) + data[i] = 'a'+i; + + } + + /* compute checksum of icmp message: (3rd Edition Comer pg 126) */ + csum = 0; + ticmp->cksum = 0; + sp = (ushort *) ticmp; + for (i=0;i<icmp_len;i++,sp++) + csum += ecs(*sp); + csum = (csum & 0xffff) + (csum >> 16); + ticmp->cksum = ~csum; + + self_ecs(ticmp->cksum); + +#if INCLUDE_ICMPTIME + if (type == ICMP_TIMEREQUEST) { + self_ecl(ticmp->orig); + self_ecl(ticmp->recv); + self_ecl(ticmp->xmit); + sendBuffer(ICMP_TIMERQSTSIZE); + } + else +#endif + sendBuffer(ICMP_ECHORQSTSIZE+datasize); + return(0); +} + +/* Send an ICMP Unreachable message. All ICMP Unreachable messages + * include the IP header and 64 bits of the datagram that could not be + * delivered. + * + * 're' is the pointer to the packet that was received in response to which + * the unreachable message is being sent. 'icmp_code' is the code of the + * ICMP message. + */ +int +SendICMPUnreachable(struct ether_header *re,uchar icmp_code) +{ + int i, len; + ushort *sp, r_iphdr_len, ip_len; + ulong t; + struct ether_header *te; + struct ip *ti, *ri; + struct icmp_unreachable_hdr *ticmp; + + /* If DONTSEND_ICMP_UNREACHABLE is set, then don't send out the + * message... + */ + if (getenv("DONTSEND_ICMP_UNREACHABLE")) + return(0); + + ri = (struct ip *) (re + 1); + + /* Length of the received IP hdr */ + r_iphdr_len = ((ri->ip_vhl & 0x0f)<<2); + + te = EtherCopy(re); + + ti = (struct ip *) (te + 1); + ti->ip_vhl = IP_HDR_VER_LEN; + ti->ip_tos = 0; + /* Length of the outgoing IP packet = IP header + ICMP header + + * IP header and 8 bytes of unreachable datagram + */ + ip_len = (IP_HDR_LEN<<2)+sizeof(struct icmp_unreachable_hdr)+r_iphdr_len+8; + ti->ip_len = ecs(ip_len); + ti->ip_id = ipId(); + ti->ip_off = 0; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_ICMP; + + /* Note that we do memcpy instead of struct copy because the ip + * header is not not word-aligned. As a result, the source and dest + * addresses are not word aligned either. The compiler generates word + * copy instructions for struct copy and this causes address alignement + * exceptions. + */ + memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr), + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), + sizeof(struct in_addr)); + + ticmp = (struct icmp_unreachable_hdr *) (ti + 1); + ticmp->type = ICMP_DESTUNREACHABLE; + ticmp->code = icmp_code; + ticmp->cksum = 0; + ticmp->unused1=0; + ticmp->unused2=0; + + /* Copy the IP header and 8 bytes of the received datagram */ + memcpy((char *)(ticmp+1),(char *)ri,r_iphdr_len+8); + + ipChksum(ti); /* compute checksum of ip hdr */ + + /* compute checksum of icmp message: (see Comer pg 91) */ + len = (ip_len - sizeof(struct ip))/2; + ticmp->cksum = 0; + sp = (ushort *) ticmp; + for (i=0,t=0;i<len;i++,sp++) + t += ecs(*sp); + t = (t & 0xffff) + (t >> 16); + ticmp->cksum = ~t; + self_ecs(ticmp->cksum); + + sendBuffer(sizeof(struct ether_header) + ip_len); + +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_OUTGOING) + printf(" Sent ICMP Dest Unreachable message. Code='%s'.\n", + IcmpDestUnreachableCode[icmp_code]); +#endif + return(0); +} + +#endif /* INCLUDE_ICMP */ +#endif /* INCLUDE_ETHERNET */ diff --git a/main/common/if.c b/main/common/if.c new file mode 100755 index 0000000..8e8c01b --- /dev/null +++ b/main/common/if.c @@ -0,0 +1,812 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * if.c: + * + * This file started off as the file for the "if" command in the monitor, + * and has since grown into the file that contains the commands that only + * make sense if they are used in scripts; hence, a prerequisite to these + * commands is that TFS is included in the build. + * It also contains the script runner portion of TFS. The name of this + * file should have been changed to tfsscript.c! + * + * if: + * Supports the monitor's ability to do conditional branching within + * scripts executed through TFS. + * + * goto: + * Tag based jumping in a script. + * + * item: + * A simple way to process a list (similar to KSH's 'for' construct). + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "genlib.h" +#include "stddefs.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "ether.h" +#include "cli.h" +#include <ctype.h> + +#if INCLUDE_TFSSCRIPT + +/* Subroutine variables: + * The definition of MAXGOSUBDEPTH (15) determines the maximum number + * of subroutines that can be nested within any one script invocation. + * ReturnToTellTbl[] + * Used by script runner to keep track of the location in the file that + * the subroutine is supposed to return to. + * ReturnToDepth + * The current subroutine nesting depth of the script runner. + */ +#define MAXGOSUBDEPTH 15 +static int ReturnToDepth; +static long ReturnToTellTbl[MAXGOSUBDEPTH+1]; +static int CurrentScriptfdTbl[TFS_MAXOPEN+1]; + +/* ScriptIsRunning: + * Non-zero if a script is active, else zero. + */ +static int ScriptIsRunning; + +/* ScriptGotoTag: + * Points to the string that is the most recent target of + * a goto or gosub command. + */ +static char *ScriptGotoTag; + +/* ScriptExitFlag: + * If non-zero, then the script must exit. + * The 'exit' command sets this flag based on options provided to exit. + */ +int ScriptExitFlag; + +/* ExecuteAfterNext: + * If the ScriptExitFlag has the EXECUTE_AFTER_EXIT flag set, then the content + * of this array is assumed to be the file that is to be executed + * automatically after the exit of the current script. + */ +char ExecuteAfterExit[TFSNAMESIZE+1]; + +/*****************************************************************************/ + +/* If: + * A simple test/action statement. + * Currently, the only action supported is "goto tag". + * Syntax: + * if ARG1 compar ARG2 {action} [else action] + * if -t TEST {action} [else action] + */ +char *IfHelp[] = { + "Conditional branching", + "-[t:v] [{arg1} {compar} {arg2}] {action} [else action]", +#if INCLUDE_VERBOSEHELP + " Options:", + " -t{test} see below", + " -v verbose mode (print TRUE or FALSE result)", + " Notes:", + " * Numerical/logical/string compare:", + " seq sec sne sin gt lt le ge eq ne and or xor", + " * Action:", + " goto tag | gosub tag | exit | return", + " * Other tests (-t args):", + " gc, ngc, iscmp {filename}", +#endif + 0, +}; + +int +If(int argc, char *argv[]) +{ + int opt, arg, true, if_else, offset, verbose; + void (*iffunc)(char *), (*elsefunc)(char *); + long var1, var2; + char *testtype, *arg1, *arg2, *iftag, *elsetag; + + verbose = 0; + testtype = 0; + while((opt=getopt(argc,argv,"vt:")) != -1) { + switch(opt) { + case 'v': + verbose = 1; + break; + case 't': + testtype = optarg; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + elsetag = 0; + elsefunc = 0; + offset = true = if_else = 0; + + /* First see if there is an 'else' present... */ + for (arg=optind;arg<argc;arg++) { + if (!strcmp(argv[arg],"else")) { + if_else = 1; + break; + } + } + + if (if_else) { + elsetag = argv[argc-1]; + if (!strcmp(argv[argc-1],"exit")) { + offset = 2; + elsefunc = exitscript; + } + else if (!strcmp(argv[argc-1],"return")) { + offset = 2; + elsefunc = gosubret; + } + else if (!strcmp(argv[argc-2],"goto")) { + offset = 3; + elsefunc = gototag; + } + else if (!strcmp(argv[argc-2],"gosub")) { + offset = 3; + elsefunc = gosubtag; + } + else + return(CMD_PARAM_ERROR); + } + + iftag = argv[argc-offset-1]; + if (!strcmp(argv[argc-offset-1],"exit")) + iffunc = exitscript; + else if (!strcmp(argv[argc-offset-1],"return")) + iffunc = gosubret; + else if (!strcmp(argv[argc-offset-2],"goto")) + iffunc = gototag; + else if (!strcmp(argv[argc-offset-2],"gosub")) + iffunc = gosubtag; + else + return(CMD_PARAM_ERROR); + + if (testtype) { + if (!strcmp(testtype,"gc")) { + if (gotachar()) + true=1; + } + else if (!strcmp(testtype,"ngc")) { + if (!gotachar()) + true=1; + } + else + return(CMD_PARAM_ERROR); + } + else { + arg1 = argv[optind]; + testtype = argv[optind+1]; + arg2 = argv[optind+2]; + + var1 = strtoul(arg1,(char **)0,0); + var2 = strtoul(arg2,(char **)0,0); + + if (!strcmp(testtype,"gt")) { + if (var1 > var2) + true = 1; + } + else if (!strcmp(testtype,"lt")) { + if (var1 < var2) + true = 1; + } + else if (!strcmp(testtype,"le")) { + if (var1 <= var2) + true = 1; + } + else if (!strcmp(testtype,"ge")) { + if (var1 >= var2) + true = 1; + } + else if (!strcmp(testtype,"eq")) { + if (var1 == var2) + true = 1; + } + else if (!strcmp(testtype,"ne")) { + if (var1 != var2) + true = 1; + } + else if (!strcmp(testtype,"and")) { + if (var1 & var2) + true = 1; + } + else if (!strcmp(testtype,"xor")) { + if (var1 ^ var2) + true = 1; + } + else if (!strcmp(testtype,"or")) { + if (var1 | var2) + true = 1; + } + else if (!strcmp(testtype,"sec")) { + if (!strcasecmp(arg1,arg2)) + true = 1; + } + else if (!strcmp(testtype,"seq")) { + if (!strcmp(arg1,arg2)) + true = 1; + } + else if (!strcmp(testtype,"sin")) { + if (strstr(arg2,arg1)) + true = 1; + } + else if (!strcmp(testtype,"sne")) { + if (strcmp(arg1,arg2)) + true = 1; + } + else + return(CMD_PARAM_ERROR); + } + + /* If the true flag is set, call the 'if' function. + * If the true flag is clear, and "else" was found on the command + * line, then call the 'else' function... + */ + if (true) { + if (verbose) + printf("TRUE\n"); + iffunc(iftag); + } + else { + if (verbose) + printf("FALSE\n"); + if (if_else) + elsefunc(elsetag); + } + + return(CMD_SUCCESS); +} + +int +InAScript(void) +{ + if (ScriptIsRunning) + return(1); + else { + printf("Invalid from outside a script\n"); + return(0); + } +} + +void +exitscript(char *ignored) +{ + if (InAScript()) { + ScriptExitFlag = EXIT_SCRIPT; + } +} + + +char *ExitHelp[] = { + "Exit currently running script", + "-[ae:r]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -a exit all scripts (if nested)", + " -e {exe} automatically execute 'exe' after exit", + " -r remove script after exit", +#endif + 0, +}; + +int +Exit(int argc, char *argv[]) +{ + int opt; + ScriptExitFlag = EXIT_SCRIPT; + + while((opt=getopt(argc,argv,"ae:r")) != -1) { + switch(opt) { + case 'a': + ScriptExitFlag |= EXIT_ALL_SCRIPTS; + break; + case 'e': + if (strlen(optarg) >= sizeof(ExecuteAfterExit)) + return(CMD_PARAM_ERROR); + ScriptExitFlag |= EXECUTE_AFTER_EXIT; + strcpy(ExecuteAfterExit,optarg); + break; + case 'r': + ScriptExitFlag |= REMOVE_SCRIPT; + break; + } + } + return(CMD_SUCCESS); +} + +char *GotoHelp[] = { + "Branch to file tag", + "{tagname}", + 0, +}; + +int +Goto(int argc, char *argv[]) +{ + if (argc != 2) + return(CMD_PARAM_ERROR); + gototag(argv[1]); + return(CMD_SUCCESS); +} + + +char *GosubHelp[] = { + "Call a subroutine", + "{tagname}", + 0, +}; + +int +Gosub(int argc, char *argv[]) +{ + if (argc != 2) + return(CMD_PARAM_ERROR); + gosubtag(argv[1]); + return(CMD_SUCCESS); +} + +char *ReturnHelp[] = { + "Return from subroutine", + "", + 0, +}; + +int +Return(int argc, char *argv[]) +{ + if (argc != 1) + return(CMD_PARAM_ERROR); + gosubret(0); + return(CMD_SUCCESS); +} + +/* Item: + * This is a simple replacement for the KSH "for" construct... + * It allows the user to build a list of strings and retrieve one at a time. + * Basically, the items can be thought of as a table. The value of idx + * (starting with 1) is used to index into the list of items and place + * that item in the shell variable "var". + * Syntax: + * item {idx} {var} {item1} {item2} {item3} .... + */ +char *ItemHelp[] = { + "Extract an item from a list", + "{idx} {stor_var} [item1] [item2] ...", +#if INCLUDE_VERBOSEHELP + "Note: idx=1 retrieves item1", +#endif + 0, +}; + +int +Item(int argc, char *argv[]) +{ + int idx; + char *varname; + + if (argc < 3) + return(CMD_PARAM_ERROR); + + idx = atoi(argv[1]); + varname = argv[2]; + + if ((idx < 1) || (idx > (argc-3))) { + setenv(varname,0); + return(CMD_SUCCESS); + } + + idx += 2; + setenv(varname,argv[idx]); + return(CMD_SUCCESS); +} + +/* Read(): + * Simple interactive shell variable entry. + * Syntax: + * read [options] [var1] [var2] [...] + * Options: + * -twww timeout after 'www' milliseconds (approximate) of + * waiting for input. + * + */ + +char *ReadHelp[] = { + "Interactive shellvar entry", +#if INCLUDE_VERBOSEHELP + "-[fnp:t:T:] [var1] [var2] ... ", + " -f flush console input", + " -n no echo during read", + " -p *** prefill string", + " -t ### msec timeout per char", + " -T ### msec timeout cumulative", + "Notes:", + " This command waits for console input terminated by ENTER.", + " Input tokens are whitespace delimited.", + "Examples:", + " * read name # wait forever", + " If user responds with ENTER, shell var 'name' is cleared;", + " else it is loaded with the first input token.", + " * read -t2000 name # timeout after 2 seconds", + " If timeout, shell var 'name' is untouched; else if timeout", + " doesn't occur, but user only types ENTER 'var' is cleared;", + " else 'var' will contain token.", +#endif + 0, +}; + +int +Read(int argc,char *argv[]) +{ + int i, reached_eol, opt, waitfor, noecho; + char *prefill, buf[64], *space, *bp; + + prefill = 0; + waitfor = noecho = 0; + while((opt=getopt(argc,argv,"fnp:t:T:")) != -1) { + switch(opt) { + case 'f': + flush_console_in(); + return(CMD_SUCCESS); + case 'n': + noecho = 1; + break; + case 'p': + prefill = optarg; + break; + case 't': + waitfor = strtol(optarg,(char **)0,0); + break; + case 'T': + waitfor = strtol(optarg,(char **)0,0); + waitfor = -waitfor; + break; + default: + return(CMD_PARAM_ERROR); + } + } + +#if INCLUDE_MONCMD + /* Since this command blocks waiting for user input on the console, + * check to see if we are running under the context of MONCMD, and, + * if yes, return CMD_FAILURE to avoid a lockup... + */ + if (IPMonCmdActive) { + printf("Invalid under moncmd context.\n"); + return(CMD_FAILURE); + } +#endif + + /* If -t, then restart the timeout for each character. + * If -T, then the timeout accumulates over all characters. + * If a timeout does occur, then do nothing to the shell variables + * that may be specified as arguments. This allows the script + * writer to distinguish between a timeout, and an empty line... + * Timeout has no affect, empty line will NULL out the variable. + */ + if (getfullline(buf,sizeof(buf)-1,0,waitfor,prefill,noecho?0:1) == -1) + return(CMD_SUCCESS); + + /* If there were no args after the option, then there is no need to + * consider populating a shell variable, so just return here. + */ + if (argc == optind) { + return(CMD_SUCCESS); + } + + bp = buf; + reached_eol = 0; + for(i=optind;i<argc;i++) { + space=strpbrk(bp," \t"); + if (space) { + *space = 0; + setenv(argv[i],bp); + bp = space+1; + } + else { + if ((reached_eol) || (*bp == 0)) { + setenv(argv[i],0); + } + else { + setenv(argv[i],bp); + reached_eol = 1; + } + } + } + return(CMD_SUCCESS); +} + +int +currentScriptfd(void) +{ + return(CurrentScriptfdTbl[ScriptIsRunning]); +} + +/* gototag(): + * Used with tfsscript to allow a command to adjust the pointer into the + * script that is currently being executed. It simply populates the + * "ScriptGotoTag" pointer with the tag that should be branched to next. + */ +void +gototag(char *tag) +{ + if (InAScript()) { + if (ScriptGotoTag) + free(ScriptGotoTag); + ScriptGotoTag = malloc(strlen(tag)+8); + sprintf(ScriptGotoTag,"# %s",tag); + } +} + +/* gosubtag(): + * Similar in basic use to gototag(), except that we keep a copy of the + * current position in the active script file so that it can be returned + * to later. + */ +void +gosubtag(char *tag) +{ + if (InAScript()) { + if (ReturnToDepth >= MAXGOSUBDEPTH) { + printf("Max return-to depth reached\n"); + return; + } + ReturnToTellTbl[ReturnToDepth++] = tfstell(currentScriptfd()); + gototag(tag); + } +} + +void +gosubret(char *ignored) +{ + int offset, err; + + if (InAScript()) { + err = 0; + + if (ReturnToDepth <= 0) { + printf("Nothing to return to\n"); + err = 1; + } + else { + ReturnToDepth--; + offset = tfsseek(currentScriptfd(), + ReturnToTellTbl[ReturnToDepth],TFS_BEGIN); + if (offset <= 0) { + err = 1; + printf("return error: %s\n",tfserrmsg(offset)); + } + } + if (err) + printf("Possible gosub/return imbalance.\n"); + } +} + +/* tfsscript(): + * Treat the file as a list of commands that should be executed + * as monitor commands. Step through each line and execute it. + * The tfsDocommand() function pointer is used so that the application + * can assign a different command interpreter to the script capbilities + * of the monitor. To really take advantage of this, the command interpreter + * that is reassigned, should allow monitor commands to run if the command + * does not exist in the application's command list. + * + * Scripts can call other scripts that call other scripts (etc...) and + * that works fine because tfsscript() will just use more stack space but + * it eventually returns through the same function call tree. A script can + * also call a COFF, ELF or AOUT file and expect it to return as long as + * the executable returns through the same point into which it was started + * (the entrypoint). If the executable uses mon_appexit() to terminate, + * then the calling script will not regain control. + */ + +int +tfsscript(TFILE *fp,int verbose) +{ + char lcpy[CMDLINESIZE], *sv; + int tfd, lnsize, lno, verbosity, ignoreerror, cmdstat; + + tfd = tfsopen(fp->name,TFS_RDONLY,0); + if (tfd < 0) + return(tfd); + + lno = 0; + + /* If ScriptIsRunning is zero, then we know that this is the top-level + * script, so we can initialize state here... + */ + if (ScriptIsRunning == 0) + ReturnToDepth = 0; + + CurrentScriptfdTbl[++ScriptIsRunning] = tfd; + + while(1) { + lno++; + lnsize = tfsgetline(tfd,lcpy,CMDLINESIZE); + if (lnsize == 0) /* end of file? */ + break; + if (lnsize < 0) { + printf("tfsscript(): %s\n",tfserrmsg(lnsize)); + break; + } + if ((lcpy[0] == '\r') || (lcpy[0] == '\n')) /* empty line? */ + continue; + + lcpy[lnsize-1] = 0; /* Remove the newline */ + + /* Just in case the goto tag was set outside a script, */ + /* clear it now. */ + if (ScriptGotoTag) { + free(ScriptGotoTag); + ScriptGotoTag = (char *)0; + } + + ScriptExitFlag = 0; + + /* Execute the command line. + * If the shell variable "SCRIPTVERBOSE" is set, then enable + * verbosity for this command; else use what was passed in + * the parameter list of the function. Note that the variable + * is tested for each command so that verbosity can be enabled + * or disabled within a script. + * If the command returns a status that indicates that there was + * some parameter error, then exit the script. + */ + sv = getenv("SCRIPTVERBOSE"); + if (sv) + verbosity = atoi(sv); + else + verbosity = verbose; + + if ((lcpy[0] == '-') || (getenv("SCRIPT_IGNORE_ERROR"))) + ignoreerror = 1; + else + ignoreerror = 0; + + if (verbosity) + printf("[%02d]: %s\n",lno,lcpy); + + cmdstat = tfsDocommand(lcpy[0] == '-' ? lcpy+1 : lcpy, 0); + + if (cmdstat != CMD_SUCCESS) { + setenv("CMDSTAT","FAIL"); + if (ignoreerror == 0) { + printf("Terminating script '%s' at line %d\n", + TFS_NAME(fp),lno); + ScriptExitFlag = EXIT_SCRIPT; + break; + } + } + else { + setenv("CMDSTAT","PASS"); + } + + /* Check for exit flag. If set, then in addition to terminating the + * script, clear the return depth here so that the "missing return" + * warning is not printed. This is done because there is likely + * to be a subroutine with an exit in it and this should not + * cause a warning. + */ + if (ScriptExitFlag) { + ReturnToDepth = 0; + break; + } + + /* If ScriptGotoTag is set, then attempt to reposition the line + * pointer to the line that contains the tag. + */ + if (ScriptGotoTag) { + int tlen; + + tlen = strlen(ScriptGotoTag); + lno = 0; + tfsseek(tfd,0,TFS_BEGIN); + while(1) { + lnsize = tfsgetline(tfd,lcpy,CMDLINESIZE); + if (lnsize == 0) { + printf("Tag '%s' not found\n",ScriptGotoTag+2); + free(ScriptGotoTag); + ScriptGotoTag = (char *)0; + tfsclose(tfd,0); + return(TFS_OKAY); + } + lno++; + if (!strncmp(lcpy,ScriptGotoTag,tlen) && + (isspace(lcpy[tlen]) || (lcpy[tlen] == ':'))) { + free(ScriptGotoTag); + ScriptGotoTag = (char *)0; + break; + } + } + } + /* After each line, poll ethernet interface. */ + pollethernet(); + } + tfsclose(tfd,0); + if (ScriptExitFlag & REMOVE_SCRIPT) + tfsunlink(fp->name); + if (ScriptIsRunning > 0) { + ScriptIsRunning--; + if ((ScriptIsRunning == 0) && (ReturnToDepth != 0)) { + printf("Error: script is done, but return-to-depth != 0\n"); + printf("(possible gosub/return imbalance)\n"); + } + } + else { + printf("Script run-depth error\n"); + } + + /* If the EXECUTE_AFTER_EXIT flag is set (by exit -e), then automatically + * start up the file specified in ExecuteAfterExit[]... + */ + if (ScriptExitFlag & EXECUTE_AFTER_EXIT) { + char *argv[2]; + + argv[0] = ExecuteAfterExit; + argv[1] = 0; + ScriptExitFlag = 0; + tfsrun(argv,0); + } + + /* Upon completion of a script, clear the ScriptExitFlag variable so + * that it is not accidentally applied to another script that may have + * called this script. + */ + if ((ScriptExitFlag & EXIT_ALL_SCRIPTS) != EXIT_ALL_SCRIPTS) + ScriptExitFlag = 0; + return(TFS_OKAY); +} + +/* tfsscriptname(): + * Return the currently running script name; else return an empty string. + */ +char * +tfsscriptname(void) +{ + struct tfsdat *slot; + + if (ScriptIsRunning) { + slot = &tfsSlots[CurrentScriptfdTbl[ScriptIsRunning]]; + if (slot->offset != (ulong)-1) + return(slot->hdr.name); + } + return(""); +} + +#else /* INCLUDE_TFSSCRIPT */ + +int +tfsscript(TFILE *fp,int verbose) +{ + return(TFSERR_NOTAVAILABLE); +} + +char * +tfsscriptname(void) +{ + return(0); +} + +#endif diff --git a/main/common/igmp.c b/main/common/igmp.c new file mode 100644 index 0000000..213d1cb --- /dev/null +++ b/main/common/igmp.c @@ -0,0 +1,200 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * igmp.c: + * + * Support some basic IGMP stuff. + * I wrote this code as an exercise for getting to know basic IGMP. + * This code doesn't do much. It will successfully send a JOIN or LEAVE + * but the monitor is not prepared to deal with multicast, so it doesn't + * add any real functionality except for the ability to observe IGMP. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_IGMP +#include "endian.h" +#include "genlib.h" +#include "ether.h" +#include "stddefs.h" +#include "cli.h" + +int SendIGMP(int type,uchar *groupip); + +char *IgmpHelp[] = { + "IGMP interface", +#if INCLUDE_VERBOSEHELP + "{operation} [args]", + "Operations...", + " join {IP}", + " leave {IP}", +#endif + 0, +}; + +int +Igmp(int argc,char *argv[]) +{ + int opt, verbose = 0; + uchar binip[8]; + char *operation, *ipadd; + + while ((opt=getopt(argc,argv,"v")) != -1) { + switch(opt) { + case 'v': + verbose = 1; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc != optind + 2) + return(CMD_PARAM_ERROR); + + operation = argv[optind]; + ipadd = argv[optind+1]; + + /* Convert IP address to binary: */ + if (IpToBin(ipadd,binip) < 0) + return(CMD_SUCCESS); + + /* If time or echo, do the common up-front stuff here... */ + if (!strcmp(operation,"join")) { + SendIGMP(IGMPTYPE_JOIN,binip); + } + else if (!strcmp(operation,"leave")) { + SendIGMP(IGMPTYPE_LEAVE,binip); + } + else { + printf("Unrecognized IGMP op: %s\n",operation); + return(CMD_FAILURE); + } + return(CMD_SUCCESS); +} + +int +SendIGMP(int type,uchar *groupip) +{ + int i; + ushort *sp; + struct ip *ti; + struct Igmphdr *tigmp; + struct ether_header *te; + ulong csum, *router_alert_opt; + + /* Retrieve an ethernet buffer from the driver and populate the */ + /* ethernet level of packet: */ + te = (struct ether_header *) getXmitBuffer(); + + /* Source MAC is this target's MAC address... + */ + memcpy((char *)&te->ether_shost,(char *)BinEnetAddr,6); + /* Destination MAC is multicast, so it is derived from the + * group IP address... + * The upper 24 bits are 0x01005e. + * For JOIN, the lower 24 bits are masked with the groupIP and 0x7fffff. + * For LEAVE, the message is sent to the All_Routers_Multicast_Group + * (224.0.0.2), so the lower three bytes are 0,0,2. + */ + te->ether_dhost.ether_addr_octet[0] = 0x01; + te->ether_dhost.ether_addr_octet[1] = 0x00; + te->ether_dhost.ether_addr_octet[2] = 0x5e; + + if (type == IGMPTYPE_LEAVE) { + te->ether_dhost.ether_addr_octet[3] = 0x00; + te->ether_dhost.ether_addr_octet[4] = 0x00; + te->ether_dhost.ether_addr_octet[5] = 0x02; + } + else { + te->ether_dhost.ether_addr_octet[3] = groupip[1] & 0x7f; + te->ether_dhost.ether_addr_octet[4] = groupip[2]; + te->ether_dhost.ether_addr_octet[5] = groupip[3]; + } + te->ether_type = ecs(ETHERTYPE_IP); + + /* Move to the IP portion of the packet and populate it appropriately: */ + ti = (struct ip *) (te + 1); + ti->ip_vhl = ((IP_VER<<4) | ((sizeof(struct ip)+sizeof(ulong)) >> 2)); + ti->ip_tos = 0; + ti->ip_len = sizeof(struct ip) + sizeof(ulong) + sizeof(struct Igmphdr); + ti->ip_id = ipId(); + ti->ip_off = 0; + ti->ip_ttl = 1; + ti->ip_p = IP_IGMP; + memcpy((char *)&ti->ip_src.s_addr,(char *)BinIpAddr,4); + if (type == IGMPTYPE_LEAVE) + ti->ip_dst.s_addr = ALL_MULTICAST_ROUTERS; + else + memcpy((char *)&ti->ip_dst.s_addr,(char *)groupip,4); + + self_ecs(ti->ip_len); + self_ecs(ti->ip_off); + self_ecs(ti->ip_id); + + router_alert_opt = (ulong *)(ti+1); + *router_alert_opt = 0x94040000; /* see RFC2113 */ + + ipChksum(ti); /* Compute csum of ip hdr */ + + /* Move to the IGMP portion of the packet and populate it appropriately: */ + tigmp = (struct Igmphdr *)(router_alert_opt+1); + tigmp->type = type; + tigmp->mrt = 0; + tigmp->csum = 0; + memcpy((char *)&tigmp->group,(char *)groupip,4); + + /* Calculate checksum of IGMP portion of the header. + * This uses the same method as is used with ipChksum()... + */ + sp = (ushort *)tigmp; + csum = 0; + for (i=0;i<4;i++,sp++) { + csum += *sp; + if (csum & 0x80000000) + csum = (csum & 0xffff) + (csum >> 16); + } + while(csum >> 16) + csum = (csum & 0xffff) + (csum >> 16); + tigmp->csum = ~csum; + + sendBuffer(IGMP_JOINRQSTSIZE); + return(0); +} + +int +MacIsMulticast(uchar *mac) +{ + if (*mac != 0x01) + return(0); + mac++; + if (*mac != 0x00) + return(0); + mac++; + if (*mac != 0x5e) + return(0); + mac++; + if (*mac & 0x80) + return(0); + return(1); +} + +#endif diff --git a/main/common/inc_check.h b/main/common/inc_check.h new file mode 100644 index 0000000..a17a62a --- /dev/null +++ b/main/common/inc_check.h @@ -0,0 +1,412 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * inc_check.h: + * + * DESCRIPTION HERE + * + * + * This is an include file used to verify that all of the monitor macros + * are defined. There is also some attempt to verify that macro conflicts + * do not exist (for example, the flash file system cannot exist if the + * flash driver is not included); however, there are probably holes in this + * check. + * + * Following is a brief description of what each macro includes if set to + * non-zero... + * + * INCLUDE_MEMCMDS: + * Memory display, modification and test commands. The included as a + * result of setting this macro is primarily found in memcmds.c. + * INCLUDE_EDIT: + * An ascii file editor. This is an on-board file editor that provides + * the system with the ability to edit files in TFS. Refer to edit.c + * for details of this functionality. This obviously assumes that TFS + * and the FLASH drivers are also enabled. + * INCLUDE_DISASSEMBLER: + * This pulls in a disassembler. + * INCLUDE_UNPACK: + * INCLUDE_UNZIP: + * These two macros define one of two different mechanisms for + * decompression of executables in TFS. UNPACK is huffman and UNZIP + * is the public domain zlib stuff. Huffman is a small addition to the + * monitor size but only provides about 15% compression. The zlib stuff + * is a bit larger and needs more RAM for malloc() but it does a MUCH + * better job of compression. I've seen as high as 75% of the file size + * compressed. It is illegal to set both of these macros. + * INCLUDE_ETHERNET: + * This pulls in the basic ethernet drivers with ARP, and some of the + * lowest level ethernet interface code. + * INCLUDE_TFTP: + * This pulls in a TFTP client and server (obviously assumes ETHERNET + * is also pulled in). + * INCLUDE_DHCPBOOT: + * This pulls in a DHCP/BOOTP client (also assumes ETHERNET + * is also pulled in). + * INCLUDE_TFS: + * INCLUDE_TFSAPI: + * INCLUDE_TFSAUTODEFRAG: + * INCLUDE_TFSSYMTBL: + * INCLUDE_TFSSCRIPT: + * INCLUDE_TFSCLI: + * The above TFS macros allow the monitor to be built with varying degrees + * of FFS capability depending on the needs of the system. INCLUDE_TFS + * is required by all others and is the minimum TFS hookup. It provides + * the minimum set of TFS facilities such as autoboot, use of a monrc file + * for startup config, and defragmentation. TFSAPI pulls in the TFS + * code that allows an application to hook into TFS's capabilities in + * code-space. TFSCLI pulls in the TFS command at the command line + * interface. TFSSAFEDEFRAG pulls in the power-safe defragmenation + * (otherwise a simpler, less robust mechanism is used). + * TFSSYMTBL pulls in the symbol-table functionality and TFSSCRIPT + * pulls in the CLI commands that are normally associated with scripts. + * INCLUDE_XMODEM: + * Pull in Xmodem. + * INCLUDE_LINEEDIT: + * Pull in a command line editor and history facility. + * INCLUDE_EE: + * Pull in an expression evaluator for the CLI. + * Note that this is not included with the public distribution. + * INCLUDE_FLASH: + * Pull in the flash drivers. + * INCLUDE_CRYPT: + * Pull in UNIX crypt() instead of a simpler encryption scheme I wrote. + * Note that this is not included with the public distribution. + * INCLUDE_GDB: + * Pull in the "gdb" command. This is an incomplete facility that + * will eventually allow the monitor to hook up to a gdb debugger. + * INCLUDE_STRACE: + * Pull in the "strack trace" command. + * INCLUDE_CAST: + * Pull in the "cast" command for complex structure display at the + * CLI. + * INCLUDE_REDIRECT: + * This pulls in the code that allows the monitor's CLI to redirect + * command output to a TFS file. + * INCLUDE_QUICKMEMCPY: + * This pulls in some faster memcpy stuff in genlib.c. + * INCLUDE_PROFILER: + * This pulls in some code and a CLI command that provides an + * application with some task and function level profiling. + * INCLUDE_BBC: + * This pulls in some code and a CLI command that provides an + * application with a basic ability to organize basic block coverage + * verification. + * INCLUDE_MEMTRACE: + * This pulls in a simple memory trace capability. It's a simple + * printf()-like function with data logged to RAM instead of a UART. + * INCLUDE_STOREMAC: + * This pulls in a function that forces the user to establish the MAC + * in the etheradd space allocated in reset.s. It needs INCLUDE_FLASH + * because flash writes are done. If not enabled the MAC address can + * still be stored in etheradd using the "ether mac" command. + * INCLUDE_SHELLVARS: + * This pulls in the monitor's ability to deal with shell variables. + * This includes the "set" command on the CLI, plus a lot of other + * subsections of the monitor depend on shell variables. + * This facility should only be disabled when there is a desperate + * need to shink the monitor's footprint. + * INCLUDE_MALLOC: + * This pulls in the monitor's malloc. This includes the "heap" + * command on the CLI, plus a few other factilies in the monitor + * assume malloc is included; so without it, they won't work either. + * This facility should only be disabled when there is a desperate + * need to shink the monitor's footprint. + * INCLUDE_HWTMR: + * If set, then the target port must supply a function called + * target_timer() which returns a 32-bit value representing a + * a hardware-resident clock whose rate is defined by the value + * specified by TIMER_TICKS_PER_MSEC. + * INCLUDE_VERBOSEHELP: + * If set, then full help text is built in; else only the usage + * and abstract is included. + * INCLUDE_PORTCMD: + * If set, then the mon_portcmd(int cmd, void *arg) API can be + * used to build port-specific API extensions. + * INCLUDE_USRLVL: + * If set, then the code that incorporates user levels is included + * in the build. + * INCLUDE_STRUCT: + * If set, then the struct command is included in the build. This + * requires that TFS be included also. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _INC_CHECK_H +#define _INC_CHECK_H + +/*********************************************************************** + * Verify that the basic set of INCLUDE macros have been defined: + */ + +#ifndef INCLUDE_ICMP +#error "INCLUDE_ICMP must be defined in config.h." +#endif + +#ifndef INCLUDE_USRLVL +#error "INCLUDE_USRLVL must be defined in config.h." +#endif + +#ifndef INCLUDE_PORTCMD +#error "INCLUDE_PORTCMD must be defined in config.h." +#endif + +#ifndef INCLUDE_HWTMR +#error "INCLUDE_HWTMR must be defined in config.h." +#endif + +#ifndef INCLUDE_VERBOSEHELP +#error "INCLUDE_VERBOSEHELP must be defined in config.h." +#endif + +#ifndef INCLUDE_MEMTRACE +#error "INCLUDE_MEMTRACE must be defined in config.h." +#endif + +#ifdef INCLUDE_TFSSAFEDEFRAG +#error "INCLUDE_TFSSAFEDEFRAG no longer needed." +#endif + +#ifndef INCLUDE_MEMCMDS +#error "INCLUDE_MEMCMDS must be defined in config.h" +#endif + +#ifndef INCLUDE_EDIT +#error "INCLUDE_EDIT must be defined in config.h" +#endif + +#ifndef INCLUDE_DISASSEMBLER +#error "INCLUDE_DISASSEMBLER must be defined in config.h" +#endif + +#ifndef INCLUDE_UNZIP +#error "INCLUDE_UNZIP must be defined in config.h" +#endif + +#ifndef INCLUDE_ETHERNET +#error "INCLUDE_ETHERNET must be defined in config.h" +#endif + +#ifndef INCLUDE_TFTP +#error "INCLUDE_TFTP must be defined in config.h" +#endif + +#ifndef INCLUDE_DHCPBOOT +#error "INCLUDE_DHCPBOOT must be defined in config.h" +#endif + +#ifndef INCLUDE_TFS +#error "INCLUDE_TFS must be defined in config.h" +#endif + +#ifndef INCLUDE_TFSCLI +#error "INCLUDE_TFSCLI must be defined in config.h" +#endif + +#ifndef INCLUDE_TFSAPI +#error "INCLUDE_TFSAPI must be defined in config.h" +#endif + +#ifndef INCLUDE_TFSSCRIPT +#error "INCLUDE_TFSSCRIPT must be defined in config.h" +#endif + +#ifndef INCLUDE_TFSSYMTBL +#error "INCLUDE_TFSSYMTBL must be defined in config.h" +#endif + +#ifndef INCLUDE_XMODEM +#error "INCLUDE_XMODEM must be defined in config.h" +#endif + +#ifndef INCLUDE_LINEEDIT +#error "INCLUDE_LINEEDIT must be defined in config.h" +#endif + +#ifndef INCLUDE_EE +#error "INCLUDE_EE must be defined in config.h" +#endif + +#ifndef INCLUDE_FLASH +#error "INCLUDE_FLASH must be defined in config.h" +#endif + +#ifndef INCLUDE_STRACE +#error "INCLUDE_STRACE must be defined in config.h" +#endif + +#ifndef INCLUDE_CAST +#error "INCLUDE_CAST must be defined in config.h" +#endif + +#ifdef INCLUDE_SHELLVAR +#error "INCLUDE_SHELLVAR definition no longer needed in config.h" +#endif + +//#ifdef INCLUDE_MALLOC +//#error "INCLUDE_MALLOC definition no longer needed in config.h" +//#endif + +#ifndef INCLUDE_REDIRECT +#error "INCLUDE_REDIRECT must be defined in config.h" +#endif + +#ifndef INCLUDE_QUICKMEMCPY +#error "INCLUDE_QUICKMEMCPY must be defined in config.h" +#endif + +#ifndef INCLUDE_PROFILER +#error "INCLUDE_PROFILER must be defined in config.h" +#endif + +#ifndef INCLUDE_BBC +#error "INCLUDE_BBC must be defined in config.h" +#endif + +#ifndef INCLUDE_STOREMAC +#error "INCLUDE_STOREMAC must be defined in config.h" +#endif + +#ifndef INCLUDE_MALLOC +#error "INCLUDE_MALLOC must be defined in config.h" +#endif + +#ifndef INCLUDE_SHELLVARS +#error "INCLUDE_SHELLVARS must be defined in config.h" +#endif + +#ifndef INCLUDE_STRUCT +#error "INCLUDE_STRUCT must be defined in config.h" +#endif + + +/*********************************************************************** + * The storemac facility needs flash to be enabled. + */ +#if INCLUDE_STOREMAC +#if !INCLUDE_FLASH +#error "Can't include STOREMAC without FLASH" +#endif +#endif + +/*********************************************************************** + * The hardware timer facility needs to know the tick rate. + */ +#if INCLUDE_HWTMR +#ifndef TIMER_TICKS_PER_MSEC +#error "Can't set INCLUDE_HWTMR without TIMER_TICKS_PER_MSEC." +#endif +#endif + +/*********************************************************************** + * Certain pieces of the monitor cannot be enabled without basic TFS: + */ +#if !INCLUDE_TFS +#if INCLUDE_REDIRECT +#error "Can't include REDIRECT without TFS" +#endif +#if INCLUDE_PROFILER +#error "Can't include PROFILER without TFS" +#endif +#if INCLUDE_USRLVL +#error "Can't include USRLVL without TFS" +#endif +#if INCLUDE_STRUCT +#error "Can't include STRUCT without TFS" +#endif +#endif + +/*********************************************************************** + * Certain pieces of the monitor cannot be enabled without TFS API: + */ + +#if !INCLUDE_TFSAPI + +#if INCLUDE_EDIT +#error "Can't include EDIT without TFSAPI" +#endif +#if INCLUDE_STRACE +#error "Can't include STRACE without TFSAPI" +#endif +#if INCLUDE_TFSSYMTBL +#error "Can't include TFSSYMTBL without TFSAPI" +#endif + +#endif + +/*********************************************************************** + * Certain pieces of the monitor cannot be enabled without ETHERNET: + */ +#if !INCLUDE_ETHERNET + +#if INCLUDE_TFTP +#error "Can't include TFTP without ETHERNET" +#endif +#if INCLUDE_DHCPBOOT +#error "Can't include DHCPBOOT without ETHERNET" +#endif +#if INCLUDE_SYSLOG +#error "Can't include SYSLOG without ETHERNET" +#endif +#if INCLUDE_ICMP +#error "Can't include ICMP without ETHERNET" +#endif + +#endif + +/*********************************************************************** + * Just history... + */ +#define DONT_INCLUDE_OLDSTYLE_FLAGCHECK + +/*********************************************************************** + * Check for things removed as of 1.0... + */ +#ifdef INCLUDE_UNPACK +#error "INCLUDE_UNPACK is unused as of uMon 1.0" +#endif +#ifdef INCLUDE_DEBUG +#error "INCLUDE_DEBUG is unused as of uMon 1.0" +#endif +#ifdef INCLUDE_PIO +#error "INCLUDE_PIO is unused as of uMon 1.0" +#endif +#ifdef INCLUDE_EXCTEST +#error "INCLUDE_EXCTEST is unused as of uMon 1.0" +#endif +#ifdef INCLUDE_IDEV +#error "INCLUDE_IDEV is unused as of uMon 1.0" +#endif +#ifdef INCLUDE_CRYPT +#error "INCLUDE_CRYPT is unused as of uMon 1.0" +#endif +#ifdef INCLUDE_TFSAUTODEFRAG +#error "INCLUDE_TFSAUTODEFRAG is unused as of uMon 1.0" +#endif +#ifdef FLASH_LOCK_SUPPORTED +#error "FLASH_LOCK_SUPPORT is unused as of uMon 1.0" +#endif +#ifdef INCLUDE_ARGV +#error "INCLUDE_ARGV is unused as of uMon 1.0" +#endif + + +#endif diff --git a/main/common/jffs2.c b/main/common/jffs2.c new file mode 100644 index 0000000..50f0422 --- /dev/null +++ b/main/common/jffs2.c @@ -0,0 +1,2336 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * jffs2.c + * + * Reads JFFS2-formatted NOR flash. + * + * Initial version written by Ed Sutter, with contributions later made + * by Bill Gatliff (bgat@billgatliff.com). + * + */ + +#include "config.h" + +#if INCLUDE_JFFS2 + +#include "stddefs.h" +#include "assert.h" +#include "genlib.h" +#include "cli.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "time.h" +#include "flash.h" + +#if INCLUDE_JFFS2ZLIB +#include "jz_zlib.h" +#endif + +#ifndef NULL +#define NULL ((void*)0) +#endif + + +/* override JFFS2_DEFAULT_BASE in target's config.h when necessary! */ +#ifndef JFFS2_DEFAULT_BASE +#define JFFS2_DEFAULT_BASE 0 +#endif + +#define JFFS2_MAXPATH 256 + +#define JFFS2_MODE_MASK 00170000 +#define JFFS2_MODE_REG 0100000 +#define JFFS2_MODE_LNK 0120000 +#define JFFS2_MODE_BLK 0060000 +#define JFFS2_MODE_DIR 0040000 +#define JFFS2_MODE_CHR 0020000 +#define JFFS2_MODE_FIFO 0010000 + +#define DT_REG (JFFS2_MODE_REG >> 12) +#define DT_LNK (JFFS2_MODE_LNK >> 12) +#define DT_BLK (JFFS2_MODE_BLK >> 12) +#define DT_DIR (JFFS2_MODE_DIR >> 12) +#define DT_CHR (JFFS2_MODE_CHR >> 12) +#define DT_FIFO (JFFS2_MODE_FIFO >> 12) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) +#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) +#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) + +#define is_reg(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_REG) +#define is_lnk(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_LNK) +#define is_blk(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_BLK) +#define is_dir(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_DIR) +#define is_chr(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_CHR) +#define is_fifo(mode) (((mode) & JFFS2_MODE_MASK) == JFFS2_MODE_FIFO) + +#define JFFS2_MAGIC 0x1985 + +#define JFFS2_COMPAT_MASK 0xc000 +#define JFFS2_FEATURE_INCOMPAT 0xc000 +#define JFFS2_FEATURE_ROCOMPAT 0x8000 +#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000 +#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000 + +#define JFFS2_NODE_ACCURATE 0x2000 + +#define JFFS2_NODETYPE_MASK 7 +#define JFFS2_NODETYPE_DIRENT 1 +#define JFFS2_NODETYPE_INODE 2 +#define JFFS2_NODETYPE_CLEANMARKER 3 +#define JFFS2_NODETYPE_PADDING 4 + +/* this is a "fake" type, not part of jffs2 proper */ +#define JFFS2_NODETYPE_CLEANREGION 8 + +#define JFFS2_OBSOLETE_FLAG 1 +#define JFFS2_UNUSED_FLAG 2 + +#define JFFS2_COMPR_NONE 0 /* no compression */ +#define JFFS2_COMPR_ZERO 1 /* data is all zeroes */ +#define JFFS2_COMPR_RTIME 2 +#define JFFS2_COMPR_RUBINMIPS 3 +#define JFFS2_COMPR_COPY 4 +#define JFFS2_COMPR_DYNRUBIN 5 +#define JFFS2_COMPR_ZLIB 6 + +#define JFFS2_FNAME_STR "JFFS2FNAME" +#define JFFS2_FTOT_STR "JFFS2FTOT" +#define JFFS2_FSIZE_STR "JFFS2FSIZE" + +/* TODO: find a better way to deal with char vs. jint8 */ +typedef unsigned char jint8; +typedef unsigned short jint16; +typedef unsigned int jint32; + +struct jffs2_unknown_node { + jint16 magic; + jint16 nodetype; + jint32 totlen; + jint32 hdr_crc; +}; + +struct jffs2_raw_dirent { + jint16 magic; + jint16 nodetype; + jint32 totlen; + jint32 hdr_crc; + jint32 pino; + jint32 version; + jint32 ino; + jint32 mctime; + jint8 nsize; + jint8 type; + jint8 unused[2]; + jint32 node_crc; + jint32 name_crc; + jint8 name[0]; +}; + +struct jffs2_raw_inode { + jint16 magic; + jint16 nodetype; + jint32 totlen; + jint32 hdr_crc; + jint32 ino; + jint32 version; + jint32 mode; + jint16 uid; + jint16 gid; + jint32 isize; + jint32 atime; + jint32 mtime; + jint32 ctime; + jint32 offset; + jint32 csize; + jint32 dsize; + jint8 compr; + jint8 usercompr; + jint16 flags; + jint32 data_crc; + jint32 node_crc; + jint8 data[0]; +}; + +struct jffs2_cleanregion_node { + jint16 magic; + jint16 nodetype; + jint32 totlen; + jint32 physaddr; +}; + +struct jffs2_umoninfo { + jint8 quiet; + jint32 direntsize; + char direntname[JFFS2_MAXPATH+1]; +}; + +/* + * The crc32 function used in this jffs2 command is from MTD utils. + * + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + */ + +static const jint32 jffs2_crc32_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +static jint32 +jffs2crc32(jint32 val, const void *ss, int len) +{ + const unsigned char *s = ss; + + while (--len >= 0) + val = jffs2_crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); + + return val; +} + +static char * +compr2str(jint8 compr) +{ + switch(compr) { + case JFFS2_COMPR_NONE: + return "none"; + case JFFS2_COMPR_ZERO: + return "zero"; + case JFFS2_COMPR_RTIME: + return "rtime"; + case JFFS2_COMPR_RUBINMIPS: + return "rubinmips"; + case JFFS2_COMPR_COPY: + return "copy"; + case JFFS2_COMPR_DYNRUBIN: + return "dynrubin"; + case JFFS2_COMPR_ZLIB: + return "zlib"; + default: + return "???"; + } +} + +static void +showUnknown(int nodenum, struct jffs2_unknown_node *u) +{ + printf("Node %3d (%04x=UNKNOWN, size=%ld) 0x%08lx...\n", + nodenum, u->nodetype, u->totlen, (long)u); + printf(" type: 0x%04x\n",u->nodetype); +} + +static void +showPadding(int nodenum, struct jffs2_raw_inode *i) +{ + printf("Node %3d (PADDING, size=%ld) @ 0x%08lx...\n", + nodenum, i->totlen, (long)i); +} + +static void +showCleanmarker(int nodenum,struct jffs2_raw_inode *i) +{ + printf("Node %3d (CLEANMARKER, size=%ld) @ 0x%08lx...\n", + nodenum,i->totlen, (long)i); +} + +static void +showInode(int nodenum,struct jffs2_raw_inode *i) +{ + printf("Node %3d (%04x=INODE, size=%ld) @ 0x%08lx", + nodenum, i->nodetype, i->totlen, (long)i); + if (i->dsize) + printf(" (data at 0x%08lx)",&i->data); + printf("...\n"); + printf(" ino: 0x%06lx, mode: 0x%06lx, version: 0x%06lx\n", + i->ino,i->mode,i->version); + printf(" isize: 0x%06lx, csize: 0x%06lx, dsize: 0x%06lx\n", + i->isize, i->csize, i->dsize); + printf(" offset: 0x%06lx, compr: %8s, ucompr: %s\n", + i->offset,compr2str(i->compr),compr2str(i->usercompr)); +} + +static void +showDirent(int nodenum, struct jffs2_raw_dirent *d) +{ + jint8 i; + + printf("Node %3d (%04x=DIRENT <\"",nodenum,d->nodetype); + for(i=0;i<d->nsize;i++) + putchar(d->name[i]); + printf("\">, size=%ld)",d->totlen); + printf(" @ 0x%06lx",(long)d); + if (d->ino == 0) + printf(" (deleted)"); + if ((d->nodetype & JFFS2_NODE_ACCURATE) == 0) + printf(" (obsolete)"); + printf("...\n"); + printf(" ino: 0x%06lx, pino: 0x%06lx, version: 0x%06lx\n", + d->ino, d->pino, d->version); + printf(" nsize: 0x%06lx, type: 0x%06lx\n", + d->nsize, d->type); +} + +static void +showCleanregion(int nodenum, struct jffs2_cleanregion_node *c) +{ + printf("Node %3d (%04x=CLEANREGION)...\n", + nodenum, c->nodetype); + printf(" physaddr: 0x%06lx, size: %d\n", + c->physaddr, c->totlen); +} + + +/* jzlibcpy(): + * A variation on "memcpy", but using JFFS2's zlib decompression... + */ +static int +jzlibcpy(char *src, char *dest, ulong srclen, ulong destlen) +{ +#if INCLUDE_JFFS2ZLIB + z_stream strm; + int ret; + + if ((strm.workspace = malloc(zlib_inflate_workspacesize())) == 0) + return(-1); + + if (Z_OK != zlib_inflateInit(&strm)) { + free(strm.workspace); + return -1; + } + + strm.next_in = (unsigned char *)src; + strm.avail_in = srclen; + strm.total_in = 0; + + strm.next_out = (unsigned char *)dest; + strm.avail_out = destlen; + strm.total_out = 0; + + while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK); + + zlib_inflateEnd(&strm); + free(strm.workspace); + return(strm.total_out); +#else + printf("INCLUDE_JFFS2ZLIB not set in config.h, can't decompress\n"); + return -1; +#endif +} + + +static int +is_accurate_node(struct jffs2_unknown_node *u) +{ + return ((u->magic == JFFS2_MAGIC) + && (u->nodetype & JFFS2_NODE_ACCURATE)) ? 1 : 0; +} + +static int +is_cleanmarker(struct jffs2_unknown_node *u) +{ + jint16 nodetype = u->nodetype & JFFS2_NODETYPE_MASK; + return nodetype == JFFS2_NODETYPE_CLEANMARKER ? 1 : 0; +} + +static int +is_padding(struct jffs2_unknown_node *u) +{ + jint16 nodetype = u->nodetype & JFFS2_NODETYPE_MASK; + return nodetype == JFFS2_NODETYPE_PADDING ? 1 : 0; +} + +static int +is_inode(struct jffs2_unknown_node *u) +{ + jint16 nodetype = u->nodetype & JFFS2_NODETYPE_MASK; + return nodetype == JFFS2_NODETYPE_INODE ? 1 : 0; +} + +static int +is_dirent(struct jffs2_unknown_node *u) +{ + jint16 nodetype = u->nodetype & JFFS2_NODETYPE_MASK; + return nodetype == JFFS2_NODETYPE_DIRENT ? 1 : 0; +} + +static int +is_deleted_dirent(struct jffs2_unknown_node *u) +{ + struct jffs2_raw_dirent *d; + + if (is_dirent(u)) { + d = (struct jffs2_raw_dirent *)u; + if (d->ino == 0) + return 1; + } + + return 0; +} + +static int +is_cleanregion(struct jffs2_unknown_node *u) +{ + return u->nodetype == JFFS2_NODETYPE_CLEANREGION ? 1 : 0; +} + +static struct jffs2_unknown_node * +allocCleanRegion(jint32 base, jint32 size) +{ + struct jffs2_cleanregion_node *c; + + c = (struct jffs2_cleanregion_node*)malloc(sizeof(*c)); + if (c) { + memset((void*)c, 0, sizeof(*c)); + c->nodetype = JFFS2_NODETYPE_CLEANREGION; + c->physaddr = base; + c->totlen = size; + } + else + printf("%s: malloc() failed\n", __func__); + return (struct jffs2_unknown_node*)c; +} + +static jint32 +calcHdrCrc(struct jffs2_unknown_node *u) +{ + return jffs2crc32(0, (void*)u, + sizeof(*u) - sizeof(u->hdr_crc)); +} + +static jint32 +calcInodeCrc(struct jffs2_raw_inode *i) +{ + return jffs2crc32(0, (void*)i, + sizeof(*i) - sizeof(i->node_crc) + - sizeof(i->data_crc)); +} + +static jint32 +calcDirentCrc(struct jffs2_raw_dirent *d) +{ + return jffs2crc32(0, (void*)d, + sizeof(*d) - sizeof(d->node_crc) + - sizeof(d->name_crc)); +} + +static jint32 +calcDataCrc(void *data, int len) +{ + return jffs2crc32(0, data, len); +} + +static int jffs2_verify_crc = 0; + +static struct jffs2_unknown_node * +findRawNode(ulong jaddr, ulong jlen, + ulong *newjaddr, ulong *newjlen) +{ + struct jffs2_unknown_node *u; + jint32 crc; + ulong size = 0; + long adj; + + while (jlen && !gotachar()) { + + adj = ulceil(jaddr, 4) - jaddr; + jaddr += adj; + jlen -= adj; + + u = (struct jffs2_unknown_node *)jaddr; + + if (is_accurate_node(u)) { + + if (jffs2_verify_crc) { + + crc = calcHdrCrc(u); + if (crc != u->hdr_crc) + printf("hdr_crc @ 0x%x: " + "calculated 0x%x read 0x%x (ignored)\n", + u, crc, u->hdr_crc); + + if (is_dirent(u)) { + struct jffs2_raw_dirent *d; + + d = (struct jffs2_raw_dirent*)u; + crc = calcDirentCrc(d); + if (crc != d->node_crc) + printf("dirent node_crc @ 0x%x: " + "calculated 0x%x read 0x%x (ignored)\n", + d, crc, d->node_crc); + + crc = calcDataCrc(d->name, d->nsize); + if (crc != d->name_crc) + printf("dirent name_crc @ 0x%x: " + "calculated 0x%x read 0x%x (ignored)\n", + d, crc, d->name_crc); + } + + else if (is_inode(u)) { + struct jffs2_raw_inode *i; + + i = (struct jffs2_raw_inode*)u; + crc = calcInodeCrc(i); + if (crc != i->node_crc) + printf("inode node_crc @ 0x%x: " + "calculated 0x%x read 0x%x (ignored)\n", + i, crc, i->node_crc); + + crc = calcDataCrc(i->data, + (i->compr != JFFS2_COMPR_NONE) ? + i->csize : i->dsize); + if (crc != i->data_crc) + printf("inode data_crc @ 0x%x: " + "calculated 0x%x read 0x%x (ignored)\n", + i, crc, i->data_crc); + } + } + + if (newjaddr) *newjaddr = jaddr; + if (newjlen) *newjlen = jlen; + return u; + } + + else { + /* manufacture a node representing unused memory */ + + /* TODO: more-carefully verify that this memory is truly + "unused", e.g. make sure there is a valid cleanmarker at the + beginning of the flash block, we don't span the end of a + flash section, etc. */ + + /* TODO: it would be much faster to use a binary search for ff's + in the current flash sector, rather than a linear search for + them */ + + for (size = 0; jlen && !gotachar() + && *(ulong*)jaddr == 0xffffffffUL; + size += 4) { + jaddr += 4; + jlen -= 4; + } + + if (size > sizeof(struct jffs2_raw_inode)) { + if (newjaddr) *newjaddr = jaddr - size; + if (newjlen) *newjlen = jlen + size; + return allocCleanRegion((ulong)u, size); + } + + if (jlen) { + jaddr += 4; + jlen -= 4; + } + } + } + + return NULL; +} + +struct jffs2_unknown_node_list { + struct jffs2_unknown_node_list *next; + struct jffs2_unknown_node_list *prev; + ulong nodenum; + struct jffs2_unknown_node *u; +}; + +static int +is_empty_list (struct jffs2_unknown_node_list *l) +{ + if ((l == NULL) || (l->next == NULL) + || (l->next->next == NULL)) return 1; + return 0; +} + +static struct jffs2_unknown_node_list * +allocListNode(ulong nodenum, struct jffs2_unknown_node *u) +{ + struct jffs2_unknown_node_list *cu; + + cu = (struct jffs2_unknown_node_list*)malloc(sizeof(*cu)); + if (cu) { + cu->next = NULL; + cu->prev = NULL; + cu->u = u; + cu->nodenum = nodenum; + } + else { + /* TODO: report/handle allocation failure */ + printf("allocListNode: malloc() failed\n"); + } + return cu; +} + +static struct jffs2_unknown_node_list * +removeNodeFromList(struct jffs2_unknown_node_list *u) +{ + if (u->prev != NULL) + u->prev->next = u->next; + if (u->next != NULL) + u->next->prev = u->prev; + return u; +} + +static int +delListNode(struct jffs2_unknown_node_list *u) +{ + removeNodeFromList(u); + if (u->u != NULL && is_cleanregion(u->u)) + free(u->u); + free(u); + return 0; +} + +static struct jffs2_unknown_node_list * +initNodeList(struct jffs2_unknown_node_list **a) +{ + /* create "sentinel" nodes */ + *a = allocListNode(-1, NULL); + if (*a == NULL) return NULL; + (*a)->next = allocListNode(-1, NULL); + if ((*a)->next == NULL) return NULL; + (*a)->next->prev = *a; + + return *a; +} + +static struct jffs2_unknown_node_list * +discardNodeList(struct jffs2_unknown_node_list *list) +{ + if (list == NULL) + return NULL; + while (list->prev != NULL) + list = list->prev; + while (list->next != NULL) + delListNode(list->next); + delListNode(list); + return NULL; +} + + + + +static struct jffs2_unknown_node_list * +insertListNodeAfter(struct jffs2_unknown_node_list *after, + struct jffs2_unknown_node_list *n) +{ + n->prev = after; + n->next = after->next; + after->next->prev = n; + after->next = n; + + return n; +} + +static int +scanMedium(ulong jaddr, ulong jlen, + struct jffs2_unknown_node_list *list, + void (*progress)(int percent)) +{ + struct jffs2_unknown_node *u; + struct jffs2_unknown_node_list *n; + ulong nodetot = 0UL; + ulong jlen_orig = jlen; + + if (progress) { + printf("scanning JFFS2 medium " + "at 0x%x, %d bytes...\n", + jaddr, jlen); + progress(0); + } + + while (!gotachar() + && jlen + && (u = findRawNode(jaddr, jlen, &jaddr, &jlen))) { + + if (progress) + progress(((unsigned long long)(jlen_orig - jlen) * 100) + / jlen_orig); + + if (is_inode(u) + || is_dirent(u) + || is_deleted_dirent(u) + || is_cleanmarker(u) + || is_cleanregion(u)) { + + n = allocListNode(nodetot++, u); + if (n != NULL) + insertListNodeAfter(list, n); + else { + printf("%s: allocListNode returned NULL (fatal)\n", + __func__); + return -1; + } + } + else printf("%s: unrecognized nodetype %x (ignored)\n", + __func__, u->nodetype & JFFS2_NODETYPE_MASK); + + jlen -= u->totlen; + jaddr += u->totlen; + } + + return nodetot; +} + +static int +formatMedium (ulong jaddr, ulong jlen, + void (*progress)(int percent)) +{ + int ret; + int start, end, sect, size; + uchar *addr; + struct jffs2_unknown_node cm = { + .magic = JFFS2_MAGIC, + .nodetype = (JFFS2_NODETYPE_CLEANMARKER + | JFFS2_FEATURE_RWCOMPAT_DELETE + | JFFS2_NODE_ACCURATE), + .totlen = sizeof(struct jffs2_unknown_node), + }; + + if (!jlen) return -1; + + cm.hdr_crc = calcHdrCrc(&cm); + + if (addrtosector((uchar*)jaddr, &start, + NULL, NULL)) { + printf("%s: invalid starting address %x (error, abort)\n", + __func__, jaddr); + return -1; + } + + if (addrtosector((uchar*)(jaddr + jlen - 1), &end, + NULL, NULL)) { + printf("%s: invalid ending address %x (error, abort)\n", + __func__, jaddr + jlen - 1); + return -1; + } + + ret = sectortoaddr(start, NULL, (uchar**)(&addr)); + if (ret || ((ulong)addr != jaddr)) { + printf("%s: must start at a sector boundary (abort)\n", + __func__); + return -1; + } + + ret = sectortoaddr(end, &size, (uchar**)(&addr)); + if (ret || ((ulong)(addr + size) != (jaddr + jlen))) { + printf("%s: must end at a sector boundary (abort)\n", + __func__); + return -1; + } + + printf("formatting JFFS2 medium " + "at 0x%x, %d sectors, %d bytes...\n", + jaddr, end - start, jlen); + + for (sect = start; sect < end; sect++) { + + if (progress) + progress(((sect - start) * 100) / (end - start)); + + if ((ret = AppFlashErase(sect)) != 1) { + printf("%s: error %d from AppFlashErase, " + "sector %d (abort)\n", + __func__, ret, sect); + return -1; + } + + if ((ret = sectortoaddr(sect, &size, (uchar**)(&addr))) != 0) { + printf("%s: error %d from sectortoaddr(%d, NULL, &addr) (abort)\n", + __func__, ret, sect); + return -1; + } + + if (size < sizeof(cm)) { + printf("%s: size of sector %d " + "is smaller than a CLEANMARKER (abort)\n", + __func__, sect); + return -1; + } + + if ((ret = AppFlashWrite(addr, (void*)&cm, cm.totlen)) != 0) { + printf("%s: error %d from AppFlashWrite, sector %d (abort)\n", + __func__, ret, sect); + return -1; + } + } + + return 0; +} + + +static int +showNode(ulong nodenum, struct jffs2_unknown_node *u) +{ + if (is_inode(u)) + showInode(nodenum, (struct jffs2_raw_inode*)u); + else if (is_dirent(u) || is_deleted_dirent(u)) + showDirent(nodenum, (struct jffs2_raw_dirent*)u); + else if (is_cleanmarker(u)) + showCleanmarker(nodenum, (struct jffs2_raw_inode*)u); + else if (is_cleanregion(u)) + showCleanregion(nodenum, (struct jffs2_cleanregion_node*)u); + else if (is_padding(u)) + showPadding(nodenum, (struct jffs2_raw_inode*)u); + else showUnknown(nodenum, u); + return 0; +} + +static struct jffs2_unknown_node_list * +findNodeOfType(struct jffs2_unknown_node_list *list, + jint16 nodetype) +{ + while (list != NULL && !gotachar()) { + if (list->u != NULL + && ((nodetype == JFFS2_NODETYPE_MASK) + || ((list->u->nodetype & JFFS2_NODETYPE_MASK) == nodetype))) + return list; + list = list->next; + } + + return NULL; +} + +static struct jffs2_unknown_node_list * +findCleanRegion(struct jffs2_unknown_node_list *list, + ulong minsize) +{ + while (list != NULL && !gotachar()) { + if (list->u != NULL + && is_cleanregion(list->u)) { + + if (list->u->totlen >= minsize) + return list; + } + list = list->next; + } + + return NULL; +} + +/* + * Finds an inode entry in <list> where u->ino == <ino>. + * + * Returns NULL if no inode of the requested number is found. Otherwise: + * + * <version> == -1: the highest-version entry in the list is returned + * <version> != -1: the specified entry in the list is returned + * + * For ownership and mode information, you want the latest inode + * entry. The only time a specific entry is interesting is when + * replaying the entire inode log to reconstruct its data or other + * history. + */ +static struct jffs2_unknown_node_list * +findInode(struct jffs2_unknown_node_list *list, + jint32 ino, jint32 version) +{ + struct jffs2_raw_inode *i; + struct jffs2_unknown_node_list *ulatest = NULL; + + while (list != NULL && !gotachar() + && (list = findNodeOfType(list, JFFS2_NODETYPE_INODE)) != NULL) { + + i = (struct jffs2_raw_inode*)list->u; + if (i->ino == ino) { + if (version != -1 && version == i->version) + return list; + else if (version == -1) { + if (ulatest == NULL) + ulatest = list; + else if (i->version > ((struct jffs2_raw_inode*)(ulatest->u))->version) + ulatest = list; + } + } + + list = list->next; + } + + if (version == -1 && ulatest != NULL) + return ulatest; + + return NULL; +} + +/* + * Searches <list> for a dirent that matches <pino>, <ino>, and/or + * <name>. Returns a pointer to the first matching dirent node found + * in <list>, including deleted dirent nodes, or NULL if a matching + * dirent cannot be found. + */ +static struct jffs2_unknown_node_list * +findNextMatchingDirent(struct jffs2_unknown_node_list *list, + jint32 pino, jint32 ino, char *name) +{ + struct jffs2_raw_dirent *d; + + while (!gotachar() + && (list = findNodeOfType(list, JFFS2_NODETYPE_DIRENT)) != NULL) { + + d = (struct jffs2_raw_dirent*)list->u; + + if ((pino == -1 || (pino == d->pino)) + && (ino == -1 || (ino == d->ino))) { + + if ((name == NULL) + || ((strlen(name) == d->nsize) + && !memcmp((char*)name, (char*)(d->name), d->nsize))) + return list; + } + + list = list->next; + } + + return NULL; +} + +/* + * Finds the highest-version, non-deleted dirent that matches the + * supplied parameters, or NULL if the highest-version dirent is a + * deleted one + */ +static struct jffs2_unknown_node_list * +findMatchingDirent(struct jffs2_unknown_node_list *list, + jint32 pino, jint32 ino, char *name) +{ + struct jffs2_unknown_node_list *u, *uret; + struct jffs2_raw_dirent *d, *dret; + + for (uret = NULL, u = list; u != NULL + && ((u = findNextMatchingDirent(u, pino, ino, name)) != NULL); + u = u->next) { + + if (uret == NULL) { + uret = u; + continue; + } + + dret = (struct jffs2_raw_dirent*)uret->u; + d = (struct jffs2_raw_dirent*)u->u; + + if (d->version > dret->version) + uret = u; + } + + if (uret == NULL) + return NULL; + + if (is_deleted_dirent(uret->u)) + return NULL; + + return uret; +} + +static struct jffs2_unknown_node_list * +findNodeOfTypeRange(struct jffs2_unknown_node_list *list, + jint16 nodetype, + char *pino, + char *ino) +{ + struct jffs2_raw_dirent *d; + struct jffs2_raw_inode *i; + + while (!gotachar() + && (list = findNodeOfType(list, nodetype)) != NULL) { + + if (is_dirent(list->u)) { + d = (struct jffs2_raw_dirent*)(list->u); + if ((pino == NULL || inRange(pino, d->pino)) + && (ino == NULL || inRange(ino, d->ino))) + return list; + } + + else if (is_inode(list->u)) { + i = (struct jffs2_raw_inode*)(list->u); + if (ino == NULL || inRange(ino, i->ino)) + return list; + } + + list = list->next; + } + + return NULL; +} + +static void +showInodeType(int type) +{ + if (is_reg(type)) printf("-"); + else if (is_dir(type)) printf("d"); + else if (is_lnk(type)) printf("l"); + else if (is_blk(type)) printf("b"); + else if (is_chr(type)) printf("c"); + else if (is_fifo(type)) printf("p"); + else printf("?"); +} + +static void +showInodePerm(int perm) +{ + printf("%s", perm & S_IRUSR ? "r" : "-"); + printf("%s", perm & S_IWUSR ? "w" : "-"); + printf("%s", perm & S_IXUSR ? "x" : "-"); + + printf("%s", perm & S_IRGRP ? "r" : "-"); + printf("%s", perm & S_IWGRP ? "w" : "-"); + printf("%s", perm & S_IXGRP ? "x" : "-"); + + printf("%s", perm & S_IROTH ? "r" : "-"); + printf("%s", perm & S_IWOTH ? "w" : "-"); + printf("%s", perm & S_IXOTH ? "x" : "-"); +} + +static int +showInodeMeta(struct jffs2_raw_inode *i) +{ + char buf[80]; + struct tm t; + + showInodeType(i->mode); + showInodePerm(i->mode); + gmtime_r(i->atime, &t); + asctime_r(&t, buf); + + printf(" %4d %4d %6d %s ", + i->uid, i->gid, i->isize, buf); + return 0; +} + +static int +showNodesOfType(struct jffs2_unknown_node_list *list, + jint16 nodetype) +{ + int count = 0; + + while ((list = findNodeOfType(list, nodetype)) != NULL + && !gotachar()) { + showNode(list->nodenum, list->u); + count++; + list = list->next; + } + return count; +} + +static int +showNodesOfTypeRange(struct jffs2_unknown_node_list *list, + jint16 nodetype, + char *pino, + char *ino) +{ + int count = 0; + + while (list && !gotachar()) { + list = findNodeOfTypeRange(list, nodetype, pino, ino); + if (list != NULL && list->u != NULL) { + showNode(list->nodenum, list->u); + count++; + } + if (list != NULL) + list = list->next; + } + return count; +} + +static struct jffs2_unknown_node_list * +findNodeOfNumRange(struct jffs2_unknown_node_list *list, + char *nodenum) +{ + while (!gotachar() && list) { + + if (list->u && inRange(nodenum, list->nodenum)) + return list; + + list = list->next; + } + + return NULL; +} + +static int +showNodesOfNumRange(struct jffs2_unknown_node_list *list, + char *range) +{ + int nodetot = 0; + + while (list && (list = findNodeOfNumRange(list, range))) { + nodetot++; + showNode(list->nodenum, list->u); + list = list->next; + } + + return nodetot; +} + +static struct jffs2_unknown_node_list * +findDirentByPath(struct jffs2_unknown_node_list *list, + char *path) +{ +#define JFFS2_ROOT_PINO 1 +#define JFFS2_PATH_SEPARATOR "/" + + char subpath[JFFS2_MAXPATH + 1]; + int pathlen; + jint32 pino = JFFS2_ROOT_PINO; + struct jffs2_unknown_node_list *u = NULL; + struct jffs2_raw_dirent *d; + + if (strlen(path) > JFFS2_MAXPATH + || (path == NULL)) + return NULL; + + while (*path) { + + path += strspn(path, JFFS2_PATH_SEPARATOR); + pathlen = strcspn(path, JFFS2_PATH_SEPARATOR); + strncpy(subpath, path, pathlen); + subpath[pathlen] = 0; + path += pathlen; + + u = findMatchingDirent(list, pino, -1, subpath); + if (u == NULL) + return NULL; + + d = (struct jffs2_raw_dirent *)u->u; + pino = d->ino; + } + + if (is_deleted_dirent(u->u)) + return NULL; + return u; +} + +static int +listDirent(struct jffs2_unknown_node_list *list, + struct jffs2_unknown_node_list *u, + struct jffs2_umoninfo *umip) +{ + struct jffs2_raw_dirent *d; + struct jffs2_raw_inode *i; + + d = (struct jffs2_raw_dirent*)u->u; + + u = findInode(list, d->ino, -1); + if (u == NULL) + return 0; + + i = (struct jffs2_raw_inode*)u->u; + if (!umip->quiet) + showInodeMeta(i); + + memset(umip->direntname, 0, sizeof(umip->direntname)); + memcpy(umip->direntname, (void*)d->name, d->nsize); + umip->direntsize = i->isize; + + if (is_dir(i->mode)) + umip->direntname[d->nsize] = '/'; + + if (!umip->quiet) + printf("%s\n", umip->direntname); + + return 1; +} + +static int +listDirentByPath(struct jffs2_unknown_node_list *list, + char *path, struct jffs2_umoninfo *umip) +{ + struct jffs2_unknown_node_list *u = NULL; + struct jffs2_unknown_node_list *n; + struct jffs2_raw_dirent *d = NULL; + struct jffs2_raw_inode *i; + jint32 pino = JFFS2_ROOT_PINO; + int ret = 0; + + /* TODO: wildcards? */ + + if (path != NULL && strlen(path) != 0 + && strcspn(path, JFFS2_PATH_SEPARATOR) != 0) { + + u = findDirentByPath(list, path); + if (u == NULL) + goto not_found; + + d = (struct jffs2_raw_dirent*)u->u; + n = findInode(list, d->ino, -1); + if (n == NULL) + goto not_found; + + i = (struct jffs2_raw_inode*)n->u; + if (!is_dir(i->mode)) + return listDirent(list, u, umip); + else pino = d->ino; + } + + for (u = list; u != NULL + && (u = findMatchingDirent(u, pino, -1, NULL)) != NULL; + u = u->next) { + ret += listDirent(list, u, umip); + } + + return ret; + + not_found: + if (!umip->quiet) + printf("%s: no such file or directory\n", path); + return 0; + +} + + +static int +readRawInode(struct jffs2_raw_inode *i, + jint32 offset /* ... into start of inode */, + jint32 len /* ... of bytes to take from inode */, + void (*callback)(void *args, int offset, void *buf, int size), + void *callback_args) +{ + static void *temp = NULL; + + /* TODO: we could allocate a 4K buffer here, read into that, and + then pass that buffer to the callback (instead of having the + callback read from flash directly); this would allow us to put + jffs2 into something other than bulk NOR flash + + (is there a uMON flash-reading function that handles + device-specific i/o details?) + */ + switch (i->compr) { + + case JFFS2_COMPR_NONE: + callback(callback_args, i->offset + offset, + (void*)(i->data + offset), len); + break; + + case JFFS2_COMPR_ZERO: + callback(callback_args, i->offset + offset, 0, len); + break; + + case JFFS2_COMPR_ZLIB: + if (temp == NULL && ((temp = malloc(4096)) == NULL)) { + printf("%s: cannot alloc tempspace (aborted)\n", + __func__); + return -1; + } + + if (i->dsize > 4096) { + printf("%s: inode dsize > 4K (aborted)\n", __func__); + return -1; + } + + if (jzlibcpy((void*)(i->data), temp, i->csize, i->dsize) < 0) + return -1; + callback(callback_args, i->offset + offset, temp + offset, len); + break; + + case JFFS2_COMPR_RTIME: + case JFFS2_COMPR_RUBINMIPS: + case JFFS2_COMPR_DYNRUBIN: + printf("%s: unsupported compression algorithm (fragment ignored)\n", + compr2str(i->compr)); + break; + } + + return len; +} + +/* + * Finds a region in <list> a.k.a. "fragment" that overlaps inode <i>, + * and populates that fragment with the contents of the inode. If the + * fragment is fully covered by the contents of the inode, then the + * fragment is removed from <list>; otherwise, the fragment list node + * is modified or bisected to record bytes that are still missing. + * + * Returns the number of bytes written, or 0 to indicate there were no + * fragments that overlapped the inode, or a negative number for + * error. + * + * You'll need to call this function with the same inode until it + * returns zero or an error, since we return at the first occurence of + * a valid fragment. Depending on the sequence of inodes, one or more + * fragments could be covered by the same inode and/or it might take + * multiple inodes to completely fill a fragment. That's just how + * jffs2 and other log-structured filesystems work. + */ +static int +readFrag(struct jffs2_unknown_node_list *list, + struct jffs2_raw_inode *i, + void (*callback)(void *args, int offset, void *buf, int size), + void *callback_args) +{ + jint32 fstart, istart, fend, iend; + struct jffs2_cleanregion_node *frag; + struct jffs2_unknown_node *newfrag; + + for ( ; list->next != NULL; list = list->next) { + + /* we "shouldn't" have to do this, but since we're emptying the + list entirely the list pointer is always aimed at the sentinel + node; skip it if we find it, and use the ->next == NULL case to + spot the end of the list (contrary to the rest of the code in + this compilation unit) */ + if (list->u == NULL) continue; + + frag = (struct jffs2_cleanregion_node*)list->u; + + fstart = frag->physaddr; + istart = i->offset; + fend = frag->physaddr + frag->totlen; + iend = i->offset + i->dsize; + + if (fend <= istart || iend <= fstart) + continue; + + if (fstart >= istart && fend <= iend) { + delListNode(list); + return readRawInode(i, fstart - istart, fend - fstart, + callback, callback_args); + } + + if (fstart <= istart && fend <= iend) { + frag->totlen = istart - fstart; + return readRawInode(i, 0, fend - istart, + callback, callback_args); + } + + if (fstart >= istart && fend >= iend) { + frag->physaddr = iend; + frag->totlen = fend - iend; + return readRawInode(i, fstart - istart, iend - fstart, + callback, callback_args); + } + + frag->totlen = iend - fend; + newfrag = allocCleanRegion(iend, fend - iend); + insertListNodeAfter(list, allocListNode(0, newfrag)); + + return readRawInode(i, 0, i->dsize, callback, callback_args); + } + + return 0; +} + + +static int +readInode(struct jffs2_unknown_node_list *list, + jint32 ino, + void (*callback)(void *callback_args, + int offset, void *buf, int size), + void *callback_args) +{ + struct jffs2_unknown_node_list *frags; + struct jffs2_unknown_node_list *u; + struct jffs2_unknown_node *fr; + struct jffs2_unknown_node_list *f; + struct jffs2_raw_inode *i; + int ret; + int len = 0; + + if ((u = findInode(list, ino, -1)) == NULL) { + printf("%d: no such inode\n", ino); + return -1; + } + + i = (struct jffs2_raw_inode*)u->u; + if (i->isize == 0) + return 0; + + if (initNodeList(&frags) == NULL) { + printf("%s: initNodeList() returned NULL (aborted)\n", + __func__); + return -1; + } + + if ((fr = allocCleanRegion(0, i->isize)) == NULL) + goto fail_alloc_initial_region; + if ((f = allocListNode(0, fr)) == NULL) + goto fail_alloc_initial_node; + insertListNodeAfter(frags, f); + + /* + * Note: The convention in most of this compilation unit is for list + * pointers to point to the first valid list member. However, in + * the case of the fragment list we know the caller is going to be + * removing nodes, including the first valid list member. Thus, + * we'll keep the list pointer on the sentinel node since that one + * never goes away. (The readFrag() iterator knows about this, and + * changes its list walking logic accordingly). + */ + + do { + i = (struct jffs2_raw_inode*)u->u; + do { + ret = readFrag(frags, i, callback, callback_args); + if (ret >= 0) len += ret; + } while (ret > 0); + + u = findInode(list, ino, i->version - 1); + } while (!is_empty_list(frags) && u != NULL); + + if (!is_empty_list(frags)) + printf("%s: warning, nonempty fragment list " + "(missing inode?) (ignored)\n"); + + while(frags->next) + delListNode(frags->next); + delListNode(frags); + + return len; + + fail_alloc_initial_node: + free(fr); + printf("%s: allocListNode() returned NULL (aborted)\n", + __func__); + return 0; + fail_alloc_initial_region: + printf("%s: allocCleanRegion() returned NULL (aborted)\n", + __func__); + return 0; +} + +static int +readDirent(struct jffs2_unknown_node_list *list, char *path, + void (*callback)(void *args, + int offset, void *buf, int size), + void *callback_args) +{ + struct jffs2_unknown_node_list *u; + struct jffs2_raw_dirent *d; + struct jffs2_raw_inode *i; + + u = findDirentByPath(list, path); + if (u == NULL) + goto no_such_file; + + d = (struct jffs2_raw_dirent *)u->u; + u = findInode(list, d->ino, -1); + if (u == NULL) + goto no_such_inode; + + i = (struct jffs2_raw_inode*)u->u; + if (!is_reg(i->mode)) + goto not_a_file; + + return readInode(list, d->ino, callback, callback_args); + + no_such_file: + printf("%s: no such file or directory\n", path); + return -1; + + no_such_inode: + printf("%d: no such inode\n", d->ino); + return -1; + + not_a_file: + printf("%s: is %s\n", path, + is_dir(i->mode) ? "a directory" : "not a file"); + return -1; +} + +static struct jffs2_unknown_node * +commitRawNode(struct jffs2_unknown_node_list *list, + struct jffs2_unknown_node *u) +{ + struct jffs2_unknown_node_list *c; + unsigned long adjtotlen; + int ret; + + /* everything is 32-bit aligned in jffs2-land, so you always need a + region slightly larger than the data itself to accomodate the + address and length rounding we may apply later on */ + c = findCleanRegion(list, u->totlen + 4); + if (c != NULL) { + + struct jffs2_cleanregion_node *f = (struct jffs2_cleanregion_node*)c->u; + + ret = AppFlashWrite((void*)(f->physaddr), (void*)u, u->totlen); + if (ret != 0) + printf("%s: AppFlashWrite returned %d (ignored)\n", __func__, ret); + + ret = f->physaddr; + + /* cleanregions must always begin on a 32-bit boundary */ + adjtotlen = ulceil(u->totlen, 4); + f->totlen -= adjtotlen; + f->physaddr += adjtotlen; + + return (struct jffs2_unknown_node*)ret; + } + + return NULL; +} + +static struct jffs2_raw_dirent * +allocDirentNode (char *name) +{ + struct jffs2_raw_dirent *d; + int namelen = 0; + + if (name != NULL) + namelen = strlen(name); + + d = (struct jffs2_raw_dirent*)malloc(sizeof(*d) + namelen); + if (d == NULL) { + printf("%s: malloc() returned NULL (aborted)\n", __func__); + return NULL; + } + + memset((void*)d, 0, sizeof(*d)); + + d->magic = JFFS2_MAGIC; + d->nodetype = JFFS2_NODETYPE_DIRENT + | JFFS2_NODE_ACCURATE + | JFFS2_FEATURE_ROCOMPAT + | JFFS2_FEATURE_RWCOMPAT_COPY; + memcpy((void*)d->name, name, d->nsize = namelen); + d->totlen = sizeof(*d) + d->nsize; + + return d; +} + +static void +freeDirentNode(struct jffs2_raw_dirent *d) +{ + free(d); +} + + +static jint32 +nextPinoVersion(struct jffs2_unknown_node_list *list, jint32 pino) +{ + jint32 version = 0; + + while(list) { + if (list->u && is_dirent(list->u)) { + struct jffs2_raw_dirent *d = (struct jffs2_raw_dirent*)list->u; + + if (d->pino == pino && d->version > version) + version = d->version; + } + list = list->next; + } + + return version + 1; +} + +static struct jffs2_unknown_node_list * +commitDirent(struct jffs2_unknown_node_list *list, ulong nodenum, + char *name, jint8 type, jint32 pino, jint32 ino, + jint32 version) +{ + struct jffs2_raw_dirent *d; + struct jffs2_unknown_node *dc; + struct jffs2_unknown_node_list *n; + + d = allocDirentNode(name); + if (d == NULL) + return NULL; + + d->type = type; + d->version = version; + d->pino = pino; + d->ino = ino; + + d->hdr_crc = calcHdrCrc((struct jffs2_unknown_node *)d); + d->node_crc = calcDirentCrc(d); + d->name_crc = calcDataCrc(d->name, d->nsize); + + dc = commitRawNode(list, (struct jffs2_unknown_node*)d); + freeDirentNode(d); + + if (dc == NULL) /* TODO: error handling? */ + return NULL; + + if ((n = allocListNode(nodenum, dc)) != NULL) + return insertListNodeAfter(list, n); + + return NULL; +} + +static struct jffs2_unknown_node_list * +moveDirent(struct jffs2_unknown_node_list *list, + int nodetot, char *oldpath, char *newpath) +{ + struct jffs2_unknown_node_list *u, *ui, *uold, *unew; + struct jffs2_raw_dirent *d = NULL; + struct jffs2_raw_inode *i; + jint32 pino; + jint32 nextver; + + char newname[JFFS2_MAXPATH + 1]; + + uold = findDirentByPath(list, oldpath); + if (uold == NULL) + goto no_such; + d = (struct jffs2_raw_dirent*)uold->u; + + unew = findDirentByPath(list, newpath); + if (unew != NULL) { + struct jffs2_raw_dirent *dnew; + + dnew = (struct jffs2_raw_dirent*)unew->u; + ui = findInode(list, dnew->ino, -1); + i = (struct jffs2_raw_inode*)ui->u; + if (!is_dir(i->mode)) + goto in_the_way; + + pino = dnew->ino; + strncpy(newname, (void*)d->name, d->nsize); + newname[d->nsize] = 0; + } + else { + strcpy(newname, newpath); + pino = JFFS2_ROOT_PINO; + } + + nextver = nextPinoVersion(list, pino); + u = commitDirent(list, nodetot++, newname, + d->type, pino, d->ino, nextver++); + /* TODO: error handling? */ + u = commitDirent(list, nodetot++, oldpath, + d->type, d->pino, 0, nextver); + return u; + + no_such: + printf("%s: no such file or directory\n", oldpath); + return NULL; + + in_the_way: + /* (yes, we could delete this ourselves...) */ + printf("%s already exists\n", newpath); + return NULL; +} + +static struct jffs2_unknown_node_list * +deleteDirent(struct jffs2_unknown_node_list *list, + int nodetot, char *path) +{ + struct jffs2_unknown_node_list *u, *ui; + struct jffs2_raw_dirent *d; + struct jffs2_raw_inode *i; + jint32 nextver; + char name[JFFS2_MAXPATH + 1]; + + u = findDirentByPath(list, path); + if (u == NULL) + goto no_such; + d = (struct jffs2_raw_dirent*)u->u; + + ui = findInode(list, d->ino, -1); + i = (struct jffs2_raw_inode*)ui->u; + if (is_dir(i->mode)) { + /* TODO: make sure directory is empty */ + printf("%s: is a directory (abort)\n", path); + return NULL; + } + + strncpy(name, (void*)d->name, d->nsize); + name[d->nsize] = 0; + + nextver = nextPinoVersion(list, d->pino); + u = commitDirent(list, nodetot++, name, + d->type, d->pino, 0, nextver); + + return u; + + no_such: + printf("%s: no such file or directory\n", path); + return NULL; +} + +#define JFFS2_DEFAULT_UID 0 +#define JFFS2_DEFAULT_GID 0 + +static struct jffs2_raw_inode * +allocInode(jint32 ino, jint32 dsize) +{ + struct jffs2_raw_inode *i; + + i = (struct jffs2_raw_inode*)malloc(sizeof(*i) + dsize); + if (i == NULL) { + printf("%s: malloc() returned NULL (aborted)\n", __func__); + return NULL; + } + + memset((void*)i, 0, sizeof(*i) + dsize); + + i->magic = JFFS2_MAGIC; + i->ino = ino; + i->nodetype = JFFS2_NODETYPE_INODE + | JFFS2_NODE_ACCURATE + | JFFS2_FEATURE_ROCOMPAT + | JFFS2_FEATURE_RWCOMPAT_COPY; + i->compr = JFFS2_COMPR_NONE; + i->dsize = i->csize = dsize; + i->totlen = sizeof(*i) + dsize; + + return i; +} + +static void +freeInode(struct jffs2_raw_inode *i) +{ + free(i); +} + +static jint32 +getUnusedIno(struct jffs2_unknown_node_list *list) +{ + /* by definition, the root pino is always taken... */ + jint32 ino = JFFS2_ROOT_PINO + 1; + + while (!gotachar() + && (list = findNodeOfType(list, JFFS2_NODETYPE_INODE)) != NULL) { + struct jffs2_raw_inode *i = (struct jffs2_raw_inode*)list->u; + if (i->ino > ino) + ino = i->ino + 1; + list = list->next; + } + + if (gotachar()) + return -1; + return ino; +} + + + +/* TODO: deleteDirectory() a.k.a. rmdir */ + +static struct jffs2_unknown_node_list * +appendInode(struct jffs2_unknown_node_list *list, + int nodenum, + char *path, + void *data, + int len) +{ + struct jffs2_unknown_node_list *n; + struct jffs2_raw_inode *iprev, *inew; + struct jffs2_raw_dirent *d; + struct jffs2_unknown_node *ic; + + /* TODO: break append up into smaller nodes, if there isn't a single + region large enough */ + + /* TODO: don't deal with large appends yet (nodes are not permitted + to exceed 4K in size per jffs2) */ + if (len >= 4096) { + printf("inode extension by >= 4K not supported (yet)\n"); + return NULL; + } + + n = findDirentByPath(list, path); + if (n == NULL) + goto not_found; + d = (struct jffs2_raw_dirent*)n->u; + + n = findInode(list, d->ino, -1); + if (n == NULL) + goto not_found; + iprev = (struct jffs2_raw_inode*)n->u; + + inew = allocInode(iprev->ino, len); + if (inew == NULL) + return NULL; + + inew->ino = iprev->ino; + inew->version = iprev->version + 1; + inew->mode = iprev->mode; + inew->uid = iprev->uid; + inew->gid = iprev->gid; + inew->atime = iprev->atime; + inew->mtime = iprev->mtime; + inew->ctime = iprev->ctime; + + inew->offset = inew->isize; + inew->isize += len; + inew->compr = JFFS2_COMPR_NONE; + inew->usercompr = 0; + memcpy((void*)inew->data, data, len); + + inew->hdr_crc = calcHdrCrc((struct jffs2_unknown_node*)inew); + inew->node_crc = calcInodeCrc(inew); + inew->data_crc = calcDataCrc(inew->data, inew->dsize); + + ic = commitRawNode(list, (struct jffs2_unknown_node*)inew); + freeInode(inew); + + if (ic == NULL) /* TODO: error handling? */ + return NULL; + + if ((n = allocListNode(nodenum++, ic)) != NULL) + return insertListNodeAfter(list, n); + + return NULL; + + not_found: + printf("%s: no such file or directory\n", path); + return NULL; +} + +static struct jffs2_unknown_node_list * +createInode(struct jffs2_unknown_node_list *list, + int nodenum, + jint32 mode, + char *path) +{ + struct jffs2_unknown_node_list *n; + struct jffs2_raw_inode *i; + struct jffs2_unknown_node *ic; + char *ppath = path; + jint32 pino = 1; + jint32 ino; + jint8 type; + char name[JFFS2_MAXPATH + 1]; + + n = findDirentByPath(list, path); + if (n != NULL) + goto already_exists; + + while (*ppath && strstr(ppath, JFFS2_PATH_SEPARATOR) != NULL) + ppath++; + + if (ppath != path) { + struct jffs2_raw_dirent *d; + strncpy(name, path, ppath - path - 1); + name[ppath - path - 1] = 0; + + n = findDirentByPath(list, name); + if (n == NULL) + goto not_found; + d = (struct jffs2_raw_dirent*)n->u; + pino = d->ino; + } + + ino = getUnusedIno(list); + if (ino == -1) + return NULL; + + i = allocInode(ino, 0); + if (i == NULL) + return NULL; + + i->mode = mode; + i->uid = JFFS2_DEFAULT_UID; + i->gid = JFFS2_DEFAULT_GID; + i->version = 1; + + i->hdr_crc = calcHdrCrc((struct jffs2_unknown_node*)i); + i->node_crc = calcInodeCrc(i); + i->data_crc = 0; + + ic = commitRawNode(list, (struct jffs2_unknown_node*)i); + freeInode(i); + + if (ic == NULL) /* TODO: error handling? */ + return NULL; + + if ((n = allocListNode(nodenum++, ic)) == NULL + || insertListNodeAfter(list, n) == NULL) + return NULL; + + if (is_lnk(mode)) type = DT_LNK; + else if (is_blk(mode)) type = DT_BLK; + else if (is_dir(mode)) type = DT_DIR; + else if (is_chr(mode)) type = DT_CHR; + else if (is_fifo(mode)) type = DT_FIFO; + else type = DT_REG; + + i = (struct jffs2_raw_inode*)ic; + + return commitDirent(list, nodenum, ppath, type, + pino, i->ino, nextPinoVersion(list, pino)); + + already_exists: + printf("%s: file exists\n", path); + return NULL; + + not_found: + printf("%s: no such file or directory\n", name); + return NULL; +} + +struct jffs2_callback_args { + void *dest; +}; + +static void +callback_to_memory (void *vargs, int offset, + void *src, int size) +{ + struct jffs2_callback_args *args = vargs; + if (src == NULL) + memset(args->dest + offset, 0, size); + else + memcpy(args->dest + offset, src, size); +} + +static void +callback_to_console (void *vargs, int offset, + void *src, int size) +{ + char *cp = src; + + if (src == NULL) + return; + + for (cp = src; size > 0; size--) + putchar(*cp++); +} + +char *Jffs2Help[] = { + "Read and write JFFS2-formatted flash space", + "[b:cs:] {operation} [args]...", +#if INCLUDE_VERBOSEHELP + "", + "Options:", + " -b {addr} base address of JFFS2 space (note 1)", + " -c check CRCs of all nodes (note 2)", + " -s {size} size of JFFS2 space {note 4}", + " -q quiet operation", + "", + "Operations:", + " add {fname} {address} {bytes}", + " append {bytes} bytes at {address} to file {fname} (note 3)", + " cat {fname} dump contents of ASCII file {fname} to console", + " cp {fname} {to_fname}", + " copy a file {fname} to {to_fname}", + " get {fname} {to_addr}", + " dump contents of file {fname} to {to_addr}", + " ls [path] list files and/or dirs of the specified [path]", + " mkdir {path} create a directory named {path}", + " mv {path} {to_path}", + " relocate a file/directory from {path} to {to_path}", + " rm {fname} delete file named {fname}", + " mkfs [{{addr} {size}}]", + " build an empty JFFS2 filesystem (notes 1,4)", + "", + "Additional operations:", + " dump display all nodes", + " dirent display all dirent nodes", + " inode display all inode nodes", + " ino [rng] display nodes with specified ino field", + " node [rng] display nodes of specified numerical range", + " pino [rng] display nodes with specified pino field", + " rescan discard current node list, if any, then scan", + " scan scan filesystem image only", + +#if 0 + " zinf {src} {dest} {srclen} {destlen}", + " inflate using JFFS2's zlib", +#endif + "", + "Notes:", + " 1. Base address defaults to $JFFS2BASE or zero, if not specified", + " 2. Defaults to off", + " 3. If {fname} does not exist, it is created", + " 4. Size defaults to $JFFS2SIZE or zero, if not specified", +#endif + 0 +}; + +static void +progress_callback(int percent) +{ + static int prev_percent; + + if (prev_percent == percent) + return; + + prev_percent = percent; + printf("\r%3d%%\r", + percent > 100 ? 100 : percent); +} + +int +Jffs2Cmd(int argc, char *argv[]) +{ + ulong jaddr, jsize; + struct jffs2_unknown_node *u; + int opt; + char *env, *cmd, *fname, *range; + int bytes, nodes; + void (*progress)(int percent) = progress_callback; + + static int nodetot = 0; + static struct jffs2_unknown_node_list *nodeList = NULL; + + jint32 jffs2_base = JFFS2_DEFAULT_BASE; + jint32 jffs2_size = 0; + + assert(sizeof(jint32) == 4); + assert(sizeof(jint16) == 2); + assert(sizeof(jint8) == 1); + + jffs2_verify_crc = 0; + + if ((env = getenv("JFFS2BASE"))) + jffs2_base = (jint32)strtoul(env,0,0); + + if ((env = getenv("JFFS2SIZE"))) + jffs2_size = (jint32)strtoul(env,0,0); + + while ((opt=getopt(argc,argv,"b:cs:q")) != -1) { + switch(opt) { + case 'b': + jffs2_base = (jint32)strtoul(optarg,0,0); + break; + case 'c': + jffs2_verify_crc = 1; + break; + case 's': + jffs2_size = (jint32)strtoul(optarg,0,0); + break; + case 'q': + progress = NULL; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc < optind + 1) + return(CMD_PARAM_ERROR); + + cmd = argv[optind]; + + if (strcmp(cmd, "mkfs") == 0) { + if (argc <= optind + 1) + jaddr = jffs2_base; + else + jaddr = strtoul(argv[optind + 1], 0, 0); + if (argc <= optind + 2) + jsize = jffs2_size; + else + jsize = strtoul(argv[optind + 2], 0, 0); + + nodeList = discardNodeList(nodeList); + + /* TODO: progress feedback needs to be optional? */ + return formatMedium(jaddr, jsize, progress) ? + CMD_FAILURE : CMD_SUCCESS; + } + + if (strcmp(cmd, "rescan") == 0) + nodeList = discardNodeList(nodeList); + + /* commands below this point require a scanMedium() */ + + if (nodeList == NULL) { + initNodeList(&nodeList); + if (nodeList != NULL) { + nodetot = scanMedium(jffs2_base, jffs2_size, nodeList, progress); + while (nodeList->prev) + nodeList = nodeList->prev; + } + } + + if (strcmp(cmd, "scan") == 0 + || strcmp(cmd, "rescan") == 0) + return CMD_SUCCESS; + + jaddr = jffs2_base; + u = (struct jffs2_unknown_node *)jaddr; + + if (strcmp(cmd,"dump") == 0) { + printf("JFFS2 base: 0x%lx\n",jffs2_base); + printf("JFFS2 size: 0x%lx\n",jffs2_size); + nodes = showNodesOfNumRange(nodeList, "all"); + printf("%d nodes\n", nodes); + return CMD_SUCCESS; + } + else if (strcmp(cmd,"node") == 0) { + if (argc == optind + 1) + range = "all"; + else + range = argv[optind + 1]; + nodes = showNodesOfNumRange(nodeList, range); + return CMD_SUCCESS; + } + + /* if you want a range of dirents or inodes, you need to specify the + ino and/or pino; don't use "dirent" or "inode" */ + else if (strcmp(cmd,"dirent") == 0) { + nodes = showNodesOfType(nodeList, JFFS2_NODETYPE_DIRENT); + printf("%d nodes\n", nodes); + } + else if (strcmp(cmd,"inode") == 0) { + nodes = showNodesOfType(nodeList, JFFS2_NODETYPE_INODE); + printf("%d nodes\n", nodes); + } + + /* TODO: this can be reimplemented just like "ino"? */ + else if (strcmp(cmd,"pino") == 0) { + jint32 pino; + struct jffs2_unknown_node_list *u = nodeList; + + if (argc != optind+2) + return CMD_PARAM_ERROR; + + pino = strtol(argv[optind+1],0,0); + + do { + u = findNextMatchingDirent(u, pino, -1, NULL); + if (u != NULL && u->u != NULL) { + showNode(u->nodenum, u->u); + u = u->next; + } + } while (u != NULL && u->u != NULL); + } + + else if (strcmp(cmd,"ino") == 0) { + + if (argc == optind+1) + range = "all"; + else + range = argv[optind+1]; + + nodes = showNodesOfTypeRange(nodeList, + JFFS2_NODETYPE_DIRENT, NULL, range); + nodes += showNodesOfTypeRange(nodeList, + JFFS2_NODETYPE_INODE, NULL, range); + printf("%d nodes\n", nodes); + return CMD_SUCCESS; + } + + else if (strcmp(cmd,"cp") == 0) { + printf("TODO: jffs2 cp {fname} {to_fname}\n" + "(it's harder than it sounds!)\n"); + return CMD_SUCCESS; + } + + else if (strcmp(cmd,"get") == 0) { + struct jffs2_callback_args args; + + if (argc == (optind + 3)) + args.dest = (void*)strtoul(argv[optind + 2], 0, 0); + else + return CMD_PARAM_ERROR; + + setenv(JFFS2_FSIZE_STR,0); + fname = argv[optind + 1]; + bytes = readDirent(nodeList, fname, callback_to_memory, &args); + if (bytes >= 0) + shell_sprintf(JFFS2_FSIZE_STR,"%d",bytes); + printf("%d bytes\n", bytes); + return CMD_SUCCESS; + } + + else if (strcmp(cmd,"cat") == 0) { + if (argc != optind + 2) + return CMD_PARAM_ERROR; + + setenv(JFFS2_FSIZE_STR,0); + fname = argv[optind + 1]; + bytes = readDirent(nodeList, fname, callback_to_console, NULL); + if (bytes >= 0) + shell_sprintf(JFFS2_FSIZE_STR,"%d",bytes); + return CMD_SUCCESS; + } + + else if (strcmp(cmd, "mkdir") == 0) { + if (argc != optind + 2) + return CMD_PARAM_ERROR; + + createInode(nodeList, nodetot++, + JFFS2_MODE_DIR + | S_IRUGO | S_IXOTH | S_IXGRP | S_IRWXU, + argv[optind + 1]); + + return CMD_SUCCESS; + } + + else if (strcmp(cmd, "chmod") == 0) { + printf("TODO: implement chmod\n"); + return CMD_SUCCESS; + } + + else if (strcmp(cmd, "add") == 0) { + if (argc != (optind + 4)) + return CMD_PARAM_ERROR; + + char *path; + long addr, len; + + path = argv[optind + 1]; + addr = strtol(argv[optind + 2], 0, 0); + len = strtol(argv[optind + 3], 0, 0); + + if (findDirentByPath(nodeList, path) == NULL) + createInode(nodeList, nodetot++, + JFFS2_MODE_REG | S_IRUGO | S_IWUSR, + path); + + appendInode(nodeList, nodetot++, path, (void*)addr, len); + return CMD_SUCCESS; + } + + else if (strcmp(cmd, "mv") == 0 && (argc == (optind + 3))) { + char *oldname, *newname; + + oldname = argv[optind + 1]; + newname = argv[optind + 2]; + + moveDirent(nodeList, nodetot, oldname, newname); + return CMD_SUCCESS; + } + + else if(strcmp(cmd, "rm") == 0 && (argc == (optind + 2))) { + deleteDirent(nodeList, nodetot, argv[optind + 1]); + return CMD_SUCCESS; + } + + else if ((strcmp(cmd, "ls") == 0) || (strcmp(cmd, "qry") == 0)) { + int ftot; + char *path; + struct jffs2_umoninfo ju; + + /* If the sub-command is "qry", then we do essentially the same + * thing as "ls" except quietly (just populate the shell variables). + */ + if (cmd[0] == 'q') + ju.quiet = 1; + else + ju.quiet = 0; + + ju.direntsize = -1; + ju.direntname[0] = 0; + setenv(JFFS2_FNAME_STR,0); + setenv(JFFS2_FSIZE_STR,0); + + if (argc == optind + 2) + path = argv[optind + 1]; + else + path = NULL; + ftot = listDirentByPath(nodeList, path, &ju); + if ((ftot > 0) && (!ju.quiet)) + printf(" Total: %d\n",ftot); + + shell_sprintf(JFFS2_FTOT_STR,"%d",ftot); + + if (ju.direntsize > 0) { + shell_sprintf(JFFS2_FSIZE_STR,"%d",ju.direntsize); + setenv(JFFS2_FNAME_STR,ju.direntname); + } + + return CMD_SUCCESS; + } + + printf("jffs2 cmd <%s> not found\n",cmd); + return CMD_FAILURE; +} + +#endif diff --git a/main/common/ledit_vi.c b/main/common/ledit_vi.c new file mode 100644 index 0000000..68f7d01 --- /dev/null +++ b/main/common/ledit_vi.c @@ -0,0 +1,737 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * lineedit.c: + * + * This code supports the monitor's command line editing capability and + * command history log. The command line editing is a subset of KSH's + * vi-mode editing. + * + * This code includes a few suggestions/fixed from Martin Carroll. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#if INCLUDE_LINEEDIT +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" +#include "cli.h" + +#define HMAX 16 +#define ESC 0x1B +#define CTLC 0x03 +#define BACKSPACE 0x08 +#define CMD 100 +#define EDIT 101 +#define EDIT1 102 +#define INSERT 103 +#define NEXT 104 +#define PREV 105 +#define NEITHER 106 + +#define EDITFILELINE 1 +#define EDITCMDLINE 2 + +static int stridx; /* store index */ +static int shwidx; /* show index */ +static int srchidx; /* search index */ +static int lastsize; /* size of last command */ +static char curChar; /* latest input character */ +static char *curPos; /* current position on command line */ +static char *startOfLine; /* start of command line */ +static int lineLen; /* length of line */ +static int lMode; /* present mode of entry */ +static char cmdhistory[HMAX+1][CMDLINESIZE];/* array for command history */ + +static void ledit(), lcmd(), showprev(), ldelete(), linsert(), lerase(); +static void gotobegin(), gotoend(), backup(), shownext(), linsertbs(); +static void delete_to_end(), delete_something(); +static void historysearch(void), ledit1(void); +static char *lineeditor(); + +/* line_edit() & file_line_edit(): + * These two functions are simply front-ends to the lineeditor() + * function. The line_edit() function is called by the command line + * interface and file_line_edit() is called by the flash file editor + * to provide a convenient single line editor when modifying a file. + */ + +char * +line_edit(char *line_to_edit) +{ + return(lineeditor(line_to_edit,EDITCMDLINE)); +} + +char * +file_line_edit(char *line_to_edit) +{ + return(lineeditor(line_to_edit,EDITFILELINE)); +} + +/* lineeditor(): + * This function is fed a pointer to a command line. + * It sets up a command line editor for that particular line. + * The line is modified in place so, if successful, the function + * returns the same pointer but with its contents modified based + * on the editor commands executed. + * If failure, the function returns (char *)0. + */ +static char * +lineeditor(char *line_to_edit,int type) +{ + lMode = CMD; + startOfLine = line_to_edit; + curPos = line_to_edit; + while(*curPos != ESC) + curPos++; + *curPos = 0; /* Remove the escape character from the line */ + lineLen = (ulong)curPos - (ulong)startOfLine; + if (lineLen > 0) { + curPos--; + putstr(" \b\b"); + } + else + putstr(" \b"); + lastsize = 0; + shwidx = stridx; + srchidx = stridx; + while(1) { + curChar = getchar(); + switch(curChar) { + case ESC: + if (lMode != CMD) { + lMode = CMD; + continue; + } + else { + putchar('\n'); + return((char *)0); + } + case '\r': + case '\n': + putchar('\n'); + if (lineLen == 0) + return((char *)0); + *(char *)(startOfLine + lineLen) = '\0'; + return(startOfLine); + case CTLC: + putchar('\n'); + *startOfLine = 0; + lineLen = 0; + return((char *)0); + } + switch(lMode) { + case CMD: + lcmd(type); + if (lMode == NEITHER) + return((char *)0); + break; + case INSERT: + linsert(); + break; + case EDIT1: + ledit1(); + break; + case EDIT: + ledit(); + break; + } + if (lineLen >= (CMDLINESIZE - 2)) { + printf("line overflow\n"); + return((char *)0); + } + } +} + +static void +ledit(void) +{ + int len; + + if (curChar == '\b') + curPos--; + else + *curPos++ = curChar; + + len = (curPos - startOfLine); /* line may get longer than original */ + if (len > lineLen) + lineLen = len; + + putchar(curChar); + switch(lMode) { + case EDIT1: + lMode = CMD; + break; + } +} + +static void +ledit1(void) +{ + *curPos = curChar; + putchar(curChar); + putchar('\b'); + lMode = CMD; +} + +static void +lcmd(int type) +{ + switch(curChar) { + case '0': + gotobegin(); + return; + case '$': + gotoend(); + return; + case 'A': + gotoend(); + putchar(*curPos++); + lMode = INSERT; + return; + case 'a': + if (curPos != startOfLine) + putchar(*curPos++); + lMode = INSERT; + return; + case 'i': + lMode = INSERT; + return; + case 'D': + delete_to_end(); + return; + case 'd': + delete_something(); + return; + case 'c': + delete_something(); + lMode = INSERT; + return; + case 'x': + ldelete(); + return; + case ' ': + case 'l': + if (curPos < startOfLine+lineLen-1) { + putchar(*curPos); + curPos++; + } + return; + case '\b': + case 'h': + if (curPos > startOfLine) { + putchar('\b'); + curPos--; + } + return; + case 'r': + lMode = EDIT1; + return; + case 'R': + lMode = EDIT; + return; + } + + /* The remaining commands should only be processed if we are editing + * a command line. For editing a line in a file, the commands that + * relate to command line history are not applicable and should be + * blocked. + */ + if (type == EDITCMDLINE) { + switch(curChar) { + case '/': + putchar('/'); + historysearch(); + return; + case '+': + case 'j': + shownext(); + return; + case '-': + case 'k': + showprev(); + return; + } + } + + /* Beep to indicate an error. */ + putchar(0x07); +} + +static void +linsert() +{ + char string[CMDLINESIZE]; + + if (curChar == BACKSPACE) { + linsertbs(); + return; + } + if (!isprint(curChar)) + return; + putchar(curChar); + putstr(curPos); + backup((int)strlen(curPos)); + strncpy(string,curPos,CMDLINESIZE-1); + *curPos++ = curChar; + strcpy(curPos,string); + lineLen++; +} + +/* linsertbs(): + * Handle the backspace when in 'INSERT' mode. + */ + +static void +linsertbs() +{ + char *eol, *now; + int cnt; + + if (curPos == startOfLine) + return; + backup(1); + curPos--; + cnt = 0; + eol = startOfLine + lineLen - 1; + now = curPos; + while(curPos <= eol) { + *curPos = *(curPos+1); + curPos++; + cnt++; + } + putbytes(now,cnt-1); + putchar(' '); + backup((int)cnt); + curPos = now; + lineLen--; +} + +static void +delete_something() +{ + char *eol, *now, C, *new; + int cnt; + + C = getchar(); + if (C == 'w') { /* word */ + now = curPos; + eol = startOfLine + lineLen -1; + while (curPos <= eol) { + if (*curPos == ' ') + break; + curPos++; + } + if (curPos < eol) { + new = curPos; + strcpy(now,new); + cnt = strlen(now); + putbytes(now,cnt); + curPos = now + cnt; + while(curPos <= eol) { + putchar(' '); + curPos++; + cnt++; + } + backup(cnt); + } + else { + curPos = now; + delete_to_end(); + return; + } + curPos = now; + lineLen = strlen(startOfLine); + } + else if (C == 'f') { /* find */ + C = getchar(); + now = curPos; + eol = startOfLine + lineLen -1; + while (curPos <= eol) { + if (*curPos == C) + break; + curPos++; + } + if (curPos < eol) { + new = curPos+1; + strcpy(now,new); + cnt = strlen(now); + putbytes(now,cnt); + curPos = now + cnt; + while(curPos <= eol) { + putchar(' '); + curPos++; + cnt++; + } + backup(cnt); + } + else { + curPos = now; + delete_to_end(); + return; + } + curPos = now; + lineLen = strlen(startOfLine); + } +} + +static void +delete_to_end() +{ + char *eol, *now, *sol; + + eol = startOfLine + lineLen; + now = curPos; + if (curPos == eol) + return; + while(curPos < eol) { + putchar(' '); + curPos++; + } + if (now == startOfLine) + sol = now+1; + else + sol = now; + while(curPos >= sol) { + putchar('\b'); + curPos--; + } + lineLen = now - startOfLine; + if (lineLen == 0) { + curPos = startOfLine; + *curPos = 0; + } + else + *(curPos+1) = '\0'; +} + +static void +ldelete() +{ + char *eol, *now; + int cnt; + + if (lineLen == 0) + return; + cnt = 0; + eol = startOfLine + lineLen - 1; + now = curPos; + if (curPos != eol) { + while(curPos <= eol) { + *curPos = *(curPos+1); + curPos++; + cnt++; + } + putbytes(now,cnt-1); + putchar(' '); + backup((int)cnt); + } + else { + putstr(" \b\b"); + *eol = '\0'; + now--; + } + curPos = now; + lineLen--; + if (lineLen == 0) + curPos = startOfLine; +} + +/* showdone(): + * Used as common completion code for the showprev() and + * shownext() functions below. + */ +static void +showdone(int idx) +{ + if (idx == HMAX) { + printf("History buffer empty.\007\n"); + lMode = NEITHER; + return; + } + + backup((int)(curPos - startOfLine)); + lineLen = strlen(cmdhistory[shwidx]); + putbytes(cmdhistory[shwidx],lineLen); + lerase((int)(lastsize-lineLen)); + backup((int)(lineLen)); + strcpy(startOfLine,cmdhistory[shwidx]); + curPos = startOfLine; + lastsize = lineLen; +} + +/* showprev() & shownext(): + * Show previous or next command in history list based on + * the current position in the list being established by + * the shwidx variable. + */ +static void +showprev() +{ + int i; + + if (shwidx == 0) + shwidx = HMAX-1; + else + shwidx--; + + for(i=0;i<HMAX;i++) { + if (*cmdhistory[shwidx]) + break; + if (shwidx == 0) + shwidx = HMAX-1; + else + shwidx--; + } + showdone(i); +} + + +static void +shownext() +{ + int i; + + if (shwidx == HMAX-1) + shwidx = 0; + else + shwidx++; + + for(i=0;i<HMAX;i++) { + if (*cmdhistory[shwidx]) + break; + if (shwidx == HMAX) + shwidx = 0; + else + shwidx++; + } + showdone(i); +} + +static void +backup(count) +int count; +{ + char string[CMDLINESIZE]; + int i; + + if (count <= 0) + return; + *string = '\0'; + for(i=0;i<count;i++) + strcat(string,"\b"); + putbytes(string,count); +} + +static void +lerase(int count) +{ + char string[CMDLINESIZE]; + int i; + + if (count <= 0) + return; + *string = '\0'; + for(i=0;i<count;i++) + strcat(string," "); + for(i=0;i<count;i++) + strcat(string,"\b"); + putbytes(string,count*2); +} + +static void +gotoend() +{ + char string[CMDLINESIZE], *eol; + int i; + + eol = startOfLine + lineLen -1; + for (i=0;i<CMDLINESIZE-1;i++) { + if (curPos == eol) + break; + string[i] = *curPos++; + } + if (i) + putbytes(string,i); +} + +static void +gotobegin() +{ + char string[CMDLINESIZE]; + int i; + + i = 0; + while(curPos != startOfLine) { + string[i++] = '\b'; + curPos--; + } + putbytes(string,i); +} + +/* History(): + * Command used at the CLI to allow the user to dump the content + * of the history buffer. + */ +char * HistoryHelp[] = { + "Display command history", + "", + 0, +}; + +int +History(int argc,char *argv[]) +{ + int i; + + for(i=stridx;i<HMAX;i++) { + if (cmdhistory[i][0]) + printf("%s\n",cmdhistory[i]); + } + if (stridx) { + for(i=0;i<stridx;i++) { + if (cmdhistory[i][0]) + printf("%s\n",cmdhistory[i]); + } + } + return(CMD_SUCCESS); +} + +/* historyinit(): + * Initialize the command history... + */ +void +historyinit() +{ + int i; + + shwidx = stridx = 0; + for (i=0;i<HMAX;i++) + cmdhistory[i][0] = 0; +} + +/* historylog(): + * This function is called by the CLI retrieval code to store away + * the command in the CLI history list, a circular queue + * (size HMAX) of most recent commands. + */ +void +historylog(char *cmdline) +{ + int idx; + + if (strlen(cmdline) >= CMDLINESIZE) + return; + + if (stridx == 0) + idx = HMAX-1; + else + idx = stridx -1; + + /* don't store if this command is same as last command */ + if (strcmp(cmdhistory[idx],cmdline) == 0) + return; + + if (stridx == HMAX) + stridx = 0; + + strcpy(cmdhistory[stridx++],cmdline); +} + + +static void +historysearch(void) +{ + static char string[100]; + char *s, *ptr, *last, C; + int size, len, count; + + lerase((int)lastsize); + s = string; + size = 0; + while(1) { + C = getchar(); + if (C == '\b') { + if (size == 0) + continue; + putstr("\b \b"); + s--; + size--; + continue; + } + if ((C == '\r') || (C == '\n')) + break; + putchar(C); + size++; + *s++ = C; + } + backup((int)(size+1)); + if (size != 0) + *s = '\0'; + else + size = strlen(string); + + count = 0; + + while(1) { + ptr = cmdhistory[srchidx]; + len = strlen(ptr); + last = ptr + len - size + 1; + while(ptr < last) { + if (strncmp(ptr,string,size) == 0) + goto gotmatch; + ptr++; + } + if (srchidx == 0) + srchidx = HMAX-1; + else + srchidx--; + if (++count == HMAX) { + backup((int)(curPos - startOfLine)); + lineLen = 0; + lerase((int)(size+1)); + backup((int)(lineLen)); + *startOfLine = '\0'; + curPos = startOfLine; + lastsize = lineLen; + return; + } + } +gotmatch: + backup((int)(curPos - startOfLine)); + lineLen = strlen(cmdhistory[srchidx]); + putbytes(cmdhistory[srchidx],lineLen); + lerase((int)(lastsize-lineLen)); + backup((int)(lineLen)); + strcpy(startOfLine,cmdhistory[srchidx]); + curPos = startOfLine; + lastsize = lineLen; + if (srchidx == 0) + srchidx = HMAX-1; + else + srchidx--; + return; +} + +#endif + diff --git a/main/common/ledit_vt100.c b/main/common/ledit_vt100.c new file mode 100644 index 0000000..0f5c50e --- /dev/null +++ b/main/common/ledit_vt100.c @@ -0,0 +1,462 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * ledit_vt.c: + * + * This is an alternative to lineedit.c. For those unfamiliar with the + * KSH VI-like editing, this is certainly a more intuitive mechanism + * for CLI edit. It uses the VT100 terminal arrow keys for basic + * line and history traversal... + * + * - UP/DOWN move through the CLI history. + * - RIGHT/LEFT move through the current line. + * - DEL deletes character that cursor is on top of. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#if INCLUDE_LINEEDIT +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" +#include "cli.h" + +#define GOT_NUTTIN 0 +#define GOT_ESCAPE 1 +#define GOT_BRACKET 2 + +#define HMAX 16 +#define ESC 0x1B +#define CTLC 0x03 +#define BACKSPACE 0x08 + +#define OPEN_BRACKET '[' +#define VT100_DEL 0x7f +#define VT100_UP 'A' +#define VT100_DOWN 'B' +#define VT100_RIGHT 'C' +#define VT100_LEFT 'D' + +#define EDITFILELINE 1 +#define EDITCMDLINE 2 + +static int stridx; /* store index */ +static int shwidx; /* show index */ +static int srchidx; /* search index */ +static int lastsize; /* size of last command */ +static char curChar; /* latest input character */ +static char *curPos; /* current position on command line */ +static char *startOfLine; /* start of command line */ +static int lineLen; /* length of line */ +static char cmdhistory[HMAX+1][CMDLINESIZE];/* array for command history */ + +static void shownext(void), showprev(void), ldelete(void), backspace(void); +static void newchar(char c); +static void backup(int count); + +/* lineeditor(): + * This is a simpler version of lineeditor() (as found in lineedit.c). + * It does not have the capability of the vi-like version; however, for + * those not familiar with ksh, this one is probably a lot more intuitive. + * + * The line is modified in place so, if successful, the function + * returns the same pointer but with its contents modified based + * on the editor commands executed. + * If failure, the function returns (char *)0. + */ +static char * +lineeditor(char *line_to_edit,int type) +{ + int state; + + if (type == EDITCMDLINE) { + if (getchar() != OPEN_BRACKET) { + putchar('\n'); + *line_to_edit = 0; + return((char *)0); + } + } + + startOfLine = line_to_edit; + curPos = line_to_edit; + while(*curPos != ESC) + curPos++; + + *curPos = 0; /* Remove the escape character from the line */ + lineLen = (ulong)curPos - (ulong)startOfLine; + if (lineLen > 0) { + curPos--; + putstr(" \b\b"); + } + else + putstr(" \b"); + + state = GOT_BRACKET; + lastsize = 0; + shwidx = stridx; + srchidx = stridx; + while(1) { + curChar = getchar(); + switch(curChar) { + case CTLC: + putchar('\n'); + *line_to_edit = 0; + return((char *)0); + case VT100_UP: + if (state == GOT_BRACKET) { + if (type == EDITCMDLINE) + showprev(); + state = GOT_NUTTIN; + } + else { + newchar(curChar); + } + break; + case VT100_DOWN: + if (state == GOT_BRACKET) { + if (type == EDITCMDLINE) + shownext(); + state = GOT_NUTTIN; + } + else { + newchar(curChar); + } + break; + case VT100_RIGHT: + if (state == GOT_BRACKET) { + if (curPos < startOfLine+lineLen) { + putchar(*curPos); + curPos++; + } + state = GOT_NUTTIN; + } + else { + newchar(curChar); + } + break; + case VT100_LEFT: + if (state == GOT_BRACKET) { + if (curPos > startOfLine) { + putchar('\b'); + curPos--; + } + state = GOT_NUTTIN; + } + else { + newchar(curChar); + } + break; + case OPEN_BRACKET: + if (state == GOT_ESCAPE) { + state = GOT_BRACKET; + } + else { + newchar(curChar); + } + break; + case ESC: + state = GOT_ESCAPE; + break; + case VT100_DEL: + if (curPos != (startOfLine + lineLen)) + ldelete(); + break; + case '\b': + if (curPos > startOfLine) + backspace(); + break; + case '\n': + case '\r': + putchar('\n'); + if (lineLen == 0) + return((char *)0); + *(char *)(startOfLine + lineLen) = '\0'; + return(startOfLine); + default: + newchar(curChar); + break; + } + } + return((char *)0); +} + +/* line_edit() & file_line_edit(): + * These two functions are simply front-ends to the lineeditor() + * function. The line_edit() function is called by the command line + * interface and file_line_edit() is called by the flash file editor + * to provide a convenient single line editor when modifying a file. + */ + +char * +line_edit(char *line_to_edit) +{ + return(lineeditor(line_to_edit,EDITCMDLINE)); +} + +char * +file_line_edit(char *line_to_edit) +{ + return(lineeditor(line_to_edit,EDITFILELINE)); +} + +static void +ldelete(void) +{ + char *eol, *now; + int cnt; + + if (lineLen == 0) + return; + cnt = 0; + eol = startOfLine + lineLen - 1; + now = curPos; +#if 0 + if (curPos != eol) { + while(curPos <= eol) { + *curPos = *(curPos+1); + curPos++; + cnt++; + } + putbytes(now,cnt-1); + putchar(' '); + backup((int)cnt); + } + else { + putstr(" \b\b"); + *eol = '\0'; + now--; + } +#else + while(curPos <= eol) { + *curPos = *(curPos+1); + curPos++; + cnt++; + } + putbytes(now,cnt-1); + putchar(' '); + backup((int)cnt); +#endif + curPos = now; + lineLen--; + if (lineLen == 0) + curPos = startOfLine; +} + +static void +backup(int count) +{ + char string[CMDLINESIZE]; + int i; + + if (count <= 0) + return; + *string = '\0'; + for(i=0;i<count;i++) + strcat(string,"\b"); + putbytes(string,count); +} + +static void +backspace(void) +{ + curPos--; + putchar('\b'); + ldelete(); +} + +static void +newchar(char c) +{ + char string[CMDLINESIZE]; + + if (curPos == startOfLine + lineLen) { + putchar(c); + *curPos++ = c; + lineLen++; + } + else { + if (!isprint(c)) + return; + putchar(c); + putstr(curPos); + backup((int)strlen(curPos)); + strncpy(string,curPos,CMDLINESIZE-1); + *curPos++ = c; + strcpy(curPos,string); + lineLen++; + } +} + +static void +lerase(int count) +{ + char string[CMDLINESIZE]; + int i; + + if (count <= 0) + return; + *string = '\0'; + for(i=0;i<count;i++) + strcat(string," "); + for(i=0;i<count;i++) + strcat(string,"\b"); + putbytes(string,count*2); +} + +/* showdone(): + * Used as common completion code for the showprev() and + * shownext() functions below. + */ +static void +showdone(int idx) +{ + if (idx == HMAX) { + printf("History buffer empty.\007\n"); + return; + } + + backup((int)(curPos - startOfLine)); + lineLen = strlen(cmdhistory[shwidx]); + putbytes(cmdhistory[shwidx],lineLen); + lerase((int)(lastsize-lineLen)); + strcpy(startOfLine,cmdhistory[shwidx]); + curPos = startOfLine + lineLen; + lastsize = lineLen; +} + +/* showprev() & shownext(): + * Show previous or next command in history list based on + * the current position in the list being established by + * the shwidx variable. + */ +static void +showprev(void) +{ + int i; + + if (shwidx == 0) + shwidx = HMAX-1; + else + shwidx--; + + for(i=0;i<HMAX;i++) { + if (*cmdhistory[shwidx]) + break; + if (shwidx == 0) + shwidx = HMAX-1; + else + shwidx--; + } + showdone(i); +} + +static void +shownext(void) +{ + int i; + + if (shwidx == HMAX-1) + shwidx = 0; + else + shwidx++; + + for(i=0;i<HMAX;i++) { + if (*cmdhistory[shwidx]) + break; + if (shwidx == HMAX) + shwidx = 0; + else + shwidx++; + } + showdone(i); +} + +/* History(): + * Command used at the CLI to allow the user to dump the content + * of the history buffer. + */ +char * HistoryHelp[] = { + "Display command history", + "", + 0, +}; + +int +History(int argc,char *argv[]) +{ + int i; + + for(i=stridx;i<HMAX;i++) { + if (cmdhistory[i][0]) + printf("%s\n",cmdhistory[i]); + } + if (stridx) { + for(i=0;i<stridx;i++) { + if (cmdhistory[i][0]) + printf("%s\n",cmdhistory[i]); + } + } + return(CMD_SUCCESS); +} + +/* historyinit(): + * Initialize the command history... + */ +void +historyinit() +{ + int i; + + shwidx = stridx = 0; + for (i=0;i<HMAX;i++) + cmdhistory[i][0] = 0; +} + +/* historylog(): + * This function is called by the CLI retrieval code to store away + * the command in the CLI history list, a circular queue + * (size HMAX) of most recent commands. + */ +void +historylog(char *cmdline) +{ + int idx; + + if (strlen(cmdline) >= CMDLINESIZE) + return; + + if (stridx == 0) + idx = HMAX-1; + else + idx = stridx -1; + + /* don't store if this command is same as last command */ + if (strcmp(cmdhistory[idx],cmdline) == 0) + return; + + if (stridx == HMAX) + stridx = 0; + + strcpy(cmdhistory[stridx++],cmdline); +} + +#endif diff --git a/main/common/malloc.c b/main/common/malloc.c new file mode 100644 index 0000000..8050e05 --- /dev/null +++ b/main/common/malloc.c @@ -0,0 +1,763 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * malloc(): + * + * A simple memory allocator useful for embedded systems to provide + * some level of debug, plus the ability to increase heap space into + * additional memory that is not contiguous with the intial statically + * allocated array of memory. The reason for supporting the ability to + * allocate from 2 distinct blocks of memory is so that the monitor can + * be built with some reasonable amount of heap space allocated to it; then + * if the application is going to also use this malloc, it can do so + * by simply extending the heap. The monitor would not have to be + * specifically built to support the large heap allocation. + * + * The allocator data structures are part of the memory space used for + * the allocation. To test for memory overruns (using memory after the + * end of the allocated space) or underruns (using memory prior to the + * beginning of the allocated space), the data structure starts and ends + * with a fixed tag that is always checked upon entry into malloc() + * or free(). + * When the memory is freed, the next and previous block is checked to + * determine if this newly freed block can be combined with a neighboring + * block. This provides some level of defragmentation. Note, at + * this point, that the blocks are only combined if they are found to be + * contiguous. This correctly implies that neighboring free blocks need + * not be within contiguous memory space. + * A function called GetMemory() must be provided as the underlying resource + * of the memory used by the allocator. + * + * NOTE THAT THERE IS ABSOLUTELY NO CONCERN FOR SPEED IN THIS MEMORY + * ALLOCATOR, IT IS SLOW! Every call to malloc/free does a sanity check + * on all allocation structures, so it is fairly good at detecting illegal + * use of the allocated memory. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_MALLOC +#include "genlib.h" +#include "stddefs.h" +#include "cli.h" + +#define FNAMESIZE 32 + +#define PRETAG 0xDEAD +#define POSTTAG 0xBEEF +#define MHDRSIZE sizeof(struct mhdr) + +extern char *GetMemory(int); +extern int GetMemoryLeft(void); +extern int extendHeap(char *,int); +extern void unExtendHeap(void); +extern char *getExtHeapBase(void); + + +/* mhdr: + The control structure used by the memory allocator. +*/ +struct mhdr { + ushort pretag; /* Fixed value used as an overrun sanity + * check for the previous memory block. + */ + int size; /* Size of useable memory block. Size is + * positive if block is free and negative if + * block is not free. + */ + struct mhdr *next; /* Points to next mhdr structure (not + * necessarily in contiguous memory space). + */ + struct mhdr *prev; /* Points to previous mhdr structure (not + * necessarily in contiguous memory space). + */ + ushort posttag; /* Fixed value used as an underrun sanity + * check for this memory block. + */ +#ifdef MALLOC_DEBUG + char fname[FNAMESIZE]; + int fline; +#endif +}; + +/* mcalls, fcalls & mfails: + * Used to keep track of malloc and free calls. Plus keep track + * of the number of times malloc is called, but it returns 0. + */ +static int mcalls, rcalls, fcalls, mfails; + +/* mtot, ftot & highwater: + * Keep track of total amount of memory allocated. + */ +static int mtot, ftot, highwater; + +/* mquiet: + * If set (by heap -q), then the MALLOC ERROR messages are not + * printed at runtime when an error is detected. + */ +static char mquiet; + +/* mtrace: + * If set (by heap -V), then each call to malloc or free will include + * a printed message. + */ +static char mtrace; + +/* heapbase: + * Initially zero, this pointer is set to the base of the heap on + * the first call to malloc(). + */ +static struct mhdr *heapbase; + +static void +heapinit(void) +{ + mcalls = rcalls = fcalls = mfails = 0; + mtot = ftot = highwater = 0; + heapbase = (struct mhdr *)GetMemory(ALLOCSIZE); + heapbase->pretag = PRETAG; + heapbase->posttag = POSTTAG; + heapbase->size = ALLOCSIZE - MHDRSIZE; + if (heapbase->size < 0) + printf("heapinit(): ALLOCSIZE too small!\n"); + heapbase->next = (struct mhdr *)0; + heapbase->prev = (struct mhdr *)0; +} + +/* heapcheck(): + * Called with an mhdr pointer (or NULL). This function just steps through + * the heap control structures to make sure there is some level of sanity. + * If the incoming mhdr pointer is non-zero, then it will also verify that + * the pointer is a valid control pointer in the heap. + */ +int +heapcheck(struct mhdr *mp,char *msg) +{ + int i, mpok; + register struct mhdr *mptr; + + mpok = 0; + if (!heapbase) + heapinit(); + + mptr = heapbase; + for(i=0;mptr;i++,mptr=mptr->next) { + if (mp == mptr) + mpok = 1; + if ((mptr->pretag != PRETAG) || (mptr->posttag != POSTTAG)) { + if (!mquiet) { + printf("\007MALLOC ERROR: heap corrupted at entry %d",i); + if (msg) + printf(" (%s)",msg); + printf("\n"); + } + return(-1); + } + } + if ((mp) && (!mpok)) { + if (!mquiet) { + printf("\007MALLOC ERROR: 0x%lx (mem @ 0x%lx) invalid heap pointer", + (ulong)mp,(ulong)(mp+1)); + if (msg) + printf(" (%s)",msg); + printf("\n"); + } + return(-1); + } + return(0); +} + +static char * +_malloc(int size) +{ + register struct mhdr *mptr, *mptr1; + + if (mtrace) + printf("malloc(%d) = ",size); + + if (size <= 0) { + if (mtrace) + printf("0\n"); + return(0); + } + + /* Start by checking sanity of heap. */ + if (heapcheck(0,0) < 0) { + if (mtrace) + printf("00\n"); + return((char *)0); + } + + /* Keep track of number of calls to malloc for debug. */ + mcalls++; + + /* Make size divisible by 4: */ + if (size & 3) { + size += 4; + size &= 0xfffffffc; + } + + mptr = (struct mhdr *)heapbase; + while(1) { + /* If request size is equal to the free block size or + * if the free block size is only slightly larger than the + * request size, then just use that free block as is. + * If the request size is at least "MHDRSIZE * 2" + * bytes smaller than free block size, then break + * that block up into 2 smaller chunks with one of the chunks + * being the size of the request and the size of the other chunk + * being whatever is left over. + */ + if (mptr->size >= size) { + if (mptr->size <= (int)(size + (MHDRSIZE * 2))) { + mtot += mptr->size; + if ((mtot - ftot) > highwater) + highwater = (mtot - ftot); + mptr->size = -mptr->size; + } + else { + mptr1 = (struct mhdr *)((char *)(mptr+1) + size); + mptr1->pretag = PRETAG; + mptr1->posttag = POSTTAG; + mptr1->next = mptr->next; + mptr->next = mptr1; + if (mptr1->next) + mptr1->next->prev = mptr1; + mptr1->prev = mptr; + mptr1->size = (mptr->size - size) - MHDRSIZE; + mptr->size = -size; + mtot += size; + if ((mtot - ftot) > highwater) + highwater = (mtot - ftot); + } + if (mtrace) + printf("0x%lx\n",(long)(mptr+1)); + return((char *)(mptr+1)); + } + if (mptr->next == (struct mhdr *)0) { + struct mhdr *moremem; + int getsize; + + getsize = size + MHDRSIZE; + moremem = (struct mhdr *)GetMemory(getsize); + if (!moremem) { + mfails++; + if (!mquiet) + printf("\007MALLOC ERROR: no more memory\n"); + if (mtrace) + printf("000\n"); + return((char *)0); + } + mptr->next = moremem; + mptr->next->prev = mptr; + mptr = mptr->next; + mptr->next = (struct mhdr *)0; + mptr->pretag = PRETAG; + mptr->posttag = POSTTAG; + mptr->size = getsize - MHDRSIZE; + } + else + mptr = mptr->next; + } +} + +#ifdef MALLOC_DEBUG +#undef malloc + +char * +malloc(int size, char *fname, int fline) +{ + char *cp; + struct mhdr *mptr; + + cp = _malloc(size); + if (cp) { + mptr = (struct mhdr *)cp; + mptr--; + strncpy(mptr->fname,fname,FNAMESIZE-1); + mptr->fline = fline; + mptr->fname[FNAMESIZE-1] = 0; + mptr->fline = fline; + } + return(cp); +} + +#else +char * +malloc(int size) +{ + return(_malloc(size)); +} +#endif + +void +free(void *vp) +{ + char *cp = vp; + struct mhdr *mptr; + + if (mtrace) + printf("free(0x%lx)\n",(long)cp); + + /* Keep track of number of calls to free for debug. */ + fcalls++; + + mptr = (struct mhdr *)cp - 1; + + /* Start by checking sanity of heap and make sure that the incoming + * pointer corresponds to a valid entry in the heap. + */ + if (heapcheck(mptr,0) < 0) + return; + + /* The first thing to do to free the block is to make the size + * positive. + */ + mptr->size = abs(mptr->size); + + /* Keep track of how much memory is freed for debug. */ + ftot += mptr->size; + + /* To defragment the memory, see if previous and/or + * next block is free; if yes, then join them into one larger + * block. Note that the blocks will only be joined if they are in + * contiguous memory space. + */ + if (mptr->next) { + if ((mptr->next->size > 0) && + (mptr->next == (struct mhdr *) + ((char *)mptr + mptr->size + MHDRSIZE))) { + mptr->size += mptr->next->size + MHDRSIZE; + mptr->next = mptr->next->next; + if (mptr->next) + mptr->next->prev = mptr; + } + } + if (mptr->prev) { + if ((mptr->prev->size > 0) && + (mptr->prev == (struct mhdr *) + ((char *)mptr-mptr->prev->size - MHDRSIZE))) { + if (mptr->next) + mptr->next->prev = mptr->prev; + mptr->prev->next = mptr->next; + mptr->prev->size += mptr->size + MHDRSIZE; + } + } +} + +/* calloc(): + * Allocate space for an array of nelem elements of size elsize. + * Initialize the space to zero. + */ +static char * +_calloc(int nelem, int elsize) +{ + register char *cp, *end; + char *base; + int size; + + size = nelem * elsize; + base = _malloc(size); + if (base) { + cp = base; + end = base+size; + while(cp<end) + *cp++ = 0; + } + return(base); +} + +#ifdef MALLOC_DEBUG +char * +calloc(int nelem, int elsize, char *fname, int fline) +{ + char *cp; + struct mhdr *mptr; + + cp = _calloc(nelem, elsize); + if (cp) { + mptr = (struct mhdr *)cp; + mptr--; + strncpy(mptr->fname,fname,FNAMESIZE-1); + mptr->fline = fline; + mptr->fname[FNAMESIZE-1] = 0; + mptr->fline = fline; + } + return(cp); +} + +#else + +char * +calloc(int nelem, int elsize) +{ + return(_calloc(nelem,elsize)); +} +#endif + + +static char * +_realloc(char *cp,int newsize) +{ + char *new; + int asize, delta; + struct mhdr *mptr, tmphdr; + + rcalls++; + + /* If incoming pointer is NULL, then do a regular malloc. */ + if (!cp) + return(_malloc(newsize)); + + /* If newsize is zero and pointer is not null, then do a free. */ + if (!newsize) { + free(cp); + return((char *)0); + } + + /* Set the mhdr pointer to the header attached to the incoming + * char pointer. We assume here that the incoming pointer is the + * base address of the block of memory that is being reallocated. + */ + mptr = (struct mhdr *)cp - 1; + + /* Start by checking sanity of heap and make sure that the incoming + * pointer corresponds to a valid entry in the heap. + */ + if (heapcheck(mptr,0) < 0) + return((char *)0); + + /* Recall that mptr->size is negative since the block is not free, so + * use the absolute value of mptr->size... + */ + asize = abs(mptr->size); + + /* Make requested size divisible by 4: + */ + if (newsize & 3) { + newsize += 4; + newsize &= 0xfffffffc; + } + + /* If newsize is less than or equal to current size, just return with + * the same pointer. At some point, this should be improved so that + * the memory made made available by this reallocation is put back in + * the pool. + */ + if (newsize <= asize) + return(cp); + + /* Now we do the actual reallocation... + * If there is a fragment after this one (next != NULL) AND it is + * available (size > 0) AND the combined size of the next fragment + * along with the current fragment exceeds the request, then we can + * reallocate quickly. + * Otherwise, we have to just malloc a whole new block and copy the + * old buffer to the new larger space. + */ + if ((mptr->next) && (mptr->next->size > 0) && + ((asize + mptr->next->size + MHDRSIZE) > newsize)) { + + /* At this point we know we have the space to reallocate without + * the malloc/free step. Now we need to add the necessary space + * to the current fragment, and take that much away from the next + * fragment... + */ + delta = newsize - asize; + /* next line used to be: tmphdr = *mptr->next... */ + memcpy((char *)&tmphdr,(char *)mptr->next, sizeof(struct mhdr)); + mptr->size = -newsize; + mptr->next = (struct mhdr *)(delta + (int)(mptr->next)); + mptr->next->size = (abs(tmphdr.size) - delta); + mptr->next->pretag = PRETAG; + mptr->next->posttag = POSTTAG; + mptr->next->next = tmphdr.next; + mptr->next->prev = tmphdr.prev; + + /* Keep track of totals and highwater: + */ + mtot += (newsize - asize); + if ((mtot - ftot) > highwater) + highwater = (mtot - ftot); + return(cp); + } + + /* If the next fragment is not large enough, then malloc new space, + * copy the existing data to that block, free the old space and return + * a pointer to the new block. + */ + new = _malloc(newsize); + if (!new) + return((char *)0); + + memcpy(new,cp,asize); + free(cp); + return(new); +} + +#ifdef MALLOC_DEBUG +#undef realloc +char * +realloc(char *buf, int newsize, char *fname, int fline) +{ + char *cp; + struct mhdr *mptr; + + cp = _realloc(buf, newsize); + if (cp) { + mptr = (struct mhdr *)cp; + mptr--; + strncpy(mptr->fname,fname,FNAMESIZE-1); + mptr->fline = fline; + mptr->fname[FNAMESIZE-1] = 0; + mptr->fline = fline; + } + return(cp); +} + +#else + +char * +realloc(char *buf, int newsize) +{ + return(_realloc(buf,newsize)); +} +#endif + + +void +heapdump(int verbose) +{ + register struct mhdr *mptr; + char freenow; + int i, alloctot, freetot, size; + + heapcheck(0,0); + + mptr = heapbase; + i=0; + freetot = 0; + alloctot = 0; + if (verbose) + printf(" addr size free? mptr nxt prv ascii@addr\n"); + else + printf("Heap summary:\n"); + for(i=0;mptr;i++) { + if (mptr->size < 0) { + freenow = 'n'; + size = -mptr->size; + alloctot += size; + } + else { + freenow = 'y'; + size = mptr->size; + freetot += size; + } + if (verbose) { + printf("%3d: 0x%08lx %5d %c 0x%08lx 0x%08lx 0x%08lx ", + i,(ulong)(mptr+1),size,freenow,(ulong)mptr, + (ulong)(mptr->next),(ulong)(mptr->prev)); + prascii((unsigned char *)(mptr+1),size > 16 ? 16 : size); + putchar('\n'); +#ifdef MALLOC_DEBUG + if (freenow == 'n') + printf(" %s %d\n",mptr->fname,mptr->fline); +#endif + } + mptr = mptr->next; + } + if (verbose) + putchar('\n'); + printf(" Malloc/realloc/free calls: %d/%d/%d\n",mcalls,rcalls,fcalls); + printf(" Malloc/free totals: %d/%d\n",mtot,ftot); + printf(" High-water level: %d\n",highwater); + printf(" Malloc failures: %d\n",mfails); + printf(" Bytes overhead: %d\n",i * MHDRSIZE); + printf(" Bytes currently allocated: %d\n",alloctot); + printf(" Bytes free on current heap: %d\n",freetot); + printf(" Bytes left in allocation pool: %d\n",GetMemoryLeft()); +} + +/* releaseExtendedHeap(): + * If memory has been allocated through the extended heap established + * by the heap -x{start,size} command, this function will attempt + * to "undo" that. It can only be un-done if there is no currently active + * allocations in that range. + * + * This function is accessible by the application through monlib. + */ +int +releaseExtendedHeap(int verbose) +{ + int i; + struct mhdr *mptr, *extbase; + + extbase = (struct mhdr *)getExtHeapBase(); + if (!extbase) { + if (verbose) + printf("Heap extension not set\n"); + return(-1); + } + + heapcheck(0,0); + mptr = heapbase; + for(i=0;mptr;i++) { + if (mptr->next == extbase) { + if (mptr->next->next == (struct mhdr *)0) { + mptr->next = (struct mhdr *)0; + unExtendHeap(); + if (verbose) + printf("Heap extension cleared\n"); + return(0); + } + else if (verbose) + printf("Extended heap space is in use.\n"); + break; + } + mptr = mptr->next; + } + if (!mptr) { /* Heap was extended, but not used. */ + unExtendHeap(); /* Remove the extension. */ + if (verbose) + printf("Heap extension cleared.\n"); + } + return(0); +} + + +char *HeapHelp[] = { + "Display heap statistics.", + "-[cf:m:qtvX:x]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -c clear high-water level and malloc/free totals", + " -f{ptr} free block @ 'ptr'", + " -m{size} malloc 'size' bytes", + " -q quiet runtime (don't print MALLOC ERROR msgs)", + " -v verbose (more detail)", + " -t toggle runtime malloc/free trace", + " -X{base,size}", + " extend heap by 'size' bytes starting at 'base'", + " -x clear heap extension", +#endif + 0 +}; + +int +Heap(int argc,char *argv[]) +{ + char *establish_extended_heap, buf[32]; + int verbose, release_extended_heap, showheap, opt; + + showheap = 1; + establish_extended_heap = (char *)0; + release_extended_heap = verbose = 0; + while((opt=getopt(argc,argv,"cf:m:qtvX:x")) != -1) { + switch(opt) { + case 'c': + mcalls = fcalls = 0; + mtot = ftot = highwater = 0; + showheap = 0; + break; + case 'f': + free((char *)strtoul(optarg,0,0)); + showheap = 0; + break; + case 'm': + shell_sprintf("MALLOC","0x%lx", + (ulong)_malloc(strtoul(optarg,0,0))); + if (verbose) + printf("%s\n",buf); + showheap = 0; + break; + case 'q': + showheap = 0; + mquiet = 1; + break; + case 't': + mtrace = ~mtrace; + printf("Runtime trace: %sabled\n", + mtrace ? "en" : "dis"); + return(CMD_SUCCESS); + case 'v': + verbose = 1; + break; + case 'X': + establish_extended_heap = optarg; + showheap = 0; + break; + case 'x': + release_extended_heap = 1; + showheap = 0; + break; + default: + return(CMD_PARAM_ERROR); + } + } + if (release_extended_heap) + releaseExtendedHeap(verbose); + + if (establish_extended_heap) { + int size, rc; + char *comma, *begin; + + comma = strchr(establish_extended_heap,','); + if (!comma) + return(CMD_PARAM_ERROR); + *comma = 0; + begin = (char *)strtoul(establish_extended_heap,0,0); + size = (int)strtoul(comma+1,0,0); + rc = extendHeap(begin,size); + if (rc == -1) { + printf("Extended heap already exists @ 0x%lx\n", + (ulong)getExtHeapBase()); + } + if (rc < 0) + return(CMD_FAILURE); + } + + if (!showheap) + return(CMD_SUCCESS); + + if (optind == argc) + heapdump(verbose); + + return(CMD_SUCCESS); +} +#else +char * +malloc(int size) +{ + return(0); +} + +void +free(char *buf) +{ +} + +char * +realloc(char *buf, int newsize, char *fname, int fline) +{ + return(0); +} + +#endif diff --git a/main/common/mallocdebug.h b/main/common/mallocdebug.h new file mode 100644 index 0000000..8ab8cf1 --- /dev/null +++ b/main/common/mallocdebug.h @@ -0,0 +1,47 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * FN: + * + * This file should be included in config.h if the monitor is + * to be built with malloc-debug enabled. The malloc-debug feature + * simply adds the filename and file line number to the mhdr structure. + * + * This makes it easier to find a memory leak because the location of + * the violating malloc call will be dumped by "heap -v". + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _MALLOCDEBUG_H_ +#define _MALLOCDEBUG_H_ + +#ifndef ASSEMBLY_ONLY + +#define MALLOC_DEBUG +extern char *malloc(int, char *, int); +extern char *realloc(char *, int, char *, int); + +#define malloc(a) malloc(a,__FILE__,__LINE__) +#define realloc(a,b) realloc(a,b,__FILE__,__LINE__) + +#endif /* ASSEMBLY_ONLY */ + +#endif diff --git a/main/common/memcmds.c b/main/common/memcmds.c new file mode 100644 index 0000000..4ea2b86 --- /dev/null +++ b/main/common/memcmds.c @@ -0,0 +1,1259 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * memcmds.c: + * + * This code allows the monitor to display, modify, search, copy, fill + * and test memory in a variety of different ways. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "genlib.h" +#include "stddefs.h" +#include <ctype.h> +#include "cli.h" + +/* With INCLUDE_MEMCMDS defined in config.h, all uMon commands in this + * file are automatically pulled into the build. If there is a need to + * be more selective, then set INCLUDE_MEMCMDS to zero in config.h and + * define only the INCLUDE_XX macros needed (shown below) to one in + * config.h. + */ +#if INCLUDE_MEMCMDS +#define INCLUDE_PM 1 +#define INCLUDE_DM 1 +#define INCLUDE_FM 1 +#define INCLUDE_CM 1 +#define INCLUDE_SM 1 +#define INCLUDE_MT 1 +#endif + +#if INCLUDE_PM + +/* Pm(): + * Put to memory. + * + * Arguments... + * arg1: address. + * arg2-argN: data to put beginning at specified address (max of 8). + * + * Options... + * -2 access as a short. + * -4 access as a long. + * -f fifo access (address does not increment). + * -s data is ascii string. + * -S data is ascii string and should be concatenated with the + * string that starts at the specified address. + */ + +char *PmHelp[] = { + "Put to Memory", + "-[24aefosSx] {addr} {val|string} [val] ...", +#if INCLUDE_VERBOSEHELP + "Options:", + " -2 short access", + " -4 long access", + " -a AND operation", + " -e endian swap", + " -f fifo mode", + " -o OR operation", + " -s strcpy", + " -S strcat", + " -x XOR operation", +#endif + 0, +}; + +#define PM_EQ_OPERATION 1 +#define PM_AND_OPERATION 2 +#define PM_OR_OPERATION 3 +#define PM_XOR_OPERATION 4 + +int +Pm(int argc,char *argv[]) +{ + ulong val4, add, base; + ushort val2; + uchar val1, c; + int opt, width, ascii, fifo, i, j, concatenate, endian_swap, pmop; + + pmop = PM_EQ_OPERATION; + width = 1; + ascii = fifo = 0; + concatenate = 0; + endian_swap = 0; + while((opt=getopt(argc,argv,"24aefosSx")) != -1) { + switch(opt) { + case '2': + width = 2; + break; + case '4': + width = 4; + break; + case 'a': + pmop = PM_AND_OPERATION; + break; + case 'e': + endian_swap = 1; + break; + case 'f': + fifo = 1; + break; + case 'o': + pmop = PM_OR_OPERATION; + break; + case 's': + ascii = 1; + break; + case 'S': + ascii = 1; + concatenate = 1; + break; + case 'x': + pmop = PM_XOR_OPERATION; + concatenate = 1; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc < (optind+2)) + return(CMD_PARAM_ERROR); + + add = strtoul(argv[optind],(char **)0,0); + + if (ascii) { + base = add; + if (concatenate) { /* If concatenate, skip to */ + while(*(uchar *)add) /* end of string, then start. */ + add++; + } + for(i=optind+1;i<argc;i++) { + j = 0; + while(argv[i][j]) { + c = argv[i][j++]; + if (c == '\\') { + c = argv[i][j++]; + if (c == 'n') + *(char *)add = '\n'; + else if (c == 'r') + *(char *)add = '\r'; + else if (c == 't') + *(char *)add = '\t'; + else { + *(char *)add = '\\'; + if (!fifo) + add++; + *(char *)add = c; + } + } + else { + *(char *)add = c; + } + if (!fifo) + add++; + } + } + *(uchar *)add = 0; + shell_sprintf("STRLEN","%d",add-base); + return(CMD_SUCCESS); + } + for(i=optind+1;i<argc;i++) { + switch(width) { + case 1: + val1 = (uchar)strtoul(argv[i],(char **)0,0); + switch (pmop) { + case PM_EQ_OPERATION: + *(uchar *)add = val1; + break; + case PM_AND_OPERATION: + *(uchar *)add &= val1; + break; + case PM_OR_OPERATION: + *(uchar *)add |= val1; + break; + case PM_XOR_OPERATION: + *(uchar *)add ^= val1; + break; + } + if (!fifo) add++; + break; + case 2: + val2 = (ushort)strtoul(argv[i],(char **)0,0); + switch (pmop) { + case PM_EQ_OPERATION: + *(ushort *)add = endian_swap ? swap2(val2) : val2; + break; + case PM_AND_OPERATION: + *(ushort *)add &= endian_swap ? swap2(val2) : val2; + break; + case PM_OR_OPERATION: + *(ushort *)add |= endian_swap ? swap2(val2) : val2; + break; + case PM_XOR_OPERATION: + *(ushort *)add ^= endian_swap ? swap2(val2) : val2; + break; + } + if (!fifo) add += 2; + break; + case 4: + val4 = (ulong)strtoul(argv[i],(char **)0,0); + switch (pmop) { + case PM_EQ_OPERATION: + *(ulong *)add = endian_swap ? swap4(val4) : val4; + break; + case PM_AND_OPERATION: + *(ulong *)add &= endian_swap ? swap4(val4) : val4; + break; + case PM_OR_OPERATION: + *(ulong *)add |= endian_swap ? swap4(val4) : val4; + break; + case PM_XOR_OPERATION: + *(ulong *)add ^= endian_swap ? swap4(val4) : val4; + break; + } + if (!fifo) add += 4; + break; + } + } + return(CMD_SUCCESS); +} +#endif + +#if INCLUDE_DM +/* Dm(): + * Display memory. + * + * Arguments... + * arg1: address to start display + * arg2: if present, specifies the number of units to be displayed. + * + * Options... + * -2 a unit is a short. + * -4 a unit is a long. + * -b print chars out as is (binary). + * -d display in decimal. + * -e endian-swap for short/long display. + * -f fifo-type access (address does not increment). + * -l# size of line to be printed. + * -m prompt user for more. + * -s print chars out as is (binary) and terminates at a null. + * -v {varname} assign last value displayed to shell var varname. + * + * Defaults... + * Display in hex, and unit type is byte. + */ + +char *DmHelp[] = { + "Display Memory", + "-[24bdefl:msv:] {addr} [byte-cnt]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -2 short access", + " -4 long access", + " -b binary", + " -d decimal", + " -e endian swap", + " -f fifo mode", + " -l# size of line (in bytes)", + " -m use 'more'", + " -s string", + " -v {var} load 'var' with element", +#endif + 0, +}; + +#define BD_NULL 0 +#define BD_RAWBINARY 1 +#define BD_ASCIISTRING 2 + +int +Dm(int argc,char *argv[]) +{ + ushort *sp; + uchar *cp, cbuf[128]; + ulong *lp, add, count_rqst; + char *varname, *prfmt, *vprfmt; + int i, count, width, opt, more, size, fifo; + int hex_display, bin_display, endian_swap, linesize, sol; + + linesize = 0; + width = 1; + more = fifo = 0; + bin_display = BD_NULL; + hex_display = 1; + endian_swap = 0; + varname = (char *)0; + while((opt=getopt(argc,argv,"24bdefl:msv:")) != -1) { + switch(opt) { + case '2': + width = 2; + break; + case '4': + width = 4; + break; + case 'b': + bin_display = BD_RAWBINARY; + break; + case 'd': + hex_display = 0; + break; + case 'e': + endian_swap = 1; + break; + case 'f': + fifo = 1; + break; + case 'l': + linesize = atoi(optarg); + break; + case 'm': + more = 1; + break; + case 'v': + varname = optarg; + break; + case 's': + bin_display = BD_ASCIISTRING; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc < (optind+1)) + return(CMD_PARAM_ERROR); + + add = strtoul(argv[optind],(char **)0,0); + if (hex_display) + vprfmt = "0x%x"; + else + vprfmt = "%d"; + + if (argc-(optind-1) == 3) { + count_rqst = strtoul(argv[optind+1],(char **)0,0); + count_rqst *= width; + } + else + count_rqst = 128; + + + if (bin_display != BD_NULL) { + cp = (uchar *)add; + if (bin_display == BD_ASCIISTRING) { + putstr((char *)cp); + if (varname) { + shell_sprintf(varname,vprfmt,cp+strlen((char *)cp)+1); + } + } + else { + for(i=0;i<count_rqst;i++) + putchar(*cp++); + } + putchar('\n'); + return(CMD_SUCCESS); + } + + sol = linesize == 0 ? 16 : linesize; + do { + count = count_rqst; + + if (width == 1) { + cp = (uchar *)add; + if (hex_display) + prfmt = "%02X "; + else + prfmt = "%3d "; + + if (varname) { + shell_sprintf(varname,vprfmt,*cp); + } + else { + while(count > 0) { + printf("%08lx: ",(ulong)cp); + if (count > sol) + size = sol; + else + size = count; + + for(i=0;i<sol;i++) { + if (i >= size) + putstr(" "); + else { + cbuf[i] = *cp; + printf(prfmt,cbuf[i]); + } + if ((linesize == 0) && (i == 7)) + putstr(" "); + if (!fifo) + cp++; + } + if ((hex_display) && (!fifo)) { + putstr(" "); + prascii(cbuf,size); + } + putchar('\n'); + count -= size; + if (!fifo) { + add += size; + cp = (uchar *)add; + } + } + } + } + else if (width == 2) { + sp = (ushort *)add; + if (hex_display) + prfmt = "%04X "; + else + prfmt = "%5d "; + + if (varname) { + shell_sprintf(varname,vprfmt,endian_swap ? swap2(*sp) : *sp); + } + else { + while(count>0) { + printf("%08lx: ",(ulong)sp); + if (count > sol) + size = sol; + else + size = count; + + for(i=0;i<size;i+=2) { + printf(prfmt,endian_swap ? swap2(*sp) : *sp); + if (!fifo) + sp++; + } + putchar('\n'); + count -= size; + if (!fifo) { + add += size; + sp = (ushort *)add; + } + } + } + } + else if (width == 4) { + lp = (ulong *)add; + if (hex_display) + prfmt = "%08X "; + else + prfmt = "%12d "; + + if (varname) { + shell_sprintf(varname,vprfmt,endian_swap ? swap4(*lp) : *lp); + } + else { + while(count>0) { + printf("%08lx: ",(ulong)lp); + if (count > sol) + size = sol; + else + size = count; + for(i=0;i<size;i+=4) { + printf(prfmt,endian_swap ? swap4(*lp) : *lp); + if (!fifo) + lp++; + } + putchar('\n'); + count -= size; + if (!fifo) { + add += size; + lp = (ulong *)add; + } + } + } + } + } while (more && More()); + return(CMD_SUCCESS); +} +#endif + + +#if INCLUDE_FM +/* Fm(): + * Fill memory with user-specified data. + * Syntax: + * fm [options] {start} {count | finish} {value} + */ + +char *FmHelp[] = { + "Fill Memory", + "-[24cinp] {start} {finish|byte-cnt} {value|pattern}", +#if INCLUDE_VERBOSEHELP + "Options:", + " -2 short access", + " -4 long access", + " -c arg2 is count (in bytes)", + " -i increment {value|pattern}", + " -n no verification", + " -p arg3 is a pattern", +#endif + 0, +}; + +int +Fm(int argc,char *argv[]) +{ + char *pp, *pattern; + ulong start, finish; + uchar *cptr, cdata; + ushort *wptr, wdata; + ulong *lptr, ldata, error_at; + int width, opt, arg2iscount, arg3ispattern, err, verify, increment; + + width = 1; + verify = 1; + increment = 0; + error_at = 0; + arg2iscount = 0; + arg3ispattern = 0; + pattern = pp = (char *)0; + while((opt=getopt(argc,argv,"24cinp")) != -1) { + switch(opt) { + case '2': + width = 2; + break; + case '4': + width = 4; + break; + case 'c': + arg2iscount = 1; + break; + case 'i': + increment = 1; + break; + case 'n': + verify = 0; + break; + case 'p': + arg3ispattern = 1; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + /* Three args required... + * If -p is specfied, then width can only be 1... + */ + if (argc != optind+3) + return(CMD_PARAM_ERROR); + + if ((arg3ispattern) && (width != 1)) { + printf("Note: -p uses byte-wide access (-%d ignored)\n",width); + width = 1; + } + + start = strtoul(argv[optind],(char **)0,0); + finish = strtoul(argv[optind+1],(char **)0,0); + if (arg3ispattern) { + pattern = pp = argv[optind+2]; + ldata = 0; + } + else + ldata = strtoul(argv[optind+2],0,0); + + if (arg2iscount) + finish = start + finish; + else if (start >= finish) { + printf("start > finish\n"); + return(CMD_PARAM_ERROR); + } + + err = 0; + switch (width) { + case 1: + cdata = (uchar) ldata; + for(cptr=(uchar *)start;cptr<(uchar *)finish;cptr++) { + if (arg3ispattern) { + if (*pp == 0) + pp = pattern; + cdata = (uchar)*pp++; + } + *cptr = cdata; + if (verify) { + if (*cptr != cdata) { + err = 1; + error_at = (ulong)cptr; + break; + } + } + cdata += increment; + } + break; + case 2: + wdata = (ushort) ldata; + for(wptr=(ushort *)start;wptr<(ushort *)finish;wptr++) { + *wptr = wdata; + if (verify) { + if (*wptr != wdata) { + err = 1; + error_at = (ulong)wptr; + break; + } + } + wdata += increment; + } + break; + case 4: + for(lptr=(ulong *)start;lptr<(ulong *)finish;lptr++) { + *lptr = ldata; + if (verify) { + if (*lptr != ldata) { + err = 1; + error_at = (ulong)lptr; + break; + } + } + ldata += increment; + } + break; + } + if (err) { + printf("Error at 0x%lx\n",error_at); + return(CMD_FAILURE); + } + return(CMD_SUCCESS); +} +#endif + +#if INCLUDE_SM + +/* Sm(): + * Search memory. + */ + +char *SmHelp[] = { + "Search Memory", + "-[24cnqsx] {start} {finish|byte-cnt} {srchfor}", +#if INCLUDE_VERBOSEHELP + "Options:", + " -2 short access", + " -4 long access", + " -c arg2 is count (in bytes)", + " -n srchfor_not (NA for -s or -x)", + " -q quit after first search hit", + " -s string srch", + " -x hexblock srch", +#endif + 0, +}; + +#define SM_NORMAL 1 /* Search for 1 value */ +#define SM_STRING 2 /* Search for ascii string */ +#define SM_HEXBLOCK 3 /* Search for block of hex data */ + +int +Sm(int argc,char *argv[]) +{ + ulong start, finish; + int width, opt, i, j, mode, arg2iscount, not, quit; + char *srchfor, tmp; + uchar *cptr, cdata, data[32]; + ushort *wptr, wdata; + ulong *lptr, ldata; + + not = 0; + quit = 0; + width = 1; + arg2iscount = 0; + mode = SM_NORMAL; + while((opt=getopt(argc,argv,"24cnqsx")) != -1) { + switch(opt) { + case '2': + width = 2; + break; + case '4': + width = 4; + break; + case 'c': + arg2iscount = 1; + break; + case 'n': + not = 1; /* opposite logic SM_NORMAL only. */ + break; + case 'q': + quit = 1; /* quit after first [no]match */ + break; + case 's': + mode = SM_STRING; /* ascii string */ + break; + case 'x': + mode = SM_HEXBLOCK; /* hex data */ + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc != optind+3) + return(CMD_PARAM_ERROR); + + start = strtoul(argv[optind],(char **)0,0); + finish = strtoul(argv[optind+1],(char **)0,0); + if (arg2iscount) + finish = start + finish; + srchfor = argv[optind+2]; + + if (mode == SM_HEXBLOCK) { + char *ex; + + if (not) + return(CMD_PARAM_ERROR); + ex = strpbrk(srchfor,"xX"); + if (ex) + srchfor=ex+1; + if (strlen(srchfor) % 2) + return(CMD_PARAM_ERROR); + for(i=0,j=0;i<(sizeof data);i++,j+=2) { + if (srchfor[j] == 0) + break; + tmp = srchfor[j+2]; + srchfor[j+2] = 0; + data[i] = (uchar)strtoul(&srchfor[j],0,16); + srchfor[j+2] = tmp; + } + for(cptr=(uchar *)start;cptr<(uchar *)finish;cptr++) { + if (memcmp((char *)cptr,(char *)data,i) == 0) { + printf("Match @ 0x%lx\n",(ulong)cptr); + if (quit || gotachar()) + break; + } + } + return(CMD_SUCCESS); + } + else if (mode == SM_STRING) { + int len; + + if (not) + return(CMD_PARAM_ERROR); + len = strlen(srchfor); + for(cptr=(uchar *)start;cptr<(uchar *)finish;cptr++) { + if (strncmp((char *)cptr,srchfor,len) == 0) { + printf("Match @ 0x%lx\n",(ulong)cptr); + if (quit || gotachar()) + break; + } + } + } + else if (width == 1) { + cdata = (uchar)strtoul(srchfor,(char **)0,0); + for(cptr=(uchar *)start;cptr<(uchar *)finish;cptr++) { + if (not) { + if (*cptr != cdata) { + printf("Nomatch @ 0x%lx (0x%x)\n",(ulong)cptr,*cptr); + if (quit || gotachar()) + break; + } + } + else if (*cptr == cdata) { + printf("Match @ 0x%lx\n",(ulong)cptr); + if (quit || gotachar()) + break; + } + } + } + else if (width == 2) { + wdata = (ushort)strtoul(srchfor,(char **)0,0); + for(wptr=(ushort *)start;wptr<(ushort *)finish;wptr++) { + if (not) { + if (*wptr != wdata) { + printf("Nomatch @ 0x%lx (0x%x)\n",(ulong)wptr,*wptr); + if (quit || gotachar()) + break; + } + } + else if (*wptr == wdata) { + printf("Match @ 0x%lx\n",(ulong)wptr); + if (quit || gotachar()) + break; + } + } + } + else { + ldata = (ulong)strtoul(srchfor,(char **)0,0); + for(lptr=(ulong *)start;lptr<(ulong *)finish;lptr++) { + if (not) { + if (*lptr != ldata) { + printf("Nomatch @ 0x%lx (0x%lx)\n",(ulong)lptr,*lptr); + if (quit || gotachar()) + break; + } + } + else if (*lptr == ldata) { + printf("Match @ 0x%lx\n",(ulong)lptr); + if (quit || gotachar()) + break; + } + } + } + return(CMD_SUCCESS); +} +#endif + +#if INCLUDE_CM + +/* Cm(): + * Copy memory. + * + * Arguments... + * arg1: source address + * arg2: destination address + * arg3: byte count + * + * Options... + * -2 access as a short. + * -4 access as a long. + * -f fifo access (address does not increment). + * -v verify (only) that the range specified, is copied. + */ + +char *CmHelp[] = { + "Copy Memory", + "-[24fv] {src} {dst} {byte-cnt}", +#if INCLUDE_VERBOSEHELP + "Options:", + " -2 short access", + " -4 long access", + " -f fifo mode", + " -v verify only", +#endif + 0, +}; + +int +Cm(int argc,char *argv[]) +{ + ulong src, dest, end, bytecount; + int opt, width, fifo, verify, verify_failed; + + width = 1; + fifo = verify = 0; + verify_failed = 0; + while((opt=getopt(argc,argv,"24fv")) != -1) { + switch(opt) { + case '2': + width = 2; + break; + case '4': + width = 4; + break; + case 'f': + fifo = 1; + break; + case 'v': + verify = 1; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc != optind+3) { + return(CMD_PARAM_ERROR); + } + if ((verify) && (fifo)) { + printf("Can't verify in fifo mode\n"); + return(CMD_FAILURE); + } + + src = strtoul(argv[optind],(char **)0,0); + dest = strtoul(argv[optind+1],(char **)0,0); + bytecount = strtoul(argv[optind+2],(char **)0,0); + + if (bytecount <= 0) { + printf("Invalid byte count\n"); + return(CMD_FAILURE); + } + + end = src+bytecount-1; + if (src > end) { + printf("Invalid range (possibly overlapping address 0?)\n"); + return(CMD_FAILURE); + } + + if (width == 1) { + while(src <= end) { + if (verify) { + if (*(uchar *)dest != *(uchar *)src) { + verify_failed = 1; + break; + } + } + else + *(uchar *)dest = *(uchar *)src; + if (!fifo) + dest++; + src++; + } + } + else if (width == 2) { + while(src <= end) { + if (verify) { + if (*(ushort *)dest != *(ushort *)src) { + verify_failed = 1; + break; + } + } + else + *(ushort *)dest = *(ushort *)src; + if (!fifo) + dest += 2; + src += 2; + } + } + else { /* width == 4 */ + while(src <= end) { + if (verify) { + if (*(ulong *)dest != *(ulong *)src) { + verify_failed = 1; + break; + } + } + else + *(ulong *)dest = *(ulong *)src; + if (!fifo) + dest += 4; + src += 4; + } + } + if ((verify) && (verify_failed)) { + printf("Verify failed: *0x%lx != *0x%lx\n",src,dest); + return(CMD_FAILURE); + } + return(CMD_SUCCESS); +} + +#endif + +#if INCLUDE_MT + +/* Mt(): + * Memory test + * Walking ones and address-in-address tests for data and address bus + * testing respectively. This test, within the context of a monitor + * command, has limited value. It must assume that the memory space + * from which this code is executing is sane (obviously, or the code + * would not be executing) and the ram used for stack and bss must + * already be somewhat useable. + */ +char *MtHelp[] = { + "Memory test", + "-[CcqSs:t:v] {addr} {len}", +#if INCLUDE_VERBOSEHELP + "Options:", + " -c continuous", + " -C crc32 calculation", + " -q quit on error", + " -S determine size of on-board memory (see note below)", + " -s## sleep ## seconds between adr-in-addr write and readback", + " -t## toggle data on '##'-bit boundary (##: 32 or 64)", + " -v cumulative verbosity...", + " -v=<ticker>, -vv=<ticker + msg-per-error>", + "", + "Memory test is walking ones followed by address-in-address", + "", + "Note1: For normal memory test, hit any key to abort test with errors", + "Note2: With -S option, {addr} is the base of physical memory and", + " {len} is the maximum expected size of that memory. The", + " shell variable MEMSIZE is loaded with the result.", +#endif + 0, +}; + +int +Mt(int argc,char *argv[]) +{ + int errcnt, len, testaborted, opt, runcrc; + int quitonerr, verbose, continuous, testtot, sizemem; + ulong arg1, arg2, *start, rwsleep, togglemask; + ulong *end, walker, readback, shouldbe; + volatile ulong *addr; + + runcrc = 0; + sizemem = 0; + continuous = 0; + quitonerr = 0; + verbose = 0; + rwsleep = 0; + togglemask = 0; + while((opt=getopt(argc,argv,"cCqSs:t:v")) != -1) { + switch(opt) { + case 'c': + continuous = 1; + break; + case 'C': + runcrc = 1; + break; + case 'q': + quitonerr = 1; + break; + case 'S': + sizemem = 1; + break; + case 's': + rwsleep = strtoul(optarg,0,0); + break; + case 't': + switch(atoi(optarg)) { + case 32: + togglemask = 0x00000004; + break; + case 64: + togglemask = 0x00000008; + break; + default: + return(CMD_PARAM_ERROR); + } + break; + case 'v': + verbose++; /* Cumulative verbosity */ + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc != optind+2) + return(CMD_PARAM_ERROR); + + arg1 = strtoul(argv[optind],(char **)0,0); + arg2 = strtoul(argv[optind+1],(char **)0,0); + + /* If -S option, then run a memory size test. + * For this case, arg1 is the base and arg2 is the maximum expected + * size of the on-board memory... + */ + if (sizemem) { + vulong tmp1, base, test; + + base = arg1; + test = arg2; + + tmp1 = *(vulong *)base; + *(vulong *)base = 0xDEADBEEF; + + /* Got this algorithm from Bill Gatliff... + * Assume that memory always starts at address 0, for + * simplicity in the explanation. What you do is write 256 + * at 256MB, 128 at 128MB, 64@64MB, and so on. When you get + * down to zero (or the smallest available memory address, if + * you want to stop sooner), you read the value stored at 0. + * That value is the size of available memory. + */ + while(test >= 0x100000) { + *(vulong *)(base + test) = test/0x100000; + if (verbose) + printf("*0x%lx = 0x%lx (0x%lx)\n",(base+test),test/0x100000, + *(vulong *)(base + test)); + test >>= 1; + } + + /* If the base location was not changed by the above algorithm + * then the address bus doesn't alias, so try something else... + * This time, walk up the address space starting at 0x100000 + * and doubling each time until the write to the address (minus 4) + * fails. The last successful write indicates the top of memory. + */ + if (*(vulong *)base == 0xDEADBEEF) { + test = 0x100000; + while(test <= arg2) { + vulong *lp = (vulong *)(base+test-sizeof(long)); + + if (verbose) + printf("write to 0x%lx, ",(long)lp); + *lp = 0xdeadbeef; + monDelay(100); + if (*lp != 0xdeadbeef) { + if (verbose) + printf("failed\n"); + break; + } + if (verbose) + printf("passed\n"); + test <<= 1; + } + test >>= 1; + printf("Size: %ld MB\n",test/0x100000); + shell_sprintf("MEMSIZE","0x%lx",test); + } + else { + printf("Size: %ld MB\n",*(vulong *)base); + shell_sprintf("MEMSIZE","0x%lx",*(vulong *)base * 0x100000); + } + + *(vulong *)base = tmp1; + return(CMD_SUCCESS); + } + + /* If -C option, then run a CRC32 on a specified block of memory... + */ + if (runcrc) { + ulong mtcrc; + + mtcrc = crc32((uchar *)arg1,arg2); + printf("CRC32 @ 0x%lx (0x%lx bytes) = 0x%lx\n",arg1,arg2,mtcrc); + shell_sprintf("MTCRC","0x%lx",mtcrc); + return(CMD_SUCCESS); + } + + arg1 &= ~0x3; /* Word align */ + arg2 &= ~0x3; + + testtot = 0; + printf("Testing 0x%lx .. 0x%lx\n",arg1,arg1+arg2); + + start = (ulong *)arg1; + len = (int)arg2; + testaborted = errcnt = 0; + + while(1) { + /* Walking Ones test: + * This test is done to verify that no data bits are shorted. + * Write 32 locations, each with a different bit set, then + * read back those 32 locations and make sure that bit (and only + * that bit) is set. + */ + walker = 1; + end = start + 32; + for (addr=start;addr<end;addr++) { + *addr = walker; + walker <<= 1; + } + + walker = 1; + for (addr=start;addr<end;addr++) { + readback = *addr; + if (readback != walker) { + errcnt++; + if (verbose > 1) + printf("WalkingOneErr @ x%lx: read x%lx expected x%lx\n", + (ulong)addr,readback,walker); + if (quitonerr) + break; + } + walker <<= 1; + } + + /* Address-in-address test: + * This test serves three purposes... + * 1. the "address-in-address" tests for stuck address bits. + * 2. the "not-address-in-address" (-t option) exercises the + * data bus. + * 3. the sleep between read and write tests for valid memory + * refresh in SDRAM based systems. + * + * The togglemask is used to determine at what rate the data + * should be flipped... every 32 bits or every 64 bits. + */ + if ((!testaborted) && ((!errcnt) || (errcnt && !quitonerr))) { + + /* In each 32-bit address, store either the address or the + * complimented address... + */ + end = (ulong *)((int)start + len); + for (addr=start;addr<end;addr++) { + if (((ulong)addr & 0x3ffff) == 0) { + if (gotachar()) { + testaborted = 1; + break; + } + if (verbose) + ticktock(); + } + + if ((ulong)addr & togglemask) + *addr = ~(ulong)addr; + else + *addr = (ulong)addr; + } + + /* If -s is specified, then delay for the specified number + * of seconds. This option just allows the ram to "sit" + * for a a while; hence, verifying automatic refresh in + * the case of SDRAM. + */ + if (rwsleep && !testaborted) { + int i; + for(i=0;i<rwsleep;i++) { + monDelay(1000); + if (gotachar()) { + testaborted = 1; + break; + } + if (verbose) + ticktock(); + } + } + + if (testaborted) + break; + + /* For each 32-bit address, verify either the address or the + * complimented address... + */ + for (addr=start;addr<end;addr++) { + if (((ulong)addr & 0x3ffff) == 0) { + if (gotachar()) { + testaborted = 1; + break; + } + if (verbose) + ticktock(); + } + + readback = *addr; + if ((ulong)addr & togglemask) + shouldbe = ~(ulong)addr; + else + shouldbe = (ulong)addr; + if (readback != shouldbe) { + errcnt++; + if (verbose > 1) + printf("AdrInAdrErr @ x%lx: read x%lx expected x%lx\n", + (ulong)addr,readback,shouldbe); + if (quitonerr) { + testaborted = 1; + break; + } + } + } + } + testtot++; + if (!continuous || testaborted || (errcnt && quitonerr)) + break; + } + + + printf("Found %d errors", errcnt); + if (continuous && testaborted) + printf(" after %d test loops",testtot); + printf(".\n"); + + if (errcnt) + return(CMD_FAILURE); + else + return(CMD_SUCCESS); +} +#endif diff --git a/main/common/memtrace.c b/main/common/memtrace.c new file mode 100644 index 0000000..2962007 --- /dev/null +++ b/main/common/memtrace.c @@ -0,0 +1,379 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * memtrace.c: + * + * This file contains CLI and API code to support a simple memory trace + * capability that allows application developers to call mon_memtrace() + * with a "printf-like" formatted arglist and the formatted string is + * put into a circular buffer in some allocated RAM space. + * The circular buffer is established by "mtrace cfg" command, then all + * subsequent calls to mon_memtrace() will have the formatted string + * destined for that buffer. + * + * To keep the output formatted clean, the user of mon_memtrace() should + * not include any line-feeds in the string. Each time mon_memtrace() is + * called, a line feed and sequence number is prepended to the string. + * This allows the dump to simply run through the buffer using putchar(). + * + * Both the mon_memtrace() API function and the dump facility in the CLI + * will deal with buffer wrapping. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#include <stdarg.h> +#include "stddefs.h" +#include "genlib.h" +#include "cli.h" + +#if INCLUDE_MEMTRACE + +#define MINBUFSIZE 512 +#define MAXLINSIZE MINBUFSIZE/2 + +#define MODE_PRINT (1<<0) /* mtrace text is output to console */ +#define MODE_NOWRAP (1<<1) /* when mtrace buffer fills, stop */ + +/* struct mtInfo: + * This structure is at the base of the memory space allocated for + * the print buffer. The control structure is part of the print buffer + * because the print buffer is assumed to be outside of the bss area + * of the monitor; hence, if a reset occurs and the monitor clears out + * its bss space, this structure will still be accessible and contain + * the data prior to the reset. + * So, to initialize a memory trace buffer use... + * mtrace cfg BASE SIZE + * and to re-establish the trace after a reset, use... + * mtrace mip BASE + */ +struct mtInfo { + char *base; /* Base of ram space allocated for print buffer. */ + char *ptr; /* Running pointer into circular print buffer. */ + char *end; /* End of ram space allocated. */ + int size; /* Size of space originally allocated for mtrace. */ + int off; /* Set if tracing is disabled. */ + int sno; /* Sequence number of Mtrace() call. */ + int wrap; /* Wrap counter. */ + int mode; /* See MODE_XXX bits above. */ + int reentered; /* Reentry counter. */ +}; + +static struct mtInfo *Mip; + +/* Mtrace(): + * Memory trace... This function can be used to place some trace statements + * (readable text) in some memory location specified by the + * setting of mtracebuf. This was originally written for debugging Xmodem + * because you can't use printf() since the protocol is using the serial + * port. I have since pulled it out of the Xmodem.c file and placed it in + * generally accessible space so that it can be made available to the + * application code and other monitor code. + */ + +int +Mtrace(char *fmt,...) +{ + static int inMtraceNow; + int len; + char *eolp; + va_list argp; + + /* Mtrace not configured or disabled, so just return. + */ + if (!Mip || Mip->off) + return(0); + + /* This may be called from interrupt and/or non-interrupt space of + * an application, so we must deal with possible reentrancy here. + */ + if (inMtraceNow) { + Mip->reentered++; + return(0); + } + + inMtraceNow = 1; + + Mip->ptr += snprintf(Mip->ptr,MAXLINSIZE,"\n<%04d> ",Mip->sno++); + + va_start(argp,fmt); + len = vsnprintf(Mip->ptr,MAXLINSIZE,fmt,argp); + va_end(argp); + + /* Strip all CR/LFs from the incoming string. + * The incoming string can have CR/LFs in it; however, they are stripped + * so that the format of the dump is stable (one line per Mtrace call). + * Notice that the top line of this function inserts a newline ahead + * of the sequence number; hence, additional CR/LFs in the text would + * just confuse the output. + */ + eolp = Mip->ptr; + while(*eolp) { + if ((*eolp == '\r') || (*eolp == '\n')) { + strcpy(eolp,eolp+1); + len--; + } + else + eolp++; + } + + /* If print flag is set, then dump to the console... + */ + if (Mip->mode & MODE_PRINT) { + int i; + for(i=0;i<len;i++) + putchar(*Mip->ptr++); + putchar('\n'); + } + else + Mip->ptr += len; + + if (Mip->ptr >= Mip->end) { + Mip->ptr = Mip->base; + if (Mip->mode & MODE_NOWRAP) + Mip->off = 1; + else + Mip->wrap++; + } + + /* Flush the d-cache of the mtrace buffer and Mip structure after each + * transfer... + * This is important because if this is being accessed from an + * application that has d-cache enabled, then the hardware is reset, + * there is a chance that the data written was in cache and would be + * lost. + */ + flushDcache((char *)Mip,sizeof(struct mtInfo)); + flushDcache((char *)Mip->base,Mip->end - Mip->base); + + inMtraceNow = 0; + return(len); +} + +void +MtraceReset(void) +{ + Mip->ptr = Mip->base; + Mip->sno = 1; + Mip->wrap = 0; + Mip->off = 0; + Mip->mode = 0; + Mip->reentered = 0; + memset(Mip->base,0,Mip->size-sizeof(struct mtInfo)); +} + +void +MtraceInit(char *base, int size) +{ + if (size < MINBUFSIZE) + return; + + Mip = (struct mtInfo *)base; + Mip->base = base + sizeof(struct mtInfo); + Mip->size = size; + Mip->end = (Mip->base + size - MAXLINSIZE); + MtraceReset(); +} + +char * +mDump(char *bp, int more) +{ + int line; + + line = 0; + + while((bp < Mip->end) && (*bp)) { + putchar(*bp); + if (more && (*bp == '\n')) { + if (++line == 24) { + line = 0; + if (!More()) + return(0); + } + } + bp++; + } + while(*bp) { + putchar(*bp); + if (more && (*bp == '\n')) { + if (++line == 24) { + line = 0; + if (!More()) + return(0); + } + } + bp++; + } + return(bp); +} + +/* If Mip pointer is configured, return 1; else return zero + * and print an error message. + */ +static int +MipConfigured(void) +{ + if (Mip) + return(1); + printf("Not configured\n"); + return(0); +} + +char *MtraceHelp[] = { + "Configure/Dump memory trace.", + "-[nm] {cmd} [cmd specific args]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -m enable 'more' flag for dump.", + " -n disable wrapping.", + "Cmd:", + " on", + " off", + " dump", + " pron", + " reset", + " log {msg}", + " mip {base}", + " cfg [{base} {size}]", +#endif + 0 +}; + +int +MtraceCmd(int argc,char *argv[]) +{ + char *bp; + int more, opt, nowrap; + + more = 0; + nowrap = 0; + while((opt=getopt(argc,argv,"nm")) != -1) { + switch(opt) { + case 'n': + nowrap = 1; + break; + case 'm': + more = 1; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc <= optind) + return(CMD_PARAM_ERROR); + + if (!strcmp(argv[optind],"cfg")) { + if (argc == optind + 3) { + MtraceInit((char *)strtoul(argv[optind+1],0,0), + strtoul(argv[optind+2],0,0)); + if (nowrap) + Mip->mode |= MODE_NOWRAP; + } + else if (argc == optind + 1) { + if (MipConfigured()) { + printf("Base: 0x%lx, End: 0x%lx\n", + (ulong)Mip->base,(ulong)Mip->end); + printf("Ptr: 0x%lx, Sno: %d\n",(ulong)Mip->ptr,Mip->sno); + printf("Wrap: %d\n",Mip->wrap); + } + } + else + return(CMD_PARAM_ERROR); + } + else if (!strcmp(argv[optind],"on")) { + if (MipConfigured()) { + Mip->mode &= ~MODE_PRINT; + Mip->off = 0; + } + } + else if (!strcmp(argv[optind],"pron")) { + if (MipConfigured()) { + Mip->mode |= MODE_PRINT; + Mip->off = 0; + } + } + else if (!strcmp(argv[optind],"off")) { + if (MipConfigured()) + Mip->off = 1; + } + else if (!strcmp(argv[optind],"reset")) { + if (MipConfigured()) + MtraceReset(); + } + else if (!strcmp(argv[optind],"mip")) { + if (argc != optind + 2) + return(CMD_PARAM_ERROR); + Mip = (struct mtInfo *)strtoul(argv[optind+1],0,0); + } + else if (!strcmp(argv[optind],"log")) { + if (argc != optind + 2) + return(CMD_PARAM_ERROR); + Mtrace(argv[optind+1]); + } + else if (!strcmp(argv[optind],"dump")) { + if (MipConfigured()) { + if (Mip->reentered) + printf("Reentry count: %d\n",Mip->reentered); + if (Mip->wrap) { + printf("Buffer wrapped...\n"); + bp = Mip->ptr; + while(bp < Mip->end) { + if (*bp == '\n') { + bp = mDump(bp,more); + break; + } + bp++; + } + if (bp) { + bp = Mip->base; + while(bp < Mip->ptr) + putchar(*bp++); + } + } + else { + bp = mDump(Mip->base,more); + } + printf("\n\n"); + } + } + else + return(CMD_PARAM_ERROR); + + return(CMD_SUCCESS); +} + +#else + +void +MtraceInit(char *base, int size) +{ + printf("Mtrace() facility not built in.\n"); +} + +int +Mtrace(char *fmt, ...) +{ + return(0); +} + +#endif diff --git a/main/common/misc.c b/main/common/misc.c new file mode 100644 index 0000000..4e32ed5 --- /dev/null +++ b/main/common/misc.c @@ -0,0 +1,528 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * misc.c: + * + * This file contains miscellaneous functions that are used by all target + * versions of the monitor. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#include "stddefs.h" +#include "cli.h" +#include "monflags.h" +#include "monlib.h" +#include "genlib.h" +#include "devices.h" +#include "cpuio.h" +#include <ctype.h> +#include "ether.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "warmstart.h" +#include "timer.h" +#include "version.h" +#include "target_version.h" + +#ifdef USR_HEADER_FUNC +extern void USR_HEADER_FUNC(int center); +#endif + +/* extWatchDog(): + * This function pointer is used by the application to override the + * monitor's configured watchdog functionality. Refer to config.h + * in umon_ports/template for more information on the WATCHDOG macro. + */ +#ifdef WATCHDOG_ENABLED +int (*extWatchDog)(void); +#endif + +/* AppExitStatus: + * Global copy of the application's exit status. + */ +int AppExitStatus; + +char * +monVersion(void) +{ + static char buf[16]; + + /* Build the version string as "X.Y.Z" + */ + snprintf(buf,sizeof(buf),"%d.%d.%d", + MAJOR_VERSION,MINOR_VERSION,TARGET_VERSION); + + return(buf); +} + +/* ShowVersion(): + * Display the build time and date of the running monitor. + */ +void +ShowVersion(void) +{ + printf("Monitor core release: %d.%d, target version %d (built: %s)\n", + MAJOR_VERSION,MINOR_VERSION,TARGET_VERSION,monBuilt()); + if (ApplicationInfo[0]) + printf("%s\n",ApplicationInfo); +} + +/* monHeader(): + * Dump the common stuff that is displayed at the console port when + * the monitor first starts up. If called with 'center' set, then + * the printed output is centered on an 80-character screen width. + */ +void +monHeader(int center) +{ + char *ip, *mac; + int (*pfunc)(char *, ...); + + /* Some folks just don't like the opening banner to be centered, so + * force center to 0 if DONT_CENTER_MONHEADER is defined... + */ +#ifdef DONT_CENTER_MONHEADER + center = 0; +#endif + + if (center) { + printf("\n\n"); + pfunc = cprintf; + } + else + pfunc = printf; + + /* Optionally support (via config.h) up to four lines of user-specified + * header text... + */ +#ifdef USR_HEADER1 + pfunc("%s\n",USR_HEADER1); +#endif +#ifdef USR_HEADER2 + pfunc("%s\n",USR_HEADER2); +#endif +#ifdef USR_HEADER3 + pfunc("%s\n",USR_HEADER3); +#endif +#ifdef USR_HEADER4 + pfunc("%s\n",USR_HEADER4); +#endif + + pfunc("MICRO MONITOR %s\n",monVersion()); + pfunc("Platform: %s\n",PLATFORM_NAME); + pfunc("CPU: %s\n",CPU_NAME); + pfunc("Built: %s\n",monBuilt()); + pfunc("Monitor RAM: 0x%06x-0x%06x\n",&bss_start,&bss_end); + pfunc("Application RAM Base: 0x%06x\n",APPLICATION_RAMSTART); + mac = getenv("ETHERADD"); + if (mac) + pfunc("MAC: %s\n",mac); + ip = getenv("IPADD"); + if (ip) + pfunc("IP: %s\n",ip); + +#ifdef USR_HEADER_FUNC + USR_HEADER_FUNC(center); +#endif + +#ifdef TOD_IN_MONHEADER + showDate(center); +#endif +} + +/* stkchk(): + * The monitor's stack is a statically allocated array (MonStack). + * At initialization the stack pointer is set to the top of this stack + * and the bottom is loaded with 0xdeaddead. This function simply + * verifies that the bottom of the stack is sane (still reads 0xdeaddead). + * If not, an error is printed. + */ +int +stkchk(char *msg) +{ + extern ulong MonStack[]; + + if (MonStack[0] != 0xdeaddead) { + printf("\n***** Monitor stack overflow (%s) *****\n",msg); + MonStack[0] = 0xdeaddead; + return(-1); + } + return(0); +} + +void +stkusage(void) +{ + int i; + ulong *sp, stackval; + extern ulong MonStack[]; + + printf("Stack: bottom=0x%lx, size=%d",(long)MonStack,MONSTACKSIZE); + + sp = MonStack; + sp++; /* Increment past 0xdeaddead */ + + /* If the very first entry in stack space is not set to + * STACK_PREINIT_VAL, then we assume that stkinit() was not called + * at startup so don't print any stack usage information... + */ + if (*sp == STACK_PREINIT_VAL) { + for(i=0;i<MONSTACKSIZE;i+=4) { + if (*sp++ != STACK_PREINIT_VAL) + break; + } + printf(" (%d%% used)",((MONSTACKSIZE-i)*100)/MONSTACKSIZE); + } + printf("\n"); + + /* Finally, check to make sure that the current stack pointer + * resides within the MonStack[] array... + */ + if ((&stackval < MonStack) || (&stackval > &MonStack[MONSTACKSIZE/4])) + printf("WARNING: SP outside MonStack[]\n"); +} + +/* stkinit(): + * This function should be called very early in uMon startup prior to + * the stack pointer being set to the end of MonStack[]. It + * simply initializes the MonStack[] array to a defined value so + * that the stack can be observed for fullness during runtime. + */ +void +stkinit(void) +{ + extern ulong MonStack[]; + volatile ulong *sp, *spend; + + sp = (ulong *)MonStack; + spend = MonStack+MONSTACKSIZE/4; + while(sp < spend) + *sp++ = STACK_PREINIT_VAL; +} + +/* writeprompt(): + * Called to print out the monitor prompt. If the shell variable PROMPT + * exists, then use the content of that variable as a prompt; otherwise, + * just print uMON>. + */ +void +writeprompt(void) +{ + char *prompt; + + prompt = getenv("PROMPT"); + if (!prompt) + prompt = "uMON>"; + else if (strcmp(prompt,"NULL") == 0) + return; + + putstr(prompt); +} + +/* CommandLoop(): + * This function is called at the end of monitor initialization. + * The monitor spends most of its time here, waiting for incoming + * characters on the console interface. + */ +void +CommandLoop(void) +{ + static char cmdline[CMDLINESIZE]; + + while(1) { + stkchk("Cmdloop"); /* Verify valid monitor stack */ + writeprompt(); /* Issue prompt */ + memset(cmdline,0,CMDLINESIZE); /* Clear command line buffer */ + if (getline(cmdline,CMDLINESIZE,INCLUDE_LINEEDIT) == 0) + continue; + docommand(cmdline,0); +#if INCLUDE_FLASH + LowerFlashProtectWindow(); +#endif + } +} + +int monitorFlags; + +struct monflag monflagtbl[] = { + { NOMONHEADER, "nophdr" }, /* Don't print header at startup */ + { NODEFRAGPRN, "nopdf" }, /* Don't print defrag msg in tfsclean */ + { NOTFTPPRN, "noptftp" }, /* Don't print for tftp RRQ or WRQ */ + { NOMONCMDPRN, "nopmcmd" }, /* Don't print for incoming moncmd */ + { NOTFTPOVW, "notftpovw" }, /* Don't allow TFTP srvr to overwrite */ + { NOEXITSTATUS, "noexitstat" }, /* Don't ptint app exit status */ + { 0,0 } +}; + +/* InitMonitorFlags(): + * If the shell variable MONFLAGS exists, then use the content of that + * variable to populate the value monitorFlags. The syntax of the shell + * variable is "xxx:yyyy:zzzz:abcd" where xxx,yyyy,zzzz and abcd are + * strings from the monflagtbl that represent some bit in the long that + * is to be set. + */ +void +InitMonitorFlags(void) +{ + char *mf, *colon; + struct monflag *mfp; + + monitorFlags = 0; + + mf = getenv("MONFLAGS"); + if (!mf) + return; + + while(1) { + colon = strchr(mf,':'); + if (colon) + *colon = 0; + mfp = monflagtbl; + while(mfp->flagname) { + if (!strcmp(mf,mfp->flagname)) { + monitorFlags |= mfp->bit; + break; + } + mfp++; + } + if (!mfp->flagname) + printf("MONFLAGS err: %s\n",mf); + if (colon) + *colon = ':'; + else + break; + mf = colon+1; + } +} + +/* exceptionAutoRestart(): + * Serves three purposes: + * 1. Copies the verbose description of the exception to the + * shell variable EXCEPTION_TYPE. + * 2. If there is an EXCEPTION_SCRIPT shell variable, then see if the + * user wants it to be executed. + * 3. If there is no NO_EXCEPTION_RESTART variable, then + * call monrestart with the incoming value (usually INITIALIZE). + */ +void +exceptionAutoRestart(int restartvalue) +{ + char *script; + char *arglist[2]; + + setenv("EXCEPTION_TYPE",ExceptionType2String(ExceptionType)); + script = getenv("EXCEPTION_SCRIPT"); + if ((script) && + (!pollConsole("Press any key to stop exception script.\n"))) { + arglist[0] = script; + arglist[1] = (char *)0; + tfsrun(arglist,0); + } + + if (!getenv("NO_EXCEPTION_RESTART")) { + if (!pollConsole("Press any key to stop auto restart.\n")) + monrestart(restartvalue); + } +} + +/* getAppRamStart(): + * First looks for the content of APPRAMBASE shell variable; + * if present, that string is converted to a long and returned, + * else the value of APPLICATION_RAMSTART is returned. + */ +ulong +getAppRamStart(void) +{ + char *apprambase; + ulong value; + + apprambase = getenv("APPRAMBASE"); + if (apprambase) + value = strtoul(apprambase,0,0); + else + value = APPLICATION_RAMSTART; + return(value); +} + +/* uMonInRam(): + * This function returns 1 if the image of the running monitor is + * in RAM; else 0. The function ramtstfunc() should NEVER be called. + * It is used as a test to determine if text space is writeable. + * If it is, then we assume that uMon is running from RAM. + */ +static int +ramtstfunc(void) +{ + return(99); +} + +int +uMonInRam(void) +{ + int rc; + volatile unsigned char origvalue; + volatile unsigned char *testmem = (unsigned char *)&ramtstfunc; + + origvalue = *testmem; + *testmem = ~origvalue; + + /* Flush d-cache here to make sure that the write & readback actually + * interact with external memory and not just d-cache... + */ + flushDcache((char *)testmem,1); + + if (*testmem == (unsigned char)~origvalue) + rc = 1; + else + rc = 0; + + *testmem = origvalue; + return(rc); +} + +/* inUmonBssSpace() + * Return 1 if the address range falls within MicroMonitor's + * own RAM space. + */ +int +inUmonBssSpace(char *start,char *end) +{ + static int nowarn; + + if (nowarn || getenv("NO_UMONBSS_WARNING")) { + nowarn = 1; + return(0); + } + + if (((start >= (char *)&bss_start) && (start < (char *)&bss_end)) || + ((end >= (char *)&bss_start) && (end < (char *)&bss_end)) || + ((start <= (char *)&bss_start) && (end >= (char *)&bss_end))) { + printf("\nError: addr range 0x%lx <-> 0x%lx violates uMon ram.\n", + (long)start,(long)end); + return(1); + } + + return(0); +} + +void +monrestart(int val) +{ + /* Allow UART0 transmit FIFO to empty... + */ + flush_console_out(); + intsoff(); + warmstart(val); +} + +void +appexit(int val) +{ + AppExitStatus = val; + monrestart(APP_EXIT); +} + +/* monWatchDog(): + * This function is hooked to the monitor API so that the application + * can use the same function used by monitor code for exciting the + * watchdog hardware. + * Note that if there is no defined WATCHDOG_MACRO, then this function + * returns -1; else it executes the macro and returns 0. This + * return value can be used by the application to decide whether or + * not the call to mon_watchdog() even needs to occur. + */ +int +monWatchDog(void) +{ +#ifdef WATCHDOG_ENABLED + WATCHDOG_MACRO; + return(0); +#else + return(-1); +#endif +} + +#if INCLUDE_SHELLVARS + +/* putargv() & getargv(): + * The getargv() function provides a hook allowing the downloaded + * application code to handle main(argc,argv) in a painless way. + * The Argv[] array location is returned by mon_getargv() and is + * assumed to contain the NULL terminated list of argv pointers... + * Immediately after the NULL termination is the data that the argv + * pointers are referencing. + * + * MONLIB NOTICE: getargv() is accessible through monlib.c. + */ + +/* ArgvList: + * Used by the code that is behind the mon_getargv() API. + */ +static char *ArgvList[32]; + +int +putargv(int argnum,char *argptr) +{ + int i; + char buf[8]; + + if (argnum >= (sizeof(ArgvList)/sizeof(char *))) + return(-1); + + if (argnum == 0) { + for(i=0;i<(sizeof(ArgvList)/sizeof(char *));i++) { + sprintf(buf,"ARG%d",i); + setenv(buf,0); + } + setenv("ARGC",0); + ArgvList[0] = (char *)0; + } + + ArgvList[argnum] = argptr; + + if (argptr) { + sprintf(buf,"ARG%d",argnum); + setenv(buf,ArgvList[argnum]); + } + else { + shell_sprintf("ARGC","%d",argnum); + } + + return(0); +} + +void +getargv(int *argc,char ***argv) +{ + int i; + + if (argv) + *argv = &ArgvList[0]; + for(i=0;;i++) + if (ArgvList[i] == 0) + break; + if (argc) + *argc = i; +} + +#endif diff --git a/main/common/misccmds.c b/main/common/misccmds.c new file mode 100644 index 0000000..742f5fb --- /dev/null +++ b/main/common/misccmds.c @@ -0,0 +1,578 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * misccmds: + * + * More monitor commands... + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "genlib.h" +#include "ether.h" +#include "devices.h" +#include "cli.h" +#include <ctype.h> +#include "warmstart.h" + + +char ApplicationInfo[82]; +int (*extgetUsrLvl)(void); + +#if INCLUDE_USRLVL +static int setUsrLvl(int, char *); +static int UserLevel; + +char *UlvlHelp[] = { + "Display or modify current user level.", + "-[c:hp] [new_level|min|max] [password]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -c{cmd,lvl}", + " set command's user level", + " -h dump system header", + " -p build new password file", + "", + " Note: cmd==ALL, applies action to all commands.", +#endif + 0 +}; + +int +Ulvl(int argc,char *argv[]) +{ + char passwd[32], *pwp; + int level, opt, newulvl; + + newulvl = 0; + pwp = (char *)0; + level = MINUSRLEVEL; + while((opt=getopt(argc,argv,"c:hp")) != -1) { + switch(opt) { + case 'c': + setCmdUlvl(optarg,1); + newulvl++; + break; + case 'h': + monHeader(0); + break; + case 'p': + newPasswordFile(); + break; + default: + return(CMD_PARAM_ERROR); + } + } + + /* At this point, the newulvl flag is used to indicate that the + * -c option was used. If it was, then we return here. + */ + if (newulvl) + return(CMD_SUCCESS); + + /* If there is one or two arguments on the command line, then + * the user must want to modify the current user level. If + * there are no arguments, then simply display the current + * user level. + * + * If the new user level is lower than the current user level, + * then the user can simply enter the new level (one argument). + * If the new user level is higher than the current user level, + * then the user must also enter a password. The password is + * entered either as the second argument or interactively + * using getpass(). + */ + newulvl = 0; + if ((argc == optind+1) || (argc == optind+2)) { + if (!strcmp(argv[optind],"min")) + level = MINUSRLEVEL; + else if (!strcmp(argv[optind],"max")) + level = MAXUSRLEVEL; + else + level = atoi(argv[optind]); + + if (argc == optind+1) { + if (level > UserLevel) { + getpass("Password: ",passwd,sizeof(passwd)-1,0); + pwp = passwd; + } + } + else { + pwp = argv[optind+1]; + } + newulvl = 1; + } + else if (argc != optind) { + return(CMD_PARAM_ERROR); + } + + /* At this point,the newulvl flag is used to indicate that an + * adjustment to the current user level is to be made. + */ + if (newulvl) { + if (level <= UserLevel) + UserLevel = level; + else + setUsrLvl(level,pwp); + } + + if (extgetUsrLvl) + printf("User level controlled by application: %d\n",extgetUsrLvl()); + else + printf("Current monitor user level: %d\n",UserLevel); + return(CMD_SUCCESS); +} + +void +initUsrLvl(int lvl) +{ + extgetUsrLvl = 0; + UserLevel = lvl; +} + +/* getUsrLvl(): + * This is the ONLY point of access for retrieval of the user level. + * This allows the application to redefine how the monitor retrieves + * what it thinks of as the user level. + */ +int +getUsrLvl(void) +{ + if (extgetUsrLvl) + return(extgetUsrLvl()); + return(UserLevel); +} + +int +setUsrLvl(int level, char *password) +{ + int olvl; + + olvl = UserLevel; + + /* If level is -1, then assume this is only a request for the current */ + /* user level. If the incoming level is any other value outside the */ + /* range of MINUSRLEVEL and MAXUSRLEVEL, return -1. */ + if (level == -1) + return(UserLevel); + if ((level > MAXUSRLEVEL) || (level < MINUSRLEVEL)) + return(olvl); + + /* If password pointer is NULL, then don't check for password, just set */ + /* the level and be done. */ + if (!password) { + UserLevel = level; + } + else { + if (validPassword(password,level)) + UserLevel = level; + } + return(olvl); +} + +/* returnMaxUsrLvl(), setTmpMaxUsrLvl() & clrTmpMaxUsrLvl(): + * These three functions are used to allow a few places in the monitor + * to temporarily force the user level to MAXUSRLEVEL. This is necessary + * for accessing the password file and the tfs log file. + * Call setTmpMaxUsrLvl() to enable MAX mode and then clrTmpMaxUsrLvl() + * with the value returned by setTmpMaxUsrLvl() when done. + */ +int +returnMaxUsrLvl(void) +{ + return(MAXUSRLEVEL); +} + +void * +setTmpMaxUsrLvl(void) +{ + void *fptr; + + fptr = (void *)extgetUsrLvl; + extgetUsrLvl = returnMaxUsrLvl; + return(fptr); +} + +void +clrTmpMaxUsrLvl(int (*fptr)(void)) +{ + extgetUsrLvl = fptr; +} + +#else + +int +getUsrLvl(void) +{ + return(MAXUSRLEVEL); +} + +#endif + +char *VersionHelp[] = { + "Version information", + "[application_info]", + 0, +}; + +int +Version(int argc,char *argv[]) +{ + extern void ShowVersion(void); + + if (argc == 1) + ShowVersion(); + else { + strncpy(ApplicationInfo,argv[1],80); + ApplicationInfo[80] = 0; + } + return(CMD_SUCCESS); +} + +#if INCLUDE_TFSSCRIPT +char *EchoHelp[] = { + "Print string to local terminal", + "[arg1] ... [argn]", +#if INCLUDE_VERBOSEHELP + " Special meaning: \\b \\c \\r \\n \\t \\x", +#endif + 0, +}; + +int +Echo(int argc,char *argv[]) +{ + int i, done; + char *cp, c, hex[3]; + + for(i=optind;i<argc;i++) { + cp = argv[i]; + done = 0; + while(!done && *cp) { + if (*cp == '\\') { + cp++; + switch(*cp) { + case 'b': /* Backspace */ + c = '\b'; + break; + case 'c': /* No newline, just end here */ + return(CMD_SUCCESS); + case 'n': /* Newline */ + c = '\n'; + break; + case 'r': /* Carriage Return */ + c = '\r'; + break; + case 't': /* Tab */ + c = '\t'; + break; + case 'x': /* Hex conversion */ + cp++; + hex[0] = *cp++; + hex[1] = *cp; + hex[2] = 0; + c = strtol(hex,0,16); + break; + case '\\': /* Backslash */ + c = '\\'; + break; + default: /* Ignore backslash */ + c = *cp; + break; + } + putchar(c); + } + else { + putchar(*cp); + } + if (cp) + cp++; + } + if (i != argc-1) { + putchar(' '); + } + } + putchar('\n'); + flush_console_out(); + return(CMD_SUCCESS); +} +#endif + +/* Call(): + * This function is called when the user wants to execute an + * embedded function. + * The the argument is preceded by an ampersand, then a pointer + * to the argument is passed to the function instead of a + * strtol() conversion. + */ +char *CallHelp[] = { + "Call embedded function", + "-[Aaqv:] {address} [arg1] [arg2] ...", +#if INCLUDE_VERBOSEHELP + " -a build (argc,argv) then call function", +#if INCLUDE_SHELLVARS + " -A build arglist for use by mon_getargv()", +#endif + " -q quiet mode", + " -v {var} put return val in varname", +#endif + 0, +}; + +int +Call(int argc,char *argv[]) +{ + char *varname; + long args[10]; + int i, j, ret, opt, useargc, quiet, monargs; + int (*func)(long,long,long,long,long,long,long,long,long,long); + + quiet = 0; + useargc = 0; + monargs = 0; + varname = (char *)0; + while((opt=getopt(argc,argv,"Aaqv:")) != -1) { + switch(opt) { + case 'a': + useargc = 1; + break; + case 'q': + quiet = 1; + break; + case 'v': + varname = optarg; + break; + case 'A': +#if INCLUDE_SHELLVARS + monargs = 1; + break; +#endif + default: + return(CMD_PARAM_ERROR); + } + } + + if ((argc < optind+1) || (argc > optind+11)) + return(CMD_PARAM_ERROR); + + func = (int(*)(long,long,long,long,long,long,long,long,long,long)) + strtol(argv[optind],(char **)0,0); + + if ((func == 0) && (isdigit(argv[optind][0]) == 0)) { + return(CMD_PARAM_ERROR); + } + + /* If useargc flag is not set, then retrieve and convert + * args from command line. If the first character of the + * argument is an ampersand (&), then a pointer to the argument + * is passed; otherwise, the argument is converted to a long + * integer using strtol()... + */ + if (!useargc) { + for(j=0,i=optind+1;i<argc;i++,j++) { + if (argv[i][0] == '&') + args[j] = (ulong)&argv[i][1]; + else + args[j] = strtol(argv[i],(char **)0,0); + } + } + +#if INCLUDE_SHELLVARS + if (monargs) { + for(j=0,i=optind;i<argc;i++,j++) + putargv(j,argv[i]); + putargv(j,(char *)0); + } +#endif + + if (useargc) { + ret = func(argc-optind,(long)&argv[optind],0,0,0,0,0,0,0,0); + } + else { + ret = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6], + args[7],args[8],args[9]); + } + + if (varname) + shell_sprintf(varname,"0x%x",ret); + + if (!quiet) + printf("Returned: %d (0x%x)\n",ret,ret); + + return(CMD_SUCCESS); +} + +/* Reset(): + * Used to re-initialize the monitor through the command interface. + */ + +char *ResetHelp[] = { + "Reset monitor firmware", + "-[xt:]", +#if INCLUDE_VERBOSEHELP + " -x app_exit", + " -t ## warmstart type", +#endif + 0, +}; + +int +Reset(int argc,char *argv[]) +{ + extern void appexit(int); + int opt; + + intsoff(); + + /* For some systems, the reset occurs while characters are in the + * UART FIFO (so they don't get printed). Adding this delay will + * hopefully allow the characters in the FIFO to drain... + */ + monDelay(250); + + while((opt=getopt(argc,argv,"xt:")) != -1) { + switch(opt) { + case 'x': + appexit(0); + break; + case 't': + monrestart((int)strtol(optarg,0,0)); + break; + default: + return(CMD_PARAM_ERROR); + } + } + target_reset(); + return(CMD_SUCCESS); +} + +#if INCLUDE_TFS +/* WhatCmd(): + * Used to search through a binary file displaying any "WHAT" strings + * that may be present... + * + * Just what is "what"? + * This is a tool that simply prints all strings found that start with + * "@(#)" in an input file. This is called a "what string". It is useful + * for storage of retrievable information from a binary file. + */ + +#define WHATSEARCH 1 +#define WHATMATCH 2 + +char *WhatHelp[] = { + "Search file for 'what' strings; put last result in 'WHATSTRING' shell var", + "[-t:v] {filename}", +#if INCLUDE_VERBOSEHELP + " -t{tok} match on what-string with subtoken", + " -v verbose", +#endif + 0, +}; + + +int +WhatCmd(int argc,char **argv) +{ + TFILE *tfp; + int opt, state, verbose, idx; + char whatbuf[64], *whattok, *varname; + char *ifile, *buf, *end, *bp, *whatstring, *wsp; + + whattok = 0; + whatstring = "@(#)"; + idx = verbose = 0; + varname = "WHATSTRING"; + while((opt=getopt(argc,argv,"t:v")) != -1) { + switch(opt) { + case 'v': + verbose++; + break; + case 't': + whattok = optarg; + break; + default: + return(CMD_FAILURE); + } + } + if (argc-optind != 1) + return(CMD_PARAM_ERROR); + + ifile = argv[optind]; + + /* Open input file: */ + if ((tfp = tfsstat(ifile)) == (TFILE *)0) { + printf("Can't find file: %s\n",ifile); + return(CMD_FAILURE); + } + bp = buf = TFS_BASE(tfp); + end = buf + TFS_SIZE(tfp); + + state = WHATSEARCH; + wsp = whatstring; + setenv(varname,0); + while(bp < end) { + switch(state) { + case WHATSEARCH: + if (*bp == *wsp) { + wsp++; + if (*wsp == 0) { + wsp = whatstring; + state = WHATMATCH; + idx = 0; + if (verbose) + putchar('\t'); + } + } + else + wsp = whatstring; + break; + case WHATMATCH: + if (isprint(*bp)) { + if (verbose) + putchar(*bp); + if (idx < sizeof(whatbuf)-1) + whatbuf[idx++] = *bp; + } + else { + if (verbose) + putchar('\n'); + if (idx < sizeof(whatbuf)) + whatbuf[idx] = 0; + if (whattok) { + if (strstr(whatbuf,whattok)) + setenv(varname,whatbuf); + } + else + setenv(varname,whatbuf); + + state = WHATSEARCH; + } + break; + } + bp++; + } + return(0); +} +#endif diff --git a/main/common/monbuilt.c b/main/common/monbuilt.c new file mode 100644 index 0000000..e4f1951 --- /dev/null +++ b/main/common/monbuilt.c @@ -0,0 +1,46 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * monbuilt.c: + * + * This file contains all of the monitor code that constructs + * the time and date of the build. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +/* whatbuild: + * A 'what' string to allow the 'what' tool to query the binary + * image built with this source code. + */ +#define WHAT_PREFIX "@(#)" + +char *whatbuild = WHAT_PREFIX __DATE__ " @ " __TIME__; + +/* monBuilt(): + * Return a pointer to a string that is a concatenation of the + * build date and build time. + */ + +char * +monBuilt(void) +{ + return(whatbuild+sizeof(WHAT_PREFIX)-1); +} diff --git a/main/common/moncom.c b/main/common/moncom.c new file mode 100644 index 0000000..319d884 --- /dev/null +++ b/main/common/moncom.c @@ -0,0 +1,427 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * moncom.c: + * + * This function is used by the application to interface to code that + * is part of the monitor. A pointer to this function exists at some + * "well-known" address in the monitors space. This location must be + * known by the application (hence... "well-known"). + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "monlib.h" +#include "genlib.h" +#include "stddefs.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "monflags.h" +#include "pci.h" +#include "i2c.h" +#include "ether.h" +#include "flash.h" +#include "date.h" +#include "timer.h" + +extern int addcommand(struct monCommand *cmdlist, char *cmdlvl); +extern int profiler(void *); +static int moncom_pcnt; + +int monErrorStub(void); + +int +moncom(int cmd, void *arg1, void *arg2, void *arg3) +{ + int retval; + + /* eliminate warnings due to arg2 & arg3 not being used... + */ + if (arg2 == arg3) + retval = 0; + else + retval = 0; + + switch(cmd) { + case GETMONFUNC_PUTCHAR: + *(unsigned long *)arg1 = (unsigned long)putchar; + break; + case GETMONFUNC_GETCHAR: + *(unsigned long *)arg1 = (unsigned long)getchar; + break; + case GETMONFUNC_GOTACHAR: + *(unsigned long *)arg1 = (unsigned long)gotachar; + break; + case GETMONFUNC_GETBYTES: + *(unsigned long *)arg1 = (unsigned long)getbytes; + break; + case GETMONFUNC_PRINTF: + *(unsigned long *)arg1 = (unsigned long)printf; + break; + case GETMONFUNC_CPRINTF: + *(unsigned long *)arg1 = (unsigned long)cprintf; + break; + case GETMONFUNC_SPRINTF: + *(unsigned long *)arg1 = (unsigned long)sprintf; + break; + case GETMONFUNC_RESTART: + *(unsigned long *)arg1 = (unsigned long)monrestart; + break; + case GETMONFUNC_GETENV: + *(unsigned long *)arg1 = (unsigned long)getenv; + break; + case GETMONFUNC_SETENV: + *(unsigned long *)arg1 = (unsigned long)setenv; + break; + +#if !INCLUDE_TFS + case GETMONFUNC_TFSINIT: + case GETMONFUNC_TFSADD: + case GETMONFUNC_TFSUNLINK: + case GETMONFUNC_TFSRUN: + case GETMONFUNC_TFSNEXT: + case GETMONFUNC_TFSFSTAT: + case GETMONFUNC_TFSTRUNCATE: + case GETMONFUNC_TFSEOF: + case GETMONFUNC_TFSSTAT: + case GETMONFUNC_TFSREAD: + case GETMONFUNC_TFSWRITE: + case GETMONFUNC_TFSOPEN: + case GETMONFUNC_TFSCLOSE: + case GETMONFUNC_TFSSEEK: + case GETMONFUNC_TFSGETLINE: + case GETMONFUNC_TFSIPMOD: + case GETMONFUNC_TFSCTRL: + case GETMONFUNC_TFSLINK: + case GETMONFUNC_TFSTELL: +#endif +#if !INCLUDE_UNZIP + case GETMONFUNC_DECOMPRESS: +#endif +#if !INCLUDE_MALLOC + case GETMONFUNC_MALLOC: + case GETMONFUNC_FREE: + case GETMONFUNC_HEAPXTEND: +#endif +#if !INCLUDE_PROFILER + case GETMONFUNC_PROFILER: +#endif +#if !INCLUDE_BBC + case GETMONFUNC_BBC: +#endif +#if !INCLUDE_MEMTRACE + case GETMONFUNC_MEMTRACE: +#endif +#if !INCLUDE_ETHERNET + case GETMONFUNC_SENDENETPKT: + case GETMONFUNC_RECVENETPKT: +#endif +#if !INCLUDE_ETHERVERBOSE + case GETMONFUNC_PRINTPKT: +#endif +#if !INCLUDE_FLASH + case GETMONFUNC_FLASHWRITE: + case GETMONFUNC_FLASHERASE: + case GETMONFUNC_FLASHINFO: + case GETMONFUNC_FLASHOVRRD: +#endif +#if !INCLUDE_PORTCMD + case GETMONFUNC_PORTCMD: +#endif +#ifndef ALLOW_HANDLER_ASSIGNMENT + case GETMONFUNC_ASSIGNHDLR: +#endif +#ifndef NO_MONLIB_PCI_STUBS + case GETMONFUNC_PCICFGREAD: + case GETMONFUNC_PCICFGWRITE: + case GETMONFUNC_PCICONTROL: +#endif +#ifndef NO_MONLIB_I2C_STUBS + case GETMONFUNC_I2CWRITE: + case GETMONFUNC_I2CREAD: + case GETMONFUNC_I2CCONTROL: +#endif +#if !INCLUDE_TIMEOFDAY + case GETMONFUNC_TIMEOFDAY: +#endif +#if !INCLUDE_SHELLVARS + case GETMONFUNC_GETARGV: +#endif + case GETMONFUNC_PIOGET: /* As of uMon 1.0, these are */ + case GETMONFUNC_PIOSET: /* no longer supported. */ + case GETMONFUNC_PIOCLR: + *(unsigned long *)arg1 = (unsigned long)monErrorStub; + break; + +#if INCLUDE_TFS + case GETMONFUNC_TFSINIT: + *(unsigned long *)arg1 = (unsigned long)tfsinit; + break; + case GETMONFUNC_TFSADD: + *(unsigned long *)arg1 = (unsigned long)tfsadd; + break; + case GETMONFUNC_TFSUNLINK: + *(unsigned long *)arg1 = (unsigned long)tfsunlink; + break; + case GETMONFUNC_TFSRUN: + *(unsigned long *)arg1 = (unsigned long)tfsrun; + break; + case GETMONFUNC_TFSNEXT: + *(unsigned long *)arg1 = (unsigned long)tfsnext; + break; + case GETMONFUNC_TFSFSTAT: + *(unsigned long *)arg1 = (unsigned long)tfsfstat; + break; + case GETMONFUNC_TFSTRUNCATE: + *(unsigned long *)arg1 = (unsigned long)tfstruncate; + break; + case GETMONFUNC_TFSEOF: + *(unsigned long *)arg1 = (unsigned long)tfseof; + break; + case GETMONFUNC_TFSSTAT: + *(unsigned long *)arg1 = (unsigned long)tfsstat; + break; + case GETMONFUNC_TFSREAD: + *(unsigned long *)arg1 = (unsigned long)tfsread; + break; + case GETMONFUNC_TFSWRITE: + *(unsigned long *)arg1 = (unsigned long)tfswrite; + break; + case GETMONFUNC_TFSOPEN: + *(unsigned long *)arg1 = (unsigned long)tfsopen; + break; + case GETMONFUNC_TFSCLOSE: + *(unsigned long *)arg1 = (unsigned long)tfsclose; + break; + case GETMONFUNC_TFSSEEK: + *(unsigned long *)arg1 = (unsigned long)tfsseek; + break; + case GETMONFUNC_TFSGETLINE: + *(unsigned long *)arg1 = (unsigned long)tfsgetline; + break; + case GETMONFUNC_TFSIPMOD: + *(unsigned long *)arg1 = (unsigned long)tfsipmod; + break; + case GETMONFUNC_TFSCTRL: + *(unsigned long *)arg1 = (unsigned long)tfsctrl; + break; + case GETMONFUNC_TFSLINK: + *(unsigned long *)arg1 = (unsigned long)tfslink; + break; + case GETMONFUNC_TFSTELL: + *(unsigned long *)arg1 = (unsigned long)tfstell; + break; +#endif +#if INCLUDE_UNZIP + case GETMONFUNC_DECOMPRESS: + *(unsigned long *)arg1 = (unsigned long)decompress; + break; +#endif +#if INCLUDE_MALLOC + case GETMONFUNC_MALLOC: + *(unsigned long *)arg1 = (unsigned long)malloc; + break; + case GETMONFUNC_FREE: + *(unsigned long *)arg1 = (unsigned long)free; + break; + case GETMONFUNC_HEAPXTEND: + *(unsigned long *)arg1 = (unsigned long)extendHeap; + break; +#endif +#if INCLUDE_PROFILER + case GETMONFUNC_PROFILER: + *(unsigned long *)arg1 = (unsigned long)profiler; + break; +#endif +#if INCLUDE_BBC + case GETMONFUNC_BBC: + *(unsigned long *)arg1 = (unsigned long)bbc; + break; +#endif +#if INCLUDE_MEMTRACE + case GETMONFUNC_MEMTRACE: + *(unsigned long *)arg1 = (unsigned long)Mtrace; + break; +#endif +#if INCLUDE_ETHERNET + case GETMONFUNC_SENDENETPKT: + *(unsigned long *)arg1 = (unsigned long)monSendEnetPkt; + break; + case GETMONFUNC_RECVENETPKT: + *(unsigned long *)arg1 = (unsigned long)monRecvEnetPkt; + break; +#endif +#if INCLUDE_ETHERVERBOSE + case GETMONFUNC_PRINTPKT: + *(unsigned long *)arg1 = (unsigned long)AppPrintPkt; + break; +#endif +#if INCLUDE_FLASH + case GETMONFUNC_FLASHOVRRD: + *(unsigned long *)arg1 = (unsigned long)FlashOpOverride; + break; + case GETMONFUNC_FLASHWRITE: + *(unsigned long *)arg1 = (unsigned long)AppFlashWrite; + break; + case GETMONFUNC_FLASHERASE: + *(unsigned long *)arg1 = (unsigned long)AppFlashErase; + break; + case GETMONFUNC_FLASHINFO: + *(unsigned long *)arg1 = (unsigned long)sectortoaddr; + break; +#endif +#if INCLUDE_PORTCMD + case GETMONFUNC_PORTCMD: + *(unsigned long *)arg1 = (unsigned long)portCmd; + break; +#endif +#ifdef ALLOW_HANDLER_ASSIGNMENT + case GETMONFUNC_ASSIGNHDLR: + *(unsigned long *)arg1 = (unsigned long)assign_handler; + break; +#endif +#ifdef NO_MONLIB_I2C_STUBS + case GETMONFUNC_I2CWRITE: + *(unsigned long *)arg1 = (unsigned long)i2cWrite; + break; + case GETMONFUNC_I2CREAD: + *(unsigned long *)arg1 = (unsigned long)i2cRead; + break; + case GETMONFUNC_I2CCONTROL: + *(unsigned long *)arg1 = (unsigned long)i2cCtrl; + break; +#endif +#ifdef NO_MONLIB_PCI_STUBS + case GETMONFUNC_PCICFGREAD: + *(unsigned long *)arg1 = (unsigned long)pciCfgRead; + break; + case GETMONFUNC_PCICFGWRITE: + *(unsigned long *)arg1 = (unsigned long)pciCfgWrite; + break; + case GETMONFUNC_PCICONTROL: + *(unsigned long *)arg1 = (unsigned long)pciCtrl; + break; +#endif +#if INCLUDE_TIMEOFDAY + case GETMONFUNC_TIMEOFDAY: + *(unsigned long *)arg1 = (unsigned long)timeofday; + break; +#endif +#if INCLUDE_SHELLVARS + case GETMONFUNC_GETARGV: + *(unsigned long *)arg1 = (unsigned long)getargv; + break; +#endif + case GETMONFUNC_ADDCOMMAND: + *(unsigned long *)arg1 = (unsigned long)addcommand; + break; + case GETMONFUNC_DOCOMMAND: + *(unsigned long *)arg1 = (unsigned long)docommand; + break; + case GETMONFUNC_CRC16: + *(unsigned long *)arg1 = (unsigned long)xcrc16; + break; + case GETMONFUNC_CRC32: + *(unsigned long *)arg1 = (unsigned long)crc32; + break; + case GETMONFUNC_INTSOFF: + *(unsigned long *)arg1 = (unsigned long)intsoff; + break; + case GETMONFUNC_INTSRESTORE: + *(unsigned long *)arg1 = (unsigned long)intsrestore; + break; + case GETMONFUNC_APPEXIT: + *(unsigned long *)arg1 = (unsigned long)appexit; + break; + case GETMONFUNC_GETLINE: + *(unsigned long *)arg1 = (unsigned long)getline; + break; + case GETMONFUNC_VERSION: + *(unsigned long *)arg1 = (unsigned long)monVersion; + break; + case GETMONFUNC_WARMSTART: + *(unsigned long *)arg1 = (unsigned long)AppWarmStart; + break; + case GETMONFUNC_MONDELAY: + *(unsigned long *)arg1 = (unsigned long)monDelay; + break; + case GETMONFUNC_GETENVP: + *(unsigned long *)arg1 = (unsigned long)getenvp; + break; + case GETMONFUNC_REALLOC: + *(unsigned long *)arg1 = (unsigned long)realloc; + break; + case GETMONFUNC_GETSYM: + *(unsigned long *)arg1 = (unsigned long)getsym; + break; + case GETMONFUNC_WATCHDOG: + *(unsigned long *)arg1 = (unsigned long)monWatchDog; + break; + case GETMONFUNC_PRINTMEM: + *(unsigned long *)arg1 = (unsigned long)printMem; + break; + case GETMONFUNC_TIMER: + *(unsigned long *)arg1 = (unsigned long)monTimer; + break; + case CACHEFTYPE_DFLUSH: + dcacheFlush = (int(*)(char *,int))arg1; + break; + case CACHEFTYPE_IINVALIDATE: + icacheInvalidate = (int(*)(char *,int))arg1; + break; + case CHARFUNC_PUTCHAR: + remoteputchar = (int(*)(int))arg1; + break; + case CHARFUNC_GETCHAR: + remotegetchar = (int(*)(void))arg1; + break; + case CHARFUNC_GOTACHAR: + remotegotachar = (int(*)(void))arg1; + break; + case CHARFUNC_RAWMODEON: + remoterawon = (int(*)(void))arg1; + break; + case CHARFUNC_RAWMODEOFF: + remoterawoff = (int(*)(void))arg1; + break; + case ASSIGNFUNC_GETUSERLEVEL: + extgetUsrLvl = (int(*)(void))arg1; + break; +#ifdef WATCHDOG_ENABLED + case ASSIGNFUNC_WATCHDOG: + remoteWatchDog = (int(*)(void))arg1; + break; +#endif + default: + printf("moncom unknown command: 0x%x\n",cmd); + retval = -1; + break; + } + moncom_pcnt++; + return(retval); +} + +int +monErrorStub(void) +{ + printf("ERROR: Facility not included in monitor build\n"); + return(-1); +} diff --git a/main/common/moncomptr.S b/main/common/moncomptr.S new file mode 100644 index 0000000..3ad94dd --- /dev/null +++ b/main/common/moncomptr.S @@ -0,0 +1,39 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * moncomptr.S: + * + * The tag moncomptr is a tag established at a point in the target's + * memory map that is unlikely to change as a result of rebuilding the + * monitor. As a result, this file is included by most of the target + * ports in the very beginning of the reset space. + * + * The address of moncom (moncomptr) is used by the monConnect() + * function in application space when the application attempts to + * connect to the monitor's API. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + .extern moncom + .global moncomptr + +moncomptr: + .long moncom diff --git a/main/common/monflags.h b/main/common/monflags.h new file mode 100644 index 0000000..d4260ea --- /dev/null +++ b/main/common/monflags.h @@ -0,0 +1,56 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * monflags.h + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _MONFLAGS_H_ +#define _MONFLAGS_H_ + +struct monflag { + unsigned long bit; + char *flagname; +}; + +extern int monitorFlags; + +#define NOMONHEADER (1 << 0) /* Don't print header at startup */ +#define NODEFRAGPRN (1 << 1) /* Don't print defrag message */ +#define NOTFTPPRN (1 << 2) /* Don't print tftp message */ +#define NOMONCMDPRN (1 << 3) /* Don't print MONCMD message */ +#define NOTFTPOVW (1 << 4) /* Don't allow tftp srvr to overwrite */ + /* an existing file. */ +#define MONCOMVERBOSE (1 << 5) /* The moncom() function will print */ + /* status. */ +#define NOEXITSTATUS (1 << 6) /* Don't print app exit status. */ + +#define MFLAGS_NOMONHEADER() (monitorFlags & NOMONHEADER) +#define MFLAGS_NODEFRAGPRN() (monitorFlags & NODEFRAGPRN) +#define MFLAGS_NOTFTPPRN() (monitorFlags & NOTFTPPRN) +#define MFLAGS_NOMONCMDPRN() (monitorFlags & NOMONCMDPRN) +#define MFLAGS_NOTFTPOVW() (monitorFlags & NOTFTPOVW) +#define MFLAGS_MONCOMVERBOSE() (monitorFlags & MONCOMVERBOSE) +#define MFLAGS_NOEXITSTATUS() (monitorFlags & NOEXITSTATUS) + +extern void InitMonitorFlags(void); + +#endif diff --git a/main/common/monlib.c b/main/common/monlib.c new file mode 100644 index 0000000..40204af --- /dev/null +++ b/main/common/monlib.c @@ -0,0 +1,1133 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * monlib.c: + * + * This file is part of the monitor code, but it is actually linked into + * the application. It is built with (but not linked with) the monitor, + * then the monlib.o file is linked with the application. + * The only requirement on the application is that it know where the address + * of the monCom function is in the monitor's space. + * The monCom function will be accessible in some "well-known" way (processor + * and platform dependent) so that this will not be a problem. + * + * This monlib.c file is a replacement for the older mechanism that was + * a bit more error-prone... A table of function pointers existed at some + * well-known location in the monitor, and the content of that table was + * assumed to also be "well-known". This new version only assumes that the + * pointer to monCom is well-known; everything else will work based on the + * fact that the monitor and application will share the monlib.h header + * file. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "monlib.h" + +static int (*_tfsseek)(int,int,int); +static int (*_tfsgetline)(int,char *,int); +static int (*_tfsipmod)(char *,char *,int,int); +static int (*_tfsinit)(void); +static int (*_tfsadd)(char *,char *,char *,unsigned char *,int); +static int (*_tfsunlink)(char *); +static int (*_tfsrun)(char **,int); +static int (*_tfsread)(int,char *,int); +static int (*_tfswrite)(int,char *,int); +static int (*_tfsopen)(char *,long,char *); +static int (*_tfsclose)(int,char *); +static int (*_printf)(); +static int (*_cprintf)(); +static int (*_sprintf)(); +static int (*_monrestart)(int); +static int (*_rputchar)(unsigned char c); +static int (*_getchar)(void); +static int (*_gotachar)(void); +static int (*_getbytes)(char *,int,int); +static int (*_addcommand)(struct monCommand *,char *); +static int (*_docommand)(char *,int); +static int (*_getline)(char *,int,int); +static int (*_tfsfstat)(char *,struct tfshdr *); +static int (*_tfseof)(int); +static int (*_decompress)(char *,int,char *); +static int (*_tfstruncate)(int,long); +static int (*_heapextend)(char *,int); +static int (*_tfslink)(char *,char *); +static int (*_pcicfgwrite)(int,int,int,int,int,unsigned long); +static int (*_i2cwrite)(int,int,unsigned char *,int); +static int (*_i2cread)(int,int,unsigned char *,int); +static int (*_flashwrite)(char *,char *,int); +static int (*_flasherase)(int); +static int (*_flashinfo)(int,int *,char **); +static int (*_flashoverride)(void *,int,int); +static int (*_sendenet)(char *,int); +static int (*_recvenet)(char *,int); +static int (*_printpkt)(char *,int,int); +static int (*_setenv)(char *,char *); +static int (*_watchdog)(void); +static int (*_timeofday)(int,void *); +static int (*_montimer)(int cmd, void *arg); + +static char *(*_getenv)(char *); +static char *(*_version)(void); +static char *(*_getenvp)(void); +#ifdef MALLOC_DEBUG +static char *(*_malloc)(int,char *,int); +static char *(*_realloc)(char *buf,int,char *,int); +#else +static char *(*_malloc)(int); +static char *(*_realloc)(char *,int); +#endif +static char *(*_getsym)(char *,char *,int); + +static void (*_intsrestore)(unsigned long); +static void (*_appexit)(int); +static void (*_free)(char *); +static void (*_getargv)(int *,char ***); +static void (*_profiler)(void *); +static void (*_bbc)(char *,int); +static void (*_memtrace)(); +static void (*_appwarmstart)(unsigned long); +static void (*_mondelay)(long); +static void (*_printmem)(char *,int,int); + +static long (*_tfsctrl)(int,long,long); +static long (*_tfstell)(int); +static long (*_portcmd)(int,void *); + +static struct tfshdr *(*_tfsnext)(struct tfshdr *); +static struct tfshdr *(*_tfsstat)(char *); + +static unsigned long (*_i2cctrl)(int,int,unsigned long,unsigned long); +static unsigned long (*_pcicfgread)(int,int,int,int,int); +static unsigned long (*_pcictrl)(int,int,unsigned long,unsigned long); +static unsigned long (*_crc32)(unsigned char *,unsigned long); +static unsigned long (*_intsoff)(void); +static unsigned long (*_assign_handler)(long,unsigned long,unsigned long); + +static unsigned short (*_xcrc16)(unsigned char *,unsigned long); + + +static void (*_monlock)(void); +static void (*_monunlock)(void); +static int (*_moncom)(int,void *,void *, void *); + +/************************************************************************** + * + * The following macros support the default monitor lock/unlock mechanism when + * they point to monLock and monUnlock. If something other than the default + * is to be used, then simply redefine them here. Refer to the monitor + * app note that discusses multi-tasking access to the monitor API for more + * information. + * + * TFS_MONLOCK/UNLOCK: + * Lock/unlock for functions that access TFS flash space: + */ +#define TFS_MONLOCK monLock +#define TFS_MONUNLOCK monUnlock + +/* ENV_MONLOCK/UNLOCK: + * Lock/unlock for functions that access monitor shell variables: + */ +#define ENV_MONLOCK monLock +#define ENV_MONUNLOCK monUnlock + +/* CONSOLE_MONLOCK/UNLOCK: + * Lock/unlock for functions in the monitor that deal with console output. + */ +#define CONSOLE_MONLOCK monLock +#define CONSOLE_MONUNLOCK monUnlock + +/* HEAP_MONLOCK/UNLOCK: + * Lock/unlock for functions in the monitor that deal with the heap. + */ +#define HEAP_MONLOCK monLock +#define HEAP_MONUNLOCK monUnlock + +/* BLOCKING_MONLOCK/UNLOCK: + * Lock/unlock for functions in the monitor that block waiting for + * console input. + */ +#define BLOCKING_MONLOCK monLock +#define BLOCKING_MONUNLOCK monUnlock + +/* GENERIC_MONLOCK/UNLOCK: + * Lock/unlock for all functions not covered by the above macros. + */ +#define GENERIC_MONLOCK monLock +#define GENERIC_MONUNLOCK monUnlock + +/************************************************************************** + * + * monConnect(): + * This must be the first call by the application code to talk to the + * monitor. It is expecting three incoming function pointers: + * + * mon: Points to the monitor's _moncom function; + * This is a "well-known" address because the monitor and + * application code (two separately linked binaries) must + * know it. + * lock: Points to a function in the application code that will be + * used by the monitor as a lock-out function (some kind of + * semaphore in the application). + * unlock: Points to a function in the application code that will be + * used by the monitor as an un-lock-out function (undo whatever + * lock-out mechanism was done by lock). + */ +int +monConnect(int (*mon)(int,void *,void *,void *), + void (*lock)(void), void (*unlock)(void)) +{ + int rc = 0; + + /* Assign incoming lock and unlock functions... */ + _monlock = lock; + _monunlock = unlock; + + /* If the mon pointer is non-zero, then make the mon_ connections... */ + if (mon) { + + _moncom = mon; + + /* Make the connections between "mon_" functions that are */ + /* symbolically accessible by the application and the corresponding */ + /* functions that exists in the monitor. */ + rc += _moncom(GETMONFUNC_PUTCHAR,&_rputchar,0,0); + rc += _moncom(GETMONFUNC_GETCHAR,&_getchar,0,0); + rc += _moncom(GETMONFUNC_GOTACHAR,&_gotachar,0,0); + rc += _moncom(GETMONFUNC_GETBYTES,&_getbytes,0,0); + rc += _moncom(GETMONFUNC_PRINTF,&_printf,0,0); + rc += _moncom(GETMONFUNC_CPRINTF,&_cprintf,0,0); + rc += _moncom(GETMONFUNC_SPRINTF,&_sprintf,0,0); + rc += _moncom(GETMONFUNC_RESTART,&_monrestart,0,0); + rc += _moncom(GETMONFUNC_GETENV,&_getenv,0,0); + rc += _moncom(GETMONFUNC_SETENV,&_setenv,0,0); + rc += _moncom(GETMONFUNC_TFSINIT,&_tfsinit,0,0); + rc += _moncom(GETMONFUNC_TFSADD,&_tfsadd,0,0); + rc += _moncom(GETMONFUNC_TFSUNLINK,&_tfsunlink,0,0); + rc += _moncom(GETMONFUNC_TFSRUN,&_tfsrun,0,0); + rc += _moncom(GETMONFUNC_TFSNEXT,&_tfsnext,0,0); + rc += _moncom(GETMONFUNC_TFSSTAT,&_tfsstat,0,0); + rc += _moncom(GETMONFUNC_TFSREAD,&_tfsread,0,0); + rc += _moncom(GETMONFUNC_TFSWRITE,&_tfswrite,0,0); + rc += _moncom(GETMONFUNC_TFSOPEN,&_tfsopen,0,0); + rc += _moncom(GETMONFUNC_TFSCLOSE,&_tfsclose,0,0); + rc += _moncom(GETMONFUNC_TFSSEEK,&_tfsseek,0,0); + rc += _moncom(GETMONFUNC_TFSGETLINE,&_tfsgetline,0,0); + rc += _moncom(GETMONFUNC_TFSIPMOD,&_tfsipmod,0,0); + rc += _moncom(GETMONFUNC_TFSCTRL,&_tfsctrl,0,0); + rc += _moncom(GETMONFUNC_ADDCOMMAND,&_addcommand,0,0); + rc += _moncom(GETMONFUNC_DOCOMMAND,&_docommand,0,0); + rc += _moncom(GETMONFUNC_GETARGV,&_getargv,0,0); + rc += _moncom(GETMONFUNC_CRC16,&_xcrc16,0,0); + rc += _moncom(GETMONFUNC_CRC32,&_crc32,0,0); + rc += _moncom(GETMONFUNC_INTSOFF,&_intsoff,0,0); + rc += _moncom(GETMONFUNC_INTSRESTORE,&_intsrestore,0,0); + rc += _moncom(GETMONFUNC_APPEXIT,&_appexit,0,0); + rc += _moncom(GETMONFUNC_MALLOC,&_malloc,0,0); + rc += _moncom(GETMONFUNC_FREE,&_free,0,0); + rc += _moncom(GETMONFUNC_GETLINE,&_getline,0,0); + rc += _moncom(GETMONFUNC_TFSFSTAT,&_tfsfstat,0,0); + rc += _moncom(GETMONFUNC_TFSEOF,&_tfseof,0,0); + rc += _moncom(GETMONFUNC_DECOMPRESS,&_decompress,0,0); + rc += _moncom(GETMONFUNC_TFSTRUNCATE,&_tfstruncate,0,0); + rc += _moncom(GETMONFUNC_HEAPXTEND,&_heapextend,0,0); + rc += _moncom(GETMONFUNC_PROFILER,&_profiler,0,0); + rc += _moncom(GETMONFUNC_TFSLINK,&_tfslink,0,0); + rc += _moncom(GETMONFUNC_BBC,&_bbc,0,0); + rc += _moncom(GETMONFUNC_MEMTRACE,&_memtrace,0,0); + rc += _moncom(GETMONFUNC_TFSTELL,&_tfstell,0,0); + rc += _moncom(GETMONFUNC_VERSION,&_version,0,0); + rc += _moncom(GETMONFUNC_WARMSTART,&_appwarmstart,0,0); + rc += _moncom(GETMONFUNC_PCICFGREAD,&_pcicfgread,0,0); + rc += _moncom(GETMONFUNC_PCICFGWRITE,&_pcicfgwrite,0,0); + rc += _moncom(GETMONFUNC_PCICONTROL,&_pcictrl,0,0); + rc += _moncom(GETMONFUNC_I2CREAD,&_i2cread,0,0); + rc += _moncom(GETMONFUNC_I2CWRITE,&_i2cwrite,0,0); + rc += _moncom(GETMONFUNC_I2CCONTROL,&_i2cctrl,0,0); + rc += _moncom(GETMONFUNC_MONDELAY,&_mondelay,0,0); + rc += _moncom(GETMONFUNC_GETENVP,&_getenvp,0,0); + rc += _moncom(GETMONFUNC_REALLOC,&_realloc,0,0); + rc += _moncom(GETMONFUNC_SENDENETPKT,&_sendenet,0,0); + rc += _moncom(GETMONFUNC_RECVENETPKT,&_recvenet,0,0); + rc += _moncom(GETMONFUNC_GETSYM,&_getsym,0,0); + rc += _moncom(GETMONFUNC_PRINTPKT,&_printpkt,0,0); + rc += _moncom(GETMONFUNC_FLASHWRITE,&_flashwrite,0,0); + rc += _moncom(GETMONFUNC_FLASHERASE,&_flasherase,0,0); + rc += _moncom(GETMONFUNC_FLASHINFO,&_flashinfo,0,0); + rc += _moncom(GETMONFUNC_ASSIGNHDLR,&_assign_handler,0,0); + rc += _moncom(GETMONFUNC_WATCHDOG,&_watchdog,0,0); + rc += _moncom(GETMONFUNC_PRINTMEM,&_printmem,0,0); + rc += _moncom(GETMONFUNC_PORTCMD,&_portcmd,0,0); + rc += _moncom(GETMONFUNC_TIMEOFDAY,&_timeofday,0,0); + rc += _moncom(GETMONFUNC_TIMER,&_montimer,0,0); + rc += _moncom(GETMONFUNC_FLASHOVRRD,&_flashoverride,0,0); + } + return(rc); +} + +/* ignorelock: + * Used as a back-door to disable the monLock()/monUnlock() stuff. + * This is useful if the application CLI falls through to the monitor's + * CLI and you are using the "call" command in the monitor to execute some + * function that has a mon_xxx function in it. In this case, the fact that + * the application has fallen through to the monitor means that the lock + * is already active, so when the function tries to call some other mon_xxx + * function it won't be able to because of the lock already being set. + * + * With these functions in the application space, the user can do the + * following: + * call %DisableLock + * call %Func_with_monXXX_in_it + * call %EnableLock + * + * Note that this is NOT to be used by application code, it is simply a + * back-door mechanism to allow "call" from the CLI to invoke functions + * that have mon_XXX functionality in them. + */ +static int ignorelock = 0; + +void +DisableMonLock(void) +{ + ignorelock = 2; +} + +void +EnableMonLock(void) +{ + ignorelock = 0; +} + +/* monLock() & monUnlock(): + * Used by all of the wrapper functions below this point to call + * the function pointed to by _monlock & _monunlock function pointers + * (if set). + * These functions must test both the function pointer and the state + * of the ignorelock variable. The function DisableMonLock() sets the + * ignorelock variable to 2 because it is being executed through "call" + * which means that the lock is active. + */ +static void +monLock() +{ + if (_monlock) { + switch(ignorelock) { + case 1: + break; + case 2: + ignorelock--; + break; + default: + _monlock(); + break; + } + } +} + +static void +monUnlock() +{ + if (_monunlock) { + switch(ignorelock) { + case 1: + break; + case 2: + ignorelock--; + default: + _monunlock(); + break; + } + } +} + +int +mon_com(int cmd, void *arg1, void *arg2, void *arg3) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _moncom(cmd,arg1,arg2,arg3); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_putchar(char c) +{ + int ret; + + CONSOLE_MONLOCK(); + ret = _rputchar(c); + CONSOLE_MONUNLOCK(); + return(ret); +} + +int +mon_getchar(void) +{ + int ret; + + BLOCKING_MONLOCK(); + ret = _getchar(); + BLOCKING_MONUNLOCK(); + return(ret); +} + +int +mon_gotachar(void) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _gotachar(); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_getbytes(char *buf,int cnt,int block) +{ + int ret; + + BLOCKING_MONLOCK(); + ret = _getbytes(buf,cnt,block); + BLOCKING_MONUNLOCK(); + return(ret); +} + +int +mon_printf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +char *fmt; +int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12; +{ + int ret; + + CONSOLE_MONLOCK(); + ret = _printf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); + CONSOLE_MONUNLOCK(); + return(ret); +} + +int +mon_cprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +char *fmt; +int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12; +{ + int ret; + + CONSOLE_MONLOCK(); + ret = _cprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); + CONSOLE_MONUNLOCK(); + return(ret); +} + +int +mon_sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +char *fmt, *buf; +int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12; +{ + int ret; + + GENERIC_MONLOCK(); + ret = _sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_restart(int val) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _monrestart(val); + GENERIC_MONUNLOCK(); + return(ret); +} + +char * +mon_getenvp(void) +{ + char *ret; + + ENV_MONLOCK(); + ret = _getenvp(); + ENV_MONUNLOCK(); + return(ret); +} + +char * +mon_getenv(char *name) +{ + char *ret; + + ENV_MONLOCK(); + ret = _getenv(name); + ENV_MONUNLOCK(); + return(ret); +} + +int +mon_setenv(char *name,char *val) +{ + int ret; + + ENV_MONLOCK(); + ret = _setenv(name,val); + ENV_MONUNLOCK(); + return(ret); +} + +char * +mon_getsym(char *name,char *buf, int bufsize) +{ + char *ret; + + ENV_MONLOCK(); + ret = _getsym(name,buf,bufsize); + ENV_MONUNLOCK(); + return(ret); +} + +int +mon_tfsinit(void) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsinit(); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsadd(char *name, char *info, char *flags, unsigned char *src, int size) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsadd(name,info,flags,src,size); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfslink(char *src, char *target) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfslink(src,target); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsunlink(char *name) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsunlink(name); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsrun(char **name,int verbose) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsrun(name,verbose); + TFS_MONUNLOCK(); + return(ret); +} + +struct tfshdr * +mon_tfsnext(struct tfshdr *fp) +{ + struct tfshdr *ret; + + TFS_MONLOCK(); + ret = _tfsnext(fp); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfstruncate(int tfd, long len) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfstruncate(tfd,len); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfseof(int tfd) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfseof(tfd); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsfstat(char *name, struct tfshdr *fp) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsfstat(name,fp); + TFS_MONUNLOCK(); + return(ret); +} + +struct tfshdr * +mon_tfsstat(char *name) +{ + struct tfshdr *ret; + + TFS_MONLOCK(); + ret = _tfsstat(name); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsread(int fd, char *buf, int cnt) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsread(fd,buf,cnt); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfswrite(int fd, char *buf, int cnt) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfswrite(fd,buf,cnt); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsopen(char *file,long flagmode,char *buf) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsopen(file,flagmode,buf); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsclose(int fd,char *info) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsclose(fd,info); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsseek(int fd, int offset, int whence) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsseek(fd,offset,whence); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsgetline(int fd,char *bp,int max) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsgetline(fd,bp,max); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_tfsipmod(char *name,char *buf,int offset,int size) +{ + int ret; + + TFS_MONLOCK(); + ret = _tfsipmod(name,buf,offset,size); + TFS_MONUNLOCK(); + return(ret); +} + +long +mon_tfsctrl(int rqst,long arg1,long arg2) +{ + long ret; + + TFS_MONLOCK(); + ret = _tfsctrl(rqst,arg1,arg2); + TFS_MONUNLOCK(); + return(ret); +} + +long +mon_tfstell(int fd) +{ + long ret; + + TFS_MONLOCK(); + ret = _tfstell(fd); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_addcommand(struct monCommand *cmdlist, char *cmdlvl) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _addcommand(cmdlist,cmdlvl); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_docommand(char *cmdline,int verbose) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _docommand(cmdline,verbose); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_getargv(int *argc,char ***argv) +{ + GENERIC_MONLOCK(); + _getargv(argc,argv); + GENERIC_MONUNLOCK(); +} + +unsigned long +mon_crc32(char *buf,long nbytes) +{ + unsigned long ret; + + GENERIC_MONLOCK(); + ret = _crc32((unsigned char *)buf,nbytes); + GENERIC_MONUNLOCK(); + return(ret); +} + +unsigned short +mon_xcrc16(char *buf,long nbytes) +{ + unsigned short ret; + + GENERIC_MONLOCK(); + ret = _xcrc16((unsigned char *)buf,nbytes); + GENERIC_MONUNLOCK(); + return(ret); +} + +unsigned long +mon_intsoff(void) +{ + unsigned long ret; + + GENERIC_MONLOCK(); + ret = _intsoff(); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_intsrestore(unsigned long msr) +{ + GENERIC_MONLOCK(); + _intsrestore(msr); + GENERIC_MONUNLOCK(); +} + +void +mon_appexit(int val) +{ + GENERIC_MONLOCK(); + _appexit(val); + GENERIC_MONUNLOCK(); +} + +#ifdef MALLOC_DEBUG +char * +mon_malloc(int size,char *fname,int fline) +{ + char *ret; + + HEAP_MONLOCK(); + ret = _malloc(size,fname,fline); + HEAP_MONUNLOCK(); + return(ret); +} + +char * +mon_realloc(char *buf, int size, char *fname, int fline) +{ + char *ret; + + HEAP_MONLOCK(); + ret = _realloc(buf,size, fname, fline); + HEAP_MONUNLOCK(); + return(ret); +} +#else +char * +mon_malloc(int size) +{ + char *ret; + + HEAP_MONLOCK(); + ret = _malloc(size); + HEAP_MONUNLOCK(); + return(ret); +} + +char * +mon_realloc(char *buf, int size) +{ + char *ret; + + HEAP_MONLOCK(); + ret = _realloc(buf,size); + HEAP_MONUNLOCK(); + return(ret); +} +#endif + +void +mon_free(char *cp) +{ + HEAP_MONLOCK(); + _free(cp); + HEAP_MONUNLOCK(); +} + +int +mon_getline(char *buf,int max,int ledit) +{ + int ret; + + BLOCKING_MONLOCK(); + ret = _getline(buf,max,ledit); + BLOCKING_MONUNLOCK(); + return(ret); +} + +int +mon_decompress(char *src,int srcsize,char *dest) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _decompress(src,srcsize,dest); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_heapextend(char *base,int size) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _heapextend(base,size); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_bbc(char *filename, int lineno) +{ + _bbc(filename, lineno); +} + +void +mon_profiler(void *pdata) +{ + _profiler(pdata); +} + +void +mon_memtrace(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +char *fmt; +int a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12; +{ + _memtrace(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); +} + +char * +mon_version(void) +{ + char *ret; + + GENERIC_MONLOCK(); + ret = _version(); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_warmstart(unsigned long mask) +{ + GENERIC_MONLOCK(); + _appwarmstart(mask); + GENERIC_MONUNLOCK(); +} + +int +mon_pcicfgwrite(int interface,int bus,int dev,int func,int reg, + unsigned long val) +{ + int retval; + + GENERIC_MONLOCK(); + retval = _pcicfgwrite(interface,bus,dev,func,reg,val); + GENERIC_MONUNLOCK(); + return(retval); +} + +unsigned long +mon_pcicfgread(int interface,int bus,int dev, int func,int reg) +{ + unsigned long retval; + + GENERIC_MONLOCK(); + retval = _pcicfgread(interface,bus,dev,func,reg); + GENERIC_MONUNLOCK(); + return(retval); +} + +unsigned long +mon_pcictrl(int interface, int cmd, unsigned long arg1, unsigned long arg2) +{ + unsigned long val; + + GENERIC_MONLOCK(); + val = _pcictrl(interface,cmd,arg1,arg2); + GENERIC_MONUNLOCK(); + return(val); +} + +unsigned long +mon_i2cctrl(int interface, int cmd, unsigned long arg1, unsigned long arg2) +{ + unsigned long val; + + GENERIC_MONLOCK(); + val = _i2cctrl(interface,cmd,arg1,arg2); + GENERIC_MONUNLOCK(); + return(val); +} + +int +mon_i2cwrite(int interface, int bigaddr, unsigned char *data, int len) +{ + int val; + + GENERIC_MONLOCK(); + val = _i2cwrite(interface,bigaddr,data,len); + GENERIC_MONUNLOCK(); + return(val); +} + +int +mon_i2cread(int interface, int bigaddr, unsigned char *data, int len) +{ + int val; + + GENERIC_MONLOCK(); + val = _i2cread(interface,bigaddr,data,len); + GENERIC_MONUNLOCK(); + return(val); +} + +void +mon_delay(long msec) +{ + GENERIC_MONLOCK(); + _mondelay(msec); + GENERIC_MONUNLOCK(); +} + +int +mon_timer(int cmd, void *arg) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _montimer(cmd, arg); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_sendenetpkt(char *pkt,int size) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _sendenet(pkt,size); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_recvenetpkt(char *pkt,int size) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _recvenet(pkt,size); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_printpkt(char *buf,int size, int incoming) +{ + GENERIC_MONLOCK(); + _printpkt(buf,size,incoming); + GENERIC_MONUNLOCK(); +} + +int +mon_flashoverride(void *flashinfo,int get,int bank) +{ + int ret; + + TFS_MONLOCK(); + ret = _flashoverride(flashinfo,get,bank); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_flashwrite(char *dest,char *src,int bytecnt) +{ + int ret; + + TFS_MONLOCK(); + ret = _flashwrite(dest,src,bytecnt); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_flasherase(int snum) +{ + int ret; + + TFS_MONLOCK(); + ret = _flasherase(snum); + TFS_MONUNLOCK(); + return(ret); +} + +int +mon_flashinfo(int snum, int *size, char **base) +{ + int ret; + + TFS_MONLOCK(); + ret = _flashinfo(snum,size,base); + TFS_MONUNLOCK(); + return(ret); +} + +unsigned long +mon_assignhandler(long hnum, unsigned long arg1, unsigned long arg2) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _assign_handler(hnum,arg1,arg2); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_watchdog(void) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _watchdog(); + GENERIC_MONUNLOCK(); + return(ret); +} + +void +mon_printmem(char *mem, int size, int ascii) +{ + GENERIC_MONLOCK(); + _printmem(mem,size,ascii); + GENERIC_MONUNLOCK(); +} + +long +mon_portcmd(int cmd, void *arg) +{ + long ret; + + GENERIC_MONLOCK(); + ret = _portcmd(cmd,arg); + GENERIC_MONUNLOCK(); + return(ret); +} + +int +mon_timeofday(int cmd, void *arg) +{ + int ret; + + GENERIC_MONLOCK(); + ret = _timeofday(cmd,arg); + GENERIC_MONUNLOCK(); + return(ret); +} diff --git a/main/common/monlib.h b/main/common/monlib.h new file mode 100644 index 0000000..36c605b --- /dev/null +++ b/main/common/monlib.h @@ -0,0 +1,253 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * monlib.h: + * + * This header file is used by both the monitor and the application that + * may reside on top of the monitor. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _MONLIB_H_ +#define _MONLIB_H_ + +#include "tfs.h" +#include "cli.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef SHOWVARARGS +#define SHOWVARARGS 1 +#endif + + +extern int monConnect(int (*monptr)(int,void *,void *,void *), + void (*lock)(void),void (*unlock)(void)); +extern void mon_getargv(int *argc,char ***argv); +extern void mon_intsrestore(unsigned long oldval); +extern void mon_appexit(int exit_value); +extern void mon_free(char *buffer); +extern void mon_profiler(void *pdata); +extern void mon_bbc(char *filename, int linenum); +extern void mon_warmstart(unsigned long mask); +extern void mon_delay(long msec); +extern void mon_printpkt(char *buf, int size, int incoming); +extern void mon_printmem(char *mem, int size, int ascii); + + +extern int mon_com(int cmd,void *arg1,void *arg2,void *arg3); +extern int mon_timer(int cmd, void * arg); +extern int mon_setenv(char *varname,char *value); +extern int mon_putchar(char c); +extern int mon_getchar(void); +extern int mon_gotachar(void); +extern int mon_getbytes(char *buf,int count,int block); +extern int mon_restart(int restart_value); +extern int mon_tfsinit(void); +extern int mon_tfsunlink(char *filename); +extern int mon_tfslink(char *source, char *target); +extern int mon_tfsrun(char **arglist,int verbosity); +extern int mon_tfsfstat(char *filename,struct tfshdr *tfp); +extern int mon_tfseof(int file_descriptor); +extern int mon_tfstruncate(int file_descriptor,long length); +extern int mon_tfsread(int file_descriptor,char *buffer,int size); +extern int mon_tfswrite(int file_descriptor,char *buffer,int size); +extern int mon_tfsopen(char *filename,long mode,char *buffer); +extern int mon_tfsclose(int file_descriptor,char *info); +extern int mon_tfsseek(int file_descriptor,int offset,int whence); +extern int mon_tfsgetline(int file_descriptor,char *buffer,int bufsize); +extern int mon_tfsipmod(char *name,char *buffer,int offset,int size); +extern int mon_addcommand(struct monCommand *command_list,char *); +extern int mon_docommand(char *cmdline,int verbosity); +extern int mon_getline(char *buffer,int max,int ledit); +extern int mon_decompress(char *src,int srcsize,char *dest); +extern int mon_heapextend(char *base,int size); +extern int mon_pcicfgwrite(int interface,int bus,int dev,int func,int reg, + unsigned long val); +extern int mon_tfsadd(char *filename, char *info, char *flags, + unsigned char *src, int size); +extern int mon_i2cwrite(int interface, int bigaddr, unsigned char *data, + int len); +extern int mon_i2cread(int interface, int bigaddr, unsigned char *data, + int len); +extern int mon_sendenetpkt(char *pkt, int len); +extern int mon_recvenetpkt(char *pkt, int len); +extern int mon_flashoverride(void *flashinfo, int get, int bank); +extern int mon_flasherase(int snum); +extern int mon_flashwrite(char *dest,char *src, int bytecnt); +extern int mon_flashinfo(int snum,int *size, char **base); +extern int mon_watchdog(void); +extern int mon_timeofday(int cmd, void *arg); + +extern char *mon_getsym(char *symname, char *buf, int bufsize); +extern char *mon_getenv(char *varname); +extern char *mon_getenvp(void); +extern char *mon_version(void); +#ifdef MALLOC_DEBUG +extern char *mon_malloc(int size,char *file, int line); +extern char *mon_realloc(char *buf,int size,char *file, int line); +#else +extern char *mon_malloc(int size); +extern char *mon_realloc(char *buf,int size); +#endif + +extern long mon_tfsctrl(int command,long arg1,long arg2); +extern long mon_tfstell(int file_descriptor); +extern long mon_portcmd(int cmd, void *arg); + +extern unsigned short mon_xcrc16(char *buffer,long length); +extern unsigned long mon_crc32(char *buffer,long length); + +extern unsigned long mon_intsoff(void); + +extern unsigned long mon_pcicfgread(int interface,int bus,int dev, + int func,int reg); + +extern unsigned long mon_pcictrl(int interface, int cmd, + unsigned long arg1, unsigned long arg2); + +extern unsigned long mon_i2cctrl(int interface, int cmd, + unsigned long arg1, unsigned long arg2); + +extern unsigned long mon_assignhandler(long hnum, + unsigned long arg1,unsigned long arg2); + +extern struct tfshdr *mon_tfsnext(struct tfshdr *tfp); +extern struct tfshdr *mon_tfsstat(char *filename); + +#if SHOWVARARGS +extern void mon_memtrace(char *fmt, ...); +extern int mon_printf(char *fmt, ...); +extern int mon_cprintf(char *fmt, ...); +extern int mon_sprintf(char *,char *fmt, ...); +#else +extern void mon_memtrace(); +extern int mon_printf(); +extern int mon_cprintf(); +extern int mon_sprintf(); +#endif + +#ifdef __cplusplus +} +#endif + + +/* defines used by monConnect(): + */ +#define GETMONFUNC_PUTCHAR 1 +#define GETMONFUNC_GETCHAR 2 +#define GETMONFUNC_GOTACHAR 3 +#define GETMONFUNC_GETBYTES 4 +#define GETMONFUNC_PRINTF 5 +#define GETMONFUNC_CPRINTF 6 +#define GETMONFUNC_SPRINTF 7 +#define GETMONFUNC_RESTART 8 +#define GETMONFUNC_GETENV 9 +#define GETMONFUNC_SETENV 10 +#define GETMONFUNC_TFSINIT 11 +#define GETMONFUNC_TFSADD 12 +#define GETMONFUNC_TFSUNLINK 13 +#define GETMONFUNC_TFSRUN 14 +#define GETMONFUNC_TFSNEXT 15 +#define GETMONFUNC_TFSSTAT 16 +#define GETMONFUNC_TFSREAD 17 +#define GETMONFUNC_TFSWRITE 18 +#define GETMONFUNC_TFSOPEN 19 +#define GETMONFUNC_TFSCLOSE 20 +#define GETMONFUNC_TFSSEEK 21 +#define GETMONFUNC_TFSGETLINE 22 +#define GETMONFUNC_TFSIPMOD 23 +#define GETMONFUNC_TFSCTRL 24 +#define GETMONFUNC_ADDCOMMAND 25 +#define GETMONFUNC_DOCOMMAND 26 +#define GETMONFUNC_GETARGV 27 +#define GETMONFUNC_CRC16 28 +#define GETMONFUNC_CRC32 29 +#define GETMONFUNC_PIOGET 30 /* NA (removed as of 1.0) */ +#define GETMONFUNC_PIOSET 31 /* NA (removed as of 1.0) */ +#define GETMONFUNC_PIOCLR 32 /* NA (removed as of 1.0) */ +#define GETMONFUNC_INTSOFF 33 +#define GETMONFUNC_INTSRESTORE 34 +#define GETMONFUNC_APPEXIT 35 +#define GETMONFUNC_MALLOC 36 +#define GETMONFUNC_FREE 37 +#define GETMONFUNC_GETLINE 38 +#define GETMONFUNC_TFSFSTAT 39 +#define GETMONFUNC_TFSEOF 40 +#define GETMONFUNC_DECOMPRESS 41 +#define GETMONFUNC_TFSTRUNCATE 42 +#define GETMONFUNC_HEAPXTEND 43 +#define GETMONFUNC_PROFILER 44 +#define GETMONFUNC_TFSLINK 45 +#define GETMONFUNC_BBC 46 +#define GETMONFUNC_MEMTRACE 47 +#define GETMONFUNC_TFSTELL 48 +#define GETMONFUNC_VERSION 49 +#define GETMONFUNC_WARMSTART 50 +#define GETMONFUNC_PCICFGREAD 51 +#define GETMONFUNC_PCICFGWRITE 52 +#define GETMONFUNC_PCICONTROL 53 +#define GETMONFUNC_I2CREAD 54 +#define GETMONFUNC_I2CWRITE 55 +#define GETMONFUNC_I2CCONTROL 56 +#define GETMONFUNC_MONDELAY 57 +#define GETMONFUNC_GETENVP 58 +#define GETMONFUNC_REALLOC 59 +#define GETMONFUNC_SENDENETPKT 60 +#define GETMONFUNC_RECVENETPKT 61 +#define GETMONFUNC_GETSYM 62 +#define GETMONFUNC_PRINTPKT 63 +#define GETMONFUNC_FLASHWRITE 64 +#define GETMONFUNC_FLASHERASE 65 +#define GETMONFUNC_FLASHINFO 66 +#define GETMONFUNC_ASSIGNHDLR 67 +#define GETMONFUNC_WATCHDOG 68 +#define GETMONFUNC_PRINTMEM 69 +#define GETMONFUNC_PORTCMD 70 +#define GETMONFUNC_TIMEOFDAY 71 +#define GETMONFUNC_TIMER 72 +#define GETMONFUNC_FLASHOVRRD 73 + +#define CACHEFTYPE_DFLUSH 200 +#define CACHEFTYPE_IINVALIDATE 201 + +#define CHARFUNC_PUTCHAR 300 +#define CHARFUNC_GETCHAR 301 +#define CHARFUNC_GOTACHAR 302 +#define CHARFUNC_RAWMODEON 303 +#define CHARFUNC_RAWMODEOFF 304 + +#define ASSIGNFUNC_GETUSERLEVEL 400 +#define ASSIGNFUNC_WATCHDOG 401 + + +/* Defines used by mon_warmstart(): + */ +#define WARMSTART_IOINIT 0x00000001 +#define WARMSTART_BSSINIT 0x00000002 +#define WARMSTART_RUNMONRC 0x00000004 +#define WARMSTART_MONHEADER 0x00000008 +#define WARMSTART_TFSAUTOBOOT 0x00000010 +#define WARMSTART_BOARDINFO 0x00000020 +#define WARMSTART_ALL 0xffffffff +#endif diff --git a/main/common/monprof.c b/main/common/monprof.c new file mode 100644 index 0000000..ebf673b --- /dev/null +++ b/main/common/monprof.c @@ -0,0 +1,646 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * monprof.c: + * + * This command and support code allow the monitor to provide an application + * with some system profiling capabilities. The function "profiler" + * is part of the API to allow the application to take advantage of this. + * + * The basic assumption is that the application has the ability to insert + * a call to mon_profiler() in its system tick handler (actually the call + * can be put anywhere in the application, but this is the most logical + * place to put it). The content of the structure passed in to + * mon_profiler() depends on what kind of profiling the application wants + * to do. The tool works partially through calls made by the application + * into the monitor's api (mon_profiler()) and partially through + * interaction with the user at the monitor command line. The runtime + * profiling calls are done in application space, but the initial setup of + * the profiling session is done at the CLI. + * + * There are a few different profiling mechanisms in place... + * + * FUNCTION LOGGING: + * This capability makes the same assumption regarding the symtbl file + * as does strace... That the symbols are listed in the file in ascending + * address order. Ideally, the only symbols in the file would be the + * functions, so some processing can be done on the symtbl file prior to + * putting it on the target, this would help (not mandatory). At the CLI, + * the user issues the "prof init [address]" command. This initializes + * a table in the monitor that contains one pdata structure for each entry + * in the symtbl file. The pdata structure simply contains the starting + * address and a pass count for each entry in symtbl. After this + * initialization, runtime profiling can start. This is used by setting + * the MONPROF_FUNCLOG (see monprof.h) flag in the 'type' member of the + * monprof structure. Upon entry into the profiler, the 'pc' member of + * the incoming structure is assumed to contain the address that was + * executing at the time of the interrupt. The profiler uses a simple + * binary search to scan through all entries in the table to find the + * symbol (function) that the address falls within. When this is found, + * that entry's pass count variable is incremented. At some point later, + * profiling is completed and the user can dump the results to show the + * user what functions were hogging the CPU during the profiling session. + * + * Example setup: + * prof init # Initialize internals. + * prof funccfg # Configure function logging using symtbl. + * prof on # Enable profiling. + * + * + * PC LOGGING: + * This capability assumes that every instruction is the same size (typical + * for RISC CPUs). It uses a block of memory equal in size to the .text + * section of the application and treats that block as a table of counters. + * Each time the profiler is called, the PC (along with some delta) is + * used as an offset into the table and that offset is incremented. + * This may be used as a better alternative to the FUNCTION LOGGING + * mechanism described above; but it does have some additional requirements, + * (fixed-width instruction & extra ram space == .text size) so it may not + * be an option. + * + * Example setup: + * prof init # Initialize internals. + * prof pccfg 4 0x22000 0x10000 # Configure pc logging for 32-bit + * # instructions. The .text space of + * # the application starts at 0x22000 + * # with a size of 0x10000 bytes. + * prof on # Enable profiling. + * + * TASK ID LOGGING: + * Similar to function logging except that the MONPROF_TIDLOG flag is set + * in the 'type' member, and the 'tid' member is used... + * The user initializes with the "prof tinit {count}" command. The count + * is the maximum number of unique task ids expected. The monitor builds + * another table and as each tid comes in through mon_profiler, if this is + * the first time mon_profiler() is being called with the specific incoming + * tid value, then it is added to the list of pdata structures and the pass + * count is set to 1; otherwise if it has already been logged, only the + * pass count is incremented. + * + * Example setup: + * prof init # Initialize internals. + * prof tidcfg 16 # Configure tid logging for 16 unique tids. + * prof on # Enable profiling. + * + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "monprof.h" +#if INCLUDE_PROFILER +#include "stddefs.h" +#include "genlib.h" +#include <ctype.h> +#include "cli.h" +#include "tfs.h" +#include "tfsprivate.h" + +#define HALF(m) (m >> 1) + +/* pdata: + * One of these represents each symbol (or tid) in the profiling session. + * For MONPROF_FUNCLOG, the data member is the starting address of the symbol + * and for MONPROF_TIDLOG, the data member is the tid value. + */ +struct pdata { + ulong data; /* Start of symbol or tid. */ + int pcount; /* Pass count. */ +}; + +static int prof_Enabled; /* If set, profiler runs; else return. */ +static int prof_BadSymCnt; /* Number of hits not within a symbol. */ +static int prof_CallCnt; /* Number of times profiler was called. */ +static int prof_FuncTot; /* Number of functions being profiled. */ +static int prof_TidTot; /* Number of TIDs being profiled. */ +static int prof_TidTally; /* Number of unique TIDs logged so far. */ +static int prof_TidOverflow; /* More TIDs than the table was built for. */ +static int prof_PcTot; /* Number of instructions being profiled. */ +static int prof_PcDelta; /* Delta between .text space and PC table. */ +static int prof_PcWidth; /* Width (2 or 4) of PC table elements. */ +static int prof_PcOORCnt; /* Out-of-range hit count for PC profiler */ +static ulong prof_PcTxtEnd; /* End of .text area being profiled */ +static ulong prof_PcTxtBase; /* Base of .text area being profiled */ + +static struct pdata *prof_FuncTbl; +static struct pdata *prof_TidTbl; +static uchar *prof_PcTbl; +static char prof_SymFile[TFSNAMESIZE+1]; + +void +profiler(struct monprof *mpp) +{ + struct pdata *current, *base; + int nmem; + + if (prof_Enabled == 0) + return; + + if (mpp->type & MONPROF_FUNCLOG) { + nmem = prof_FuncTot; + base = prof_FuncTbl; + while(nmem) { + current = &base[HALF(nmem)]; + if (mpp->pc < current->data) + nmem = HALF(nmem); + else if (mpp->pc > current->data) { + if (mpp->pc < (current+1)->data) { + current->pcount++; + goto tidlog; + } + else { + base = current + 1; + nmem = (HALF(nmem)) - (nmem ? 0 : 1); + } + } + else { + current->pcount++; + goto tidlog; + } + } + prof_BadSymCnt++; + } +tidlog: + if (mpp->type & MONPROF_TIDLOG) { + /* First see if the tid is already in the table. If it is, + * increment the pcount. If it isn't add it to the table. + */ + nmem = prof_TidTally; + base = prof_TidTbl; + while(nmem) { + current = &base[HALF(nmem)]; + if (mpp->tid < current->data) + nmem = HALF(nmem); + else if (mpp->tid > current->data) { + base = current + 1; + nmem = (HALF(nmem)) - (nmem ? 0 : 1); + } + else { + current->pcount++; + goto pclog; + } + } + /* Since we got here, the tid must not be in the table, so + * do an insertion into the table. Items are in the table in + * ascending order. + */ + if (prof_TidTally == 0) { + prof_TidTbl->pcount = 1; + prof_TidTbl->data = mpp->tid; + prof_TidTally++; + } + else if (prof_TidTally >= prof_TidTot) { + prof_TidOverflow++; + } + else { + current = prof_TidTbl + prof_TidTally - 1; + while(current >= prof_TidTbl) { + if (mpp->tid > current->data) { + current++; + current->pcount = 1; + current->data = mpp->tid; + break; + } + else { + *(current+1) = *current; + if (current == prof_TidTbl) { + current->pcount = 1; + current->data = mpp->tid; + break; + } + } + current--; + } + prof_TidTally++; + } + } +pclog: + if (mpp->type & MONPROF_PCLOG) { + ulong offset; + + if ((mpp->pc > prof_PcTxtEnd) || (mpp->pc < prof_PcTxtBase)) { + prof_PcOORCnt++; + } + else { + offset = mpp->pc - prof_PcDelta; + switch(prof_PcWidth) { + case 2: + (*(ushort *)offset)++; + break; + case 4: + (*(ulong *)offset)++; + break; + } + } + } + prof_CallCnt++; + return; +} + +int +prof_GetSymFile(void) +{ + int tfd; + + if (prof_SymFile[0] == 0) { + tfd = SymFileFd(1); + } + else { + tfd = tfsopen(prof_SymFile,TFS_RDONLY,0); + if (tfd < 0) { + printf("%s: %s\n",prof_SymFile,(char *)tfsctrl(TFS_ERRMSG,tfd,0)); + } + } + return(tfd); +} + +void +prof_ShowStats(int minhit, int more) +{ + int i, tfd, linecount; + ulong notused; + char symname[64]; + struct pdata *pptr; + + printf("FuncCount Cfg: tbl: 0x%08lx, size: 0x%x\n", + (ulong)prof_FuncTbl, prof_FuncTot); + printf("TidCount Cfg: tbl: 0x%08lx, size: 0x%x\n", + (ulong)prof_TidTbl, prof_TidTot); + printf("PcCount Cfg: tbl: 0x%08lx, size: 0x%x\n", + (ulong)prof_PcTbl, prof_PcTot*prof_PcWidth); + + if (prof_CallCnt == 0) { + printf("No data collected%s", + prof_Enabled == 0 ? " (profiling disabled)\n" : "\n"); + return; + } + linecount = 0; + tfd = prof_GetSymFile(); + if ((prof_FuncTbl) && (prof_FuncTot > 0)) { + printf("\nFUNC_PROF stats:\n"); + pptr = prof_FuncTbl; + for(i=0;i<prof_FuncTot;pptr++,i++) { + if (pptr->pcount < minhit) + continue; + if ((tfd < 0) || + (AddrToSym(tfd,pptr->data,symname,¬used) == 0)) { + printf(" %08lx : %d\n",pptr->data,pptr->pcount); + } + else { + printf(" %-25s: %d\n",symname,pptr->pcount); + } + if ((more) && (++linecount >= more)) { + linecount = 0; + if (More() == 0) + goto showdone; + } + } + } + if ((prof_TidTbl) && (prof_TidTot > 0)) { + printf("\nTID_PROF stats:\n"); + pptr = prof_TidTbl; + for(i=0;i<prof_TidTot;pptr++,i++) { + if (pptr->pcount < minhit) + continue; + printf(" %08lx : %d\n",pptr->data,pptr->pcount); + if ((more) && (++linecount >= more)) { + linecount = 0; + if (More() == 0) + goto showdone; + } + } + } + if (prof_PcTbl) { + ushort *sp; + ulong *lp; + + sp = (ushort *)prof_PcTbl; + lp = (ulong *)prof_PcTbl; + printf("\nPC_PROF stats:\n"); + for(i=0;i<prof_PcTot;i++) { + switch(prof_PcWidth) { + case 2: + if (*sp >= minhit) { + printf(" %08x : %d\n", + (int)sp + prof_PcDelta,*sp); + linecount++; + } + sp++; + break; + case 4: + if (*lp >= minhit) { + printf(" %08x : %ld\n", + (int)lp + prof_PcDelta,*lp); + linecount++; + } + lp++; + break; + } + if ((more) && (linecount >= more)) { + linecount = 0; + if (More() == 0) + goto showdone; + } + } + } +showdone: + putchar('\n'); + if (prof_BadSymCnt) + printf("%d out-of-range symbols\n",prof_BadSymCnt); + if (prof_TidOverflow) + printf("%d tid overflow attempts\n",prof_TidOverflow); + if (prof_PcOORCnt) + printf("%d pc out-of-range hits\n",prof_PcOORCnt); + printf("%d total profiler calls\n",prof_CallCnt); + + if (tfd >= 0) + tfsclose(tfd,0); + return; +} + +/* prof_FuncConfig(): + * This function builds a table of pdata structures based on the + * content of the symbol table. + * It assumes the file is a list of symbols and addresses listed + * in ascending address order. + */ +void +prof_FuncConfig(void) +{ + int tfd, i; + struct pdata *pfp; + char line[80], *space; + + tfd = prof_GetSymFile(); + if (tfd < 0) + return; + + prof_FuncTot = 0; + pfp = prof_FuncTbl; + + while(tfsgetline(tfd,line,sizeof(line)-1)) { + space = strpbrk(line,"\t "); + if (!space) + continue; + *space++ = 0; + while(isspace(*space)) + space++; + pfp->data = strtoul(space,0,0); + pfp->pcount = 0; + pfp++; + prof_FuncTot++; + } + tfsclose(tfd,0); + + /* Add one last item to the list so that there is an upper limit for + * the final symbol in the table: + */ + pfp->data = 0xffffffff; + pfp->pcount = 0; + + /* Test to verify that all symbols are in ascending address order... + */ + for (i=0;i<prof_FuncTot;i++) { + if (prof_FuncTbl[i].data > prof_FuncTbl[i+1].data) { + printf("Warning: function addresses not in order\n"); + break; + } + } + prof_FuncTot++; +} + +/* prof(): + */ + +char *ProfHelp[] = { + "Profiler configuration and result display", + "-[h:m:s:] [operation] [op-specific args]", +#if INCLUDE_VERBOSEHELP + "Operations:", + " on enable profiler", + " off disable profiler", + " show dump stats", + " init clear internal tables and runtime stats", + " call {type pc tid} call profiler from CLI", + " ('type' can be any combination of 't', 'f' & 'p')", + " restart clear runtime stats only", + " tidcfg {tidtot} init tid profiler based on number of task ids", + " funccfg init function profiler from symtbl file", + " pccfg {wid add siz} init pc profiler with instruction width (2 or 4)", + " plus size and addr of text area", + "", + "Options:", + " -a{#} address to use for table", + " -h{#} minimum hit count for show", + " -m{#} line count for output throttling in show", + " -s{symfile} use this file for symbols instead of default", +#endif + 0, +}; + +int +Prof(int argc,char *argv[]) +{ + char *arg1, *arg2, *arg3, *arg4; + ulong address; + int i, opt, minhit, ret, more; + + ret = CMD_SUCCESS; + minhit = 1; + more = 0; + address = 0; + while((opt=getopt(argc,argv,"a:h:m:s:")) != -1) { + switch(opt) { + case 'a': + address = strtoul(optarg,0,0); + break; + case 'h': + minhit = atoi(optarg); + break; + case 'm': + more = atoi(optarg); + break; + case 's': + strncpy(prof_SymFile,optarg,TFSNAMESIZE); + prof_SymFile[TFSNAMESIZE] = 0; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + arg1 = argv[optind]; + arg2 = argv[optind+1]; + arg3 = argv[optind+2]; + arg4 = argv[optind+3]; + + if (argc == optind+1) { + if (!strcmp(arg1,"on")) { + prof_Enabled = 1; + } + else if (!strcmp(arg1,"off")) { + prof_Enabled = 0; + } + else if (!strcmp(arg1,"show")) { + prof_ShowStats(minhit, more); + } + else if (!strcmp(arg1,"init")) { + prof_BadSymCnt = 0; + prof_CallCnt = 0; + prof_TidTally = 0; + prof_Enabled = 0; + prof_FuncTot = 0; + prof_TidTot = 0; + prof_PcTot = 0; + prof_FuncTbl = (struct pdata *)0; + prof_TidTbl = (struct pdata *)0; + prof_PcTbl = (uchar *)0; + prof_PcWidth = 0; + prof_PcDelta = 0; + prof_SymFile[0] = 0; + } + else if (!strcmp(arg1,"restart")) { + prof_BadSymCnt = 0; + prof_CallCnt = 0; + prof_TidTally = 0; + if (prof_FuncTbl) { + for(i=0;i<prof_FuncTot;i++) + prof_FuncTbl[i].pcount = 0; + } + if (prof_TidTbl) { + for(i=0;i<prof_TidTot;i++) + prof_TidTbl[i].pcount = 0; + prof_TidTbl[i].data = 0; + } + if (prof_PcTbl) { + memset((char *)prof_PcTbl,0,prof_PcTot*prof_PcWidth); + } + } + else if (!strcmp(arg1,"funccfg")) { + if (prof_FuncTbl) { + printf("Already configured, run init to re-configure\n"); + return(CMD_FAILURE); + } + else if (prof_PcTbl) { + printf("Can't use PC and FUNC profiling simultaneously\n"); + return(CMD_FAILURE); + } + else if (address) { + prof_FuncTbl = (struct pdata *)address; + } + else if (prof_TidTbl) { + prof_FuncTbl = &prof_TidTbl[prof_TidTot]; + } + else + prof_FuncTbl = (struct pdata *)getAppRamStart(); + + prof_FuncConfig(); + } + else + ret = CMD_PARAM_ERROR; + } + else if (argc == optind+2) { + if (!strcmp(arg1,"tidcfg")) { + if (prof_TidTbl) { + printf("Already configured, run init to re-configure\n"); + return(CMD_FAILURE); + } + else if (address) { + prof_TidTbl = (struct pdata *)address; + } + else if (prof_FuncTbl) { + prof_TidTbl = &prof_FuncTbl[prof_FuncTot]; + } + else if (prof_PcTbl) { + prof_TidTbl = (struct pdata *)&prof_PcTbl[prof_PcTot]; + } + else + prof_TidTbl = (struct pdata *)getAppRamStart(); + prof_TidTot = strtoul(arg2,0,0); + for(i=0;i<prof_TidTot;i++) { + prof_TidTbl[i].data = 0; + prof_TidTbl[i].pcount = 0; + } + } + else + ret = CMD_PARAM_ERROR; + } + else if (argc == optind+4) { + if (!strcmp(arg1,"call")) { + struct monprof mp; + + mp.type = 0; + + if (strchr(arg2,'f')) + mp.type |= MONPROF_FUNCLOG; + if (strchr(arg2,'p')) + mp.type |= MONPROF_PCLOG; + if (strchr(arg2,'t')) + mp.type |= MONPROF_TIDLOG; + + mp.pc = strtoul(arg3,0,0); + mp.tid = strtoul(arg4,0,0); + + profiler(&mp); + } + else if (!strcmp(arg1,"pccfg")) { + int size; + + if (prof_PcTbl) { + printf("Already configured, run init to re-configure\n"); + return(CMD_FAILURE); + } + else if (prof_FuncTbl) { + printf("Can't use PC and FUNC profiling simultaneously\n"); + return(CMD_FAILURE); + } + else if (address) { + prof_PcTbl = (uchar *)address; + } + else if (prof_TidTbl) { + prof_PcTbl = (uchar *)&prof_TidTbl[prof_TidTot]; + } + else + prof_PcTbl = (uchar *)getAppRamStart(); + prof_PcWidth = strtol(arg2,0,0); /* instruction width */ + prof_PcTxtBase = strtol(arg3,0,0); /* address of .text */ + size = strtol(arg4,0,0); /* size of .text */ + prof_PcTxtEnd = prof_PcTxtBase + size; + prof_PcTot = size / prof_PcWidth; + prof_PcDelta = (ulong)prof_PcTxtBase - (ulong)prof_PcTbl; + memset((char *)prof_PcTbl,0,prof_PcTot*prof_PcWidth); + + } + else + ret = CMD_PARAM_ERROR; + } + else + ret = CMD_PARAM_ERROR; + + return(ret); +} +#else + +void +profiler(struct monprof *mpp) +{ +} + +#endif diff --git a/main/common/monprof.h b/main/common/monprof.h new file mode 100644 index 0000000..5eebe31 --- /dev/null +++ b/main/common/monprof.h @@ -0,0 +1,39 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * monprof.h + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _MONPROF_H_ +#define _MONPROF_H_ + +#define MONPROF_FUNCLOG (1 << 0) +#define MONPROF_TIDLOG (1 << 1) +#define MONPROF_PCLOG (1 << 2) + +struct monprof { + unsigned long type; + unsigned long pc; + unsigned long tid; +}; + +#endif diff --git a/main/common/mprintf.c b/main/common/mprintf.c new file mode 100644 index 0000000..c178253 --- /dev/null +++ b/main/common/mprintf.c @@ -0,0 +1,691 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * vmprintf.c: + * + * Same as mprintf, but this uses stdarg.h. + * Cleaner and simpler. I have some targets using this and will probably + * convert all targets to use this eventually. + * + * Note that this requires that the CFLAGS used in the building of this + * file should omit the "-nostdinc" option, so that the standard header + * (stdarg.h) can be pulled in. + * + * Public functions: + * vsnprintf(), snprintf(), sprintf(), printf(), cprintf() + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include <stdarg.h> +#include "stddefs.h" +#include "cli.h" + +extern long abs(long); +extern void puts(char *); +extern int atoi(char *), putchar(char); +int printf(char *fmt, ...); + +static char *hexdigits = "0123456789abcdef"; +static char *Hexdigits = "0123456789ABCDEF"; + +#define MAX_NUMBER_SIZE 18 +#define HDRSIZE 4 +#define NEGATIVE 1 +#define POSITIVE 2 +#define SCREENWIDTH 80 + +/* PROCCHARP(), PROCCHAR(), BUFDEC() & BUFINC(): + * Macros used to conveniently distinguish between buffer-bound + * and console-bound characters during the formatting process. + */ +#define PROCCHARP(bp,eob,cp) \ + if (bp) { \ + if (eob && (bp >= eob)) { \ + puts("s_printf buffer overflow"); \ + return(-1); \ + } \ + *bp++ = *cp++; \ + } \ + else { \ + putchar(*cp++); \ + } + +#define PROCCHAR(bp,eob,c) \ + if (bp) { \ + if (eob && (bp >= eob)) { \ + puts("s_printf buffer overflow"); \ + return(-1); \ + } \ + *bp++ = c; \ + } \ + else { \ + if (c) \ + putchar(c); \ + } + +#define BUFDEC(bp,val) \ + if (bp) { \ + bp -= val; \ + } + +#define BUFINC(bp,val) \ + if (bp) { \ + bp += val; \ + } + + +/* isdigit(): + * Copied here to avoid inclusion of ctype.h + */ +static int +isdigit(char ch) +{ + return ((ch >= '0') && (ch <= '9')); +} + +/* proc_d_prefix(): + * Deal with the characters prior to the 'd' format designator. + * For example, hdr would be '8' in the format %8d. + */ +static int +proc_d_prefix(char *hdr, char *lbp) +{ + char fill; + int minsize, i; + + minsize = 0; + if (hdr[0]) { + if (hdr[0] == '0') + fill = '0'; + else + fill = ' '; + minsize = (short)atoi(hdr); + for(i=0;i<minsize;i++) + *lbp++ = fill; + } + return(minsize); +} + + +/* long_to_dec(): + * Convert an incoming long value to ASCII decimal notation. + */ +int +long_to_dec(long lval,char *buf,char *bufend,char *hdr) +{ + unsigned long value; + short size, i, minsize; + char lbuf[MAX_NUMBER_SIZE], *lbp; + + lbp = lbuf; + minsize = proc_d_prefix(hdr,lbuf); + + /* First determine how many ascii digits are needed. */ + value = abs(lval); + size = 0; + while (value > 0) { + size++; + value /= 10; + } + if (lval < 0) + size++; + if (minsize > size) + size = minsize; + lbp += size; + + /* Now build the string. */ + value = abs(lval); + if (value == 0) { + if (minsize==0) { + lbuf[0] = '0'; + size = 1; + } + else + *--lbp = '0'; + } + else { + while (value > 0) { + *--lbp = (char)((value % 10) + '0'); + value /= 10; + } + } + if (lval < 0) + *--lbp = '-'; + lbuf[size] = 0; + + /* At this point, lbuf[] contains the ascii decimal string + * so we can now pass it through PROCCHAR... + */ + for(i=0;i<size;i++) { + PROCCHAR(buf,bufend,lbuf[i]); + } + return((int)size); +} + +/* llong_to_dec(): + * Convert an incoming long long value to ASCII decimal notation. + * This is essentially identical to long_to_dec, but we use longlong. + */ +static int +llong_to_dec(int64_t llval,char *buf,char *bufend,char *hdr) +{ + uint64_t value; + short size, i, minsize; + char lbuf[MAX_NUMBER_SIZE], *lbp; + + lbp = lbuf; + minsize = proc_d_prefix(hdr, lbuf); + + /* First determine how many ascii digits are needed. */ + value = llval < 0 ? -llval : llval; + size = 0; + while (value > 0) { + size++; + value /= 10; + } + if (llval < 0) + size++; + if (minsize > size) + size = minsize; + lbp += size; + + /* Now build the string. */ + value = llval < 0 ? -llval : llval; + if (value == 0) { + if (minsize==0) { + lbuf[0] = '0'; + size = 1; + } + else + *--lbp = '0'; + } + else { + while (value > 0) { + *--lbp = (char)((value % 10) + '0'); + value /= 10; + } + } + if (llval < 0) + *--lbp = '-'; + lbuf[size] = 0; + + /* At this point, lbuf[] contains the ascii decimal string + * so we can now pass it through PROCCHAR... + */ + for(i=0;i<size;i++) { + PROCCHAR(buf,bufend,lbuf[i]); + } + return((int)size); +} + +/* long_to_ip(): + * Convert an incoming long value to an ascii IP formatted + * string (i.e. 0x01020304 is converted to "1.2.3.4") + */ +static int +long_to_ip(long lval,char *buf,char *bufend,char *hdr) +{ + int i, j, len; + unsigned char *lp; + + len = 0; + lp = (unsigned char *)&lval; + for(j=0;j<4;j++) { + i = long_to_dec(*lp++,buf,bufend,hdr); + BUFINC(buf,i); + if (j < 3) { + PROCCHAR(buf,bufend,'.'); + } + len += (i + 1); + } + BUFDEC(buf,1); + len--; + return(len); +} + +/* proc_x_prefix(): + * Deal with the characters prior to the 'x' format designator. + * For example, hdr would be '02' in the format %02x. + */ +static int +proc_x_prefix(char *hdr, char *lbp) +{ + int i, minsize; + + minsize = 0; + if (hdr[0]) { + if (hdr[1]) { + minsize = (short)(hdr[1]&0xf); + for(i=0;i<minsize;i++) + *lbp++ = hdr[0]; + } + else { + minsize = (short)(hdr[0]&0xf); + for(i=0;i<minsize;i++) + *lbp++ = ' '; + } + } + return(minsize); +} + +/* long_to_hex(): + * Convert an incoming long value to ASCII hexadecimal notation. + */ +static int +long_to_hex(ulong lval,char *buf,char *bufend,char *hdr, char x) +{ + ulong value; + short size, i, minsize; + char lbuf[MAX_NUMBER_SIZE], *lbp; + + lbp = lbuf; + minsize = proc_x_prefix(hdr,lbuf); + + /* First determine how many ascii digits are needed. */ + value = lval; + size = 0; + while (value > 0) { + size++; + value /= 16; + } + if (minsize > size) + size = minsize; + lbp += size; + + /* Now build the string. */ + if (lval == 0) { + if (size == 0) + size = 1; + else + lbp--; + *lbp = '0'; + } + else { + while (lval > 0) { + if (x == 'X') + *--lbp = Hexdigits[(int)(lval % 16)]; + else + *--lbp = hexdigits[(int)(lval % 16)]; + lval /= 16; + } + } + lbp[size] = 0; + + /* At this point, lbuf[] contains the ascii hex string + * so we can now pass it through PROCCHAR... + */ + for(i=0;i<size;i++) { + PROCCHAR(buf,bufend,lbuf[i]); + } + + return((int)size); +} + +/* llong_to_hex(): + * Convert an incoming long long value to ASCII hexadecimal notation. + */ +static int +llong_to_hex(uint64_t llval,char *buf,char *bufend,char *hdr, char x) +{ + uint64_t value; + short size, i, minsize; + char lbuf[MAX_NUMBER_SIZE], *lbp; + + lbp = lbuf; + minsize = proc_x_prefix(hdr,lbuf); + + /* First determine how many ascii digits are needed. */ + value = llval; + size = 0; + while (value > 0) { + size++; + value /= 16; + } + if (minsize > size) + size = minsize; + lbp += size; + + /* Now build the string. */ + if (llval == 0) { + if (size == 0) + size = 1; + else + lbp--; + *lbp = '0'; + } + else { + while (llval > 0) { + if (x == 'X') + *--lbp = Hexdigits[(int)(llval % 16)]; + else + *--lbp = hexdigits[(int)(llval % 16)]; + llval /= 16; + } + } + lbp[size] = 0; + + /* At this point, lbuf[] contains the ascii hex string + * so we can now pass it through PROCCHAR... + */ + for(i=0;i<size;i++) { + PROCCHAR(buf,bufend,lbuf[i]); + } + + return((int)size); +} + +/* bin_to_mac(): + * Convert an incoming buffer to an ascii MAC formatted + * string (i.e. buf[] = 010203040506 is converted to "01:02:03:04:05:06") + */ +static int +bin_to_mac(uchar *ibin,char *buf,char *bufend) +{ + int i, j, len; + + len = 0; + for(j=0;j<6;j++) { + i = long_to_hex(*ibin++,buf,bufend,"02",'x'); + BUFINC(buf,i); + if (j < 5) { + PROCCHAR(buf,bufend,':'); + } + len += (i + 1); + } + BUFDEC(buf,1); + len--; + return(len); +} + +/* build_string(): + * Build a string from 'src' to 'dest' based on the hdr and sign + * values. Return the size of the string (may include left or right + * justified padding). + */ +static int +build_string(char *src,char *dest,char *bufend,char *hdr,int sign) +{ + char *cp1; + short minsize, i, j; + + if (!src) { + cp1 = "NULL_POINTER"; + while(*cp1) { + PROCCHARP(dest,bufend,cp1); + } + return(12); + } + if (!*src) + return(0); + if (!hdr[0]) { + j = 0; + while(*src) { + PROCCHARP(dest,bufend,src); + j++; + } + return(j); + } + minsize = (short)atoi(hdr); + i = 0; + cp1 = (char *)src; + while(*cp1) { + i++; + cp1++; + } + cp1 = (char *)src; + j = 0; + if (minsize > i) { + if (sign == POSITIVE) { + while(minsize > i) { + j++; + PROCCHAR(dest,bufend,' '); + minsize--; + } + while(*cp1) { + j++; + PROCCHARP(dest,bufend,cp1); + } + } + else { + while(*cp1) { + j++; + PROCCHARP(dest,bufend,cp1); + } + while(minsize > i) { + j++; + PROCCHAR(dest,bufend,' '); + minsize--; + } + } + } + else { + while(*cp1) { + j++; + PROCCHARP(dest,bufend,cp1); + } + } + return(j); +} + +/* vsnprintf(): + * Backend to all the others below it. + * Formats incoming argument list based on format string. + * Terminates population of buffer if it is to exceed the + * specified buffer size. + */ +int +vsnprintf(char *buf,int bsize, char *fmt, va_list argp) +{ + long arg_l; + long long arg_ll; + int i, sign, tot; + char *cp, hdr[HDRSIZE], *base, *bufend, arg_c, *arg_cp, ll; + + ll = 0; + tot = 0; + base = buf; + + if (bsize == 0) + bufend = 0; + else + bufend = base+(bsize-1); + + cp = fmt; + for(i=0;i<HDRSIZE;i++) + hdr[i] = 0; + while(*cp) { + if (*cp != '%') { + PROCCHARP(buf,bufend,cp); + tot++; + continue; + } + cp++; + if (*cp == '%') { + PROCCHARP(buf,bufend,cp); + tot++; + continue; + } + sign = POSITIVE; + if (*cp == '-') { + sign = NEGATIVE; + cp++; + } + if (isdigit(*cp)) { + for(i=0;i<(HDRSIZE-1);i++) { + if (isdigit(*cp)) + hdr[i] = *cp++; + else + break; + } + } + + ll = 0; + if (*cp == 'l') { /* Ignore the 'long' designator */ + cp++; + if (*cp == 'l') { /* unless its the longlong designator */ + cp++; + ll = 1; + } + } + + switch(*cp) { + case 'c': /* Character conversion */ + arg_c = (char)va_arg(argp,int); + PROCCHAR(buf,bufend,arg_c); + tot++; + break; + case 's': /* String conversion */ + arg_cp = (char *)va_arg(argp,int); + i = build_string(arg_cp,buf,bufend,hdr,sign); + BUFINC(buf,i); + tot += i; + break; + case 'M': /* MAC address conversion */ + arg_cp = (char *)va_arg(argp,int); + i = bin_to_mac((uchar *)arg_cp,buf,bufend); + BUFINC(buf,i); + tot += i; + break; + case 'I': /* IP address conversion */ + arg_l = (long)va_arg(argp,int); + i = long_to_ip(arg_l,buf,bufend,hdr); + BUFINC(buf,i); + tot += i; + break; + case 'd': /* Decimal conversion */ + case 'u': + if (ll) { + arg_ll = (long long)va_arg(argp,long long); + i = llong_to_dec(arg_ll,buf,bufend,hdr); + } + else { + arg_l = (long)va_arg(argp,int); + i = long_to_dec(arg_l,buf,bufend,hdr); + } + BUFINC(buf,i); + tot += i; + break; + case 'p': /* Hex conversion */ + case 'x': + case 'X': + if (*cp == 'p') { + PROCCHAR(buf,bufend,'0'); + PROCCHAR(buf,bufend,'x'); + } + if (ll) { + arg_ll = (long long)va_arg(argp,long long); + i = llong_to_hex(arg_ll,buf,bufend,hdr,*cp); + } + else { + arg_l = (long)va_arg(argp,int); + i = long_to_hex((ulong)arg_l,buf,bufend,hdr,*cp); + } + BUFINC(buf,i); + tot += i; + break; + default: + PROCCHARP(buf,bufend,cp); + tot++; + break; + } + cp++; + + if (hdr[0]) { + for(i=0;i<HDRSIZE;i++) + hdr[i] = 0; + } + } + PROCCHAR(buf,bufend,0); + return(tot); +} + +/* snprintf(), sprintf(), printf() & cprintf(): + * All functions use vsnprintf() to format a string. + * The string is either transferred to a buffer or transferred + * directly to this target's console through putchar (refer to + * the macros at the top of this file). + * + * - sprintf() formats to a buffer. + * - printf() formats to stdio. + * - cprintf() formats to a buffer, then centers the content of + * the buffer based on its size and a console screen with of + * SCREENWIDTH characters. + */ +int +snprintf(char *buf, int bsize, char *fmt, ...) +{ + int tot; + va_list argp; + + va_start(argp,fmt); + tot = vsnprintf(buf,bsize,fmt,argp); + va_end(argp); + return(tot); +} + +int +sprintf(char *buf, char *fmt, ...) +{ + int tot; + va_list argp; + + va_start(argp,fmt); + tot = vsnprintf(buf,0,fmt,argp); + va_end(argp); + return(tot); +} + +int +printf(char *fmt, ...) +{ + int tot; + va_list argp; + + va_start(argp,fmt); + tot = vsnprintf(0,0,fmt,argp); + va_end(argp); + return(tot); +} + +int +cprintf(char *fmt, ...) +{ + int i, tot, spaces; + char pbuf[CMDLINESIZE]; + va_list argp; + + va_start(argp,fmt); + tot = vsnprintf(pbuf,CMDLINESIZE,fmt,argp); + va_end(argp); + + if (tot < SCREENWIDTH) { + spaces = (SCREENWIDTH-tot)/2; + for(i=0;i<spaces;i++) + putchar(' '); + } + else + spaces = 0; + + for(i=0;i<tot;i++) + putchar(pbuf[i]); + + return(tot+spaces); +} diff --git a/main/common/msbin.h b/main/common/msbin.h new file mode 100644 index 0000000..dd9650f --- /dev/null +++ b/main/common/msbin.h @@ -0,0 +1,87 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * msbin.h: + * + * The following information was retrieved from the MSDN technical + * support web site... + * + * Windows CE Binary Image Data Format (.bin): + * The binary image file format organizes data by sections. + * Each section contains a section header that specifies the starting + * address, length, and checksum for that section. Romimage.exe writes + * data organized by logical sections, such as an application's text or + * .data region, to the .bin file. The image terminates with an image + * record header with the physical address and checksum set to zero. + * A configuration file formatted as a .bin file is small and fast. + * A .bin file is about half the size of an .sre file. + * This smaller size allows a .bin file to download faster than an + * .sre file when you are using the Windows CE Console Debug Shell + * tool (Cesh.exe). + * + * The following table shows the .bin file format. + * + * FIELD LENGTH DESCRIPTION + * (bytes) + * Sync bytes (optional) 7 Byte 0 is B, indicating a .bin file + * format. Bytes 1-6 are reserved + * and set to 0, 0, 0, F, F, \n. + * Or in hex: 0x4230303046460a + * Image header, consisting of: + * Image address 4 Start address of image. + * Image length 4 Length, in bytes, of image. + * One or more records of: + * Record address 4 Starting address of data record. + * If this value is zero, the record + * address is the end of the file, + * and record length contains the + * starting address of the image. + * Record length 4 Length of record data, in bytes. + * Record checksum 4 Signed 32-bit sum of record data bytes. + * Record data N Record data + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _MSBIN_H_ +#define _MSBIN_H_ + +#define MSBIN_SYNC_SIZE 7 +#define MSBIN_SYNC_DATA "B000FF\n" + +#define MSBINFHDR struct msbin_imghdr +#define MSBINSHDR struct msbin_record + +/* File header: + */ +struct msbin_imghdr { + ulong imageaddr; + ulong imagelen; +}; + +/* Section header: + */ +struct msbin_record { + ulong addr; + ulong len; + ulong csum; +}; + +#endif diff --git a/main/common/nand.c b/main/common/nand.c new file mode 100755 index 0000000..45e7483 --- /dev/null +++ b/main/common/nand.c @@ -0,0 +1,350 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * nand.c + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_NANDCMD +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "cli.h" +#include "nand.h" + +int nandVerbose; + +#define END_OF_NAND (BASE_OF_NAND+SIZE_OF_NAND-1) + +#ifdef FLASHRAM_BASE +#ifndef NAND_TFSRAM_BASE +#define NAND_TFSRAM_BASE FLASHRAM_BASE +#endif +#endif + +char *nandHelp[] = { + "Interface with Nand-Flash", + "-[v] {cmd} [cmd-specific args]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -v incrementing verbosity level", + "", + "Cmds:", + " init initialize interface", + " info show device info", +#ifdef FLASHRAM_BASE + " tfsls list files directly out of SPI flash", + " tfsload copy NAND to TFSRAM", + " tfsstat show state of SPI flash", + " tfsstore copy TFSRAM to NAND", + " tfserase erase NAND space allocated to TFS", + " tfsrm {name} remove file directly out of NAND flash", + " tfsadd {name} [src sz] add file directly to NAND flash", +#endif + " erase {addr len} erase block", + " read {addr dest len} read block", + " write {addr src len} write block", +#endif + 0, +}; + +int +nandCmd(int argc,char *argv[]) +{ + unsigned long addr; + char *cmd, *dest, *src; + int opt, len, rc; + + rc = 0; + nandVerbose = 0; + while((opt=getopt(argc,argv,"v")) != -1) { + switch(opt) { + case 'v': + nandVerbose++; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc < optind+1) + return(CMD_PARAM_ERROR); + + cmd = argv[optind]; + + if (nandVerbose) + printf("CMD: %s\n",cmd); + + if (strcmp(cmd,"init") == 0) { + nandInit(); + } + else if (strcmp(cmd,"info") == 0) { + nandInfo(); + } + else if (strcmp(cmd,"erase") == 0) { + if (argc != optind+3) + return(CMD_PARAM_ERROR); + addr = strtoul(argv[optind+1],0,0); + len = (int)strtol(argv[optind+2],0,0); + nandEraseChunk((char *)addr,len); + } + else if (strcmp(cmd,"write") == 0) { + if (argc != optind+4) + return(CMD_PARAM_ERROR); + addr = strtoul(argv[optind+1],0,0); + src = (char *)strtoul(argv[optind+2],0,0); + len = (int)strtol(argv[optind+3],0,0); + nandWriteChunk((char *)addr,src,len); + } + else if (strcmp(cmd,"read") == 0) { + if (argc != optind+4) + return(CMD_PARAM_ERROR); + addr = strtoul(argv[optind+1],0,0); + dest = (char *)strtoul(argv[optind+2],0,0); + len = (int)strtol(argv[optind+3],0,0); + nandReadChunk((char *)addr,dest,len); + } +#ifdef FLASHRAM_BASE + else if (strcmp(cmd,"tfsload") == 0) { + } + else if (strcmp(cmd,"tfsstore") == 0) { + } + else if (strcmp(cmd,"tfserase") == 0) { + } + else if (strcmp(cmd, "tfsls") == 0) { + int ftot; + char *addr; + TFILE tfshdr, *fp; + + ftot = 0; + fp = &tfshdr; + addr = (char *)BASE_OF_NAND; + while(addr < (char *)END_OF_NAND) { + char fbuf[32], *flags; + + if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) { + printf("nandReadChunk failed %d\n",rc); + break; + } + if (fp->hdrsize == 0xffff) + break; + if (TFS_FILEEXISTS(fp)) { + if (ftot == 0) + printf(" Name Size Offset Flags Info\n"); + ftot++; + flags = tfsflagsbtoa(TFS_FLAGS(fp),fbuf); + if ((!flags) || (!fbuf[0])) + flags = " "; + printf(" %-23s %7ld 0x%08lx %-5s %s\n",TFS_NAME(fp), + TFS_SIZE(fp),(unsigned long)(addr+TFSHDRSIZ), + flags,TFS_INFO(fp)); + } + addr += TFS_SIZE(fp); + addr += TFSHDRSIZ; + while((long)addr & 0xf) addr++; + } + } + else if (strcmp(cmd, "tfsrm") == 0) { + char *addr; + TFILE tfshdr, *fp; + char *arg2 = argv[optind+1]; + + fp = &tfshdr; + addr = (char *)BASE_OF_NAND; + while(addr < (char *)END_OF_NAND) { + if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) { + printf("nandReadChunk failed %d\n",rc); + break; + } + if (fp->hdrsize == 0xffff) { + printf("%s not found\n",arg2); + break; + } + if (strcmp(TFS_NAME(fp),arg2) == 0) { + if (TFS_FILEEXISTS(fp)) { + fp->flags &= ~TFS_ACTIVE; + if ((rc = nandWriteChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) + printf(" write_hdr failed %d\n",rc); + break; + } + } + addr += TFS_SIZE(fp); + addr += TFSHDRSIZ; + while((long)addr & 0xf) addr++; + } + } + else if (strcmp(cmd, "tfsadd") == 0) { + int size; + long bflags; + TFILE tfshdr, *fp; + char *addr; + char *src, *name, *info; + char *arg2 = argv[optind+1]; + char *arg3 = argv[optind+2]; + char *arg4 = argv[optind+3]; + char *icomma, *fcomma; + + info = ""; + bflags = 0; + name = arg2; + addr = (char *)BASE_OF_NAND; + + /* The incoming arguments can be either just the filename (in which + * case we assume the source is the file in TFS with the same name), + * or the filename, source address and size... + */ + if (argc == optind+2) { // Just filename? + if ((fp = tfsstat(name)) == (TFILE *)0) { + printf("File '%s' not in TFS\n",name); + return(CMD_FAILURE); + } + name = fp->name; + info = fp->info; + bflags = fp->flags; + size = fp->filsize; + src = (char *)(fp + 1); + fp = &tfshdr; + memset((char *)fp,0,TFSHDRSIZ); + } + else if (argc == optind+4) { // Filename with addr and len + // Extract flags and info fields (if any) from the name... + fcomma = strchr(name,','); + if (fcomma) { + icomma = strchr(fcomma+1,','); + if (icomma) { + *icomma = 0; + info = icomma+1; + } + *fcomma = 0; + bflags = tfsctrl(TFS_FATOB,(long)(fcomma+1),0); + } + + fp = &tfshdr; + memset((char *)fp,0,TFSHDRSIZ); + size = (int)strtol(arg4,0,0); + src = (char *)strtoul(arg3,0,0); + } + else + return(CMD_PARAM_ERROR); + + while(addr < (char *)END_OF_NAND) { + if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) + break; + if (fp->hdrsize == 0xffff) { + unsigned long nextfileaddr; + + /* We're at the address in NAND where we can add the new + * file, but first we need to make sure there's enough + * room... + */ + if ((TFSHDRSIZ + size + 16) >= ((char *)END_OF_NAND - addr)) { + printf(" not enough space\n"); + return(CMD_FAILURE); + } + + /* Copy name and info data to header. + */ + strcpy(fp->name, name); + strcpy(fp->info, info); + fp->hdrsize = TFSHDRSIZ; + fp->hdrvrsn = TFSHDRVERSION; + fp->filsize = size; + fp->flags = bflags; + fp->flags |= (TFS_ACTIVE | TFS_NSTALE); + fp->filcrc = crc32((unsigned char *)src,size); + fp->modtime = tfsGetLtime(); +#if TFS_RESERVED + { + int rsvd; + for(rsvd=0;rsvd<TFS_RESERVED;rsvd++) + fp->rsvd[rsvd] = 0xffffffff; + } +#endif + fp->next = 0; + fp->hdrcrc = 0; + fp->hdrcrc = crc32((unsigned char *)fp,TFSHDRSIZ); + nextfileaddr = NAND_TFSRAM_BASE - NAND_TFS_BASE + (long)addr + TFSHDRSIZ + size; + if (nextfileaddr & 0xf) + nextfileaddr = (nextfileaddr | 0xf) + 1; + + fp->next = (TFILE *)nextfileaddr; + + printf(" writing %s...\n",arg2); + if ((rc = nandWriteChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) + printf(" write_hdr failed %d\n",rc); + + if ((rc = nandWriteChunk(addr+TFSHDRSIZ,src,size)) < 0) + printf(" write_file failed %d\n",rc); + break; + } + if (strcmp(TFS_NAME(fp),arg2) == 0) { + if (TFS_FILEEXISTS(fp)) { + printf(" removing %s...\n",arg2); + fp->flags &= ~TFS_ACTIVE; + if ((rc = nandWriteChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) + printf(" write_hdr failed %d\n",rc); + } + } + addr += TFS_SIZE(fp); + addr += TFSHDRSIZ; + while((long)addr & 0xf) addr++; + } + } + else if (strcmp(cmd, "tfsstat") == 0) { + char *addr, *oaddr; + TFILE tfshdr, *fp; + unsigned long meminuse, memdead; + + fp = &tfshdr; + meminuse = memdead = 0; + addr = (char *)BASE_OF_NAND; + while(addr < (char *)END_OF_NAND) { + if ((rc = nandReadChunk(addr,(char *)fp,TFSHDRSIZ)) < 0) { + printf("nandReadChunk failed %d\n",rc); + break; + } + if (fp->hdrsize == 0xffff) + break; + + oaddr = addr; + addr += TFS_SIZE(fp); + addr += TFSHDRSIZ; + while((long)addr & 0xf) addr++; + + if (TFS_FILEEXISTS(fp)) + meminuse += addr - oaddr; + else + memdead += addr - oaddr; + } + printf("Total: 0x%x, used: 0x%x, dead: 0x%x, avail: 0x%x\n", + SIZE_OF_NAND, meminuse, memdead, + SIZE_OF_NAND - (meminuse + memdead)); + } +#endif + else + return(CMD_PARAM_ERROR); + + return(CMD_SUCCESS); +} +#endif diff --git a/main/common/nand.h b/main/common/nand.h new file mode 100644 index 0000000..d3ee697 --- /dev/null +++ b/main/common/nand.h @@ -0,0 +1,34 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * nand.h + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +extern int nandVerbose; +extern int nandInit(void); +extern int nandInfo(void); +extern int nandEraseChunk(char *addr, int len); +extern int nandReadChunk(char *src, char *dest, int len); +extern int nandWriteChunk(char *src, char *dest, int len); + + diff --git a/main/common/password.c b/main/common/password.c new file mode 100644 index 0000000..94f8f9c --- /dev/null +++ b/main/common/password.c @@ -0,0 +1,289 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * password: + * + * Code that supports the use of a password in the monitor. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "genlib.h" +#include "ether.h" +#include "tfs.h" +#include "tfsprivate.h" + +#if INCLUDE_USRLVL + +extern char *crypt(char *,char *,char *); + +/* PASSWORD_FILE: + * The name of the file that is used to store passwords. + */ +#ifndef PASSWORD_FILE +#define PASSWORD_FILE ".monpswd" +#endif + +#define SALT0 'T' +#define SALT1 'J' + +int +passwordFileExists(void) +{ + if (tfsstat(PASSWORD_FILE)) + return(1); + return(0); +} + +/* backdoor(): + * A mechanism that allows a password to be generated based on the + * MAC address of the board... + * + * Return 1 if the password matches the return of crypt(KEY,SALT). + * Where: + * KEY is an 8-character string created from the MAC address + * stored in the ETHERADD environment variable; + * SALT is a 2-character string made up of the first and last + * character of the ETHERADD env var; + */ +int +backdoor(char *password) +{ + int i; + char *etherstr, salt[3], encryption[32]; + unsigned char etherbin[9]; + + etherstr = getenv("ETHERADD"); + if (!etherstr) /* just in case... */ + etherstr = "00:00:00:00:00:00"; + + /* 2 salt characters are the first and last characters of etherstr: */ + salt[0] = etherstr[0]; + salt[1] = etherstr[strlen(etherstr)-1]; + salt[2] = 0; + + EtherToBin(etherstr,etherbin); + etherbin[6] = 'A'; + etherbin[7] = 'a'; + etherbin[8] = 0; + + for(i=0;i<6;i++) { + while (etherbin[i] > 0x7e) { + etherbin[i] -= 0x20; + etherbin[6]++; + } + while (etherbin[i] < 0x20) { + etherbin[i] += 0x8; + etherbin[7]++; + } + } + + crypt((char *)etherbin,salt,encryption); + + /* Note that the first two characters of the return from crypt() */ + /* are not used in the comparison... */ + if (!strcmp(password,encryption+2)) + return(1); + else + return(0); +} + +/* validPassword(): + * Called with a password and user level. There are a few different ways + * in which this can pass... + * 1. If there is no PASSWORD_FILE in TFS, return true. + * 2. If the password matches the backdoor entry, return true. + * 3. If the password matches appropriate entry in the password file, + * return true. + */ + +int +validPassword(char *password, int ulvl) +{ + char line[80]; + int (*fptr)(void); + int tfd, lno, pass, lsize; + + /* If there is a password file, then use it. + * If there is no password file, then call extValidPassword() to + * support systems that store the password some other way. + * The extValidPassword() function should return 0 if password check + * failed, 1 if the check succeeded and -1 if there is no external + * password storage hardware. + * Finally, if there is no password file, AND there is no external + * password storage hardware, then just return 1 to + * indicate that ANY password is a valid password. In other words... + * the password protection stuff is only enabled if you have a password + * stored away somewhere. + */ + if (!passwordFileExists()) { + static int warning; + + switch(extValidPassword(password,ulvl)) { + case 0: /* Password check failed. */ + return(0); + case 1: /* Password check passed. */ + return(1); + default: /* No external password check in use. */ + break; + } + if (!warning) { + printf("WARNING: no %s file, security inactive.\n",PASSWORD_FILE); + warning = 1; + } + return(1); + } + + /* First check for backdoor entry... */ + if (backdoor(password)) + return(1); + + /* Incoming user level must be in valid range... */ + if ((ulvl < MINUSRLEVEL) || (ulvl > MAXUSRLEVEL)) + return(0); + + /* If user level is MINUSRLEVEL, there is no need for a password. */ + if (ulvl == MINUSRLEVEL) + return(1); + + /* Check for a match in the password file... + * The PASSWORD_FILE dedicates one line for each user level. + * Line1 is password for user level 1. + * Line2 is password for user level 2. + * Line3 is password for user level 3. + * User level 0 doesn't require a password. + */ + + /* Force the getUsrLvl() function to return MAX: */ + fptr = (int(*)(void))setTmpMaxUsrLvl(); + + tfd = tfsopen(PASSWORD_FILE,TFS_RDONLY,0); + if (tfd < 0) { + /* Restore the original getUsrLvl() functionality: */ + clrTmpMaxUsrLvl(fptr); + printf("%s\n",(char *)tfsctrl(TFS_ERRMSG,tfd,0)); + return(0); + } + + lno = 1; + pass = 0; + while((lsize=tfsgetline(tfd,line,sizeof(line)))) { + char encryption[32], salt[3]; + + if (lno != ulvl) { + lno++; + continue; + } + + line[lsize-1] = 0; /* Remove the newline */ + + salt[0] = SALT0; + salt[1] = SALT1; + salt[2] = 0; + + crypt(password,salt,encryption); + + if (!strncmp(line,encryption+2,strlen(line)-2)) + pass = 1; + break; + } + tfsclose(tfd,0); + + /* Restore the original getUsrLvl() functionality: */ + clrTmpMaxUsrLvl(fptr); + + return(pass); +} + +/* newPasswordFile(): + * Prompt the user for three passwords. One for each user level. + * Then, after retrieving them, make sure the user wants to update + * the password file; if yes, do it; else abort. + */ +int +newPasswordFile(void) +{ + int err, i; + char pswd1[16], pswd2[16]; + char salt[3], *epwp, buf[32], epswd[34*3], flags[8]; + + /* For each of the three levels (1,2&3), get the password, encrypt it + * and concatenate newline for storate into the password file. + */ + + epwp = epswd; + for(i=1;i<4;i++) { + while(1) { + printf("Lvl%d ",i); + getpass("passwd: ",pswd1,sizeof(pswd1)-1,0); + if (strlen(pswd1) < 8) { + printf("password must be >= 8 chars.\n"); + continue; + } + getpass("verify: ",pswd2,sizeof(pswd2)-1,0); + if (strcmp(pswd1,pswd2)) + printf("Entries do not match, try again...\n"); + else + break; + } + salt[0] = SALT0; + salt[1] = SALT1; + salt[2] = 0; + crypt(pswd1,salt,buf); + sprintf(epwp,"%s\n",&buf[2]); + epwp += strlen(epwp); + } + + if (!askuser("Are you sure?")) + return(0); + + err = tfsunlink(PASSWORD_FILE); + if ((err != TFS_OKAY) && (err != TFSERR_NOFILE)) { + printf("%s\n",(char *)tfsctrl(TFS_ERRMSG,err,0)); + return(-1); + } + + sprintf(flags,"u%d",MAXUSRLEVEL); + err = tfsadd(PASSWORD_FILE,0, flags, (uchar *)epswd, strlen(epswd)); + if (err != TFS_OKAY) { + printf("%s\n",(char *)tfsctrl(TFS_ERRMSG,err,0)); + return(-1); + } + return(0); +} + + +#ifndef EXT_VALID_PASSWORD +/* extValidPassword(): + * See validPassword() above for notes on the purpose of this function. + * + * This is the default stub, if a real extValidPassword() function is + * provided by the port, then EXT_VALID_PASSWORD should be defined in + * that port's config.h file. +*/ +int +extValidPassword(char *password, int ulvl) +{ + return(-1); +} +#endif /* EXT_VALID_PASSWORD */ +#endif /* INCLUDE_USRLVL */ diff --git a/main/common/pci.c b/main/common/pci.c new file mode 100644 index 0000000..2dddb0f --- /dev/null +++ b/main/common/pci.c @@ -0,0 +1,747 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * pci.c: + * + * This file provides the monitor with a reusable mechanism for + * interfacing with a PCI bus. Four target-specific functions are + * required: + * + * pciCtrl(), pciCfgRead(), pciCfgWrite(), pciShow() + * + * The two most important are pciCfgRead() and pciCfgWrite(). Refer to + * the bottom of pci.h for further details. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "pci.h" +#include "stddefs.h" +#include "genlib.h" +#include "cli.h" + +#if INCLUDE_PCI +int pciVerbose; +int pciBusNum; + +#define IMPLEMENTED 0x80000000 + +#ifdef USE_DEFAULT_PCISHOW +void +pciShow(int interface) +{ + printf("No fixed devices on this platform\n"); +} +#endif + +/* pciCfgAddress(): + * Return a 32-bit value based on the input + * bus number, device number, function number and register + * number: + * + * 31 30 .... 24 23 ... 16 15 ... 11 10 .... 8 7 ... 2 1 0 + * -------------------------------------------------------------- + * | | | Bus | Device | Function | Register |0|T| + * |En| Reserved | Number | Number | Number | Number | | | + * -------------------------------------------------------------- + * ^ ^ + * |---- Enable bit 1=enabled, 0=disabled | + * | + * Type0: 0 --------------------------------------------| + * Type1: 1 --------------------------------------------| + * + * See pg 32 of the PCI2.2 spec for more details. + */ + +unsigned long +pciCfgAddress(int busno,int devno,int fncno,int regno) +{ + int type; + + if (busno > 0) + type = 1; + else + type = 0; + + return((type | PCICFG_ENABLE_BIT | + ((busno & PCICFG_BUSNO_MASK) << PCICFG_BUSNO_SHIFT) | + ((devno & PCICFG_DEVNO_MASK) << PCICFG_DEVNO_SHIFT) | + ((fncno & PCICFG_FNCNO_MASK) << PCICFG_FNCNO_SHIFT) | + ((regno & PCICFG_REGNO_MASK) << PCICFG_REGNO_SHIFT))); +} + +/* pciBaseClass(): + * Based on appendix D of spec, return a simple string that describes + * the base class of the incoming class code. + */ +char * +pciBaseClass(unsigned long classcode) +{ + unsigned long baseclass; + unsigned long subclass_progif; + + baseclass = (classcode >> 16) & 0xff; + subclass_progif = classcode & 0xffff; + + switch(baseclass) { + case 0: + return("pre-class-code-definitions"); + case 1: + return("mass storage ctrlr"); + case 2: + return("network ctrlr"); + case 3: + return("display ctrlr"); + case 4: + return("multimedia device"); + case 5: + return("memory ctrlr"); + case 6: /* Supply additional information for bridge class... + */ + switch(subclass_progif) { + case 0x0000: + return("host/pci bridge"); + case 0x0100: + return("pci/isa bridge"); + case 0x0200: + return("pci/eisa bridge"); + case 0x0300: + return("pci/microchannel bridge"); + case 0x0400: + return("pci/pci bridge"); + case 0x0500: + return("pci/pcmcia bridge"); + case 0x0600: + return("pci/nubus bridge"); + case 0x0700: + return("pci/cardbus bridge"); + case 0x8000: + return("other bridge type"); + default: + return("bridge device"); + } + case 7: + return("simple communication ctrlr"); + case 8: + return("base system peripheral"); + case 9: + return("input device"); + case 10: + return("docking station"); + case 11: + return("processor"); + case 12: + return("serial bus ctrlr"); + case 13: + return("wireless ctrlr"); + case 14: + return("intelligent io ctrlr"); + case 15: + return("satellite communication ctrlr"); + case 16: + return("encrypt/decrypt ctrlr"); + case 17: + return("data acquisition ctrlr"); + case 256: + return("no fit"); + default: + return("reserved"); + } +} + +/* pciscan(): + * This function is used by "pci scan" and "pci enum" to look + * at the devices on the pci bus. When the enumerate flag is set, + * this function will recursively nest itself each time it sees a + * PCI-to-PCI bridge device on the bus, and while doing this, it will + * assign bus numbers to each bridge appropriately. This function does + * not assign address ranges or anything else, it simply provides a quick + * means of scanning all devices on the bus(es). + * + * NOTE: This has only been tested with simple PCI bus configurations (one + * bridge deep) so deeper configurations (bridges on bridges on bridges...) + * are untested as far as I know. + */ +void +pciscan(long interface, long bus, long func, int showhdr, int enumerate) +{ + long device; + uchar hdr_type, rev_id; + ushort vendor_id, device_id; + ulong value, class_code; + + if (showhdr) { + printf("\nInterface %ld...\n",interface); + printf("Bus Dev Vndr Dev Rev Hdr Class\n"); + printf("Num Num Id Id Id Type Code\n"); + } + + if ((enumerate == 1) && (bus == 0)) + pciBusNum = 0; + + for(device=0;device<=31;device++) { + /* Retrieve portions of the configuration header that + * are required by all PCI compliant devices... + * Vendor, Device and Revision IDs, Class Code and Header Type + * (see pg 191 of spec). + */ + + /* Read reg_0 for vendor and device ids: + */ + value = pciCfgRead(interface,bus,device,func,0); + if (value == NO_DEVICE) + continue; + + vendor_id = (ushort)(value & 0xffff); + device_id = (ushort)((value>>16) & 0xffff); + + /* Read reg_2 for class code and revision id: + */ + value = pciCfgRead(interface,bus,device,func,2); + rev_id = (uchar)(value & 0xff); + class_code = (ulong)((value>>8) & 0xffffff); + + /* Read reg_3: header type: + */ + value = pciCfgRead(interface,bus,device,func,3); + hdr_type = (uchar)((value>>16) & 0xff); + + printf("%2ld %02ld x%04x x%04x",bus, + device,vendor_id,device_id); + printf(" x%02x x%02x x%06lx (%s)\n",rev_id, + hdr_type,class_code,pciBaseClass(class_code)); + + /* If enumeration is enabled, see if this is a PCI-to-PCI + * bridge. If it is, then nest into pciscan... + */ + if ((enumerate) && (class_code == 0x060400)) { + ulong pribus, secbus, subbus; + + pribus = pciBusNum & 0x0000ff; + pciBusNum++; + secbus = ((pciBusNum << 8) & 0x00ff00); + subbus = ((pciBusNum << 16) & 0xff0000); + + value = pciCfgRead(interface,bus,device,func,6); + value &= 0xffff0000; + value |= (pribus | secbus); + pciCfgWrite(interface,bus,device,func,6,value); + + pciscan(interface,pciBusNum,func,0,1); + + value = pciCfgRead(interface,bus,device,func,6); + value &= 0xff000000; + value |= (subbus | pribus | secbus); + pciCfgWrite(interface,bus,device,func,6,value); + } + } +} + +/* getBarInfo(): + * Apply the algorithm as specified in PCI spec... + * Place size information in sizehi & sizelo (to support 64-bit). + * Return 0 if not implemented; else return value to indicate + * size (32 or 64 bit) and type (mem or io). + */ +ulong +getBarInfo(long interface,long bus,long device,long func,int barnum, + ulong *sizehi, ulong *sizelo) +{ + int barregno; + ulong implemented, barval1, barval2, barinfo1, barinfo2, cmd; + + /* Translate the incoming bar number to a register number + * in PCI config space: + */ + barregno = barnum + 4; + + /* Disable decoding through the command register: + */ + cmd = pciCfgRead(interface,bus,device,func,1); + pciCfgWrite(interface,bus,device,func,1, + cmd & ~(IO_SPACE | MEMORY_SPACE)); + + /* Read the BAR: + */ + barval1 = pciCfgRead(interface,bus,device,func,barregno); + + /* Write 0xffffffff to the BAR: + */ + pciCfgWrite(interface,bus,device,func,barregno,0xffffffff); + + /* Read the value returned as a result of writing + * 0xffffffff to the BAR: + */ + barinfo1 = pciCfgRead(interface,bus,device,func,barregno); + + /* Restore original bar: + */ + pciCfgWrite(interface,bus,device,func,barregno,barval1); + + if (barinfo1 == 0) { + implemented = 0; + } + else { + implemented = IMPLEMENTED; + + if (barval1 & BASEADDRESS_IO) { + implemented |= BASEADDRESS_IO; + + if (sizelo) { + /* Clear encoding bits: + */ + barinfo1 &= 0xfffffffe; + /* Invert and add 1: + */ + *sizelo = (~barinfo1 + 1) & 0xffff; + + if (sizehi) + *sizehi = 0; + } + } + else { + implemented |= (barinfo1 & PREFETCHABLE); + + if (barval1 & TYPE_64) { + implemented |= TYPE_64; + + /* Apply same sequence as above to the next bar... + */ + barregno++; + barval2 = pciCfgRead(interface,bus,device,func,barregno); + pciCfgWrite(interface,bus,device,func,barregno,0xffffffff); + barinfo2 = pciCfgRead(interface,bus,device,func,barregno); + pciCfgWrite(interface,bus,device,func,barregno,barval2); + + + if (sizelo) { + barinfo1 &= 0xfffffff0; + *sizelo = ~barinfo1 + 1; + if (sizehi) + *sizehi = ~barinfo2 + 1; + } + } + else { + if (sizelo) { + barinfo1 &= 0xfffffff0; + *sizelo = ~barinfo1 + 1; + + if (sizehi) + *sizehi = 0; + } + } + } + } + + /* Now that we've completed messing with the BARS, + * restore original cmd: + */ + pciCfgWrite(interface,bus,device,func,1,cmd); + + return(implemented); +} + +int +showBar(int barnum,long interface,long bus,long device,long func) +{ + int rtot; + ulong bar, barnext, sizehi, sizelo, implemented; + + if ((barnum < 0) || (barnum > 5)) + return(-1); + + bar = pciCfgRead(interface,bus,device,func,barnum+4); + + implemented = getBarInfo(interface,bus,device,func, + barnum,&sizehi,&sizelo); + + if (!implemented) { + printf("%02d BAR%d : not implemented\n",barnum+4,barnum); + return(0); + } + + printf("%02d BAR%d",barnum+4,barnum); + if (!(implemented & BASEADDRESS_IO) && (implemented & TYPE_64)) { + barnext = pciCfgRead(interface,bus,device,func,barnum+5); + printf("-%d: 0x%08lx 0x%08lx", barnum+1,bar,barnext); + } + else { + printf(" : 0x%08lx",bar); + } + + printf(" Size: 0x"); + if (!(implemented & BASEADDRESS_IO) && (implemented & TYPE_64)) { + printf("%08lx%08lx ",sizehi,sizelo); + rtot = 2; + } + else { + printf("%08lx ",sizelo); + rtot = 1; + } + + if (bar & BASEADDRESS_IO) { + printf("IO"); + } + else { + printf("MEM %sbit",bar & TYPE_64 ? "64" : "32"); + } + + if (bar & PREFETCHABLE) + printf(" prefetchable"); + + putchar('\n'); + return(rtot); +} + +void +dumpRawCfg(long interface,long bus,long device,long func,char *range, + char* varname) +{ + int gotone; + long regno; + ulong value; + + value = 0; + gotone = 0; + for(regno=0;regno<64;regno++) { + if (inRange(range,regno)) { + value = pciCfgRead(interface,bus,device,func,regno); + printf("Cfg reg #%02ld: 0x%08lx\n",regno,value); + gotone = 1; + } + } + if ((varname) && (gotone)) + shell_sprintf(varname,"0x%08lx",value); +} + +void +dumpConfig(long interface,long bus,long device,long func) +{ + int i; + char *multifunc, *type; + ulong hdrtype, values[16]; + + for(i=0;i<16;i++) + values[i] = pciCfgRead(interface,bus,device,func,i); + + hdrtype = values[3] & HDR_MASK; + + if (hdrtype & HDR_MULTIFUNC) { + multifunc = "multi-function "; + hdrtype &= ~HDR_MULTIFUNC; + } + else { + multifunc = ""; + } + + switch(hdrtype) { + case HDR_PCI2PCI: + type = "PCI-to-PCI"; + break; + case HDR_CARDBUS: + type = "CardBus"; + break; + case HDR_STANDARD: + type = "Standard"; + break; + default: + printf("dumpConfig(): hdrtype 0x%08lx not supported\n",hdrtype); + return; + } + printf("%s %sconfig...\n",type,multifunc); + + printf("00 DevId/VendorId: 0x%04lx/%04lx\n", + (values[0] & 0xffff0000) >> 16,values[0] & 0xffff); + + printf("01 Status/Command: 0x%04lx/%04lx\n", + (values[1] & 0xffff0000) >> 16,values[1] & 0xffff); + + printf("02 ClassCode/RevId: 0x%06lx/%02lx\n", + (values[2] & 0xffffff00) >> 8,values[2] & 0xff); + + + printf("03 BIST/HdrType/LatencyTmr/CacheLnSz: 0x%02lx/%02lx/%02lx/%02lx\n", + (values[3] & 0xff000000) >> 24, (values[3] & 0xff0000) >> 16, + (values[3] & 0xff00) >> 8,values[3] & 0xff); + + if (showBar(0,interface,bus,device,func) == 1) + showBar(1,interface,bus,device,func); + + if (hdrtype == HDR_STANDARD) { + if (showBar(2,interface,bus,device,func) == 1) + showBar(3,interface,bus,device,func); + if (showBar(4,interface,bus,device,func) == 1) + showBar(5,interface,bus,device,func); + + printf("10 Cardbus CIS Ptr: 0x%08lx\n",values[10]); + printf("11 SubSysId/SubVendorId: 0x%04lx/%04lx\n", + (values[11] & 0xffff0000) >> 16,values[11] & 0xffff); + printf("12 Expansion ROM BaseAddr: 0x%08lx\n",values[12]); + } + else if (hdrtype == HDR_PCI2PCI) { + printf("06 Secondary Latency Tmr: 0x%02lx\n", + (values[6] & 0xff000000) >> 24); + printf("06 BusNum Subordinate/Secondary/Primary: 0x%02lx/%02lx/%02lx\n", + (values[6] & 0xff0000) >> 16, + (values[6] & 0xff00) >> 8,values[6] & 0xff); + + printf("07 Secondary Status: 0x%04lx\n", + (values[7] & 0xffff0000) >> 16); + printf("07 IO Limit/Base: 0x%02lx/%02lx\n", + (values[7] & 0xff00) >> 8,(values[7] & 0xff)); + + printf("08 Memory Limit/Base: 0x%04lx/%04lx\n", + (values[8] & 0xffff0000) >> 16,values[8] & 0xffff); + + printf("09 Prefetchable Memory Limit/Base: 0x%04lx/%04lx\n", + (values[9] & 0xffff0000) >> 16,values[9] & 0xffff); + + printf("10 Prefetchable Base Upper 32 bits: 0x%08lx\n",values[10]); + printf("11 Prefetchable Limit Upper 32 bits: 0x%08lx\n",values[11]); + + printf("12 IO Upper 16 Bits Limit/Base: 0x%04lx/%04lx\n", + (values[12] & 0xffff0000) >> 16,values[12] & 0xffff); + } + + printf("13 Capabilities Ptr: 0x%02lx\n",values[13] & 0xff); + + if (hdrtype == HDR_STANDARD) { + printf("15 MaxLat/MinGnt: 0x%02lx/%02lx\n", + (values[15] & 0xff000000) >> 24, (values[15] & 0xff0000) >> 16); + } + else { + printf("14 Expansion ROM BaseAddr: 0x%08lx\n", + values[14]); + printf("15 BridgeControl: 0x%04lx\n", + (values[15] & 0xffff0000) >> 16); + } + + printf("15 Interrupt Pin/Line: 0x%02lx/%02lx\n", + (values[15] & 0xff00) >> 8, values[15] & 0xff); +} + +char *PciHelp[] = { + "PCI Config Interface", + "-[b:d:f:i:v] {operation} [args]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -b{###} bus #", + " -d{###} device #", + " -f{###} function #", + " -i{###} interface #", + " -v verbose", + "Operations:", + " scan, enum, bist, show, size {bar#}", + " crd [reg#] [varname], cwr {reg#} {value}", + "Note:", + " bus, device, function & interface default to zero", +#endif + 0 +}; + +/* PciCmd(): + * General purpose command to provide access to the config portion of + * a PCI interface. + * + * Notice that there is reference to an "interface number" as well as a + * "bus number". In most systems, there will be one host-to-pci interface. + * and one pci bus. Some targets will have more than one host-to-pci + * interface (galileo 64260A, for example, has 2 distinct host-to-PCI + * interface). Some targets will have more than one bus (depends on whether + * or not there is a pci-to-pci bridge hanging off the bus). + * + */ +int +PciCmd(int argc, char *argv[]) +{ + ulong value, bar; + long bus, device, interface, regno, func; + int enumerate, opt; + + bus = 0; + func = 0; + device = 0; + enumerate = 0; + interface = 0; + pciVerbose = 0; + while ((opt=getopt(argc,argv,"b:d:f:i:v")) != -1) { + switch(opt) { + case 'b': + bus = strtol(optarg,0,0); + break; + case 'd': + device = strtol(optarg,0,0); + break; + case 'f': + func = strtol(optarg,0,0); + break; + case 'i': /* Most systems will only have 1 interface */ + interface = strtol(optarg,0,0); + break; + case 'v': + pciVerbose = 1; + break; + default: + return(CMD_FAILURE); + } + } + + if (argc < optind+1) + return(CMD_PARAM_ERROR); + + /* The "scan" and "enum" commands are very similar. They both use + * the pciscan() function. + * + * Scan: look at the devices on the specified bus. + * Enum: a recursive scan... start with bus 0 and attempt to query + * all devices on all busses, making the necessary bus-number assignments + * along the way. + */ + + /* For scan, the device number is ignored, all devices on a particular + * interface/bus are checked. If ths bus number is something other than + * zero, then this function assumes that the appropriate pci-to-pci + * bridge device has already had its bus numbers assigned. + */ + if (!strcmp(argv[optind],"scan")) { + if (argc != optind+1) + return(CMD_PARAM_ERROR); + + pciscan(interface,bus,func,1,0); + return(CMD_SUCCESS); + } + + /* For enum, we start with bus 0, and attempt to enumerate all busses... + */ + if (!strcmp(argv[optind],"enum")) { + if (argc != optind+1) + return(CMD_PARAM_ERROR); + + pciscan(interface,0,func,1,1); + return(CMD_SUCCESS); + } + + if (!strcmp(argv[optind],"size")) { /* See pg 204 of PCI2.2 spec */ + int barnum; + ulong implemented, sizehi, sizelo; + + if (argc != optind+2) + return(CMD_PARAM_ERROR); + + /* The argument to size is the BAR #. The value can be a single + * digit or a range specification... + */ + printf(" Bar Type Value Size\n"); + for(barnum=0;barnum<6;barnum++) { + setenv("PCISIZE",0); + if (inRange(argv[optind+1],barnum)) { + /* Disable decoding through the command register: + * See section 6.2.2, pg 193. + */ + value = pciCfgRead(interface,bus,device,func,1); + pciCfgWrite(interface,bus,device,0,1, + value & ~(IO_SPACE | MEMORY_SPACE)); + + bar = pciCfgRead(interface,bus,device,func,barnum+4); + implemented = getBarInfo(interface,bus,device,func, + barnum,&sizehi,&sizelo); + + printf(" %d ",barnum); + + if (implemented) { + shell_sprintf("PCISIZE","0x%08lx",bar); + printf("%s 0x%08lx ", + implemented & BASEADDRESS_IO ? "io " : "mem", bar); + if (implemented & TYPE_64) + printf("0x%08lx%08lx",sizehi,sizelo); + else + printf("0x%08lx",sizelo); + if (implemented & PREFETCHABLE) + printf(" (prefetchable)"); + putchar('\n'); + } + else + printf("not implemented\n"); + } + } + } + else if (!strcmp(argv[optind],"bist")) { + if (argc != optind+1) + return(CMD_PARAM_ERROR); + + value = pciCfgRead(interface,bus,device,func,3); + + if (value & BIST_CAPABLE) { + /* Set the BIST_START bit to begin the test, then wait for + * the BIST_START bit to clear as an indication that the + * test has completed. + */ + pciCfgWrite(interface,bus,device,func,3,value | BIST_START); + while(1) { + value = pciCfgRead(interface,bus,device,func,3); + if ((value & BIST_START) != BIST_START) + break; + } + if ((value & BIST_COMPCODE_MASK) != 0) + printf("BIST failed: 0x%lx\n",value & BIST_COMPCODE_MASK); + else + printf("BIST passed\n"); + } + else { + printf("Device %ld is not BIST-capable\n",device); + } + } + else if (!strcmp(argv[optind],"crd")) { + char *varname = (char *)0; + + if (argc == optind+3) { /* varname specified ? */ + varname = argv[optind+2]; + argc--; + } + + if (argc == optind+2) { + dumpRawCfg(interface,bus,device,func,argv[optind+1],varname); + } + else if (argc == optind+1) { + dumpConfig(interface,bus,device,func); + } + else + return(CMD_PARAM_ERROR); + } + else if (!strcmp(argv[optind],"cwr")) { + if (argc != optind+3) + return(CMD_PARAM_ERROR); + + regno = strtol(argv[optind+1],0,0); + value = strtol(argv[optind+2],0,0); + pciCfgWrite(interface,bus,device,func,regno,value); + } + else if (!strcmp(argv[optind],"init")) { + pciCtrl(interface,PCICTRL_INIT,0,0); + } + else if (!strcmp(argv[optind],"show")) { + pciShow(interface); + } + else + return(CMD_PARAM_ERROR); + return(CMD_SUCCESS); +} +#endif diff --git a/main/common/pci.h b/main/common/pci.h new file mode 100644 index 0000000..dbb225b --- /dev/null +++ b/main/common/pci.h @@ -0,0 +1,363 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * pci.h: + * + * GENERAL PCI Definitions. + * The majority of this is extracted from the PCI Local Bus Specification + * Revision 2.2. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + */ + +/* Layout of configuration address register: + * See section 3.2.2.3.2 (Software Generation of Configuration + * Transactions, pg 32). + */ +#ifndef _PCI_H_ +#define _PCI_H_ + +#define PCICFG_ENABLE_BIT 0x80000000 +#define PCICFG_BUSNO_MASK 0x000000ff +#define PCICFG_BUSNO_SHIFT 16 +#define PCICFG_DEVNO_MASK 0x0000001f +#define PCICFG_DEVNO_SHIFT 11 +#define PCICFG_FNCNO_MASK 0x00000007 +#define PCICFG_FNCNO_SHIFT 8 +#define PCICFG_REGNO_MASK 0x0000003f +#define PCICFG_REGNO_SHIFT 2 + +/* Command register layout (as it would be in the 32-bit register) + * See section 6.2.2 (Device Control, pg 193). + */ +#define FAST_BKTOBK_ENABLE 0x00000200 +#define SERR_ENABLE 0x00000100 +#define STEPPING_CTRL 0x00000080 +#define PARITY_ERROR_RESP 0x00000040 +#define VGA_PALETTE_SNOOP 0x00000020 +#define MEM_WRITE_INV_ENABLE 0x00000010 +#define SPECIAL_CYCLES 0x00000008 +#define BUS_MASTER 0x00000004 +#define MEMORY_SPACE 0x00000002 +#define IO_SPACE 0x00000001 + +/* Status register layout (as it would be in the 32-bit register) + * See section 6.2.3 (Device Status, pg 196). + */ +#define DETECTED_PARITY_ERR 0x80000000 +#define SIGNALED_SYSTEM_ERR 0x40000000 +#define RECVD_MASTER_ABORT 0x20000000 +#define RECVD_TARGET_ABORT 0x10000000 +#define SIGNALED_TARGET_ABORT 0x08000000 +#define DEV_SEL_TIMING_MASK 0x06000000 +#define DEV_SEL_TIMING_FAST 0x00000000 +#define DEV_SEL_TIMING_MEDIUM 0x02000000 +#define DEV_SEL_TIMING_SLOW 0x04000000 +#define MASTER_DATA_PARITY_ERR 0x01000000 +#define FAST_BKTOBK_CAPABLE 0x00800000 +#define CAPABLE_66MHZ 0x00200000 +#define CAPABILITIES_LIST 0x00100000 + +/* BaseAddressMapping + * See section 6.2.5.1 (Address Maps, pg 202). + */ +#define IMPLEMENTED 0x80000000 +#define BASEADDRESS_IO 0x00000001 +#define BASEADDRESS_MEM 0x00000000 +#define PREFETCHABLE 0x00000008 +#define TYPE_MASK 0x00000006 +#define TYPE_32 0x00000000 +#define TYPE_64 0x00000004 + +/* HeaderType definitions, as they would be in the 32-bit register. + * See section 6.2.1, pg 192. + */ +#define HDR_MASK 0x00ff0000 +#define HDR_STANDARD 0x00000000 +#define HDR_PCI2PCI 0x00010000 +#define HDR_CARDBUS 0x00020000 +#define HDR_MULTIFUNC 0x00800000 + +/* BIST bits, as they would be in the 32-bit register. + * See section 6.2.4 pg 199. + */ +#define BIST_CAPABLE 0x80000000 +#define BIST_START 0x40000000 +#define BIST_COMPCODE_MASK 0x0f000000 + +/*----------------------------------------------------------------------------- + * Mappings for PCI memory and IO spaces + */ + +/* Macros for getting an individual device or function from a combined + * device/function number + */ +#define PCI_MAKE_DEV_FUNC(_dev_, _func_) (((_dev_)<<3)|(_func_)) +#define PCI_GET_DEV(_dev_func_) ((_dev_func_ >> 3) & 0x1f) +#define PCI_GET_FUNC(_dev_func_) (_dev_func_ & 0x7) + +/* Macros for BUS, FUNC and DEV in PCI_CFG_ADD + */ +#define PCI_CFG_BUS(_x_) ((_x_ & 0xff) << 16) /* Bus Number */ +#define PCI_CFG_DEV(_x_) ((_x_ & 0xf8) << 11) /* Device Number */ +#define PCI_CFG_FUNC(_x_) ((_x_ & 0x07) << 8) /* Function Number */ +#define PCI_CFG_REG(_x_) ((_x_ & 0xfc) << 0) /* Register Number */ + +/*----------------------------------------------------------------------------- + * Configuration header offsets + *----------------------------------------------------------------------------- + */ +#define PCI_CFG_VEN_ID_REG 0x0 +#define PCI_CFG_DEV_ID_REG 0x2 +#define PCI_CFG_CMD_REG 0x4 +#define PCI_CFG_STAT_REG 0x6 +#define PCI_CFG_REV_REG 0x8 +#define PCI_CFG_IF_REG 0x9 +#define PCI_CFG_SUBCLASS_REG 0xa +#define PCI_CFG_CLASS_REG 0xb +#define PCI_CFG_HDR_TYPE_REG 0xe +#define PCI_CFG_BIST_REG 0xf +#define PCI_CFG_BAR0_REG 0x10 +#define PCI_CFG_BAR1_REG 0x14 +#define PCI_CFG_BAR2_REG 0x18 +#define PCI_CFG_BAR3_REG 0x1c +#define PCI_CFG_BAR4_REG 0x20 +#define PCI_CFG_BAR5_REG 0x24 +#define PCI_CFG_CIS_REG 0x28 /* Cardbus only */ +#define PCI_CFG_SUB_VEN_ID_REG 0x2c +#define PCI_CFG_SUB_DEV_ID_REG 0x2e +#define PCI_CFG_ROM_BASE_REG 0x30 +#define PCI_CFG_RES0_REG 0x34 +#define PCI_CFG_RES1_REG 0x38 +#define PCI_CFG_INT_REG 0x3c +#define PCI_CFG_CACHE_REG 0x3d +#define PCI_CFG_GNT_REG 0x3e +#define PCI_CFG_LAT_REG 0x3f + +/* bridge devices only + */ +#define PCI_CFG_BAR0_REG 0x10 +#define PCI_CFG_BAR1_REG 0x14 +#define PCI_CFG_PRI_BUS_REG 0x18 +#define PCI_CFG_SEC_BUS_REG 0x19 +#define PCI_CFG_SUB_BUS_REG 0x1a +#define PCI_CFG_SEC_LAT_REG 0x1b +#define PCI_CFG_IO_BASE_LO_REG 0x1c +#define PCI_CFG_IO_LIMIT_LO_REG 0x1d +#define PCI_CFG_MEM_BASE_REG 0x20 +#define PCI_CFG_MEM_LIMIT_REG 0x22 +#define PCI_CFG_PREFETCH_BASE_REG 0x24 +#define PCI_CFG_PREFETCH_LIMIT_REG 0x26 +#define PCI_CFG_IO_BASE_HI_REG 0x30 +#define PCI_CFG_IO_LIMIT_HI_REG 0x32 + +/* CLASS Codes + */ +#define PCI_CLASS_OLD 0x00 +#define PCI_CLASS_MASS 0x01 +#define PCI_CLASS_NET 0x02 +#define PCI_CLASS_DISPLAY 0x03 +#define PCI_CLASS_MULTIMEDIA 0x04 +#define PCI_CLASS_MEMORY 0x05 +#define PCI_CLASS_BRIDGE 0x06 +#define PCI_CLASS_SIMPLE_COMM 0x07 +#define PCI_CLASS_BASE_PERIPH 0x08 +#define PCI_CLASS_INPUT 0x09 +#define PCI_CLASS_DOCK 0x0a +#define PCI_CLASS_CPU 0x0b +#define PCI_CLASS_SERIAL_BUS 0x0c +#define PCI_CLASS_UNKNOWN 0xff + +/* BRIDGE SUBCLASS Codes + */ +#define PCI_SUBCLASS_BRIDGE_PCI_PCI 0x04 + +/* BAR types + */ +#define PCI_MEM_BAR_TYPE_32BIT 0x00 +#define PCI_MEM_BAR_TYPE_1M 0x01 +#define PCI_MEM_BAR_TYPE_64BIT 0x02 + +/* PCI Command Register bit defines + */ +#define PCI_CFG_CMD_IO 0x0001 +#define PCI_CFG_CMD_MEM 0x0002 +#define PCI_CFG_CMD_MASTER 0x0004 +#define PCI_CFG_CMD_SPECIAL 0x0008 +#define PCI_CFG_CMD_INVALIDATE 0x0010 +#define PCI_CFG_CMD_VGA_SNOOP 0x0020 +#define PCI_CFG_CMD_PARITY 0x0040 +#define PCI_CFG_CMD_WAIT 0x0080 +#define PCI_CFG_CMD_SERR 0x0100 +#define PCI_CFG_CMD_FAST_BACK 0x0200 + +/* PCI Status Register bit defines + */ +#define PCI_CFG_STAT_PERR 0x8000 /* 1 = MPC8245 detected an */ + /* addr or data parity error */ +#define PCI_CFG_STAT_SERR 0x4000 /* 1 = MPC8245 asserted SERR.*/ +#define PCI_CFG_STAT_MST_ABRT 0x2000 /* 1 = MPC8245 asserted */ + /* master-abort. */ +#define PCI_CFG_STAT_TGT_ABRT_MST 0x1000 /* 1 = MPC8245 received a */ + /* target-abort while acting */ + /* as a PCI master. */ +#define PCI_CFG_STAT_TGT_ABRT_TGT 0x0800 /* 1 = MPC8245 asserted a */ + /* target-abort while acting */ + /* as a PCI target. */ +#define PCI_CFG_STAT_PERR_DAT 0x0100 /* 1 = MPC8245 detected a */ + /* data parity error while */ + /* acting as a PCI master. */ + +/*-------------------------------------------------------------------------- + * Error messages from pci_probe_bus + */ +#define PCI_DEV_MAX_ERR 0x01 /* Ran out of space in */ + /* static structure, is this */ + /* really an error? */ +#define PCI_IO_BAR_MAX_ERR 0x02 /* IO Dev asked for too much space */ +#define PCI_IO_SPACE_ERR 0x03 /* We ran out of IO space to give */ +#define PCI_MEM_BAR_TYPE_ERR 0x04 /* Unsupported BAR type */ +#define PCI_MEM_BAR_MAX_ERR 0x05 /* MEM Dev asked for too much space */ +#define PCI_MEM_SPACE_ERR 0x06 /* We ran out of MEM space to give */ +#define PCI_BRIDGE_TYPE_ERR 0x07 /* Unsupported PCI Bridge type */ + +/* Probe limits + */ +#define PCI_IO_BAR_MAX 0x00100000 /* 1Mbyte IO Space per device */ +#define PCI_MEM_BAR_MAX 0x01000000 /* 16Mbyte MEM Space per device */ +#define PCI_DEV_MAX 31 /* 32 devices total */ + +/*-------------------------------------------------------------------------- + * Structure that gets filled in by pci_bus_probe + */ +typedef struct /* PCI device data */ +{ + unsigned short ven_id; /* vendor ID */ + unsigned short dev_id; /* device ID */ + unsigned char class; /* device Class */ + unsigned char subclass; /* device Subclass */ + unsigned long bar_size[6]; /* Memory size for each base address, */ + /* 0 for unused BAR's */ + unsigned long bar_map[6]; /* Physical address mapped - */ + /* 0 for unused BAR's */ + unsigned long func; /* The function number - usually 0 */ + unsigned long dev; /* The device number */ + unsigned long bus; /* The bus this device resides on. */ + /* Non-0 means it's across a bridge */ +} pci_device_structure; + + +/* See text of section 6.1 (Configuration Space Organization, pg 190) for an + * explanation of why 0xffff is used to indicate "no device" in a + * particular PCI slot. For all configuration space of a slot that is + * unoccupied, the PCI bridge device must return all ones. + * + * (Note that read accesses to unused registers within a valid PCI device + * should return 0). + */ +#define NO_DEVICE 0xffffffff + + +/* Commands used by pciCtrl(): + */ +#define PCICTRL_INIT 1 + +/* Functions in pci.c: + */ +extern int pciVerbose; +extern unsigned long pciCfgAddress(int busno,int devno,int fncno,int regno); +extern char *pciBaseClass(unsigned long classcode); + +/**************************************************************************** + * + * Functions needed by pci.c, that must be defined in the target + * specific source code: + */ +/* pciCtrl() + * Parameters: + * int interface- + * This parameter supports the case where the target hardware has more + * than one pci controller. The interface number would correspond to + * one of potentially several different controllers. + * int cmd- + * Command to be carried out by the control function. + * ulong arg1- + * First command-specific argument. + * ulong arg2- + * Second command-specific argument. + */ +extern int pciCtrl(int interface,int cmd,unsigned long arg1,unsigned long arg2); + +/* pciCfgWrite() + * Parameters: + * int interface- + * Refer to description in pciCtrl() above. + * int bus- + * Bus number. + * int dev- + * Device number on bus. + * int func- + * Function number on device. + * int reg- + * Register number to be written. Each reg number represents one 32-bit + * chunk of space in the configuration; hence, reg0 is offset 0, reg1 is + * offset 4, reg2 is offset 8, etc... + * ulong val- + * Value to be written into the specified config location. + * Return: + * int + * Return negative if failure, else 0. + */ +extern int pciCfgWrite(int interface,int bus,int dev,int func,int reg, + unsigned long val); + +/* pciCfgRead() + * Parameters: + * int interface- + * Refer to description in pciCtrl() above. + * int bus- + * Bus number. + * int dev- + * Device number on bus. + * int func- + * Function number on device. + * int reg- + * Register number to be written. Each reg number represents one 32-bit + * chunk of space in the configuration; hence, reg0 is offset 0, reg1 is + * offset 4, reg2 is offset 8, etc... + * Return: + * ulong + * Return the value stored in the specified config location. + */ +extern unsigned long pciCfgRead(int interface,int bus,int dev, + int func,int reg); + +/* pciShow() + * If appropriate, dump text to the user that verbosely describes the + * devices on the PCI bus. If the devices on the bus are not fixed, then + * this function should return a message indicating that. + * + * Parameters: + * int interface- + * Refer to description in pciCtrl() above. + */ +extern void pciShow(int interface); + +#endif diff --git a/main/common/redirect.c b/main/common/redirect.c new file mode 100644 index 0000000..f9de297 --- /dev/null +++ b/main/common/redirect.c @@ -0,0 +1,265 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * redirect: + * + * This code supports the monitor's ability to redirect what was destined for + * the console to a block of memory in RAM. Enough data is maintained so + * that the block of memory can be transferred to a file using tfsadd(). + * + * Description of redirection CLI syntax: + * > buffer_addr,buffer_size[,filename] + * >> [filename] + * + * - Single arrow starts up a redirection to some specified block of memory + * with a specified size. If the filename is specified, then the output + * of that single command is redirected to the buffer then transferred to + * the specified file in TFS. Any previously existent file of the same + * name is overwritten. + * + * - Double arrow with no argument says append output of this command to + * the previously established buffer. + * + * - Double arrow with an argument says append output of this command to + * the previously established buffer and then write that buffer to the + * specified filename. Once again, any previously existent file of the + * same name is overwritten. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "genlib.h" +#include "stddefs.h" +#include <ctype.h> +#include "tfs.h" +#include "tfsprivate.h" + +#if INCLUDE_REDIRECT + +/* Redirect states: + * ACTIVE: the current command has issued some redirection, so + * when RedirectCharacter() is called, it should copy the + * character to the redirect buffer. + * IDLE: the current command has not issued any redirection, so + * when RedirectCharacter() is called, it simply returns. + * UNINITIALIZED: the first call to >base,size[,file] has not been + * made so we don't have a buffer; hence we can't redirect anything. + */ +#define REDIRECT_UNINITIALIZED 0 +#define REDIRECT_ACTIVE 0x12345678 +#define REDIRECT_IDLE 0x87654321 + +static int RedirectSize, RedirectState; +static char *RedirectBase, *RedirectPtr, *RedirectEnd; +static char RedirectFile[TFSNAMESIZE]; + +/* getEnvVal(): + * This function is used under the context of the redirection code + * because of the fact that the docommand() function processes the + * redirection arrow prior to converting shell variables. + * This is important because we want to support the ability to do + * something like... + * + * echo hello >$APPRAMBASE,100 + * + * but we also want to allow a shell variable to contain a right + * arrow that is NOT processed by this redirection code. + */ +static ulong +getEnvVal(char *ptr) +{ +#if INCLUDE_SHELLVARS + char *v; + + /* If the incoming string starts with a '$', then retrieve the + * value and then convert that to a long; otherwise, just convert + * the string to a long immediately. + */ + if (*ptr == '$') { + v = shellsym_chk(*ptr,ptr+1,0,0,0); + if (!v) + return(0); + } + else + v = ptr; + return(strtoul(v,0,0)); +#else + return(0); +#endif +} + +int +RedirectionCheck(char *cmdcpy) +{ + int inquote; + char *arrow, *base, *comma, *space; + + base = cmdcpy; + arrow = (char *)0; + + /* Parse the incoming command line looking for a right arrow. + * This parsing assumes that there will be no negated arrows + * (preceding backslash) after a non-negated arrow is detected. + * Note that a redirection arrow within a double-quote set is + * ignored. This allows a shell variable that contains a right arrow + * to be printed properly if put in double quotes. + * For example... + * set PROMPT "maint> " + * echo $PROMPT # This will generate a redirection syntax error + * echo "$PROMPT" # This won't. + */ + inquote = 0; + while(*cmdcpy) { + if ((*cmdcpy == '"') && ((cmdcpy == base) || (*(cmdcpy-1) != '\\'))) { + inquote = inquote == 1 ? 0 : 1; + cmdcpy++; + continue; + } + if (inquote == 1) { + cmdcpy++; + continue; + } + if (*cmdcpy == '>') { + arrow = cmdcpy; + if (*(arrow-1) == '\\') { + strcpy(arrow-1,arrow); + cmdcpy = arrow+1; + arrow = (char *)0; + continue; + } + break; + } + cmdcpy++; + } + if (arrow == (char *)0) + return(0); + + /* Remove the remaining text from the command line because it is to + * be used only by the redirection mechanism. + */ + *arrow = 0; + + /* Now parse the text after the first non-negated arrow. */ + if (*(arrow+1) == '>') { + if (RedirectState == REDIRECT_UNINITIALIZED) { + printf("Redirection not initialized\n"); + return(-1); + } + arrow += 2; + while(isspace(*arrow)) + arrow++; + if (*arrow != 0) { + strncpy(RedirectFile,*arrow == '$' ? getenv(arrow+1) : arrow, + TFSNAMESIZE); + } + } + else { + RedirectPtr = RedirectBase = (char *)getEnvVal(arrow+1); + comma = strchr(arrow+1,','); + if (comma) { + RedirectSize = (int)getEnvVal(comma+1); + comma = strchr(comma+1,','); + if (RedirectSize <= 0) { + printf("Redirection size error: %d\n",RedirectSize); + return(-1); + } + RedirectEnd = RedirectBase + RedirectSize; + if (comma) { + space = strpbrk(comma," \t\r\n"); + if (space) + *space = 0; + if (*(comma+1) == '$') { + if (getenv(comma+2)) + strncpy(RedirectFile,getenv(comma+2),TFSNAMESIZE); + else + RedirectFile[0] = 0; + } + else + strncpy(RedirectFile,comma+1,TFSNAMESIZE); + } + else + RedirectFile[0] = 0; + } + else { + printf("Redirection syntax error\n"); + return(-1); + } + } + RedirectState = REDIRECT_ACTIVE; + return(0); +} + +/* RedirectCmdDone(): + * As each command completes, this redirection mechanism must be notified. + * When this function is called (by docmd() after the command function has + * completed), if the RedirectFile[] array is populated, it transfers the + * buffer to the specified file; if the array is empty, then no TFS action + * is taken. + * The file specified in RedirectFile[] may have additional commas in it. + * They allow the filename to contain flags and info field. + */ +void +RedirectionCmdDone(void) +{ + + if (RedirectState != REDIRECT_UNINITIALIZED) { + RedirectState = REDIRECT_IDLE; + if (RedirectFile[0]) { + char *comma, *info, *flags; + + comma = info = flags = (char *)0; + comma = strchr(RedirectFile,','); + if (comma) { + *comma = 0; + flags = comma+1; + comma = strchr(flags,','); + if (comma) { + *comma = 0; + info = comma+1; + } + } + tfsadd(RedirectFile,info,flags,(uchar *)RedirectBase, + (int)(RedirectPtr-RedirectBase)); + RedirectFile[0] = 0; + RedirectPtr = RedirectBase; + } + } +} + +/* RedirectCharacter(): + * This function is called from putchar() in chario.c. It simply + * copies the incoming character to the redirection buffer. + */ +void +RedirectCharacter(char c) +{ + if (RedirectState == REDIRECT_ACTIVE) { + if (RedirectPtr < RedirectEnd) + *RedirectPtr++ = c; + } +} +#else +int +RedirectionCheck(char *cmdcpy) +{ + return(0); +} +#endif diff --git a/main/common/reg_cache.c b/main/common/reg_cache.c new file mode 100644 index 0000000..1c6c794 --- /dev/null +++ b/main/common/reg_cache.c @@ -0,0 +1,218 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * reg_cache.c: + * + * Allow the user to display CPU registers that are locally cached + * when an exception is hit. These registers are not the currently + * active registers in the CPU context; rather, a copy of the context at + * the time of the most recent breakpoint or exception. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpu.h" +#include "genlib.h" +#include <ctype.h> +#include "stddefs.h" +#include "regnames.c" +#include "cli.h" + +/* The file regnames.c will contain a table of character pointers that + * corresond to registers that are stored away by the target's exception + * handler. The table of names and the order in which the registers are + * stored by the exception handler must be synchronized. + * An example table is as follows (taken from FADS-MPC860 target)... + * + * static char *regnames[] = { + * "R0", "R1", "R2", "R3", + * "R4", "R5", "R6", "R7", + * "R8", "R9", "R10", "R11", + * "R12", "R13", "R14", "R15", + * "R16", "R17", "R18", "R19", + * "R20", "R21", "R22", "R23", + * "R24", "R25", "R26", "R27", + * "R28", "R29", "R30", "R31", + * "MSR", "CR", "LR", "XER", + * "DAR", "DSISR", "SRR0", "SRR1", + * "CTR", "DEC", "TBL", "TBU", + * "SPRG0", "SPRG1", "SPRG2", "SPRG3", + * }; + * + * The real definition of this array would be in the file regnames.c in + * the target-specific directory. + */ + +#define REGTOT (sizeof regnames/sizeof(char *)) + +/* regtbl[]: + * This array is used to store the actual register values. Storage + * is done by the target's exception handler and must match the order + * of the register names in the regnames[] array. + */ +ulong regtbl[REGTOT]; + +void +flushRegtbl(void) +{ + flushDcache((char *)regtbl,sizeof(regtbl)); +} + +/* regidx(): + * Return an index into the regnames[] array that matches the + * incoming register name. + * If no match is found, print an error message and return -1. + */ +static int +regidx(char *name) +{ + int i; + + strtoupper(name); + for(i=0;i<REGTOT;i++) { + if (!strcmp(name,regnames[i])) { + return(i); + } + } + printf("Bad reg: '%s'\n",name); + return(-1); +} + +/* putreg(): + * Put the specified value into the specified register + * storage location. + */ +int +putreg(char *name,ulong value) +{ + int idx; + + if ((idx = regidx(name)) == -1) + return(-1); + + regtbl[idx] = value; + return(0); +} + +/* getreg(): + * Retrieve the value of the specified register. + */ +int +getreg(char *name,ulong *value) +{ + int idx; + + if ((idx = regidx(name)) == -1) + return(-1); + + *value = regtbl[idx]; + return(0); +} + +/* showregs(): + * Dump the content of the register cache in a tabular format + * showing the entry in the regnames[] array and the corresponding + * entry in the regtbl[] array. + */ +void +showregs(void) +{ + int i, j; + + for(i=0;i<REGTOT;) { + for(j=0;((j<4) && (i<REGTOT));j++,i++) + printf("%6s=0x%08lx ",regnames[i],regtbl[i]); + printf("\n"); + } +} + +/* reginit(): + * Clear the register cache. + */ +void +reginit(void) +{ + int i; + + for(i=0;i<REGTOT;i++) + regtbl[i] = 0; +} + +#if INCLUDE_STRACE +char *RegHelp[] = { + "Display/modify content of monitor's register cache", + "-[v:] [regname] [value]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -v {var} quietly load 'var' with register content", +#endif + 0, +}; + +int +Reg(int argc,char *argv[]) +{ + ulong reg; + int opt, i, forscript; + char *varname, buf[32]; + + forscript = 0; + varname = (char *)0; + while((opt=getopt(argc,argv,"sv:")) != -1) { + switch(opt) { + case 's': + forscript = 1; + break; + case 'v': + varname = optarg; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc == optind) { + if (forscript) { + for(i=0;i<REGTOT;i++) + printf("reg %s 0x%lx\n",regnames[i],regtbl[i]); + } + else + showregs(); + return(CMD_SUCCESS); + } + else if (argc == optind + 1) { + if (getreg(argv[optind],®) != -1) { + sprintf(buf,"0x%lx",reg); + if (varname) + setenv(varname,buf); + else + printf("%s = %s\n",argv[optind],buf); + } + } + else if (argc == optind + 2) { + putreg(argv[1],strtol(argv[optind+1],(char **)0,0)); + } + else { + return(CMD_PARAM_ERROR); + } + return(CMD_SUCCESS); +} +#endif diff --git a/main/common/sbrk.c b/main/common/sbrk.c new file mode 100644 index 0000000..8d55679 --- /dev/null +++ b/main/common/sbrk.c @@ -0,0 +1,144 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * sbrk.c: + * + * Used by malloc to get memory from "somewhere". + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_MALLOC +#include "genlib.h" +#define NULL 0 + +extern int releaseExtendedHeap(int); + +static long allocbuf[ALLOCSIZE/sizeof(long)]; +static char *allocp1; +static char *ext_heapbase, *ext_heapspace, *ext_heapend; + +/* GetMemory(): + * This function is called by the guts of malloc when it needs to expand + * the size of the heap. Initially, GetMemory() will allocate memory + * from a static array (allocbuf[]) that is allocated memory space when the + * monitor is built. If the variable ext_heapbase is non-zero + * at the point when GetMemory() runs out of space in allocbuf[], it + * will start allocating memory from the block pointed to by ext_heapspase + * and ext_heapsize. + * WARNING: this feature can only be used if the malloc()/free() code + * can handle the fact that memory within its heap will be different + * blocks of non-contiguous space. +*/ +char * +GetMemory(int n) +{ + if (!allocp1) + allocp1 = (char *)allocbuf; + + /* First try to allocate from allocbuf[]... */ + if (allocp1 + n <= (char *)allocbuf + ALLOCSIZE) { + allocp1 += n; + return (allocp1 - n); + } + /* Else try to allocated from the extended heap (if one)... */ + else if (ext_heapbase) { + if (ext_heapspace + n <= ext_heapend) { + ext_heapspace += n; + return(ext_heapspace - n); + } + else { + return(NULL); + } + } + /* Else, no space left to allocate from. */ + else { + return (NULL); + } +} + +/* ExtendHeap(): + * Called by the heap command to provide GetMemory() with more space. + * This function can be called through the monitor API. + */ +int +extendHeap(char *start, int size) +{ + /* If the size is -1, then assume this is a release request. */ + if (size == -1) + return(releaseExtendedHeap(0)); + + /* If extension is already loaded, then return -1 for failure. */ + if (ext_heapbase) + return(-1); + + if (inUmonBssSpace(start,start+size-1)) + return(-2); + + ext_heapbase = ext_heapspace = start; + ext_heapend = start + size; + return(0); +} + +/* UnextendHeap(): + * Called by the heap command to "undo" the memory extension. + */ +void +unExtendHeap(void) +{ + ext_heapbase = ext_heapspace = ext_heapend = 0; +} + +char * +getExtHeapBase(void) +{ + return(ext_heapbase); +} + +/* GetMemoryLeft(): + * Return the amount of memory that has yet to be allocated from + * the static and extended heap (if one). +*/ +int +GetMemoryLeft(void) +{ + int spaceleft; + + if (!allocp1) + allocp1 = (char *)allocbuf; + + spaceleft = ((char *)allocbuf + ALLOCSIZE) - allocp1; + + if (ext_heapbase) + spaceleft += (ext_heapend - ext_heapspace); + + return(spaceleft); +} + +#else + +int +extendHeap(char *start, int size) +{ + return(-1); +} + +#endif diff --git a/main/common/sd.c b/main/common/sd.c new file mode 100644 index 0000000..6d2857d --- /dev/null +++ b/main/common/sd.c @@ -0,0 +1,561 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * sd.c: + * + * This code is the user interface portion of the sd (compact flash) + * command for uMon. + * This command is intended to be the "interface" portion of some + * other command (for example "fatfs"). Refer to the discussion in + * fatfs.c for more details. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#if INCLUDE_SD +#include "stddefs.h" +#include "genlib.h" +#include "cli.h" +#include "timer.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "sd.h" + +struct sdinfo sdInfoTbl[SD_DEVTOT]; +char sdVerbose; +static int sdInum; /* Interface number: to support multiple SD interfaces. + * Typically this will always be zero. + */ + + +static struct sdcmd sdCardCmdTbl[] = { + { GO_IDLE_STATE, R1_RLEN, R1 }, + { SEND_OP_COND, R1_RLEN, R1 }, + { SWITCH_FUNC, R1_RLEN, R1 }, + { SEND_IF_COND, R7_RLEN, R7 }, + { SEND_CSD, R1_RLEN, R1 }, + { SEND_CID, R1_RLEN, R1 }, + { STOP_TRANSMISSION, R1_RLEN, R1B }, + { SEND_STATUS, R2_RLEN, R2 }, + { SET_BLOCKLEN, R1_RLEN, R1 }, + { READ_SINGLE_BLK, R1_RLEN, R1 }, + { READ_MULTIPLE_BLK, R1_RLEN, R1 }, + { WRITE_BLK, R1_RLEN, R1B }, + { WRITE_MULTIPLE_BLK, R1_RLEN, R1B }, + { PROGRAM_CSD, R1_RLEN, R1 }, + { SET_WRITE_PROT, R1_RLEN, R1B }, + { CLR_WRITE_PROT, R1_RLEN, R1B }, + { SEND_WRITE_PROT, R1_RLEN, R1 }, + { ERASE_WR_BLK_START_ADDR, R1_RLEN, R1 }, + { ERASE_WR_BLK_END_ADDR, R1_RLEN, R1 }, + { ERASE, R1_RLEN, R1B }, + { LOCK_UNLOCK, R1_RLEN, R1 }, + { APP_CMD, R1_RLEN, R1 }, + { GEN_CMD, R1_RLEN, R1 }, + { READ_OCR, R3_RLEN, R3 }, + { CRC_ON_OFF, R1_RLEN, R1 }, + { SD_SEND_OP_COND, R1_RLEN, R1 }, + { -1,-1,-1 } +}; + +char *SdHelp[] = { + "Secure Digital Flash Interface", + "[options] {operation} [args]...", +#if INCLUDE_VERBOSEHELP + "", + "Options:", + " -i ## interface # (default is 0)", + " -v additive verbosity", + "", + "Operations:", + " init [prefix]", + " cmd {cmdnum} [arg]", + " read {dest} {blk} {blktot}", + " write {blk} {dest} {blktot}", +#endif + 0 +}; + +int +SdCmd(int argc, char *argv[]) +{ + char *cmd, *buf, *prefix, varname[16]; + int opt, verbose, sdret, blknum, blkcnt; + + verbose = 0; + while ((opt=getopt(argc,argv,"i:v")) != -1) { + switch(opt) { + case 'i': + sdInum = atoi(optarg); /* sticky */ + break; + case 'v': + verbose++; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc < optind + 1) + return(CMD_PARAM_ERROR); + + cmd = argv[optind]; + + if (sdInum >= SD_DEVTOT) { + printf("Configured to support %d SD interface%s\n", + SD_DEVTOT,SD_DEVTOT == 1 ? "" : "s"); + return(CMD_FAILURE); + } + + if (sdInstalled(sdInum) == 0) { + printf("SDCard not installed\n"); + return(CMD_FAILURE); + } + + if (strcmp(cmd,"init") == 0) { + sdret = sdInit(sdInum, verbose); + if (sdret < 0) { + printf("sdInit returned %d\n",sdret); + return(CMD_FAILURE); + } + + // If prefix is specified, then load shell variables: + if (argc == optind+2) { + prefix = argv[optind+1]; + if (strlen(prefix)+4 > sizeof(varname)) { + printf("prefix %s too long\n",prefix); + return(CMD_PARAM_ERROR); + } + + sprintf(varname,"%s_RD",prefix); + shell_sprintf(varname,"0x%lx",(long)sdRead); + + sprintf(varname,"%s_WR",prefix); + shell_sprintf(varname,"0x%lx",(long)sdWrite); + } + + shell_sprintf("SD_BLKSIZE","0x%lx",SD_BLKSIZE); + } + else if (strcmp(cmd,"cmd") == 0) { + ulong cmdarg; + uchar resp[8]; + int rtot, i, cmdnum; + + cmdarg = 0; + memset((char *)resp,0xff,sizeof(resp)); + + if ((argc != (optind+2)) && (argc != (optind+3))) + return(CMD_PARAM_ERROR); + + cmdnum = (uchar)strtoul(argv[optind+1],0,0); + if (argc == optind+3) + cmdarg = strtoul(argv[optind+2],0,0); + sdret = sdCardCmd(sdInum, cmdnum , cmdarg ,resp); + if (sdret < 0) { + printf("sdCardCmd returned %d\n",sdret); + return(CMD_FAILURE); + } + + rtot = sdCmdrlen(cmdnum); + + printf("CMD_%d resp: ",cmdnum); + for(i=0;i<rtot;i++) + printf("%02x ",resp[i]); + printf("\n"); + } + else if (strcmp(cmd,"read") == 0) { + if (argc != optind+4) + return(CMD_PARAM_ERROR); + + buf = (char *)strtoul(argv[optind+1],0,0); + blknum = strtoul(argv[optind+2],0,0); + blkcnt = strtoul(argv[optind+3],0,0); + + sdret = sdRead(sdInum,buf,blknum,blkcnt); + if (sdret < 0) { + printf("sdRead returned %d\n",sdret); + return(CMD_FAILURE); + } + } + else if (strcmp(cmd,"write") == 0) { + if (argc != optind+4) + return(CMD_PARAM_ERROR); + buf = (char *)strtoul(argv[optind+1],0,0); + blknum = strtoul(argv[optind+2],0,0); + blkcnt = strtoul(argv[optind+3],0,0); + + sdret = sdWrite(sdInum,buf,blknum,blkcnt); + if (sdret < 0) { + printf("sdWrite returned %d\n",sdret); + return(CMD_FAILURE); + } + } + else { + printf("sd op <%s> not found\n",cmd); + return(CMD_FAILURE); + } + + return(CMD_SUCCESS); +} + +/* sdCmdrlen(): + * Given the command number, return the response length. + */ +int +sdCmdrlen(int cmd) +{ + struct sdcmd *sdp = sdCardCmdTbl; + + while(sdp->cmd != -1) { + if (cmd == sdp->cmd) + return(sdp->rlen); + sdp++; + } + return(-1); +} + +/* sdCmdrtype(): + * Given the command number, return the response type. + */ +int +sdCmdrtype(int cmd) +{ + struct sdcmd *sdp = sdCardCmdTbl; + + while(sdp->cmd != -1) { + if (cmd == sdp->cmd) + return(sdp->rtype); + sdp++; + } + return(-1); +} + +static char *months[] = { + "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", +}; + +void +sdShowCID(uchar *cid) +{ + int year, mon; + + printf(" Manufacturer ID: x%02x\n", cid[0]); + printf(" OEM/Application ID: x%02x%02x\n", cid[1],cid[2]); + printf(" Product name: %c%c%c%c%c\n", + cid[3],cid[4],cid[5],cid[6],cid[7]); + printf(" Product rev: x%02x\n", cid[8]); + printf(" Product serialno: x%02x%02x%02x%02x\n", + cid[9],cid[10],cid[11],cid[12]); + + year = (((cid[13] & 0x0f) << 4) | ((cid[14] & 0xf0) >> 4)); + mon = (cid[14] & 0x0f); + if ((mon < 1) || (mon > 12)) + mon = 0; + printf(" Manufactured: %s/%d\n",months[mon],2000+year); +} + +void +sdShowCSD(uchar *csd) +{ + uchar csdver; + long long capacity; + int mult, csize, csm, rbl; + int blocknr, blocklen, i; + + printf(" CSD Response: "); + for(i=0;i<16;i++) + printf("%02x ",csd[i]); + printf("\n"); + + mult = csize = csm = rbl = 0; + + if ((csd[0] & 0xc0) == 0) + csdver = 1; + else if ((csd[0] & 0xc0) == 0x40) + csdver = 2; + else { + printf("Invalid CSD structure type\n"); + return; + } + + printf(" CSD version %d.0\n",csdver); + if (csdver == 1) { + rbl = csd[5] & 0x0f; + csize = ((csd[8] & 0xC0) >> 6); + csize |= (csd[7] << 2); + csize |= ((csd[6] & 0x03) << 10); + csm = (csd[9] & 0x03); + csm <<= 1; + csm |= ((csd[10] & 0x80) >> 7); + + mult = (1 << (csm+2)); + blocknr = (csize+1)*mult; + blocklen = (1 << rbl); + capacity = (long long)((long long)blocknr * (long long)blocklen); + //printf(" (csm=%d, csize=%d, rbl=%d, mult=%d, blknr=%d, blkln=%d)\n", + // csm, csize, rbl, mult, blocknr, blocklen); + } + else if (csdver == 2) { + rbl = csd[5] & 0x0f; + csize = (csd[7] & 0x3f) << 16; + csize |= (csd[8] << 8); + csize |= csd[9]; + capacity = (long long)((long long)(csize + 1) * 512LL * 1024LL); + } + else { + printf(" Unrecognized CSD version.\n"); + return; + } + printf(" Card capacity: %lld bytes\n",capacity); +} + +/* sdGenericStartup(): + * Called by the interface-specific sdInit() code to do the generic + * portion of the SD-Card initialization. + * + * Refer to the flowchart shown in figure 7.2 of the Simplified + * Physical Layer Specification for an overview of the initialization. + * + * The card wakes up in SD bus mode, so the first thing we need to d + * here (after the very basic initialization of the SPI pin config) is + * to get the card into SPI mode. + * By default, the card assumes CRC checking is disabled. The field used + * to hold the CRC is still part of the protocol, but it is ignored. If + * needed, the master can turn it on with CMD59. + */ +int +sdGenericStartup(int interface) +{ + ulong hcs; + uchar resp[16], cid[16], csd[16]; + int retry, rc, version; + struct elapsed_tmr tmr; + int check_pattern_retry = 2; + + sdInfoTbl[interface].initialized = 0; + + rc = 0; + check_pattern_retry = 2; + + // Start with at least 74 clocks to powerup the card... + sdPowerup(10); + + // Put card in SPI mode: + + // This command always seems to fail on the first try after a + // powerup, so give it a few attempts... + for(retry=0;retry<3;retry++) { + if ((rc = sdCardCmd(interface,GO_IDLE_STATE,0,resp)) != -1) + break; + } + + if (retry == 3) { + printf("\nSD GO_IDLE_STATE failed, card installed?\n"); + return(-1); + } + + // According to Physical Layer Simplified Spec (PLSS), it is mandatory + // for the host compliant to Version 2.00 to send CMD8 (SEND_IF_COND). + // If CMD8 is not recognized (illegal command), then we can assume that + // the card is version 1.00. + // The argument sent with the command is defined in section 4.3.13 + // of the PLSS. + // The spec says that if the check-patter test fails, to retry... + do { + if ((rc = sdCardCmd(interface,SEND_IF_COND,SEND_IF_COND_ARG,resp)) == -1) + return(-1); + + if (resp[0] & R1_ILLEGAL_CMD) { + version = VERSION_10; + hcs = 0; + break; // Check pattern only applies to V2 and later + } + else { + // The card should echo back the VHS and check pattern... + if (resp[3] != VHS27_36) { + if (sdVerbose & 2) + printf("SDCARD not 3.3v compliant!\n"); + return(-1); + } + if (resp[4] != CHECK_PATTERN) { + if (--check_pattern_retry <= 0) { + if (sdVerbose & 2) + printf("SDCARD check-pattern failed.\n"); + return(-1); + } + } + version = VERSION_20; + hcs = HCS; + } + } while(resp[4] != CHECK_PATTERN); + + // Read OCR to make sure the card will run at 3.3v... + if ((rc = sdCardCmd(interface,READ_OCR,hcs,resp)) == -1) + return(-1); + + if ((resp[2] & MSK_OCR_33) != MSK_OCR_33) { + if (sdVerbose & 2) + printf("SDCARD: OCR_33 failed, card isn't 3.3v capable\n"); + return(-1); + } + + // Wait for card to complete initialization: + startElapsedTimer(&tmr,1000); + while(1) { + if ((rc = sdCardCmd(interface,SD_SEND_OP_COND,HCS,resp)) == -1) + return(-1); + if ((resp[0] & R1_IDLE) == 0) + break; + if(msecElapsed(&tmr)) { + printf("SDCARD: gaveup waiting for init to complete.\n"); + return(-1); + } + } + + if (version == VERSION_20) { + // Get CCS... + if ((rc = sdCardCmd(interface,READ_OCR,0,resp)) == -1) + return(-1); + } + else { + if ((rc = sdCardCmd(interface,SET_BLOCKLEN,SD_BLKSIZE,resp)) == -1) + return(-1); + } + + if (sdVerbose) { + printf("SD/SPI Initialized (version %s)\n", + version == VERSION_10 ? "1.0" : ">=2.0"); + } + + sdInfoTbl[interface].cardversion = version; + + sdReadCxD(interface,cid,SEND_CID); + if (sdVerbose) + sdShowCID(cid); + sdReadCxD(interface,csd,SEND_CSD); + if (sdVerbose) + sdShowCSD(csd); + + if ((csd[0] & 0xc0) == 0x00) + sdInfoTbl[interface].highcapacity = 0; + else + sdInfoTbl[interface].highcapacity = 1; + + sdInfoTbl[interface].initialized = 1; + return(0); +} + +/* Got this crc7 code off the web... + * The original text claimed "use-as-you-wish"... + */ +#define POLYNOM (0x9) // polynomical value to XOR when 1 pops out. + +static unsigned char +Encode(uchar seed, uchar input, uchar depth) +{ + uchar regval, count, cc; + + regval = seed; + cc = input; + + for (count = depth ; count-- ; cc <<= 1) { + regval = (regval << 1) + ((cc & 0x80) ? 1 : 0); + if (regval & 0x80) + regval ^= POLYNOM; + } + return(regval & 0x7f); // return lower 7 bits of CRC as value to use. +} + +uchar +crc7(uchar seed, uchar *buf, int len) +{ + int i; + uchar crc; + + crc = seed; + for (i = 0; i < len; i++) + crc = Encode(crc, buf[i], 8); + + crc = Encode(crc,0,7); + crc = (crc << 1) + 1; + return(crc); +} + +#ifdef INCLUDE_SD_DUMMY_FUNCS +/* This code is included here just for simulating the SD + * interface (temporarily if a real one isn't ready. In a real system, + * the INCLUDE_SD_DUMMY_FUNCS definition would be off. + */ + +int +sdInit(int interface, int verbose) +{ + if (interface != 0) + return(-1); + + return(0); +} + +int +sdRead(int interface, char *buf, int blk, int blkcnt) +{ + char *from; + int size; + + if (interface != 0) + return(-1); + + from = (char *)(blk * SD_BLKSIZE); + size = blkcnt * SD_BLKSIZE; + memcpy(buf,from,size); + return(0); +} + +int +sdWrite(int interface, char *buf, int blk, int blkcnt) +{ + char *to; + int size; + + if (interface != 0) + return(-1); + + to = (char *)(blk * SD_BLKSIZE); + size = blkcnt * SD_BLKSIZE; + memcpy(to,buf,size); + return(0); +} + +/* sdInstalled(): + * Return 1 if installed, 0 if not installed or -1 if + * the hardware can't detect installation. + */ +int +sdInstalled(int interface) +{ + return(-1); +} + +#endif + +#endif diff --git a/main/common/sd.h b/main/common/sd.h new file mode 100644 index 0000000..67dcfcc --- /dev/null +++ b/main/common/sd.h @@ -0,0 +1,237 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * sd.h: + * + * Header file supporting SD card interface command. + * + * Much of this information is extracted from the Physical Layer Simplified + * Specification Version 2.00 (PLSS) document. + * + * Note that as of this writing, this header file is limited in scope to + * SPI-based SD. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#ifndef SD_BLKSIZE +#define SD_BLKSIZE 512 +#endif + +#define SPISD_LO_SPEED 400000 +#define SPISD_HI_SPEED 25000000 + +#define VERSION_10 1 +#define VERSION_20 2 + +#ifndef SD_DEVTOT +#define SD_DEVTOT 1 +#endif + +#define MSK_OCR_33 0xC0 + +// Fields used by SEND_IF_COND command: +// (refer to section 4.3.13 of PLSS) +#define VHS27_36 0x01 +#define CHECK_PATTERN 0xAA +#define SEND_IF_COND_ARG (((long)VHS27_36 << 8) | CHECK_PATTERN) + +#define HCS 0x40000000 // High capacity support +#define CCS 0x40000000 // Card capacity status + + +/* Response type 1 (section 7.3.2.1 of PLSS): + */ +#define R1_RLEN 1 +#define R1_STARTBIT 0x80 +#define R1_PARAM_ERR 0x40 +#define R1_ADDRESS_ERR 0x20 +#define R1_ERASESEQ_ERR 0x10 +#define R1_CRC_ERR 0x08 +#define R1_ILLEGAL_CMD 0x04 +#define R1_ERASE_RESET 0x02 +#define R1_IDLE 0x01 +#define R1_ERRMASK (R1_PARAM_ERR | R1_ADDRESS_ERR | R1_ERASESEQ_ERR | R1_CRC_ERR | R1_ILLEGAL_CMD) + + +/* Response type 2 (section 7.3.2.3 of PLSS): + */ +#define R2_RLEN 2 +#define R2H_STARTBIT R1_STARTBIT +#define R2H_PARAM_ERR R1_PARAM_ERR +#define R2H_ADDRESS_ERR R1_ADDRESS_ERR +#define R2H_ERASESEQ_ERR R1_ERASESEQ_ERR +#define R2H_CRC_ERR R1_CRC_ERR +#define R2H_ILLEGAL_CMD R1_ILLEGAL_CMD +#define R2H_ERASE_RESET R1_ERASE_RESET +#define R2H_IDLE R1_IDLE +#define R2L_OUTOFRANGE 0x80 +#define R2L_ERASEPARAM 0x40 +#define R2L_WPVIOLATION 0x20 +#define R2L_ECCFAILED 0x10 +#define R2L_CCERR 0x08 +#define R2L_ERROR 0x04 +#define R2L_WPES_LKFAIL 0x02 +#define R2L_CARDLOCKED 0x01 + +/* Response type 3 (section 7.3.2.4 of PLSS): + * This is the card's response to the READ_OCR command. + * First byte is identical to R1, the remaining 4 bytes + * are the card's OCR register. + */ +#define R3_RLEN 5 +#define R3_STARTBIT R1_STARTBIT +#define R3_PARAM_ERR R1_PARAM_ERR +#define R3_ADDRESS_ERR R1_ADDRESS_ERR +#define R3_ERASESEQ_ERR R1_ERASESEQ_ERR +#define R3_CRC_ERR R1_CRC_ERR +#define R3_ILLEGAL_CMD R1_ILLEGAL_CMD +#define R3_ERASE_RESET R1_ERASE_RESET +#define R3_IDLE R1_IDLE + +/* Reponsee R4 & R5 are reserved for IO mode. + */ + +/* Response type 7 (section 7.3.2.6 of PLSS): + * This is the card's response to the SEND_IF_COND command. + * First bytes is identical to R1. + */ +#define R7_RLEN 5 +#define R7_STARTBIT R1_STARTBIT +#define R7_PARAM_ERR R1_PARAM_ERR +#define R7_ADDRESS_ERR R1_ADDRESS_ERR +#define R7_ERASESEQ_ERR R1_ERASESEQ_ERR +#define R7_CRC_ERR R1_CRC_ERR +#define R7_ILLEGAL_CMD R1_ILLEGAL_CMD +#define R7_ERASE_RESET R1_ERASE_RESET +#define R7_IDLE R1_IDLE + +#define R7_CMDVSNMSK 0xf8 // upper 5 bits of 2nd byte of response +#define R7_VAMSK 0x0f // lower 4 bits of 3nd byte of response + + +/* Data response token (7.3.3.1 of PLSS): + */ +#define DRT_FIXEDMASK 0x11 +#define DRT_FIXED 0x10 +#define DRT_STATMASK 0x0e +#define DRT_STATACCEPTED (0x2<<1) +#define DRT_STATCRCERR (0x5<<1) +#define DRT_STATWRITEERR (0x6<<1) + + +/* Data error token: + */ +#define DET_ERROR 0x01 +#define DET_CCERR 0x02 +#define DET_ECCFAILED 0x04 +#define DET_OOR 0x08 + +/* Start block token: + */ +#define START_BLOCK_TOKEN 0xfe +#define START_BLKMBW_TOKEN 0xfc +#define STOP_TRAN_TOKEN 0xfd + + +#define R1 0x01 +#define R1B 0x81 +#define R2 0x02 +#define R3 0x03 +#define R7 0x07 + +#define APP 0x1000 +#define CMD_APP(cmd) ((cmd & APP) ? 1 : 0) + +/* SD-Card command macros used by SPI mode: + * This definitions carry three pieces of information per macro: + * Response lenght, response type & command index. + */ +#define GO_IDLE_STATE 0 +#define SEND_OP_COND 1 +#define SWITCH_FUNC 6 +#define SEND_IF_COND 8 +#define SEND_CSD 9 +#define SEND_CID 10 +#define STOP_TRANSMISSION 12 +#define SEND_STATUS 13 +#define SET_BLOCKLEN 16 +#define READ_SINGLE_BLK 17 +#define READ_MULTIPLE_BLK 18 +#define WRITE_BLK 24 +#define WRITE_MULTIPLE_BLK 25 +#define PROGRAM_CSD 27 +#define SET_WRITE_PROT 28 +#define CLR_WRITE_PROT 29 +#define SEND_WRITE_PROT 30 +#define ERASE_WR_BLK_START_ADDR 32 +#define ERASE_WR_BLK_END_ADDR 33 +#define ERASE 38 +#define LOCK_UNLOCK 42 +#define APP_CMD 55 +#define GEN_CMD 56 +#define READ_OCR 58 +#define CRC_ON_OFF 59 +#define SD_SEND_OP_COND (41 | APP) + + +/* struct sdcmd: + * Used to carry information about each of the commands handled + * by this driver for the SD-Memory Card interface. + */ +struct sdcmd { + int cmd; + int rlen; + int rtype; +}; + +/* struct sdinfo: + * Used to maintain some information about each of the interfaces. + * Note, in almost all cases, there will only be one SD-Card interface; + * however there is a table of these structures anyway. + */ +struct sdinfo { + char initialized; + char cardversion; + char highcapacity; +}; + +/* These two functions must be supplied by the port-specific code. + */ +extern char sdVerbose; +extern void sdio_init(void); +extern int sdCardCmd(int interface, int cmd, unsigned long arg, + unsigned char *resp); +extern int sdInit(int interface, int verbosity); +extern int sdRead(int interface, char *buf, int blknum, int blkcount); +extern int sdWrite(int interface, char *buf, int blknum, int blkcount); +extern int sdInstalled(int interface); +extern int sdPowerup(int tot); +extern int sdGenericStartup(int interface); +extern int sdCmdrlen(int); +extern int sdCmdrtype(int); +extern void sdShowCID(uchar *cidbuf); +extern void sdShowCSD(uchar *csdbuf); +extern int sdReadCxD(int interface, unsigned char *buf, int cmd); +extern unsigned char crc7(unsigned char seed, unsigned char *buf, int len); + +extern struct sdinfo sdInfoTbl[]; + diff --git a/main/common/spif.c b/main/common/spif.c new file mode 100644 index 0000000..3b8d91e --- /dev/null +++ b/main/common/spif.c @@ -0,0 +1,456 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * spif.c: + * + * This is the generic portion of the spi-flash interface command. + * It assumes there is an underlying SPI-flash device interface + * that provides the expected API (see spif.h). + * + * The "tfs-specific" portions of this code support the model of having + * non-volatile TFS storage in SPI-flash that is transferred to RAM for + * general use, but also provides the ability to do the following: + + * tfsload: + * Transfer a SPIF_TFS_SIZE area in SPI-flash from SPIF_TFS_BASE to + * FLASHRAM_BASE in RAM. + * tfserase: + * Erase the area in SPI-flash that is allocated to SPIF_TFS. + * tfsstore: + * Transfer the RAM-based TFS space back to SPI-flash. + * tfsls: + * List the files out of SPI_TFS directly. + * tfsrm: + * Mark a file in SPI_TFS as deleted. + * tfsadd: + * Append a file just after the last file currently stored in SPIF_TFS. + * + * NOTE: this does NOT support powersafe mode as of this writing. + * + * The spifmap.h file is port specific; hence would be part of the + * port directory. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "genlib.h" +#include "cli.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "spif.h" +#include "spifmap.h" + + +static unsigned long spif_tfs_size; +static unsigned long spif_tfs_base; +static unsigned long base_of_serialtfs; +static unsigned long end_of_serialtfs; + +#ifndef SPIF_TFSRAM_BASE +#define SPIF_TFSRAM_BASE FLASHRAM_BASE +#endif + +char *SpifHelp[] = { + "Interface with SPI-Flash", + "-[v] {cmd} [arg1] [arg2] [...]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -v incrementing verbosity level", + "", + "Cmds:", + " wen write enable", + " wfr wait-for-ready", + " stat show flash status register", + " gprot global protect", + " cerase chip erase", + " gunprot global unprotect", +#if INCLUDE_TFS + " tfsls list files directly out of SPI flash", + " tfsload copy SPIF to TFSRAM", + " tfsstat show state of SPI flash", + " tfsstore copy TFSRAM to SPIF", + " tfserase erase SPIF space allocated to TFS", + " tfsrm {name} remove file directly out of SPI flash", + " tfsadd {name} [src sz] add file directly to SPI flash", +#endif + " berase {addr bsize} block erase (bsize=4K,32K,64K)", + " read {addr dest len} read block", + " write {addr src len} write block", +#endif + 0, +}; + +int +SpifCmd(int argc,char *argv[]) +{ + unsigned long addr; + char *cmd, *dest, *src; + int opt, verbose, len, bsize, rc; + + spif_tfs_size = spifGetTFSSize(); + spif_tfs_base = spifGetTFSBase(); + base_of_serialtfs = spif_tfs_base; + end_of_serialtfs = spif_tfs_base + spif_tfs_size; + + verbose = 0; + while((opt=getopt(argc,argv,"v")) != -1) { + switch(opt) { + case 'v': + verbose++; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc < optind+1) + return(CMD_PARAM_ERROR); + + cmd = argv[optind]; + + if (verbose) + printf("CMD: %s\n",cmd); + + // Establish the SPI configuration to match that of the SPI flash... + spifQinit(); + + if (strcmp(cmd,"stat") == 0) { + spifId(1); + spifReadStatus(verbose+1); + } + else if (strcmp(cmd,"gprot") == 0) { + spifGlobalProtect(); + } + else if (strcmp(cmd,"berase") == 0) { + + if (argc != optind+3) + return(CMD_PARAM_ERROR); + + addr = strtoul(argv[optind+1],0,0); + + if (strcmp(argv[optind+2],"4K") == 0) + bsize = 0x1000; + else if (strcmp(argv[optind+2],"32K") == 0) + bsize = 0x8000; + else if (strcmp(argv[optind+2],"64K") == 0) + bsize = 0x10000; + else + return(CMD_PARAM_ERROR); + + spifBlockErase(bsize,addr); + } + else if (strcmp(cmd,"cerase") == 0) { + spifChipErase(); + } + else if (strcmp(cmd,"wfr") == 0) { + spifWaitForReady(); + } + else if (strcmp(cmd,"gunprot") == 0) { + spifGlobalUnprotect(); + } + else if (strcmp(cmd,"write") == 0) { + if (argc != optind+4) + return(CMD_PARAM_ERROR); + addr = strtoul(argv[optind+1],0,0); + src = (char *)strtoul(argv[optind+2],0,0); + len = (int)strtol(argv[optind+3],0,0); + if ((rc = spifWriteBlock(addr,src,len)) < 0) + printf("spifWriteBlock returned %d\n",rc); + + } + else if (strcmp(cmd,"read") == 0) { + if (argc != optind+4) + return(CMD_PARAM_ERROR); + addr = strtoul(argv[optind+1],0,0); + dest = (char *)strtoul(argv[optind+2],0,0); + len = (int)strtol(argv[optind+3],0,0); + if ((rc = spifReadBlock(addr,dest,len)) < 0) + printf("spifReadBlock returned %d\n",rc); + } + else if (strcmp(cmd,"wen") == 0) { + spifWriteEnable(); + } +#if INCLUDE_TFS + else if (strcmp(cmd,"tfsload") == 0) { + rc = spifReadBlock(spif_tfs_base,(char *)FLASHRAM_BASE,spifGetTFSSize()); + if (rc < 0) + printf("spifReadBlock returned %d\n",rc); + } + else if (strcmp(cmd,"tfsstore") == 0) { + spifWriteEnable(); + spifGlobalUnprotect(); + rc = spifWriteBlock(spif_tfs_base,(char *)FLASHRAM_BASE,spifGetTFSSize()); + if (rc < 0) + printf("spifWriteBlock returned %d\n",rc); + spifGlobalProtect(); + } + else if (strcmp(cmd,"tfserase") == 0) { + spifWriteEnable(); + spifGlobalUnprotect(); + addr = spif_tfs_base; + while (addr < (spif_tfs_base+spif_tfs_size)) { + spifWriteEnable(); + rc = spifBlockErase(0x10000,addr); + if (rc < 0) { + printf("spifBlockErase(0x%lx) returned %d\n",addr,rc); + break; + } + if (verbose) + //ticktock(); + printf("%lx ",addr); + addr += 0x10000; + } + spifGlobalProtect(); + } + else if (strcmp(cmd, "tfsls") == 0) { + int ftot; + unsigned long addr; + TFILE tfshdr, *fp; + + ftot = 0; + fp = &tfshdr; + addr = base_of_serialtfs; + while(addr < end_of_serialtfs) { + char fbuf[32], *flags; + + if ((rc = spifReadBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) { + printf("spifReadBlock failed %d\n",rc); + break; + } + if (fp->hdrsize == 0xffff) + break; + if (TFS_FILEEXISTS(fp)) { + if (ftot == 0) + printf(" Name Size Offset Flags Info\n"); + ftot++; + flags = tfsflagsbtoa(TFS_FLAGS(fp),fbuf); + if ((!flags) || (!fbuf[0])) + flags = " "; + printf(" %-23s %7ld 0x%08lx %-5s %s\n",TFS_NAME(fp), + TFS_SIZE(fp),(unsigned long)(addr+TFSHDRSIZ), + flags,TFS_INFO(fp)); + } + addr += TFS_SIZE(fp); + addr += TFSHDRSIZ; + while(addr & 0xf) addr++; + } + } + else if (strcmp(cmd, "tfsrm") == 0) { + unsigned long addr; + TFILE tfshdr, *fp; + char *arg2 = argv[optind+1]; + + fp = &tfshdr; + addr = base_of_serialtfs; + while(addr < end_of_serialtfs) { + if ((rc = spifReadBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) { + printf("spifReadBlock failed %d\n",rc); + break; + } + if (fp->hdrsize == 0xffff) { + printf("%s not found\n",arg2); + break; + } + if (strcmp(TFS_NAME(fp),arg2) == 0) { + if (TFS_FILEEXISTS(fp)) { + fp->flags &= ~TFS_ACTIVE; + spifWriteEnable(); + spifGlobalUnprotect(); + if ((rc = spifWriteBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) + printf(" write_hdr failed %d\n",rc); + spifGlobalProtect(); + break; + } + } + addr += TFS_SIZE(fp); + addr += TFSHDRSIZ; + while(addr & 0xf) addr++; + } + } + else if (strcmp(cmd, "tfsadd") == 0) { + int size; + long bflags; + TFILE tfshdr, *fp; + unsigned long addr; + char *src, *name, *info; + char *arg2 = argv[optind+1]; + char *arg3 = argv[optind+2]; + char *arg4 = argv[optind+3]; + char *icomma, *fcomma; + + info = ""; + bflags = 0; + name = arg2; + addr = base_of_serialtfs; + + /* The incoming arguments can be either just the filename (in which + * case we assume the source is the file in TFS with the same name), + * or the filename, source address and size... + */ + if (argc == optind+2) { // Just filename? + if ((fp = tfsstat(name)) == (TFILE *)0) { + printf("File '%s' not in TFS\n",name); + return(CMD_FAILURE); + } + name = fp->name; + info = fp->info; + bflags = fp->flags; + size = fp->filsize; + src = (char *)(fp + 1); + fp = &tfshdr; + memset((char *)fp,0,TFSHDRSIZ); + } + else if (argc == optind+4) { // Filename with addr and len + // Extract flags and info fields (if any) from the name... + fcomma = strchr(name,','); + if (fcomma) { + icomma = strchr(fcomma+1,','); + if (icomma) { + *icomma = 0; + info = icomma+1; + } + *fcomma = 0; + bflags = tfsctrl(TFS_FATOB,(long)(fcomma+1),0); + } + + fp = &tfshdr; + memset((char *)fp,0,TFSHDRSIZ); + size = (int)strtol(arg4,0,0); + src = (char *)strtoul(arg3,0,0); + } + else + return(CMD_PARAM_ERROR); + + while(addr < end_of_serialtfs) { + if ((rc = spifReadBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) + break; + if (fp->hdrsize == 0xffff) { + unsigned long nextfileaddr; + + /* We're at the address in SPIF where we can add the new + * file, but first we need to make sure there's enough + * room... + */ + if ((TFSHDRSIZ + size + 16) >= (end_of_serialtfs - addr)) { + printf(" not enough space\n"); + return(CMD_FAILURE); + } + + /* Copy name and info data to header. + */ + strcpy(fp->name, name); + strcpy(fp->info, info); + fp->hdrsize = TFSHDRSIZ; + fp->hdrvrsn = TFSHDRVERSION; + fp->filsize = size; + fp->flags = bflags; + fp->flags |= (TFS_ACTIVE | TFS_NSTALE); + fp->filcrc = crc32((unsigned char *)src,size); + fp->modtime = tfsGetLtime(); +#if TFS_RESERVED + { + int rsvd; + for(rsvd=0;rsvd<TFS_RESERVED;rsvd++) + fp->rsvd[rsvd] = 0xffffffff; + } +#endif + fp->next = 0; + fp->hdrcrc = 0; + fp->hdrcrc = crc32((unsigned char *)fp,TFSHDRSIZ); + nextfileaddr = SPIF_TFSRAM_BASE - spif_tfs_base + addr + TFSHDRSIZ + size; + if (nextfileaddr & 0xf) + nextfileaddr = (nextfileaddr | 0xf) + 1; + + fp->next = (TFILE *)nextfileaddr; + + printf(" writing %s...\n",arg2); + spifWriteEnable(); + spifGlobalUnprotect(); + spifWaitForReady(); + + spifWriteEnable(); + if ((rc = spifWriteBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) + printf(" write_hdr failed %d\n",rc); + spifWaitForReady(); + + spifWriteEnable(); + spifGlobalUnprotect(); + if ((rc = spifWriteBlock(addr+TFSHDRSIZ,src,size)) < 0) + printf(" write_file failed %d\n",rc); + spifWaitForReady(); + spifGlobalProtect(); + break; + } + if (strcmp(TFS_NAME(fp),arg2) == 0) { + if (TFS_FILEEXISTS(fp)) { + printf(" removing %s...\n",arg2); + fp->flags &= ~TFS_ACTIVE; + spifWriteEnable(); + spifGlobalUnprotect(); + spifWaitForReady(); + spifWriteEnable(); + if ((rc = spifWriteBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) + printf(" write_hdr failed %d\n",rc); + spifWaitForReady(); + spifGlobalProtect(); + } + } + addr += TFS_SIZE(fp); + addr += TFSHDRSIZ; + while(addr & 0xf) addr++; + } + } + else if (strcmp(cmd, "tfsstat") == 0) { + unsigned long oaddr, addr, meminuse, memdead; + TFILE tfshdr, *fp; + + fp = &tfshdr; + meminuse = memdead = 0; + addr = base_of_serialtfs; + while(addr < end_of_serialtfs) { + if ((rc = spifReadBlock(addr,(char *)fp,TFSHDRSIZ)) < 0) { + printf("spifReadBlock failed %d\n",rc); + break; + } + if (fp->hdrsize == 0xffff) + break; + + oaddr = addr; + addr += TFS_SIZE(fp); + addr += TFSHDRSIZ; + while(addr & 0xf) addr++; + + if (TFS_FILEEXISTS(fp)) + meminuse += addr - oaddr; + else + memdead += addr - oaddr; + } + printf("Total: 0x%x, used: 0x%x, dead: 0x%x, avail: 0x%x\n", + (end_of_serialtfs - base_of_serialtfs), + meminuse, memdead, + (end_of_serialtfs - base_of_serialtfs) - (meminuse + memdead)); + } +#endif + else + return(CMD_PARAM_ERROR); + + return(CMD_SUCCESS); +} diff --git a/main/common/spif.h b/main/common/spif.h new file mode 100644 index 0000000..89310ec --- /dev/null +++ b/main/common/spif.h @@ -0,0 +1,69 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * spif.h: + * + * SPI-flash iterface. See spif.c for details. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +/* Status register bits for ATMEL device: */ +#define SPRL 0x80 // Sector protection registers locked (if 1) +#define RES 0x40 // Reserved for future use +#define EPE 0x20 // Erase or program error (if 1) +#define WPP 0x10 // *WP pin is deasserted (if 1) +#define SWPS 0x0c // Software protection status bits +#define SWPS00 0x00 // 00: all sectors unprotected +#define SWPS01 0x04 // 01: some sectors unprotected +#define SWPS10 0x08 // 10: reserved for future use +#define SWPS11 0x0c // 11: all sectors protected (default) +#define WEL 0x02 // Write enable latch (1=write enabled) +#define BSY 0x01 // Busy (1=busy, 0=ready) + +/* Baudrate could be much higher, but we keep it low here for easier + * ability to trace out on the scope... + */ +#ifndef SPIFBAUD +#define SPIFBAUD 25000000 +#endif + +/* The ATMEL part supports three different erase block sizes (not + * including the 'whole-chip' erase)... + */ +#define BLKSZ_4K 0x20 +#define BLKSZ_32K 0x52 +#define BLKSZ_64K 0xD8 + +extern void spifQinit(void); +extern int spifInit(void); +extern int spifWaitForReady(void); +extern int spifId(int verbose); +extern int spifWriteEnable(void); +extern int spifWriteDisable(void); +extern int spifChipErase(void); +extern int spifGlobalUnprotect(void); +extern int spifGlobalProtect(void); +extern int spifReadBlock(unsigned long addr,char *data,int len); +extern int spifWriteBlock(unsigned long addr, char *data, int len); +extern int spifBlockErase(int bsize, long addr); +extern unsigned short spifReadStatus(int verbose); +extern unsigned long spifGetTFSBase(void); +extern unsigned long spifGetTFSSize(void); diff --git a/main/common/start.c b/main/common/start.c new file mode 100644 index 0000000..18919a2 --- /dev/null +++ b/main/common/start.c @@ -0,0 +1,496 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * start.c: + * + * This is typically the first 'C' code executed by the processor after a + * reset. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpu.h" +#include "cpuio.h" +#include "stddefs.h" +#include "genlib.h" +#include "devices.h" +#include "ether.h" +#include "warmstart.h" +#include "monlib.h" +#include "monflags.h" +#include "boardinfo.h" +#include "cli.h" +#include "tfsprivate.h" +#include "fbi.h" + +#ifdef PRE_COMMANDLOOP_HOOK +extern void PRE_COMMANDLOOP_HOOK(); +#endif + +#ifndef EXCEPTION_HEADING +#define EXCEPTION_HEADING "EXCEPTION" +#endif + +extern void vinit(void); +extern int addcommand(struct monCommand *cmdlist, char *cmdlvl); + +/* StateOfMonitor: + * The StateOfMonitor variable is used throughout the code to determine + * how the monitor started up. In general, the three most common + * startup types are: INITIALIZE, APP_EXIT and EXCEPTION. + */ +int StateOfMonitor; + +/* MonStack: + * The monitor's stack is declared within the monitor's own .bss space. + * This keeps the memory map simple, the only thing that needs to be + * accounted for is that in the bss init loop, this section should not + * be initialized. MONSTACKSIZE must be defined in config.h. + */ +ulong MonStack[MONSTACKSIZE/4]; + +/* APPLICATION_RAMSTART: + * Loaded with the address after which the application can be loaded. + */ +ulong APPLICATION_RAMSTART; + +/* BOOTROM_BASE: + * Loaded with the address considered to be the base address at which + * the monitor is burned into flash. + */ +ulong BOOTROM_BASE; + +/* LoopsPerMillisecond: + * Loaded with a count (established in config.h) that is an estimation of + * one second of elapsed time. It is NOT an accurate value, but serves the + * purpose of providing a hardware-independent mechanism for establishing + * a reasonable estimation of one second's worth of elapsed time. + */ +ulong LoopsPerMillisecond; + +/* init0(): + * The code in this function was originally part of start(). It has been + * moved out so that this portion of the initialization can be re-used by + * AppWarmStart(). See notes in AppWarmStart() for more details on this. + */ +void +init0(void) +{ + /* Store the base address of memory that is used by application. + * Start it off on the next 4K boundary after the end of monitor ram. + * Usually APPRAMBASE and BOOTROMBASE can be retrieved from bss_end and + * boot_base; but they can be overridden with values specified in the + * target-specific config.h file. + */ +#ifdef APPRAMBASE_OVERRIDE + APPLICATION_RAMSTART = APPRAMBASE_OVERRIDE; +#else + APPLICATION_RAMSTART = (((ulong)&bss_end) | 0xfff) + 1; +#endif + +#ifdef BOOTROMBASE_OVERRIDE + BOOTROM_BASE = BOOTROMBASE_OVERRIDE; +#else + BOOTROM_BASE = (ulong)&boot_base; +#endif + + /* Load bottom of stack with 0xdeaddead to be used by stkchk(). + */ + MonStack[0] = 0xdeaddead; + + /* Set up default loops-per-millisecond count. + */ + LoopsPerMillisecond = LOOPS_PER_SECOND/1000; + + /* Clear any user-installed command list. + */ + addcommand(0,0); +} + +/* init1(): + * This is the first level of initialization (aside from the most fundamental + * stuff that must be done in reset.s) that is done after the system resets. + */ +void +init1(void) +{ + initCPUio(); /* Configure all chip-selects, parallel IO + * direction registers, etc... This may have + * been done already in reset.s + */ + vinit(); /* Initialize the CPU's vector table. */ + InitRemoteIO(); /* Initialize all application-settable IO functions */ + + if (ConsoleBaudRate == 0) + ConsoleBaudRate = DEFAULT_BAUD_RATE; + + devInit(ConsoleBaudRate); + +} + +/* init2(): + */ +void +init2(void) +{ +#if INCLUDE_FLASH | INCLUDE_TFS + int rc = 0; +#endif + +#if INCLUDE_FBI + if (StateOfMonitor == INITIALIZE) + fbdev_init(); /* Initialize the frame-buffer device */ +#endif + +#if INCLUDE_FLASH + if (StateOfMonitor == INITIALIZE) + rc = FlashInit(); /* Init flashop data structures and (possibly) */ + /* the relocatable functions. This MUST be */ +#endif /* done prior to turning on cache!!! */ + + cacheInit(); /* Initialize cache. */ + +#if INCLUDE_ETHERNET + enreset(); /* Clear the ethernet interface. */ +#endif + +#if INCLUDE_TFS + if (rc != -1) /* Start up TFS as long as flash */ + tfsstartup(); /* initialization didn't fail. */ +#endif +} + +/* init3(): + * As each target boots up, it calls init1() and init2() to do multiple + * phases of hardware initialization. This third initialization phase + * is always common to all targets... + * It is possible that this is being called by AppWarmStart(). In this + * case, the user can specify which portions of the monitor code are + * to be initialized by specifying them in the startmode mask. + */ +static void +_init3(ulong startmode) +{ + char *baud; + +#if INCLUDE_LINEEDIT + /* Initialize command line history table. */ + historyinit(); +#endif + +#if INCLUDE_SHELLVARS + /* Init shell variable table. */ + ShellVarInit(); +#endif + +#if INCLUDE_USRLVL + /* Set user level to its max, then allow monrc file to adjust it. */ + initUsrLvl(MAXUSRLEVEL); +#endif + +#if INCLUDE_BOARDINFO + /* Check for board-specific-information in some otherwise unused + * sector. Also, establish shell variables from this information + * based on the content of the boardinfo structure. + * Note that the second half of the board-specific information setup + * (the call to BoardInfoEnvInit()) must be done AFTER ShellVarInit() + * because shell variables are established here. + */ + if (startmode & WARMSTART_BOARDINFO) { + BoardInfoInit(); + BoardInfoEnvInit(); + } +#endif + +#ifdef MONCOMPTR + /* If MONCOMPTR is defined, then verify that the definition matches + * the location of the actual moncomptr value. The definition in + * config.h is provided so that outside applications can include that + * header file so that the value passed into monConnect() is defined + * formally. The REAL value of moncomptr is based on the location of + * the pointer in monitor memory space, determined only after the final + * link has been done. As a result, this check is used to simply verify + * that the definition matches the actual value. + */ + { + if (MONCOMPTR != (ulong)&moncomptr) + printf("\nMONCOMPTR WARNING: runtime != definition\n"); + } +#endif + +#if INCLUDE_TFS + /* After basic initialization, if the monitor's run-control file + * exists, run it prior to EthernetStartup() so that the + * MAC/IP addresses can be configured based on shell variables + * that would be loaded by the rc file. + */ + if (startmode & WARMSTART_RUNMONRC) + tfsrunrcfile(); +#endif + + /* After MONRC is run, establish monitor flags... + */ + InitMonitorFlags(); + + /* We've run the monrc file at this point, so check for the + * presence of the CONSOLEBAUD shell variable. If it's set, + * then use the value to re-establish the console baud rate. + * If it isn't set, then establish the CONSOLEBAUD shell variable + * using the default, pre-configured baud rate. + */ + baud = getenv("CONSOLEBAUD"); + if (baud) + ChangeConsoleBaudrate(atoi(baud)); + ConsoleBaudEnvSet(); + +#if INCLUDE_ETHERNET +#if INCLUDE_STOREMAC + storeMac(0); +#endif + if (startmode & WARMSTART_IOINIT) + EthernetStartup(0,1); +#endif + + /* Now that all has been initialized, display the monitor header. */ +#ifndef NO_UMON_STARTUP_HDR + if (startmode & WARMSTART_MONHEADER) { + if (!MFLAGS_NOMONHEADER()) + monHeader(1); + } +#endif + +#if INCLUDE_FBI + if (StateOfMonitor == INITIALIZE) + fbi_splash(); +#endif + +#if INCLUDE_TFS + if (startmode & WARMSTART_TFSAUTOBOOT) + tfsrunboot(); +#endif +} + +void +init3(void) +{ + _init3(WARMSTART_ALL); +} + +/* umonBssInit(): + * All of the monitor-owned ram is within it's bss space as defined + * by the locations of bss_start and bss_end in the memory map + * definition file. This includes the the monitor's stack and + * heap. To support a generic, C-based BSS initialzation loop, + * this loop must skip over the space allocated to the stack because + * the stack is likely to be in use during this loop... + */ +void +umonBssInit(void) +{ + int *tmp; + volatile ulong *bssptr; + + tmp = &bss_start; + bssptr = (ulong *)tmp; + while(bssptr < MonStack) + *bssptr++ = 0; + bssptr = (ulong *)MonStack+(MONSTACKSIZE/4); + tmp = &bss_end; + while(bssptr < (ulong *)tmp) + *bssptr++ = 0; +} + +/* AppWarmStart(): + * This function is provided to allow the application to partially + * restart the monitor. It supports the situation where an application + * run but the monitor has not already been initialized. This would be + * the case if some type of debugger (JTAG or BDM probably) was attached + * to the target and it was used to download and run the application. + * If this type of debug connection does not support the ability to run + * after the monitor runs, then the application must be able to somehow + * get the monitor initialized without having it go through a complete + * warmstart. + * This will only run through the stack space provided by the application. + */ +void +AppWarmStart(ulong mask) +{ + /* First initialize monitor bss space (skipping over MonStack[]): */ + if (mask & WARMSTART_BSSINIT) + umonBssInit(); + + StateOfMonitor = INITIALIZE; + + /* Initialize some of the real fundamental stuff regardless of + * the incoming mask. + */ + init0(); + + /* Subset of init1(): */ + if (mask & WARMSTART_IOINIT) { + initCPUio(); + InitRemoteIO(); + if (ConsoleBaudRate == 0) + ConsoleBaudRate = DEFAULT_BAUD_RATE; + devInit(ConsoleBaudRate); + } + init2(); + _init3(mask); +} + +/* start(): + * Called at the end of reset.s as the first C function after processor + * bootup. It is passed a state that is used to determine whether or not + * the CPU is restarting as a result of a warmstart or a coldstart. If + * the restart is a coldstart, then state will be INITIALIZE. if the + * restart is a warmstart, then there are a few typical values of state, + * the most common of which are APP_EXIT and EXCEPTION. + * + * The bss_start and bss_end variables are usually defined in the + * target-specific linker memory-map definition file. They symbolically + * identify the beginning and end of the .bss section. Many compilers + * support intrinsic tags for this; however, since it is apparently not + * consistent from one toolset to the next; I chose to make up my own + * tags so that this file never changes from one toolset to the next. + * + * The FORCE_BSS_INIT definition can be established in the target-specific + * config.h file to force .bss space initialization regardless of warm/cold + * start. + */ +void +start(int state) +{ + char buf[48]; + +#ifdef FORCE_BSS_INIT + state = INITIALIZE; +#endif + + /* Based on the incoming value of 'state' we may or may not initialize + * monitor-owned ram. Ideally, we only want to initialize + * monitor-owned ram when 'state' is INITIALIZE (power-up or reset); + * however, to support the case where the incoming state variable may + * be corrupted, we also initialize monitor-owned ram when 'state' + * is anything unexpected... + */ + switch(state) { + case EXCEPTION: + case APP_EXIT: + break; + case INITIALIZE: + default: + umonBssInit(); + break; + } + + /* Now that the BSS clear loop has been done, we can copy the + * value of state (either a register or on stack) to the global + * variable (in BSS) StateOfMonitor... + */ + StateOfMonitor = state; + + /* Step through different phases of startup... + */ + init0(); + init1(); + init2(); + + /* Depending on the type of startup, alert the console and do + * further initialization as needed... + */ + switch(StateOfMonitor) { + case INITIALIZE: + reginit(); + init3(); + break; + case APP_EXIT: + EthernetStartup(0,0); + if (!MFLAGS_NOEXITSTATUS()) { + printf("\nApplication Exit Status: %d (0x%x)\n", + AppExitStatus,AppExitStatus); + } + break; + case EXCEPTION: + EthernetStartup(0,0); + printf("\n%s: '%s'\n",EXCEPTION_HEADING, + ExceptionType2String(ExceptionType)); + printf(" Occurred near 0x%lx",ExceptionAddr); + if (AddrToSym(-1,ExceptionAddr,buf,0)) + printf(" (within %s)",buf); + printf("\n\n"); + exceptionAutoRestart(INITIALIZE); + break; + default: + printf("Unexpected monitor state: 0x%x (sp @ 0x%x)\n", + StateOfMonitor, buf); + /* To attempt to recover from the bad state, just do + * what INITIALIZE would do... + */ + reginit(); + init3(); + break; + } + +#ifdef LOCK_FLASH_PROTECT_RANGE + /* Issue the command that will cause the range of sectors + * designated by FLASH_PROTECT_RANGE to be locked. This only + * works if the flash device is capable of being locked. + */ + sprintf(buf,"flash lock %s",FLASH_PROTECT_RANGE); + docommand(buf,0); +#endif + +#ifdef PRE_COMMANDLOOP_HOOK + PRE_COMMANDLOOP_HOOK(); +#endif + + /* Enter the endless loop of command processing: */ + CommandLoop(); + + printf("ERROR: CommandLoop() returned\n"); + monrestart(INITIALIZE); +} + +/* __eabi(): + * Called intrinsically by main for some PowerPc builds. + * I'm not sure what the purpose of it is, but EABI is Embedded Application + * Binary Interface, and is documented on Motorola's web site at + * http://www.mcu.motsps.com/lit/manuals/eabispec.html#536421 + */ +void +__eabi(void) +{ +} + +/* __main() or __gccmain(): called intrinsically by main. One or the other + * is typically used to run constructors and destructors for C++. If this + * function is not created here, then the compiler will automatically create + * one and with it, will come other unnecessary baggage. + */ +void +__main(void) +{ +} + +void +__gccmain(void) +{ +} diff --git a/main/common/stddefs.h b/main/common/stddefs.h new file mode 100644 index 0000000..cef8fb9 --- /dev/null +++ b/main/common/stddefs.h @@ -0,0 +1,62 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * stddefs.h: + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _STDDEFS_H_ +#define _STDDEFS_H_ + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed long int32_t; +typedef signed long long int64_t; + +typedef volatile unsigned char vuint8_t; +typedef volatile unsigned short vuint16_t; +typedef volatile unsigned long vuint32_t; +typedef volatile unsigned long long vuint64_t; + +typedef volatile signed char vint8_t; +typedef volatile signed short vint16_t; +typedef volatile signed long vint32_t; +typedef volatile signed long long vint64_t; + + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; +typedef unsigned int uint; + +typedef volatile unsigned char vuchar; +typedef volatile unsigned short vushort; +typedef volatile unsigned long vulong; +typedef volatile unsigned int vuint; +typedef volatile int vint; + + +#endif diff --git a/main/common/struct.c b/main/common/struct.c new file mode 100644 index 0000000..5a60a3c --- /dev/null +++ b/main/common/struct.c @@ -0,0 +1,783 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * struct.c: + * + * This command allows the user to build a structure into memory based + * on a structure set up in the definition file ("structfile"). + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "tfs.h" +#include "tfsprivate.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" +#include "cli.h" +#include "ether.h" +#include <stdarg.h> + +#if INCLUDE_STRUCT + +#define OPENBRACE '{' +#define CLOSEBRACE '}' +#define PTRSIZE 4 + +int structsize(char *name); + +struct mbrtype { + char *type; + int size; +}; + +struct mbrtype types[] = { + { "long", 4 }, + { "short", 2 }, + { "char", 1 }, + { 0, -1 } +}; + +static int struct_sfd; +static ulong struct_base; +static char *struct_fname; +static char struct_verbose; +static char struct_scriptisstructfile; + +/* err_general(), err_nostruct(), err_nomember(): + * Error processing functions... + */ +static void +err_general(int errnum,int linenum, long tfsloc) +{ + printf("%s: err%d at ln %d\n",struct_fname,errnum,linenum); + tfsseek(struct_sfd,tfsloc,TFS_BEGIN); +} + +static void +err_nostruct(char *structname, long tfsloc) +{ + printf("%s: can't find struct '%s'\n",struct_fname,structname); + tfsseek(struct_sfd,tfsloc,TFS_BEGIN); +} + +static void +err_nomember(char *structname, char *mbrname, long tfsloc) +{ + printf("%s: member '%s' not in struct '%s'\n", + struct_fname,mbrname,structname); + tfsseek(struct_sfd,tfsloc,TFS_BEGIN); +} + +/* struct_printf(): + * Use this function instead of "if (struct_verbose) printf(...)" + * all over the place. + */ +static int +struct_printf(int mask, char *fmt, ...) +{ + int tot; + va_list argp; + + if (!(struct_verbose & mask)) + return(0); + + va_start(argp,fmt); + tot = vsnprintf(0,0,fmt,argp); + va_end(argp); + return(tot); +} + +/* struct_prleft(): + * Print all characters of the incoming string up to the + * end of the string or the first occurrence of the equals sign. + * Then print the formatted string that follows. + */ +static int +struct_prleft(int mask, char *str, char *fmt, ...) +{ + int tot = 0; + va_list argp; + + if (!(struct_verbose & mask)) + return(tot); + + while((*str) && (*str != '=')) { + tot++; + putchar(*str++); + } + + va_start(argp,fmt); + tot += vsnprintf(0,0,fmt,argp); + va_end(argp); + return(tot); +} + +/* skipline(): + * If the line is filled with only whitespace, or if the first non-whitespace + * character is a poundsign, return 1; else return 0. + */ +static int +skipline(char *line) +{ + if (struct_scriptisstructfile) { + if (strncmp(line,"###>>",5) == 0) { + strcpy(line,line+5); + return(0); + } + else + return(1); + } + else { + while(isspace(*line)) line++; + + switch(*line) { + case 0: + case '#': + return(1); + } + return(0); + } +} + +/* typesize(): + * Given the incoming type name, return the size of that symbol. + * Take into account the possibility of it being a pointer (leading '*') + * or an array (trailing [xx]). + */ +static int +typesize(char *typename, char *name) +{ + char *np; + struct mbrtype *mp; + int nlen, ptr, arraysize; + + ptr = 0; + arraysize = 1; + + struct_printf(4,"typesize(%s,%s)\n",typename,name); + + if (name[0] == '*') + ptr = 1; + + nlen = strlen(name); + np = name+nlen-1; + if (*np == ']') { + while(*np && (*np != '[')) np--; + if (*np == 0) + return(-1); + arraysize = atoi(np+1); + } + + mp = types; + while(mp->type) { + if (strncmp(mp->type,typename,strlen(mp->type)) == 0) + break; + mp++; + } + + if (ptr) + return(PTRSIZE * arraysize); + + return(mp->size * arraysize); +} + +/* structline(): + * Assume that the incoming line is text within a structure definition + * from the structure file. Parse it, expecting either two or three + * tokens (2 if the member is a basic type, 3 if the member is another + * structure). Return the count and pointers to each token. + */ +static int +structline(char *line, char **type, char **name) +{ + int tot; + char *cp, *token1, *token2, *token3; + + cp = line; + while(isspace(*cp)) cp++; + token1 = cp; + while(!isspace(*cp)) cp++; + *cp++ = 0; + + if (!strcmp(token1,"struct")) { + while(isspace(*cp)) cp++; + token2 = cp; + while(!isspace(*cp)) cp++; + *cp++ = 0; + while(isspace(*cp)) cp++; + token3 = cp; + while((!isspace(*cp)) && (*cp != ';')) cp++; + if (*cp != ';') + return(-1); + *cp++ = 0; + *type = token2; + *name = token3; + tot = 3; + } + else { + while(isspace(*cp)) cp++; + token2 = cp; + while((!isspace(*cp)) && (*cp != ';')) cp++; + if (*cp != ';') + return(-1); + *cp++ = 0; + *type = token1; + *name = token2; + tot = 2; + } + struct_printf(4,"structline: type='%s', name='%s'\n",*type,*name); + return(tot); + +} + +/* structsize(): + * Assuming the incoming string is a pointer to some structure definition + * in the structure file, parse the file and figure out how big the + * structure is. Return the size of successful; else return -1 to indicate + * some kind of parsing error. + */ +int +structsize(char *structname) +{ + long loc; + int offset, slen, lno, size; + char line[80], *cp, *cp1, *type, *name; + + struct_printf(4,"structsize(%s)\n",structname); + + loc = tfstell(struct_sfd); + + if (tfsseek(struct_sfd,0,TFS_BEGIN) < 0) { + tfsseek(struct_sfd,loc,TFS_BEGIN); + return(-1); + } + + offset = 0; + slen = strlen(structname); + lno = 0; + while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) { + lno++; + if (skipline(line)) + continue; + if (!strncmp(line,"struct ",7)) { + cp = line+7; + while(isspace(*cp)) cp++; + if ((!strncmp(structname,cp,slen)) && (isspace(cp[slen]))) { + cp1 = cp+slen; + while(isspace(*cp1)) cp1++; + if (*cp1 != OPENBRACE) { + err_general(1,lno,loc); + return(-1); + } + + while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) { + lno++; + if (skipline(line)) + continue; + if (line[0] == CLOSEBRACE) { + tfsseek(struct_sfd,loc,TFS_BEGIN); + return(offset); + } + switch(structline(line,&type,&name)) { + case 2: + if ((size = typesize(type,name)) < 0) { + err_general(2,lno,loc); + return(-1); + } + break; + case 3: + if ((size = structsize(type)) < 0) { + err_general(3,lno,loc); + return(-1); + } + break; + default: + err_general(4,lno,loc); + return(-1); + } + offset += size; + } + err_general(5,lno,loc); + return(-1); + } + } + } + err_nostruct(structname,loc); + return(-1); +} + +int +membertype(char *structname, char *mbrname, char *mbrtype) +{ + long loc; + int rc, slen, lno; + char line[80], *cp, *cp1, *type, *name; + + struct_printf(4,"membertype(%s,%s)\n",structname,mbrname); + + loc = tfstell(struct_sfd); + + if (tfsseek(struct_sfd,0,TFS_BEGIN) < 0) { + tfsseek(struct_sfd,loc,TFS_BEGIN); + return(-1); + } + + slen = strlen(structname); + lno = 0; + while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) { + lno++; + if (skipline(line)) + continue; + if (!strncmp(line,"struct ",7)) { + cp = line+7; + while(isspace(*cp)) cp++; + if ((!strncmp(structname,cp,slen)) && (isspace(cp[slen]))) { + cp1 = cp+slen; + while(isspace(*cp1)) cp1++; + if (*cp1 != OPENBRACE) { + err_general(6,lno,loc); + return(-1); + } + + while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) { + lno++; + if (skipline(line)) + continue; + if (line[0] == CLOSEBRACE) { + err_nomember(structname,mbrname,loc); + return(-1); + } + if ((rc = structline(line,&type,&name)) < 0) { + err_general(7,lno,loc); + return(-1); + } + if (!strcmp(name,mbrname)) { + tfsseek(struct_sfd,loc,TFS_BEGIN); + if (mbrtype) + strcpy(mbrtype,type); + return(rc); + } + } + err_general(8,lno,loc); + return(-1); + } + } + } + err_nostruct(structname,loc); + return(-1); +} + +/* memberoffset(): + * Return the offset into the structure at which point the member resides. + * If mbrsize is non-zero, then assume it is a pointer to an integer + * into which this function will also load the size of the member. + */ +int +memberoffset(char *structname, char *mbrname, int *mbrsize) +{ + long loc; + int offset, slen, size, lno; + char line[80], *cp, *cp1, *type, *name; + + struct_printf(4,"memberoffset(%s,%s)\n",structname,mbrname); + + loc = tfstell(struct_sfd); + + if (tfsseek(struct_sfd,0,TFS_BEGIN) < 0) { + tfsseek(struct_sfd,loc,TFS_BEGIN); + return(-1); + } + + offset = 0; + slen = strlen(structname); + lno = 0; + while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) { + lno++; + if (skipline(line)) + continue; + if (!strncmp(line,"struct ",7)) { + cp = line+7; + while(isspace(*cp)) cp++; + if ((!strncmp(structname,cp,slen)) && (isspace(cp[slen]))) { + cp1 = cp+slen; + while(isspace(*cp1)) cp1++; + if (*cp1 != OPENBRACE) { + err_general(9,lno,loc); + return(-1); + } + + while(tfsgetline(struct_sfd,line,sizeof(line)) > 0) { + lno++; + if (skipline(line)) + continue; + if (line[0] == '#') + continue; + if (line[0] == CLOSEBRACE) { + err_nomember(structname,mbrname,loc); + return(-1); + } + switch(structline(line,&type,&name)) { + case 2: + if ((size = typesize(type,name)) < 0) { + err_general(10,lno,loc); + return(-1); + } + break; + case 3: + if ((size = structsize(type)) < 0) { + err_general(11,lno,loc); + return(-1); + } + break; + default: + err_general(12,lno,loc); + return(-1); + } + if (!strcmp(name,mbrname)) { + tfsseek(struct_sfd,loc,TFS_BEGIN); + if (mbrsize) + *mbrsize = size; + return(offset); + } + offset += size; + } + err_general(13,lno,loc); + return(-1); + } + } + } + err_nostruct(structname,loc); + return(-1); +} + +char *StructHelp[] = { + "Build a structure in memory", + "-[b:f:v] {struct.mbr[=val]} [struct.mbr1[=val1]] ...", +#if INCLUDE_VERBOSEHELP + "Options:", + " -b{addr} base address of structure (overrides STRUCTBASE)", + " -f{fname} structure definition filename (overrides STRUCTFILE)", + " -v additive verbosity", + "", + "Notes:", + " * The 'val' can be a normal value or a processed function...", + " strcpy(str|src), strcat(str|src), memcpy(src,size)", + " sizeof(structtype), tagsiz(str1,str2), e2b(enet), i2l(ip)", + " * If '=val' is not specified, then the size and offset of the", + " specified structure/member is loaded into STRUCTSIZE and", + " STRUCTOFFSET shellvars respectively.", +#endif + 0, +}; + +int +StructCmd(int argc,char *argv[]) +{ + unsigned long lval, dest; + char copy[CMDLINESIZE], type[32]; + char *eq, *dot, *str, *mbr, *env, *equation; + int opt, i, offset, mbrtype, rc, size, processlval; + + struct_fname = 0; + struct_verbose = 0; + struct_base = 0xffffffff; + while((opt=getopt(argc,argv,"b:f:v")) != -1) { + switch(opt) { + case 'b': + struct_base = strtoul(optarg,0,0); + break; + case 'f': + struct_fname = optarg; + break; + case 'v': + struct_verbose++; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc < optind + 1) + return(CMD_PARAM_ERROR); + + /* If base and/or filename are not set, get them from environment + * variables... + */ + if (struct_base == 0xffffffff) { + if ((env = getenv("STRUCTBASE")) == 0) { + printf("No struct base\n"); + return(CMD_FAILURE); + } + struct_base = strtoul(env,0,0); + } + if (struct_fname == 0) { + if ((struct_fname = getenv("STRUCTFILE")) == 0) { + printf("No struct filename\n"); + return(CMD_FAILURE); + } + } + + struct_sfd = tfsopen(struct_fname,TFS_RDONLY,0); + + if (struct_sfd < 0) { + printf("Can't find file '%s'\n",struct_fname); + return(CMD_FAILURE); + } + + /* If the specified structure description file is the currently + * running script, then set a flag so that this code will look + * for the "###>>" prefix as a required line prefix in the + * structure file. + */ + if (strcmp(struct_fname,tfsscriptname()) == 0) + struct_scriptisstructfile = 1; + else + struct_scriptisstructfile = 0; + + /* Assume each command line argument is some "struct=val" statement, + * and process each one... + */ + for(i=optind;i<argc;i++) { + equation = argv[i]; + + /* Make a copy of the argument so we can modify it. + * (no need to check length because sizeof(copy) is CMDLINESIZE). + */ + strcpy(copy,equation); + + /* Check for equal sign... + */ + if ((eq = strchr(copy,'='))) + *eq = 0; + + /* Start parsing and processing the structure request... + */ + offset = mbrtype = 0; + dot = strchr(copy,'.'); + if (!dot) { + size = structsize(copy); + } + else { + while(dot) { + *dot++ = 0; + mbr = dot; + str = dot-2; + while((*str != 0) && (str != copy) && (*str != '.')) + str--; + if (str != copy) + str++; + while((dot != 0) && (*dot != '.')) + dot++; + *dot = 0; + + if (mbrtype == 3) + str = type; + + if ((rc = memberoffset(str,mbr,&size)) < 0) + goto done; + + if ((mbrtype = membertype(str,mbr,type)) < 0) + goto done; + + offset += rc; + *dot = '.'; + dot = strchr(mbr,'.'); + } + } + + shell_sprintf("STRUCTOFFSET","0x%lx",offset); + shell_sprintf("STRUCTSIZE","0x%lx",size); + + /* If there is no "right half" of the equation, then just + * continue here... + */ + if (!eq) + continue; + + /* At this point we have the size of the member and its offset + * from the base, so now we parse the "val" side of the + * equation... + */ + + /* Check for functions (sizeof, strcpy, enet, ip, etc...). + * If found, then something other than just normal lval processing + * is done... + */ + eq++; + lval = processlval = 0; + dest = struct_base + offset; + if (!strncmp(eq,"sizeof(",7)) { + char *cp; + + eq += 7; + cp = eq; + if ((cp = strchr(cp,')')) == 0) + goto paramerr; + *cp=0; + lval = structsize(eq); + processlval = 1; + } + else if (!strncmp(eq,"i2l(",4)) { + char *cp, *cp1; + + eq += 4; + cp = cp1 = eq; + if ((cp1 = strchr(cp,')')) == 0) + goto paramerr; + *cp1 = 0; + if (struct_verbose & 1) { + } + struct_printf(3,"i2l(0x%lx,%s)\n", dest, cp); + + if (IpToBin(cp,(uchar *)dest) < 0) + goto paramerr; + } + else if (!strncmp(eq,"e2b(",4)) { + char *cp, *cp1; + + cp = cp1 = eq+4; + if ((cp1 = strchr(cp,')')) == 0) + goto paramerr; + *cp1 = 0; + struct_printf(3,"e2b(0x%lx,%s)\n", dest, cp); + + if (EtherToBin(cp,(uchar *)dest) < 0) + goto paramerr; + } + else if (!strncmp(eq,"tagsiz(",7)) { + char *comma, *paren; + int siz1, siz2; + + eq += 7; + comma = eq; + if ((comma = strchr(comma,',')) == 0) + goto paramerr; + *comma++ = 0; + if ((paren = strrchr(comma,')')) == 0) + goto paramerr; + *paren = 0; + if ((siz1=structsize(eq)) < 0) + goto paramerr; + if ((siz2=structsize(comma)) < 0) + goto paramerr; + lval = (siz1+siz2)/4; + processlval = 1; + } + else if (!strncmp(eq,"memcpy(",7)) { + int len; + char *comma, *cp; + + eq += 7; + comma = eq; + if ((comma = strchr(comma,',')) == 0) + goto paramerr; + *comma++ = 0; + cp = comma; + cp = (char *)strtoul(eq,0,0); + len = (int)strtoul(comma,0,0); + struct_printf(3,"memcpy(0x%lx,0x%lx,%d)\n",dest,(long)cp,len); + memcpy((void *)dest,(void *)cp,len); + } + else if (!strncmp(eq,"strcpy(",7)) { + char *cp, *cp1; + + eq += 7; + cp = cp1 = eq; + if ((cp1 = strrchr(cp,')')) == 0) + goto paramerr; + *cp1 = 0; + + + if (!strncmp(cp,"0x",2)) { + cp = (char *)strtoul(eq,0,0); + struct_printf(3,"strcpy(0x%lx,0x%lx)\n",dest,(long)cp); + } + else { + struct_prleft(1,equation," = \"%s\"\n",cp); + struct_printf(2,"strcpy(0x%lx,%s)\n", dest,cp); + } + strcpy((char *)dest,cp); + } + else if (!strncmp(eq,"strcat(",7)) { + char *cp, *cp1; + + eq += 7; + cp = cp1 = eq; + if ((cp1 = strrchr(cp,')')) == 0) + goto paramerr; + *cp1 = 0; + + if (!strncmp(cp,"0x",2)) { + cp = (char *)strtoul(eq,0,0); + struct_printf(3,"strcat(0x%lx,0x%lx)\n",dest,(long)cp); + } + else { + struct_prleft(1,equation," += \"%s\"\n",cp); + struct_printf(2,"strcat(0x%lx,%s)\n", dest,cp); + } + strcat((char *)dest,cp); + } + else { + lval = strtoul(eq,0,0); + processlval = 1; + } + + if (processlval) { + switch(size) { + case 1: + struct_prleft(1,equation," = %d (0x%x)\n", + (uchar)lval,(uchar)lval); + struct_printf(2,"*(uchar *)0x%lx = %d (0x%x)\n", + dest,(uchar)lval,(uchar)lval); + *(uchar *)(dest) = (uchar)lval; + break; + case 2: + struct_prleft(1,equation," = %d (0x%x)\n", + (ushort)lval,(ushort)lval); + struct_printf(2,"*(ushort *)0x%lx = %d (0x%x)\n", + dest,(ushort)lval,(ushort)lval); + *(ushort *)dest = (ushort)lval; + break; + case 4: + struct_prleft(1,equation," = %ld (0x%lx)\n", + (ulong)lval,(ulong)lval); + struct_printf(2,"*(ulong *)0x%lx = %d (0x%x)\n", + dest,lval,lval); + *(ulong *)dest = lval; + break; + default: + struct_printf(3,"memset(0x%lx,0x%x,%d)\n", + dest,(uchar)lval,size); + memset((void *)dest,lval,size); + break; + } + } + } +done: + tfsclose(struct_sfd,0); + return(CMD_SUCCESS); + +paramerr: + tfsclose(struct_sfd,0); + return(CMD_PARAM_ERROR); +} +#endif diff --git a/main/common/symtbl.c b/main/common/symtbl.c new file mode 100644 index 0000000..efc08c4 --- /dev/null +++ b/main/common/symtbl.c @@ -0,0 +1,215 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * symtbl.c: + * + * This file contains functions related to the symbol table option in + * the monitor. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "genlib.h" +#if INCLUDE_TFSSYMTBL +#include <ctype.h> +#include "tfs.h" +#include "tfsprivate.h" + +#ifndef SYMFILE +#define SYMFILE "symtbl" +#endif + +/* SymFileFd(): + * Attempt to open the symbol table file. First look to the SYMFILE env var; + * else default to SYMFILE definition. If the file exists, open it and return + * the file descriptor; else return TFSERR_NOFILE. + */ +int +SymFileFd(int verbose) +{ + TFILE *tfp; + int tfd; + char *symfile; + + /* Load symbol table file name. If SYMFILE is not a variable, default + * to the string defined by SYMFILE. + */ + symfile = getenv("SYMFILE"); + if (!symfile) + symfile = SYMFILE; + + tfp = tfsstat(symfile); + if (!tfp) + return(TFSERR_NOFILE); + + tfd = tfsopen(symfile,TFS_RDONLY,0); + if (tfd < 0) { + if (verbose) + printf("%s: %s\n",symfile,(char *)tfsctrl(TFS_ERRMSG,tfd,0)); + return(TFSERR_NOFILE); + } + return(tfd); +} + +/* AddrToSym(): + * Assumes each line of symfile is formatted as... + * synmame SP hex_address + * and that the symbols are sorted from lowest to highest address. + * Using the file specified by the incoming TFS file descriptor, + * determine what symbol's address range covers the incoming address. + * If found, store the name of the symbol as well as the offset between + * the address of the symbol and the incoming address. + * Note, if the incoming file descriptor is -1, then we open (and later + * close) the file here. + * + * Return 1 if a match is found, else 0. + */ +int +AddrToSym(int tfdin,ulong addr,char *name,ulong *offset) +{ + int lno, tfd; + char *space; + ulong thisaddr, lastaddr; + char thisline[84]; + char lastline[sizeof(thisline)]; + + lno = 1; + if (offset) + *offset = 0; + lastaddr = 0; + if (tfdin == -1) { + tfd = SymFileFd(0); + if (tfd == TFSERR_NOFILE) + return(0); + } + else + tfd = tfdin; + tfsseek(tfd,0,TFS_BEGIN); + while(tfsgetline(tfd,thisline,sizeof(thisline)-1)) { + space = strpbrk(thisline,"\t "); + if (!space) + continue; + *space++ = 0; + while(isspace(*space)) + space++; + + thisaddr = strtoul(space,0,0); /* Compute address from entry in */ + /* symfile. */ + + if (thisaddr == addr) { /* Exact match, use this entry */ + strcpy(name,thisline); /* in symfile. */ + if (tfdin == -1) + tfsclose(tfd,0); + return(1); + } + else if (thisaddr > addr) { /* Address in symfile is greater */ + if (lno == 1) /* than incoming address... */ + break; /* If this is first line of symfile */ + strcpy(name,lastline); /* then return error. */ + if (offset) + *offset = addr-lastaddr;/* Otherwise return the symfile */ + if (tfdin == -1) + tfsclose(tfd,0); + return(1); /* entry previous to this one. */ + } + else { /* Address in symfile is less than */ + lastaddr = thisaddr; /* incoming address, so just keep */ + strcpy(lastline,thisline); /* a copy of this line and go to */ + lno++; /* the next. */ + } + } + if (tfdin == -1) + tfsclose(tfd,0); + sprintf(name,"0x%lx",addr); + return(0); +} + +/* getsym(): + * Provides a similar capability to shell variables on the command line + * except that here, the variable replacement is based on the content of + * a symbol file. The file would be be loaded into TFS to provide + * a potentially large number of symbols. + * Looks for the file SYMFILE. If non-existent, just return NULL. + * If file exists, then search through the file for the incoming + * symbol name and, if found, return the replacement for the symbol. + * else return NULL. + * The text file is formatted such that no line is greater than 40 characters. + * Each line has 2 whitespace delimited strings. The first string is + * the symbol name and the second string is the replacement value for that + * symbol. The first string is assumed to start at the beginning of the + * line, and the second string is separated from the first string by + * spaces and/or tabs. + * For example, here are a few lines: + * + * main 0x10400 + * func 0x10440 + * + * With the above lines in SYMFILE, if %main were on the command line, it + * would be replaced with 0x10400. + */ +char * +getsym(char *symname,char *line,int sizeofline) +{ + int tfd; + char *space; + + if ((tfd = SymFileFd(1)) < 0) { + return((char *)0); + } + + while(tfsgetline(tfd,line,sizeofline)) { + char *eol; + eol = strpbrk(line,"\r\n"); + if (eol) + *eol = 0; + space = strpbrk(line,"\t "); + if (!space) + continue; + *space = 0; + if (!strcmp(line,symname)) { + tfsclose(tfd,0); + space++; + while((*space == ' ') || (*space == '\t')) + space++; + return(space); + } + } + tfsclose(tfd,0); + return((char *)0); +} + +#else + +char * +getsym(char *symname,char *line,int sizeofline) +{ + return((char *)0); +} + +int +AddrToSym(int tfd,ulong addr,char *name,ulong *offset) +{ + sprintf(name,"0x%lx",addr); + return(0); +} + +#endif diff --git a/main/common/syslog.c b/main/common/syslog.c new file mode 100644 index 0000000..a6f0334 --- /dev/null +++ b/main/common/syslog.c @@ -0,0 +1,337 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * syslog.c: + * + * This code supports the monitor's SYSLOC client. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_SYSLOG +#include "endian.h" +#include "genlib.h" +#include "ether.h" +#include "stddefs.h" +#include "cli.h" + +#define SYSLOG_PORT 514 + +struct nameval { + char *name; + int val; +}; + +/* Priority codes: + */ +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but significant condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ + +/* Facility codes: + */ +#define LOG_KERN (0<<3) /* kernel messages */ +#define LOG_USER (1<<3) /* random user-level messages */ +#define LOG_MAIL (2<<3) /* mail system */ +#define LOG_DAEMON (3<<3) /* system daemons */ +#define LOG_AUTH (4<<3) /* security/authorization messages */ +#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ +#define LOG_LPR (6<<3) /* line printer subsystem */ +#define LOG_NEWS (7<<3) /* network news subsystem */ +#define LOG_UUCP (8<<3) /* UUCP subsystem */ +#define LOG_CRON (9<<3) /* clock daemon */ +#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */ +#define LOG_FTP (11<<3) /* ftp daemon */ +#define LOG_LOCAL0 (16<<3) /* reserved for local use */ +#define LOG_LOCAL1 (17<<3) /* reserved for local use */ +#define LOG_LOCAL2 (18<<3) /* reserved for local use */ +#define LOG_LOCAL3 (19<<3) /* reserved for local use */ +#define LOG_LOCAL4 (20<<3) /* reserved for local use */ +#define LOG_LOCAL5 (21<<3) /* reserved for local use */ +#define LOG_LOCAL6 (22<<3) /* reserved for local use */ +#define LOG_LOCAL7 (23<<3) /* reserved for local use */ + +#define FACILITY_MASK 0x03f8 +#define PRIORITY_MASK 0x0007 + +struct nameval prioritynames[] = { + { "emerg", LOG_EMERG }, + { "alert", LOG_ALERT }, + { "critical", LOG_CRIT }, + { "error", LOG_ERR }, + { "warning", LOG_WARNING }, + { "notice", LOG_NOTICE }, + { "info", LOG_INFO }, + { "debug", LOG_DEBUG }, + { 0, 0 } +}; + +struct nameval facilitynames[] = { + { "kernel", LOG_KERN }, + { "user", LOG_USER }, + { "mail", LOG_MAIL }, + { "daemon", LOG_DAEMON }, + { "authorize", LOG_AUTH }, + { "syslog", LOG_SYSLOG }, + { "lpr", LOG_LPR }, + { "news", LOG_NEWS }, + { "uucp", LOG_UUCP }, + { "cron", LOG_CRON }, + { "authpriv", LOG_AUTHPRIV }, + { "ftp", LOG_FTP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, + { 0, 0 } +}; + +void +syslogInfo(void) +{ + int tot; + struct nameval *nvp; + + tot = 0; + nvp = prioritynames; + printf("\nValid 'priority' names:\n"); + while(nvp->name) { + printf("%12s",nvp->name); + nvp++; + if (++tot == 4) { + printf("\n"); + tot = 0; + } + } + + tot = 0; + nvp = facilitynames; + printf("\nValid 'facility' names:\n"); + while(nvp->name) { + printf("%12s",nvp->name); + nvp++; + if (++tot == 4) { + printf("\n"); + tot = 0; + } + } +} + + +int +getPriorityValue(char *prio) +{ + struct nameval *nvp; + + if (prio == 0) + return(0); + + nvp = prioritynames; + while(nvp->name) { + if (!strcmp(nvp->name,prio)) + return(nvp->val); + nvp++; + } + return(-1); +} + +int +getFacilityValue(char *fac) +{ + struct nameval *nvp; + + if (fac == 0) + return(0); + + nvp = facilitynames; + while(nvp->name) { + if (!strcmp(nvp->name,fac)) + return(nvp->val); + nvp++; + } + return(-1); +} + +int +sendSyslog(uchar *syslogsrvr,char *msg, short port, int null) +{ + int msglen; + uchar *syslogmsg; + ushort ip_len, sport; + struct ether_header *enetp; + struct ip *ipp; + struct Udphdr *udpp; + uchar binip[8], binenet[8], *enetaddr; + + /* msglen is the length of the message, plus optionally the + * terminating null character (-n option of syslog command).. + */ + msglen = strlen(msg) + null; + + /* Convert IP address to binary: + */ + if (IpToBin((char *)syslogsrvr,(unsigned char *)binip) < 0) + return(0); + + /* Get the ethernet address for the IP: + */ + enetaddr = ArpEther(binip,binenet,0); + if (!enetaddr) { + printf("ARP failed for %s\n",syslogsrvr); + return(0); + } + + /* Retrieve an ethernet buffer from the driver and populate the + * ethernet level of packet: + */ + enetp = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&enetp->ether_shost,(char *)BinEnetAddr,6); + memcpy((char *)&enetp->ether_dhost,(char *)binenet,6); + enetp->ether_type = ecs(ETHERTYPE_IP); + + /* Move to the IP portion of the packet and populate it + * appropriately: + */ + ipp = (struct ip *) (enetp + 1); + ipp->ip_vhl = IP_HDR_VER_LEN; + ipp->ip_tos = 0; + ip_len = sizeof(struct ip) + sizeof(struct Udphdr) + msglen; + ipp->ip_len = ecs(ip_len); + ipp->ip_id = ipId(); + ipp->ip_off = 0; + ipp->ip_ttl = UDP_TTL; + ipp->ip_p = IP_UDP; + memcpy((char *)&ipp->ip_src.s_addr,(char *)BinIpAddr,4); + memcpy((char *)&ipp->ip_dst.s_addr,(char *)binip,4); + + /* Now UDP... + */ + sport = port+1; + udpp = (struct Udphdr *) (ipp + 1); + udpp->uh_sport = ecs(sport); + udpp->uh_dport = ecs(port); + udpp->uh_ulen = ecs((ushort)(ip_len - sizeof(struct ip))); + + /* Finally, the SYSLOG data ... + */ + syslogmsg = (uchar *)(udpp+1); + strcpy((char *)syslogmsg,(char *)msg); + + ipChksum(ipp); /* Compute csum of ip hdr */ + udpChksum(ipp); /* Compute UDP checksum */ + + sendBuffer(ETHERSIZE + IPSIZE + UDPSIZE + msglen); + return(0); +} + +char *SyslogHelp[] = { + "Syslog client", + "-[f:lP:np:v] {srvr ip} {msg}", +#if INCLUDE_VERBOSEHELP + "Options:", + " -f {fac} specify facility", + " -l list facility & priority strings", + " -n append null-char to message", + " -P {##} override default port 514", + " -p {prio} specify priority", + " -v verbose", +#endif + 0, +}; + + +int +SyslogCmd(int argc, char *argv[]) +{ + char *facility, *priority, *msg; + int opt, verbose, fac_val, prio_val, val, port, null; + + port = SYSLOG_PORT; + facility = priority = 0; + null = fac_val = prio_val = verbose = 0; + + while((opt=getopt(argc,argv,"f:lnP:p:v")) != -1) { + switch(opt) { + case 'f': + facility = optarg; + break; + case 'l': + syslogInfo(); + return(CMD_SUCCESS); + case 'n': + null = 1; + break; + case 'P': + port = atoi(optarg); + break; + case 'p': + priority = optarg; + break; + case 'v': + verbose = 1; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc != optind+2) + return(CMD_PARAM_ERROR); + + prio_val = getPriorityValue(priority); + fac_val = getFacilityValue(facility); + + if ((prio_val == -1) || (fac_val == -1)) + return(CMD_PARAM_ERROR); + + val = (prio_val | fac_val); + + if ((priority != 0) || (facility != 0)) { + msg = malloc(strlen(argv[optind+1])+16); + if (!msg) + return(CMD_FAILURE); + sprintf(msg,"<%d>%s",val,argv[optind+1]); + } + else + msg = argv[optind+1]; + + if (verbose) + printf("Syslog msg '%s' to %s\n",msg,argv[optind]); + + sendSyslog((unsigned char *)argv[optind],msg,port,null); + + if (val) + free(msg); + + return(CMD_SUCCESS); +} + +#endif + diff --git a/main/common/tcpstuff.c b/main/common/tcpstuff.c new file mode 100644 index 0000000..8122637 --- /dev/null +++ b/main/common/tcpstuff.c @@ -0,0 +1,168 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tcpstuff.c + * + * Absolute minimum to properly refuse TCP connection requests to this + * device. The processTCP function is called if the incoming protocol is + * TCP, but this code simply responds with a TCP RESET which is essentially + * a refusal to establish the connection request being made from a remote + * machine. + * This is similar in functionality to the ICMP "destination unreachable + * message". Note that this is not an absolute necessity but it does + * provide a "clean" response to the remote machine that is making the + * connection request. Without it, the remote machine would keep trying + * to connect. + * For more details, refer to TCP/IP Comer 3rd Edition pg 216-219. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "endian.h" +#if INCLUDE_ETHERNET +#include "genlib.h" +#include "ether.h" +#include "stddefs.h" + +/* SendTcpConnectionReset(): + * Called in response to any incoming TCP request. + * It is used to let the sender know that the TCP connection is being + * refused. + */ +int +SendTcpConnectionReset(struct ether_header *re) +{ + short datalen, flags; + ulong ackno; + struct ether_header *te; + struct ip *ti, *ri; + struct tcphdr *ttcp, *rtcp; + + ri = (struct ip *) (re + 1); + datalen = ecs(ri->ip_len) - ((ri->ip_vhl & 0x0f) * 4); + + te = EtherCopy(re); + ti = (struct ip *) (te + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ti->ip_len = ri->ip_len; + ti->ip_id = ri->ip_id; + ti->ip_off = ecs(IP_DONTFRAG); + ti->ip_ttl = ri->ip_ttl/2; + ti->ip_p = ri->ip_p; + memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr), + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), + sizeof(struct in_addr)); + + ttcp = (struct tcphdr *) (ti + 1); + rtcp = (struct tcphdr *) (ri + 1); + flags = ecs(rtcp->flags); + flags &= ~TCP_FLAGMASK; + flags |= (TCP_ACK | TCP_RESET); + ttcp->flags = ecs(flags); + ttcp->sport = rtcp->dport; + ttcp->dport = rtcp->sport; + memset((char *)&ttcp->seqno,0,4); + memcpy((char *)&ackno,(char *)&rtcp->seqno,4); + self_ecl(ackno); + ackno+=1; + self_ecl(ackno); + memcpy((char *)&ttcp->ackno,(char *)&ackno,4); + + ttcp->windowsize = 0; + ttcp->urgentptr = 0; + memcpy((char *)(ttcp+1),(char *)(rtcp+1),datalen-sizeof(struct tcphdr)); + + ipChksum(ti); /* compute checksum of ip hdr: (3rd Edition Comer pg 100) */ + tcpChksum(ti); /* Compute TCP checksum */ + + sendBuffer(sizeof(struct ether_header) + ecs(ti->ip_len)); + return(0); +} + +/* tcpChksum(): + * Compute the checksum of the TCP packet. + * The incoming pointer is to an ip header, the tcp header after that ip + * header is directly populated with the result. Similar to the udp + * checksum calculation. This one is mandatory. + */ +void +tcpChksum(struct ip *ihdr) +{ + register int i; + register ushort *sp; + register ulong t; + short len; + struct tcphdr *thdr; + struct UdpPseudohdr pseudohdr; + + thdr = (struct tcphdr *)(ihdr+1); + thdr->tcpcsum = 0; + + /* Start by building the pseudo header: */ + memcpy((char *)&pseudohdr.ip_src.s_addr,(char *)&ihdr->ip_src.s_addr,4); + memcpy((char *)&pseudohdr.ip_dst.s_addr,(char *)&ihdr->ip_dst.s_addr,4); + pseudohdr.zero = 0; + pseudohdr.proto = ihdr->ip_p; + len = ecs(ihdr->ip_len) - sizeof(struct ip); + pseudohdr.ulen = ecs(len); + + /* Get checksum of pseudo header: */ + sp = (ushort *) &pseudohdr; + for (i=0,t=0;i<(sizeof(struct UdpPseudohdr)/sizeof(ushort));i++,sp++) + t += *sp; + + /* If length is odd, pad and add one. */ + if (len & 1) { + uchar *ucp; + ucp = (uchar *)thdr; + ucp[len] = 0; + len++; + } + len >>= 1; + + sp = (ushort *) thdr; + for (i=0;i<len;i++,sp++) + t += *sp; + t = (t & 0xffff) + (t >> 16); + thdr->tcpcsum = ~t; +} + +void +tcperrmsg(char *msg) +{ + printf("TCP error: %s\n",msg); +} + +void +processTCP(struct ether_header *ehdr,ushort size) +{ + //struct ip *ipp; + //struct tcphdr *tcpp; + + //ipp = (struct ip *)(ehdr + 1); + //tcpp = (struct tcphdr *)((char *)ipp + IP_HLEN(ipp)); + SendTcpConnectionReset(ehdr); + return; +} + +#endif diff --git a/main/common/term.c b/main/common/term.c new file mode 100644 index 0000000..67d198e --- /dev/null +++ b/main/common/term.c @@ -0,0 +1,160 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * term.c: + * + * This file contains miscellaneous snippets of code that will allow + * umon to talk to a vt100-compatible terminal. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#include "genlib.h" +#include "timer.h" +#include "term.h" + +#if INCLUDE_TERM + +static int +gettermtype(void) +{ + char *term = getenv("TERM"); + int termtype = TERMTYPE_UNDEFINED; + + if (term != 0) { + if (strcasecmp(term,"VT100") == 0) + termtype = TERMTYPE_VT100; + } + + return(termtype); +} + +int +term_settextcolor(int fg) +{ + if (gettermtype() == TERMTYPE_VT100) { + printf("%c[%dm", 0x1B, fg + 30); + return(0); + } + return(-1); +} + +int +term_setbgcolor(int bg) +{ + if (gettermtype() == TERMTYPE_VT100) { + printf("%c[%dm", 0x1B, bg + 40); + return(0); + } + return(-1); +} + +int +term_settextattribute(int attr) +{ + if (gettermtype() == TERMTYPE_VT100) { + printf("%c[%dm", 0x1B, attr); + return(0); + } + return(-1); +} + + +int +term_resettext(void) +{ + if (gettermtype() == TERMTYPE_VT100) { + printf("%c[0m",0x1b); + return(0); + } + return(-1); +} + +/* term_getsize(): + * Attempt to query the terminal for its row/col values... + */ +int +term_getsize(int *rows, int *cols) +{ + int c, i, rtot, ctot; + char *semi, buf[16]; + struct elapsed_tmr tmr; + + if (gettermtype() == TERMTYPE_UNDEFINED) + return(-1); + + setenv("ROWS",0); + setenv("COLS",0); + + /* Send the "what is your terminal size?" request... + */ + printf("\E[6n"); + + /* Wait for a response that looks like: "ESC[rrr;cccR" + * where 'rrr' is the number of rows, and 'ccc' is the + * number of columns. + */ + memset(buf,0,sizeof(buf)); + startElapsedTimer(&tmr,1000); + for(i=0;i<sizeof(buf);i++) { + while (!gotachar()) { + if(msecElapsed(&tmr)) { + return(-1); + } + } + c = getchar(); + if ((i == 0) && (c != 0x1b)) { + return(-1); + } + if ((i == 1) && (c != '[')) { + return(-1); + } + if (c == 'R') + break; + buf[i] = c; + } + if (i == sizeof(buf)) { + return(-1); + } + semi = strchr(buf,';'); + if (semi == (char *)0) { + return(-1); + } + *semi = 0; + buf[i] = 0; + rtot = atoi(buf+2); + ctot = atoi(semi+1); + shell_sprintf("ROWS","%d",rtot); + shell_sprintf("COLS","%d",ctot); + if (rows) *rows = rtot; + if (cols) *cols = ctot; + return(0); +} + +void +term_clearscreen(void) +{ + if (gettermtype() == TERMTYPE_VT100) + printf("\E[0J"); +} + +#endif diff --git a/main/common/term.h b/main/common/term.h new file mode 100644 index 0000000..274120c --- /dev/null +++ b/main/common/term.h @@ -0,0 +1,61 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * term.h: + * + * See term.c for details. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + */ +#ifndef _TERM_H_ +#define _TERM_H_ + +#define TERMTYPE_UNDEFINED 0 +#define TERMTYPE_VT100 1 + +/* Font attributes: + */ +#define ATTR_RESET 0 +#define ATTR_BRIGHT 1 +#define ATTR_DIM 2 +#define ATTR_UNDERLINE 3 +#define ATTR_BLINK 4 +#define ATTR_REVERSE 7 +#define ATTR_HIDDEN 8 + +/* Font colors: + */ +#define BLACK 0 +#define RED 1 +#define GREEN 2 +#define YELLOW 3 +#define BLUE 4 +#define MAGENTA 5 +#define CYAN 6 +#define WHITE 7 + +extern int term_settextcolor(int fg); +extern int term_setbgcolor(int bg); +extern int term_resettext(void); +extern int term_getsize(int *row, int *col); + +#endif + + diff --git a/main/common/tfs.c b/main/common/tfs.c new file mode 100644 index 0000000..5223ba2 --- /dev/null +++ b/main/common/tfs.c @@ -0,0 +1,3379 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfs.c: + * + * Tiny File System + * TFS supports the ability to store/access files in flash. The TFS + * functions provide a command at the monitor's user interface (the + * "tfs" command) as well as a library of functions that are available to + * the monitor/application code on this target (TFS api). + * + * The code that supports TFS in the MicroMonitor package spans across + * several files. This is done so that various pieces of TFS can optionally + * be compiled in or out (using INCLUDE_XXX macros in config.h) of the + * monitor package... + * + * tfs.c: + * Core TFS code that cannot be optionally omitted without eliminating + * the TFS facility from the monitor. + * + * tfsapi.c: + * This file contains the code that supports the application's ability + * to use the TFS api. Since some of the api is used by the monitor + * itself, not all of the api-specific code is there, some of it is + * in tfs.c. + * + * tfscleanX.c: + * TFS can be configured with one of several different flash defrag + * mechanisms. Currently, tfsclean[123].c are available. + * + * tfscli.c: + * If you don't need the "tfs" command in your command line interface, + * then the code in this file can be omitted. + * + * tfsloader.c: + * TFS can support COFF, ELF or A.OUT binary file formats. The code + * to load each of these formats from flash to RAM is here. + * + * tfslog.c: + * If there is a need to log flash interaction to a file, then this + * file contains code to support that. + * + * + * NOTES: + * * Dealing with multiple task access: + * Since the monitor is inherently a single threaded program + * potentially being used in a multi-tasking environment, the monitor's + * access functions (API) must be provided with a lock/unlock + * wrapper that will guarantee sequential access to all of the monitor + * facilities. Refer to monlib.c to see this implementation. This + * provides the protection needed by TFS to keep multiple "mon_" + * functions from being executed by different tasks. + * Note that originally this was supported with tfsctrl(TFS_MUTEX ) and + * it only protected the tfs API functions. This turned out to be + * insufficient because it did not prevent other tasks from calling + * other non-tfs functions in the monitor while tfs access (and + * potentially, flash update) was in progress. This meant that a flash + * update could be in progress and some other task could call mon_getenv() + * (for example). This could screw up the flash update because + * mon_getenv() might be fetched out of the same flash device that + * the TFS operation is being performed on. + * + * * Dealing with cache coherency: + * I believe the only concern here is that Icache must be invalidated + * and Dcache must be flushed whenever TFS does a memory copy that may + * ultimately be executable code. This is handled at the end of the + * tfsmemcpy function by calling flushDcache() and invalidateIcache(). + * It is the application's responsibility to give the monitor the + * appropriate functions (see assigncachefuncs()) if necessary. + * + * * Configuring a device to run as TFS memory: + * Assuming you are using power-safe cleanup... + * TFS expects that on any given device used for storage of files, the + * device is broken up into some number of sectors with the last sector + * being the largest and used as the spare sector for defragmentation. + * All other sector sizes must be smaller than the SPARE sector and the + * sector just prior to the spare is used for defragmentation state + * overhead. This sector should be large enough to allow the overhead + * space to grow down from the top without filling the sector. For most + * flash devices, these two sectors (spare and overhead) are usually the + * same size and are large. For FlashRam, the device should be configured + * so that these two sectors are large. The spare sector will never be + * allowed to contain any file information (because it is 100% dedicated to + * the defragmentation process) and the sector next to this can have files + * in it, but the overhead space is also in this sector. + * + * * Testing TFS: + * There are three files dedicated to testing the file system. Two of them + * (tfstestscript & tfstestscript1) are scripts that are put into the + * file system and run. The third file (tfstest.c) is a piece of code + * that can be built into a small application that runs out of TFS to test + * all of the API functionality. + * - tfstestscript: + * This script is used to simply bang on normal defragmentation. It + * builds files with sizes and names based on the content of memory + * starting at $APPRAMBASE. Changing the content of memory starting at + * $APPRAMBASE will change the characteristics of this test so it is + * somewhat random. It is not 100% generic, but can be used as a + * base for testing TFS on various systems. + * - tfstestscript1: + * This script is used to bang on the power-safe defragmentation of + * TFS. It simulates power hits that might occur during defragmentation. + * This script assumes that the monitor has been built with the + * DEFRAG_TEST_ENABLED flag set. + * - tfstest.c: + * This code can be built into a small application that will thoroughly + * exercise the TFS API. This file can also be used as a reference for + * some examples of TFS api usage. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpu.h" +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "tfsdev.h" +#include "flash.h" +#include "cli.h" + +#if INCLUDE_TFS + +int tfsrun_abortableautoboot(char **arglist,int verbose); +char *(*tfsGetAtime)(long,char *,int); +long (*tfsGetLtime)(void); +int (*tfsDocommand)(char *,int); +TDEV tfsDeviceTbl[TFSDEVTOT+1]; /* See notes above tfsramdevice() */ +TFILE **tfsAlist; +struct tfsdat tfsSlots[TFS_MAXOPEN]; +long tfsTrace; +int TfsCleanEnable; +long tfsFmodCount; +char tfsInitialized; + +static void pre_tfsautoboot_hook(void); + +static int tfsAlistSize, tfsOldDelFlagCheckActive; +static int tfsMonrcActive; + +/* alt_tfsdevtbl[]: + * This pre-initialized table of "flash-empty" tfsdev structures allows + * the user to override the default configuration of TFS as it is defined + * in tfsdev.h in the port directory. This is primarily useful for cases + * where uMon is being deployed on an evaluation board and the users have + * varying needs for TFS and it's use of the on-board flash memory. + * + * If TFS_ALTDEVTBL_BASE is defined, then the flash space used as the + * alternate device table can be anywhere in flash memory. Obviously + * it has to be in space that is not used by anything else (and is erased + * if not in use); however, this does provide the user with the option to + * allocate one sector of flash for this; thus allowing the structure to + * be re-written by simply eraseing that sector. + */ +#ifdef TFS_ALTDEVTBL_BASE + +struct tfsdev *alt_tfsdevtbl = (struct tfsdev *)TFS_ALTDEVTBL_BASE; + +#else + +/* The following initialized array uses a GNU-extension to + * force an array of structures and an array of arrays be initialized + * to 0xff in flash. This may break for other compilers (in that case, + * define TFS_ALTDEVTBL_BASE). This syntax is discussed in gcc.gnu.org + * online documentation under the topic "Designated Initializers". + */ +struct tfsdev alt_tfsdevtbl[TFSDEVTOT] = { + [0 ... (TFSDEVTOT-1)] = + { (char *)0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } +}; + +#endif + +#define TFS_ALTDEVTBL_SIZE (TFSDEVTOT * sizeof(struct tfsdev)) + +/* tfsflgtbl & tfserrtbl: + * Tables that establish an easy lookup mechanism to convert from + * bitfield to string or character. + * Note that TFS_ULVL0 is commented out. I leave it in here as a place + * holder (comment), but it actually is not needed becasue ulvl_0 is the + * default if no other ulvl is specified. + */ +struct tfsflg tfsflgtbl[] = { + { TFS_BRUN, 'b', "run_at_boot", TFS_BRUN }, + { TFS_QRYBRUN, 'B', "qry_run_at_boot", TFS_QRYBRUN }, + { TFS_EXEC, 'e', "executable", TFS_EXEC }, + { TFS_SYMLINK, 'l', "symbolic link", TFS_SYMLINK }, + { TFS_EBIN, 'E', TFS_EBIN_NAME, TFS_EBIN }, + { TFS_IPMOD, 'i', "inplace_modifiable", TFS_IPMOD }, + { TFS_UNREAD, 'u', "ulvl_unreadable", TFS_UNREAD }, +/* { TFS_ULVL0, '0', "ulvl_0", TFS_ULVLMSK }, */ + { TFS_ULVL1, '1', "ulvl_1", TFS_ULVLMSK }, + { TFS_ULVL2, '2', "ulvl_2", TFS_ULVLMSK }, + { TFS_ULVL3, '3', "ulvl_3", TFS_ULVLMSK }, + { 0, 0, 0, 0 } +}; + +static struct tfserr tfserrtbl[] = { + { TFS_OKAY, "no error" }, + { TFSERR_NOFILE, "file not found" }, + { TFSERR_NOSLOT, "max fps opened" }, + { TFSERR_EOF, "end of file" }, + { TFSERR_BADARG, "bad argument" }, + { TFSERR_NOTEXEC, "not executable" }, + { TFSERR_BADCRC, "bad crc" }, + { TFSERR_FILEEXISTS, "file already exists" }, + { TFSERR_FLASHFAILURE, "flash operation failed" }, + { TFSERR_WRITEMAX, "max write count exceeded" }, + { TFSERR_RDONLY, "file is read-only" }, + { TFSERR_BADFD, "invalid descriptor" }, + { TFSERR_BADHDR, "bad binary executable header" }, + { TFSERR_CORRUPT, "corrupt file" }, + { TFSERR_MEMFAIL, "memory failure" }, + { TFSERR_NOTIPMOD, "file is not in-place-modifiable" }, + { TFSERR_FLASHFULL, "out of flash space" }, + { TFSERR_USERDENIED, "user level access denied" }, + { TFSERR_NAMETOOBIG, "name or info field too big" }, + { TFSERR_FILEINUSE, "file in use" }, + { TFSERR_NOTAVAILABLE, "tfs facility not available" }, + { TFSERR_BADFLAG, "bad flag" }, + { TFSERR_CLEANOFF, "defragmentation is disabled" }, + { TFSERR_FLAKEYSOURCE, "dynamic source data" }, + { TFSERR_BADEXTENSION, "invalid file extension" }, + { TFSERR_LINKERROR, "file link error" }, + { TFSERR_BADPREFIX, "invalid device prefix" }, + { TFSERR_ALTINUSE, "alternate devcfg in use" }, + { TFSERR_NORUNMONRC, "can't run from monrc" }, + { TFSERR_DSIMAX, "out of DSI space" }, + { TFSERR_TOOSMALL, "partition size too small" }, + { 0,0 } +}; + + +/* dummyAtime() & dummyLtime(): + * These two functions are loaded into the function pointers as defaults + * for the time-retrieval stuff used in TFS. + */ +static char * +dummyAtime(long tval,char *buf,int buflen) +{ +/* strcpy(buf,"Fri Sep 13 00:00:00 1986"); */ + *buf = 0; + return(buf); +} + +static long +dummyLtime(void) +{ + return(TIME_UNDEFINED); +} + +/* getdfsdev(): + * Input is a file pointer; based on that pointer return the appropriate + * device header pointer. If error, just return 0. + * A "device" in TFS is some block of some type of memory that is assumed + * to be contiguous space that can be configured as a block of sectors (to + * look like flash). For most systems, there is only one (the flash); + * other systems may have battery-backed RAM, etc... + * Note that this is not fully implemented. + */ +static TDEV * +gettfsdev(TFILE *fp) +{ + TDEV *tdp; + + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + if ((fp >= (TFILE *)tdp->start) && + (fp < (TFILE *)tdp->end)) + return(tdp); + } + return(0); +} + +TDEV * +gettfsdev_fromprefix(char * prefix, int verbose) +{ + TDEV *tdp; + + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + if (!strcmp(prefix,tdp->prefix)) + return(tdp); + } + if (verbose) + printf("Bad device prefix: %s\n",prefix); + return(0); +} + +/* tfsspace(): + * Return 1 if the incoming address is within TFS space; else + * return 0. + */ +int +tfsspace(char *addr) +{ + TDEV *tdp; + + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + if ((addr >= (char *)tdp->start) && + (addr <= (char *)tdp->end)) + return(1); + if ((addr >= (char *)tdp->spare) && + (addr < (char *)(tdp->spare+tdp->sparesize))) + return(1); + } + return(0); +} + +#ifndef TFS_NON_STANDARD_FLASH_INTERFACE +/* tfsflasherase(), tfsflasheraseall() & tfsflashwrite(): + * Wrappers for corresponding flash operations. The wrappers are used + * to provide one place for the incrmentation of tfsFmodCount. + * + * In almost all cases, this code is included here; however, there + * are some cases where the flash access functions that TFS uses must + * be port-specific; hence, TFS_NON_STANDARD_FLASH_INTERFACE would be defined + * in config.h and they would be provided by the port . + */ +int +tfsflasheraseall(TDEV *tdp) +{ +#if INCLUDE_FLASH + int snum, last; + + if (tfsTrace > 2) + printf(" tfsflasheraseall(%s)\n",tdp->prefix); + + tfsFmodCount++; + + /* Erase the sectors within the device that are used for file store... + */ + if (addrtosector((uchar *)tdp->start,&snum,0,0) < 0) + return(TFSERR_MEMFAIL); + last = snum + tdp->sectorcount; + + while(snum < last) { + if (AppFlashErase(snum++) <= 0) + return(TFSERR_MEMFAIL); + } + + /* Erase the spare (if there is one)... + * (if this system is configured with tfsclean2.c, then + * there is no need for a spare sector). + */ + if (tdp->spare) { + if (addrtosector((uchar *)tdp->spare,&snum,0,0) < 0) + return(TFSERR_MEMFAIL); + if (AppFlashErase(snum) <= 0) + return(TFSERR_MEMFAIL); + } +#else + memset((void *)tdp->start,(int)0xff,(int)(tdp->end-tdp->start)); +#endif + return(TFS_OKAY); +} + +int +tfsflasherase(int snum) +{ +#if INCLUDE_FLASH + if (tfsTrace > 2) + printf(" tfsflasherase(%d)\n",snum); + + tfsFmodCount++; + return(AppFlashErase(snum)); +#else + return(TFSERR_NOTAVAILABLE); +#endif +} + +int +tfsflashwrite(uchar *dest,uchar *src,long bytecnt) +{ +#if INCLUDE_FLASH + if (tfsTrace > 2) + printf(" tfsflashwrite(0x%lx,0x%lx,%ld)\n", + (ulong)dest,(ulong)src,bytecnt); + + if (bytecnt < 0) + return(TFSERR_BADARG); + + tfsFmodCount++; + + if (AppFlashWrite(dest,src,bytecnt) == 0) + return(TFS_OKAY); + else + return(TFSERR_FLASHFAILURE); +#else + return(TFSERR_NOTAVAILABLE); +#endif +} + +#endif /* TFS_NON_STANDARD_FLASH_INTERFACE */ + +/* tfserrmsg(): + * Return the error message string that corresponds to the incoming + * tfs error number. + */ +char * +tfserrmsg(int errno) +{ + struct tfserr *tep; + + tep = tfserrtbl; + while(tep->msg) { + if (errno == tep->err) + return(tep->msg); + tep++; + } + return("unknown tfs errno"); +} + +/* tfsmakeStale(): + * Modify the state of a file to be stale. + * Do this by clearing the TFS_NOTSTALE flag in the tfs header. + * This function is used by tfsadd() when in the process of + * updating a file that already exists in the flash. + * See comments above tfsadd() for more details on the TFS_NOTSTALE flag. + */ +static int +tfsmakeStale(TFILE *tfp) +{ + ulong flags; + + flags = TFS_FLAGS(tfp) & ~TFS_NSTALE; + return(tfsflashwrite((uchar *)&tfp->flags,(uchar *)&flags, + (long)sizeof(long))); +} + +/* tfsflagsbtoa(): + * Convert binary flags to ascii and return the string. + */ +char * +tfsflagsbtoa(long flags,char *fstr) +{ + int i; + struct tfsflg *tfp; + + if ((!flags) || (!fstr)) + return((char *)0); + + i = 0; + tfp = tfsflgtbl; + *fstr = 0; + while(tfp->sdesc) { + if ((flags & tfp->mask) == tfp->flag) + fstr[i++] = tfp->sdesc; + tfp++; + } + fstr[i] = 0; + return(fstr); +} + +/* tfsflagsatob(): + * Convert ascii flags to binary and return the long. + */ +int +tfsflagsatob(char *fstr, long *flag) +{ + struct tfsflg *tfp; + + *flag = 0; + + if (!fstr) + return(TFSERR_BADFLAG); + + while(*fstr) { + tfp = tfsflgtbl; + while(tfp->sdesc) { + if (*fstr == tfp->sdesc) { + *flag |= tfp->flag; + break; + } + tfp++; + } + if (!tfp->flag) + return(TFSERR_BADFLAG); + fstr++; + } + return(TFS_OKAY); +} + +/* hdrcrc(): + * The crc of the file header was originally calculated (in tfsadd()) + * with the header crc and next pointer nulled out; so a copy must + * be made and these two fields cleared. Also, note that the + * TFS_NSTALE and TFS_ACTIVE flags are forced to be set in the copy. + * This is done because it is possible that either of these bits may + * have been cleared due to other TFS interaction; hence, they need + * to be set prior to crc calculation. + * Note also that earlier versions of TFS deleted a file by clearing + * the entire flags field. This made it impossible to do a header crc + * check on a deleted file; deletion has been changed to simply clear + * the TFS_ACTIVE bit in the flags, so now a deleted file's header can + * can be crc tested by simply forcing the TFS_ACTIVE bit high as was + * mentioned above. + */ +ulong +tfshdrcrc(TFILE *hdr) +{ + TFILE hdrcpy; + + memcpy((char *)&hdrcpy,(char *)hdr,sizeof(TFILE)); + hdrcpy.next = 0; + hdrcpy.hdrcrc = 0; + hdrcpy.flags |= (TFS_NSTALE | TFS_ACTIVE); + return(crc32((uchar *)&hdrcpy,TFSHDRSIZ)); +} + +/* validtfshdr(): + * Return 1 if the header pointed to by the incoming header pointer is valid. + * Else return 0. The header crc is calculated based on the hdrcrc + * and next members of the structure being zero. + * Note that if the file is deleted, then just ignore the crc and return 1. + */ +int +validtfshdr(TFILE *hdr) +{ + /* A few quick checks... */ + if (!hdr || hdr->hdrsize == ERASED16) + return(0); + + if (tfshdrcrc(hdr) == hdr->hdrcrc) { + return(1); + } + else { + /* Support transition to new deletion flag method... + */ + if ((hdr->flags == 0) && tfsOldDelFlagCheckActive) + return(1); + + printf("Bad TFS hdr crc @ 0x%lx\n",(ulong)hdr); + return(0); + } +} + +/* nextfp(): + * Used as a common means of retrieving the next file header pointer. It + * does some sanity checks based on the fact that all pointers must fall + * within the TFSSTART<->TFSEND memory range and since each file is placed + * just after the previous one in linear memory space, fp->next should + * always be greater than fp. + */ +TFILE * +nextfp(TFILE *fp, TDEV *tdp) +{ + if (!tdp) + tdp = gettfsdev(fp); + + /* Make some basic in-range checks... + */ + if ((!tdp) || (fp < (TFILE *)tdp->start) || (fp > (TFILE *)tdp->end) || + (fp->next < (TFILE *)tdp->start) || (fp->next > (TFILE *)tdp->end) || + (fp->next <= fp)) { + printf("Bad TFS hdr ptr @ 0x%lx\n",(ulong)fp); + return(0); + } + return(fp->next); +} + +/* tfsflasherased(): + * Jump to the point in flash after the last file in TFS, then verify + * that all remaining flash that is dedicated to TFS is erased (0xff). + * If erased, return 1; else return 0. + */ +int +tfsflasherased(TDEV *tdp, int verbose) +{ + ulong *lp; + TFILE *tfp; + + tfp = (TFILE *)tdp->start; + while(validtfshdr(tfp)) + tfp = nextfp(tfp,tdp); + + lp = (ulong *)tfp; + while (lp < (ulong *)tdp->end) { + if (*lp != ERASED32) { + if (verbose) + printf("End of TFS on %s not erased at 0x%lx\n", + tdp->prefix,(ulong)lp); + return(0); + } +#ifdef WATCHDOG_ENABLED + if (((ulong)lp & 0x3f) == 0) + WATCHDOG_MACRO; +#endif + lp++; + } + return(1); +} + +static int +tfsftot(TDEV *tdpin) +{ + int ftot; + TFILE *tfp; + TDEV *tdp; + + ftot = 0; + for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + if (!tdpin || (tdpin == tdp)) { + tfp = (TFILE *)tdp->start; + while(validtfshdr(tfp)) { + if (TFS_FILEEXISTS(tfp)) + ftot++; + tfp = nextfp(tfp,tdp); + } + } + } + return(ftot); +} + +/* tfsmemuse(): + * Step through one (or all) TFS devices and tally up various memory usage + * totals. See definition of tfsmem structure for more details. + * If incoming tdpin pointer is NULL, then tally up for all TFS devices; + * otherwise, tally up for only the one device pointed to by tdpin. + */ +int +tfsmemuse(TDEV *tdpin, TINFO *tinfo, int verbose) +{ + TFILE *tfp; + TDEV *tdp, *dsimax; + int devtot, devidx, ftot, fmax; + char *cfgerr, varname[TFSNAMESIZE+16]; + + /* Start by clearing incoming structure... + */ + tinfo->pso = 0; + tinfo->sos = 0; + tinfo->memtot = 0; + tinfo->liveftot = 0; + tinfo->deadftot = 0; + tinfo->livedata = 0; + tinfo->deaddata = 0; + tinfo->liveovrhd = 0; + tinfo->deadovrhd = 0; + tinfo->sectortot = 0; + + if (verbose) { + printf("TFS Memory Usage...\n "); + printf(" name start end spare spsize scnt type\n"); + } + + devtot = fmax = 0; + for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) + devtot++; + + devidx = 0; + dsimax = 0; + for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + if (!tdpin || (tdpin == tdp)) { + tfp = (TFILE *)tdp->start; + + cfgerr = (char *)0; + + /* Do some sanity checks on the configuration... + */ + if ((tdp->spare >= tdp->start) && (tdp->spare <= tdp->end)) { + cfgerr = "spare within storage space"; + } + if (cfgerr) { + printf("Bad %s TFS config: %s.\n",tdp->prefix,cfgerr); + } + + /* Store TFS device info to shell variables. + */ + sprintf(varname,"TFS_PREFIX_%d", devidx); + shell_sprintf(varname,"%s",tdp->prefix); + + sprintf(varname,"TFS_START_%d", devidx); + shell_sprintf(varname,"0x%lx",tdp->start); + + sprintf(varname,"TFS_END_%d", devidx); + shell_sprintf(varname,"0x%lx",tdp->end); + + sprintf(varname,"TFS_SPARE_%d", devidx); + shell_sprintf(varname,"0x%lx",tdp->spare); + + sprintf(varname,"TFS_SPARESZ_%d", devidx); + shell_sprintf(varname,"0x%lx",tdp->sparesize); + + sprintf(varname,"TFS_SCNT_%d", devidx); + shell_sprintf(varname,"%d",tdp->sectorcount); + + sprintf(varname,"TFS_DEVINFO_%d", devidx); + shell_sprintf(varname,"0x%lx",tdp->devinfo); + + if (verbose) { + printf("%10s: 0x%08lx|0x%08lx|", + tdp->prefix,(ulong)(tdp->start),(ulong)(tdp->end)); + + if (TFS_DEVTYPE_ISRAM(tdp)) + printf(" - NA - | - NA - | NA "); + else + printf("0x%08lx|0x%06lx|%4ld",(ulong)(tdp->spare), + tdp->sparesize,tdp->sectorcount); + + printf("|0x%lx\n",(ulong)(tdp->devinfo)); + } + tinfo->memtot += ((tdp->end - tdp->start) + 1) + tdp->sparesize; + tinfo->pso += (tdp->sectorcount * 4) + 16; + tinfo->sos += tdp->sparesize; + tinfo->sectortot += tdp->sectorcount; + ftot = 0; + while(validtfshdr(tfp)) { + if (TFS_FILEEXISTS(tfp)) { + ftot++; + tinfo->liveftot++; + tinfo->livedata += TFS_SIZE(tfp); + tinfo->liveovrhd += (TFSHDRSIZ + DEFRAGHDRSIZ); + } + else { + tinfo->deadftot++; + tinfo->deaddata += TFS_SIZE(tfp); + tinfo->deadovrhd += TFSHDRSIZ; + } + tfp = nextfp(tfp,tdp); + } + +#if INCLUDE_FLASH + /* Keep track of how many files are stored, relative to the + * size of the sector used to store DSI info at defrag time... + */ + if (!TFS_DEVTYPE_ISRAM(tdp)) { + int sector_ovrhd, ssize; + + if (addrtosector((uchar *)(tdp->end),0,&ssize,0) < 0) + return(TFSERR_MEMFAIL); + sector_ovrhd = tdp->sectorcount * sizeof(struct sectorcrc); + + if ((((ftot + 1) * DEFRAGHDRSIZ) + sector_ovrhd) > ssize) + dsimax = tdp; + + fmax += (ssize - sector_ovrhd)/DEFRAGHDRSIZ; + } +#endif + } + devidx++; + } + shell_sprintf("TFS_DEVTOT","%d",devtot); + + tinfo->memused = tinfo->livedata + tinfo->liveovrhd + + tinfo->deaddata + tinfo->deadovrhd + tinfo->pso + tinfo->sos + + tinfo->sectortot * sizeof(struct sectorcrc); + tinfo->memfree = tinfo->memtot - tinfo->memused; + + /* Remaining space may not even be big enough to contain the + * file overhead, if this is the case, show a remaining space + * of zero rather than a negative number... + */ + tinfo->memfordata = + tinfo->memfree - (devtot * (TFSHDRSIZ + DEFRAGHDRSIZ)); + if (tinfo->memfordata < 0) + tinfo->memfordata = 0; + + + if (verbose) { + printf("\n Total memory: %d bytes (used=%d, avail=%d (%d for data)).\n", + tinfo->memtot,tinfo->memused,tinfo->memfree, tinfo->memfordata); + printf(" Per-device overhead: %d bytes ",tinfo->pso+tinfo->sos); + printf("(defrag-state=%d spare-sector=%d).\n",tinfo->pso,tinfo->sos); + printf(" File data space: %d bytes (live=%d, dead=%d).\n", + tinfo->livedata+tinfo->deaddata, + tinfo->livedata,tinfo->deaddata); + printf(" File overhead space: %d bytes (live=%d, dead=%d).\n", + tinfo->liveovrhd+tinfo->deadovrhd, + tinfo->liveovrhd,tinfo->deadovrhd); + printf(" Sector overhead space: %d bytes.\n", + tinfo->sectortot*sizeof(struct sectorcrc)); + printf(" File count: %d (live=%d, dead=%d).\n", + tinfo->liveftot+tinfo->deadftot,tinfo->liveftot,tinfo->deadftot); + printf(" Defrag will release %d bytes\n", + tinfo->deadovrhd+tinfo->deaddata); + printf(" Max # files storable in flash: %d\n",fmax); + if (dsimax) + printf(" Device '%s' has max Defrag-State-Info\n",dsimax->prefix); + printf("\n"); + } + return(tinfo->liveftot + tinfo->deadftot); +} + +/* tfscheck(): + * Step through each file in a particular device making a few checks... + * - First look at the header. If hdrsize is erased, it "should" indicate + * the end of the linear list of files. To be anal about it, verify that + * the entire header is erased. If it is, we truly are at the end of the + * list; otherwise, header error. + * - Second, do a crc32 on the header. + * - Third, if the file is not deleted, then do a crc32 on the data portion + * of the file (if the file is deleted, then it really doesn't matter if + * there is a crc32 error on that data). + * - Finally, if the header is not corrupted, index to the next pointer and + * continue. If the header is corrupt, see if enough information + * in the header is valid to allow us to step to the next file. Do this + * by calculating where the next pointer should be (using current pointer, + * file+header size and mod16 adjustment) and then see if that matches the + * value stored in the actual "next" pointer. If yes, go to next file; + * else break out of the loop. + * + * The purpose is to do more sophisticated file system checks than are + * done in normal TFS operations. + */ +#define TFS_CORRUPT 1 +#define HDR_CORRUPT 2 +#define DATA_CORRUPT 4 + +int +tfscheck(TDEV *tdp, int verbose) +{ + TFILE *fp, *fp1; + int tfscorrupt, filtot, err; + + /* If the incoming device pointer is null, then loop through all + * devices in TFS, recursively calling tfscheck() with each pointer... + */ + if (!tdp) { + for (tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + err = tfscheck(tdp,verbose); + if (err != TFS_OKAY) + return(err); + } + return(TFS_OKAY); + } + + if (verbose) + printf("TFS device %s check:\n",tdp->prefix); + + filtot = tfscorrupt = 0; + + fp = (TFILE *)tdp->start; + while(1) { + tfscorrupt &= ~(HDR_CORRUPT | DATA_CORRUPT); + + /* If hdrsize is ERASED16, then verify that the whole header is + * also ERASED16, if yes, we're at the end of the linear list of + * files; otherwise, we have a corrupt header. + */ + if (fp->hdrsize == ERASED16) { + int i; + ushort *sp; + + /* If this is right at the edge of the end of the TFS device, + * then break with no further checks to this header. + */ + if ((fp+1) > (TFILE *)tdp->end) + break; + + /* Make sure the entire header is erased... + */ + sp = (ushort *)fp; + for(i=0;i<TFSHDRSIZ;i+=2,sp++) { + if (*sp != ERASED16) { + if (verbose) + printf(" Corrupt hdr @ 0x%lx",(ulong)fp); + tfscorrupt = HDR_CORRUPT | TFS_CORRUPT; + break; + } + } + if (!(tfscorrupt & HDR_CORRUPT)) + break; + else + goto nextfile; + } + + /* Run a crc check on the header even if file is deleted... + */ + if (tfshdrcrc(fp) != fp->hdrcrc) { + if (verbose) + printf(" CRC error in hdr @ 0x%lx\n",(ulong)fp); + tfscorrupt = HDR_CORRUPT | TFS_CORRUPT; + goto nextfile; + } + + /* If file exists, and it's not IPMOD, run a crc check on data... + */ + if (TFS_FILEEXISTS(fp) && !(fp->flags & TFS_IPMOD)) { + filtot++; + if (verbose) + printf(" %s...",fp->name); + + if ((!(fp->flags & TFS_IPMOD)) && + (crc32((uchar *)(TFS_BASE(fp)),fp->filsize) != fp->filcrc)) { + if (verbose) + printf(" CRC error in data"); + tfscorrupt = DATA_CORRUPT | TFS_CORRUPT; + } + else { + if (verbose) + printf(" ok"); + } + } + + /* Prior to incrementing to the next file pointer, if the header + * is corrupted, attempt to salvage the next pointer... + * If the value of the next pointer matches what is calculated + * from the file size and header size, then assume it is ok + * and allow the tfscheck() loop to continue; otherwise break. + */ +nextfile: + if (tfscorrupt & HDR_CORRUPT) { + if (fp->next) { + ulong modnext; + + modnext = (ulong)((int)(fp+1) + fp->filsize); + if (modnext & 0xf) { + modnext += 16; + modnext &= ~0xf; + } + if (verbose) + printf(" (next ptr "); + if (fp->next != (TFILE *)modnext) { + if (verbose) + printf("damaged)\n"); + break; + } + else { + if (verbose) + printf("salvaged)"); + } + } + } + fp1 = nextfp(fp,tdp); + if (!fp1) { + tfscorrupt = HDR_CORRUPT | TFS_CORRUPT; + break; + } + if ((verbose) && (TFS_FILEEXISTS(fp) || tfscorrupt)) + putchar('\n'); + fp = fp1; + } + tfsflasherased(tdp,verbose); + if (tfscorrupt) + return(TFSERR_CORRUPT); + if (verbose) + printf(" PASSED\n"); + return (TFS_OKAY); +} + +void +tfsclear(TDEV *tdp) +{ + int i; + + /* Clear the fileslot[] table indicating that no files are opened. + * Only clear the slots applicable to the incoming TDEV pointer. + */ + for (i = 0; i < TFS_MAXOPEN; i++) { + ulong offset; + + offset = tfsSlots[i].offset; + if (offset != (ulong)-1) { + if ((tdp == (TDEV *)0) || + ((offset >= tdp->start) && (offset <= tdp->end))) + tfsSlots[i].offset = -1; + } + } + + /* If the incoming TDEV pointer is NULL, then we can assume a global + * clear and go ahead and cleanup everything; otherwise, we just return + * here. + */ + if (tdp != (TDEV *)0) + return; + + /* Turn off tracing. + */ + tfsTrace = 0; + + /* Init the time retrieval function pointers to their dummy values. + */ + tfsGetAtime = dummyAtime; + tfsGetLtime = dummyLtime; + + /* Default to using standard docommand() within scripts. + */ + tfsDocommand = docommand; + + /* Start off with a buffer for 16 files. This is probably more than + * will be used, so it avoids reallocations in tfsreorder(). + * + * Note that this function may be called as a result of the monitor + * doing an application exit. In that case, the heap is not + * re-initialized; hence, tfsAlist may already be allocated. + * If it is, then just leave it alone... + */ + if (tfsAlist == 0) { + tfsAlistSize = 16; + tfsAlist = (TFILE **)malloc((tfsAlistSize+1) * sizeof(TFILE **)); + if (!tfsAlist) { + printf("tfsclear(): tfsAlist allocation failed\n"); + tfsAlistSize = 0; + } + } +} + +/* tfsqstalecheck(): + * This originally was just part of the tfsstalecheck() function. + * As of Nov2009 a bug was reported where TFS *could* end up with + * two files with the same name. The only case that I was able to + * find that allowed this to occur is if tfsadd() was aborted just + * after a new file is put in flash, and prior to the old one + * (already marked stale) is deleted. If that occurs and uMon + * isn't restarted (which is what would call tfsstalecheck()), then + * this "duplicate file" case would be created if yet another version + * of the file was put into TFS. + * Anyway, calling tfsqstalecheck() at the top of tfsadd() prevents + * this confusion by making sure that the stale file is removed + * even if uMon doesn't reset. + */ +static TFILE * +tfsqstalecheck(void) +{ + TDEV *tdp; + TFILE *tfp, *tfpa; + + tfpa = (TFILE *)0; + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + tfp = (TFILE *)tdp->start; + tfpa = (TFILE *)0; + while(validtfshdr(tfp)) { + if (TFS_FILEEXISTS(tfp)) { + if (tfpa) { + if (!strcmp(TFS_NAME(tfp),TFS_NAME(tfpa))) { + _tfsunlink(TFS_NAME(tfpa)); + return((TFILE *)0); + } + } + else if (TFS_STALE(tfp)) { + tfpa = tfp; + } + } + tfp = nextfp(tfp,tdp); + } + if (tfpa) + break; + } + return(tfpa); +} + +/* tfsstalecheck(): + * Called at startup to clean up any file that may be in STALE mode. + * A file is stale if it was in the process of being modified + * and a power hit occurred. Refer to notes in tfsadd() for details. + * There are a few cases to be covered here... + * 1. there is no stale file; so there is nothing to do. + * 2. there is a stale file, but no other file with the same name... + * In this case, the stale file must be copied to another file (with the + * TFS_NSTALE flag set) and the stale file is deleted. + * 3. there is stale file and another file with the same name... + * In this case, the stale file is simply deleted because the other file + * with the same name is newer. + */ +static void +tfsstalecheck(void) +{ + int err; + ulong flags; + TFILE *tfpa; + char buf[16]; + + tfpa = tfsqstalecheck(); + if (tfpa) { + char name[TFSNAMESIZE+1]; + + strcpy(name,TFS_NAME(tfpa)); + printf("TFS stale fixup (%s)...\n",name); + if (pollConsole("ok?")) { + printf("aborted\n"); + return; + } + flags = TFS_FLAGS(tfpa) | TFS_NSTALE; + err = tfsadd(TFS_NAME(tfpa),TFS_INFO(tfpa),tfsflagsbtoa(flags,buf), + (uchar *)(TFS_BASE(tfpa)),TFS_SIZE(tfpa)); + + /* If rewrite was successful, then remove the stale one; + * else, leave it there and report the error. + */ + if (err == TFS_OKAY) { + _tfsunlink(TFS_NAME(tfpa)); + } + else { + printf("TFS stalecheck(%s) error: %s\n",name,tfserrmsg(err)); + } + } +} + +/* tfsdevtblinit(): + * Transfer the information in tfsdevtbl (in tfsdev.h) to tfsDeviceTbl[]. + * In most cases, this will be a simple copy. If the device flag is set + * to indicate that the initalization is dynamic, then use the flash + * ops to retrieve the information from the specified bank. + * + * For dynamic configuration, the "start" member of the tfsdev structure + * must be set in tfsdev.h and the "devinfo & TFS_DEVINFO_BANKMASK" area + * must contain the number of the last flash bank that is to be part of + * the TFS device. Typically this value is the same bank number as the + * starting bank, but it could span across multiple contiguous banks + * if the hardware is set up that way. + * + * To support the use of top-boot devices, plus the TFS requirement that + * the SPARE sector be at-least as large as any other sector in the device, + * this code will automatically step down the sector list until it finds + * the first large sector below all the small ones usually at the top of + * a top-boot device. The call to lastlargesector() takes care of this. + * + * NOTE: + * This dynamic configuration assumes that the end of the TFS space is + * just below the beginning of the spare space. + * + */ +void +tfsdevtblinit(void) +{ + int i; +#if INCLUDE_FLASH + int startsector, endsector, bank; +#endif + TDEV *tDp, *tdp; + + for(i=0;i<TFSDEVTOT;i++) { + if ((alt_tfsdevtbl != (struct tfsdev *)0xffffffff) && + (alt_tfsdevtbl[i].prefix != (char *)0xffffffff)) { + tdp = &alt_tfsdevtbl[i]; + + /* do some sanity checking on the alternate table: + */ + if ((tdp->start >= tdp->end) || + (tdp->sparesize > (1024*1024)) || + (tdp->sectorcount > (1024*16))) { + printf("TFS altdevtbl[%d] appears corrupt\n",i); + tdp = &tfsdevtbl[i]; + } + } + else + tdp = &tfsdevtbl[i]; + + tDp = &tfsDeviceTbl[i]; + memcpy((char *)tDp,(char *)tdp,sizeof(struct tfsdev)); + if (i == TFSDEVTOT-1) + break; + +#if INCLUDE_FLASH + if (tdp->devinfo & TFS_DEVINFO_DYNAMIC) { + bank = tDp->devinfo & TFS_DEVINFO_BANKMASK; + + /* The spare sector may not be the last sector in the device... + * device. Especially if the device is TopBoot type. + */ + if (lastlargesector(bank, (uchar *)tDp->start, + tDp->sectorcount+1, &endsector, + (int *)&tDp->sparesize,(uchar **)&tDp->spare) == -1) + break; + + tDp->end = tDp->spare - 1; + if (addrtosector((uchar *)tDp->start,&startsector,0,0) == -1) + break; + tDp->sectorcount = endsector - startsector; + + /* + printf( "tfsdevtblinit - dynamic TFS allocation\n" + " prefix........ %s\n" + " start......... 0x%08X\n" + " end........... 0x%08X\n" + " spare......... 0x%08X\n" + " sparesize..... 0x%08X\n" + " sectorcount... %d\n", + tDp->prefix, tDp->start, tDp->end, tDp->spare, + tDp->sparesize, tDp->sectorcount); + */ + } +#endif + } +} + +/* tfsstartup(): + * Called at system startup to get things properly initialized. + */ +void +tfsstartup() +{ + TDEV *tdp; + + if (!tfsInitialized) + tfsdevtblinit(); + + tfsclear((TDEV *)0); + + /* No need to walk through the entire TFS init if it has already + * been done... + */ + if (tfsInitialized) + return; + + /* Step through the table looking for TFS devices that may need to + * be automatically initialized at startup. There are two cases: + * - if the devtype is TFS_DEVTYPE_RAM. + * - if the devtype is TFS_DEVTYPE_NVRAM with AUTOINIT set. + */ + for(tdp = tfsDeviceTbl;tdp->prefix != 0;tdp++) { + if (((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_RAM) || + (((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_NVRAM) && + (tdp->devinfo & TFS_DEVINFO_AUTOINIT))) { + _tfsinit(tdp); + } + } + + tfsfixup(3,0); + tfsstalecheck(); + tfsInitialized = 1; +} + +/* tfsexec: Treat the file as machine code that is COFF or ELF. */ + +static int +tfsexec(TFILE *fp,int verbose) +{ + int err, (*entry)(void); + long address; + + err = tfsloadebin(fp,verbose,&address,0,0); + if (err != TFS_OKAY) + return(err); + + entry = (int(*)(void))address; + entry(); /* Call entrypoint (may not return). */ + return(TFS_OKAY); +} + +/* struct tfsran: + Used by tfsrunboot only. No need to put this in tfs.h. + */ +struct tfsran { + char name[TFSNAMESIZE+1]; +}; + +/* tfsrunboot(): + * This function is called at monitor startup. It scans the list of + * files built by tfsreorder() and executes each file in the list that has + * the BRUN flag set. As each file is run its name is added to the + * ranlist[] table. + * + * After each file is run, there is a check made to see if the flash has + * been modified. If yes, then tfsreorder() is run again and we start + * over at the top of the list of files organized by tfsreorder(). As + * we step through the tfsAlist[] array, if the file has a BRUN flag set + * but it is already in the ranlist[] table, it is not run again. + * + * This scheme allows a file in the initial list of BRUN files to modify + * the file list without confusing the list of files that are to be run. + * Files (even new BRUN files) can be added to the list by some other BRUN + * file, and these new files will be run. + */ +int +tfsrunboot(void) +{ + static struct tfsran *ranlist; + char *argv[2]; + int rancnt, aidx, ridx, err, fmodcnt; + +#if TFS_RUN_DISABLE + return(TFSERR_NOTAVAILABLE); +#endif + + if (!tfsInitialized) { + printf("TFS not initialized, tfsrunboot aborting.\n"); + return(0); + } + + /* The argv[] array is used by tfsrun(); argv[0] is name of file to be + * executed, argv[1] must be nulled to indicate no command line args + * passed to the BRUN file/script. + */ + argv[1] = (char *)0; + + /* Keep a local copy of tfsFmodCount so that we can determine if flash + * was modified by one of the BRUN files executed. + */ + fmodcnt = tfsFmodCount; + + /* Create list of file pointers (tfsAlist[]) in alphabetical order + * based on name... + */ + if ((err = tfsreorder()) < 0) { + printf("tfsrunboot() reorder1: %s\n",tfserrmsg(err)); + return(-1); + } + + /* Clear the ranlist pointer. This pointer is the base address of a + * list of file names that have been run. + */ + rancnt = 0; + ranlist = (struct tfsran *)0; + +restartloop: + for (aidx=0;tfsAlist[aidx];aidx++) { + char fname[TFSNAMESIZE+1]; + int alreadyran; + TFILE *fp; + struct tfsran *rp; + + fp = tfsAlist[aidx]; + strcpy(fname,TFS_NAME(fp)); + + /* If the file has no BRUN flag set, just continue. If a BRUN flag + * is set, then see if the file has already been run. If yes, then + * just continue; else run the file. + */ + alreadyran = 0; + if (fp->flags & (TFS_BRUN | TFS_QRYBRUN)) { + for(ridx=0;ridx<rancnt;ridx++) { + if (!strcmp(ranlist[ridx].name,fname)) { + alreadyran = 1; + break; + } + } + } + else + continue; /* No BRUN flag set. */ + + if (alreadyran) { /* BRUN flag set, but file has already */ + continue; /* been run. */ + } + + err = TFS_OKAY; + argv[0] = fname; + + /* At this point we know the file is a BRUN type, so just see if + * the query should precede the run... + */ + if (fp->flags & TFS_QRYBRUN) { + int pollval; + char query[TFSNAMESIZE+8]; + + sprintf(query,"%s?",fname); + pollval = pollConsole(query); +#ifdef TFS_AUTOBOOT_CANCEL_CHAR + if (pollval == (int)TFS_AUTOBOOT_CANCEL_CHAR) + continue; +#else + if (pollval) + continue; +#endif + } + /* Increase the size of the ranlist[] table and add the file that + * is about to be run to that list... + */ + rancnt++; + rp = (struct tfsran*)realloc((char *)ranlist, + rancnt*sizeof(struct tfsran)); + + if (!rp) { + if (ranlist) + free((char *)ranlist); + printf("tfsrunboot() runlist realloc failure\n"); + return(-1); + } + + ranlist = rp; + strcpy(ranlist[rancnt-1].name,fname); + + /* Run the executable... + */ + if (fp->flags & TFS_BRUN) { + err = tfsrun_abortableautoboot(argv,0); + } + else { + pre_tfsautoboot_hook(); + err = tfsrun(argv,0); + } + + if (err != TFS_OKAY) + printf("%s: %s\n",fname,tfserrmsg(err)); + + /* If flash has been modified, then we must re-run tfsreorder() and + * start over... + */ + if (fmodcnt != tfsFmodCount) { + if ((err = tfsreorder()) < 0) { + printf("tfsrunboot() reorder2: %s\n",tfserrmsg(err)); + return(err); + } + fmodcnt = tfsFmodCount; + goto restartloop; + } + } + if (ranlist) + free((char *)ranlist); + return(rancnt); +} + +/* tfsreorder(): + * Populate the tfsAlist[] array with the list of currently active file + * pointers, but put in alphabetical (lexicographical using strcmp()) order + * based on the filename. + * Note that after each file addition/deletion, this must be re-run. + */ +int +tfsreorder(void) +{ + TFILE *fp; + TDEV *tdp; + int i, j, tot; + + /* Determine how many valid files exist, and create tfsAlist array: + */ + tot = 0; + + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + fp = (TFILE *)tdp->start; + while(validtfshdr(fp)) { + if (TFS_FILEEXISTS(fp)) + tot++; + fp = nextfp(fp,tdp); + } + } + + /* If tfsAlist already exists, and is already big enough, then + * don't do any allocation; otherwise, create the array with one extra + * slot for a NULL pointer used elsewhere as an end-of-list indicator. + */ + if (tot > tfsAlistSize) { + tfsAlist = (TFILE **)realloc((char *)tfsAlist, + (tot+1) * sizeof(TFILE **)); + if (!tfsAlist) { + tfsAlistSize = 0; + return(TFSERR_MEMFAIL); + } + tfsAlistSize = tot; + } + + /* Clear the entire table (plus the extra one at the end): + */ + for(i=0;i<=tot;i++) + tfsAlist[i] = (TFILE *)0; + + /* Populate tfsAlist[] with a pointer to each active file + * in flash as they exist in memory... + */ + i = 0; + + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + fp = (TFILE *)tdp->start; + while(validtfshdr(fp)) { + if (TFS_FILEEXISTS(fp)) { + tfsAlist[i++] = fp; + } + fp = nextfp(fp,tdp); + } + } + + /* Now run a bubble sort on that list based on the lexicographical + * ordering returned by strcmp... + */ + for(i=1;i<tot;++i) { + for(j=tot-1;j>=i;--j) { + if (strcmp(TFS_NAME(tfsAlist[j-1]),TFS_NAME(tfsAlist[j])) > 0) { + fp = tfsAlist[j-1]; + tfsAlist[j-1] = tfsAlist[j]; + tfsAlist[j] = fp; + } + } + } + return(tot); +} + +/* tfsheadroom(): + * Based on the current offset into the file specified by the incoming + * descriptor, return the gap between the current offset and the end + * of the file. + */ +static long +tfsheadroom(int fd) +{ + struct tfsdat *tdat; + + if ((fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADARG); + + tdat = &tfsSlots[fd]; + if (tdat->flagmode & TFS_RDONLY) + return(tdat->hdr.filsize - tdat->offset); + else + return(tdat->hwp - tdat->offset); +} + +/* tfstell(): + * Return the offset into the file that is specified by the incoming + * descriptor. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +long +tfstell(int fd) +{ + if ((fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADARG); + return(tfsSlots[fd].offset); +} + +/* tfscompare(): + * Compare the content of the file specified by tfp with the content pointed + * to by the remaining arguments. If identical, return 0; else return -1. + */ +static int +tfscompare(TFILE *tfp,char *name, char *info, char *flags, uchar *src, int size) +{ + long bflags; + + /* Compare size, name, info field, flags and data: + */ + + /* Size... + */ + if (TFS_SIZE(tfp) != size) + return(-1); + + /* Name... + */ + if (strcmp(name,TFS_NAME(tfp))) + return(-1); + + /* Info field... + */ + if (info) { + if (strcmp(info,TFS_INFO(tfp))) + return(-1); + } + else { + if (TFS_INFO(tfp)[0] != 0) + return(-1); + } + + /* Flags... + */ + if (tfsflagsatob(flags, &bflags) == -1) + return(-1); + if (bflags != (TFS_FLAGS(tfp) & 0x7ff)) + return(-1); + + /* Data... + */ + if (memcmp(TFS_BASE(tfp),(char *)src,size)) + return(-1); + + return(0); +} + +/* tfsinit(): + * Clear out all the flash that is dedicated to the file system. + * This removes all currently stored files and erases the flash. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +_tfsinit(TDEV *tdpin) +{ + int ret; + TDEV *tdp; + + /* Step through the table of TFS devices and erase each sector... + */ + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + if (!tdpin || (tdp == tdpin)) { + ret = tfsflasheraseall(tdp); + if (ret != TFS_OKAY) + return(ret); + } + } + return(TFS_OKAY); +} + +int +tfsinit(void) +{ + if (tfsTrace > 0) + printf("tfsinit()\n"); + return(_tfsinit(0)); +} + + +/* tfsFtot(): + * Return the number of files in a device, or all devices if tdpin is null. + */ +int +tfsFtot(TDEV *tdpin) +{ + int ftot; + TFILE *fp; + TDEV *tdp; + + ftot = 0; + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + if (!tdpin || (tdpin == tdp)) { + fp = (TFILE *)tdp->start; + while (fp->hdrsize != ERASED16) { + ftot++; + fp = nextfp(fp,tdp); + } + } + } + return(ftot); +} + +/* tfsFileIsOpened(): + * Return 1 if file is currently opened; else 0. + */ +int +tfsFileIsOpened(char *name) +{ + int i; + struct tfsdat *slot; + + slot = tfsSlots; + for (i=0;i<TFS_MAXOPEN;i++,slot++) { + if ((slot->offset >= 0) && !strcmp(slot->hdr.name,name)) + return(1); + } + return(0); +} + +/* tfsunopen(): + * If the incoming file descriptor is valid, mark that file as no-longer + * opened and return TFS_OKAY; else return TFSERR_BADARG. + * descriptor. + */ +static long +tfsunopen(int fd) +{ + if ((fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADARG); + if (tfsSlots[fd].offset == -1) + return(TFSERR_BADARG); + tfsSlots[fd].offset = -1; + return(TFS_OKAY); +} + +/* tfsctrl(): + * Provides an ioctl-like interface to tfs. + * Requests supported: + * TFS_ERRMSG: Return error message (char *) corresponding to + * the incoming error number (arg1). + * TFS_MEMUSE: Return the total amount of memory currently in use by + * TFS. + * TFS_MEMAVAIL: Return the amount of memory currently avaialable for + * use in TFS. + * TFS_MEMDEAD: Return the amount of memory currently in use by + * dead files in TFS. + * TFS_DEFRAG: Mechanism for the application to issue + * a defragmentation request. + * Arg1: if 1, then reset after defrag is complete. + * Arg2: verbosity level. + * TFS_TELL: Return the offset into the file specified by the + * incoming file descriptor (arg1). + * TFS_FATOB: Return the binary equivalent of the TFS flags string + * pointed to by arg1. + * TFS_FBTOA: Return the string equivalent of the TFS flags (long) + * in arg1, destination buffer in arg2. + * TFS_UNOPEN: In TFS, a the data is not actually written to FLASH + * until the tfsclose() function is called. This argument + * to tfsctrl() allows a file to be opened and possibly + * written to, then unopened without actually modifying + * the FLASH. The value of arg1 file descriptor to + * apply the "unopen" to. + * TFS_TIMEFUNCS: This ctrl call is used to tell TFS what function + * to call for time information... + * Arg1 is a pointer to: + * (long)getLtime(void) + * - Get Long Time... + * Returns a long representation of time. + * Arg2 is a pointer to: + * (char *)getAtime(long tval,char *buf). + * - Get Ascii Time... + * If tval is zero, the buf is loaded with a string + * representing the current time; + * If tval is non-zero, then buf is loaded with a + * string conversion of the value of tval. + * Note that since it is up to these functions to + * make the conversion between binary version of time + * and ascii version, we don't define the exact meaning + * of the value returne by getBtime(). + * TFS_DOCOMMAND: Allows the application to redefine the function + * that is called to process each line of a script. + * This is useful if the application has its own + * command interpreter, but wants to use the scripting + * facilities of the monitor. + * Arg1 is a pointer to the docommand function to be + * used instead of the standard; + * Arg2 is a pointer to a location into which the current + * docommand function pointer can be stored. + * If arg1 is 0, load standard docommand; + * if arg2 is 0, don't load old value. + * TFS_INITDEV: Allows the application to initialize one of TFS's + * devices. Arg1 is a pointer to the device name prefix. + * TFS_DEFRAGDEV: Allows the application to defrag one of TFS's + * devices. Arg1 is a pointer to the device name prefix. + * TFS_CHECKDEV: Allows the application to check one of TFS's + * devices. Arg1 is a pointer to the device name prefix. + * TFS_RAMDEV: Allows the application to create (or remove) a + * special temporary TFS device in RAM. + * + * + * MONLIB NOTICE: this function is accessible through monlib.c. + */ + +long +tfsctrl(int rqst,long arg1,long arg2) +{ + long retval, flag; + TDEV *tdp; + TINFO tinfo; + TRAMDEV *trdp; + + if (tfsTrace > 0) + printf("tfsctrl(%d,0x%lx,0x%lx)\n",rqst,arg1,arg2); + + switch(rqst) { + case TFS_ERRMSG: + retval = (long)tfserrmsg(arg1); + break; + case TFS_MEMUSE: + tfsmemuse(0,&tinfo,0); + retval = tinfo.memused; + break; + case TFS_MEMAVAIL: + tfsmemuse(0,&tinfo,0); + retval = tinfo.memfordata; + break; + case TFS_MEMDEAD: + tfsmemuse(0,&tinfo,0); + retval = tinfo.deadovrhd+tinfo.deaddata; + break; + case TFS_INITDEV: + tdp = gettfsdev_fromprefix((char *)arg1,0); + if (!tdp) + retval = TFSERR_BADARG; + else + retval = _tfsinit(tdp); + break; + case TFS_CHECKDEV: + tdp = 0; + if (arg1 != 0) + tdp = gettfsdev_fromprefix((char *)arg1,0); + retval = tfscheck(tdp,0); + break; + case TFS_DEFRAGDEV: + tdp = gettfsdev_fromprefix((char *)arg1,0); + if (!tdp) + retval = TFSERR_BADARG; + else + retval = tfsclean(tdp,0); + break; + case TFS_DEFRAG: + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) + tfsclean(tdp,(int)arg1); + retval = 0; + break; + case TFS_FCOUNT: + if (arg1) { + tdp = gettfsdev_fromprefix((char *)arg1,0); + if (!tdp) + retval = TFSERR_BADARG; + else + retval = tfsftot(tdp); + } + else { + retval = tfsftot(0); + } + break; + case TFS_DEFRAGON: + retval = tfsclean_on(); + break; + case TFS_DEFRAGOFF: + retval = tfsclean_off(); + break; + case TFS_UNOPEN: + retval = tfsunopen((int)arg1); + break; + case TFS_FATOB: + retval = tfsflagsatob((char *)arg1,&flag); + if (retval == TFS_OKAY) + retval = flag; + break; + case TFS_FBTOA: + retval = (long)tfsflagsbtoa(arg1,(char *)arg2); + if (retval == 0) + retval = TFSERR_BADARG; + break; + case TFS_HEADROOM: + retval = tfsheadroom(arg1); + break; + case TFS_RAMDEV: + trdp = (TRAMDEV *)arg1; + retval = tfsramdevice(trdp->name,trdp->base,trdp->size); + break; + case TFS_TELL: + retval = tfstell(arg1); + break; + case TFS_TIMEFUNCS: + tfsGetLtime = (long(*)(void))arg1; + tfsGetAtime = (char *(*)(long,char *,int))arg2; + retval = TFS_OKAY; + break; + case TFS_DOCOMMAND: + if (arg2) + *(long *)arg2 = (long)tfsDocommand; + if (arg1) + tfsDocommand = (int(*)(char *,int))arg1; + else + tfsDocommand = docommand; + retval = TFS_OKAY; + break; + default: + retval = TFSERR_BADARG; + break; + } + return(retval); +} + +/* tfsNameToDevice(): + * Given the filename, return the device pointer associated with + * that filename. The device used depends on the prefix of + * the incoming file name. If the incoming prefix doesn't match + * any of the devices in the table, then return a pointer to the + * first device in the table (assumed to be the default). + */ +TDEV * +tfsNameToDevice(char *name) +{ + TDEV *tdp; + + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + if (!strncmp(name,tdp->prefix,strlen(tdp->prefix))) + break; + } + if (tdp->start == TFSEOT) + tdp = tfsDeviceTbl; + + return(tdp); +} + +/* tfsramdevice(): + * Create (or remove) a temporary (RAM-based) TFS device.. + * This function is callable from both the API and the CLI. + * The TFS device table is established with one extra slot. + * The purpose of that slot is to allow the user to establish + * a temporary, ram-based TFS device. This function supports + * that capability. + */ +int +tfsramdevice(char *name,long base,long size) +{ + TFILE *fp; + TDEV *tdp, *ramdev; + char tmpname[TFSNAMESIZE+1]; + static char devname[TFSNAMESIZE+1]; + + ramdev = (TDEV *)0; + snprintf(tmpname,TFSNAMESIZE,"//%s/",name); + + if (tfsTrace > 0) + printf("tfsramdevice(%s,0x%lx,%ld)\n",name,base,size); + + /* Scan through the current list of files and make sure that + * the name being requested is not the name of a file already + * in TFS... Note that the incoming name can't form even the + * same prefix as any file currently in TFS. + */ + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + fp = (TFILE *)tdp->start; + while(validtfshdr(fp)) { + if ((TFS_FILEEXISTS(fp)) && + (strncmp(tmpname,fp->name,strlen(tmpname)) == 0)) + return(TFSERR_FILEEXISTS); + fp = nextfp(fp,tdp); + } + } + + /* Scan through the device table to find the slot that can + * be used by the "ramdev" device... + */ + tdp = tfsDeviceTbl; + while(tdp->start != TFSEOT) { + if ((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_RAM) + ramdev = tdp; + if (strcmp(tdp->prefix,tmpname) == 0) { + if (size != 0) { + return(TFSERR_FILEEXISTS); + } + else { + if (ramdev != tdp) + return(TFSERR_FILEEXISTS); + } + } + tdp++; + } + + if (ramdev) { + if (size == 0) { + if (strcmp(tmpname,ramdev->prefix) != 0) + return(TFSERR_NOFILE); + + memset((char *)ramdev->start,0,ramdev->end - ramdev->start); + ramdev->prefix = 0; + ramdev->start = 0; + ramdev->devinfo = 0; + ramdev->end = 0; + ramdev->start = TFSEOT; + } + else + return(TFSERR_FILEEXISTS); + } + else { + /* If size is zero, just do nothing and return OK... + */ + if (size == 0) + return(TFS_OKAY); + + /* Minimum size of a TFS partition is 1024 bytes... + */ + if (size < 1024) + return(TFSERR_TOOSMALL); + + strcpy(devname,tmpname); + tdp->prefix = devname; + tdp->start = base; + tdp->sparesize = 0; + tdp->sectorcount = 0; + tdp->devinfo = TFS_DEVTYPE_RAM; + tdp->end = tdp->start + size - 1; + tdp->spare = 0; + memset((char *)tdp->start,0xff,size); + tdp++; + tdp->start = TFSEOT; + } + return(TFS_OKAY); +} + +/* tfsadd(): + * Add a file to the current list. + * If the file already exists AND everything is identical between the + * old and the new (flags, info and data), then return and do nothing; + * else remove the old file prior to adding the new one. + * + * Note: + * At the point when tfsadd is called for a file that currently exists, + * the old file must be removed and a new one is put in its place. This + * opens up the possibility of losing the file if a power-hit or reset was + * to occur between the point at which the old file was removed and the new + * one was put in its place. To overcome this problem, TFS files have a + * flag called TFS_NSTALE. It is a bit that is normally 1, but cleared + * if it becomes stale (hence the name TFS_NSTALE). A file is + * in this mode only for a short time... the time it takes to write the + * new file that replaces the file that was made stale. + * Now, if a reset occurs after the file is stale, depending on + * whether or not the new file was written, it will either be removed or + * used to recreate the original file because the write of the new file + * was chopped off by the power hit. Refer to the function tfsstalecheck() + * for details on the recovery after a reset or powerhit. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfsadd(char *name, char *info, char *flags, uchar *src, int size) +{ + TDEV *tdp; + TFILE *fp, tf, *sfp; + long bflags; + ulong endoftfsflash, nextfileaddr, thisfileaddr; + ulong crc_pass1, crc_pass2; + int ftot, cleanupcount, err, stale, rc; + + if (!info) info = ""; + if (!flags) flags = ""; + + if (tfsTrace > 0) + printf("tfsadd(%s,%s,%s,0x%lx,%d)\n", name,info,flags,(ulong)src,size); + + /* Check for valid size and name: + */ + if ((size < 0) || (!name) || (*name == 0)) + return(TFSERR_BADARG); + + /* If name or info field length is too long, abort now... + */ + if ((strlen(name) > TFSNAMESIZE) || + ((info) && (strlen(info) > TFSINFOSIZE))) + return(TFSERR_NAMETOOBIG); + + /* The incoming filename cannot match any of the existing + * TFS device names... + */ + tdp = tfsDeviceTbl; + while(tdp->start != TFSEOT) { + if (strcmp(tdp->prefix,name) == 0) + return(TFSERR_FILEEXISTS); + tdp++; + } + + /* If the file is currently opened, then don't allow the add... + */ + if (tfsFileIsOpened(name)) + return(TFSERR_FILEINUSE); + + /* If incoming flags are illegal, abort now... + */ + if (*flags == 0) { + bflags = 0; + } + else { + err = tfsflagsatob(flags,&bflags); + if (err != TFS_OKAY) + return(err); + + /* If we're adding a link, then the size better be zero... + */ + if ((bflags & TFS_SYMLINK) && (size != 0)) + return(TFSERR_LINKERROR); + } + + /* Make sure that there isn't a stale file and a normal file + * of the same name already in TFS... + */ + tfsqstalecheck(); + + /* If size is zero, but the request is not a link, then + * error... + */ + if ((size == 0) && ((bflags & TFS_SYMLINK) != TFS_SYMLINK)) + return(TFSERR_BADARG); + + stale = 0; + cleanupcount = 0; + + /* Take snapshot of source crc. Note that we only run the CRC + * if the IPMOD flag is not set. If this flag is set, then the + * CRC is invalid... + */ + if (!(bflags & TFS_IPMOD)) + crc_pass1 = crc32(src, size); + else + crc_pass1 = 0; + + /* Establish the device that is to be used for the incoming file + * addition request... + */ + tdp = tfsNameToDevice(name); + +#ifndef TFS_DISABLE_AUTODEFRAG +tryagain: +#endif + fp = (TFILE *)tdp->start; + + /* Find end of current storage: */ + ftot = 0; + while (fp) { + if (fp->hdrsize == ERASED16) + break; + if (TFS_FILEEXISTS(fp)) { + ftot++; + if (!strcmp(TFS_NAME(fp),name)) { + if (!(TFS_STALE(fp))) { + /* If destination file exists, but we do not meet the + * user level requirements, return error now. + */ + if (TFS_USRLVL(fp) > getUsrLvl()) + return(TFSERR_USERDENIED); + + /* If file of the same name exists AND it is identical to + * the new file to be added, then return TFS_OKAY and be + * done; otherwise, remove the old one and continue. + * Two exceptions to this: + * 1. If the current file is stale, then we are here + * because of a stale-file fixup at system startup. + * 2. If the src file is in-place-modify then source + * data is undefined. + */ + if (!(bflags & TFS_IPMOD) && + (!tfscompare(fp,name,info,flags,src,size))) { + return(TFS_OKAY); + } + +#ifdef TFS_DISABLE_MAKE_BEFORE_BREAK + err = _tfsunlink(name); + if (err != TFS_OKAY) + printf("%s: %s\n",name,tfserrmsg(err)); +#else + /* If a file of the same name exists but is different + * than the new file, set a flag to indicate that the + * file should be marked stale just prior to + * adding the new file. + */ + stale = 1; +#endif + } + } + } + fp = nextfp(fp,tdp); + } + if (!fp) /* If fp is 0, then nextfp() (above) detected corruption. */ + return(TFSERR_CORRUPT); + + /* Calculate location of next file (on mod16 address). This will be + * initially used to see if we have enough space left in flash to store + * the current request; then, if yes, it will become part of the new + * file's header. + */ + thisfileaddr = (ulong)(fp+1); + nextfileaddr = thisfileaddr + size; + if (nextfileaddr & 0xf) + nextfileaddr = (nextfileaddr | 0xf) + 1; + + /* Make sure that the space is available for writing to flash... + * Remember that the end of useable flash space must take into + * account the fact that some space must be left over for the + * defragmentation state tables. Also, the total space needed for + * state tables cannot exceed the size of the sector that will contain + * those tables. + */ + if (TFS_DEVTYPE_ISRAM(tdp)) { + endoftfsflash = tdp->end; + } + else { +#if INCLUDE_FLASH + int ssize; + ulong state_table_overhead; + + /* The state table overhead cannot exceed one additional + * sector's space, so we need to check for that... + */ + state_table_overhead = ((ftot+1) * DEFRAGHDRSIZ) + + (tdp->sectorcount * sizeof(struct sectorcrc)); + + if (addrtosector((uchar *)(tdp->end),0,&ssize,0) < 0) + return(TFSERR_MEMFAIL); + + if (state_table_overhead >= (ulong)ssize) + return(TFSERR_DSIMAX); + + endoftfsflash = (tdp->end + 1) - state_table_overhead; +#else + return(TFSERR_NOTAVAILABLE); +#endif + } + + if ((nextfileaddr >= endoftfsflash) || + (nextfileaddr < thisfileaddr) || + (!flasherased((uchar *)fp,(uchar *)fp + (size+TFSHDRSIZ)))) { +#ifndef TFS_DISABLE_AUTODEFRAG + if (!cleanupcount) { + err = tfsclean(tdp,0); + if (err != TFS_OKAY) { + printf("tfsadd autoclean failed: %s\n", + (char *)tfsctrl(TFS_ERRMSG,err,0)); + return(err); + } + cleanupcount++; + goto tryagain; + } + else +#endif + return(TFSERR_FLASHFULL); + } + + memset((char *)&tf,0,TFSHDRSIZ); + + /* Do another crc on the source data. If crc_pass1 != crc_pass2 then + * somehow the source is changing. This is typically caused by the fact + * that the source address is within TFS space that was automatically + * defragmented above. There is no need to check source data if the + * source is in-place-modifiable. + */ + if (!(bflags & TFS_IPMOD)) { + crc_pass2 = crc32(src,size); + if (crc_pass1 != crc_pass2) + return(TFSERR_FLAKEYSOURCE); + } + else + crc_pass2 = ERASED32; + + /* Now that we have determined that we have enough space to do the + * copy, if the "stale" flag was set (indicating that there is already + * a file in TFS with the same name as the incoming file), we must now + * mark the file stale... + */ + if (stale) { + sfp = (TFILE *)tdp->start; + while (sfp) { + if (sfp->hdrsize == ERASED16) + break; + if (TFS_FILEEXISTS(sfp)) { + if (!strcmp(TFS_NAME(sfp),name)) { + if (TFS_DEVTYPE_ISRAM(tdp)) { + TFS_FLAGS(sfp) &= ~TFS_NSTALE; + } + else { + if ((err = tfsmakeStale(sfp)) != TFS_OKAY) + return(err); + } + break; + } + } + sfp = nextfp(sfp,tdp); + } + if (!sfp) + return(TFSERR_CORRUPT); + } + + /* Copy name and info data to header. + */ + strcpy(tf.name, name); + strcpy(tf.info, info); + tf.hdrsize = TFSHDRSIZ; + tf.hdrvrsn = TFSHDRVERSION; + tf.filsize = size; + tf.flags = bflags; + tf.flags |= (TFS_ACTIVE | TFS_NSTALE); + tf.filcrc = crc_pass2; + tf.modtime = tfsGetLtime(); +#if TFS_RESERVED + { + int rsvd; + for(rsvd=0;rsvd<TFS_RESERVED;rsvd++) + tf.rsvd[rsvd] = 0xffffffff; + } +#endif + tf.next = 0; + tf.hdrcrc = 0; + tf.hdrcrc = crc32((uchar *)&tf,TFSHDRSIZ); + tf.next = (TFILE *)nextfileaddr; + + /* Now copy the file and header to flash. + * Note1: the header is copied AFTER the file has been + * successfully copied. If the header was written successfully, + * then the data write failed, the header would be incorrectly + * pointing to an invalid file. To avoid this, simply write the + * data first. + * Note2: if the file is in-place-modifiable, then there is no + * file data to be written to the flash. It will be left as all FFs + * so that the flash can be modified by tfsipmod() later. + */ + + /* Write the file to flash if not TFS_IPMOD: + */ + if (!(tf.flags & TFS_IPMOD)) { + if (TFS_DEVTYPE_ISRAM(tdp)) + memcpy((char *)(fp+1),(char *)src,size); + else { + rc = tfsflashwrite((uchar *)(fp+1),(uchar *)src,size); + if (rc != TFS_OKAY) + return(rc); + } + } + + /* Write the file header to flash: + */ + if (TFS_DEVTYPE_ISRAM(tdp)) + memcpy((char *)fp,(char *)&tf,TFSHDRSIZ); + else { + rc = tfsflashwrite((uchar *)fp,(uchar *)(&tf),TFSHDRSIZ); + if (rc != TFS_OKAY) + return(rc); + } + + /* Double check the CRC now that it is in flash. + */ + if (!(tf.flags & TFS_IPMOD)) { + if (crc32((uchar *)(fp+1), size) != tf.filcrc) + return(TFSERR_BADCRC); + } + + /* If the add was a file that previously existed, then the stale flag + * will be set and the old file needs to be deleted... + */ + if (stale) { + err = _tfsunlink(name); + if (err != TFS_OKAY) + printf("%s: %s\n",name,tfserrmsg(err)); + } + + tfslog(TFSLOG_ADD,name); + return(TFS_OKAY); +} + +/* tfsunlink(): + * Delete a file from the current list of files. Note that there + * is no attempt to de-fragment the flash; it simply nulls out the flags + * field of the file. If successful return 0; else return error number. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfsunlink(char *name) +{ + if (tfsTrace > 0) + printf("tfsunlink(%s)\n",name); + + /* If the file is currently opened, then don't allow the deletion... + */ + if (tfsFileIsOpened(name)) + return(TFSERR_FILEINUSE); + + return(_tfsunlink(name)); +} + +int +_tfsunlink(char *name) +{ + int rc; + TFILE *fp; + TDEV *tdp; + ulong flags_marked_deleted; + + if (tfsTrace > 0) + printf("_tfsunlink(%s)\n",name); + + fp = _tfsstat(name,0); + if (!fp) + return(TFSERR_NOFILE); + + if (TFS_USRLVL(fp) > getUsrLvl()) + return(TFSERR_USERDENIED); + + flags_marked_deleted = fp->flags & ~TFS_ACTIVE; + + tdp = tfsNameToDevice(name); + if (TFS_DEVTYPE_ISRAM(tdp)) + memcpy((char *)&fp->flags,(char *)&flags_marked_deleted,sizeof(long)); + else { + rc = tfsflashwrite((uchar *)&fp->flags, + (uchar *)&flags_marked_deleted, sizeof(long)); + if (rc != TFS_OKAY) + return(rc); + } + + tfslog(TFSLOG_DEL,name); + return (TFS_OKAY); +} + +int +tfslink(char *src, char *target) +{ + TFILE *tfp; + char linfo[TFSINFOSIZE+1]; + char flags[16]; + + tfp = tfsstat(src); + if (tfp) { + if (TFS_ISLINK(tfp)) + return(TFSERR_LINKERROR); + + strncpy(linfo,src,TFSINFOSIZE-1); + linfo[TFSINFOSIZE] = 0; + flags[0] = 'l'; + tfsflagsbtoa(tfp->flags,flags+1); + return(tfsadd(target,linfo,flags,0,0)); + } + return(TFSERR_NOFILE); +} + + +static void +pre_tfsautoboot_hook(void) +{ +#ifdef PRE_TFSAUTOBOOT_HOOK + extern void PRE_TFSAUTOBOOT_HOOK(); + + if (tfsMonrcActive == 0) + { + PRE_TFSAUTOBOOT_HOOK(); + } +#endif +} + +/* + * tfsrun_abortableautoboot(): + * + * Aborting execution of the monrc & non-query-autoboot files: + * The code wrapped within the #ifdef TFS_AUTOBOOT_ABORTABLE definition + * is an implementation of an idea from Jason DiDonato (Jan 2004). + * These files can be aborted by an escape character under two + * circumstances: + * + * 1. There is no password file installed + * 2. The user correctly enters the level-three password when + * prompted by the abort interaction below. + * + * This mechanism maintains security, but only when security is desired. + * A system that needs security will have a password file installed; + * hence, if no password file is found, the escape character + * (AUTOBOOT_ABORT_CHAR) is all that is needed at startup to abort an + * otherwise non-abortable file. + * If a password file is found, then the user must know the level-3 password + * to abort the execution; otherwise, after a few seconds, the interaction + * will terminate and the file will be executed. + * + * Prior to this implementation, autobootables were not abortable in any + * way. This is still the default, which is overridden by the definition + * of TFS_AUTOBOOT_ABORTABLE in config.h + */ + + +#define AUTOBOOT_ABORT_NULL 0 +#define AUTOBOOT_ABORT_NO 1 +#define AUTOBOOT_ABORT_YES 2 +#define AUTOBOOT_ABORT_FAILED 3 + +#ifndef AUTOBOOT_ABORT_CHAR +#ifdef TFS_AUTOBOOT_CANCEL_CHAR +#define AUTOBOOT_ABORT_CHAR TFS_AUTOBOOT_CANCEL_CHAR +#else +#define AUTOBOOT_ABORT_CHAR 0x03 /* CTRL-C */ +#endif +#endif + +int +tfsrun_abortableautoboot(char **arglist,int verbose) +{ +#ifdef TFS_AUTOBOOT_ABORTABLE + int err; + static int autoboot_abort; + + /* If a character has been detected at the console, and the + * character is AUTOBOOT_ABORT_CHAR, then, if a password file + * exists, require that the user enter the level-3 password + * to abort the autoboot file... + * Note that this is only done on the first pass through this + * function. All subsequent passes use the result of the initial + * pass. + */ + if (autoboot_abort == AUTOBOOT_ABORT_NULL) { + autoboot_abort = AUTOBOOT_ABORT_NO; + + if (gotachar() && (getchar() == AUTOBOOT_ABORT_CHAR)) { +#if INCLUDE_USRLVL + if (passwordFileExists()) { + char passwd[16]; + + /* To allow the user to simply hold down on the abort + * character during a target, reset, this loop will + * absorb a burst of incoming characters. Then, when + * the burst halts, the user will be queried for the + * password. + */ + monDelay(500); + while(gotachar()) { + getchar(); + monDelay(500); + } + + getpass("autoboot-abort password: ",passwd,sizeof(passwd)-1,50); + if (validPassword(passwd,3)) + autoboot_abort = AUTOBOOT_ABORT_YES; + else + autoboot_abort = AUTOBOOT_ABORT_FAILED; + } + else +#endif + autoboot_abort = AUTOBOOT_ABORT_YES; + } + } + + err = TFS_OKAY; + + switch(autoboot_abort) { + case AUTOBOOT_ABORT_NO: + pre_tfsautoboot_hook(); + err = tfsrun(arglist,verbose); + break; + case AUTOBOOT_ABORT_YES: + printf("%s aborted\n",arglist[0]); + break; + case AUTOBOOT_ABORT_FAILED: + printf("%s abort attempt failed\n",arglist[0]); + pre_tfsautoboot_hook(); + err = tfsrun(arglist,verbose); + break; + } + return(err); +#else + pre_tfsautoboot_hook(); + return(tfsrun(arglist,verbose)); +#endif /* TFS_AUTOBOOT_ABORTABLE */ +} + + +/* tfsrun(): + * Run the named file. Based on the file flags, the file is either + * executed as a COFF/ELF file with all relocation data in the file + * or run as a simple script of monitor commands. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ + +int +tfsrun(char **arglist,int verbose) +{ + int i, err; + TFILE fstat, *fp; + char *name; + + name = arglist[0]; + fp = tfsstat(name); + + if (!fp) + return (TFSERR_NOFILE); + + tfsfstat(name,&fstat); + + if (TFS_USRLVL(fp) > getUsrLvl()) + return(TFSERR_USERDENIED); + +#if INCLUDE_TFSSCRIPT + /* Store away the argument list so that it is accessible by the script + * or executable application about to be run: + */ + for(i=0;arglist[i];i++) + putargv(i,arglist[i]); + putargv(i,(char *)0); +#endif + + /* Executable file can be script or binary... + */ + if (!(fp->flags & (TFS_EXEC|TFS_EBIN))) + return(TFSERR_NOTEXEC); + + if (!(fp->flags & TFS_IPMOD)) { + if (crc32((uchar *)(TFS_BASE(fp)), fp->filsize) != fp->filcrc) + return(TFSERR_BADCRC); + } + /* Machine code or script... + * If machine code, then block it if monrc is active. + */ + if (fp->flags & TFS_EBIN) { + if (tfsRunningMonrc()) + err = TFSERR_NORUNMONRC; + else + err = tfsexec(fp,verbose); + } + else { + err = tfsscript(&fstat,verbose); + } + + return(err); +} + +/* tfsrunrcfile(): + * Called at system startup to run the monitor's run-control file (monrc). + * Three attempts are made to find the monrc file... + * 1. Call tfsstat("monrc") + * 2. Call tfsstat("monrc.bak") + * 3. For each device, prepend the device prefix to the monrc name + * and run tfsstat() on that string (i.e.. tfsstat(//A/monrc)). + * This supports a multi-device system in which the monrc file is not + * in the first TFS device. + * + * If one of the above is found, it will be automatically executed. + * Note that only the first one found will be executed. + * If the file is flagged as autobootable, post a warning message. + * This lets the user know that the monrc file is going to be run twice + * (probably not what they want, so when the warning is seen, the flag + * should be changed by the user). + * + */ + +void +tfsrunrcfile(void) +{ + int err; + TDEV *tdp; + TFILE *tfp; + char *arglist[2], bigname[TFSNAMESIZE+1], *name; + +#if TFS_RUN_DISABLE + return; +#endif + + if (!tfsInitialized) { + printf("TFS not initialized, tfsrunrcfile aborting.\n"); + return; + } + + name = TFS_RCFILE; + tfp = tfsstat(name); + if (!tfp) { + name = TFS_RCFILE ".bak"; + tfp = tfsstat(name); + } + if (!tfp) { + for(tdp=tfsDeviceTbl; (tdp->start != TFSEOT) ; tdp++) { + sprintf(bigname,"%smonrc",tdp->prefix); + if ((tfp = tfsstat(bigname))) { + name = bigname; + break; + } + } + } + if (!tfp) + return; + + if (TFS_FLAGS(tfp) & (TFS_BRUN | TFS_QRYBRUN)) + printf("Warning: %s is autobootable\n",name); + + arglist[0] = name; + arglist[1] = (char *)0; + + tfsMonrcActive = 1; + err = tfsrun_abortableautoboot(arglist,0); + tfsMonrcActive = 0; + if (err != TFS_OKAY) + printf("%s: %s\n",name,tfserrmsg(err)); + return; +} + +int +tfsRunningMonrc(void) +{ + return(tfsMonrcActive); +} + +/* tfsnext(): + * Called to retrieve the "next" file in the tfs list. If + * incoming argument is NULL then return the first file in the list. If no + * more files, return NULL; else return the tfshdr structure pointer to the + * next (or first) file in the tfs. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +TFILE * +tfsnext(TFILE *fp) +{ + TDEV *tdp; + TFILE *fpnext; + + if (!fp) { + tdp = tfsDeviceTbl; + fpnext = (TFILE *) tfsDeviceTbl[0].start; + } + else { + tdp = gettfsdev(fp); + fpnext = nextfp(fp,0); + } + + while(tdp->start != TFSEOT) { + while(validtfshdr(fpnext)) { + if (TFS_FILEEXISTS(fpnext)) + return (fpnext); + fpnext = nextfp(fpnext,0); + } + tdp++; + fpnext = (TFILE *)tdp->start; + } + return ((TFILE *) 0); +} + +/* tfsBase() and the notion of a "fake" file header... + * Generally speaking TFS code assumes that the data portion of a file + * follows the header contiguously in flash memory space. As a result, the + * code that looks for the data portion of the file just adds the size of + * the header to the file header pointer... + * + * #define TFS_BASE(fp) (char *)(fp)+(fp->hdrsize) + * + * As of Mar 2007, TFS supports the ability to load an executable image + * (usually elf) from outside TFS space by simply using the command... + * + * tfs ld 0x12345678,E,info + * + * This is useful for cases where users don't want the large elf image to + * be in TFS because each time it is updated, a defrag will occur. If put + * in raw flash space, that flash space can simply be erased and written + * over as needed; thus, eliminating the overhead of tfs defrag. + * + * When this is needed, TFS must be able to load the elf image using a + * 'fake' TFS header that points to an elf-formatted block of data in raw + * flash space. As a result, we now allocate the first reserved entry of + * TFS's header structure to this funcationality. If this first entry is + * not 0xffffffff, then it is assumed to be a pointer to the data area of + * the file. + */ +char * +tfsBase(TFILE *fp) +{ + if (fp->rsvd[0] != 0xffffffff) + return((char *)fp->rsvd[0]); + else + return(TFS_BASE(fp)); +} + + +/* tfsstat(): + * Steps through the list of files until it finds the specified + * filename or reaches the end of the list. If found, a pointer to that + * file's structure is returned; else return 0. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +TFILE * +tfsstat(char *name) +{ + if (!tfsInitialized) { + printf("TFS not initialized, tfsstat aborting.\n"); + return(0); + } + + return(_tfsstat(name,1)); +} + +TFILE * +_tfsstat(char *name,int uselink) +{ + int len; + TFILE *fp; + TDEV *tdp; + char *prefix, *dotslash = "./"; + + if (tfsTrace > 0) + printf("_tfsstat(%s,%d)\n",name,uselink); + + /* Support the ability to have a hex address for a filename... + * This uses a "fake" file header. + */ + if ((name[0] == '0') && (name[1] == 'x')) { + int rsvd; + static TFILE fakehdr; /* WARNING: not reentrant!!! */ + char *comma1, *comma2, tmpname[TFSNAMESIZE+1]; + + strncpy(tmpname,name,sizeof(tmpname)); + + comma1 = comma2 = (char *)0; + if ((comma1 = strchr(tmpname,',')) != 0) + comma2 = strchr(comma1+1,','); + + if (comma1) *comma1 = 0; + if (comma2) *comma2 = 0; + + strcpy(fakehdr.name,tmpname); + if (comma2) + strcpy(fakehdr.info,comma2+1); + else + fakehdr.info[0] = 0; + fakehdr.hdrsize = TFSHDRSIZ; + fakehdr.hdrvrsn = TFSHDRVERSION; + fakehdr.filsize = 0; + if (comma1) + tfsflagsatob(comma1+1, &fakehdr.flags); + else + fakehdr.flags = 0; + fakehdr.flags |= TFS_ACTIVE | TFS_NSTALE; + fakehdr.filcrc = 0; + fakehdr.modtime = tfsGetLtime(); + + for(rsvd=0;rsvd<TFS_RESERVED;rsvd++) + fakehdr.rsvd[rsvd] = 0xffffffff; + fakehdr.rsvd[0] = strtol(name,0,0); + + fakehdr.next = 0; + fakehdr.hdrcrc = 0; + fakehdr.hdrcrc = crc32((uchar *)&fakehdr,TFSHDRSIZ); + fakehdr.next = (TFILE *)0; + return(&fakehdr); + } + + /* Account for the possibility that the filename might have the + * device name prefixed for the first device in the table (or "./"). + */ + tdp = &tfsDeviceTbl[0]; + if (strncmp(name,tdp->prefix,strlen(tdp->prefix)) == 0) { + len = strlen(tdp->prefix); + prefix = tdp->prefix; + } + else if (strncmp(name,dotslash,2) == 0) { + len = 2; + prefix = dotslash; + } + else { + len = 0; + prefix = 0; + } + + if (prefix) { + fp = (TFILE *) tdp->start; + while(validtfshdr(fp)) { + if (TFS_FILEEXISTS(fp) && (strcmp(name+len, fp->name) == 0)) { + if (uselink && TFS_ISLINK(fp)) + return(_tfsstat(TFS_INFO(fp),0)); + else + return(fp); + } + fp = nextfp(fp,tdp); + } + } + + /* Then, if not found, walk through all TFS devices normally... + */ + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + fp = (TFILE *) tdp->start; + while(validtfshdr(fp)) { + if (TFS_FILEEXISTS(fp) && (strcmp(name, fp->name) == 0)) { + if (uselink && TFS_ISLINK(fp)) + return(_tfsstat(TFS_INFO(fp),0)); + else + return(fp); + } + fp = nextfp(fp,tdp); + } + } + return ((TFILE *) 0); +} + +/* tfsfstat(): + * Very similar in purpose to tfsstat(). This version is provided to the + * API as a "defrag-safe" version of tfsstat()... + * If tfsstat() is called (returning a pointer into TFS memory space), then + * a defragmentation occurs, that pointer is stale; hence, the need for + * an alternative that will load the content of the TFILE structure into + * an application-supplied block of memory (usually a pointer to a local + * TFILE structure). Using tfsfstat avoids this because if a defrag occurs, + * it does not affect the content of the locally stored TFILE structure. + * NOTE: + * addition of this function to the TFS API was due to the fact that + * I did not consider the above described condition when first adding + * tfsstat() to the TFS API. In general, tfsfstat() should be considered + * a replacement for all tfsstat() situations that will dereference the + * pointer. + * NOTE1: + * The return value is similar to standard "stat"... Return 0 if + * successful, else -1. + */ +int +tfsfstat(char *name, TFILE *apptfp) +{ + TFILE *tfp; + int otrace; + + otrace = tfsTrace; + + if (tfsTrace > 0) { + tfsTrace = 0; + printf("tfsfstat(%s)\n",name); + } + + tfp = tfsstat(name); + tfsTrace = otrace; + + if (!tfp) + return(-1); + + memcpy((char *)apptfp,(char *)tfp,sizeof(TFILE)); + return(0); +} + +int +showTfsError(int errno, char *msg) +{ + if (errno == TFS_OKAY) + return(TFS_OKAY); + + if (msg) + printf("%s: %s\n",msg,tfserrmsg(errno)); + else + printf("%s\n",tfserrmsg(errno)); + return(errno); +} + +/* tfscfg(): + * If the alt_tfsdev structure for the specified device prefix is + * not already established, then this function allows the caller to + * re-configure TFS for that device. + */ +int +tfscfg(char *prefix, ulong tfsstart, ulong tfsend, ulong spare) +{ +#if INCLUDE_FLASH + uchar *base; + TDEV *tdp, td; + int idx, sec_start, sec_end, size, flash_not_erased, rc; + + if (tfsTrace) { + printf("tfscfg(%s,0x%lx,0x%lx,0x%lx)\n", + prefix, tfsstart, tfsend, spare); + } + + /* If the alt_tfsdevtbl pointer is initialized to 0xffffffff, then + * we assume that this feature has been disable for this port. + */ + if (alt_tfsdevtbl == (struct tfsdev *)0xffffffff) { + return(TFSERR_NOTAVAILABLE); + } + +#ifndef TFS_ALTDEVTBL_BASE + /* We assume that if TFS_ALTDEVTBL_BASE is defined, then it is pointing + * to fixed area in flash; hence, we don't care if uMon is running out + * of RAM or not (because the default alt_tfsdevtbl[] which would be + * relocated to ram at startup isn't being used). + */ + if (uMonInRam()) { + printf("tfs cfg applies to rom-based images only\n"); + return(TFSERR_MEMFAIL); + } +#endif + + /* Match incoming prefix with an entry in the TFS device table. + * If prefix pointer is NULL, then use first device in table... + */ + if (prefix == (char *)0) { + tdp=&tfsDeviceTbl[0]; + idx = 0; + } + else { + for(idx=0,tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++,idx++) { + if (!strcmp(prefix,tdp->prefix)) + break; + } + } + if (tdp->start == TFSEOT) + return(TFSERR_BADPREFIX); + + /* If no change, just return success... + */ + if ((tfsstart == tdp->start) && (tfsend == tdp->end)) + return(TFS_OKAY); + + /* If the alternate table entry is already written, then error... + * User must run "tfs cfg restore" first. + */ + if (alt_tfsdevtbl[idx].prefix != (char *)0xffffffff) { + printf("Hint: try 'tfs cfg restore' first.\n"); + return(TFSERR_ALTINUSE); + } + + if (spare == 0xffffffff) + spare = tfsend+1; + + /* Do some checking prior to applying the new configuration... + */ + if (tfsend <= tfsstart) + return(TFSERR_BADARG); + + if (addrtosector((uchar *)tfsstart,&sec_start,0,&base) == -1) + return(TFSERR_BADARG); + + if (tfsstart != (ulong)base) { + printf("Start (0x%lx) is not base address of sector\n",tfsstart); + return(TFSERR_BADARG); + } + + if (addrtosector((uchar *)tfsend,&sec_end,&size,&base) == -1) + return(TFSERR_BADARG); + + if (addrtosector((uchar *)spare,0,&size,&base) == -1) + return(TFSERR_BADARG); + + if (spare != (ulong)base) { + printf("Spare (0x%lx) is not base address of sector\n",spare); + return(TFSERR_BADARG); + } + + flash_not_erased = 0; + +#ifdef TFS_ALTDEVTBL_BASE + /* If TFS_ALTDEVTBL_BASE is defined, then the alt_tfsdevtbl value is + * pointing to space that may not be automatically allocated by the + * compiler (as it would have been if TFS_ALTDEVTBL_BASE wasn't + * defined). As a result, we need to check to make sure that the + * space we need is erased and available... + * If this check fails, it probably indicates that the space allocated + * for this structure at build time (possibly in rom_reset.s) is just + * not big enough and needs to be increased at build time. + */ + { + uchar *end = (uchar *)&alt_tfsdevtbl[idx]; + end += sizeof(struct tfsdev) - 1; + if (!flasherased((uchar *)&alt_tfsdevtbl[idx],end)) { + printf("Alternate tfsdev structure area (0x%lx-0x%lx) not erased\n", + (long)alt_tfsdevtbl,(long)end); + flash_not_erased = 1; + } + } +#endif + + if (tfsend < tdp->end) { + if (!flasherased((uchar *)tfsend,(uchar *)tdp->end)) { + printf("flash within 0x%lx -> 0x%lx not erased\n", + tfsend,tdp->end); + flash_not_erased = 1; + } + } + else if (tdp->end < tfsend) { + if (!flasherased((uchar *)tdp->end,(uchar *)tfsend)) { + printf("flash within 0x%lx -> 0x%lx not erased\n", + tdp->end,tfsend); + flash_not_erased = 1; + } + } + if (tfsstart < tdp->start) { + if (!flasherased((uchar *)tfsstart,(uchar *)tdp->start)) { + printf("flash within 0x%lx -> 0x%lx not erased\n", + tfsstart,tdp->start); + flash_not_erased = 1; + } + } + else if (tdp->start < tfsstart) { + if (!flasherased((uchar *)tdp->start,(uchar *)tfsstart)) { + printf("flash within 0x%lx -> 0x%lx not erased\n", + tdp->start,tfsstart); + flash_not_erased = 1; + } + } + + if (flash_not_erased) + return(TFSERR_MEMFAIL); + + td.prefix = tdp->prefix; + td.start = tfsstart; + td.end = tfsend; + td.spare = spare; + td.sparesize = size; + td.sectorcount = sec_end - sec_start + 1; + + /* When a TFS device is re-configured using "tfs cfg", it + * shouldn't do any self-adjustment based on flash because + * the user is forcing the configuration. So, the reconfigured + * device must always have TFS_DEVINFO_DYNAMIC cleared... + */ + tdp->devinfo &= ~TFS_DEVINFO_DYNAMIC; + td.devinfo = tdp->devinfo; + + rc = tfsflashwrite((uchar *)&alt_tfsdevtbl[idx], + (uchar *)&td,sizeof(TDEV)); + + if (rc == TFS_OKAY) { + tdp->start = tfsstart; + tdp->end = tfsend; + tdp->spare = spare; + tdp->sparesize = size; + tdp->sectorcount = sec_end - sec_start + 1; + } + return(rc); +#else + return(TFSERR_NOTAVAILABLE); +#endif +} + +/* tfscfgrestore(): + * This function is used to erase any alternate TFS configuration + * structure that may have been previously written. This function + * is DANGEROUS because it does a self-modification of uMon binary + * space; hence, should be done with caution (i.e. don't interrupt + * it). + */ +int +tfscfgrestore(void) +{ +#if INCLUDE_FLASH + char *ram; + ulong offset; + uchar *base; + int sec_start, size; + + printf("WARNING: uMon control structure restoration in progress.\n"); + printf("Allow this to complete (2-5 seconds) without interruption\n"); + + if (addrtosector((uchar *)alt_tfsdevtbl,&sec_start,&size,&base) == -1) + return(TFSERR_FLASHFAILURE); + + offset = (ulong)alt_tfsdevtbl - (ulong)base; + ram = (char *)getAppRamStart(); + + if (s_memcpy(ram,(char *)base,size,0,0) == -1) + return(TFSERR_MEMFAIL); + if (s_memset((uchar *)(ram+offset),0xff,TFS_ALTDEVTBL_SIZE,0,0) == -1) + return(TFSERR_MEMFAIL); + + /* In most ports, flashewrite() doesn't return. */ + if (flashewrite((uchar *)base,(uchar *)ram,size) < 0) + return(TFSERR_FLASHFAILURE); + else + return(TFS_OKAY); +#else + return(TFSERR_NOTAVAILABLE); +#endif +} + +int +tfsclean_on(void) +{ + TfsCleanEnable++; + return(TfsCleanEnable); +} + +int +tfsclean_off(void) +{ + TfsCleanEnable--; + return(TfsCleanEnable); +} + +/* tfsclean_nps(): + * This is an alternative to the complicated powersafe defragmentation + * scheme used in tfsclean1.c. It simply scans through the file list + * and copies all valid files + * to RAM; then flash is erased and the RAM is copied back to flash. + * <<< WARNING >>> + * THIS FUNCTION SHOULD NOT BE INTERRUPTED AND IT WILL BLOW AWAY + * ANY APPLICATION CURRENTLY IN CLIENT RAM SPACE. + */ +int +tfsclean_nps(TDEV *tdp, char *ramstart, ulong ramsize) +{ + TFILE *tfp; + ulong appramstart; + uchar *tbuf, *ramend, *cp1, *cp2; + int dtot, nfadd, len, chkstat; +#if INCLUDE_FLASH + TFILE *lasttfp; +#endif + + if (TfsCleanEnable < 0) + return(TFSERR_CLEANOFF); + + if (ramstart) + appramstart = (ulong)ramstart; + else + appramstart = getAppRamStart(); + + if (ramsize) + ramend = (uchar *)appramstart + appramstart; + else + ramend = 0; + + /* Determine how many "dead" files exist. */ + dtot = 0; + tfp = (TFILE *)tdp->start; + while(validtfshdr(tfp)) { + if (!TFS_FILEEXISTS(tfp)) + dtot++; + tfp = nextfp(tfp,tdp); + } + + if (dtot == 0) + return(TFS_OKAY); + + printf("TFS device '%s' non-powersafe defragmentation\n",tdp->prefix); + + tbuf = (uchar *)appramstart; + tfp = (TFILE *)(tdp->start); +#if INCLUDE_FLASH + lasttfp = tfp; +#endif + nfadd = tdp->start; + while(validtfshdr(tfp)) { + if (TFS_FILEEXISTS(tfp)) { + len = TFS_SIZE(tfp) + sizeof(struct tfshdr); + if (len % TFS_FSIZEMOD) + len += TFS_FSIZEMOD - (len % TFS_FSIZEMOD); + nfadd += len; + + if (ramend && ((tbuf+len) > ramend)) { + printf("Insufficient ram, aborting defrag.\n"); + return(TFSERR_MEMFAIL); + } + + if (s_memcpy((char *)tbuf,(char *)tfp,len,0,0) != 0) + return(TFSERR_MEMFAIL); + + ((struct tfshdr *)tbuf)->next = (struct tfshdr *)nfadd; + tbuf += len; + } +#if INCLUDE_FLASH + lasttfp = tfp; +#endif + tfp = nextfp(tfp,tdp); + } + + /* We've now copied all of the active files from flash to ram. + * Now we want to see how much of the flash space needs to be + * erased. We only need to erase the sectors that have changed... + */ + cp1 = (uchar *)tdp->start; + cp2 = (uchar *)appramstart; + while(cp2 < tbuf) { + if (*cp1 != *cp2) + break; + cp1++; cp2++; + } +#if INCLUDE_FLASH + if ((cp2 != tbuf) || (!TFS_FILEEXISTS(lasttfp))) { + int first, last; + + if (addrtosector(cp1,&first,0,0) == -1) + return(TFSERR_FLASHFAILURE); + + if (addrtosector((uchar *)tdp->end,&last,0,0) == -1) + return(TFSERR_FLASHFAILURE); + printf("Erasing sectors %d-%d...\n",first,last); + while(first<last) { + if (flasherase(first++) == 0) + return(TFSERR_FLASHFAILURE); + } + } +#endif + + /* Copy data placed in RAM back to flash: */ + printf("Restoring flash...\n"); + if (TFS_DEVTYPE_ISRAM(tdp)) { + memcpy((char *)(tdp->start),(char *)appramstart, + (tbuf-(uchar*)appramstart)); + } + else { +#if INCLUDE_FLASH + int err; + + err = AppFlashWrite((uchar *)(tdp->start),(uchar *)appramstart, + (tbuf-(uchar*)appramstart)); + if (err < 0) +#endif + return(TFSERR_FLASHFAILURE); + } + + /* All defragmentation is done, so verify sanity of files... */ + chkstat = tfscheck(tdp,1); + + return(chkstat); +} + +/* tfsclean(): + * Wrapper to the underlying _tfsclean() function. + * The original intent of this was to enable a call to appexit() if there + * is an error returned by tfsclean(). This is used for testing TFS... + * If a script is running to try to cause tfsclean to break, then we want + * it to halt if tfsclean does return an error. + + + * As of uMon1.0, if this function detects that the device is volatile + * RAM, then the clean is not powersafe; hence, doesn't have to go + * through the rigorous sector-based defragmentation. + */ +int +tfsclean(TDEV *tdp,int verbose) +{ + TFILE *tfp, *tfp1, *tfpnxt; + int cleanresult, size; + char *cp; + + if (TFS_DEVTYPE_ISRAM(tdp)) { + cp = 0; + tfp = (TFILE *)tdp->start; + while(validtfshdr(tfp)) { + tfpnxt = nextfp(tfp,tdp); + if (TFS_DELETED(tfp)) { + if (cp == 0) + cp = (char *)tfp; + } + else { + if (cp != 0) { + size = TFS_SIZE(tfp) + TFSHDRSIZ; + if (size & 0xf) + size = (size | 0xf) + 1; + memcpy(cp,(char *)tfp,size); + tfp1 = (TFILE *)cp; + tfp1->next = (TFILE *)(cp+size); + tfp1->hdrcrc = tfshdrcrc(tfp1); + cp += size; + } + } + tfp = tfpnxt; + } + if (cp) + memset(cp,0xff,(char *)(tdp->end)-cp); + cleanresult = TFS_OKAY; + } + else { + cleanresult = _tfsclean(tdp,0,verbose); + if (cleanresult != TFS_OKAY) { + if (getenv("APP_EXITONCLEANERROR")) + appexit(0); +#if INCLUDE_TFSSCRIPT + if (getenv("SCR_EXITONCLEANERROR")) + ScriptExitFlag = EXIT_SCRIPT; +#endif + } + } + + return(cleanresult); +} + +#else /* INCLUDE_TFS */ + +char * +tfserrmsg(int errno) +{ + return(0); +} +int +tfsinit(void) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfsfstat(char *name, TFILE *apptfp) +{ + return(TFSERR_NOTAVAILABLE); +} + +TFILE * +tfsstat(char *name) +{ + return ((TFILE *) 0); +} + +int +tfslink(char *src, char *target) +{ + return(TFSERR_NOTAVAILABLE); +} + +TFILE * +tfsnext(TFILE *fp) +{ + return ((TFILE *) 0); +} + +int +tfsrun(char **arglist,int verbose) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfsunlink(char *name) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfsadd(char *name, char *info, char *flags, uchar *src, int size) +{ + return(TFSERR_NOTAVAILABLE); +} + +long +tfsctrl(int rqst,long arg1,long arg2) +{ + return(TFSERR_NOTAVAILABLE); +} + +long +tfstell(int fd) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfsRunningMonrc(void) +{ + return(0); +} + +int +tfsspace(char *addr) +{ + return(0); +} + +#endif /* INCLUDE_TFS else */ diff --git a/main/common/tfs.h b/main/common/tfs.h new file mode 100644 index 0000000..d4e21e5 --- /dev/null +++ b/main/common/tfs.h @@ -0,0 +1,213 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfs.h: + * + * Header file for TFS transactions, used by both application and monitor. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _TFS_H_ +#define _TFS_H_ + +#define TFSINFOSIZE 23 /* Max size of info string (mod4-1). */ + +#ifndef TFSNAMESIZE /* This specifies the maximum size of a file */ +#define TFSNAMESIZE 23 /* name that can be used in TFS. */ +#endif /* This MUST be some value mod4 - 1. */ + +#ifndef TFS_CHANGELOG_FILE /* Information used for change-log */ +#define TFS_CHANGELOG_SIZE 0 /* facility within tfs. */ +#define TFS_CHANGELOG_FILE ".tfschlog" +#endif + +#ifndef SYMFILE /* This specifies the default filename */ +#define SYMFILE "symtbl" /* used by the monitor for the symbol */ +#endif /* table. */ + +#define MINUSRLEVEL 0 /* Minimum user level supported. */ +#define MAXUSRLEVEL 3 /* Maximum user level supported. */ + +#ifndef TFS_RESERVED +#define TFS_RESERVED 4 /* Number of "reserved" entries (ulong) */ +#endif /* in the TFS header. */ + + +/* Flags: */ +#define TFS_EXEC 0x00000001 /* 'e': Executable script. */ +#define TFS_BRUN 0x00000002 /* 'b': To be executed at boot. */ +#define TFS_QRYBRUN 0x00000004 /* 'B': To be executed at boot if */ + /* query passes. */ +#define TFS_SYMLINK 0x00000008 /* 'l': Symbolic link file. */ +#define TFS_EBIN 0x00000010 /* 'E': Executable binary (coff/elf/a.out). */ +#define TFS_IPMOD 0x00000080 /* 'i': File is in-place modifiable. */ +#define TFS_UNREAD 0x00000100 /* 'u': File is not even readable if the */ + /* user-level requirement is not met; */ + /* else, it is read-only. */ +#define TFS_ULVLMSK 0x00000600 /* User level mask defines 4 access levels: */ +#define TFS_ULVL0 0x00000000 /* '0' level 0 */ +#define TFS_ULVL1 0x00000200 /* '1' level 1 */ +#define TFS_ULVL2 0x00000400 /* '2' level 2 */ +#define TFS_ULVL3 0x00000600 /* '3' level 3 */ +#define TFS_NSTALE 0x00000800 /* File is NOT stale, invisible to user. + * When this bit is clear, the file is + * considered stale (see notes in tfsadd()). + * See notes in tfsclose() for this. + */ +#define TFS_ACTIVE 0x00008000 /* Used to indicate that file is not deleted. */ + +#define TFS_ULVLMAX TFS_ULVL3 +#define TFS_USRLVL(f) ((f->flags & TFS_ULVLMSK) >> 9) + +/* Open modes */ +#define TFS_RDONLY 0x00010000 /* File is opened for reading. */ +#define TFS_CREATE 0x00020000 /* File is to be created. Error if file */ + /* with the same name already exists. */ +#define TFS_APPEND 0x00040000 /* Append to existing file. If OR'ed */ + /* with TFS_CREATE, then create if */ + /* necessary. */ +#define TFS_ALLFFS 0x00080000 /* File is created with all FFs. */ +#define TFS_CREATERM 0x00100000 /* File is to be created. If file with */ + /* same name already exists, then allow */ + /* tfsadd() to remove it if necessary. */ + +/* The function tfsrunrc() will search through the current file set and */ +/* if the file defined by TFS_RCFILE exists, it will be executed. */ +/* If this file exists, it will NOT be run by tfsrunboot(). */ +#define TFS_RCFILE "monrc" + +/* Requests that can be made to tfsctrl(): */ +#define TFS_ERRMSG 1 +#define TFS_MEMUSE 2 +#define TFS_MEMDEAD 3 +#define TFS_DEFRAG 4 +#define TFS_TELL 5 +#define TFS_UNOPEN 7 +#define TFS_FATOB 8 +#define TFS_FBTOA 9 +#define TFS_MEMAVAIL 10 +#define TFS_TIMEFUNCS 11 +#define TFS_DOCOMMAND 12 +#define TFS_INITDEV 13 +#define TFS_CHECKDEV 14 +#define TFS_DEFRAGDEV 15 +#define TFS_DEFRAGOFF 16 +#define TFS_DEFRAGON 17 +#define TFS_HEADROOM 18 +#define TFS_FCOUNT 19 +#define TFS_RAMDEV 20 + +/* struct tfshdr: + * It is in FLASH as part of the file system to record the attributes of + * the file at the time of creation. + * + * New as of March 2007... + * See tfsBase() for info on the use of the first entry of the rsvd[] array. + */ +struct tfshdr { + unsigned short hdrsize; /* Size of this header. */ + unsigned short hdrvrsn; /* Header version #. */ + long filsize; /* Size of the file. */ + long flags; /* Flags describing the file. */ + unsigned long filcrc; /* 32 bit CRC of file. */ + unsigned long hdrcrc; /* 32 bit CRC of the header. */ + unsigned long modtime; /* Time when file was last modified. */ + struct tfshdr *next; /* Pointer to next file in list. */ + char name[TFSNAMESIZE+1]; /* Name of file. */ + char info[TFSINFOSIZE+1]; /* Miscellaneous info field. */ +#if TFS_RESERVED + unsigned long rsvd[TFS_RESERVED]; +#endif +}; + +/* struct tfsramdev: + * Used with the tfsctrl function TFS_RAMDEV to allow the user to + * specify the name, base address and size of a new, temporary + * ram-based TFS device. + */ +struct tfsramdev { + char *name; + long base; + long size; +}; + +#define TFSHDRSIZ sizeof(struct tfshdr) + +/* TFS error returns. */ +#define TFS_OKAY 0 +#define TFSERR_NOFILE -1 +#define TFSERR_NOSLOT -2 +#define TFSERR_EOF -3 +#define TFSERR_BADARG -4 +#define TFSERR_NOTEXEC -5 +#define TFSERR_BADCRC -6 +#define TFSERR_FILEEXISTS -7 +#define TFSERR_FLASHFAILURE -8 +#define TFSERR_WRITEMAX -9 +#define TFSERR_RDONLY -10 +#define TFSERR_BADFD -11 +#define TFSERR_BADHDR -12 +#define TFSERR_CORRUPT -13 +#define TFSERR_MEMFAIL -14 +#define TFSERR_NOTIPMOD -16 +#define TFSERR_MUTEXFAILURE -17 +#define TFSERR_FLASHFULL -18 +#define TFSERR_USERDENIED -19 +#define TFSERR_NAMETOOBIG -20 +#define TFSERR_FILEINUSE -21 +#define TFSERR_NOTAVAILABLE -23 +#define TFSERR_BADFLAG -24 +#define TFSERR_CLEANOFF -25 +#define TFSERR_FLAKEYSOURCE -26 +#define TFSERR_BADEXTENSION -27 +#define TFSERR_LINKERROR -28 +#define TFSERR_BADPREFIX -29 +#define TFSERR_ALTINUSE -30 +#define TFSERR_NORUNMONRC -31 +#define TFSERR_DSIMAX -32 +#define TFSERR_TOOSMALL -33 +#define TFSERR_MIN -100 + +/* TFS seek options. */ +#define TFS_BEGIN 1 +#define TFS_CURRENT 2 +#define TFS_END 3 + +/* Macros: */ +#define TFS_DELETED(fp) (!((fp)->flags & TFS_ACTIVE)) +#define TFS_FILEEXISTS(fp) ((fp)->flags & TFS_ACTIVE) +#define TFS_ISEXEC(fp) ((fp)->flags & TFS_EXEC) +#define TFS_ISBOOT(fp) ((fp)->flags & TFS_BRUN) +#define TFS_ISLINK(fp) ((fp)->flags & TFS_SYMLINK) +#define TFS_STALE(fp) (!((fp)->flags & TFS_NSTALE)) +#define TFS_FLAGS(fp) ((fp)->flags) +#define TFS_NAME(fp) ((fp)->name) +#define TFS_SIZE(fp) ((fp)->filsize) +#define TFS_TIME(fp) ((fp)->modtime) +#define TFS_INFO(fp) ((fp)->info) +#define TFS_NEXT(fp) ((fp)->next) +#define TFS_CRC(fp) ((fp)->filcrc) +#define TFS_ENTRY(fp) ((fp)->entry) +#define TFS_BASE(fp) ((char *)(fp)+(fp)->hdrsize) + +typedef struct tfshdr TFILE; +typedef struct tfsramdev TRAMDEV; +#endif diff --git a/main/common/tfsapi.c b/main/common/tfsapi.c new file mode 100644 index 0000000..212d264 --- /dev/null +++ b/main/common/tfsapi.c @@ -0,0 +1,622 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfsapi.c: + * + * This file contains the portion of TFS that provides the function-level + * API to the application. If this is not being used by the application + * then it can be omitted from the monitor build. + * Note that not all of the api-specific code is here; some of it is in + * tfs.c. This is because the the MicroMonitor uses some of the api itself, + * so it cannot be omitted from the TFS package without screwing up some + * other monitor functionality that needs it. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpu.h" +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#if INCLUDE_TFSAPI + +/* tfstruncate(): + * To support the ability to truncate a file (make it smaller); this + * function allows the user to adjust the high-water point of the currently + * opened (and assumed to be opened for modification) file and replaces + * that with the incoming argument. This replacement is only done if the + * current high-water point is higher than the incoming length. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfstruncate(int fd, long len) +{ + struct tfsdat *tdat; + + if (tfsTrace > 1) + printf("tfstruncate(%d,%ld)\n",fd,len); + + /* Verify valid range of incoming file descriptor. */ + if ((fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADFD); + + tdat = &tfsSlots[fd]; + + /* Make sure the file pointed to by the incoming descriptor is active + * and that the incoming length is greater than the current high-water + * point... + */ + if (tdat->offset == -1) + return(TFSERR_BADFD); + if (len > tdat->hwp) + return(TFSERR_BADARG); + + /* Make the adjustment... */ + tdat->hwp = len; + return(TFS_OKAY); +} + +/* tfseof(): + * Return 1 if at the end of the file, else 0 if not at end; else negative + * if error. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfseof(int fd) +{ + struct tfsdat *tdat; + + /* Verify valid range of incoming file descriptor. */ + if ((fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADARG); + + tdat = &tfsSlots[fd]; + + /* Make sure the file pointed to by the incoming descriptor is active. */ + if (tdat->offset == -1) + return(TFSERR_BADFD); + + if (tdat->offset >= tdat->hdr.filsize) + return(1); + else + return(0); +} + +/* tfsread(): + * Similar to a standard read call to a file. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfsread(int fd, char *buf, int cnt) +{ + struct tfsdat *tdat; + uchar *from; + + if (tfsTrace > 1) + printf("tfsread(%d,0x%lx,%d)\n",fd,(ulong)buf,cnt); + + /* Verify valid range of incoming file descriptor. */ + if ((cnt < 1) || (fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADARG); + + tdat = &tfsSlots[fd]; + + /* Make sure the file pointed to by the incoming descriptor is active. */ + if (tdat->offset == -1) + return(TFSERR_BADFD); + + if (tdat->offset >= tdat->hdr.filsize) + return(TFSERR_EOF); + + from = (uchar *) tdat->base + tdat->offset; + + /* If request size is within the range of the file and current + * then copy the data to the requestors buffer, increment offset + * and return the count. + */ + if ((tdat->offset + cnt) <= tdat->hdr.filsize) { + if (s_memcpy((char *)buf, (char *)from, cnt,0,0) != 0) + return(TFSERR_MEMFAIL); + } + /* If request size goes beyond the size of the file, then copy + * to the end of the file and return that smaller count. + */ + else { + cnt = tdat->hdr.filsize - tdat->offset; + if (s_memcpy((char *)buf, (char *)from, cnt, 0, 0) != 0) + return(TFSERR_MEMFAIL); + } + tdat->offset += cnt; + return(cnt); +} + +/* tfswrite(): + * Similar to a standard write call to a file. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfswrite(int fd, char *buf, int cnt) +{ + struct tfsdat *tdat; + + if (tfsTrace > 1) + printf("tfswrite(%d,0x%lx,%d)\n", fd,(ulong)buf,cnt); + + /* Verify valid range of incoming file descriptor. */ + if ((cnt < 1) || (fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADARG); + + /* Make sure the file pointed to by the incoming descriptor is active. */ + if (tfsSlots[fd].offset == -1) + return(TFSERR_BADARG); + + tdat = &tfsSlots[fd]; + + /* Make sure file is not opened as read-only */ + if (tdat->flagmode & TFS_RDONLY) + return(TFSERR_RDONLY); + + if (s_memcpy((char *)tdat->base+tdat->offset,(char *)buf,cnt,0,0) != 0) + return(TFSERR_MEMFAIL); + + tdat->offset += cnt; + + /* If new offset is greater than current high-water point, then + * adjust the high water point so that it is always reflecting the + * highest offset into which the file has had some data written. + */ + if (tdat->offset > tdat->hwp) + tdat->hwp = tdat->offset; + + return(TFS_OKAY); +} + +/* tfsseek(): + * Adjust the current pointer into the specified file. + * If file is read-only, then the offset cannot exceed the file size; + * otherwise, the only check made to the offset is that it is positive. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfsseek(int fd, int offset, int whence) +{ + int o_offset; + struct tfsdat *tdat; + + if (tfsTrace > 1) + printf("tfsseek(%d,%d,%d)\n",fd,offset,whence); + + if ((fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADARG); + + tdat = &tfsSlots[fd]; + o_offset = tdat->offset; + + switch (whence) { + case TFS_BEGIN: + tdat->offset = offset; + break; + case TFS_CURRENT: + tdat->offset += offset; + break; + default: + return(TFSERR_BADARG); + } + + /* If new offset is less than zero or if the file is read-only and the + * new offset is greater than the file size, return EOF... + */ + if ((tdat->offset < 0) || + ((tdat->flagmode & TFS_RDONLY) && (tdat->offset > tdat->hdr.filsize))){ + tdat->offset = o_offset; + return(TFSERR_EOF); + } + return(tdat->offset); +} + +/* tfsipmod(): + * Modify "in-place" a portion of a file in TFS. + * This is a cheap and dirty way to modify a file... + * The idea is that a file is created with a lot of writeable flash space + * (data = 0xff). This function can then be called to immediately modify + * blocks of space in that flash. It will not do any tfsunlink/tfsadd, and + * it doesn't even require a tfsopen() tfsclose() wrapper. Its a fast and + * efficient way to modify flash in the file system. + * Arguments: + * name = name of the file to be in-place-modified; + * buf = new data to be written to flash; + * offset = offset into file into which new data is to be written; + * size = size of new data (in bytes). + * + * With offset of -1, set offset to location containing first 0xff value. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfsipmod(char *name,char *buf,int offset,int size) +{ + int rc; + TFILE *fp; + uchar *cp; + + fp = tfsstat(name); + if (!fp) + return (TFSERR_NOFILE); + if (!(fp->flags & TFS_IPMOD)) + return(TFSERR_NOTIPMOD); + + if (offset == -1) { + cp = (uchar *)(TFS_BASE(fp)); + for (offset=0;offset<fp->filsize;offset++,cp++) { + if (*cp == 0xff) + break; + } + } + else if (offset < -1) + return(TFSERR_BADARG); + + if ((offset + size) > fp->filsize) + return(TFSERR_WRITEMAX); + + /* BUG fixed: 2/21/2001: + * The (ulong *) cast was done prior to adding offset to the base. + * This caused the offset to be quadrupled. + */ + rc = tfsflashwrite((uchar *)(TFS_BASE(fp)+offset),(uchar *)buf,size); + if (rc != TFS_OKAY) + return(rc); + + tfslog(TFSLOG_IPM,name); + return(TFS_OKAY); +} + +/* tfsopen(): + * Open a file for reading or creation. If file is opened for writing, + * then the caller must provide a RAM buffer pointer to be used for + * the file storage until it is transferred to flash by tfsclose(). + * Note that the "buf" pointer is only needed for opening a file for + * creation or append (writing). + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfsopen(char *file,long flagmode,char *buf) +{ + register int i; + int errno, retval; + long fmode; + TFILE *fp; + struct tfsdat *slot; + + errno = TFS_OKAY; + + fmode = flagmode & (TFS_RDONLY | TFS_APPEND | TFS_CREATE | TFS_CREATERM); + + /* See if file exists... */ + fp = tfsstat(file); + + /* If file exists, do a crc32 on the data. + * If the file is in-place-modifiable, then the only legal flagmode + * is TFS_RDONLY. Plus, in this case, the crc32 test is skipped. + */ + if (fp) { + if (!((fmode == TFS_RDONLY) && (fp->flags & TFS_IPMOD))) { + if (crc32((unsigned char *)TFS_BASE(fp),fp->filsize) != fp->filcrc) { + retval = TFSERR_BADCRC; + goto done; + } + } + } + + /* This switch verifies... + * - that the file exists if TFS_RDONLY or TFS_APPEND + * - that the file does not exist if TFS_CREATE + */ + switch(fmode) { + case TFS_RDONLY: /* Read existing file only, no change to file at all. */ + if (!fp) { + if (_tfsstat(file,0)) + errno = TFSERR_LINKERROR; + else + errno = TFSERR_NOFILE; + } + else { + if ((fp->flags & TFS_UNREAD) && (TFS_USRLVL(fp) > getUsrLvl())) + errno = TFSERR_USERDENIED; + } + break; + case TFS_APPEND: /* Append to the end of the current file. */ + if (!fp) + errno = TFSERR_NOFILE; + else { + if (TFS_USRLVL(fp) > getUsrLvl()) + errno = TFSERR_USERDENIED; + } + break; + case TFS_CREATERM: /* Create a new file, allow tfsadd() to remove */ + fmode = TFS_CREATE; /* it if it exists. */ + break; + case TFS_CREATE: /* Create a new file, error if it exists. */ + if (fp) + errno = TFSERR_FILEEXISTS; + break; + case (TFS_APPEND|TFS_CREATE): /* If both mode bits are set, clear one */ + if (fp) { /* based on the presence of the file. */ + if (TFS_USRLVL(fp) > getUsrLvl()) + errno = TFSERR_USERDENIED; + fmode = TFS_APPEND; + } + else { + fmode = TFS_CREATE; + } + break; + default: + errno = TFSERR_BADARG; + break; + } + + if (errno != TFS_OKAY) { + retval = errno; + goto done; + } + + /* Find an empty slot... + */ + slot = tfsSlots; + for (i=0;i<TFS_MAXOPEN;i++,slot++) { + if (slot->offset == -1) + break; + } + + /* Populate the slot structure if a slot is found to be + * available... + */ + if (i < TFS_MAXOPEN) { + retval = i; + slot->hwp = 0; + slot->offset = 0; + slot->flagmode = fmode; + if (fmode & TFS_CREATE) { + strncpy(slot->hdr.name,file,TFSNAMESIZE); + slot->flagmode |= (flagmode & TFS_FLAGMASK); + slot->base = (uchar *)buf; + } + else if (fmode & TFS_APPEND) { + memcpy((char *)&slot->hdr,(char *)fp,sizeof(struct tfshdr)); + if (s_memcpy((char *)buf,(char *)(TFS_BASE(fp)), + fp->filsize,0,0) != 0) { + retval = TFSERR_MEMFAIL; + goto done; + } + slot->flagmode = fp->flags; + slot->flagmode |= TFS_APPEND; + slot->base = (uchar *)buf; + slot->hwp = fp->filsize; + slot->offset = fp->filsize; + } + else { + slot->base = (uchar *) (TFS_BASE(fp)); + memcpy((char *)&slot->hdr,(char *)fp,sizeof(struct tfshdr)); + } + } + else { + retval = TFSERR_NOSLOT; + } + +done: + if (tfsTrace > 0) + printf("tfsopen(%s,0x%lx,0x%lx)=%d\n",file,flagmode,(ulong)buf,retval); + + return(retval); +} + +/* tfsclose(): + * If the file was opened for reading only, then just close out the + * entry in the tfsSlots table. If the file was opened for creation, + * then add it to the tfs list. Note the additional argument is + * only needed for tfsclose() of a newly created file. + * info = additional text describing the file. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfsclose(int fd,char *info) +{ + int err; + struct tfsdat *tdat; + + if (!info) info = ""; + + if (tfsTrace > 0) + printf("tfsclose(%d,%s)\n",fd,info); + + if ((fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADARG); + + tdat = &tfsSlots[fd]; + + if (tdat->offset == -1) + return(TFSERR_BADFD); + + /* Mark the file as closed by setting the offset to -1. + * Note that this is done prior to potentially calling tfsadd() so + * that tfsadd() will not think the file is opened and reject the add... + */ + tdat->offset = -1; + + /* If the file was opened for creation or append, and the hwp + * (high-water-point) is greater than zero, then add it now. + * + * Note regarding hwp==0... + * In cases where a non-existent file is opened for creation, + * but then nothing is written to the file, the hwp value will + * be zero; hence, no need to call tfsadd(). + */ + if ((tdat->flagmode & (TFS_CREATE | TFS_APPEND)) && (tdat->hwp > 0)) { + char buf[16]; + + err = tfsadd(tdat->hdr.name, info, tfsflagsbtoa(tdat->flagmode,buf), + tdat->base, tdat->hwp); + if (err != TFS_OKAY) { + printf("%s: %s\n",tdat->hdr.name,tfserrmsg(err)); + return(err); + } + } + return(TFS_OKAY); +} + +#else /* INCLUDE_TFSAPI */ + +int +tfstruncate(int fd, long len) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfseof(int fd) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfsread(int fd, char *buf, int cnt) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfswrite(int fd, char *buf, int cnt) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfsseek(int fd, int offset, int whence) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfsopen(char *file,long flagmode,char *buf) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfsclose(int fd,char *info) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +tfsipmod(char *name,char *buf,int offset,int size) +{ + return(TFSERR_NOTAVAILABLE); +} + +#endif /* INCLUDE_TFSAPI else */ + +#if INCLUDE_TFSAPI || INCLUDE_TFSSCRIPT + +/* tfsgetline(): + * Read into the buffer a block of characters upto the next EOL delimiter + * the file. After the EOL, or after max-1 chars are loaded, terminate + * with a NULL. Return the number of characters loaded. + * At end of file return 0. + * MONLIB NOTICE: this function is accessible through monlib.c. + */ +int +tfsgetline(int fd,char *buf,int max) +{ + uchar *from; + int tot, rtot; + struct tfsdat *tdat; + volatile char *to; + + max--; + + if (tfsTrace > 1) + printf("tfsgetline(%d,0x%lx,%d)\n",fd,(ulong)buf,max); + + /* Verify valid range of incoming file descriptor. */ + if ((max < 1) || (fd < 0) || (fd >= TFS_MAXOPEN)) + return(TFSERR_BADARG); + + /* Make sure the file pointed to by the incoming descriptor is active. */ + if (tfsSlots[fd].offset == -1) + return(TFSERR_BADARG); + + tdat = &tfsSlots[fd]; + + if (tdat->offset == -1) + return(TFSERR_BADFD); + + if (tdat->offset >= tdat->hdr.filsize) + return(0); + + from = (uchar *) tdat->base + tdat->offset; + to = buf; + + /* If the incoming buffer size is larger than needed, adjust the + * 'max' value so that we don't pass the end of the file... + */ + if ((tdat->offset + max) > tdat->hdr.filsize) + max = tdat->hdr.filsize - tdat->offset + 1; + + /* Read from the file data area until newline (0x0a) is found + * (or until the 'max buffer space' value is reached). + * Strip 0x0d (if present) and terminate with NULL in all cases. + */ + for(rtot=0,tot=0;tot < max; from++) { + /* Terminate on Ctrl-Z, non-ASCII, Newline or NULL. + * Ignore carriage return completely... + */ + if ((*from == 0x1a) || (*from > 0x7f) || (*from == 0)) + break; + + tot++; + + if (*from == 0x0d) + continue; + + *to = *from; + if (*to != *from) + return(TFSERR_MEMFAIL); + + to++; rtot++; + + if (*from == 0x0a) + break; + } + *to = 0; + + tdat->offset += tot; + return(rtot); +} + +#else + +int +tfsgetline(int fd,char *buf,int max) +{ + return(TFSERR_NOTAVAILABLE); +} + +#endif diff --git a/main/common/tfsclean1.c b/main/common/tfsclean1.c new file mode 100755 index 0000000..801db29 --- /dev/null +++ b/main/common/tfsclean1.c @@ -0,0 +1,2195 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfsclean1.c: + * + * This is one of several different versions of tfsclean(). This version + * is by far the most complex, but offers power-hit safety and minimal + * flash overhead. It uses a "spare" sector to backup the + * "one-sector-at-a-time" defragmentation process. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpu.h" +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "flash.h" +#include "monflags.h" +#include "warmstart.h" + +#if INCLUDE_TFS + +#if !INCLUDE_FLASH +#error: If flash is not included, then use tfsclean2.c +#endif + +#if DEFRAG_TEST_ENABLED +void +defragExitTestPoint(int val) +{ + if ((DefragTestType == DEFRAG_TEST_EXIT) && (DefragTestPoint == val)) { + printf("\n+++++++++ EXIT @ TEST POINT(%d)\n",val); + CommandLoop(); + } +} +#else +#define defragExitTestPoint(val) +#endif + +/* Variables for testing tfsclean(): + * They are set up through arguments to "tfs clean" in tfscli.c. + */ +int DefragTestType; +int DefragTestPoint; +int DefragTestSector; + +/* defragTick(): + * Used to show progress, just to let the user know that we aren't + * dead in the water. + */ +static void +defragTick(int verbose) +{ + static int tick; + static char clockhand[] = { '|', '/', '-', '\\' }; + + if (!verbose && (!MFLAGS_NODEFRAGPRN())) { + if (tick > 3) + tick = 0; + printf("%c\b",clockhand[tick++]); + } +} + +/* defragCrcTable(): + * Return a pointer to the crc table for the specified TFS device. + */ +struct sectorcrc * +defragCrcTable(TDEV *tdp) +{ + return((struct sectorcrc *)(tdp->end+1) - tdp->sectorcount); +} + +/* defragSerase(): + * Common function to call from within tfsclean() to erase a sector + * and generate an error message if necessary. + * + * If DEFRAG_TEST_ENABLED is defined and the type/sector/point criteria + * is met, then instead of erasing the sector; just change the first non-zero + * byte to zero to corrupt it. This essentially makes it a corrupted erase. + */ +static int +defragSerase(int tag, int snum) +{ + int ret = 0; + +#if DEFRAG_TEST_ENABLED + int ssize; + uchar *sbase, *send, zero; + + printf(" serase_%02d(%02d)\n",tag,snum); + + if ((DefragTestType == DEFRAG_TEST_SERASE) && + (DefragTestSector == snum) && (DefragTestPoint == tag)) { + sectortoaddr(snum,&ssize,&sbase); + send = sbase+ssize; + zero = 0; + while(sbase < send) { + if (*sbase != 0) { + tfsflashwrite((ulong *)sbase,(ulong *)&zero,1); + break; + } + sbase++; + } + printf("DEFRAG_TEST_SERASE activated @ %d sector %d\n",tag,snum); + CommandLoop(); + } + else +#endif + ret = tfsflasherase(snum); + if (ret <= 0) { + printf("tfsclean() serase erase failed: %d,%d,%d\n",snum,tag,ret); + } + return(ret); +} + +/* defragFwrite(): + * Common function to call from within tfsclean() to write to flash + * and generate an error message if necessary. + * If DEFRAG_TEST_ENABLED is defined and the test type is set to + * DEFRAG_TEST_FWRITE, then use APPRAMBASE as the source of the data + * so that the end result is an errored flash write. + */ +static int +defragFwrite(int tag, uchar *dest,uchar *src,int size) +{ + int ret = 0; + +#if DEFRAG_TEST_ENABLED + int snum; + + addrtosector((char *)dest,&snum,0,0); + printf(" fwrite_%02d(%d,0x%lx,0x%lx,%d)\n", + tag,snum,(ulong)dest,(ulong)src,size); + + if ((DefragTestType == DEFRAG_TEST_FWRITE) && + (DefragTestSector == snum) && (DefragTestPoint == tag)) { + tfsflashwrite((ulong *)dest,(ulong *)getAppRamStart(),size/2); + printf("DEFRAG_TEST_FWRITE activated @ %d sector %d\n",tag,snum); + CommandLoop(); + } + else +#endif + ret = tfsflashwrite(dest,src,size); + if (ret != TFS_OKAY) { + printf("tfsclean() fwrite failed: 0x%lx,0x%lx,%d,%d\n", + (ulong)dest,(ulong)src,size,tag); + } + return(ret); +} + +/* defragGetSpantype(): + * With the incoming sector base and end (s_base, s_end), + * determine the type of span that the incoming file (f_base, f_end) + * has across it. There are six different ways the spanning can + * occur: + * 1. begin and end in previous active sector (bpep); + * 2. begin in previously active sector, end in this one (bpec); + * 3. begin in previously active sector, end in later one (bpel); + * 4. begin and end in this active sector (bcec); + * 5. begin in this active sector, end in later one (bcel); + * 6. begin and end in later active sector (blel); + */ +static int +defragGetSpantype(char *s_base,char *s_end,char *f_base,char *f_end) +{ + int spantype; + + if (f_base < s_base) { + if ((f_end > s_base) && (f_end <= s_end)) + spantype = SPANTYPE_BPEC; + else if (f_end > s_end) + spantype = SPANTYPE_BPEL; + else + spantype = SPANTYPE_BPEP; + } + else { + if (f_base > s_end) + spantype = SPANTYPE_BLEL; + else if (f_end <= s_end) + spantype = SPANTYPE_BCEC; + else + spantype = SPANTYPE_BCEL; + } + return(spantype); +} + +/* defragGetSpantypeStr(): + * Return a string that corresponds to the incoming state value. + */ +static char * +defragGetSpantypeStr(int spantype) +{ + char *str; + + switch(spantype) { + case SPANTYPE_BPEC: + str = "BPEC"; + break; + case SPANTYPE_BLEL: + str = "BLEL"; + break; + case SPANTYPE_BPEL: + str = "BPEL"; + break; + case SPANTYPE_BPEP: + str = "BPEP"; + break; + case SPANTYPE_BCEC: + str = "BCEC"; + break; + case SPANTYPE_BCEL: + str = "BCEL"; + break; + default: + str = "???"; + break; + } + return(str); +} + +/* defragEraseSpare(): + * Erase the spare sector associated with the incoming TFS device. + * The underlying flash driver SHOULD have a check so that it only + * erases the sector if the sector is not already erased, so this + * extra check (call to flasherased()) may not be necessary in + * most cases. + */ +static int +defragEraseSpare(TDEV *tdp) +{ + int snum, ssize; + uchar *sbase; + + if (addrtosector((unsigned char *)tdp->spare,&snum,&ssize,&sbase) < 0) + return(TFSERR_FLASHFAILURE); + + if (!flasherased(sbase,sbase+(ssize-1))) { + if (defragSerase(1,snum) < 0) { + return(TFSERR_FLASHFAILURE); + } + } + return(TFS_OKAY); +} + +/* defragValidDSI(): + * Test to see if we have a valid defrag state information (DSI) + * area. The DSI area, working back from tdp->end, consists of a + * table of 32-bit crcs (one per sector), a table of defraghdr + * structures (one per active file) and a 32-bit crc of the DSI + * itself. Knowing this format, we can easily step backwards into + * the DSI space to see if it all makes sense. + * If the table is 100% valid, then we will be able to step + * backwards through the DSI to find the 32-bit crc of the DSI area. + * If it matches, then we can be sure that the DSI is valid. + * Return total number of files in header if the defrag header + * table appears to be sane, else 0. + */ +static int +defragValidDSI(TDEV *tdp, struct sectorcrc **scp) +{ + int ftot, valid, lastssize; + uchar *lastsbase; + struct sectorcrc *crctbl; + ulong hdrcrc, *crc; + struct defraghdr *dhp, dfhcpy; + + ftot = valid = 0; + crctbl = defragCrcTable(tdp); + dhp = (struct defraghdr *)crctbl - 1; + /* next line was <dfhcpy = *dhp> ... */ + memcpy((char *)&dfhcpy,(char *)dhp,sizeof(struct defraghdr)); + hdrcrc = dfhcpy.crc; + dfhcpy.crc = 0; + if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) { + ftot = dhp->idx + 1; + dhp = (struct defraghdr *)crctbl - ftot; + crc = (ulong *)dhp - 1; + if (crc32((uchar *)dhp,(uchar *)tdp->end-(uchar *)dhp) == *crc) { + if (scp) + *scp = crctbl; + return(ftot); + } + } + + /* It's possible that the DSI space has been relocated to the spare + * sector, so check for that here... + */ + addrtosector((unsigned char *)tdp->end,0,&lastssize,&lastsbase); + + crctbl = ((struct sectorcrc *)(tdp->spare+lastssize) - tdp->sectorcount); + dhp = (struct defraghdr *)crctbl - 1; + /* next line was <dfhcpy = *dhp> ... */ + memcpy((char *)&dfhcpy,(char *)dhp,sizeof(struct defraghdr)); + hdrcrc = dfhcpy.crc; + dfhcpy.crc = 0; + if (crc32((uchar *)&dfhcpy,DEFRAGHDRSIZ) == hdrcrc) { + ftot = dhp->idx + 1; + dhp = (struct defraghdr *)crctbl - ftot; + crc = (ulong *)dhp - 1; + if (crc32((uchar *)dhp, + (uchar *)(tdp->spare+lastssize-1) - (uchar *)dhp) == *crc) { +#if DEFRAG_TEST_ENABLED + printf("TFS: DSI in spare\n"); +#endif + if (scp) + *scp = crctbl; + return(ftot); + } + } + return(0); +} + +/* defragSectorInSpare(): + * For each sector, run a CRC32 on the content of the spare + * using the size of the sector in question. If the calculated + * crc matches that of the table, then we have located the sector + * that has been copied to the spare. + * This is a pain in the butt because we can't just run a CRC32 on + * the spare sector itself because the size of the spare may not match + * the size of the sector that was copied to it. The source sector + * might have been smaller; hence when we calculate the CRC32, we need + * to use the size of the potential source sector. + */ +static int +defragSectorInSpare(TDEV *tdp, struct sectorcrc *crctbl) +{ + uchar *sbase; + struct defraghdr *dhp; + int i, ssize, snum, ftot; + + sbase = (uchar *)tdp->start; + dhp = (struct defraghdr *)crctbl - 1; + ftot = dhp->idx + 1; + + for(i=0;i<tdp->sectorcount;i++) { + addrtosector(sbase,&snum,&ssize,0); + if (i == tdp->sectorcount - 1) { + ssize -= /* CRC table */ + (tdp->sectorcount * sizeof(struct sectorcrc)); + ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */ + ssize -= 4; /* Crc of the tables */ + } + if (crc32((uchar *)tdp->spare,ssize) == crctbl[i].precrc) + return(snum); + sbase += ssize; + } + return(-1); +} + +/* defragTouchedSectors(): + * Step through the crc table and TFS flash space to find the first + * and last sectors that have been touched by defragmentation. + * This is used by defragGetState() to recover from an interrupted + * defragmentation, so a few verbose messages are useful to indicate + * status to the user. + */ +void +defragTouchedSectors(TDEV *tdp,int *first, int *last) +{ + uchar *sbase; + struct defraghdr *dhp; + struct sectorcrc *crctbl; + int i, ssize, snum, ftot; + + *first = -1; + *last = -1; + sbase = (uchar *)tdp->start; + crctbl = defragCrcTable(tdp); + dhp = (struct defraghdr *)crctbl - 1; + ftot = dhp->idx + 1; + + printf("TFS: calculating per-sector crcs... "); + for(i=0;i<tdp->sectorcount;i++) { + addrtosector(sbase,&snum,&ssize,0); + if (i == tdp->sectorcount - 1) { + ssize -= /* CRC table */ + (tdp->sectorcount * sizeof(struct sectorcrc)); + ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */ + ssize -= 4; /* Crc of the tables */ + } + if (crc32(sbase,ssize) != crctbl[i].precrc) { + if (*first == -1) + *first = snum; + *last = snum; + } + sbase += ssize; + defragTick(0); + } + printf("done\n"); + return; +} + +/* defragPostCrcCheck(): + * Return 1 if the post-crc check of the incoming sector number passes; + * else 0. + */ +int +defragPostCrcCheck(TDEV *tdp, int isnum) +{ + uchar *sbase; + struct defraghdr *dhp; + struct sectorcrc *crctbl; + int ftot, i, snum, ssize, lastsnum, lastssize; + + sbase = (uchar *)tdp->start; + crctbl = defragCrcTable(tdp); + dhp = (struct defraghdr *)crctbl - 1; + ftot = dhp->idx + 1; + + addrtosector((uchar *)tdp->end,&lastsnum,&lastssize,0); + + for(i=0;i<tdp->sectorcount;i++) { + addrtosector(sbase,&snum,&ssize,0); + if (snum == isnum) + break; + sbase += ssize; + } + if (isnum == lastsnum) { + ssize -= (tdp->sectorcount * sizeof(struct sectorcrc)); + ssize -= (ftot * DEFRAGHDRSIZ); + ssize -= 4; + } + if (crctbl[i].postcrc == crc32(sbase,ssize)) + return(1); + else + return(0); +} + +/* defragGetStateStr(): + * Return a string that corresponds to the incoming state value. + */ +static char * +defragGetStateStr(int state) +{ + char *str; + + switch(state) { + case SECTOR_DEFRAG_INACTIVE: + str = "SectorDefragInactive"; + break; + case SECTOR_DEFRAG_ABORT_RESTART: + str = "DefragRestartAborted"; + break; + case SCANNING_ACTIVE_SECTOR_1: + str = "ScanningActiveSector1"; + break; + case SCANNING_ACTIVE_SECTOR_2: + str = "ScanningActiveSector2"; + break; + case SCANNING_ACTIVE_SECTOR_3: + str = "ScanningActiveSector3"; + break; + case SCANNING_ACTIVE_SECTOR_4: + str = "ScanningActiveSector4"; + break; + case SCANNING_ACTIVE_SECTOR_5: + str = "ScanningActiveSector5"; + break; + case SECTOR_DEFRAG_ALMOST_DONE: + str = "DefragAlmostDone"; + break; + default: + str = "???"; + break; + } + return(str); +} + +/* defragRestart(): + * Poll the console allowing the user to abort the auto-restart of + * the defragmentation. If a character is received on the console, + * then return 0 indicating that the defrag should not be restarted; + * else return 1. + */ +int +defragRestart(int state,int snum) +{ + printf("TFS defrag restart state: %s sector %d\n", + defragGetStateStr(state),snum); + if (pollConsole("Hit any key to abort...")) + return(0); + return(1); +} + +/* defragGetState(): + * Step through the files in the specified device and check for + * sanity. Return SECTOR_DEFRAG_INACTIVE if it is determined that + * a defragmentation was not in progress; otherwise, return one of + * several different defrag state values depending on what is found + * in the TFS flash area. + * + * NOTE: + * As of Jan 2008, the code wrapped within the ifdef/endif + * ENABLE_FLASHERASED_CHECK_AT_STARTUP is not used by default + * (the macro must be defined in config.h to pull it in). + * This change has been determined to be safe and allows startup + * to be much faster for systems that have a lot of empty TFS + * space. The code was used to verify that all flash space after + * the last stored file in TFS was actually erased. If not, then + * it erases it. + * This turns out to not really be necessary because if tfsadd() + * runs and finds that the area it needs isn't erased, it will + * automatically fall into a tfsclean anyway. As a result, to + * make startup quicker, this code is not enabled by default. If + * it is needed, then just define the macro in config.h. + * + * As of Mar 2011, thanks to input from Jamie Randall, I'm essentially + * undoing the previous change by defining the + * ENABLE_FLASHERASED_CHECK_AT_STARTUP right here. Turns out that + * while removal of this snippet of code does make bootup faster for + * those cases where the flash has a large number of sectors, it does + * cause powersafe defrag to fail in certain cases if a hit occurs. + * + */ +#define ENABLE_FLASHERASED_CHECK_AT_STARTUP /* see note above */ + +static int +defragGetState(TDEV *tdp, int *activesnum) +{ + TFILE *tfp; + struct defraghdr *dhp; + struct sectorcrc *crctbl; + int snum_in_spare, firstsnum; + int first_touched_snum, last_touched_snum; + int break_cause, break1_cause, spare_is_erased, ftot, ftot1, errstate; + + /* Establish state of spare sector: + */ + spare_is_erased = flasherased((uchar *)tdp->spare, + (uchar *)tdp->spare+tdp->sparesize-1); + + ftot = 0; + break_cause = break1_cause = 0; + for(tfp=(TFILE *)tdp->start; tfp < (TFILE *)tdp->end; tfp=tfp->next) { + /* If we are legally at the end of file storage space, then we + * will hit a header size that is ERASED16. If we reach this + * point and the remaining space dedicated to file storage is + * erased and the spare is erased, it is safe to assume that we + * were not in the middle of a defrag. + */ + if (tfp->hdrsize == ERASED16) { +#ifdef ENABLE_FLASHERASED_CHECK_AT_STARTUP /* (see note above) */ + /* Is space from last file to end of TFS space erased? */ + if (!flasherased((uchar *)tfp,(uchar *)tdp->end)) { + break_cause = 1; + break; + } + if (!spare_is_erased) { + break_cause = 2; + break; + } +#if DEFRAG_TEST_ENABLED + printf("\ndefragGetState: inactive_1\n"); +#endif +#endif + return(SECTOR_DEFRAG_INACTIVE); + } + + /* If the crc32 of the header is corrupt, or if the next pointer + * doesn't make any sense, then we must assume that a defrag + * was in progress... + */ + if (tfshdrcrc(tfp) != tfp->hdrcrc) { + break; + } + + if (!(tfp->next) || (tfp->next <= (TFILE *)tdp->start) || + (tfp->next >= (TFILE *)tdp->end)) { + break; + } + if (TFS_FILEEXISTS(tfp)) + ftot++; + } + /* If we are here, then something is not "perfect" with the flash + * space used by TFS. If break_cause is non-zero, there is a chance + * that the only problem is that a file-write was interrupted and + * we did not actually interrupt an in-progress-defrag. An interrupted + * file write would place some incomplete data after the last file. + */ + ftot1 = defragValidDSI(tdp,&crctbl); + + /* If we don't have valid defrag state info (DSI), then we can assume + * that the files in TFS have not yet been touched (since if we had + * touched them, we would have already successfully created the DSI). + * This being the case, then we will not continue with any defrag, + * let TFS clean things up when the space is needed. + */ + if (!ftot1) { + if (break_cause) { + /* Hmmm... Should something be done here? */ + } +#if DEFRAG_TEST_ENABLED + printf("\ndefragGetState: inactive_2\n"); +#endif + return(SECTOR_DEFRAG_INACTIVE); + } + + /* If we get here, then we have a valid defrag header table, so we + * can use it and the state of each of the sectors to figure out + * where we are in the defragmentation process. We need to determine + * which sector was being worked on at the point in time when the + * defragmentation was interrupted. A sector is in the "touched" + * state if a crc32 on its content does not match the crc32 stored + * in the crc table above the defrag header table. + * + * Here we step through the defrag header table and see if each file + * in the header table exists in TFS. If all files exist, then we + * must have been very close to completion of the defrag process. + */ + printf("TFS: scanning DSI space... "); + dhp = (struct defraghdr *)crctbl - ftot1; + while(dhp < (struct defraghdr *)crctbl) { + tfp = (TFILE *)dhp->nda; + if (tfp->hdrcrc != dhp->ohdrcrc) + break; + + if (tfshdrcrc(tfp) != tfp->hdrcrc) { + break1_cause = 1; + break; + } + if (crc32((uchar *)(tfp+1),tfp->filsize) != tfp->filcrc) { + break1_cause = 2; + break; + } + dhp++; + defragTick(0); + } + printf("done\n"); + + /* If we stepped through the entire table, then we've completed the + * file relocation process, but we still have to clean up... + */ + if (dhp >= (struct defraghdr *)crctbl) { + if (defragRestart(SECTOR_DEFRAG_ALMOST_DONE,0)) { + return(SECTOR_DEFRAG_ALMOST_DONE); + } + else { + return(SECTOR_DEFRAG_ABORT_RESTART); + } + } + + if (addrtosector((unsigned char *)tdp->start,&firstsnum,0,0) < 0) { + errstate = 50; + goto state_error; + } + defragTouchedSectors(tdp,&first_touched_snum,&last_touched_snum); + + /* If there are no touched sectors, then we will not continue with + * the defrag because we didn't start relocation of any of the files + * yet. + */ + if (first_touched_snum == -1) { +#if DEFRAG_TEST_ENABLED + printf("\ndefragGetState: inactive_3\n"); +#endif + return(SECTOR_DEFRAG_INACTIVE); + } + + if (spare_is_erased) + snum_in_spare = -1; + else + snum_in_spare = defragSectorInSpare(tdp,crctbl); + +#if DEFRAG_TEST_ENABLED + printf("\ndefragGetState info: %d %d %d\n", + first_touched_snum, last_touched_snum, snum_in_spare); +#endif + + /* At this point we know what sector was the last to be touched. + * What we don't know is whether or not the "touch" was completed. + * So we don't know if the active sector is last_touched_snum or + * last_touched_snum+1. + * The only useful piece of data we 'might' have is the fact that + * the spare may contain the content of the last touched sector. + */ + + /* If the spare is erased, it may be because defrag was just getting + * ready to start working on the next sector (meaning that the active + * sector is last_touched_snum+1) or the sector was in the process of + * being modified. We use the post-crc in the DHT to determine what + * the active sector is... + */ + if (spare_is_erased) { + if (last_touched_snum >= 0) { + if (defragPostCrcCheck(tdp,last_touched_snum)) { + *activesnum = last_touched_snum + 1; + + if (defragRestart(SCANNING_ACTIVE_SECTOR_1,*activesnum)) + return(SCANNING_ACTIVE_SECTOR_1); + else + return(SECTOR_DEFRAG_ABORT_RESTART); + } + else { + if (defragSerase(2,last_touched_snum) < 0) { + errstate = 51; + goto state_error; + } + *activesnum = last_touched_snum; + + if (defragRestart(SCANNING_ACTIVE_SECTOR_2,*activesnum)) + return(SCANNING_ACTIVE_SECTOR_2); + else + return(SECTOR_DEFRAG_ABORT_RESTART); + } + + } + else { + errstate = 52; + goto state_error; + } + } + + /* If the sector copied to spare is one greater than the last touched + * sector, then the active sector is last_touched_snum+1 and it was + * just copied to the spare. In this case we erase the spare and + * return indicating the active sector. + */ + if (snum_in_spare == last_touched_snum+1) { + if (defragEraseSpare(tdp) < 0) { + errstate = 53; + goto state_error; + } + *activesnum = snum_in_spare; + + if (defragRestart(SCANNING_ACTIVE_SECTOR_3,*activesnum)) + return(SCANNING_ACTIVE_SECTOR_3); + else + return(SECTOR_DEFRAG_ABORT_RESTART); + } + + /* If the spare is not erased, but it does not match any of the + * sector CRCs, then we must have been in the process of copying + * the active sector to the spare, so we can erase it and return + * to the SCANNING_ACTIVE_SECTOR state. + */ + if (snum_in_spare == -1) { + if (last_touched_snum >= 0) { + *activesnum = last_touched_snum + 1; + + if (!defragRestart(SCANNING_ACTIVE_SECTOR_4,*activesnum)) + return(SECTOR_DEFRAG_ABORT_RESTART); + + if (defragEraseSpare(tdp) < 0) { + errstate = 54; + goto state_error; + } + return(SCANNING_ACTIVE_SECTOR_4); + } + else { + errstate = 55; + goto state_error; + } + } + + /* If the sector copied to spare is the number of the last touched + * sector, then we were in the middle of modifying the sector, so + * we have to erase that sector, copy the spare to it and return + * to the scanning state. + */ + if (snum_in_spare == last_touched_snum) { + int ssize; + uchar *sbase; + + *activesnum = snum_in_spare; + + if (!defragRestart(SCANNING_ACTIVE_SECTOR_5,*activesnum)) + return(SECTOR_DEFRAG_ABORT_RESTART); + + if (defragSerase(3,snum_in_spare) < 0) { + errstate = 56; + goto state_error; + } + if (sectortoaddr(snum_in_spare,&ssize,&sbase) < 0) { + errstate = 57; + goto state_error; + } + if (defragFwrite(1,sbase,(uchar *)tdp->spare,ssize) < 0) { + errstate = 58; + goto state_error; + } + if (defragEraseSpare(tdp) < 0) { + errstate = 59; + goto state_error; + } + return(SCANNING_ACTIVE_SECTOR_5); + } + + /* If we got here, then we are confused, so don't do any defrag + * continuation... + */ + errstate = 90; + +state_error: + printf("DEFRAG_STATE_ERROR: #%d.\n",errstate); + return(SECTOR_DEFRAG_INACTIVE); +} + +/* inSector(): + * We are trying to figure out if the address space that we want to copy + * from is within the active sector. If it is, then we need to adjust + * our pointers so that we retrieve the at least some of data from the + * spare. + * If the range specified by 'i_base' and 'i_size' overlays (in any way) + * the address space used by the sector specified by 'snum', + * then return the address in the spare and the size of the overlay. + */ +static int +inSector(TDEV *tdp,int snum,uchar *i_base,int i_size,uchar **saddr,int *ovlysz) +{ + int s_size; + uchar *s_base, *s_end, *i_end; + + /* Retrieve information about the sector: */ + if (sectortoaddr(snum,&s_size,&s_base) == -1) + return(TFSERR_MEMFAIL); + + i_end = i_base + i_size; + s_end = s_base + s_size; + + if ((i_end < s_base) || (i_base > s_end)) { + *ovlysz = 0; + return(0); + } + + if (i_base < s_base) { + if (i_end > s_end) { + *ovlysz = s_size; + } + else { + *ovlysz = (i_size - (s_base - i_base)); + } + *saddr = (uchar *)tdp->spare; + } + else { + if (i_end > s_end) { + *ovlysz = (i_size - (i_end - s_end)); + } + else { + *ovlysz = i_size; + } + *saddr = (uchar *)tdp->spare + (i_base - s_base); + } + return(0); +} + +/* struct fillinfo & FILLMODE definitions: + * Structure used by the "Fill" functions below. + */ +#define FILLMODE_FWRITE 1 /* Do the flash write */ +#define FILLMODE_SPAREOVERLAP 2 /* Determine if there is SPARE overlap */ +#define FILLMODE_CRCONLY 3 /* Calculate a 32-bit crc on the data */ + +struct fillinfo { + struct defraghdr *dhp; /* pointer to defrag header table */ + TDEV *tdp; /* pointer to TFS device */ + ulong crc; /* used in FILLMODE_CRCONLY mode */ + int crcsz; /* size of crc calculation */ + int fhdr; /* set if we're working on a file header */ + int asnum; /* the active sector */ + int mode; /* see FILLMODE_xxx definitions */ +}; + +/* defragFillFlash(): + * This function is called by the defragFillActiveSector() function + * below. It covers the four different cases of a file spanning over + * the active sector, plus it deals with the possibility that the source + * of the file data may be the same sector as the active one (meaning that + * the source is taken from the spare). It is within this function that + * the active sector is actually modified and it assumes that the portion + * of the active sector to be written to is already erased. + * + * + * SPANTYPE_BCEC: + * In this case, the file starts in the active sector and ends in + * the active sector... + * -----------|----------|----------|----------|---------|---------|---------- + * | | | | | | | | + * | | |<-active->| | | | SPARE | + * | | | sector | | | | SECTOR | + * | | | | | | | | + * | | | newfile | | | | | + * | | | |<-->| | | | | | + * -----------|----------|----------|----------|---------|---------|---------- + * + * + * SPANTYPE_BPEC: + * In this case, the file starts in a sector prior to the currently active + * sector and ends in the active sector... + * -----------|----------|----------|----------|---------|---------|---------- + * | | | | | | | | + * | | | |<-active->| | | SPARE | + * | | | | sector | | | SECTOR | + * | | | | | | | | + * | | |<----newfile----->| | | | | + * | | | | | | | | + * -----------|----------|----------|----------|---------|---------|---------- + * + * + * SPANTYPE_BPEL: + * In this case, the file starts in some sector prior to the currently + * active sector and ends in some sector after the currently active + * sector... + * -----------|----------|----------|----------|---------|---------|---------- + * | | | | | | | | + * | | |<-active->| | | | SPARE | + * | | | sector | | | | SECTOR | + * | | | | | | | | + * | |<---------- newfile------------------->| | | | + * | | | | | | | | + * -----------|----------|----------|----------|---------|---------|---------- + * + * + * SPANTYPE_BCEL: + * In this case, the file starts in the active sector and ends in + * a later sector. + * -----------|----------|----------|----------|---------|---------|---------- + * | | | | | | | | + * | |<-active->| | | | | SPARE | + * | | sector | | | | | SECTOR | + * | | | | | | | | + * | | |<----newfile----->| | | | | + * | | ****| | | | | | + * -----------|----------|----------|----------|---------|---------|---------- + */ +static int +defragFillFlash(struct fillinfo *fip,int spantype,char **activeaddr,int verbose) +{ + char *hp; + TFILE nfhdr; + struct defraghdr *dhp; + int ohdroffset, nhdroffset; + uchar *ovly, *src, *activesbase; + int ovlysz, srcsz, activessize; + + src = 0; + ovly = 0; + srcsz = 0; + nhdroffset = ohdroffset = 0; + dhp = fip->dhp; + + if (verbose >= 2) { + printf(" defragFillFlash %s %s (%s %d)\n",fip->fhdr ? "hdr" : "dat", + defragGetSpantypeStr(spantype), dhp->fname,fip->asnum); + } + + if (spantype == SPANTYPE_BCEC) { + if (fip->fhdr) { + src = (uchar *)dhp->ohdr; + srcsz = TFSHDRSIZ; + } + else { + src = (uchar *)dhp->ohdr+TFSHDRSIZ; + srcsz = dhp->filsize; + } + } + else if (spantype == SPANTYPE_BPEC) { + if (fip->fhdr) { + /* Calculate the offset into the header at which point a + * sector boundary occurs. Do this for both the old (before + * defrag relocation) and new (after defrag relocation) + * location of the header. + */ + /* Changed as of Dec 2010, based on error found by Leon... + * We need to figure out how the header overlaps the sector + * boundary. Prior to 12/2010, this code did not account for + * the case where the file size spans beyond the currently + * active sector. + */ + if ((dhp->neso > dhp->filsize) && (dhp->oeso > dhp->filsize)) { + nhdroffset = TFSHDRSIZ - (dhp->neso - dhp->filsize); + ohdroffset = TFSHDRSIZ - (dhp->oeso - dhp->filsize); + srcsz = (dhp->oeso - dhp->filsize) + (ohdroffset - nhdroffset); + src = (uchar *)dhp->ohdr + nhdroffset; + } + else { + int ssz; + int sno = dhp->nesn; + int fsz = dhp->filsize; + while(sno > fip->asnum) { + if (sectortoaddr(sno,&ssz,0) < 0) + return(TFSERR_MEMFAIL); + if (fsz == dhp->filsize) + fsz -= dhp->neso; + else + fsz -= ssz; + sno--; + } + if (sectortoaddr(fip->asnum,&ssz,0) < 0) + return(TFSERR_MEMFAIL); + srcsz = ssz - fsz; + src = (uchar *)dhp->ohdr; + src += (TFSHDRSIZ-srcsz); + nhdroffset = (TFSHDRSIZ-srcsz); + } + } + else { + src = (uchar *)dhp->ohdr + TFSHDRSIZ + (dhp->filsize - dhp->neso); + srcsz = dhp->neso; + } + } + else if (spantype == SPANTYPE_BCEL) { + if (sectortoaddr(fip->asnum,&activessize,&activesbase) == -1) + return(TFSERR_MEMFAIL); + + if (fip->fhdr) { + src = (uchar *)dhp->ohdr; + } + else { + src = (uchar *)dhp->ohdr+TFSHDRSIZ; + } + srcsz = (activesbase + activessize) - (uchar *)*activeaddr; + } + else if (spantype == SPANTYPE_BPEL) { + if (sectortoaddr(fip->asnum,&activessize,0) == -1) + return(TFSERR_MEMFAIL); + + if (fip->fhdr) { + src = (uchar *)dhp->ohdr; + } + else { + src = (uchar *)dhp->ohdr+TFSHDRSIZ; + } + + src += ((*activeaddr - dhp->nda) - TFSHDRSIZ); + srcsz = activessize; + } + else { + return(0); + } + + /* Do some error checking on the computed size: + */ + if (srcsz < 0) { + printf("defragFillFlash: srcsz < 0\n"); + return(TFSERR_MEMFAIL); + } + + if (fip->fhdr) { + if (srcsz > TFSHDRSIZ) { + printf("defragFillFlash: srcsz > TFSHDRSIZ\n"); + return(TFSERR_MEMFAIL); + } + } + else { + if (srcsz > dhp->filsize) { + printf("defragFillFlash: srcsz > filsize\n"); + return(TFSERR_MEMFAIL); + } + } + + /* Determine if any portion of the source was part of the sector that + * is now the active sector.. If yes (ovlysz > 0), then we must + * deal with the fact that some (or all) of the fill source is in the + * spare sector... + */ + if (inSector(fip->tdp,fip->asnum,src,srcsz,&ovly,&ovlysz) < 0) + return(TFSERR_MEMFAIL); + + /* If the mode is not FILLMODE_FWRITE, then we don't do any of the + * flash operations. We are in this function only to determine + * if we need to copy the active sector to the spare prior to + * starting the modification of the active sector. + */ + if (fip->mode == FILLMODE_FWRITE) { + if (fip->fhdr) { + hp = (char *)&nfhdr; + if (ovlysz) { + memcpy((char *)hp+nhdroffset,(char *)ovly,ovlysz); + if (ovlysz != srcsz) { + memcpy(hp+nhdroffset+ovlysz,(char *)src+ovlysz, + srcsz-ovlysz); + } + } + else { + /* next line was <nfhdr = *dhp->ohdr> ... */ + memcpy((char *)&nfhdr,(char *)dhp->ohdr,sizeof(TFILE)); + } + nfhdr.next = dhp->nextfile; + if (defragFwrite(2,(uchar *)*activeaddr,(uchar *)hp+nhdroffset,srcsz) == -1) + return(TFSERR_FLASHFAILURE); + } + else { + if (ovlysz) { + if (defragFwrite(3,(uchar *)*activeaddr,(uchar *)ovly,ovlysz) == -1) + return(TFSERR_FLASHFAILURE); + if (ovlysz != srcsz) { + if (defragFwrite(4,(uchar *)*activeaddr+ovlysz,(uchar *)src+ovlysz, + srcsz-ovlysz) == -1) + return(TFSERR_FLASHFAILURE); + } + } + else { + if (defragFwrite(5,(uchar *)*activeaddr,(uchar *)src,srcsz) == -1) + return(TFSERR_FLASHFAILURE); + } + } + } + else if (fip->mode == FILLMODE_CRCONLY) { + register uchar *bp; + int sz, temp; + + if (fip->fhdr) { + hp = (char *)&nfhdr; + /* next line was <nfhdr = *dhp->ohdr> ... */ + memcpy((char *)&nfhdr,(char *)dhp->ohdr,sizeof(TFILE)); + nfhdr.next = dhp->nextfile; + bp = (uchar *)hp + nhdroffset; + } + else { + bp = (uchar *)src; + } + sz = srcsz; + fip->crcsz += sz; + while(sz) { + temp = (fip->crc ^ *bp++) & 0x000000FFL; + fip->crc = ((fip->crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp]; + sz--; + } + } + *activeaddr += srcsz; + + if ((spantype == SPANTYPE_BCEC || spantype == SPANTYPE_BPEC) && + (!fip->fhdr) && ((ulong)*activeaddr & 0xf)) { + int sz, temp, modfixsize; + + modfixsize = (TFS_FSIZEMOD - ((ulong)*activeaddr & (TFS_FSIZEMOD-1))); + *activeaddr += modfixsize; + if (fip->mode == FILLMODE_CRCONLY) { + sz = modfixsize; + fip->crcsz += sz; + while(sz) { + temp = (fip->crc ^ 0xff) & 0x000000FFL; + fip->crc = ((fip->crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp]; + sz--; + } + } + } + + /* Return ovlysz so that the caller will know if this function + * needed the spare sector. This is used in the "mode = SPARE_OVERLAP" + * pass of defragFillActiveSector(). + */ + return(ovlysz); +} + +/* defragFillActiveSector(): + * This and defragFillFlash() are the workhorses of the tfsclean() function. + * The bulk of this function is used to determine if we need to do anything + * to the active sector and if so, do we need to copy the active sector to + * the spare prior to erasing it. + * The first loop in this function determines whether we need to do anything + * at all with this sector (it may not be touched by the defragmentation). + * The second loop determines if we have to copy the active sector to the + * spare prior to erasing the active sector. + * The final loop in this function does the call to defragFillFlash() + * to do the actual flash writes. + */ +static int +defragFillActiveSector(TDEV *tdp, int ftot, int snum, int verbose) +{ + int firstsnum; /* number of first TFS sector */ + int activesnum; /* number of sector currently being written to */ + int activessize; /* size of active sector */ + char *activeaddr; /* offset being written to in the active sector */ + uchar *activesbase; /* base address of active sector */ + char *activesend; /* end address of active sector */ + struct defraghdr *sdhp;/* pointer into defrag hdr table in spare */ + struct defraghdr *dhp; /* pointer into defrag header table */ + int fullsize; /* size of file and header */ + char *new_dend; /* new end of data */ + char *new_dbase; /* new base of data */ + char *new_hend; /* new end of header */ + char *new_hbase; /* new base of header */ + char *new_fend; /* new end of file */ + char *new_fbase; /* new base of file */ + int new_fspan; /* span type for new file */ + int new_hspan; /* span type for new header */ + int new_dspan; /* span type for new data */ + int fillstat; /* result of defragFillFlash() function call */ + int noreloctot; /* number of files spanning the active sector */ + /* that do not have to be relocated */ + int tmptot; /* temps used for the "SPARE_OVERLAP" mode */ + char *tmpactiveaddr; + struct defraghdr *tmpdhp; + struct fillinfo finfo; + struct sectorcrc *crctbl; + int lastsnum, tot; + int copytospare; + int lastfileisnotrelocated; + + /* Retrieve number of first TFS sector: */ + if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0) + return(TFSERR_MEMFAIL); + + activesnum = snum + firstsnum; + crctbl = defragCrcTable(tdp); + + /* Retrieve information about active sector: */ + if (sectortoaddr(activesnum,&activessize,&activesbase) == -1) + return(TFSERR_MEMFAIL); + + if (verbose) + printf(" Active sector: %3d @ 0x%lx\n",activesnum,(ulong)activesbase); + + if (addrtosector((uchar *)tdp->end,&lastsnum,0,0) < 0) + return(TFSERR_MEMFAIL); + + /* Establish a pointer to the defrag header table. + * For the case when the active sector is the last sector, the defrag + * header table will be in the spare, so we also establish a pointer + * to that space... + */ + dhp = (struct defraghdr *)crctbl; + dhp -= ftot; + sdhp = (struct defraghdr *)(tdp->spare+activessize - + (tdp->sectorcount * sizeof(struct sectorcrc))); + sdhp -= ftot; + + activeaddr = (char *)activesbase; + tmpactiveaddr = (char *)activesbase; + activesend = (char *)activesbase + activessize - 1; + + /* FIRST LOOP: + * See if we need to do anything... + * In this state, we are simply checking to see if anything is going + * to cause the currently active sector to be written to. + * If yes, then we need to copy it to the spare and start the + * modification process; else, we just return and do nothing + * to this sector. + * For each file in the defrag header table that is destined for + * the address space occupied by the currently active sector, copy + * that file (header and data) to the active sector... + * Note that it may only be a partial copy, depending on the size + * of the file and the amount of space left in the active sector. + */ + + noreloctot = 0; + new_fspan = SPANTYPE_UNDEF; + lastfileisnotrelocated = 0; + for(tot=0;tot<ftot;tot++,dhp++,sdhp++) { + fullsize = TFSHDRSIZ + dhp->filsize; + new_fbase = dhp->nda; + new_fend = (new_fbase + fullsize); + + /* We must figure out how the new version of the file will + * span across the active sector. + * See defragGetSpantype() for details. + */ + new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_fbase,(char *)new_fend); + + /* If the file we are looking at entirely spans a sector that is + * prior to the currently active sector, then we just continue + * through the list. + * If the file entirely spans a sector that is after the + * currently active sector, then we are done with this active sector. + * If the file falls within the active sector in any way, and its + * new location does not match its old location, then we + * break out of this loop and begin the modification of this + * active sector... + */ + if (new_fspan == SPANTYPE_BLEL) + return(0); + + if (new_fspan != SPANTYPE_BPEP) { + if (dhp->nda == (char *)dhp->ohdr) { + noreloctot++; + if (tot == ftot-1) { + lastfileisnotrelocated = 1; + if (verbose > 1) + printf(" last file not relocated\n"); + } + } + else + break; + } + } + + /* If tot == ftot, then we got through the entire loop above without + * finding a file that needs to be relocated into this active sector. + * This means one of two things: either all the files fall into a + * sector prior to this active sector, or the files in this active + * sector do not need to be relocated. In either case, we simply + * return without touching this sector. + * Note that we also keep track of the possibility that the last file + * may not be relocated. If this ends up to be the case, then we are + * simply cleaning up one or more dead files after a full set of active + * files, so we should clean up the sector. + */ + if ((tot == ftot) && (lastfileisnotrelocated == 0)) + return(0); + + /* If tot != ftot, then we must subtract noreloctot from tot so that + * we establish 'tot' as the index into the first file that must be + * copied to the active sector... + */ + if (noreloctot) { + tot -= noreloctot; + dhp -= noreloctot; + sdhp -= noreloctot; + } + + /* Exit immediately before cleaning up the spare... */ + defragExitTestPoint(10000+activesnum); + + /* Since we got here, we know that we have to do some work on the + * currently active sector. We may not have to copy it to the spare, + * but we will erase the spare anyway because the sector erase is + * supposed to be smart enough to avoid the erase if it is already + * erased. This should be handled by the flash driver because in + * ALL cases the erase should be avoided if possible. + */ + if (defragEraseSpare(tdp) < 0) + return(TFSERR_FLASHFAILURE); + + /* Exit immediately after cleaning up the spare... */ + defragExitTestPoint(10001+activesnum); + + /* If the active sector is the last sector (which would contain the + * defrag header table), then we reference the copy of the table that + * is in the spare... + * Also, if this is the last sector, then we HAVE to copy it to + * spare, so we can skip the 2nd loop that attempts to determine + * if we need to do it. + */ + if (activesnum == lastsnum) { + dhp = sdhp; + copytospare = 1; + } + else { + /* SECOND LOOP: + * See if we need to copy the active sector to the spare... + * We do this by continuing the loop we started above. Notice that + * we do an almost identical loop again below this. + * On this pass through the loop we are only checking to see if it is + * necessary to copy this active sector to the spare. + */ + tmptot = tot; + tmpdhp = dhp; + copytospare = 0; + finfo.mode = FILLMODE_SPAREOVERLAP; + for(;tmptot<ftot;tmptot++,tmpdhp++) { + finfo.tdp = tdp; + finfo.dhp = tmpdhp; + finfo.asnum = activesnum; + + fullsize = TFSHDRSIZ + tmpdhp->filsize; + new_fbase = tmpdhp->nda; + new_fend = (new_fbase + fullsize); + + new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_fbase,(char *)new_fend); + + if (new_fspan == SPANTYPE_BPEP) + continue; + else if (new_fspan == SPANTYPE_BLEL) + break; + + /* Now retrieve span information about header and data + * portions of the file (new and orig)... + */ + new_hbase = new_fbase; + new_hend = new_hbase + TFSHDRSIZ; + new_dbase = new_hbase + TFSHDRSIZ; + new_dend = new_fend; + + new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_hbase,(char *)new_hend); + new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_dbase,(char *)new_dend); + + /* If defragFillFlash() returns positive (with mode == + * FILLMODE_SPAREOVERLAP set above), then we know that the + * spare sector must be loaded with a copy of this active + * sector, so we can break out of this loop at that point... + */ + finfo.fhdr = 1; + fillstat = defragFillFlash(&finfo,new_hspan,&tmpactiveaddr,verbose); + if (fillstat < 0) + return(fillstat); + if (fillstat > 0) { + copytospare = 1; + break; + } + if (new_hspan == SPANTYPE_BCEL) + break; + + finfo.fhdr = 0; + fillstat = defragFillFlash(&finfo,new_dspan,&tmpactiveaddr,verbose); + if (fillstat < 0) + return(fillstat); + if (fillstat > 0) { + copytospare = 1; + break; + } + if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL) + break; + } + } + + finfo.mode = FILLMODE_FWRITE; + + defragExitTestPoint(10002+activesnum); + + if (copytospare) { + defragTick(verbose); +#if DEFRAG_TEST_ENABLED + printf(" copying sector %d to spare\n",activesnum); +#endif + if (defragFwrite(6,(uchar *)tdp->spare,activesbase,activessize) == -1) { + printf("Failed to copy active %d to spare\n",activesnum); + return(TFSERR_FLASHFAILURE); + } + } +#if DEFRAG_TEST_ENABLED + else { + printf(" copy saved\n"); + } +#endif + + defragTick(verbose); + + /* We can now begin actual modification of the active sector, + * so start off by eraseing it... + */ + defragExitTestPoint(10003+activesnum); + + if (defragSerase(4,activesnum) < 0) + return(TFSERR_FLASHFAILURE); + + defragExitTestPoint(10004+activesnum); + + /* THIRD LOOP: + * Now we pass through the loop to do the real flash modifications... + */ + for(;tot<ftot;tot++,dhp++) { + finfo.tdp = tdp; + finfo.dhp = dhp; + finfo.asnum = activesnum; + + fullsize = TFSHDRSIZ + dhp->filsize; + new_fbase = dhp->nda; + new_fend = (new_fbase + fullsize); + + new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_fbase,(char *)new_fend); + + if (new_fspan == SPANTYPE_BPEP) + continue; + else if (new_fspan == SPANTYPE_BLEL) + break; + + if (verbose) + printf(" File: %s\n",dhp->fname); + + /* Now retrieve span information about header and data + * portions of the file (new and orig)... + */ + new_hbase = new_fbase; + new_hend = new_hbase + TFSHDRSIZ; + new_dbase = new_hbase + TFSHDRSIZ; + new_dend = new_fend; + + new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_hbase,(char *)new_hend); + new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_dbase,(char *)new_dend); + + /* At this point we have all the information we need to copy + * the appropriate amount of the file from orignal space + * to new space. + * We have to break the write up into two parts, the header + * (new_hspan) and the data (new_dspan) so we have to look + * at the spantype for each to determine what part of the + * header and/or data we are going to copy. + * + * Also, we must consider the possibility that the source + * data may be in the spare sector. This would be the case + * if the active sector is the same sector that the original + * data was in. If the source data is in the spare sector, + * then an added complication is the fact that it may not + * all be there, we may have to copy some from the spare, + * then some from the original space. + */ + finfo.fhdr = 1; + fillstat = defragFillFlash(&finfo,new_hspan,&activeaddr,verbose); + if (fillstat < 0) + return(fillstat); + if (new_hspan == SPANTYPE_BCEL) + break; + + finfo.fhdr = 0; + fillstat = defragFillFlash(&finfo,new_dspan,&activeaddr,verbose); + if (fillstat < 0) + return(fillstat); + if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL) + break; + defragTick(verbose); + } + return(0); +} + +static int +defragNewSectorCrc(TDEV *tdp, struct defraghdr *dht, int snum, + ulong *newcrc, int verbose) +{ + int firstsnum; /* number of first TFS sector */ + int activesnum; /* number of sector currently being written to */ + int activessize; /* size of active sector */ + char *activeaddr; /* offset being written to in the active sector */ + uchar *activesbase; /* base address of active sector */ + char *activesend; /* end address of active sector */ + struct defraghdr *dhp; /* pointer into defrag header table */ + int fullsize; /* size of file and header */ + char *new_dend; /* new end of data */ + char *new_dbase; /* new base of data */ + char *new_hend; /* new end of header */ + char *new_hbase; /* new base of header */ + char *new_fend; /* new end of file */ + char *new_fbase; /* new base of file */ + int new_fspan; /* span type for new file */ + int new_hspan; /* span type for new header */ + int new_dspan; /* span type for new data */ + int fillstat; /* result of defragFillFlash() function call */ + int ftot; + struct fillinfo finfo; + struct sectorcrc *crctbl; + int lastsnum, tot, sz, temp; + + /* Retrieve number of first TFS sector: */ + if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0) + return(TFSERR_MEMFAIL); + + activesnum = snum + firstsnum; + crctbl = defragCrcTable(tdp); + + /* Retrieve information about active sector: */ + if (sectortoaddr(activesnum,&activessize,&activesbase) == -1) + return(TFSERR_MEMFAIL); + + if (addrtosector((uchar *)tdp->end,&lastsnum,0,0) < 0) + return(TFSERR_MEMFAIL); + + dhp = (struct defraghdr *)crctbl - 1; + ftot = dhp->idx + 1; + dhp = dht; + activeaddr = (char *)activesbase; + activesend = (char *)activesbase + activessize - 1; + + finfo.tdp = tdp; + finfo.crcsz = 0; + finfo.crc = 0xffffffff; + finfo.asnum = activesnum; + finfo.mode = FILLMODE_CRCONLY; + + for(tot=0;tot<ftot;tot++,dhp++) { + finfo.dhp = dhp; + + fullsize = TFSHDRSIZ + dhp->filsize; + new_fbase = dhp->nda; + new_fend = (new_fbase + fullsize); + + new_fspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_fbase,(char *)new_fend); + + if (new_fspan == SPANTYPE_BPEP) + continue; + else if (new_fspan == SPANTYPE_BLEL) + break; + + /* Now retrieve span information about header and data + * portions of the file (new and orig)... + */ + new_hbase = new_fbase; + new_hend = new_hbase + TFSHDRSIZ; + new_dbase = new_hbase + TFSHDRSIZ; + new_dend = new_fend; + + new_hspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_hbase,(char *)new_hend); + new_dspan = defragGetSpantype((char *)activesbase,(char *)activesend, + (char *)new_dbase,(char *)new_dend); + + finfo.fhdr = 1; + fillstat = defragFillFlash(&finfo,new_hspan,&activeaddr,verbose); + if (fillstat < 0) + return(fillstat); + if (new_hspan == SPANTYPE_BCEL) + break; + + finfo.fhdr = 0; + fillstat = defragFillFlash(&finfo,new_dspan,&activeaddr,verbose); + if (fillstat < 0) + return(fillstat); + if (new_dspan == SPANTYPE_BCEL || new_dspan == SPANTYPE_BPEL) + break; + } + sz = activessize - finfo.crcsz; + + /* If this is the last sector, then we must not include the space used + * for defrag state storage in the crc calculation. + * We deduct size of CRC table, DHT table and the crc of the DSI space... + */ + if (activesnum == lastsnum) { + sz -= (tdp->sectorcount * sizeof(struct sectorcrc)); + sz -= (ftot * DEFRAGHDRSIZ); + sz -= 4; + } + while(sz) { + temp = (finfo.crc ^ 0xff) & 0x000000FFL; + finfo.crc = ((finfo.crc >> 8) & 0x00FFFFFFL) ^ crc32tab[temp]; + sz--; + } + *newcrc = ~finfo.crc; + return(0); +} + +/* defragBuildCrcTable(): + * Build the table of sector crcs. + * This consists of a set of CRCs representing each sector + * before defrag starts and after defrag has completed. + * One set for each sector. This table is then used if the + * defrag process is interrupted to determine the state of + * the interrupted defragmentation process. + */ +int +defragBuildCrcTable(TDEV *tdp, struct defraghdr *dht, int verbose) +{ + ulong crc; + uchar *sbase; + int i, ssize, dhstsize; + struct sectorcrc *crctbl; + + dhstsize = (ulong)(tdp->end+1) - (ulong)dht + 4; + crctbl = defragCrcTable(tdp); + + /* The pre-defrag crc table... + * This one's easy because it is simply a crc for each of the current + * sectors. + */ + sbase = (uchar *)tdp->start; + for(i=0;i<tdp->sectorcount;i++) { + if (addrtosector(sbase,0,&ssize,0) < 0) + return(-1); + + if (i == tdp->sectorcount-1) + ssize -= dhstsize; + + /* The pre-defrag crc: */ + crc = crc32(sbase,ssize); + if (defragFwrite(7,(uchar *)&crctbl[i].precrc, + (uchar *)&crc,4) == -1) { + return(-1); + } + + /* The post-defrag crc: */ + if (defragNewSectorCrc(tdp,dht,i,&crc,verbose) < 0) + return(-1); + + if (defragFwrite(8,(uchar *)&crctbl[i].postcrc, + (uchar *)&crc,4) == -1) { + return(-1); + } + + sbase += ssize; + + defragTick(0); + } + return(0); +} + +/* _tfsclean(): + * This is the front-end of the defragmentation process, following are the + * basic steps of defragmentation... + * + * Build the Defrag State Information (DSI) area: + * 1. Create a table of 32-bit CRCs, two for each sector. One is the CRC + * of the sector prior to beginning defragmentation and the other is + * what will be the CRC of the sector after defragmentation has completed. + * These CRCs are used to help recover from an interrupted defragmentation. + * 2. Create a table of struct defraghdr structures, one for each file in + * TFS that is currently active (not dead). + * 3. Create a CRC of the tables created in steps 1 & 2. + * + * The data created in steps 1-3 is stored at the end of the last sector + * used by TFS for file storage. After this is created, the actual flash + * defragmentation process starts. + * + * File relocation: + * 4. Step through each sector in TFS flash space, process each file whose + * relocated space overlaps with that sector. As each sector is being + * re-built, the original version of that sector is stored in the spare. + * + * End of flash cleanup: + * 5. Run through the remaining, now unsused, space in TFS flash and make + * sure it is erased. + * + * File check: + * 6. Run a check of all of the relocated files to make sure everything is + * still sane. + * + * Defragmentation success depends on some coordination with tfsadd()... + * Whenever a file is added to TFS, tfsadd() must verify that the space + * needed for defrag overhead (defrag state & header tables) will be + * available. Also, tfsadd() must make sure that the defrag overhead will + * always fit into one sector (the sector just prior to the spare). + */ + +int +_tfsclean(TDEV *tdp, int restart, int verbose) +{ + int dhstsize; /* Size of state table overhead */ + int firstsnum; /* Number of first sector in TFS device. */ + int lastsnum; /* Number of last sector in TFS device. */ + int lastssize; /* Size of last sector in TFS device. */ + uchar *lastsbase; /* Base address of last sector in TFS device. */ + int sectorcheck; /* Used to verify proper TFS configuration. */ + struct defraghdr *dht; /* Pointer to defrag header table. */ + int chkstat; /* Result of tfscheck() after defrag is done. */ + int ftot; /* Total number of active files in TFS. */ + int dtot; /* Total number of deleted files in TFS. */ + int fcnt; /* Running file total, used in hdrtbl build. */ + TFILE *tfp; /* Misc file pointer */ + char *newaddress; /* Used to calculate "new" location of file. */ + struct defraghdr dfhdr; /* Used to build defrag header table. */ + int activesnum; /* Sector being worked on restarted defrag. */ + struct sectorcrc *crctbl; /* Pointer to table of per-sector crcs. */ + int defrag_state; + int sidx, snum; + char *end; + + if (TfsCleanEnable < 0) + return(TFSERR_CLEANOFF); + + /* If incoming TFS device pointer is NULL, return error + */ + if (!tdp) + return(TFSERR_BADARG); + + activesnum = 0; + + /* If the 'restart' flag is set, then we only want to do a defrag if + * we determine that one is already in progress; so we have to look at + * the current state of the defrag state table to figure out if a defrag + * was active. If not, just return. + */ + if (restart) { + defrag_state = defragGetState(tdp,&activesnum); + switch(defrag_state) { + case SECTOR_DEFRAG_INACTIVE: + case SECTOR_DEFRAG_ABORT_RESTART: + return(TFS_OKAY); + case SCANNING_ACTIVE_SECTOR_1: + case SCANNING_ACTIVE_SECTOR_2: + case SCANNING_ACTIVE_SECTOR_3: + case SCANNING_ACTIVE_SECTOR_4: + case SCANNING_ACTIVE_SECTOR_5: + defrag_state = SCANNING_ACTIVE_SECTOR; + break; + } + } + else { + defrag_state = SECTOR_DEFRAG_INACTIVE; + } + + if (verbose || restart || (!MFLAGS_NODEFRAGPRN())) { + printf("TFS device '%s' powersafe defragmentation\n",tdp->prefix); + if ((restart) && pollConsole("ok?")) { + printf("aborted\n"); + return(TFS_OKAY); + } + } + + if (addrtosector((uchar *)tdp->start,&firstsnum,0,0) < 0) + return(TFSERR_MEMFAIL); + lastsnum = firstsnum + tdp->sectorcount - 1; + if (addrtosector((uchar *)tdp->end,§orcheck,0,0) < 0) + return(TFSERR_MEMFAIL); + if (lastsnum != sectorcheck) { + /* If this error occurs, it is an indication that TFS was not + * properly configured in config.h, this error should not occur + * if TFS is properly configured. + */ + printf("%s: SECTORCOUNT != TFSSTART <-> TFSEND\n", tdp->prefix); + printf("First TFS sector = %d, last = %d\n",firstsnum,sectorcheck); + return(TFSERR_MEMFAIL); + } + + if (defrag_state == SECTOR_DEFRAG_INACTIVE) { + activesnum = firstsnum; + } + + /* Retrieve information about last sector: + */ + if (sectortoaddr(lastsnum,&lastssize,&lastsbase) == -1) + return(TFSERR_MEMFAIL); + + /* Establish a pointer to a table of CRCs that will contain + * one 32-bit CRC for each sector (prior to starting the defrag). + */ + crctbl = defragCrcTable(tdp); + + /* Retrieve the number of "dead" and "living" files: + * If there are no dead files, then there is no need to defrag. + * If there are no "living" files, then we can just init the flash. + */ + ftot = dtot = 0; + if (restart && defragValidDSI(tdp,0)) { + dht = (struct defraghdr *)crctbl - 1; + ftot = dht->idx + 1; + } + else { + tfp = (TFILE *)tdp->start; + while(validtfshdr(tfp)) { + if (TFS_FILEEXISTS(tfp)) + ftot++; + else + dtot++; + tfp = nextfp(tfp,tdp); + } + if (dtot == 0) { + if (verbose) + printf("No dead files in %s.\n",tdp->prefix); + if (tfsflasherased(tdp,verbose)) + return(0); + if (verbose) + printf("Cleaning up end of flash...\n"); + } + } + if (ftot == 0) { + if (verbose) + printf("No active files detected, erasing all %s flash...\n", + tdp->prefix); + _tfsinit(tdp); + return(0); + } + + /* Now that we know how many files are in TFS, we can establish + * a pointer to the defrag header table, and the size of the table... + */ + dht = (struct defraghdr *)crctbl - ftot; + dhstsize = (ulong)(tdp->end+1) - (ulong)dht; + dhstsize += 4; /* Account for the CRC of the state tables. */ + + if (defrag_state == SECTOR_DEFRAG_INACTIVE) { + ulong crc; + + if (verbose) { + printf("TFS defrag: building DSI space...\n"); + } + + /* We start by making sure that the space needed by the + * defrag header and state table at the end of the last + * sector is clear... + */ + if (!flasherased((uchar *)dht, (uchar *)(tdp->end))) { + if (defragEraseSpare(tdp) < 0) + return(TFSERR_FLASHFAILURE); + + if (defragFwrite(9,(uchar *)(tdp->spare),lastsbase, + lastssize-dhstsize) == -1) { + return(TFSERR_FLASHFAILURE); + } + if (defragSerase(5,lastsnum) < 0) { + return(TFSERR_FLASHFAILURE); + } + if (defragFwrite(10,lastsbase,(uchar *)(tdp->spare), + lastssize) == -1) { + return(TFSERR_FLASHFAILURE); + } + } + + /* Erase the spare then copy the portion of the last TFS + * sector that does not overlap with the defrag header and + * state table area to the spare. We do this so that the spare + * sector contains a defrag header and state table area that + * is erased. + */ + if (defragEraseSpare(tdp) < 0) + return(TFSERR_FLASHFAILURE); + + if (defragFwrite(11,(uchar *)tdp->spare, + lastsbase,lastssize-dhstsize) == -1) { + return(TFSERR_FLASHFAILURE); + } + + /* At this point we have a valid copy of the last sector in + * the spare. If any portion of the last sector is not identical + * to what is in the spare, then we need to erase the last sector + * and re-copy what is in the spare to the last sector. This is + * necessary because an interrupt may have occurred while writing + * to the last sector, and it may have corrupted something. + */ + + if ((memcmp((char *)lastsbase,(char *)(tdp->spare),lastssize-dhstsize)) || + (!flasherased((uchar *)dht,(uchar *)tdp->end))) { + if (defragSerase(6,lastsnum) < 0) { + return(TFSERR_FLASHFAILURE); + } + if (defragFwrite(12,lastsbase,(uchar *)(tdp->spare), + lastssize) == -1) { + return(TFSERR_FLASHFAILURE); + } + } + /* Build the header table: + */ + fcnt = 0; + tfp = (TFILE *)tdp->start; + newaddress = (char *)tdp->start; + + if (verbose > 2) { + printf("\nDEFRAG HEADER DATA (dht=0x%lx, ftot=%d):\n", + (ulong)dht,ftot); + } + + while(validtfshdr(tfp)) { + if (TFS_FILEEXISTS(tfp)) { + uchar *base, *eof, *neof, *nbase; + int size, slot; + struct tfsdat *slotptr; + + strcpy(dfhdr.fname,TFS_NAME(tfp)); + dfhdr.ohdr = tfp; + dfhdr.ohdrcrc = tfp->hdrcrc; + dfhdr.filsize = TFS_SIZE(tfp); + if (addrtosector((uchar *)tfp,0,0,&base) < 0) + return(TFSERR_MEMFAIL); + + eof = (uchar *)(tfp+1)+TFS_SIZE(tfp)-1; + if (addrtosector((uchar *)eof,0,0,&base) < 0) + return(TFSERR_MEMFAIL); + dfhdr.oeso = eof - base + 1; + + neof = (uchar *)newaddress+TFSHDRSIZ+TFS_SIZE(tfp)-1; + if (addrtosector((uchar *)neof,&dfhdr.nesn,0,&nbase) < 0) + return(TFSERR_MEMFAIL); + dfhdr.neso = neof - nbase + 1; + + dfhdr.crc = 0; + dfhdr.idx = fcnt; + dfhdr.nda = newaddress; + + /* If the file is currently opened, adjust the base address. */ + slotptr = tfsSlots; + for (slot=0;slot<TFS_MAXOPEN;slot++,slotptr++) { + if (slotptr->offset != -1) { + if (slotptr->base == (uchar *)(TFS_BASE(tfp))) { + slotptr->base = (uchar *)(newaddress+TFSHDRSIZ); + } + } + } + size = TFS_SIZE(tfp) + TFSHDRSIZ; + if (size & 0xf) { + size += TFS_FSIZEMOD; + size &= ~(TFS_FSIZEMOD-1); + } + newaddress += size; + dfhdr.nextfile = (TFILE *)newaddress; + dfhdr.crc = crc32((uchar *)&dfhdr,DEFRAGHDRSIZ); + if (verbose > 2) { + printf(" File %s (sz=%d):\n",TFS_NAME(tfp),TFS_SIZE(tfp)); + printf(" nda= 0x%08lx, ohdr= 0x%08lx, nxt= 0x%08lx\n", + (ulong)(dfhdr.nda),(ulong)(dfhdr.ohdr), + (ulong)(dfhdr.nextfile)); + printf(" oeso= 0x%08lx, nesn= 0x%08lx, neso= 0x%08lx\n", + (ulong)(dfhdr.oeso),(ulong)(dfhdr.nesn), + (ulong)(dfhdr.neso)); + } + if (defragFwrite(13,(uchar *)(&dht[fcnt]), + (uchar *)(&dfhdr),DEFRAGHDRSIZ) == -1) { + return(TFSERR_FLASHFAILURE); + } + fcnt++; + defragTick(0); + } + tfp = nextfp(tfp,tdp); + } + + if (defragBuildCrcTable(tdp,dht,verbose) < 0) + return(TFSERR_FLASHFAILURE); + + /* Now, the last part of the state table build is to store a + * 32-bit crc of the data we just wrote... + */ + crc = crc32((uchar *)dht,(uchar *)tdp->end - (uchar *)dht); + if (defragFwrite(14,(uchar *)((ulong *)dht-1),(uchar *)&crc,4) == -1) { + return(TFSERR_FLASHFAILURE); + } + + defrag_state = SCANNING_ACTIVE_SECTOR; + } + + /* Exit here to have a complete defrag header installed. */ + defragExitTestPoint(1000); + + if (defrag_state == SCANNING_ACTIVE_SECTOR) { + + if (verbose) { + printf("TFS: updating sectors %d-%d...\n", + activesnum,lastsnum); + } + + /* Now we begin the actual defragmentation. We have built enough + * state information (defrag header and state table) into the last + * TFS sector, so now we can start the cleanup. + */ + for(sidx = activesnum - firstsnum; sidx < tdp->sectorcount; sidx++) { + if (defragFillActiveSector(tdp,ftot,sidx,verbose) < 0) + return(TFSERR_FLASHFAILURE); + } + + defrag_state = SECTOR_DEFRAG_ALMOST_DONE; + } + + /* Exit here to test "almost-done" state detection. */ + defragExitTestPoint(1001); + + if (defrag_state == SECTOR_DEFRAG_ALMOST_DONE) { + + /* We've completed the relocation of all files into a defragmented + * area of TFS flash space. Now we have to erase all sectors after + * the sector used by the last file in TFS (including the spare)... + * If the last file in TFS uses the last sector, then the defrag + * header table will be erased and there is nothing left to do + * except erase the spare. + */ + if (verbose) { + printf("TFS: clearing available space...\n"); + } + if (dht[ftot-1].crc != ERASED32) { + end = (dht[ftot-1].nda + dht[ftot-1].filsize + TFSHDRSIZ) - 1; + if (addrtosector((uchar *)end,&snum,0,0) < 0) + return(TFSERR_FLASHFAILURE); + snum++; + while(snum <= lastsnum) { + if (defragSerase(7,snum) < 0) + return(TFSERR_FLASHFAILURE); + snum++; + defragTick(0); + } + } + if (defragEraseSpare(tdp) < 0) + return(TFSERR_FLASHFAILURE); + + /* All defragmentation is done, so verify sanity of files... */ + chkstat = tfscheck(tdp,verbose); + } + else { + chkstat = TFS_OKAY; + } + + if ((verbose) || (!MFLAGS_NODEFRAGPRN())) + printf("Defragmentation complete\n"); + + return(chkstat); +} + +/* tfsfixup(): + * Called at system startup to finish up a TFS defragmentation if one + * was in progress. + */ +int +tfsfixup(int verbose, int dontquery) +{ + TDEV *tdp; + + /* Clear test data... */ + DefragTestType = 0; + DefragTestPoint = 0; + DefragTestSector = 0; + +#if !DEFRAG_TEST_ENABLED + tfsTrace = 99; +#endif + + /* For each TFS device, run defrag with "fixup" flag set to let + * the defragger know that it should only defrag if a defrag was + * in progress. + */ + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + /* Call tfsclean() with fixup flag set... */ +#if TFS_VERBOSE_STARTUP + if (StateOfMonitor == INITIALIZE) + printf("TFS Scanning %s...\n",tdp->prefix); +#endif + _tfsclean(tdp,1,99); + } + +#if !DEFRAG_TEST_ENABLED + tfsTrace = 0; +#endif + return(0); +} + +#if DEFRAG_TEST_ENABLED +int +dumpDhdr(DEFRAGHDR *dhp) +{ + printf("ohdr: 0x%08lx\n",(ulong)dhp->ohdr); + printf("nextfile: 0x%08lx\n",(ulong)dhp->nextfile); + printf("filsize: 0x%08lx\n",(ulong)dhp->filsize); + printf("crc: 0x%08lx\n",(ulong)dhp->crc); + printf("idx: 0x%08lx\n",(ulong)dhp->idx); + printf("nesn: 0x%08lx\n",(ulong)dhp->nesn); + printf("neso: 0x%08lx\n",(ulong)dhp->neso); + printf("nda: 0x%08lx\n",(ulong)dhp->nda); + printf("fname: %s\n",dhp->fname); + return(TFS_OKAY); +} + +int +dumpDhdrTbl(DEFRAGHDR *dhp, int ftot) +{ + TDEV *tdp; + uchar *sbase; + ulong *crc, calccrc; + int i, ssize, snum; + struct sectorcrc *crctbl; + + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + + if (!dhp) { + crctbl = defragCrcTable(tdp); + printf("Device %s...\n",tdp->prefix); + dhp = (struct defraghdr *)crctbl - 1; + ftot = dhp->idx + 1; + printf("(%d files):\n",ftot); + dhp = (struct defraghdr *)crctbl - ftot; + crc = (ulong *)dhp-1; + if (*crc != crc32((uchar *)dhp,(uchar *)tdp->end - (uchar *)dhp)) { + printf("Table CRC failure\n"); + return(TFS_OKAY); + } + } + else + crctbl = (struct sectorcrc *)(dhp + ftot); + + printf("dhp=0x%lx, ftot=%d\n",(ulong)dhp,ftot); + + while(dhp < (struct defraghdr *)crctbl) { + printf(" %s (dhp=0x%lx, idx=%ld):\n", + dhp->fname,(ulong)dhp,dhp->idx); + printf(" nda: 0x%08lx, ohdr: 0x%08lx\n", + (ulong)dhp->nda,(ulong)dhp->ohdr); + dhp++; + } + + sbase = (uchar *)tdp->start; + printf("crctbl at 0x%lx\n",(ulong)crctbl); + for(i=0;i<tdp->sectorcount;i++) { + if (addrtosector(sbase,&snum,&ssize,0) < 0) + return(0); + if (i == tdp->sectorcount-1) { + ssize -= /* CRC table */ + (tdp->sectorcount * sizeof(struct sectorcrc)); + ssize -= (ftot * DEFRAGHDRSIZ); /* DHT table */ + ssize -= 4; /* Crc of the tables */ + } + calccrc = crc32(sbase,ssize); + if (calccrc == crctbl[i].precrc) + printf("crctbl[%d] (snum=%d) pre-pass\n",i,snum); + else if (calccrc == crctbl[i].postcrc) + printf("crctbl[%d] (snum=%d) post-pass\n",i,snum); + else { + printf("crctbl[%d] (snum=%d) test failed\n",i,snum); + printf("pre: 0x%lx, post: 0x%lx,calc: 0x%lx\n", + crctbl[i].precrc,crctbl[i].postcrc,calccrc); + } + sbase += ssize; + } + } + return(TFS_OKAY); +} +#endif /* DEFRAG_TEST_ENABLED */ +#endif /* INCLUDE_TFS */ diff --git a/main/common/tfsclean2.c b/main/common/tfsclean2.c new file mode 100644 index 0000000..e304f88 --- /dev/null +++ b/main/common/tfsclean2.c @@ -0,0 +1,180 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfsclean2.c: + * + * This version of defragmentation is not power-hit safe and does not + * require any flash overhead. The defragmentation simply copies all + * good files to an allocated block of ram erases the flash, then copies + * the concatenated data back to the flash. Simple but dangerous. + * + * If automatic defragmentation (through tfsadd()) is to be used in this + * mode, then the application must reside in ram space that is above + * APPRAMSTART + SIZEOF_TFSFLASH. This version of defragmentation assumes + * that the ram space needed for defrag will start at APPRAMBASE. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpu.h" +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "flash.h" +#include "monflags.h" + +#if INCLUDE_TFS + +int +tfsfixup(int verbose, int dontquery) +{ + return(TFSERR_NOTAVAILABLE); +} + +#if DEFRAG_TEST_ENABLED +int +dumpDhdr(DEFRAGHDR *dhp) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +dumpDhdrTbl(DEFRAGHDR *dhp, int ftot) +{ + return(TFSERR_NOTAVAILABLE); +} +#endif + + +/* _tfsclean(): + * This is an alternative to the complicated defragmentation above. + * It simply scans through the file list and copies all valid files + * to RAM; then flash is erased and the RAM is copied back to flash. + * <<< WARNING >>> + * THIS FUNCTION SHOULD NOT BE INTERRUPTED AND IT WILL BLOW AWAY + * ANY APPLICATION CURRENTLY IN CLIENT RAM SPACE. + */ +int +_tfsclean(TDEV *tdp, int notused, int verbose) +{ + TFILE *tfp; + ulong appramstart; + uchar *tbuf, *cp1, *cp2; + int dtot, nfadd, len, chkstat; +#if INCLUDE_FLASH + TFILE *lasttfp; +#endif + + if (TfsCleanEnable < 0) + return(TFSERR_CLEANOFF); + + appramstart = getAppRamStart(); + + /* Determine how many "dead" files exist. */ + dtot = 0; + tfp = (TFILE *)tdp->start; + while(validtfshdr(tfp)) { + if (!TFS_FILEEXISTS(tfp)) + dtot++; + tfp = nextfp(tfp,tdp); + } + + if (dtot == 0) + return(TFS_OKAY); + + printf("TFS device '%s' non-powersafe defragmentation\n",tdp->prefix); + + tbuf = (uchar *)appramstart; + tfp = (TFILE *)(tdp->start); +#if INCLUDE_FLASH + lasttfp = tfp; +#endif + nfadd = tdp->start; + while(validtfshdr(tfp)) { + if (TFS_FILEEXISTS(tfp)) { + len = TFS_SIZE(tfp) + sizeof(struct tfshdr); + if (len % TFS_FSIZEMOD) + len += TFS_FSIZEMOD - (len % TFS_FSIZEMOD); + nfadd += len; + if (s_memcpy((char *)tbuf,(char *)tfp,len,0,0) != 0) + return(TFSERR_MEMFAIL); + + ((struct tfshdr *)tbuf)->next = (struct tfshdr *)nfadd; + tbuf += len; + } +#if INCLUDE_FLASH + lasttfp = tfp; +#endif + tfp = nextfp(tfp,tdp); + } + + /* We've now copied all of the active files from flash to ram. + * Now we want to see how much of the flash space needs to be + * erased. We only need to erase the sectors that have changed... + */ + cp1 = (uchar *)tdp->start; + cp2 = (uchar *)appramstart; + while(cp2 < tbuf) { + if (*cp1 != *cp2) + break; + cp1++; cp2++; + } +#if INCLUDE_FLASH + if ((cp2 != tbuf) || (!TFS_FILEEXISTS(lasttfp))) { + int first, last; + + if (addrtosector(cp1,&first,0,0) == -1) + return(TFSERR_FLASHFAILURE); + + if (addrtosector((uchar *)tdp->end,&last,0,0) == -1) + return(TFSERR_FLASHFAILURE); + printf("Erasing sectors %d-%d...\n",first,last); + while(first<last) { + if (flasherase(first++) == 0) + return(TFSERR_FLASHFAILURE); + } + } +#endif + + /* Copy data placed in RAM back to flash: */ + printf("Restoring flash...\n"); + if (TFS_DEVTYPE_ISRAM(tdp)) { + memcpy((char *)(tdp->start),(char *)appramstart, + (tbuf-(uchar*)appramstart)); + } + else { +#if INCLUDE_FLASH + int err; + + err = AppFlashWrite((uchar *)(tdp->start),(uchar *)appramstart, + (tbuf-(uchar*)appramstart)); + if (err < 0) +#endif + return(TFSERR_FLASHFAILURE); + } + + /* All defragmentation is done, so verify sanity of files... */ + chkstat = tfscheck(tdp,verbose); + + return(chkstat); +} +#endif diff --git a/main/common/tfsclean3.c b/main/common/tfsclean3.c new file mode 100644 index 0000000..af095b0 --- /dev/null +++ b/main/common/tfsclean3.c @@ -0,0 +1,153 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfsclean3.c: + * + * --- NOT READY YET --- + * + * This version of defragmentation is power-hit safe and requires + * that there be double the amount of flash as is needed for use by + * TFS. The basic idea is similar to tfsclean2.c... + * Copy all of the good files over to the "other" flash bank, then have + * TFS use the "other" bank as the storage area. + * The idea is that the defrag is simply a copy of the good stuff to + * the alternate flash block. This requires that after the + * good stuff is copied, the now-dirty flash block must be erased in + * the background prior to the next tfsclean() call. The fact that + * there is no sector erase is what makes this faster. + * + * If both of these flash banks are in the same flash device, then + * having a background erase in progress means that it must be an + * interruptible erase (device specific). This is necessary because + * while the background erase is in progress there may be a need to + * interact with the flash and most devices don't let you do both at the + * same time. + * + * Note that this "background-erase" is what makes this method the + * fastest defrag method. It does require that the erase operation be + * interruptible, and it requires that the application will provide the + * hooks to do this... + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpu.h" +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "flash.h" +#include "monflags.h" + +#if INCLUDE_TFS + +int +tfsfixup(int verbose, int dontquery) +{ + return(TFSERR_NOTAVAILABLE); +} + +#if DEFRAG_TEST_ENABLED +int +dumpDhdr(DEFRAGHDR *dhp) +{ + return(TFSERR_NOTAVAILABLE); +} + +int +dumpDhdrTbl(DEFRAGHDR *dhp, int ftot) +{ + return(TFSERR_NOTAVAILABLE); +} +#endif + + +/* _tfsclean(): + * This is an alternative to the complicated defragmentation above. + * It simply scans through the file list and copies all valid files + * to RAM; then flash is erased and the RAM is copied back to flash. + * <<< WARNING >>> + * THIS FUNCTION SHOULD NOT BE INTERRUPTED AND IT WILL BLOW AWAY + * ANY APPLICATION CURRENTLY IN CLIENT RAM SPACE. + */ +int +_tfsclean(TDEV *tdp, int notused, int verbose) +{ + TFILE *tfp; + uchar *tbuf; + ulong appramstart; + int dtot, nfadd, len, err, chkstat; + + if (TfsCleanEnable < 0) + return(TFSERR_CLEANOFF); + + appramstart = getAppRamStart(); + + /* Determine how many "dead" files exist. */ + dtot = 0; + tfp = (TFILE *)tdp->start; + while(validtfshdr(tfp)) { + if (!TFS_FILEEXISTS(tfp)) + dtot++; + tfp = nextfp(tfp,tdp); + } + + if (dtot == 0) + return(TFS_OKAY); + + printf("Reconstructing device %s with %d dead file%s removed...\n", + tdp->prefix, dtot,dtot>1 ? "s":""); + + tbuf = (char *)appramstart; + tfp = (TFILE *)(tdp->start); + nfadd = tdp->start; + while(validtfshdr(tfp)) { + if (TFS_FILEEXISTS(tfp)) { + len = TFS_SIZE(tfp) + sizeof(struct tfshdr); + if (len % TFS_FSIZEMOD) + len += TFS_FSIZEMOD - (len % TFS_FSIZEMOD); + nfadd += len; + if (s_memcpy(tbuf,(uchar *)tfp,len,0,0) != 0) + return(TFSERR_MEMFAIL); + + ((struct tfshdr *)tbuf)->next = (struct tfshdr *)nfadd; + tbuf += len; + } + tfp = nextfp(tfp,tdp); + } + + /* Erase the flash device: */ + err = _tfsinit(tdp); + if (err != TFS_OKAY) + return(err); + + /* Copy data placed in RAM back to flash: */ + err = AppFlashWrite((ulong *)(tdp->start),(ulong *)appramstart, + (tbuf-(uchar*)appramstart)); + if (err < 0) + return(TFSERR_FLASHFAILURE); + + /* All defragmentation is done, so verify sanity of files... */ + chkstat = tfscheck(tdp,verbose); + + return(chkstat); +} +#endif diff --git a/main/common/tfscli.c b/main/common/tfscli.c new file mode 100644 index 0000000..754d20c --- /dev/null +++ b/main/common/tfscli.c @@ -0,0 +1,939 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfscli.c: + * + * This file contains the TFS code that is only needed if the "tfs" command + * is included in the command set. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "cli.h" + +#if INCLUDE_TFSCLI + +/* tfsprflags(): + * Print the specified set of flags. + */ +static void +tfsprflags(long flags, int verbose) +{ + struct tfsflg *tfp; + + if (verbose) + printf(" Flags: "); + tfp = tfsflgtbl; + while(tfp->sdesc) { + if ((flags & tfp->mask) == tfp->flag) { + if (verbose) { + printf("%s", tfp->ldesc); + if ((tfp+1)->flag) + printf(", "); + } + else + putchar(tfp->sdesc); + } + tfp++; + } + if (!(flags & TFS_NSTALE)) + printf("stale"); + + if (verbose) + printf("\n"); +} + +static char * +tfsmodebtoa(ulong mode,char *buf) +{ + char *pipe, *bp; + + pipe = ""; + bp = buf; + *bp = 0; + if (mode & TFS_RDONLY) { + bp += sprintf(bp,"rdonly"); + pipe = "|"; + } + if (mode & TFS_CREATE) { + bp += sprintf(bp,"%screate",pipe); + pipe = "|"; + } + if (mode & TFS_APPEND) + sprintf(bp,"%sappend",pipe); + + return(buf); +} + +/* tfsld(): + * If the filename specified is AOUT, COFF or ELF, then load it. + */ +static int +tfsld(char *name,int verbose,char *sname,int verifyonly) +{ + int err; + TFILE *fp; + + err = TFS_OKAY; + fp = tfsstat(name); + + if (!fp) + return (TFSERR_NOFILE); + + if (TFS_USRLVL(fp) > getUsrLvl()) + return(TFSERR_USERDENIED); + + if (fp->flags & TFS_EBIN) { + long entry; + + err = tfsloadebin(fp,verbose,&entry,sname,verifyonly); + if (err == TFS_OKAY) { + char buf[16]; + sprintf(buf,"0x%lx",entry); + setenv("ENTRYPOINT",buf); + } + else + setenv("ENTRYPOINT",0); + } + else { + err = TFSERR_NOTEXEC; + } + + return(err); +} + +/* listfilter(): + * If the incoming filename (fname) passes the incoming filter, then + * return 1; else return 0. + * + * Examples: + * if filter is "*.html" and fname is "index.html" return 1. + * if filter is "dir SLASH ASTERISK" and fname is "dir/abc" return 1. + * if filter is "abc" and fname is "abc" return 1. + * + * Notes: + * * A valid filter will have the asterisk as either the first or last + * character of the filter. If first, assume filter is a suffix, + * if last (or none at all), assume filter is a prefix. + * * If there is an asterisk in the middle of the filter, it is chopped + * at the asterisk without warning. + */ +static int +listfilter(char *filter,char *fname) +{ + int flen; + char *prefix, *suffix, *asterisk, *sp; + + if (!filter) /* No filter means match everything. */ + return(1); + + flen = 0; + prefix = suffix = (char *)0; + asterisk = strchr(filter,'*'); + + /* If no asterisk, then just compare filter to fname... */ + if (!asterisk) { + if (!strcmp(filter,fname)) + return(1); + } + else if (asterisk == filter) { + suffix = asterisk+1; + flen = strlen(suffix); + sp = fname + strlen(fname) - flen; + if (!strcmp(suffix,sp)) + return(1); + } + else { + *asterisk = 0; + prefix = filter; + flen = strlen(prefix); + if (!strncmp(prefix,fname,flen)) { + *asterisk = '*'; + return(1); + } + *asterisk = '*'; + } + return(0); +} + +/* tfsvlist(): verbose list... + * Display all files currently stored. Do not put them in alphabetical + * order; display them as they are physically listed in the file system. + * Display complete structure of file header for each file. + * Note1: This version of file listing is only called if "tfs -vv ls" + * or "tfs -vvv ls" is called. The first level of verbosity is handled + * by tfsqlist to simply display the "dot" files. + */ +static int +tfsvlist(char *filter[], int verbose, int more) +{ + TDEV *tdp; + TFILE *fp; + int tot, sizetot; + char tbuf[32], **fltrptr; + + tot = 0; + sizetot = 0; + for(tdp=tfsDeviceTbl;tdp->start != TFSEOT;tdp++) { + fltrptr = filter; + while(1) { + fp = (TFILE *)tdp->start; + while(validtfshdr(fp)) { + + if ((TFS_DELETED(fp)) && (verbose < 3)) { + fp = nextfp(fp,tdp); + continue; + } + if (!listfilter(*fltrptr,TFS_NAME(fp))) { + fp = nextfp(fp,tdp); + continue; + } + if ((fp->flags & TFS_UNREAD) && (TFS_USRLVL(fp)>getUsrLvl())) { + fp = nextfp(fp,tdp); + continue; + } + printf(" Name: '%s'%s\n", + fp->name,TFS_DELETED(fp) ? " (deleted)" : ""); + printf(" Info: '%s'\n", fp->info); + if (TFS_FILEEXISTS(fp)) + tfsprflags(fp->flags, 1); + printf(" Addr: 0x%lx (hdr @ 0x%lx, nxtptr = 0x%lx)\n", + (ulong)(TFS_BASE(fp)),(ulong)fp,(ulong)(fp->next)); + printf(" Size: %ld bytes (crc=0x%lx)", + fp->filsize,fp->filcrc); +#if INCLUDE_FLASH + if ((tdp->devinfo & TFS_DEVTYPE_MASK) != TFS_DEVTYPE_RAM) { + int start_sector, end_sector; + addrtosector((uchar *)fp,&start_sector,0,0); + addrtosector((uchar *)fp+fp->filsize+TFSHDRSIZ, + &end_sector,0,0); + if (start_sector == end_sector) { + printf(" in sector %d",start_sector); + } + else { + printf(" spanning sectors %d-%d", + start_sector,end_sector); + } + } +#endif + putchar('\n'); + sizetot += (fp->filsize + TFSHDRSIZ + DEFRAGHDRSIZ); + if (TFS_TIME(fp) != TIME_UNDEFINED) + printf(" Time: %s\n", + tfsGetAtime(TFS_TIME(fp),tbuf,sizeof(tbuf))); + printf("\n"); + tot++; + fp = nextfp(fp,tdp); + if ((more) && ((tot % more) == 0)) { + if (!More()) + return(TFS_OKAY); + } + } + /* If this or the next pointer is null, terminate loop now... */ + if (!*fltrptr) break; + fltrptr++; + if (!*fltrptr) break; + } + } + printf("Total: %d accessible file%s (%d bytes).\n", + tot,tot == 1 ? "" : "s",sizetot); + return (TFS_OKAY); +} + +/* tfsqlist(): quick list... + * Display list of files in alphabetical order. + * Display only the name and flag summary. + * + * To support listing of files in a bit of an orderly manner, if this + * function sees that a filename has a slash in it, it will only print the + * characters upto and including the first slash. This gives the appearance + * of a directory structure, even though there really isn't one. + * For example, if there are three files... + * CONFIG/file1 + * CONFIG/file2 + * CONFIG/file3 + * then if no filter is specified, then that listing will be replaced with + * CONFIG/ + * printed only once. To display all the files prefixed with CONFIG/, the + * user must type "tfs ls CONFIG/\*". + * + * Note: a file with a leading dot ('.') is invisible unless verbose is set. + */ +static int +tfsqlist(char *filter[], int verbose, int more) +{ + TFILE *fp; + char dirname[TFSNAMESIZE+1], tmpname[TFSNAMESIZE+1]; + char *name, fbuf[16], **fltrptr, *slash, *flags; + int idx, sidx, filelisted, err, sizetot; + + if ((err = tfsreorder()) < 0) + return(err); + + filelisted = 0; + sizetot = 0; + dirname[0] = 0; + fltrptr = filter; + printf(" Name Size Location Flags Info\n"); + while(1) { + idx = 0; + while((fp = tfsAlist[idx])) { + name = TFS_NAME(fp); + if (((name[0] == '.') && (!verbose)) || + (!listfilter(*fltrptr,name)) || + ((fp->flags & TFS_UNREAD) && (TFS_USRLVL(fp) > getUsrLvl()))) { + idx++; + continue; + } + + /* If name contains a slash, process it differently (but ignore */ + /* any leading slashes) */ + strcpy(tmpname,TFS_NAME(fp)); + for(sidx=0;sidx<TFSNAMESIZE;sidx++) { + if (tmpname[sidx] != '/') + break; + } + slash = strchr(&tmpname[sidx],'/'); + if (slash && !*fltrptr) { + char tmp; + + tmp = *(slash+1); + *(slash+1) = 0; + if (strcmp(dirname,tmpname)) { + filelisted++; + printf(" %-34s (dir)\n",tmpname); + strcpy(dirname,tmpname); + *(slash+1) = tmp; + } + else { + idx++; + *(slash+1) = tmp; + continue; + } + } + else { + filelisted++; + sizetot += TFS_SIZE(fp); + flags = tfsflagsbtoa(TFS_FLAGS(fp),fbuf); + if ((!flags) || (!fbuf[0])) + flags = " "; + printf(" %-23s %7ld 0x%08lx %-5s %s\n",TFS_NAME(fp), + TFS_SIZE(fp),(ulong)(TFS_BASE(fp)),flags,TFS_INFO(fp)); + } + idx++; + if ((more) && !(filelisted % more)) { + if (!More()) + return(TFS_OKAY); + } + } + /* If this or the next pointer is null, terminate loop now... */ + if (!*fltrptr) break; + fltrptr++; + if (!*fltrptr) break; + } + printf("\nTotal: %d item%s listed (%d bytes).\n",filelisted, + filelisted == 1 ? "" : "s",sizetot); + return (TFS_OKAY); +} + +/* tfsrm(): + * Remove all files that pass the incoming filter. + * This replaces the older tfs rm stuff in Tfs(). + */ +static int +tfsrm(char *filter[]) +{ + TFILE *fp; + char *name, **fltrptr; + int idx, err, rmtot; + + if ((err = tfsreorder()) < 0) + return(err); + + fltrptr = filter; + while (*fltrptr) { + idx = rmtot = 0; + while((fp = tfsAlist[idx])) { + name = TFS_NAME(fp); + if (listfilter(*fltrptr,name)) { + if ((err = tfsunlink(name)) != TFS_OKAY) + printf("%s: %s\n",name,(char *)tfsctrl(TFS_ERRMSG,err,0)); + rmtot++; + } + idx++; + } + /* This function will potentially delete many files, but if the */ + /* filter doesn't match at least one file, indicate that... */ + if (!rmtot) + printf("%s: file not found\n",*fltrptr); + fltrptr++; + } + + return(TFS_OKAY); +} + +/* tfscat(): + * Print each character of the file until NULL terminate. Replace + * each instance of CR or LF with CRLF. + */ +static void +tfscat(TFILE *fp, int more) +{ + int i, lcnt; + char *cp; + + lcnt = 0; + cp = (char *) (TFS_BASE(fp)); + for(i=0;i<fp->filsize;i++) { + if (*cp == 0x1a) /* EOF or ctrl-z */ + break; + putchar(*cp); + if ((*cp == '\r') || (*cp == '\n')) { + lcnt++; + if (lcnt == more) { + if (More() == 0) + break; + lcnt = 0; + } + } + cp++; + } +} + +int +dumpFhdr(TFILE *fhp) +{ + int crcok; + + if (tfshdrcrc(fhp) == fhp->hdrcrc) + crcok = 1; + else + crcok = 0; + printf("hdrsize: 0x%04x (%s)\n",fhp->hdrsize, + fhp->hdrsize == TFSHDRSIZ ? "ok" : "bad"); + printf("hdrvrsn: 0x%04x\n",fhp->hdrvrsn); + printf("filsize: 0x%08lx\n",fhp->filsize); + printf("flags : 0x%08lx\n",fhp->flags); +#if 0 + printf("filcrc : 0x%08lx (%s)\n",fhp->filcrc, + crc32((uchar *)(fhp+1),fhp->filsize) == fhp->filcrc ? "ok" : "bad"); +#else + printf("filcrc : 0x%08lx\n",fhp->filcrc); +#endif + printf("hdrcrc : 0x%08lx (%s)\n",fhp->hdrcrc,crcok ? "ok" : "bad"); + printf("modtime: 0x%08lx\n",fhp->modtime); + printf("next : 0x%08lx\n",(ulong)fhp->next); + if (crcok) { + printf("name : %s\n",fhp->name); + printf("info : %s\n",fhp->info ? fhp->info : ""); + } + else { + printf("name at: 0x%08lx\n",(ulong)fhp->name); + printf("info at: 0x%08lx\n",(ulong)fhp->info); + } + printf("data at: 0x%08lx\n",(ulong)(fhp+1)); + return(TFS_OKAY); +} + +char *TfsHelp[] = { + "Tiny File System Interface", + "-[df:i:mv] operation [args]...", +#if INCLUDE_VERBOSEHELP + "", + "Options:", + " -d tfs device", + " -f flags (see below)", + " -i info", + " -m enable more throttle", + " -v enable verbosity", + "", + "Operations (alphabetically):", + " add {name} {src_addr} {size}, base {file} {var}, cat {name}", + " cfg {start | restore} [{end} [spare_addr]], check [var], clean", + " cp {from} {to_name | addr}, fhdr {addr}, freemem [var]", + " info {file} {var}, init, ld[v] {name} [sname]", + " log {on|off} {msg}, ln {src} {lnk}, ls [filter]", + " qclean [ramstart] [ramlen], ramdev {name} {base} {size}", + " rm {filter}, run {name}, size {file} {var}, stat", + " trace [lvl], uname {prefix} {var}", +#if DEFRAG_TEST_ENABLED + "", + "Operations for testing TFS defragmentation:", + " clean {E|S|F} {tag#} {sector#}", + " E=Exit, S=SectorErase F=FlashWrite", + " rms {size} [exclude_file1] [exclude_file2] ...", + " dhdr {address}", + " dht", +#endif + "", + "Flags:", + " E=exec_" +#if TFS_EBIN_AOUT + "aout" +#elif TFS_EBIN_COFF + "coff" +#elif TFS_EBIN_ELF + "elf" +#elif TFS_EBIN_MSBIN + "msbin" +#elif TFS_EBIN_ELFMSBIN + "elf|msbin" +#else +#error: No TFS EBIN format specified. +#endif + ", e=exec_script, c=compressed, l=symlink", + " b=run_at_boot, B=qry_run_at_boot, i=inplace_modifiable", + " 0-3=usrlvl_0-3, u=ulvl_unreadable", +#endif + 0, +}; + +/* Tfs(): + * Entry point for the tfs command through the monitor's command line + * interface. This function provides access to most TFS functionality + * through the CLI. + */ + +int +Tfs(int argc, char *argv[]) +{ + TDEV *tdp, *tdptmp; + TFILE *fp; + TINFO tinfo; + long size; + int err, opt, verbose, i, more, retval, status; + char *src, *name, *info, *flags, *to, *from, *devprefix; + char *arg1, *arg2, *arg3, *arg4; + + tdp = 0; + more = 0; + retval = CMD_SUCCESS; + verbose = 0; + status = TFS_OKAY; + info = (char *)0; + flags = (char *)0; + devprefix = (char *)0; + while ((opt = getopt(argc, argv, "d:vmf:i:")) != -1) { + switch (opt) { + case 'd': + devprefix = optarg; + tdp = gettfsdev_fromprefix(devprefix,1); + if (!tdp) + return(CMD_FAILURE); + break; + case 'f': + flags = optarg; + break; + case 'i': + info = optarg; + break; + case 'm': + more++; + break; + case 'v': + verbose++; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + arg1 = argv[optind]; + arg2 = argv[optind+1]; + arg3 = argv[optind+2]; + arg4 = argv[optind+3]; + + if (argc == optind) { + retval = CMD_PARAM_ERROR; + } + else if (strcmp(arg1, "trace") == 0) { + if (argc == (optind+2)) + tfsTrace = strtoul(arg2,0,0); + else if (argc == (optind+1)) + printf("Current trace mode: 0x%lx\n",tfsTrace); + else + retval = CMD_PARAM_ERROR; + } + else if (strcmp(arg1, "init") == 0) { + if (getUsrLvl() < MAXUSRLEVEL) { + status = showTfsError(TFSERR_USERDENIED,0); + } + else { + status = _tfsinit(tdp); + showTfsError(status,"init"); + if (status == TFS_OKAY) + tfsclear(tdp); + } + } + else if ((strcmp(arg1,"ramdev") == 0) && (argc == (optind+4))) { + err = tfsramdevice(arg2,strtol(arg3,0,0),strtol(arg4,0,0)); + if (err != TFS_OKAY) { + printf("%s: %s\n",arg2,(char *)tfsctrl(TFS_ERRMSG,err,0)); + retval = CMD_FAILURE; + } + } + else if (strcmp(arg1, "log") == 0) { + retval = tfsLogCmd(argc,argv,optind); + } + else if (strcmp(arg1, "cfg") == 0) { + /* args: + * tfsstart tfsend spare_address + */ + ulong start, end, spare; + + if ((argc == (optind+2)) && !strcmp(arg2,"restore")) { + status = tfscfgrestore(); + showTfsError(status,"cfg"); + } + else if ((argc == (optind+3)) || (argc == (optind+4))) { + start = strtol(arg2,0,0); + end = strtol(arg3,0,0); + if (argc == (optind+4)) + spare = strtol(arg4,0,0); + else + spare = 0xffffffff; + status = tfscfg(devprefix,start,end,spare); + showTfsError(status,"cfg"); + } + else { + retval = CMD_PARAM_ERROR; + } + } + else if (strcmp(arg1, "stat") == 0) { + char buf[32]; + int opencnt; + struct tfsdat *slot; + + /* Display current TFS memory usage: */ + tfsmemuse(tdp,&tinfo,1); + printf("TFS Hdr size: %d\n",TFSHDRSIZ); + + /* Display currently opened files: */ + opencnt = 0; + slot = tfsSlots; + for (i=0;i<TFS_MAXOPEN;i++,slot++) { + if (slot->offset >= 0) { + printf("%3d: 0x%08lx %s %s\n",i,(ulong)(slot->base), + tfsmodebtoa(slot->flagmode,buf),slot->hdr.name); + opencnt++; + } + } + printf("Total files currently opened: %d\n",opencnt); + } + else if (strcmp(arg1, "freemem") == 0) { + char *prefix; + + tfsmemuse(tdp,&tinfo,0); + if (tdp) + prefix = tdp->prefix; + else + prefix = ""; + if (argc == (optind+1)) { + printf("0x%x (%d) bytes available to TFS %s\n", + tinfo.memfordata,tinfo.memfordata,prefix); + } + else if (argc == (optind+2)) { + shell_sprintf(arg2,"0x%x",tinfo.memfordata); + } + else + retval = CMD_PARAM_ERROR; + } +#if DEFRAG_TEST_ENABLED + else if (strcmp(arg1, "dht") == 0) { + if (argc == (optind+1)) { + status = dumpDhdrTbl(0,0); + showTfsError(status,"dht"); + } + else if (argc == (optind+3)) { + status = dumpDhdrTbl((DEFRAGHDR *)strtol(arg2,0,0), + atoi(arg3)); + showTfsError(status,"dht"); + } + else + retval = CMD_PARAM_ERROR; + } + else if ((strcmp(arg1, "dhdr") == 0) && (argc == (optind+2))) { + status = dumpDhdr((DEFRAGHDR *)strtol(arg2,0,0)); + showTfsError(status,"dhdr"); + } +#endif + else if ((strcmp(arg1, "fhdr") == 0) && (argc == (optind+2))) { + status = dumpFhdr((TFILE *)strtol(arg2,0,0)); + showTfsError(status,"fhdr"); + } + else if (((strcmp(arg1, "base") == 0) || + (strcmp(arg1, "info") == 0) || + (strcmp(arg1, "size") == 0)) && (argc == (optind+3))) { + fp = tfsstat(arg2); + if ((!fp) || + ((fp->flags & TFS_UNREAD) && (TFS_USRLVL(fp) > getUsrLvl()))) + setenv(arg3,0); + else { + switch(arg1[0]) { + case 'b': + shell_sprintf(arg3,"0x%x",(char *)fp+TFSHDRSIZ); + break; + case 'i': + setenv(arg3,fp->info); + break; + case 's': + shell_sprintf(arg3,"%ld",fp->filsize); + break; + } + } + } + else if ((strcmp(arg1, "uname") == 0) && (argc == (optind+3))) { + char uname[TFSNAMESIZE]; + for(i=0;;i++) { + sprintf(uname,"%s%d",arg2,i); + if (!tfsstat(uname)) { + setenv(arg3,uname); + break; + } + } + } + else if (strcmp(arg1, "ls") == 0) { + if (verbose > 1) + status = tfsvlist(&argv[optind+1],verbose,more << 1); + else + status = tfsqlist(&argv[optind+1],verbose,more << 3); + + showTfsError(status,"ls"); + } + else if ((strcmp(arg1, "ln") == 0) && (argc == optind+3)) { + from = arg2; + to = arg3; + status = tfslink(from,to); + showTfsError(status,from); + } + else if ((strcmp(arg1, "cp") == 0) && (argc == (optind+3))) { + char buf[16], linfo[TFSINFOSIZE]; + + from = arg2; + to = arg3; + fp = tfsstat(from); + if (fp) { + if (flags) { + if (strcmp(flags,"0") == 0) + flags = (char *)0; + } + else { + flags = tfsflagsbtoa(fp->flags,buf); + } + if (!info) + strcpy(linfo,fp->info); + else + strcpy(linfo,info); + if ((fp->flags & TFS_UNREAD) && + (TFS_USRLVL(fp) > getUsrLvl())) { + status = showTfsError(TFSERR_USERDENIED,from); + } + else if (to[0] == '0' && to[1] == 'x') { + memcpy((char *)strtol(to,0,16),TFS_BASE(fp),TFS_SIZE(fp)); + flushDcache((char *)strtol(to,0,16), TFS_SIZE(fp)); + invalidateIcache((char *)strtol(to,0,16), TFS_SIZE(fp)); + } + else { + int freespace; + + /* First check to see if a defrag is needed... + */ + freespace = tfsctrl(TFS_MEMAVAIL,0,0); + if (freespace <= TFS_SIZE(fp)) { + tfsctrl(TFS_DEFRAG,0,0); + fp = tfsstat(from); + } + status = tfsadd(to,linfo,flags,(uchar *)TFS_BASE(fp), + TFS_SIZE(fp)); + showTfsError(status,to); + } + } + else + status = showTfsError(TFSERR_NOFILE,from); + } + else if ((strcmp(arg1, "cat") == 0) && (argc >= (optind+2))) { + for(i=optind+1;i<argc;i++) { + name = argv[i]; + fp = tfsstat(name); + if (fp) { + if ((fp->flags & TFS_UNREAD) && + (TFS_USRLVL(fp) > getUsrLvl())) { + status = showTfsError(TFSERR_USERDENIED,name); + } + else { + tfscat(fp,more << 3); /* more times 8 */ + } + } + else + status = showTfsError(TFSERR_NOFILE,name); + } + } +#if DEFRAG_TEST_ENABLED + /* rms: "remove space". Used for testing only... Keep removing files + * until the number of bytes freed up is greater than the argument + * to rms. Skip over all files listed after the first size argument. + * Arglist to tfs rms is... + * + * tfs rms {SIZE} [EXCLUDEFILE1] [EXCLUDEFILE2] ... + * where SIZE is the amount of space to freeup and EXCLUDEFILEN is + * a filename that is not to be removed. + */ + else if ((strcmp(arg1, "rms") == 0) && (argc >= (optind+2))) { + int insize, totsize; + + totsize = 0; + insize = strtol(arg2,0,0); + tfsreorder(); + for(i=0;tfsAlist[i];i++) { + int j; + + for(j=optind+1;j<argc;j++) { + if (!strcmp(TFS_NAME(tfsAlist[i]),argv[j])) + break; + } + if (j != argc) { + continue; + } + if (devprefix && + strncmp(TFS_NAME(tfsAlist[i]),devprefix,strlen(devprefix))) + continue; + totsize += (TFS_SIZE(tfsAlist[i]) + TFSHDRSIZ); + if (verbose) + printf("rms: removing %s (%ld)\n",TFS_NAME(tfsAlist[i]), + TFS_SIZE(tfsAlist[i]) + TFSHDRSIZ); + _tfsunlink(TFS_NAME(tfsAlist[i])); + if (totsize > insize) + break; + totsize += TFSHDRSIZ; + } + } +#endif + else if ((strcmp(arg1, "rm") == 0) && (argc >= (optind+2))) { + status = tfsrm(&argv[optind+1]); + showTfsError(status,0); + } + else if (strcmp(arg1, "fix") == 0) { + tfsfixup(verbose,1); + } + else if (strcmp(arg1, "qclean") == 0) { + char *ramstart = 0; + ulong ramlen = 0; + + if (argc >= optind+2) + ramstart = (char *)strtoul(arg2,0,0); + if (argc >= optind+3) + ramlen = strtoul(arg2,0,0); + + for (tdptmp=tfsDeviceTbl;tdptmp->start != TFSEOT;tdptmp++) { + if (!tdp || (tdp == tdptmp)) { + status = tfsclean_nps(tdptmp,ramstart,ramlen); + showTfsError(status,tdptmp->prefix); + } + } + } + else if (strcmp(arg1, "clean") == 0) { + int otrace; + +#if DEFRAG_TEST_ENABLED + DefragTestPoint = DefragTestSector = DefragTestType = 0; + if (argc == (optind+4)) { + if (arg2[0] == 'S') + DefragTestType = DEFRAG_TEST_SERASE; + else if (arg2[0] == 'F') + DefragTestType = DEFRAG_TEST_FWRITE; + else if (arg2[0] == 'E') + DefragTestType = DEFRAG_TEST_EXIT; + else + return(CMD_PARAM_ERROR); + DefragTestPoint = atoi(arg3); + DefragTestSector = atoi(arg4); + printf("Testtype=%c, Testpoint=%d, Testsector=%d\n", + arg2[0],DefragTestPoint,DefragTestSector); + } + else +#endif + if (argc != optind+1) + return(CMD_PARAM_ERROR); + + /* If verbosity request is extreme, then turn on TFS trace also... + */ + otrace = tfsTrace; + if (verbose >= 5) + tfsTrace = 99; + + /* If tdp has been set by the -d option, only defrag the affected + * device; else, defrag all devices... + */ + for (tdptmp=tfsDeviceTbl;tdptmp->start != TFSEOT;tdptmp++) { + if (!tdp || (tdp == tdptmp)) { + status = tfsclean(tdptmp,verbose+1); + showTfsError(status,tdptmp->prefix); + } + } + tfsTrace = otrace; + } + else if (strcmp(arg1, "check") == 0) { + if (argc == optind+1) + verbose = 1; + + if (tfscheck(tdp,verbose) != TFS_OKAY) + status = TFSERR_CORRUPT; + + /* If an additional argument is provided after the "check" command + * then assume it is a shell variable name that is to be populated + * with the pass/fail status of the check... + */ + if (argc == optind+2) + setenv(arg2,status == TFS_OKAY ? "PASS" : "FAIL"); + } + else if ((!strncmp(arg1, "ld",2)) && + ((argc == optind+2) || (argc == optind+3))) { + int vfy = 0; + + if (arg1[2] == 'v') + vfy = 1; + else if (arg1[2] != 0) + return(CMD_PARAM_ERROR); + status = tfsld(arg2,verbose,arg3,vfy); + showTfsError(status,arg2); + } + else if ((strcmp(arg1, "run") == 0) && (argc >= (optind+2))) { + status = tfsrun(&argv[optind+1],verbose); + showTfsError(status,arg2); + } + else if ((!(strcmp(arg1, "add"))) && (argc == (optind+4))) { + src = (char *) strtol(arg3, (char **) 0, 0); + size = strtol(arg4, (char **) 0, 0); + status = tfsadd(arg2, info, flags, (uchar *)src, size); + showTfsError(status,arg2); + if (status != TFS_OKAY) + retval = CMD_FAILURE; + } + else { + retval = CMD_PARAM_ERROR; + } + return(retval); +} +#endif diff --git a/main/common/tfsloader.c b/main/common/tfsloader.c new file mode 100644 index 0000000..1b3d8ac --- /dev/null +++ b/main/common/tfsloader.c @@ -0,0 +1,523 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfsloader.c: + * + * This file contains the code that is specific to each of the file types + * supported by TFS as the binary executable type. + * Currently, COFF, ELF, A.OUT and MSBIN are supported. This requires that + * TFS_EBIN_COFF, TFS_EBIN_ELF, TFS_EBIN_AOUT or TFS_EBIN_MSBIN + * respectively, be set in the monitor's config.h file. Also, defining + * TFS_EBIN_ELFMSBIN will allow TFS to support both ELF and MSBIN. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "coff.h" +#include "elf.h" +#include "aout.h" +#include "msbin.h" +#if INCLUDE_TFS + + +/* tfsld_memcpy(), tfsld_memset() & tfsld_decompress(): + * Front end to all bulk memory modification calls done by the + * loader. Each function just does a quick check to make sure that + * the address ranged being copied to is not part of the monitor's + * own .bss space... + * Then after the memory transfer, caches are flushed/invalidated. + * + * How we return here depends on the verbosity level. If verbosity + * is greater than 1, then assume that this pass through tfsld_memcpy() + * is to dump out map information, not to actually do a memcpy(). + * This same logic is used within the s_memcpy() routine and must remain + * consistent to work properly. + */ +#ifdef USE_ALTERNATE_TFSLD_MEMCPY +extern int tfsld_memcpy(char *to,char *from,int count,int verbose,int verify); +#else +int +tfsld_memcpy(char *to, char *from, int count, int verbose, int verify) +{ + int rc; + + if (verbose <= 1) { + if (inUmonBssSpace(to,to+count-1)) + return(-1); + } + + rc = s_memcpy(to,from,count,verbose,verify); + + if (verbose <= 1) { + flushDcache(to,count); + invalidateIcache(to,count); + } + + return(rc); +} +#endif + +int +tfsld_memset(uchar *to,uchar val,int count,int verbose,int verifyonly) +{ + int rc; + + if (verbose <= 1) { + if (inUmonBssSpace((char *)to, (char *)to+count-1)) + return(-1); + } + + rc = s_memset(to,val,count,verbose,verifyonly); + + if (verbose <= 1) { + flushDcache((char *)to, count); + invalidateIcache((char *)to, count); + } + + return(rc); +} + +void +showEntrypoint(unsigned long entrypoint) +{ + printf(" entrypoint: 0x%lx\n",entrypoint); +} + +void +showSection(char *sname) +{ + printf(" %-10s: ",sname); +} + +#if TFS_EBIN_AOUT + +/* tfsloadaout(): + * The file pointed to by fp is assumed to be an AOUT + * formatted file. This function loads the sections of that file into + * the designated locations and returns the address of the entry point. + */ +int +tfsloadaout(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly) +{ + uchar *tfrom, *dfrom; + struct exec *ehdr; + + if (tfsTrace) + printf("tfsloadaout(%s)\n",TFS_NAME(fp)); + + /* Establish file header pointer... */ + ehdr = (struct exec *)(tfsBase(fp)); + + /* Return error if relocatable... */ + if ((ehdr->a_trsize) || (ehdr->a_drsize)) + return(TFSERR_BADHDR); + + /* Establish locations from which text and data are to be */ + /* copied from ... */ + tfrom = (uchar *)(ehdr+1); + dfrom = tfrom+ehdr->a_text; + + /* Copy/verify text and data sections to RAM: */ + if (verbose) + showSection("text"); + + if (tfsld_memcpy((char *)(ehdr->a_entry),(char *)tfrom, + ehdr->a_text,verbose,verifyonly) != 0) + return(TFSERR_MEMFAIL); + + if (verbose) + showSection("data"); + + if (tfsld_memcpy((char *)(ehdr->a_entry+ehdr->a_text),(char *)dfrom, + ehdr->a_data,verbose,verifyonly) != 0) + return(TFSERR_MEMFAIL); + + /* Clear out bss space: */ + if (verbose) + showSection("bss"); + + if (tfsld_memset((char *)(ehdr->a_entry+ehdr->a_text+ehdr->a_data), + 0,ehdr->a_bss,verbose,verifyonly) != 0) + return(TFSERR_MEMFAIL); + + + if (verbose & !verifyonly) + showEntrypoint(ehdr->a_entry); + + /* Store entry point: */ + if (entrypoint) + *entrypoint = (long)(ehdr->a_entry); + + return(TFS_OKAY); +} +#endif + +#if TFS_EBIN_COFF + +/* tfsloadcoff(): + * The file pointed to by fp is assumed to be a COFF file. + * This function loads the sections of that file into the designated + * locations. + */ +int +tfsloadcoff(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly) +{ + int i, err; + FILHDR *fhdr; + AOUTHDR *ahdr; + SCNHDR *shdr; + + if (tfsTrace) + printf("tfsloadcoff(%s)\n",TFS_NAME(fp)); + + /* Establish file header pointers... */ + fhdr = (FILHDR *)(tfsBase(fp)); + if ((fhdr->f_opthdr == 0) || ((fhdr->f_flags & F_EXEC) == 0)) + return(TFSERR_BADHDR); + + err = 0; + ahdr = (AOUTHDR *)(fhdr+1); + shdr = (SCNHDR *)((uchar *)ahdr + fhdr->f_opthdr); + + /* For each section header, relocate or clear if necessary... */ + for (i=0;!err && i<fhdr->f_nscns;i++) { + if (shdr->s_size == 0) { + shdr++; + continue; + } + + /* If incoming section name is specified, then we only load the + * section with that name... + */ + if ((sname != 0) && (strcmp(sname,shdr->s_name) != 0)) + continue; + + if (verbose) + showSection(shdr->s_name); + + if (ISLOADABLE(shdr->s_flags)) { + if (tfsld_memcpy((char *)(shdr->s_paddr), + (char *)(shdr->s_scnptr+(int)fhdr), + shdr->s_size,verbose,verifyonly) != 0) + err++; + } + else if (ISBSS(shdr->s_flags)) { + if (tfsld_memset((char *)(shdr->s_paddr),0,shdr->s_size, + verbose,verifyonly) != 0) + err++; + } + else if (verbose) + printf("???\n"); + shdr++; + } + + if (verbose && !verifyonly && !sname) + showEntrypoint(ahdr->entry); + + if (err) + return(TFSERR_MEMFAIL); + + /* Store entry point: */ + if (entrypoint) + *entrypoint = (long)(ahdr->entry); + + return(TFS_OKAY); +} +#endif + +#if TFS_EBIN_ELF | TFS_EBIN_ELFMSBIN + +/* tfsloadelf(): + * The file pointed to by fp is assumed to be an ELF file. + * This function loads the sections of that file into the designated + * locations. + */ +int +tfsloadelf(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly) +{ + Elf32_Word size, notproctot; + int i, j, err; + char *shname_strings, *name; + Elf32_Addr sh_addr; + ELFFHDR *ehdr; + ELFSHDR *shdr; + ELFPHDR *phdr; + + if (tfsTrace) + printf("tfsloadelf(%s)\n",TFS_NAME(fp)); + + /* Establish file header pointers... */ + /* If the first reserved entry isn't 0xffffffff, then assume this is a + * 'fake' header, and it contains the base address of the file data... + * See tfsld() for more info. + */ + ehdr = (ELFFHDR *)(tfsBase(fp)); + shdr = (ELFSHDR *)((int)ehdr + ehdr->e_shoff); + err = 0; + + /* Verify basic file sanity... */ + if ((ehdr->e_ident[0] != 0x7f) || (ehdr->e_ident[1] != 'E') || + (ehdr->e_ident[2] != 'L') || (ehdr->e_ident[3] != 'F')) + return(TFSERR_BADHDR); + + /* Store the section name string table base: */ + shname_strings = (char *)ehdr + shdr[ehdr->e_shstrndx].sh_offset; + notproctot = 0; + + /* For each section header, relocate or clear if necessary... */ + for (i=0;!err && i<ehdr->e_shnum;i++,shdr++) { + if ((size = shdr->sh_size) == 0) + continue; + + name = shname_strings + shdr->sh_name; + + /* If incoming section name is specified, then we only load the + * section with that name... + */ + if ((sname != 0) && (strcmp(sname,name) != 0)) + continue; + + if ((verbose) && (ehdr->e_shstrndx != SHN_UNDEF)) + showSection(shname_strings + shdr->sh_name); + + if (!(shdr->sh_flags & SHF_ALLOC)) { + notproctot += size; + if (verbose) + printf(" %7ld bytes not processed (tot=%ld)\n", + size,notproctot); + continue; + } + + sh_addr = shdr->sh_addr; + + /* Look to the program header to see if the destination address + * of this section needs to be adjusted. If this section is + * within a program header and that program header's members + * p_vaddr & p_paddr are not equal, then adjust the section + * address based on the delta between p_vaddr and p_paddr... + */ + phdr = (ELFPHDR *)((int)ehdr + ehdr->e_phoff); + for (j=0;j<ehdr->e_phnum;j++,phdr++) { + if ((phdr->p_type == PT_LOAD) && + (sh_addr >= phdr->p_vaddr) && + (sh_addr < phdr->p_vaddr+phdr->p_filesz) && + (phdr->p_vaddr != phdr->p_paddr)) { + sh_addr += (phdr->p_paddr - phdr->p_vaddr); + break; + } + } + + if (shdr->sh_type == SHT_NOBITS) { + if (tfsld_memset((uchar *)(sh_addr),0,size, + verbose,verifyonly) != 0) + err++; + } + else { + if (tfsld_memcpy((char *)(sh_addr), + (char *)((int)ehdr+shdr->sh_offset), + size,verbose,verifyonly) != 0) + err++; + } + } + + if (err) + return(TFSERR_MEMFAIL); + + if (verbose && !verifyonly && !sname) + showEntrypoint(ehdr->e_entry); + + /* Store entry point: */ + if (entrypoint) + *entrypoint = (long)(ehdr->e_entry); + + return(TFS_OKAY); +} + +#endif + +#if TFS_EBIN_ELFMSBIN | TFS_EBIN_MSBIN + +/* tfsloadmsbin(): + * This loader is a bit different than the others. + * The model for AOUT, COFF & ELF is simply to load each section from + * the stored location in flash to the location specifed by the section + * header. The sections may be compressed. + * The MSBIN loader supports a few additional options because of the + * fact that WinCE files can be formatted as .bin or .nbo. When + * the file is the ".bin" type, then this loader is used similar to + * the AOUT, COFF & ELF loaders. When the file is the ".nbo" type, + * then it is simply loaded into the starting address of the target's + * DRAM and the entrypoint is that base address. + * To support this scheme, TFS uses both the 'c' flag (compressed) + * and the extension on the filename as follows... + * + * 1 filename.bin with 'c' flag inactive: + * Load the file as specified by the sections within the file + * header. + * 2 filename.bin with 'c' flag active: + * Load the file as specified by the sections within the file + * header and assume each section is compressed. + * 3 filename.nbo with 'c' flag inactive: + * Copy the entire content of the file from TFS flash space to + * APPRAMBASE and return the address APPRAMBASE as the entrypoint. + * 4 filename.nbo with 'c' flag active: + * Decompress the entire content of the file from TFS flash space + * to APPRAMBASE and return the address APPRAMBASE as the entrypoint. + * + * In three of the 4 cases above (1,2&3) some level of sanity checking + * can be done on the file prior to beginning the load. For the 4th + * case there is no sanity check, this function assumes the file is + * compressed and is destined for the base of DRAM. + */ +int +tfsloadmsbin(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly) +{ + ulong offset; + MSBINFHDR filhdr; + MSBINSHDR scnhdr; + char *dot; + int err, snum; + + if (tfsTrace) + printf("tfsloadmsbin(%s)\n",TFS_NAME(fp)); + + dot = strrchr(TFS_NAME(fp),'.'); + if (!dot) + return(TFSERR_BADEXTENSION); + + /* Check the filename extension for ".bin" or ".nbo" and process + * accordingly... + */ + if (strcmp(dot,".bin") == 0) { + /* Verify basic file sanity... */ + if (memcmp((char *)tfsBase(fp),MSBIN_SYNC_DATA,MSBIN_SYNC_SIZE) != 0) + return(TFSERR_BADHDR); + + /* The file header is at offset MSBIN_SYNC_SIZE in the + * file, so copy it from the file to a local structure... + */ + memcpy((char *)&filhdr,(tfsBase(fp) + MSBIN_SYNC_SIZE), + sizeof(MSBINFHDR)); + + /* Start by clearing the entire image space to zero... + */ + if (verbose) + printf("MsbinImage: "); + + tfsld_memset((uchar *)filhdr.imageaddr,0,(int)filhdr.imagelen,verbose, + verifyonly); + + err = snum = 0; + offset = (ulong)(tfsBase(fp) + MSBIN_SYNC_SIZE + sizeof(MSBINFHDR)); + + /* Walk through all sections within the file. For each section, + * copy the structure out of TFS to local space, then process it. + */ + for(snum = 1;err==0;snum++) { + memcpy((char *)&scnhdr,(char *)offset,sizeof(MSBINSHDR)); + offset += sizeof(MSBINSHDR); + + /* The image terminates with an image record header with the + * physical address and checksum set to zero... + */ + if ((scnhdr.addr == 0) && (scnhdr.csum == 0)) + break; + + if (verbose) + printf("section %02d: ", snum); + + if (tfsld_memcpy((char *)(scnhdr.addr), + (char *)offset,scnhdr.len,verbose,verifyonly) != 0) + err++; + + offset += scnhdr.len; + } + + if (err) + return(TFSERR_MEMFAIL); + + if (verbose && !verifyonly && !sname) + showEntrypoint(filhdr.imageaddr); + + /* Store entry point: */ + if (entrypoint) + *entrypoint = (long)(filhdr.imageaddr); + } + else if (strcmp(dot,".nb0") == 0) { + char *drambase; + + drambase = (char *)getAppRamStart(); + + tfsld_memcpy(drambase,(char *)tfsBase(fp),(int)TFS_SIZE(fp), + verbose,verifyonly); + + /* Store entry point: */ + if (entrypoint) + *entrypoint = (long)(drambase); + } + else { + return(TFSERR_BADEXTENSION); + } + + return(TFS_OKAY); +} + +#endif + +int +tfsloadebin(TFILE *fp,int verbose,long *entrypoint,char *sname,int verifyonly) +{ +#if TFS_EBIN_ELFMSBIN + int err; +#endif + + /* If verbosity is greater than one and verifyonly is not set, then + * we are simply dumping a map, so start with an appropriate + * header... + */ + if ((verbose > 1) && (verifyonly == 0)) + printf("Load map:\n"); + +#if TFS_EBIN_AOUT + return(tfsloadaout(fp,verbose,entrypoint,sname,verifyonly)); +#elif TFS_EBIN_COFF + return(tfsloadcoff(fp,verbose,entrypoint,sname,verifyonly)); +#elif TFS_EBIN_ELF + return(tfsloadelf(fp,verbose,entrypoint,sname,verifyonly)); +#elif TFS_EBIN_MSBIN + return(tfsloadmsbin(fp,verbose,entrypoint,sname,verifyonly)); +#elif TFS_EBIN_ELFMSBIN + err = tfsloadelf(fp,verbose,entrypoint,sname,verifyonly); + if (err == TFSERR_BADHDR) + return(tfsloadmsbin(fp,verbose,entrypoint,sname,verifyonly)); + else + return(err); +#else +#error Invalid TFS_EBIN type. +#endif +} + + +#endif /* INCLUDE_TFS */ diff --git a/main/common/tfslog.c b/main/common/tfslog.c new file mode 100644 index 0000000..a31b8fa --- /dev/null +++ b/main/common/tfslog.c @@ -0,0 +1,171 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfslog.c: + * + * Optional facility for TFS that supports the ability to log all + * tfs actions that affect flash, to a log file. + * + * This function is called by tfsadd(), tfsunlink() and tfsipmod() to + * write to a log file indicating that something in tfs has been changed. + * Note that the function can be called at any user level, but it must be + * able to modify the TFS_CHANGELOG_FILE that has "u3" flags. The + * user level must be temporarily forced to MAXUSRLEVEL for this. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "genlib.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "cli.h" + +#if TFS_CHANGELOG_SIZE +static int tfsLogging; +#endif + +void +tfslog(int action, char *string) +{ +#if TFS_CHANGELOG_SIZE + static char *tfslogaction[] = { "ADD", "DEL", "IPM", " ON", "OFF" }; + + extern void *setTmpMaxUsrLvl(); + static char buf[TFS_CHANGELOG_SIZE]; + TFILE *tfp; + int (*fptr)(); + char *eol, *eob, *logaction, tbuf[32]; + int newfsize, fsize, lsize, tfd, err, len, tbuflen; + + switch(action) { + case TFSLOG_ADD: /* Return here if logging is off, */ + case TFSLOG_DEL: /* or this tfslog() call is on the */ + case TFSLOG_IPM: /* TFS_CHANGELOG_FILE itself. */ + if (!tfsLogging || !strcmp(string,TFS_CHANGELOG_FILE)) + return; + break; + case TFSLOG_ON: + if (tfsLogging == 1) + return; + tfsLogging = 1; + break; + case TFSLOG_OFF: + if (tfsLogging == 0) + return; + tfsLogging = 0; + break; + } + + /* Force the getUsrLvl() function to return MAX: */ + fptr = (int(*)())setTmpMaxUsrLvl(); + + logaction = tfslogaction[action]; + tfp = tfsstat(TFS_CHANGELOG_FILE); + tfsGetAtime(0,tbuf,sizeof(tbuf)); + tbuflen = strlen(tbuf); + + if (tfp) { + tfd = tfsopen(TFS_CHANGELOG_FILE,TFS_RDONLY,0); + fsize = tfsread(tfd,buf,TFS_CHANGELOG_SIZE); + tfsclose(tfd,0); + + newfsize = (fsize+strlen(logaction)+strlen(string)+3); + if (tbuflen) + newfsize += tbuflen + 3; + + eob = buf + fsize; + + /* If newfsize is greater than the maximum size the file is + * allowed to grow, then keep removing the first line + * (oldest entry) until new size is within the limit... + */ + if (newfsize > TFS_CHANGELOG_SIZE) { + lsize = 0; + eol = buf; + while ((newfsize-lsize) > TFS_CHANGELOG_SIZE) { + while((*eol != '\r') && (*eol != '\n')) eol++; + while((*eol == '\r') || (*eol == '\n')) eol++; + lsize = eol-buf; + } + fsize -= lsize; + newfsize -= lsize; + eob -= lsize; + memcpy(buf,eol,fsize); + } + if (tbuflen) + sprintf(eob,"%s: %s @ %s\n",logaction,string,tbuf); + else + sprintf(eob,"%s: %s\n",logaction,string); + err = _tfsunlink(TFS_CHANGELOG_FILE); + if (err < 0) + printf("%s: %s\n",TFS_CHANGELOG_FILE, + (char *)tfsctrl(TFS_ERRMSG,err,0)); + err = tfsadd(TFS_CHANGELOG_FILE,0,"u3",buf,newfsize); + if (err < 0) + printf("%s: %s\n",TFS_CHANGELOG_FILE, + (char *)tfsctrl(TFS_ERRMSG,err,0)); + } + else { + if (tbuflen) + len = sprintf(buf,"%s: %s @ %s\n",logaction,string,tbuf); + else + len = sprintf(buf,"%s: %s\n",logaction,string); + err = tfsadd(TFS_CHANGELOG_FILE,0,"u3",buf,len); + if (err < 0) + printf("%s: %s\n",TFS_CHANGELOG_FILE, + (char *)tfsctrl(TFS_ERRMSG,err,0)); + } + + /* Restore the original getUsrLvl() functionality: */ + clrTmpMaxUsrLvl(fptr); +#endif +} + +int +tfsLogCmd(int argc,char *argv[], int optind) +{ +#if TFS_CHANGELOG_SIZE + int status; + int retval = 0; + + if (getUsrLvl() < MAXUSRLEVEL) { + status = showTfsError(TFSERR_USERDENIED,0); + } + else { + if (argc == optind + 3) { + if (!strcmp(argv[optind+1],"on")) + tfslog(TFSLOG_ON,argv[optind+2]); + else if (!strcmp(argv[optind+1],"off")) + tfslog(TFSLOG_OFF,argv[optind+2]); + else + retval = CMD_PARAM_ERROR; + } + else if (argc == optind + 1) + printf("TFS logging %sabled\n",tfsLogging ? "en" : "dis"); + else + retval = CMD_PARAM_ERROR; + } + return(retval); +#else + return(CMD_FAILURE); +#endif +} diff --git a/main/common/tfsprivate.h b/main/common/tfsprivate.h new file mode 100644 index 0000000..7cfb840 --- /dev/null +++ b/main/common/tfsprivate.h @@ -0,0 +1,328 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tfsprivate.h: + * + * Header file for TFS used only by the monitor code. + * (that is... this should not be used by anything under umon_apps) + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _TFSPRIVATE_H_ +#define _TFSPRIVATE_H_ + +#define SANITY 0xBEEF +#define ERASED16 0xFFFF +#define ERASED32 0xFFFFFFFF +#define TFS_MAXOPEN 10 /* Maximum of 10 open files */ +#define TFS_QRYTMOUT 100000 /* Timeout for QRYBRUN */ +#define TFS_FSIZEMOD 16 /* File size must be a multiple of this value */ +#define MINUSRLEVEL 0 /* Minimum user level supported. */ +#define MAXUSRLEVEL 3 /* Maximum user level supported. */ + +#define TFSHDRVERSION 1 /* Increment this if TFS header changes. */ + +#if TFS_EBIN_COFF +#define TFS_EBIN_NAME "coff" +#elif TFS_EBIN_AOUT +#define TFS_EBIN_NAME "aout" +#elif TFS_EBIN_ELF +#define TFS_EBIN_NAME "elf" +#elif TFS_EBIN_MSBIN +#define TFS_EBIN_NAME "msbin" +#elif TFS_EBIN_ELFMSBIN +#define TFS_EBIN_NAME "elf_msbin" +#else +#define TFS_EBIN_NAME "NA" +#endif + +/* Two different types of Defragmentation tests: + * sector erase and flash write. + */ +#define DEFRAG_TEST_SERASE 1 +#define DEFRAG_TEST_FWRITE 2 +#define DEFRAG_TEST_EXIT 3 + +/* Masks used to allow flags and modes to be part of the same long word. */ +#define TFS_FLAGMASK 0x0000ffff +#define TFS_MODEMASK 0xffff0000 + +/* Definitions related to tfslog: */ +#define TFSLOG_ADD 0 +#define TFSLOG_DEL 1 +#define TFSLOG_IPM 2 +#define TFSLOG_ON 3 +#define TFSLOG_OFF 4 +#define TIME_UNDEFINED 0xffffffff + +/* Used by tfsscript.. */ +#define EXIT_SCRIPT (1 << 0) +#define REMOVE_SCRIPT (1 << 1) +#define EXECUTE_AFTER_EXIT (1 << 2) +#define EXIT_ALL_SCRIPTS (1 << 3) + +/* Device Table structure and definitions: + * The Device table is typically only one entry in length. It is defined + * on a per-target basis in the file tfsdev.h. In the simplest case, the + * table in tfsdev.h has all of the information in it. This is fine as long + * as there is no need to support different devices with the same monitor + * binary. To support the ability to have a device-table that is constructed + * based on the type of flash on-board, the TFS_DEVINFO_DYNAMIC bit must + * be set in the devinfo member of tfsdevtbl (in tfsdev.h). This tells TFS + * to figure out the addresses based on a few assumptions... + * * Regardless of the device type, the start address will be the same. + * * The spare sector starts immediately after the end of TFS storage space. + * In dynamic mode, all that needs to be specified in the tfsdevtbl of + * tfsdev.h is a prefix, start and devinfo fields. The other fields will + * be built based on information taken from the flash interface. + * One important note: if there is a block of contiguous flash space that + * spans accross multiple flash banks, then the bank # of the LAST bank in + * that block is what should be specified in the devinfo BANKMASK field. + */ + +#define TFSEOT 0xffffffff +#define TDEV struct tfsdev + +#define TFS_DEVTYPE_RAM 0x00100000 +#define TFS_DEVTYPE_FLASH 0x00200000 +#define TFS_DEVTYPE_NVRAM 0x00300000 +#define TFS_DEVTYPE_MASK 0x00f00000 +#define TFS_DEVINFO_DYNAMIC 0x00080000 +#define TFS_DEVINFO_AUTOINIT 0x00040000 +#define TFS_DEVINFO_BANKMASK 0x00000fff +#define TFSDEVTOT ((sizeof(tfsdevtbl))/(sizeof(struct tfsdev))) + +#define TFS_DEVTYPE_ISRAM(tdp) \ + (((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_RAM) || \ + ((tdp->devinfo & TFS_DEVTYPE_MASK) == TFS_DEVTYPE_NVRAM)) + +struct tfsdev { + char *prefix; /* Device name prefix. */ + unsigned long start; /* First location into which TFS can */ + /* begin to store files. */ + unsigned long end; /* Last address into which TFS can */ + /* place file data. This is usually */ + /* one unit below the start of the */ + /* spare sector. */ + unsigned long spare; /* Start address of device spare */ + /* sector. */ + unsigned long sparesize; /* Size of device spare sector. */ + unsigned long sectorcount; /* Number of sectors in this device. */ + unsigned long devinfo; /* RAM or FLASH, etc... */ +}; + +/* TFS defragmentation header: + * This header is used during defragmentation to record the state of the + * files in flash prior to the start of the defragmentation process. + */ +struct defraghdr { + struct tfshdr *ohdr; /* Original location of header. */ + struct tfshdr *nextfile; /* Location of next file. */ + long filsize; /* Size of file. */ + unsigned long crc; /* 32 bit crc of this header. */ + unsigned long ohdrcrc; /* Copy of file's original hdrcrc. */ + long idx; /* Index into defrag hdr table. */ + int nesn; /* New end sector number. */ + long neso; /* New end sector offset. */ + long oeso; /* Original end sector offset. */ + char *nda; /* New destination address. */ + char fname[TFSNAMESIZE+1]; /* Name of file. */ +}; + +/* sectorcrc: + * This structure is used to store the crc of the sectors before and + * after a defragmentation. A table of these structures is built prior + * to startup of any file relocation. + */ +struct sectorcrc { + unsigned long precrc; + unsigned long postcrc; +}; + +#define DEFRAGHDRSIZ sizeof(struct defraghdr) +#define DEFRAGHDR struct defraghdr + +/* States used during defragmentation: */ +#define SECTOR_DEFRAG_INACTIVE 1 +#define SCANNING_ACTIVE_SECTOR 2 +#define SCANNING_ACTIVE_SECTOR_1 3 +#define SCANNING_ACTIVE_SECTOR_2 4 +#define SCANNING_ACTIVE_SECTOR_3 5 +#define SCANNING_ACTIVE_SECTOR_4 6 +#define SCANNING_ACTIVE_SECTOR_5 7 +#define SECTOR_DEFRAG_ALMOST_DONE 8 +#define SECTOR_DEFRAG_ABORT_RESTART 9 + +/* Different ways in which a file can span across the active sector. */ +#define SPANTYPE_UNDEF 0 /* Span type undefined */ +#define SPANTYPE_BPEP 1 /* Begin-previous/end-previous */ +#define SPANTYPE_BPEC 2 /* Begin-previous/end-current */ +#define SPANTYPE_BPEL 3 /* Begin-previous/end-later */ +#define SPANTYPE_BCEC 4 /* Begin-current/end-current */ +#define SPANTYPE_BCEL 5 /* Begin-current/end-later */ +#define SPANTYPE_BLEL 6 /* Begin-later/end-later */ + +/* struct tfsdat: + Used by TFS to keep track of an opened file. +*/ +struct tfsdat { + long offset; /* Current offset into file. */ + long hwp; /* High water point for modified file. */ + unsigned char *base; /* Base address of file. */ + long flagmode; /* Flags & mode file was opened with. */ + struct tfshdr hdr; /* File structure. */ +}; + +/* struct tfsdfg, tfsflg & tfserr: + Structures provide an easy means of translation between values and + strings that explain those values. +*/ +struct tfsflg { + long flag; + char sdesc; + char *ldesc; + long mask; +}; + +struct tfserr { + long err; + char *msg; +}; + +struct tfsdfg { + long state; + char *msg; +}; + +struct tfsinfo { + int liveftot; /* Number of live files. */ + int livedata; /* Space used by living file data. */ + int liveovrhd; /* Space used by living file overhead. */ + int deadftot; /* Number of dead files. */ + int deaddata; /* Space used by dead file data. */ + int deadovrhd; /* Space used by dead file overhead. */ + int pso; /* Per-sector (not per file) TFS overhead. */ + int sos; /* Size of spare sector(s). */ + int memtot; /* Total tfs memory space in device(s). */ + int memfree; /* Memory space available for new file data. */ + int memused; /* Total memory space used by files & overhead. */ + int memfordata; /* Total memory available for new file data. */ + int sectortot; /* Total number of sectors in this tfs device. */ +}; +typedef struct tfsinfo TINFO; + + +/* Extern data: */ +extern long tfsTrace; +extern long tfsFmodCount; +extern TFILE **tfsAlist; +extern TDEV tfsDeviceTbl[]; +#ifdef TFS_ALTDEVTBL_BASE +extern TDEV *alt_tfsdevtbl; +#endif +extern TDEV alt_tfsdevtbl_base; +extern struct tfsdat tfsSlots[]; +extern struct tfsflg tfsflgtbl[]; +extern int ScriptExitFlag; +extern int TfsCleanEnable; +extern int DefragTestPoint; +extern int DefragTestType; +extern int DefragTestSector; + +/* Extern functions: */ +extern int tfseof(int); +extern int tfsinit(void); +extern int _tfsinit(TDEV *); +extern int tfsreorder(void); +extern int tfsrunboot(void); +extern int tfsfixup(int,int); +extern int tfsunlink(char *); +extern int tfslink(char *,char *); +extern int tfsclean_on(void); +extern int tfsclean_off(void); +extern int _tfsunlink(char *); +extern int tfsflasherase(int); +extern int tfsrun(char **,int); +extern int tfscheck(TDEV *,int); +extern int validtfshdr(TFILE *); +extern int tfstruncate(int,long); +extern int tfsclose(int, char *); +extern int tfsscript(TFILE *,int); +extern int tfsseek(int, int, int); +extern int tfsread(int,char *,int); +extern int tfsspace(char *); +extern int showTfsError(int,char *); +extern int tfsflasheraseall(TDEV *); +extern int tfsflasherased(TDEV *,int); +extern int tfswrite(int, char *, int); +extern int tfsgetline(int,char *,int); +extern int tfsLogCmd(int,char **,int); +extern int tfsopen(char *,long,char *); +extern int tfsfstat(char *name,TFILE *); +extern int tfsmemuse(TDEV *,TINFO *,int); +extern int tfsipmod(char *,char *,int,int); +extern int tfsclean_nps(TDEV *, char *, unsigned long); +extern int tfsloadebin(TFILE *,int,long *,char *,int); +extern int tfsloadebin_l(TFILE *,int,long *,int); +extern int tfsadd(char *,char *,char *,unsigned char *,int); +extern int tfsflashwrite(unsigned char *,unsigned char *,long); +extern int tfsclean(TDEV *,int); +extern int _tfsclean(TDEV *,int,int); +extern int tfsautoclean(TDEV *,int); +extern int (*tfsDocommand)(char *,int); +extern int dumpDhdr(struct defraghdr *), dumpDhdrTbl(struct defraghdr *,int); +extern int dumpFhdr(TFILE *); +extern int tfsRunningMonrc(void); +extern int tfsramdevice(char *,long,long); +extern int tfscfg(char *,unsigned long, unsigned long, unsigned long); +extern int tfscfgrestore(void); +extern int tfsflagsatob(char *, long *); + + +extern TDEV *gettfsdev_fromprefix(char *,int); + +extern TFILE *tfsnext(TFILE *); +extern TFILE *tfsstat(char *name); +extern TFILE *_tfsstat(char *name,int uselink); +extern TFILE *nextfp(TFILE *,TDEV *); + +extern long tfstell(int); +extern long (*tfsGetLtime)(void); +extern long tfsctrl(int,long,long); + +extern unsigned long tfshdrcrc(TFILE *); + +extern char *tfsBase(TFILE *); +extern char *tfserrmsg(int); +extern char *tfsscriptname(void); +extern char *tfsflagsbtoa(long,char *); +extern char *(*tfsGetAtime)(long,char *,int); + +extern void tfsclear(TDEV *); +extern void gototag(char *); +extern void gosubtag(char *); +extern void gosubret(char *); +extern void exitscript(char *); +extern void tfsstartup(void); +extern void tfslog(int,char *); +extern void tfsFacilityUnavailable(char *); +extern void tfsrunrcfile(void); +#endif diff --git a/main/common/tftp.c b/main/common/tftp.c new file mode 100644 index 0000000..f4b9130 --- /dev/null +++ b/main/common/tftp.c @@ -0,0 +1,1542 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tftp.c: + * + * This code supports the monitor's TFTP server. + * TFTP is covered under RFC 783. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_TFTP +#include <stdarg.h> +#include "endian.h" +#include "genlib.h" +#include "cpuio.h" +#include "ether.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "monflags.h" +#include "stddefs.h" +#include "flash.h" +#include "cli.h" +#include "timer.h" + +/* To reduce uMon footprint size, INCLUDE_TFTPSRVR can be set to 0 in + * config.h... + */ +#ifndef INCLUDE_TFTPSRVR +#define INCLUDE_TFTPSRVR 1 +#endif + +#if INCLUDE_ETHERVERBOSE +#define TFTPVERBOSE(a) a +#else +#define TFTPVERBOSE(a) +#endif + + +#define MODE_NULL 0 +#define MODE_NETASCII 1 +#define MODE_OCTET 2 + +void ShowTftpStats(void); +static int SendTFTPData(struct ether_header *,ushort,uchar *,int); +static int SendTFTPErr(struct ether_header *,short,int,char *fmt, ...); +static int SendTFTPAck(struct ether_header *,ushort); +static int SendTFTPRRQ(uchar *,uchar *,char *,char *,uchar *); +static int SendTFTPWRQ(uchar *,uchar *,char *,char *); + + +static struct elapsed_tmr tftpTmr; + +static ushort tftpPrevBlock; /* Keeps the value of the block number of + * the previous TFTP transaction. + */ +static int TftpWrqMode; /* Set to MODE_NETASCII, MODE_OCTET or + * MODE_NULL based on the incoming WRQ + * request + */ +static int TftpChopCount; /* Number of characters chopped from the + * incoming file because of NETASCII + * conversion (remove 0x0d). + */ +static short TftpLastPktSize; +static uchar TftpLastPkt[TFTP_PKTOVERHEAD+TFTP_DATAMAX+4]; + /* Storage of last packet sent. This is + * used if it is determined that the packet + * most recently sent must be sent again. + */ + +static long TftpRetryTimeout; /* Count used during a TFTP transfer to + * kick off a retransmission of a packet. + */ +static ushort TftpRmtPort; /* Remote port of tftp transfer */ +static uchar *TftpAddr; /* Current destination address used for tftp + * file transfer to/from local memory. + */ +static char *TftpLTMptr; /* List-to-mem pointer used when filename + * for RRQ is ".". + */ +static int TftpCount; /* Running total number of bytes transferred + * for a particular tftp transaction. + */ +static char TftpState; /* Used to keep track of the current state + * of a tftp transaction. + */ +static char TftpTurnedOff; /* If non-zero, then tftp is disabled. */ +static char TftpGetActive; /* If non-zero, then 'get' is in progress. */ +static char TftpPutActive; /* If non-zero, then 'put' is in progress. */ +static char TftpErrString[32]; /* Used to post a tftp error message. */ +static char TftpTfsFname[TFSNAMESIZE+64]; /* Store name of WRQ destination + * file (plus flags & info). + */ +#if INCLUDE_TFTPSRVR +/* ls_to_mem(): + * Turn the list of files into a string buffer that contains + * each filename followed by a newline. Each filename is the "full" + * name, meaning that it will contain commas to delimit the flags and + * info fields of the file. + * Return a pointer to the allocated space. + */ +static char * +ls_to_mem(void) +{ +#if INCLUDE_TFS + int size; + TFILE *tfp; + char *base, *bp, *info, *flags, fbuf[16]; + + /* First determine how much memory will be needed to store + * the list of files... Each filename in the list will consist + * of the string formatted as "name,flags,info\n"... + */ + size = 0; + tfp = (TFILE *)0; + while((tfp = tfsnext(tfp))) { + /* Increment size to include filename, 2 commas and a newline... + */ + size += (strlen(TFS_NAME(tfp)) + 3); + + /* Determine if flags and/or info field is to be present in + * the name, and add that to the size appropriately... + */ + flags = tfsflagsbtoa(TFS_FLAGS(tfp),fbuf); + if (!fbuf[0]) + flags = 0; + if (flags) + size += strlen(flags); + if (TFS_INFO(tfp)) + size += strlen(TFS_INFO(tfp)); + } + + if (size == 0) + return(0); + + /* Allocate the space. Add one additional byte to the size to + * account for the NULL termination at the end of the string... + */ + base = bp = malloc(size+1); + if (bp == (char *)0) + return(0); + + /* Load the buffer with the list of names with their + * TFS extensions... + */ + tfp = (TFILE *)0; + while((tfp = tfsnext(tfp))) { + flags = tfsflagsbtoa(TFS_FLAGS(tfp),fbuf); + if (!flags || !fbuf[0]) + flags = ""; + if (TFS_INFO(tfp)) + info = TFS_INFO(tfp); + else + info = ""; + + bp += sprintf(bp,"%s,%s,%s\n",TFS_NAME(tfp),flags,info); + } + + return(base); +#else + return(0); +#endif +} +#endif + +static char * +tftpStringState(int state) +{ + switch(state) { + case TFTPOFF: + return("OFF"); + case TFTPIDLE: + return("IDLE"); + case TFTPACTIVE: + return("ACTIVE"); + case TFTPERROR: + return("ERROR"); + case TFTPHOSTERROR: + return("HOSTERROR"); + case TFTPSENTRRQ: + return("SENTRRQ"); + case TFTPSENTWRQ: + return("SENTWRQ"); + case TFTPTIMEOUT: + return("TIMEOUT"); + default: + return("???"); + } +} + +static int +tftpGotoState(int state) +{ + int ostate; + + ostate = TftpState; + TftpState = state; +#if INCLUDE_ETHERVERBOSE + if ((EtherVerbose & SHOW_TFTP_STATE) && (state != ostate)) + printf(" TFTP State change %s -> %s\n", + tftpStringState(ostate), tftpStringState(state)); +#endif + return(ostate); +} + +/* tftpGet(): + * Return size of file if successful; else 0. + */ +int +tftpGet(ulong addr,char *tftpsrvr,char *mode, char *hostfile,char *tfsfile, + char *tfsflags,char *tfsinfo) +{ + int done; + uchar binip[8], binenet[8], *enetaddr; + + setenv("TFTPGET",0); + + /* Convert IP address to binary: */ + if (IpToBin(tftpsrvr,binip) < 0) + return(0); + + /* Get the ethernet address for the IP: */ + /* Give ARP the same verbosity (if any) set up for TFTP: */ + TFTPVERBOSE(if (EtherVerbose & SHOW_TFTP_STATE) EtherVerbose |= SHOW_ARP); + enetaddr = ArpEther(binip,binenet,0); + TFTPVERBOSE(EtherVerbose &= ~SHOW_ARP); + if (!enetaddr) { + printf("ARP failed for %s\n",tftpsrvr); + return(0); + } + + printf("Retrieving %s from %s...\n",hostfile,tftpsrvr); + + /* Send the TFTP RRQ to initiate the transfer. */ + if (SendTFTPRRQ(binip,binenet,hostfile,mode,(uchar *)addr) < 0) { + printf("RRQ failed\n"); + return(0); + } + + TftpGetActive = 1; + + /* Wait for TftpState to indicate that the transaction has completed... */ + done = 0; + while(!done) { + pollethernet(); + switch(TftpState) { + case TFTPIDLE: + printf("Rcvd %d bytes",TftpCount); + done = 1; + break; + case TFTPERROR: + printf("TFTP Terminating\n"); + done = 2; + break; + case TFTPHOSTERROR: + printf("Host error: %s\n",TftpErrString); + done = 2; + break; + case TFTPTIMEOUT: + printf("Timing out (%d bytes rcvd)\n",TftpCount); + done = 2; + break; + default: + break; + } + } + TftpGetActive = 0; + + if (done == 2) { + tftpInit(); + return(0); + } + + if (tfsfile) { + int err, filesize; + + filesize = TftpCount - TftpChopCount; + printf("\nAdding %s (size=%d) to TFS...",tfsfile,filesize); + err = tfsadd(tfsfile,tfsinfo,tfsflags,(uchar *)addr,filesize); + if (err != TFS_OKAY) + printf("%s: %s\n",tfsfile,(char *)tfsctrl(TFS_ERRMSG,err,0)); + } + printf("\n"); + shell_sprintf("TFTPGET","%d",TftpCount); + return(TftpCount); +} + +/* tftpPut(): + * Return size of file if successful; else 0. + * + * Simple steps from RFC 1350 for PUT are: + * 1. Send WRQ to port 69 of remote server + * 2. Receive ACK 0 from Server RemotePort (not 69) + * 3. Send data less than 512 bytes to RemotePort which closes it out. + * 4. Reinit if error (above in GET errors if done == 2) + * + * This 'put' capability was contributed by Steve Shireman. + */ + +int +tftpPut(char *tftpsrvr,char *mode,char *hostfile,char *tfsfile, + char *tfsflags,char *tfsinfo) +{ +#if INCLUDE_TFS + int done, tot; + TFILE *tfp; + uchar binip[8], binenet[8], *enetaddr; + + setenv("TFTPPUT",0); + + if ((tfp = tfsstat(tfsfile)) == (TFILE *)0) + return(0); + + /* For 'put', the address increments and the count decrements as + * the transfer progresses. + */ + TftpAddr = (uchar *)TFS_BASE(tfp); + TftpCount = tot = TFS_SIZE(tfp); + + /* Convert IP address to binary: */ + if (IpToBin(tftpsrvr,binip) < 0) + return(0); + + /* Get the ethernet address for the IP: + * (give ARP the same verbosity set up for TFTP) + */ + TFTPVERBOSE(if (EtherVerbose & SHOW_TFTP_STATE) EtherVerbose |= SHOW_ARP); + enetaddr = ArpEther(binip,binenet,0); + TFTPVERBOSE(EtherVerbose &= ~SHOW_ARP); + + if (!enetaddr) { + printf("ARP failed for %s\n",tftpsrvr); + return(0); + } + + printf("Sending %s to %s:%s...\n",tfsfile,tftpsrvr,hostfile); + TftpPutActive = 1; + tftpPrevBlock = 0; + + /* Send the TFTP WRQ to initiate the transfer. */ + if (SendTFTPWRQ(binip,binenet,hostfile,mode) < 0) { + printf("WRQ failed\n"); + return(0); + } + + /* Wait for TftpState to indicate that the transaction has completed... */ + done = 0; + while(!done) { + pollethernet(); + switch(TftpState) { + case TFTPIDLE: + printf("Sent %d bytes",tot); + done = 1; + break; + case TFTPERROR: + printf("TFTP Terminating\n"); + done = 2; + break; + case TFTPHOSTERROR: + printf("Host error: %s\n",TftpErrString); + done = 2; + break; + case TFTPTIMEOUT: + printf("Timing out (%d bytes sent)\n",TftpCount); + done = 2; + break; + default: + break; + } + } + TftpPutActive = 0; + + if (done == 2) { + tftpInit(); + return(0); + } + printf("\n"); + shell_sprintf("TFTPPUT","%d",tot); + return(tot); +#else + printf("TFTP 'put' requires TFS\n"); + return(0); +#endif +} + +/* tftpInit(): + * Called by the ethenet initialization to initialize state variables. + */ +void +tftpInit() +{ + TftpCount = -1; + TftpRmtPort = 0; + TftpTurnedOff = 0; + tftpGotoState(TFTPIDLE); + TftpAddr = (uchar *)0; +} + +/* storePktAndSend(): + * The final stage in sending a TFTP packet... + * 1. Compute IP and UDP checksums; + * 2. Copy ethernet packet to a buffer so that it can be resent + * if necessary (by tftpStateCheck()). + * 3. Store the size of the packet; + * 4. Send the packet out the interface. + * 5. Reset the timeout count and re-transmission delay variables. + */ +static void +storePktAndSend(struct ip *ipp, struct ether_header *epkt,int size) +{ + ipChksum(ipp); /* Compute csum of ip hdr */ + udpChksum(ipp); /* Compute UDP checksum */ + /* Copy packet to static buffer */ + memcpy((char *)TftpLastPkt,(char *)epkt,size); + TftpLastPktSize = size; /* Copy size to static location */ + sendBuffer(size); /* Send buffer out ethernet i*/ + + /* Re-initialize the re-transmission delay variables. + */ + TftpRetryTimeout = RetransmitDelay(DELAY_INIT_TFTP); + startElapsedTimer(&tftpTmr,TftpRetryTimeout * 1000); +} + +/* getTftpSrcPort(): + * Each time a TFTP RRQ goes out, use a new source port number. + * Cycle through a block of 256 port numbers... + */ +static ushort +getTftpSrcPort(void) +{ + if (TftpSrcPort < (IPPORT_TFTPSRC+256)) + TftpSrcPort++; + else + TftpSrcPort = IPPORT_TFTPSRC; + return(TftpSrcPort); +} + +/* tftpStateCheck(): + * Called by the pollethernet function to support the ability to retry + * on a TFTP transmission that appears to have terminated prematurely + * due to a lost packet. If a packet is sent and the response is not + * received within about 1-2 seconds, the packet is re-sent. The retry + * will repeat 8 times; then give up and set the TFTP state to idle. + * + * Taken from RFC 1350 section 2 "Overview of the Protocol"... + * ... If a packet gets lost in the network, the intended recipient will + * timeout and may retransmit his last packet (which may be data or an + * acknowledgement), thus causing the sender of the lost packet to retransmit + * the lost packet. + * + * Taken from RFC 1123 section 4.2.3.2 "Timeout Algorithms"... + * ... a TFTP implementation MUST use an adaptive timeout ... + */ + +void +tftpStateCheck(void) +{ + uchar *buf; + long delay; + ushort tftp_opcode; + struct ip *ihdr; + struct Udphdr *uhdr; + struct ether_header *ehdr; + + switch(TftpState) { + case TFTPIDLE: + case TFTPTIMEOUT: + case TFTPERROR: + return; + default: + break; + } + + /* If timeout occurs, re-transmit the packet... + */ + if (!msecElapsed(&tftpTmr)) + return; + + delay = RetransmitDelay(DELAY_INCREMENT); + if (delay == RETRANSMISSION_TIMEOUT) { +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" TFTP_RETRY giving up\n"); +#endif + tftpGotoState(TFTPTIMEOUT); + enableBroadcastReception(); + return; + } + + /* Get a transmit buffer and copy the packet that was last sent. + * Insert a new IP ID, recalculate the checksums and send it again... + * If the opcode of the packet to be re-transmitted is RRQ, then + * use a new port number. + */ + buf = (uchar *)getXmitBuffer(); + memcpy((char *)buf,(char *)TftpLastPkt,TftpLastPktSize); + ehdr = (struct ether_header *)buf; + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)(ihdr + 1); + tftp_opcode = *(ushort *)(uhdr + 1); + ihdr->ip_id = ipId(); + if (tftp_opcode == ecs(TFTP_RRQ)) { + uhdr->uh_sport = getTftpSrcPort(); + self_ecs(uhdr->uh_sport); + } + ipChksum(ihdr); + udpChksum(ihdr); + sendBuffer(TftpLastPktSize); + +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" TFTP_RETRY (%ld secs)\n",TftpRetryTimeout); +#endif + + TftpRetryTimeout = delay; + startElapsedTimer(&tftpTmr,TftpRetryTimeout * 1000); + return; +} + +#if INCLUDE_TFTPSRVR +/* tftpStartSrvrFilter(): + * Called when either a TFTP_RRQ or TFTP_WRQ is received indicating that + * a client wants to start up a transfer. + * If TftpState is IDLE, ERROR or TIMEOUT, this means it is safe to start + * up a new transfer through the server; otherwise return 0. + * Also, if the server has been disabled by "tftp off" at the command line + * (i.e. TftpTurnedOff == 1) then return 0. + */ +static int +tftpStartSrvrFilter(struct ether_header *ehdr,struct Udphdr *uhdr) +{ + if (TftpTurnedOff) { + SendTFTPErr(ehdr,0,1,"TFTP srvr off"); + return(0); + } + + if ((TftpState == TFTPIDLE) || (TftpState == TFTPERROR) || + (TftpState == TFTPTIMEOUT)) { + TftpTfsFname[0] = 0; + TftpRmtPort = ecs(uhdr->uh_sport); + tftpGotoState(TFTPACTIVE); + return(1); + } + /* If block is zero and the incoming WRQ request is from the same + * port as was previously recorded, then assume the ACK sent back + * to the requester was not received, and this is a WRQ that is + * being re-sent. That being the case, just send the Ack back. + */ + else if ((tftpPrevBlock == 0) && (TftpRmtPort == uhdr->uh_sport)) { + SendTFTPAck(ehdr,0); + return(0); + } + else { + /* Note: the value of TftpState is not changed (final arg to + * SendTFTPErr is 0) to TFTPERROR. This is because + * we received a RRQ/WRQ request while processing a different + * TFTP transfer. We want to send the error response to the + * sender, but we don't want to stay in an error state because + * there is another valid TFTP transfer in progress. + */ + SendTFTPErr(ehdr,0,0,"TFTP srvr busy"); + return(0); + } +} +#endif + +/* tftpTransferComplete(): + * Print a message indicating that the transfer has completed. + */ +static void +tftpTransferComplete(void) +{ +#if INCLUDE_ETHERVERBOSE + if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN())) + printf("TFTP transfer complete.\n"); +#endif +} + +/* processTFTP(): + * This function handles the majority of the TFTP requests that a + * TFTP server must be able to handle. There is no real robust + * error handling, but it seems to work pretty well. + * Refer to Stevens' "UNIX Network Programming" chap 12 for details + * on TFTP. + * Note: During TFTP, promiscuity, broadcast & multicast reception + * are all turned off. This is done to speed up the file transfer. + */ +int +processTFTP(struct ether_header *ehdr,ushort size) +{ + struct ip *ihdr; + struct Udphdr *uhdr; + uchar *data; + int count; + ushort opcode, block, errcode; + char *errstring, *tftpp; +#if INCLUDE_TFTPSRVR + char *comma, *env, *filename, *mode; +#endif + + ihdr = (struct ip *)(ehdr + 1); + uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr)); + tftpp = (char *)(uhdr + 1); + opcode = *(ushort *)tftpp; + + switch (opcode) { +#if INCLUDE_TFTPSRVR + case ecs(TFTP_WRQ): + filename = tftpp+2; +#if INCLUDE_ETHERVERBOSE + if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN())) + printf("TFTP rcvd WRQ: file <%s>\n", filename); +#endif + if (!tftpStartSrvrFilter(ehdr,uhdr)) + return(0); + + mode = filename; + while(*mode) + mode++; + mode++; + + /* Destination of WRQ can be an address (0x...), environment + * variable ($...) or a TFS filename... + */ + if (filename[0] == '$') { + env = getenv(&filename[1]); + if (env) { + TftpAddr = (uchar *)strtol(env,(char **)0,0); + } + else { + SendTFTPErr(ehdr,0,1,"Shell var not set"); + return(0); + } + } + else if ((filename[0] == '0') && (filename[1] == 'x')) { + TftpAddr = (uchar *)strtol(filename,(char **)0,0); + } + else { + if (MFLAGS_NOTFTPOVW() && tfsstat(filename)) { + SendTFTPErr(ehdr,6,1,"File exists"); + return(0); + } + TftpAddr = (uchar *)getAppRamStart(); + strncpy(TftpTfsFname,filename,sizeof(TftpTfsFname)-1); + TftpTfsFname[sizeof(TftpTfsFname)-1] = 0; + } + TftpCount = -1; /* not used with WRQ, so clear it */ + + /* Convert mode to lower case... */ + strtolower(mode); + if (!strcmp(mode,"netascii")) + TftpWrqMode = MODE_NETASCII; + else if (!strcmp(mode,"octet")) + TftpWrqMode = MODE_OCTET; + else { + SendTFTPErr(ehdr,0,1,"Mode '%s' not supported.",mode); + TftpWrqMode = MODE_NULL; + TftpCount = -1; + return(0); + } + block = 0; + tftpPrevBlock = block; + TftpChopCount = 0; + disableBroadcastReception(); + break; + case ecs(TFTP_RRQ): + filename = tftpp+2; +#if INCLUDE_ETHERVERBOSE + if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN())) + printf("TFTP rcvd RRQ: file <%s>\n",filename); +#endif + if (!tftpStartSrvrFilter(ehdr,uhdr)) + return(0); + mode = filename; + while(*mode) mode++; + mode++; + comma = strchr(filename,','); + if (!comma) { + TFILE *tfp; + + if (!strcmp(filename,".")) { + TftpLTMptr = (char *)ls_to_mem(); + TftpAddr = (uchar *)TftpLTMptr; + if (TftpLTMptr) + TftpCount = strlen((char *)TftpAddr); + else + TftpCount = 0; + } + else { + tfp = tfsstat(filename); + if (!tfp) { + SendTFTPErr(ehdr,0,1,"File (%s) not found",filename); + TftpCount = -1; + return(0); + } + TftpAddr = (uchar *)TFS_BASE(tfp); + TftpCount = TFS_SIZE(tfp); + } + } + else { + *comma++ = 0; + if ((filename[0] == '$') && (getenv(&filename[1]))) + TftpAddr = (uchar *)strtol(getenv(&filename[1]),(char **)0,0); + else + TftpAddr = (uchar *)strtol(filename,(char **)0,0); + TftpCount = strtol(comma,(char **)0,0); + } + if (strcmp(mode,"octet")) { + SendTFTPErr(ehdr,0,1,"Must use binary mode"); + TftpCount = -1; + return(0); + } + block = tftpPrevBlock = 1; + disableBroadcastReception(); + tftpGotoState(TFTPACTIVE); + SendTFTPData(ehdr,block,TftpAddr,TftpCount); + return(0); +#endif + case ecs(TFTP_DAT): + block = ecs(*(ushort *)(tftpp+2)); + count = ecs(uhdr->uh_ulen) - (sizeof(struct Udphdr)+4); +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" Rcvd TFTP_DAT (%d,blk=%d)\n",count,block); + else if (EtherVerbose & SHOW_TFTP_TICKER) + ticktock(); +#endif + + if (TftpState == TFTPSENTRRQ) { /* See notes in SendTFTPRRQ() */ + tftpPrevBlock = 0; + if (block == 1) { + TftpRmtPort = ecs(uhdr->uh_sport); + tftpGotoState(TFTPACTIVE); + } + else { + SendTFTPErr(ehdr,0,1,"invalid block (%d)",block); + return(0); + } + } + /* Since we don't ACK the final TFTP_DAT from the server until after + * the file has been written, it is possible that we will receive + * a re-transmitted TFTP_DAT from the server. This is ignored by + * Sending another ACK... + */ + else if ((TftpState == TFTPIDLE) && (block == tftpPrevBlock)) { + SendTFTPAck(ehdr,block); +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" (packet ignored)\n"); +#endif + return(0); + } + else if (TftpState != TFTPACTIVE) { + SendTFTPErr(ehdr,0,1,"Bad state (%s) for incoming TFTP_DAT", + tftpStringState(TftpState)); + return(0); + } + + if (ecs(uhdr->uh_sport) != TftpRmtPort) { + SendTFTPErr(ehdr,0,0,"TFTP_DAT porterr: rcvd %d, expected %d", + ecs(uhdr->uh_sport),TftpRmtPort); + return(0); + } + if (block == tftpPrevBlock) { /* If block didn't increment, assume */ + SendTFTPAck(ehdr,block); /* retry. Ack it and return here. */ + return(0); /* Otherwise, if block != tftpPrevBlock+1, */ + } /* return an error, and quit now. */ + else if ((block == 0) && ((tftpPrevBlock & 0xffff) == 0xffff)) { + /* This case occurs when the block number wraps. + * It is a legal case where the downloaded data exceeds + * 32Mg (blockno > 0xffff). + */ + } + else if (block != tftpPrevBlock+1) { +#ifdef DONT_IGNORE_OUT_OF_SEQUENCE_BLOCKS + SendTFTPErr(ehdr,0,1,"TFTP_DAT blockerr: rcvd %d, expected %d", + block,tftpPrevBlock+1); + TftpCount = -1; +#endif + return(0); + } + TftpCount += count; + tftpPrevBlock = block; + data = (uchar *)(tftpp+4); + + /* If count is less than TFTP_DATAMAX, this must be the last + * packet of the transfer, so clean up state here. + */ + if (count < TFTP_DATAMAX) { + enableBroadcastReception(); + tftpGotoState(TFTPIDLE); + } + + /* Make sure the destination address for the data is not flash + * or BSS space... + */ + if (inUmonBssSpace((char *)TftpAddr,(char *)(TftpAddr+count))) { + SendTFTPErr(ehdr,0,1,"TFTP can't write to uMon BSS space"); + TftpCount = -1; + return(0); + } + +#if INCLUDE_FLASH + if (InFlashSpace(TftpAddr,count)) { + SendTFTPErr(ehdr,0,1,"TFTP can't write directly to flash"); + TftpCount = -1; + return(0); + } +#endif + /* Copy data from enet buffer to TftpAddr location. + * If netascii mode is active, then this transfer is much + * slower... + * If not netascii, then we use s_memcpy() because it does + * a verification of each byte written and will abort as soon + * as a failure is detected. + */ + if (TftpWrqMode == MODE_NETASCII) { + int tmpcount = count; + + while(tmpcount) { + if (*data == 0x0d) { + data++; + tmpcount--; + TftpChopCount++; + continue; + } + + *TftpAddr = *data; + if (*TftpAddr != *data) { + SendTFTPErr(ehdr,0,1,"Write error at 0x%lx", + (ulong)TftpAddr); + TftpCount = -1; + return(0); + } + TftpAddr++; + data++; + tmpcount--; + } + } + else { + if (s_memcpy((char *)TftpAddr,(char *)data,count,0,0) != 0) { + SendTFTPErr(ehdr,0,1,"Write error at 0x%lx",(ulong)TftpAddr); + TftpCount = -1; + return(0); + } + TftpAddr += count; + } + + /* Check for transfer complete (count < TFTP_DATAMAX)... */ + if (count < TFTP_DATAMAX) { + if (TftpTfsFname[0]) { + char *fcomma, *icomma, *flags, *info; + int err; + + /* If the transfer is complete and TftpTfsFname[0] + * is non-zero, then write the data to the specified + * TFS file... Note that a comma in the filename is + * used to find the start of (if any) the TFS flags + * string. A second comma, marks the info field. + */ + info = (char *)0; + flags = (char *)0; + fcomma = strchr(TftpTfsFname,','); + if (fcomma) { + icomma = strchr(fcomma+1,','); + if (icomma) { + *icomma = 0; + info = icomma+1; + } + if (tfsctrl(TFS_FATOB,(long)(fcomma+1),0) != -1) { + *fcomma = 0; + flags = fcomma+1; + } + else { + SendTFTPErr(ehdr,0,1,"Invalid flag '%s'", + TftpTfsFname); + TftpTfsFname[0] = 0; + break; + } + } +#if INCLUDE_ETHERVERBOSE + if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN())) + printf("TFTP adding file: '%s' to TFS.\n",TftpTfsFname); +#endif + err = tfsadd(TftpTfsFname,info,flags, + (uchar *)getAppRamStart(),TftpCount+1-TftpChopCount); + if (err != TFS_OKAY) { + SendTFTPErr(ehdr,0,1,"TFS err: %s", + (char *)tfsctrl(TFS_ERRMSG,err,0)); + } + TftpTfsFname[0] = 0; + } + else { + int cnt; + char *addr; + + /* If the transfer is complete and no file add is to + * be done, then we flush d-cache and invalidate + * i-cache across the memory space that was just + * copied to. This is necessary in case the + * binary data that was just transferred is code. + */ + cnt = TftpCount + 1; + addr = (char *)TftpAddr - cnt; + flushDcache(addr,cnt); + invalidateIcache(addr,cnt); + } + if (!TftpGetActive) + shell_sprintf("TFTPRCV","%d",TftpCount+1); + tftpTransferComplete(); + } + break; + case ecs(TFTP_ACK): + block = ecs(*(ushort *)(tftpp+2)); +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" Rcvd TFTP_ACK (blk#%d)\n",block); +#endif + if ((TftpState != TFTPACTIVE) && (TftpState != TFTPSENTWRQ)) { + SendTFTPErr(ehdr,0,1,"Bad state (%s) for incoming TFTP_ACK", + tftpStringState(TftpState)); + return(0); + } + if (block == tftpPrevBlock) { + if (TftpCount > TFTP_DATAMAX) { + if (TftpState == TFTPACTIVE) { + TftpCount -= TFTP_DATAMAX; + TftpAddr += TFTP_DATAMAX; + } + SendTFTPData(ehdr,block+1,TftpAddr,TftpCount); + if (TftpState == TFTPSENTWRQ) { + TftpCount -= TFTP_DATAMAX; + TftpAddr += TFTP_DATAMAX; + } + tftpPrevBlock++; + } + else if (TftpCount == TFTP_DATAMAX) { + if (TftpState == TFTPACTIVE) + TftpCount = 0; + SendTFTPData(ehdr,block+1,TftpAddr,TftpCount); + if (TftpState == TFTPSENTWRQ) { + TftpCount = 0; + } + tftpPrevBlock++; + } + else { + if (TftpState == TFTPSENTWRQ) { + if (TftpCount == -1) { + TftpCount = 0; + tftpGotoState(TFTPIDLE); + enableBroadcastReception(); + tftpTransferComplete(); + } + else { + SendTFTPData(ehdr,block+1,TftpAddr,TftpCount); + TftpAddr += TftpCount; + TftpCount = -1; + tftpPrevBlock++; + } + } + else { + TftpAddr += TftpCount; + TftpCount = 0; + tftpGotoState(TFTPIDLE); + if (TftpLTMptr) { + free(TftpLTMptr); + TftpLTMptr = (char *)0; + } + enableBroadcastReception(); + tftpTransferComplete(); + } + } + } + else if (block == tftpPrevBlock-1) { + SendTFTPData(ehdr,block+1,TftpAddr,TftpCount); + } + else { +#ifdef DONT_IGNORE_OUT_OF_SEQUENCE_BLOCKS + SendTFTPErr(ehdr,0,1,"TFTP_ACK blockerr: rcvd %d, expected %d", + block,tftpPrevBlock-1); + TftpCount = -1; +#endif + return(0); + } + return(0); + case ecs(TFTP_ERR): + errcode = ecs(*(ushort *)(tftpp+2)); + errstring = tftpp+4; +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" Rcvd TFTP_ERR #%d (%s)\n",errcode,errstring); +#endif + TftpCount = -1; + tftpGotoState(TFTPHOSTERROR); + strncpy(TftpErrString,errstring,sizeof(TftpErrString)-1); + TftpErrString[sizeof(TftpErrString)-1] = 0; + return(0); + default: +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" Rcvd <%04x> unknown TFTP opcode\n", opcode); +#endif + TftpCount = -1; + return(-1); + } + SendTFTPAck(ehdr,block); + return(0); +} + +/* SendTFTPRRQ(): + * Pass the ether and ip address of the TFTP server, along with the + * filename and mode to start up a target-initiated TFTP download. + * The initial TftpState value is TFTPSENTRRQ, this is done so that incoming + * TFTP_DAT packets can be verified... + * - If a TFTP_DAT packet is received and TftpState is TFTPSENTRRQ, then + * the block number should be 1. If this is true, then that server's + * source port is stored away in TftpRmtPort so that all subsequent + * TFTP_DAT packets will be compared to the initial source port. If no + * match, then respond with a TFTP error or ICMP PortUnreachable message. + * - If a TFTP_DAT packet is received and TftpState is TFTPSENTRRQ, then + * if the block number is not 1, generate a error. + */ +static int +SendTFTPRRQ(uchar *ipadd,uchar *eadd,char *filename,char *mode,uchar *loc) +{ + uchar *tftpdat; + ushort ip_len; + struct ether_header *te; + struct ip *ti; + struct Udphdr *tu; + + TftpChopCount = 0; + tftpGotoState(TFTPSENTRRQ); + TftpAddr = loc; + TftpCount = 0; + + /* Retrieve an ethernet buffer from the driver and populate the + * ethernet level of packet: + */ + te = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&te->ether_shost,(char *)BinEnetAddr,6); + memcpy((char *)&te->ether_dhost,(char *)eadd,6); + te->ether_type = ecs(ETHERTYPE_IP); + + /* Move to the IP portion of the packet and populate it appropriately: */ + ti = (struct ip *) (te + 1); + ti->ip_vhl = IP_HDR_VER_LEN; + ti->ip_tos = 0; + ip_len = sizeof(struct ip) + + sizeof(struct Udphdr) + strlen(filename) + strlen(mode) + 4; + ti->ip_len = ecs(ip_len); + ti->ip_id = ipId(); + ti->ip_off = 0; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&ti->ip_src.s_addr,(char *)BinIpAddr,4); + memcpy((char *)&ti->ip_dst.s_addr,(char *)ipadd,4); + + /* Now udp... */ + tu = (struct Udphdr *) (ti + 1); + tu->uh_sport = getTftpSrcPort(); + self_ecs(tu->uh_sport); + tu->uh_dport = ecs(TftpPort); + tu->uh_ulen = ecs((ushort)(ip_len - sizeof(struct ip))); + + /* Finally, the TFTP specific stuff... */ + tftpdat = (uchar *)(tu+1); + *(ushort *)(tftpdat) = ecs(TFTP_RRQ); + strcpy((char *)tftpdat+2,(char *)filename); + strcpy((char *)tftpdat+2+strlen((char *)filename)+1,mode); + + if (!strcmp(mode,"netascii")) + TftpWrqMode = MODE_NETASCII; + else + TftpWrqMode = MODE_OCTET; + + storePktAndSend(ti, te,TFTPACKSIZE+strlen(filename)+strlen(mode)); + +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf("\n Sent TFTP_RRQ (file=%s)\n",filename); +#endif + + return(0); +} + + +/* SendTFTPWRQ(): SSADDED + * Pass the ether and ip address of the TFTP server, along with the + * filename and mode to start up a target-initiated TFTP download. + * The initial TftpState value is TFTPSENTRRQ, this is done so that incoming + * TFTP_DAT packets can be verified... + * - If a TFTP_DAT packet is received and TftpState is TFTPSENTRRQ, then + * the block number should be 1. If this is true, then that server's + * source port is stored away in TftpRmtPort so that all subsequent + * TFTP_DAT packets will be compared to the initial source port. If no + * match, then respond with a TFTP error or ICMP PortUnreachable message. + * - If a TFTP_DAT packet is received and TftpState is TFTPSENTRRQ, then + * if the block number is not 1, generate a error. + */ +static int +SendTFTPWRQ(uchar *ipadd,uchar *eadd,char *filename,char *mode) +{ + uchar *tftpdat; + ushort ip_len; + struct ether_header *te; + struct ip *ti; + struct Udphdr *tu; + + TftpChopCount = 0; + + /* Retrieve an ethernet buffer from the driver and populate the + * ethernet level of packet: + */ + te = (struct ether_header *) getXmitBuffer(); + memcpy((char *)&te->ether_shost,(char *)BinEnetAddr,6); + memcpy((char *)&te->ether_dhost,(char *)eadd,6); + te->ether_type = ecs(ETHERTYPE_IP); + + /* Move to the IP portion of the packet and populate it appropriately: */ + ti = (struct ip *) (te + 1); + ti->ip_vhl = IP_HDR_VER_LEN; + ti->ip_tos = 0; + ip_len = sizeof(struct ip) + + sizeof(struct Udphdr) + strlen(filename) + strlen(mode) + 4; + ti->ip_len = ecs(ip_len); + ti->ip_id = ipId(); + ti->ip_off = 0; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&ti->ip_src.s_addr,(char *)BinIpAddr,4); + memcpy((char *)&ti->ip_dst.s_addr,(char *)ipadd,4); + + /* Now udp... */ + tu = (struct Udphdr *) (ti + 1); + tu->uh_sport = getTftpSrcPort(); + self_ecs(tu->uh_sport); + tu->uh_dport = ecs(TftpPort); + tu->uh_ulen = ecs((ushort)(ip_len - sizeof(struct ip))); + + /* Finally, the TFTP specific stuff... */ + tftpdat = (uchar *)(tu+1); + *(ushort *)(tftpdat) = ecs(TFTP_WRQ); + strcpy((char *)tftpdat+2,(char *)filename); + strcpy((char *)tftpdat+2+strlen((char *)filename)+1,mode); + + if (!strcmp(mode,"netascii")) + TftpWrqMode = MODE_NETASCII; + else + TftpWrqMode = MODE_OCTET; + + storePktAndSend(ti, te,TFTPACKSIZE+strlen(filename)+strlen(mode)); + +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf("\n Sent TFTP_WRQ (file=%s)\n",filename); +#endif + + tftpGotoState(TFTPSENTWRQ); + return(0); +} +//ss END OF ADDED SendTRTPWRQ + + +/* SendTFTPAck(): + */ +static int +SendTFTPAck(struct ether_header *re,ushort block) +{ + uchar *tftpdat; + ushort ip_len; + struct ether_header *te; + struct ip *ti, *ri; + struct Udphdr *tu, *ru; + + te = EtherCopy(re); + + ti = (struct ip *) (te + 1); + ri = (struct ip *) (re + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ip_len = sizeof(struct ip) + sizeof(struct Udphdr) + 4; + ti->ip_len = ecs(ip_len); + ti->ip_id = ipId(); + ti->ip_off = ri->ip_off; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr), + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), + sizeof(struct in_addr)); + + tu = (struct Udphdr *) (ti + 1); + ru = (struct Udphdr *) (ri + 1); + tu->uh_sport = ru->uh_dport; + tu->uh_dport = ru->uh_sport; + tu->uh_ulen = ecs((ushort)(ip_len - sizeof(struct ip))); + + tftpdat = (uchar *)(tu+1); + *(ushort *)(tftpdat) = ecs(TFTP_ACK); + *(ushort *)(tftpdat+2) = ecs(block); + + storePktAndSend(ti,te,TFTPACKSIZE); + +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" Sent TFTP_ACK (blk#%d)\n",block); +#endif + return(0); +} + +/* SendTFTPErr(): + */ +static int +SendTFTPErr(struct ether_header *re,short errno,int changestate,char *fmt, ...) +{ + va_list argp; + short len, tftplen, hdrlen; + uchar *tftpmsg; + struct ether_header *te; + struct ip *ti, *ri; + struct Udphdr *tu, *ru; + static char errmsg[128]; + + if (changestate) + tftpGotoState(TFTPERROR); + + va_start(argp,fmt); + vsnprintf(errmsg,sizeof(errmsg),fmt,argp); + va_end(argp); + +#if INCLUDE_ETHERVERBOSE + if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN())) + printf("TFTP err: %s\n",errmsg); +#endif + + tftplen = strlen(errmsg) + 1 + 4; + hdrlen = sizeof(struct ip) + sizeof(struct Udphdr); + len = tftplen + hdrlen ; + + te = EtherCopy(re); + + ti = (struct ip *) (te + 1); + ri = (struct ip *) (re + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ti->ip_len = ecs(len); + ti->ip_id = ipId(); + ti->ip_off = ri->ip_off; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr), + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), + sizeof(struct in_addr)); + + tu = (struct Udphdr *) (ti + 1); + ru = (struct Udphdr *) (ri + 1); + tu->uh_sport = ru->uh_dport; + tu->uh_dport = ru->uh_sport; + tu->uh_ulen = sizeof(struct Udphdr) + tftplen; + self_ecs(tu->uh_ulen); + + tftpmsg = (uchar *)(tu+1); + *(ushort *)(tftpmsg) = ecs(TFTP_ERR); + * (ushort *)(tftpmsg+2) = ecs(errno); + strcpy((char *)tftpmsg+4,(char *)errmsg); + + storePktAndSend(ti,te,TFTPACKSIZE + strlen(errmsg) + 1); + +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" Sent TFTP Err#%d (%s) \n",errno,errmsg); +#endif + + return(0); +} + +/* SendTFTPData(): + */ +static int +SendTFTPData(struct ether_header *re,ushort block,uchar *data,int count) +{ + int len, tftplen, hdrlen; + uchar *tftpmsg; + struct ether_header *te; + struct ip *ti, *ri; + struct Udphdr *tu, *ru; + + if (count > TFTP_DATAMAX) + count = TFTP_DATAMAX; + + tftplen = count + 2 + 2; /* sizeof (data + opcode + blockno) */ + hdrlen = sizeof(struct ip) + sizeof(struct Udphdr); + len = tftplen + hdrlen ; + + te = EtherCopy(re); + + ti = (struct ip *) (te + 1); + ri = (struct ip *) (re + 1); + ti->ip_vhl = ri->ip_vhl; + ti->ip_tos = ri->ip_tos; + ti->ip_len = ecs(len); + ti->ip_id = ipId(); + ti->ip_off = ri->ip_off; + ti->ip_ttl = UDP_TTL; + ti->ip_p = IP_UDP; + memcpy((char *)&(ti->ip_src.s_addr),(char *)&(ri->ip_dst.s_addr), + sizeof(struct in_addr)); + memcpy((char *)&(ti->ip_dst.s_addr),(char *)&(ri->ip_src.s_addr), + sizeof(struct in_addr)); + + tu = (struct Udphdr *) (ti + 1); + ru = (struct Udphdr *) (ri + 1); + tu->uh_sport = ru->uh_dport; + tu->uh_dport = ru->uh_sport; + tu->uh_ulen = sizeof(struct Udphdr) + tftplen; + self_ecs(tu->uh_ulen); + + tftpmsg = (uchar *)(tu+1); + *(ushort *)(tftpmsg) = ecs(TFTP_DAT); + *(ushort *)(tftpmsg+2) = ecs(block); + memcpy((char *)tftpmsg+4,(char *)data,count); + + len+=sizeof(struct ether_header); + + storePktAndSend(ti,te,len); + +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_TFTP_STATE) + printf(" Sent TFTP data blk#%d (%d bytes @ 0x%lx) \n", + block,count,(ulong)data); +#endif + return(0); +} + +#if 0 +THIS IS NOT YET TESTED +/* parseLongFilename(): + * Given a full filename that may contain up to three different + * comma-delimited tokens, this function will parse that string and + * return the requested tokens. + * + * The syntax of fullname can be... + * - name + * - name,flags + * - name,flags,info + * - name,,info + * + * Return 0 if successful, -1 if failure. + */ +int +parseLongFilename(char *fullname,char *name, char *flags, char *info) +{ + char *comma, *cp; + + /* Parse the fullname string looking for commas to determine what + * information is in the string. Then, based on the presence of + * the commas, populate the incoming pointers with the appropriate + * portion of the fullname string. + * If the pointer is NULL, then just skip over that portion of the + * algorithm. + */ + cp = fullname; + comma = strchr(cp,','); + if (comma) { + if (name) { + while(cp != comma) + *name++ = *cp++; + *name = 0; + } + cp++; + comma = strchr(cp,','); + if (comma) { + if (flags) { + while(cp != comma) + *flags++ = *cp++; + *flags = 0; + } + cp++; + if (info) { + strcpy(info,cp); + } + } + else { + if (flags) + strcpy(flags,cp); + } + } + else { + if (name) + strcpy(name,fullname); + } + return(0); +} +#endif + +/* Tftp(): + * Initiate a tftp transfer at the target (target is client). + * Command line: + * tftp [options] {IP} {get|put} {file|addr} [len]... + * tftp [options] {IP} get file dest_addr + * tftp [options] {IP} put addr dest_file len + * Currently, only "get" is supported. + */ + +char *TftpHelp[] = { + "Trivial file transfer protocol", + "-[aF:f:i:vV] [on|off|IP] {get|put filename [addr]} ss", +#if INCLUDE_VERBOSEHELP + " -a use netascii mode", + " -F {file} name of tfs file to copy to", + " -f {flgs} file flags (see tfs)", + " -i {info} file info (see tfs)", + " -v verbosity = ticker", + " -V verbosity = state", +#endif + 0, +}; + +int +Tftp(int argc,char *argv[]) +{ + int opt, verbose; + char *mode, *file, *info, *flags; + ulong addr; + + verbose = 0; + file = (char *)0; + info = (char *)0; + flags = (char *)0; + mode = "octet"; + while ((opt=getopt(argc,argv,"aF:f:i:vV")) != -1) { + switch(opt) { + case 'a': + mode = "netascii"; + break; + case 'f': + flags = optarg; + break; + case 'F': + file = optarg; + break; + case 'i': + info = optarg; + break; + case 'v': + verbose |= SHOW_TFTP_TICKER; + break; + case 'V': + verbose |= SHOW_TFTP_STATE; + break; + default: + return(CMD_PARAM_ERROR); + } + } + if (argc < (optind+1)) + return(CMD_PARAM_ERROR); + + if (argc == optind+1) { + if (!strcmp(argv[optind],"on")) { + TftpTurnedOff = 0; + TftpGetActive = 0; + TftpPutActive = 0; //ss ADDED + } + else if (!strcmp(argv[optind],"off")) { + TftpTurnedOff = 1; + TftpGetActive = 0; + tftpGotoState(TFTPIDLE); + TftpPutActive = 0; //ss ADDED + } + else + return(CMD_PARAM_ERROR); + return(CMD_SUCCESS); + } + + /* If either the info or flags field has been specified, but the */ + /* filename is not specified, error here... */ + if ((info || flags) && (!file)) { + printf("Filename missing\n"); + return(CMD_FAILURE); + } + + if (!strcmp(argv[optind+1],"get")) { + + if (argc == optind+4) + addr = (ulong)strtol(argv[optind+3],0,0); + else if (argc == optind+3) + addr = getAppRamStart(); + else + return(CMD_PARAM_ERROR); + + TFTPVERBOSE(EtherVerbose |= verbose); + tftpGet(addr,argv[optind],mode,argv[optind+2],file,flags,info); + TFTPVERBOSE(EtherVerbose &= ~verbose); + } + else if (!strcmp(argv[optind+1],"put")) { + + if (argc == (optind+3)) + file = argv[optind+2]; + else if (argc == (optind+4)) + file = argv[optind+3]; + else + return(CMD_PARAM_ERROR); + + TFTPVERBOSE(EtherVerbose |= verbose); + tftpPut(argv[optind],mode,file,argv[optind+2],flags,info); + TFTPVERBOSE(EtherVerbose &= ~verbose); + + } + else + return(CMD_PARAM_ERROR); + + return(CMD_SUCCESS); +} + +void +ShowTftpStats(void) +{ + printf("Current TFTP state: %s\n",tftpStringState(TftpState)); +} + +#endif diff --git a/main/common/time.h b/main/common/time.h new file mode 100755 index 0000000..f0ae1ce --- /dev/null +++ b/main/common/time.h @@ -0,0 +1,42 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * time.h: + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +typedef long time_t; + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +struct tm *gmtime_r(const time_t t, struct tm* tout); +char *asctime_r(const struct tm *t, char *buf); diff --git a/main/common/timer.h b/main/common/timer.h new file mode 100644 index 0000000..dab62df --- /dev/null +++ b/main/common/timer.h @@ -0,0 +1,71 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * timer.h + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +struct elapsed_tmr { + unsigned long start; // Start value of elapsed timeout. + unsigned long tmrval; // Running timer value + // (used by elapsed timeout) + unsigned long currenttmrval; // Current timer value + // (not used by elapsed timeout) + unsigned long tpm; // Ticks per millisecond + + unsigned long elapsed_low; + unsigned long elapsed_high; + + unsigned long timeout_low; + unsigned long timeout_high; + + unsigned long tmrflags; +}; + +/* Timer flags: + */ +#define HWTMR_ENABLED (1 << 0) +#define TIMEOUT_OCCURRED (1 << 1) + +/* Timer macros: + */ +#define HWRTMR_IS_ENABLED(tmr) \ + ((tmr)->tmrflags & HWTMR_ENABLED) + +#define ELAPSED_TIMEOUT(tmr) \ + ((tmr)->tmrflags & TIMEOUT_OCCURRED) + +/* uMon API timer commands: + */ +#define TIMER_START 1 +#define TIMER_ELAPSED 2 +#define TIMER_QUERY 3 + +extern unsigned long target_timer(void); +extern void startElapsedTimer(struct elapsed_tmr *tmr,long timeout); +extern int msecElapsed(struct elapsed_tmr *tmr); +extern unsigned long msecRemaining(struct elapsed_tmr *tmr); +extern int monTimer(int cmd, void *arg); + +#endif diff --git a/main/common/timestuff.c b/main/common/timestuff.c new file mode 100755 index 0000000..5cab2d3 --- /dev/null +++ b/main/common/timestuff.c @@ -0,0 +1,386 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * timestuff.c + * + * These functions support the monitor's ability to deal with elapsed + * time on targets with or without hardware-timer support. + * + * The INCLUDE_HWTMR definition in config.h determines which mode + * the timer will run in. + * + * The monitor does not require any hardware-assist for maintaining + * elapsed time. With no hardware assist (INCLUDE_HWTMR set to 0), + * the value of LOOPS_PER_SECOND must be established in config.h, and + * can be calibrated using the '-c' option in the sleep command. Even + * with this calibration the accuracy of this mechanism is limited; + * however, since there is no code in the monitor that really requires + * extremely accurate timing this may be ok. + * + * On the other hand, it is preferrable to have accuracy, so on targets + * that have a pollable clock, the hooks can be put in place to allow + * that clock to be used as the hardware assist for the monitor's + * elapsed time measurements. The INCLUDE_HWTMR is set to 1, and + * TIMER_TICKS_PER_MSEC defines the number of ticks of the timer that + * correspond to 1 millisecond of elapsed time. The function target_timer() + * is assumed to be established and must return an unsigned long value + * that is the content of the polled hardware timer. + * + * Regardless of the hardware-assist or not, the following interface is + * used by the code in the monitor... + * + * #include "timer.h" + * + * struct elapsed_tmr tmr; + * + * startElapsedTimer(&tmr,TIMEOUT): + * do { + * SOMETHING(); + * } while(!msecElapsed(&tmr)); + * + * Refer to the functions startElapsedTimer() and msecElapsed() below for + * more details. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#include "stddefs.h" +#include "cli.h" +#include "genlib.h" +#include "ether.h" +#include "timer.h" +#include "cpuio.h" + +/* startElapsedTimer() & msecElapsed(): + * The timer is started by loading the values timeout_low and timeout_high + * with the number of ticks that must elapse for the timer to expire. + * + * In the case of the non-hardware-assisted timer, the expiration count + * is based on the value of LoopsPerMillisecond (derived from the + * LOOPS_PER_SECOND definition in config.h). Each time msecElapsed() + * is called the elapsed count is incremented until it exceeds the timeout + * timeout_low timeout_high values recorded by startElapsedTimer(). + * + * The case of the hardware-assisted timer is similar except that now + * the number of ticks initialized in timeout_low and timeout_high are + * based on the tick rate of the hardware timer (TIMER_TICKS_PER_MSEC). + * This value is expected to be set in config.h. Each time msecElapsed() + * is called, it samples the timer and adds to the running total of ticks + * until it matches or exceeds the timeout_low and timeout_high values. + * + * Notice that 64-bit values are used (high & low) because a 32-bit value + * isn't large enough to deal with the tick rates (per second) of various + * CPUs. + */ +void +startElapsedTimer(struct elapsed_tmr *tmr, long milliseconds) +{ + unsigned long new_tm_low; + unsigned long stepmsecs, stepticks, remainder; + +#if INCLUDE_HWTMR + tmr->tmrflags = HWTMR_ENABLED; + tmr->tpm = (unsigned long)TIMER_TICKS_PER_MSEC; +#else + tmr->tmrflags = 0; + tmr->tpm = (unsigned long)LoopsPerMillisecond; +#endif + + tmr->elapsed_low = 0; + tmr->elapsed_high = 0; + tmr->timeout_high = 0; + tmr->timeout_low = 0; + + /* Convert incoming timeout from a millisecond count to a + * tick count... + * Maximum number of milliseconds and ticks before 32-bit + * (tick counter) unsigned long overlaps + */ + stepmsecs = 0xffffffff / tmr->tpm; + stepticks = stepmsecs * tmr->tpm; + remainder = (milliseconds % stepmsecs); + + /* Take care of the step remainder + */ + tmr->timeout_low = remainder * tmr->tpm; + milliseconds -= remainder; + + for (;milliseconds; milliseconds -= stepmsecs) { + new_tm_low = tmr->timeout_low + stepticks; + + if (new_tm_low < tmr->timeout_low) + tmr->timeout_high++; + tmr->timeout_low = new_tm_low; + } + +#if INCLUDE_HWTMR + tmr->tmrval = target_timer(); +#else + tmr->tmrval = 0; +#endif + +} + +int +msecElapsed(struct elapsed_tmr *tmr) +{ + ulong new_elapsed_low, new_tmrval, elapsed; + + /* If timeout has already occurred, then we can assume that this + * function being called without a matching startElapsedTimer() call. + */ + if (ELAPSED_TIMEOUT(tmr)) + return(1); + +#if INCLUDE_HWTMR + new_tmrval = target_timer(); +#else + new_tmrval = tmr->tmrval + 1; +#endif + + /* Record how many ticks elapsed since the last call to msecElapsed + * and add that value to the total number of ticks that have elapsed. + */ + elapsed = new_tmrval - tmr->tmrval; + new_elapsed_low = tmr->elapsed_low + elapsed; + + if (new_elapsed_low < tmr->elapsed_low) + tmr->elapsed_high++; + + /* If the total elapsed number of ticks exceeds the timeout number + * of ticks, then we can return 1 to indicate that the requested + * amount of time has elapsed. Otherwise, we record the values and + * return 0. + */ + if ((tmr->elapsed_high >= tmr->timeout_high) && + (new_elapsed_low >= tmr->timeout_low)) { + tmr->tmrflags |= TIMEOUT_OCCURRED; + return(1); + } + + tmr->tmrval = new_tmrval; + tmr->elapsed_low = new_elapsed_low; + return(0); +} + +/* msecRemainging(): + * Used to query how many milliseconds were left (if any) in the timeout. + */ +ulong +msecRemaining(struct elapsed_tmr *tmr) +{ + ulong high, low, msectot, leftover, divisor; + + if (ELAPSED_TIMEOUT(tmr)) + return(0); + + high = tmr->timeout_high - tmr->elapsed_high; + low = tmr->timeout_low - tmr->elapsed_low; + + msectot = leftover = 0; + +#if INCLUDE_HWTMR + divisor = (ulong)TIMER_TICKS_PER_MSEC; +#else + divisor = (ulong)LoopsPerMillisecond; +#endif + + while(1) { + while (low > divisor) { + msectot++; + low -= divisor; + } + leftover += low; + if (high == 0) + break; + else { + high--; + low = 0xffffffff; + } + } + + while(leftover > divisor) { + msectot++; + low -= divisor; + } + return(msectot); +} + +/* monDelay(): + * Delay for specified number of milliseconds. + * Refer to msecElapsed() description for a discussion on the + * accuracy of this delay. + */ +void +monDelay(int milliseconds) +{ + struct elapsed_tmr tmr; + + startElapsedTimer(&tmr,milliseconds); + while(!msecElapsed(&tmr)) { + WATCHDOG_MACRO; + pollethernet(); + } +} + +/* monTimer(): + * Provide the API with the ability to start a millisecond-granularity + * timer with some countdown value, and poll it waiting for completion. + */ +int +monTimer(int cmd, void *arg) +{ + int rc = 0; + struct elapsed_tmr *tmr = (struct elapsed_tmr *)arg; + + switch(cmd) { + case TIMER_START: + startElapsedTimer(tmr,tmr->start); + break; + case TIMER_ELAPSED: + msecElapsed(tmr); + if (ELAPSED_TIMEOUT(tmr)) + rc = 1; + break; + case TIMER_QUERY: +#if INCLUDE_HWTMR + tmr->tmrflags = HWTMR_ENABLED; + tmr->tpm = (unsigned long)TIMER_TICKS_PER_MSEC; + tmr->currenttmrval = target_timer(); +#else + tmr->tmrflags = 0; + tmr->tpm = (unsigned long)LoopsPerMillisecond; + tmr->currenttmrval = 0; +#endif + break; + default: + rc = -1; + break; + } + return(rc); +} + +#if INCLUDE_TFSSCRIPT + +/* Sleep(): + * Simple delay loop accessible by the command line. + * This loop count is dependent on the underlying hardware. + * The LoopsPerMillisecond count is loaded with a default at startup, or + * it can be calibrated by the user via the -c option. + * Note that this LoopsPerMillisecond value is used in a few other places + * in the monitor also for time-dependent stuff. + * NOTES: + * - This is obviously not real accurate (not intended to be), but allows the + * monitor to be independent of the underlying hardware. + * - The delay time is very dependent on ethernet activity, since the call + * to pollethernet() part of the loop. + */ + + +char *SleepHelp[] = { + "Second or msec delay (not precise)", + "-[clmv:] {count}", +#if INCLUDE_VERBOSEHELP + " -c calibrate new LPS count", + " -l store LPS count", + " -m millisecond", + " -v {LPSvarname}", +#endif + 0, +}; + +int +Sleep(int argc,char *argv[]) +{ + int opt, calibrate, count, multiplier; + + multiplier = 1000; + calibrate = 0; + while ((opt=getopt(argc,argv,"clmv:")) != -1) { + switch(opt) { + case 'c': + calibrate = 2; + break; + case 'l': + calibrate = 1; + break; + case 'm': + multiplier = 1; + break; + case 'v': + shell_sprintf(optarg,"%d",LoopsPerMillisecond*1000); + return(CMD_SUCCESS); + default: + return(CMD_PARAM_ERROR); + } + } + + /* If no args, just print the current LPS value and return... */ + if (argc == 1) { +#if INCLUDE_HWTMR + printf("Hardware-based timer, LPS not applicable\n"); +#else + printf("Current LPS = %ld\n",LoopsPerMillisecond * 1000); +#endif + return(CMD_SUCCESS); + } + + /* For calibration, take in the count on the command line, then use + * it to put out 5 dots dot at the rate of the loop to allow the user + * to adjust it to be about 1 second. + */ + if (calibrate) { +#if INCLUDE_HWTMR + printf("Hardware-based timer, doesn't calibrate\n"); +#else + long lps; + + if (argc != optind+1) + return(CMD_PARAM_ERROR); + + printf("Current LPS: %ld\n",LoopsPerMillisecond * 1000); + lps = strtol(argv[optind],0,0); + LoopsPerMillisecond = lps/1000; + printf("New LPS: %ld%s\n",LoopsPerMillisecond * 1000, + lps % 1000 ? " (truncated by 1000)" : ""); + + if (calibrate == 2) { + count = 10; + while(count-- > 0) { + monDelay(1000); + putstr(".\007"); + } + putchar('\n'); + } +#endif + return(CMD_SUCCESS); + } + + if (argc == optind) + count = 1; + else + count = strtol(argv[optind],(char **)0,0); + + monDelay(count * multiplier); + return(CMD_SUCCESS); +} +#endif diff --git a/main/common/tsi.c b/main/common/tsi.c new file mode 100755 index 0000000..dd5a53e --- /dev/null +++ b/main/common/tsi.c @@ -0,0 +1,231 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tsi.c: + * + * Touch Screen Interface... + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_TSI & INCLUDE_FBI +#include "genlib.h" +#include "cli.h" +#include "fbi.h" +#include "tsi.h" +#include "timer.h" + + +int +tsi_scribble(int width, long color) +{ + int x, y, xx, yy, done, last_x, last_y; + static int xadjust, yadjust; + + printf("Entering 'scribble' mode, hit any key to terminate...\n"); + + last_x = last_y = done = 0; + while (!done) { + /* Use 'a', 'd', 'w' and 'x' as special input to adjust the + * coordinates between touch and frame buffer. + */ + if (gotachar()) { + switch(getchar()) { + case 'a': // LEFT + xadjust--; + break; + case 'd': // RIGHT + xadjust++; + break; + case 'w': // UP + yadjust--; + break; + case 'x': // DOWN + yadjust++; + break; + default: + done = 1; + break; + } + } + if (tsi_active()) { + x = tsi_getx(); + y = tsi_gety(); + + /* If incoming coordinate is ever more than 'PEN_MOVE_FILTER' + * pixels away from the previous position, then assume it + * to be noise and don't display it. + */ + if ((x < (last_x + PEN_MOVE_FILTER)) && + (x > (last_x - PEN_MOVE_FILTER)) && + (y < (last_y + PEN_MOVE_FILTER)) && + (y > (last_y - PEN_MOVE_FILTER))) + { + x += xadjust; + y += yadjust; + for(xx = x-width;xx <= x+width;xx++) { + for(yy = y-width;yy <= y+width;yy++) + fbi_setpixel(xx,yy,color); + } + } + last_x = x; + last_y = y; + } + } + if ((xadjust != 0) || (yadjust != 0)) + printf("Xadjust: %d, Yadjust: %d\n",xadjust, yadjust); + return(0); +} + +#define WFNT_FILTER 200 + +char *TsiHelp[] = { + "Touch screen interface", + "-[v] {cmd} [args...]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -v additive verbosity", + "", + "Commands:", + " scribble {width} {color} # draw on the frame buffer", + " wft [msec-timeout] # wait for touch", + " wfnt [msec-timeout] # wait for no touch", + "", + "Notes:", + " Shell variable 'TSI_X' and 'TSI_Y' are populated by 'wft'.", +#endif + 0, +}; + +int +TsiCmd(int argc,char *argv[]) +{ + static int tsiInitialized; + int opt, verbose; + char *cmd, *arg1; + static struct elapsed_tmr tmr; + + // Make sure the touch-screen interface is initialized... + if (!tsiInitialized) { + if (tsi_init() == -1) { + printf("Error intializing touch screen!\n"); + return(CMD_FAILURE); + } + tsiInitialized = 1; + } + verbose = 0; + while((opt=getopt(argc,argv,"v")) != -1) { + switch(opt) { + case 'v': + verbose++; + break; + default: + return(CMD_PARAM_ERROR); + } + } + if (argc < optind + 1) + return(CMD_FAILURE); + + cmd = argv[optind]; + arg1 = argv[optind+1]; + + if (strcmp(cmd,"scribble") == 0) { + int width; + long color; + + if (argc != optind+3) + return(CMD_PARAM_ERROR); + + width = strtol(arg1,0,0); + color = strtol(argv[optind+2],0,0); + tsi_scribble(width,color); + } + else if (strcmp(cmd,"wfnt") == 0) { + int x, y; + int filter, ftot; + + if (argc == optind+2) { + int timeout = strtol(arg1,0,0); + + startElapsedTimer(&tmr,timeout); + while(1) { + x = tsi_getx(); + y = tsi_gety(); + if (!tsi_active()) { + for(ftot=0,filter=0;filter<WFNT_FILTER;filter++) + ftot += tsi_active() ? 0 : 1; + if (ftot == WFNT_FILTER) + break; + } + if(msecElapsed(&tmr)) { + x = y = -1; + break; + } + } + } + else { + while(1) { + x = tsi_getx(); + y = tsi_gety(); + if (!tsi_active()) { + for(ftot=0,filter=0;filter<WFNT_FILTER;filter++) + ftot += tsi_active() ? 0 : 1; + if (ftot == WFNT_FILTER) + break; + } + } + } + shell_sprintf("TSI_X","%d",x); + shell_sprintf("TSI_Y","%d",y); + } + else if (strcmp(cmd,"wft") == 0) { + int x, y; + + if (argc == optind+2) { + int timeout = strtol(arg1,0,0); + + startElapsedTimer(&tmr,timeout); + while(1) { + if (tsi_active()) { + x = tsi_getx(); + y = tsi_gety(); + break; + } + if(msecElapsed(&tmr)) { + x = y = -1; + break; + } + } + } + else { + while(!tsi_active()); + x = tsi_getx(); + y = tsi_gety(); + } + shell_sprintf("TSI_X","%d",x); + shell_sprintf("TSI_Y","%d",y); + } + else + return(CMD_PARAM_ERROR); + + return(CMD_SUCCESS); +} +#endif diff --git a/main/common/tsi.h b/main/common/tsi.h new file mode 100644 index 0000000..4156415 --- /dev/null +++ b/main/common/tsi.h @@ -0,0 +1,35 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * tsi.h: + * + * Header file for the touch-screen-interface code. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +extern int tsi_init(void); +extern int tsi_active(void); +extern int tsi_getx(void); +extern int tsi_gety(void); + +#ifndef PEN_MOVE_FILTER +#define PEN_MOVE_FILTER 15 +#endif diff --git a/main/common/umongpio.h b/main/common/umongpio.h new file mode 100644 index 0000000..c58f1cb --- /dev/null +++ b/main/common/umongpio.h @@ -0,0 +1,65 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * gpio.h + * DESCRIPTION HERE + * A common way of looking at general purpose IO. + * + * This header is included by all code that uses uMon's general purpose + * GPIO interface mechanism. The idea is as follows: + * Each bit has two values associated with it: + * + * bit: + * The bit number within the register it is assigned (starting from 0). + * + * vbit: + * The bit number within a device which may have multiple registers of GPIO. + * For example, if a device has three 32-bit registers for GPIO, then there + * would be a total of 96 port numbers where 0-31 represent the bits of + * register 0, 32-63 represetnt the bits of register 1 and 64 + * + * For each bit, the GPIO(vbit,bit) macro uses fields within a 32-bit value to + * define this information; hence, one 32-bit value contains both the register + * and device specific bit position. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _UMONGPIO_H_ +#define _UMONGPIO_H_ + +#define GPIO_BITNUM_MASK 0x000000ff +#define GPIO_VBITNUM_MASK 0xffff0000 +#define GPIO(vbit,bit) (((vbit << 16) & GPIO_VBITNUM_MASK) | \ + (bit & GPIO_BITNUM_MASK)) +#define GPIOVBIT(val) ((val & GPIO_VBITNUM_MASK) >> 16) +#define GPIOBIT(val) (1 << (val & GPIO_BITNUM_MASK)) + +extern void GPIO_init(void); + +/* Each of these functions uses the "virtual" bit number... + */ +extern int GPIO_set(int vbit); +extern int GPIO_clr(int vbit); +extern int GPIO_tst(int vbit); +extern int GPIO_in(int vbit); +extern int GPIO_out(int vbit); + +#endif diff --git a/main/common/version.h b/main/common/version.h new file mode 100644 index 0000000..9eb1b9f --- /dev/null +++ b/main/common/version.h @@ -0,0 +1,170 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * version.h: + * + * MicroMonitor started using a version number as of December 2004. + * Since it has been around for quite some time, the initial version + * number is: 1.0.1.1 + * The version number for MicroMonitor is 4 'dot' separated numbers. + * Each number can be as large as is needed. + * + * MAJOR_VERSION.MINOR_VERSION.BUILD_NUMBER.TARGET_VERSION + + * MAJOR, MINOR & BUILD apply to the common code applicable to all targets. + * TARGET applies to the target-specific code. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _VERSION_H_ +#define _VERSION_H_ + +/* MAJOR_VERSION: + * Incremented as a result of a major change or enhancement to the core + * monitor code or as a means of dropping the MINOR_VERSION back to zero; + * hence, simply identifying a significant set of MINOR changes or some + * big change. + */ +#define MAJOR_VERSION 1 + +/* MINOR_VERSION: + * Incremented as a result of a new command or feature, or as a result + * of a bug fix to the core monitor code. + * When MAJOR_VERSION is incremented, MINOR_VERSION is reset to 0. + * 0->1: + * Formalize the uMon1.0 transition. Needed to do this because of the + * amount of churn in 1.0. + * 1->2: + * - New 'call -A' option + * - Work on flash internals to reduce the need for callers to know + * the flash bank pointer. + * - New tfs 'qclean' subcommand. + * - Bug fix: file in "tfs ramdev" space could not be marked stale. + * 2->3: + * - Bug fix: uMonInRam() re-write. + * - Bug fix: "tfs ramdev" device would be lost after mon_appexit(). + * - Bug fix: "tfs ramdev" naming conflict could occur between device + * and file. + * 3->4: + * - The tfscheck() function accepts a NULL input TDEV pointer to signify + * a request to check all TFS devices (instead of just one named device). + * - The address used by xmodem -B for determining the last sector burned + * had to be decremented by 1. + * 4->5: + * - The "flash erase" command takes addresses as well as sector numbers. + * - The "flash info" and "tfs stat" populate shellvars with their info. + * - Bug fix: tftp get would turn on the server, now fixed so that if + * server was off, it stays off. + * - Bug fix: if destination file received by tftp server started with + * a $, but the shell variable didn't exist, the server would create + * a file with the $. This will now generate an error. + * 5->6: + * - Added more configurability so that uMon's footprint can be smaller. + * - Broke up memcmds.c into individually configurable commands using + * INCLUDE_DM, INCLUDE_PM, etc. + * - Added support to configure USRLVL, ICMP, and ICMPTIME in or out. + * - TFS now supports the option of being built without FLASH. + * - New read options: -p -n. + * - New pm options: -a -o -x. + * - New PRE_TFSAUTOBOOT_HOOK() macro. + * - Converted genlib.c to a library. + * - New api: mon_portcmd(). + * 6->7: + * - New JFFS2 command. + * - New TFSERR_DSIMAX error checking in tfsmemuse() and tfsadd(). + * - Eliminated the -x option in tfs command. + * - The tfs command now returns CMD_FAILURE if tfsadd fails. + * - Moncmd server will process a leading '.' as indication that the + * command is to be executed immediately rather than after the + * incoming packet queue is empty. + * 7->8: + * - New TFS_ALTDEVTBL_BASE code to support an alternat TFS device table + * that is outside uMon's text/data space. + * - Fixed bug in JFFS2 related to file truncation. + * 8->9: + * - New DOSFS/FATFS/CF facility (much help from Graham Henderson). + * - CodeWarrior-specific code cleanup (submitted by Arun Biyani). + * - Atmel NIOS port (submitted by Graham Henderson). + * 9->10: + * - New 'struct' command to hopefully eliminate 'lboot' and 'ldatags'. + * 10->11: + * - Fixed problems with packet transfer interface. + * - Updated the umon_apps/udp application. + * - New Microblaze port (as3dev). + * 11->12: + * - Added the 'to' side of the ARP request in ethernet verbosity. + * - Fixed bugs in tcpstuff.c that were only seen on little-endian CPUs. + * - Added the ability to load an elf file from raw memory space. This + * introduces the notion of a 'fake' tfs file header to tfs, using the + * first reserved entry in the header as a pointer to the data portion + * of the file. + * 12->14: + * - Added new DHCP shell variable ROOTPATH (reflects option 17). + * - New DHCP variable: DHCPDONTBOOT. Tells DHCP not to do anything with + * the incoming DHCP transaction (except store away the info in the + * shell variables); thus, allowing a script to do what it wants to do. + * - Change in TFTP server: if an out-of-sequence block number is received, + * it is now just ignored, the transaction doesn't terminate with an error. + * - Added inUmonBssSpace() check to the heap extension code. + * - Fixed bug in "tfs ramdev" command... If partition didn't exist and + * a size of zero was specified, TFS incorrectly attempted to create a + * zero-size ramdev partition. + * - Fixed bug in multiple-command-line-processing that occurs if a + * shell variable is expanded within one of the commands. See CVS + * log for docmd.c for more info. + * 14->15: + * - Fixed a bug in TFTP packet reception that was causing all incoming + * file downloads greater than 32Mg to fail because that is the point + * at which the block number will wrap. + * - Updates/cleanups made to keep the build warning-free with GCC 4.2 + * from Microcross. + * 15->16: + * - Added lwip user application. + * - Added better exception handling to blackfin. + * - Added mon_timer() api. + * 16->17: + * - Lotta new stuff, refer to user manual for complete list... + * - Lwipapp: httpget, telnet client. + * - Tested support for nor-less system (booting from SPI flash). + * - TSI, FBI, mDNS, LLAD, etc... + * 17->18: + * - Refer to user manual for complete list... + * - SPI-SD support for BF537. + * - New FATFS + * - SPI-resident TFS support. + * - JFFS2 extended by B.Gatliff + * 18->19: + * - Refer to user manual for complete list... + * - TFS defrag bug fixes. + */ +#define MINOR_VERSION 19 + +/* TARGET_VERSION: + * Incremented as a result of a bug fix or change made to the + * target-specific (i.e. port) portion of the code. + * + * To keep a "cvs-like" log of the changes made to a port that is + * not under CVS, it is recommended that the target_version.h file be + * used as the log to keep track of changes in one place. + */ +#include "target_version.h" + +#endif diff --git a/main/common/warmstart.h b/main/common/warmstart.h new file mode 100644 index 0000000..50300eb --- /dev/null +++ b/main/common/warmstart.h @@ -0,0 +1,34 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * warmstart.h: + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#ifndef _WARMSTART_H_ + +/* Standard restart (warmstart) definitions used by monitor... */ +#define EXCEPTION (1<<4) +#define INITIALIZE (3<<4) +#define APPLICATION (5<<4) +#define APP_EXIT (9<<4) + +#endif diff --git a/main/common/xmodem.c b/main/common/xmodem.c new file mode 100644 index 0000000..38ba48b --- /dev/null +++ b/main/common/xmodem.c @@ -0,0 +1,855 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * xmodem.c: + * + * Command to upload or download via XMODEM protocol. Xmodem is quite + * limited, but adequate for simple file up/down load. + * This also supports XMODEM-1K and YMODEM. YMODEM is an extension to XMODEM + * that uses a 1K packet size, CRC and the first packet (seqno=0) contains + * information about the file being downloaded (in partiuclar, the name). + * YMODEM also supports BATCH downloads (multiple files downloaded in one + * transaction). This code supports incoming BATCH downloads (not tested + * because I can't find any terminal emulators that do it), but not for + * uploads. + + * Minicom notes: + * Minicom is the terminal emulation program that comes with Linux. + * For some reason I had to make some adjustments to the xmodem.c + * to accommodate Minicom... + * - Minicom sends an initial 0x1a (EOF). Not sure why, so I just absorb + * that now. + * - Minicom doesn't like a fast nak-resend rate, so each additional + * 'd' option on the xmodem command line now causes the delay + * between outgoing NAKs (used to start up the protocol in Xdown()) + * to double. As a result, when running with minicom, a file download + * may need "xmodem -ddd". Not exactly sure why this is necessary but + * here's my hunch... + * To do an xmodem transfer to the target running uMon, the "xmodem -d" + * command is issued on the uMon command line. This causes uMon to start + * generating periodic NAKs (part of the xmodem startup handshake). + * Then via CTRL-A Z, the minicom side of the transaction starts up. + * Apparently, minicom doesn't flush the input buffer when the xmodem + * transfer is started on its side. As a result there may be several + * NAKs buffered up on the TTY. The end result is that if too many + * NAKs have been queued up in the TTY's buffer, Minicom chokes on + * them at startup. + * Adding the ability to slow down the NAK send rate keeps uMon from + * sending too many NAKs prior to Minicom actually starting up its + * side of the protocol; hence, Minicom doesn't choke and the transfer + * works ok. + * + * By default, this code will disable the ethernet interface + * during the xmodem transaction. This is done because in most + * cases the monitor runs with no flow control; and getchar polls + * the ethernet interface. If the poll results in an incoming + * packet, then it may cause the serial port to lose characters. + * If this is not desireable (or if the uart has a large input fifo), + * then this can be changed with the DONT_DISABLE_ENET_IN_XMODEM + * #define set up in config.h + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "genlib.h" +#include "stddefs.h" +#include "flash.h" +#include "tfs.h" +#include "tfsprivate.h" +#include "cli.h" +#include "ether.h" +#include "timer.h" + +#if INCLUDE_XMODEM + +#define PUTCHAR putchar + + +/* struct xinfo: + * Used to contain information pertaining to the current transaction. + * The structure is built by the command Xmodem, then passed to the other + * support functions (Xup, Xdown, etc..) for reference and update. + */ +struct xinfo { + uchar sno; /* Sequence number. */ + uchar pad; /* Unused, padding. */ + int xfertot; /* Running total of transfer. */ + int pktlen; /* Length of packet (128 or 1024). */ + int pktcnt; /* Running tally of number of packets processed. */ + int filcnt; /* Number of files transferred by ymodem. */ + long size; /* Size of upload. */ + ulong flags; /* Storage for various runtime flags. */ + ulong base; /* Starting address for data transfer. */ + ulong dataddr; /* Running address for data transfer. */ + int errcnt; /* Keep track of errors (used in verify mode). */ + int nakresend; /* Time between each NAK sent at Xdown startup. */ + char *firsterrat; /* Pointer to location of error detected when */ + /* transfer is in verify mode. */ + char fname[TFSNAMESIZE]; +}; + +/* Runtime flags: */ +#define USECRC (1<<0) +#define VERIFY (1<<1) +#define YMODEM (1<<2) + +/* Current xmodem operation: */ +#define XNULL 0 +#define XUP 1 +#define XDOWN 2 + +/* X/Ymodem protocol: */ +#define SOH 0x01 +#define STX 0x02 +#define EOT 0x04 +#define ACK 0x06 +#define NAK 0x15 +#define CAN 0x18 +#define EOF 0x1a +#define ESC 0x1b + +#define PKTLEN_128 128 +#define PKTLEN_1K 1024 + +#define BYTE_TIMEOUT 1000 + +static int Xup(struct xinfo *); +static int Xdown(struct xinfo *); +static int getPacket(uchar *,struct xinfo *); +static int putPacket(uchar *,struct xinfo *); + +char *XmodemHelp[] = { + "Xmodem file transfer", + "-[a:BcdF:f:i:ks:uvy]", +#if INCLUDE_VERBOSEHELP + "Options:", + " -a{##} address (overrides default of APPRAMBASE)", +#if INCLUDE_FLASH + " -B boot sector reload", +#endif + " -c use crc (default = checksum)", + " -d download", +#if INCLUDE_TFS + " -F{name} filename", + " -f{flags} file flags (see tfs)", + " -i{info} file info (see tfs)", +#endif + " -k force packet length to 1K", + " -s{##} size (overrides computed size)", + " -u upload", + " -v verify only", +#if INCLUDE_TFS + " -y use Ymodem extensions", +#endif + "Notes:", + " * Either -d or -u must be specified (-B implies -d).", + " * Each additional 'd' option cuts the nak-resend rate in half.", + " * XMODEM forces a 128-byte modulo on file size. The -s option", + " can be used to override this when transferring a file to TFS.", + " * File upload requires no address or size (size will be mod 128).", + " * When using -B, it should be the ONLY command line option,", + " it's purpose is to reprogram the boot sector, so be careful!", +#endif + (char *)0, +}; + +int +Xmodem(int argc,char *argv[]) +{ + int opt, xop; + struct xinfo xi; + char *info, *flags; +#if INCLUDE_TFS + TFILE *tfp; +#endif +#if INCLUDE_FLASH + int newboot = 0; +#endif +#if INCLUDE_ETHERNET + int eon; +#endif + + xop = XNULL; + info = (char *)0; + flags = (char *)0; + xi.fname[0] = 0; + xi.size = 0; + xi.flags = 0; + xi.filcnt = 0; + xi.nakresend = 2; + xi.pktlen = PKTLEN_128; + xi.base = xi.dataddr = getAppRamStart(); + while ((opt=getopt(argc,argv,"a:BcdF:f:i:ks:uvy")) != -1) { + switch(opt) { + case 'a': + xi.dataddr = xi.base = strtoul(optarg,(char **)0,0); + break; + case 'B': + xop = XDOWN; +#if INCLUDE_FLASH + newboot = 1; +#endif + break; + case 'c': + xi.flags |= USECRC; + break; + case 'd': + xi.nakresend *= 2; /* -ddd increases Xdown() resend delay */ + xop = XDOWN; + break; +#if INCLUDE_TFS + case 'F': + strncpy(xi.fname,optarg,TFSNAMESIZE); + break; + case 'f': + flags = optarg; + break; + case 'i': + info = optarg; + break; +#endif + case 'k': + xi.pktlen = PKTLEN_1K; + break; + case 's': + xi.size = strtol(optarg,(char **)0,0); + break; + case 'u': + xop = XUP; + break; + case 'v': + xi.flags |= VERIFY; + break; +#if INCLUDE_TFS + case 'y': + xi.flags |= (YMODEM | USECRC); + xi.pktlen = PKTLEN_1K; + break; +#endif + default: + return(CMD_PARAM_ERROR); + } + } + + /* There should be no arguments after the option list. */ + if (argc != optind) + return(CMD_PARAM_ERROR); + + if (xop == XUP) { + if ((xi.flags & YMODEM) && !(xi.fname[0])) + printf("Ymodem upload needs filename\n"); + else { + if (xi.fname[0]) { /* Causes -a and -s options to be ignored. */ +#if INCLUDE_TFS + tfp = tfsstat(xi.fname); + if (!tfp) { + printf("%s: file not found\n",xi.fname); + return(CMD_FAILURE); + } + xi.base = xi.dataddr = (ulong)TFS_BASE(tfp); + xi.size = TFS_SIZE(tfp); +#endif + } +#ifdef DONT_DISABLE_ENET_IN_XMODEM /* See note at top of file */ + Xup(&xi); +#else +#if INCLUDE_ETHERNET + eon = DisableEthernet(); +#endif + Xup(&xi); +#if INCLUDE_ETHERNET + if (eon) + EthernetStartup(0,0); +#endif +#endif + } + } + else if (xop == XDOWN) { + long tmpsize; + + if ((xi.flags & YMODEM) && (xi.fname[0])) + printf("Ymodem download gets name from protocol, '%s' ignored\n", + xi.fname); + +#ifdef DONT_DISABLE_ENET_IN_XMODEM /* See note at top of file */ + tmpsize = (long)Xdown(&xi); +#else +#if INCLUDE_ETHERNET + eon = DisableEthernet(); +#endif + tmpsize = (long)Xdown(&xi); +#if INCLUDE_ETHERNET + if (eon) + EthernetStartup(0,0); +#endif +#endif + if (tmpsize == -1) + return(CMD_FAILURE); + if ((!xi.size) || (tmpsize < 0)) + xi.size = tmpsize; + +#if INCLUDE_TFS + if ((xi.fname[0]) && (xi.size > 0)) { + int err; + + printf("Writing to file '%s'...\n",xi.fname); + err = tfsadd(xi.fname,info,flags,(uchar *)xi.base,xi.size); + if (err != TFS_OKAY) { + printf("%s: %s\n",xi.fname,(char *)tfsctrl(TFS_ERRMSG,err,0)); + return(CMD_FAILURE); + } + } +#if INCLUDE_FLASH + else +#endif +#endif +#if INCLUDE_FLASH + if ((newboot) && (xi.size > 0)) { + extern int FlashProtectWindow; + int rc; + char *bb; + ulong bootbase; + + bb = getenv("BOOTROMBASE"); + if (bb) + bootbase = strtoul(bb,0,0); + else + bootbase = BOOTROM_BASE; +#ifdef TO_FLASH_ADDR + /* The address the program is linked to is not necessarily the + * physical address where flash operations can be performed on. + * A typical use could be that the program is linked to run in + * a cacheable region but writing to the flash can only be done + * in an uncached region. + * "config.h" is a good place to define the TO_FLASH_ADDR macro. + */ + bootbase = (ulong)TO_FLASH_ADDR(bootbase); +#endif + printf("Reprogramming boot @ 0x%lx from 0x%lx, %ld bytes.\n", + bootbase,xi.base,xi.size); + if (askuser("OK?")) { + int first, last; + + /* If sector(s) need to be unlocked, do that now... + */ + if (addrtosector((uchar *)bootbase,&first,0,0) == -1) + return(CMD_FAILURE); + + if (addrtosector((uchar *)bootbase+xi.size-1,&last,0,0) == -1) + return(CMD_FAILURE); + + if (flashlock(first,FLASH_LOCKABLE) != -1) { + FlashProtectWindow = 1; + while(first < last) + flashlock(first++,FLASH_UNLOCK); + } + + FlashProtectWindow = 1; + rc = flashewrite((uchar *)bootbase,(uchar *)xi.base,xi.size); + if (rc == -1) { + printf("failed\n"); + return(CMD_FAILURE); + } + } + } +#endif + } + else + return(CMD_PARAM_ERROR); + shell_sprintf("XMODEMGET","%ld",xi.size); + return(CMD_SUCCESS); +} + +/* xgetchar(): + * Wrap getchar with a timer, so that after 5 seconds of waiting + * we giveup... + */ +int +xgetchar(char *cp, int lno) +{ + struct elapsed_tmr tmr; + + startElapsedTimer(&tmr,5000); + while(!msecElapsed(&tmr) && !gotachar()); + if (!gotachar()) { + Mtrace("Xgetchar tmt %d",lno); + return(-1); + } + *cp = getchar(); + return(0); +} + +/* putPacket(): + * Used by Xup to send packets. + */ +static int +putPacket(uchar *tmppkt, struct xinfo *xip) +{ + char c; + int i; + ushort chksm; + + chksm = 0; + + if (xip->pktlen == PKTLEN_128) + PUTCHAR(SOH); + else + PUTCHAR(STX); + + PUTCHAR((char)(xip->sno)); + PUTCHAR((char)~(xip->sno)); + + if (xip->flags & USECRC) { + for(i=0;i<xip->pktlen;i++) { + PUTCHAR((char)*tmppkt); + chksm = (chksm<<8)^xcrc16tab[(chksm>>8)^*tmppkt++]; + } + /* An "endian independent way to extract the CRC bytes. */ + PUTCHAR((char)(chksm >> 8)); + PUTCHAR((char)chksm); + } + else { + for(i=0;i<xip->pktlen;i++) { + PUTCHAR((char)*tmppkt); + chksm = ((chksm+*tmppkt++)&0xff); + } + PUTCHAR((char)(chksm&0x00ff)); + } + + if (xgetchar(&c,__LINE__) == -1) /* Wait for ack */ + return(-1); + + /* If pktcnt == -1, then this is the first packet sent by + * YMODEM (filename) and we must wait for one additional + * character in the response. + */ + if (xip->pktcnt == -1) { + if (xgetchar(&c,__LINE__) == -1) + return(-1); + } + return((int)c); +} + +/* getPacket(): + * Used by Xdown to retrieve packets. + */ +static int +getPacket(uchar *tmppkt, struct xinfo *xip) +{ + char *pkt; + int i,rcvd; + uchar seq[2]; + + if ((rcvd = getbytes_t((char *)seq,2,BYTE_TIMEOUT)) != 2) { + PUTCHAR(NAK); + Mtrace("RCVD %d != 2",rcvd); + return(0); + } + + if (xip->flags & VERIFY) { + rcvd = getbytes_t((char *)tmppkt,xip->pktlen,BYTE_TIMEOUT); + if (rcvd != xip->pktlen) { + PUTCHAR(NAK); + Mtrace("RCVD %d != %d",rcvd,xip->pktlen); + return(0); + } + for(i=0;i<xip->pktlen;i++) { + if (tmppkt[i] != ((char *)xip->dataddr)[i]) { + if (xip->errcnt++ == 0) + xip->firsterrat = (char *)(xip->dataddr+i); + } + } + pkt = (char *)tmppkt; + } + else { + rcvd = getbytes_t((char *)xip->dataddr,xip->pktlen,BYTE_TIMEOUT); + if (rcvd != xip->pktlen) { + PUTCHAR(NAK); + Mtrace("RCVD %d != %d",rcvd,xip->pktlen); + return(0); + } + pkt = (char *)xip->dataddr; + } + + if (xip->flags & USECRC) { + char c; + ushort crc, xcrc; + + /* An "endian independent way to combine the CRC bytes. */ + if (xgetchar(&c,__LINE__) == -1) + return(0); + crc = (ushort)c; + crc <<= 8; + if (xgetchar(&c,__LINE__) == -1) + return(0); + crc += (ushort)c; + xcrc = xcrc16((uchar *)pkt,(ulong)(xip->pktlen)); + if (crc != xcrc) { + PUTCHAR(NAK); + Mtrace("CRC %04x != %04x",crc,xcrc); + return(0); + } + } + else { + uchar csum, xcsum; + + if (xgetchar((char *)&xcsum,__LINE__) == -1) + return(0); + csum = 0; + for(i=0;i<xip->pktlen;i++) + csum += *pkt++; + if (csum != xcsum) { + PUTCHAR(NAK); + Mtrace("CSUM %02x != %02x (%d)",csum,xcsum,xip->pktlen); + return(0); + } + Mtrace("CSUM %02x (%d)",csum,xip->pktlen); + } + + /* Test the sequence number compliment... + */ + if ((uchar)seq[0] != (uchar)~seq[1]) { + PUTCHAR(NAK); + Mtrace("SNOCMP %02x != %02x",(uchar)seq[0],(uchar)~(seq[1])); + return(0); + } + + /* Verify that the incoming sequence number is the expected value... + */ + if ((uchar)seq[0] != xip->sno) { + /* If the incoming sequence number is one less than the expected + * sequence number, then we assume that the sender did not recieve + * our previous ACK, and they are resending the previously received + * packet. In that case, we send ACK and don't process the + * incoming packet... + */ + if ((uchar)seq[0] == xip->sno-1) { + Mtrace("R_ACK"); + PUTCHAR(ACK); + return(0); + } + + /* Otherwise, something's messed up... + */ + PUTCHAR(CAN); + Mtrace("SNO: %02x != %02x",seq[0],xip->sno); + return(-1); + } + + /* First packet of YMODEM contains information about the transfer: + * FILENAME SP FILESIZE SP MOD_DATE SP FILEMODE SP FILE_SNO + * Only the FILENAME is required and if others are present, then none + * can be skipped. + */ + if ((xip->flags & YMODEM) && (xip->pktcnt == 0)) { + char *slash, *space, *fname; + + slash = strrchr((char *)(xip->dataddr),'/'); + space = strchr((char *)(xip->dataddr),' '); + if (slash) + fname = slash+1; + else + fname = (char *)(xip->dataddr); + Mtrace("<fname=%s>",fname); + if (space) { + *space = 0; + xip->size = atoi(space+1); + } + strcpy(xip->fname,fname); + if (fname[0]) + xip->filcnt++; + } + else + xip->dataddr += xip->pktlen; + xip->sno++; + xip->pktcnt++; + xip->xfertot += xip->pktlen; + Mtrace("ACK"); + PUTCHAR(ACK); + if (xip->flags & YMODEM) { + if (xip->fname[0] == 0) { + printf("\nRcvd %d file%c\n", + xip->filcnt,xip->filcnt > 1 ? 's' : ' '); + return(1); + } + } + return(0); +} + +/* Xup(): + * Called when a transfer from target to host is being made (considered + * an upload). + */ +static int +Xup(struct xinfo *xip) +{ + uchar c, buf[PKTLEN_128]; + int tmp, done, pktlen; + + Mtrace("Xup starting"); + + if (xip->size & 0x7f) { + xip->size += 128; + xip->size &= 0xffffff80L; + } + + printf("Upload %ld bytes from 0x%lx\n",xip->size,(ulong)xip->base); + + /* Startup synchronization... */ + /* Wait to receive a NAK or 'C' from receiver. */ + done = 0; + while(!done) { + if (xgetchar((char *)&c,__LINE__) == -1) + return(0); + switch(c) { + case NAK: + done = 1; + Mtrace("CSM"); + break; + case 'C': + xip->flags |= USECRC; + done = 1; + Mtrace("CRC"); + break; + case 'q': /* ELS addition, not part of XMODEM spec. */ + return(0); + default: + break; + } + } + + rawon(); + + if (xip->flags & YMODEM) { + Mtrace("SNO_0"); + xip->sno = 0; + xip->pktcnt = -1; + memset((char *)buf,0,PKTLEN_128); + sprintf((char *)buf,"%s",xip->fname); + pktlen = xip->pktlen; + xip->pktlen = PKTLEN_128; + if (putPacket(buf,xip) == -1) + return(0); + xip->pktlen = pktlen; + } + + done = 0; + xip->sno = 1; + xip->pktcnt = 0; + while(!done) { + if ((tmp = putPacket((uchar *)(xip->dataddr),xip)) == -1) + return(0); + c = (uchar)tmp; + switch(c) { + case ACK: + xip->sno++; + xip->pktcnt++; + xip->size -= xip->pktlen; + xip->dataddr += xip->pktlen; + Mtrace("A"); + break; + case NAK: + Mtrace("N"); + break; + case CAN: + done = -1; + Mtrace("C"); + break; + case EOT: + done = -1; + Mtrace("E"); + break; + default: + done = -1; + Mtrace("<%02x>",c); + break; + } + if (xip->size <= 0) { + char tmp; + + PUTCHAR(EOT); + if (xgetchar(&tmp,__LINE__) == -1) /* Flush the ACK */ + return(0); + break; + } + Mtrace("!"); + } + + Mtrace("Xup_almost"); + if ((done != -1) && (xip->flags & YMODEM)) { + xip->sno = 0; + memset((char *)buf,0,PKTLEN_128); + pktlen = xip->pktlen; + xip->pktlen = PKTLEN_128; + if (putPacket(buf,xip) == -1) + return(0); + xip->pktlen = pktlen; + } + Mtrace("Xup_done."); + rawoff(); + return(0); +} + + +/* Xdown(): + * Called when a transfer from host to target is being made (considered + * an download). + * Note that if we don't have INCLUDE_MALLOC set (in config.h), then + * we allocate a 128-byte static buffer and only support the 128-byte + * packet size here. + */ + +static int +Xdown(struct xinfo *xip) +{ + struct elapsed_tmr tmr; + char c, *tmppkt; + int i, done; +#if !INCLUDE_MALLOC + static char pkt[PKTLEN_128]; + + tmppkt = pkt; +#else + tmppkt = malloc(PKTLEN_1K); + if (!tmppkt) { + Mtrace("malloc failed"); + return(-1); + } +#endif + + rawon(); + +nextfile: + if (xip->flags & YMODEM) + xip->sno = 0x00; + else + xip->sno = 0x01; + xip->pktcnt = 0; + xip->errcnt = 0; + xip->xfertot = 0; + xip->firsterrat = 0; + + /* Startup synchronization... */ + /* Continuously send NAK or 'C' until sender responds. */ +restart: + Mtrace("Xdown"); + for(i=0;i<32;i++) { + if (xip->flags & USECRC) + PUTCHAR('C'); + else + PUTCHAR(NAK); + + startElapsedTimer(&tmr,xip->nakresend * 1000); + while(!msecElapsed(&tmr) && !gotachar()); + if (gotachar()) + break; + } + if (i == 32) { + Mtrace("Giveup @ %d",__LINE__); + return(-1); + } + + done = 0; + Mtrace("Got response"); + while(done == 0) { + if (xgetchar(&c,__LINE__) == -1) + return(-1); + switch(c) { + case SOH: /* 128-byte incoming packet */ + Mtrace("O"); + xip->pktlen = 128; + done = getPacket((uchar *)tmppkt,xip); + if (done < 0) + Mtrace("GP_%d",done); + if (!done && (xip->pktcnt == 1) && (xip->flags & YMODEM)) + goto restart; + break; +#if INCLUDE_MALLOC + case STX: /* 1024-byte incoming packet */ + Mtrace("T"); + xip->pktlen = 1024; + done = getPacket((uchar *)tmppkt,xip); + if (done < 0) + Mtrace("GP_%d",done); + if (!done && (xip->pktcnt == 1) && (xip->flags & YMODEM)) + goto restart; + break; +#endif + case CAN: + Mtrace("C"); + done = -1; + break; + case EOT: + Mtrace("E"); + PUTCHAR(ACK); + if (xip->flags & YMODEM) { +#if INCLUDE_TFS + if (!xip->size) + xip->size = xip->pktcnt * xip->pktlen; + if (xip->fname[0]) + tfsadd(xip->fname,0,0,(uchar *)xip->base,xip->size); + xip->dataddr = xip->base; +#endif + goto nextfile; + } + else { + done = xip->xfertot; + rawoff(); + printf("\nRcvd %d pkt%c (%d bytes)\n",xip->pktcnt, + xip->pktcnt > 1 ? 's' : ' ',xip->xfertot); + + /* If the transfer is complete and no file add is to + * be done, then we flush d-cache and invalidate + * i-cache across the memory space that was just + * copied to. This is necessary in case the + * binary data that was just transferred is code. + */ + flushDcache((char *)xip->base,xip->xfertot); + invalidateIcache((char *)xip->base,xip->xfertot); + } + break; + case ESC: /* User-invoked abort */ + Mtrace("X"); + done = -1; + break; + case EOF: /* 0x1a sent by MiniCom, just ignore it. */ + break; + default: + Mtrace("<%02x>",c); + done = -1; + break; + } + Mtrace("!"); + } + rawoff(); + if (xip->flags & VERIFY) { + if (xip->errcnt) + printf("%d errors, first at 0x%lx\n", + xip->errcnt,(ulong)(xip->firsterrat)); + else + printf("verification passed\n"); + } + free(tmppkt); + return(done); +} + + +#endif diff --git a/main/cpu/arm/arm.h b/main/cpu/arm/arm.h new file mode 100644 index 0000000..8c9c53e --- /dev/null +++ b/main/cpu/arm/arm.h @@ -0,0 +1,78 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * arm.h + * + * PSR Bits + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#define PSR_THUMB_STATE 0x00000020 +#define PSR_IMASK_IRQ 0x00000080 +#define PSR_IMASK_FRQ 0x00000040 +#define PSR_CONDITION_NEGATIVE 0x80000000 +#define PSR_CONDITION_ZERO 0x40000000 +#define PSR_CONDITION_CARRY 0x20000000 +#define PSR_CONDITION_OVERFLOW 0x10000000 +#define PSR_MODE_MASK 0x0000001f + +/* Mode bits within PSR: + */ +#define ABORT_MODE 0x00000017 +#define FASTINTRQST_MODE 0x00000011 +#define INTRQST_MODE 0x00000012 +#define SUPERVISOR_MODE 0x00000013 +#define SYSTEM_MODE 0x0000001f +#define UNDEFINED_MODE 0x0000001b +#define USER_MODE 0x00000010 + +/* Exception types: + */ +#define EXCTYPE_UNDEF 1 +#define EXCTYPE_ABORTP 2 +#define EXCTYPE_ABORTD 3 +#define EXCTYPE_IRQ 4 +#define EXCTYPE_FIRQ 5 +#define EXCTYPE_SWI 6 +#define EXCTYPE_NOTASSGN 7 + +/* Link register adjustments for each exception: + * These adjustments are used by the exception handler to establish the + * address at which the exception occurred. + */ +#define LRADJ_UNDEF 4 +#define LRADJ_ABORTP 4 +#define LRADJ_ABORTD 8 +#define LRADJ_IRQ 4 +#define LRADJ_FIRQ 4 +#define LRADJ_SWI 4 + +/* Vector numbers used by assign_handler and the mon_assignhandler() + * API function... + */ +#define VEC_RST 0 +#define VEC_UND 1 +#define VEC_SWI 2 +#define VEC_ABP 3 +#define VEC_ABD 4 +#define VEC_IRQ 5 +#define VEC_RESERVED 6 +#define VEC_FIQ 7 diff --git a/main/cpu/arm/cache_arm.c b/main/cpu/arm/cache_arm.c new file mode 100644 index 0000000..cc471da --- /dev/null +++ b/main/cpu/arm/cache_arm.c @@ -0,0 +1,124 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * cache_arm.c + * + * ARM's definition of "flush" and "clean" (as taken from the + * "ARM System Developer's Guide") ... + * + * To "flush a cache" is to clear it of any stored data. Flushing clears + * the valid bit in the affected cache line... The term "invalidate" + * is sometimes used in place of the term "flush". + * + * To "clean a cache" is to force a write of the dirty cache lines + * from the cache out to main memory and clear the dirty bits in the + * cache line. + * + * This conflicts with uMon's general use of the terms "flush" and + * "invalidate". For uMon, "flush" refers to what ARM calls "clean" + * and "invalidate" refers to what ARM calls "flush". ARRGGHH!! + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "cache.h" + +int +arm_cleanDcache(char *base, int size) +{ + return(0); +} + +int +arm_flushIcache(char *base, int size) +{ + /* Flush (i.e. "invlidate in uMon terminology) entire instruction + * cache (ignore incoming args). + */ + asm(" MOV r0, #0"); + asm(" MCR p15, 0, r0, c7, c5, 0"); + return(0); +} + +/* cacheInitForTarget(): + Enable instruction cache only... +*/ +void +cacheInitForTarget() +{ + asm(" MRC p15, 0, r0, c1, c0, 0"); + asm(" ORR r0, r0, #0x1000"); /* bit 12 is ICACHE enable*/ + asm(" MCR p15, 0, r0, c1, c0, 0"); + + /* Flush instruction cache */ + arm_flushIcache(0,0); + + dcacheFlush = arm_cleanDcache; + icacheInvalidate = arm_flushIcache; +} + +/* MRC/MCR assembler syntax (for ARM general): + * + * <MCR|MRC>{cond} p#,<expression1>,Rd,cn,cm{,<expression2>} + * + * Where: + * - MRC move from coprocessor to ARM register (L=1) + * - MCR move from ARM register to coprocessor (L=0) + * - {cond} two character condition mnemonic (see list below) + * - p# the unique number of the required coprocessor + * - <expression1> evaluated to a constant and placed in the CP Opc field + * - Rd is an expression evaluating to a valid ARM processor register + * number + * - cn and cm are expressions evaluating to the valid coprocessor register + * numbers CRn and CRm respectively + * - <expression2> where present is evaluated to a constant and placed in + * the CP field + * + * Examples + * - MRC 2,5,R3,c5,c6 ;request coproc 2 to perform operation 5 + * ;on c5 and c6, and transfer the (single + * ;32-bit word) result back to R3 + * - MCR 6,0,R4,c6 ;request coproc 6 to perform operation 0 + * ;on R4 and place the result in c6 + * - MRCEQ 3,9,R3,c5,c6,2 ;conditionally request coproc 2 to + * ;perform + * ;operation 9 (type 2) on c5 and c6, and + * ;transfer the result back to R3 + * + * Condition codes: + * EQ (equal) - Z set + * NE (not equal) - Z clear + * CS (unsigned higher or same) - C set + * CC (unsigned lower) - C clear + * MI (negative) - N set + * PL (positive or zero) - N clear + * VS (overflow) - V set + * VC (no overflow) - V clear + * HI (unsigned higher) - C set and Z clear + * LS (unsigned lower or same) - C clear or Z set + * GE (greater or equal) - N set and V set, or N clear and V clear + * LT (less than) - N set and V clear, or N clear and V set + * GT (greater than) - Z clear, and either N set and Vset, + * or N clear and V clear + * LE (less than or equal) - Z set, or N set and V clear, + * or N clear and V set + * AL - always + * NV - never + */ diff --git a/main/cpu/arm/except_arm.c b/main/cpu/arm/except_arm.c new file mode 100644 index 0000000..f9e4f30 --- /dev/null +++ b/main/cpu/arm/except_arm.c @@ -0,0 +1,94 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * FILENAME_HERE + * + * DESCRIPTION_HERE + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "config.h" +#include "arm.h" +#include "stddefs.h" +#include "genlib.h" +#include "warmstart.h" + +ulong ExceptionAddr; +int ExceptionType; + +/*********************************************************************** + * + * umon_exception() + * Default exception handler used by the low level code in vectors_arm.S. + */ +void +umon_exception(ulong addr, ulong type) +{ + ExceptionAddr = addr; + ExceptionType = type; + monrestart(EXCEPTION); +} + +/*********************************************************************** + * + * ExceptionType2String(): + * This function simply returns a string that verbosely describes + * the incoming exception type (vector number). + */ +char * +ExceptionType2String(int type) +{ + char *string; + + switch(type) { + case EXCTYPE_UNDEF: + string = "Undefined instruction"; + break; + case EXCTYPE_ABORTP: + string = "Abort prefetch"; + break; + case EXCTYPE_ABORTD: + string = "Abort data"; + break; + case EXCTYPE_IRQ: + string = "IRQ"; + break; + case EXCTYPE_FIRQ: + string = "Fast IRQ"; + break; + case EXCTYPE_NOTASSGN: + string = "Not assigned"; + break; + case EXCTYPE_SWI: + string = "Software Interrupt"; + break; + default: + string = "???"; + break; + } + return(string); +} + +void +vinit(void) +{ +} diff --git a/main/cpu/arm/gdbregs_arm.c b/main/cpu/arm/gdbregs_arm.c new file mode 100644 index 0000000..11953a9 --- /dev/null +++ b/main/cpu/arm/gdbregs_arm.c @@ -0,0 +1,36 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * gdbregs_arm.c + * + * List of the register names for the ARM in the order they + * are expected by the GDB 'g' command (read all registers). + * R13=SP, R14=LR + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#define CPU_PC_REG "PC" + +static char *gdb_regtbl[] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", "R12", "R13", "R14", "PC", + "R0", "CPSR", +}; diff --git a/main/cpu/arm/ldatags.c b/main/cpu/arm/ldatags.c new file mode 100644 index 0000000..f647f2d --- /dev/null +++ b/main/cpu/arm/ldatags.c @@ -0,0 +1,441 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * ldatags: + * + * Load (install) ARM Tags for booting Linux. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "stddefs.h" +#include "genlib.h" +#include "ether.h" +#include "cli.h" +#include "tfs.h" +#include "tfsprivate.h" + +#define __PACKED__ __attribute__ ((packed)) +#define TAG_SIZE(a) ((sizeof(a) + sizeof(struct tag_hdr))/4) +#define STR_LEN(string) (sizeof(string) - 1) + +#define MEM32_SIZE "mem32_size=" +#define MEM32_START "mem32_start=" +#define CORE_FLAGS "core_flags=" +#define CORE_PGSIZE "core_pgsize=" +#define CORE_ROOTDEV "core_rootdev=" +#define INITRD_SIZE "initrd_size=" +#define INITRD_START "initrd_start=" +#define RAMDISK_FLAGS "ramdisk_flags=" +#define RAMDISK_SIZE "ramdisk_size=" +#define RAMDISK_START "ramdisk_start=" +#define SERIAL_HI "serial_hi=" +#define SERIAL_LO "serial_lo=" +#define CMDLINE "cmdline=" +#define CMDLINE_APP "cmdline_append=" +#define REVISION "revision=" + +void sno_mac_warning(int); +void initrd_file_warning(int); + +#ifdef ATAG_SPACE_DEFINED +extern int atag_space, end_atag_space; +#endif + +#define CLISIZE 1024 + +/* Tag specification defaults: + */ +#define RAMDISK_MAJOR 1 +#define PAGE_SIZE 4096 +#define PHYS_OFFSET 0x20000000 +#define MEM_SIZE 0x01e00000 + +/* Tag identifiers: + */ +#define ATAG_NONE 0x00000000 +#define ATAG_CORE 0x54410001 +#define ATAG_MEM 0x54410002 +#define ATAG_VIDEOTEXT 0x54410003 +#define ATAG_RAMDISK 0x54410004 +#define ATAG_INITRD 0x54410005 +#define ATAG_INITRD2 0x54420005 +#define ATAG_SERIAL 0x54410006 +#define ATAG_REVISION 0x54410007 +#define ATAG_VIDEOLFB 0x54410008 +#define ATAG_CMDLINE 0x54410009 +#define ATAG_ACORN 0x41000101 +#define ATAG_MEMCLK 0x41000402 +#define ATAG_SNOMAC ATAG_SERIAL + +/* Tag structures: + */ +struct tag_hdr { + ulong size; + ulong tag; +}__PACKED__; + +struct tag_core { + ulong flags; + ulong pgsize; + ulong rootdev; +}__PACKED__; + +struct tag_mem32 { + ulong size; + ulong start; +}__PACKED__; + +union tag_snomac { + struct tag_serial { + ulong hi; + ulong lo; + } serial; + struct tag_mac { + char mac[8]; /* only use first 6 bytes */ + } mac; +}__PACKED__; + +struct tag_initrd { + ulong start; + ulong size; +}__PACKED__; + +struct tag_ramdisk { + ulong flags; + ulong size; + ulong start; +}__PACKED__; + +struct tag_cmdline { + char cmdline[CLISIZE]; +}__PACKED__; + +struct tag_revno { + ulong rev; +}__PACKED__; + +struct init_tags { + struct tag_hdr hdr1; + struct tag_core core; + struct tag_hdr hdr2; + struct tag_mem32 mem; + struct tag_hdr hdr3; + union tag_snomac snomac; + struct tag_hdr hdr4; + struct tag_ramdisk ramdisk; + struct tag_hdr hdr5; + struct tag_initrd initrd; + struct tag_hdr hdr6; + struct tag_cmdline cmdline; + struct tag_hdr hdr7; + struct tag_revno revno; + struct tag_hdr hdr_last; +}__PACKED__; + +/* This is the default tag list. All entries in this list can + * be overridden by sub-commands within the ldatags command. + */ +static struct init_tags inittag = { + { TAG_SIZE(struct tag_core), ATAG_CORE }, + { 1, PAGE_SIZE, 0xff }, + + { TAG_SIZE(struct tag_mem32), ATAG_MEM }, + { MEM_SIZE, PHYS_OFFSET }, + + { TAG_SIZE(union tag_snomac), ATAG_SNOMAC }, + { {0xffffffff, 0xffffffff} }, + + { TAG_SIZE(struct tag_ramdisk), ATAG_RAMDISK }, + { 0, 0, 0 }, + + { TAG_SIZE(struct tag_initrd), ATAG_INITRD2 }, + { 0, 0 }, + + { TAG_SIZE(struct tag_cmdline), ATAG_CMDLINE }, + { {0} }, + + { TAG_SIZE(struct tag_revno), ATAG_REVISION }, + { 0 }, + + { 0, ATAG_NONE }, +}; + + +char *ldatagsHelp[] = { + "Install ARM tags for Linux startup.", + "[-a:cf:imv] [sub-cmd1 sub-cmd2 ...]", + "Options:", + " -a {addr} tag list address", + " -c clear tag list memory", + " -f {fname} initrd filename", + " -i init default tag list", + " -m load MAC address into serial_no tag", + " -v enable verbosity", + "Sub-commands:", + " " CORE_FLAGS "{value}", + " " CORE_PGSIZE "{value}", + " " CORE_ROOTDEV "{value}", + " " MEM32_SIZE "{value}", + " " MEM32_START "{value}", + " " SERIAL_LO "{value} (serial hi/lo overrides -m)", + " " SERIAL_HI "{value}", + " " INITRD_SIZE "{value} (initrd size/start overrides -f)", + " " INITRD_START "{value}", + " " RAMDISK_FLAGS "{value}", + " " RAMDISK_SIZE "{value}", + " " RAMDISK_START "{value}", + " " REVISION "{value}", + " " CMDLINE "{string}", + " " CMDLINE_APP "{string}", + 0 +}; + + +int +ldatags(int argc,char *argv[]) +{ + TFILE *tfp; + char *eadd, *initrd_fname; + struct init_tags *tagaddr; + int opt, verbose, arg, clear, init, mac, len; + int sno_mac_warned, initrd_file_warned; + + initrd_fname = 0; + sno_mac_warned = initrd_file_warned = 0; + mac = init = verbose = clear = 0; +#ifdef ATAG_SPACE_DEFINED + tagaddr = (struct init_tags *)&atag_space; +#else + tagaddr = (struct init_tags *)getAppRamStart(); +#endif + while((opt=getopt(argc,argv,"a:cf:imv")) != -1) { + switch(opt) { + case 'a': /* Override default tag list address. */ + tagaddr = (struct init_tags *)strtoul(optarg,0,0); + break; + case 'c': /* Clear the tag list space. */ + clear++; + break; + case 'f': /* Initrd filename. */ + initrd_fname = optarg; + break; + case 'i': /* Initialize tag list with defaults. */ + init++; + break; + case 'm': /* Load MAC address into list. */ + mac++; + break; + case 'v': /* Enable verbosity. */ + verbose++; + break; + default: + return(CMD_PARAM_ERROR); + } + } + +#ifdef ATAG_SPACE_DEFINED + /* If the ATAG space is allocated externally (usually in rom.lnk file), + * then if at this point the tag address still points to that space, + * we must start by verifying that the allocated space is large enough + * to hold the init_tags structure... + */ + if (tagaddr == (struct init_tags *)&atag_space) { + if (((int)&end_atag_space - (int)&atag_space) < sizeof(struct init_tags)) { + printf("Error: the size of struct init_tags (%d) is larger than\n", + sizeof(struct init_tags)); + printf(" the size of the allocated atag space (%d bytes).\n", + ((int)&end_atag_space - (int)&atag_space)); + return(CMD_FAILURE); + } + } +#endif + + if (clear) { + memset((char *)tagaddr,0,sizeof(struct init_tags)); + if (verbose) + printf("Tagspace at 0x%lx cleared\n",(long)tagaddr); + return(CMD_SUCCESS); + } + + /* If -i specified, then load default tag list for starters... + */ + if (init) + memcpy((char *)tagaddr,(char *)&inittag,sizeof(struct init_tags)); + + /* Insert this board's MAC address: + */ + if (mac) { + memset(tagaddr->snomac.mac.mac,0,8); + eadd = getenv("ETHERADD"); + if (eadd) { + if (EtherToBin(eadd,(uchar *)tagaddr->snomac.mac.mac) < 0) + return(CMD_FAILURE); + } + else { + printf("ETHERADD shell var not set.\n"); + return(CMD_FAILURE); + } + } + + if (initrd_fname) { + tfp = tfsstat(initrd_fname); + if (!tfp) { + printf("No such file: %s\n",initrd_fname); + return(CMD_FAILURE); + } + tagaddr->initrd.size = (ulong)TFS_SIZE(tfp); + tagaddr->initrd.start = (ulong)TFS_BASE(tfp); + } + + /* Process the command line arguments: + */ + for(arg=optind;arg<argc;arg++) { + if (strncmp(argv[arg],CORE_FLAGS,STR_LEN(CORE_FLAGS)) == 0) { + tagaddr->core.flags = + strtoul(argv[arg]+STR_LEN(CORE_FLAGS),0,0); + } + else if (strncmp(argv[arg],CORE_PGSIZE,STR_LEN(CORE_PGSIZE)) == 0) { + tagaddr->core.pgsize = + strtoul(argv[arg]+STR_LEN(CORE_PGSIZE),0,0); + } + else if (strncmp(argv[arg],CORE_ROOTDEV,STR_LEN(CORE_ROOTDEV)) == 0) { + tagaddr->core.rootdev = + strtoul(argv[arg]+STR_LEN(CORE_ROOTDEV),0,0); + } + else if (strncmp(argv[arg],MEM32_SIZE,STR_LEN(MEM32_SIZE)) == 0) { + tagaddr->mem.size = + strtoul(argv[arg]+STR_LEN(MEM32_SIZE),0,0); + } + else if (strncmp(argv[arg],MEM32_START,STR_LEN(MEM32_START)) == 0) { + tagaddr->mem.start = + strtoul(argv[arg]+STR_LEN(MEM32_START),0,0); + } + else if (strncmp(argv[arg],INITRD_SIZE,STR_LEN(INITRD_SIZE)) == 0) { + if (initrd_fname) + initrd_file_warning(initrd_file_warned++); + tagaddr->initrd.size = + strtoul(argv[arg]+STR_LEN(INITRD_SIZE),0,0); + } + else if (strncmp(argv[arg],INITRD_START,STR_LEN(INITRD_START)) == 0) { + if (initrd_fname) + initrd_file_warning(initrd_file_warned++); + tagaddr->initrd.start = + strtoul(argv[arg]+STR_LEN(INITRD_START),0,0); + } + else if (strncmp(argv[arg],RAMDISK_FLAGS,STR_LEN(RAMDISK_FLAGS)) == 0) { + tagaddr->ramdisk.flags = + strtoul(argv[arg]+STR_LEN(RAMDISK_FLAGS),0,0); + } + else if (strncmp(argv[arg],RAMDISK_SIZE,STR_LEN(RAMDISK_SIZE)) == 0) { + tagaddr->ramdisk.size = + strtoul(argv[arg]+STR_LEN(RAMDISK_SIZE),0,0); + } + else if (strncmp(argv[arg],RAMDISK_START,STR_LEN(RAMDISK_START)) == 0) { + tagaddr->ramdisk.start = + strtoul(argv[arg]+STR_LEN(RAMDISK_START),0,0); + } + else if (strncmp(argv[arg],SERIAL_HI,STR_LEN(SERIAL_HI)) == 0) { + if (mac) + sno_mac_warning(sno_mac_warned++); + mac = 0; + tagaddr->snomac.serial.hi = + strtoul(argv[arg]+STR_LEN(SERIAL_HI),0,0); + } + else if (strncmp(argv[arg],SERIAL_LO,STR_LEN(SERIAL_LO)) == 0) { + if (mac) + sno_mac_warning(sno_mac_warned++); + mac = 0; + tagaddr->snomac.serial.lo = + strtoul(argv[arg]+STR_LEN(SERIAL_LO),0,0); + } + else if (strncmp(argv[arg],CMDLINE,STR_LEN(CMDLINE)) == 0) { + len = strlen(argv[arg]+STR_LEN(CMDLINE)); + if (len > CLISIZE-1) + printf("Kernel cli too big (%d>%d)\n",len,CLISIZE); + else + strcpy(tagaddr->cmdline.cmdline,argv[arg]+STR_LEN(CMDLINE)); + } + else if (strncmp(argv[arg],CMDLINE_APP,STR_LEN(CMDLINE_APP)) == 0) { + len = strlen(argv[arg]+STR_LEN(CMDLINE_APP)); + len += strlen(tagaddr->cmdline.cmdline); + if (len > CLISIZE-1) + printf("Kernel cli too big (%d>%d)\n",len,CLISIZE); + else + strcat(tagaddr->cmdline.cmdline,argv[arg]+STR_LEN(CMDLINE_APP)); + } + else if (strncmp(argv[arg],REVISION,STR_LEN(REVISION)) == 0) { + tagaddr->revno.rev = + strtoul(argv[arg]+STR_LEN(REVISION),0,0); + } + else { + printf("Unrecognized sub-command: %s\n",argv[arg]); + return(CMD_FAILURE); + } + } + + if (verbose) { + printf("ATAGS (%d bytes) at 0x%lx...\n", + sizeof(struct init_tags),(long)tagaddr); + printf(" Core (flags/pgsize/rootdev) = 0x%lx/0x%0lx/0x%lx\n", + tagaddr->core.flags,tagaddr->core.pgsize,tagaddr->core.rootdev); + printf(" Mem32 (size/offset) = 0x%08lx/0x%08lx\n", + tagaddr->mem.size,tagaddr->mem.start); + if (mac) { + printf(" Mac = %02x:%02x:%02x:%02x:%02x:%02x\n", + tagaddr->snomac.mac.mac[0], tagaddr->snomac.mac.mac[1], + tagaddr->snomac.mac.mac[2], tagaddr->snomac.mac.mac[3], + tagaddr->snomac.mac.mac[4], tagaddr->snomac.mac.mac[5]); + } + else { + printf(" Serial (hi/lo) = 0x%08lx/0x%08lx\n", + tagaddr->snomac.serial.hi, tagaddr->snomac.serial.lo); + } + printf(" Ramdisk (flags/size/start) = 0x%lx/0x%lx/0x%lx\n", + tagaddr->ramdisk.flags, tagaddr->ramdisk.size, + tagaddr->ramdisk.start); + + printf(" Initrd (size/start) = 0x%lx/0x%lx\n", + tagaddr->initrd.size, tagaddr->initrd.start); + + printf(" Cmdline = <%s>\n",tagaddr->cmdline.cmdline); + } + + return(CMD_SUCCESS); +} + +void +sno_mac_warning(int already_warned) +{ + if (already_warned) + return; + + printf("Warning: serialno command overrides -m option.\n"); +} + +void +initrd_file_warning(int already_warned) +{ + if (already_warned) + return; + + printf("Warning: initrd command overrides -f option.\n"); +} diff --git a/main/cpu/arm/misc_arm.c b/main/cpu/arm/misc_arm.c new file mode 100644 index 0000000..355245c --- /dev/null +++ b/main/cpu/arm/misc_arm.c @@ -0,0 +1,64 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * misc_arm.c + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +/* + * Set the Current Program Status Register. + * old way assumed argument was in R0: + * asm(" msr CPSR_c, r0"); + */ +void +putpsr(unsigned long psr) +{ + volatile unsigned register reg; + + reg = psr; + asm volatile ("msr CPSR_c, %0" : "=r" (reg)); +} + +/* + * Return the Current Program Status Register. + * old way assumed return in R0: + * asm(" mrs r0, CPSR"); + */ +unsigned long +getpsr(void) +{ + volatile unsigned register reg; + asm volatile ("mrs %0, CPSR" : "=r" (reg)); + return(reg); +} + +/* getsp(): + * Return the current stack pointer. + * oldway: asm(" mov r0, r13"); + */ +unsigned long +getsp(void) +{ + volatile unsigned register reg; + asm volatile ("mov %0, r13" : "=r" (reg)); + return(reg); +} diff --git a/main/cpu/arm/misc_arm.h b/main/cpu/arm/misc_arm.h new file mode 100644 index 0000000..add61d3 --- /dev/null +++ b/main/cpu/arm/misc_arm.h @@ -0,0 +1,28 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * misc_arm.h + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +extern void putpsr(unsigned long psr); +extern unsigned long getpsr(void); +extern unsigned long getsp(void); diff --git a/main/cpu/arm/regs_arm.c b/main/cpu/arm/regs_arm.c new file mode 100644 index 0000000..13180f0 --- /dev/null +++ b/main/cpu/arm/regs_arm.c @@ -0,0 +1,32 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * FILENAME_HERE + * + * DESCRIPTION_HERE + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +static char *regnames[] = { + "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", + "R8", "R9", "R10", "R11", "R12", "SP", "LR", + "PC", "CPSR" +}; diff --git a/main/cpu/arm/strace_arm.c b/main/cpu/arm/strace_arm.c new file mode 100644 index 0000000..8dd7456 --- /dev/null +++ b/main/cpu/arm/strace_arm.c @@ -0,0 +1,156 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * strace.c: + * + * Note that this stack trace can be used to trace REAL exceptions or + * user-induced exceptions. If one is user-induced, then the user is + * typically just replacing an instruction at the point at which the break + * is to occur with a SC (syscall) instruction. The point at which this + * insertion is made must be after the function sets up its stack frame + * otherwise it is likely that the trace will be bogus. + * + * BTW... the SC instruction is 0x44000002. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_STRACE +#include "tfs.h" +#include "tfsprivate.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +char *StraceHelp[] = { + "Stack trace", + "-[d:rs:v]", + " -d # max depth count (def=20)", + " -r dump regs", + " -s {func} stop at function 'func'", + " -v verbose", + 0, +}; + +int +Strace(int argc,char *argv[]) +{ + TFILE *tfp; + char *symfile, *stopat, fname[64]; + ulong *framepointer, pc, fp, offset; + int tfd, opt, maxdepth, pass, verbose; + + tfd = fp = 0; + maxdepth = 20; + verbose = 0; + stopat = 0; + pc = ExceptionAddr; + while ((opt=getopt(argc,argv,"d:rs:v")) != -1) { + switch(opt) { + case 'd': + maxdepth = atoi(optarg); + break; + case 'r': + showregs(); + break; + case 's': + stopat = optarg; + break; + case 'v': + verbose = 1; + break; + default: + return(0); + } + } + + if (!fp) + getreg("R11", &fp); + + framepointer = (ulong *)fp; + + /* Start by detecting the presence of a symbol table file... */ + symfile = getenv("SYMFILE"); + if (!symfile) + symfile = SYMFILE; + + tfp = tfsstat(symfile); + if (tfp) { + tfd = tfsopen(symfile,TFS_RDONLY,0); + if (tfd < 0) + tfp = (TFILE *)0; + } + + /* Show current position: */ + printf(" 0x%08lx",pc); + if (tfp) { + AddrToSym(tfd,pc,fname,&offset); + printf(": %s()",fname); + if (offset) + printf(" + 0x%lx",offset); + } + putchar('\n'); + + /* Now step through the stack frame... */ + pass = 0; + while(maxdepth) { + if (pass != 0) + framepointer = (ulong *)*(framepointer - 3); + + pc = *(framepointer - 1); + + if (verbose) { + printf("fp=0x%lx,*fp=0x%lx,pc=%lx\n", (ulong)framepointer, + (ulong)*framepointer,pc); + } + + if (((ulong)framepointer & 3) || (!framepointer) || + (!*framepointer) || (!pc)) { + break; + } + + printf(" 0x%08lx",pc); + if (tfp) { + int match; + + match = AddrToSym(tfd,pc,fname,&offset); + printf(": %s()",fname); + if (offset) + printf(" + 0x%lx",offset); + if ((!match) || ((stopat != 0) && (strcmp(fname,stopat) == 0))) { + putchar('\n'); + break; + } + } + putchar('\n'); + maxdepth--; + pass++; + } + + if (!maxdepth) + printf("Max depth termination\n"); + + if (tfp) { + tfsclose(tfd,0); + } + return(0); +} +#endif diff --git a/main/cpu/arm/vectors_arm.S b/main/cpu/arm/vectors_arm.S new file mode 100644 index 0000000..c4389ed --- /dev/null +++ b/main/cpu/arm/vectors_arm.S @@ -0,0 +1,65 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * vectors_arm.S + * + * Minimalist exception handlers... + * Catch the exception, call generic handler with exception-specific id. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +#include "arm.h" + + .global undefined_instruction +undefined_instruction: + mov r1, #EXCTYPE_UNDEF + b umon_exception + + .global software_interrupt +software_interrupt: + mov r1, #EXCTYPE_SWI + b umon_exception + + .global abort_prefetch +abort_prefetch: + mov r1, #EXCTYPE_ABORTP + b umon_exception + + .global abort_data +abort_data: + mov r1, #EXCTYPE_ABORTD + b umon_exception + + .global not_assigned +not_assigned: + mov r1, #EXCTYPE_NOTASSGN + b umon_exception + + .global interrupt_request +interrupt_request: + mov r1, #EXCTYPE_IRQ + b umon_exception + + .global fast_interrupt_request +fast_interrupt_request: + mov r1, #EXCTYPE_FIRQ + b umon_exception diff --git a/main/cpu/template/except_template.c b/main/cpu/template/except_template.c new file mode 100644 index 0000000..1623d5c --- /dev/null +++ b/main/cpu/template/except_template.c @@ -0,0 +1,87 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * except_template.c: + * + * Template for cpu-specific code that handles exceptions that are caught + * by the exception vectors that have been installed by the monitor through + * vinit(). + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpu.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "warmstart.h" + +ulong ExceptionAddr; +int ExceptionType; + +/* exception(): + * This is the first 'C' function called out of a monitor-installed + * exception handler. + */ +void +exception(void) +{ + /* ADD_CODE_HERE */ + + /* Populating these two values is target specific. + * Refer to other target-specific examples for details. + * In some cases, these values are extracted from registers + * already put into the register cache by the lower-level + * portion of the exception handler in vectors_template.s + */ + ExceptionAddr = 0; + ExceptionType = 0; + + /* Allow the console uart fifo to empty... + */ + flushconsole(); + monrestart(EXCEPTION); +} + +/* vinit(): + * This function is called by init1() at startup of the monitor to + * install the monitor-based vector table. The actual functions are + * in vectors.s. + */ +void +vinit() +{ + /* ADD_CODE_HERE */ +} + +/* ExceptionType2String(): + * This function simply returns a string that verbosely describes + * the incoming exception type (vector number). + */ +char * +ExceptionType2String(int type) +{ + char *string; + + /* ADD_CODE_HERE */ + return(string); +} + diff --git a/main/cpu/template/strace_template.c b/main/cpu/template/strace_template.c new file mode 100644 index 0000000..559f5b8 --- /dev/null +++ b/main/cpu/template/strace_template.c @@ -0,0 +1,124 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * strace_template.c: + * + * Template for creating cpu-specific stack-trace command. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#if INCLUDE_STRACE +#include "tfs.h" +#include "tfsprivate.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" +#include "cpu.h" + +char *StraceHelp[] = { + "Stack trace", + "-[d:F:P:rs:v]", + " -d # max depth count (def=20)", + " -F # specify frame-pointer (don't use content of A6)", + " -P # specify PC (don't use content of PC)", + " -r dump regs", + " -v verbose", + 0, +}; + +int +Strace(int argc,char *argv[]) +{ + char *symfile, fname[64]; + TFILE *tfp; + ulong *framepointer, pc, fp, offset; + int tfd, opt, maxdepth, pass, verbose, bullseye; + + tfd = fp = 0; + maxdepth = 20; + verbose = 0; + pc = ExceptionAddr; + while ((opt=getopt(argc,argv,"d:F:P:rs:v")) != -1) { + switch(opt) { + case 'd': + maxdepth = atoi(optarg); + break; + case 'F': + fp = strtoul(optarg,0,0); + break; + case 'P': + pc = strtoul(optarg,0,0); + break; + case 'r': + showregs(); + break; + case 'v': + verbose = 1; + break; + default: + return(0); + } + } + + if (!fp) + getreg("A6", (ulong *)&framepointer); + else + framepointer = (ulong *)fp; + + /* Start by detecting the presence of a symbol table file... */ + symfile = getenv("SYMFILE"); + if (!symfile) + symfile = SYMFILE; + + tfp = tfsstat(symfile); + if (tfp) { + tfd = tfsopen(symfile,TFS_RDONLY,0); + if (tfd < 0) + tfp = (TFILE *)0; + } + + /* Show current position: */ + printf(" 0x%08lx",pc); + if (tfp) { + AddrToSym(tfd,pc,fname,&offset); + printf(": %s()",fname); + if (offset) + printf(" + 0x%lx",offset); + } + putchar('\n'); + + /* Now step through the stack frame... */ + bullseye = pass = 0; + while(maxdepth) { + /* ADD_CODE_HERE */ + } + + if (!maxdepth) + printf("Max depth termination\n"); + + if (tfp) { + tfsclose(tfd,0); + } + return(0); +} + +#endif diff --git a/main/dev/bp b/main/dev/bp new file mode 100644 index 0000000..c472414 --- /dev/null +++ b/main/dev/bp @@ -0,0 +1,27 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * FILENAME_HERE + * + * DESCRIPTION_HERE + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ diff --git a/main/dev/fb_draw.c b/main/dev/fb_draw.c new file mode 100644 index 0000000..a0f9391 --- /dev/null +++ b/main/dev/fb_draw.c @@ -0,0 +1,261 @@ +//========================================================================== +// +// fb_draw.c +// +// Author(s): Michael Kelly - Cogent Computer Systems, Inc. +// Date: 10/18/03 +// Description: generic frame buffer drawing routines - based on +// lcd.c (c) 1999 Cirrus Logic. +// +// These routines all end up calling fb_set_pixel(). That routine must +// be provided in the target specific code. +// +//========================================================================== +#include "config.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "fb_fonts.h" +#include "vga_lookup.h" + +#if INCLUDE_LCD +extern uchar bcolor; +extern void fb_set_pixel(int X, int Y, uchar color); + +void fb_draw_line2(int x0, int y0, int x1, int y1, uchar color) + { + int i; + int steep = 1; + int sx, sy; /* step positive or negative (1 or -1) */ + int dx, dy; /* delta (difference in X and Y between points) */ + int e; + + /* + * optimize for vertical and horizontal lines here + */ + + dx = (x1 > x0) ? (x1 - x0) : x0 - x1; + sx = ((x1 - x0) > 0) ? 1 : -1; + dy = (y1 > y0) ? (y1 - y0) : y0 - y1; + sy = ((y1 - y0) > 0) ? 1 : -1; + e = (dy << 1) - dx; + for (i = 0; i < dx; i++) { + if (steep) { + fb_set_pixel(x0,y0,color); + } else { + fb_set_pixel(y0,x0,color); + } + while (e >= 0) { + y0 += sy; + e -= (dx << 1); + } + x0 += sx; + e += (dy << 1); + } + } + +// ------------------------------------------------------------------ +// fb_draw_circle draws a circle at the specified location based on +// bresenham's circle drawing algorithm +void fb_draw_circle(ulong x, ulong y, ulong radius, uchar color) +{ + ulong xpos, ypos, d; + + xpos = x; + ypos = radius; + + d = 3 - (2 * ypos); + + while(ypos >= xpos) + { + fb_set_pixel(x + xpos, y + ypos, color); // point in octant 1 + fb_set_pixel(x - xpos, y + ypos, color); // point in octant 4 + fb_set_pixel(x - xpos, y - ypos, color); // point in octant 5 + fb_set_pixel(x + xpos, y - ypos, color); // point in octant 8 + fb_set_pixel(x + ypos, y + xpos, color); // point in octant 2 + fb_set_pixel(x - ypos, y + xpos, color); // point in octant 3 + fb_set_pixel(x - ypos, y - xpos, color); // point in octant 6 + fb_set_pixel(x + ypos, y - xpos, color); // point in octant 7 + + if (d < 0) + { + d = (d + (4 * xpos)) + 6; + } + else + { + d = (d + (4 * (xpos - ypos))) + 10; + ypos = ypos - 1; + } + + xpos++; + } +} + +void fb_draw_circle2(ulong xpos, ulong ypos, ulong radius, uchar color) +{ + int x; + int y = radius; + int d = -radius; + for(x = 1; x < (radius/1.414); x++) + { d += (2 * x) - 1; + if (d >= 0) + { y--; + d -= (2 * y); /* Must do this AFTER y-- */ + } + // fb_set_pixel(x + xpos, y + ypos, color); + fb_set_pixel(xpos + x, ypos + y, color); // point in octant 1 + fb_set_pixel(xpos - x, ypos + y, color); // point in octant 4 + fb_set_pixel(xpos - x, ypos - y, color); // point in octant 5 + fb_set_pixel(xpos + x, ypos - y, color); // point in octant 8 + fb_set_pixel(xpos + y, ypos + x, color); // point in octant 2 + fb_set_pixel(xpos - y, ypos + x, color); // point in octant 3 + fb_set_pixel(xpos - y, ypos - x, color); // point in octant 6 + fb_set_pixel(xpos + y, ypos - x, color); // point in octant 7 + } +} + +// ------------------------------------------------------------------ +// fb_draw_circle draws a filled circle at the specified location based on +// bresenham's circle drawing algorithm +// +void fb_fill_circle(ulong x, ulong y, ulong radius, uchar color) +{ + ulong xpos, ypos, d; + + xpos = x; + ypos = radius; + + d = 3 - (2 * ypos); + + while(ypos >= xpos) + { + fb_draw_line2(x - xpos, y + ypos, x + xpos, y + ypos, color); + fb_draw_line2(x - ypos, y + xpos, x + ypos, y + xpos, color); + fb_draw_line2(x - xpos, y - ypos, x + xpos, y - ypos, color); + fb_draw_line2(x - ypos, y - xpos, x + ypos, y - xpos, color); + + if(d < 0) + { + d += (4 * xpos) + 6; + } + else + { + d += 10 + (4 * (xpos - ypos)); + ypos--; + } + + xpos++; + } +} + +// ------------------------------------------------------------------ +// fb_print_char prints a character at the specified location. +// +void fb_print_char(uchar cchar, ulong x, ulong y, uchar color) +{ + ulong idx1, idx2; + uchar font_line, fcolor; + + // printable characters only + if ((cchar < FIRST_CHAR) || (cchar > LAST_CHAR)) + return; + + // loop through each row of the font. + for(idx1 = 0; idx1 < FONT_HEIGHT; idx1++) + { + // read the byte which describes this row of the font. + font_line = fb_font_data[(cchar - FIRST_CHAR) * FONT_STEP][idx1]; + + // loop through each column of this row. + for(idx2 = 0; idx2 < 8; idx2++) + { + // set the pixel based on the value of this bit of the font, + // using the requested or the backround color. + fcolor = font_line & 1 << ((FONT_WIDTH - 1) - idx2) ? color : bcolor; + + fb_set_pixel(x + idx2, y + idx1, fcolor); + } + } +} + +// ------------------------------------------------------------------ +// fb_print_string prints a string at the specified location. +// +void +fb_print_string(uchar *pcbuffer, ulong x, ulong y, uchar color) +{ + // loop through each character in the string. + while(*pcbuffer) + { + // print this character. + fb_print_char(*pcbuffer++, x, y, color); + + // advance horizontaly past this character. + x += FONT_WIDTH; + } +} + +// ------------------------------------------------------------------ +// fb_print_charx2 prints a double-sized character at the specified location. +// +void fb_print_charx2(char cchar, ulong x, ulong y, uchar color) +{ + ulong idx1, idx2; + ushort font_line; + uchar fcolor; + + // printable characters only + if (((unsigned char)cchar < FIRST_CHAR) || + ((unsigned char)cchar > LAST_CHAR)) + return; + + // loop through each row of the font. + for(idx1 = 0; idx1 < FONT_HEIGHT; idx1++) + { + // read the byte which describes this row of the font. + font_line = (fb_font_data[(cchar - FIRST_CHAR) * FONT_STEP][idx1]) << 8; + if (FONT_WIDTH > 8) // get the second byte if present + { + font_line = fb_font_data[(cchar - FIRST_CHAR) * FONT_STEP][idx1 + 1]; + } + + // loop through each column of this row. + for(idx2 = 0; idx2 < FONT_WIDTH; idx2++) + { + // determine the color of this pixel block. + fcolor = font_line & (1 << ((FONT_WIDTH - 1) - idx2)) ? color : bcolor; + + // set the pixel block (2x2) based on the value of this bit of + // the font, using the requested or the backround color. + fb_set_pixel(x + (idx2 << 1), y + (idx1 << 1), fcolor); + fb_set_pixel(x + (idx2 << 1) + 1, y + (idx1 << 1), fcolor); + fb_set_pixel(x + (idx2 << 1), y + (idx1 << 1) + 1, fcolor); + fb_set_pixel(x + (idx2 << 1) + 1, y + (idx1 << 1) + 1, fcolor); + } + } +} + +// ------------------------------------------------------------------ +// fb_print_stringx2 prints a string of double-sized characters at the +// specified location. +// +void fb_print_stringx2(char *pcbuffer, ulong x, ulong y, uchar color) +{ + // + // loop through each character in the string. + // + while(*pcbuffer) + { + // + // print this character. + // + fb_print_charx2(*pcbuffer++, x, y, color); + + // + // advance horizontaly past this character. + // + x += 16; + } +} +#endif + diff --git a/main/dev/fb_draw.h b/main/dev/fb_draw.h new file mode 100644 index 0000000..4c5de0a --- /dev/null +++ b/main/dev/fb_draw.h @@ -0,0 +1,8 @@ +extern void fb_draw_line2(int x0, int y0, int x1, int y1, uchar color); +extern void fb_draw_circle(ulong x, ulong y, ulong radius, uchar color); +extern void fb_draw_circle2(int xpos, int ypos, int radius, uchar color); +extern void fb_fill_circle(ulong x, ulong y, ulong radius, uchar color); +extern void fb_print_char(uchar cchar, ulong x, ulong y, uchar color); +extern void fb_print_string(uchar *pcbuffer, ulong x, ulong y, uchar color); +extern void fb_print_charx2(char cchar, ulong x, ulong y, uchar color); +extern void fb_print_stringx2(char *pcbuffer, ulong x, ulong y, uchar color); diff --git a/main/dev/fb_fonts.h b/main/dev/fb_fonts.h new file mode 100644 index 0000000..9a96782 --- /dev/null +++ b/main/dev/fb_fonts.h @@ -0,0 +1,237 @@ +//------------------------------------------------------------------------ +// fb_fonts.h +// +// Author(s): Michael Kelly - Cogent Computer Systems, Inc. +// Date: 10/18/03 +// Description: basic fonts for different screen sizes. 8x16 +// is good for VGA and above, 8x8 is good for QVGA +// landscape (320 x 240), while 5x7 gives the most +// characters on QVGA portrait mode (240 x 320). +// +// Note that 8x8 and 5x7 use one byte per font row, +// but 5x7 uses only the upper 5 bits. +// +// To lookoup, subtract FIRST_CHAR from the character, +// multiply x FONT_HEIGHT and get the next FONT_WIDTH +// bytes. Thes efonts only support printable ascii +// characters 0x20 to 0x7f +// + +#define FIRST_CHAR 0x20 +#define LAST_CHAR 0x7F +#define CURSOR_ON 0x7F +#define CURSOR_OFF 0x20 + +#ifdef USE_FONT8X8 +#define FONT_HEIGHT 8 +#define FONT_WIDTH 8 +#define FONT_STEP 8 // font rows are 8 bytes apart + +static uchar fb_font_data[LAST_CHAR-FIRST_CHAR+1][FONT_STEP] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x20 + { 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00, }, // 0x21 ! + { 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x22 " + { 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, }, // 0x23 # + { 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00, }, // 0x24 $ + { 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, }, // 0x25 % + { 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00, }, // 0x26 & + { 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x27 ' + { 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, }, // 0x28 ( + { 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, }, // 0x29 ) + { 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, }, // 0x2a * + { 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, }, // 0x2b + + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, }, // 0x2c , + { 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, }, // 0x2d - + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, }, // 0x2e . + { 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, }, // 0x2f / + { 0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00, }, // 0x30 0 + { 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00, }, // 0x31 1 + { 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00, }, // 0x32 2 + { 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00, }, // 0x33 3 + { 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, }, // 0x34 4 + { 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00, }, // 0x35 5 + { 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, }, // 0x36 6 + { 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, }, // 0x37 7 + { 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, }, // 0x38 8 + { 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00, }, // 0x39 9 + { 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, }, // 0x3a : + { 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, }, // 0x3b ; + { 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, }, // 0x3c < + { 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00, }, // 0x3d = + { 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, }, // 0x3e > + { 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, }, // 0x3f ? + { 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00, }, // 0x40 @ + { 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00, }, // 0x41 A + { 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, }, // 0x42 B + { 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, }, // 0x43 C + { 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, }, // 0x44 D + { 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, }, // 0x45 E + { 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, }, // 0x46 F + { 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00, }, // 0x47 G + { 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, }, // 0x48 H + { 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, }, // 0x49 I + { 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, }, // 0x4a J + { 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, }, // 0x4b K + { 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, }, // 0x4c L + { 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, }, // 0x4d M + { 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, }, // 0x4e N + { 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, }, // 0x4f O + { 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, }, // 0x50 P + { 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00, }, // 0x51 Q + { 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, }, // 0x52 R + { 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00, }, // 0x53 S + { 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, }, // 0x54 T + { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00, }, // 0x55 U + { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, }, // 0x56 V + { 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00, }, // 0x57 W + { 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, }, // 0x58 X + { 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00, }, // 0x59 Y + { 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, }, // 0x5a Z + { 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, }, // 0x5b [ + { 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, }, // 0x5c '\' + { 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, }, // 0x5d ] + { 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, }, // 0x5e ^ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, }, // 0x5f _ + { 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x60 ` + { 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, }, // 0x61 a + { 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00, }, // 0x62 b + { 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00, }, // 0x63 c + { 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, }, // 0x64 d + { 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, }, // 0x65 e + { 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00, }, // 0x66 f + { 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, }, // 0x67 g + { 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, }, // 0x68 h + { 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, }, // 0x69 i + { 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, }, // 0x6a j + { 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, }, // 0x6b k + { 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, }, // 0x6c l + { 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, }, // 0x6d m + { 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, }, // 0x6e n + { 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, }, // 0x6f o + { 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, }, // 0x70 p + { 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, }, // 0x71 q + { 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00, }, // 0x72 r + { 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00, }, // 0x73 s + { 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00, }, // 0x74 t + { 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, }, // 0x75 u + { 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, }, // 0x76 v + { 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00, }, // 0x77 w + { 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, }, // 0x78 x + { 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, }, // 0x79 y + { 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, }, // 0x7a z + { 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00, }, // 0x7b { + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, }, // 0x7c | + { 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00, }, // 0x7d } + { 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x7e ~ + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, // block cursor +}; + +#endif + +#ifdef USE_FONT8X16 +#define FONT_WIDTH 8 +#define FONT_HEIGHT 16 +#define FONT_STEP 16 // font rows are 16 bytes apart + +const uchar fb_font_data[LAST_CHAR-FIRST_CHAR+1][FONT_STEP] = { +// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x20 +{ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, }, // 0x21 ! +{ 0x00, 0x00, 0x48, 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x22 " +{ 0x00, 0x00, 0x00, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, }, // 0x23 # +{ 0x00, 0x10, 0x10, 0x7c, 0x92, 0x90, 0x90, 0x7c, 0x12, 0x12, 0x92, 0x7c, 0x10, 0x10, 0x00, 0x00, }, // 0x24 $ +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x94, 0x68, 0x10, 0x2c, 0x52, 0x8c, 0x00, 0x00, 0x00, 0x00, }, // 0x25 % +{ 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x56, 0x8c, 0x88, 0x8c, 0x76, 0x00, 0x00, 0x00, 0x00, }, // 0x26 & +{ 0x00, 0x00, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x27 ' +{ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, }, // 0x28 ( +{ 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, }, // 0x29 ) +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0xfe, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x2a * +{ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x2b + +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, }, // 0x2c , +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x2d - +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, }, // 0x2e . +{ 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x2f / +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x30 0 +{ 0x00, 0x00, 0x00, 0x08, 0x18, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, }, // 0x31 1 +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x04, 0x18, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x32 2 +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x1c, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x33 3 +{ 0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, }, // 0x34 4 +{ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x35 5 +{ 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x36 6 +{ 0x00, 0x00, 0x00, 0x7e, 0x42, 0x02, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, }, // 0x37 7 +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x38 8 +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00, }, // 0x39 9 +{ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x3a : +{ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, }, // 0x3b ; +{ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, }, // 0x3c < +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x3d = +{ 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, }, // 0x3e > +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x04, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, }, // 0x3f ? +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x4e, 0x52, 0x52, 0x4e, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x40 @ +{ 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x41 A +{ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, }, // 0x42 B +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x43 C +{ 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00, }, // 0x44 D +{ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x45 E +{ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, }, // 0x46 F +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x4e, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, }, // 0x47 G +{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x48 H +{ 0x00, 0x00, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, }, // 0x49 I +{ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x4a J +{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x4b K +{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x4c L +{ 0x00, 0x00, 0x00, 0x82, 0xc6, 0xaa, 0x92, 0x92, 0x82, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, }, // 0x4d M +{ 0x00, 0x00, 0x00, 0x42, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x4e N +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x4f O +{ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, }, // 0x50 P +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x4a, 0x4a, 0x3c, 0x04, 0x06, 0x00, 0x00, }, // 0x51 Q +{ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x44, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x52 R +{ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x20, 0x18, 0x04, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x53 S +{ 0x00, 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, }, // 0x54 T +{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x55 U +{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, }, // 0x56 V +{ 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0x92, 0x92, 0xba, 0x6c, 0x44, 0x00, 0x00, 0x00, 0x00, }, // 0x57 W +{ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x58 X +{ 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x44, 0x38, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, }, // 0x59 Y +{ 0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x5a Z +{ 0x00, 0x00, 0x00, 0x3c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x5b [ +{ 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x5c '\' +{ 0x00, 0x00, 0x00, 0x3c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x5d ] +{ 0x00, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x5e ^ +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, }, // 0x5f _ +{ 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x60 ` +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, }, // 0x61 a +{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, }, // 0x62 b +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x63 c +{ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, }, // 0x64 d +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x65 e +{ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, }, // 0x66 f +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x42, 0x3c, 0x00, 0x00, }, // 0x67 g +{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x68 h +{ 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, }, // 0x69 i +{ 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1c, 0x00, 0x00, }, // 0x6a j +{ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x42, 0x44, 0x78, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x6b k +{ 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, }, // 0x6c l +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0xee, 0x92, 0x92, 0x92, 0x82, 0x00, 0x00, 0x00, 0x00, }, // 0x6d m +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x6e n +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x6f o +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x00, 0x00, }, // 0x70 p +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x03, 0x00, 0x00, }, // 0x71 q +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, }, // 0x72 r +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x38, 0x04, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, }, // 0x73 s +{ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, }, // 0x74 t +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, }, // 0x75 u +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, }, // 0x76 v +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x92, 0x92, 0xba, 0x6c, 0x44, 0x00, 0x00, 0x00, 0x00, }, // 0x77 w +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00, }, // 0x78 x +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x04, 0x78, 0x00, 0x00, }, // 0x79 y +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, }, // 0x7a z +{ 0x00, 0x00, 0x00, 0x06, 0x08, 0x08, 0x08, 0x30, 0x08, 0x08, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, }, // 0x7b { +{ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, }, // 0x7c | +{ 0x00, 0x00, 0x00, 0x60, 0x10, 0x10, 0x10, 0x0c, 0x10, 0x10, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, }, // 0x7d } +{ 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, // 0x7e ~ +{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, // 0x7f block cursor +}; + +#endif diff --git a/main/dev/smsc911x.c b/main/dev/smsc911x.c new file mode 100644 index 0000000..bf4e7d0 --- /dev/null +++ b/main/dev/smsc911x.c @@ -0,0 +1,392 @@ +//========================================================================== +// +// smsc911x.c +// +// +// +// Author(s): Jay Monkman <jtm@lopingdog.com> +// Contributors: +// Date: 06-07-2007 +// Description: Driver for the SMSC 911x and 912x families of +// ethernet controllers +// +//-------------------------------------------------------------------------- + +#include "config.h" +#if INCLUDE_ETHERNET +#include "cpuio.h" +#include "stddefs.h" +#include "genlib.h" +#include "ether.h" +#include "smsc911x.h" + + +//-------------------------------------------------------------------------- +// smsc911x_mac_read() +// +// Reads a register mapped through the MAC_CSR register +//-------------------------------------------------------------------------- +static ulong smsc911x_mac_read(int reg) +{ + while (MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) { + continue; + } + + MAC_CSR_CMD = MAC_RD_CMD(reg); + + while (MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) { + continue; + } + + return MAC_CSR_DATA; +} + +//-------------------------------------------------------------------------- +// smsc911x_mac_write() +// +// Writes a register mapped through the MAC_CSR register +//-------------------------------------------------------------------------- +static void smsc911x_mac_write(int reg, ulong val) +{ + while (MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) { + continue; + } + + MAC_CSR_DATA = val; + MAC_CSR_CMD = MAC_WR_CMD(reg); + + while (MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) { + continue; + } +} + +//-------------------------------------------------------------------------- +// smsc911x_phy_read() +// +// Reads a PHY register +//-------------------------------------------------------------------------- +#if 0 +static ulong smsc911x_phy_read(int reg) +{ + while (smsc911x_mac_read(MII_ACC) & MII_ACC_BUSY) { + continue; + } + + smsc911x_mac_write(MII_ACC, MII_ACC_ADDR(1) | MII_ACC_REG(reg)); + + while (smsc911x_mac_read(MII_ACC) & MII_ACC_BUSY) { + continue; + } + + return smsc911x_mac_read(MII_DATA); +} +#endif + +//-------------------------------------------------------------------------- +// smsc911x_phy_write() +// +// Writes a PHY register +//-------------------------------------------------------------------------- +static void smsc911x_phy_write(int reg, ushort val) +{ + while (smsc911x_mac_read(MII_ACC) & MII_ACC_BUSY) { + continue; + } + + smsc911x_mac_write(MII_DATA, val); + + smsc911x_mac_write(MII_ACC, (MII_ACC_ADDR(1) | + MII_ACC_REG(reg) | + MII_ACC_WR)); + + while (smsc911x_mac_read(MII_ACC) & MII_ACC_BUSY) { + continue; + } +} + +//-------------------------------------------------------------------------- +// smsc911x_reset() +// +// This function performs a soft reset of the controller +//-------------------------------------------------------------------------- +void smsc911x_reset(void) +{ + + HW_CFG |= HW_CFG_SRST; + + /* Wait for it */ + while (HW_CFG & HW_CFG_SRST) { + continue; + } + + PMT_CTRL |= PMT_CTRL_PHY_RST; + + /* Wait for it */ + while (PMT_CTRL & PMT_CTRL_PHY_RST) { + continue; + } +} + +//-------------------------------------------------------------------------- +// smsc911x_set_mac() +// +// This function puts the mac address from BinEnetAddr into the smsc911x. +//-------------------------------------------------------------------------- +static void smsc911x_set_mac(void) +{ + ulong i; + + i = ((BinEnetAddr[5] << 8) | + (BinEnetAddr[4] << 0)); + smsc911x_mac_write(ADDRH, i); + + + i = ((BinEnetAddr[3] << 24) | + (BinEnetAddr[2] << 16) | + (BinEnetAddr[1] << 8) | + (BinEnetAddr[0] << 0)); + smsc911x_mac_write(ADDRL, i); + +} + +//-------------------------------------------------------------------------- +// smsc911x_init() +// +// This code initializes the ethernet controller. +//-------------------------------------------------------------------------- +int smsc911x_init(void) +{ + ulong val; + + /* Set the PHY clock config */ + HW_CFG = (HW_CFG & ~HW_CFG_PHY_CLK_MASK) | HW_CFG_PHY_CLK_INT; + + /* reset the controller, PHY */ + smsc911x_reset(); + + switch(ID_REV) { + case ID_REV_CHIP_9118: + if (EtherVerbose & SHOW_DRIVER_DEBUG) + printf("Found SMSC9118\n"); + break; + case ID_REV_CHIP_9211: + if (EtherVerbose & SHOW_DRIVER_DEBUG) + printf("Found SMSC9211\n"); + break; + case ID_REV_CHIP_9215: + if (EtherVerbose & SHOW_DRIVER_DEBUG) + printf("Found SMSC9215\n"); + break; + case ID_REV_CHIP_9218: + if (EtherVerbose & SHOW_DRIVER_DEBUG) + printf("Found SMSC9218\n"); + break; + default: + printf("Unidentified Ethernet controller: 0x%x\n", ID_REV); + return -1; + } + + // set the mac address + smsc911x_set_mac(); + + /* These came from SMSC's example driver */ + HW_CFG = (HW_CFG & ~HW_CFG_TX_FIF_MASK) | HW_CFG_TX_FIF_SZ(5); + + AFC_CFG = (AFC_CFG_AFC_HI(0x6e) | + AFC_CFG_AFC_LO(0x37) | + AFC_CFG_BACK_DUR(0x4)); + + /* Configure the GPIOs as LEDs */ + GPIO_CFG = (GPIO_CFG_LED3_EN | + GPIO_CFG_LED2_EN | + GPIO_CFG_LED1_EN | + GPIO_CFG_GPIOBUF(2) | + GPIO_CFG_GPIOBUF(1) | + GPIO_CFG_GPIOBUF(0)); + + /* Configure PHY to advertise all speeds */ + smsc911x_phy_write(PHY_ANAR, (PHY_ANAR_100TX_FD | + PHY_ANAR_100TX | + PHY_ANAR_10T_FD | + PHY_ANAR_10T | + PHY_ANAR_SF)); + + /* Enable auto negotiation */ + smsc911x_phy_write(PHY_BCR, (PHY_BCR_ANE | + PHY_BCR_RAN)); + + /* Set the controller to buffer entire packets */ + HW_CFG |= HW_CFG_SF; + + /* Configure FIFO thresholds */ + FIFO_INT = FIFO_INT_TDAL(0xff); + + /* Enable the MAC */ + val = smsc911x_mac_read(MAC_CR); + val |= (MAC_CR_TXEN | MAC_CR_RXEN); + smsc911x_mac_write(MAC_CR, val); + + TX_CFG |= TX_CFG_TX_ON; + + RX_CFG = 0; + + return 0; +} + +void +smsc911x_enable_multicast_reception(void) +{ + ulong val; + val = smsc911x_mac_read(MAC_CR); + val |= MAC_CR_MCPAS; + smsc911x_mac_write(MAC_CR, val); +} + +void +smsc911x_disable_multicast_reception(void) +{ + ulong val; + val = smsc911x_mac_read(MAC_CR); + val &= ~MAC_CR_MCPAS; + smsc911x_mac_write(MAC_CR, val); +} + +void +smsc911x_enable_promiscuous_reception(void) +{ + ulong val; + val = smsc911x_mac_read(MAC_CR); + val |= MAC_CR_PRMS; + smsc911x_mac_write(MAC_CR, val); +} + +void +smsc911x_disable_promiscuous_reception(void) +{ + ulong val; + val = smsc911x_mac_read(MAC_CR); + val &= ~MAC_CR_PRMS; + smsc911x_mac_write(MAC_CR, val); +} + +void +smsc911x_enable_broadcast_reception(void) +{ + ulong val; + val = smsc911x_mac_read(MAC_CR); + val |= MAC_CR_BCAST; + smsc911x_mac_write(MAC_CR, val); +} + +void +smsc911x_disable_broadcast_reception(void) +{ + ulong val; + val = smsc911x_mac_read(MAC_CR); + val &= ~MAC_CR_BCAST; + smsc911x_mac_write(MAC_CR, val); +} + + +//-------------------------------------------------------------------------- +// smsc911x_tx() +// +// This function transmits a packet +//-------------------------------------------------------------------------- +int smsc911x_tx(uchar *txbuf, ulong len) +{ + int avail; + ulong cmda; + ulong cmdb; + int i; + ulong *p; + vulong tmp __attribute__((unused)); + + tmp = TX_STATUS_FIFO_PORT; + + /* Wait until space is available for the packet */ + do { + avail = TX_FIFO_INF & TX_FIFO_TDFREE_MASK; + } while (avail < len); + + cmda = (TX_CMD_FS | + TX_CMD_LS | + TX_CMD_BS(len)); + + cmdb = TX_CMD_PKTLEN(len); + + TX_FIFO_PORT = cmda; + TX_FIFO_PORT = cmdb; + p = (ulong*)txbuf; + + for (i = 0; i < (len/4); i++) { + TX_FIFO_PORT = p[i]; + + } + + if ((len & 0x3) != 0) { + int index = len & ~3; + int num = len & 3; + ulong last = 0; + + for (i = 0; i < num; i++) { + last |= (txbuf[index + i] << (i * 8)); + } + + TX_FIFO_PORT = last; + } + + + return 0; +} + +//-------------------------------------------------------------------------- +// smsc911x_rx() +// +// This function checks to see if the smsc911x has a receive buffer +// ready. If so, it copies it into the buffer pointed to by pktbuf +//-------------------------------------------------------------------------- +int smsc911x_rx(uchar *pktbuf) +{ + ulong status; + int i; + int size; + ulong inf = RX_FIFO_INF; + ulong *p = (ulong *)pktbuf; + + if (((inf >> 16) & 0xffff) == 0) { + return 0; + } + + status = RX_STATUS_FIFO_PORT; + size = (status & RX_STATUS_PL_MASK) >> RX_STATUS_PL_SHIFT; + if (size == 0) { + return 0; + } + if ((status & RX_STATUS_ES) == 0) { + for (i = 0; i < ((size + 3) / 4); i++) { + p[i] = RX_FIFO_PORT; + } + + return size - 4; + } else { + /* Fast forward */ + if (size >= 16) { + RX_DP_CTL = RX_DP_RX_FFWD; + while (RX_DP_CTL & RX_DP_RX_FFWD) { + continue; + } + } else { + ulong tmp; + for (i = 0; i < ((size + 3)/4); i++) { + tmp = RX_FIFO_PORT; + } + tmp = tmp; // eliminate 'set-but-not-unused' warning + } + return 0; + } +} + + +#endif // INCLUDE_ETHERNET + diff --git a/main/dev/smsc911x.h b/main/dev/smsc911x.h new file mode 100644 index 0000000..64d5819 --- /dev/null +++ b/main/dev/smsc911x.h @@ -0,0 +1,304 @@ +//========================================================================== +// +// smsc911x.h +// +// +// Author(s): Jay Monkman <jtm@lopingdog.com> +// Contributors: +// Date: 06-07-2007 +// Description: This file contains definitions for the SMSC 911x and 912x +// families of ethernet controllers. +// +//-------------------------------------------------------------------------- + +// ------------------------------------------------------------------------ +// cpuio.h must provide SMSC911X_BASE_ADDRESS +// defines +#define SMSC_REG(_x_) *(vulong *)(SMSC911X_BASE_ADDRESS + _x_) + +// ------------------------------------------------------------------------ +// Directly visible registers. +#define RX_FIFO_PORT SMSC_REG(0x00) +#define TX_FIFO_PORT SMSC_REG(0x20) +#define RX_FIFO_PORT_INC SMSC_REG(0x100) +#define TX_FIFO_PORT_INC SMSC_REG(0x120) +#define RX_STATUS_FIFO_PORT SMSC_REG(0x40) +#define RX_STATUS_FIFO_PEEK SMSC_REG(0x44) +#define RX_STATUS_FF (1 << 30) +#define RX_STATUS_PL_MASK (0x3fff << 16) +#define RX_STATUS_PL_SHIFT (16) +#define RX_STATUS_ES (1 << 15) +#define RX_STATUS_BF (1 << 13) +#define RX_STATUS_LE (1 << 12) +#define RX_STATUS_RF (1 << 11) +#define RX_STATUS_MF (1 << 10) +#define RX_STATUS_FTL (1 << 7) +#define RX_STATUS_CS (1 << 6) +#define RX_STATUS_FT (1 << 5) +#define RX_STATUS_RWTO (1 << 4) +#define RX_STATUS_ME (1 << 3) +#define RX_STATUS_DB (1 << 2) +#define RX_STATUS_CE (1 << 1) + +#define TX_STATUS_FIFO_PORT SMSC_REG(0x48) +#define TX_STATUS_FIFO_PEEK SMSC_REG(0x4c) +#define TX_STATUS_FIFO_ES (1 << 15) +#define TX_STATUS_FIFO_LOC (1 << 11) +#define TX_STATUS_FIFO_NC (1 << 10) +#define TX_STATUS_FIFO_LC (1 << 9) +#define TX_STATUS_FIFO_EC (1 << 8) +#define TX_STATUS_FIFO_ED (1 << 2) +#define TX_STATUS_FIFO_UE (1 << 1) +#define TX_STATUS_FIFO_D (1 << 0) +#define TX_STATUS_FIFO_TAG_MASK (0xffff << 16) + +#define ID_REV SMSC_REG(0x50) +#define ID_REV_ID_MASK (0xffff << 16) +#define ID_REV_CHIP_9118 (0x0115 << 16) +#define ID_REV_CHIP_9211 (0x9211 << 16) +#define ID_REV_CHIP_9215 (0x115A << 16) +#define ID_REV_CHIP_9218 (0x118A << 16) +#define ID_REV_REV_MASK (0xffff << 0) + +#define INT_STS SMSC_REG(0x58) +#define INT_STS_SW_INT (1 << 21) +#define INT_STS_TXSTOP_INT (1 << 25) +#define INT_STS_RXSTOP_INT (1 << 24) +#define INT_STS_RXDFH_INT (1 << 23) +#define INT_STS_TIOC_INT (1 << 21) +#define INT_STS_RXD_INT (1 << 20) +#define INT_STS_GPT_INT (1 << 19) +#define INT_STS_PHY_INT (1 << 18) +#define INT_STS_PMT_INT (1 << 17) +#define INT_STS_TXSO_INT (1 << 16) +#define INT_STS_RWT_INT (1 << 15) +#define INT_STS_RXE_INT (1 << 14) +#define INT_STS_TXE_INT (1 << 13) +#define INT_STS_TDFU_INT (1 << 11) +#define INT_STS_TDFO_INT (1 << 10) +#define INT_STS_TDFA_INT (1 << 9) +#define INT_STS_TSFF_INT (1 << 8) +#define INT_STS_TSFL_INT (1 << 7) +#define INT_STS_RDXF_INT (1 << 6) +#define INT_STS_RDFL_INT (1 << 5) +#define INT_STS_RSFF_INT (1 << 4) +#define INT_STS_RSFL_INT (1 << 3) +#define INT_STS_GPIO2_INT (1 << 2) +#define INT_STS_GPIO1_INT (1 << 1) +#define INT_STS_GPIO0_INT (1 << 0) + +#define BYTE_TEST SMSC_REG(0x64) +#define BYTE_TEST_VAL (0x87654321) + +#define FIFO_INT SMSC_REG(0x68) +#define FIFO_INT_TDAL(x) (((x) & 0xff) << 24) +#define FIFO_INT_TSL(x) (((x) & 0xff) << 16) +#define FIFO_INT_RDAL(x) (((x) & 0xff) << 8) +#define FIFO_INT_RSL(x) (((x) & 0xff) << 0) + +#define RX_CFG SMSC_REG(0x6c) +#define RX_CFG_END_ALIGN4 (0 << 30) +#define RX_CFG_END_ALIGN16 (1 << 30) +#define RX_CFG_END_ALIGN32 (2 << 30) +#define RX_CFG_FORCE_DISCARD (1 << 15) +#define RX_CFG_RXDOFF(x) (((x) & 0x1f) << 8) + +#define TX_CFG SMSC_REG(0x70) +#define TX_CFG_TXS_DUMP (1 << 15) +#define TX_CFG_TXD_DUMP (1 << 14) +#define TX_CFG_TXSAO (1 << 2) +#define TX_CFG_TX_ON (1 << 1) +#define TX_CFG_STOP_TX (1 << 0) + +#define HW_CFG SMSC_REG(0x74) +#define HW_CFG_TTM (1 << 21) +#define HW_CFG_SF (1 << 20) +#define HW_CFG_TX_FIF_SZ(x) (((x) & 0xf) << 16) +#define HW_CFG_TX_FIF_MASK (0xf << 16) +#define HW_CFG_TR(x) (((x) & 0x3) << 12) +#define HW_CFG_PHY_CLK_MASK (3 << 5) +#define HW_CFG_PHY_CLK_INT (0 << 5) +#define HW_CFG_PHY_CLK_EXT (1 << 5) +#define HW_CFG_PHY_CLK_DIS (2 << 5) +#define HW_CFG_SMI_SEL (1 << 3) +#define HW_CFG_EXT_PHY_EN (1 << 2) +#define HW_CFG_BITMD_32 (1 << 2) +#define HW_CFG_SRST_TO (1 << 1) +#define HW_CFG_SRST (1 << 0) + +#define RX_DP_CTL SMSC_REG(0x78) +#define RX_DP_RX_FFWD (1 << 31) + +#define RX_FIFO_INF SMSC_REG(0x7c) +#define TX_FIFO_RXSUSED_MASK (0x00ff << 16) +#define TX_FIFO_RXDUSED_MASK (0xffff << 0) + +#define TX_FIFO_INF SMSC_REG(0x80) +#define TX_FIFO_TXSUSED_MASK (0x00ff << 16) +#define TX_FIFO_TDFREE_MASK (0xffff << 0) + +#define PMT_CTRL SMSC_REG(0x84) +#define PMT_CTRL_PM_MODE_D0 (0 << 12) +#define PMT_CTRL_PM_MODE_D1 (1 << 12) +#define PMT_CTRL_PM_MODE_D2 (2 << 12) +#define PMT_CTRL_PHY_RST (1 << 10) +#define PMT_CTRL_WOL_EN (1 << 9) +#define PMT_CTRL_ED_EN (1 << 8) +#define PMT_CTRL_PME_TYPE (1 << 6) +#define PMT_CTRL_WUPS_NONE (0 << 4) +#define PMT_CTRL_WUPS_D2 (1 << 4) +#define PMT_CTRL_WUPS_D1 (2 << 4) +#define PMT_CTRL_WUPS_MULT (3 << 4) +#define PMT_CTRL_PME_IND (1 << 3) +#define PMT_CTRL_PME_POL (1 << 2) +#define PMT_CTRL_PME_EN (1 << 1) +#define PMT_CTRL_PME_READY (1 << 0) + +#define GPIO_CFG SMSC_REG(0x88) +#define GPIO_CFG_LED3_EN (1 << 30) +#define GPIO_CFG_LED2_EN (1 << 29) +#define GPIO_CFG_LED1_EN (1 << 28) +#define GPIO_CFG_GPIO_INT_POL(x) (1 << (((x) & 0x3) + 24)) +#define GPIO_CFG_EEPR_EEPROM (0 << 20) +#define GPIO_CFG_GPIOBUF(x) (1 << (((x) & 0x3) + 16)) +#define GPIO_CFG_GPIODIR(x) (1 << (((x) & 0x3) + 8)) + +#define GPT_CFG SMSC_REG(0x8c) +#define GPT_CFG_TIMER_EN (1 << 29) +#define GPT_CFG_GPT_LOAD(x) (((x) & 0xffff) << 0) + +#define GPT_CNT SMSC_REG(0x90) +#define GPT_CNT_MASK (0xffff << 0) + +#define WORD_SWAP SMSC_REG(0x98) +#define WORD_SWAP_BIG (0xFFFFFFFF) + +#define FREE_RUN SMSC_REG(0x9c) + +#define RX_DROP SMSC_REG(0xa0) + +#define MAC_CSR_CMD SMSC_REG(0xa4) +#define MAC_CSR_CMD_CSR_BUSY (0x80000000) +#define MAC_CSR_CMD_RNW (0x40000000) +#define MAC_RD_CMD(x) (((x) & 0xff) | (MAC_CSR_CMD_CSR_BUSY |\ + MAC_CSR_CMD_RNW)) +#define MAC_WR_CMD(x) (((x) & 0xff) | (MAC_CSR_CMD_CSR_BUSY)) + +#define MAC_CSR_DATA SMSC_REG(0xa8) + +#define AFC_CFG SMSC_REG(0xac) +#define AFC_CFG_AFC_HI(x) (((x) & 0xff) << 16) +#define AFC_CFG_AFC_LO(x) (((x) & 0xff) << 8) +#define AFC_CFG_BACK_DUR(x) (((x) & 0xf) << 4) +#define AFC_CFG_FCMULT (1 << 3) +#define AFC_CFG_FCBRD (1 << 2) +#define AFC_CFG_FCADD (1 << 1) +#define AFC_CFG_FCANY (1 << 0) + +#define E2P_CMD SMSC_REG(0xb0) +#define E2P_DATA SMSC_REG(0xb4) + +// ---------------------------------------------------------- +// Registers available via MAC_CSR_CMD/MAC_CSR_DATA registers +#define MAC_CR (0x1) +#define MAC_CR_RXALL (1 << 31) +#define MAC_CR_RCVOWN (1 << 23) +#define MAC_CR_LOOPBK (1 << 21) +#define MAC_CR_FDPX (1 << 20) +#define MAC_CR_MCPAS (1 << 18) +#define MAC_CR_PRMS (1 << 18) +#define MAC_CR_INVFILT (1 << 17) +#define MAC_CR_PASSBAD (1 << 16) +#define MAC_CR_HO (1 << 15) +#define MAC_CR_HPFILT (1 << 13) +#define MAC_CR_LCOLL (1 << 12) +#define MAC_CR_BCAST (1 << 11) +#define MAC_CR_DISRTY (1 << 10) +#define MAC_CR_PADSTR (1 << 8) +#define MAC_CR_BOLMT10 (0 << 6) +#define MAC_CR_BOLMT8 (1 << 6) +#define MAC_CR_BOLMT4 (2 << 6) +#define MAC_CR_BOLMT1 (3 << 6) +#define MAC_CR_DFCHK (1 << 5) +#define MAC_CR_TXEN (1 << 3) +#define MAC_CR_RXEN (1 << 2) + +#define ADDRH (0x2) +#define ADDRL (0x3) +#define HASHH (0x4) +#define HASHL (0x5) + +#define MII_ACC (0x6) +#define MII_ACC_ADDR(x) (((x) & 0x1f) << 11) +#define MII_ACC_REG(x) (((x) & 0x1f) << 6) +#define MII_ACC_WR (1 << 1) +#define MII_ACC_BUSY (1 << 0) + +#define MII_DATA (0x7) +#define FLOW (0x8) +#define VLAN1 (0x9) +#define VLAN2 (0xa) +#define WUFF (0xb) +#define WUCSR (0xc) + +// ---------------------------------------------------------- +// PHY Registers +#define PHY_BCR 0 +#define PHY_BCR_RESET (1 << 15) +#define PHY_BCR_LOOP (1 << 14) +#define PHY_BCR_SPEED (1 << 13) +#define PHY_BCR_ANE (1 << 12) +#define PHY_BCR_PD (1 << 11) +#define PHY_BCR_RAN (1 << 9) +#define PHY_BCR_FD (1 << 8) +#define PHY_BCR_CT (1 << 7) + +#define PHY_BSR 1 +#define PHY_PHY1 2 +#define PHY_PHY2 3 +#define PHY_ANAR 4 +#define PHY_ANAR_NP (1 << 15) +#define PHY_ANAR_RF (1 << 13) +#define PHY_ANAR_PAUSE(x) (((x) & 0x3) << 10) +#define PHY_ANAR_100T4 (1 << 9) +#define PHY_ANAR_100TX_FD (1 << 8) +#define PHY_ANAR_100TX (1 << 7) +#define PHY_ANAR_10T_FD (1 << 6) +#define PHY_ANAR_10T (1 << 5) +#define PHY_ANAR_SF (0x01) + + +#define PHY_ANLPAR 5 +#define PHY_ANER 6 +#define PHY_MCSR 17 +#define PHY_SMR 18 +#define PHY_SCSI 27 +#define PHY_ISR 29 +#define PHY_IMR 30 +#define PHY_PSCSR 31 + + +// ---------------------------------------------------------- +// TX and RX command definitions +#define TX_CMD_IC (1 << 31) +#define TX_CMD_BEA(x) (((x) & 0x3) << 24) +#define TX_CMD_DS(x) (((x) & 0x1f) << 16) +#define TX_CMD_FS (1 << 13) +#define TX_CMD_LS (1 << 12) +#define TX_CMD_BS(x) (((x) & 0x7ff) << 0) +#define TX_CMD_TAG(x) (((x) & 0xffff) << 16) +#define TX_CMD_CRCDIS (1 << 13) +#define TX_CMD_PKTLEN(x) (((x) & 0x7ff) << 0) + + + +void smsc911x_reset(void); +int smsc911x_rx(uchar *); +int smsc911x_tx(uchar *, ulong); +int smsc911x_init(void); +void smsc911x_enable_promiscuous_reception(void); +void smsc911x_disable_promiscuous_reception(void); +void smsc911x_enable_multicast_reception(void); +void smsc911x_disable_multicast_reception(void); +void smsc911x_enable_broadcast_reception(void); +void smsc911x_disable_broadcast_reception(void); diff --git a/main/dev/uart16550.c b/main/dev/uart16550.c new file mode 100644 index 0000000..0326d7a --- /dev/null +++ b/main/dev/uart16550.c @@ -0,0 +1,195 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * FILENAME_HERE + * + * Generic (hopefully) 16550 uart code for use as a MicroMonitor + * console serial port driver. + * + * The baud-rate divisor can be derived in one of two ways: + * If BRD_115200 is defined, then this code assumes that the full + * set of BRD_XXX definitions are defined (in config.h) and they + * are used. If BRD_115200 is not defined, then this driver assumes + * the getUartDivisor() function is externally provided by the + * port-specific code. + * + * The base address of the UART used as the console port must be + * defined as CONSOLE_UART_BASE (also in config.h). + * + * Also, if the uart is configured in the memory map such that the + * gap between registers is not 1, then set SIO_STEP (see uart16550.h) + * to 2 or 4 appropriately. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "uart16550.h" + + +#define CONSOLE(offset) *(volatile unsigned char *)(CONSOLE_UART_BASE+offset) + +#ifdef MORE_GOTACHAR +extern void MORE_GOTACHAR(); +#endif +#ifdef MORE_GETCHAR +extern void MORE_GETCHAR(); +#endif +#ifdef MORE_PUTCHAR +extern void MORE_PUTCHAR(); +#endif + +/* Establish default initialization values that can be overridden + * in config.h: + */ +#ifndef MCTL_DEFAULT +#define MCTL_DEFAULT (SIO_MCTL_DTR | SIO_MCTL_RTS) +#endif +#ifndef FCTL_DEFAULT +#define FCTL_DEFAULT (SIO_FCTL_FEN | SIO_FCTL_RXDC | SIO_FCTL_TXDC) +#endif +#ifndef SPR_DEFAULT +#define SPR_DEFAULT 0x00 // Clear scratchpad +#endif +#ifndef IEN_DEFAULT +#define IEN_DEFAULT 0x00 // Ints used +#endif +#ifndef LCTL_DEFAULT +#define LCTL_DEFAULT SIO_LCTL_W8 +#endif + +/* getDlLsb(): + * Populate hi & lo, default to 9600... + */ +#ifdef BRD_115200 +int +getUartDivisor(int baud, unsigned char *hi, unsigned char *lo) +{ + switch(baud) { + case 115200: + *lo = BRD_115200; + break; + case 57600: + *lo = BRD_57600; + break; + case 38400: + *lo = BRD_38400; + break; + case 19200: + *lo = BRD_19200; + break; + case 9600: + *lo = BRD_9600; + break; + default: + return(-1); + } + *hi = 0; + return(0); +} +#endif + +int +ConsoleBaudSet(int baud) +{ + unsigned char tmp, hi, lo; + + /* If either getDivisor returns -1 or both hi & lo are zero we + * return failure to indicate that the requested baud rate could + * not be established. + */ + if (getUartDivisor(baud,&hi,&lo) == -1) + return(-1); + if ((hi == 0) && (lo == 0)) + return(-1); + + tmp = CONSOLE(SIO_LCTL); /* Save linectl reg */ + CONSOLE(SIO_LCTL) = SIO_LCTL_DLAB; + CONSOLE(SIO_BAUDLO) = lo; /* Set baud */ + CONSOLE(SIO_BAUDHI) = hi; + CONSOLE(SIO_LCTL) = tmp; /* Restore linectl reg */ + return(0); +} + + +void +InitUART(int baud) +{ + unsigned char tmp, hi, lo; + + getUartDivisor(baud,&hi,&lo); + + CONSOLE(SIO_LCTL) = SIO_LCTL_DLAB; + CONSOLE(SIO_BAUDLO) = lo; /* Set baud */ + CONSOLE(SIO_BAUDHI) = hi; + CONSOLE(SIO_LCTL) = LCTL_DEFAULT; /* 8-bits, no parity */ + CONSOLE(SIO_MCTL) = MCTL_DEFAULT; + tmp = CONSOLE(SIO_LSTAT); /* clear line stat */ + tmp = CONSOLE(SIO_RXD); /* read receive buffer */ + tmp = tmp; /* eliminate unused warning */ + CONSOLE(SIO_IEN) = IEN_DEFAULT; + CONSOLE(SIO_FCTL) = FCTL_DEFAULT; + CONSOLE(SIO_SPR) = SPR_DEFAULT; +} + +int +target_console_empty(void) +{ + if (CONSOLE(SIO_LSTAT) & SIO_LSTAT_TRDY) + return(0); + return(1); +} + +int +target_putchar(char c) +{ + while(!(CONSOLE(SIO_LSTAT) & SIO_LSTAT_TRDY)); + CONSOLE(SIO_TXD) = c; +#ifdef MORE_PUTCHAR + MORE_PUTCHAR(c); +#endif + return((int)c); +} + +int +target_getchar(void) +{ + char c; + +#ifdef MORE_GETCHAR + if (MORE_GOTACHAR()) + c = MORE_GETCHAR(); + else +#endif + c = CONSOLE(SIO_RXD); + return((int)c); +} + +int +target_gotachar(void) +{ + if (CONSOLE(SIO_LSTAT) & SIO_LSTAT_RRDY) + return(1); +#ifdef MORE_GOTACHAR + if (MORE_GOTACHAR()) + return(1); +#endif + return(0); +} diff --git a/main/dev/uart16550.h b/main/dev/uart16550.h new file mode 100644 index 0000000..3700445 --- /dev/null +++ b/main/dev/uart16550.h @@ -0,0 +1,137 @@ +/************************************************************************** + * + * Copyright (c) 2013 Alcatel-Lucent + * + * Alcatel Lucent licenses this file to You under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. A copy of the License is contained the + * file LICENSE at the top level of this repository. + * You may also obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ************************************************************************** + * + * uart16550.h + * + * Defines for standard Dual Uart + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ + +// If other than 1, SIO_STEP must be defined in config.h +#ifndef SIO_STEP +#define SIO_STEP 1 +#endif + +// register defines +#define SIO_RXD (0 * SIO_STEP) // receive data, read, dlab = 0 +#define SIO_TXD (0 * SIO_STEP) // transmit data, write, dlab = 0 +#define SIO_BAUDLO (0 * SIO_STEP) // baud divisor 0-7, read/write, dlab = 1 +#define SIO_IEN (1 * SIO_STEP) // interrupt enable, read/write, dlab = 0 +#define SIO_BAUDHI (1 * SIO_STEP) // baud divisor 8-15, read/write, dlab = 1 +#define SIO_ISTAT (2 * SIO_STEP) // interrupt status, read, dlab = 0 +#define SIO_FCTL (2 * SIO_STEP) // fifo control, write, dlab = 0 +#define SIO_AFR (2 * SIO_STEP) // alt function reg, read/write, dlab = 1 +#define SIO_LCTL (3 * SIO_STEP) // line control, read/write +#define SIO_MCTL (4 * SIO_STEP) // modem control read/write +#define SIO_LSTAT (5 * SIO_STEP) // line status read +#define SIO_MSTAT (6 * SIO_STEP) // modem status read +#define SIO_SPR (7 * SIO_STEP) // scratch pad register + +// interrupt enable register bit defines +#define SIO_IEN_RXD 0x01 // enable int on rcv holding reg full +#define SIO_IEN_TXD 0x02 // enable int on xmt holding reg empty +#define SIO_IEN_LSTAT 0x04 // enable int on line status reg state change +#define SIO_IEN_MSTAT 0x08 // enable int on modem status reg state change + +// interrupt status register bit defines +#define SIO_ISTAT_PEND 0x01 // 0 = interrupt pending +#define SIO_ISTAT_MASK 0x0e // mask for interrupt ID bits +#define SIO_ISTAT_INT 0x0F // bits 0-3 describe current highest priority + // interrupt pending. They can be used to + // vector to the correct routine. + // The codes are as follows: +#define SIO_ISTAT_MI 0x00 // Modem Status Register interrupt +#define SIO_ISTAT_TI 0x02 // Transmit Holding Register Empty interrupt +#define SIO_ISTAT_RI 0x04 // Receive Holding Register Ready interrupt +#define SIO_ISTAT_LI 0x06 // Line Status Register interrupt +#define SIO_ISTAT_FI 0x0C // Rcv Holding Register Fifo Timeout interrupt + +// fifo control register bit defines +#define SIO_FCTL_FEN 0x01 // 1 = fifo operation enabled +#define SIO_FCTL_RXDC 0x02 // 1 = clear rxd fifo and reset counter, + // returns to 0 automatically +#define SIO_FCTL_TXDC 0x04 // 1 = clear txd fifo and reset counter, + // returns to 0 automatically +#define SIO_FCTL_MODE 0x08 // set txrdy and rxrdy modes, unused + + // Bits 6 and 7 set the desired fifo trigger + // level as follows: +#define SIO_FCTL_T1 0x00 // 00 = trigger when 1 character in fifo +#define SIO_FCTL_T4 0x40 // 01 = trigger when 4 characters in fifo +#define SIO_FCTL_T8 0x80 // 10 = trigger when 8 characters in fifo +#define SIO_FCTL_T14 0xC0 // 11 = trigger when 14 characters in fifo + +// line control register bit defines + // bits 0 and 1 set the word length as follows: +#define SIO_LCTL_W5 0x00 // 00 = 5 +#define SIO_LCTL_W6 0x01 // 01 = 6 +#define SIO_LCTL_W7 0x02 // 10 = 7 +#define SIO_LCTL_W8 0x03 // 11 = 8 + +#define SIO_LCTL_STOP 0x04 // 0 = 1 stop bit, 1 = 1.5 stop bits if + // word length is 5, 2 otherwise +#define SIO_LCTL_PAR 0x08 // 0 = no parity enabled, 1 = parity enabled +#define SIO_LCTL_EVEN 0x10 // 0 = odd parity, 1 = even parity, + // if parity is enabled +#define SIO_LCTL_FRC 0x20 // 0 = force parity bit to 1, + // 1 = force to 0, if parity is enabled +#define SIO_LCTL_BRK 0x40 // 1 = send continuous break +#define SIO_LCTL_DLAB 0x80 // 1 = select baud and alt function registers + +// modem control register bit defines +#define SIO_MCTL_DTR 0x01 // 0 = set DTR output = 0, + // 1 = set DTR = 1, unused +#define SIO_MCTL_RTS 0x02 // 0 = set RTS output = 0, + // 1 = set RTS = 1, channel A only +#define SIO_MCTL_OP2 0x08 // 0 = set OP2 output = 0, + // 1 = set OP2 = 1, unused +#define SIO_MCTL_LB 0x10 // 0 = normal operation, + // 1 = loopback mode + +// line status register bit defines +#define SIO_LSTAT_RRDY 0x01 // 1 = receive register ready +#define SIO_LSTAT_OVER 0x02 // 1 = receive overrun error +#define SIO_LSTAT_PERR 0x04 // 1 = receive parity error +#define SIO_LSTAT_FRAM 0x08 // 1 = receive framing error +#define SIO_LSTAT_BRK 0x10 // 1 = receive break +#define SIO_LSTAT_TRDY 0x20 // 1 = transmit hold register empty +#define SIO_LSTAT_TEMTY 0x40 // 1 = transmit register empty +#define SIO_LSTAT_ERR 0x80 // 1 = any error condition + +// modem status register bit defines +#define SIO_MSTAT_CTS 0x01 // 1 = CTS state has changed, channel A only +#define SIO_MSTAT_DSR 0x02 // 1 = DSR state has changed, unused +#define SIO_MSTAT_RI 0x04 // 1 = RI state has changed, unused +#define SIO_MSTAT_CD 0x08 // 1 = CD state has changed, unused +#define SIO_MSTAT_RTS 0x10 // reflects RTS bit during loopback, chA only +#define SIO_MSTAT_DTR 0x20 // reflects DTR bit during loopback, unused +#define SIO_MSTAT_OP1 0x40 // reflects OP1 bit during loopback, unused +#define SIO_MSTAT_OP2 0x80 // reflects OP2 bit during loopback, unused + +extern void InitUART(int baud); +extern int ConsoleBaudSet(int baud); +extern int target_getchar(void); +extern int target_gotachar(void); +extern int target_putchar(char c); +extern int target_console_empty(void); +extern int getUartDivisor(int baud,unsigned char *hi, unsigned char *lo); + diff --git a/main/dev/vga_lookup.h b/main/dev/vga_lookup.h new file mode 100644 index 0000000..6c280b2 --- /dev/null +++ b/main/dev/vga_lookup.h @@ -0,0 +1,51 @@ +//========================================================================== +// +// vga_lookup.h +// +// Author(s): Michael Kelly, Cogent Computer Systems, Inc. +// Contributors: +// Date: 03/06/2005 +// Description: This file contains vga color lookup + +// 16-bit pixels are RGB 565 - LSB of RED and BLUE are tied low at the +// LCD Interface, while the LSB of GREEN is loaded as 0 +#define RED_SUBPIXEL(n) (n & 0x1f) << 11 +#define GREEN_SUBPIXEL(n) (n & 0x1f) << 6 +#define BLUE_SUBPIXEL(n) (n & 0x1f) << 0 + +// define a simple VGA style 16-color pallette +#define LU_BLACK RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00) +#define LU_BLUE RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00) +#define LU_GREEN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x00) +#define LU_CYAN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x0f) +#define LU_RED RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00) +#define LU_VIOLET RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x0f) +#define LU_YELLOW RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x00) +#define LU_GREY RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x0f) +#define LU_WHITE RED_SUBPIXEL(0x17) | GREEN_SUBPIXEL(0x17) | BLUE_SUBPIXEL(0x17) +#define LU_BRT_BLUE RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x1f) +#define LU_BRT_GREEN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x00) +#define LU_BRT_CYAN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f) +#define LU_BRT_RED RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00) +#define LU_BRT_VIOLET RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x1f) +#define LU_BRT_YELLOW RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f) +#define LU_BRT_WHITE RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f) + +const static unsigned short vga_lookup[] = { +LU_BLACK, +LU_BLUE, +LU_GREEN, +LU_CYAN, +LU_RED, +LU_VIOLET, +LU_YELLOW, +LU_GREY, +LU_WHITE, +LU_BRT_BLUE, +LU_BRT_GREEN, +LU_BRT_CYAN, +LU_BRT_RED, +LU_BRT_VIOLET, +LU_BRT_YELLOW, +LU_BRT_WHITE +}; diff --git a/main/flash/README b/main/flash/README new file mode 100644 index 0000000..f870647 --- /dev/null +++ b/main/flash/README @@ -0,0 +1,16 @@ +devices: + Each .c file represents one configuration of one particular flash + device. These files can be used standalone or mixed, depending on + the configuration of the board. Refer to devices/README for full + details. + Not all driver files have been updated to conform with uMon1.0. + The easiest way to determine if the driver has been updated to + uMon1.0 is to look at the relocatable xxx_lock() function. If + it supports the FLASH_LOCKABLE operation properly, then it has + been updated to be uMon1.0 compatible. + +Note that several of these drivers may need updating. +Especially notable is the need for the WATCHDOG_MACRO to be inserted +in strategic points within the driver. Obviously this will only be +needed if the hardware runs with a watchdog. + diff --git a/main/flash/devices/s29gl512n_16x1.c b/main/flash/devices/s29gl512n_16x1.c new file mode 100644 index 0000000..cbe28c4 --- /dev/null +++ b/main/flash/devices/s29gl512n_16x1.c @@ -0,0 +1,763 @@ +/* s29gl512n_16x1.c + * Device interface for Spansion S29GL512N flash device configured for + * x16 mode with 1 device in parallel. + * The device contains 512 128Kbyte sectors. + * There are four different memory configurations that this driver + * handles: + * 1. A single S29GL512N_16x1 device + * 2. Piggybacked S29GL512N_16x1 devices (2 devices). + * 3. 70GL01GN: 2 S29GL512N_16x1 devices in one package. + * 4. GL01GP: This is a single device with double the density of the + * S29GL512N_16x1 device. + */ +#include "config.h" + +#if INCLUDE_FLASH + +#define WRITE_BUFFER_SIZE 32 +#define WRITE_BUFFER_ADDR_MASK (~(WRITE_BUFFER_SIZE-1)) + +#include "stddefs.h" +#include "genlib.h" +#include "cpu.h" +#include "cpuio.h" +#include "flash.h" /* Part of monitor common code */ +#include "s29gl512n_16x1.h" + +#define ftype volatile unsigned short +#define Is_ff(add) (*(ftype *)add == 0xffff) +#define Is_not_ff(add) (*(ftype *)add != 0xffff) +#define Is_Equal(p1,p2) (*(ftype *)p1 == *(ftype *)p2) +#define Is_Equal_d7(p1,p2) ((*(ftype *)p1&0x80) == (*(ftype *)p2&0x80)) +#define Is_Not_Equal(p1,p2) (*(ftype *)p1 != *(ftype *)p2) +#define Is_Not_Equal_d7(p1,p2) ((*(ftype *)p1&0x80) != (*(ftype *)p2&0x80)) +#define Fwrite(to,frm) (*(ftype *)to = *(ftype *)frm) +#define D5_Timeout(add) ((*(ftype *)(add) & 0x0020) == 0x0020) + +#define SECTOR_TOTAL (512*2) +#define SECTOR_SIZE 0x20000 +#define SPANSION_29GL512N_ID 0x00012223 +#define SPANSION_29GL1024N_ID 0x00012228 + +#define D6 0x0040 +#define D5 0x0020 +#define D3 0x0008 + +#define SECTOR_ERASE(add) { \ + *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa; \ + *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055; \ + *(ftype *)((fdev->base+(0x555<<1))) = 0x0080; \ + *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa; \ + *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055; \ + *(ftype *)(add) = 0x0030; } + + +#define FLASH_WRITE(dest,src) { \ + *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa; \ + *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055; \ + *(ftype *)((fdev->base+(0x555<<1))) = 0x00a0; \ + Fwrite((ftype *)(dest),src); } + +#define AUTO_SELECT() { \ + *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa; \ + *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055; \ + *(ftype *)((fdev->base+(0x555<<1))) = 0x0090; } + +#define READ_RESET() { \ + ftype val; \ + *(ftype *)(fdev->base) = 0x00f0; \ + val = *(ftype *)(fdev->base); \ + val = val; } // eliminate "variable unused warning" + +#define WHILE_D6_TOGGLES(a) \ + while ((*(ftype *)(a) & D6) != (*(ftype *)(a) & D6)) + + +/* S29gl512n_16x1_erase(): + * Based on the 'snum' value, erase the appropriate sector(s). + * Return 0 if success, else -1. + */ +int +S29gl512n_16x1_erase(struct flashinfo *fdev,int snum) +{ + ulong add; + int ret; + + ret = 0; + add = (ulong)(fdev->sectors[snum].begin); + + + SECTOR_ERASE(add); + + /* Wait for sector erase to complete or timeout.. + * DQ7 polling: wait for D7 to be 1. + * DQ6 toggling: wait for D6 to not toggle. + * DQ5 timeout: if DQ7 is 0, and DQ5 = 1, timeout. + */ + while(1) { + WATCHDOG_MACRO; + if (*(ftype *)(add) == 0xffff) { + if (*(ftype *)(add) == 0xffff) + break; + } + if (D5_Timeout(add)) { + if (*(ftype *)(add) != 0xffff) + ret = -1; + break; + } + } + + /* If the erase failed for some reason, then issue the read/reset + * command sequence prior to returning... + */ + if (ret == -1) + READ_RESET(); + + return(ret); +} + +/* EndS29gl512n_16x1_erase(): + * Function place holder to determine the end of the above function. + */ +void +EndS29gl512n_16x1_erase(void) +{ +} + +#ifdef BUFFERED_WRITE + +/* S29gl512n_16x1_write(): + * Copy specified number of bytes from source to destination. The destination + * address is assumed to be flash space. + */ +int +S29gl512n_16x1_write(struct flashinfo *fdev, + uchar *dest,uchar *src,long bytecnt) +{ + ftype val; + int i, ret; + ulong cnt; + uchar *src1; + + ret = 0; + src1 = (uchar *)&val; + + /* Since we are working on a 2-byte wide device, every write to the + * device must be aligned on a 2-byte boundary. If our incoming + * destination address is odd, then decrement the destination by one + * and build a fake source using *dest-1 and src[0]... + */ + if (((ulong)dest)&1) { + dest--; + + src1[0] = *dest; + src1[1] = *src; + + FLASH_WRITE(dest,src1); + + /* Wait for write to complete or timeout. */ + while(1) { + if (Is_Equal_d7(dest,src1)) { + if (Is_Equal_d7(dest,src1)) + break; + } + /* Check D5 for timeout... */ + if (D5_Timeout(dest)) { + if (Is_Not_Equal_d7(dest,src1)) { + ret = -1; + goto done; + } + break; + } + } + + dest += 2; + src++; + bytecnt--; + } + + /* Now determine how many whole words can be written to the destination. + * We try to take advantage of buffer writes. + */ + for(cnt=bytecnt; cnt>1; ) { + ulong tmpLen; + uchar buf[WRITE_BUFFER_SIZE]; + tmpLen=(((ulong)dest&WRITE_BUFFER_ADDR_MASK)+WRITE_BUFFER_SIZE)- + (ulong)dest; + if (tmpLen > cnt) { + tmpLen=cnt; + } + if (tmpLen&1) { + tmpLen--; + } + /* Because the source might be the flash itself, first copy the + * bytes to a RAM-based buffer just to be safe. + */ + for(i=0; i<tmpLen; ++i) { + buf[i]=src[i]; + } + + /* Buffered write... + */ + { + long b_cnt; + int i, rc; + uchar *b_src, *saddr, *eaddr; + + rc = 0; + b_src = buf; + saddr = dest; + b_cnt = tmpLen; + eaddr = saddr + b_cnt - 1; + + if (!b_cnt) return 0; + + if (((ulong)eaddr&WRITE_BUFFER_ADDR_MASK) != + ((ulong)saddr&WRITE_BUFFER_ADDR_MASK)) { + /* Overall buffer straddles a boundary */ + return -1; + } + + if (b_cnt&1) { + ret = -1; + goto done; + } + + *(ftype *)(fdev->base+(0x555<<1)) = 0x00aa; + *(ftype *)(fdev->base+(0x2aa<<1)) = 0x0055; + *(ftype *)(saddr) = 0x0025; + *(ftype *)(saddr) = (b_cnt/2)-1; + + for(i=0; i<b_cnt/2; i++) { + Fwrite(saddr,b_src); + saddr+=2; + b_src+=2; + } + /* We'll poll the last adress that was written */ + saddr-=2; + b_src-=2; + + *(ftype *)(saddr) = 0x0029; + + /* Wait for write to complete or timeout. */ + while(1) { + if (Is_Equal_d7(saddr,b_src)) { + if (Is_Equal_d7(saddr,b_src)) + break; + } + /* Check D5 for timeout... */ + if (D5_Timeout(saddr)) { + if (Is_Not_Equal_d7(saddr,b_src)) { + if (*(ftype *)saddr & 0x2) { + /* Reset the operation */ + *(ftype *)(fdev->base+(0x555<<1)) = 0x00aa; + *(ftype *)(fdev->base+(0x2aa<<1)) = 0x0055; + *(ftype *)(fdev->base+(0x555<<1)) = 0x00F0; + } + ret = -1; + goto done; + } + break; + } + } + + if (rc) { + READ_RESET(); + } + //return rc; + } + + dest+=tmpLen; + src+=tmpLen; + cnt-=tmpLen; + } + + /* We still have to deal with the possibility that there might be a trailing + * byte that might have to be written + */ + if (cnt) { + /* One additional byte left */ + src1[0] = *src; + src1[1] = dest[1]; + + FLASH_WRITE(dest,src1); + + /* Wait for write to complete or timeout. */ + while(1) { + if (Is_Equal_d7(dest,src1)) { + if (Is_Equal_d7(dest,src1)) + break; + } + /* Check D5 for timeout... */ + if (D5_Timeout(dest)) { + if (Is_Not_Equal_d7(dest,src1)) { + ret = -1; + goto done; + } + break; + } + } + } + +done: + if (ret) { + READ_RESET(); + } + return(ret); +} + +#else + +/* S29gl512n_16x1_write(): + * Copy specified number of bytes from source to destination. The destination + * address is assumed to be flash space. + */ +int +S29gl512n_16x1_write(struct flashinfo *fdev, + uchar *dest,uchar *src,long bytecnt) +{ + ftype val; + int cnt, ret; + uchar *src1; + + ret = 0; + cnt = bytecnt & ~1; + src1 = (uchar *)&val; + + /* Since we are working on a 2-byte wide device, every write to the + * device must be aligned on a 2-byte boundary. If our incoming + * destination address is odd, then decrement the destination by one + * and build a fake source using *dest-1 and src[0]... + */ + if (NotAligned16(dest)) { + dest--; + + src1[0] = *dest; + src1[1] = *src; + + FLASH_WRITE(dest,src1); + + /* Wait for write to complete or timeout. */ + while(1) { + WATCHDOG_MACRO; + + if (*(ftype *)(dest) == *(ushort *)src1) { + if (*(ftype *)(dest) == *(ushort *)src1) + break; + } + /* Check D5 for timeout... */ + if (D5_Timeout(dest)) { + if (*(ftype *)(dest) != *(ushort *)src1) { + ret = -1; + goto done; + } + break; + } + } + + dest += 2; + src++; + bytecnt--; + } + + /* Each pass through this loop writes 'fdev->width' bytes... + */ + + while (bytecnt >= fdev->width) { + + /* Just in case src is not aligned... */ + src1[0] = src[0]; + src1[1] = src[1]; + + + FLASH_WRITE(dest,src1); + + /* Wait for write to complete or timeout. */ + while(1) { + WATCHDOG_MACRO; + + if (*(ftype *)(dest) == *(ushort *)src1) { + if (*(ftype *)(dest) == *(ushort *)src1) + break; + } + /* Check D5 for timeout... */ + if (D5_Timeout(dest)) { + if (*(ftype *)(dest) != *(ushort *)src1) { + ret = -1; + goto done; + } + break; + } + } + dest += fdev->width; + src += fdev->width; + bytecnt -= 2; + } + + /* Similar to the front end of this function, if the byte count is not + * even, then we have one byte left to write, so we need to write a + * 16-bit value by writing the last byte, plus whatever is already in + * the next flash location. + */ + if (bytecnt) { + src1[0] = *src; + src1[1] = dest[1]; + + + FLASH_WRITE(dest,src1); + + /* Wait for write to complete or timeout. */ + while(1) { + WATCHDOG_MACRO; + if (*(ftype *)(dest) == *(ushort *)src1) { + if (*(ftype *)(dest) == *(ushort *)src1) + break; + } + /* Check D5 for timeout... */ + if (D5_Timeout(dest)) { + if (*(ftype *)(dest) != *(ushort *)src1) { + ret = -1; + goto done; + } + break; + } + } + } + +done: + READ_RESET(); + + return(ret); +} +#endif + +/* EndS29gl512n_16x1_write(): + * Function place holder to determine the end of the above function. + */ +void +EndS29gl512n_16x1_write(void) +{} + +/* S29gl512n_16x1_ewrite(): + * Erase all sectors that are part of the address space to be written, + * then write the data to that address space. + * This function is optimized for speed by using the write buffer and + * erase delay timer. It assumes the incoming destination address is + * aligned on a 32-byte boundary and that the bytecount will be even. + */ +int +S29gl512n_16x1_ewrite(struct flashinfo *fdev, + uchar *dest,uchar *src,long bytecnt) +{ + int i; + ulong add; + + add = (ulong)(fdev->base); + + /* For each sector, if it overlaps any of the destination space + * then erase that sector. + */ + for (i=0;i<fdev->sectorcnt;i++) { + long size; + long *begin, *end; + struct sectorinfo *sip; + + sip = &(fdev->sectors[i]); + begin = (long *)(sip->begin); + end = (long *)(sip->end); + size = sip->size; + + /* If this sector is not overlapping the destination, then + * don't erase it... + */ + if ((((uchar *)dest) > (uchar *)end) || + (((uchar *)dest+bytecnt-1) < (uchar *)begin)) { + add += size; + continue; + } + + /* If this sector is already erased, then don't erase it... + */ + while(begin < end) { + if (*begin != 0xffffffff) + break; + begin++; + } + if (begin >= end) { + add += size; + continue; + } + SECTOR_ERASE(add); + + WHILE_D6_TOGGLES(add); + + add += size; + } + + READ_RESET(); + + while(bytecnt > 0) { + int tot, tot1; + uchar *sa; + + sa = dest; + *(ftype *)((fdev->base+(0x555<<1))) = 0x00aa; + *(ftype *)((fdev->base+(0x2aa<<1))) = 0x0055; + + *(ftype *)(sa) = 0x0025; + if (bytecnt >= 32) + tot = tot1 = 32; + else + tot = tot1 = bytecnt; + *(ftype *)(dest) = (tot/2 - 1); + while(tot > 0) { + Fwrite((ftype *)(dest),src); + dest+=2; + src+=2; + tot -= 2; + } + *(ftype *)(sa) = 0x0029; + + WHILE_D6_TOGGLES(sa); + + bytecnt -= tot1; + } + + READ_RESET(); + + /* Now that the re-programming of flash is complete, reset: */ + { +#ifdef RESETMACRO + RESETMACRO(); +#else + void (*reset)(); + reset = RESETFUNC(); + reset(); +#endif + } + + return(0); /* won't get here */ +} + +/* EndS29gl512n_16x1_ewrite(): + * Function place holder to determine the end of the above function. + */ +void +EndS29gl512n_16x1_ewrite(void) +{} + + +/* S29gl512n_16x1_type(): + * Run the AUTOSELECT algorithm to retrieve the manufacturer and + * device id of the flash. + */ +int +S29gl512n_16x1_type(struct flashinfo *fdev) +{ + ushort man, dev; + ulong id; + + + AUTO_SELECT(); + + man = *(ftype *)(fdev->base); /* manufacturer ID */ + dev = *(ftype *)((fdev->base + 28)); /* device ID */ + id = man; + id <<= 16; + id |= dev; + + fdev->id = id; + + READ_RESET(); + + return((int)(fdev->id)); +} + +/* EndS29gl512n_16x1_type(): + * Function place holder to determine the end of the above function. + */ +void +EndS29gl512n_16x1_type(void) +{} + +/************************************************************************** + ************************************************************************** + * + * The remainder of the code in this file should only included if the + * target configuration is such that this AM29F040 device is the only + * real flash device in the system that is to be visible to the monitor. + * + ************************************************************************** + ************************************************************************** + */ +#ifdef SINGLE_FLASH_DEVICE + +/* FlashXXXFbuf[]: + * If FLASH_COPY_TO_RAM is defined then these arrays will contain the + * flash operation functions above. To operate on most flash devices, + * you cannot be executing out of it (there are exceptions, but + * in general, we do not assume the flash supports this). The flash + * functions are copied here, then executed through the function + * pointers established in the flashinfo structure below. + * One obvious requirement... The size of each array must be at least + * as large as the function that it will contain. + */ +#ifdef FLASH_COPY_TO_RAM +ulong FlashTypeFbuf[400]; +ulong FlashEraseFbuf[400]; +#ifdef BUFFERED_WRITE +ulong FlashWriteFbuf[600]; +#else +ulong FlashWriteFbuf[400]; +#endif +ulong FlashEwriteFbuf[400]; +#endif + +/* FlashNamId[]: + * Used to correlate between the ID and a string representing the name + * of the flash device. + */ +struct flashdesc FlashNamId[] = { + { SPANSION_29GL512N_ID, "Spansion-29GL512N" }, + { SPANSION_29GL1024N_ID, "Spansion-29GL1024N" }, + { 0, (char *)0 }, +}; + + +struct sectorinfo sinfo_bank0[SECTOR_TOTAL]; +struct sectorinfo sinfo_bank1[SECTOR_TOTAL]; + +int +flashBankInit(int banknum, int snum, struct sectorinfo *sinfotbl) +{ + int i; + uchar *begin; + struct flashinfo *fbnk; + + fbnk = &FlashBank[banknum]; + if (banknum == 0) + fbnk->base = (unsigned char *)FLASH_BANK0_BASE_ADDR; + else + fbnk->base = (unsigned char *)FLASH_BANK0_BASE_ADDR+0x04000000; + + fbnk->width = 2; + +#ifdef FLASH_COPY_TO_RAM + fbnk->fltype = (int(*)())FlashTypeFbuf; + fbnk->flerase = (int(*)())FlashEraseFbuf; + fbnk->flwrite = (int(*)())FlashWriteFbuf; + fbnk->flewrite = (int(*)())FlashEwriteFbuf; +#else + fbnk->fltype = S29gl512n_16x1_type; + fbnk->flerase = S29gl512n_16x1_erase; + fbnk->flwrite = S29gl512n_16x1_write; + fbnk->flewrite = S29gl512n_16x1_ewrite; +#endif + + /* This device doesn't support flash lock, so set the pointer + * to the default FlashLockNotSupported() function... + */ + fbnk->fllock = FlashLockNotSupported; + + fbnk->sectors = sinfotbl; + fbnk->id = flashtype(fbnk); + switch(fbnk->id) { + case SPANSION_29GL512N_ID: + fbnk->end = fbnk->base + 0x04000000 - 1; + fbnk->sectorcnt = SECTOR_TOTAL/2; + break; + case SPANSION_29GL1024N_ID: + fbnk->end = fbnk->base + 0x08000000 - 1; + fbnk->sectorcnt = SECTOR_TOTAL; + break; + default: + /* The second bank may legitimately not be populated, so if it + * isn't found, indicate unavailable, don't claim an error... + */ + printf("Flash bank %d: ",banknum); + if (banknum == 0) + printf("invalid id: 0x%lx.\n",fbnk->id); + else + printf("not available.\n"); + return(-1); + } + + begin = fbnk->base; + for(i=0;i<fbnk->sectorcnt;i++,snum++) { + fbnk->sectors[i].snum = snum; + fbnk->sectors[i].size = SECTOR_SIZE; + fbnk->sectors[i].begin = begin; + fbnk->sectors[i].end = fbnk->sectors[i].begin + SECTOR_SIZE - 1; + fbnk->sectors[i].protected = 0; + begin += SECTOR_SIZE; + } + return(snum); +} + +/* FlashInit(): + * Initialize data structures for each bank of flash... + */ +int +FlashInit() +{ + int snum; + + FlashCurrentBank = 0; + + /* If code is in flash, then we must copy the flash ops to RAM. + * Note that this MUST be done when cache is disabled to assure + * that the RAM is occupied by the designated block of code. + */ + +#ifdef FLASH_COPY_TO_RAM + if (flashopload((ulong *)S29gl512n_16x1_type, + (ulong *)EndS29gl512n_16x1_type, + FlashTypeFbuf,sizeof(FlashTypeFbuf)) < 0) + return(-1); + + if (flashopload((ulong *)S29gl512n_16x1_erase, + (ulong *)EndS29gl512n_16x1_erase, + FlashEraseFbuf,sizeof(FlashEraseFbuf)) < 0) + return(-1); + + if (flashopload((ulong *)S29gl512n_16x1_ewrite, + (ulong *)EndS29gl512n_16x1_ewrite, + FlashEwriteFbuf,sizeof(FlashEwriteFbuf)) < 0) + return(-1); + + if (flashopload((ulong *)S29gl512n_16x1_write, + (ulong *)EndS29gl512n_16x1_write, + FlashWriteFbuf,sizeof(FlashWriteFbuf)) < 0) + return(-1); +#endif + +#ifdef IS_MONOLITHIC_FLASH + ActiveFlashBanks = 1; + snum = flashBankInit(0,0,sinfo_bank0); + + if (!IS_MONOLITHIC_FLASH()) { + if (flashBankInit(1,snum,sinfo_bank1) != -1) + ActiveFlashBanks++; + } +#else + snum = flashBankInit(0,0,sinfo_bank0); +#endif + + if (snum < 0) + return(-1); + +#ifdef FLASH_PROTECT_RANGE + sectorProtect(FLASH_PROTECT_RANGE,1); +#endif + +#if FLASHRAM_BASE + FlashRamInit(snum, FLASHRAM_SECTORCOUNT, &FlashBank[FLASHRAM_BANKNUM], + sinfoRAM, 0); +#endif + + return(0); +} + +#endif /* SINGLE_FLASH_DEVICE */ + +#endif /* INCLUDE_FLASH */ diff --git a/main/flash/devices/s29gl512n_16x1.h b/main/flash/devices/s29gl512n_16x1.h new file mode 100644 index 0000000..f2b0a36 --- /dev/null +++ b/main/flash/devices/s29gl512n_16x1.h @@ -0,0 +1,12 @@ +extern int S29gl512n_16x1_erase(struct flashinfo *,int); +extern void End_s29gl512n_16x1_erase(void); + +extern int S29gl512n_16x1_write(struct flashinfo *,unsigned char *,unsigned char *,long); +extern void End_s29gl512n_16x1_write(void); + +extern int S29gl512n_16x1_ewrite(struct flashinfo *,unsigned char *,unsigned char *,long); +extern void End_s29gl512n_16x1_ewrite(void); + +extern int S29gl512n_16x1_type(struct flashinfo *); +extern void End_s29gl512n_16x1_type(void); + diff --git a/main/glib/abs.c b/main/glib/abs.c new file mode 100644 index 0000000..8758947 --- /dev/null +++ b/main/glib/abs.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)abs.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdlib.h> + +int +abs(j) + int j; +{ + return(j < 0 ? -j : j); +} diff --git a/main/glib/asctime.c b/main/glib/asctime.c new file mode 100644 index 0000000..7a042c3 --- /dev/null +++ b/main/glib/asctime.c @@ -0,0 +1,19 @@ +#include <time.h> +#include "genlib.h" + +static const char *days[] = + {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + +static const char *months[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +char *asctime_r(const struct tm *t, char *ret) +{ + sprintf(ret, "%s %s %2d, %4d %2d:%02d:%02d", + days[t->tm_wday], months[t->tm_mon], + t->tm_mday, t->tm_year + 1970, + t->tm_hour, t->tm_min, t->tm_sec); + return ret; +} + diff --git a/main/glib/atoi.c b/main/glib/atoi.c new file mode 100644 index 0000000..de76b27 --- /dev/null +++ b/main/glib/atoi.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> + +int +atoi(str) +const char *str; +{ + return (int)strtol(str, (char **)NULL, 10); +} diff --git a/main/glib/crc16.c b/main/glib/crc16.c new file mode 100644 index 0000000..19409fd --- /dev/null +++ b/main/glib/crc16.c @@ -0,0 +1,59 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +/* CRC-CCITT crc16 used primarily by Xmodem... + */ +ushort xcrc16tab[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +ushort +xcrc16(uchar *buffer,ulong nbytes) +{ + ulong i; + ushort crc; + + crc = 0; + for(i=0;i<nbytes;i++) { + crc = (ushort)((crc << 8) ^ xcrc16tab[(crc>>8) ^ buffer[i]]); +#ifdef WATCHDOG_ENABLED + /* Every 256 bytes call the watchdog macro... */ + if ((nbytes & 0xff) == 0) + WATCHDOG_MACRO; +#endif + } + return(crc); +} diff --git a/main/glib/crc32.c b/main/glib/crc32.c new file mode 100644 index 0000000..5a5568c --- /dev/null +++ b/main/glib/crc32.c @@ -0,0 +1,155 @@ +/*- + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + * + * + * CRC32 code derived from work by Gary S. Brown. + */ + +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +const unsigned long crc32tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +/* If the watchdog macro is enabled, then we break up the crc algorithm + * into CRC_CHUNK_SIZE blocks so that after each block we can run the + * watchdog macro... + */ + +ulong +crc32chunk(uchar *buffer,ulong nbytes, ulong crc_rslt) +{ + unsigned long temp; + + while(nbytes) { + temp = (crc_rslt ^ *buffer++) & 0x000000FFL; + crc_rslt = ((crc_rslt >> 8) & 0x00FFFFFFL) ^ crc32tab[(int)temp]; + nbytes--; + } + return(crc_rslt); +} + +#ifdef WATCHDOG_ENABLED + +#define CRC_CHUNK_SIZE 0x4000 + +ulong +crc32(uchar *buffer, ulong nbytes) +{ + int size; + ulong crcval = 0xffffffff; + + while(nbytes > 0) { + if (nbytes > CRC_CHUNK_SIZE) + size = CRC_CHUNK_SIZE; + else + size = nbytes; + nbytes -= size; + + crcval = crc32chunk(buffer,size,crcval); + buffer += size; + + WATCHDOG_MACRO; + } + return(~crcval); +} + +#else + +ulong +crc32(uchar *buffer,ulong nbytes) +{ + unsigned long temp, crc_rslt; + + crc_rslt = 0xffffffff; + while(nbytes) { + temp = (crc_rslt ^ *buffer++) & 0x000000FFL; + crc_rslt = ((crc_rslt >> 8) & 0x00FFFFFFL) ^ crc32tab[(int)temp]; + nbytes--; + } + return(~crc_rslt); +} + +#endif diff --git a/main/glib/div.c b/main/glib/div.c new file mode 100644 index 0000000..7dfe553 --- /dev/null +++ b/main/glib/div.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)div.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdlib.h> /* div_t */ + +div_t +div(num, denom) + int num, denom; +{ + div_t r; + + r.quot = num / denom; + r.rem = num % denom; + /* + * The ANSI standard says that |r.quot| <= |n/d|, where + * n/d is to be computed in infinite precision. In other + * words, we should always truncate the quotient towards + * 0, never -infinity. + * + * Machine division and remainer may work either way when + * one or both of n or d is negative. If only one is + * negative and r.quot has been truncated towards -inf, + * r.rem will have the same sign as denom and the opposite + * sign of num; if both are negative and r.quot has been + * truncated towards -inf, r.rem will be positive (will + * have the opposite sign of num). These are considered + * `wrong'. + * + * If both are num and denom are positive, r will always + * be positive. + * + * This all boils down to: + * if num >= 0, but r.rem < 0, we got the wrong answer. + * In that case, to get the right answer, add 1 to r.quot and + * subtract denom from r.rem. + */ + if (num >= 0 && r.rem < 0) { + r.quot++; + r.rem -= denom; + } + return (r); +} diff --git a/main/glib/getglib b/main/glib/getglib new file mode 100755 index 0000000..4c963b2 --- /dev/null +++ b/main/glib/getglib @@ -0,0 +1,49 @@ +# +# This is the original script I used to pull in files from the FreeBsd project: +# +export GLIBFILES="abs.c atoi.c crc16.c crc32.c ctypetbl.c div.c getopt.c gmtime.c inrange.c lceil.c ldiv.c little_print.c memccpy.c memchr.c memcmp.c memcpy.c memset.c pollconsole.c prascii.c printmem.c smemcpy.c smemset.c sprnfloat.c strcasecmp.c strcat.c strchr.c strcmp.c strcpy.c strcspn.c strlen.c strncat.c strncmp.c strncpy.c strnlen.c strpbrk.c strrchr.c strspn.c strstr.c strtod.c strtok.c strtol.c strtoul.c strtolower.c strtoupper.c swap.c ticktock.c ulceil.c" + +export MYFILES="asctime.c inrange.c memcpy.c pollconsole.c prascii.c printmem.c smemcpy.c smemset.c swap.c ticktock.c" + +export BSDPATH=https://raw.githubusercontent.com/freebsd/freebsd/master + +export BSD_STRING_FILES="memccpy.c memchr.c memcmp.c memset.c strcasecmp.c strcat.c strchr.c strcmp.c strcpy.c strcspn.c strlen.c strncat.c strncmp.c strncpy.c strnlen.c strpbrk.c strrchr.c strspn.c strstr.c strtok.c" + +export BSD_STDLIB_FILES="abs.c atoi.c div.c getopt.c ldiv.c strtol.c" + +rm -f *.c *.1 list + +for file in $MYFILES +do + cp orig/$file . + echo "myfile: $file" >>list +done + +for file in $BSD_STDLIB_FILES +do + if ! [ -f $file ] + then + wget ${BSDPATH}/lib/libc/stdlib/$file + if [ $? == 0 ] + then + echo "stdlib: $file" >>list + fi + fi +done + +for file in $BSD_STRING_FILES +do + if ! [ -f $file ] + then + wget ${BSDPATH}/lib/libc/string/$file + if [ $? == 0 ] + then + echo "string: $file" >>list + fi + fi +done + +wget ${BSDPATH}/contrib/tzcode/stdtime/asctime.c +wget https://raw.githubusercontent.com/LADSoft/OrangeC/master/src/clibs/time/gmtime.c +wget https://raw.githubusercontent.com/freebsd/freebsd-ports/master/converters/ta2as/files/strtolower.c +wget https://raw.githubusercontent.com/freebsd/freebsd/master/sys/libkern/crc32.c diff --git a/main/glib/getopt.c b/main/glib/getopt.c new file mode 100644 index 0000000..cf43256 --- /dev/null +++ b/main/glib/getopt.c @@ -0,0 +1,139 @@ +/* $NetBSD: getopt.c,v 1.29 2014/06/05 22:00:22 christos Exp $ */ +#include <string.h> +extern int printf(char *fmt,...); + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +int opterr = 1, /* if error message should be printed */ + optind = 1, /* index into parent argv vector */ + optopt, /* character checked for validity */ + optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define BADCH (int)'?' +#define BADARG (int)':' +#define EMSG "" + +/* + * getopt -- + * Parse argc/argv argument vector. + */ +int +getopt(int nargc, char * const nargv[], const char *ostr) +{ + static char *place = EMSG; /* option letter processing */ + char *oli; /* option letter list index */ + + if (optreset || *place == 0) { /* update scanning pointer */ + optreset = 0; + place = nargv[optind]; + if (optind >= nargc || *place++ != '-') { + /* Argument is absent or is not an option */ + place = EMSG; + return (-1); + } + optopt = *place++; + if (optopt == '-' && *place == 0) { + /* "--" => end of options */ + ++optind; + place = EMSG; + return (-1); + } + if (optopt == 0) { + /* Solitary '-', treat as a '-' option + if the program (eg su) is looking for it. */ + place = EMSG; + if (strchr(ostr, '-') == 0) + return (-1); + optopt = '-'; + } + } else + optopt = *place++; + + /* See if option letter is one the caller wanted... */ + if (optopt == ':' || (oli = strchr(ostr, optopt)) == 0) { + if (*place == 0) + ++optind; + if (opterr && *ostr != ':') + (void)printf( + "illegal option -- %c\n", optopt); + return (BADCH); + } + + /* Does this option need an argument? */ + if (oli[1] != ':') { + /* don't need argument */ + optarg = 0; + if (*place == 0) + ++optind; + } else { + /* Option-argument is either the rest of this argument or the + entire next argument. */ + if (*place) + optarg = place; + else if (oli[2] == ':') + /* + * GNU Extension, for optional arguments if the rest of + * the argument is empty, we return NULL + */ + optarg = 0; + else if (nargc > ++optind) + optarg = nargv[optind]; + else { + /* option-argument absent */ + place = EMSG; + if (*ostr == ':') + return (BADARG); + if (opterr) + (void)printf( + "option requires an argument -- %c\n", + optopt); + return (BADCH); + } + place = EMSG; + ++optind; + } + return (optopt); /* return option letter */ +} + +/* getoptinit(): + * Since getopt() can be used by every command in the monitor + * it's variables must be reinitialized prior to each command + * executed through docommand()... + */ +void +getoptinit(void) +{ + optind = 1; + opterr = 1; + optopt = 0; + optreset = 0; + optarg = (char *)0; +} diff --git a/main/glib/inrange.c b/main/glib/inrange.c new file mode 100755 index 0000000..d687a8e --- /dev/null +++ b/main/glib/inrange.c @@ -0,0 +1,71 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +/* inRange(): + * This function is handed a range string and a value. + * If the value is within the range of the string specified, then + * return 1; else return 0. + * The incoming string can be a mix of ranges and values with each + * range and/or value separated by a comma and a range is specified + * by 2 numbers separated by a dash. + * Also, incoming ranges of "all" or "any" immediately return true + * and an incoming range of "none" or a null or empty pointer will + * return false. + */ +int +inRange(char *range, int value) +{ + int lo, hi; + char rcopy[32], *rsp, *comma, *dash; + + /* If incoming range is NULL, return zero. + */ + if ((range == 0) || (*range == 0) || (strcmp(range,"none") == 0)) + return(0); + + /* If the range string is "all" or "any", then immediately return true... + */ + if ((strcmp(range,"all") == 0) || (strcmp(range,"any") == 0)) + return(1); + + /* Scan the range string for valid characters: + */ + rsp = range; + while(*rsp) { + if ((*rsp == ',') || (*rsp == '-') || + (*rsp == 'x') || isxdigit(*rsp)) + rsp++; + else + break; + } + if (*rsp) + return(0); + + /* If incoming range string exceeds size of copy buffer, return 0. + */ + if (strlen(range) > sizeof(rcopy)-1) + return(0); + + strcpy(rcopy,range); + rsp = rcopy; + do { + comma = strchr(rsp,','); + if (comma) + *comma = 0; + dash = strchr(rsp,'-'); + if (dash) { + lo = strtol(rsp,0,0); + hi = strtol(dash+1,0,0); + if ((value >= lo) && (value <= hi)) + return(1); + } + else { + if (value == strtol(rsp,0,0)) + return(1); + } + rsp = comma+1; + } while (comma); + return(0); +} diff --git a/main/glib/ldiv.c b/main/glib/ldiv.c new file mode 100644 index 0000000..0ec98e6 --- /dev/null +++ b/main/glib/ldiv.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)ldiv.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdlib.h> /* ldiv_t */ + +ldiv_t +ldiv(num, denom) + long num, denom; +{ + ldiv_t r; + + /* see div.c for comments */ + + r.quot = num / denom; + r.rem = num % denom; + if (num >= 0 && r.rem < 0) { + r.quot++; + r.rem -= denom; + } + return (r); +} diff --git a/main/glib/list b/main/glib/list new file mode 100644 index 0000000..99ad5c5 --- /dev/null +++ b/main/glib/list @@ -0,0 +1,34 @@ +myfile: inrange.c +myfile: pollconsole.c +myfile: prascii.c +myfile: printmem.c +myfile: smemcpy.c +myfile: smemset.c +myfile: ticktock.c +stdlib: abs.c +stdlib: atoi.c +stdlib: div.c +stdlib: getopt.c +stdlib: ldiv.c +stdlib: strtol.c +string: memccpy.c +string: memchr.c +string: memcmp.c +string: memcpy.c +string: memset.c +string: strcasecmp.c +string: strcat.c +string: strchr.c +string: strcmp.c +string: strcpy.c +string: strcspn.c +string: strlen.c +string: strncat.c +string: strncmp.c +string: strncpy.c +string: strnlen.c +string: strpbrk.c +string: strrchr.c +string: strspn.c +string: strstr.c +string: strtok.c diff --git a/main/glib/memccpy.c b/main/glib/memccpy.c new file mode 100644 index 0000000..a13bbf1 --- /dev/null +++ b/main/glib/memccpy.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)memccpy.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> +#include <stdlib.h> + +void * +memccpy(void *t, const void *f, int c, size_t n) +{ + + if (n) { + unsigned char *tp = t; + const unsigned char *fp = f; + unsigned char uc = c; + do { + if ((*tp++ = *fp++) == uc) + return (tp); + } while (--n != 0); + } + return (0); +} diff --git a/main/glib/memchr.c b/main/glib/memchr.c new file mode 100644 index 0000000..14b66c8 --- /dev/null +++ b/main/glib/memchr.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)memchr.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> +#include <stdlib.h> + +void * +memchr(const void *s, int c, size_t n) +{ + if (n != 0) { + const unsigned char *p = s; + + do { + if (*p++ == (unsigned char)c) + return ((void *)(p - 1)); + } while (--n != 0); + } + return (NULL); +} diff --git a/main/glib/memcmp.c b/main/glib/memcmp.c new file mode 100644 index 0000000..baef47e --- /dev/null +++ b/main/glib/memcmp.c @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)memcmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> +#include <stdlib.h> + +/* + * Compare memory regions. + */ +int +memcmp(const void *s1, const void *s2, size_t n) +{ + if (n != 0) { + const unsigned char *p1 = s1, *p2 = s2; + + do { + if (*p1++ != *p2++) + return (*--p1 - *--p2); + } while (--n != 0); + } + return (0); +} diff --git a/main/glib/memcpy.c b/main/glib/memcpy.c new file mode 100644 index 0000000..3cfbfa3 --- /dev/null +++ b/main/glib/memcpy.c @@ -0,0 +1,108 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +#ifndef MEMCPY_CHUNK +#define MEMCPY_CHUNK (256*1024) +#endif + +/* memcpy(): + * Copy n bytes from 'from' to 'to'; return 'to'. + * This version of memcpy() tries to take advantage of address alignment. + * The goal is to do as many of the copies on 4-byte aligned addresses, + * falling back to 2-byte alignment, and finally, if there is no other + * way, simple byte-by-byte copy. + * Note that there is some point where the amount of overhead may exceed + * the byte count; hence, this will take longer for small byte counts. + * The assumption here is that small byte count memcpy() calls don't really + * care. + */ +char * +memcpy(char *to,char *from,int count) +{ + char *to_copy, *end; +#if INCLUDE_QUICKMEMCPY + char *tend; +#endif + + to_copy = to; + +#if INCLUDE_QUICKMEMCPY + /* If count is greater than 8, get fancy, else just do byte-copy... */ + if (count > 8) { + /* Attempt to optimize the transfer here... */ + if (((int)to & 3) && ((int)from & 3)) { + /* If from and to pointers are both unaligned to the + * same degree then we can do a few char copies to get them + * 4-byte aligned and then do a lot of 4-byte aligned copies. + */ + if (((int)to & 3) == ((int)from & 3)) { + while((int)to & 3) { + *to++ = *from++; + count--; + } + } + /* If from and to pointers are both odd, but different, then + * we can increment them both by 1 and do a bunch of 2-byte + * aligned copies... + */ + else if (((int)to & 1) && ((int)from & 1)) { + *to++ = *from++; + count--; + } + } + + /* If both pointers are now 4-byte aligned or 2-byte aligned, + * take advantage of that here... + */ + if (!((int)to & 3) && !((int)from & 3)) { + tend = end = to + (count & ~3); + count = count & 3; +#ifdef WATCHDOG_ENABLED + do { + tend = (end - to <= MEMCPY_CHUNK) ? end : to + MEMCPY_CHUNK; +#endif + while(to < tend) { + *(ulong *)to = *(ulong *)from; + from += 4; + to += 4; + } +#ifdef WATCHDOG_ENABLED + WATCHDOG_MACRO; + } while (tend != end); +#endif + } + else if (!((int)to & 1) && !((int)from & 1)) { + tend = end = to + (count & ~1); + count = count & 1; +#ifdef WATCHDOG_ENABLED + do { + tend = (end - to <= MEMCPY_CHUNK) ? end : to + MEMCPY_CHUNK; +#endif + while(to < tend) { + *(ushort *)to = *(ushort *)from; + from += 2; + to += 2; + } +#ifdef WATCHDOG_ENABLED + WATCHDOG_MACRO; + } while (tend != end); +#endif + } + } +#endif + + if (count) { + end = to + count; + while(to < end) + *to++ = *from++; + } + return(to_copy); +} + +void +bcopy(char *from, char *to, int size) +{ + memcpy(to,from,size); +} diff --git a/main/glib/memset.c b/main/glib/memset.c new file mode 100644 index 0000000..ad0d513 --- /dev/null +++ b/main/glib/memset.c @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Hibler and Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)memset.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> + +#include <limits.h> + +#define wsize sizeof(u_int) +#define wmask (wsize - 1) + +#ifdef BZERO +#include <strings.h> + +#define RETURN return +#define VAL 0 +#define WIDEVAL 0 + +void +bzero(void *dst0, size_t length) +#else +#include <string.h> + +#define RETURN return (dst0) +#define VAL c0 +#define WIDEVAL c + +void * +memset(void *dst0, int c0, size_t length) +#endif +{ + size_t t; +#ifndef BZERO + u_int c; +#endif + u_char *dst; + + dst = dst0; + /* + * If not enough words, just fill bytes. A length >= 2 words + * guarantees that at least one of them is `complete' after + * any necessary alignment. For instance: + * + * |-----------|-----------|-----------| + * |00|01|02|03|04|05|06|07|08|09|0A|00| + * ^---------------------^ + * dst dst+length-1 + * + * but we use a minimum of 3 here since the overhead of the code + * to do word writes is substantial. + */ + if (length < 3 * wsize) { + while (length != 0) { + *dst++ = VAL; + --length; + } + RETURN; + } + +#ifndef BZERO + if ((c = (u_char)c0) != 0) { /* Fill the word. */ + c = (c << 8) | c; /* u_int is 16 bits. */ +#if UINT_MAX > 0xffff + c = (c << 16) | c; /* u_int is 32 bits. */ +#endif +#if UINT_MAX > 0xffffffff + c = (c << 32) | c; /* u_int is 64 bits. */ +#endif + } +#endif + /* Align destination by filling in bytes. */ + if ((t = (long)dst & wmask) != 0) { + t = wsize - t; + length -= t; + do { + *dst++ = VAL; + } while (--t != 0); + } + + /* Fill words. Length was >= 2*words so we know t >= 1 here. */ + t = length / wsize; + do { + *(u_int *)dst = WIDEVAL; + dst += wsize; + } while (--t != 0); + + /* Mop up trailing bytes, if any. */ + t = length & wmask; + if (t != 0) + do { + *dst++ = VAL; + } while (--t != 0); + RETURN; +} diff --git a/main/glib/pollconsole.c b/main/glib/pollconsole.c new file mode 100755 index 0000000..62d05b2 --- /dev/null +++ b/main/glib/pollconsole.c @@ -0,0 +1,44 @@ +#include "config.h" +#include <ctype.h> +#include "ether.h" +#include "genlib.h" +#include "stddefs.h" +#include "timer.h" + +/* pollConsole(): + * Common function used to query the console port with a message. + * If after about a 2-second period (or the time specified by POLLTIMEOUT), + * there is no response from the console, then return 0; else return + * the character that was received. + */ +int +pollConsole(char *msg) +{ + char *env; + int pollval, msec; + struct elapsed_tmr tmr; + + env = getenv("POLLTIMEOUT"); + if (env) + msec = strtol(env,0,0); + else + msec = 2000; + + pollval = 0; + printf("%s",msg); + startElapsedTimer(&tmr,msec); + while(!msecElapsed(&tmr)) { + if (gotachar()) { + while(gotachar()) + pollval = getchar(); + break; + } + pollethernet(); + } + putstr("\r\n"); + + if (ELAPSED_TIMEOUT(&tmr)) + return(0); + + return(pollval); +} diff --git a/main/glib/prascii.c b/main/glib/prascii.c new file mode 100755 index 0000000..67a61d5 --- /dev/null +++ b/main/glib/prascii.c @@ -0,0 +1,22 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +/* prascii(): + * Print the incoming data stream as ascii if printable, else just + * print a dot. + */ +void +prascii(uchar *data,int cnt) +{ + int i; + + for(i=0;i<cnt;i++) { + if ((*data > 0x1f) && (*data < 0x7f)) + printf("%c",*data); + else + putchar('.'); + data++; + } +} diff --git a/main/glib/printmem.c b/main/glib/printmem.c new file mode 100755 index 0000000..5dfbea1 --- /dev/null +++ b/main/glib/printmem.c @@ -0,0 +1,40 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +/* printMem(): + * Dump a block of memory. + */ +void +printMem(uchar *base, int size, int showascii) +{ + int i, col; + uchar *cp, *cp1; + + cp = cp1 = base; + printf(" "); + for(col=1,i=0;i<size;i++,col++) { + printf("%02x ",*cp++); + if ((col == 8) || (col == 16)) { + printf(" "); + if (col == 16) { + col = 0; + if (showascii) + prascii(cp1,16); + cp1 += 16; + printf("\n "); + } + } + } + if ((showascii) && (col > 1)) { + int space; + + space = (3 * (17 - col)) + (col <= 8 ? 4 : 2); + while(space--) + putchar(' '); + prascii(cp1,col-1); + } + printf("\n"); + return; +} diff --git a/main/glib/smemcpy.c b/main/glib/smemcpy.c new file mode 100755 index 0000000..5b17470 --- /dev/null +++ b/main/glib/smemcpy.c @@ -0,0 +1,150 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +/* s_memcpy(): + * Superset of memcpy(). Note, this used to be tfsmemcpy() in tfs.c; + * however, since it has no real TFS dependencies, and code outside of + * TFS uses it, it has been moved here and the name is changed. + * + * Includes verbose option plus verification after copy. + * Takes advantage of address alignment when possible. + * + * Note: + * If verbose is greater than one, then this function doesn't + * do any memory transfer, it simply displays the memory range + * that is to be transferred. This is used by TFS to dump a map without + * actually touching memory. + * + * Return: + * 0 if successful, else -1 indicating some part of the copy failed. + */ +int +s_memcpy(char *_to,char *_from,int count, int verbose,int verifyonly) +{ + int err; + volatile register char *to, *from, *end; + + to = _to; + from = _from; + + if (verbose) + printf("%s %7d bytes from 0x%08lx to 0x%08lx", + verifyonly ? "vrfy" : "copy", count,(ulong)from,(ulong)to); + + if (_to == _from) { + if (verbose) + printf("\n"); + return(0); + } + + if (count < 0) + return(-1); + + if (verifyonly) { + while(count) { + if (*to != *from) + break; + to++; + from++; + count--; +#ifdef WATCHDOG_ENABLED + if ((count & 0xff) == 0) + WATCHDOG_MACRO; +#endif + } + if (count) { + if (verbose) { + printf(" FAILED\n"); + printf(" (0x%02x @ 0x%08lx should be 0x%02x)\n", + *to,(ulong)to,*from); + } + return(-1); + } + else + if (verbose) + printf(" OK\n"); + return(0); + } + + /* If verbose is greater than 1, then we don't even do a memcpy, + * we just let the user know what we would have done... + */ + if ((count == 0) || (verbose > 1)) + goto done; + + if (to != from) { + + err = 0; + if (!((int)to & 3) && !((int)from & 3) && !(count & 3)) { + volatile register ulong *lto, *lfrom, *lend; + + count >>= 2; + lto = (ulong *)to; + lfrom = (ulong *)from; + lend = lto + count; + while(lto < lend) { + *lto = *lfrom; + if (*lto != *lfrom) { + err = 1; + break; + } + lto++; + lfrom++; +#ifdef WATCHDOG_ENABLED + if (((int)lto & 0xff) == 0) + WATCHDOG_MACRO; +#endif + } + } + else if (!((int)to & 1) && !((int)from & 1) && !(count & 1)) { + volatile register ushort *sto, *sfrom, *send; + + count >>= 1; + sto = (ushort *)to; + sfrom = (ushort *)from; + send = sto + count; + while(sto < send) { + *sto = *sfrom; + if (*sto != *sfrom) { + err = 1; + break; + } + sto++; + sfrom++; +#ifdef WATCHDOG_ENABLED + if (((int)sto & 0xff) == 0) + WATCHDOG_MACRO; +#endif + } + } + else { + end = to + count; + while(to < end) { + *to = *from; + if (*to != *from) { + err = 1; + break; + } + to++; + from++; +#ifdef WATCHDOG_ENABLED + if (((int)to & 0xff) == 0) + WATCHDOG_MACRO; +#endif + } + } + if (err) { + if (verbose) + printf(" failed\n"); + return(-1); + } + } + +done: + if (verbose) + printf("\n"); + + return(0); +} diff --git a/main/glib/smemset.c b/main/glib/smemset.c new file mode 100755 index 0000000..9216b50 --- /dev/null +++ b/main/glib/smemset.c @@ -0,0 +1,71 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +/* s_memset(): + * Superset of memset() (used to be tfsmemset()). + * Includes verbose option, test to make sure the destination is not + * within MicroMonitor's own space, plus verification after set. + */ +int +s_memset(uchar *to,uchar val,int count,int verbose,int verifyonly) +{ + int failed; + uchar *end; + + failed = 0; + +#ifndef MONAPP + if (inUmonBssSpace((char *)to,(char *)to+count)) + return(-1); +#endif + + if (verbose) { + printf("%s %7d bytes at 0x%08lx to 0x%02x", + verifyonly ? "vrfy" : "set ",count,(ulong)to,val); + } + + if ((count == 0) || (verbose > 1)) + goto done; + + end = to+count; + + if (verifyonly) { + while(to < end) { +#ifdef WATCHDOG_ENABLED + if (((ulong)to & 0xff) == 0) + WATCHDOG_MACRO; +#endif + if (*to++ != val) { + failed = 1; + break; + } + } + } + else { + while(to < end) { +#ifdef WATCHDOG_ENABLED + if (((ulong)to & 0xff) == 0) + WATCHDOG_MACRO; +#endif + *to = val; + if (*to++ != val) { + failed = 1; + break; + } + } + } +done: + if (verbose) { + if (failed) + printf(" failed"); + else if (verifyonly) + printf(" OK"); + printf("\n"); + } + if (failed) + return(-1); + else + return(0); +} diff --git a/main/glib/strcasecmp.c b/main/glib/strcasecmp.c new file mode 100644 index 0000000..12610f5 --- /dev/null +++ b/main/glib/strcasecmp.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ctype.h> +#include <stdlib.h> + +int +strcasecmp(const char *s1, const char *s2) +{ + const unsigned char + *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + while (tolower(*us1) == tolower(*us2++)) + if (*us1++ == '\0') + return (0); + return (tolower(*us1) - tolower(*--us2)); +} + +int +strncasecmp(const char *s1, const char *s2, size_t n) +{ + if (n != 0) { + const unsigned char + *us1 = (const unsigned char *)s1, + *us2 = (const unsigned char *)s2; + + do { + if (tolower(*us1) != tolower(*us2++)) + return (tolower(*us1) - tolower(*--us2)); + if (*us1++ == '\0') + break; + } while (--n != 0); + } + return (0); +} diff --git a/main/glib/strcat.c b/main/glib/strcat.c new file mode 100644 index 0000000..07a3c08 --- /dev/null +++ b/main/glib/strcat.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcat.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> + +char * +strcat(char * __restrict s, const char * __restrict append) +{ + char *save = s; + + for (; *s; ++s); + while ((*s++ = *append++)); + return(save); +} diff --git a/main/glib/strchr.c b/main/glib/strchr.c new file mode 100644 index 0000000..ab83b39 --- /dev/null +++ b/main/glib/strchr.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)index.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stddef.h> +#include <string.h> + +char * +strchr(const char *p, int ch) +{ + char c; + + c = ch; + for (;; ++p) { + if (*p == c) + return ((char *)p); + if (*p == '\0') + return (NULL); + } + /* NOTREACHED */ +} + +__weak_reference(strchr, index); diff --git a/main/glib/strcmp.c b/main/glib/strcmp.c new file mode 100644 index 0000000..9daf624 --- /dev/null +++ b/main/glib/strcmp.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> + +/* + * Compare strings. + */ +int +strcmp(const char *s1, const char *s2) +{ + while (*s1 == *s2++) + if (*s1++ == '\0') + return (0); + return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); +} diff --git a/main/glib/strcpy.c b/main/glib/strcpy.c new file mode 100644 index 0000000..8a48d0d --- /dev/null +++ b/main/glib/strcpy.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> + +char * +strcpy(char * __restrict to, const char * __restrict from) +{ + char *save = to; + + for (; (*to = *from); ++from, ++to); + return(save); +} diff --git a/main/glib/strlen.c b/main/glib/strlen.c new file mode 100644 index 0000000..6c665eb --- /dev/null +++ b/main/glib/strlen.c @@ -0,0 +1,18 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +/* strlen(): + * Returns the number of + * non-NULL bytes in string argument. + */ +int +strlen(register char *s) +{ + register char *s0 = s + 1; + + while (*s++ != '\0') + ; + return (s - s0); +} diff --git a/main/glib/strncat.c b/main/glib/strncat.c new file mode 100644 index 0000000..9630ba3 --- /dev/null +++ b/main/glib/strncat.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strncat.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> +#include <stdlib.h> + +/* + * Concatenate src on the end of dst. At most strlen(dst)+n+1 bytes + * are written at dst (at most n+1 bytes being appended). Return dst. + */ +char * +strncat(char * __restrict dst, const char * __restrict src, size_t n) +{ + if (n != 0) { + char *d = dst; + const char *s = src; + + while (*d != 0) + d++; + do { + if ((*d = *s++) == 0) + break; + d++; + } while (--n != 0); + *d = 0; + } + return (dst); +} diff --git a/main/glib/strncmp.c b/main/glib/strncmp.c new file mode 100644 index 0000000..fba4854 --- /dev/null +++ b/main/glib/strncmp.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strncmp.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> +#include <stdlib.h> + +int +strncmp(const char *s1, const char *s2, size_t n) +{ + + if (n == 0) + return (0); + do { + if (*s1 != *s2++) + return (*(const unsigned char *)s1 - + *(const unsigned char *)(s2 - 1)); + if (*s1++ == '\0') + break; + } while (--n != 0); + return (0); +} diff --git a/main/glib/strncpy.c b/main/glib/strncpy.c new file mode 100644 index 0000000..740ac0d --- /dev/null +++ b/main/glib/strncpy.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strncpy.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> +#include <stdlib.h> + +/* + * Copy src to dst, truncating or null-padding to always copy n bytes. + * Return dst. + */ +char * +strncpy(char * __restrict dst, const char * __restrict src, size_t n) +{ + if (n != 0) { + char *d = dst; + const char *s = src; + + do { + if ((*d++ = *s++) == '\0') { + /* NUL pad the remaining n-1 bytes */ + while (--n != 0) + *d++ = '\0'; + break; + } + } while (--n != 0); + } + return (dst); +} diff --git a/main/glib/strnlen.c b/main/glib/strnlen.c new file mode 100644 index 0000000..f44151f --- /dev/null +++ b/main/glib/strnlen.c @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2009 David Schultz <das@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> + +size_t +strnlen(const char *s, size_t maxlen) +{ + size_t len; + + for (len = 0; len < maxlen; len++, s++) { + if (!*s) + break; + } + return (len); +} diff --git a/main/glib/strpbrk.c b/main/glib/strpbrk.c new file mode 100644 index 0000000..513f9ce --- /dev/null +++ b/main/glib/strpbrk.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> +#include <stdlib.h> + +/* + * Find the first occurrence in s1 of a character in s2 (excluding NUL). + */ +char * +strpbrk(const char *s1, const char *s2) +{ + const char *scanp; + int c, sc; + + while ((c = *s1++) != 0) { + for (scanp = s2; (sc = *scanp++) != '\0';) + if (sc == c) + return ((char *)(s1 - 1)); + } + return (NULL); +} diff --git a/main/glib/strrchr.c b/main/glib/strrchr.c new file mode 100644 index 0000000..f84ffb7 --- /dev/null +++ b/main/glib/strrchr.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)rindex.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stddef.h> +#include <string.h> + +char * +strrchr(const char *p, int ch) +{ + char *save; + char c; + + c = ch; + for (save = NULL;; ++p) { + if (*p == c) + save = (char *)p; + if (*p == '\0') + return (save); + } + /* NOTREACHED */ +} + +__weak_reference(strrchr, rindex); diff --git a/main/glib/strstr.c b/main/glib/strstr.c new file mode 100644 index 0000000..22f4835 --- /dev/null +++ b/main/glib/strstr.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <string.h> +#include <stdlib.h> + +/* + * Find the first occurrence of find in s. + */ +char * +strstr(const char *s, const char *find) +{ + char c, sc; + size_t len; + + if ((c = *find++) != '\0') { + len = strlen(find); + do { + do { + if ((sc = *s++) == '\0') + return (NULL); + } while (sc != c); + } while (strncmp(s, find, len) != 0); + s--; + } + return ((char *)s); +} diff --git a/main/glib/strtok.c b/main/glib/strtok.c new file mode 100644 index 0000000..063a554 --- /dev/null +++ b/main/glib/strtok.c @@ -0,0 +1,136 @@ +/*- + * Copyright (c) 1998 Softweyr LLC. All rights reserved. + * + * strtok_r, from Berkeley strtok + * Oct 13, 1998 by Wes Peters <wes@softweyr.com> + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notices, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notices, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE + * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strtok.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stddef.h> +#ifdef DEBUG_STRTOK +#include <stdio.h> +#endif +#include <string.h> + +char *__strtok_r(char *, const char *, char **); + +__weak_reference(__strtok_r, strtok_r); + +char * +__strtok_r(char *s, const char *delim, char **last) +{ + char *spanp, *tok; + int c, sc; + + if (s == NULL && (s = *last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = '\0'; + *last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +char * +strtok(char *s, const char *delim) +{ + static char *last; + + return (__strtok_r(s, delim, &last)); +} + +#ifdef DEBUG_STRTOK +/* + * Test the tokenizer. + */ +int +main(void) +{ + char blah[80], test[80]; + char *brkb, *brkt, *phrase, *sep, *word; + + sep = "\\/:;=-"; + phrase = "foo"; + + printf("String tokenizer test:\n"); + strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function."); + for (word = strtok(test, sep); word; word = strtok(NULL, sep)) + printf("Next word is \"%s\".\n", word); + strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function."); + + for (word = strtok_r(test, sep, &brkt); word; + word = strtok_r(NULL, sep, &brkt)) { + strcpy(blah, "blah:blat:blab:blag"); + + for (phrase = strtok_r(blah, sep, &brkb); phrase; + phrase = strtok_r(NULL, sep, &brkb)) + printf("So far we're at %s:%s\n", word, phrase); + } + + return (0); +} + +#endif /* DEBUG_STRTOK */ diff --git a/main/glib/strtol.c b/main/glib/strtol.c new file mode 100644 index 0000000..4c3571c --- /dev/null +++ b/main/glib/strtol.c @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <limits.h> +#include <ctype.h> +#include <stdlib.h> + + +/* + * Convert a string to a long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long +strtol(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + const char *s; + unsigned long acc; + char c; + unsigned long cutoff; + int neg, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = *s++; + } while (isspace((unsigned char)c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set 'any' if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX + : LONG_MAX; + cutlim = cutoff % base; + cutoff /= base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_MIN : LONG_MAX; + } else if (!any) { + } else if (neg) + acc = -acc; + +noconv: + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} diff --git a/main/glib/strtolower.c b/main/glib/strtolower.c new file mode 100755 index 0000000..658ab7e --- /dev/null +++ b/main/glib/strtolower.c @@ -0,0 +1,33 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +/* strtolower(): + * In-place modification of a string to be all lower case. + */ +char * +strtolower(char *string) +{ + char *cp; + + cp = string; + while(*cp) { + *cp = tolower(*cp); + cp++; + } + return(string); +} + +char * +strtoupper(char *string) +{ + char *cp; + + cp = string; + while(*cp) { + *cp = toupper(*cp); + cp++; + } + return(string); +} diff --git a/main/glib/strtoul.c b/main/glib/strtoul.c new file mode 100644 index 0000000..9bc4a0b --- /dev/null +++ b/main/glib/strtoul.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <limits.h> +#include <ctype.h> +#include <stdlib.h> + +/* + * Convert a string to an unsigned long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long +strtoul(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + const char *s; + unsigned long acc; + char c; + unsigned long cutoff; + int neg, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + s = nptr; + do { + c = *s++; + } while (isspace((unsigned char)c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X') && + ((s[1] >= '0' && s[1] <= '9') || + (s[1] >= 'A' && s[1] <= 'F') || + (s[1] >= 'a' && s[1] <= 'f'))) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + cutoff = ULONG_MAX / base; + cutlim = ULONG_MAX % base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_MAX; + } else if (!any) { + } else if (neg) + acc = -acc; +noconv: + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} diff --git a/main/glib/swap.c b/main/glib/swap.c new file mode 100755 index 0000000..fa19cbf --- /dev/null +++ b/main/glib/swap.c @@ -0,0 +1,18 @@ +#include "config.h" +#include <ctype.h> +#include "genlib.h" +#include "stddefs.h" + +ushort +swap2(ushort sval_in) +{ + return(((sval_in & 0x00ff) << 8) | ((sval_in & 0xff00) >> 8)); +} + +ulong +swap4(ulong sval_in) +{ + return(((sval_in & 0x000000ff) << 24) | ((sval_in & 0x0000ff00) << 8) | + ((sval_in & 0x00ff0000) >> 8) | ((sval_in & 0xff000000) >> 24)); +} + diff --git a/main/glib/ticktock.c b/main/glib/ticktock.c new file mode 100755 index 0000000..6a29eec --- /dev/null +++ b/main/glib/ticktock.c @@ -0,0 +1,48 @@ +#include "config.h" +#include <ctype.h> +#include "ether.h" +#include "genlib.h" +#include "stddefs.h" + +/* ticktock(): + * Put out a ticker... + */ +void +ticktock(void) +{ + static short tick; + char tock; + +#if INCLUDE_MONCMD + /* Don't do any ticker if the command was issued + * from UDP (i.e. moncmd)... + */ + if (IPMonCmdActive) + return; +#endif + + switch(tick) { + case 1: + case 5: + tock = '|'; + break; + case 2: + case 6: + tock = '/'; + break; + case 3: + case 7: + tock = '-'; + break; + case 4: + case 8: + tock = '\\'; + break; + default: + tock = '|'; + tick = 1; + break; + } + tick++; + printf("%c\b",tock); +} diff --git a/main/make/common.make b/main/make/common.make new file mode 100755 index 0000000..161ae77 --- /dev/null +++ b/main/make/common.make @@ -0,0 +1,132 @@ +############################################################################ +# +# common.make: +# This file contains all the common stuff used by MicroMonitor port-specific +# make files. + +############################################################################ +# +# Various relative directories used to build the monitor: +# +BASE = $(TOPDIR)/target +CPUDIR = $(BASE)/cpu/$(CPUTYPE) +ZLIBDIR = $(BASE)/zlib +GLIBDIR = $(BASE)/glib +COMDIR = $(BASE)/common +MAKEDIR = $(BASE)/make +DEVDIR = $(BASE)/dev +FSDIR = $(BASE)/fs +FATFSDIR = $(FSDIR)/elmfatfs +JFFS2DIR = $(BASE)/fs/jffs2 + +ifeq ($(TOOLBIN),) +TOOLBIN = $(TOPDIR)/host/bin +endif + +############################################################################ +# +# Generic tools used by all make files: +# Names are derived from the TOOL_PREFIX variable +# assumed to be established in the make file that +# includes this. +# + +ifeq ($(TOOL_PREFIX),) +TOOL_PREFIX = $(CPUTYPE)-$(FILETYPE) +endif +NM = $(TOOL_PREFIX)-nm +AR = $(TOOL_PREFIX)-ar +LD = $(TOOL_PREFIX)-ld +ASM = $(TOOL_PREFIX)-as +CC = $(TOOL_PREFIX)-gcc +STRIP = $(TOOL_PREFIX)-strip +OBJCOPY = $(TOOL_PREFIX)-objcopy +OBJDUMP = $(TOOL_PREFIX)-objdump + +LIBGCC = `$(CC) --print-libgcc-file-name` +LIBDIR = $(LIBGCC:/libgcc.a=) +NOF_LIBGCC = $(LIBDIR)/nof/libgcc.a + +# FLASHSUBDIR: +# This is actually a portion of the PATH to the flash source files. +# If not specified in the port-specific makefile, then assign the +# default type of "devices". This then makes the assumption that +# the files specified by the FLASHSRC variable in the port-specific +# makefile are under $(BASE)/flash/devices (the new style flash +# driver for uMon). For the older drivers, use the appropriate +# directory found under "boards" in the umon_main tree. +# The prefix $(BASE)/flash is assumed. +# +ifeq ($(FLASHSUBDIR),) +FLASHSUBDIR = devices +endif + +ifeq ($(FLASHDIR),) +FLASHDIR = $(BASE)/flash/$(FLASHSUBDIR) +endif + +# PORTDIR: +# By default, PORTDIR is umon/umon_ports; however some ports are not part +# of the CVS distribution; hence, umon/umon_ports sometimes needs to be +# overridden... +ifeq ($(PORTDIR),) +PORTDIR = umon/umon_ports +endif + +############################################################################ +# +# Miscellaneous variables used by all targets: +# +DEPEND = depend +DEPENDFILE = depends +BUILDDIR = build_$(PLATFORM) + +COMMON_INCLUDE = -I. -I$(COMDIR) -I$(CPUDIR) -I$(FLASHDIR) -I$(DEVDIR) \ + -I$(ZLIBDIR) $(PORT_INCLUDE) + +COMMON_CFLAGS = -g -c -Wall -DPLATFORM_$(PLATFORM)=1 \ + -fno-builtin -fno-toplevel-reorder + +COMMON_AFLAGS = -xassembler-with-cpp -c -D PLATFORM_$(PLATFORM)=1 \ + -D ASSEMBLY_ONLY + +CFLAGS = $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) +ASMFLAGS = $(COMMON_AFLAGS) $(CUSTOM_AFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) + + +MAKE_LDFILE = $(TOOLBIN)/vsub $(PLATFORM)_$(@F:.$(FILETYPE)=.ldt) \ + $(PLATFORM)_$(@F:.$(FILETYPE)=.ld) +MAKE_MONBUILT = $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) \ + $(COMMON_INCLUDE) -omonbuilt.o $(COMDIR)/monbuilt.c +MAKE_GNUSYMS = $(NM) --numeric-sort $@ > $(@:.$(FILETYPE)=.gsym) +DUMP_MAP = $(OBJDUMP) -fh $@ +MAKE_BINARY = $(OBJCOPY) -O binary $@ $(@:.$(FILETYPE)=.bin) +LINK = $(LD) -nostartfiles -o $@ \ + -T $(PLATFORM)_$(@F:.$(FILETYPE)=.ld) +DISASSEMBLE = $(OBJDUMP) --source --disassemble $@> \ + $(@:.$(FILETYPE)=.dis) + +MAKE_CTAGS = ctags --file-tags=yes -n -L cscope.files +MAKE_MONSYMS = $(TOOLBIN)/monsym -p0x -Pmm_ -Sx $(@:.$(FILETYPE)=.gsym) > \ + $(@:.$(FILETYPE)=.usym) +DUMP_MAP_ALT = $(TOOLBIN)/$(FILETYPE) -m $@ +MAKE_BINARY_ALT = $(TOOLBIN)/$(FILETYPE) -B $(@:.$(FILETYPE)=.bin) $@ + +############################################################################ +# +# Various source lists used to build libraries: +# +FATFSSRC = ff.c ffcmd.c cc932.c + +ZLIBSRC = adler32.c gzio.c infblock.c infcodes.c inffast.c inflate.c \ + inftrees.c infutil.c trees.c uncompr.c zcrc32.c zutil.c + +GLIBSRC = abs.c asctime.c atoi.c crc16.c crc32.c div.c \ + getopt.c inrange.c ldiv.c memccpy.c memchr.c \ + memcmp.c memcpy.c memset.c pollconsole.c prascii.c printmem.c \ + smemcpy.c smemset.c strcat.c strchr.c strcasecmp.c \ + strcmp.c strcpy.c strlen.c strncat.c strncmp.c \ + strncpy.c strpbrk.c strrchr.c strstr.c strtok.c \ + strtol.c strtoul.c strtolower.c swap.c ticktock.c diff --git a/main/make/defaults.make b/main/make/defaults.make new file mode 100644 index 0000000..13ac240 --- /dev/null +++ b/main/make/defaults.make @@ -0,0 +1,23 @@ +############################################################################ +# +# defaults.make: +# Miscellaneous defaults that can be overridden in the makefile. +# +# LEDIT: +# Line editor mode (vt100 or vi)... +LEDIT = ledit_vt100.c + +# TFSCLEAN: +# Powersafe defrag (tfsclean1) or non-powersafe defrag (tfsclean2)... +TFSCLEAN = tfsclean1.c + +# FLASHDIR: +# For systems that use the newer style flash driver, use +# $(BASE)/flash/devices, or for the older drivers, refer +# to the flash/boards directory. +FLASHDIR = $(BASE)/flash/devices + +# DHCP: +# For standard DHCP, use dhcp_00.c, else refer to other dhcp_XX.c file +# for options. +DHCP = dhcp_00.c diff --git a/main/make/objects.make b/main/make/objects.make new file mode 100644 index 0000000..ec3da67 --- /dev/null +++ b/main/make/objects.make @@ -0,0 +1,25 @@ +# Object lists built from the target-specific source lists: +# +# LOCSSRC: Assembly source code files in this directory. +# CPUSSRC: Assembly source code files in the common/cpu directory. +# LOCCSRC: C source code files in this directory. +# COMCSRC: C source code files in the common/monitor directory. +# CPUCSRC: C source code files in the common/cpu directory. +# +LOCSOBJ = $(LOCSSRC:%.S=%.o) +LOCCOBJ = $(LOCCSRC:%.c=%.o) +CPUSOBJ = $(CPUSSRC:%.S=%.o) +CPUCOBJ = $(CPUCSRC:%.c=%.o) +COMCOBJ = $(COMCSRC:%.c=%.o) + +# FATFSOBJ: C source code files used by elm-fatfs +FATFSOBJ = $(FATFSSRC:%.c=%.o) + +# ZLIBOBJ: C source code files in the common/zlib directory. +ZLIBOBJ = $(ZLIBSRC:%.c=%.o) + +# GLIBOBJ: C source code files in the common/glib directory. +GLIBOBJ = $(GLIBSRC:%.c=%.o) + +FLASHOBJ = $(FLASHSRC:%.c=%.o) +IODEVOBJ = $(IODEVSRC:%.c=%.o) diff --git a/main/make/rules.make b/main/make/rules.make new file mode 100644 index 0000000..1918fda --- /dev/null +++ b/main/make/rules.make @@ -0,0 +1,461 @@ +########################################################################### +# +# targets.make: +# Targets used by all target builds. +# +-include $(DEPENDFILE) + +$(LOCSOBJ): + $(CC) $(ASMFLAGS) -o ${@F} $(@:%.o=%.S) + +$(LOCCOBJ): + $(CC) $(CFLAGS) -o ${@F} $(@:%.o=%.c) + +$(CPUSOBJ): + $(CC) $(ASMFLAGS) -o ${@F} $(CPUDIR)/$(@:%.o=%.S) + +$(CPUCOBJ): + $(CC) $(CFLAGS) -o ${@F} $(CPUDIR)/$(@:%.o=%.c) + +$(COMCOBJ): + $(CC) $(CFLAGS) -o ${@F} $(COMDIR)/$(@:%.o=%.c) + +$(IODEVOBJ): + $(CC) $(CFLAGS) -o ${@F} $(DEVDIR)/$(@:%.o=%.c) + +$(FLASHOBJ): + $(CC) $(CFLAGS) -o ${@F} $(FLASHDIR)/$(@:%.o=%.c) + +$(ZLIBOBJ): + $(CC) $(CFLAGS) -o ${@F} $(ZLIBDIR)/$(@:%.o=%.c) + +$(GLIBOBJ): + $(CC) $(CFLAGS) -o ${@F} $(GLIBDIR)/$(@:%.o=%.c) + +$(FATFSOBJ): + $(CC) $(CFLAGS) -o ${@F} $(FATFSDIR)/$(@:%.o=%.c) + +libg.a: $(GLIBOBJ) + $(AR) rc libg.a $(GLIBOBJ) + +libz.a: $(ZLIBOBJ) + $(AR) rc libz.a $(ZLIBOBJ) + +libfatfs.a: $(FATFSOBJ) + $(AR) rc libfatfs.a $(FATFSOBJ) + +########################################################################### +# +# depend: +# Build a file of dependencies to be included in the main makefile. +# +$(DEPEND): + @if [ ! -f $(DEPENDFILE) ] ; \ + then \ + for obj in $(LOCSSRC); do \ + $(CC) $(COMMON_AFLAGS) $(CUSTOM_AFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) -MM $$obj >>$(DEPENDFILE) ; \ + echo $$obj dependencies... ; \ + done; \ + for obj in $(LOCCSRC); do \ + $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) -MM $$obj >>$(DEPENDFILE) ; \ + echo $$obj dependencies... ; \ + done; \ + for obj in $(CPUSSRC); do \ + $(CC) $(COMMON_AFLAGS) $(CUSTOM_AFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) -MM $(CPUDIR)/$$obj >>$(DEPENDFILE) ; \ + echo $$obj dependencies... ; \ + done; \ + for obj in $(CPUCSRC); do \ + $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) -MM $(CPUDIR)/$$obj >>$(DEPENDFILE) ; \ + echo $$obj dependencies... ; \ + done; \ + for obj in $(COMCSRC); do \ + $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) -MM $(COMDIR)/$$obj >>$(DEPENDFILE) ; \ + echo $$obj dependencies... ; \ + done; \ + for obj in $(IODEVSRC); do \ + $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) -MM $(DEVDIR)/$$obj >>$(DEPENDFILE) ; \ + echo $$obj dependencies... ; \ + done; \ + for obj in $(FLASHSRC); do \ + $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) -MM $(FLASHDIR)/$$obj >>$(DEPENDFILE) ; \ + echo $$obj dependencies... ; \ + done; \ + for obj in $(ZLIBSRC); do \ + $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) -MM $(ZLIBDIR)/$$obj >>$(DEPENDFILE) ; \ + echo $$obj dependencies... ; \ + done; \ + for obj in $(GLIBSRC); do \ + $(CC) $(COMMON_CFLAGS) $(CUSTOM_CFLAGS) $(COMMON_INCLUDE) \ + $(CUSTOM_INCLUDE) -MM $(GLIBDIR)/$$obj >>$(DEPENDFILE) ; \ + echo $$obj dependencies... ; \ + done; \ + fi + + +########################################################################### +# +# builddir: +# All output files that are not just .o's or .a's are put in the +# build directory, so make sure that directory exists... +# +$(BUILDDIR): + @if ! test -d $(BUILDDIR) ; then rm -f $(BUILDDIR); mkdir $(BUILDDIR); fi + +########################################################################### +# +# clobber: +# Remove all files built by this makefile... +# +clobber: + rm -f *.o *.a *.ld + rm -rf $(BUILDDIR) tags cscope* *.gz *.ld depends + +########################################################################### +# +# clean: +# Remove all the object files that were built by this makefile... +# +clean: + rm -f *.o *.a + +########################################################################### +# Added on 6-6-05, to make boot and ramtst files with only one command +# Top level target: all +# +all: boot ramtst + +########################################################################### +# +# ctags: +# Build tags file for use by various editors. +# +ctags: + @if ! test -f cscope.files ; then make cscope; fi + $(MAKE_CTAGS) + +########################################################################### +# +# cscope: +# Build 'cscope.files' file, which consists of all source files +# that make up the build. It is used by the cscope tool. +# +cscope: cscope_local + for file in $(LOCSOBJ:%.o=%.S); do ls $$file \ + >>cscope.files; done + for file in $(LOCCOBJ:%.o=%.c); do ls $$file \ + >>cscope.files; done + for file in $(CPUSOBJ:%.o=%.S); do ls $(CPUDIR)/$$file \ + >>cscope.files; done + for file in $(CPUCOBJ:%.o=%.c); do ls $(CPUDIR)/$$file \ + >>cscope.files; done + for file in $(COMCOBJ:%.o=%.c); do ls $(COMDIR)/$$file \ + >>cscope.files; done + for file in $(IODEVOBJ:%.o=%.c); do ls $(DEVDIR)/$$file \ + >>cscope.files; done + for file in $(GLIBOBJ:%.o=%.c); do ls $(GLIBDIR)/$$file \ + >>cscope.files; done + for file in $(ZLIBOBJ:%.o=%.c); do ls $(ZLIBDIR)/$$file \ + >>cscope.files; done + ls $(COMDIR)/monbuilt.c >>cscope.files + ls *.h >>cscope.files + ls $(CPUDIR)/*.h >>cscope.files + ls $(COMDIR)/*.h >>cscope.files + ls $(ZLIBDIR)/*.h >>cscope.files + +########################################################################### +# +# libgcc: +# Dump the current libgcc library +# +libgcc: + @$(CC) --print-libgcc-file-name + + +########################################################################### +# +# buildcheck: +# Check for the presence of the BUILD variable and $(BUILDDIR) directory. +# +buildcheck: +ifeq ($(BUILD),) + @echo Must set BUILD variable. + @exit 1 +endif + @if ! test -d $(BUILDDIR) ; \ + then \ + echo Directory $(BUILDDIR) doesn\'t exist; \ + exit 1; \ + fi + +########################################################################### +# +# monsym: +# Build the symbol table file used by the monitor +# +monsym: buildcheck + @if ! test -f $(BUILDDIR)/$(BUILD).gsym ; \ + then \ + echo File $(BUILDDIR)/$(BUILD).gsym doesn\'t exist; \ + exit 1; \ + fi + $(TOOLBIN)/monsym -Pmm_ -Sx $(BUILDDIR)/$(BUILD).gsym \ + > $(BUILDDIR)/$(BUILD).usym + +########################################################################### +# +# strip: +# Remove symbols from ramtst.elf image. +# +strip: + @if ! test -f $(BUILDDIR)/ramtst.elf ; \ + then \ + echo File $(BUILDDIR)/ramtst.elf doesn\'t exist; \ + exit 1; \ + fi + $(STRIP) $(BUILDDIR)/ramtst.elf + +########################################################################### +# +# map: +# Dump a map of the specified build using objdump. +# +map: buildcheck + @if ! test -f $(BUILDDIR)/$(BUILD).elf ; \ + then \ + echo File $(BUILDDIR)/$(BUILD).elf doesn\'t exist; \ + exit 1; \ + fi + $(OBJDUMP) -fh $(BUILDDIR)/$(BUILD).elf + +########################################################################### +# +# emap: +# Dump a map of the specified build using the 'elf' tool. +# +emap: buildcheck + @if ! test -f $(BUILDDIR)/$(BUILD).elf ; \ + then \ + echo File $(BUILDDIR)/$(BUILD).elf doesn\'t exist; \ + exit 1; \ + fi + $(TOOLBIN)/elf -m $(BUILDDIR)/$(BUILD).elf + +########################################################################### +# +# rebuild: +# Rebuild entirely. +# +rebuild: clobber depend boot ramtst + @echo + +########################################################################### +# +# dis: +# Generate a source/assembly file from the specified build. +# +dis: buildcheck + @if ! test -f $(BUILDDIR)/$(BUILD).elf ; \ + then \ + echo File $(BUILDDIR)/$(BUILD).elf doesn\'t exist; \ + exit 1; \ + fi + $(OBJDUMP) --source --disassemble $(BUILDDIR)/$(BUILD).elf > \ + $(BUILDDIR)/$(BUILD).dis + +########################################################################### +# +# newmon: +# Use the newmon tool to overwrite a running monitor. +# Allow the makefile to use "NEWMONBASE" as an override of the +# default "BOOTROMBASE" for specifying the base address at which +# newmon is to place the image. +# +newmon: + @if ! test -f $(BUILDDIR)/boot.bin ; \ + then \ + echo File $(BUILDDIR)/boot.bin doesn\'t exist; \ + exit 1; \ + fi +ifndef TARGET_IP + @echo "Must specify TARGET_IP on command line (or environment)." + @exit 1 +endif +ifdef NEWMONBASE + $(TOOLBIN)/newmon -u -B $(NEWMONBASE) $(TARGET_IP) $(BUILDDIR)/boot.bin +else +ifndef BOOTROMBASE + @echo "Must specify BOOTROMBASE or NEWMONBASE." + @exit 1 +endif + $(TOOLBIN)/newmon -u -B $(BOOTROMBASE) $(TARGET_IP) $(BUILDDIR)/boot.bin +endif + +########################################################################### +# +# rundisable: +# Build the tfs.c file with -D TFS_RUN_DISABLE defined so that the +# image can be built with no ability to autoboot. +# +rundisable: + $(CC) $(COMMON_CFLAGS) -D TFS_RUN_DISABLE $(CUSTOM_CFLAGS) \ + $(COMMON_INCLUDE) -o tfs.o $(COMDIR)/tfs.c + +########################################################################### +# +# tar: +# Create a .tgz file that includes the current port & template source, +# portions of umon_main applicable to the port and umon_apps/demo_app. +# This assumes that umon_main and umon_ports are peer directories +# that reside under the top-most directory level called "umon". +# +tar: clean + @rm -f *.tgz cscope.out tags + @/bin/sh -c "cd $(UMONTOP)/host; make clean" + @/bin/sh -c "cd $(UMONTOP)/../.. ; tar -cvzf umon_$(PLATFORM).tgz \ + umon/README umon/umon_main/README \ + umon/umon_main/host umon/umon_main/target/common \ + umon/umon_main/target/cpu/$(CPUTYPE) \ + umon/umon_main/target/dev umon/umon_main/target/make \ + umon/umon_main/target/flash/$(FLASHSUBDIR) \ + umon/umon_ports/template $(PORTDIR)/$(TGTDIR) \ + umon/umon_main/target/fs umon/umon_main/target/glib \ + umon/umon_main/target/zlib umon/umon_apps/demo \ + umon/umon_apps/user_manual" + mv $(UMONTOP)/../../umon_$(PLATFORM).tgz . + +########################################################################### +# +# bdibuild: +# Build all the stuff needed to create the images (boot.bin & ramtst.elf) +# used for BDI2000 recovery. +# +bdibuild: clobber depend boot rundisable ramtst clean + echo The ramtst target is built with "TFS run" disabled. + +########################################################################### +# +# recovercopy: +# Primarily used by esutter to copy the recovery file set to the +# umon_recover directory. This is usually done after a "make bdibuild" +# has done and tested. +# +recovercopy: + @if ! test -f $(BUILDDIR)/boot.bin ; \ + then \ + echo File $(BUILDDIR)/boot.bin doesn\'t exist; \ + exit 1; \ + fi + @if ! test -f $(BUILDDIR)/ramtst.elf ; \ + then \ + echo File $(BUILDDIR)/ramtst.elf doesn\'t exist; \ + exit 1; \ + fi + @if ! test -f bdi2000.cfg ; \ + then \ + echo File bdi2000.cfg doesn\'t exist; \ + exit 1; \ + fi + @if ! test -f bdi_hookup.jpg ; \ + then \ + echo File bdi_hookup.jpg doesn\'t exist; \ + exit 1; \ + fi + @rm -rf ../../umon_recover/$(TGTDIR) + @mkdir ../../umon_recover/$(TGTDIR) + @mkdir ../../umon_recover/$(TGTDIR)/$(BUILDDIR) + @cp $(BUILDDIR)/boot.bin ../../umon_recover/$(TGTDIR)/$(BUILDDIR) + @cp $(BUILDDIR)/ramtst.elf ../../umon_recover/$(TGTDIR)/$(BUILDDIR) + @cp bdi2000.cfg ../../umon_recover/$(TGTDIR) + @cp bdi_hookup.jpg ../../umon_recover/$(TGTDIR) + @echo Recovery file set for $(PLATFORM): + @find ../../umon_recover/$(TGTDIR) -type f + + + +########################################################################### +# +# dld: +# Use the ttftp tool to download the ramtst elf image into TFS. +# +dld: strip +ifndef TARGET_IP + @echo "Must specify TARGET_IP on command line (or environment)." + @exit 1 +endif + @if ! test -f $(BUILDDIR)/ramtst.elf ; \ + then \ + echo File $(BUILDDIR)/ramtst.elf doesn\'t exist; \ + exit 1; \ + fi + $(TOOLBIN)/ttftp $(TARGET_IP) put $(BUILDDIR)/ramtst.elf ramtst,E + +########################################################################### +# +# dldbin: +# Use the ttftp tool to download the ramtst binary image into RAM. +# +dldbin: +ifndef TARGET_IP + @echo "Must specify TARGET_IP on command line (or environment)." + @exit 1 +endif + @if ! test -f $(BUILDDIR)/ramtst.bin ; \ + then \ + echo File $(BUILDDIR)/ramtst.bin doesn\'t exist; \ + exit 1; \ + fi + $(TOOLBIN)/ttftp $(TARGET_IP) put $(BUILDDIR)/ramtst.bin $(RAMTSTBASE) + + +########################################################################### +# +# help: +# Dump the common make targets and their purpose: +# +help: help_local + @echo The following generic make-targets are available: + @echo "boot: Build a bootrom-resident version of uMon" + @echo "ramtst: Build a ram-resident version of uMon for testing" + @echo "clobber: Remove all files built by this makefile." + @echo "clean: Remove all object files built by this makefile." + @echo "ctags: Build a tags file for use by most source editors." + @echo "cscope: Build a cscope.files file for use by cscope." + @echo "libgcc: Dump the libgcc used." + @echo "depend: Create a dependency list (file=depends) for the build." + @echo "map: Dump a map of the build using objdump." + @echo " This requires BUILD=xxxx to be specified on the" + @echo " make command line. The value of xxxx will usually" + @echo " be 'boot', 'ram' or 'ramtst'." + @echo " Example: make BUILD=boot map" + @echo "emap: Dump a map of the build using the 'elf' tool." + @echo " See notes on 'map' above regarding BUILD." + @echo "monsym: Create the symbol table file (*.usym) used by" + @echo " MicroMonitor. See note in 'map' above regarding BUILD." + @echo "dis: Create a source/disassembly file (*.dis) of the image." + @echo " See note in 'map' above regarding BUILD." + @echo "rebuild: Concatenation of \"clobber, depend, boot and ramtst\"" + @echo "newmon: Run through the steps needed to burn a new monitor" + @echo " Must specify TARGET_IP=a.b.c.d" + @echo "dld: Download the ramtst image to the target." + @echo " Must specify TARGET_IP=a.b.c.d" + @echo "rundisable:" + @echo " Rebuild with the tfs run functionality disabled." + @echo "bdibuild: Build the files used for BDI2000 disaster recovery." + @echo + @echo Build-specific outputs for $(PLATFORM) are suffixed as follows: + @echo " *.bin: Raw binary image of build, suitable for transfer" + @echo " directly to memory." + @echo " *.elf: ELF-formatted image." + @echo " *.dis: Disassembly of uMon build." + @echo " *.gsym: Symbol table formatted by gnu tools (nm)." + @echo " *.usym: Symbol table formatted by uMon tools (monsym)." + @echo and will be placed in the directory \"build_$(PLATFORM)\". + @echo diff --git a/main/zlib/README b/main/zlib/README new file mode 100644 index 0000000..f71730c --- /dev/null +++ b/main/zlib/README @@ -0,0 +1,25 @@ + This code is taken from ftp://ftp.freesoftware.com/pub/infozip/zlib/. + For conditions of distribution and use, see copyright notice in zlib.h + Most of the code is untouched from the original. The gzio.c file contains + the majority of the rework for use within MicroMonitor. + + The ZLIB homepage is http://www.info-zip.org/pub/infozip/zlib + + + General notice: + This code is part of a boot-monitor package developed as a generic base + platform for embedded system designs. As such, it is likely to be + distributed to various projects beyond the control of the original + author. Please notify the author of any enhancements made or bugs found + so that all may benefit from the changes. In addition, notification back + to the author will allow the new user to pick up changes that may have + been made by other users after this version of the code was distributed. + + Note1: the majority of this code was edited with 4-space tabs. + Note2: as more and more contributions are accepted, the term "author" + is becoming a mis-representation of credit. + + Original author: Ed Sutter + Email: esutter@lucent.com + Phone: 908-582-2351 + diff --git a/main/zlib/adler32.c b/main/zlib/adler32.c new file mode 100644 index 0000000..3b8249f --- /dev/null +++ b/main/zlib/adler32.c @@ -0,0 +1,46 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zlib.h" + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff --git a/main/zlib/adler_mail_1.txt b/main/zlib/adler_mail_1.txt new file mode 100644 index 0000000..6084cd2 --- /dev/null +++ b/main/zlib/adler_mail_1.txt @@ -0,0 +1,23 @@ +Subject: Re: copies of zlib source code +Date: Wed, 15 Dec 1999 13:12:37 -0800 +From: Mark Adler <Mark.Adler@quest.jpl.nasa.gov> +To: esutter@lucent.com +CC: jloup@gzip.org + +At 1:03 PM -0600 12/15/99, Ed wrote: +>Is there any problem with providing copies of the zlib source +>within the directory structure of the other code I am releasing +>or must I indirectly refer to your zlib web site and have users +>get it from there? + +No there is no problem, you can distribute it directly. You must not +misrepresent the origin of the source. If you have modified the zlib +sources at all, then you have to mark them as such and include that +in the ChangeLog. + +I recommend that you include a reference to the zlib web site so that +users can if they wish get the latest version. + + http://www.cdrom.com/pub/infozip/zlib/ + +mark diff --git a/main/zlib/adler_mail_2.txt b/main/zlib/adler_mail_2.txt new file mode 100644 index 0000000..9aa117c --- /dev/null +++ b/main/zlib/adler_mail_2.txt @@ -0,0 +1,12 @@ +Subject: Re: copies of zlib source code +Date: Thu, 16 Dec 1999 13:29:34 -0800 +From: Mark Adler <Mark.Adler@quest.jpl.nasa.gov> +To: esutter@lucent.com + +At 4:04 PM -0500 12/16/99, Ed Sutter wrote: +>Is there any license associated with zlib? + +It is simply the copyright notice, which is in zlib.h, and repeated +in the README file. That gives you license to use the code. + +mark diff --git a/main/zlib/deflate.h b/main/zlib/deflate.h new file mode 100644 index 0000000..f94fa4a --- /dev/null +++ b/main/zlib/deflate.h @@ -0,0 +1,316 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-1998 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _DEFLATE_H +#define _DEFLATE_H + +#include "zutil.h" + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int noheader; /* suppress zlib header and adler32 */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif diff --git a/main/zlib/gzio.c b/main/zlib/gzio.c new file mode 100644 index 0000000..8225dc0 --- /dev/null +++ b/main/zlib/gzio.c @@ -0,0 +1,455 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * This has been seriously re-arranged for use within MicroMonitor. + * The majority of the rework is to strip out unnecessary parts because this + * will reside in flash space. Also, there is no file system interface, all + * decompression is done from one point in memory to another point in memory. + */ + +#include "config.h" +#if INCLUDE_UNZIP +#include "tfs.h" +#include "cli.h" +#include "tfsprivate.h" +#include "genlib.h" +#include "zutil.h" + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free((char *)p);} + +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ +} gz_stream; + + +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + gzInit(): + Rewritten (from gzopen()) to support only decompression of data in + memory. The next_in member points directly to the compressed data and + avail_in is the number of bytes remaining. + Things get simpler because of the removal of the file system interface + as well as the "only decompression" mode. +*/ +gz_stream * +gzInit(unsigned char *compressed_data,int size) +{ + int err; + gz_stream *s; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) + return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = compressed_data; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = size; + s->stream.avail_out = 0; + s->z_err = Z_OK; + s->z_eof = 0; + s->crc = zcrc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + s->mode = 'r'; + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK) { + destroy(s); + return((gz_stream *)Z_NULL); + } + + s->stream.avail_out = Z_BUFSIZE; + check_header(s); /* skip the .gz header */ + return(s); +} + +/* =========================================================================== + get_byte() + Simple now because we assume that avail_in is pointing to the number + of bytes in the source buffer that are remaining to be decompressed + and next_in is the pointer to the next byte to be retrieved from the + buffer. +*/ +local int +get_byte(s) +gz_stream *s; +{ + if (s->z_eof) + return EOF; + if (s->stream.avail_in == 0) { + s->z_eof = 1; + return EOF; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + check_header(): + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void +check_header(s) +gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Check the gzip magic header */ + for (len = 0; len < 2; len++) { + c = get_byte(s); + if (c != gz_magic[len]) { + if (len != 0) { + s->stream.avail_in++; + s->stream.next_in--; + } + if (c != EOF) { + s->stream.avail_in++; + s->stream.next_in--; + s->transparent = 1; + } + s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; + return; + } + } + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) + (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + +/* =========================================================================== + destroy(): + Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. +*/ +local int +destroy (s) +gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) + err = inflateEnd(&(s->stream)); + + if (s->z_err < 0) + err = s->z_err; + + TRYFREE(s->outbuf); + TRYFREE(s); + return err; +} + +/* =========================================================================== + gzRead(): + Reads the given number of uncompressed bytes from the compressed file. + gzRead returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT +gzRead (gzFile file, voidp buf,unsigned len) +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + while (s->stream.avail_out != 0) { + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy((char *)s->stream.next_out, (char *)s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + int i, c; + + for(i=0;i<(int)(s->stream.avail_out);i++) { + c = get_byte(s); + if (c == EOF) + break; + *next_out++ = (Byte)c; + s->stream.avail_out--; + } + } + len -= s->stream.avail_out; + s->stream.total_in += (uLong)len; + s->stream.total_out += (uLong)len; + if (len == 0) + s->z_eof = 1; + return (int)len; + } + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = zcrc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may + * be different from s->stream.total_out) in case of + * concatenated .gz files. Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + uLong total_in = s->stream.total_in; + uLong total_out = s->stream.total_out; + + inflateReset(&(s->stream)); + s->stream.total_in = total_in; + s->stream.total_out = total_out; + s->crc = zcrc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) + break; + } + s->crc = zcrc32(s->crc, start, (uInt)(s->stream.next_out - start)); + return (int)(len - s->stream.avail_out); +} + +/* =========================================================================== + getLong(): + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong +getLong (s) +gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + unZip(): + This is the front end to the whole zlib decompressor. + It is a chop-up of the original minigzip.c code that came with + the zlib source. +*/ +int +unZip(char *src, int srclen, char *dest, int destlen) +{ + int len; + gz_stream *s; + + if ((s = gzInit((unsigned char *)src,srclen)) == Z_NULL) { + printf("gzInit(0x%lx,%d) failed!\n",(ulong)src,srclen); + return(-1); + } + len = gzRead(s,dest,destlen); + if (len < 0) + printf("gzRead() returned %d\n",len); + + destroy(s); + + if (len > 0) { + flushDcache(dest,len); + invalidateIcache(dest,len); + } + + return(len); +} + +char *UnzipHelp[] = { + "Decompress memory (or file) to some other block of memory.", + "-[v:] {src} [dest]", + " src: addr,len | filename", + " dest: addr[,len]", + "Options:", + " -v{varname} place decompress size into shellvar", + 0, +}; + +/* Unzip(): + * Access ZLIB decompressor from monitor command line. + */ +int +Unzip(int argc,char *argv[]) +{ + int opt, tot; + ulong srclen, destlen; + char *varname, *asc_src, *asc_dst, *comma, *src, *dest; + + destlen = 99999999; + varname = asc_dst = (char *)0; + dest = (char *)getAppRamStart(); + + while((opt=getopt(argc,argv,"v:")) != -1) { + switch(opt) { + case 'v': + varname = optarg; + break; + default: + return(CMD_PARAM_ERROR); + } + } + + if (argc == optind+1) { + asc_src = argv[optind]; + } + else if (argc == optind+2) { + asc_src = argv[optind]; + asc_dst = argv[optind+1]; + } + else { + return(CMD_PARAM_ERROR); + } + + comma = strchr(asc_src,','); + if (comma) { + *comma = 0; + src = (char *)strtoul(asc_src,(char **)0,0); + srclen = strtoul(comma+1,(char **)0,0); + } + else { + TFILE *tfp; + tfp = tfsstat(asc_src); + if (!tfp) { + printf("%s: file not found\n",asc_src); + return(CMD_FAILURE); + } + src = TFS_BASE(tfp); + srclen = TFS_SIZE(tfp); + } + + if (asc_dst) { + comma = strchr(asc_dst,','); + if (comma) { + *comma = 0; + destlen = strtoul(comma+1,(char **)0,0); + } + dest = (char *)strtoul(asc_dst,(char **)0,0); + } + + tot = unZip(src,srclen,dest,destlen); + printf("Decompressed %ld bytes from 0x%lx to %d bytes at 0x%lx.\n", + srclen,(ulong)src,tot,(ulong)dest); + + if (varname) + shell_sprintf(varname,"%d",tot); + + return(0); +} + +/* Front end to the rest of the unZip() stuff... + Return the size of the decompressed data or -1 if failure. + The same front API end is available if unpack is used instead of unzip. +*/ +int +decompress(char *src,int srclen, char *dest) +{ + return(unZip(src,srclen,dest,99999999)); +} +#else +int +decompress(char *src,int srclen, char *dest) +{ + return(-1); +} +#endif diff --git a/main/zlib/infblock.c b/main/zlib/infblock.c new file mode 100644 index 0000000..b51113a --- /dev/null +++ b/main/zlib/infblock.c @@ -0,0 +1,400 @@ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +extern int memcpy(char *,char *,int); + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +local const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); + Tracev((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_streamp z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy((char *)q, (char *)p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(s, z) +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(s, d, n) +inflate_blocks_statef *s; +const Bytef *d; +uInt n; +{ + zmemcpy((char *)s->window, (char *)d, n); + s->read = s->write = s->window + n; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(s) +inflate_blocks_statef *s; +{ + return s->mode == LENS; +} diff --git a/main/zlib/infblock.h b/main/zlib/infblock.h new file mode 100644 index 0000000..bd25c80 --- /dev/null +++ b/main/zlib/infblock.h @@ -0,0 +1,39 @@ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Bytef *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); diff --git a/main/zlib/infcodes.c b/main/zlib/infcodes.c new file mode 100644 index 0000000..d4e5ee9 --- /dev/null +++ b/main/zlib/infcodes.c @@ -0,0 +1,257 @@ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +z_streamp z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_streamp z; +{ + ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} diff --git a/main/zlib/infcodes.h b/main/zlib/infcodes.h new file mode 100644 index 0000000..6c750d8 --- /dev/null +++ b/main/zlib/infcodes.h @@ -0,0 +1,27 @@ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + diff --git a/main/zlib/inffast.c b/main/zlib/inffast.c new file mode 100644 index 0000000..61a78ee --- /dev/null +++ b/main/zlib/inffast.c @@ -0,0 +1,170 @@ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}} +#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} diff --git a/main/zlib/inffast.h b/main/zlib/inffast.h new file mode 100644 index 0000000..8facec5 --- /dev/null +++ b/main/zlib/inffast.h @@ -0,0 +1,17 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_streamp )); diff --git a/main/zlib/inffixed.h b/main/zlib/inffixed.h new file mode 100644 index 0000000..77f7e76 --- /dev/null +++ b/main/zlib/inffixed.h @@ -0,0 +1,151 @@ +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local uInt fixed_bl = 9; +local uInt fixed_bd = 5; +local inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +local inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; diff --git a/main/zlib/inflate.c b/main/zlib/inflate.c new file mode 100644 index 0000000..bcdebe1 --- /dev/null +++ b/main/zlib/inflate.c @@ -0,0 +1,370 @@ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "config.h" +#include "genlib.h" +#include "zutil.h" +#include "infblock.h" + +struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ + +typedef enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + DICT4, /* four dictionary check bytes to go */ + DICT3, /* three dictionary check bytes to go */ + DICT2, /* two dictionary check bytes to go */ + DICT1, /* one dictionary check byte to go */ + DICT0, /* waiting for inflateSetDictionary */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int ZEXPORT inflateReset(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + + +int ZEXPORT inflateEnd(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + + +int ZEXPORT inflateInit2_(z, w, version, stream_size) +z_streamp z; +int w; +const char *version; +int stream_size; +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int ZEXPORT inflateInit_(z, version, stream_size) +z_streamp z; +const char *version; +int stream_size; +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define NEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int ZEXPORT inflate(z, f) +z_streamp z; +int f; +{ + int r; + uInt b; + + WATCHDOG_MACRO; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + b = NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = BLOCKS; + break; + } + z->state->mode = DICT4; + case DICT4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = DICT3; + case DICT3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = DICT2; + case DICT2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = DICT1; + case DICT1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z->state->mode = BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +int ZEXPORT inflateSetDictionary(z, dictionary, dictLength) +z_streamp z; +const Bytef *dictionary; +uInt dictLength; +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<<z->state->wbits)) + { + length = (1<<z->state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = BLOCKS; + return Z_OK; +} + + +int ZEXPORT inflateSync(z) +z_streamp z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(z) +z_streamp z; +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} diff --git a/main/zlib/inftrees.c b/main/zlib/inftrees.c new file mode 100644 index 0000000..35dacc0 --- /dev/null +++ b/main/zlib/inftrees.c @@ -0,0 +1,457 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#if !defined(BUILDFIXED) && !defined(STDC) +# define BUILDFIXED /* non ANSI compilers may not accept inffixed.h */ +#endif + +const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ +struct internal_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uIntf *, /* list of base values for non-simple codes */ + const uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uIntf * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +local int huft_build(b, n, s, d, e, t, m, hp, hn, v) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= 288) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +const uIntf *d; /* list of base values for non-simple codes */ +const uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +inflate_huft *hp; /* space for trees */ +uInt *hn; /* hufts used in space */ +uIntf *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + r.base = 0; /* Suppress use-before-init warning */ + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(c, bb, tb, hp, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +inflate_huft *hp; /* space for trees */ +z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uIntf *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +#ifdef BUILDFIXED +local int fixed_built = 0; +#define FIXEDH 544 /* number of hufts used by fixed tables */ +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; +#else +#include "inffixed.h" +#endif + + +int inflate_trees_fixed(bl, bd, tl, td, z) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_streamp z; /* for memory allocation */ +{ +#ifdef BUILDFIXED + /* build fixed tables if not already */ + if (!fixed_built) + { + int k; /* temporary variable */ + uInt f = 0; /* number of hufts used in fixed_mem */ + uIntf *c; /* length list for huft_build */ + uIntf *v; /* work area for huft_build */ + + /* allocate memory */ + if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + { + ZFREE(z, c); + return Z_MEM_ERROR; + } + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 9; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, + fixed_mem, &f, v); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, + fixed_mem, &f, v); + + /* done */ + ZFREE(z, v); + ZFREE(z, c); + fixed_built = 1; + } +#endif + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} diff --git a/main/zlib/inftrees.h b/main/zlib/inftrees.h new file mode 100644 index 0000000..85853e0 --- /dev/null +++ b/main/zlib/inftrees.h @@ -0,0 +1,58 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_streamp)); /* for memory allocation */ diff --git a/main/zlib/infutil.c b/main/zlib/infutil.c new file mode 100644 index 0000000..4c9fd54 --- /dev/null +++ b/main/zlib/infutil.c @@ -0,0 +1,88 @@ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +extern int memcpy(char *,char *, int); +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt n; + Bytef *p; + Bytef *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + zmemcpy((char *)p, (char *)q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy((char *)p, (char *)q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} diff --git a/main/zlib/infutil.h b/main/zlib/infutil.h new file mode 100644 index 0000000..99d1135 --- /dev/null +++ b/main/zlib/infutil.h @@ -0,0 +1,98 @@ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}} +#define DUMPBITS(j) {b>>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#endif diff --git a/main/zlib/trees.c b/main/zlib/trees.c new file mode 100644 index 0000000..0bbf974 --- /dev/null +++ b/main/zlib/trees.c @@ -0,0 +1,1212 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-1998 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include <ctype.h> +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +#define MAX(a,b) (a >= b ? a : b) +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1<<extra_lbits[code]); n++) { + _length_code[length++] = (uch)code; + } + } + Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length-1] = (uch)code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<<extra_dbits[code]); n++) { + _dist_code[dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include <stdio.h> +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +local void build_tree(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute first the block length in bytes*/ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/main/zlib/trees.h b/main/zlib/trees.h new file mode 100644 index 0000000..72facf9 --- /dev/null +++ b/main/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/main/zlib/uncompr.c b/main/zlib/uncompr.c new file mode 100644 index 0000000..61e1dc6 --- /dev/null +++ b/main/zlib/uncompr.c @@ -0,0 +1,56 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/main/zlib/zconf.h b/main/zlib/zconf.h new file mode 100644 index 0000000..79b58e6 --- /dev/null +++ b/main/zlib/zconf.h @@ -0,0 +1,277 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateReset z_inflateReset +# define compress z_compress +# define compress2 z_compress2 +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32)) && !defined(STDC) +# define STDC +#endif +#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__) +# ifndef STDC +# define STDC +# endif +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Old Borland C incorrectly complains about missing returns: */ +#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500) +# define NEED_DUMMY_RETURN +#endif + + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR _far +# endif +#endif + +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if defined(ZLIB_DLL) +# if defined(_WINDOWS) || defined(WINDOWS) +# ifdef FAR +# undef FAR +# endif +# include <windows.h> +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR _cdecl _export +# endif +# endif +# if defined (__BORLANDC__) +# if (__BORLANDC__ >= 0x0500) && defined (WIN32) +# include <windows.h> +# define ZEXPORT __declspec(dllexport) WINAPI +# define ZEXPORTRVA __declspec(dllexport) WINAPIV +# else +# if defined (_Windows) && defined (__DLL__) +# define ZEXPORT _export +# define ZEXPORTVA _export +# endif +# endif +# endif +#endif + +#if defined (__BEOS__) +# if defined (ZLIB_DLL) +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +#endif + +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif +#ifndef ZEXTERN +# define ZEXTERN extern +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(MACOS) && !defined(TARGET_OS_MAC) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef HAVE_UNISTD_H +# include <sys/types.h> /* for off_t */ +# include <unistd.h> /* for SEEK_* and off_t */ +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(inflate_blocks,"INBL") +# pragma map(inflate_blocks_new,"INBLNE") +# pragma map(inflate_blocks_free,"INBLFR") +# pragma map(inflate_blocks_reset,"INBLRE") +# pragma map(inflate_codes_free,"INCOFR") +# pragma map(inflate_codes,"INCO") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_flush,"INFLU") +# pragma map(inflate_mask,"INMA") +# pragma map(inflate_set_dictionary,"INSEDI2") +# pragma map(inflate_copyright,"INCOPY") +# pragma map(inflate_trees_bits,"INTRBI") +# pragma map(inflate_trees_dynamic,"INTRDY") +# pragma map(inflate_trees_fixed,"INTRFI") +# pragma map(inflate_trees_free,"INTRFR") +#endif + +#endif /* _ZCONF_H */ diff --git a/main/zlib/zcrc32.c b/main/zlib/zcrc32.c new file mode 100644 index 0000000..55ba233 --- /dev/null +++ b/main/zlib/zcrc32.c @@ -0,0 +1,33 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zlib.h" + +#define local static +extern unsigned long crc32tab[]; + +#define DO1(buf) crc = crc32tab[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uLong ZEXPORT zcrc32(crc, buf, len) +uLong crc; +const Bytef *buf; +uInt len; +{ + if (buf == Z_NULL) + return 0L; + crc = crc ^ 0xffffffffL; + while (len >= 8) { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} diff --git a/main/zlib/zlib.h b/main/zlib/zlib.h new file mode 100644 index 0000000..923ad45 --- /dev/null +++ b/main/zlib/zlib.h @@ -0,0 +1,893 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT zcrc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = zcrc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = zcrc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int err)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* _ZLIB_H */ diff --git a/main/zlib/zutil.c b/main/zlib/zutil.c new file mode 100644 index 0000000..1819bd6 --- /dev/null +++ b/main/zlib/zutil.c @@ -0,0 +1,236 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char *z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + + +#ifndef HAVE_MEMCPY + +void +zmemcpy(dest, source, len) +Bytef* dest; +const Bytef* source; +uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifdef __TURBOC__ +#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) +/* Small and medium model in Turbo C are for now limited to near allocation + * with reduced MAX_WBITS and MAX_MEM_LEVEL + */ +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} +#endif +#endif /* __TURBOC__ */ + + +#if defined(M_I86) && !defined(__32BIT__) +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* MSC */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + extern char *malloc(int); + extern int memset(char *,int,int); + char *cp; + + if (opaque) + items += size - size; /* make compiler happy */ + cp = malloc(items*size); + if (cp) { + memset(cp,0,items*size); + return((voidpf)cp); + } + return((voidpf)0); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + extern void free(char *); + + free((char *)ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/main/zlib/zutil.h b/main/zlib/zutil.h new file mode 100644 index 0000000..52e9378 --- /dev/null +++ b/main/zlib/zutil.h @@ -0,0 +1,217 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "zlib.h" + +typedef unsigned long ulong; + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef EOF +#define EOF -1 +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include <alloc.h> +# endif +# else /* MSC or DJGPP */ +# include <malloc.h> +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include <unix.h> /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# define fdopen(fd,type) _fdopen(fd,type) +#endif + + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include <stdio.h> + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, + uInt len)); +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */ diff --git a/ports/csb740/.vimrc b/ports/csb740/.vimrc new file mode 100755 index 0000000..2a127e5 --- /dev/null +++ b/ports/csb740/.vimrc @@ -0,0 +1,13 @@ +" Very basic VIM startup file +" +" Set tab stop to 4 characters: +set ts=4 + +" Turn off syntax-sensitive coloring: +" syntax off + +" Enable C-style indentation: +" set cindent + +" Disable the highlighting of search items: +set nohlsearch diff --git a/ports/csb740/CSB740_boot.ldt b/ports/csb740/CSB740_boot.ldt new file mode 100755 index 0000000..c8bc089 --- /dev/null +++ b/ports/csb740/CSB740_boot.ldt @@ -0,0 +1,63 @@ +/* CSB740_boot.ld: + * This is the memory map file used for the boot-flash based version + * of MicroMonitor. The only value that should be considered adjustable + * here is the base address of the 'dram' memory block. + * + */ +MEMORY +{ + rom : org = ROMBASE, len = ROMLEN + dram : org = DRAMBASE, len = DRAMLEN +} + +SECTIONS +{ + .text : + { + boot_base = .; + rom_reset.o(.text) + *(.glue_7t) + *(.glue_7) + } >rom + + .data : + { + *(.data) + } >rom + + .sdata : + { + *(.sdata) + } >rom + + .sdata2 : + { + *(.sdata2) + } >rom + + .rodata : + { + *(.rodata) + *(.rodata.str1.4) + } >rom + + .got : + { + *(.got) + } >rom + + .bss : + { + bss_start = .; + atag_space = .; + . += ATAGSIZE; + end_atag_space = .; + *(.bss) *(COMMON) + } >dram + + .sbss : + { + *(.sbss) + bss_end = .; + } >dram +} diff --git a/ports/csb740/CSB740_ramtst.ldt b/ports/csb740/CSB740_ramtst.ldt new file mode 100755 index 0000000..76fbce4 --- /dev/null +++ b/ports/csb740/CSB740_ramtst.ldt @@ -0,0 +1,59 @@ +etheraddr = MACADDRBASE; +alt_tfsdevtbl_base = ALTTFSDEVTBLBASE; + +MEMORY +{ + rom : org = RAMTSTROMBASE, len = RAMTSTROMLEN +} + +SECTIONS +{ + .text : + { + boot_base = .; + ram_reset.o(.text) + *(.glue_7t) + *(.glue_7) + } >rom + + .data : + { + *(.data) + } >rom + + .sdata : + { + *(.sdata) + } >rom + + .sdata2 : + { + *(.sdata2) + } >rom + + .rodata : + { + *(.rodata) + *(.rodata.str1.4) + } >rom + + .got : + { + *(.got) + } >rom + + .bss : + { + bss_start = .; + atag_space = .; + . += ATAGSIZE; + end_atag_space = .; + *(.bss) *(COMMON) + } >rom + + .sbss : + { + *(.sbss) + bss_end = .; + } >rom +} diff --git a/ports/csb740/_vimrc b/ports/csb740/_vimrc new file mode 100755 index 0000000..2a127e5 --- /dev/null +++ b/ports/csb740/_vimrc @@ -0,0 +1,13 @@ +" Very basic VIM startup file +" +" Set tab stop to 4 characters: +set ts=4 + +" Turn off syntax-sensitive coloring: +" syntax off + +" Enable C-style indentation: +" set cindent + +" Disable the highlighting of search items: +set nohlsearch diff --git a/ports/csb740/ad7843.c b/ports/csb740/ad7843.c new file mode 100755 index 0000000..79e37ba --- /dev/null +++ b/ports/csb740/ad7843.c @@ -0,0 +1,334 @@ +//========================================================================== +// +// ad7843.c +// +// Author(s): Michael Kelly - Cogent Computer Systems, Inc. +// Date: 03/06/03 +// Description: AD7843 Interface routines for CSB740 +// Modified from MC9328mxl version to use SPI1 +// +//========================================================================== + +#include "config.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "omap3530.h" +#include "cpu_gpio.h" +#include "ad7843.h" +#include "cli.h" +#include "umongpio.h" + +//-------------------------------------------------------------------------- +// function prototypes +// +int ads_init(void); +int ads_rd(uchar ads_ctl); + +extern void udelay(int delay); + +#ifdef AD7843_GPIOMODE + +// After several days trying to get the OMAP's SPI3 controller to interface +// to the AD7843, I gave up and implemented the protocol with GPIO... +// SPI_CS: GPIO_91 +// SPI_CLK: GPIO_88 +// SPI_MOSI: GPIO_89 +// SPI_MISO: GPIO_90 + +#define clrSpiCs() GPIO3_REG(GPIO_DATAOUT) &= ~BIT27 +#define setSpiCs() GPIO3_REG(GPIO_DATAOUT) |= BIT27 +#define clrSpiClk() GPIO3_REG(GPIO_DATAOUT) &= ~BIT24 +#define setSpiClk() GPIO3_REG(GPIO_DATAOUT) |= BIT24 +#define clrSpiMosi() GPIO3_REG(GPIO_DATAOUT) &= ~BIT25 +#define setSpiMosi() GPIO3_REG(GPIO_DATAOUT) |= BIT25 +#define getSpiMiso() (GPIO3_REG(GPIO_DATAIN) & BIT26) ? 1 : 0 + + +// ads_rd(): +// A bit-banged implementation of the SPI access for AD7843... +// Slow and steady gets the job done! +// +int +ads_rd(uchar ads_ctl) +{ + ushort mask, val; + + clrSpiClk(); + clrSpiCs(); + + for(mask = 0x80;mask != 0;mask >>= 1) { + if (ads_ctl & mask) + setSpiMosi(); + else + clrSpiMosi(); + + setSpiClk(); + clrSpiClk(); + } + + val = 0; + for(mask = 0x8000;mask != 0;mask >>= 1) { + setSpiClk(); + if (getSpiMiso()) + val |= mask; + clrSpiClk(); + } + + clrSpiClk(); + setSpiCs(); + return(val); +} + +int +ads_init(void) +{ + GPIO3_REG(GPIO_OE) &= ~(BIT27 | BIT25 | BIT24); // 0 = out + GPIO3_REG(GPIO_OE) |= BIT26; + setSpiCs(); + clrSpiClk(); + clrSpiMosi(); + return(0); +} + +#else + +//-------------------------------------------------------------------------- +// ads_init()/ads_rd(): +// +// This routine sets up the OMAP3530 SPI3 port. It also turns on +// the AD7843 pen interrupt via a dummy read. We are using CS0 on SPI3. +// Can't get this to work. Signals look good on scope, but we're not +// able to read the data back; hence the need for a GPIO version (above). + +int +ads_rd(uchar ads_ctl) +{ + volatile ulong rxval; + + SPI3_REG(SPI_IRQSTATUS) = 0x0003777f; + SPI3_REG(SPI_IRQENABLE) = 0x0000007f; + SPI3_REG(SPI_CH0_CTRL) = 0x00000001; // Enable SPI3 Channel 0 + + // We have this OMAP3530 SPI ctrlr set up in 24-bit data mode, full + // duplex transmit/receive. So, put the byte to be transferred in the + // upper 8 bits of the 24-bit word, then read back the next 16 bits... + SPI3_REG(SPI_TXD0) = ads_ctl << 16; + + // Wait for the receive channel to be full... + while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_RX0_FULL)); + + SPI3_REG(SPI_IRQSTATUS) = 0x0003777f; + + // Read the value... + rxval = SPI3_REG(SPI_RXD0); + + SPI3_REG(SPI_CH0_CTRL) = 0x00000000; // Disable SPI3 Channel 0 + +// if (rxval) +// printf("%08x\n",rxval); + + return (rxval); +} + +int +ads_init() +{ + unsigned long conf; + + + // Soft reset... + SPI3_REG(SPI_SYSCONFIG) = 0x00000002; + + // Wait for reset done... + while((SPI3_REG(SPI_SYSSTATUS) & 1) == 0); + + // Configure chan zero of SPI3... + SPI3_REG(SPI_IRQSTATUS) = 0x0003777f; + SPI3_REG(SPI_IRQENABLE) = 0x0000007f; + SPI3_REG(SPI_MODULCTRL) = 0x00000000; // Master, auto CS generation + SPI3_REG(SPI_CH0_CTRL) = 0x00000001; // Enable SPI3 Channel 0 + + conf = SPI_CH_CONF_DPE0 + | SPI_CH_CONF_TRM_TR + | SPI_CH_CONF_WL(23) // 24-bit data mode + | SPI_CH_CONF_EPOL // CS is active low + | SPI_CH_CONF_SB_POL // + | SPI_CH_CONF_CLKD(9); // divide by 512 = 93Khz + + SPI3_REG(SPI_CH0_CONF) = conf; + + // enable the AD7843 so it can generate a touch interrupt. + // this consists of reading any channel, but setting the + // power down mode in the control byte to 00b. note we + // flush the returned data + + if (ads_rd(AD7843_S | AD7843_ADD_DFR_Y | AD7843_PD_MOD0) == -1) + { + printf("Error returned from ads_rd(0x%02x)!\n", (AD7843_S | AD7843_ADD_DFR_Y | AD7843_PD_MOD0)); + return -1; + } + + return 0; +} +#endif + + +//-------------------------------------------------------------------------- +char *adsHelp[] = { + "Screen touch demo using AD7843 and OMAP3530 SPI port.", + "", + "Detect screen touches and display the x,y values via", + "the AD7843 and OMAP3530 SPI port.", + 0 +}; + +int ads(int argc, char *argv[]) +{ + uchar c; + int pen, i; + //int last_x, last_y; + int sum_x, sum_y, average_x, average_y; + + // init the SPI and AD7843 + if (ads_init() == -1) + { + printf("Error intializing AD7843!\n"); + return (CMD_FAILURE); + } + + printf("Waiting for Touch (Press \'X\' to end test)...\n"); + + pen = 0; + while (1) + { + if (gotachar()) + { + c = getchar(); + if ((c == 'X') || (c == 'x')) goto done; + if (c == 'L') { + printf("In ads_rd loop...\n"); + while(1) + ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_X); + } + } + if (GPIO_tst(PIRQ) == 0) + { + printf("Pen Down....\n"); + pen = 1; + //last_x = last_y = 0; + while(GPIO_tst(PIRQ) == 0) // keep reading until touch goes away + { + sum_x = sum_y = 0; + + // display every 4 samples + for (i = 0; i < 64 ; i++) + { + sum_x += ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_X); + sum_y += ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_Y); + } + average_x = sum_x/4; + average_y = sum_y/4; + + //if ((average_x != last_x) || (average_y != last_y)) + printf("X = %04d, Y = %04d\n", average_x, average_y); + + //last_x = average_x; + //last_y = average_y; + + } // while pen is down + } + if (pen) + { + printf("Pen Up....\n"); + pen = 0; + } + + } + +done: + return(CMD_SUCCESS); +} + + +/* The next four functions are required for the "scribble" feature in + * the FBI command to work... + */ +#include "tsi.h" + +#define TOUCH_MAX_YVAL 32760 +#define TOUCH_MAX_XVAL 30752 + +/* tsi_init(): + * Used to initialize the touch screen interface. + */ +int +tsi_init(void) +{ + return(ads_init()); +} + +/* tsi_active(): + * Return 1 if the screen is being touched, else 0. + */ +int +tsi_active(void) +{ + if (GPIO_tst(PIRQ) == 0) + return(1); + return(0); +} + +/* tsi_getx()/tsi_gety(): + * Return the current 'x' or 'y' position detected by the touch screen. + * Notice that these functions return a value that is relative to the + * frame-buffer coordinates, not raw the coordinates generated by the + * touch-screen hardware. + * This requires not only that the incoming value from the AD7843 be + * normalized to the range of the X/Y coordinates of the frame buffer, + * but it also requires that the 'Y' coordinate be adjusted to be from + * top-down, not bottom up. + */ +int +tsi_getx(void) +{ + int i, val, tot, stot, tmp; + + tot = stot = 0; + + /* Attempt 8 samples, then average... + */ + for(i=0;i<8;i++) { + tmp = ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_X); + if ((tmp > 0) && (tmp < TOUCH_MAX_XVAL)) { + tot += tmp; + stot++; + } + } + tot /= stot; + + val = tot / (TOUCH_MAX_XVAL/PIXELS_PER_ROW); + return(val); +} + +int +tsi_gety(void) +{ + int i, val, tot, stot, tmp; + + tot = stot = 0; + + /* Attempt 8 samples, then average... + */ + for(i=0;i<8;i++) { + tmp = ads_rd(AD7843_S | AD7843_PD_MOD0 | AD7843_ADD_DFR_Y); + if ((tmp > 0) && (tmp < TOUCH_MAX_YVAL)) { + tot += tmp; + stot++; + } + } + tot /= stot; + + val = PIXELS_PER_COL - (tot/(TOUCH_MAX_YVAL/PIXELS_PER_COL)); + return(val); +} diff --git a/ports/csb740/ad7843.h b/ports/csb740/ad7843.h new file mode 100755 index 0000000..f4a0b71 --- /dev/null +++ b/ports/csb740/ad7843.h @@ -0,0 +1,35 @@ +//========================================================================== +// +// ad7843.h +// +// Author(s): Michael Kelly, Cogent Computer Systems, Inc. +// Contributors: +// Date: 03/06/03 +// Description: This file contains register offsets and bit defines +// for the Analog Devices AD7843 Touch Screen Controller +// + +// +// Bit positions for AD7843 Control byte +// +#define AD7843_S 0x80 // Start bit, always 1 +#define AD7843_8BIT 0x08 // 0 = 12-bit conversion, 1 = 8-bits +#define AD7843_SER 0x04 // 0 = Differential, 1 = Single ended + +// Address select defines for Single-Ended mode +#define AD7843_ADD_SER_Y (AD7843_SER | (0x1 << 4)) // Y position measurement +#define AD7843_ADD_SER_IN3 (AD7843_SER | (0x2 << 4)) // auxillary input 1 measurement +#define AD7843_ADD_SER_X (AD7843_SER | (0x5 << 4)) // X position measurement +#define AD7843_ADD_SER_IN4 (AD7843_SER | (0x6 << 4)) // auxillary input 2 measurement + +// Address select defines for Differential mode +#define AD7843_ADD_DFR_Y (0x1 << 4) // Y position measurement +#define AD7843_ADD_DFR_X (0x5 << 4) // X position measurement + +// Power Down Modes +#define AD7843_PD_MOD0 0x0 // low-power mode, no power-up delay, *IRQ is enabled +#define AD7843_PD_MOD1 0x1 // same as low-power mode, except *IRQ is disabled +#define AD7843_PD_MOD2 0x2 // device on, *IRQ is enabled +#define AD7843_PD_MOD3 0x3 // device on, *IRQ is disabled + +//#define AD7843_GPIOMODE diff --git a/ports/csb740/ads7846.c b/ports/csb740/ads7846.c new file mode 100755 index 0000000..e3b2a68 --- /dev/null +++ b/ports/csb740/ads7846.c @@ -0,0 +1,180 @@ +//========================================================================== +// +// ads7846.c +// +// Author(s): Michael Kelly - Cogent Computer Systems, Inc. +// Date: 03/06/03 +// Description: ADS7846 Interface routines for CSB740 +// Modified from MC9328mxl version to use SPI1 +// +//========================================================================== + +#include "config.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "omap3530.h" +#include "cpu_gpio.h" +#include "ads7846.h" +#include "cli.h" +#include "umongpio.h" + +//-------------------------------------------------------------------------- +// function prototypes +// +int ads_init(void); +int ads_rd(uchar ads_ctl); + +extern void udelay(int delay); + +//-------------------------------------------------------------------------- +// ads_init() +// +// This routine sets up the OMAP3530 SPI3 port in Microwire mode +// (8 bit control, 16 bit data, 24 bit total). It also turns on +// the ADS7843 pen interrupt via a dummy read. Note that we assume +// that PERCLK2 is 12Mhz (HCLK/4). We are using CS0 on SPI3. +// +int ads_init() +{ + volatile uchar temp; + + + SPI3_REG(SPI_CH0_CTRL) = 0x00; // Disable SPI3 Channel 0 + + SPI3_REG(SPI_CH0_CONF) = SPI_CH_CONF_CLKG + | SPI_CH_CONF_DPE0 // no transmission on SPI3_MISO + | SPI_CH_CONF_WL(7) // 8-bit data mode + | SPI_CH_CONF_EPOL // CS is active low +// | SPI_CH_CONF_SB_POL // +// | SPI_CH_CONF_SBE // + | SPI_CH_CONF_CLKD(9); // divide by 512 = 93Khz +// | SPI_CH_CONF_PHA; // Data is latched on even numbered edges +// | SPI_CH_CONF_POL; // SPI clock is active low + + SPI3_REG(SPI_MODULCTRL) = 0x0; // Functional mode, Master, and auto CS generation + + SPI3_REG(SPI_CH0_CTRL) = 0x01; // Enable SPI3 Channel 0 + + // enable the ADS7846 so it can generate a touch interrupt. + // this consists of reading any channel, but setting the + // power down mode in the control byte to 00b. note we + // flush the returned data + //ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_ADD_DFR_X); + ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_8BIT | ADS7846E_ADD_DFR_Y); +// ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_ADD_DFR_Y); + temp = SPI3_REG(SPI_RXD0); + + return 0; +} + +//-------------------------------------------------------------------------- +int ads_rd(uchar ads_ctl) +{ + int timeout = 100; + volatile uchar temp0, temp1; + + // the OMAP3530 only handles up to 16-bits per transfer + // so we send 8-bits at a time to get our total of 24 + +// SPI3_REG(SPI_TXD0) = ads_ctl; +// udelay(10); +// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_TX0_EMPTY)); +// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_RX0_FULL)); +// temp0 = SPI3_REG(SPI_RXD0); +// +// SPI3_REG(SPI_TXD0) = 0; +// udelay(10); +// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_TX0_EMPTY)); +// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_RX0_FULL)); +// temp0 = SPI3_REG(SPI_RXD0); +// +// SPI3_REG(SPI_TXD0) = 0; +// udelay(10); +// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_TX0_EMPTY)); +// while (!(SPI3_REG(SPI_IRQSTATUS) & SPI_RX0_FULL)); +// temp1 = SPI3_REG(SPI_RXD0); + + SPI3_REG(SPI_TXD0) = ads_ctl; + udelay(10); + while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_TX0_EMPTY)); + while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_RX0_FULL)); + temp0 = SPI3_REG(SPI_RXD0); + + SPI3_REG(SPI_TXD0) = 0; + udelay(10); + while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_TX0_EMPTY)); + while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_RX0_FULL)); + temp0 = SPI3_REG(SPI_RXD0); + +// SPI3_REG(SPI_TXD0) = 0; +// udelay(10); +// while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_TX0_EMPTY)); +// while (!(SPI3_REG(SPI_CH0_STAT) & SPI_CH_RX0_FULL)); +// temp1 = SPI3_REG(SPI_RXD0); + temp1 = 0; + return ((temp0 << 8) | temp1); +} + +//-------------------------------------------------------------------------- +char *adsHelp[] = { + "Screen touch demo using ADS7846 and OMAP3530 SPI port.", + "", + 0 +}; + +int ads(int argc, char *argv[]) +{ + uchar c; + int pen, i; + int average_x, average_y; + + // init the SPI and ADS7846 + if (ads_init() == -1) + { + printf("Error intializing ADS7846!\n"); + return (CMD_FAILURE); + } + + printf("Waiting for Touch (Press \'X\' to end test)...\n"); + + pen = 0; + while (1) + { + if (gotachar()) + { + c = getchar(); + if ((c == 'X') || (c == 'x')) goto done; + } + if (GPIO_tst(PIRQ) == 0) + { + printf("Pen Down....\n"); + pen = 1; + while(GPIO_tst(PIRQ) == 0) // keep reading until touch goes away + { + average_x = 0; + average_y = 0; + + // display every 256 samples (less if pen is down a short time) + for (i = 0; i < 256 ; i++) + { +// average_x += ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_ADD_DFR_X); +// average_y += ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_ADD_DFR_Y); + average_x += ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_8BIT | ADS7846E_ADD_DFR_X); + average_y += ads_rd(ADS7846E_S | ADS7846E_PD_ADC | ADS7846E_8BIT | ADS7846E_ADD_DFR_Y); + } + printf("X = %04d, Y = %04d\n", average_x/i, average_y/i); + + } // while pen is down + } + if (pen) + { + printf("Pen Up....\n"); + pen = 0; + } + + } + +done: + return(CMD_SUCCESS); +} diff --git a/ports/csb740/ads7846.h b/ports/csb740/ads7846.h new file mode 100755 index 0000000..9ee33dc --- /dev/null +++ b/ports/csb740/ads7846.h @@ -0,0 +1,56 @@ +//========================================================================== +// +// ads7846.h +// +// Author(s): Michael Kelly, Cogent Computer Systems, Inc. +// Contributors: +// Date: 03/06/03 +// Description: This file contains register offsets and bit defines +// for the TI ADS7846 Touch Screen Controller +// + +// +// Bit positions for ADS7846E Control byte +// +#define ADS7846E_S 0x80 // Start bit, always 1 +#define ADS7846E_8BIT 0x08 // 0 = 12-bit conversion, 1 = 8-bits +#define ADS7846E_SER 0x04 // 0 = Differential, 1 = Single ended + +// +// Address select defines for single ended mode (or'ed with the single ended select bit) +// +// USE FOR ADS7846 +//#define ADS7846E_ADD_SER_TEMP0 (ADS7846E_SER | (0x0 << 4)) // temperature measurement 1 +//#define ADS7846E_ADD_SER_Y (ADS7846E_SER | (0x1 << 4)) // Y position measurement +//#define ADS7846E_ADD_SER_BAT (ADS7846E_SER | (0x2 << 4)) // battery input measurement +//#define ADS7846E_ADD_SER_Z1 (ADS7846E_SER | (0x3 << 4)) // pressure measurement 1 +//#define ADS7846E_ADD_SER_Z2 (ADS7846E_SER | (0x4 << 4)) // pressure measurement 2 +//#define ADS7846E_ADD_SER_X (ADS7846E_SER | (0x5 << 4)) // X position measurement +//#define ADS7846E_ADD_SER_AUX (ADS7846E_SER | (0x6 << 4)) // auxillary input measurement +//#define ADS7846E_ADD_SER_TEMP1 (ADS7846E_SER | (0x7 << 4)) // temperature measurement 2 + +// USE FOR ADS7843 +//#define ADS7846E_ADD_SER_TEMP0 (ADS7846E_SER | (0x0 << 4)) // temperature measurement 1 +#define ADS7846E_ADD_SER_Y (ADS7846E_SER | (0x1 << 4)) // Y position measurement +//#define ADS7846E_ADD_SER_BAT (ADS7846E_SER | (0x2 << 4)) // battery input measurement +//#define ADS7846E_ADD_SER_Z1 (ADS7846E_SER | (0x2 << 4)) // pressure measurement 1 +//#define ADS7846E_ADD_SER_Z2 (ADS7846E_SER | (0x6 << 4)) // pressure measurement 2 +#define ADS7846E_ADD_SER_X (ADS7846E_SER | (0x5 << 4)) // X position measurement +//#define ADS7846E_ADD_SER_AUX (ADS7846E_SER | (0x6 << 4)) // auxillary input measurement +//#define ADS7846E_ADD_SER_TEMP1 (ADS7846E_SER | (0x7 << 4)) // temperature measurement 2 + +// +// Address select defines for differential mode +// +#define ADS7846E_ADD_DFR_X (0x1 << 4) // Y position measurement +//#define ADS7846E_ADD_DFR_Z1 (0x2 << 4) // pressure measurement 1 +//#define ADS7846E_ADD_DFR_Z2 (0x6 << 4) // pressure measurement 2 +#define ADS7846E_ADD_DFR_Y (0x5 << 4) // X position measurement + +// +// Power Down Modes +// +#define ADS7846E_PD_LPWR 0x0 // low-power mode, no power-up delay, *IRQ is enabled +#define ADS7846E_PD_REF 0x1 // 2.5V reference off, ADC on, requires delay before conversion +#define ADS7846E_PD_ADC 0x2 // ADC off, REF on, no delay required +#define ADS7846E_PD_IRQ 0x3 // device on, but *IRQ is disabled diff --git a/ports/csb740/bashrc b/ports/csb740/bashrc new file mode 100755 index 0000000..b329597 --- /dev/null +++ b/ports/csb740/bashrc @@ -0,0 +1,12 @@ +PS1=CSB740: +export TITLE="COGENT CSB740 ARM Monitor Development" +export UMONTOP=../../umon_main +export tools=$UMONTOP/host +export target=$UMONTOP/target +export cpu=$target/cpu +export zlib=$target/zlib +export com=$target/common +export misc=$target/misc +export make=$target/make +export flash=$target/flash +export dev=$target/dev diff --git a/ports/csb740/bdi2000.cfg b/ports/csb740/bdi2000.cfg new file mode 100755 index 0000000..93a82cf --- /dev/null +++ b/ports/csb740/bdi2000.cfg @@ -0,0 +1,188 @@ +; bdiGDB configuration for TI OMAP3430 ES1.0 +; ------------------------------------------ +; +; To halt the core as soon as possible after power-up, +; select EMU1=1,EMU0=0 (Wait In Reset mode WIR). +; +; Commands supported in the SCANINIT and SCANPOST strings: +; +; I<n>=<...b2b1b0> write IR, b0 is first scanned +; D<n>=<...b2b1b0> write DR, b0 is first scanned +; n : the number of bits 1..256 +; bx : a data byte, two hex digits +; W<n> wait for n (decimal) micro seconds +; T1 assert TRST +; T0 release TRST +; R1 assert RESET +; R0 release RESET +; CH<n> clock TCK n (decimal) times with TMS high +; CL<n> clock TCK n (decimal) times with TMS low +; +; +[INIT] +WREG CPSR 0x000001D3 ;select ARM / supervisor mode + +WM32 0x48314048 0x0000aaaa ;disable watchdog WDT2 +WM32 0x48314048 0x00005555 ;disable watchdog WDT2 + +WGPR 11 0x40200020 ;set frame pointer to free RAM +WM32 0x40200020 0x40200028 ;dummy stack frame + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Initialize Pins +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +WM32 0x48002170 0x01190019 ; Enable UART2 RX and TX +WM32 0x48002a18 0x0018010f ; Enable SYS_CLKOUT1 +WM32 0x480021e0 0x0018010f ; Enable SYS_CLKOUT2 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Initialize Clocks +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;WM32 0x48306d70 0x00000000 ; disable sys_clk1 +;WM32 0x4830729C 0x00000006 ; set polarity +WM32 0x48306814 0x00000000 ; Enable Interface clock to be Free running +WM32 0x48004e10 0x00000001 ; Enable L3_ICLK and L4_ICLK +WM32 0x48004a30 0x00006000 ; Enable Auto Clock for UART1 and UART2 +;WM32 0x48004d70 0x00000000 ; Enable source for SYS_CLKOUT2 +;WM32 0x48004d70 0x00000080 ; Enable SYS_CLKOUT2 +WM32 0x48004a00 0xc3fffe01 ; Turn on all available module clocks +WM32 0x48004a10 0x7ffffedb ; Turn on all available peripheral clocks +;WM32 0x48306d70 0x00000080 ; enable sys_clk1 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Initialize CS0 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +WM32 0x6E000010 0x08 ; Set No-idle, Normal Mode, CLK free running +WM32 0x6E000078 0x00000C48 ; Config7 +WM32 0x6E000060 0x00001200 ; Config1 +WM32 0x6E000064 0x000f0f01 ; Config2 +WM32 0x6E000068 0x00020201 ; Config3 +WM32 0x6E00006C 0x0C060C06 ; Config4 +WM32 0x6E000070 0x01131F1F ; Config5 +WM32 0x6E000074 0x0F030000 ; Config6 + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Initialize DDR +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;/* SDRAM software reset */ +;/* No idle ack and RESET enable */ +;__raw_writel(0x1A, SDRC_REG(SYSCONFIG)); +WM32 0x6D000010 0x0000001A ; reset DDR +;sdelay(100); +DELAY 100 +;/* No idle ack and RESET disable */ +;__raw_writel(0x18, SDRC_REG(SYSCONFIG)); +WM32 0x6D000010 0x00000018 ; release reset +DELAY 100 +; +;/* SDRC Sharing register */ +;/* 32-bit SDRAM on data lane [31:0] - CS0 */ +;/* pin tri-stated = 1 */ +;__raw_writel(0x00000100, SDRC_REG(SHARING)); +WM32 0x6D000044 0x00000100 +; +;/* ----- SDRC Registers Configuration --------- */ +;/* SDRC_MCFG0 register */ +;__raw_writel(0x02584099, SDRC_REG(MCFG_0)); +WM32 0x6D000080 0x02584099 +; +;/* SDRC_RFR_CTRL0 register */ +;__raw_writel(0x54601, SDRC_REG(RFR_CTRL_0)); +WM32 0x6D0000a4 0x00054601 +; +;/* SDRC_ACTIM_CTRLA0 register */ +;__raw_writel(0xA29DB4C6, SDRC_REG(ACTIM_CTRLA_0)); +WM32 0x6D00009c 0xA29DB4C6 +; +;/* SDRC_ACTIM_CTRLB0 register */ +;__raw_writel(0x12214, SDRC_REG(ACTIM_CTRLB_0)); +WM32 0x6D0000A0 0x00012214 +; +;/* Disble Power Down of CKE due to 1 CKE on combo part */ +;__raw_writel(0x00000081, SDRC_REG(POWER)); +WM32 0x6D000070 0x00000081 +; +;/* SDRC_MANUAL command register */ +;/* NOP command */ +;__raw_writel(0x00000000, SDRC_REG(MANUAL_0)); +WM32 0x6D0000A8 0x00000000 +; +;/* Precharge command */ +;__raw_writel(0x00000001, SDRC_REG(MANUAL_0)); +WM32 0x6D0000A8 0x00000001 +; +;/* Auto-refresh command */ +;__raw_writel(0x00000002, SDRC_REG(MANUAL_0)); +WM32 0x6D0000A8 0x00000002 +; +;/* Auto-refresh command */ +;__raw_writel(0x00000002, SDRC_REG(MANUAL_0)); +WM32 0x6D0000A8 0x00000002 +; +;/* SDRC MR0 register Burst length=4 */ +;__raw_writel(0x00000032, SDRC_REG(MR_0)); +WM32 0x6D000084 0x00000032 +; +;/* SDRC DLLA control register */ +;__raw_writel(0x0000000A, SDRC_REG(DLLA_CTRL)); +WM32 0x6D000060 0x0000000A + +[TARGET] +CPUTYPE OMAP3430 +CLOCK 1 ; JTAG clock +POWERUP 2000 ; power-up delay +TRST PUSHPULL ; TRST driver type (OPENDRAIN | PUSHPULL) +RESET HARD ; NONE | HARD <n> (ms) +STARTUP HALT ; let boot code setup the system +;STARTUP RUN ; let boot code setup the system +ENDIAN LITTLE ; memory model (LITTLE | BIG) +;MEMACCESS CORE 10 ; memory access via core (8 TCK's access delay) +MEMACCESS AHB 8 ; memory access via AHB (64 TCK's access delay) +;VECTOR CATCH 0x1B ; catch Abort, Undef, Reset + +SCANPRED 1 6 ; count for ICEPick TAP +SCANSUCC 1 8 ; Xilinx + +; Configure ICEPick module to make Cortex-A8 DAP-TAP visible +SCANINIT t1:w1000:t0:w1000: ; toggle TRST, +SCANINIT ch10:w1000: ; clock TCK with TMS high and wait +SCANINIT i6=07:d8=89:i6=02: ; connect and select router +SCANINIT d32=81000080: ; IP control: KeepPowered +SCANINIT d32=a3002048: ; TAP3: DebugConnect, ForcePower, ForceActive +SCANINIT d32=81000081: ; IP control: KeepPowered, SysReset +SCANINIT d32=a3002148: ; enable TAP3 +SCANINIT cl10:i10=ffff ; clock 10 times in RTI, scan bypass + +;assert SysSeset after debugger has setup +;SCANPOST i10=ffff: ; scan bypass +;SCANPOST i10=002f: ; IP(router) - TAP3(bypass) +;SCANPOST d33=0102000102: ; IP control = SysReset +;SCANPOST i10=ffff ; scan bypass + +[HOST] +IP 192.168.1.3 +FILE build_csb740\ramtst.elf +FORMAT ELF +LOAD MANUAL ;load file MANUAL or AUTO after reset +PROMPT CSB740_> +TELNET NOECHO + +[FLASH] +WORKSPACE 0x80001000 ;workspace at 0x1000 +CHIPSIZE 0x4000000 +CHIPTYPE MIRRORX16 +BUSWIDTH 16 +FILE build_csb740\boot.bin +FORMAT BIN 0x08000000 +ERASE 0x08000000 +ERASE 0x08020000 +ERASE 0x08040000 +ERASE 0x08060000 +ERASE 0x08080000 + +[REGS] +FILE C:\els\abatron\arm11\regOMAP3430.def diff --git a/ports/csb740/config.h b/ports/csb740/config.h new file mode 100755 index 0000000..8a05ff1 --- /dev/null +++ b/ports/csb740/config.h @@ -0,0 +1,202 @@ +/* + * Monitor configuration file for CSB740 + * + * Adapted by Luis Torrico, Cogent Computer Systems, Inc. + * email: luis@cogcomp.com + * + * + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Author: Ed Sutter + * email: esutter@lucent.com + * phone: 908-582-2351 + */ + +/* + * The target_putchar() function also drops the character at the + * LCD... + */ +//#define MORE_PUTCHAR lcd_putchar +//#define CONSOLE_UART_BASE (OMAP35XX_L4_IO_BASE+0x6C000) +#define CONSOLE_UART_BASE 0x4806C000 + +#define SIO_STEP 4 +#define IEN_DEFAULT 0x40 +#define MCTL_DEFAULT 0x01 + +#define TIMER_TICKS_PER_MSEC 545000 + +/* DEFAULT_ETHERADD & DEFAULT_IPADD: + * Refer to notes in ethernet.c function EthernetStartup() for details + * regarding the use of these definitions. + * DEFAULT_IPADD could be set to "DHCP" or "BOOTP" as well. + */ +#define DEFAULT_ETHERADD "00:30:23:40:00:" // Cogent Block +#define DEFAULT_IPADD "192.168.254.110" + +#define CPU_LE + +// override the app ram base to set it to 2Mbyte. This reserves space +// for umon and the LCD controller buffer +#define APPRAMBASE_OVERRIDE 0x80400000 + +// Establish a user defined function to be called when uMon +// prints out the startup banner... +// If this is defined, then the output similar to the following will +// be printed just above the uMon header... +// Silicon ID: 1.0 +// CPU Rev: 2, Variant: 1 +// CM Rev: 1.0, PRM Rev: 1.0 +// #define USR_HEADER_FUNC show_revision + +/* Defining DONT_CENTER_MONHEADER eliminates the automatic centering + * of the monitor's startup banner... + */ +#define DONT_CENTER_MONHEADER + +/* XBUFCNT & RBUFCNT: + * Number of transmit and receive buffers allocated to ethernet. + * The total of XBUFCNT+RBUFCNT should not exceed MAXEBDS + */ +#define XBUFCNT 8 +#define RBUFCNT 8 +#define XBUFSIZE 2048 +#define RBUFSIZE 2048 + +/* LOOPS_PER_SECOND: + * Approximately the size of a loop that will cause a 1-second delay. + * This can be guestimated or modified with the sleep -c command at the + * monitor command line. + */ +#define LOOPS_PER_SECOND 15000 + +#define INCLUDE_NANDCMD 0 + +#if INCLUDE_NANDCMD +/* Needed for NAND to work with TFSRAM: + */ +#define NAND_TFS_BASE 0x10000 // base of TFS in NAND + +#define FLASHRAM_BASE 0x80300000 +#define FLASHRAM_END 0x8037ffff +#define FLASHRAM_SECTORSIZE 0x00010000 +#define FLASHRAM_SPARESIZE FLASHRAM_SECTORSIZE +#define FLASHRAM_BANKNUM 1 +#define FLASHRAM_SECTORCOUNT 8 +#endif + +/* Flash bank configuration: + */ +#ifdef FLASHRAM_BASE +#define FLASHBANKS 2 +#else +#define FLASHBANKS 1 +#endif +#define SINGLE_FLASH_DEVICE 1 +#define FLASH_COPY_TO_RAM 1 +#define FLASH_BANK0_BASE_ADDR 0x08000000 +#define FLASH_PROTECT_RANGE "0-2" +#define FLASH_BANK0_WIDTH 2 +#define FLASH_LARGEST_SECTOR 0x20000 +#define FLASH_LOOP_TIMEOUT 10000000 +#define BUFFERED_WRITE + +/* TFS definitions: + * TFSSTART: Base address in FLASH at which TFS starts. + * TFSEND: End address of TFS in FLASH. + * TFSSPARE: Location of sector that is used as the spare sector + * by TFS for defragmentation. + * TFSSPARESIZE: Size of the spare sector used by TFS for defragmentation. + * TFSSECTORCOUNT: Number of eraseable sectors that TFS covers, not including + * the TFSSPARE sector. + */ +#define TFSSPARESIZE FLASH_LARGEST_SECTOR +#define TFS_DEVTOT 1 +#define TFSSTART (FLASH_BANK0_BASE_ADDR+0x060000) +//#define TFSEND (FLASH_BANK0_BASE_ADDR+0x007dffff) // 8MB Flash +#define TFSEND (FLASH_BANK0_BASE_ADDR+0x00edffff) // 16MB Flash +//#define TFSEND (FLASH_BANK0_BASE_ADDR+0x03dfffff) // 64MB Flash +#define TFSSPARE (TFSEND+1) +#define TFSSECTORCOUNT ((TFSSPARE-TFSSTART)/0x20000) +#define TFS_EBIN_ELFMSBIN 1 +#define TFS_VERBOSE_STARTUP 1 +#define TFS_ALTDEVTBL_BASE &alt_tfsdevtbl_base + +/* Specify CPU/PLATFORM type and name so that common code can be used + * for a similar cpu, on different platforms. + * The 'TYPE' definition is used for ifdefs in the code and the 'NAME' + * is used for printfs in the code. + */ +#define CPU_TYPE OMAP3530 +#define CPU_NAME "TI OMAP3530 Cortex-A8" +#define PLATFORM_TYPE CSB740 +#define PLATFORM_NAME "Cogent CSB740" + +/* Specify the size of the memory block (in monitor space) that is to be + * allocated to malloc in the monitor. Note that this size can be dynamically + * increased using the heap extension option in the heap command. + */ +#define ALLOCSIZE (64*1024) +#define MONSTACKSIZE (16*1024) + +// Cogent specific options +#define INCLUDE_I2C 0 +#define INCLUDE_LCD 1 + +/* Specify inclusion of subsystems within the monitor here. + * Refer to comments in common/monitor/inc_check.h for details on + * each of these macros. + */ + +#define INCLUDE_MEMTRACE 1 +#define INCLUDE_MEMCMDS 1 +#define INCLUDE_EDIT 1 +#define INCLUDE_DISASSEMBLER 0 +#define INCLUDE_UNZIP 1 +#define INCLUDE_ETHERNET 1 +#define INCLUDE_ICMP 1 +#define INCLUDE_TFTP 1 +#define INCLUDE_DHCPBOOT 1 +#define INCLUDE_TFS 1 +#define INCLUDE_TFSCLI 1 +#define INCLUDE_TFSAPI 1 +#define INCLUDE_TFSSCRIPT 1 +#define INCLUDE_TFSSYMTBL 1 +#define INCLUDE_XMODEM 1 +#define INCLUDE_LINEEDIT 1 +#define INCLUDE_EE 0 +#define INCLUDE_FLASH 1 +#define INCLUDE_STRACE 1 +#define INCLUDE_CAST 0 +#define INCLUDE_STRUCT 1 +#define INCLUDE_REDIRECT 1 +#define INCLUDE_QUICKMEMCPY 1 +#define INCLUDE_PROFILER 1 +#define INCLUDE_BBC 0 +#define INCLUDE_STOREMAC 1 +#define INCLUDE_SHELLVARS 1 +#define INCLUDE_MALLOC 1 +#define INCLUDE_PORTCMD 0 +#define INCLUDE_SYSLOG 1 +#define INCLUDE_HWTMR 1 +#define INCLUDE_VERBOSEHELP 1 +#define INCLUDE_GDB 1 +#define INCLUDE_USRLVL 0 +#define INCLUDE_JFFS2 0 +#define INCLUDE_JFFS2ZLIB 0 +#define INCLUDE_FBI 1 +#define INCLUDE_TSI 1 +#define INCLUDE_SD 0 +#define INCLUDE_DNS 1 + +/* Inclusion of this next file will make sure that all of the above + * inclusions are legal; and warn/adjust where necessary. + */ +#include "inc_check.h" diff --git a/ports/csb740/cpu.h b/ports/csb740/cpu.h new file mode 100755 index 0000000..ddedd7b --- /dev/null +++ b/ports/csb740/cpu.h @@ -0,0 +1,25 @@ +/* cpu.h: + General notice: + This code is part of a boot-monitor package developed as a generic base + platform for embedded system designs. As such, it is likely to be + distributed to various projects beyond the control of the original + author. Please notify the author of any enhancements made or bugs found + so that all may benefit from the changes. In addition, notification back + to the author will allow the new user to pick up changes that may have + been made by other users after this version of the code was distributed. + + Author: Ed Sutter + email: esutter@lucent.com + phone: 908-582-2351 + +*/ +#include "omap3530.h" + +#define RESETMACRO() \ +{ \ + WD2_REG(WD_WCRR) = 0xfffffff0; \ + WD2_REG(WD_WSPR) = 0x0000bbbb; \ + while(*(volatile unsigned long *)(WD2_BASE_ADD + WD_WWPS)); \ + WD2_REG(WD_WSPR) = 0x00004444; \ + while(1); \ +} diff --git a/ports/csb740/cpu_gpio.h b/ports/csb740/cpu_gpio.h new file mode 100755 index 0000000..cf071db --- /dev/null +++ b/ports/csb740/cpu_gpio.h @@ -0,0 +1,113 @@ + +//============================================================================= +// +// cpu_gpio.h +// +// CPU/Board Specific GPIO assignments +// +// Author(s): Luis Torrico, Cogent Computer Systems, Inc. +// Date: 05/12/2008 +// Description: This file contains the GPIOIO usage for the CSB733 +// +// +//============================================================================= + +// PORT 1 - Virtual GPIO Bits 0-31 +#define PORT1_VBIT 0 +// Signal Bit Dir Active Usage + +// Define initial direction (0 = output) and value +#define PORT1_OE 0xFFFFFFFF +// Define data value +#define PORT1_DR 0 + +// ----------------------------------------------------------------------------------------------- +// PORT 2 +#define PORT2_VBIT 32 +// Signal Bit Dir Active Usage +#define N_RDY_BIT BIT30 // In High NAND Ready +#define N_RDY PORT2_VBIT + 30 +#define LCD_BKL_BIT BIT26 // Out High LCD Backlight Enable +#define LCD_BKL PORT2_VBIT + 26 +#define EXP_INT_BIT BIT25 // In Low Expansion Interrupt +#define EXP_INT PORT2_VBIT + 25 + +// Define initial direction (0 = output) and value +#define PORT2_OE ~(LCD_BKL_BIT) +// Define data value +#define PORT2_DR (LCD_BKL_BIT) + +// ----------------------------------------------------------------------------------------------- +// PORT 3 +#define PORT3_VBIT 64 + +// Signal Bit Dir Active Usage +#define GPIO7_BIT BIT28 // In High Set as GPIO Input, pulled high. Shared with SPI1_CS1 +#define GPIO7 PORT3_VBIT + 28 +#define SPI3_CS0_BIT BIT27 // In High SPI3_CS0 +#define SPI3_CS0 PORT3_VBIT + 27 +#define E_INT_BIT BIT1 // In Low LAN9211 Interrupt +#define E_INT PORT3_VBIT + 1 + +// Define initial direction (0 = output) and value +#define PORT3_OE ~(SPI3_CS0_BIT) +// Define data value +#define PORT3_DR SPI3_CS0_BIT + +// ----------------------------------------------------------------------------------------------- +// PORT 4 +#define PORT4_VBIT 96 + +// Signal Bit Dir Active Usage +#define PIRQ_BIT BIT31 // In Low Touch Interrupt from ADS7843 +#define PIRQ PORT4_VBIT + 31 +#define I2C_INT_BIT BIT30 // In Low I2C Interrupt +#define I2C_INT PORT4_VBIT + 30 + +// Define initial direction (0 = output) and value +#define PORT4_OE 0xFFFFFFFF +// Define data value +#define PORT4_DR 0 + +// ----------------------------------------------------------------------------------------------- +// PORT 5 +#define PORT5_VBIT 128 + +// Signal Bit Dir Active Usage +#define U_SEL_BIT BIT12 // Out N/A Selects between USB Host or Device +#define U_SEL PORT5_VBIT + 12 +#define GPIO1_BIT BIT1 // In High Push button on CSB703 +#define GPIO1 PORT5_VBIT + 1 +#define GPIO0_BIT BIT0 // Out N/A LED on CSB703 +#define GPIO0 PORT5_VBIT + 0 + +// Define initial direction (0 = output) and value +#define PORT5_OE ~(U_SEL_BIT | GPIO0_BIT) +// Define data value +#define PORT5_DR (U_SEL_BIT | GPIO0_BIT) + +// ----------------------------------------------------------------------------------------------- +// PORT 6 +#define PORT6_VBIT 160 + +// Signal Bit Dir Active Usage +#define GPIO9_BIT BIT25 // In High Set as GPIO Input, pulled high. +#define GPIO9 PORT6_VBIT + 25 +#define GPIO8_BIT BIT24 // In High Set as GPIO Input, pulled high. +#define GPIO8 PORT6_VBIT + 24 +#define GPIO2_BIT BIT22 // In High Set as GPIO Input, pulled high. +#define GPIO2 PORT6_VBIT + 22 +#define GPIO3_BIT BIT21 // In High Set as GPIO Input, pulled high. +#define GPIO3 PORT6_VBIT + 21 +#define GPIO4_BIT BIT20 // In High Set as GPIO Input, pulled high. +#define GPIO4 PORT6_VBIT + 20 +#define GPIO5_BIT BIT19 // In High Set as GPIO Input, pulled high. +#define GPIO5 PORT6_VBIT + 19 +#define GPIO6_BIT BIT17 // In High Set as GPIO Input, pulled high. +#define GPIO6 PORT6_VBIT + 17 + +// Define initial direction (0 = output) and value +#define PORT6_OE 0xFFFFFFFF +// Define data value +#define PORT6_DR 0 + diff --git a/ports/csb740/cpu_i2c.c b/ports/csb740/cpu_i2c.c new file mode 100755 index 0000000..53c3ebb --- /dev/null +++ b/ports/csb740/cpu_i2c.c @@ -0,0 +1,322 @@ +//========================================================================== +// +// cpu_i2c.c +// +// Author(s): Michael Kelly - Cogent Computer Systems, Inc. +// Date: 03/26/2003 +// Description: Generic IIC Routines - requires I2C_SCL and I2C_SDA to +// be defined in cpu_gpio.h +// +//========================================================================== + +#include "config.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "cli.h" +#include "cpu_gpio.h" +#include "cpu_gpio.h" +#include "umongpio.h" + +//-------------------------------------------------------------------------- +// function prototypes +// +ulong i2c_init(void); +ulong i2c_wr_device(uchar dev, uchar reg, uchar data); +ulong i2c_rd_device(uchar dev, uchar reg, uchar *data); +ulong i2c_wr_byte(uchar data); +uchar i2c_rd_byte(void); +void i2c_start(void); +void i2c_stop(void); +int i2c(int argc,char *argv[]); + +extern void udelay(int delay); + +//-------------------------------------------------------------------------- +// I2C Macros +// +#define I2C_SCL_CLR GPIO_out(I2C_SCL) +#define I2C_SCL_SET GPIO_in(I2C_SCL) + +#define I2C_SDA_CLR GPIO_out(I2C_SDA) +#define I2C_SDA_SET GPIO_in(I2C_SDA) + +#define I2C_SCL_RD GPIO_tst(I2C_SCL) +#define I2C_SDA_RD GPIO_tst(I2C_SDA) + +#define I2C_DELAY udelay(1000) + +//-------------------------------------------------------------------------- +// i2c_init() +// +// I2C is a shared bus. We drive a low by setting the SCL/SDA GPIO as +// an output. We must preset a 0 in the GPIO output bit so the line will +// go low whenever we make it an output. For a high, we make the GPIO an +// input, thus letting the external pullup to pull the line high. +// +ulong i2c_init() +{ + GPIO_out(I2C_SCL); + GPIO_clr(I2C_SCL); + GPIO_in(I2C_SCL); + + GPIO_out(I2C_SDA); + GPIO_clr(I2C_SDA); + GPIO_in(I2C_SDA); + + return 0; + +} + +//-------------------------------------------------------------------------- +// i2c_wr_device() +// +// This function writes an 8-bit value to the I2C device at the requested +// register. +// +ulong i2c_wr_device(uchar dev, uchar reg, uchar data) +{ + + // issue a start command + i2c_start(); + + // write the 7-bit device address with write = 0 + if(i2c_wr_byte((dev << 1) & 0xfe)){ + return -1; + } + // Write the 8-bit register address + if(i2c_wr_byte(reg)){ + return -1; + } + // Write the 8-bit data value + if(i2c_wr_byte(data)){ + return -1; + } + + // issue a stop + i2c_stop(); + + return 0; +} + +//-------------------------------------------------------------------------- +// i2c_rd_device() +// +// This function reads an 8-bit value from the I2C device at the requested +// register. +// +ulong i2c_rd_device(uchar dev, uchar reg, uchar *data) +{ + + // issue a start command + i2c_start(); + + // write the 7-bit device address with write = 0 + if(i2c_wr_byte((dev << 1) & 0xfe)){ + return -1; + } + // Write the 8-bit register address + if(i2c_wr_byte(reg)){ + return -1; + } + // repeat the start command + i2c_start(); + // write the 7-bit device address again plus data direction (read = 1) + if(i2c_wr_byte((dev << 1) | 0x01)){ + return -1; + } + *data = i2c_rd_byte(); + + // issue a stop + i2c_stop(); + + return 0; +} + +//-------------------------------------------------------------------------- +// i2c_wr_byte() +// +// This function writes an 8-bit value to the I2C bus, MSB first. +// Data is written by changing SDA during SCL low, then bringing +// SCL high. SCL is returned low to setup for the next transition. +// +ulong i2c_wr_byte(uchar data) +{ + + int i; + + for (i = 0; i < 8; i++){ + if (data & 0x80) { + // write a 1 bit + I2C_SDA_SET; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; + } + else { + // write a 0 bit + I2C_SDA_CLR; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; + } + data = data << 1; + } + // Release SDA, bring SCL high, then read SDA. + // A low indicates an acknowledge. + I2C_SDA_SET; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + if(I2C_SDA_RD){ // a high means no ack + // re-enable SDA for output + I2C_SCL_CLR; + I2C_DELAY; + return -1; + } + + I2C_SCL_CLR; + I2C_DELAY; + + return 0; +} + +//-------------------------------------------------------------------------- +// i2c_rd_byte() +// +// This function reads an 8-bit data value from the I2C bus, MSB first. +// Data is read from SDA after each low to high SCL transition. +// +uchar i2c_rd_byte() +{ + + int i; + uchar volatile data; + + data = 0; + + for (i = 0; i < 8; i++){ + data = data << 1; + data = data & 0xfe; + // clock the data out of the slave + I2C_SCL_SET; + I2C_DELAY; + // check it + if (I2C_SDA_RD){ + data = data | 0x01; + } + I2C_SCL_CLR; + I2C_DELAY; + } + // generate an extra SCL transition + // The slave generates no acknowledge for reads. + I2C_SCL_SET; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; + + return data; +} + + +//-------------------------------------------------------------------------- +// i2c_start() +// +// This function issues an I2C start command which is a high to low +// transition on SDA while SCL is high. +// +void i2c_start() +{ + + I2C_SDA_SET; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + I2C_SDA_CLR; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; + I2C_SDA_SET; + I2C_DELAY; +} + +//-------------------------------------------------------------------------- +// i2c_stop() +// +// This function issues an I2C stop command which is a low to high +// transition on SDA while SCL is high. +// +void i2c_stop() +{ + + I2C_SDA_CLR; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + I2C_SDA_SET; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; +} + +char *i2cHelp[] = { + " This command allows the user to read ", + " and write devices on the i2c bus. \n ", + " Usage:", + " i2c -[w] {device} {register} {val/count}", + " Options...", + " -w write val to device/register", + " no options, read from device/register up to count", + 0 +}; + +int i2c(int argc,char *argv[]) +{ + int i, opt; + int write = 0; + uchar dev, reg, data, count; + + while ((opt=getopt(argc,argv,"w")) != -1) { + if (opt == 'w') write = 1; + } + + // make sure we have the right number of paramters + if (argc < (optind+3)) + return(CMD_PARAM_ERROR); + + dev = (uchar) strtoul(argv[optind],(char **)0,0); + reg = (uchar) strtoul(argv[optind+1],(char **)0,0); + + // 3rd arg is the data value if it's a write, count if it's a read + data = (uchar) strtoul(argv[optind+2],(char **)0,0); + count = data; + // do it + if (write) + { + printf("Writing 0x%02x to Device 0x%02x @ Register 0x%02x.\n", data, dev, reg); + if(i2c_wr_device(dev, reg, data)) + { + printf("I2C Bus Failure - Check Paramters!\n"); + return (CMD_FAILURE); + } + } + else + { + for (i = 0; i < count; i++) + { + printf("Read Device 0x%02x, Register 0x%02x = ", dev, reg + i); + if(i2c_rd_device(dev, reg + i, &data)) + { + printf("I2C Bus Failure - Check Paramters!\n"); + return (CMD_FAILURE); + } + printf("0x%02x.\n", data); + } + } + return(CMD_SUCCESS); +} + diff --git a/ports/csb740/cpu_i2c.h b/ports/csb740/cpu_i2c.h new file mode 100755 index 0000000..779ee67 --- /dev/null +++ b/ports/csb740/cpu_i2c.h @@ -0,0 +1,269 @@ +//========================================================================== +// +// cpu_i2c.c +// +// Author(s): Michael Kelly - Cogent Computer Systems, Inc. +// Date: 03/30/2002 +// Description: CSB272 - 405GP Single Board IIC Routines +// +//========================================================================== + +#include "config.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" + +//-------------------------------------------------------------------------- +// some 405GP I2C register and bit defines +// +#define I2C_XCTL *(vulong *)(0xef60050f) // extended control register +#define I2C_XCTL_SRST 0x01000000 // Soft Reset Bit - must be set + // to 1 to use direct control + +#define I2C_DCTL *(vulong *)(0xef600510) // direct control of IIC bits +#define I2C_DCTL_SDA_OUT 0x08000000 // SDA Out, 0 = drive low, 1 = tri-state +#define I2C_DCTL_SCL_OUT 0x04000000 // SCL Out, 0 = drive low, 1 = tri-state +#define I2C_DCTL_SDA_IN 0x02000000 // SDA In, Direct Read +#define I2C_DCTL_SCL_IN 0x01000000 // SCL In, Direct Read + +//-------------------------------------------------------------------------- +// Low level I2C Macros +// +#define I2C_SCL_CLR I2C_DCTL &= ~(I2C_DCTL_SCL_OUT) +#define I2C_SCL_SET I2C_DCTL |= (I2C_DCTL_SCL_OUT) + +#define I2C_SDA_CLR I2C_DCTL &= ~(I2C_DCTL_SDA_OUT) +#define I2C_SDA_SET I2C_DCTL |= (I2C_DCTL_SDA_OUT) + +#define I2C_SDA_RD I2C_DCTL & I2C_DCTL_SDA_IN +#define I2C_SCL_RD I2C_DCTL & I2C_DCTL_SCL_IN + +#define I2C_DELAY udelay(100) + +//-------------------------------------------------------------------------- +// function prototypes +// +ulong i2c_init(void); +ulong i2c_wr_device(uchar dev, uchar reg, uchar data); +ulong i2c_rd_device(uchar dev, uchar reg, uchar *data); +ulong i2c_wr_byte(uchar data); +uchar i2c_rd_byte(void); +void i2c_start(void); +void i2c_stop(void); + +extern void udelay(int delay); + +extern ulong sed_disp_mode; + +//-------------------------------------------------------------------------- +// i2c_init() +// +// Initialize the I2C registers for direct I2C control +ulong i2c_init() +{ + // place the automatic I2C logic in reset + I2C_XCTL |= I2C_XCTL_SRST; + + // Set the SCL and SDA outputs into tristate + I2C_DCTL |= (I2C_DCTL_SDA_OUT | I2C_DCTL_SCL_OUT); + + return 0; + +} + +//-------------------------------------------------------------------------- +// i2c_wr_device() +// +// This function writes an 8-bit value to the I2C device at the requested +// register. +// +ulong i2c_wr_device(uchar dev, uchar reg, uchar data) +{ + + // issue a start command + i2c_start(); + + // write the 7-bit device address with write = 0 + if(i2c_wr_byte((dev << 1) & 0xfe)){ + return -1; + } + // Write the 8-bit register address + if(i2c_wr_byte(reg)){ + return -1; + } + // Write the 8-bit data value + if(i2c_wr_byte(data)){ + return -1; + } + + // issue a stop + i2c_stop(); + + return 0; +} + +//-------------------------------------------------------------------------- +// i2c_rd_device() +// +// This function reads an 8-bit value from the I2C device at the requested +// register. +// +ulong i2c_rd_device(uchar dev, uchar reg, uchar *data) +{ + + // issue a start command + i2c_start(); + + // write the 7-bit device address with write = 0 + if(i2c_wr_byte((dev << 1) & 0xfe)){ + return -1; + } + // Write the 8-bit register address + if(i2c_wr_byte(reg)){ + return -1; + } + // repeat the start command + i2c_start(); + // write the 7-bit device address again plus data direction (read = 1) + if(i2c_wr_byte((dev << 1) | 0x01)){ + return -1; + } + *data = i2c_rd_byte(); + + // issue a stop + i2c_stop(); + + return 0; +} + +//-------------------------------------------------------------------------- +// i2c_wr_byte() +// +// This function writes an 8-bit value to the I2C bus, MSB first. +// Data is written by changing SDA during SCL low, then bringing +// SCL high. SCL is returned low to setup for the next transition. +// +ulong i2c_wr_byte(uchar data) +{ + + int i; + + for (i = 0; i < 8; i++){ + if (data & 0x80) { + // write a 1 bit + I2C_SDA_SET; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; + } + else { + // write a 0 bit + I2C_SDA_CLR; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; + } + data = data << 1; + } + // Release SDA, bring SCL high, then read SDA. + // A low indicates an acknowledge. + I2C_SDA_SET; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + if(I2C_SDA_RD){ // a high means no ack + // re-enable SDA for output + I2C_SCL_CLR; + I2C_DELAY; + return -1; + } + + I2C_SCL_CLR; + I2C_DELAY; + + return 0; +} + +//-------------------------------------------------------------------------- +// i2c_rd_byte() +// +// This function reads an 8-bit data value from the I2C bus, MSB first. +// Data is read from SDA after each low to high SCL transition. +// +uchar i2c_rd_byte() +{ + + int i; + uchar volatile data; + + data = 0; + + for (i = 0; i < 8; i++){ + data = data << 1; + data = data & 0xfe; + // clock the data out of the slave + I2C_SCL_SET; + I2C_DELAY; + // check it + if (I2C_SDA_RD){ + data = data | 0x01; + } + I2C_SCL_CLR; + I2C_DELAY; + } + // generate an extra SCL transition + // The slave generates no acknowledge for reads. + I2C_SCL_SET; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; + + return data; +} + + +//-------------------------------------------------------------------------- +// i2c_start() +// +// This function issues an I2C start command which is a high to low +// transition on SDA while SCL is high. +// +void i2c_start() +{ + + I2C_SDA_SET; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + I2C_SDA_CLR; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; + I2C_SDA_SET; + I2C_DELAY; +} + +//-------------------------------------------------------------------------- +// i2c_stop() +// +// This function issues an I2C stop command which is a low to high +// transition on SDA while SCL is high. +// +void i2c_stop() +{ + + I2C_SDA_CLR; + I2C_DELAY; + I2C_SCL_SET; + I2C_DELAY; + I2C_SDA_SET; + I2C_DELAY; + I2C_SCL_CLR; + I2C_DELAY; +} + + diff --git a/ports/csb740/cpuio.c b/ports/csb740/cpuio.c new file mode 100755 index 0000000..0a9a262 --- /dev/null +++ b/ports/csb740/cpuio.c @@ -0,0 +1,313 @@ +//============================================================================= +// +// cpuio.c +// +// CPU/Board Specific IO +// +// Author(s): Luis Torrico, Cogent Computer Systems, Inc. +// Date: 12/04/2008 +// Description: This file contains the IO functions required by Micro Monitor +// that are unique to the CSB740 +// +// +//============================================================================= + +#include "config.h" +#include "cpuio.h" +#include "genlib.h" +#include "ether.h" +#include "stddefs.h" +#include "warmstart.h" +#include "omap3530.h" +#include "omap3530_mem.h" +#include "cpu_gpio.h" +#include "fb_draw.h" +#include "uart16550.h" +#include "umongpio.h" +#include "ad7843.h" + +#define __raw_readl(a) (*(volatile unsigned int *)(a)) + +extern ulong i2c_init(void); +extern ulong getpsr(void); +extern void putpsr(ulong); + +uchar bcolor=0; // vga black + +/****************************************************** +// Delay for some usecs. - Not accurate, assumes ROM mode +// and no Cache + ******************************************************/ +void udelay(int delay) +{ + volatile int i; + for ( i = LOOPS_PER_USEC * delay; i ; i--); +} + +/****************************************************** + * Routine: wait_for_command_complete + * Description: Wait for posting to finish on watchdog + ******************************************************/ +void wait_for_command_complete(unsigned int wd_base) +{ + int pending = 1; + do { + pending = __raw_readl(wd_base + WD_WWPS); + } while (pending); +} + +/****************************************************** +// getUARTDivisor is called from UART16550.c + ******************************************************/ +int +getUartDivisor(int baud, unsigned char *hi, unsigned char *lo) +{ + *lo = ((48000000/16)/baud) & 0x00ff; + *hi = (((48000000/16)/baud) & 0xff00) >> 8; + return(0); +} + +/****************************************************** +// Set pads (pins) to correct mode. Refer to section 7.4.4 + in TI omap35xx_tech_ref_manual for bit defines. + ******************************************************/ +void pads_init() +{ + // Set up chip selects + SCM_REG(PADCONFS_GPMC_NCS3) = 0x00180018; // NCS3[15:0], NCS4[31:16] + SCM_REG(PADCONFS_GPMC_NCS5) = 0x011C0018; // NCS5[15:0], EXP_INTX[31:16] + + // Set LCD_BKL_X to output, pullup enabled, mode 4 + // Set LCLK to output, no pull-type and disabled, mode 0 + SCM_REG(PADCONFS_GPMC_NCS7) = 0x0000001C; // LCD_BKL_X[15:0], LCLK(or GPIO_59)[31:16] + + // Set LCD pads to outputs, pull-type = up, pullud disabled, mode 0 + SCM_REG(PADCONFS_DSS_PCLK) = 0x00100010; // LCD_PCLK_X[15:0], LCD_HS_X[31:16] + SCM_REG(PADCONFS_DSS_VSYNC) = 0x00100010; // LCD_VS_X[15:0], LCD_OE_X[31:16] + SCM_REG(PADCONFS_DSS_DATA0) = 0x00100010; // LCD_B0_X[15:0], LCD_B1_X[31:16] + SCM_REG(PADCONFS_DSS_DATA2) = 0x00100010; // LCD_B2_X[15:0], LCD_B3_X[31:16] + SCM_REG(PADCONFS_DSS_DATA4) = 0x00100010; // LCD_B4_X[15:0], LCD_B5_X[31:16] + SCM_REG(PADCONFS_DSS_DATA6) = 0x00100010; // LCD_G0_X[15:0], LCD_G1_X[31:16] + SCM_REG(PADCONFS_DSS_DATA8) = 0x00100010; // LCD_G2_X[15:0], LCD_G3_X[31:16] + SCM_REG(PADCONFS_DSS_DATA10) = 0x00100010; // LCD_G4_X[15:0], LCD_G5_X[31:16] + SCM_REG(PADCONFS_DSS_DATA12) = 0x00100010; // LCD_R0_X[15:0], LCD_R1_X[31:16] + SCM_REG(PADCONFS_DSS_DATA14) = 0x00100010; // LCD_R2_X[15:0], LCD_R3_X[31:16] + SCM_REG(PADCONFS_DSS_DATA16) = 0x00100010; // LCD_R4_X[15:0], LCD_R5_X[31:16] + + // Set D_TXD for output and D_RXD for input. Set both to pullup enabled and mode 1 + SCM_REG(PADCONFS_MCBSP3_CLKX) = 0x01190019; // D_TXD[15:0], D_RXD[31:16] + +#ifdef AD7843_GPIOMODE + // Depending on AD7843_GPIOMODE setting, we either configure the SPI + // interface to the AD7843 as a real SPI device using the OMAP's SPI + // controller, or we set it up with GPIO bits... + SCM_REG(PADCONFS_DSS_DATA18) = 0x00040004; + SCM_REG(PADCONFS_DSS_DATA20) = 0x00040104; +#else + SCM_REG(PADCONFS_DSS_DATA18) = 0x0002011A; // SPI1_CLK_X[15:0], SPI1_MOSI_X[31:16] + SCM_REG(PADCONFS_DSS_DATA20) = 0x001A011A; // SPI1_MISO_X[15:0], *SPI1_CS0_X[31:16] +#endif + + // Set PIRQ for ADS7843 touch interrupt. Set both to pullup enabled and mode 4 + SCM_REG(PADCONFS_MMC1_DAT4) = 0x01040104; // *I2C_INT_X[15:0], *PIRQ_X[31:16] + + // GPIO1 is the push button on CSB703(set as input), GPIO0 is is LED on CSB703(set as output) + SCM_REG(PADCONFS_MMC1_DAT6) = 0x01040004; // GPIO0_X[15:0], GPIO1_X[31:16] + + // Set E_INT* to be an input in GPIO mode + SCM_REG(PADCONFS_GPMC_WAIT2) = 0x011C011f; // NA[15:0], E_INTX[31:16] + + // Set SYS_CLKOUT1 for USB_CLK + SCM_REG(PADCONFS_SYS_OFF_MODE) = 0x0000010f; // OFF_MODE_X[15:0], SYS_CLKOUT1[31:16] + + // Set SYS_CLKOUT2 for debug purposes + SCM_REG(PADCONFS_SYS_NIRQ) = 0x0000011f; // FIQ[15:0], SYS_CLK2[31:16] + +} + +int +devInit(int baud) +{ + // Initialize pads + pads_init(); + + // Disable MPU Watchdog WDT2 + WD2_REG(WD_WSPR) = 0x0000aaaa; + wait_for_command_complete(WD2_BASE_ADD); + WD2_REG(WD_WSPR) = 0x00005555; + + // Initialize GPIO + GPIO_init(); + + // Setup UART pins to UART mode before calling InitUART from uart16550.c + UART2_REG(UART_MDR1) = 0x0000; + // Initialize the UART + InitUART(baud); + + // Setup CS0 for 110ns Spansion Flash + GPMC_REG(GPMC_CS0_CONFIG7) = 0x00000c48; // Base addr 0x08000000, 64M + GPMC_REG(GPMC_CS0_CONFIG1) = 0x00001210; + //GPMC_REG(GPMC_CS0_CONFIG5) = 0x00080808; // Config5 + + // Setup CS4 for LAN9211, on the CSB740 it is refered to as CS2 + // and mapped to E_CS + GPMC_REG(GPMC_CS4_CONFIG7) = 0x00000F6C; // Base addr 0x2C000000, 16M + GPMC_REG(GPMC_CS4_CONFIG1) = 0x00001200; + + return 0; +} + +/* Referring to table 25-10 of the TRM, install + * the RAM exception vectors... + */ +void +ram_vector_install(void) +{ + extern unsigned long abort_data; + extern unsigned long abort_prefetch; + extern unsigned long undefined_instruction; + extern unsigned long software_interrupt; + extern unsigned long interrupt_request; + extern unsigned long fast_interrupt_request; + extern unsigned long not_assigned; + + *(ulong **)0x4020ffe4 = &undefined_instruction; + *(ulong **)0x4020ffe8 = &software_interrupt; + *(ulong **)0x4020ffec = &abort_prefetch; + *(ulong **)0x4020fff0 = &abort_data; + *(ulong **)0x4020fff4 = ¬_assigned; + *(ulong **)0x4020fff8 = &interrupt_request; + *(ulong **)0x4020fffc = &fast_interrupt_request; +} + +void +initCPUio() +{ + volatile unsigned register cntens; + volatile unsigned register usren; + volatile unsigned register pmnc; + + ram_vector_install(); + + /* Do this stuff to enable the cycle counter + * (for use by target_timer)... + */ + /* Allow user mode to have access to performance monitor registers: + */ + asm volatile (" MRC p15, 0, %0, c9, c14, 0" : "=r" (usren)); + usren |= 1; + asm volatile (" MCR p15, 0, %0, c9, c14, 0" : : "r" (usren)); + + /* Enable all counters, and reset Cycle counter... + */ + asm volatile (" MRC p15, 0, %0, c9, c12, 0" : "=r" (pmnc)); + pmnc |= 5; + asm volatile (" MCR p15, 0, %0, c9, c12, 0" : : "r" (pmnc)); + + /* Enable all performance counter registers... + */ + asm volatile (" MRC p15, 0, %0, c9, c12, 1" : "=r" (cntens)); + cntens |= 0x8000000f; + asm volatile (" MCR p15, 0, %0, c9, c12, 1" : : "r" (cntens)); +} + +/* target_reset(): + * Set the counter to 16 ticks before trigger, then enable the + * watchdog timer (WDT2) and wait... + */ +void +target_reset(void) +{ + // Preload the count-up register... + WD2_REG(WD_WCRR) = 0xfffffff0; + + // Start MPU Watchdog WDT2 + WD2_REG(WD_WSPR) = 0x0000bbbb; + wait_for_command_complete(WD2_BASE_ADD); + WD2_REG(WD_WSPR) = 0x00004444; + + // Now just wait... + while(1); +} + +void +intsrestore(psr) +ulong psr; +{ + putpsr(psr); +} + +/* + * Read the program status register (CPSR) + * and set the FIQ and IRQ bits. + */ +ulong +intsoff(void) +{ + ulong psr; + + psr = getpsr(); + + /* + * Set bit 6, bit 7 to disable interrupts. + */ + putpsr(psr | 0x000000c0); + return(psr); +} + +/* show_revision(): + * Called when the system banner is printed... + */ +void +show_revision(int center) +{ + int (*pfunc)(char *, ...); + volatile unsigned register main_id; + volatile unsigned register silicon_id; + + if (center) + pfunc = cprintf; + else + pfunc = printf; + + asm(" MRC p15, 0, %0, c0, c0, 0" : "=r" (main_id)); + asm(" MRC p15, 1, %0, c0, c0, 7" : "=r" (silicon_id)); + + pfunc("Silicon ID: %d.%d\n", + ((silicon_id & 0xf0)>>4),(silicon_id & 0xf)); + + pfunc("CPU Rev: %d, Variant: %d\n", + main_id & 0xf,(main_id & 0x00f00000) >> 20); + + pfunc("CM Rev: %d.%d, PRM Rev: %d.%d\n", + CM_REV_MAJ(),CM_REV_MIN(),PRM_REV_MAJ(),PRM_REV_MIN()); +} + +/* target_timer(): + * Used in conjunction with INCLUDE_HWTMR and TIMER_TICKS_PER_MSEC + * to set up a hardware based time base. + */ +unsigned long +target_timer(void) +{ + volatile unsigned register ccr; + + asm(" MRC p15, 0, %0, c9, c13, 0" : "=r" (ccr)); + + return(ccr); +} + +/* cacheInitForTarget(): + Enable instruction cache only... +*/ +void +cacheInitForTarget() +{ + asm(" MRC p15, 0, r0, c1, c0, 0"); + asm(" ORR r0, r0, #0x1000"); /* bit 12 is ICACHE enable*/ + asm(" MCR p15, 0, r0, c1, c0, 0"); + + /* Flush instruction cache */ + asm(" MCR p15, 0, r0, c7, c5, 0"); +} + diff --git a/ports/csb740/cpuio.h b/ports/csb740/cpuio.h new file mode 100755 index 0000000..64ff49c --- /dev/null +++ b/ports/csb740/cpuio.h @@ -0,0 +1,76 @@ +//============================================================================= +// +// cpuio.h +// +// CPU/Board Specific IO +// +// Author(s): Luis Torrico, Cogent Computer Systems, Inc. +// Date: 05-16-2008 +// Description: This file contains the IO functions required by Micro Monitor +// that are unique to each CPU/Board combination +// +// +// cpuio.h for the CSB740 OMAP3530 Cortex-A8 +// +//============================================================================= + +// board specific defines for micro monitor +#define DEFAULT_BAUD_RATE 38400 +#define MON_CPU_CLOCK 400000000 + +#define LOOPS_PER_USEC 5 + +#define BASE_OF_NAND 0x1000 +#define SIZE_OF_NAND 0x100000 + +// SMSC LAN9211 Ethernet +#define SMSC911X_BASE_ADDRESS 0x2C000000 // CS4 on OMAP3530 but we call it CS2 + +// LCD Defines +// +// The LCD frame buffer is fixed at 0x80200000, which is 2Mbyte from the +// beginning of SDRAM space. Note that we access it 16-bits at a time. + +#define LCD_BUF_ADD 0x80200000 +#define LCD_BUF(_x_) *(vushort *)(LCD_BUF_ADD + _x_) // Frame Buffer +#define USE_FONT8X8 +#define LCD_GET_PIXEL_ADD(_X_, _Y_) (((_Y_ * PIXELS_PER_ROW) + _X_)*2) + +// defines for the display geometry - OSD043TN24 480x272 TFT +// (some of these defines are also used by uMon's frame buffer interface) +#define PIXELS_PER_ROW 480 // +#define PIXELS_PER_COL 272 // +#define BITS_PER_PIXEL 16 // +#define PIXFMT_IS_RGB565 1 +#define FBDEV_SETSTART fbdev_setstart +#define FRAME_BUFFER_BASE_ADDR LCD_BUF_ADD +#define LCD_H_WIDTH 41 // pulse width in pixels +#define LCD_H_FRONT 2 // front porch (sync to enable) +#define LCD_H_BACK 2 // back porch (enable to sync) +#define LCD_V_WIDTH 10 // pulse width in lines +#define LCD_V_FRONT 2 // front porch (sync to enable) +#define LCD_V_BACK 2 // back porch (enable to sync) +//#define LCD_PCD 2 // LCD PERCLK3 = 32Mhz/PCD +1 = Pixel Clock ~ 4Mhz + +#define TOP 1 +#define BOTTOM (PIXELS_PER_COL-1) +#define LEFT 0 +#define RIGHT (PIXELS_PER_ROW-1) +#define CENTER_X (PIXELS_PER_ROW/2) +#define CENTER_Y (PIXELS_PER_COL/2) + +#define ROWS_PER_SCREEN 17 +#define COLS_PER_SCREEN 60 + +#define LCD_BG_DEF 9 +#define LCD_FG_DEF 15 + +#define LCD_FB_SIZE(_depth_) (((PIXELS_PER_COL * PIXELS_PER_ROW) * _depth_) / 8) + +#define LCD_ROW_SIZE(_depth_) ((PIXELS_PER_ROW * _depth_) / 8) + +#define LCD_GET_ADD(_row_, _col_, _depth_) (((((_row_ * PIXELS_PER_ROW) * FONT_HEIGHT) \ + + (_col_ * FONT_WIDTH)) \ + * _depth_) / 8) + + diff --git a/ports/csb740/etherdev.c b/ports/csb740/etherdev.c new file mode 100755 index 0000000..690d21b --- /dev/null +++ b/ports/csb740/etherdev.c @@ -0,0 +1,241 @@ +//============================================================================= +// +// etherdev.c +// +// Ethernet Abstraction Layer for Micro Monitor +// +// Author(s): Michael Kelly, Cogent Computer Systems, Inc. +// Contributors: Luis Torrico, Cogent Computer Systems, Inc. +// Date: 05-26-2002 +// Modified: 06-26-2007 +// Description: This file contains the interface layer between Micro Monitor +// and the Ethernet driver for the LAN921x on the CSB733. +// +//============================================================================= + +#include "config.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "ether.h" + +extern void smsc911x_reset(void); +extern ushort smsc911x_rx(uchar *pktbuf); +extern int smsc911x_init(void); +extern ulong smsc911x_tx(ulong txbuf, ulong length); +extern void smsc911x_enable_promiscuous_reception(void); +extern void smsc911x_disable_promiscuous_reception(void); +extern void smsc911x_enable_multicast_reception(void); +extern void smsc911x_disable_multicast_reception(void); +extern void smsc911x_enable_broadcast_reception(void); +extern void smsc911x_disable_broadcast_reception(void); + +ulong tx_buf[400]; + +#if INCLUDE_ETHERNET + +/* + * enreset(): + * Reset the PHY and MAC. + */ +void +enreset(void) +{ + smsc911x_reset(); +} + +/* + * eninit(): + * This would include establishing buffer descriptor tables and + * all the support code that will be used by the ethernet device. + * + * It can be assumed at this point that the array uchar BinEnetAddr[6] + * contains the 6-byte MAC address. + * + * Return 0 if successful; else -1. + */ +int +eninit(void) +{ + return smsc911x_init(); + +} + +int +EtherdevStartup(int verbose) +{ + /* Initialize local device error counts (if any) here. */ + /* OPT_ADD_CODE_HERE */ + + /* Put ethernet controller in reset: */ + enreset(); + + /* Initialize controller: */ + eninit(); + + return(0); +} + +/* disablePromiscuousReception(): + * Provide the code that disables promiscuous reception. + */ +void +disablePromiscuousReception(void) +{ + smsc911x_disable_promiscuous_reception(); +} + +/* enablePromiscuousReception(): + * Provide the code that enables promiscuous reception. + */ +void +enablePromiscuousReception(void) +{ + smsc911x_enable_promiscuous_reception(); +} + +/* disableBroadcastReception(): + * Provide the code that disables broadcast reception. + */ +void +disableBroadcastReception(void) +{ + smsc911x_disable_broadcast_reception(); +} + +/* enableBroadcastReception(): + * Provide the code that enables broadcast reception. + */ +void +enableBroadcastReception(void) +{ + smsc911x_enable_broadcast_reception(); +} + +void +disableMulticastReception(void) +{ + smsc911x_disable_multicast_reception(); +} + +void +enableMulticastReception(void) +{ + smsc911x_enable_multicast_reception(); +} + + +/* + * enselftest(): + * Run a self test of the ethernet device(s). This can be stubbed + * with a return(1). + * Return 1 if success; else -1 if failure. + */ +int +enselftest(int verbose) +{ + return(1); +} + +/* ShowEtherdevStats(): + * This function is used to display device-specific stats (error counts + * usually). + */ +void +ShowEtherdevStats(void) +{ + /* OPT_ADD_CODE_HERE */ +} + +/* getXmitBuffer(): + * Return a pointer to the buffer that is to be used for transmission of + * the next packet. Since the monitor's driver is EXTREMELY basic, + * there will only be one packet ever being transmitted. No need to queue + * up transmit packets. + */ +uchar * +getXmitBuffer(void) +{ + return((uchar *) tx_buf); +} + +/* sendBuffer(): + * Send out the packet assumed to be built in the buffer returned by the + * previous call to getXmitBuffer() above. + */ +int +sendBuffer(int length) +{ + ulong temp32; + + if (length < 64) + length = 64; + + if (EtherVerbose & SHOW_OUTGOING) + printPkt((struct ether_header *)tx_buf,length,ETHER_OUTGOING); + + // tell the cs8900a to send the tx buffer pointed to by tx_buf + temp32 = smsc911x_tx((ulong)tx_buf, (ulong)length); + + EtherXFRAMECnt++; + if (temp32) { + return -1; + } + else { + return 0; + } +} + +/* DisableEtherdev(): + * Fine as it is... + */ +void +DisableEtherdev(void) +{ + enreset(); +} + +/* extGetIpAdd(): + * If there was some external mechanism (other than just using the + * IPADD shell variable established in the monrc file) for retrieval of + * the board's IP address, then do it here... + */ +char * +extGetIpAdd(void) +{ + return((char *)0); +} + +/* extGetEtherAdd(): + * If there was some external mechanism (other than just using the + * ETHERADD shell variable established in the monrc file) for retrieval of + * the board's MAC address, then do it here... + */ +char * +extGetEtherAdd(void) +{ + return((char *)0); +} + +/* + * polletherdev(): + * Called continuously by the monitor (ethernet.c) to determine if there + * is any incoming ethernet packets. + */ +int +polletherdev(void) +{ + ulong pktbuf[RBUFSIZE/4]; + int pktlen, pktcnt = 0; + + pktlen = smsc911x_rx((uchar *)pktbuf); + + if(pktlen) { + pktcnt = 1; + EtherRFRAMECnt++; + processPACKET((struct ether_header *)pktbuf, pktlen); + } + return(pktcnt); +} + +#endif diff --git a/ports/csb740/fbidemo b/ports/csb740/fbidemo new file mode 100755 index 0000000..1a9e21c --- /dev/null +++ b/ports/csb740/fbidemo @@ -0,0 +1,163 @@ +# This is a useful demo script to show off some of the functionality +# of uMon's FBI interface... +# It expects to find two files: fb/splash.bin and fb/umon1 that are +# assumed to be two frame-buffer formatted images. +# +echo "Image file \#1: \c" +read IMAGEFILE1 +echo "Image file \#2: \c" +read IMAGEFILE2 +set FBICOLOR 0x005500 + +fbi font 0 1 1 0xf0f0f0 0x101010 +fbi consolemode off +fbi fill $IMAGEFILE1 +sleep 2 + +fbi -t1 color $FBICOLOR +fbi font 0 4 4 -- transparent +fbi -o 1,0 print "MicroMonitor" +fbi font 0 2 2 -- -- +fbi -o 7,3 print "(aka uMon)" +fbi -o 2,5 print "FBI:" +fbi -o 2,6 print "Frame Buffer Interface" +fbi -o 2,7 print "***** Demo *****" +sleep 2 + +fbi -t2 color $FBICOLOR +fbi font 0 1 1 -- -- +fbi -o 5,1 print "print small" +sleep 1 +fbi font 0 3 3 -- -- +fbi -o 5,1 print "or..." +sleep 1 +fbi font 0 7 7 -- -- +fbi -o 1,1 print "large" +sleep 2 + +fbi -t3 color $FBICOLOR +fbi font 0 2 4 -- -- +sleep 1 +fbi -o 8,1 print "Independent" +fbi -o 8,2 print " x & y" +fbi -o 8,3 print "dimensions..." +sleep 1 + +fbi -t1 color $FBICOLOR +fbi font 0 5 1 -- -- +fbi -o 1,1 print "print wide" +sleep 1 +fbi font 0 3 3 -- -- +fbi -o 3,3 print "or..." +sleep 1 +fbi font 0 2 18 -- -- +fbi -o 15,0 print "tall" +sleep 2 + +fbi -t2 color $FBICOLOR +fbi font 0 3 3 -- -- +fbi -o 3,2 print "or" +sleep 1 +fbi -o 3,4 print "mix it up..." +sleep 1 + +fbi -t3 color $FBICOLOR +fbi font 0 1 1 -- -- +fbi -o 0,1 print 1 +fbi font 0 1 2 -- -- +fbi print 2 +fbi font 0 1 3 -- -- +fbi print 3 +fbi font 0 1 4 -- -- +fbi print 4 +fbi font 0 1 5 -- -- +fbi print 5 +fbi font 0 1 6 -- -- +fbi print 6 +fbi font 0 1 7 -- -- +fbi print 7 +fbi font 0 1 8 -- -- +fbi print 8 +fbi font 0 1 9 -- -- +fbi print 9 +fbi font 0 2 9 -- -- +fbi -o 5,1 print 0 +fbi font 0 2 8 -- -- +fbi -o 6,1 print 9 +fbi font 0 3 7 -- -- +fbi -o 5,1 print 8 +fbi font 0 4 6 -- -- +fbi -o 5,1 print 7 +fbi font 0 5 5 -- -- +fbi -o 5,1 print 6 +fbi font 0 6 4 -- -- +fbi -o 5,1 print 5 +fbi font 0 7 3 -- -- +fbi -o 5,1 print 4 +fbi font 0 8 2 -- -- +fbi -o 5,1 print 3 +fbi font 0 9 1 -- -- +fbi -o 5,1 print 2 +fbi font 0 10 1 -- -- +fbi -o 5,0 print 1 +sleep 4 + +fbi -t1 color $FBICOLOR +fbi font 0 3 3 -- -- +fbi -o 3,1 print "or" +sleep 1 +fbi -o 3,3 print "console mode..." +fbi -o 3,4 print "(normal font)" +sleep 2 + +fbi font 0 1 1 -- -- +fbi consolemode on +echo uMON\> +sleep 1 +tfs ls +echo uMON\> +sleep 1 +tfs cat monrc +echo uMON\> +sleep 1 +fbi consolemode off + +fbi -t2 color $FBICOLOR +fbi font 0 3 3 -- -- +fbi consolemode on +fbi -o 3,1 print "or" +sleep 1 +fbi -o 3,3 print "console mode..." +fbi -o 3,4 print "(taller font)" +sleep 2 +fbi consolemode off + +fbi font 0 1 2 -- -- +fbi consolemode on +echo uMON\> +sleep 1 +tfs ls +echo uMON\> +sleep 1 +tfs cat monrc +echo uMON\> +sleep 1 +fbi font 0 1 1 -- -- +fbi consolemode off + + +# SPLASHLOOPINIT: +set TTYPE 1 + +# SPLASHLOOP: +if $TTYPE gt 3 goto SPLASHLOOPINIT +if -tgc exit +fbi -t $TTYPE fill $IMAGEFILE1 +if -tgc exit +sleep 2 +if -tgc exit +fbi -t $TTYPE fill $IMAGEFILE2 +set TTYPE=$TTYPE+1 +sleep 2 +if -tgc exit +goto SPLASHLOOP diff --git a/ports/csb740/font8x16.h b/ports/csb740/font8x16.h new file mode 100755 index 0000000..808c9e4 --- /dev/null +++ b/ports/csb740/font8x16.h @@ -0,0 +1,3679 @@ +//------------------------------------------------------------------------ +// font8x16.h +// +// Simple 8 x 16 font printable characters only. To lookoup, subtract +// FIRST_CHAR from the character, multiply x FONT_HEIGHT and get the next +// FONT_WIDTH bytes. +// +// 10.03.2003 : added font8x16 def. + +#define FONT_WIDTH 8 +#define FONT_HEIGHT 16 +#define FIRST_CHAR 0x20 +#define LAST_CHAR 0x7f +#define CURSOR_ON 0x7F +#define CURSOR_OFF 0x20 + +#if 0 +const uchar fonttbl[] = { +/* 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 */ +/* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x21 ! */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +/* 0x22 " */ 0x00, 0x00, 0x48, 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x23 # */ 0x00, 0x00, 0x00, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x44, 0xfe, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, +/* 0x24 $ */ 0x00, 0x10, 0x10, 0x7c, 0x92, 0x90, 0x90, 0x7c, 0x12, 0x12, 0x92, 0x7c, 0x10, 0x10, 0x00, 0x00, +/* 0x25 % */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x94, 0x68, 0x10, 0x2c, 0x52, 0x8c, 0x00, 0x00, 0x00, 0x00, +/* 0x26 & */ 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x38, 0x56, 0x8c, 0x88, 0x8c, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0x27 ' */ 0x00, 0x00, 0x10, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x28 ( */ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, +/* 0x29 ) */ 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, +/* 0x2a * */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0xfe, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b + */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c , */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, +/* 0x2d - */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e . */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, +/* 0x2f / */ 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x30 0 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x31 1 */ 0x00, 0x00, 0x00, 0x08, 0x18, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, +/* 0x32 2 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x04, 0x18, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, +/* 0x33 3 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x1c, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x34 4 */ 0x00, 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, +/* 0x35 5 */ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x36 6 */ 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x37 7 */ 0x00, 0x00, 0x00, 0x7e, 0x42, 0x02, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, +/* 0x38 8 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x39 9 */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00, +/* 0x3a : */ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b ; */ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, +/* 0x3c < */ 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, +/* 0x3d = */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e > */ 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, +/* 0x3f ? */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x04, 0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, +/* 0x40 @ */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x4e, 0x52, 0x52, 0x4e, 0x40, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x41 A */ 0x00, 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x42 B */ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0x43 C */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x44 D */ 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x00, +/* 0x45 E */ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, +/* 0x46 F */ 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, +/* 0x47 G */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x4e, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, +/* 0x48 H */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x49 I */ 0x00, 0x00, 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, +/* 0x4a J */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x4b K */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x4c L */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, +/* 0x4d M */ 0x00, 0x00, 0x00, 0x82, 0xc6, 0xaa, 0x92, 0x92, 0x82, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, +/* 0x4e N */ 0x00, 0x00, 0x00, 0x42, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x4f O */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x50 P */ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, +/* 0x51 Q */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x4a, 0x4a, 0x3c, 0x04, 0x06, 0x00, 0x00, +/* 0x52 R */ 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x44, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x53 S */ 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x20, 0x18, 0x04, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x54 T */ 0x00, 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, +/* 0x55 U */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x56 V */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, +/* 0x57 W */ 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0x92, 0x92, 0xba, 0x6c, 0x44, 0x00, 0x00, 0x00, 0x00, +/* 0x58 X */ 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x59 Y */ 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x44, 0x38, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, +/* 0x5a Z */ 0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, +/* 0x5b [ */ 0x00, 0x00, 0x00, 0x3c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x5c \ */ 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d ] */ 0x00, 0x00, 0x00, 0x3c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x5e ^ */ 0x00, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f _ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, +/* 0x60 ` */ 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x61 a */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, +/* 0x62 b */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0x63 c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x64 d */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00, +/* 0x65 e */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x66 f */ 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, +/* 0x67 g */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x42, 0x3c, 0x00, 0x00, +/* 0x68 h */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x69 i */ 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, +/* 0x6a j */ 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x22, 0x22, 0x1c, 0x00, 0x00, +/* 0x6b k */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x42, 0x44, 0x78, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x6c l */ 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00, +/* 0x6d m */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0xee, 0x92, 0x92, 0x92, 0x82, 0x00, 0x00, 0x00, 0x00, +/* 0x6e n */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x6f o */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x70 p */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x00, 0x00, +/* 0x71 q */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x03, 0x00, 0x00, +/* 0x72 r */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, +/* 0x73 s */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x38, 0x04, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0x74 t */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, +/* 0x75 u */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, +/* 0x76 v */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00, +/* 0x77 w */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x92, 0x92, 0xba, 0x6c, 0x44, 0x00, 0x00, 0x00, 0x00, +/* 0x78 x */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00, +/* 0x79 y */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x04, 0x78, 0x00, 0x00, +/* 0x7a z */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00, +/* 0x7b { */ 0x00, 0x00, 0x00, 0x06, 0x08, 0x08, 0x08, 0x30, 0x08, 0x08, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, +/* 0x7c | */ 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, +/* 0x7d } */ 0x00, 0x00, 0x00, 0x60, 0x10, 0x10, 0x10, 0x0c, 0x10, 0x10, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, +/* 0x7e ~ */ 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x44, 0x82, 0x82, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +#else + +const uchar fonttbl[] = { + + +/* Character (0x20): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character ! (0x21): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | **** | + | **** | + | **** | + | **** | + | ** | + | ** | + | | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x3c, +0x3c, +0x3c, +0x3c, +0x18, +0x18, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +/* Character " (0x22): + ht=16, width=8 + +--------+ + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | * * | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x36, +0x36, +0x36, +0x36, +0x14, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character # (0x23): + ht=16, width=8 + +--------+ + | | + | | + | ** ** | + | ** ** | + | ** ** | + |******* | + | ** ** | + | ** ** | + |******* | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x6c, +0x6c, +0x6c, +0xfe, +0x6c, +0x6c, +0xfe, +0x6c, +0x6c, +0x6c, +0x00, +0x00, +0x00, +0x00, + +/* Character $ (0x24): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ***** | + |** ** | + |** | + | **** | + | **** | + | ** | + |** ** | + | ***** | + | ** | + | ** | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x18, +0x7c, +0xc6, +0xc0, +0x78, +0x3c, +0x06, +0xc6, +0x7c, +0x18, +0x18, +0x00, +0x00, + +/* Character % (0x25): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** * | + | ** ** | + | ** | + | ** | + | ** | + | ** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x62, +0x66, +0x0c, +0x18, +0x30, +0x66, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character & (0x26): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** ** | + | *** | + | ** | + | *** ** | + | ****** | + |** ** | + |** ** | + |** ** | + | *** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x38, +0x6c, +0x38, +0x30, +0x76, +0x7e, +0xcc, +0xcc, +0xcc, +0x76, +0x00, +0x00, +0x00, +0x00, + +/* Character ' (0x27): + ht=16, width=8 + +--------+ + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x0c, +0x0c, +0x0c, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character ( (0x28): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x0c, +0x18, +0x30, +0x30, +0x30, +0x30, +0x30, +0x30, +0x18, +0x0c, +0x00, +0x00, +0x00, +0x00, + +/* Character ) (0x29): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x30, +0x18, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x18, +0x30, +0x00, +0x00, +0x00, +0x00, + +/* Character * (0x2a): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** ** | + | *** | + |******* | + | *** | + | ** ** | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x6c, +0x38, +0xfe, +0x38, +0x6c, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character + (0x2b): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** | + | ** | + | ****** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x7e, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character , (0x2c): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x0c, +0x0c, +0x0c, +0x18, +0x00, +0x00, +0x00, + +/* Character - (0x2d): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + |******* | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character . (0x2e): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +/* Character / (0x2f): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | * | + | ** | + | ** | + | ** | + | ** | + | ** | + |** | + |* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x02, +0x06, +0x0c, +0x18, +0x30, +0x60, +0xc0, +0x80, +0x00, +0x00, +0x00, +0x00, + +/* Character 0 (0x30): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** *** | + |** **** | + |**** ** | + |*** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xce, +0xde, +0xf6, +0xe6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 1 (0x31): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x78, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x7e, +0x00, +0x00, +0x00, +0x00, + +/* Character 2 (0x32): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0x06, +0x0c, +0x18, +0x30, +0x60, +0xc6, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character 3 (0x33): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + | ** | + | ** | + | **** | + | ** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0x06, +0x06, +0x3c, +0x06, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 4 (0x34): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | *** | + | **** | + | ** ** | + |** ** | + |** ** | + |******* | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x0c, +0x1c, +0x3c, +0x6c, +0xcc, +0xcc, +0xfe, +0x0c, +0x0c, +0x1e, +0x00, +0x00, +0x00, +0x00, + +/* Character 5 (0x35): + ht=16, width=8 + +--------+ + | | + | | + |******* | + |** | + |** | + |** | + |****** | + | ** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0xc0, +0xc0, +0xc0, +0xfc, +0x06, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 6 (0x36): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** | + |** | + |****** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0xc0, +0xfc, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 7 (0x37): + ht=16, width=8 + +--------+ + | | + | | + |******* | + |** ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0xc6, +0x06, +0x0c, +0x18, +0x30, +0x30, +0x30, +0x30, +0x30, +0x00, +0x00, +0x00, +0x00, + +/* Character 8 (0x38): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character 9 (0x39): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + | ****** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0x7e, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character : (0x3a): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** | + | ** | + | | + | | + | ** | + | ** | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character ; (0x3b): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** | + | ** | + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x00, +0x0c, +0x0c, +0x0c, +0x18, +0x00, +0x00, +0x00, + +/* Character < (0x3c): + ht=16, width=8 + +--------+ + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + |** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x0c, +0x18, +0x30, +0x60, +0xc0, +0x60, +0x30, +0x18, +0x0c, +0x00, +0x00, +0x00, +0x00, + +/* Character = (0x3d): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + |******* | + | | + |******* | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x00, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character > (0x3e): + ht=16, width=8 + +--------+ + | | + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x60, +0x30, +0x18, +0x0c, +0x06, +0x0c, +0x18, +0x30, +0x60, +0x00, +0x00, +0x00, +0x00, + +/* Character ? (0x3f): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + | ** | + | ** | + | ** | + | ** | + | | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0x0c, +0x18, +0x18, +0x18, +0x00, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +/* Character @ (0x40): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** **** | + |** **** | + |** **** | + |** *** | + |** | + | ****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xde, +0xde, +0xde, +0xdc, +0xc0, +0x7e, +0x00, +0x00, +0x00, +0x00, + +/* Character A (0x41): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** ** | + |** ** | + |** ** | + |** ** | + |******* | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x38, +0x6c, +0xc6, +0xc6, +0xc6, +0xfe, +0xc6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character B (0x42): + ht=16, width=8 + +--------+ + | | + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfc, +0x66, +0x66, +0x66, +0x7c, +0x66, +0x66, +0x66, +0x66, +0xfc, +0x00, +0x00, +0x00, +0x00, + +/* Character C (0x43): + ht=16, width=8 + +--------+ + | | + | | + | **** | + | ** ** | + |** * | + |** | + |** | + |** | + |** | + |** * | + | ** ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x3c, +0x66, +0xc2, +0xc0, +0xc0, +0xc0, +0xc0, +0xc2, +0x66, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character D (0x44): + ht=16, width=8 + +--------+ + | | + | | + |***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xf8, +0x6c, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x6c, +0xf8, +0x00, +0x00, +0x00, +0x00, + +/* Character E (0x45): + ht=16, width=8 + +--------+ + | | + | | + |******* | + | ** ** | + | ** | + | ** * | + | ***** | + | ** * | + | ** | + | ** | + | ** ** | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0x66, +0x60, +0x64, +0x7c, +0x64, +0x60, +0x60, +0x66, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character F (0x46): + ht=16, width=8 + +--------+ + | | + | | + |******* | + | ** ** | + | ** | + | ** * | + | ***** | + | ** * | + | ** | + | ** | + | ** | + |**** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0x66, +0x60, +0x64, +0x7c, +0x64, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, +0x00, + +/* Character G (0x47): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** | + |** | + |** | + |** *** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc0, +0xc0, +0xc0, +0xce, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character H (0x48): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |******* | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xfe, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character I (0x49): + ht=16, width=8 + +--------+ + | | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x3c, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character J (0x4a): + ht=16, width=8 + +--------+ + | | + | | + | **** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + |** ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x3c, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0xd8, +0xd8, +0x70, +0x00, +0x00, +0x00, +0x00, + +/* Character K (0x4b): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |**** | + |**** | + |** ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xcc, +0xd8, +0xf0, +0xf0, +0xd8, +0xcc, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character L (0x4c): + ht=16, width=8 + +--------+ + | | + | | + |**** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** * | + | ** ** | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xf0, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x62, +0x66, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character M (0x4d): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |*** *** | + |*** *** | + |******* | + |** * ** | + |** * ** | + |** * ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xee, +0xee, +0xfe, +0xd6, +0xd6, +0xd6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character N (0x4e): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |*** ** | + |*** ** | + |**** ** | + |** **** | + |** *** | + |** *** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xe6, +0xe6, +0xf6, +0xde, +0xce, +0xce, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character O (0x4f): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character P (0x50): + ht=16, width=8 + +--------+ + | | + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | ** | + | ** | + | ** | + |**** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfc, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, +0x00, + +/* Character Q (0x51): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** * ** | + |** * ** | + | ***** | + | ** | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xd6, +0xd6, +0x7c, +0x06, +0x00, +0x00, +0x00, + +/* Character R (0x52): + ht=16, width=8 + +--------+ + | | + | | + |****** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | **** | + | ** ** | + | ** ** | + | ** ** | + |*** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfc, +0x66, +0x66, +0x66, +0x7c, +0x78, +0x6c, +0x66, +0x66, +0xe6, +0x00, +0x00, +0x00, +0x00, + +/* Character S (0x53): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + |** ** | + |** | + |** | + | *** | + | *** | + | ** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0xc0, +0x70, +0x1c, +0x06, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character T (0x54): + ht=16, width=8 + +--------+ + | | + | | + | ****** | + | * ** * | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7e, +0x5a, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character U (0x55): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character V (0x56): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ** ** | + | *** | + | * | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x10, +0x00, +0x00, +0x00, +0x00, + +/* Character W (0x57): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + |** * ** | + |** * ** | + |** * ** | + |******* | + |*** *** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xd6, +0xd6, +0xd6, +0xfe, +0xee, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character X (0x58): + ht=16, width=8 + +--------+ + | | + | | + |** ** | + |** ** | + |** ** | + | ** ** | + | *** | + | *** | + | ** ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x38, +0x6c, +0xc6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character Y (0x59): + ht=16, width=8 + +--------+ + | | + | | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x66, +0x66, +0x66, +0x66, +0x66, +0x3c, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character Z (0x5a): + ht=16, width=8 + +--------+ + | | + | | + |******* | + |** ** | + |* ** | + | ** | + | ** | + | ** | + | ** | + |** * | + |** ** | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xfe, +0xc6, +0x86, +0x0c, +0x18, +0x30, +0x60, +0xc2, +0xc6, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character [ (0x5b): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x60, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character \ (0x5c): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + |* | + |** | + | ** | + | ** | + | ** | + | ** | + | ** | + | * | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x80, +0xc0, +0x60, +0x30, +0x18, +0x0c, +0x06, +0x02, +0x00, +0x00, +0x00, +0x00, + +/* Character ] (0x5d): + ht=16, width=8 + +--------+ + | | + | | + | ***** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x7c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character ^ (0x5e): + ht=16, width=8 + +--------+ + | | + | * | + | *** | + | ** ** | + |** ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x10, +0x38, +0x6c, +0xc6, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character _ (0x5f): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + |********| + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0xff, +0x00, +0x00, + +/* Character ` (0x60): + ht=16, width=8 + +--------+ + | | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x18, +0x18, +0x18, +0x0c, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character a (0x61): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | **** | + | ** | + | ***** | + |** ** | + |** ** | + |** *** | + | *** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x78, +0x0c, +0x7c, +0xcc, +0xcc, +0xdc, +0x76, +0x00, +0x00, +0x00, +0x00, + +/* Character b (0x62): + ht=16, width=8 + +--------+ + | | + | | + |*** | + | ** | + | ** | + | ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xe0, +0x60, +0x60, +0x7c, +0x66, +0x66, +0x66, +0x66, +0x66, +0xfc, +0x00, +0x00, +0x00, +0x00, + +/* Character c (0x63): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ***** | + |** ** | + |** | + |** | + |** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0xc0, +0xc0, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character d (0x64): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** | + | ** | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ****** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x1c, +0x0c, +0x0c, +0x7c, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0x7e, +0x00, +0x00, +0x00, +0x00, + +/* Character e (0x65): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ***** | + |** ** | + |** ** | + |******* | + |** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xfe, +0xc0, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character f (0x66): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** ** | + | ** | + | ** | + |****** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x1c, +0x36, +0x30, +0x30, +0xfc, +0x30, +0x30, +0x30, +0x30, +0x78, +0x00, +0x00, +0x00, +0x00, + +/* Character g (0x67): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | *** ** | + |** *** | + |** ** | + |** ** | + |** *** | + | *** ** | + | ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x76, +0xce, +0xc6, +0xc6, +0xce, +0x76, +0x06, +0xc6, +0x7c, +0x00, +0x00, + +/* Character h (0x68): + ht=16, width=8 + +--------+ + | | + | | + |*** | + | ** | + | ** | + | ***** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + |*** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xe0, +0x60, +0x60, +0x7c, +0x66, +0x66, +0x66, +0x66, +0x66, +0xe6, +0x00, +0x00, +0x00, +0x00, + +/* Character i (0x69): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + | **** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x18, +0x00, +0x38, +0x18, +0x18, +0x18, +0x18, +0x18, +0x3c, +0x00, +0x00, +0x00, +0x00, + +/* Character j (0x6a): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | | + | *** | + | ** | + | ** | + | ** | + | ** | + | ** | + |** ** | + |** ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x00, +0x0c, +0x0c, +0x00, +0x1c, +0x0c, +0x0c, +0x0c, +0x0c, +0x0c, +0xcc, +0xcc, +0x78, +0x00, +0x00, + +/* Character k (0x6b): + ht=16, width=8 + +--------+ + | | + | | + |*** | + | ** | + | ** | + | ** ** | + | ** ** | + | ** ** | + | **** | + | ** ** | + | ** ** | + |*** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0xe0, +0x60, +0x60, +0x66, +0x66, +0x6c, +0x78, +0x6c, +0x66, +0xe6, +0x00, +0x00, +0x00, +0x00, + +/* Character l (0x6c): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x18, +0x1c, +0x00, +0x00, +0x00, +0x00, + +/* Character m (0x6d): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ** ** | + |******* | + |** * ** | + |** * ** | + |** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x6c, +0xfe, +0xd6, +0xd6, +0xc6, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character n (0x6e): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xdc, +0x66, +0x66, +0x66, +0x66, +0x66, +0x66, +0x00, +0x00, +0x00, +0x00, + +/* Character o (0x6f): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ***** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc6, +0xc6, +0xc6, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character p (0x70): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** *** | + | ** ** | + | ** ** | + | ** ** | + | ** ** | + | ***** | + | ** | + | ** | + |**** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xdc, +0x66, +0x66, +0x66, +0x66, +0x7c, +0x60, +0x60, +0xf0, +0x00, +0x00, + +/* Character q (0x71): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | *** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | ***** | + | ** | + | ** | + | **** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x76, +0xcc, +0xcc, +0xcc, +0xcc, +0x7c, +0x0c, +0x0c, +0x1e, +0x00, +0x00, + +/* Character r (0x72): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** *** | + | ** ** | + | ** | + | ** | + | ** | + | ** | + |**** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xdc, +0x66, +0x60, +0x60, +0x60, +0x60, +0xf0, +0x00, +0x00, +0x00, +0x00, + +/* Character s (0x73): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | ***** | + |** ** | + |** | + | ***** | + | ** | + |** ** | + | ***** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x7c, +0xc6, +0xc0, +0x7c, +0x06, +0xc6, +0x7c, +0x00, +0x00, +0x00, +0x00, + +/* Character t (0x74): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + |****** | + | ** | + | ** | + | ** | + | ** | + | ** ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x30, +0x30, +0x30, +0xfc, +0x30, +0x30, +0x30, +0x30, +0x36, +0x1c, +0x00, +0x00, +0x00, +0x00, + +/* Character u (0x75): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + |** ** | + | *** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0xcc, +0x76, +0x00, +0x00, +0x00, +0x00, + +/* Character v (0x76): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + | ** ** | + | *** | + | * | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0x6c, +0x38, +0x10, +0x00, +0x00, +0x00, +0x00, + +/* Character w (0x77): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** * ** | + |** * ** | + |** * ** | + |******* | + | ** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0xd6, +0xd6, +0xd6, +0xfe, +0x6c, +0x00, +0x00, +0x00, +0x00, + +/* Character x (0x78): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + | ** ** | + | *** | + | ** ** | + |** ** | + |** ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0x6c, +0x38, +0x6c, +0xc6, +0xc6, +0x00, +0x00, +0x00, +0x00, + +/* Character y (0x79): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |** ** | + |** ** | + |** ** | + |** ** | + |** *** | + | *** ** | + | ** | + |** ** | + | ***** | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xc6, +0xc6, +0xc6, +0xc6, +0xce, +0x76, +0x06, +0xc6, +0x7c, +0x00, +0x00, + +/* Character z (0x7a): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + |******* | + |* ** | + | ** | + | ** | + | ** | + | ** * | + |******* | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0xfe, +0x86, +0x0c, +0x18, +0x30, +0x62, +0xfe, +0x00, +0x00, +0x00, +0x00, + +/* Character { (0x7b): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** | + | ** | + | ** | + | *** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x0e, +0x18, +0x18, +0x18, +0x70, +0x18, +0x18, +0x18, +0x18, +0x0e, +0x00, +0x00, +0x00, +0x00, + +/* Character | (0x7c): + ht=16, width=8 + +--------+ + | | + | | + | ** | + | ** | + | ** | + | ** | + | | + | ** | + | ** | + | ** | + | ** | + | ** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x18, +0x18, +0x18, +0x18, +0x00, +0x18, +0x18, +0x18, +0x18, +0x18, +0x00, +0x00, +0x00, +0x00, + +/* Character } (0x7d): + ht=16, width=8 + +--------+ + | | + | | + | *** | + | ** | + | ** | + | ** | + | *** | + | ** | + | ** | + | ** | + | ** | + | *** | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x70, +0x18, +0x18, +0x18, +0x0e, +0x18, +0x18, +0x18, +0x18, +0x70, +0x00, +0x00, +0x00, +0x00, + +/* Character ~ (0x7e): + ht=16, width=8 + +--------+ + | | + | | + | *** ** | + |** *** | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x76, +0xdc, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, +0x00, + +/* Character (0x7f): + ht=16, width=8 + +--------+ + | | + | | + | | + | | + | | + | * | + | *** | + | *** | + | ** ** | + | ** ** | + |******* | + | | + | | + | | + | | + | | + +--------+ */ +0x00, +0x00, +0x00, +0x00, +0x00, +0x10, +0x38, +0x38, +0x6c, +0x6c, +0xfe, +0x00, +0x00, +0x00, +0x00, +0x00, + +}; + +#endif + +//#define font8x16 fonttbl diff --git a/ports/csb740/gdbregs.c b/ports/csb740/gdbregs.c new file mode 100755 index 0000000..7930f9c --- /dev/null +++ b/ports/csb740/gdbregs.c @@ -0,0 +1 @@ +#include "gdbregs_arm.c" diff --git a/ports/csb740/lcd_lut.h b/ports/csb740/lcd_lut.h new file mode 100755 index 0000000..9b074f6 --- /dev/null +++ b/ports/csb740/lcd_lut.h @@ -0,0 +1,289 @@ +//------------------------------------------------------------------------ +// lcd_lut.h: Lookup Table Values +// + +uchar lcd_lut[256][3] = { +// RED, GREEN, BLUE // Entry + { 0x0, 0x0, 0x0, }, // 00 + { 0x0, 0x0, 0xA, }, // 01 + { 0x0, 0xA, 0x0, }, // 02 + { 0x0, 0xA, 0xA, }, // 03 + { 0xA, 0x0, 0x0, }, // 04 + { 0xA, 0x0, 0xA, }, // 05 + { 0xA, 0xA, 0x0, }, // 06 + { 0xA, 0xA, 0xA, }, // 07 + { 0x5, 0x5, 0x5, }, // 08 + { 0x5, 0x5, 0xF, }, // 09 + { 0x5, 0xF, 0x5, }, // 0A + { 0x5, 0xF, 0xF, }, // 0B + { 0xF, 0x5, 0x5, }, // 0C + { 0xF, 0x5, 0xF, }, // 0D + { 0xF, 0xF, 0x5, }, // 0E + { 0xF, 0xF, 0xF, }, // 0F + { 0x0, 0x0, 0x0, }, // 10 + { 0x1, 0x1, 0x1, }, // 11 + { 0x2, 0x2, 0x2, }, // 12 + { 0x2, 0x2, 0x2, }, // 13 + { 0x3, 0x3, 0x3, }, // 14 + { 0x4, 0x4, 0x4, }, // 15 + { 0x5, 0x5, 0x5, }, // 16 + { 0x6, 0x6, 0x6, }, // 17 + { 0x7, 0x7, 0x7, }, // 18 + { 0x8, 0x8, 0x8, }, // 19 + { 0x9, 0x9, 0x9, }, // 1A + { 0xA, 0xA, 0xA, }, // 1B + { 0xB, 0xB, 0xB, }, // 1C + { 0xC, 0xC, 0xC, }, // 1D + { 0xE, 0xE, 0xE, }, // 1E + { 0xF, 0xF, 0xF, }, // 1F + { 0x0, 0x0, 0xF, }, // 20 + { 0x4, 0x0, 0xF, }, // 21 + { 0x7, 0x0, 0xF, }, // 22 + { 0xB, 0x0, 0xF, }, // 23 + { 0xF, 0x0, 0xF, }, // 24 + { 0xF, 0x0, 0xB, }, // 25 + { 0xF, 0x0, 0x7, }, // 26 + { 0xF, 0x0, 0x4, }, // 27 + { 0xF, 0x0, 0x0, }, // 28 + { 0xF, 0x4, 0x0, }, // 29 + { 0xF, 0x7, 0x0, }, // 2A + { 0xF, 0xB, 0x0, }, // 2B + { 0xF, 0xF, 0x0, }, // 2C + { 0xB, 0xF, 0x0, }, // 2D + { 0x7, 0xF, 0x0, }, // 2E + { 0x4, 0xF, 0x0, }, // 2F + { 0x0, 0xF, 0x0, }, // 30 + { 0x0, 0xF, 0x4, }, // 31 + { 0x0, 0xF, 0x7, }, // 32 + { 0x0, 0xF, 0xB, }, // 33 + { 0x0, 0xF, 0xF, }, // 34 + { 0x0, 0xB, 0xF, }, // 35 + { 0x0, 0x7, 0xF, }, // 36 + { 0x0, 0x4, 0xF, }, // 37 + { 0x7, 0x7, 0xF, }, // 38 + { 0x9, 0x7, 0xF, }, // 39 + { 0xB, 0x7, 0xF, }, // 3A + { 0xD, 0x7, 0xF, }, // 3B + { 0xF, 0x7, 0xF, }, // 3C + { 0xF, 0x7, 0xD, }, // 3D + { 0xF, 0x7, 0xB, }, // 3E + { 0xF, 0x7, 0x9, }, // 3F + { 0xF, 0x7, 0x7, }, // 40 + { 0xF, 0x9, 0x7, }, // 41 + { 0xF, 0xB, 0x7, }, // 42 + { 0xF, 0xD, 0x7, }, // 43 + { 0xF, 0xF, 0x7, }, // 44 + { 0xD, 0xF, 0x7, }, // 45 + { 0xB, 0xF, 0x7, }, // 46 + { 0x9, 0xF, 0x7, }, // 47 + { 0x7, 0xF, 0x7, }, // 48 + { 0x7, 0xF, 0x9, }, // 49 + { 0x7, 0xF, 0xB, }, // 4A + { 0x7, 0xF, 0xD, }, // 4B + { 0x7, 0xF, 0xF, }, // 4C + { 0x7, 0xD, 0xF, }, // 4D + { 0x7, 0xB, 0xF, }, // 4E + { 0x7, 0x9, 0xF, }, // 4F + { 0xB, 0xB, 0xF, }, // 50 + { 0xC, 0xB, 0xF, }, // 51 + { 0xD, 0xB, 0xF, }, // 52 + { 0xE, 0xB, 0xF, }, // 53 + { 0xF, 0xB, 0xF, }, // 54 + { 0xF, 0xB, 0xE, }, // 55 + { 0xF, 0xB, 0xD, }, // 56 + { 0xF, 0xB, 0xC, }, // 57 + { 0xF, 0xB, 0xB, }, // 58 + { 0xF, 0xC, 0xB, }, // 59 + { 0xF, 0xD, 0xB, }, // 5A + { 0xF, 0xE, 0xB, }, // 5B + { 0xF, 0xF, 0xB, }, // 5C + { 0xE, 0xF, 0xB, }, // 5D + { 0xD, 0xF, 0xB, }, // 5E + { 0xC, 0xF, 0xB, }, // 5F + { 0xB, 0xF, 0xB, }, // 60 + { 0xB, 0xF, 0xC, }, // 61 + { 0xB, 0xF, 0xD, }, // 62 + { 0xB, 0xF, 0xE, }, // 63 + { 0xB, 0xF, 0xF, }, // 64 + { 0xB, 0xE, 0xF, }, // 65 + { 0xB, 0xD, 0xF, }, // 66 + { 0xB, 0xC, 0xF, }, // 67 + { 0x0, 0x0, 0x7, }, // 68 + { 0x1, 0x0, 0x7, }, // 69 + { 0x3, 0x0, 0x7, }, // 6A + { 0x5, 0x0, 0x7, }, // 6B + { 0x7, 0x0, 0x7, }, // 6C + { 0x7, 0x0, 0x5, }, // 6D + { 0x7, 0x0, 0x3, }, // 6E + { 0x7, 0x0, 0x1, }, // 6F + { 0x7, 0x0, 0x0, }, // 70 + { 0x7, 0x1, 0x0, }, // 71 + { 0x7, 0x3, 0x0, }, // 72 + { 0x7, 0x5, 0x0, }, // 73 + { 0x7, 0x7, 0x0, }, // 74 + { 0x5, 0x7, 0x0, }, // 75 + { 0x3, 0x7, 0x0, }, // 76 + { 0x1, 0x7, 0x0, }, // 77 + { 0x0, 0x7, 0x0, }, // 78 + { 0x0, 0x7, 0x1, }, // 79 + { 0x0, 0x7, 0x3, }, // 7A + { 0x0, 0x7, 0x5, }, // 7B + { 0x0, 0x7, 0x7, }, // 7C + { 0x0, 0x5, 0x7, }, // 7D + { 0x0, 0x3, 0x7, }, // 7E + { 0x0, 0x1, 0x7, }, // 7F + { 0x3, 0x3, 0x7, }, // 80 + { 0x4, 0x3, 0x7, }, // 81 + { 0x5, 0x3, 0x7, }, // 82 + { 0x6, 0x3, 0x7, }, // 83 + { 0x7, 0x3, 0x7, }, // 84 + { 0x7, 0x3, 0x6, }, // 85 + { 0x7, 0x3, 0x5, }, // 86 + { 0x7, 0x3, 0x4, }, // 87 + { 0x7, 0x3, 0x3, }, // 88 + { 0x7, 0x4, 0x3, }, // 89 + { 0x7, 0x5, 0x3, }, // 8A + { 0x7, 0x6, 0x3, }, // 8B + { 0x7, 0x7, 0x3, }, // 8C + { 0x6, 0x7, 0x3, }, // 8D + { 0x5, 0x7, 0x3, }, // 8E + { 0x4, 0x7, 0x3, }, // 8F + { 0x3, 0x7, 0x3, }, // 90 + { 0x3, 0x7, 0x4, }, // 91 + { 0x3, 0x7, 0x5, }, // 92 + { 0x3, 0x7, 0x6, }, // 93 + { 0x3, 0x7, 0x7, }, // 94 + { 0x3, 0x6, 0x7, }, // 95 + { 0x3, 0x5, 0x7, }, // 96 + { 0x3, 0x4, 0x7, }, // 97 + { 0x5, 0x5, 0x7, }, // 98 + { 0x5, 0x5, 0x7, }, // 99 + { 0x6, 0x5, 0x7, }, // 9A + { 0x6, 0x5, 0x7, }, // 9B + { 0x7, 0x5, 0x7, }, // 9C + { 0x7, 0x5, 0x6, }, // 9D + { 0x7, 0x5, 0x6, }, // 9E + { 0x7, 0x5, 0x5, }, // 9F + { 0x7, 0x5, 0x5, }, // A0 + { 0x7, 0x5, 0x5, }, // A1 + { 0x7, 0x6, 0x5, }, // A2 + { 0x7, 0x6, 0x5, }, // A3 + { 0x7, 0x7, 0x5, }, // A4 + { 0x6, 0x7, 0x5, }, // A5 + { 0x6, 0x7, 0x5, }, // A6 + { 0x5, 0x7, 0x5, }, // A7 + { 0x5, 0x7, 0x5, }, // A8 + { 0x5, 0x7, 0x5, }, // A9 + { 0x5, 0x7, 0x6, }, // AA + { 0x5, 0x7, 0x6, }, // AB + { 0x5, 0x7, 0x7, }, // AC + { 0x5, 0x6, 0x7, }, // AD + { 0x5, 0x6, 0x7, }, // AE + { 0x5, 0x5, 0x7, }, // AF + { 0x0, 0x0, 0x4, }, // B0 + { 0x1, 0x0, 0x4, }, // B1 + { 0x2, 0x0, 0x4, }, // B2 + { 0x3, 0x0, 0x4, }, // B3 + { 0x4, 0x0, 0x4, }, // B4 + { 0x4, 0x0, 0x3, }, // B5 + { 0x4, 0x0, 0x2, }, // B6 + { 0x4, 0x0, 0x1, }, // B7 + { 0x4, 0x0, 0x0, }, // B8 + { 0x4, 0x1, 0x0, }, // B9 + { 0x4, 0x2, 0x0, }, // BA + { 0x4, 0x3, 0x0, }, // BB + { 0x4, 0x4, 0x0, }, // BC + { 0x3, 0x4, 0x0, }, // BD + { 0x2, 0x4, 0x0, }, // BE + { 0x1, 0x4, 0x0, }, // BF + { 0x0, 0x4, 0x0, }, // C0 + { 0x0, 0x4, 0x1, }, // C1 + { 0x0, 0x4, 0x2, }, // C2 + { 0x0, 0x4, 0x3, }, // C3 + { 0x0, 0x4, 0x4, }, // C4 + { 0x0, 0x3, 0x4, }, // C5 + { 0x0, 0x2, 0x4, }, // C6 + { 0x0, 0x1, 0x4, }, // C7 + { 0x2, 0x2, 0x4, }, // C8 + { 0x2, 0x2, 0x4, }, // C9 + { 0x3, 0x2, 0x4, }, // CA + { 0x3, 0x2, 0x4, }, // CB + { 0x4, 0x2, 0x4, }, // CC + { 0x4, 0x2, 0x3, }, // CD + { 0x4, 0x2, 0x3, }, // CE + { 0x4, 0x2, 0x2, }, // CF + { 0x4, 0x2, 0x2, }, // D0 + { 0x4, 0x2, 0x2, }, // D1 + { 0x4, 0x3, 0x2, }, // D2 + { 0x4, 0x3, 0x2, }, // D3 + { 0x4, 0x4, 0x2, }, // D4 + { 0x3, 0x4, 0x2, }, // D5 + { 0x3, 0x4, 0x2, }, // D6 + { 0x2, 0x4, 0x2, }, // D7 + { 0x2, 0x4, 0x2, }, // D8 + { 0x2, 0x4, 0x2, }, // D9 + { 0x2, 0x4, 0x3, }, // DA + { 0x2, 0x4, 0x3, }, // DB + { 0x2, 0x4, 0x4, }, // DC + { 0x2, 0x3, 0x4, }, // DD + { 0x2, 0x3, 0x4, }, // DE + { 0x2, 0x2, 0x4, }, // DF + { 0x2, 0x2, 0x4, }, // E0 + { 0x3, 0x2, 0x4, }, // E1 + { 0x3, 0x2, 0x4, }, // E2 + { 0x3, 0x2, 0x4, }, // E3 + { 0x4, 0x2, 0x4, }, // E4 + { 0x4, 0x2, 0x3, }, // E5 + { 0x4, 0x2, 0x3, }, // E6 + { 0x4, 0x2, 0x3, }, // E7 + { 0x4, 0x2, 0x2, }, // E8 + { 0x4, 0x3, 0x2, }, // E9 + { 0x4, 0x3, 0x2, }, // EA + { 0x4, 0x3, 0x2, }, // EB + { 0x4, 0x4, 0x2, }, // EC + { 0x3, 0x4, 0x2, }, // ED + { 0x3, 0x4, 0x2, }, // EE + { 0x3, 0x4, 0x2, }, // EF + { 0x2, 0x4, 0x2, }, // F0 + { 0x2, 0x4, 0x3, }, // F1 + { 0x2, 0x4, 0x3, }, // F2 + { 0x2, 0x4, 0x3, }, // F3 + { 0x2, 0x4, 0x4, }, // F4 + { 0x2, 0x3, 0x4, }, // F5 + { 0x2, 0x3, 0x4, }, // F6 + { 0x2, 0x3, 0x4, }, // F7 + { 0x0, 0x0, 0x0, }, // F8 + { 0x0, 0x0, 0x0, }, // F9 + { 0x0, 0x0, 0x0, }, // FA + { 0x0, 0x0, 0x0, }, // FB + { 0x0, 0x0, 0x0, }, // FC + { 0x0, 0x0, 0x0, }, // FD + { 0x0, 0x0, 0x0, }, // FE + { 0x0, 0x0, 0x0, }, // FF +}; + +// 16-bit pixels are RGB 565 - LSB of RED and BLUE are tied low at the +// LCD Interface, while the LSB of GREEN is loaded as 0 +//#define RED_SUBPIXEL(n) (n & 0x1f) << 11 +//#define GREEN_SUBPIXEL(n) (n & 0x1f) << 6 +//#define BLUE_SUBPIXEL(n) (n & 0x1f) << 0 + +// define a simple VGA style 16-color pallette +//#define LU_BLACK RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00) +//#define LU_BLUE RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x0f) +//#define LU_GREEN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x00) +//#define LU_CYAN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x0f) +//#define LU_RED RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00) +//#define LU_VIOLET RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x0f) +//#define LU_YELLOW RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x00) +//#define LU_GREY RED_SUBPIXEL(0x0f) | GREEN_SUBPIXEL(0x0f) | BLUE_SUBPIXEL(0x0f) +//#define LU_WHITE RED_SUBPIXEL(0x17) | GREEN_SUBPIXEL(0x17) | BLUE_SUBPIXEL(0x17) +//#define LU_BRT_BLUE RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x1f) +//#define LU_BRT_GREEN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x00) +//#define LU_BRT_CYAN RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f) +//#define LU_BRT_RED RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x00) +//#define LU_BRT_VIOLET RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x00) | BLUE_SUBPIXEL(0x1f) +//#define LU_BRT_YELLOW RED_SUBPIXEL(0x00) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f) +//#define LU_BRT_WHITE RED_SUBPIXEL(0x1f) | GREEN_SUBPIXEL(0x1f) | BLUE_SUBPIXEL(0x1f) + + diff --git a/ports/csb740/makefile b/ports/csb740/makefile new file mode 100755 index 0000000..3a350c6 --- /dev/null +++ b/ports/csb740/makefile @@ -0,0 +1,129 @@ +############################################################################### +# +# CSB740 board makefile. +# +# +PLATFORM = CSB740 +TOPDIR = $(UMONTOP) +TGTDIR = csb740 +CPUTYPE = arm +FILETYPE = elf + +# Using tools installed by "sudo apt-get install gcc-arm-none-eabi"... +ABIDIR = /usr/lib/gcc/arm-none-eabi/4.8.2 +LIBABIDIR = -L $(ABIDIR) +TOOL_PREFIX = /usr/bin/arm-none-eabi + +COMMON_AFLAGS = -c -D PLATFORM_$(PLATFORM)=1 -D ASSEMBLY_ONLY +CUSTOM_CFLAGS = -mcpu=arm1136j-s -O2 -isystem $(ABIDIR)/include -Wno-char-subscripts + + +############################################################################### +# +# Memory map configuration: +# The following variables are used to establish the system's memory map. +# +BOOTROMBASE=0x08000000 +BOOTROMLEN=0x100000 +BOOTRAMBASE=0x80000000 +BOOTRAMLEN=0x100000 +RAMTSTROMBASE=0x80100000 +RAMTSTROMLEN=0x100000 +ATAGSIZE=0x1000 + +# These next two hard-coded values are used by the ramtst version of +# uMon to allow it to know where these flash-based structures are located. +MACADDRBASE=0x08000020 +ALTTFSDEVTBLBASE=0x08000040 + +include $(TOPDIR)/target/make/common.make + +# Build each variable from a list of individual filenames... +# +LOCSSRC = +CPUSSRC = vectors_arm.S +LOCCSRC = ad7843.c cpuio.c etherdev.c nand740.c omap3530_gpio.c \ + omap3530_lcd.c omap3530_sdmmc.c +COMCSRC = arp.c cast.c cache.c chario.c cmdtbl.c \ + docmd.c dhcp_00.c dhcpboot.c dns.c edit.c env.c ethernet.c \ + flash.c gdb.c icmp.c if.c ledit_vt100.c monprof.c \ + fbi.c font.c mprintf.c memcmds.c malloc.c moncom.c memtrace.c \ + misccmds.c misc.c nand.c password.c redirect.c \ + reg_cache.c sbrk.c sd.c \ + start.c struct.c symtbl.c syslog.c tcpstuff.c tfs.c tfsapi.c \ + tfsclean1.c tfscli.c tfsloader.c tfslog.c tftp.c timestuff.c \ + tsi.c xmodem.c +CPUCSRC = ldatags.c except_arm.c misc_arm.c strace_arm.c +IODEVSRC = smsc911x.c uart16550.c fb_draw.c +FLASHSRC = s29gl512n_16x1.c + + +include $(TOPDIR)/target/make/objects.make + +OBJS = $(LOCSOBJ) $(CPUSOBJ) $(LOCCOBJ) $(CPUCOBJ) $(COMCOBJ) \ + $(FLASHOBJ) $(IODEVOBJ) + +######################################################################### +# +# Targets... + +# boot: +# The default target is "boot", a shortcut to $(BUILDDIR)/boot.$(FILETYPE). +# This builds the bootflash image that can be used by 'newmon' to +# load a new version onto an already running system. +# +boot: $(BUILDDIR)/boot.$(FILETYPE) + @echo Boot version of uMon built under $(BUILDDIR) ... + @ls $(BUILDDIR)/boot* + +# ramtst: +# A shortcut to $(BUILDDIR)/ramtst.$(FILETYPE). This is a version of uMon +# that resides strictly in RAM and is used for two main purposes: +# 1. To test new monitor features prior to burning the boot flash. +# 2. To be downloaded into the RAM space of a board that has no programmed +# boot flash. This provides a running monitor that can then accept +# an incoming bootflash image using 'newmon'. +# +ramtst: $(BUILDDIR)/ramtst.$(FILETYPE) + @echo Ram-resident test version of uMon built under $(BUILDDIR) ... + @ls $(BUILDDIR)/ramtst* + +$(BUILDDIR)/boot.$(FILETYPE): $(BUILDDIR) $(OBJS) libz.a \ + libg.a makefile + $(CC) $(ASMFLAGS) -o rom_reset.o rom_reset.S + $(MAKE_MONBUILT) + sed -e s/ROMBASE/$(BOOTROMBASE)/ -e s/ROMLEN/$(BOOTROMLEN)/ \ + -e s/DRAMBASE/$(BOOTRAMBASE)/ -e s/DRAMLEN/$(BOOTRAMLEN)/ -e s/ATAGSIZE/$(ATAGSIZE)/ \ + $(PLATFORM)_$(@F:.$(FILETYPE)=.ldt) > $(PLATFORM)_$(@F:.$(FILETYPE)=.ld) + $(LINK) -e coldstart $(OBJS) monbuilt.o libz.a \ + libg.a $(LIBABIDIR) $(LIBGCC) + $(MAKE_BINARY) + $(MAKE_GNUSYMS) + +$(BUILDDIR)/ramtst.$(FILETYPE): $(BUILDDIR) $(OBJS) libz.a \ + libg.a makefile + $(CC) $(ASMFLAGS) -o ram_reset.o ram_reset.S + $(MAKE_MONBUILT) + sed -e s/RAMTSTROMBASE/$(RAMTSTROMBASE)/ \ + -e s/RAMTSTROMLEN/$(RAMTSTROMLEN)/ -e s/ATAGSIZE/$(ATAGSIZE)/ \ + -e s/MACADDRBASE/$(MACADDRBASE)/ -e s/ALTTFSDEVTBLBASE/$(ALTTFSDEVTBLBASE)/ \ + $(PLATFORM)_$(@F:.$(FILETYPE)=.ldt) > $(PLATFORM)_$(@F:.$(FILETYPE)=.ld) + + $(LINK) -e coldstart $(OBJS) monbuilt.o libz.a libg.a $(LIBGCC) + $(MAKE_BINARY) + $(MAKE_GNUSYMS) + +include $(TOPDIR)/target/make/rules.make + + +######################################################################### +# +# Miscellaneous... +cscope_local: + ls rom_reset.S ram_reset.S >cscope.files + ls $(FLASHDIR)/s29gl512n_16x1.c >>cscope.files + ls $(FLASHDIR)/s29gl512n_16x1.h >>cscope.files + +help_local: + +varcheck: diff --git a/ports/csb740/nand740.c b/ports/csb740/nand740.c new file mode 100644 index 0000000..95a912a --- /dev/null +++ b/ports/csb740/nand740.c @@ -0,0 +1,333 @@ +/* + * Board/device specific connection between the generic + * nand command and the CSB740's NAND memory access through + * the OMAP3530. + * + * The CSB740 uses K9K4GO8UOM NAND (512Mx8bit) device from Samsung. + * It is connected to the OMAP3530's CS3 through the CPLD. + * The device ID for this part number should be: 0xECDC109554 + * + * Maker code: 0xEC + * Device code: 0xDC + * Third cycle: 0x10 + * Fourth cycle: 0x95 + * Fifth cycle: 0x54 + * + * Blocksize: 128K (smallest eraseable chunk) + * Pagesize: 2K (64 pages per block) + * + * Taken from the NAND datasheet... + * The 528M byte physical space requires 30 addresses, thereby + * requiring five cycles for addressing : + * 2 cycles of column address, 3 cycles of row address, in that + * order. Page Read and Page Program need the same five address + * cycles following the required command input. In Block Erase + * operation, however, only the three row address cycles are used. + * Device operations are selected by writing specific commands into + * the command register. + * + * Taken from ONFI Spec: + * The address is comprised of a row address and a column address. + * The row address identifies the page, block, and LUN to be accessed. + * The column address identifies the byte or word within a page to access. + * + * Note: + * Apparently this Sansung device is not ONFI compliant. There was an + * earlier version of the CSB740 that had a Micron part on it and it was + * ONFI compliant (ONFI=Open Nand Flash Interface specification). + * + */ +#include "config.h" +#if INCLUDE_NANDCMD +#include "stddefs.h" +#include "genlib.h" +#include "omap3530.h" +#include "omap3530_mem.h" +#include "nand.h" + +static int pgSiz; +static int blkSiz; +static char onfi; + +#define NANDSTAT_FAIL 0x01 +#define NANDSTAT_READY 0x40 +#define NANDSTAT_NOTWP 0x80 + +#define NAND_CMD(cs) (vuchar *)(0x6e00007C + (0x30 * cs)) +#define NAND_ADR(cs) (vuchar *)(0x6e000080 + (0x30 * cs)) +#define NAND_DAT(cs) (vuchar *)(0x6e000084 + (0x30 * cs)) + +#define PREFETCH_READ_MODE() GPMC_REG(GPMC_PREFETCH_CONFIG1) &= ~1 +#define WRITE_POSTING_MODE() GPMC_REG(GPMC_PREFETCH_CONFIG1) |= 1 + +#define NAND_CS_BASEADDR 0x18000000 + +/* some discussion to follow: + * http://e2e.ti.com/support/dsp/omap_applications_processors/f/42/p/29683/103192.aspx + * Address is "page/block/column"... + */ + +/* nandBusyWait(): + * Poll the WAIT3 bit of the gmpc-status register, waiting for + * it to go active. + * The R/B (ready/busy) pin of the NAND device is low when busy. + * It is tied to WAIT3 of the CPU. + */ +void +nandHardBusyWait(void) +{ + while((GPMC_REG(GPMC_STATUS) & 0x800) == 0x800); + //while((GPMC_REG(GPMC_STATUS) & 0x800) == 0); +} + +void +nandSoftBusyWait(void) +{ + do { + *NAND_CMD(3) = 0x70; + } while((*NAND_DAT(3) & NANDSTAT_READY) == 0); +} + +void +nandSetColAddr(unsigned long addr) +{ + // Column1 (A07|A06|A05|A04|A03|A02|A01|A00): + *NAND_ADR(3) = ((addr & 0x000000ff)); + + // Column2 (---|---|---|---|A11|A10|A09|A08): + *NAND_ADR(3) = ((addr & 0x00000f00) >> 8); +} + +void +nandSetRowAddr(unsigned long addr) +{ + // Row1 (A19|A18|A17|A16|A15|A14|A13|A12): + *NAND_ADR(3) = ((addr & 0x000ff000) >> 12); + + // Row2 (A27|A26|A25|A24|A23|A22|A21|A20): + *NAND_ADR(3) = ((addr & 0x0ff00000) >> 20); + + // Row3 (---|---|---|---|---|---|A29|A28): + *NAND_ADR(3) = ((addr & 0x30000000) >> 28); +} + +/* nandReadChunk(): + * Transfer some chunk of memory from NAND to a destination. + */ +int +nandReadChunk(char *src, char *dest, int len) +{ + unsigned long addr = (long)src; + + PREFETCH_READ_MODE(); + + if (nandVerbose) + printf("nandReadChunk(src=0x%x,dest=0x%x,len=%d)\n",src,dest,len); + + while(len > 0) { + int tot; + + *NAND_CMD(3) = 0x00; + nandSetColAddr(addr); + nandSetRowAddr(addr); + *NAND_CMD(3) = 0x30; + + nandHardBusyWait(); + + tot = len > pgSiz ? pgSiz : len; + memcpy(dest,(char *)NAND_CS_BASEADDR,tot); + + len -= tot; + dest += tot; + } + return(0); +} + +int +nandWriteChunk(char *dest, char *src, int len) +{ + unsigned long addr = (long)dest; + + WRITE_POSTING_MODE(); + + if (nandVerbose) + printf("nandWriteBlock(dest=0x%x,src=0x%x,len=%d)\n",dest,src,len); + + *NAND_CMD(3) = 0x80; + nandSetColAddr(addr); + nandSetRowAddr(addr); + memcpy((char *)NAND_CS_BASEADDR,src,len); + *NAND_CMD(3) = 0x10; + + nandSoftBusyWait(); + + return(0); +} + +int +nandEraseChunk(char *base, int len) +{ + unsigned long addr = (long)base; + + if (nandVerbose) + printf("nandEraseChunk(addr=0x%x,len=%d)\n",addr,len); + + *NAND_CMD(3) = 0x60; + nandSetRowAddr(addr); + *NAND_CMD(3) = 0xd0; + + nandSoftBusyWait(); + + return(0); +} + +void +nandId(void) +{ + uchar d[5]; + uchar d1[4]; + + *NAND_CMD(3) = 0x90; + *NAND_ADR(3) = 0x00; + d[0] = *NAND_DAT(3); + d[1] = *NAND_DAT(3); + d[2] = *NAND_DAT(3); + d[3] = *NAND_DAT(3); + d[4] = *NAND_DAT(3); + + switch(d[3] & 3) { + case 0: + pgSiz = 1024; + break; + case 1: + pgSiz = 1024*2; + break; + case 2: + pgSiz = 1024*4; + break; + case 3: + pgSiz = 1024*8; + break; + } + switch((d[3] & 0x30) >> 4) { + case 0: + blkSiz = 1024*64; + break; + case 1: + blkSiz = 1024*128; + break; + case 2: + blkSiz = 1024*256; + break; + case 3: + blkSiz = 1024*512; + break; + } + + *NAND_CMD(3) = 0x90; + *NAND_ADR(3) = 0x20; + d1[0] = *NAND_DAT(3); + d1[1] = *NAND_DAT(3); + d1[2] = *NAND_DAT(3); + d1[3] = *NAND_DAT(3); + if (memcmp((char *)d1,"ONFI",4) == 0) + onfi = 1; + else + onfi = 0; + + if (nandVerbose) { + printf("nandID(): %02x%02x%02x%02x%02x\n",d[0],d[1],d[2],d[3],d[4]); + printf("nandID+(): %02x%02x%02x%02x%02x\n",d1[0],d1[1],d1[2],d1[3]); + printf("Page size: 0x%x\n",pgSiz); + printf("Block size: 0x%x\n",blkSiz); + printf("%sONFI compliant\n",onfi ? "" : "Not "); + } +} + +int +nandInit(void) +{ + vulong cfgreg; + +#if 0 + printf("CFG1: dm -4 0x%08x 1 = %08x\n", + MYGPMC_REG(GPMC_CS3_CONFIG1),GPMC_REG(GPMC_CS3_CONFIG1)); + printf("CFG2: dm -4 0x%08x 1 = %08x\n", + MYGPMC_REG(GPMC_CS3_CONFIG2),GPMC_REG(GPMC_CS3_CONFIG2)); + printf("CFG3: dm -4 0x%08x 1 = %08x\n", + MYGPMC_REG(GPMC_CS3_CONFIG3),GPMC_REG(GPMC_CS3_CONFIG3)); + printf("CFG4: dm -4 0x%08x 1 = %08x\n", + MYGPMC_REG(GPMC_CS3_CONFIG4),GPMC_REG(GPMC_CS3_CONFIG4)); + printf("CFG5: dm -4 0x%08x 1 = %08x\n", + MYGPMC_REG(GPMC_CS3_CONFIG5),GPMC_REG(GPMC_CS3_CONFIG5)); + printf("CFG6: dm -4 0x%08x 1 = %08x\n", + MYGPMC_REG(GPMC_CS3_CONFIG6),GPMC_REG(GPMC_CS3_CONFIG6)); + printf("CFG7: dm -4 0x%08x 1 = %08x\n", + MYGPMC_REG(GPMC_CS3_CONFIG7),GPMC_REG(GPMC_CS3_CONFIG7)); +#endif + + + /* WAIT3 of the CPU is tied to the NAND's READY pin. The NAND + * is on CS3. Referring to section 11.1.7.2.10 of the OMAP3530 TRM, + * the GPMC_CONFIGX registers must be programmed... + */ + GPMC_REG(GPMC_CONFIG) |= 0x1; // Force posted write. + GPMC_REG(GPMC_CONFIG) &= ~0x800; // WAIT3 active low. + GPMC_REG(GPMC_CS3_CONFIG7) = 0x00000858; // Base addr 0x18000000 + GPMC_REG(GPMC_CS3_CONFIG1) = 0x00030800; // 8-bit NAND, WAIT3 + GPMC_REG(GPMC_CS3_CONFIG2) = 0x00000000; // Chipselect timing + GPMC_REG(GPMC_CS3_CONFIG3) |= 0x7; + GPMC_REG(GPMC_CS3_CONFIG6) = 0x8f0307c0; + + // Set drive strength of BE0/CLE + *(vulong *)0x48002444 |= 0x00000020; + + /*********************************************************** + * + * ALE and CLE on the NAND are both active high, so we want + * them to be pulled low... + * + * ALE config is the low half of this config register, so we only + * touch the bottom half... + */ + cfgreg = SCM_REG(PADCONFS_GPMC_NADV_ALE); // NOE[31:16], NADV_ALE[15:0] + cfgreg &= 0xffff0000; + cfgreg |= 0x00000008; + SCM_REG(PADCONFS_GPMC_NADV_ALE) = cfgreg; + /* + * CLE config is the upper half of this config register, so we only + * touch the upper half... + */ + cfgreg = SCM_REG(PADCONFS_GPMC_NWE); // NBE0_CLE[31:16], NWE[15:0] + cfgreg &= 0x0000ffff; + cfgreg |= 0x00080000; + SCM_REG(PADCONFS_GPMC_NWE) = cfgreg; + + + /* WAIT3 of CPU is tied to R/B pin of NAND... + * So, we configure that pin to run as WAIT3. + * NOTE: + * There is some confusion between this and what is in cpuio.c. + * The PADCONFS_GPMC_WAIT2 register sets this pin as GPIO-65 there; + * however the comments are confusing. + */ + cfgreg = SCM_REG(PADCONFS_GPMC_WAIT2); // WAIT3[31:16], WAIT2[15:0] + cfgreg &= 0x0000ffff; + cfgreg |= 0x00080000; + SCM_REG(PADCONFS_GPMC_NWE) = cfgreg; + + nandId(); + return(0); +} + +int +nandInfo(void) +{ + nandId(); + return(0); +} + + +#endif + + diff --git a/ports/csb740/omap3530.h b/ports/csb740/omap3530.h new file mode 100755 index 0000000..7b16ffc --- /dev/null +++ b/ports/csb740/omap3530.h @@ -0,0 +1,497 @@ +//========================================================================== +// +// omap3530.h +// +// Author(s): Luis Torrico, Cogent Computer Systems, Inc. +// Contributors: +// Date: 05/02/2008 +// Description: This file contains register base addresses and offsets +// and access macros for the OMAP3530 on-chip peripherals +// Peripherals not used by UMON have not been tested (and +// may not be defined). Use these defines with caution!! +// + +#include "bits.h" + +/* + * 3530 specific Section + */ + +/* Stuff on L3 Interconnect */ +#define SMX_APE_BASE 0x68000000 + +/* L3 Firewall */ +#define A_REQINFOPERM0 (SMX_APE_BASE + 0x05048) +#define A_READPERM0 (SMX_APE_BASE + 0x05050) +#define A_WRITEPERM0 (SMX_APE_BASE + 0x05058) + +/* GPMC */ +#define OMAP35XX_GPMC_BASE 0x6E000000 + +/* SMS */ +#define OMAP35XX_SMS_BASE 0x6C000000 + +/* SDRC */ +#define OMAP35XX_SDRC_BASE 0x6D000000 + +/* + * L4 Peripherals - L4 Wakeup and L4 Core now + */ +#define OMAP35XX_CORE_L4_IO_BASE 0x48000000 + +#define OMAP35XX_WAKEUP_L4_IO_BASE 0x48300000 + +#define OMAP35XX_L4_PER 0x49000000 + +#define OMAP35XX_L4_IO_BASE OMAP35XX_CORE_L4_IO_BASE + +/* TAP information dont know for 3430*/ +#define OMAP35XX_TAP_BASE (0x49000000) /*giving some junk for virtio */ + +/* base address for indirect vectors (internal boot mode) */ +#define SRAM_OFFSET0 0x40000000 +#define SRAM_OFFSET1 0x00200000 +#define SRAM_OFFSET2 0x0000F800 +#define SRAM_VECT_CODE (SRAM_OFFSET0|SRAM_OFFSET1|SRAM_OFFSET2) + +#define LOW_LEVEL_SRAM_STACK 0x4020FFFC + +/*-------------------------------------------------------------------------------------*/ +/* UART */ +/*-------------------------------------------------------------------------------------*/ +#define OMAP35XX_UART1 (OMAP35XX_L4_IO_BASE+0x6A000) +#define OMAP35XX_UART2 (OMAP35XX_L4_IO_BASE+0x6C000) +#define OMAP35XX_UART3 (OMAP35XX_L4_PER+0x20000) +#define UART1_REG(_x_) *(vulong *)(OMAP35XX_UART1 + _x_) +#define UART2_REG(_x_) *(vulong *)(OMAP35XX_UART2 + _x_) +#define UART3_REG(_x_) *(vulong *)(OMAP35XX_UART3 + _x_) + +/* UART Register offsets */ +#define UART_RHR 0x00 // Receive Holding Register (read only) +#define UART_THR 0x00 // Transmit Holding Register (write only) +#define UART_DLL 0x00 // Baud divisor lower byte (read/write) +#define UART_DLH 0x04 // Baud divisor higher byte (read/write) +#define UART_IER 0x04 // Interrupt Enable Register (read/write) +#define UART_IIR 0x08 // Interrupt Identification Register (read only) +#define UART_FCR 0x08 // FIFO Control Register (write only) +#define UART_EFR 0x08 // Enhanced Feature Register +#define UART_LCR 0x0C // Line Control Register (read/write) +#define UART_MCR 0x10 // Modem Control Register (read/write) +#define UART_LSR 0x14 // Line Status Register (read only) +#define UART_MSR 0x18 // Modem Status Register (read only) +#define UART_TCR 0x18 // +#define UART_TLR 0x1C // +#define UART_SPR 0x1C // Scratch Pad Register (read/write) +#define UART_MDR1 0x20 // Mode Definition Register 1 +#define UART_MDR2 0x24 // Mode Definition Register 2 +//#define UART_SFLSR 0x28 // Status FIFO Line Status Register (IrDA modes only) +//#define UART_TXFLL 0x28 // Transmit Frame Length Register Low (IrDA modes only) +//#define UART_RESUME 0x2C // Resume Register (IR-IrDA and IR-CIR modes only) +//#define UART_TXFLH 0x2C // Transmit Frame Length Register High (IrDA modes only) +//#define UART_RXFLL 0x30 // Receive Frame Length Register Low (IrDA modes only) +//#define UART_SFREGL 0x30 // Status FIFO Register Low (IrDA modes only) +//#define UART_RXFLH 0x34 // Receive Frame Length Register High (IrDA modes only) +//#define UART_SFREGH 0x34 // Status FIFO Register High (IrDA modes only) +//#define UART_BLR 0x38 // BOF Control Register (IrDA modes only) +//#define UART_UASR 0x38 // UART Autobauding Status Register (UART autobauding mode only) +//#define UART_ACREG 0x3C // Auxiliary Control Register (IrDA-CIR modes only) +#define UART_SCR 0x40 // Supplementary Control Register +#define UART_SSR 0x44 // Supplementary Status Register +//#define UART_EBLR 0x48 // BOF Length Register (IR-IrDA and IR-CIR modes only) +#define UART_SYSC 0x54 // System Configuration Register +#define UART_SYSS 0x58 // System Status Register +#define UART_WER 0x5C // Wake-up Enable Register +#define UART_CFPS 0x60 // Carrier Frequency Prescaler Register + +/*-------------------------------------------------------------------------------------*/ +/* SPI - Serial Peripheral Interface */ +/*-------------------------------------------------------------------------------------*/ +#define SPI1_BASE_ADD (OMAP35XX_L4_IO_BASE+0x98000) // routed to I/O sites on CSB703 +#define SPI2_BASE_ADD (OMAP35XX_L4_IO_BASE+0x9A000) +#define SPI3_BASE_ADD (OMAP35XX_L4_IO_BASE+0xB8000) // routed to AD7843 touch controller on CSB703 +#define SPI4_BASE_ADD (OMAP35XX_L4_IO_BASE+0xBA000) +#define SPI1_REG(_x_) *(vulong *)(SPI1_BASE_ADD + _x_) +#define SPI2_REG(_x_) *(vulong *)(SPI2_BASE_ADD + _x_) +#define SPI3_REG(_x_) *(vulong *)(SPI3_BASE_ADD + _x_) +#define SPI4_REG(_x_) *(vulong *)(SPI4_BASE_ADD + _x_) + +// SPI Register Defines +#define SPI_SYSCONFIG 0x10 // System Configuration Register +#define SPI_SYSSTATUS 0x14 // System Status Register +#define SPI_IRQSTATUS 0x18 // Interrupt Status Register +#define SPI_IRQENABLE 0x1C // Interrupt Enable/Disable Register +#define SPI_WAKEUPENABLE 0x20 // WakeUp Enable/Disable Register +#define SPI_SYST 0x24 // System Test Register +#define SPI_MODULCTRL 0x28 // Serial Port Interface Configuration Register +#define SPI_CH0_CONF 0x2C // Channel 0 Configuration Register +#define SPI_CH1_CONF 0x40 // Channel 1 Configuration Register +#define SPI_CH2_CONF 0x54 // Channel 2 Configuration Register +#define SPI_CH3_CONF 0x68 // Channel 3 Configuration Register +#define SPI_CH0_STAT 0x30 // Channel 0 Status Register +#define SPI_CH1_STAT 0x44 // Channel 1 Status Register +#define SPI_CH2_STAT 0x58 // Channel 2 Status Register +#define SPI_CH3_STAT 0x6C // Channel 3 Status Register +#define SPI_CH0_CTRL 0x34 // Channel 0 Control Register +#define SPI_CH1_CTRL 0x48 // Channel 1 ControlRegister +#define SPI_CH2_CTRL 0x5C // Channel 2 ControlRegister +#define SPI_CH3_CTRL 0x70 // Channel 3 ControlRegister +#define SPI_TXD0 0x38 // Channel 0 Transmit Data Register +#define SPI_TXD1 0x4C // Channel 1 Transmit Data Register +#define SPI_TXD2 0x60 // Channel 2 Transmit Data Register +#define SPI_TXD3 0x74 // Channel 3 Transmit Data Register +#define SPI_RXD0 0x3C // Channel 0 Receive Data Register +#define SPI_RXD1 0x50 // Channel 1 Receive Data Register +#define SPI_RXD2 0x64 // Channel 2 Receive Data Register +#define SPI_RXD3 0x78 // Channel 3 Receive Data Register +#define SPI_XFERLEVEL 0x7C // FIFO Transfer Levels Register + +// SPI Channel x Configuration Bit Defines +#define SPI_CH_CONF_CLKG BIT29 // 1 = One clock cycle granularity +#define SPI_CH_CONF_FFER BIT28 // 1 = FIFO buffer is used to Receive data +#define SPI_CH_CONF_FFEW BIT27 // 1 = FIFO buffer is used to Transmit data +#define SPI_CH_CONF_TCS_0_5 (0x00 << 25) // 0.5 clock cycles between CS toggling and first (or last) edge of SPI clock +#define SPI_CH_CONF_TCS_1_5 (0x01 << 25) // 1.5 clock cycles between CS toggling and first (or last) edge of SPI clock +#define SPI_CH_CONF_TCS_2_5 (0x02 << 25) // 2.5 clock cycles between CS toggling and first (or last) edge of SPI clock +#define SPI_CH_CONF_TCS_3_5 (0x03 << 25) // 3.5 clock cycles between CS toggling and first (or last) edge of SPI clock +#define SPI_CH_CONF_SB_POL BIT24 // 1 = Start bit polarity is held to 1 during SPI transfer +#define SPI_CH_CONF_SBE BIT23 // 1 = Start bit added before SPI transfer, 0 = default length specified by WL +#define SPI_CH_CONF_SPIENSLV_0 (0x00 << 21) // Slave select detection enabled on CS0 +#define SPI_CH_CONF_SPIENSLV_1 (0x01 << 21) // Slave select detection enabled on CS1 +#define SPI_CH_CONF_SPIENSLV_2 (0x02 << 21) // Slave select detection enabled on CS2 +#define SPI_CH_CONF_SPIENSLV_3 (0x03 << 21) // Slave select detection enabled on CS3 +#define SPI_CH_CONF_FORCE BIT20 // 1 = CSx high when EPOL is 0 and low when EPOL is 1 +#define SPI_CH_CONF_TURBO BIT19 // 1 = Turbo is activated +#define SPI_CH_CONF_IS BIT18 // 1 = spim_simo selected for reception, 0 = spim_somi selected for reception +#define SPI_CH_CONF_DPE1 BIT17 // 1 = no transmission on spim_simo, 0 = spim_simo selected for transmission +#define SPI_CH_CONF_DPE0 BIT16 // 1 = no transmission on spim_somi, 0 = spim_somi selected for transmission +#define SPI_CH_CONF_DMAR BIT15 // 1 = DMA read request enabled +#define SPI_CH_CONF_DMAW BIT14 // 1 = DMA write request enabled +#define SPI_CH_CONF_TRM_TR (0x00 << 12) // Transmit and receive mode +#define SPI_CH_CONF_TRM_RO (0x01 << 12) // Receive-only mode +#define SPI_CH_CONF_TRM_TO (0x02 << 12) // Transmit-only mode +#define SPI_CH_CONF_WL(_x_) ((_x_ & 0x1f) << 7) // SPI word length, 0x7 = 8-bit +#define SPI_CH_CONF_EPOL BIT6 // 1 = SPIM_CSx is low during active state, 0 = high during active state +#define SPI_CH_CONF_CLKD(_x_) ((_x_ & 0xf) << 2) // Frequency divider for spim_clk +#define SPI_CH_CONF_POL BIT1 // 1 = spim_clk is low during active state, 0 = high during active state +#define SPI_CH_CONF_PHA BIT0 // 1 = data latched on even-numbered edges, 0 = data latched on odd-numbered edges + +// SPI Interrupt Status Register Bit Defines +#define SPI_RX3_FULL BIT14 // +#define SPI_TX3_EMPTY BIT12 // +#define SPI_RX2_FULL BIT10 // +#define SPI_TX2_EMPTY BIT8 // +#define SPI_RX1_FULL BIT14 // +#define SPI_TX1_EMPTY BIT6 // +#define SPI_RX0_FULL BIT2 // +#define SPI_TX0_EMPTY BIT0 // + +// SPI Channel Status Register Bit Defines +#define SPI_RXF_FULL BIT6 // +#define SPI_RXF_EMPTY BIT5 // +#define SPI_TXF_FULL BIT4 // +#define SPI_TXF_EMPTY BIT3 // +#define SPI_CH_EOT BIT2 // +#define SPI_CH_TX0_EMPTY BIT1 // +#define SPI_CH_RX0_FULL BIT0 // + +/*-------------------------------------------------------------------------------------*/ +/* General Purpose Timers */ +/*-------------------------------------------------------------------------------------*/ +#define OMAP35XX_GPT1 0x48318000 +#define OMAP35XX_GPT2 0x49032000 +#define OMAP35XX_GPT3 0x49034000 +#define OMAP35XX_GPT4 0x49036000 +#define OMAP35XX_GPT5 0x49038000 +#define OMAP35XX_GPT6 0x4903A000 +#define OMAP35XX_GPT7 0x4903C000 +#define OMAP35XX_GPT8 0x4903E000 +#define OMAP35XX_GPT9 0x49040000 +#define OMAP35XX_GPT10 0x48086000 +#define OMAP35XX_GPT11 0x48088000 +#define OMAP35XX_GPT12 0x48304000 + +/*-------------------------------------------------------------------------------------*/ +/* General Purpose I/O */ +/*-------------------------------------------------------------------------------------*/ +#define GPIO1_BASE_ADD 0x48310000 +#define GPIO2_BASE_ADD 0x49050000 +#define GPIO3_BASE_ADD 0x49052000 +#define GPIO4_BASE_ADD 0x49054000 +#define GPIO5_BASE_ADD 0x49056000 +#define GPIO6_BASE_ADD 0x49058000 +#define GPIO1_REG(_x_) *(vulong *)(GPIO1_BASE_ADD + _x_) +#define GPIO2_REG(_x_) *(vulong *)(GPIO2_BASE_ADD + _x_) +#define GPIO3_REG(_x_) *(vulong *)(GPIO3_BASE_ADD + _x_) +#define GPIO4_REG(_x_) *(vulong *)(GPIO4_BASE_ADD + _x_) +#define GPIO5_REG(_x_) *(vulong *)(GPIO5_BASE_ADD + _x_) +#define GPIO6_REG(_x_) *(vulong *)(GPIO6_BASE_ADD + _x_) + +/* GPIO Register offsets */ +#define GPIO_SYSCONFIG 0x10 // +#define GPIO_SYSSTATUS 0x14 // +#define GPIO_CTRL 0x30 // +#define GPIO_OE 0x34 // +#define GPIO_DATAIN 0x38 // +#define GPIO_DATAOUT 0x3C // +#define GPIO_CLEARDATAOUT 0x90 // +#define GPIO_SETDATAOUT 0x94 // + +/*-------------------------------------------------------------------------------------*/ +/* WatchDog Timers (1 secure, 3 GP) */ +/*-------------------------------------------------------------------------------------*/ +#define WD1_BASE_ADD 0x4830C000 +#define WD2_BASE_ADD 0x48314000 +#define WD3_BASE_ADD 0x49030000 +#define WD1_REG(_x_) *(vulong *)(WD1_BASE_ADD + _x_) +#define WD2_REG(_x_) *(vulong *)(WD2_BASE_ADD + _x_) +#define WD3_REG(_x_) *(vulong *)(WD3_BASE_ADD + _x_) + +/* WatchDog Timer Register offsets */ +#define WD_CONFIG 0x10 // System Configuration Register +#define WD_STATUS 0x14 // System Configuration Register +#define WD_WISR 0x18 // System Configuration Register +#define WD_WIER 0x1C // System Configuration Register +#define WD_WCLR 0x24 // System Configuration Register +#define WD_WCRR 0x28 // System Configuration Register +#define WD_WLDR 0x2C // System Configuration Register +#define WD_WTGR 0x30 // System Configuration Register +#define WD_WWPS 0x34 // System Configuration Register +#define WD_WSPR 0x48 // System Configuration Register + +/*-------------------------------------------------------------------------------------*/ +/* 32KTIMER */ +/*-------------------------------------------------------------------------------------*/ +#define SYNC_32KTIMER_BASE (0x48320000) +#define S32K_CR (SYNC_32KTIMER_BASE+0x10) + +/*-------------------------------------------------------------------------------------*/ +/* System Control Module */ +/*-------------------------------------------------------------------------------------*/ +/* Module Name Base Address Size */ +/* + INTERFACE 0x48002000 36 bytes + PADCONFS 0x48002030 564 bytes + GENERAL 0x48002270 767 bytes + MEM_WKUP 0x48002600 1K byte + PADCONFS_WKU 0x48002A00 80 bytes + GENERAL_WKUP 0x48002A60 31 bytes +*/ +/*-------------------------------------------------------------------------------------*/ +#define OMAP35XX_CTRL_BASE (OMAP35XX_L4_IO_BASE+0x2000) +#define SCM_REG(_x_) *(vulong *)(OMAP35XX_CTRL_BASE + _x_) + +/* Pad Configuration Registers */ +/* Note: Cogent is only defining the PADCONFS registers that are used in Micromonitor */ +#define PADCONFS_GPMC_NCS3 0xB4 // NCS3[15:0], NCS4[31:16] +#define PADCONFS_GPMC_NCS5 0xB8 // NCS5[15:0], EXP_INTX[31:16] +#define PADCONFS_GPMC_NCS7 0xBC // LCD_BKL_X[15:0], LCLK[31:16] +#define PADCONFS_GPMC_NADV_ALE 0xC0 // NADV_ALE[15:0], NOE[31:16] +#define PADCONFS_GPMC_NWE 0xC4 // NWE[15:0], NBE0_CLE[31:16] +#define PADCONFS_DSS_PCLK 0xD4 // LCD_PCLK_X[15:0], LCD_HS_X[31:16] +#define PADCONFS_DSS_VSYNC 0xD8 // LCD_VS_X[15:0], LCD_OE_X[31:16] +#define PADCONFS_DSS_DATA0 0xDC // LCD_B0_X[15:0], LCD_B1_X[31:16] +#define PADCONFS_DSS_DATA2 0xE0 // LCD_B2_X[15:0], LCD_B3_X[31:16] +#define PADCONFS_DSS_DATA4 0xE4 // LCD_B4_X[15:0], LCD_B5_X[31:16] +#define PADCONFS_DSS_DATA6 0xE8 // LCD_G0_X[15:0], LCD_G1_X[31:16] +#define PADCONFS_DSS_DATA8 0xEC // LCD_G2_X[15:0], LCD_G3_X[31:16] +#define PADCONFS_DSS_DATA10 0xF0 // LCD_G4_X[15:0], LCD_G5_X[31:16] +#define PADCONFS_DSS_DATA12 0xF4 // LCD_R0_X[15:0], LCD_R1_X[31:16] +#define PADCONFS_DSS_DATA14 0xF8 // LCD_R2_X[15:0], LCD_R3_X[31:16] +#define PADCONFS_DSS_DATA16 0xFC // LCD_R4_X[15:0], LCD_R5_X[31:16] +#define PADCONFS_DSS_DATA18 0x100 // SPI1_CLK_X[15:0], SPI1_MOSI_X[31:16] +#define PADCONFS_DSS_DATA20 0x104 // SPI1_MISO_X[15:0], *SPI1_CS0_X[31:16] +#define PADCONFS_DSS_DATA22 0x108 // GPIO7_X[15:0], NC[31:16] +#define PADCONFS_MMC1_DAT4 0x150 // *I2C_INT_X[15:0], *PIRQ_X[31:16] +#define PADCONFS_MMC1_DAT6 0x154 // GPIO0_X[15:0], GPIO1_X[31:16] +#define PADCONFS_MCBSP3_CLKX 0x170 // D_TXD[15:0], D_RXD[31:16] +#define PADCONFS_SYS_NIRQ 0x1E0 // FIQ[15:0], SYS_CLK2[31:16] +#define PADCONFS_SYS_OFF_MODE 0xA18 // OFF_MODE_X[15:0], USB_CLK[31:16] +#define PADCONFS_GPMC_WAIT2 0xD0 // NA[15:0], E_INTX[31:16] +#define PADCONFS_MMC1_CLK 0x144 // MMC1_CLK[15:0], MMC1_CMD[31:16] +#define PADCONFS_MMC1_DAT0 0x148 // MMC1_DAT0[15:0], MMC1_DAT1[31:16] +#define PADCONFS_MMC1_DAT2 0x14C // MMC1_DAT2[15:0], MMC1_DAT3[31:16] + + +#define CM_REV_REG 0x48004800 +#define PRM_REV_REG 0x48306804 +#define CM_REV_MAJ() ((*(volatile unsigned long *)CM_REV_REG & 0xf0)>>4) +#define CM_REV_MIN() (*(volatile unsigned long *)CM_REV_REG & 0x0f) +#define PRM_REV_MAJ() ((*(volatile unsigned long *)PRM_REV_REG & 0xf0)>>4) +#define PRM_REV_MIN() (*(volatile unsigned long *)PRM_REV_REG & 0x0f) + +/* MMC registers... + */ +#define CM_FCLKEN1_CORE 0x48004a00 +#define CM_ICLKEN1_CORE 0x48004a10 +#define CM_IDLEST1_CORE 0x48004a20 +#define CM_AUTOIDLE1_CORE 0x48004a30 +#define PM_WKEN1_CORE 0x48306aa0 +#define PM_MPUGRPSEL1_CORE 0x48306aa4 +#define PM_IVA2GRPSEL1_CORE 0x48306aa8 +#define PM_WKST1_CORE 0x48306ab0 +#define CONTROL_DEVCONF0 0x48002274 +#define MMC1_BASE_ADD 0x4809c000 +#define MMC2_BASE_ADD 0x480ad000 +#define MMC3_BASE_ADD 0x480b4000 +#define MMC1_REG(_x_) *(vulong *)(MMC1_BASE_ADD + _x_) +#define MMC2_REG(_x_) *(vulong *)(MMC2_BASE_ADD + _x_) +#define MMC3_REG(_x_) *(vulong *)(MMC3_BASE_ADD + _x_) +#define MMCHS_SYSCONFIG 0x10 +#define MMCHS_SYSSTATUS 0x14 +#define MMCHS_CSRE 0x24 +#define MMCHS_SYSTEST 0x28 +#define MMCHS_CON 0x2C +#define MMCHS_PWCNT 0x30 +#define MMCHS_BLK 0x104 +#define MMCHS_ARG 0x108 +#define MMCHS_CMD 0x10C +#define MMCHS_RSP10 0x110 +#define MMCHS_RSP32 0x114 +#define MMCHS_RSP54 0x118 +#define MMCHS_RSP76 0x11C +#define MMCHS_DATA 0x120 +#define MMCHS_PSTATE 0x124 +#define MMCHS_HCTL 0x128 +#define MMCHS_SYSCTL 0x12C +#define MMCHS_STAT 0x130 +#define MMCHS_IE 0x134 +#define MMCHS_ISE 0x138 +#define MMCHS_AC12 0x13C +#define MMCHS_CAPA 0x140 +#define MMCHS_CUR_CAPA 0x148 +#define MMCHS_REV 0x1FC + +/* Miscellaneous MMC register bits... + * (only specified the ones I use) + */ +#define EN_MMC1 (1 << 24) +#define ST_MMC1 (1 << 24) +#define AUTO_MMC1 (1 << 24) +#define GRPSEL_MMC1 (1 << 24) +#define VS18 0x04000000 +#define VS30 0x02000000 +#define VS33 0x01000000 +#define MMCINIT 0x00000002 +#define ODE 0x00000001 +#define SVDS 0x00000e00 +#define SVDS18 (5 << 9) +#define SVDS30 (6 << 9) +#define SVDS33 (7 << 9) +#define SDBP 0x00000100 +#define ICE 0x00000001 +#define ICS 0x00000002 +#define CEN 0x00000004 +#define CLKD(v) ((v & 0x3ff) << 6) +#define CLKDMSK (0x3ff << 6) +#define CLKACTIVITYMSK (3 << 8) +#define CLKACTIVITY(n) ((n & 3) << 8) +#define SIDLEMODEMSK (3 << 3) +#define SIDLEMODE(n) ((n & 3) << 3) +#define ENWAKEUP (1 << 2) +#define IWE (1 << 24) +#define AUTOIDLE 1 +#define CLKEXTFREE (1 << 16) +#define SRESET 0x00000002 +#define CC 0x00000001 +#define RESETDONE 0x00000001 +#define IE_ALL 0x317f8337 +#define CDP (1 << 7) +#define CMD(v) ((v & 0x3f) << 24) +#define CMDMSK (0x3f << 24) +#define CMDI 0x00000001 +#define DEBOUNCE (3 << 16) +#define CCRC (1 << 17) +#define DCRC (1 << 21) +#define CERR (1 << 28) +#define CTO (1 << 16) +#define DP (1 << 21) +#define RSPTYPE_NONE 0x00000000 +#define RSPTYPE_136 0x00010000 +#define RSPTYPE_48 0x00020000 +#define RSPTYPE_48BSY 0x00030000 +#define RSPTYPE 0x00030000 +#define SRD (1 << 26) +#define SRC (1 << 25) +#define SRA (1 << 24) +#define DTOMSK (0xf<<16) +#define DTO(a) ((a&0xf) << 16) +#define NBLK(a) ((a&0xffff) << 16) +#define BLEN(a) (a&0x7ff) +#define MMCSDIO1ADPCLKISEL (1 << 24) + +/* PBIAS... + */ +#define CONTROL_PBIAS_LITE 0x48002520 +#define PBIAS_LITE_VMMC1_3V (0x0101) +#define MMC_PWR_STABLE (0x0202) +#define PBIAS_LITE_VMMC1_52MHZ (0x0404) +#define PBIAS_LITE_MMC1_ERROR (0x0808) +#define PBIAS_LITE_MMC1_HIGH (0x8080) + +/* Control status... + */ +#define CONTROL_STATUS 0x480022f0 +#define SYSBOOT 0x3f +#define DEVICETYPE (0x3 << 8) + +/* 16 bit access CONTROL */ +#define MUX_VAL(OFFSET,VALUE)\ + *(unsigned short *) (OMAP35XX_CTRL_BASE + (OFFSET)) = VALUE; + +#define CP(x) (CONTROL_PADCONF_##x) + +#define CONTROL_PADCONF_DSS_DATA18 0x0100 +#define CONTROL_PADCONF_DSS_DATA19 0x0102 +#define CONTROL_PADCONF_DSS_DATA20 0x0104 +#define CONTROL_PADCONF_DSS_DATA21 0x0106 + +#define CONTROL_PADCONF_MMC1_CLK 0x0144 +#define CONTROL_PADCONF_MMC1_CMD 0x0146 +#define CONTROL_PADCONF_MMC1_DAT0 0x0148 +#define CONTROL_PADCONF_MMC1_DAT1 0x014A +#define CONTROL_PADCONF_MMC1_DAT2 0x014C +#define CONTROL_PADCONF_MMC1_DAT3 0x014E + +#define CONTROL_PADCONF_HSUSB0_CLK 0x01A2 +#define CONTROL_PADCONF_HSUSB0_STP 0x01A4 +#define CONTROL_PADCONF_HSUSB0_DIR 0x01A6 +#define CONTROL_PADCONF_HSUSB0_NXT 0x01A8 +#define CONTROL_PADCONF_HSUSB0_DATA0 0x01AA +#define CONTROL_PADCONF_HSUSB0_DATA1 0x01AC +#define CONTROL_PADCONF_HSUSB0_DATA2 0x01AE +#define CONTROL_PADCONF_HSUSB0_DATA3 0x01B0 +#define CONTROL_PADCONF_HSUSB0_DATA4 0x01B2 +#define CONTROL_PADCONF_HSUSB0_DATA5 0x01B4 +#define CONTROL_PADCONF_HSUSB0_DATA6 0x01B6 +#define CONTROL_PADCONF_HSUSB0_DATA7 0x01B8 +#define CONTROL_PADCONF_I2C1_SCL 0x01BA +#define CONTROL_PADCONF_I2C1_SDA 0x01BC +#define CONTROL_PADCONF_McBSP3_DX 0x016C + +/* bits used in control reg's above + * IEN - Input Enable + * IDIS - Input Disable + * PTD - Pull type Down + * PTU - Pull type Up + * DIS - Pull type selection is inactive + * EN - Pull type selection is active + * M0 - Mode 0 + */ + +#define IEN (1 << 8) + +#define IDIS (0 << 8) +#define PTU (1 << 4) +#define PTD (0 << 4) +#define EN (1 << 3) +#define DIS (0 << 3) + +#define M0 0 /* modes */ +#define M1 1 +#define M2 2 +#define M3 3 +#define M4 4 +#define M5 5 +#define M6 6 +#define M7 7 + diff --git a/ports/csb740/omap3530_gpio.c b/ports/csb740/omap3530_gpio.c new file mode 100755 index 0000000..e1e4315 --- /dev/null +++ b/ports/csb740/omap3530_gpio.c @@ -0,0 +1,329 @@ +//========================================================================== +// +// mx31_gpio.c +// +// +// Author(s): Luis Torrico, Cogent Computer Systems, Inc. +// Contributors: +// Date: 05/09/2008 +// Description: This file contains code to intialize the MCIMX31 GPIO +// section as well as functions for manipulating the GPIO +// bits +// +//-------------------------------------------------------------------------- + +#include "config.h" +#include "cpuio.h" +#include "stddefs.h" +#include "genlib.h" +#include "omap3530.h" +#include "cpu_gpio.h" // pull in target board specific header + +//#define GPIO_DBG + +//-------------------------------------------------------- +// GPIO_init() +// +// This function sets the startup state for the MCIMX31 GPIO +// registers as used on the target CPU. Refer to cpu_gpio.h +// for a description of the default values. Here we just put +// them into the chip in the following order: +// 1. Port x DR - Data Register +// 2. Port x DIR - Direction Register +// 3. Port x PSTAT - Pad Status Register +// 4. Port x ICR1 - GPIO Interrupt Configuration Register 1 +// 5. Port x ICR2 - GPIO Interrupt Configuration Register 2 +// 6. Port x IMASK - GPIO Interrupt Mask Register +// 7. Port x ISTAT - GPIO Interrupt Status Register + +void GPIO_init() +{ + // Port 1 + GPIO1_REG(GPIO_OE) = PORT1_OE; + GPIO1_REG(GPIO_DATAOUT) = PORT1_DR; + //GPIO1_REG(GPIO_CLEARDATAOUT) = 0; + //GPIO1_REG(GPIO_SETDATAOUT) = 0; + + // Port 2 + //GPIO2_REG(GPIO_OE) = 0xFEFFFFFF; + GPIO2_REG(GPIO_OE) = PORT2_OE; + GPIO2_REG(GPIO_DATAOUT) = PORT2_DR; + //GPIO2_REG(GPIO_CLEARDATAOUT) = 0; + //GPIO2_REG(GPIO_SETDATAOUT) = 0; + + // Port 3 + GPIO3_REG(GPIO_OE) = PORT3_OE; + GPIO3_REG(GPIO_DATAOUT) = PORT3_DR; + //GPIO3_REG(GPIO_CLEARDATAOUT) = 0; + //GPIO3_REG(GPIO_SETDATAOUT) = 0; + + // Port 4 + GPIO4_REG(GPIO_OE) = PORT4_OE; + GPIO4_REG(GPIO_DATAOUT) = PORT4_DR; + //GPIO4_REG(GPIO_CLEARDATAOUT) = 0; + //GPIO4_REG(GPIO_SETDATAOUT) = 0; + + // Port 5 + GPIO5_REG(GPIO_OE) = PORT5_OE; + GPIO5_REG(GPIO_DATAOUT) = PORT5_DR; + //GPIO5_REG(GPIO_CLEARDATAOUT) = 0; + //GPIO5_REG(GPIO_SETDATAOUT) = 0; + + // Port 6 + GPIO6_REG(GPIO_OE) = PORT6_OE; + GPIO6_REG(GPIO_DATAOUT) = PORT6_DR; + //GPIO6_REG(GPIO_CLEARDATAOUT) = 0; + //GPIO6_REG(GPIO_SETDATAOUT) = 0; +} + +//-------------------------------------------------------- +// GPIO_set() +// +// This function sets the desired bit passed in. +// NOTE: We do not test to see if setting the bit +// would screw up any alternate functions. Use +// this function with caution! +// + +int GPIO_set(int gpio_bit) +{ + // quick sanity test +#ifdef GPIO_DBG + printf("GPIO_set %d.\n", gpio_bit); +#endif + if (gpio_bit > 191) return -1; + + if (gpio_bit < 32) + { + // Port 1 + GPIO1_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 0)); + } + else if (gpio_bit < 64) + { + // Port 2 + GPIO2_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 32)); + } + else if (gpio_bit < 96) + { + // Port 3 + GPIO3_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 64)); + } + else if (gpio_bit < 128) + { + // Port 4 + GPIO4_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 96)); + } + else if (gpio_bit < 160) + { + // Port 5 + GPIO5_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 128)); + } + else + { + // Port 6 + GPIO6_REG(GPIO_DATAOUT) |= (1 << (gpio_bit - 160)); + } + return 0; +} + +//-------------------------------------------------------- +// GPIO_clr() +// +// This function clears the desired bit passed in. +// + +int GPIO_clr(int gpio_bit) +{ +#ifdef GPIO_DBG + printf("GPIO_clr %d.\n", gpio_bit); +#endif + // quick sanity test + if (gpio_bit > 191) return -1; + + if (gpio_bit < 32) + { + // Port 1 + GPIO1_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 0)); + } + else if (gpio_bit < 64) + { + // Port 2 + GPIO2_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 32)); + } + else if (gpio_bit < 96) + { + // Port 3 + GPIO3_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 64)); + } + else if (gpio_bit < 128) + { + // Port 4 + GPIO4_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 96)); + } + else if (gpio_bit < 160) + { + // Port 5 + GPIO5_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 128)); + } + else + { + // Port 6 + GPIO6_REG(GPIO_DATAOUT) &= ~(1 << (gpio_bit - 160)); + } + return 0; +} +//-------------------------------------------------------- +// GPIO_tst() +// +// This function returns the state of desired bit passed in. +// It does not test to see if it's an input or output and thus +// can be used to verify if an output set/clr has taken place +// as well as for testing an input state. +// + +int GPIO_tst(int gpio_bit) +{ +#ifdef GPIO_DBG + printf("GPIO_tst %d.\n", gpio_bit); +#endif + // quick sanity test + if (gpio_bit > 191) return -1; + + if (gpio_bit < 32) + { + // Port 1 + if (GPIO1_REG(GPIO_DATAIN) & (1 << (gpio_bit - 0))) return 1; + } + else if (gpio_bit < 64) + { + // Port 2 + if (GPIO2_REG(GPIO_DATAIN) & (1 << (gpio_bit - 32))) return 1; + } + else if (gpio_bit < 96) + { + // Port 3 + if (GPIO3_REG(GPIO_DATAIN) & (1 << (gpio_bit - 64))) return 1; + } + else if (gpio_bit < 128) + { + // Port 4 + if (GPIO4_REG(GPIO_DATAIN) & (1 << (gpio_bit - 96))) return 1; + } + else if (gpio_bit < 160) + { + // Port 5 + if (GPIO5_REG(GPIO_DATAIN) & (1 << (gpio_bit - 128))) return 1; + } + else + { + // Port 6 + if (GPIO6_REG(GPIO_DATAIN) & (1 << (gpio_bit - 160))) return 1; + } + return 0; // bit was not set +} + +//-------------------------------------------------------- +// GPIO_out() +// +// This function changes the direction of the desired bit +// to output. NOTE: We do not test to see if changing the +// direction of the bit would screw up anything. Use this +// function with caution! +// +// This only worlks if the GPIO has been defined as a GPIO +// during init. It will not override the init setting, only +// change the direction bit + +int GPIO_out(int gpio_bit) +{ +#ifdef GPIO_DBG + printf("GPIO_out %d.\n", gpio_bit); +#endif + // quick sanity test + if (gpio_bit > 191) return -1; + + if (gpio_bit < 32) + { + // Port 1 + GPIO1_REG(GPIO_OE) &= ~(1 << (gpio_bit - 0)); + } + else if (gpio_bit < 64) + { + // Port 2 + GPIO2_REG(GPIO_OE) &= ~(1 << (gpio_bit - 32)); + } + else if (gpio_bit < 96) + { + // Port 3 + GPIO3_REG(GPIO_OE) &= ~(1 << (gpio_bit - 64)); + } + else if (gpio_bit < 128) + { + // Port 4 + GPIO4_REG(GPIO_OE) &= ~(1 << (gpio_bit - 96)); + } + else if (gpio_bit < 160) + { + // Port 5 + GPIO5_REG(GPIO_OE) &= ~(1 << (gpio_bit - 128)); + } + else + { + // Port 6 + GPIO6_REG(GPIO_OE) &= ~(1 << (gpio_bit - 160)); + } + return 0; +} + +//-------------------------------------------------------- +// GPIO_in() +// +// This function changes the direction of the desired bit +// to input. NOTE: We do not test to see if changing the +// direction of the bit would screw up anything. Use this +// function with caution! +// +// This only worlks if the GPIO has been defined as a GPIO +// during init. It will not override the init setting, only +// change the direction bit +int GPIO_in(int gpio_bit) +{ +#ifdef GPIO_DBG + printf("GPIO_in %d.\n", gpio_bit); +#endif + // quick sanity test + if (gpio_bit > 191) return -1; + + if (gpio_bit < 32) + { + // Port 1 + GPIO1_REG(GPIO_OE) |= (1 << (gpio_bit - 0)); + } + else if (gpio_bit < 64) + { + // Port 2 + GPIO2_REG(GPIO_OE) |= (1 << (gpio_bit - 32)); + } + else if (gpio_bit < 96) + { + // Port 3 + GPIO3_REG(GPIO_OE) |= (1 << (gpio_bit - 64)); + } + else if (gpio_bit < 128) + { + // Port 4 + GPIO4_REG(GPIO_OE) |= (1 << (gpio_bit - 96)); + } + else if (gpio_bit < 160) + { + // Port 5 + GPIO5_REG(GPIO_OE) |= (1 << (gpio_bit - 128)); + } + else + { + // Port 6 + GPIO6_REG(GPIO_OE) |= (1 << (gpio_bit - 160)); + } + return 0; +} + diff --git a/ports/csb740/omap3530_iomux.c b/ports/csb740/omap3530_iomux.c new file mode 100755 index 0000000..586ac48 --- /dev/null +++ b/ports/csb740/omap3530_iomux.c @@ -0,0 +1,530 @@ +//mx31_iomux.c + +#include "config.h" +#include "cpuio.h" +#include "stddefs.h" +#include "genlib.h" +#include "omap3530.h" +#include "omap3530_iomux.h" +#include "cpu_gpio.h" // pull in target board specific header + +void iomux_init() +{ + +// Initialization of GPR for CSB733 +IOMUX_CTL_REG(GENERAL_REGISTER) = WEIM_ON_CS3_EN | CSPI1_ON_UART_EN; + +// MX31_PIN_TTM_PAD = can not be written to. +// cspi_miso = U2_RXD, cspi3_sclk = U2_RTS, cspi3_spi_rdy = U2_CTS, ttm_pad = default +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER1) = MX31_PIN_CSPI3_MISO((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)) + | MX31_PIN_CSPI3_SCLK((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)) + | MX31_PIN_CSPI3_SPI_RDY((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)); +// | MX31_PIN_TTM_PAD(); + +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER1) = MX31_PIN_CSPI3_MISO(0x20) +// | MX31_PIN_CSPI3_SCLK(0x20) +// | MX31_PIN_CSPI3_SPI_RDY(0x20); +//// | MX31_PIN_TTM_PAD(); + +// MX31_PIN_CLKSS and MX31_PIN_CE_CONTROL = can not be written to. +// reset_b = NC, ce_control = default, ctl_clkss = default, cspi3_mosi = U2_RXD +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER2) = MX31_PIN_ATA_RESET_B((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_CE_CONTROL((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) +// | MX31_PIN_CLKSS() + | MX31_PIN_CSPI3_MOSI((OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1)); + +// ata_cs1 = NC, ata_dior = D_TXD, ata_diow = NC, ata, dmack = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER3) = MX31_PIN_ATA_CS1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_ATA_DIOR((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)) + | MX31_PIN_ATA_DIOW((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_ATA_DMACK((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// sd1_data1 = SD_D1, sd1_data2 = SD_D2, sd1_data3 = SD_D3, ata_cs0 = D_RXD +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER4) = MX31_PIN_SD1_DATA1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SD1_DATA2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SD1_DATA3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_ATA_CS0((OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1)); + +// d3_spl = NC, sd1_cmd = SD_CMD, sd1_clk - SD_CLK, sd1_data0 = SD_D0 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER5) = MX31_PIN_D3_SPL((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_SD1_CMD((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SD1_CLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)) + | MX31_PIN_SD1_DATA0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// vsync3 = LCD_VSYNC, contrast = NC, d3_rev = NC, d3_cls = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER6) = MX31_PIN_VSYNC3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CONTRAST((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_D3_REV((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_D3_CLS((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)); + +// ser_rs = NC, par_rs = NC, write = NC, read = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER7) = MX31_PIN_SER_RS((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_PAR_RS((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_WRITE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_READ((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// sd_d_io = NC, sd_d_clk = NC, lcs0 = NC, lcs1 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER8) = MX31_PIN_SD_D_IO((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_SD_D_CLK((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_LCS0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_LCS1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// hsync = LCD_HSYNC, fpshift = LCD_PCLK, drdy0 = LCD_OE, sd_d_i = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER9) = MX31_PIN_HSYNC((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)) + | MX31_PIN_FPSHIFT((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)) + | MX31_PIN_DRDY0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SD_D_I((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// ld15 = LCD_R3, ld16 = LCD_R4, ld17 = LCD_R5, sd_d_i = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER10) = MX31_PIN_LD15((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD16((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD17((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_VSYNC0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// ld11 = LCD_G5, ld12 = LCD_R0, ld13 = LCD_R1, ld14 = LCD_R2 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER11) = MX31_PIN_LD11((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD12((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD13((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD14((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// ld7 = LCD_G1, ld8 = LCD_G2, ld9 = LCD_G3, ld10 = LCD_G4 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER12) = MX31_PIN_LD7((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD8((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD9((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD10((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// ld3 = LCD_B3, ld4 = LCD_B4, ld5 = LCD_B5, ld6 = LCD_G0 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER13) = MX31_PIN_LD3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD4((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// usbh2_data1 = UH2_D1, ld0 = LCD_B0, ld1 = LCD_B1, ld2 = LCD_B0 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER14) = MX31_PIN_USBH2_DATA1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_LD2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// usbh2_dir = UH2_DIR, usbh2_stp = UH2_STP, usbh2_nxt = UH2_NXT, usbh2_data0 = UH2_D0 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER15) = MX31_PIN_USBH2_DIR((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)) + | MX31_PIN_USBH2_STP((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBH2_NXT((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBH2_DATA0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// usbotg_data5 = UD_D5, usbotg_data6 = UD_D6, usbotg_data7 = UD_D7, usbh2_clk = UH2_CLK +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER16) = MX31_PIN_USBOTG_DATA5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBOTG_DATA6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBOTG_DATA7((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBH2_CLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// usbotg_data1 = UD_D1, usbotg_data2 = UD_D2, usbotg_data3 = UD_D3, usbotg_data4 = UD_D4 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER17) = MX31_PIN_USBOTG_DATA1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBOTG_DATA2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBOTG_DATA3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBOTG_DATA4((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// usbotg_dir = UD_DIR, usbotg_stp = UD_STP, usbotg_nxt = UD_NXT, usbotg_data0 = UD_D0 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER18) = MX31_PIN_USBOTG_DIR((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBOTG_STP((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)) + | MX31_PIN_USBOTG_NXT((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_USBOTG_DATA0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// usb_pwr = NC, usb_oc = CF_RST, usb_byp = NC, usbotg_clk = UD_CLK +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER19) = MX31_PIN_USB_PWR((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_USB_OC((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_USB_BYP((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_USBOTG_CLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// MX31_PIN_TDO and MX31_PIN_SJC_MOD = can not be written to +// tdo = TDO_C, trstb = TRST_C, de_b = TP1, sjc_mod = GND +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER20) = MX31_PIN_TDO() +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER20) = MX31_PIN_TRSTB((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_DE_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); +// | MX31_PIN_SJC_MOD(); + +// MX31_PIN_RTCK = can not be written to. +// rtck = NC, tck = TCK_C, tms = TMS_C, tdi = TDI_C +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER21) = MX31_PIN_RTCK() +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER21) = MX31_PIN_TCK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_TMS((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_TDI((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// key_col4 = NC, key_col5 = NC, key_col6 = NC, key_col7 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER22) = MX31_PIN_KEY_COL4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_KEY_COL5((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_KEY_COL6((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_KEY_COL7((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// key_col0 = NC, key_col1 = NC, key_col2 = NC, key_col3 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER23) = MX31_PIN_KEY_COL0((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_KEY_COL1((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_KEY_COL2((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_KEY_COL3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)); + +// key_row4 = NC, key_row5 = NC, key_row6 = NC, key_row7 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER24) = MX31_PIN_KEY_ROW4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_KEY_ROW5((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_KEY_ROW6((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_KEY_ROW7((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// key_row0 = NC, key_row1 = NC, key_row2 = NC, key_row3 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER25) = MX31_PIN_KEY_ROW0((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_KEY_ROW1((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_KEY_ROW2((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_KEY_ROW3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)); + +// txd2 = U1_TXD, rts2 = U1_RTS, cts2 = U1_CTS, batt_line = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER26) = MX31_PIN_TXD2((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)) + | MX31_PIN_RTS2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CTS2((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)) + | MX31_PIN_BATT_LINE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// ri_dte1, dcd_dte1, and dtr_dce2 are set to CSPI1 signals by GPR(2) +// rxd2 = U1_RXD +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER27) = MX31_PIN_RI_DTE1() +// | MX31_PIN_DCD_DTE1() +// | MX31_PIN_DTR_DCE2() +// | MX31_PIN_RXD2(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC); +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER27) = MX31_PIN_RXD2((OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC)); + +// dtr_dte1 and dsr_dte1 are set to CSPI1 signals by GPR(2) +// ri_dce1 = SPI0_RDY, dcd_dce1 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER28) = MX31_PIN_RI_DCE1((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)) + | MX31_PIN_DCD_DCE1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); +// | MX31_PIN_DTR_DTE1() +// | MX31_PIN_DSR_DTE1(); + +// rts1 = U0_RTS, cts1 = U0_CTS, dtr_dce1 = NC, dsr_dce1 = SPI0_CLK +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER29) = MX31_PIN_RTS1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CTS1((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)) + | MX31_PIN_DTR_DCE1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_DSR_DCE1((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)); + +// cspi2_sclk = SPI1_CLK, cspi2_spi_rdy = SPI1_RDY, rxd1 = U0_RXD, txd1 = U0_TXD +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER30) = MX31_PIN_CSPI2_SCLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSPI2_SPI_RDY((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_RXD1((OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC)) + | MX31_PIN_TXD1((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)); + +// cspi2_miso = SPI1_MISO, cspi2_ss0 = SPI1_CS0, cspi2_ss1 = SPI1_CS1, cspi2_ss2 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER31) = MX31_PIN_CSPI2_MISO((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSPI2_SS0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSPI2_SS1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSPI2_SS2((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)); + +// cspi1_ss2 = UH1_RCV, cspi1_sclk = UH1_OE, cspi1_spi_rdy = UH1_FS, cspi2_mosi = SPI1_MOSI +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER32) = MX31_PIN_CSPI1_SS2((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)) + | MX31_PIN_CSPI1_SCLK((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)) + | MX31_PIN_CSPI1_SPI_RDY((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)) + | MX31_PIN_CSPI2_MOSI((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// cspi1_mosi = UH1_RXDM, cspi1_miso = UH1_RXDP, cspi1_ss0 = UH1_TXDM, cspi1_ss1 = UH1_TXDP +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER33) = MX31_PIN_CSPI1_MOSI((OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1)) + | MX31_PIN_CSPI1_MISO((OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1)) + | MX31_PIN_CSPI1_SS0((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)) + | MX31_PIN_CSPI1_SS1((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)); + +// stxd6 = AC_SDOUT, srxd6 = AC_SDIN, sck6 = AC_BCLK, sfs6 = AC_SYNC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER34) = MX31_PIN_STXD6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SRXD6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SCK6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SFS6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// stxd5 = SSI_TXD, srxd5 = SSI_RXD, sck5 = SSI_CLK, sfs5 = SSI_FRM +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER35) = MX31_PIN_STXD5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SRXD5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SCK5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SFS5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// stxd4 = NC, srxd4 = NC, sck4 = SSI_MCLK, sfs4 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER36) = MX31_PIN_STXD4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_SRXD4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_SCK4((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SFS4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// stxd3 = AC_RST, srxd3 = NC, sck3 = NC, sfs3 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER37) = MX31_PIN_STXD3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_SRXD3((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_SCK3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_SFS3((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)); + +// csi_hsync = VIP_HSYNC, csi_pixclk = VIP_PCLK, i2c_clk = I2C_SCL, i2c_dat = I2C_SDA +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER38) = MX31_PIN_CSI_HSYNC((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_PIXCLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_I2C_CLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_I2C_DAT((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// csi_d14 = VIP_D8, csi_d15 = VIP_D9, csi_mclk = VIP_MCLK, csi_vsync = VIP_VSYNC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER39) = MX31_PIN_CSI_D14((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_D15((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_MCLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE)) + | MX31_PIN_CSI_VSYNC((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// csi_d10 = VIP_D4, csi_d11 = VIP_D5, csi_D12 = VIP_D6, csi_D13 = VIP_D7 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER40) = MX31_PIN_CSI_D10((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_D11((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_D12((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_D13((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// csi_d6 = VIP_D0, csi_d7 = VIP_D1, csi_D8 = VIP_D2, csi_D9 = VIP_D3 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER41) = MX31_PIN_CSI_D6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_D7((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_D8((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_D9((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// m_request = NC, m_grant = NC, csi_d4 = NC, csi_d5 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER42) = MX31_PIN_M_REQUEST((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_M_GRANT((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CSI_D4((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_CSI_D5((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// pc_rst = UH2_D5, isis16 = UH2_D6, pc_rw_b = UH2_D7, pc_poe = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER43) = MX31_PIN_PC_RST((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)) + | MX31_PIN_IOIS16((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)) + | MX31_PIN_PC_RW_B((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)) + | MX31_PIN_PC_POE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// pc_vs1 = NC, pc_vs2 = UH2_D2, pc_bvd1 = UH2_D3, pc_bvd2 = UH2_D4 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER44) = MX31_PIN_PC_VS1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_PC_VS2((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)) + | MX31_PIN_PC_BVD1((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)) + | MX31_PIN_PC_BVD2((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)); + +// pc_cd2_b = CF_CD, pc_wait_b = CF_WAIT, pc_ready = CF_RDY, pc_pwron = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER45) = MX31_PIN_PC_CD2_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_PC_WAIT_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_PC_READY((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_PC_PWRON((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// d2, d1, and d0 are not writable, reset values are correct. +// d2 = LD2, d1 = LD1, d0 = LD0, pc_cd1_b = CF_CD +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER46) = MX31_PIN_D2() +// | MX31_PIN_D1() +// | MX31_PIN_D0() +// | MX31_PIN_PC_CD1_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); + +// d6, d5, d4 and d3 are not writable, reset values are correct. +// d6 = LD6, d5 = LD5, d4 = LD4, d3 = LD3 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER47) = MX31_PIN_D6() +// | MX31_PIN_D5() +// | MX31_PIN_D4() +// | MX31_PIN_D3(); + +// d10, d9, d8 and d7 are not writable, reset values are correct. +// d10 = LD10, d9 = LD9, d8 = LD8, d7 = LD7 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER48) = MX31_PIN_D10() +// | MX31_PIN_D9() +// | MX31_PIN_D8() +// | MX31_PIN_D7(); + +// d14, d13, d12 and d11 are not writable, reset values are correct. +// d14 = LD14, d13 = LD13, d12 = LD12, d11 = L11 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER49) = MX31_PIN_D14() +// | MX31_PIN_D13() +// | MX31_PIN_D12() +// | MX31_PIN_D11(); + +// d15 is not writable, reset value is correct. +// nfwp_b = *N_WP, nfce_b = *N_CE, nfrb = N_RDY, d15 = LD15 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER50) = MX31_PIN_NFWP_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_NFCE_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_NFRB((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); +// | MX31_PIN_D15(); + +// nfwe_b = *N_WE, nfre_b = *N_RE, nfale = N_ALE, nfcle = N_CLE +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER51) = MX31_PIN_NFWE_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_NFRE_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_NFALE((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_NFCLE((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// sdqs0, sdqs1, sdqs2, and sdqs3 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER52) = MX31_PIN_SDQS0() +// | MX31_PIN_SDQS1() +// | MX31_PIN_SDQS2() +// | MX31_PIN_SDQS3(); + +// sdclk_b is not writable, reset value is correct. +// sdcke0 = SDCKE, sdcke1 = NC, sdclk = SDCLK, sdclk_b = *SDCLK +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER53) = MX31_PIN_SDCKE0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SDCKE1((OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC)) + | MX31_PIN_SDCLK((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); +// | MX31_PIN_SDCLK_B(); + +// rw = *WE, ras = *SDRAS, cas = *SDCAS, sdwe = *SDWE +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER54) = MX31_PIN_RW((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_RAS((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CAS((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SDWE((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// ecb is not writable, reset value is correct. +// cs5 = *CS5, ecb = ECB, lba = LBA, bclk = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER55) = MX31_PIN_CS5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) +// | MX31_PIN_ECB() + | MX31_PIN_LBA((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_BCLK((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// cs1 = *CS1, cs2 = *SDCS, cs3 = NC, cs4 = *DTACK +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER56) = MX31_PIN_CS1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CS2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CS3((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_CS4((OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1)); + +// eb0 = *BE0, eb1 = *BE1, oe = *OE, cs0 = *CS0 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER57) = MX31_PIN_EB0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_EB1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_OE((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_CS0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// dqm0 = DQM0, dqm1 = DQM1, dqm2 = DQM2, dqm3 = DQM3 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER58) = MX31_PIN_DQM0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_DQM1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_DQM2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_DQM3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// sd28, sd29, sd30 and sd31 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER59) = MX31_PIN_SD28() +// | MX31_PIN_SD29() +// | MX31_PIN_SD30() +// | MX31_PIN_SD31(); + +// sd24, sd25, sd26 and sd27 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER60) = MX31_PIN_SD24() +// | MX31_PIN_SD25() +// | MX31_PIN_SD26() +// | MX31_PIN_SD27(); + +// sd20, sd21, sd22 and sd23 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER61) = MX31_PIN_SD20() +// | MX31_PIN_SD21() +// | MX31_PIN_SD22() +// | MX31_PIN_SD23(); + +// sd16, sd17, sd18 and sd19 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER62) = MX31_PIN_SD16() +// | MX31_PIN_SD17() +// | MX31_PIN_SD18() +// | MX31_PIN_SD19(); + +// sd12, sd13, sd14 and sd15 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER63) = MX31_PIN_SD12() +// | MX31_PIN_SD13() +// | MX31_PIN_SD14() +// | MX31_PIN_SD15(); + +// sd8, sd9, sd10 and sd11 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER64) = MX31_PIN_SD8() +// | MX31_PIN_SD9() +// | MX31_PIN_SD10() +// | MX31_PIN_SD11(); + +// sd4, sd5, sd6 and sd7 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER65) = MX31_PIN_SD4() +// | MX31_PIN_SD5() +// | MX31_PIN_SD6() +// | MX31_PIN_SD7(); + +// sd0, sd1, sd2 and sd3 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER66) = MX31_PIN_SD0() +// | MX31_PIN_SD1() +// | MX31_PIN_SD2() +// | MX31_PIN_SD3(); + +// a24 = A24, a25 = A25, sdba1 = SDBA1, sdba0 = SDBA0 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER67) = MX31_PIN_A24((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A25((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SDBA1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_SDBA0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// address lines are one to one. +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER68) = MX31_PIN_A20((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A21((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A22((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A23((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// address lines are one to one. +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER69) = MX31_PIN_A16((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A17((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A18((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A19((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// address lines are one to one. +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER70) = MX31_PIN_A12((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A13((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A14((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A15((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// address lines are one to one. +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER71) = MX31_PIN_A9((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A10((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_MA10((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A11((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// address lines are one to one. +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER72) = MX31_PIN_A5((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A6((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A7((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A8((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// address lines are one to one. +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER73) = MX31_PIN_A1((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A2((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A3((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)) + | MX31_PIN_A4((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// dvfs1 = NC, vpg0 = NC, vpg1 = NC, a0 = A0 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER74) = MX31_PIN_DVFS1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_VPG0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_VPG1((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_A0((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); + +// ckil and power_fail are not writable, reset values are correct. +//ckil = 32K, power_fail = PWR_FAIL, vstby = VSTBY, dvfs0 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER75) = MX31_PIN_CKIL() +// | MX31_PIN_POWER_FAIL() +// | MX31_PIN_VSTBY(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_DVFS0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); + +// boot_mode1, boot_mode2, boot_mode3, and boot_mode4 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER76) = MX31_PIN_BOOT_MODE1() +// | MX31_PIN_BOOT_MODE2() +// | MX31_PIN_BOOT_MODE3() +// | MX31_PIN_BOOT_MODE4(); + +// por_b, clko, and boot_mode0 are not writable, reset values are correct. +// reset_in_b = *RST_IN (this is set in the GPR) +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER77) = MX31_PIN_RESET_IN_B((OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC)); +// | MX31_PIN_POR_B() +// | MX31_PIN_CLKO() +// | MX31_PIN_BOOT_MODE0(); + +// ckih is not writable, reset value is correct. +// stx0 = GPIO1, srx0 = GPIO4, simpd0 = GPIO5 +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER78) = MX31_PIN_STX0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_SRX0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_SIMPD0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); +// | MX31_PIN_CKIH(); + +// gpio3_1 = VF_EN, sclk0 = GPIO8, srst0 = GPIO9, sven0 = GPIO0 (USR_LED) +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER79) = MX31_PIN_GPIO3_1((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)) + | MX31_PIN_SCLK0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_SRST0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_SVEN0((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)); + +// gpio1_4 = UH1_SUSP, gpio1_5 = PWR_RDY, gpio1_6 = UH1_MODE, gpio3_0 = NC +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER80) = MX31_PIN_GPIO1_4((OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE)) + | MX31_PIN_GPIO1_5((OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC)) + | MX31_PIN_GPIO1_6((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_GPIO3_0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// gpio1_0 = *PIRQ, gpio1_1 = *E_INT, gpio1_2 = *EXP_INT, gpio1_3 = *I2C_INT +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER81) = MX31_PIN_GPIO1_0((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_GPIO1_1((OUTPUTCONFIG_FUNC | INPUTCONFIG_GPIO)) + | MX31_PIN_GPIO1_2((OUTPUTCONFIG_FUNC | INPUTCONFIG_GPIO)) + | MX31_PIN_GPIO1_3((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)); + +// capture = GPIO2, compare = GPIO3, watchdog_rst = NC, pwm0 = LCD_BKL +IOMUX_CTL_REG(SW_MUX_CTL_REGISTER82) = MX31_PIN_CAPTURE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_COMPARE((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_WATCHDOG_RST((OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO)) + | MX31_PIN_PWMO((OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE)); +} diff --git a/ports/csb740/omap3530_iomux.h b/ports/csb740/omap3530_iomux.h new file mode 100755 index 0000000..f424664 --- /dev/null +++ b/ports/csb740/omap3530_iomux.h @@ -0,0 +1,1077 @@ +//========================================================================== +// +// mx31_gpio.h +// +// Author(s): Luis Torrico, Cogent Computer Systems, Inc. +// Contributors: +// Date: 05/02/2008 +// Description: This file contains offsets and bit defines +// for the MCIMX31 Software Multiplexor Control Register +// + +#include "omap3530.h" +#include "bits.h" + +// Base address for Software Multiplexor Control Register (SW_MUX_CTL). +// The SW_MUX_CTL has 82 seperate registers each of which contains 4 +// seperate Control Signals. So we have to write to a total of 328 +// different signals in order to set-up the MX31 to run on the Cogent platform. +#define IOMUXC_BASE_ADDR 0x43FAC000 +#define IOMUX_CTL_REG(_x_) *(vulong *)(IOMUXC_BASE_ADDR + _x_) + +#define GENERAL_REGISTER 0x008 +#define SW_MUX_CTL_REGISTER1 0x00C // Contains cspi3_miso, cspi3_sclk, sspi3_spi_rdy, and ttm_pad +#define SW_MUX_CTL_REGISTER2 0x010 // Contains ata_reset_b, ce_control, clkss, and cspi3_mosi +#define SW_MUX_CTL_REGISTER3 0x014 // Contains ata_cs1, ata_dior, ata_diow, and ata_dmack +#define SW_MUX_CTL_REGISTER4 0x018 // Contains sd1_data1, sd1_data2, sd1_data3, and ata_cs0 +#define SW_MUX_CTL_REGISTER5 0x01C // Contains d3_spl, sd1_cmd, sd1_clk, and sd1_data0 +#define SW_MUX_CTL_REGISTER6 0x020 // Contains vsync3, contrast, d3_rev, and d3_cls +#define SW_MUX_CTL_REGISTER7 0x024 // Contains ser_rs, par_rs, write, and read +#define SW_MUX_CTL_REGISTER8 0x028 // Contains sd_d_io, sd_d_clk, lcs0, and lcs1 +#define SW_MUX_CTL_REGISTER9 0x02C // Contains hsync, fpshift, drdy0, and sd_d_i +#define SW_MUX_CTL_REGISTER10 0x030 // Contains ld15, ld16, ld17, and vsync0 +#define SW_MUX_CTL_REGISTER11 0x034 +#define SW_MUX_CTL_REGISTER12 0x038 +#define SW_MUX_CTL_REGISTER13 0x03C +#define SW_MUX_CTL_REGISTER14 0x040 +#define SW_MUX_CTL_REGISTER15 0x044 +#define SW_MUX_CTL_REGISTER16 0x048 +#define SW_MUX_CTL_REGISTER17 0x04C +#define SW_MUX_CTL_REGISTER18 0x050 +#define SW_MUX_CTL_REGISTER19 0x054 +#define SW_MUX_CTL_REGISTER20 0x058 +#define SW_MUX_CTL_REGISTER21 0x05C +#define SW_MUX_CTL_REGISTER22 0x060 +#define SW_MUX_CTL_REGISTER23 0x064 +#define SW_MUX_CTL_REGISTER24 0x068 +#define SW_MUX_CTL_REGISTER25 0x06C +#define SW_MUX_CTL_REGISTER26 0x070 +#define SW_MUX_CTL_REGISTER27 0x074 +#define SW_MUX_CTL_REGISTER28 0x078 +#define SW_MUX_CTL_REGISTER29 0x07C +#define SW_MUX_CTL_REGISTER30 0x080 +#define SW_MUX_CTL_REGISTER31 0x084 +#define SW_MUX_CTL_REGISTER32 0x088 +#define SW_MUX_CTL_REGISTER33 0x08C +#define SW_MUX_CTL_REGISTER34 0x090 +#define SW_MUX_CTL_REGISTER35 0x094 +#define SW_MUX_CTL_REGISTER36 0x098 +#define SW_MUX_CTL_REGISTER37 0x09C +#define SW_MUX_CTL_REGISTER38 0x0A0 +#define SW_MUX_CTL_REGISTER39 0x0A4 +#define SW_MUX_CTL_REGISTER40 0x0A8 +#define SW_MUX_CTL_REGISTER41 0x0AC +#define SW_MUX_CTL_REGISTER42 0x0B0 +#define SW_MUX_CTL_REGISTER43 0x0B4 +#define SW_MUX_CTL_REGISTER44 0x0B8 +#define SW_MUX_CTL_REGISTER45 0x0BC +#define SW_MUX_CTL_REGISTER46 0x0C0 +#define SW_MUX_CTL_REGISTER47 0x0C4 +#define SW_MUX_CTL_REGISTER48 0x0C8 +#define SW_MUX_CTL_REGISTER49 0x0CC +#define SW_MUX_CTL_REGISTER50 0x0D0 +#define SW_MUX_CTL_REGISTER51 0x0D4 +#define SW_MUX_CTL_REGISTER52 0x0D8 +#define SW_MUX_CTL_REGISTER53 0x0DC +#define SW_MUX_CTL_REGISTER54 0x0E0 +#define SW_MUX_CTL_REGISTER55 0x0E4 +#define SW_MUX_CTL_REGISTER56 0x0E8 +#define SW_MUX_CTL_REGISTER57 0x0EC +#define SW_MUX_CTL_REGISTER58 0x0F0 +#define SW_MUX_CTL_REGISTER59 0x0F4 +#define SW_MUX_CTL_REGISTER60 0x0F8 +#define SW_MUX_CTL_REGISTER61 0x0FC +#define SW_MUX_CTL_REGISTER62 0x100 +#define SW_MUX_CTL_REGISTER63 0x104 +#define SW_MUX_CTL_REGISTER64 0x108 +#define SW_MUX_CTL_REGISTER65 0x10C +#define SW_MUX_CTL_REGISTER66 0x110 +#define SW_MUX_CTL_REGISTER67 0x114 +#define SW_MUX_CTL_REGISTER68 0x118 +#define SW_MUX_CTL_REGISTER69 0x11C +#define SW_MUX_CTL_REGISTER70 0x120 +#define SW_MUX_CTL_REGISTER71 0x124 +#define SW_MUX_CTL_REGISTER72 0x128 +#define SW_MUX_CTL_REGISTER73 0x12C +#define SW_MUX_CTL_REGISTER74 0x130 +#define SW_MUX_CTL_REGISTER75 0x134 +#define SW_MUX_CTL_REGISTER76 0x138 +#define SW_MUX_CTL_REGISTER77 0x13C +#define SW_MUX_CTL_REGISTER78 0x140 +#define SW_MUX_CTL_REGISTER79 0x144 +#define SW_MUX_CTL_REGISTER80 0x148 +#define SW_MUX_CTL_REGISTER81 0x14C +#define SW_MUX_CTL_REGISTER82 0x150 + +// General Purpose Register Bit Defines +#define DDR_MODE_ON_CLK0_EN BIT31 // 1 = Enable DDR mode on CLK0 contact +#define USBH2_LOOPBACK_EN BIT30 // 1 = Turn on sw_input_on (loopback) on some USBH2 contacts +#define USBH1_LOOPBACK_EN BIT29 // 1 = Turn on sw_input_on (loopback) on some USBH1 contacts +#define USBOTG_LOOPBACK_EN BIT28 // 1 = Turn on sw_input_on (loopback) on some USBOTG contacts +#define USBH1_SUS_ON_SFS6_EN BIT27 // 1 = Enable USBH1_SUSPEND signal on SFS6 contact +#define ATA_ON_KEYPAD_EN BIT26 // 1 = Enable ATA signals on Keypad Group contacts +#define UART5_DMA_REQ_EN BIT25 // Selects either CSPI3 or UART5 DMA requests for events 10 and 11, 1 = UART5, 0 = CSPI1 +#define SLEW_RATE_SEL BIT24 // 1 = Fast Slew Rate, 0 = Slow Slew Rate +#define DRIVE_STRENGTH_SEL BIT23 // 1 = Maximum drive strength, 0 = standard or high drive strength +#define UPLL_ON_GPIO3_1_EN BIT22 // 1 = Enable UPLL clock bypass through GPIO3_1 contact +#define SPLL_ON_GPIO3_0_EN BIT21 // 1 = Enable SPLL clock bypass through GPIO3_0 contact +#define MSHC2_DMA_REQ_EN BIT20 // Selects either SDHC2 or MSHC2 DMA requests, 1 = MSCHC2, 0 = SDHC2 +#define MSHC1_DMA_REQ_EN BIT19 // Selects either SDHC1 or MSHC1 DMA requests, 1 = MSCHC1, 0 = SDHC1 +#define OTG_DATA_ON_UART_EN BIT18 // 1 = Enable USBOTG_DATA[5:3] on Full UART Group contacts +#define OTG_D4_ON_DSR_DCE1_EN BIT17 // 1 = Enable USBOTG_DATA4 on DSR_DCE1 contact +#define TAMPER_DETECT_EN BIT16 // 1 = Enable Tamper detect logic +#define MBX_DMA_REQ_EN BIT15 // Selects either External or MBX DMA requests, 1 = MDX, 0 = External +#define UART_DMA_REQ_EN BIT14 // Selects either CSPI1 or UART3 DMA requests, 1 = UART3, 0 = CSPI1 +#define WEIM_ON_CS3_EN BIT13 // Selects either CSD1 or WEIM on EMI CS3 contact, 1 = CSD1, 0 = WEIM +#define WEIM_ON_CS2_EN BIT12 // Selects either CSD0 or WEIM on EMI CS2 contact, 1 = CSD0, 0 = WEIM +#define USBH2_ON_AUDIO_EN BIT11 // 1 = Enable USBH2 signals on AudioPort 3 and AudioPort6 +#define ATA_SIG_ON_CSPI1_EN BIT10 // 1 = Enable ATA signals on CSPI1 Group contacts +#define ATA_DATA_ON_CSPI1_EN BIT9 // 1 = Enable ATA DATA14-15 on Timer Group contacts and DATA0-6 on CSPI1 Group contacts +#define ATA_DATA_ON_AUDIO_EN BIT8 // 1 = Enable DATA7-10 signals of ATA on AudioPort3 and DATA11-13 on AudioPort6 +#define ATA_DATA_ON_IPU_EN BIT7 // 1 = Enable DATA0-13 signals of ATA on IPU (CSI) and DATA14-15 on I2C +#define ATA_SIG_ON_NANDF_EN BIT6 // 1 = Enable ATA signals on NANF contacts +#define ATA_DATA_ON_NANDF_EN BIT5 // 1 = Enable ATA DATA7-13 on NANDF contacts +#define ATA_ON_USBH2_EN BIT4 // 1 = Enable ATA signals on USBH2 contacts +#define PWMO_ON_ATA_IORDY_EN BIT3 // 1 = Enable ATA IORDY signal on PWMO contact +#define CSPI1_ON_UART_EN BIT2 // 1 = Replaces Full UART Group with CSPI1 signals +#define DDR_MODE_EN BIT1 // 1 = Forces DDR type I/O contacts to DDR mode +#define FIR_DMA_REQ_EN BIT0 // Selects FIR or UART2 SDMA events, 1 = FIR, 0 = UART2 + +// Initialization of GPR for CSB733 +//IOMUX_CTL_REG(GENERAL_REGISTER) = WEIM_ON_CS3_EN | CSPI1_ON_UART_EN; + +// various IOMUX output functions +#define OUTPUTCONFIG_GPIO 0x00 // used as GPIO +#define OUTPUTCONFIG_FUNC 0x10 // output used as function +#define OUTPUTCONFIG_ALT1 0x20 // output used as alternate function 1 +#define OUTPUTCONFIG_ALT2 0x30 // output used as alternate function 2 +#define OUTPUTCONFIG_ALT3 0x40 // output used as alternate function 3 +#define OUTPUTCONFIG_ALT4 0x50 // output used as alternate function 4 +#define OUTPUTCONFIG_ALT5 0x60 // output used as alternate function 5 +#define OUTPUTCONFIG_ALT6 0x70 // output used as alternate function 6 + +// various IOMUX input functions +#define INPUTCONFIG_NONE 0x00 // not configured for input +#define INPUTCONFIG_GPIO 0x01 // input used as GPIO +#define INPUTCONFIG_FUNC 0x02 // input used as function +#define INPUTCONFIG_ALT1 0x04 // input used as alternate function 1 +#define INPUTCONFIG_ALT2 0x08 // input used as alternate function 2 + +// Software Mux Control Signal Defines (SW_MUX_CTL_SIGNAL 1-4) +#define MX31_PIN_CSPI3_MISO(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CSPI3_SCLK(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CSPI3_SPI_RDY(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_TTM_PAD(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_ATA_RESET_B(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CE_CONTROL(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CLKSS(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CSPI3_MOSI(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_ATA_CS1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_ATA_DIOR(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_ATA_DIOW(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_ATA_DMACK(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD1_DATA1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD1_DATA2(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD1_DATA3(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_ATA_CS0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_D3_SPL(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD1_CMD(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD1_CLK(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD1_DATA0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_VSYNC3(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CONTRAST(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_D3_REV(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_D3_CLS(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SER_RS(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_PAR_RS(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_WRITE(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_READ(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD_D_IO(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD_D_CLK(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_LCS0(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_LCS1(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_HSYNC(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_FPSHIFT(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_DRDY0(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD_D_I(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_LD15(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_LD16(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_LD17(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_VSYNC0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_LD11(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_LD12(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_LD13(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_LD14(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_LD7(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_LD8(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_LD9(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_LD10(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_LD3(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_LD4(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_LD5(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_LD6(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_USBH2_DATA1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_LD0(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_LD1(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_LD2(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_USBH2_DIR(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_USBH2_STP(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_USBH2_NXT(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_USBH2_DATA0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_USBOTG_DATA5(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_USBOTG_DATA6(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_USBOTG_DATA7(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_USBH2_CLK(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_USBOTG_DATA1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_USBOTG_DATA2(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_USBOTG_DATA3(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_USBOTG_DATA4(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_USBOTG_DIR(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_USBOTG_STP(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_USBOTG_NXT(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_USBOTG_DATA0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_USB_PWR(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_USB_OC(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_USB_BYP(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_USBOTG_CLK(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_TDO(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_TRSTB(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_DE_B(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SJC_MOD(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_RTCK(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_TCK(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_TMS(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_TDI(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_KEY_COL4(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_KEY_COL5(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_KEY_COL6(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_KEY_COL7(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_KEY_COL0(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_KEY_COL1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_KEY_COL2(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_KEY_COL3(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_KEY_ROW4(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_KEY_ROW5(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_KEY_ROW6(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_KEY_ROW7(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_KEY_ROW0(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_KEY_ROW1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_KEY_ROW2(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_KEY_ROW3(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_TXD2(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_RTS2(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CTS2(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_BATT_LINE(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_RI_DTE1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_DCD_DTE1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_DTR_DCE2(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_RXD2(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_RI_DCE1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_DCD_DCE1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_DTR_DTE1(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_DSR_DTE1(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_RTS1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CTS1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_DTR_DCE1(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_DSR_DCE1(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CSPI2_SCLK(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CSPI2_SPI_RDY(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_RXD1(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_TXD1(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CSPI2_MISO(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CSPI2_SS0(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CSPI2_SS1(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CSPI2_SS2(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CSPI1_SS2(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CSPI1_SCLK(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CSPI1_SPI_RDY(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CSPI2_MOSI(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CSPI1_MOSI(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CSPI1_MISO(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CSPI1_SS0(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CSPI1_SS1(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_STXD6(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SRXD6(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SCK6(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SFS6(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_STXD5(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SRXD5(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SCK5(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SFS5(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_STXD4(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SRXD4(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SCK4(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SFS4(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_STXD3(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SRXD3(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SCK3(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SFS3(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CSI_HSYNC(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CSI_PIXCLK(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_I2C_CLK(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_I2C_DAT(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CSI_D14(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CSI_D15(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CSI_MCLK(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CSI_VSYNC(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CSI_D10(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CSI_D11(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CSI_D12(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CSI_D13(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CSI_D6(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CSI_D7(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CSI_D8(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CSI_D9(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_M_REQUEST(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_M_GRANT(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CSI_D4(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CSI_D5(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_PC_RST(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_IOIS16(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_PC_RW_B(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_PC_POE(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_PC_VS1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_PC_VS2(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_PC_BVD1(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_PC_BVD2(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_PC_CD2_B(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_PC_WAIT_B(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_PC_READY(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_PC_PWRON(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_D2(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_D1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_D0(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_PC_CD1_B(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_D6(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_D5(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_D4(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_D3(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_D10(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_D9(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_D8(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_D7(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_D14(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_D13(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_D12(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_D11(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_NFWP_B(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_NFCE_B(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_NFRB(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_D15(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_NFWE_B(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_NFRE_B(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_NFALE(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_NFCLE(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SDQS0(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SDQS1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SDQS2(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SDQS3(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SDCKE0(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SDCKE1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SDCLK(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SDCLK_B(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_RW(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_RAS(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CAS(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SDWE(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CS5(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_ECB(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_LBA(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_BCLK(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CS1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_CS2(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CS3(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CS4(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_EB0(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_EB1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_OE(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CS0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_DQM0(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_DQM1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_DQM2(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_DQM3(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD28(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD29(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD30(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD31(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD24(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD25(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD26(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD27(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD20(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD21(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD22(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD23(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD16(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD17(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD18(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD19(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD12(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD13(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD14(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD15(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD8(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD9(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD10(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD11(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD4(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD5(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD6(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD7(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_SD0(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SD1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SD2(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SD3(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_A24(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_A25(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SDBA1(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SDBA0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_A20(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_A21(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_A22(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_A23(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_A16(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_A17(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_A18(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_A19(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_A12(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_A13(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_A14(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_A15(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_A9(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_A10(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_MA10(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_A11(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_A5(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_A6(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_A7(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_A8(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_A1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_A2(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_A3(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_A4(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_DVFS1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_VPG0(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_VPG1(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_A0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CKIL(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_POWER_FAIL(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_VSTBY(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_DVFS0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_BOOT_MODE1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_BOOT_MODE2(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_BOOT_MODE3(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_BOOT_MODE4(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_RESET_IN_B(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_POR_B(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_CLKO(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_BOOT_MODE0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_STX0(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SRX0(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SIMPD0(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_CKIH(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_GPIO3_1(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_SCLK0(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_SRST0(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_SVEN0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_GPIO1_4(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_GPIO1_5(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_GPIO1_6(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_GPIO3_0(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_GPIO1_0(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_GPIO1_1(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_GPIO1_2(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_GPIO1_3(_x_) ((_x_ & 0xff) << 0) + +#define MX31_PIN_CAPTURE(_x_) ((_x_ & 0xff) << 24) +#define MX31_PIN_COMPARE(_x_) ((_x_ & 0xff) << 16) +#define MX31_PIN_WATCHDOG_RST(_x_) ((_x_ & 0xff) << 8) +#define MX31_PIN_PWMO(_x_) ((_x_ & 0xff) << 0) + +//// MX31_PIN_TTM_PAD = can not be written to. +//// cspi_miso = U2_RXD, cspi3_sclk = U2_RTS, cspi3_spi_rdy = U2_CTS, ttm_pad = default +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER1) = MX31_PIN_CSPI3_MISO(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE) +// | MX31_PIN_CSPI3_SCLK(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE) +// | MX31_PIN_CSPI3_SPI_RDY(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE) +// | MX31_PIN_TTM_PAD(); +// +//// MX31_PIN_CLKSS and MX31_PIN_CE_CONTROL = can not be written to. +//// reset_b = NC, ce_control = default, ctl_clkss = default, cspi3_mosi = U2_RXD +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER2) = MX31_PIN_ATA_RESET_B(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_CE_CONTROL(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CLKSS() +// | MX31_PIN_CSPI3_MOSI(OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT2); +// +//// ata_cs1 = NC, ata_dior = D_TXD, ata_diow = NC, ata, dmack = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER3) = MX31_PIN_ATA_CS1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_ATA_DIOR(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE) +// | MX31_PIN_ATA_DIOW(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_ATA_DMACK(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// sd1_data1 = SD_D1, sd1_data2 = SD_D2, sd1_data3 = SD_D3, ata_cs0 = D_RXD +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER4) = MX31_PIN_SD1_DATA1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SD1_DATA2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SD1_DATA3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_ATA_CS0(OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1); +// +//// d3_spl = NC, sd1_cmd = SD_CMD, sd1_clk - SD_CLK, sd1_data0 = SD_D0 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER5) = MX31_PIN_D3_SPL(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_SD1_CMD(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SD1_CLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_SD1_DATA0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// vsync3 = LCD_VSYNC, contrast = NC, d3_rev = NC, d3_cls = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER6) = MX31_PIN_VSYNC3(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_CONTRAST(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_D3_REV(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_D3_CLS(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE); +// +//// ser_rs = NC, par_rs = NC, write = NC, read = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER7) = MX31_PIN_SER_RS(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_PAR_RS(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_WRITE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_READ(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// sd_d_io = NC, sd_d_clk = NC, lcs0 = NC, lcs1 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER8) = MX31_PIN_SD_D_IO(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_SD_D_CLK(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_LCS0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_LCS1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// hsync = LCD_HSYNC, fpshift = LCD_PCLK, drdy0 = LCD_OE, sd_d_i = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER9) = MX31_PIN_HSYNC(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_FPSHIFT(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_DRDY0(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_SD_D_I(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// ld15 = LCD_R3, ld16 = LCD_R4, ld17 = LCD_R5, sd_d_i = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER10) = MX31_PIN_LD15(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD16(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD17(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_VSYNC0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// ld11 = LCD_G5, ld12 = LCD_R0, ld13 = LCD_R1, ld14 = LCD_R2 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER11) = MX31_PIN_LD11(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD12(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD13(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD14(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// ld7 = LCD_G1, ld8 = LCD_G2, ld9 = LCD_G3, ld10 = LCD_G4 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER12) = MX31_PIN_LD7(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD8(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD9(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD10(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// ld3 = LCD_B3, ld4 = LCD_B4, ld5 = LCD_B5, ld6 = LCD_G0 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER13) = MX31_PIN_LD3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD4(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// usbh2_data1 = UH2_D1, ld0 = LCD_B0, ld1 = LCD_B1, ld2 = LCD_B0 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER14) = MX31_PIN_USBH2_DATA1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_LD2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// usbh2_dir = UH2_DIR, usbh2_stp = UH2_STP, usbh2_nxt = UH2_NXT, usbh2_data0 = UH2_D0 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER15) = MX31_PIN_USBH2_DIR(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_USBH2_STP(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBH2_NXT(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBH2_DATA0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// usbotg_data5 = UD_D5, usbotg_data6 = UD_D6, usbotg_data7 = UD_D7, usbh2_clk = UH2_CLK +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER16) = MX31_PIN_USBOTG_DATA5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBOTG_DATA6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBOTG_DATA7(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBH2_CLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// usbotg_data1 = UD_D1, usbotg_data2 = UD_D2, usbotg_data3 = UD_D3, usbotg_data4 = UD_D4 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER17) = MX31_PIN_USBOTG_DATA1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBOTG_DATA2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBOTG_DATA3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBOTG_DATA4(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// usbotg_dir = UD_DIR, usbotg_stp = UD_STP, usbotg_nxt = UD_NXT, usbotg_data0 = UD_D0 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER18) = MX31_PIN_USBOTG_DIR(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBOTG_STP(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_USBOTG_NXT(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_USBOTG_DATA0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// usb_pwr = NC, usb_oc = CF_RST, usb_byp = NC, usbotg_clk = UD_CLK +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER19) = MX31_PIN_USB_PWR(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_USB_OC(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_USB_BYP(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_USBOTG_CLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// MX31_PIN_TDO and MX31_PIN_SJC_MOD = can not be written to +//// tdo = TDO_C, trstb = TRST_C, de_b = TP1, sjc_mod = GND +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER20) = MX31_PIN_TDO() +// | MX31_PIN_TRSTB(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_DE_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SJC_MOD(); +// +//// MX31_PIN_RTCK = can not be written to. +//// rtck = NC, tck = TCK_C, tms = TMS_C, tdi = TDI_C +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER21) = MX31_PIN_RTCK() +// | MX31_PIN_TCK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_TMS(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_TDI(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// key_col4 = NC, key_col5 = NC, key_col6 = NC, key_col7 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER22) = MX31_PIN_KEY_COL4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_KEY_COL5(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_KEY_COL6(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_KEY_COL7(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// key_col0 = NC, key_col1 = NC, key_col2 = NC, key_col3 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER23) = MX31_PIN_KEY_COL0(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_KEY_COL1(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_KEY_COL2(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_KEY_COL3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE); +// +//// key_row4 = NC, key_row5 = NC, key_row6 = NC, key_row7 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER24) = MX31_PIN_KEY_ROW4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_KEY_ROW5(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_KEY_ROW6(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_KEY_ROW7(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// key_row0 = NC, key_row1 = NC, key_row2 = NC, key_row3 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER25) = MX31_PIN_KEY_ROW0(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_KEY_ROW1(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_KEY_ROW2(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_KEY_ROW3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE); +// +//// txd2 = U1_TXD, rts2 = U1_RTS, cts2 = U1_CTS, batt_line = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER26) = MX31_PIN_TXD2(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_RTS2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CTS2(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_BATT_LINE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// ri_dte1, dcd_dte1, and dtr_dce2 are set to CSPI1 signals by GPR(2) +//// rxd2 = U1_RXD +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER27) = MX31_PIN_RI_DTE1() +// | MX31_PIN_DCD_DTE1() +// | MX31_PIN_DTR_DCE2() +// | MX31_PIN_RXD2(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC); +// +//// dtr_dte1 and dsr_dte1 are set to CSPI1 signals by GPR(2) +//// ri_dce1 = SPI0_RDY, dcd_dce1 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER28) = MX31_PIN_RI_DCE1(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1) +// | MX31_PIN_DCD_DCE1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_DTR_DTE1() +// | MX31_PIN_DSR_DTE1(); +// +//// rts1 = U0_RTS, cts1 = U0_CTS, dtr_dce1 = NC, dsr_dce1 = SPI0_CLK +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER29) = MX31_PIN_RTS1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CTS1(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_DTR_DCE1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_DSR_DCE1(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1); +// +//// cspi2_sclk = SPI1_CLK, cspi2_spi_rdy = SPI1_RDY, rxd1 = U0_RXD, txd1 = U0_TXD +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER30) = MX31_PIN_CSPI2_SCLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSPI2_SPI_RDY(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_RXD1(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC) +// | MX31_PIN_TXD1(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE); +// +//// cspi2_miso = SPI1_MISO, cspi2_ss0 = SPI1_CS0, cspi2_ss1 = SPI1_CS1, cspi2_ss2 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER31) = MX31_PIN_CSPI2_MISO(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSPI2_SS0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSPI2_SS1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSPI2_SS2(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE); +// +//// cspi1_ss2 = UH1_RCV, cspi1_sclk = UH1_OE, cspi1_spi_rdy = UH1_FS, cspi2_mosi = SPI1_MOSI +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER32) = MX31_PIN_CSPI1_SS2(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1) +// | MX31_PIN_CSPI1_SCLK(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1) +// | MX31_PIN_CSPI1_SPI_RDY(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1) +// | MX31_PIN_CSPI2_MOSI(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// cspi1_mosi = UH1_RXDM, cspi1_miso = UH1_RXDP, cspi1_ss0 = UH1_TXDM, cspi1_ss1 = UH1_TXDP +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER33) = MX31_PIN_CSPI1_MOSI(OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1) +// | MX31_PIN_CSPI1_MISO(OUTPUTCONFIG_GPIO | INPUTCONFIG_ALT1) +// | MX31_PIN_CSPI1_SS0(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE) +// | MX31_PIN_CSPI1_SS1(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE); +// +//// stxd6 = AC_SDOUT, srxd6 = AC_SDIN, sck6 = AC_BCLK, sfs6 = AC_SYNC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER34) = MX31_PIN_STXD6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SRXD6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SCK6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SFS6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// stxd5 = SSI_TXD, srxd5 = SSI_RXD, sck5 = SSI_CLK, sfs5 = SSI_FRM +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER35) = MX31_PIN_STXD5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SRXD5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SCK5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SFS5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// stxd4 = NC, srxd4 = NC, sck4 = SSI_MCLK, sfs4 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER36) = MX31_PIN_STXD4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_SRXD4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_SCK4(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SFS4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// stxd3 = AC_RST, srxd3 = NC, sck3 = NC, sfs3 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER37) = MX31_PIN_STXD3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_SRXD3(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_SCK3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_SFS3(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE); +// +//// csi_hsync = VIP_HSYNC, csi_pixclk = VIP_PCLK, i2c_clk = I2C_SCL, i2c_dat = I2C_SDA +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER38) = MX31_PIN_CSI_HSYNC(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_PIXCLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_I2C_CLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_I2C_DAT(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// csi_d14 = VIP_D8, csi_d15 = VIP_D9, csi_mclk = VIP_MCLK, csi_vsync = VIP_VSYNC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER39) = MX31_PIN_CSI_D14(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_D15(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_MCLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_NONE) +// | MX31_PIN_CSI_VSYNC(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// csi_d10 = VIP_D4, csi_d11 = VIP_D5, csi_D12 = VIP_D6, csi_D13 = VIP_D7 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER40) = MX31_PIN_CSI_D10(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_D11(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_D12(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_D13(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// csi_d6 = VIP_D0, csi_d7 = VIP_D1, csi_D8 = VIP_D2, csi_D9 = VIP_D3 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER41) = MX31_PIN_CSI_D6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_D7(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_D8(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_D9(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// m_request = NC, m_grant = NC, csi_d4 = NC, csi_d5 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER42) = MX31_PIN_M_REQUEST(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_M_GRANT(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CSI_D4(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_CSI_D5(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// pc_rst = UH2_D5, isis16 = UH2_D6, pc_rw_b = UH2_D7, pc_poe = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER43) = MX31_PIN_PC_RST(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1) +// | MX31_PIN_IOIS16(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1) +// | MX31_PIN_PC_RW_B(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1) +// | MX31_PIN_PC_POE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// pc_vs1 = NC, pc_vs2 = UH2_D2, pc_bvd1 = UH2_D3, pc_bvd2 = UH2_D4 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER44) = MX31_PIN_PC_VS1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_PC_VS2(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1) +// | MX31_PIN_PC_BVD1(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1) +// | MX31_PIN_PC_BVD2(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1); +// +//// pc_cd2_b = CF_CD, pc_wait_b = CF_WAIT, pc_ready = CF_RDY, pc_pwron = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER45) = MX31_PIN_PC_CD2_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_PC_WAIT_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_PC_READY(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_PC_PWRON(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// d2, d1, and d0 are not writable, reset values are correct. +//// d2 = LD2, d1 = LD1, d0 = LD0, pc_cd1_b = CF_CD +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER46) = MX31_PIN_D2() +// | MX31_PIN_D1() +// | MX31_PIN_D0() +// | MX31_PIN_PC_CD1_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// d6, d5, d4 and d3 are not writable, reset values are correct. +//// d6 = LD6, d5 = LD5, d4 = LD4, d3 = LD3 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER47) = MX31_PIN_D6() +// | MX31_PIN_D5() +// | MX31_PIN_D4() +// | MX31_PIN_D3(); +// +//// d10, d9, d8 and d7 are not writable, reset values are correct. +//// d10 = LD10, d9 = LD9, d8 = LD8, d7 = LD7 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER48) = MX31_PIN_D10() +// | MX31_PIN_D9() +// | MX31_PIN_D8() +// | MX31_PIN_D7(); +// +//// d14, d13, d12 and d11 are not writable, reset values are correct. +//// d14 = LD14, d13 = LD13, d12 = LD12, d11 = L11 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER49) = MX31_PIN_D14() +// | MX31_PIN_D13() +// | MX31_PIN_D12() +// | MX31_PIN_D11(); +// +//// d15 is not writable, reset value is correct. +//// nfwp_b = *N_WP, nfce_b = *N_CE, nfrb = N_RDY, d15 = LD15 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER50) = MX31_PIN_NFWP_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_NFCE_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_NFRB(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_D15(); +// +//// nfwe_b = *N_WE, nfre_b = *N_RE, nfale = N_ALE, nfcle = N_CLE +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER51) = MX31_PIN_NFWE_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_NFRE_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_NFALE(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_NFCLE(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// sdqs0, sdqs1, sdqs2, and sdqs3 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER52) = MX31_PIN_SDQS0() +// | MX31_PIN_SDQS1() +// | MX31_PIN_SDQS2() +// | MX31_PIN_SDQS3(); +// +//// sdclk_b is not writable, reset value is correct. +//// sdcke0 = SDCKE, sdcke1 = NC, sdclk = SDCLK, sdclk_b = *SDCLK +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER53) = MX31_PIN_SDCKE0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SDCKE1(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC) +// | MX31_PIN_SDCLK(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SDCLK_B(); +// +//// rw = *WE, ras = *SDRAS, cas = *SDCAS, sdwe = *SDWE +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER54) = MX31_PIN_RW(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_RAS(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CAS(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SDWE(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// ecb is not writable, reset value is correct. +//// cs5 = *CS5, ecb = ECB, lba = LBA, bclk = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER55) = MX31_PIN_CS5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_ECB() +// | MX31_PIN_LBA(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_BCLK(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// cs1 = *CS1, cs2 = *SDCS, cs3 = NC, cs4 = *DTACK +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER56) = MX31_PIN_CS1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CS2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CS3(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_CS4(OUTPUTCONFIG_ALT1 | INPUTCONFIG_ALT1); +// +//// eb0 = *BE0, eb1 = *BE1, oe = *OE, cs0 = *CS0 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER57) = MX31_PIN_EB0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_EB1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_OE(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_CS0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// dqm0 = DQM0, dqm1 = DQM1, dqm2 = DQM2, dqm3 = DQM3 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER58) = MX31_PIN_DQM0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_DQM1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_DQM2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_DQM3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// sd28, sd29, sd30 and sd31 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER59) = MX31_PIN_SD28() +// | MX31_PIN_SD29() +// | MX31_PIN_SD30() +// | MX31_PIN_SD31(); +// +//// sd24, sd25, sd26 and sd27 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER60) = MX31_PIN_SD24() +// | MX31_PIN_SD25() +// | MX31_PIN_SD26() +// | MX31_PIN_SD27(); +// +//// sd20, sd21, sd22 and sd23 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER61) = MX31_PIN_SD20() +// | MX31_PIN_SD21() +// | MX31_PIN_SD22() +// | MX31_PIN_SD23(); +// +//// sd16, sd17, sd18 and sd19 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER62) = MX31_PIN_SD16() +// | MX31_PIN_SD17() +// | MX31_PIN_SD18() +// | MX31_PIN_SD19(); +// +//// sd12, sd13, sd14 and sd15 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER63) = MX31_PIN_SD12() +// | MX31_PIN_SD13() +// | MX31_PIN_SD14() +// | MX31_PIN_SD15(); +// +//// sd8, sd9, sd10 and sd11 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER64) = MX31_PIN_SD8() +// | MX31_PIN_SD9() +// | MX31_PIN_SD10() +// | MX31_PIN_SD11(); +// +//// sd4, sd5, sd6 and sd7 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER65) = MX31_PIN_SD4() +// | MX31_PIN_SD5() +// | MX31_PIN_SD6() +// | MX31_PIN_SD7(); +// +//// sd0, sd1, sd2 and sd3 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER66) = MX31_PIN_SD0() +// | MX31_PIN_SD1() +// | MX31_PIN_SD2() +// | MX31_PIN_SD3(); +// +//// a24 = A24, a25 = A25, sdba1 = SDBA1, sdba0 = SDBA0 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER67) = MX31_PIN_A24(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A25(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SDBA1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_SDBA0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// address lines are one to one. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER68) = MX31_PIN_A20(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A21(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A22(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A23(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// address lines are one to one. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER69) = MX31_PIN_A16(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A17(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A18(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A19(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// address lines are one to one. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER70) = MX31_PIN_A12(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A13(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A14(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A15(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// address lines are one to one. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER71) = MX31_PIN_A9(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A10(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_MA10(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A11(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// address lines are one to one. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER72) = MX31_PIN_A5(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A6(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A7(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A8(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// address lines are one to one. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER73) = MX31_PIN_A1(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A2(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A3(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_A4(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// dvfs1 = NC, vpg0 = NC, vpg1 = NC, a0 = A0 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER74) = MX31_PIN_DVFS1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_VPG0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_VPG1(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_A0(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC); +// +//// ckil and power_fail are not writable, reset values are correct. +////ckil = 32K, power_fail = PWR_FAIL, vstby = VSTBY, dvfs0 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER75) = MX31_PIN_CKIL() +// | MX31_PIN_POWER_FAIL() +// | MX31_PIN_VSTBY(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_DVFS0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// boot_mode1, boot_mode2, boot_mode3, and boot_mode4 are not writable, reset values are correct. +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER76) = MX31_PIN_BOOT_MODE1() +// | MX31_PIN_BOOT_MODE2() +// | MX31_PIN_BOOT_MODE3() +// | MX31_PIN_BOOT_MODE4(); +// +//// por_b, clko, and boot_mode0 are not writable, reset values are correct. +//// reset_in_b = *RST_IN (this is set in the GPR) +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER77) = MX31_PIN_RESET_IN_B(OUTPUTCONFIG_FUNC | INPUTCONFIG_FUNC) +// | MX31_PIN_POR_B() +// | MX31_PIN_CLKO() +// | MX31_PIN_BOOT_MODE0(); +// +//// ckih is not writable, reset value is correct. +//// stx0 = GPIO1, srx0 = GPIO4, simpd0 = GPIO5 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER78) = MX31_PIN_STX0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_SRX0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_SIMPD0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_CKIH(); +// +//// gpio3_1 = VF_EN, sclk0 = GPIO8, srst0 = GPIO9, sven0 = GPIO0 +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER79) = MX31_PIN_GPIO3_1(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE) +// | MX31_PIN_SCLK0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_SRST0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_SVEN0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// gpio1_4 = UH1_SUSP, gpio1_5 = PWR_RDY, gpio1_6 = UH1_MODE, gpio3_0 = NC +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER80) = MX31_PIN_GPIO1_4(OUTPUTCONFIG_ALT1 | INPUTCONFIG_NONE) +// | MX31_PIN_GPIO1_5(OUTPUTCONFIG_GPIO | INPUTCONFIG_FUNC) +// | MX31_PIN_GPIO1_6(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_GPIO3_0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// gpio1_0 = *PIRQ, gpio1_1 = *E_INT, gpio1_2 = *EXP_INT, gpio1_3 = *I2C_INT +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER81) = MX31_PIN_GPIO1_0(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_GPIO1_1(OUTPUTCONFIG_FUNC | INPUTCONFIG_GPIO) +// | MX31_PIN_GPIO1_2(OUTPUTCONFIG_FUNC | INPUTCONFIG_GPIO) +// | MX31_PIN_GPIO1_3(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO); +// +//// capture = GPIO2, compare = GPIO3, watchdog_rst = NC, pwm0 = LCD_BKL +//IOMUX_CTL_REG(SW_MUX_CTL_REGISTER82) = MX31_PIN_CAPTURE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_COMPARE(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_WATCHDOG_RST(OUTPUTCONFIG_GPIO | INPUTCONFIG_GPIO) +// | MX31_PIN_PWMO(OUTPUTCONFIG_GPIO | INPUTCONFIG_NONE); diff --git a/ports/csb740/omap3530_lcd.c b/ports/csb740/omap3530_lcd.c new file mode 100755 index 0000000..13a2c37 --- /dev/null +++ b/ports/csb740/omap3530_lcd.c @@ -0,0 +1,342 @@ +//========================================================================== +// +// omap3530_lcd.c +// +// Author(s): Luis Torrico - Cogent Computer Systems, Inc. +// Date: 12-10-2008 +// Description: Init Code for TI OMAP3530 LCD Controller +// NOTE Only 16-bit mode has been tested! +// +//========================================================================== + +#include "config.h" +#include "cpuio.h" +#include "stddefs.h" +#include "genlib.h" +#include "omap3530.h" +#include "omap3530_lcd.h" +#include "cpu_gpio.h" +#include "vga_lookup.h" +#include "font8x16.h" +#include "fb_draw.h" +#include "warmstart.h" + +#if INCLUDE_LCD + +//-------------------------------------------------------------------------- +// function prototypes and externs +// +void fbdev_init(void); + +extern void udelay(int); +extern int GPIO_clr(int); +extern int GPIO_set(int); +extern int GPIO_tst(int); +extern int GPIO_out(int); +extern int GPIO_in(int); + +// ADDED FOR WRITING CHARACTERS TO THE DISPLAY +void lcd_putchar(char c); +void lcd_writechar(uchar c); +void lcd_clr_row(int char_row); +void lcd_clr_scr(void); +void lcd_switch_buffer(void); + +// globals to keep track of foreground, background colors and x,y position +int lcd_color_depth; // 4, 8 or 16 +int lcd_fg_color; // 0 to 15, used as lookup into VGA color table +int lcd_bg_color; // 0 to 15, used as lookup into VGA color table +int lcd_col; // current column, 0 to COLS_PER_SCREEN - 1 +int lcd_row; // current row, 0 to (ROWS_PER_SCREEN * 2) - 1 +int lcd_tst_mode = 0; +ulong lcd_fb_offset; // current offset into frame buffer for lcd_putchar + +//#define LCD_DBG +//-------------------------------------------------------------------------- +// fbdev_init +// +// This function sets up the OMAP3530 LCD Controller, to be used +// as uMon's frame buffer device. +// +void +fbdev_init(void) +{ + //ushort temp16; + + if (StateOfMonitor != INITIALIZE) + return; + + lcd_color_depth = 16; + lcd_fg_color = vga_lookup[LCD_FG_DEF]; + lcd_bg_color = vga_lookup[LCD_BG_DEF]; + + // Select DSS1_ALWON_FCLK (96MHz) as source for DSI and DISPC + DSS_REG(DSS_CONTROL) = 0x30; + + // apply a soft reset to the display subsystem + DISPC_REG(DISPC_SYSCONFIG) = 0x02; + + udelay(1000); + + // Set interface and functional clock to on during wakeup + // and no standby or idle + DISPC_REG(DISPC_SYSCONFIG) |= 0x2015; + + // Set up the DMA base address + DISPC_REG(DISPC_GFX_BA) = 0x80200000; + + // Set up RGB 16 and disable the DMA for now + DISPC_REG(DISPC_GFX_ATTR) = 0x0000000C; + + // Set preload based on equation in section 15.5.3.2 in RM + //DISPC_REG(DISPC_GFX_PRELOAD) = 0x60; + + // Set number of bytes to increment at end of row to 1 (default value) + DISPC_REG(DISPC_GFX_ROW_INC) = 0x0001; + + // Set number of bytes to increment between two pixels to 1 (default value) + DISPC_REG(DISPC_GFX_PIX_INC) = 0x0001; + + // Set FIFO thresholds to defaults (hi = 1023, lo = 960) + //DISPC_REG(DISPC_GFX_FIFO_TH) = 0x03FF03C0; + DISPC_REG(DISPC_GFX_FIFO_TH) = 0x03FC03BC; + + // Set start position to 0 (frame buffer and active display area are the same) + DISPC_REG(DISPC_GFX_POS) = 0x00000000; + + // Set frame buffer size, Y = PIXELS_PER_COL, X = PIXELS_PER_ROW + DISPC_REG(DISPC_GFX_SIZE) = (((PIXELS_PER_COL -1) << 16) | (PIXELS_PER_ROW - 1)); + + // Set the control register keep bit 5 (GOLCD) and bit 28 (LCDENABLESIGNAL) low + // until shadow registers have all been written + DISPC_REG(DISPC_CONTROL) = 0x38019209; + + // Disable all gating, pixel clock always toggles, frame data only + // loaded every frame (palette/gamma table off) + DISPC_REG(DISPC_CONFIG) = 0x00000004; + //DISPC_REG(DISPC_CONFIG) = 0x00000000; + + // Disable all capabilities not used for LCD + DISPC_REG(DISPC_CAPABLE) = 0x00000000; + + // Set horizontal timing + DISPC_REG(DISPC_TIMING_H) = ((LCD_H_BACK << 20) | (LCD_H_FRONT << 8) | LCD_H_WIDTH); + + // Set vertical timing + DISPC_REG(DISPC_TIMING_V) = ((LCD_V_BACK << 20) | (LCD_V_FRONT << 8) | LCD_V_WIDTH); + + // Set syncs low true and DE to hi true + DISPC_REG(DISPC_POL_FREQ) = 0x00003000; + + // Set logic divisor to 1 and pixel divisor to 2 + DISPC_REG(DISPC_DIVISOR) = 0x00020001; + + // Set LCD size, lines per panel is , pixels per line is + DISPC_REG(DISPC_SIZE_LCD) = (((PIXELS_PER_COL -1) << 16) | (PIXELS_PER_ROW - 1)); + + // Enable the DMA + DISPC_REG(DISPC_GFX_ATTR) |= 0x00000001; + + // Set bit 5 (GOLCD) to enable LCD + DISPC_REG(DISPC_CONTROL) |= 0x00000020; + + printf("OMAP3530 LCD Initialization Complete.\n"); + + return; +} + +/* fbdev_setstart(): + * Used by uMon's FBI interface to establish the starting address of + * the frame buffer memory. + */ +void +fbdev_setstart(long offset) +{ + // Select DSS1_ALWON_FCLK (96MHz) as source for DSI and DISPC + DSS_REG(DSS_CONTROL) = 0x30; + + // Set up the DMA base address + DISPC_REG(DISPC_GFX_BA) = offset; + + // Enable the DMA + DISPC_REG(DISPC_GFX_ATTR) |= 0x00000001; + + // Set bit 5 (GOLCD) to enable LCD + DISPC_REG(DISPC_CONTROL) |= 0x00000020; + + return; +} + +char *lcd_tstHelp[] = { + "OMAP3530 LCD controller test", + "-[n,x,d[4,8,16]]", + "The user may set color depth to run the test at.", + "The frame buffer R/W test will test all of the frame ", + "buffer regardless of depth.", + "Options...", + " -n run test without keycheck - CAUTION: RESET SYSTEM TO STOP!", + " -d4 run test, force a depth of 4-bits/pixel", + " -d8 run test, force a depth of 8-bits/pixel", + " -d16 run test, force a depth of 16-bits/pixel", + " -x init only, do not run frame buffer tests", + "", + " No options, default to current mode and depth.", + 0 +}; + +int lcd_tst(int argc,char *argv[]) +{ + volatile ushort wr16, rd16; + int i, x, opt; + int no_wait = 0; + int init_only = 0; + char c; + + lcd_tst_mode = 1; + + while ((opt=getopt(argc,argv,"clnsxd:4,8,16")) != -1) { + switch(opt) { + case 'd': // set the color depth + switch(*optarg) { + case '4': + lcd_color_depth = 4; + printf("Forcing 4bpp Mode!\n"); + break; + case '8': + lcd_color_depth = 8; + printf("Forcing 8bpp Mode!\n"); + break; + default: // test with 16bpp + lcd_color_depth = 16; + printf("Forcing 16bpp Mode!\n"); + break; + } + break; + case 'n': // no waiting for keypress - fastest operation + no_wait = 1; + printf("No Keypress Mode, Must Reset System to Stop!\n"); + break; + case 'x': // init only + no_wait = 1; + printf("Initializing LCD, Skipping testsp!\n"); + init_only = 1; + break; + default: // test with current mode + break; + } + } + + // get the new parameters into the LCD controller + fbdev_init(); + + if (init_only) return 0; + + printf("Frame Buffer R/W..."); + // do an address=data read/write test on the frame buffer + // PIXELS_PER_COL * PIXELS_PER_ROW is the highest pixel. + // Multiply by bits_per_pixel (sed_color_depth), then + // divide by 8 to get the actual byte count. + for (i = 0; i < LCD_FB_SIZE(lcd_color_depth) + LCD_ROW_SIZE(lcd_color_depth); i += 2){ + LCD_BUF(i) = i & 0xffff; + rd16 = LCD_BUF(i); + if(rd16 != (i & 0xffff)){ + printf("Fail at 0x%08x, WR 0x%08x, RD 0x%04lx!\n",LCD_BUF_ADD + i, i, (ulong)rd16); + return -1; + } + } + + printf("OK!, Press key to continue.\n"); + + c = getchar(); + + printf("Frame Buffer Start: 0x%08x, End 0x%08x\n",LCD_BUF_ADD, + LCD_BUF_ADD + LCD_FB_SIZE(lcd_color_depth) + LCD_ROW_SIZE(lcd_color_depth)); + if (no_wait) + { + printf("Begin Full Screen Color Test.\n"); + while(1){ + // fill the frame buffer with incrementing color values + for (x = 0; x < 16; x++){ + switch (lcd_color_depth){ + case 4: wr16 = x | x << 4 | x << 8 | x << 12; break; + case 8: wr16 = x | x << 8; break; + default: wr16 = vga_lookup[x]; break; // 16-bits bypasses the lookup table + } + for (i = 0; i < LCD_FB_SIZE(lcd_color_depth); i += 2){ + LCD_BUF(i) = wr16; + } + } // for x + } // while + } // no_wait + else + { + printf("Begin Full Screen Color Test, Press any key to go to next color, \'x\' to end.\n"); + while(1){ + // fill the frame buffer with incrementing color values + for (x = 0; x < 16; x++){ + switch (lcd_color_depth){ + case 4: wr16 = x | x << 4 | x << 8 | x << 12; break; + case 8: wr16 = x | x << 8; break; + default: wr16 = vga_lookup[x]; break; // 16-bits bypasses the lookup table + } + for (i = 0; i < LCD_FB_SIZE(lcd_color_depth) + LCD_ROW_SIZE(lcd_color_depth); i += 2){ + LCD_BUF(i) = wr16; + } + c = getchar(); + if (c == 'x') goto lcd_tst_next; + } // for x + } // while + } // else no keycheck test + + lcd_tst_next: + + // write a one pixel border around the screen + lcd_fg_color = 15; // VGA Bright White + fb_draw_line2(LEFT, TOP, RIGHT, TOP, lcd_fg_color); + fb_draw_line2(LEFT, TOP, LEFT, BOTTOM, lcd_fg_color); + fb_draw_line2(LEFT, BOTTOM, RIGHT, BOTTOM, lcd_fg_color); // bottom left to bottom right + fb_draw_line2(RIGHT, TOP, RIGHT, BOTTOM, lcd_fg_color); // bottom right to top right + // draw an x + fb_draw_line2(LEFT, TOP, RIGHT, BOTTOM, lcd_fg_color); + fb_draw_line2(LEFT, BOTTOM, RIGHT, TOP, lcd_fg_color); + // draw 3 circles at the center of the screen, one inside the other + lcd_fg_color = 12; // VGA Bright Red + fb_draw_circle2(CENTER_X, CENTER_Y, 100, lcd_fg_color); + lcd_fg_color = 10; // VGA Bright Green + fb_draw_circle2(CENTER_X, CENTER_Y, 66, lcd_fg_color); + lcd_fg_color = 9; // VGA Bright Blue + fb_draw_circle2(CENTER_X, CENTER_Y, 33, lcd_fg_color); + + return 0; +} + +// fb_set_pixel sets a pixel to the specified color. +// This is target specific and is called from the generic +// fb_draw.c functions +void fb_set_pixel(ulong X, ulong Y, uchar color) +{ + // Make sure the specified pixel is valid. +#if 0 + if((X < 0) || (X >= PIXELS_PER_ROW) || (Y < 0) || (Y >= PIXELS_PER_COL)) + { + printf("fb_set_pixel() bad X (%ld) or Y (%ld)!\n", X, Y); + return; + } +#else + if (X < 0) + X = 0; + else { + if (X >= PIXELS_PER_ROW) + X = PIXELS_PER_ROW - 1; + } + if (Y < 0) + Y = 0; + else { + if (Y >= PIXELS_PER_COL) + Y = PIXELS_PER_COL - 1; + } +#endif + + LCD_BUF(LCD_GET_PIXEL_ADD(X, Y)) = vga_lookup[color]; +} +#endif diff --git a/ports/csb740/omap3530_lcd.h b/ports/csb740/omap3530_lcd.h new file mode 100755 index 0000000..0457548 --- /dev/null +++ b/ports/csb740/omap3530_lcd.h @@ -0,0 +1,75 @@ +//========================================================================== +// +// omap3530_lcd.h +// +// Author(s): Luis Torrico, Cogent Computer Systems, Inc. +// Contributors: +// Date: 12/10/2008 +// Description: This file contains register offsets and bit defines +// for the OMAP3530 Cortex-A8 LCD Controller +// + +#include "bits.h" + +/* The DSS is designed to support video and graphics processing functions and to */ +/* interface with video/still image sensors and displays. */ + +/*-------------------------------------------------------------------------------------*/ +/* Display Interface Subsystem */ +/*-------------------------------------------------------------------------------------*/ +/* Module Name Base Address Size */ +/* + DSI Protocol Engine 0x4804FC00 512 bytes + DSI Complex I/O 0x4804FE00 64 bytes + DSI PLL Controller 0x4804FF00 32 bytes + DISS 0x48050000 512 byte + DISPC 0x48050400 1K byte + RFBI 0x48050800 256 bytes + VENC 0x48050C00 256 bytes +*/ +/*-------------------------------------------------------------------------------------*/ +#define DSS_BASE_ADD 0x48050000 // Display Subsystem Base Address +#define DISPC_BASE_ADD 0x48050400 // Display Controller Base Address +#define DSS_REG(_x_) *(vulong *)(DSS_BASE_ADD + _x_) +#define DISPC_REG(_x_) *(vulong *)(DISPC_BASE_ADD + _x_) + +// Display Subsystem Registers +#define DSS_SYSCONFIG 0x10 // +#define DSS_SYSSTATUS 0x14 // +#define DSS_IRQSTATUS 0x18 // +#define DSS_CONTROL 0x40 // +#define DSS_SDI_CONTROL 0x44 // +#define DSS_PLL_CONTROL 0x48 // +#define DSS_SDI_STATUS 0x5C // + +// Display Controller Registers +#define DISPC_SYSCONFIG 0x10 // +#define DISPC_SYSSTATUS 0x14 // +#define DISPC_IRQSTATUS 0x18 // +#define DISPC_IRQENABLE 0x1C // +#define DISPC_CONTROL 0x40 // +#define DISPC_CONFIG 0x44 // +#define DISPC_CAPABLE 0x48 // +#define DISPC_DEFAULT_COLOR 0x4C // +#define DISPC_TRANS_COLOR 0x54 // +#define DISPC_LINE_STATUS 0x5C // +#define DISPC_LINE_NUMBER 0x60 // +#define DISPC_TIMING_H 0x64 // +#define DISPC_TIMING_V 0x68 // +#define DISPC_POL_FREQ 0x6C // +#define DISPC_DIVISOR 0x70 // +#define DISPC_GLOBAL_ALPHA 0x74 // +#define DISPC_SIZE_DIG 0x78 // +#define DISPC_SIZE_LCD 0x7C // +#define DISPC_GFX_BA 0x80 // +#define DISPC_GFX_POS 0x88 // +#define DISPC_GFX_SIZE 0x8C // +#define DISPC_GFX_ATTR 0xA0 // +#define DISPC_GFX_FIFO_TH 0xA4 // +#define DISPC_GFX_FIFO_SS 0xA8 // +#define DISPC_GFX_ROW_INC 0xAC // +#define DISPC_GFX_PIX_INC 0xB0 // +#define DISPC_GFX_WIN_SKIP 0xB4 // +#define DISPC_GFX_TABLE_BA 0xB8 // +#define DISPC_GFX_PRELOAD 0x62C // + diff --git a/ports/csb740/omap3530_mem.h b/ports/csb740/omap3530_mem.h new file mode 100755 index 0000000..820873c --- /dev/null +++ b/ports/csb740/omap3530_mem.h @@ -0,0 +1,184 @@ +//========================================================================== +// +// omap3530_mem.h +// +// Author(s): Luis Torrico, Cogent Computer Systems, Inc. +// Contributors: +// Date: 12/09/2008 +// Description: This file contains register base addresses and offsets +// and access macros for the OMAP3530 Cortex-A8 memory controller +// + +#include "bits.h" + +// The GPMC supports up to eight chip-select regions of programmable size, and programmable base +// addresses in a total address space of 1 Gbyte. +// Chip Select mapping for CSB740 +// CS0 = NOR = 0x08000000 +// CS1 = N/A +// CS2 = N/A +// CS3 = NAND = 0x18000000 +// CS4 = Ethernet = 0x2C000000 +// CS5 = Expansion = 0x28000000 +// CS6 = N/A +// CS7 = N/A + +//#define OMAP35XX_GPMC_BASE 0x6E000000 +#define GPMC_REG(_x_) *(vulong *)(OMAP35XX_GPMC_BASE + _x_) +#define MYGPMC_REG(_x_) (vulong *)(OMAP35XX_GPMC_BASE + _x_) + +// GPMC - General Purpose Memory Controller +#define GPMC_SYS_CONFIG 0x10 // Chip Select 0 Upper Control Register +#define GPMC_SYS_STATUS 0x14 // Chip Select 0 Lower Control Register +#define GPMC_IRQ_STATUS 0x18 // Chip Select 0 Additional Control Register +#define GPMC_IRQ_EN 0x1C // Chip Select 1 Upper Control Register +#define GPMC_TIMEOUT 0x40 // Chip Select 1 Lower Control Register +#define GPMC_ERR_ADD 0x44 // Chip Select 1 Additional Control Register +#define GPMC_ERR_TYPE 0x48 // Chip Select 2 Upper Control Register +#define GPMC_CONFIG 0x50 // Chip Select 2 Lower Control Register +#define GPMC_STATUS 0x54 // Chip Select 2 Additional Control Register + +#define GPMC_CS0_CONFIG1 0x60 // Chip Select 3 Upper Control Register +#define GPMC_CS0_CONFIG2 0x64 // Chip Select 3 Lower Control Register +#define GPMC_CS0_CONFIG3 0x68 // Chip Select 3 Additional Control Register +#define GPMC_CS0_CONFIG4 0x6C // Chip Select 4 Upper Control Register +#define GPMC_CS0_CONFIG5 0x70 // Chip Select 4 Lower Control Register +#define GPMC_CS0_CONFIG6 0x74 // Chip Select 4 Additional Control Register +#define GPMC_CS0_CONFIG7 0x78 // Chip Select 5 Upper Control Register + +#define GPMC_CS1_CONFIG1 0x90 // Chip Select 5 Lower Control Register +#define GPMC_CS1_CONFIG2 0x94 // Chip Select 5 Additional Control Register +#define GPMC_CS1_CONFIG3 0x98 // Configuration Register +#define GPMC_CS1_CONFIG4 0x9C // Chip Select 5 Lower Control Register +#define GPMC_CS1_CONFIG5 0xA0 // Chip Select 5 Additional Control Register +#define GPMC_CS1_CONFIG6 0xA4 // Configuration Register +#define GPMC_CS1_CONFIG7 0xA8 // Configuration Register + +#define GPMC_CS2_CONFIG1 0xC0 // Chip Select 5 Lower Control Register +#define GPMC_CS2_CONFIG2 0xC4 // Chip Select 5 Additional Control Register +#define GPMC_CS2_CONFIG3 0xC8 // Configuration Register +#define GPMC_CS2_CONFIG4 0xCC // Chip Select 5 Lower Control Register +#define GPMC_CS2_CONFIG5 0xD0 // Chip Select 5 Additional Control Register +#define GPMC_CS2_CONFIG6 0xD4 // Configuration Register +#define GPMC_CS2_CONFIG7 0xD8 // Configuration Register + +#define GPMC_CS3_CONFIG1 0xF0 // Chip Select 5 Lower Control Register +#define GPMC_CS3_CONFIG2 0xF4 // Chip Select 5 Additional Control Register +#define GPMC_CS3_CONFIG3 0xF8 // Configuration Register +#define GPMC_CS3_CONFIG4 0xFC // Chip Select 5 Lower Control Register +#define GPMC_CS3_CONFIG5 0x100 // Chip Select 5 Additional Control Register +#define GPMC_CS3_CONFIG6 0x104 // Configuration Register +#define GPMC_CS3_CONFIG7 0x108 // Configuration Register + +#define GPMC_CS4_CONFIG1 0x120 // Chip Select 5 Lower Control Register +#define GPMC_CS4_CONFIG2 0x124 // Chip Select 5 Additional Control Register +#define GPMC_CS4_CONFIG3 0x128 // Configuration Register +#define GPMC_CS4_CONFIG4 0x12C // Chip Select 5 Lower Control Register +#define GPMC_CS4_CONFIG5 0x130 // Chip Select 5 Additional Control Register +#define GPMC_CS4_CONFIG6 0x134 // Configuration Register +#define GPMC_CS4_CONFIG7 0x138 // Configuration Register + +#define GPMC_CS5_CONFIG1 0x150 // Chip Select 5 Lower Control Register +#define GPMC_CS5_CONFIG2 0x154 // Chip Select 5 Additional Control Register +#define GPMC_CS5_CONFIG3 0x158 // Configuration Register +#define GPMC_CS5_CONFIG4 0x15C // Chip Select 5 Lower Control Register +#define GPMC_CS5_CONFIG5 0x160 // Chip Select 5 Additional Control Register +#define GPMC_CS5_CONFIG6 0x164 // Configuration Register +#define GPMC_CS5_CONFIG7 0x168 // Configuration Register + +#define GPMC_CS6_CONFIG1 0x180 // Chip Select 5 Lower Control Register +#define GPMC_CS6_CONFIG2 0x184 // Chip Select 5 Additional Control Register +#define GPMC_CS6_CONFIG3 0x188 // Configuration Register +#define GPMC_CS6_CONFIG4 0x18C // Chip Select 5 Lower Control Register +#define GPMC_CS6_CONFIG5 0x190 // Chip Select 5 Additional Control Register +#define GPMC_CS6_CONFIG6 0x194 // Configuration Register +#define GPMC_CS6_CONFIG7 0x198 // Configuration Register + +#define GPMC_CS7_CONFIG1 0x1B0 // Chip Select 5 Lower Control Register +#define GPMC_CS7_CONFIG2 0x1B4 // Chip Select 5 Additional Control Register +#define GPMC_CS7_CONFIG3 0x1B8 // Configuration Register +#define GPMC_CS7_CONFIG4 0x1BC // Chip Select 5 Lower Control Register +#define GPMC_CS7_CONFIG5 0x1C0 // Chip Select 5 Additional Control Register +#define GPMC_CS7_CONFIG6 0x1C4 // Configuration Register +#define GPMC_CS7_CONFIG7 0x1C8 // Configuration Register + +#define GPMC_PREFETCH_CONFIG1 0x1E0 +#define GPMC_PREFETCH_CONFIG2 0x1E4 +#define GPMC_PREFETCH_CONTROL 0x1EC +#define GPMC_PREFETCH_STATUS 0x1F0 + +// Bit Defines for OMAP3530 GPMC +// WEIM_CS0U to WEIM_CS5U - Chip Select Upper Control Register +#define WEIM_CSU_SP BIT31 // Supervisor Protect, 0 = User mode accesses allowed, 1 = User mode accesses prohibited +#define WEIM_CSU_WP BIT30 // Write Protect, 0 = Writes allowed, 1 = Writes prohibited +#define WEIM_CSU_BCD(_x_) ((_x_ & 0x03) << 28) // Burst Clock Divisor, when EIM_CFG_BCM = 0 +#define WEIM_CSU_BCS(_x_) ((_x_ & 0x03) << 24) // Burst Clock Start, # of 1/2 cycles from LBA to BCLK high +#define WEIM_CSU_PSZ_4 (0 << 22) // page size = 4 words +#define WEIM_CSU_PSZ_8 (1 << 22) // page size = 8 words +#define WEIM_CSU_PSZ_16 (2 << 22) // page size = 16 words +#define WEIM_CSU_PSZ_32 (3 << 22) // page size = 32 words +#define WEIM_CSU_PME BIT21 // 1 = Enables page mode emulation +#define WEIM_CSU_SYNC BIT20 // 1 = Enables synchronous burst mode +#define WEIM_CSU_DOL(_x_) ((_x_ & 0x0f) << 16) // # of clocks -1 before latching read data when SYNC = 1 +#define WEIM_CSU_CNC_0 (0 << 14) // Hold CS negated after end of cycle for 0 clocks +#define WEIM_CSU_CNC_1 (1 << 14) // Hold CS negated after end of cycle for 1 clock +#define WEIM_CSU_CNC_2 (2 << 14) // Hold CS negated after end of cycle for 2 clocks +#define WEIM_CSU_CNC_3 (3 << 14) // Hold CS negated after end of cycle for 3 clocks +#define WEIM_CSU_WSC(_x_) ((_x_ & 0x3f) << 8) // Wait States, 0 = 2, 1 = 2, 2-62 = +1, 63 = dtack +#define WEIM_CSU_WSC_DTACK (0x3f << 8) // Wait States, 0 = 2, 1 = 2, 2-62 = +1, 63 = dtack +#define WEIM_CSU_EW BIT7 // Determines how WEIM supports the ECB input +#define WEIM_CSU_WWS(_x_) ((_x_ & 0x07) << 4) // Additional wait states for write cycles +#define WEIM_CSU_EDC(_x_) ((_x_ & 0x0f) << 0) // Dead Cycles after reads for bus turn around + +// Bit Defines for MCIMX31 +// WEIM_CS0L to WEIM_CS5L - Chip Select Lower Control Register +#define WEIM_CSL_OEA(_x_) ((_x_ & 0x0f) << 28) // # of 1/2 cycles after CS asserts before OE asserts +#define WEIM_CSL_OEN(_x_) ((_x_ & 0x0f) << 24) // # of 1/2 cycles OE negates before CS negates +#define WEIM_CSL_WEA(_x_) ((_x_ & 0x0f) << 20) // # of 1/2 cycles EB0-3 assert before WE asserts +#define WEIM_CSL_WEN(_x_) ((_x_ & 0x0f) << 16) // # of 1/2 cycles EB0-3 negate before WE negates +#define WEIM_CSL_CSA(_x_) ((_x_ & 0x0f) << 12) // # of clocks address is asserted before CS and held after CS +#define WEIM_CSL_EBC BIT11 // 0 = assert EB0-3 for Reads & Writes, 1 = Writes only +#define WEIM_CSL_DSZ_BYTE_3 (0 << 8) // device is 8-bits wide, located on byte 3 (D31-24) +#define WEIM_CSL_DSZ_BYTE_2 (1 << 8) // device is 8-bits wide, located on byte 2 (D23-16) +#define WEIM_CSL_DSZ_BYTE_1 (2 << 8) // device is 8-bits wide, located on byte 1 (D15-8) +#define WEIM_CSL_DSZ_BYTE_0 (3 << 8) // device is 8-bits wide, located on byte 0 (D7-0) +#define WEIM_CSL_DSZ_HALF_1 (4 << 8) // device is 16-bits wide, located on half word 1 (D31-16) +#define WEIM_CSL_DSZ_HALF_0 (5 << 8) // device is 16-bits wide, located on half word 1 (D15-0) +#define WEIM_CSL_DSZ_WORD (6 << 8) // device is 32-bits wide, located on half word 1 (D15-0) +#define WEIM_CSL_CSN(_x_) ((_x_ & 0x0f) << 4) // Chip Select Negate +#define WEIM_CSL_PSR BIT3 // PSRAM Enable, 0 = disabled, 1 = enabled +#define WEIM_CSL_CRE BIT2 // Control Register Enable +#define WEIM_CSL_WRAP BIT1 // 0 = Memory in linear mode, 1 = Memory in wrap mode +#define WEIM_CSL_CSEN BIT0 // 1 = Enable Chip Select + +// Bit Defines for MCIMX31 +// WEIM_CS0A to WEIM_CS5A - Chip Select Additional Control Register +#define WEIM_CSA_EBRA(_x_) ((_x_ & 0x0f) << 28) // # of half AHB clock cycles before EB asserted. +#define WEIM_CSA_EBRN(_x_) ((_x_ & 0x0f) << 24) // # of half AHB clock cycles between EB negation and end of access. +#define WEIM_CSA_RWA(_x_) ((_x_ & 0x0f) << 20) // # of half AHB clock cycles RW delay +#define WEIM_CSA_RWN(_x_) ((_x_ & 0x0f) << 16) // # of half AHB clock cycles between EB negation and end of access +#define WEIM_CSA_MUM BIT15 // 1 = Muxed Mode +#define WEIM_CSA_LAH_0 (0 << 13) // 0 AHB half clock cycles between LBA negation and address invalid +#define WEIM_CSA_LAH_1 (1 << 13) // 1 AHB half clock cycles between LBA negation and address invalid +#define WEIM_CSA_LAH_2 (2 << 13) // 2 AHB half clock cycles between LBA negation and address invalid +#define WEIM_CSA_LAH_3 (3 << 13) // 3 AHB half clock cycles between LBA negation and address invalid +#define WEIM_CSA_LBN(_x_) ((_x_ & 0x07) << 10) // This bit field determines when LBA is negated +#define WEIM_CSA_LBA_0 (0 << 8) // 0 AHB half clock cycles between beginning of access and LBA assertion. +#define WEIM_CSA_LBA_1 (1 << 8) // 1 AHB half clock cycles between beginning of access and LBA assertion. +#define WEIM_CSA_LBA_2 (2 << 8) // 2 AHB half clock cycles between beginning of access and LBA assertion. +#define WEIM_CSA_LBA_3 (3 << 8) // 3 AHB half clock cycles between beginning of access and LBA assertion. +#define WEIM_CSA_DWW(_x_) ((_x_ & 0x03) << 6) // Decrease Write Wait State +#define WEIM_CSA_DCT_0 (0 << 4) // 0 AHB clock cycles between CS assertion and first DTACK check. +#define WEIM_CSA_DCT_1 (1 << 4) // 1 AHB clock cycles between CS assertion and first DTACK check. +#define WEIM_CSA_DCT_2 (2 << 4) // 2 AHB clock cycles between CS assertion and first DTACK check. +#define WEIM_CSA_DCT_3 (3 << 4) // 3 AHB clock cycles between CS assertion and first DTACK check. +#define WEIM_CSA_WWU BIT3 // 1 = Allow wrap on write +#define WEIM_CSA_AGE BIT2 // 1 = Enable glue logic +#define WEIM_CSA_CNC2 BIT1 // Chip Select Negation Clock Cycles +#define WEIM_CSA_FCE BIT0 // 1 = Data captured using BCLK_FB + +// WEIM_CFG - Configuration Register +#define WEIM_CFG_BCM BIT2 // 1 = Burst Clock always on, 0 = when CS with SYNC = 1 is accessed +#define WEIM_CFG_MAS BIT0 // 1 = Merged address space + + diff --git a/ports/csb740/omap3530_sdmmc.c b/ports/csb740/omap3530_sdmmc.c new file mode 100755 index 0000000..b542d4e --- /dev/null +++ b/ports/csb740/omap3530_sdmmc.c @@ -0,0 +1,505 @@ +/* NOTE: + * THIS CODE IS NOT READY FOR USE YET!!! + */ +#include "config.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "timer.h" +#include "omap3530.h" +#include "sd.h" + + +#define MMCTMOUT 2000 + +/* This code is included here just for simulating the SD + * interface (temporarily if a real one isn't ready. In a real system, + * the INCLUDE_SD_DUMMY_FUNCS definition would be off. + */ +int +xsdCmd(unsigned long cmd, unsigned short argh, unsigned short argl) +{ + vulong stat, rsp; + struct elapsed_tmr tmr; + + printf("sdCmd(0x%08lx) (cmd=%d)\n",cmd,(cmd & 0x3f000000) >> 24); + + startElapsedTimer(&tmr,MMCTMOUT); // Wait for command line not-in-use + while(MMC1_REG(MMCHS_PSTATE) & CMDI) { + if(msecElapsed(&tmr)) { + printf("sdInit: CMDI timeout\n"); + return(-1); + } + } + + MMC1_REG(MMCHS_ARG) = ((argh << 16) | argl); + MMC1_REG(MMCHS_IE) = 0xfffffeff; + MMC1_REG(MMCHS_CMD) = cmd; + +again: + stat = MMC1_REG(MMCHS_STAT); + if (stat & CTO) { + if (stat & CCRC) + printf("cmdline in use\n"); + else + printf("CTO1 CCRC0\n"); + MMC1_REG(MMCHS_SYSCTL) |= SRC; + startElapsedTimer(&tmr,MMCTMOUT); + while(MMC1_REG(MMCHS_SYSCTL) & SRC) { + if(msecElapsed(&tmr)) + printf("sdInit: SRC timeout\n"); + } + return(-1); + } + if ((stat & CC) == 0) + goto again; + + cmd = MMC1_REG(MMCHS_CMD); + if ((cmd & RSPTYPE) == RSPTYPE_NONE) { + printf("Success!\n"); + return(0); + } + + if ((cmd & RSPTYPE) == RSPTYPE_136) { + rsp = MMC1_REG(MMCHS_RSP10); + printf("RSP0: %04x, RSP1: %04x\n", + rsp & 0xffff,(rsp & 0xffff0000) >> 16); + rsp = MMC1_REG(MMCHS_RSP32); + printf("RSP2: %04x, RSP3: %04x\n", + rsp & 0xffff,(rsp & 0xffff0000) >> 16); + rsp = MMC1_REG(MMCHS_RSP54); + printf("RSP4: %04x, RSP5: %04x\n", + rsp & 0xffff,(rsp & 0xffff0000) >> 16); + rsp = MMC1_REG(MMCHS_RSP76); + printf("RSP6: %04x, RSP7: %04x\n", + rsp & 0xffff,(rsp & 0xffff0000) >> 16); + } + if ((cmd & RSPTYPE) == RSPTYPE_48) { + rsp = MMC1_REG(MMCHS_RSP10); + printf("RSP0: %04x, RSP1: %04x\n", + rsp & 0xffff,(rsp & 0xffff0000) >> 16); + rsp = MMC1_REG(MMCHS_RSP32); + printf("RSP2: %04x, RSP3: %04x\n", + rsp & 0xffff,(rsp & 0xffff0000) >> 16); + } + if ((cmd & RSPTYPE) == RSPTYPE_48BSY) { + rsp = MMC1_REG(MMCHS_RSP10); + printf("RSP0: %04x, RSP1: %04x\n", + rsp & 0xffff,(rsp & 0xffff0000) >> 16); + rsp = MMC1_REG(MMCHS_RSP32); + printf("RSP2: %04x, RSP3: %04x\n", + rsp & 0xffff,(rsp & 0xffff0000) >> 16); + } + + return(0); +} + +int +sdCmd(unsigned long cmd, unsigned short argh, unsigned short argl) +{ + vulong stat, arg; + struct elapsed_tmr tmr; + + printf("sdCmd(0x%08lx) (cmd=%d)\n",cmd,(cmd & 0x3f000000) >> 24); + + MMC1_REG(MMCHS_STAT) = 0xffffffff; + MMC1_REG(MMCHS_BLK) = NBLK(1) | BLEN(512); + MMC1_REG(MMCHS_SYSCTL) &= ~DTOMSK; + MMC1_REG(MMCHS_SYSCTL) |= DTO(14); + + startElapsedTimer(&tmr,MMCTMOUT); // Wait for command line not-in-use + while(MMC1_REG(MMCHS_PSTATE) & CMDI) { + if(msecElapsed(&tmr)) { + printf("sdCmd: CMDI timeout\n"); + return(-1); + } + monDelay(1); + } + + arg = argh; + arg <<= 16; + arg |= argl; + MMC1_REG(MMCHS_ARG) = arg; + MMC1_REG(MMCHS_IE) = 0xfffffeff; + MMC1_REG(MMCHS_CMD) = cmd; + + startElapsedTimer(&tmr,MMCTMOUT); + do { + stat = MMC1_REG(MMCHS_STAT); + if (stat & CTO) { + if (stat & CCRC) + printf("CCRC1\n"); + else + printf("CTO1 CCRC0\n"); + MMC1_REG(MMCHS_SYSCTL) |= SRC; + startElapsedTimer(&tmr,MMCTMOUT); + while(MMC1_REG(MMCHS_SYSCTL) & SRC) { + if(msecElapsed(&tmr)) + printf("sdCmd: SRC timeout\n"); + } + return(-1); + } + if(msecElapsed(&tmr)) { + printf("sdCmd: CC timeout\n"); + return(-1); + } + monDelay(1); + } while ((stat & CC) == 0); + + stat = MMC1_REG(MMCHS_STAT); + if (stat & CCRC) + printf("Cmd crc\n"); + if (stat & DCRC) + printf("Data crc\n"); + if (stat & CERR) { + printf("Card error 0x%lx\n",stat); + return(-1); + } + if (stat & CTO) { + printf("CTO set!\n"); + return(-1); + } + if (stat & CC) { + printf("Success!\n"); + return(0); + } + else { + printf("Didn't complete!\n"); + return(-1); + } +} + +int +sdClkSet(int clkval) +{ + vulong reg; + struct elapsed_tmr tmr; + + MMC1_REG(MMCHS_SYSCTL) &= ~CEN; + reg = MMC1_REG(MMCHS_SYSCTL); + reg &= ~CLKDMSK; + reg |= CLKD(96000/clkval); + MMC1_REG(MMCHS_SYSCTL) = reg; + + startElapsedTimer(&tmr,MMCTMOUT); // Wait for clock stable + while((MMC1_REG(MMCHS_SYSCTL) & ICS) == 0) { + if(msecElapsed(&tmr)) { + printf("sdClkSet: ICS timeout\n"); + return(-1); + } + monDelay(1); + } + MMC1_REG(MMCHS_SYSCTL) |= CEN; + startElapsedTimer(&tmr,MMCTMOUT); // Wait for clock stable + while((MMC1_REG(MMCHS_SYSCTL) & CEN) == 0) { + if(msecElapsed(&tmr)) { + printf("sdClkSet: ICS timeout\n"); + return(-1); + } + monDelay(1); + } + return(0); +} + +/* sdInit(): + * This function is called by the "sd init" command on the command line. + * Where applicable, the text refers to the section in the Sept 2008 + * Technical Reference Manual (TRM) from which I got the code/functionality. + */ +int +sdInit(int interface, int verbose) +{ + int i, pbiasretry = 0; + vulong reg; + struct elapsed_tmr tmr; + + /* There's only one interface on the CSB740, so reject anything + * other than interface 0... + */ + if (interface != 0) + return(-1); + + /******************************* + * + * Clock configuration: + * (TRM 22.5.1.1) + */ + *(vulong *)CM_ICLKEN1_CORE |= EN_MMC1; // Configure interface and + *(vulong *)CM_FCLKEN1_CORE |= EN_MMC1; // functional clocks. + + /******************************* + * + * Not really sure what this is... apparently some kind of clock steering. + * I tried both setting the bit and clearing it. Made no difference. + * In both cases the clock was present on the CLK pin. + */ + *(vulong *)CONTROL_DEVCONF0 |= MMCSDIO1ADPCLKISEL; + + /******************************** + * + * Set up BIAS (this allows the pins to run at 1.8 or 3.0 volts I think). + * This is configured as 0606 in rom_reset.S (i don't think thats right). + * Note: The CSB703 ties this interface to 3.3 volts. + * TRM 22.5.3 + * TRM 7.5.2 and flowchart in figure 7-24... + */ +pbias_retry: + *(vulong *)CONTROL_PBIAS_LITE = PBIAS_LITE_VMMC1_52MHZ; + monDelay(100); + *(vulong *)CONTROL_PBIAS_LITE |= MMC_PWR_STABLE; + monDelay(100); + if (*(vulong *)CONTROL_PBIAS_LITE & PBIAS_LITE_MMC1_ERROR) { + *(vulong *)CONTROL_PBIAS_LITE &= (~MMC_PWR_STABLE); + monDelay(100); + if (pbiasretry++ < 3) { + goto pbias_retry; + } + else { + printf("sdInit: PBIAS timeout\n"); + return(-1); + } + } + +#if 0 + /******************************* + * + * These registers are things I found when scouring the TRM for "MMC". + * I don't think they have any affect on basic startup of the interface + * so they are removed for now... + */ + *(vulong *)CM_AUTOIDLE1_CORE &= ~AUTO_MMC1; // Disable auto clock enable + *(vulong *)PM_WKEN1_CORE &= ~EN_MMC1; // Disable wakeup event + *(vulong *)PM_MPUGRPSEL1_CORE &= ~GRPSEL_MMC1; // Disable mpu-group wakeup + *(vulong *)PM_IVA2GRPSEL1_CORE &= ~GRPSEL_MMC1; // Disable iva2-group wakeup + *(vulong *)PM_WKST1_CORE &= ~EN_MMC1; // Clear wakeup status +#endif + + /******************************* + * + * Issue soft reset and wait for completion... + * (TRM 22.5.1.2) + */ + MMC1_REG(MMCHS_SYSCONFIG) |= SRESET; // Software reset + if ((MMC1_REG(MMCHS_SYSSTATUS) & RESETDONE) == 0) + printf("Good, RESETDONE is low here\n"); + + startElapsedTimer(&tmr,MMCTMOUT); // Wait for completion + while((MMC1_REG(MMCHS_SYSSTATUS) & RESETDONE) == 0) { + if(msecElapsed(&tmr)) { + printf("sdInit: SRST failed\n"); + return(-1); + } + } + /******************************** + * + * Set SRA bit, then wait for it to clear. + */ + MMC1_REG(MMCHS_SYSCTL) |= SRA; + startElapsedTimer(&tmr,MMCTMOUT); + while((MMC1_REG(MMCHS_SYSCTL) & SRA)) { + if(msecElapsed(&tmr)) { + printf("sdInit: SRA timeout\n"); + return(-1); + } + } + + startElapsedTimer(&tmr,MMCTMOUT); // Wait for debounce stable. + while((MMC1_REG(MMCHS_PSTATE) & DEBOUNCE) != DEBOUNCE) { + if(msecElapsed(&tmr)) { + printf("sdInit: DEBOUNCE timeout\n"); + return(-1); + } + } + + /******************************* + * + * Establish hardware capabilities: + * TRM 22.5.1.3 + */ + reg = MMC1_REG(MMCHS_CAPA); + reg &= ~(VS18 | VS30 | VS33); + reg |= VS18; + MMC1_REG(MMCHS_CAPA) = reg; + +#if 0 + /******************************** + * + * Enable wakeup mode (don't think I need this, tried both ways) + * TRM 22.5.1.4 + */ + MMC1_REG(MMCHS_SYSCONFIG) |= ENWAKEUP; + MMC1_REG(MMCHS_HCTL) |= IWE; +#endif + + /******************************** + * + * MMC Host and Bus Configuration + * TRM 22.5.1.5 + */ + //MMC1_REG(MMCHS_CON) = + MMC1_REG(MMCHS_HCTL) &= ~SVDS; + MMC1_REG(MMCHS_HCTL) |= SVDS18; + monDelay(10); + MMC1_REG(MMCHS_HCTL) |= SDBP; + monDelay(100); + + startElapsedTimer(&tmr,MMCTMOUT); // Wait for SVDS verification + while((MMC1_REG(MMCHS_HCTL) & SDBP) == 0) { + if(msecElapsed(&tmr)) { + printf("sdInit: SDBP timeout\n"); + return(-1); + } + } + + MMC1_REG(MMCHS_SYSCTL) |= ICE; // Enable internal clock + + MMC1_REG(MMCHS_SYSCTL) &= ~CLKDMSK; // Set clock divisor: + MMC1_REG(MMCHS_SYSCTL) |= CLKD(960); // (should be <= 80Khz initially) + + startElapsedTimer(&tmr,MMCTMOUT); // Wait for clock stable + while((MMC1_REG(MMCHS_SYSCTL) & ICS) == 0) { + if(msecElapsed(&tmr)) { + printf("sdInit: ICS timeout\n"); + return(-1); + } + } + + /* I set these two bits with the hope that the clock will be + * active even if there is no card installed (so I atleast can + * see *some* activity). + */ + MMC1_REG(MMCHS_SYSCTL) |= CEN; // External clock enable +#if 0 + MMC1_REG(MMCHS_CON) |= CLKEXTFREE; + + reg = MMC1_REG(MMCHS_SYSCONFIG); + reg &= ~SIDLEMODEMSK; + reg &= ~CLKACTIVITYMSK; + reg &= ~AUTOIDLE; + reg |= (SIDLEMODE(1) | CLKACTIVITY(3)); + MMC1_REG(MMCHS_SYSCONFIG) = reg; +#endif + + /******************************** + * + * Set the INIT bit to send an initialization stream to the card... + * (top of left flowchart in TRM section 22.5.2.1) + */ + MMC1_REG(MMCHS_CON) |= MMCINIT; + for(i=0;i<10;i++) { + sdCmd(CMD(0) | RSPTYPE_NONE,0,0); + monDelay(2); + } + MMC1_REG(MMCHS_CON) &= ~MMCINIT; + MMC1_REG(MMCHS_STAT) = 0xffffffff; + + if (sdClkSet(400) != 0) + return(-1); + + /* this is the get_card_type() function in the code from TI... + */ + if (sdCmd(CMD(55) | RSPTYPE_48,0,0) < 0) { + printf("Card type = MMC\n"); + MMC1_REG(MMCHS_CON) |= ODE; + } + else { + if ((MMC1_REG(MMCHS_RSP10) & 0xffff) == 0x0120) { + printf("Card type = SD\n"); + } + else { + printf("Card type = MMC_CARD\n"); + MMC1_REG(MMCHS_CON) |= ODE; + } + } + + +#if 0 + /******************************** + * + * Send Command 5 + * (top of right flowchart in TRM section 22.5.2.1) + */ + sdCmd(CMD(5) | RSPTYPE_NONE,0,0); + + startElapsedTimer(&tmr,MMCTMOUT); + do { + reg = MMC1_REG(MMCHS_STAT); + if (reg & CC) { + /* For now we assume only SD cards... */ + printf("SDIO detected!!! Shouldn't be here!\n"); + return(-1); + } + if(msecElapsed(&tmr)) { + printf("sdInit: CTO timeout1\n"); + return(-1); + } + + } while((reg & CTO) == 0); + + /******************************** + * + * Set SRC bit, then wait for it to clear. + * (midway down right flowchart in TRM section 22.5.2.1) + */ + MMC1_REG(MMCHS_SYSCTL) |= SRC; + startElapsedTimer(&tmr,MMCTMOUT); + while((MMC1_REG(MMCHS_SYSCTL) & SRC)) { + if(msecElapsed(&tmr)) { + printf("sdInit: SRC timeout\n"); + return(-1); + } + } + + sdCmd(CMD(8) | RSPTYPE_NONE,0,0); + + startElapsedTimer(&tmr,MMCTMOUT); + do { + reg = MMC1_REG(MMCHS_STAT); + if (reg & CC) { + /* For now we assume only SD cards... */ + printf("SD BINGO!!! This is where we want to be!\n"); + return(0); + } + if(msecElapsed(&tmr)) { + printf("sdInit: CTO timeout2\n"); + return(-1); + } + + } while((reg & CTO) == 0); + + /* For now we assume only SD cards... */ + printf("MMC detected!!! Shouldn't be here!\n"); +#endif + return(-1); +} + +int +sdRead(int interface, char *buf, int blk, int blkcnt) +{ + char *from; + int size; + + if (interface != 0) + return(-1); + + from = (char *)(blk * SD_BLKSIZE); + size = blkcnt * SD_BLKSIZE; + memcpy(buf,from,size); + return(0); +} + +int +sdWrite(int interface, char *buf, int blk, int blkcnt) +{ + char *to; + int size; + + if (interface != 0) + return(-1); + + to = (char *)(blk * SD_BLKSIZE); + size = blkcnt * SD_BLKSIZE; + memcpy(to,buf,size); + return(0); +} + diff --git a/ports/csb740/ram_reset.S b/ports/csb740/ram_reset.S new file mode 100755 index 0000000..f801b19 --- /dev/null +++ b/ports/csb740/ram_reset.S @@ -0,0 +1,211 @@ + .file "ram_reset.s" + +/* + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Author: Ed Sutter + * email: esutter@lucent.com + * phone: 908-582-2351 + * + * + * Modified for the CSB740 - OMAP3530 Single Board + * + * ram_reset.s: + */ + +#include "warmstart.h" +#include "omap3530.h" +#include "config.h" + + /* + * Have a separate stack for each processor mode. + */ + + /* define sizes for each mode's stack */ + .equ FiqStackSz, 4096 + .equ IrqStackSz, 4096 + .equ AbtStackSz, 4096 + .equ UndStackSz, 4096 + .equ SysStackSz, 4096 + + /* declare the stacks */ + .extern MonStack + .global FiqStack + .global IrqStack + .global AbtStack + .global UndStack + .global SysStack + + /* allocate the stacks */ + .comm FiqStack, FiqStackSz /* for the FIQ mode */ + .comm IrqStack, IrqStackSz /* for the IRQ mode */ + .comm AbtStack, AbtStackSz /* for the Abort mode */ + .comm UndStack, UndStackSz /* for the Undef mode */ + .comm SysStack, SysStackSz /* for the System mode */ + /* User mode has the same stack as system mode. */ + +/*********************************************************************/ + + .extern start + + .global reset + .global coldstart + .global lukewarmstart + .global warmstart + .global ipaddr + .global etheraddr + .global moncomptr + + .text + + /* + * Exception table at address 0 + */ +reset: + b coldstart + b undefined_instruction + b software_interrupt + b abort_prefetch + b abort_data + b not_assigned + b interrupt_request + b fast_interrupt_request + +#include "etheraddr.S" +#include "moncomptr.S" + +/*********************************************************************/ + + /* + * At the end of the reset sequence, MMU, Icache, Dcache, + * and write buffer are all disabled. + * Also IRQs and FIQs are disabled in the processor's CPSR + * The operating mode is SVC (supervisory mode), and the + * PC is vectored at 0x00000000. A branch in 0x00000000 + * brings us directly here. + * + */ + +coldstart: +// ldr r0, =0x2001 /* allow access to all coprocessors */ +// mcr p15,0,r0,c15,c1,0 +// nop +// nop +// nop + +// ldr r0, =0x00000078 +// mcr p15,0,r0,c1,c0,0 /* Disable MMU, caches, write buffer */ +// nop +// nop +// nop + +// ldr r0, =0x00000000 +// mcr p15,0,r0,c8,c7,0 /* flush TLB's */ +// mcr p15,0,r0,c7,c7,0 /* flush Caches */ +// mcr p15,0,r0,c7,c10,4 /* Flush Write Buffer */ +// nop +// nop +// nop + +// mvn r0, #0 /* grant manager access to all domains */ +// mcr p15,0,r0,c3,c0,0 + +/********************************************************************/ + +midstart: + ldr r0, =INITIALIZE + + /* fall-through to 'lukewarmstart' */ + +/********************************************************************/ + +lukewarmstart: + /* Save the argument to r11 */ + mov r11, r0 + + /* + * *** DO NOT TOUCH R11 *** + */ + + /* + * Set-up the stack-pointers for all operating modes + */ + + /* FIQ mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x11 /* set FIQ mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(FiqStack + FiqStackSz - 4) /* initialize the stack ptr */ + /* IRQ mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x12 /* set IRQ mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(IrqStack + IrqStackSz - 4) /* initialize the stack ptr */ + /* Abort mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x17 /* set Abort mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(AbtStack + AbtStackSz - 4) /* initialize the stack ptr */ + /* Undef mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x1b /* set Undef mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(UndStack + UndStackSz - 4) /* initialize the stack ptr */ + /* System mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x1f /* set System mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(SysStack + SysStackSz - 4) /* initialize the stack ptr */ + /* 'warmstart' will take us back to SVC mode + stack for SVC mode will also be setup in warmstart */ + + mov r0, r11 /* get argument back from r11 */ + + b warmstart + + +/********************************************************************/ + +warmstart: + /* Save the argument to r11 */ + mov r11, r0 + + /* + * *** DO NOT TOUCH R11 *** + */ + + + /* Change (back) to SVC mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x13 /* set System mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + /* Reset the stack pointer for the SVC mode (our current mode) */ + ldr sp, =(MonStack + MONSTACKSIZE - 4) + + /* + * Restore argument which was saved to r11 and jump to + * the C function start(). + */ + + mov r0, r11 +jump_to_c: + bl start + + /* the C code should never return */ + b reset + +.align 4 + diff --git a/ports/csb740/regnames.c b/ports/csb740/regnames.c new file mode 100755 index 0000000..9c4747e --- /dev/null +++ b/ports/csb740/regnames.c @@ -0,0 +1 @@ +#include "regs_arm.c" diff --git a/ports/csb740/rom_reset.S b/ports/csb740/rom_reset.S new file mode 100755 index 0000000..d2c9cfb --- /dev/null +++ b/ports/csb740/rom_reset.S @@ -0,0 +1,418 @@ + .file "rom_reset.S" + +/* + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Author: Ed Sutter + * email: esutter@lucent.com + * phone: 908-582-2351 + * + * + * Modified for the CSB740 - OMAP3530 Single Board + * + * rom_reset.s: + */ + +#include "warmstart.h" +#include "omap3530.h" +#include "config.h" + + /* + * Have a separate stack for each processor mode. + */ + + /* define sizes for each mode's stack */ + .equ FiqStackSz, 4096 + .equ IrqStackSz, 4096 + .equ AbtStackSz, 4096 + .equ UndStackSz, 4096 + .equ SysStackSz, 4096 + + /* declare the stacks */ + .extern MonStack + .global FiqStack + .global IrqStack + .global AbtStack + .global UndStack + .global SysStack + .global raise + .global cache_init + + /* allocate the stacks */ + .comm FiqStack, FiqStackSz /* for the FIQ mode */ + .comm IrqStack, IrqStackSz /* for the IRQ mode */ + .comm AbtStack, AbtStackSz /* for the Abort mode */ + .comm UndStack, UndStackSz /* for the Undef mode */ + .comm SysStack, SysStackSz /* for the System mode */ + /* User mode has the same stack as system mode. */ + +/*********************************************************************/ + + .extern start + + .global reset + .global coldstart + .global lukewarmstart + .global warmstart + + .text + + /* + * Exception table at address 0 + */ +reset: + b coldstart + b undefined_instruction + b software_interrupt + b abort_prefetch + b abort_data + b not_assigned + b interrupt_request + b fast_interrupt_request + +#include "etheraddr.S" +#include "moncomptr.S" +#include "alttfsdevtbl.S" + +coldstart: + ldr pc, =coldstart_1 // jump to actual ROM location + nop + +coldstart_1: + /* Make sure interrupts are off, and we're in supervisor mode... + */ + mrs r0,cpsr // Retreive current program status register + bic r0,r0,#0x1f // Clear all mode bits. + orr r0,r0,#0xd3 // Set mode to supervisor, IRQ FIQ disabled. + msr cpsr,r0 + +// bl cache_init + +//---------------------------------------------------------- +// Start of Cogent Setup for CSB740 OMAP3530 +//---------------------------------------------------------- + +init_pbias: + ldr r2, =0x00000000 // set bias for sdio1 + ldr r1, =0x48002520 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000606 // set bias for sdio1 + ldr r1, =0x48002520 + str r2, [r1] + + bl delay_200 +init_clocks: + ldr r2, =0x00000037 // Enable DPLL1 in lock mode + ldr r1, =0x48004904 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x000A7115 // Set DPLL1 (MPU) M = 625, (N +1)= 21 + 1, MPU_CLK = ~545MHz + ldr r1, =0x48004940 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x099F1700 // Set DPLL3 (CORE) M = 415, (N +1)= 23 + 1, CORE_CLK = ~332MHz + ldr r1, =0x48004D40 + str r2, [r1] + + bl delay_200 + + //ldr r2, =0x00000080 // Enable SYS_CLKOUT2 for debug purposes + //ldr r1, =0x48004D70 + //str r2, [r1] + + //bl delay_200 + + ldr r2, =0x43fffe00 // Turn on all available module clocks + ldr r1, =0x48004a00 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x7ffffedb // Turn on all available peripheral clocks + ldr r1, =0x48004a10 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00006000 // enable auto clock for UART1 and UART2 + ldr r1, =0x48004a30 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000028 // enable WDT2 and GPIO 1 functional clock + ldr r1, =0x48004c00 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x0000002c // enable WDT2, GPIO 1 interface and 32Ksync (for Linux) clock + ldr r1, =0x48004c10 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x0003E000 // enable GPIO 2-6 functional clocks + ldr r1, =0x48005000 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x0003E000 // enable GPIO 2-6 interface clocks + ldr r1, =0x48005010 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000003 // enable DSS1_ALWON_FCLK + ldr r1, =0x48004e00 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000001 // enable DSS interface clock + ldr r1, =0x48004e10 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x0000100A // Set CLKSEL_DSS1 to divide by 1 + ldr r1, =0x48004e40 + str r2, [r1] + + bl delay_200 + +init_ddr: + ldr r2, =0x0000001A // reset DDR + ldr r1, =0x6D000010 + str r2, [r1] + + ldr r1, =0x6D000014 // SDRC_SYSSTATUS +wait_reset: + ldr r2, [r1] + tst r2, #1 // test RESETDONE + beq wait_reset + + ldr r2, =0x00000018 // release DDR reset + ldr r1, =0x6D000010 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000100 // 32-bit SDRAM on data lane [31:0] - CS0 + ldr r1, =0x6D000044 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x02584099 // SDRC_MCFG0 register + ldr r1, =0x6D000080 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00054601 // SDRC_RFR_CTRL0 register + ldr r1, =0x6D0000a4 + str r2, [r1] + + bl delay_200 + + ldr r2, =0xA29DB4C6 // SDRC_ACTIM_CTRLA0 register + ldr r1, =0x6D00009c + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00012214 // SDRC_ACTIM_CTRLB0 register + ldr r1, =0x6D0000A0 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000081 // Disble Power Down of CKE due to 1 CKE on combo part + ldr r1, =0x6D000070 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000000 // NOP command + ldr r1, =0x6D0000A8 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000001 // Precharge command + ldr r1, =0x6D0000A8 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000002 // Auto-refresh command + ldr r1, =0x6D0000A8 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000002 // Auto-refresh command + ldr r1, =0x6D0000A8 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x00000032 // SDRC MR0 register Burst length=4 + ldr r1, =0x6D000084 + str r2, [r1] + + bl delay_200 + + ldr r2, =0x0000000A // SDRC DLLA control register + ldr r1, =0x6D000060 + str r2, [r1] + + bl delay_200 + +/********************************************************************/ + +midstart: + ldr r0, =INITIALIZE + + /* fall-through to 'lukewarmstart' */ + +/********************************************************************/ + +lukewarmstart: + /* Save the argument to r11 */ + mov r11, r0 + + /* + * *** DO NOT TOUCH R11 *** + */ + + /* + * Set-up the stack-pointers for all operating modes + */ + + /* FIQ mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x11 /* set FIQ mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(FiqStack + FiqStackSz - 4) /* initialize the stack ptr */ + /* IRQ mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x12 /* set IRQ mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(IrqStack + IrqStackSz - 4) /* initialize the stack ptr */ + /* Abort mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x17 /* set Abort mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(AbtStack + AbtStackSz - 4) /* initialize the stack ptr */ + /* Undef mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x1b /* set Undef mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(UndStack + UndStackSz - 4) /* initialize the stack ptr */ + /* System mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x1f /* set System mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + ldr sp, =(SysStack + SysStackSz - 4) /* initialize the stack ptr */ + /* 'warmstart' will take us back to SVC mode + stack for SVC mode will also be setup in warmstart */ + + mov r0, r11 /* get argument back from r11 */ + b warmstart + + +/********************************************************************/ + +warmstart: + /* Save the argument to r11 */ + mov r11, r0 + + /* + * *** DO NOT TOUCH R11 *** + */ + + + /* Change (back) to SVC mode */ + mrs r0, cpsr /* move CPSR to r0 */ + bic r0, r0, #0x1f /* clear all mode bits */ + orr r0, r0, #0x13 /* set System mode bits */ + msr CPSR_c, r0 /* move back to CPSR */ + /* Reset the stack pointer for the SVC mode (our current mode) */ + ldr sp, =(MonStack + MONSTACKSIZE - 4) + + /* + * Restore argument which was saved to r11 and jump to + * the C function start(). + */ + + mov r0, r11 +jump_to_c: + bl start + + /* the C code should never return */ + b reset + +.align 4 + + +/********************************************************************* + * simple delay loop + */ +delay_200: + ldr r3, =200 /* loop count */ +delay_loop: + subs r3,r3,#1 + bne delay_loop + nop + + mov pc, lr + +raise: mov pc, lr /* to make linker happy */ + +/********************************************************************* + * Cache initialization: + * Turn everything down and invalidate... + */ +cache_init: + /* Make sure caches are turned down... + */ + mrc p15, 0, r3, cr1, cr0, 0 // turn off I/D-cache + bic r3, r3, #4096 // I + bic r3, r3, #4 // D + mcr p15, 0, r3, cr1, cr0, 0 + + mov r0, #0 +// mcr p15, 0, r0, cr7, cr7, 0 // arm_cache_invalidate + mcr p15, 0, r0, cr7, cr6, 0 // arm_dcache_invalidate + mcr p15, 0, r0, cr7, cr5, 0 // arm_icache_invalidate + + mrc p15, 0, r0, cr1, cr0, 1 // l2cache_disable + bic r0, r0, #2 + mcr p15, 0, r0, cr1, cr0, 1 + + mov r0, #1 + mrc p15, 1, r0, cr0, cr0, 1 // emu_ext_boot_l2_inv + mov pc, lr + diff --git a/ports/csb740/target_version.h b/ports/csb740/target_version.h new file mode 100755 index 0000000..4abd503 --- /dev/null +++ b/ports/csb740/target_version.h @@ -0,0 +1,17 @@ +/* target_version.h: + * Initial version for all ports is zero. As the TARGET_VERSION incrments + * as a result of changes made to the target-specific code, this file should + * be used as an informal log of those changes for easy reference by others. + * + * 0: UART/DRAM/FLASH/TFS working through BDI2000 + * 0->1: Boots from flash (without bdi2000), sleep delay adjusted. + * 1->2: Ethernet added. + * 2->3: LCD interface added. + * 3->4: Flash driver fix, enabled INCLUDE_HWTMR, and added show_version(), + * and the splash screen is loaded from TFS. + * 4->5: Added support for the FBI (frame buffer) interface, and hard-reset. + * 5->6: Speedup (clock configuration) provided by Luis; also changed + * cpuio.c so that SPI-mode of the touch-screen interface now works. + */ + +#define TARGET_VERSION 6 diff --git a/ports/csb740/tfsdev.h b/ports/csb740/tfsdev.h new file mode 100755 index 0000000..4331851 --- /dev/null +++ b/ports/csb740/tfsdev.h @@ -0,0 +1,31 @@ +/* tfsdev.h: + This file is ONLY included by tfs.c. It is seperate from tfs.h because + it is target-specific. It is not part of config.h because it includes + the declaration of the tfsdevtbl[]. + A prefix in the name of the file determines what device is used to store + that file. If no prefix is found the the first device in the table is + used as a default. The syntax of the prefix is "//STRING/" where STRING + is user-definable, but the initial // and final / are required by tfs + code. +*/ + +struct tfsdev tfsdevtbl[] = { + { "//FLASH/", + TFSSTART, + TFSEND, + TFSSPARE, + TFSSPARESIZE, + TFSSECTORCOUNT, + TFS_DEVTYPE_FLASH, }, + +#ifdef FLASHRAM_BASE + { "//RAM/", + FLASHRAM_BASE, + FLASHRAM_END-FLASHRAM_SECTORSIZE, + FLASHRAM_END-FLASHRAM_SECTORSIZE+1, + FLASHRAM_SECTORSIZE, + FLASHRAM_SECTORCOUNT-1, + TFS_DEVTYPE_RAM | TFS_DEVINFO_AUTOINIT, }, +#endif + { 0, TFSEOT,0,0,0,0,0 } +}; diff --git a/ports/csb740/xcmddcl.h b/ports/csb740/xcmddcl.h new file mode 100755 index 0000000..13552a3 --- /dev/null +++ b/ports/csb740/xcmddcl.h @@ -0,0 +1,34 @@ + +/* extcmddcl.h: */ +/* This file must exist even if it is empty because it is #included in the */ +/* common file cmdtbl.c. The purpose is to keep the common comand table */ +/* file (common/cmdtbl.c) from being corrupted with non-generic commands */ +/* that may be target specific. */ +/* It is the declaration portion of the code that must be at the top of */ +/* the cmdtbl[] array. */ +/* For example: + +extern int dummycmd(); Function declaration. +extern char *dummyHelp[]; Command help array declaration. + +*/ + +extern int date(); +extern char *dateHelp[]; + +#if INCLUDE_LCD +extern int lcd_tst(); +extern char *lcd_tstHelp[]; +#endif + +//extern int i2c(); +//extern char *i2cHelp[]; + +extern int nandCmd(); +extern char *nandHelp[]; + +extern int ads(); +extern char *adsHelp[]; + +extern int ldatags(); +extern char *ldatagsHelp[]; diff --git a/ports/csb740/xcmdtbl.h b/ports/csb740/xcmdtbl.h new file mode 100755 index 0000000..334218c --- /dev/null +++ b/ports/csb740/xcmdtbl.h @@ -0,0 +1,19 @@ +/* extcmdtbl.h: */ +/* This file must exist even if it is empty because it is #included in the */ +/* common file cmdtbl.c. The purpose is to keep the common comand table */ +/* file (common/cmdtbl.c) from being corrupted with non-generic commands */ +/* that may be target specific. */ +/* It is the entry in the command table representing the new command being */ +/* added to the cmdtbl[] array. */ +/* For example: + "dummy", dummycmd, dummyHelp, +*/ +{"ads", ads, adsHelp,}, +//{"i2c", i2c, i2cHelp,}, +#if INCLUDE_LCD +{"lcd_tst", lcd_tst, lcd_tstHelp,}, +#endif +{"ldatags", ldatags, ldatagsHelp,}, +#if INCLUDE_NANDCMD +{"nand", nandCmd, nandHelp,}, +#endif diff --git a/ports/template/OLD_TO_NEW.txt b/ports/template/OLD_TO_NEW.txt new file mode 100644 index 0000000..e0ce7e3 --- /dev/null +++ b/ports/template/OLD_TO_NEW.txt @@ -0,0 +1,100 @@ +################################################################## +# +# Converting an old-style (pre uMon1.0) monitor port over to the new +# uMon1.0 structure... +# +1. Copy old to new, remove vssver.scc and make all files writeable. +2. Run d2u on all files and change all .s files to .S. +3. Using a bashrc file from another port directory as a reference, + convert the old file over to the new format. Also, if necessary, + change the name from ".bashrc" to "bashrc". +4. Remove the obj directory. +5. Move makefile to omakefile. +6. Create a new target_version.h file... Copy from some other target + and start with version 1. +7. Create new makefile... + + TOPDIR = $(UMONTOP) + PLATFORM = copy from omakefile + TGTDIR = copy from omakefile + FILETYPE = elf | coff | aout + CPUTYPE = arm | m68k | mips | ppc | sh + CUSTOM_CFLAGS = -mcpu=XXX (at least) + CUSTOM_AFLAGS = -mcpu=XXX (at least) + +8. Establish the memory map. For each hard-coded address in the + .lnk files... create a variable name and set up the variable + to equal the hard-coded value in the makefile. In the .lnk file + replace the hard-coded address with the variable name. For example, + replace the following lines in the .lnk file... + + flash : ORIGIN = 0xFF800000, LENGTH = 0x0007FFFF + ram : ORIGIN = 0x00000400, LENGTH = 0x0001FBFF + + with: + + flash : ORIGIN = FLASHBASE, LENGTH = FLASHLEN + ram : ORIGIN = RAMBASE, LENGTH = RANLEN + + and then add these variable initializations to the makefile: + + FLASHBASE = 0xFF800000 + FLASHLEN = 0x0007FFFF + RAMBASE = 0x00000400 + RANLEN = 0x0001FBFF + + then change the name of the .lnk file from *.lnk to *.ldt. This + file will be used as the loader template (.ldt) file and the actual + linker map file (*.ld) will be created at build time by the vsub + tool. + Also, if there are any references to object files in the .lnk file, + remove the "obj/" directory path prefix. That isn't used anymore. + Finally, the filenames should be "PLATFORM_rule.ldt", where "PLATFORM" + is the value assigned to the PLATFORM variable in the makefile and "rule" + is the rule in the makefile that uses that map file. So, if "boot" is + the rule and its for the CSB337, then the filename would be + CSB337_boot.ldt. This naming convention must be followed for the + makefile to use the pre-defined variables and rules provided by the + xxx.make files that come with the main tree. + +9. Include the common.make file... + + include $(TOPDIR)/target/make/common.make + +10. Establish the directory that is the base location of the flash + device driver source. In most cases this will be $(COMBASE)/flash/devices + for the newer device driver model; however, the directories under + $(COMBASE)/flash/boards does have valid drivers as well. + + FLASHDIR = $(COMBASE)/flash/devices + +11. Now convert the OBJS list to several smaller lists as follows + (refer to some similar target makefile for reference). Note + that there are a few new files as of uMon1.0, so also refer to + the list in this template makefile: + + LOCSSRC: local assembler source (.S files) + LOCCSRC: local C source code. + CPUSSRC: CPU-specific assembler source which is found under the + directory specified by the $(CPUTYPE) variable above. + COMSRC: all of the source that is to be pulled in from the core + code directory. + CPUCSRC: CPU-specific C source code. + IODEVSRC:Device driver code found under $(COMBASE)/iodev + COMCSRC: Common C code found under $(COMBASE)/core + FLASHSRC: Flash driver C source files in the FLASHDIR. + +12. Include the common objects.make file... + +include $(TOPDIR)/target/make/objects.make + +13. Build the objects list... + +OBJS = $(LOCSOBJ) $(CPUSOBJ) $(LOCCOBJ) $(CPUCOBJ) $(COMCOBJ) \ + $(FLASHOBJ) $(IODEVOBJ) + +14. Use the new cpuio.c and config.h files in this directory as an + example of the rework needed to the current files. + +15. Make sure that the stack uses the MonStack array and the MONSTACKSIZE + specified in config.h. diff --git a/ports/template/README.txt b/ports/template/README.txt new file mode 100644 index 0000000..977e99b --- /dev/null +++ b/ports/template/README.txt @@ -0,0 +1,10 @@ +This is a template directory (or starting point) for a MicroMonitor +port. If you are transitioning from a pre-1.0 version of MicroMonitor +then you can refer to the OLD_TO_NEW.txt file for steps on how to +convert the makefile. + +Refer to the text in the makefile for detailed information on the +structure of the makefile. + +Refer to reset.s for basic bootup (assembler) initialization. +Refer to cpuio.c for port-specific 'C' level startup functions. diff --git a/ports/template/TEMPLATE_boot.ldt b/ports/template/TEMPLATE_boot.ldt new file mode 100644 index 0000000..cda955f --- /dev/null +++ b/ports/template/TEMPLATE_boot.ldt @@ -0,0 +1,69 @@ +/* Linker file for building monitor using GNU toolset on PC... + + General notice: + This code is part of a boot-monitor package developed as a generic base + platform for embedded system designs. As such, it is likely to be + distributed to various projects beyond the control of the original + author. Please notify the author of any enhancements made or bugs found + so that all may benefit from the changes. In addition, notification back + to the author will allow the new user to pick up changes that may have + been made by other users after this version of the code was distributed. + + Author: Ed Sutter + email: esutter@lucent.com + phone: 908-582-2351 + +*/ + +MEMORY +{ + ram (RWX): org = BOOTRAMBASE, len = BOOTRAMLEN + rom (RWX): org = BOOTROMBASE, len = BOOTROMLEN + resetv (RWX): org = 0xfffffff0, len = 0x10 +} + +SECTIONS +{ + .bss : + { + bss_start = .; + *(.bss) *(COMMON) + } >ram + + .sbss : + { + *(.sbss) + bss_end = .; + } >ram + + .text : + { + boot_base = .; + reset.o(.text) + } >rom + + .data : + { + *(.data) + } >rom + + .sdata : + { + *(.sdata) + } >rom + + .sdata2 : + { + *(.sdata2) + } >rom + + .rodata : + { + *(.rodata) + } >rom + + .got : + { + *(.got) + } >rom +} diff --git a/ports/template/TEMPLATE_ramtst.ldt b/ports/template/TEMPLATE_ramtst.ldt new file mode 100644 index 0000000..34d4203 --- /dev/null +++ b/ports/template/TEMPLATE_ramtst.ldt @@ -0,0 +1,69 @@ +/* Linker file for building monitor using GNU toolset on PC... + + General notice: + This code is part of a boot-monitor package developed as a generic base + platform for embedded system designs. As such, it is likely to be + distributed to various projects beyond the control of the original + author. Please notify the author of any enhancements made or bugs found + so that all may benefit from the changes. In addition, notification back + to the author will allow the new user to pick up changes that may have + been made by other users after this version of the code was distributed. + + Author: Ed Sutter + email: esutter@lucent.com + phone: 908-582-2351 + +*/ +etheraddr = MACADDRBASE; +alt_tfsdevtbl_base = ALTTFSDEVTBLBASE; + +MEMORY +{ + ram (RWX): org = RAMTSTBASE, len = RAMTSTLEN +} + +SECTIONS +{ + .text : + { + boot_base = .; + reset.o(.text) + } >ram + + .data : + { + *(.data) + } >ram + + .sdata : + { + *(.sdata) + } >ram + + .sdata2 : + { + *(.sdata2) + } >ram + + .rodata : + { + *(.rodata) + } >ram + + .got : + { + *(.got) + } >ram + + .bss : + { + bss_start = .; + *(.bss) *(COMMON) + } >ram + + .sbss : + { + *(.sbss) + bss_end = .; + } >ram +} diff --git a/ports/template/_vimrc b/ports/template/_vimrc new file mode 100644 index 0000000..2a127e5 --- /dev/null +++ b/ports/template/_vimrc @@ -0,0 +1,13 @@ +" Very basic VIM startup file +" +" Set tab stop to 4 characters: +set ts=4 + +" Turn off syntax-sensitive coloring: +" syntax off + +" Enable C-style indentation: +" set cindent + +" Disable the highlighting of search items: +set nohlsearch diff --git a/ports/template/bashrc b/ports/template/bashrc new file mode 100644 index 0000000..16ded27 --- /dev/null +++ b/ports/template/bashrc @@ -0,0 +1,16 @@ +# Set prompt to reflect the target: +PS1=TEMPLATE: + +# TITLE may be used by the 'title' tool in umon_setup +export TITLE="TEMPLATE Monitor Development" + +# If UMONTOP is not set, then set it to the default: +if [ "$UMONTOP" == "" ] +then + export UMONTOP=../../umon_main +fi + +# The umon_setup script looks for the presence of the EXT_UMON_SETUP +# as a shell variable. If it is present it assumes it is the fullpath +# of a user-defined script that will be run as part of the umon setup. +. $UMONTOP/host/bin/umon_setup diff --git a/ports/template/config.h b/ports/template/config.h new file mode 100644 index 0000000..6e61dd5 --- /dev/null +++ b/ports/template/config.h @@ -0,0 +1,199 @@ +/* Template MicroMonitor configuration file. + */ +#define CPU_BE + +/* PLATFORM_NAME: + * Some string that briefly describes your target. + */ +#define PLATFORM_NAME "Name of your Board here" + +/* CPU_NAME: + * The name of your CPU (i.e. "PowerPC 405", "Coldfire 5272" ,etc...). + */ +#define CPU_NAME "CPU_NAME_HERE" + +/* LOOPS_PER_SECOND: + * Approximately the size of a loop that will cause a 1-second delay. + * This value can be adjusted by using the "sleep -c" command. + */ +#define LOOPS_PER_SECOND 23000 + +/* PRE_TFSAUTOBOOT_HOOK(): + * This is a port-specific function that will be called just prior to + * uMon running any/each autobootable file (not including monrc). +#define PRE_TFSAUTOBOOT_HOOK() func() + */ + +/* PRE_COMMANDLOOP_HOOK(): + * This is a port-specific function that will be called just before + * MicroMonitor turns over control to the endless command processing + * loop in start() (start.c). +#define PRE_COMMANDLOOP_HOOK() func() + */ + +/* If a watchdog macro is needed, this is how you do it + * (using target specific code in the macro of course)... + * The remoteWatchDog() call is only needed if your appliation + * will override the monitor's watchdog macro. If that isn't + * needed, then that logic can be omitted from the macro. + +#define WATCHDOG_MACRO \ + { \ + extern void (*remoteWatchDog)(void); \ + if (remoteWatchDog) { \ + remoteWatchdog() \ + } \ + else { \ + *(unsigned long *)0xff000000 |= 0x00100000; \ + *(unsigned long *)0xff000000 &= ~0x00100000; \ + } + } + * + */ + +/* If the ENET_LINK_IS_UP macro is defined as some function, then + * that function will be called every half second for some number of + * ticks. The default tick count is set by the definition of + * LINKUP_TICK_MAX also defined in that file. This can be overridden + * here if necessary. Refer to the function EthernetWaitforLinkup() in + * ethernet.c (umon_main/target/common/ethernet.c) for complete details. + * + * The function defined by ENET_LINK_IS_UP (shown below as phy_linkup()) + * is assumed to return 1 if the link is up; else 0. + * +#define ENET_LINK_IS_UP phy_linkup +#define LINKUP_TICK_MAX 10 + * + * The purpose of this is to provide a common way to wait for the up-state + * of the link prior to allowing other commands to execute from uMon at + * startup. + */ + + +/* Flash bank configuration: + * Basic information needed to configure the flash driver. + * Fill in port specific values here. + */ +#define SINGLE_FLASH_DEVICE 1 +#define FLASH_COPY_TO_RAM 1 +#define FLASH_BANK0_BASE_ADDR 0xFF800000 +#define FLASH_PROTECT_RANGE "0-2" +#define FLASH_BANK0_WIDTH 2 +#define FLASH_LARGEST_SECTOR 0x20000 + +/* If there is a need to have the range of protected sectors locked (and + * the flash device driver supports it), then enable this macro... +#define LOCK_FLASH_PROTECT_RANGE + */ + +/* TFS definitions: + * Values that configure the flash space that is allocated to TFS. + * Fill in port specific values here. + */ +#define TFSSPARESIZE FLASH_LARGEST_SECTOR +#define TFSSTART (FLASH_BANK0_BASE_ADDR+0x80000) +#define TFSEND 0xFFFDFFFF +#define TFSSPARE (TFSEND+1) +#define TFSSECTORCOUNT ((TFSSPARE-TFSSTART)/0x20000) +#define TFS_EBIN_ELF 1 +#define TFS_VERBOSE_STARTUP 1 +#define TFS_ALTDEVTBL_BASE &alt_tfsdevtbl_base + +/* FLASHRAM Parameters (not required): + * Primarily used for configuring TFS on battery-backed RAM. + * For a simple (volatile) RAM-based TFS device, use the + * "tfs ramdev" command. + * + * Define a block of RAM space to be used as a TFS-device. + * This is a block of RAM that TFS is fooled into treating like flash. + * It essentially provides a RAM-based file-storage area. + */ +#define FLASHRAM_BASE 0x380000 + +#ifdef FLASHRAM_BASE +# define FLASHRAM_END 0x3fffff +# define FLASHRAM_SECTORSIZE 0x010000 +# define FLASHRAM_SPARESIZE FLASHRAM_SECTORSIZE +# define FLASHRAM_SECTORCOUNT 8 +# define FLASHRAM_BANKNUM 1 +# define FLASHBANKS 2 +#else +# define FLASHBANKS 1 +#endif + +/* ALLOCSIZE: + * Specify the size of the memory block (in monitor space) that + * is to be allocated to malloc in the monitor. Note that this + * size can be dynamically increased using the heap command at + * runtime. + */ +#define ALLOCSIZE (64*1024) + +/* MONSTACKSIZE: + * The amount of space allocated to the monitor's stack. + */ +#define MONSTACKSIZE (8*1024) + +/* INCLUDE_XXX Macros: + * Set/clear the appropriate macros depending on what you want + * to configure in your system. The sanity of this list is tested + * through the inclusion of "inc_check.h" at the bottom of this list... + * When starting a port, set all but INCLUDE_MALLOC, INCLUDE_SHELLVARS, + * INCLUDE_MEMCMDS and INCLUDE_XMODEM to zero. Then in small steps + * enable the following major features in the following order: + * + * INCLUDE_FLASH to test the flash device drivers. + * INCLUDE_TFS* to overlay TFS onto the flash. + * INCLUDE_ETHERNET, INCLUDE_TFTP to turn the ethernet interface. + * + * All other INCLUDE_XXX macros can be enabled as needed and for the + * most part, they're hardware independent. + * Note that for building a very small footprint, INCLUDE_MALLOC and + * INCLUDE_SHELLVARS can be disabled. + */ + +#define INCLUDE_MALLOC 1 +#define INCLUDE_MEMCMDS 1 +#define INCLUDE_SHELLVARS 1 +#define INCLUDE_XMODEM 1 +#define INCLUDE_EDIT 0 +#define INCLUDE_DISASSEMBLER 0 +#define INCLUDE_UNZIP 0 +#define INCLUDE_ETHERNET 0 +#define INCLUDE_ICMP 0 +#define INCLUDE_TFTP 0 +#define INCLUDE_TFS 0 +#define INCLUDE_FLASH 0 +#define INCLUDE_LINEEDIT 0 +#define INCLUDE_DHCPBOOT 0 +#define INCLUDE_TFSAPI 0 +#define INCLUDE_TFSSYMTBL 0 +#define INCLUDE_TFSSCRIPT 0 +#define INCLUDE_TFSCLI 0 +#define INCLUDE_EE 0 +#define INCLUDE_GDB 0 +#define INCLUDE_STRACE 0 +#define INCLUDE_CAST 0 +#define INCLUDE_STRUCT 0 +#define INCLUDE_REDIRECT 0 +#define INCLUDE_QUICKMEMCPY 0 +#define INCLUDE_PROFILER 0 +#define INCLUDE_BBC 0 +#define INCLUDE_MEMTRACE 0 +#define INCLUDE_STOREMAC 0 +#define INCLUDE_VERBOSEHELP 0 +#define INCLUDE_HWTMR 0 +#define INCLUDE_PORTCMD 0 +#define INCLUDE_USRLVL 0 + +/* Some fine tuning (if needed)... + * If these #defines are not in config.h, they default to '1' in + * various other include files within uMon source; hence, they're + * really only useful if you need to turn off ('0') the specific + * facility or block of code. + */ +#define INCLUDE_TFTPSRVR 0 +#define INCLUDE_ETHERVERBOSE 0 +#define INCLUDE_MONCMD 0 + +#include "inc_check.h" diff --git a/ports/template/cpu.h b/ports/template/cpu.h new file mode 100644 index 0000000..9d17721 --- /dev/null +++ b/ports/template/cpu.h @@ -0,0 +1,3 @@ +/* cpu.h: + */ +#define MONARGV0 "umon" diff --git a/ports/template/cpuio.c b/ports/template/cpuio.c new file mode 100644 index 0000000..0ce553b --- /dev/null +++ b/ports/template/cpuio.c @@ -0,0 +1,192 @@ +#include "config.h" +#include "stddefs.h" +#include "cpuio.h" +#include "genlib.h" +#include "cache.h" +#include "warmstart.h" +#include "timer.h" + +/* devInit(): + * As a bare minimum, initialize the console UART here using the + * incoming 'baud' value as the baud rate. + */ +void +devInit(int baud) +{ + /* ADD_CODE_HERE */ +} + +/* ConsoleBaudSet(): + * Provide a means to change the baud rate of the running + * console interface. If the incoming value is not a valid + * baud rate, then default to 9600. + * In the early stages of a new port this can be left empty. + * Return 0 if successful; else -1. + */ +int +ConsoleBaudSet(int baud) +{ + /* ADD_CODE_HERE */ + return(0); +} + +/* target_console_empty(): + * Target-specific portion of flush_console() in chario.c. + * This function returns 1 if there are no characters waiting to + * be put out on the UART; else return 0 indicating that the UART + * is still busy outputting characters from its FIFO. + * In the early stages of a new port this can simply return 1. + */ +int +target_console_empty(void) +{ + /* if (UART_OUTPUT_BUFFER_IS_EMPTY()) <- FIX CODE HERE */ + return(0); + return(1); +} + +/* target_putchar(): + * When buffer has space available, load the incoming character + * into the UART. + */ +int +target_putchar(char c) +{ + /* Wait for transmit ready bit */ + while(1) { + /* if (UART_IS_READY_FOR_CHARACTER()) <- FIX CODE HERE */ + break; + } + + /* ADD_CODE_HERE + * Put character into UART buffer here + */ + + return((int)c); +} + +/* target_gotachar(): + * Return 0 if no char is avaialable at UART rcv fifo; else 1. + * Do NOT pull character out of fifo, just return status. + * + * Define INCLUDE_BLINKLED in config.h and add STATLED_ON() + * and STATLED_OFF() macros (or functions) so that uMon will + * run and blink a target LED at a configured (or default 500msec) + * interval... + */ +int +target_gotachar(void) +{ +#if INCLUDE_BLINKLED + static uint8_t ledstate; + static struct elapsed_tmr tmr; + +#ifndef BLINKON_MSEC +#define BLINKON_MSEC 500 +#define BLINKOFF_MSEC 500 +#endif + + switch(ledstate) { + case 0: + startElapsedTimer(&tmr,BLINKON_MSEC); + ledstate = 1; + STATLED_ON(); + break; + case 1: + if(msecElapsed(&tmr)) { + STATLED_OFF(); + ledstate = 2; + startElapsedTimer(&tmr,BLINKOFF_MSEC); + } + break; + case 2: + if(msecElapsed(&tmr)) { + STATLED_ON(); + ledstate = 1; + startElapsedTimer(&tmr,BLINKON_MSEC); + } + break; + } +#endif + /* if (UART_INPUT_BUFFER_IS_NOT_EMPTY()) <- FIX CODE HERE */ + return(1); + return(0); +} + +/* target_getchar(): + * Assume there is a character in the UART's input buffer and just + * pull it out and return it. + */ +int +target_getchar(void) +{ + char c; + + /* c = GET_CHARACTER_FROM_UART(); <- FIX CODE HERE */ + return((int)c); +} + +/* intsoff(): + * Disable all system interrupts here and return a value that can + * be used by intsrestore() (later) to restore the interrupt state. + */ +ulong +intsoff(void) +{ + ulong status; + + /* ADD_CODE_HERE */ + return(status); +} + +/* intsrestore(): + * Re-establish system interrupts here by using the status value + * that was returned by an earlier call to intsoff(). + */ +void +intsrestore(ulong status) +{ + /* ADD_CODE_HERE */ +} + +/* cacheInitForTarget(): + * Establish target specific function pointers and + * enable i-cache... + * Refer to $core/cache.c for a description of the function pointers. + * NOTE: + * If cache (either I or D or both) is enabled, then it is important + * that the appropriate cacheflush/invalidate function be established. + * This is very important because programs (i.e. cpu instructions) are + * transferred to memory using data memory accesses and could + * potentially result in cache coherency problems. + */ +void +cacheInitForTarget(void) +{ + /* ADD_CODE_HERE */ +} + +/* target_reset(): + * The default (absolute minimum) action to be taken by this function + * is to call monrestart(INITIALIZE). It would be better if there was + * some target-specific function that would really cause the target + * to reset... + */ +void +target_reset(void) +{ + flushDcache(0,0); + disableDcache(); + invalidateIcache(0,0); + disableIcache(); + monrestart(INITIALIZE); +} + +/* If any CPU IO wasn't initialized in reset.S, do it here... + * This just provides a "C-level" IO init opportunity. + */ +void +initCPUio(void) +{ + /* ADD_CODE_HERE */ +} diff --git a/ports/template/cpuio.h b/ports/template/cpuio.h new file mode 100644 index 0000000..2021851 --- /dev/null +++ b/ports/template/cpuio.h @@ -0,0 +1,3 @@ +#define DEFAULT_BAUD_RATE 38400 + +#define MONARGV0 "umon" diff --git a/ports/template/etherdev.c b/ports/template/etherdev.c new file mode 100644 index 0000000..1271ecd --- /dev/null +++ b/ports/template/etherdev.c @@ -0,0 +1,247 @@ +/* template_etherdev.c: + * This is a "starter" file for the ethernet driver interface used by + * the monitor. The functions are described, but empty. + * At a minimum, code must be added in all places marked ADD_CODE_HERE. + * Additional OPT_ADD_CODE_HERE tags indicate locations that can be + * omitted, but would be nice to have additional facilities. + * + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Author: Ed Sutter + * email: esutter@lucent.com + * phone: 908-582-2351 + */ + +#include "config.h" +#include "genlib.h" +#include "stddefs.h" +#include "ether.h" + +#if INCLUDE_ETHERNET + +ulong tx_buff[400]; + +/* + * enreset(): + * Reset the PHY and MAC. + */ +void +enreset(void) +{ + /* ADD_CODE_HERE */ +} + +/* + * eninit(): + * Initialize the PHY and MAC. + * This would include establishing buffer descriptor tables and + * all the support code that will be used by the ethernet device. + * + * It can be assumed at this point that the array uchar BinEnetAddr[6] + * contains the 6-byte MAC address. + * + * Return 0 if successful; else -1. + */ +int +eninit(void) +{ + /* Initialize the Phy */ + /* ADD_CODE_HERE */ + + /* Query the PHY to determine if the link is up. + * If not just default to a 10Base-T, half-duplex interface config. + * If link is up, then attempt auto-negotiation. + */ + /* ADD_CODE_HERE */ + + /* Initialize the MAC */ + /* ADD_CODE_HERE */ + + return (0); +} + +int +EtherdevStartup(int verbose) +{ + /* Initialize local device error counts (if any) here. */ + /* OPT_ADD_CODE_HERE */ + + /* Put ethernet controller in reset: */ + enreset(); + + /* Initialize controller and return the value returned by + * eninit(). + */ + return(eninit()); +} + +/* disablePromiscuousReception(): + * Provide the code that disables promiscuous reception. + */ +void +disablePromiscuousReception(void) +{ + /* OPT_ADD_CODE_HERE */ +} + +/* enablePromiscuousReception(): + * Provide the code that enables promiscuous reception. + */ +void +enablePromiscuousReception(void) +{ + /* OPT_ADD_CODE_HERE */ +} + +/* disableBroadcastReception(): + * Provide the code that disables broadcast reception. + */ +void +disableBroadcastReception(void) +{ + /* ADD_CODE_HERE */ +} + +/* enableBroadcastReception(): + * Provide the code that enables broadcast reception. + */ +void +enableBroadcastReception(void) +{ + /* ADD_CODE_HERE */ +} + +/* + * enselftest(): + * Run a self test of the ethernet device(s). This can be stubbed + * with a return(1). + * Return 1 if success; else -1 if failure. + */ +int +enselftest(int verbose) +{ + return(1); +} + +/* ShowEtherdevStats(): + * This function is used to display device-specific stats (error counts + * usually). + */ +void +ShowEtherdevStats(void) +{ + /* OPT_ADD_CODE_HERE */ +} + +/* getXmitBuffer(): + * Return a pointer to the buffer that is to be used for transmission of + * the next packet. Since the monitor's driver is EXTREMELY basic, + * there will only be one packet ever being transmitted. No need to queue + * up transmit packets. + */ +uchar * +getXmitBuffer(void) +{ + /* ADD_CODE_HERE */ + return((uchar *)tx_buff); +} + +/* sendBuffer(): + * Send out the packet assumed to be built in the buffer returned by the + * previous call to getXmitBuffer() above. + */ +int +sendBuffer(int length) +{ +#if INCLUDE_ETHERVERBOSE + if (EtherVerbose & SHOW_OUTGOING) + printPkt((struct ether_header *)tx_buff,length,ETHER_OUTGOING); +#endif + + /* Bump up the packet length to a minimum of 64 bytes. + */ + if (length < 64) + length = 64; + + /* Add the code that will tickle the device into sending out the + * buffer that was previously returned by getXmitBuffer() above... + */ + /* ADD_CODE_HERE */ + + EtherXFRAMECnt++; + return(0); +} + +/* DisableEtherdev(): + * Fine as it is... + */ +void +DisableEtherdev(void) +{ + enreset(); +} + +/* extGetIpAdd(): + * If there was some external mechanism (other than just using the + * IPADD shell variable established in the monrc file) for retrieval of + * the board's IP address, then do it here... + */ +char * +extGetIpAdd(void) +{ + return((char *)0); +} + +/* extGetEtherAdd(): + * If there was some external mechanism (other than just using the + * ETHERADD shell variable established in the monrc file) for retrieval of + * the board's MAC address, then do it here... + */ +char * +extGetEtherAdd(void) +{ + return((char *)0); +} + +/* + * polletherdev(): + * Called continuously by the monitor (ethernet.c) to determine if there + * is any incoming ethernet packets. + * + * NOTES: + * 1. This function must be reentrant, because there are a few cases in + * processPACKET() where pollethernet() may be called. + * 2. It should only process one packet per call. This is important + * because if allowed to stay here to flush all available packets, + * it may starve the rest of the system (especially in cases of heavy + * network traffic). + * 3. There are cases in the monitor's execution that may cause the + * polling polletherdev() to cease for several seconds. Depending on + * network traffic, this may cause the input buffering mechanism on + * the ethernet device to overflow. A robust polletherdev() function + * should support this gracefully (i.e. when the error is detected, + * attempt to pass all queued packets to processPACKET(), then do what + * is necessary to clear the error). + */ +int +polletherdev(void) +{ + uchar *pktbuf = (char *)0; + int pktlen = 0, pktcnt = 0; + + if (PACKET_AVAILABLE()) { + GET_PACKET_FROM_DEVICE(); + processPACKET((struct ether_header *)pktbuf, pktlen); + pktcnt++; + } + return(pktcnt); +} + +#endif diff --git a/ports/template/except_template.c b/ports/template/except_template.c new file mode 100644 index 0000000..7e74ba8 --- /dev/null +++ b/ports/template/except_template.c @@ -0,0 +1,78 @@ +/* except_template.c: + * This code handles exceptions that are caught by the exception vectors + * that have been installed by the monitor through vinit(). It is likely + * that there is already a version of this function available for the CPU + * being ported to, so check the cpu directory prior to porting this to a + * new target. + * + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Author: Ed Sutter + * email: esutter@lucent.com + * phone: 908-582-2351 + */ +#include "config.h" +#include "cpu.h" +#include "cpuio.h" +#include "genlib.h" +#include "stddefs.h" +#include "warmstart.h" + +ulong ExceptionAddr; +int ExceptionType; + +/* exception(): + * This is the first 'C' function called out of a monitor-installed + * exception handler. + */ +void +exception(void) +{ + /* ADD_CODE_HERE */ + + /* Populating these two values is target specific. + * Refer to other target-specific examples for details. + * In some cases, these values are extracted from registers + * already put into the register cache by the lower-level + * portion of the exception handler in vectors_template.s + */ + ExceptionAddr = 0; + ExceptionType = 0; + + /* Allow the console uart fifo to empty... + */ + flush_console_out(); + monrestart(EXCEPTION); +} + +/* vinit(): + * This function is called by init1() at startup of the monitor to + * install the monitor-based vector table. The actual functions are + * in vectors.s. + */ +void +vinit() +{ + /* ADD_CODE_HERE */ +} + +/* ExceptionType2String(): + * This function simply returns a string that verbosely describes + * the incoming exception type (vector number). + */ +char * +ExceptionType2String(int type) +{ + char *string; + + /* ADD_CODE_HERE */ + return(string); +} + diff --git a/ports/template/flashtest.scr b/ports/template/flashtest.scr new file mode 100755 index 0000000..c45f8c5 --- /dev/null +++ b/ports/template/flashtest.scr @@ -0,0 +1,122 @@ +# flashtest.scr: +# This script can be run after a port is completed to verify +# that the flash driver can properly deal with various address +# and data alignments. +# +# Required shell variables: SECTORBASE & SNUM ... +# +# SECTORBASE: set to the base address of some sector within +# TFS that can be erased during this test. +# SNUM: the number of the sector whose base address is +# $SECTORBASE. +# NOLOCK: set to TRUE if the flash driver doesn't support flash +# lock/unlock + +if $SECTORBASE seq \$SECTORBASE goto USAGE +if $SNUM seq \$SNUM goto USAGE + +# Copy SECTORBASE to SBASE, and APPRAMBASE to SRC +set SBASE $SECTORBASE +set SRC $APPRAMBASE + +# TEST1: +echo TEST1: +echo Verify pattern +# Establish a few known bytes of source data: +pm $SRC 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a +set SRC=hex($SRC+8) +pm $SRC 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a 0x2a +dm $APPRAMBASE 16 +set SRC $APPRAMBASE + +# Unlock and erase the sector and verify erasure +# (should be all 0xff): +gosub FLASH_UNLOCK +flash erase $SNUM +dm $SBASE 16 +set SIZE 16 + +# LOOP: +if $SIZE eq 0 goto NEXTLOOP +gosub FLASHTEST +set SBASE=hex($SBASE+1) +set SRC=hex($SRC+1) +set SIZE=hex($SIZE-2) +goto LOOP + +# NEXTLOOP: +set SRC $APPRAMBASE +set SBASE $SECTORBASE +set SIZE 8 +# LOOP2: +if $SIZE eq 0 goto TEST2 +gosub FLASHTEST +set SIZE=hex($SIZE-1) +goto LOOP2 + +# FLASHTEST +flash write $SBASE $SRC $SIZE +dm $SECTORBASE 16 +flash erase $SNUM +dm $SECTORBASE 16 +return + +# TEST2: +# Write a few known initial bytes of data with 0xff's within +# the data... +echo TEST2: +pm $APPRAMBASE 0x41 0xff 0xff 0x44 0x45 0xff 0x47 0x48 +flash write $SECTORBASE $APPRAMBASE 8 + +# Then try to insert data into the fields that were +# originally 0xff... +pm $APPRAMBASE 0x42 0x43 +set ADDR=hex($SECTORBASE+1) +flash write $ADDR $APPRAMBASE 2 + +pm $APPRAMBASE 0x46 +set ADDR=hex($SECTORBASE+5) +flash write $ADDR $APPRAMBASE 1 + +# Now make sure the write worked... +pm $APPRAMBASE 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 +echo Next two lines of data should match... +dm $SECTORBASE 8 +dm $APPRAMBASE 8 +cm -v $APPRAMBASE $SECTORBASE 8 +flash erase $SNUM + +##################### +# +# TEST 3: +echo TEST3: +if $NOLOCK seq TRUE exit +echo Verify that a locked sector will not write or erase: +set SCRIPT_IGNORE_ERROR TRUE +flash write $SECTORBASE $APPRAMBASE 1 +flash lock $SNUM +dm $SECTORBASE 16 +echo This line should generate a flash write error... +flash write $SECTORBASE $APPRAMBASE 16 +dm $SECTORBASE 16 +echo This erase should fail... +flash erase $SNUM +gosub FLASH_UNLOCK +echo This erase should succeed... +flash erase $SNUM +dm $SECTORBASE 16 + +exit + +# FLASH_UNLOCK: +if $NOLOCK seq TRUE return +flash unlock $SNUM +return + +# FLASH_LOCK: +if $NOLOCK seq TRUE return +flash lock $SNUM +return + +# USAGE: +echo Establish SECTORBASE and SNUM, then rerun. diff --git a/ports/template/makefile b/ports/template/makefile new file mode 100644 index 0000000..b808f97 --- /dev/null +++ b/ports/template/makefile @@ -0,0 +1,212 @@ +############################################################################### +# +# MicroMonitor Release 1.0 template board makefile. +# +# This file can be used as a starting point for a new port makefile. +# Structurally, this makefile should work for all ports, so the majority +# of the changes will be to modify the content of variables already defined. +# If you are transitioning to release 1.0 of MicroMonitor from an earlier +# verion, refer to the OLD_TO_NEW.txt file for a set of conversion steps. +# +# The VERY FIRST ERROR that this makefile is likely to generate will +# be due to the fact that the UMONTOP shell variable is either missing +# or not properly specified. Make sure you start off by setting +# the UMONTOP variable to be set to the full path of the umon_main +# directory which contains all of the common source code for both target +# and host related builds for uMon. +# +# This template defaults to use a ppc-elf- GCC tool prefix. Refer to +# CPUTYPE & FILETYPE variables below to change that. +# +############################################################################### +# +# Build Variables: +# TOPDIR: +# Set to the content of UMONTOP, which is an externally defined +# shell variable assumed by this environment to be set to the full +# path of the umon_main directory. +# PLATFORM: +# ASCII name of the target platform (e.g. "Cogent CSB472") +# TGTDIR: +# The name of the working directory that this port is to be built in. +# CPUTYPE/FILETYPE: +# This combination of variables builds the GCC prefix (and is used for +# a few other purposes. +# Typical values for CPUTYPE are arm, ppc, m68k, mips and xscale. +# Typical values for FILETYPE are elf, coff, rtems and aout. +# CUSTOM_FLAGS: +# Establish the custom portion of the 'C' flags used for cross-compilation. +# Refer to the file $(UMONTOP)/target/make/common.make for the set of +# variables used (in addition to this one) to build the final CFLAGS +# variable. +# CUSTOM_AFLAGS: +# Similar to CUSTOM_FLAGS, this is used for assembler files. +# CUSTOM_INCLUDE: +# Used to specify port-specific additions to the INCLUDES list. +# +PLATFORM = TEMPLATE +TOPDIR = $(UMONTOP) +TGTDIR = template +CPUTYPE = arm +FILETYPE = elf +CUSTOM_CFLAGS = +CUSTOM_AFLAGS = +CUSTOM_INCLUDE = + +# Using tools installed by "sudo apt-get install gcc-arm-none-eabi"... +ABIDIR = /usr/lib/gcc/arm-none-eabi/4.8.2 +TOOL_PREFIX = /usr/bin/arm-none-eabi + +# If using something other than the Microcross model for the GNU +# tools (i.e. CPUTYPE-FILETYPE-TOOL) then specify the tool prefix +# here... (for example, powerpc-405-linux-gnu) +#TOOL_PREFIX = powerpc-405-linux-gnu + +############################################################################### +# +# Memory map configuration: +# The following variables are used to establish the system's memory map. +# The values associated with these variables are substituted into +# the .ldt (.ld template) files to generate the .ld files actually used +# for the final linkage. This allows the user to override these defaults +# without touching a memory map file. Adjust them appropriately based on +# the target memory map. +# +# BOOTRAMBASE/BOOTRAMLEN: +# BOOTROMBASE/BOOTROMLEN: +# Specify the base and length of RAM and ROM (i.e. flash) space used by +# the version of the monitor that will reside (and run out of) boot flash. +# RAMTSTBASE/RAMTSTLEN: +# Specify the base and length of RAM to be used by the "test" version of +# the monitor that will reside entirely in RAM. +BOOTRAMBASE=0x3000 +BOOTRAMLEN=0x7ffff +BOOTROMBASE=0xfff80000 +BOOTROMLEN=0x7ffff +RAMTSTBASE=0x200000 +RAMTSTLEN=0x7ffff + +# These next two hard-coded values are used by ram-based versions of +# uMon to allow them to know where these flash-based structures are located. +# Obviously the addresses are port-specific and are specified here for +# reference only. +MACADDRBASE=0xfff80000 +ALTTFSDEVTBLBASE=0xfff80020 + + +include $(TOPDIR)/target/make/common.make + +############################################################################### +# +# Build each variable from a list of individual filenames... +# +# LOCSSRC: +# Local (in this directory) assembler files. +# LOCCSRC: +# Local (in this directory) 'C' files. +# Note regarding except_xxx.c and strace_xxx.c... +# Prior to writing your processor-specific except_xxx.c and strace_xxx.c +# check the target's cpu directory to make sure it isn't already available. +# If available, then change the filenames accordingly and move them to +# the CPUCSRC filelist. If you need to develop them, build them in +# this port-specific directory, then upon completion they can be moved +# to the cpu-specific directory so that they can be used by other ports. +# CPUSSRC: +# CPU-specific assembler files in the main/target/cpu/CPU directory. +# CPUSSRC: +# CPU-specific 'C' files in the main/target/cpu/CPU directory. +# COMCSRC: +# Core 'C' files found in the main/target/core directory. +# IODEVSRC: +# Device-specific files found in main/target/dev directory. +# FLASHSRC: +# The flash driver file found in main/target/flash/devices directory. +# +LOCSSRC = reset.S +CPUSSRC = +LOCCSRC = cpuio.c etherdev.c except_template.c strace_template.c +COMCSRC = arp.c bbc.c cast.c cache.c chario.c cmdtbl.c crypt.c \ + docmd.c dhcp_00.c dhcpboot.c edit.c ee.c env.c ethernet.c \ + flash.c genlib.c icmp.c if.c ledit_vt100.c monprof.c \ + mprintf.c memcmds.c malloc.c moncom.c memtrace.c misccmds.c \ + misc.c password.c redirect.c reg_cache.c sbrk.c start.c \ + struct.c symtbl.c tcpstuff.c tfs.c tfsapi.c tfsclean1.c \ + tfscli.c \ + tfsloader.c tfslog.c tftp.c timestuff.c xmodem.c gdb.c +CPUCSRC = +IODEVSRC = +FLASHSRC = am29lv160d_16x1.c + +include $(TOPDIR)/target/make/objects.make + +OBJS = $(LOCSOBJ) $(CPUSOBJ) $(LOCCOBJ) $(CPUCOBJ) $(COMCOBJ) \ + $(FLASHOBJ) $(IODEVOBJ) + +######################################################################### +# +# Targets... + +# boot: +# The default target is "boot", a shortcut to $(BUILDDIR)/boot.$(FILETYPE). +# This builds the bootflash image that can be used by 'newmon' to +# load a new version onto an already running system. +# +boot: $(BUILDDIR)/boot.$(FILETYPE) + @echo Boot version of uMon built under $(BUILDDIR) ... + @ls $(BUILDDIR)/boot* + +# ramtst: +# A shortcut to $(BUILDDIR)/ramtst.$(FILETYPE). This is a version of uMon +# that resides strictly in RAM and is used for two main purposes: +# 1. To test new monitor features prior to burning the boot flash. +# 2. To be downloaded into the RAM space of a board that has no programmed +# boot flash. This provides a running monitor that can then accept +# an incoming bootflash image using 'newmon'. +# +ramtst: $(BUILDDIR)/ramtst.$(FILETYPE) + @echo Ram-resident test version of uMon built under $(BUILDDIR) ... + @ls $(BUILDDIR)/ramtst* + +$(BUILDDIR)/boot.$(FILETYPE): $(BUILDDIR) $(OBJS) libz.a libg.a makefile + $(MAKE_MONBUILT) + $(MAKE_LDFILE) \ + BOOTRAMBASE=$(BOOTRAMBASE) BOOTRAMLEN=$(BOOTRAMLEN) \ + BOOTROMBASE=$(BOOTROMBASE) BOOTROMLEN=$(BOOTROMLEN) + $(LINK) -e coldstart $(OBJS) monbuilt.o libz.a libg.a $(LIBGCC) + $(MAKE_BINARY) + $(MAKE_GNUSYMS) + +$(BUILDDIR)/ramtst.$(FILETYPE): $(BUILDDIR) $(OBJS) libz.a libg.a makefile + $(MAKE_MONBUILT) + $(MAKE_LDFILE) \ + RAMTSTBASE=$(RAMTSTBASE) RAMTSTLEN=$(RAMTSTLEN) \ + MACADDRBASE=$(MACADDRBASE) ALTTFSDEVTBLBASE=$(ALTTFSDEVTBLBASE) + $(LINK) -e coldstart $(OBJS) monbuilt.o libz.a libg.a $(LIBGCC) + $(MAKE_BINARY) + $(MAKE_GNUSYMS) + +include $(TOPDIR)/target/make/rules.make + +######################################################################### +# +# Miscellaneous... +# +###### +# +# cscope_local: +# Put additional files here that should be included in the cscope +# files list. This is called before the generic cscope file builder, +# so it should create the cscope.files file. +# +cscope_local: + echo $(CPUDIR)/regs_403.c >cscope.files + +###### +# +# help_local: +# Add text here as needed by the port. +# +help_local: + @echo "This template defaults to using ppc-elf as the tool prefix." + @echo "To override this default modify CPU & FILETYPE variables." + @echo diff --git a/ports/template/regnames.c b/ports/template/regnames.c new file mode 100644 index 0000000..4e4afd3 --- /dev/null +++ b/ports/template/regnames.c @@ -0,0 +1,10 @@ +/* This file is included by the common file reg_cache.c. + * The file included below is the table of register names. + * The purpose behind this multiple level of file inclusion is to allow + * the common file "reg_cache.c" to include a file called "regnames.c" + * which will have a target-specific register table without the target- + * specific filename. + * If the file specified below isn't correct, then check main/cpu/CPU for + * others. + */ +#include "regs_403.c" diff --git a/ports/template/reset.S b/ports/template/reset.S new file mode 100644 index 0000000..08ddf72 --- /dev/null +++ b/ports/template/reset.S @@ -0,0 +1,110 @@ +/* reset.s: + * + * First bit of boot code run by the processor. + * + */ + .file "reset.s" + + .extern start + .extern MonStack + .global reset + .global warmstart + .global coldstart + +#include "warmstart.h" + +/* Depending on the CPU, these entries may have to be shuffled + * around a bit. The position of coldstart is very CPU specific + * and the location of moncomptr should be in a place where it is + * unlikely to be moved if other monitor functionality is changed. + */ + +/********************************************************************* + * + * coldstart: + * The reset point. + */ +reset: +coldstart: + /* - Invalidate and disable caches + * - Load INITIALIZE (defined in warmstart.h) into whereever it + * needs to be put so that warmstart sees it as an argument + * passed to it. + * + * - Jump to warmstart + */ + +/********************************************************************* + * + * moncomptr: + * Pointer to the moncom function, used to link application to monitor. + * Refer to umon_main/target/core/moncomptr.S + */ +#include "moncomptr.S" + +/********************************************************************* + * + * etheraddr: + * Location that could be used to store a fixed MAC address. + * Refer to umon_main/target/core/etheraddr.S. + * NOTE: + * This should only be included in flash-resident code, then + * the address in flash should be accessible to ram-based versions of + * uMon via tags in the linker map file. + */ +#include "etheraddr.S" + +/********************************************************************* + * + * alttfsdevtbl.S: + * Location that could be used to store an "alternate" TFS device + * table for use by the "tfs cfg" command. + * Refer to umon_main/target/core/alttfsdevtbl.S. + * NOTE: + * This should only be included in flash-resident code, then + * the address in flash should be accessible to ram-based versions of + * uMon via tags in the linker map file. + */ +#include "alttfsdevtbl.S" + +/********************************************************************* + * + * warmstart: + * A point callable by C, as warmstart(int type), where + * 'type' is one of the values defined in warmstart.h. + */ +warmstart: + /* Minimal CPU/IO Initialization (i.e. chip selects) here. + * Stay in assembler here if possible. + */ + +/********************************************************************* + * + * SPInit: + * Establish a stack frame. + */ +SPInit: + /* First initialize stack to point to MonStack+MONSTACKSIZE+64 + * (an address that is outside the MonStack array), and then + * call stkinit(). This loads the MonStack[] array with a known + * pattern that allows uMon to later analyze the running stack usage. + */ + + /* Next, re-initialize stack to point to MonStack+MONSTACKSIZE... + * This is important because other portions of the code + * assume this is where the stack resides. + */ + +/********************************************************************* + * + * gotoC: + * This code jumps to the start() function in the monitor + * and should never return. + */ +gotoC: + /* - Retrieve the variable passed to warmstart and place it + * whereever it needs to be so that the start() function in + * 'C' sees it as an argument. Note that if FORCE_BSS_INIT + * is defined, then start() will ignore this argument. + * - Branch to start(). + */ diff --git a/ports/template/strace_template.c b/ports/template/strace_template.c new file mode 100644 index 0000000..38a44c0 --- /dev/null +++ b/ports/template/strace_template.c @@ -0,0 +1,116 @@ +/* strace.c: + * General notice: + * This code is part of a boot-monitor package developed as a generic base + * platform for embedded system designs. As such, it is likely to be + * distributed to various projects beyond the control of the original + * author. Please notify the author of any enhancements made or bugs found + * so that all may benefit from the changes. In addition, notification back + * to the author will allow the new user to pick up changes that may have + * been made by other users after this version of the code was distributed. + * + * Note1: the majority of this code was edited with 4-space tabs. + * Note2: as more and more contributions are accepted, the term "author" + * is becoming a mis-representation of credit. + * + * Original author: Ed Sutter + * Email: esutter@lucent.com + * Phone: 908-582-2351 + * + */ +#include "config.h" +#if INCLUDE_STRACE +#include "tfs.h" +#include "tfsprivate.h" +#include "ctype.h" +#include "genlib.h" +#include "stddefs.h" +#include "cpu.h" + +char *StraceHelp[] = { + "Stack trace", + "-[d:F:P:rs:v]", + " -d # max depth count (def=20)", + " -F # specify frame-pointer (don't use content of A6)", + " -P # specify PC (don't use content of PC)", + " -r dump regs", + " -v verbose", + 0, +}; + +int +Strace(int argc,char *argv[]) +{ + char *symfile, fname[64]; + TFILE *tfp; + ulong *framepointer, pc, fp, offset; + int tfd, opt, maxdepth, pass, verbose, bullseye; + + tfd = fp = 0; + maxdepth = 20; + verbose = 0; + pc = ExceptionAddr; + while ((opt=getopt(argc,argv,"d:F:P:rs:v")) != -1) { + switch(opt) { + case 'd': + maxdepth = atoi(optarg); + break; + case 'F': + fp = strtoul(optarg,0,0); + break; + case 'P': + pc = strtoul(optarg,0,0); + break; + case 'r': + showregs(); + break; + case 'v': + verbose = 1; + break; + default: + return(0); + } + } + + if (!fp) + getreg("A6", (ulong *)&framepointer); + else + framepointer = (ulong *)fp; + + /* Start by detecting the presence of a symbol table file... */ + symfile = getenv("SYMFILE"); + if (!symfile) + symfile = SYMFILE; + + tfp = tfsstat(symfile); + if (tfp) { + tfd = tfsopen(symfile,TFS_RDONLY,0); + if (tfd < 0) + tfp = (TFILE *)0; + } + + /* Show current position: */ + printf(" 0x%08lx",pc); + if (tfp) { + AddrToSym(tfd,pc,fname,&offset); + printf(": %s()",fname); + if (offset) + printf(" + 0x%lx",offset); + } + putchar('\n'); + + /* Now step through the stack frame... */ + bullseye = pass = 0; + while(maxdepth) { + /* ADD_CODE_HERE */ + } + + if (!maxdepth) + printf("Max depth termination\n"); + + if (tfp) { + tfsclose(tfd,0); + } + return(0); +} + +#endif diff --git a/ports/template/target_version.h b/ports/template/target_version.h new file mode 100644 index 0000000..fa728a7 --- /dev/null +++ b/ports/template/target_version.h @@ -0,0 +1,8 @@ +/* target_version.h: + * Initial version for all ports is zero. As the TARGET_VERSION incrments + * as a result of changes made to the target-specific code, this file should + * be used as an informal log of those changes for easy reference by others. + * + * 1->2: Added 'struct' command. + */ +#define TARGET_VERSION 2 diff --git a/ports/template/tfsdev.h b/ports/template/tfsdev.h new file mode 100644 index 0000000..541f3fb --- /dev/null +++ b/ports/template/tfsdev.h @@ -0,0 +1,36 @@ +/* tfsdev.h: + This file is ONLY included by tfs.c. It is seperate from tfs.h because + it is target-specific. It is not part of config.h because it includes + the declaration of the tfsdevtbl[]. + A prefix in the name of the file determines what device is used to store + that file. If no prefix is found the the first device in the table is + used as a default. The syntax of the prefix is "//STRING/" where STRING + is user-definable, but the initial // and final / are required by tfs + code. +*/ + +struct tfsdev tfsdevtbl[] = { + { + "//FLASH/", + TFSSTART, + TFSEND, + TFSSPARE, + TFSSPARESIZE, + TFSSECTORCOUNT, + TFS_DEVTYPE_FLASH }, + +#ifdef FLASHRAM_BASE + { + "//RAM/", + FLASHRAM_BASE, + FLASHRAM_END - FLASHRAM_SPARESIZE, + FLASHRAM_END - FLASHRAM_SPARESIZE + 1, + FLASHRAM_SPARESIZE, + FLASHRAM_SECTORCOUNT-1, + TFS_DEVTYPE_RAM | TFS_DEVINFO_AUTOINIT }, +#endif + + { 0, TFSEOT,0,0,0,0,0 } +}; + +#define TFSDEVTOT ((sizeof(tfsdevtbl))/(sizeof(struct tfsdev))) diff --git a/ports/template/xcmddcl.h b/ports/template/xcmddcl.h new file mode 100644 index 0000000..1057b07 --- /dev/null +++ b/ports/template/xcmddcl.h @@ -0,0 +1,14 @@ +/* xcmdtbl.h: + * This file must exist even if it is empty because it is #included in the + * common file cmdtbl.c. The purpose is to keep the common comand table + * file (common/cmdtbl.c) from being corrupted with non-generic commands + * that may be target specific. + * This is the declaration portion of the code that must be at the top of + * the cmdtbl[] array. + * + * For example... + +extern int date(); +extern char *dateHelp[]; + + */ diff --git a/ports/template/xcmdtbl.h b/ports/template/xcmdtbl.h new file mode 100644 index 0000000..ad74e63 --- /dev/null +++ b/ports/template/xcmdtbl.h @@ -0,0 +1,12 @@ +/* xcmdtbl.c: + * This file must exist even if it is empty because it is #included in the + * common file cmdtbl.c. The purpose is to keep the common comand table + * file (common/cmdtbl.c) from being corrupted with non-generic commands + * that may be target specific. + * It is the entry in the command table representing the new command being + * added to the cmdtbl[] array. + * For example: + +{"date", date, dateHelp, 0}, + + */ |