/******************************************************************************* **+--------------------------------------------------------------------------+** **| **** |** **| **** |** **| ******o*** |** **| ********_///_**** |** **| ***** /_//_/ **** |** **| ** ** (__/ **** |** **| ********* |** **| **** |** **| *** |** **| |** **| Copyright (c) 1998-2003 Texas Instruments Incorporated |** **| ALL RIGHTS RESERVED |** **| |** **| Permission is hereby granted to licensees of Texas Instruments |** **| Incorporated (TI) products to use this computer program for the sole |** **| purpose of implementing a licensee product based on TI products. |** **| No other rights to reproduce, use, or disseminate this computer |** **| program, whether in part or in whole, are granted. |** **| |** **| TI makes no representation or warranties with respect to the |** **| performance of this computer program, and specifically disclaims |** **| any responsibility for any damages, special or consequential, |** **| connected with the use of this program. |** **| |** **+--------------------------------------------------------------------------+** *******************************************************************************/ /******************************************************************************* * FILE PURPOSE: Environment variables routines. ******************************************************************************* * FILE NAME: env.c * * DESCRIPTION: Environment variables routines. * * (C) Copyright 2003, Texas Instruments, Inc ******************************************************************************/ #ifdef _STANDALONE #include #include #include #include #include #include #include #include "shell.h" #else #include "platform.h" #include "env.h" #include "flashop.h" #include "debug.h" #include "errno.h" #include "shell.h" #include "sysconf.h" #endif #define MAX_ENV_ENTRY (block_size/FLASH_ENV_ENTRY_SIZE) unsigned int strlen(const char *str); int strcmp(const char *A, const char *B); char *strcpy(char *DST, const char *SRC); typedef enum ENV_VARS { env_vars_start = 0, CPUFREQ, MEMSZ, FLASHSZ, MODETTY0, MODETTY1, PROMPT, BOOTCFG, HWA_0, #if !defined (AVALANCHE) || defined(TNETC401B) HWA_1, #endif HWA_RNDIS, #if defined (TNETD73XX_BOARD) HWA_3, #endif IPA, IPA_SVR, BLINE_MAC0, #if !defined (AVALANCHE) || defined(TNETC401B) BLINE_MAC1, #endif BLINE_RNDIS, #if defined (TNETD73XX_BOARD) BLINE_ATM, #endif USB_PID, USB_VID, USB_EPPOLLI, IPA_GATEWAY, SUBNET_MASK, #if defined (TNETV1050_BOARD) BLINE_ESWITCH, #endif USB_SERIAL, HWA_HRNDIS, /* Host (PC) side RNDIS address */ REMOTE_USER, REMOTE_PASS, REMOTE_DIR, SYSFREQ, LINK_TIMEOUT, #ifndef AVALANCHE /* Avalanche boards use only one mac port */ MAC_PORT, #endif PATH, HOSTNAME, #ifdef WLAN HW_REV_MAJOR, HW_REV_MINOR, HW_PATCH, SW_PATCH, SERIAL_NUMBER, #endif TFTPCFG, #if defined (TNETV1050_BOARD) HWA_ESWITCH, #endif /* * Add new env variables here. * NOTE: New environment variables should always be placed at the end, ie * just before env_vars_end. */ env_vars_end } ENV_VARS; typedef struct ENVDESC { ENV_VARS idx; char *nm; } ENVDESC; #define ENVSTR(x) #x #define _ENV_ENTRY(x) {x, ENVSTR(x)} ENVDESC env_ns[] = { _ENV_ENTRY(1), /* start. */ _ENV_ENTRY(CPUFREQ), _ENV_ENTRY(MEMSZ), _ENV_ENTRY(FLASHSZ), _ENV_ENTRY(MODETTY0), _ENV_ENTRY(MODETTY1), _ENV_ENTRY(PROMPT), _ENV_ENTRY(BOOTCFG), _ENV_ENTRY(HWA_0), #if !defined (AVALANCHE) || defined(TNETC401B) _ENV_ENTRY(HWA_1), #endif _ENV_ENTRY(HWA_RNDIS), #if defined (TNETD73XX_BOARD) _ENV_ENTRY(HWA_3), #endif _ENV_ENTRY(IPA), _ENV_ENTRY(IPA_SVR), _ENV_ENTRY(IPA_GATEWAY), _ENV_ENTRY(SUBNET_MASK), _ENV_ENTRY(BLINE_MAC0), #if !defined (AVALANCHE) || defined(TNETC401B) _ENV_ENTRY(BLINE_MAC1), #endif _ENV_ENTRY(BLINE_RNDIS), #if defined (TNETD73XX_BOARD) _ENV_ENTRY(BLINE_ATM), #endif _ENV_ENTRY(USB_PID), _ENV_ENTRY(USB_VID), _ENV_ENTRY(USB_EPPOLLI), #if defined (TNETV1050_BOARD) _ENV_ENTRY(BLINE_ESWITCH), #endif _ENV_ENTRY(USB_SERIAL), _ENV_ENTRY(HWA_HRNDIS), _ENV_ENTRY(REMOTE_USER), _ENV_ENTRY(REMOTE_PASS), _ENV_ENTRY(REMOTE_DIR), _ENV_ENTRY(SYSFREQ), _ENV_ENTRY(LINK_TIMEOUT), #ifndef AVALANCHE /* Avalanche boards use only one mac port */ _ENV_ENTRY(MAC_PORT), #endif _ENV_ENTRY(PATH), _ENV_ENTRY(HOSTNAME), #ifdef WLAN _ENV_ENTRY(HW_REV_MAJOR), _ENV_ENTRY(HW_REV_MINOR), _ENV_ENTRY(HW_PATCH), _ENV_ENTRY(SW_PATCH), _ENV_ENTRY(SERIAL_NUMBER), #endif _ENV_ENTRY(TFTPCFG), #if defined (TNETV1050_BOARD) _ENV_ENTRY(HWA_ESWITCH), #endif /* * Add new entries below this. */ _ENV_ENTRY(0) /* delimiter. */ }; /* TODO: remove this */ t_env_var env_vars[50]; char * envVersion = "TIENV0.6"; /* string size should be <= sizeof(ENV_VAR) */ #define ENV_CELL_SIZE 16 /* control field decode */ #define ENV_GARBAGE_BIT 0x01 /* Env is garbage if this bit is off */ #define ENV_DYNAMIC_BIT 0x02 /* Env is dynamic if this bit is off */ typedef struct ENV_VAR_t { unsigned char varNum; unsigned char ctrl; unsigned short chksum; unsigned char numCells; unsigned char data[ENV_CELL_SIZE - 5]; /* The data section starts here, continues for * numCells. */ }ENV_VAR; static unsigned int MaxEnvVarsNum; /* Holds count for the maximum * number of environment variable * that can be set. */ static PSBL_REC* psbl_rec = (PSBL_REC*)0x94000300; /* Exported APIs */ int sys_setenv (char* env_nm, char* env_val); char* sys_getenv (char* env_nm); void sh_printenv (void); int EnvInit (void); /* Internal functions */ static int IsPreDefinedVar(const char* var); /* Checks for variable in * pre-defined list. * Returns Index if found - else 0. * Please note: * ZERO is illegal index. */ int enter_critical_section(void); int exit_critical_section(void); /* Internal macros */ #define IsEnvGarbage(var) (((var)->ctrl & ENV_GARBAGE_BIT) == 0) #define IsEnvDynamic(var) (((var)->ctrl & ENV_DYNAMIC_BIT) == 0) #define EnvGetNextBlock(var) ((ENV_VAR*)( (char*)(var) + (var)->numCells * ENV_CELL_SIZE)) static int EnvMakeGarbage(ENV_VAR* pVar) { int status; enter_critical_section(); status = FWBOpen((int)&((pVar)->ctrl)); FWBWriteByte((int)&((pVar)->ctrl), (pVar)->ctrl & ~ENV_GARBAGE_BIT); FWBClose(); exit_critical_section(); return (status == 0); } static char* GetEnvBaseAndSize(unsigned int* size) { *size = psbl_rec->env_size; #ifdef ENV_SPACE_SIZE if(*size > ENV_SPACE_SIZE){ *size = ENV_SPACE_SIZE; } #endif return( (char *) psbl_rec->env_base); } #if ENV_DEBUG static int GetChecksum(ENV_VAR* var) { unsigned short chksum = 0; unsigned int tmp, i; chksum = var->varNum + var->numCells; tmp = strlen(var->data); if(IsEnvDynamic(var)) { tmp += strlen(var->data + tmp + 1) + 1; } for(i = 0; i < tmp; i++) { chksum += var->data[i]; } return chksum; } #endif static int IsPreDefinedVar(const char* var) { unsigned int ii; for (ii = 1; env_ns[ii].idx != 0; ii++){ /* check if the env variable is listed */ if (strcmp(env_ns[ii].nm, var) == 0) { if ( env_ns[ii].idx >= env_vars_end || env_ns[ii].idx <= env_vars_start) { return 0; } return env_ns[ii].idx; } } return 0; } static char* GetPreDefinedVarName(int index) { int ii; if ( index >= env_vars_end || index <= env_vars_start) { return NULL; } for(ii = 1; env_ns[ii].idx != 0; ii++) { if(env_ns[ii].idx == index) { return env_ns[ii].nm; } } return NULL; } /* Gives the nth non-garbage environment block. Indexed starting ZERO */ static ENV_VAR* GetEnvBlockByNumber(int index) { ENV_VAR* pVar; int count = 0, size; pVar = (ENV_VAR*)GetEnvBaseAndSize(&size); /* skip first block */ pVar++; enter_critical_section(); for(;pVar->varNum!=0xFF; pVar = EnvGetNextBlock(pVar)) { if(!IsEnvGarbage(pVar)) { if(count == index){ exit_critical_section(); return pVar; } else count++; } } exit_critical_section(); return NULL; } static void GetNameAndValueFromEnvVar(ENV_VAR* pVar, char** ppName, char** ppValue) { enter_critical_section(); if(IsEnvDynamic(pVar)) { *ppName = pVar->data; *ppValue = pVar->data + strlen(pVar->data) + 1; } else { *ppName = GetPreDefinedVarName(pVar->varNum); *ppValue = pVar->data; } exit_critical_section(); return; } /* returns the non-garbage block corresponding to the asked var. */ static ENV_VAR* GetEnvBlockByName(char *var) { ENV_VAR* pVar; int index = IsPreDefinedVar(var); int i; for(i = 0; i < MaxEnvVarsNum; i++) { if( !(pVar = GetEnvBlockByNumber(i)) ) return NULL; enter_critical_section(); if(index) { /* Pre-defined environment variables */ if(pVar->varNum == index) { exit_critical_section(); return pVar; } } else { /* Dynamic environment variables */ if(!strcmp(var, pVar->data)) { exit_critical_section(); return pVar; } } exit_critical_section(); } return NULL; } static int FormatEnvBlock(void) { unsigned int size, status, i; unsigned char* pFlash = GetEnvBaseAndSize(&size); #ifdef ENV_SPACE_SIZE char *pExtraSpace, *pTmp; if(!(pExtraSpace = _malloc(psbl_rec->env_size - size))) { return SBL_EFAILURE; } memset(pExtraSpace, 0xFF, psbl_rec->env_size - size); memcpy(pExtraSpace, (char*)psbl_rec->env_base + ENV_SPACE_SIZE, psbl_rec->env_size - size); #endif enter_critical_section(); status = FWBErase((unsigned int)pFlash, size, 0); FWBOpen((int)pFlash); for (i = 0; i <= strlen(envVersion) ;i++) { FWBWriteByte( (int)(pFlash++), envVersion[i]); } #ifdef ENV_SPACE_SIZE pFlash = (char*)psbl_rec->env_base + ENV_SPACE_SIZE; for (i = 0; i < psbl_rec->env_size - size ;i++) { FWBWriteByte( (int)(pFlash++), pExtraSpace[i]); } _free(pExtraSpace); #endif FWBClose(); exit_critical_section(); return status; } int EnvInit(void) { unsigned char* pFlash; unsigned int size; int status = 0; pFlash = GetEnvBaseAndSize(&size); MaxEnvVarsNum = (size)/(ENV_CELL_SIZE) - 1; /* Ignore the header */ if(strcmp(pFlash, envVersion) == 0) { /* TODO: Visit each environment variable and calculate the checksum. * If incorrect, mark as garbage */ } else { status = FormatEnvBlock(); } return(status == 0); } /* Returns: * SBL_SUCCESS: successfully configured. * SBL_ERESCRUNCH: env block is exhausted, env set failed. */ int sys_setenv(char *env_nm, char *env_val) { ENV_VAR *pVar, new, *pBase, *pOldEnv = NULL; unsigned int size, i, newsize; char *pTmp; #if (AUTO_DEFRAG_ENVIRONMENT == TRUE) int IsGarbagePresent = FALSE; #endif /* * CPUFREQ and SYSFREQ should not be modified */ #ifndef _STANDALONE if (strcmp("CPUFREQ", env_nm) == 0) { sys_printf("Env: CPUFREQ is read-only."); return SBL_EFAILURE; } if (strcmp("SYSFREQ", env_nm) == 0) { sys_printf("Env: SYSFREQ is read-only."); return SBL_EFAILURE; } #endif /* Check for pre-existance of the variable */ if((pTmp = sys_getenv(env_nm))) { /* Env Exists. See if the value to be set is same as old one */ if(!strcmp(pTmp, env_val)) { return SBL_SUCCESS; } /* Env Exists but is a different value. Make old one garbage */ pOldEnv = GetEnvBlockByName(env_nm); #if (AUTO_DEFRAG_ENVIRONMENT == TRUE) IsGarbagePresent = TRUE; #endif } pBase = pVar = (ENV_VAR*)GetEnvBaseAndSize(&size); /* skip first block */ pVar++; enter_critical_section(); /* Go to the end of Available Flash space */ for( ; pVar->varNum != 0xFF ; pVar = EnvGetNextBlock(pVar) ) { #if (AUTO_DEFRAG_ENVIRONMENT == TRUE) if(IsEnvGarbage(pVar)) { IsGarbagePresent = TRUE; } #endif } exit_critical_section(); #if ENV_DEBUG sys_printf("New Environment to be written at %x", pVar); #endif memset((char*)&new, 0xFF, sizeof(new)); if(!(new.varNum = IsPreDefinedVar(env_nm))) { /* Dynamic variable */ new.ctrl &= ~(ENV_DYNAMIC_BIT); } newsize = sizeof(ENV_VAR) - sizeof(new.data) + strlen(env_val) + 1; enter_critical_section(); if(IsEnvDynamic(&new)) { newsize += strlen(env_nm) + 1; } exit_critical_section(); new.numCells = ((newsize)/ENV_CELL_SIZE)+((newsize%ENV_CELL_SIZE)?1:0); if(((char*)pVar + (new.numCells*ENV_CELL_SIZE)) > ((char*)pBase + size)) { #if (AUTO_DEFRAG_ENVIRONMENT == TRUE) if(IsGarbagePresent){ sys_defragenv(); return sys_setenv(env_nm, env_val); } #endif sys_printf("Error: Out of Environment space\n"); return SBL_ERESCRUNCH; } #if ENV_DEBUG sys_printf("newsize = %d\n", newsize); sys_printf("new.numCells = %d\n", new.numCells); #endif enter_critical_section(); /* Write to flash */ FWBOpen((int)pVar); for(i = 0; i < sizeof(ENV_VAR) - sizeof(new.data); i++) { FWBWriteByte(((int)pVar)++, ((char*)&new)[i]); } if(IsEnvDynamic(&new)) { for(i = 0; i <= strlen(env_nm); i++) { FWBWriteByte(((int)pVar)++, env_nm[i]); } } for(i = 0; i <= strlen(env_val); i++) { FWBWriteByte(((int)pVar)++, env_val[i]); } FWBClose(); exit_critical_section(); if(pOldEnv) { EnvMakeGarbage(pOldEnv); } return SBL_SUCCESS; } int sys_unsetenv(char *env_nm) { ENV_VAR* pVar; if (strcmp("CPUFREQ", env_nm) == 0) { goto fail; } if (strcmp("SYSFREQ", env_nm) == 0) { goto fail; } if( !(pVar = GetEnvBlockByName(env_nm)) ) return SBL_EFAILURE; EnvMakeGarbage(pVar); return SBL_SUCCESS; fail: sys_printf("Env: %s is read-only.", env_nm); return SBL_EFAILURE; } void echo(int argc, char **argv) { int ii; if (argc == 1) { sh_printenv(); } else { if (strcmp(argv[1], "envlist") == 0) { sys_printf("Pre-defined Variable list:\n\n"); for ( ii = env_vars_start + 1; ii < env_vars_end; ii++) { sys_printf("%-13s\n", GetPreDefinedVarName(ii)); } } else { /* user gave some unsupported echo request */ sh_printenv(); } } } #ifndef _STANDALONE int FWBGet_flash_type(); int sys_initenv(void) { unsigned int size; #ifdef TNETV1050SDB FWBGet_flash_type(); #endif GetEnvBaseAndSize(&size); MaxEnvVarsNum = (size)/(ENV_CELL_SIZE) - 1; /* Ignore the header */ return TRUE; } #endif void sh_printenv(void) { ENV_VAR* pVar; int i; char *pName, *pValue; for(i = 0; i < MaxEnvVarsNum; i++) { if( !(pVar = GetEnvBlockByNumber(i)) ) goto out; #if ENV_DEBUG sys_printf("%s %x\n", "sh_printenv", pVar); #endif GetNameAndValueFromEnvVar(pVar, &pName, &pValue); sys_printf("\n%-13s\t%s", pName, pValue); } out: sys_printf("\n"); return; } char* sys_getenv(char *var) { ENV_VAR* pVar; char *pName, *pValue; if( !(pVar = GetEnvBlockByName(var)) ) return NULL; #if ENV_DEBUG sys_printf("%s %x\n", "sys_getenv", pVar); #endif GetNameAndValueFromEnvVar(pVar, &pName, &pValue); return pValue; } int sys_defragenv(void) { char **ppRamStore = NULL; char *pName, *pValue; unsigned int i; ENV_VAR* pVar; int defragFail=FALSE; if( !(ppRamStore = (char**)_malloc(sizeof(char*)*MaxEnvVarsNum)) ) { defragFail = TRUE; goto defragerror; } memset ((char*)ppRamStore, 0, sizeof(char*)*MaxEnvVarsNum); for(i = 0; i < MaxEnvVarsNum; i++) { if( !(pVar = GetEnvBlockByNumber(i)) ) continue; GetNameAndValueFromEnvVar(pVar, &pName, &pValue); if( !(ppRamStore[i] = _malloc(strlen(pName) + strlen(pValue) + 2)) ) { defragFail = TRUE; goto defragerror; } /* store name and value in RAM */ memcpy((char*)ppRamStore[i], pName, strlen(pName) + 1); memcpy((char*)ppRamStore[i] + strlen(pName) + 1, pValue,strlen(pValue) + 1); } FormatEnvBlock(); defragerror: for(i = 0; i < MaxEnvVarsNum; i++) { if(ppRamStore[i]) { sys_setenv(ppRamStore[i], ppRamStore[i]+strlen(ppRamStore[i]) + 1); _free(ppRamStore[i]); } } if(ppRamStore) { _free(ppRamStore); } if(defragFail) { sys_printf("Out of memory. Defragment aborted.\n"); return SBL_ERESCRUNCH; } return SBL_SUCCESS; } int get_envstring(int index, char *buffer) { ENV_VAR* pVar; if( !(pVar = GetEnvBlockByNumber(index)) ) return 0; #ifndef _STANDALONE /* OS context */ return sprintf(buffer, "%-13s\t%s\n", sys_getivar(index), sys_getienv(index)); #else return sys_sprintf(buffer, "%-20s %s\r\n", sys_getivar(index), sys_getienv(index)); #endif } char* sys_getienv(int var_num) { ENV_VAR* pVar; char* pName, *pValue; if( !(pVar = GetEnvBlockByNumber(var_num)) ) return 0; GetNameAndValueFromEnvVar(pVar, &pName, &pValue); return pValue; } char* sys_getivar (int var_num) { ENV_VAR* pVar; char* pName, *pValue; if( !(pVar = GetEnvBlockByNumber(var_num)) ) return 0; GetNameAndValueFromEnvVar(pVar, &pName, &pValue); return pName; }