diff options
author | root <root@lamia.panaceas.james.local> | 2015-12-19 13:13:57 +0000 |
---|---|---|
committer | root <root@lamia.panaceas.james.local> | 2015-12-19 14:18:03 +0000 |
commit | 1a2238d1bddc823df06f67312d96ccf9de2893cc (patch) | |
tree | c58a3944d674a667f133ea5a730f5037e57d3d2e /cfe/cfe/main | |
download | bootloader-1a2238d1bddc823df06f67312d96ccf9de2893cc.tar.gz bootloader-1a2238d1bddc823df06f67312d96ccf9de2893cc.tar.bz2 bootloader-1a2238d1bddc823df06f67312d96ccf9de2893cc.zip |
CFE from danitool [without hostTools dir]: https://mega.nz/#!mwZyFK7a!CPT3BKC8dEw29kubtdYxhB91G9vIIismTkgzQ3iUy3k
Diffstat (limited to 'cfe/cfe/main')
28 files changed, 11123 insertions, 0 deletions
diff --git a/cfe/cfe/main/cfe.mk b/cfe/cfe/main/cfe.mk new file mode 100644 index 0000000..05b16b6 --- /dev/null +++ b/cfe/cfe/main/cfe.mk @@ -0,0 +1,301 @@ + +# +# CFE's version number +# + +include ${TOP}/main/cfe_version.mk + +# +# Default values for certain parameters +# + +CFG_MLONG64 ?= 0 +CFG_LITTLE ?= 0 +CFG_RELOC ?= 0 +CFG_UNCACHED ?= 0 +CFG_NEWRELOC ?= 0 +CFG_BOOTRAM ?= 0 +CFG_VGACONSOLE ?= 0 +CFG_PCI ?= 1 +CFG_LDT_REV_017 ?= 0 +CFG_ZLIB ?= 0 +CFG_BIENDIAN ?= 0 +CFG_DOWNLOAD ?= 0 +CFG_RAMAPP ?= 0 +CFG_USB ?= 0 + +# +# Paths to other parts of the firmware. Everything's relative to ${TOP} +# so that you can actually do a build anywhere you want. +# + +ARCH_TOP = ${TOP}/arch/${ARCH} +ARCH_SRC = ${ARCH_TOP}/common/src +ARCH_INC = ${ARCH_TOP}/common/include +CPU_SRC = ${ARCH_TOP}/cpu/${CPU}/src +CPU_INC = ${ARCH_TOP}/cpu/${CPU}/include + +# +# It's actually optional to have a 'board' +# directory. If you don't specify BOARD, +# don't include the files. +# + +ifneq ("$(strip ${BOARD})","") +BOARD_SRC = ${ARCH_TOP}/board/${BOARD}/src +BOARD_INC = ${ARCH_TOP}/board/${BOARD}/include +endif + +# +# Preprocessor defines for CFE's version number +# + +VDEF = -DCFE_VER_MAJ=${CFE_VER_MAJ} -DCFE_VER_MIN=${CFE_VER_MIN} -DCFE_VER_ECO=${CFE_VER_ECO} + +# +# Construct the list of paths that will eventually become the include +# paths and VPATH +# + +SRCDIRS = ${ARCH_SRC} ${CPU_SRC} ${BOARD_SRC} ${TOP}/main ${TOP}/vendor ${TOP}/include ${TOP}/net ${TOP}/dev ${TOP}/pci ${TOP}/ui ${TOP}/lib ${TOP}/common ${TOP}/verif + +CFE_INC = ${TOP}/include ${TOP}/pci ${TOP}/net + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +SRCDIRS += ${TOP}/x86emu ${TOP}/pccons +CFE_INC += ${TOP}/x86emu ${TOP}/pccons +endif + +ifeq ($(strip ${CFG_VAPI}),1) +SRCDIRS += ${TOP}/verif +CFE_INC += ${TOP}/verif +endif + +ifeq ($(strip ${CFG_ZLIB}),1) +SRCDIRS += ${TOP}/zlib +CFE_INC += ${TOP}/zlib +endif + + +INCDIRS = $(patsubst %,-I%,$(subst :, ,$(ARCH_INC) $(CPU_INC) $(BOARD_INC) $(CFE_INC))) + +VPATH = $(SRCDIRS) + +# +# Bi-endian support: If we're building the little-endian +# version, use a different linker script so we can locate the +# ROM at a higher address. You'd think we could do this with +# normal linker command line switches, but there appears to be no +# command-line way to override the 'AT' qualifier in the linker script. +# + +CFG_TEXTAT1MB=0 +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),1) + CFG_TEXTAT1MB=1 + endif +endif + + +# +# Configure tools and basic tools flags. This include sets up +# macros for calling the C compiler, basic flags, +# and linker scripts. +# + +include ${ARCH_SRC}/tools.mk + +# +# Add some common flags that are used on any architecture. +# + +CFLAGS += -I. $(INCDIRS) +CFLAGS += -D_CFE_ ${VDEF} -DCFG_BOARDNAME=\"${CFG_BOARDNAME}\" + +# +# Gross - allow more options to be supplied from command line +# + +ifdef CFG_OPTIONS +OPTFLAGS = $(patsubst %,-D%,$(subst :, ,$(CFG_OPTIONS))) +CFLAGS += ${OPTFLAGS} +endif + + +# +# This is the makefile's main target. Note that we actually +# do most of the work in 'ALL' not 'all', since we include +# other makefiles after this point. +# + +all : build_date.c makereg pcidevs_data2.h ALL + +# +# Macros that expand to the list of arch-independent files +# + +DEVOBJS = dev_flash.o dev_newflash.o dev_null.o dev_promice.o \ + dev_ide_common.o dev_ns16550.o dev_ds17887clock.o +LIBOBJS = lib_malloc.o lib_printf.o lib_queue.o lib_string.o lib_string2.o \ + lib_arena.o lib_misc.o lib_setjmp.o lib_qsort.o lib_hssubr.o lib_physio.o +NETOBJS = net_ether.o net_arp.o net_ip.o net_udp.o net_api.o net_dns.o \ + net_dhcp.o net_tftp.o net_icmp.o net_tcp.o net_tcpbuf.o dev_tcpconsole.o +CFEOBJS = env_subr.o cfe_attach.o cfe_iocb_dispatch.o cfe_devfuncs.o \ + nvram_subr.o cfe_console.o cfe_main.o cfe_mem.o cfe_timer.o \ + cfe_background.o cfe_error.o build_date.o \ + cfe_rawfs.o cfe_zlibfs.o cfe_xreq.o cfe_fatfs.o cfe_httpfs.o cfe_filesys.o cfe_boot.o \ + cfe_autoboot.o cfe_ldr_elf.o cfe_ldr_raw.o cfe_ldr_srec.o cfe_loader.o url.o \ + cfe_savedata.o +UIOBJS = ui_command.o ui_cmddisp.o ui_envcmds.o ui_devcmds.o \ + ui_netcmds.o ui_tcpcmds.o ui_memcmds.o ui_loadcmds.o ui_pcicmds.o \ + ui_examcmds.o ui_flash.o ui_misccmds.o \ + ui_test_disk.o ui_test_ether.o ui_test_flash.o ui_test_uart.o + +# +# Add more object files if we're supporting PCI +# + +ifeq ($(strip ${CFG_PCI}),1) +PCIOBJS = pciconf.o ldtinit.o pci_subr.o +PCIOBJS += pci_devs.o +DEVOBJS += dev_sp1011.o dev_ht7520.o +DEVOBJS += dev_ide_pci.o dev_ns16550_pci.o +DEVOBJS += dev_tulip.o dev_dp83815.o +CFLAGS += -DCFG_PCI=1 +ifeq ($(strip ${CFG_LDT_REV_017}),1) +CFLAGS += -DCFG_LDT_REV_017=1 +endif +ifeq ($(strip ${CFG_DOWNLOAD}),1) +DEVOBJS += dev_bcm1250.o download.data +CFLAGS += -DCFG_DOWNLOAD=1 +endif +endif + +# +# If doing bi-endian, add the compiler switch to change +# the way the vectors are generated. These switches are +# only added to the big-endian portion of the ROM, +# which is located at the real boot vector. +# + +ifeq ($(strip ${CFG_BIENDIAN}),1) + ifeq ($(strip ${CFG_LITTLE}),0) + CFLAGS += -DCFG_BIENDIAN=1 + endif +endif + +# +# Include the makefiles for the architecture-common, cpu-specific, +# and board-specific directories. Each of these will supply +# some files to "ALLOBJS". The BOARD directory is optional +# as some ports are so simple they don't need boad-specific stuff. +# + +include ${ARCH_SRC}/Makefile +include ${CPU_SRC}/Makefile + +ifneq ("$(strip ${BOARD})","") +include ${BOARD_SRC}/Makefile +endif + +# +# Add the common object files here. +# + +ALLOBJS += $(LIBOBJS) $(DEVOBJS) $(CFEOBJS) $(VENOBJS) $(UIOBJS) $(NETOBJS) $(PCIOBJS) + +# +# VAPI continues to be a special case. +# + +ifeq ($(strip ${CFG_VAPI}),1) +include ${TOP}/verif/Makefile +endif + +# +# USB support +# + +ifeq ($(strip ${CFG_USB}),1) +SRCDIRS += ${TOP}/usb +CFE_INC += ${TOP}/usb +include ${TOP}/usb/Makefile +endif + +# +# If we're doing the VGA console thing, pull in the x86 emulator +# and the pcconsole subsystem +# + +ifeq ($(strip ${CFG_VGACONSOLE}),1) +include ${TOP}/x86emu/Makefile +include ${TOP}/pccons/Makefile +endif + +# +# If we're including ZLIB, then add its makefile. +# + +ifeq ($(strip ${CFG_ZLIB}),1) +include ${TOP}/zlib/Makefile +CFLAGS += -DCFG_ZLIB=1 -DMY_ZCALLOC -DNO_MEMCPY +endif + +# +# Vendor extensions come next - they live in their own directory. +# + +include ${TOP}/vendor/Makefile + +.PHONY : all +.PHONY : ALL +.PHONY : build_date.c + +# +# Build the local tools that we use to construct other source files +# + +mkpcidb : ${TOP}/hosttools/mkpcidb.c + gcc -o mkpcidb ${TOP}/hosttools/mkpcidb.c + +memconfig : ${TOP}/hosttools/memconfig.c + gcc -o memconfig -D_MCSTANDALONE_ -D_MCSTANDALONE_NOISY_ -I${TOP}/arch/mips/cpu/sb1250/include ${TOP}/hosttools/memconfig.c ${TOP}/arch/${ARCH}/cpu/${CPU}/src/sb1250_draminit.c + +pcidevs_data2.h : mkpcidb ${TOP}/pci/pcidevs_data.h + ./mkpcidb > pcidevs_data2.h + +mkflashimage : ${TOP}/hosttools/mkflashimage.c + gcc -o mkflashimage -I${TOP}/include ${TOP}/hosttools/mkflashimage.c + +pci_subr.o : ${TOP}/pci/pci_subr.c pcidevs_data2.h + +build_date.c : + echo "const char *builddate = \"`date`\";" > build_date.c + echo "const char *builduser = \"`whoami`@`hostname`\";" >> build_date.c + +# +# Make a define for the board name +# + +CFLAGS += -D_$(patsubst "%",%,${CFG_BOARDNAME})_ + +LIBCFE = libcfe.a + +%.o : %.c + $(GCC) $(CFLAGS) -o $@ $< + +%.o : %.S + $(GCC) $(CFLAGS) -o $@ $< + +# +# This rule constructs "libcfe.a" which contains most of the object +# files. +# + +$(LIBCFE) : $(ALLOBJS) + rm -f $(LIBCFE) + $(AR) cr $(LIBCFE) $(ALLOBJS) + $(RANLIB) $(LIBCFE) + + + diff --git a/cfe/cfe/main/cfe_attach.c b/cfe/cfe/main/cfe_attach.c new file mode 100644 index 0000000..1235d6e --- /dev/null +++ b/cfe/cfe/main/cfe_attach.c @@ -0,0 +1,265 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Device Attach routines File: cfe_attach.c + * + * This module manages the list of device drivers. When a driver + * is probed, it can call cfe_attach to create actual device + * instances. The routines in this module manage the + * device list and the assignment of device names. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_queue.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_device.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define CFE_MAX_DEVINST 64 /* max # of instances of devices */ + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +/* + * Our device list. + */ + +queue_t cfe_devices = {&cfe_devices, &cfe_devices}; + +/* ********************************************************************* + * cfe_finddev(name) + * + * Locate a device in the device list by its name and return + * a pointer to the device structure. + * + * Input parameters: + * name - name of device, e.g., "uart0" + * + * Return value: + * cfe_device_t pointer or NULL + ********************************************************************* */ + +cfe_device_t *cfe_finddev(char *name) +{ + queue_t *qb; + cfe_device_t *dev; + + for (qb = cfe_devices.q_next; qb != &cfe_devices; qb = qb->q_next) { + dev = (cfe_device_t *) qb; + if (strcmp(dev->dev_fullname,name) == 0) { + return dev; + } + } + + return NULL; +} + + +/* ********************************************************************* + * cfe_device_reset() + * + * Call all the "reset" methods in the devices on the device + * list. Note that the methods get called even when the + * devices are closed! + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_device_reset(void) +{ + queue_t *qb; + cfe_device_t *dev; + + for (qb = cfe_devices.q_next; qb != &cfe_devices; qb = qb->q_next) { + dev = (cfe_device_t *) qb; + if (dev->dev_dispatch->dev_reset) { + (*(dev->dev_dispatch->dev_reset))(dev->dev_softc); + } + } +} + +/* ********************************************************************* + * cfe_attach_idx(drv,idx,softc,bootinfo,description) + * + * Add a device to the device list at a specific index. This + * is mainly used for devices like SCSI disks or CD-ROMs so + * we can use an index that matches the target ID or LUN. + * + * Input parameters: + * drv - driver structure (from the device driver module) + * idx - requested index (e.g., uartn where 'n' is the idx) + * softc - Unique information maintained for this device + * bootinfo - suffix for long form of the device name. For + * example, scsi0.3.1 might mean SCSI controller + * 0, device ID 3, LUN 1. The bootinfo would be + * "3.1" + * description - something nice to say for the devices command + * + * Return value: + * 0 if device has already been added at this index + * <0 for other problems + * 1 if we were successful. + ********************************************************************* */ + +int cfe_attach_idx(cfe_driver_t *drv,int idx,void *softc, + char *bootinfo,char *description) +{ + char name[64]; + cfe_device_t *dev; + + xsprintf(name,"%s%d",drv->drv_bootname,idx); + + if (bootinfo) { + strcat(name,"."); + strcat(name,bootinfo); + } + + if (cfe_finddev(name) != NULL) { + return 0; + } + + dev = (cfe_device_t *) KMALLOC(sizeof(cfe_device_t),0); + if (!dev) return -1; + + dev->dev_fullname = strdup(name); + dev->dev_softc = softc; + dev->dev_class = drv->drv_class; + dev->dev_dispatch = drv->drv_dispatch; + dev->dev_description = description ? strdup(description) : NULL; + dev->dev_opencount = 0; + + q_enqueue(&cfe_devices,(queue_t *) dev); + + return 1; + +} + + + +/* ********************************************************************* + * cfe_attach(drv,softc,bootinfo,description + * + * Add a device to the system. This is a callback from the + * probe routine, and is used to actually add devices to CFE's + * device list. + * + * Input parameters: + * drv - driver structure (from the device driver module) + * softc - Unique information maintained for this device + * bootinfo - suffix for long form of the device name. For + * example, scsi0.3.1 might mean SCSI controller + * 0, device ID 3, LUN 1. The bootinfo would be + * "3.1" + * description - something nice to say for the devices command + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_attach(cfe_driver_t *drv,void *softc, + char *bootinfo, + char *description) +{ + int idx; + int res; + + /* + * Try device indicies 0..CFE_MAX_DEVINST to assign a unique + * device name for this device. This is a really braindead way to + * do this, but how many devices are we expecting anyway? + */ + + for (idx = 0; idx < CFE_MAX_DEVINST; idx++) { + + res = cfe_attach_idx(drv,idx,softc,bootinfo,description); + + if (res < 0) break; /* out of memory or other badness */ + if (res > 0) break; /* success! */ + /* otherwise, try again, slot is taken */ + } + +} + +/* ********************************************************************* + * cfe_attach_init() + * + * Initialize this module. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ +void cfe_attach_init(void) +{ + q_init(&(cfe_devices)); +} + + +/* ********************************************************************* + * cfe_device_name(ctx) + * + * Given a device context, return a device name + * + * Input parameters: + * ctx - context + * + * Return value: + * name + ********************************************************************* */ + +char *cfe_device_name(cfe_devctx_t *ctx) +{ + return ctx->dev_dev->dev_fullname; +} diff --git a/cfe/cfe/main/cfe_autoboot.c b/cfe/cfe/main/cfe_autoboot.c new file mode 100644 index 0000000..14f3d3c --- /dev/null +++ b/cfe/cfe/main/cfe_autoboot.c @@ -0,0 +1,456 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Automatic OS bootstrap File: cfe_autoboot.c + * + * This module handles OS bootstrap stuff. We use this version + * to do "automatic" booting; walking down a list of possible boot + * options, trying them until something good happens. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "env_subr.h" +#include "cfe.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_api.h" +#include "cfe_fileops.h" +#include "cfe_bootblock.h" +#include "bsp_config.h" +#include "cfe_boot.h" + +#include "cfe_loader.h" + +#include "cfe_autoboot.h" + +/* ********************************************************************* + * data + ********************************************************************* */ + +queue_t cfe_autoboot_list = {&cfe_autoboot_list,&cfe_autoboot_list}; + +extern cfe_loadargs_t cfe_loadargs; /* from cfe_boot.c */ +extern const char *bootvar_device; +extern const char *bootvar_file; +extern const char *bootvar_flags; + +extern char *varchars; + +/* ********************************************************************* + * macroexpand(instr,outstr) + * + * Expand environment variables in "instr" to "outstr" + * + * Input parameters: + * instr - to be expanded + * outstr - expanded. + * + * Return value: + * nothing + ********************************************************************* */ + +static void macroexpand(char *instr,char *outstr) +{ + char macroname[50]; + char *m; + + while (*instr) { + if (*instr == '$') { + instr++; + m = macroname; + while (*instr && strchr(varchars,*instr)) { + *m++ = *instr++; + } + *m = '\0'; + m = env_getenv(macroname); + if (m) { + while (*m) *outstr++ = *m++; + } + } + else { + *outstr++ = *instr++; + } + } + + *outstr = '\0'; +} + +/* ********************************************************************* + * cfe_tryauto_common(method,loadargs) + * + * Common portion of autoboot + * + * Input parameters: + * method - details on device to boot from + * filename - canonical name of file to load + * loadargs - cfe_loadargs_t of digested load parameters. + * + * Return value: + * does not return if successful + ********************************************************************* */ + +static int cfe_tryauto_common(cfe_autoboot_method_t *method, + char *filename, + cfe_loadargs_t *la) +{ + int res; + + la->la_filename = filename; + la->la_options = env_getenv(bootvar_flags); + la->la_filesys = method->ab_filesys; + la->la_device = method->ab_dev; + la->la_flags = method->ab_flags | LOADFLG_NOISY | LOADFLG_EXECUTE; + la->la_address = 0; + la->la_maxsize = 0; + la->la_entrypt = 0; + + /* okay, go for it. */ + + xprintf("Loader:%s Filesys:%s Dev:%s File:%s Options:%s\n", + method->ab_loader,la->la_filesys,la->la_device,la->la_filename,la->la_options); + + res = cfe_boot(method->ab_loader,&cfe_loadargs); + + return res; + +} + + +/* ********************************************************************* + * cfe_tryauto_network(method) + * + * Try to autoboot from a network device. + * + * Input parameters: + * method - details on device to boot from + * + * Return value: + * does not return unless there is an error + ********************************************************************* */ + +#if CFG_NETWORK +static int cfe_tryauto_network(cfe_autoboot_method_t *method) +{ + int res; + dhcpreply_t *reply = NULL; + cfe_loadargs_t *la = &cfe_loadargs; + char buffer[512]; + char *x; + + /* + * First turn off any network interface that is currently active. + */ + + net_uninit(); + + /* + * Now activate the network hardware. + */ + + res = net_init(method->ab_dev); + if (res < 0) { + printf("Could not initialize network device %s: %s\n", + method->ab_dev, + cfe_errortext(res)); + return res; + } + + /* + * Do a DHCP query. + */ + + res = dhcp_bootrequest(&reply); + if (res < 0) { + printf("DHCP request failed on device %s: %s\n",method->ab_dev, + cfe_errortext(res)); + net_uninit(); + return res; + } + + net_setparam(NET_IPADDR,reply->dr_ipaddr); + net_setparam(NET_NETMASK,reply->dr_netmask); + net_setparam(NET_GATEWAY,reply->dr_gateway); + net_setparam(NET_NAMESERVER,reply->dr_nameserver); + net_setparam(NET_DOMAIN,reply->dr_domainname); + + /* Set all our environment variables. */ + net_setnetvars(); + dhcp_set_envvars(reply); + + if (reply) dhcp_free_reply(reply); + + /* + * Interface is now configured and ready, we can + * load programs now. + */ + + /* + * Construct the file name to load. If the method does not + * specify a file name directly, get it from DHCP. + * + * For network booting, the format of the file name + * is 'hostname:filename' + * + * If the method's filename includes a hostname, ignore + * BOOT_SERVER. Otherwise, combine BOOT_SERVER with the + * filename. This way we can provide the name here + * but have the file come off the server specified in the + * DHCP message. + */ + + if (method->ab_file && strchr(method->ab_file,':')) { + macroexpand(method->ab_file,buffer); + } + else { + buffer[0] = '\0'; + x = env_getenv("BOOT_SERVER"); + if (x) { + strcat(buffer,x); + strcat(buffer,":"); + } + + x = method->ab_file; + if (!x) x = env_getenv(bootvar_file); + if (x) { + strcat(buffer,x); + } + } + + /* Okay, do it. */ + + cfe_tryauto_common(method,buffer,la); + + /* If we get here, something bad happened. */ + + net_uninit(); + + return res; + +} + +#endif + + +/* ********************************************************************* + * cfe_tryauto_disk(method) + * + * Try to autoboot from a disk device. + * + * Input parameters: + * method - details on device to boot from + * + * Return value: + * does not return unless there is an error + ********************************************************************* */ +static int cfe_tryauto_disk(cfe_autoboot_method_t *method) +{ + int res; + cfe_loadargs_t *la = &cfe_loadargs; + char buffer[512]; + char *filename; + + buffer[0] = '\0'; + + if (method->ab_file) { + macroexpand(method->ab_file,buffer); + filename = buffer; + } + else { + filename = env_getenv("BOOT_FILE"); + if (filename) strcpy(buffer,filename); + } + + res = cfe_tryauto_common(method,filename,la); + + return res; +} + +/* ********************************************************************* + * cfe_tryauto(method) + * + * Try a single autoboot method. + * + * Input parameters: + * method - autoboot method to try + * + * Return value: + * does not return if bootstrap is successful + * else error code + ********************************************************************* */ + +static int cfe_tryauto(cfe_autoboot_method_t *method) +{ + switch (method->ab_type) { +#if CFG_NETWORK + case CFE_AUTOBOOT_NETWORK: + return cfe_tryauto_network(method); + break; +#endif + + case CFE_AUTOBOOT_DISK: + case CFE_AUTOBOOT_RAW: + return cfe_tryauto_disk(method); + break; + } + + return -1; +} + +/* ********************************************************************* + * cfe_autoboot(dev,flags) + * + * Try to perform an automatic system bootstrap + * + * Input parameters: + * dev - if not NULL, restrict bootstrap to named device + * flags - controls behaviour of cfe_autoboot + * + * Return value: + * should not return if bootstrap is successful, otherwise + * error code + ********************************************************************* */ +int cfe_autoboot(char *dev,int flags) +{ + queue_t *qb; + cfe_autoboot_method_t *method; + int res; + cfe_timer_t timer; + int forever; + int pollconsole; + + forever = (flags & CFE_AUTOFLG_TRYFOREVER) ? 1 : 0; + pollconsole = (flags & CFE_AUTOFLG_POLLCONSOLE) ? 1 : 0; + + do { /* potentially forever */ + for (qb = cfe_autoboot_list.q_next; qb != &cfe_autoboot_list; qb = qb->q_next) { + + method = (cfe_autoboot_method_t *) qb; + + /* + * Skip other devices if we passed in a specific one. + */ + + if (dev && (strcmp(dev,method->ab_dev) != 0)) continue; + + printf("\n*** Autoboot: Trying device '%s' ", method->ab_dev); + if (method->ab_file) printf("file %s ",method->ab_file); + printf("(%s,%s)\n\n",method->ab_dev,method->ab_filesys,method->ab_loader); + + /* + * Scan keyboard if requested. + */ + if (pollconsole) { + TIMER_SET(timer,CFE_HZ); + while (!TIMER_EXPIRED(timer)) { + POLL(); + if (console_status()) goto done; + } + } + + /* + * Try something. may not return. + */ + + res = cfe_tryauto(method); + } + } while (forever); + + /* bail. */ +done: + + printf("\n*** Autoboot failed.\n\n"); + + return -1; +} + + +/* ********************************************************************* + * cfe_add_autoboot(type,flags,dev,loader,filesys,file) + * + * Add an autoboot method to the table. + * This is typically called in the board_finalinit one or more + * times to provide a list of bootstrap methods to try for autoboot + * + * Input parameters: + * type - CFE_AUTOBOOT_xxx (disk,network,raw) + * flags - loader flags (LOADFLG_xxx) + * loader - loader string (elf, raw, srec) + * filesys - file system string (raw, tftp, fat) + * file - name of file to load (if null, will try to guess) + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int cfe_add_autoboot(int type,int flags,char *dev,char *loader,char *filesys,char *file) +{ + cfe_autoboot_method_t *method; + + method = (cfe_autoboot_method_t *) KMALLOC(sizeof(cfe_autoboot_method_t),0); + + if (!method) return CFE_ERR_NOMEM; + + method->ab_type = type; + method->ab_flags = flags; + method->ab_dev = dev; + method->ab_loader = loader; + method->ab_filesys = filesys; + method->ab_file = file; + + q_enqueue(&cfe_autoboot_list,(queue_t *)method); + return 0; +} diff --git a/cfe/cfe/main/cfe_background.c b/cfe/cfe/main/cfe_background.c new file mode 100644 index 0000000..9a64e0a --- /dev/null +++ b/cfe/cfe/main/cfe_background.c @@ -0,0 +1,174 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Timer routines File: cfe_timer.c + * + * This module manages the list of routines to call periodically + * during "background processing." CFE has no interrupts or + * multitasking, so this is just where all the polling routines + * get called from. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" + +#include "cfe_timer.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define MAX_BACKGROUND_TASKS 16 + + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +static void (*cfe_bg_tasklist[MAX_BACKGROUND_TASKS])(void *); +static void *cfe_bg_args[MAX_BACKGROUND_TASKS]; + + +/* ********************************************************************* + * cfe_bg_init() + * + * Initialize the background task list + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_bg_init(void) +{ + memset(cfe_bg_tasklist,0,sizeof(cfe_bg_tasklist)); +} + + +/* ********************************************************************* + * cfe_bg_add(func,arg) + * + * Add a function to be called periodically in the background + * polling loop. + * + * Input parameters: + * func - function pointer + * arg - arg to pass to function + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_bg_add(void (*func)(void *x),void *arg) +{ + int idx; + + for (idx = 0; idx < MAX_BACKGROUND_TASKS; idx++) { + if (cfe_bg_tasklist[idx] == NULL) { + cfe_bg_tasklist[idx] = func; + cfe_bg_args[idx] = arg; + return; + } + } +} + +/* ********************************************************************* + * cfe_bg_remove(func) + * + * Remove a function from the background polling loop + * + * Input parameters: + * func - function pointer + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_bg_remove(void (*func)(void *)) +{ + int idx; + + for (idx = 0; idx < MAX_BACKGROUND_TASKS; idx++) { + if (cfe_bg_tasklist[idx] == func) break; + } + + if (idx == MAX_BACKGROUND_TASKS) return; + + for (; idx < MAX_BACKGROUND_TASKS-1; idx++) { + cfe_bg_tasklist[idx] = cfe_bg_tasklist[idx+1]; + cfe_bg_args[idx] = cfe_bg_args[idx+1]; + } + + cfe_bg_tasklist[idx] = NULL; + cfe_bg_args[idx] = NULL; +} + + +/* ********************************************************************* + * background() + * + * The main loop and other places that wait for stuff call + * this routine to make sure the background handlers get their + * time. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void background(void) +{ + int idx; + void (*func)(void *arg); + + for (idx = 0; idx < MAX_BACKGROUND_TASKS; idx++) { + func = cfe_bg_tasklist[idx]; + if (func == NULL) break; + (*func)(cfe_bg_args[idx]); + } +} diff --git a/cfe/cfe/main/cfe_boot.c b/cfe/cfe/main/cfe_boot.c new file mode 100644 index 0000000..12fecaa --- /dev/null +++ b/cfe/cfe/main/cfe_boot.c @@ -0,0 +1,248 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * OS bootstrap File: cfe_boot.c + * + * This module handles OS bootstrap stuff + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" + +#include "cfe_error.h" + +#include "env_subr.h" +#include "cfe.h" + +#include "net_ebuf.h" +#include "net_ether.h" + +#include "net_api.h" +#include "cfe_fileops.h" +#include "cfe_bootblock.h" +#include "bsp_config.h" +#include "cfe_boot.h" + +#include "cfe_loader.h" + +#if CFG_UI +extern int ui_docommands(char *buf); +#endif + +/* ********************************************************************* + * data + ********************************************************************* */ + +const char *bootvar_device = "BOOT_DEVICE"; +const char *bootvar_file = "BOOT_FILE"; +const char *bootvar_flags = "BOOT_FLAGS"; + +cfe_loadargs_t cfe_loadargs; + +/* ********************************************************************* + * splitpath(path,devname,filename) + * + * Split a path name (a boot path, in the form device:filename) + * into its parts + * + * Input parameters: + * path - pointer to path string + * devname - receives pointer to device name + * filename - receives pointer to file name + * + * Return value: + * nothing + ********************************************************************* */ + +void splitpath(char *path,char **devname,char **filename) +{ + char *x; + + *devname = NULL; + *filename = NULL; + + x = strchr(path,':'); + + if (!x) { + *devname = NULL; /* path consists of device name */ + *filename = path; + } + else { + *x++ = '\0'; /* have both device and file name */ + *filename = x; + *devname = path; + } +} + + +/* ********************************************************************* + * cfe_go(la) + * + * Starts a previously loaded program. cfe_loadargs.la_entrypt + * must be set to the entry point of the program to be started + * + * Input parameters: + * la - loader args + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_go(cfe_loadargs_t *la) +{ + if (la->la_entrypt == 0) { + xprintf("No program has been loaded.\n"); + return; + } + +#if CFG_NETWORK + if (!(la->la_flags & LOADFLG_NOCLOSE)) { + if (net_getparam(NET_DEVNAME)) { + xprintf("Closing network.\n"); + net_uninit(); + } + } +#endif + + xprintf("Starting program at 0x%p\n",la->la_entrypt); + + cfe_start(la->la_entrypt); +} + + +/* ********************************************************************* + * cfe_boot(la) + * + * Bootstrap the system. + * + * Input parameters: + * la - loader arguments + * + * Return value: + * error, or does not return + ********************************************************************* */ +int cfe_boot(char *ldrname,cfe_loadargs_t *la) +{ + int res; + + la->la_entrypt = 0; + + if (la->la_flags & LOADFLG_NOISY) { + xprintf("Loading: "); + } + + res = cfe_load_program(ldrname,la); + + if (res < 0) { + if (la->la_flags & LOADFLG_NOISY) { + xprintf("Failed.\n"); + } + return res; + } + + /* + * Special case: If loading a batch file, just do the commands here + * and return. For batch files we don't want to set up the + * environment variables. + */ + + if (la->la_flags & LOADFLG_BATCH) { +#if CFG_UI + ui_docommands((char *) la->la_entrypt); +#endif + return 0; + } + + /* + * Otherwise set up for running a real program. + */ + + if (la->la_flags & LOADFLG_NOISY) { + xprintf("Entry at 0x%p\n",la->la_entrypt); + } + + /* + * Set up the environment variables for the bootstrap + */ + + if (la->la_device) { + env_setenv(bootvar_device,la->la_device,ENV_FLG_BUILTIN); + } + else { + env_delenv(bootvar_device); + } + + if (la->la_filename) { + env_setenv(bootvar_file,la->la_filename,ENV_FLG_BUILTIN); + } + else { + env_delenv(bootvar_file); + } + + if (la->la_options) { + env_setenv(bootvar_flags,la->la_options,ENV_FLG_BUILTIN); + } + else { + env_delenv(bootvar_flags); + } + + /* + * Banzai! Run the program. + */ + + if ((la->la_flags & LOADFLG_EXECUTE) && + (la->la_entrypt != 0)) { + cfe_go(la); + } + + return 0; +} + diff --git a/cfe/cfe/main/cfe_console.c b/cfe/cfe/main/cfe_console.c new file mode 100755 index 0000000..a9464f1 --- /dev/null +++ b/cfe/cfe/main/cfe_console.c @@ -0,0 +1,1190 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Console Interface File: cfe_console.c + * + * This module contains high-level routines for dealing with + * the console (TTY-style) device. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include <stdarg.h> +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" +#include "cfe_error.h" +#include "env_subr.h" +#include "cfe_console.h" +#include "cfe.h" + +#include "bsp_config.h" + + +/* + * Escape sequences: + * + * Sequence Descr Emulator + * + * ESC [ A UP xterm + * ESC [ B DOWN xterm + * ESC [ C RIGHT xterm + * ESC [ D LEFT xterm + * + * ESC O P F1 xterm + * ESC O Q F2 xterm + * ESC O R F3 xterm + * ESC O S F4 xterm + * + * ESC [ 1 1 ~ F1 teraterm + * ESC [ 1 2 ~ F2 teraterm + * ESC [ 1 3 ~ F3 teraterm + * ESC [ 1 4 ~ F4 teraterm + * + * ESC [ 1 5 ~ F5 xterm,teraterm + * ESC [ 1 7 ~ F6 xterm,teraterm + * ESC [ 1 8 ~ F7 xterm,teraterm + * ESC [ 1 9 ~ F8 xterm,teraterm + * ESC [ 2 0 ~ F9 xterm,teraterm + * ESC [ 2 1 ~ F10 xterm,teraterm + * ESC [ 2 3 ~ F11 xterm,teraterm + * ESC [ 2 4 ~ F12 xterm,teraterm + * + * ESC [ 5 ~ PGUP xterm + * ESC [ 6 ~ PGDN xterm + * ESC [ F HOME xterm + * ESC [ H END xterm + * + * ESC [ 2 ~ HOME teraterm + * ESC [ 3 ~ PGUP teraterm + * ESC [ 5 ~ END teraterm + * ESC [ 6 ~ PGDN teraterm + * + */ + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + + +#define CTRL(x) ((x)-'@') + +#define GETCHAR(x) while (console_read(&(x),1) != 1) { POLL(); } + +#define XTERM 0 +#define TERATERM 1 + +#define MAXSAVELINES 30 +#define MSGQUEUEMAX 10 /* number of chunks of log to keep */ +#define MSGQUEUESIZE 256 /* size of each chunk of console log */ + + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +typedef struct msgqueue_s { /* saved console log message */ + queue_t link; + int len; + char data[MSGQUEUESIZE]; +} msgqueue_t; + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +#if !CFG_MINIMAL_SIZE +int console_nextsave = 0; +char *console_savedlines[MAXSAVELINES] = {0}; +static char *console_killbuffer = NULL; +queue_t console_msgq = {&console_msgq,&console_msgq}; +static int console_buffer_flg = 0; +static int console_mode = XTERM; + +static void console_flushbuffer(void); +static void console_save(unsigned char *buffer,int length); + +#endif + +#if defined(CONFIG_MIPS_BRCM) +int g_console_abort = 0; +#endif +int console_handle = -1; +static int console_xprint(const char *str); +char *console_name = NULL; +static int console_inreadline = 0; +static int console_redisplay = 0; + +/* ********************************************************************* + * console_log(tmplt,...) + * + * Sort of like printf, but used during things that might be + * called in the polling loop. If you print out a message + * using this call and it happens to be printed while processing + * the console "readline" loop, the readline and the associated + * prompt will be redisplayed. Don't include the \r\n in the + * string to be displayed. + * + * Input parameters: + * tmplt, ... - printf parameters + * + * Return value: + * nothing + ********************************************************************* */ + +void console_log(const char *tmplt,...) +{ + char buffer[256]; + va_list marker; + int count; + + va_start(marker,tmplt); + count = xvsprintf(buffer,tmplt,marker); + va_end(marker); + xprintf("\r%s\033[J\r\n",buffer); + + if (console_inreadline) console_redisplay = 1; +} + +/* ********************************************************************* + * console_open(name) + * + * Open the specified device and make it the console + * + * Input parameters: + * name - name of device + * + * Return value: + * 0 if ok, else return code. + * console_handle contains the console's handle + ********************************************************************* */ + +int console_open(char *name) +{ +#if CFG_MINIMAL_SIZE + if (console_handle != -1) { + console_close(); + } + + console_handle = cfe_open(name); + if (console_handle < 0) return CFE_ERR_DEVNOTFOUND; + +#else + + int flushbuf; + + console_name = NULL; + + if (console_handle != -1) { + console_close(); + } + + flushbuf = console_buffer_flg; + console_buffer_flg = 0; + + console_handle = cfe_open(name); + if (console_handle < 0) return CFE_ERR_DEVNOTFOUND; + + console_name = name; + if (flushbuf) console_flushbuffer(); +#endif + + return 0; +} + +/* ********************************************************************* + * console_close() + * + * Close the console device + * + * Input parameters: + * nothing + * + * Return value: + * 0 + ********************************************************************* */ + +int console_close(void) +{ + if (console_handle != -1) { + cfe_close(console_handle); + } + + console_handle = -1; + + return 0; +} + +/* ********************************************************************* + * console_read(buffer,length) + * + * Read characters from the console. + * + * Input parameters: + * buffer - pointer to buffer to receive characters + * length - total size of the buffer + * + * Return value: + * number of characters received, or <0 if error code + ********************************************************************* */ + +int console_read(char *buffer,int length) +{ + if (console_handle == -1) return -1; + + return cfe_read(console_handle,(unsigned char*)buffer,length); +} + + +/* ********************************************************************* + * console_write(buffer,length) + * + * Write text to the console. If the console is not open and + * we're "saving" text, put the text on the in-memory queue + * + * Input parameters: + * buffer - pointer to data + * length - number of characters to write + * + * Return value: + * number of characters written or <0 if error + ********************************************************************* */ + +int console_write(char *buffer,int length) +{ + int res; + +#if !CFG_MINIMAL_SIZE + /* + * Buffer text if requested + */ + if (console_buffer_flg) { + console_save(buffer,length); + return length; + } +#endif + + /* + * Do nothing if no console + */ + + if (console_handle == -1) return -1; + + /* + * Write text to device + */ + + for (;;) { + res = cfe_write(console_handle,(unsigned char*)buffer,length); + if (res < 0) break; + buffer += res; + length -= res; + if (length == 0) break; + } + + if (res < 0) return -1; + return 0; +} + +/* ********************************************************************* + * console_status() + * + * Return the status of input for the console. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if no characters are available + * 1 if characters are available. + ********************************************************************* */ + +int console_status(void) +{ + if (console_handle == -1) return 0; + + return cfe_inpstat(console_handle); +} + +/* ********************************************************************* + * console_xprint(str) + * + * printf callback for the console device. the "xprintf" + * routine ends up calling this. This routine also cooks the + * output, turning "\n" into "\r\n" + * + * Input parameters: + * str - string to write + * + * Return value: + * number of characters written + ********************************************************************* */ + +static int console_xprint(const char *str) +{ + int count = 0; + int len; + const char *p; + + /* Convert CR to CRLF as we write things out */ + + while ((p = strchr(str,'\n'))) { + console_write((char*)str,p-str); + console_write("\r\n",2); + count += (p-str); + str = p + 1; + } + + len = strlen(str); + console_write((char*)str, len); + count += len; + + return count; +} + + +/* ********************************************************************* + * console_readline_noedit(str,len) + * + * A simple 'gets' type routine for the console. We support + * backspace and carriage return. No line editing support here, + * this routine is used in places where we don't want it. + * + * Input parameters: + * prompt - prompt string + * str - pointer to user buffer + * len - length of user buffer + * + * Return value: + * number of characters read (terminating newline is not + * placed in the buffer) + ********************************************************************* */ + +int console_readline_noedit(char *prompt,char *str,int len) +{ + int reading = 1; + char ch; + int res = -1; + int idx = 0; + + console_inreadline++; + + if (prompt && *prompt) console_write(prompt,strlen(prompt)); + + POLL(); + while (reading) { + + /* + * If someone used console_log (above) or hit Control-C (below), + * redisplay the prompt and the string we've got so far. + */ + + if (console_redisplay) { + if (prompt && *prompt) console_write(prompt,strlen(prompt)); + console_write(str,idx); + console_redisplay = 0; + continue; + } + +#if defined(CONFIG_MIPS_BRCM) + + /* + * If a background process has set the global g_console_abort flag, stop + * reading from the keyboard. + */ + + if (g_console_abort) { + g_console_abort = 0; + break; + } + +#endif + + /* + * if nobody's typed anything, keep polling + */ + + if (console_status() == 0) { + POLL(); + continue; + } + + /* + * Get the char from the keyboard + */ + + res = console_read(&ch,1); + if (res < 0) break; + if (res == 0) continue; + + /* + * And dispatch it + */ + + switch (ch) { + case 3: /* Ctrl-C */ + console_write("^C\r\n",4); + console_redisplay = 1; + idx = 0; + break; + case 0x7f: + case '\b': + if (idx > 0) { + idx--; + console_write("\b \b",3); + } + break; + case 21: /* Ctrl-U */ + while (idx > 0) { + idx--; + console_write("\b \b",3); + } + break; + case '\r': + case '\n': + console_write("\r\n",2); + reading = 0; + break; + default: + if (ch >= ' ') { + if (idx < (len-1)) { + str[idx] = ch; + idx++; + console_write(&ch,1); + } + } + break; + } + } + POLL(); + + console_inreadline--; + + str[idx] = 0; + return idx; +} + + +/* ********************************************************************* + * cfe_set_console(name) + * + * This routine is usually called from the BSP's initialization + * module to set up the console device. We set the xprintf + * callback and open the console device. If we open a special + * magic console device (CFE_BUFFER_CONSOLE) the console subsystem + * will buffer text instead. A later call to cfe_set_console + * with a real console name will cause this text to be flushed. + * + * Input parameters: + * name - name of console device + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int cfe_set_console(char *name) +{ + xprinthook = console_xprint; + +#if !CFG_MINIMAL_SIZE + if (strcmp(name,CFE_BUFFER_CONSOLE) == 0) { + console_buffer_flg = 1; + return 0; + } +#endif + + if (name) { + int res; + res = env_setenv("BOOT_CONSOLE",name, + ENV_FLG_BUILTIN | ENV_FLG_READONLY | ENV_FLG_ADMIN); + return console_open(name); + } + return -1; +} + +#if !CFG_MINIMAL_SIZE + +/* ********************************************************************* + * console_flushbuffer() + * + * Flush queued (saved) console messages to the real console + * device. This is used if we need to delay console + * initialization until after other devices are initialized, + * for example, with a VGA console that won't work until + * after PCI initialization. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void console_flushbuffer(void) +{ + msgqueue_t *msg; + char *buffer; + int length; + int res; + + /* + * Remove console messages from the queue + */ + + while ((msg = (msgqueue_t *) q_deqnext(&console_msgq))) { + + buffer = msg->data; + length = msg->len; + res = 0; + + /* + * Write each message to the console + */ + + for (;;) { + res = cfe_write(console_handle,buffer,length); + if (res < 0) break; + buffer += res; + length -= res; + if (length == 0) break; + } + + /* + * Free the storage + */ + + KFREE(msg); + } +} + + +/* ********************************************************************* + * console_save(buffer,length) + * + * This is used when we want to generate console output + * before the device is initialized. The console_save + * routine saves a copy of the log messages in a queue + * for later retrieval when the console device is open. + * + * Input parameters: + * buffer - message text to save + * length - number of bytes + * + * Return value: + * nothing + ********************************************************************* */ + +static void console_save(unsigned char *buffer,int length) +{ + msgqueue_t *msg; + + /* + * Get a pointer to the last message in the queue. If + * it's full, preprare to allocate a new one + */ + + msg = (msgqueue_t *) console_msgq.q_prev; + if (q_isempty(&(console_msgq)) || (msg->len == MSGQUEUESIZE)) { + msg = NULL; + } + + /* + * Stuff characters into message chunks till we're done + */ + + while (length) { + + /* + * New chunk + */ + if (msg == NULL) { + + msg = (msgqueue_t *) KMALLOC(sizeof(msgqueue_t),0); + if (msg == NULL) return; + msg->len = 0; + q_enqueue(&console_msgq,(queue_t *) msg); + + /* + * Remove chunks to prevent chewing too much memory + */ + + while (q_count(&console_msgq) > MSGQUEUEMAX) { + msgqueue_t *dropmsg; + dropmsg = (msgqueue_t *) q_deqnext(&console_msgq); + if (dropmsg) KFREE(dropmsg); + } + } + + /* + * Save text. If we run off the end of the buffer, prepare + * to allocate a new one + */ + msg->data[msg->len++] = *buffer++; + length--; + if (msg->len == MSGQUEUESIZE) msg = NULL; + } +} + + +/* ********************************************************************* + * console_readnum(num,ch) + * + * Read digits from the console until we get a non-digit. This + * is used to process escape sequences like ESC [ digits ~ + * + * Input parameters: + * num - where to put returned number + * ch - pointer to character that starts sequence, returns + * character that terminated sequence + * + * Return value: + * nothing + ********************************************************************* */ + +static void console_readnum(int *num,char *ch) +{ + int total = 0; + + for (;;) { + total = (total * 10) + (*ch - '0'); + while (console_read(ch,1) != 1) { POLL(); } + if (!((*ch >= '0') && (*ch <= '9'))) break; + } + + *num = total; +} + + +/* ********************************************************************* + * console_readkey(void) + * + * Very simple ANSI escape sequence parser, returns virtual + * key codes for function keys, arrows, etc. + * + * Hold your lunch, three levels of nested switch statements! :-) + * + * Input parameters: + * nothing + * + * Return value: + * virtual key code + ********************************************************************* */ + +int console_readkey(void) +{ + unsigned char ch; + int num; + + GETCHAR(ch); + + switch (ch) { + case VKEY_ESC: + GETCHAR(ch); + switch (ch) { + case 'O': + GETCHAR(ch); + switch (ch) { + case 'P': + return VKEY_F1; + case 'Q': + return VKEY_F2; + case 'R': + return VKEY_F3; + case 'S': + return VKEY_F4; + } + return (int)ch; + + case '[': + GETCHAR(ch); + if ((ch >= '0') && (ch <= '9')) { + console_readnum(&num,&ch); + if (ch == '~') { + switch (num) { + case 2: + return VKEY_HOME; + case 3: + return VKEY_PGUP; + case 5: + if (console_mode == XTERM) return VKEY_PGUP; + return VKEY_END; + case 6: + if (console_mode == XTERM) return VKEY_PGDN; + return VKEY_PGDN; + case 11: + return VKEY_F1; + case 12: + return VKEY_F2; + case 13: + return VKEY_F3; + case 14: + return VKEY_F4; + case 15: + return VKEY_F5; + case 17: + return VKEY_F6; + case 18: + return VKEY_F7; + case 19: + return VKEY_F8; + case 20: + return VKEY_F9; + case 21: + return VKEY_F10; + case 23: + return VKEY_F11; + case 24: + return VKEY_F12; + } + return (int)ch; + } + } + else { + switch (ch) { + case 'A': + return VKEY_UP; + case 'B': + return VKEY_DOWN; + case 'C': + return VKEY_RIGHT; + case 'D': + return VKEY_LEFT; + case 'F': + return VKEY_HOME; + case 'H': + return VKEY_END; + default: + return (int) ch; + } + } + default: + return (int)ch; + + } + default: + return (int) ch; + } +} + + +/* ********************************************************************* + * console_xxx(...) + * + * Various small routines to write out cursor control sequences. + * + * Input parameters: + * # of iterations, if necessary + * + * Return value: + * nothing + ********************************************************************* */ + +static void console_backspace(int n) +{ + int t; + + for (t = 0; t < n; t++) console_write("\b",1); +} + +static void console_whiteout(int n) +{ + int t; + + for (t = 0; t < n; t++) console_write(" ",1); + for (t = 0; t < n; t++) console_write("\b",1); +} + + +static void console_eraseeol(void) +{ + console_write("\033[K",3); +} + +static void console_crlf(void) +{ + console_write("\r\n",2); +} + +/* ********************************************************************* + * console_readline(str,len) + * + * A simple 'gets' type routine for the console, with line + * editing support. + * + * Input parameters: + * prompt - prompt string + * str - pointer to user buffer + * len - length of user buffer + * + * Return value: + * number of characters read (terminating newline is not + * placed in the buffer) + ********************************************************************* */ + +int console_readline(char *prompt,char *str,int maxlen) +{ + int reading = 1; + int ch; + int idx = 0; + int len = 0; + int t; + int klen; + int recall; + int nosave = 0; + char *x; + char env[10]; + + console_inreadline++; + recall = console_nextsave; + + if (console_savedlines[console_nextsave]) { + KFREE(console_savedlines[console_nextsave]); + console_savedlines[console_nextsave] = NULL; + } + console_savedlines[console_nextsave] = strdup(""); + + if (prompt && *prompt) console_write(prompt,strlen(prompt)); + + POLL(); + while (reading) { + + /* + * If someone used console_log (above) or hit Control-C (below), + * redisplay the prompt and the string we've got so far. + */ + + if (console_redisplay) { + if (prompt && *prompt) console_write(prompt,strlen(prompt)); + console_write(str,idx); + console_redisplay = 0; + continue; + } + +#if defined(CONFIG_MIPS_BRCM) + + /* + * If a background process has set the global g_console_abort flag, stop + * reading from the keyboard. + */ + + if (g_console_abort) { + g_console_abort = 0; + break; + } + +#endif + + /* + * if nobody's typed anything, keep polling + */ + + if (console_status() == 0) { + POLL(); + continue; + } + + /* + * Get the char from the keyboard + */ + + ch = console_readkey(); + if (ch < 0) break; + if (ch == 0) continue; + + /* + * And dispatch it. Lots of yucky character manipulation follows + */ + + switch (ch) { + case CTRL('C'): /* Ctrl-C - cancel line */ + console_write("^C\r\n",4); + console_redisplay = 1; + nosave = 1; + idx = 0; + break; + + case 0x7f: /* Backspace, Delete */ + case CTRL('H'): + if (idx > 0) { + nosave = 0; + len--; + idx--; + console_write("\b",1); + if (len != idx) { + for (t = idx; t < len; t++) str[t] = str[t+1]; + console_write(&str[idx],len-idx); + console_whiteout(1); + console_backspace(len-idx); + } + else { + console_whiteout(1); + } + } + break; + + case CTRL('D'): /* Ctrl-D */ + if ((idx >= 0) && (len != idx)) { + nosave = 0; + len--; + for (t = idx; t < len; t++) str[t] = str[t+1]; + console_write(&str[idx],len-idx); + console_whiteout(1); + console_backspace(len-idx); + } + break; + + case CTRL('B'): /* cursor left */ + case VKEY_LEFT: + if (idx > 0) { + idx--; + console_backspace(1); + } + break; + + case CTRL('F'): /* cursor right */ + case VKEY_RIGHT: + if (idx < len) { + console_write(&str[idx],1); + idx++; + } + break; + + case CTRL('A'): /* cursor to BOL */ + console_backspace(idx); + idx = 0; + break; + + case CTRL('E'): /* cursor to EOL */ + if (len-idx > 0) console_write(&str[idx],len-idx); + idx = len; + break; + + case CTRL('K'): /* Kill to EOL */ + if (idx != len) { + str[len] = '\0'; + if (console_killbuffer) KFREE(console_killbuffer); + console_killbuffer = strdup(&str[idx]); + console_whiteout(len-idx); + len = idx; + nosave = 0; + } + break; + + case CTRL('Y'): /* Yank killed data */ + if (console_killbuffer == NULL) break; + klen = strlen(console_killbuffer); + if (klen == 0) break; + if (len + klen > maxlen) break; + nosave = 0; + for (t = len + klen; t > idx; t--) { + str[t-1] = str[t-klen-1]; + } + for (t = 0; t < klen; t++) str[t+idx] = console_killbuffer[t]; + len += klen; + console_write(&str[idx],len-idx); + idx += klen; + console_backspace(len-idx-1); + break; + + case CTRL('R'): /* Redisplay line */ + str[len] = 0; + console_crlf(); + console_write(prompt,strlen(prompt)); + console_write(str,len); + console_backspace(len-idx); + break; + + case CTRL('U'): /* Cancel line */ + console_backspace(idx); + console_eraseeol(); + if (len > 0) nosave = 1; + idx = 0; + len = 0; + break; + + case CTRL('M'): /* terminate */ + case CTRL('J'): + console_crlf(); + reading = 0; + break; + + case CTRL('P'): + case VKEY_UP: /* recall previous line */ + t = recall; + t--; + if (t < 0) t = MAXSAVELINES-1; + if (console_savedlines[t] == NULL) break; + recall = t; + console_backspace(idx); + strcpy(str,console_savedlines[recall]); + len = idx = strlen(console_savedlines[recall]); + console_eraseeol(); + console_write(str,len); + nosave = (t == ((console_nextsave - 1) % MAXSAVELINES)); + break; + + case CTRL('N'): + case VKEY_DOWN: /* Recall next line */ + t = recall; + t++; + if (t == MAXSAVELINES) t = 0; + if (console_savedlines[t] == NULL) break; + recall = t; + console_backspace(idx); + strcpy(str,console_savedlines[recall]); + len = idx = strlen(console_savedlines[recall]); + console_eraseeol(); + console_write(str,len); + nosave = 1; + break; + + case VKEY_F1: + case VKEY_F2: + case VKEY_F3: + case VKEY_F4: + case VKEY_F5: + case VKEY_F6: + case VKEY_F7: + case VKEY_F8: + case VKEY_F9: + case VKEY_F10: + case VKEY_F11: + case VKEY_F12: + sprintf(env,"F%d",ch-VKEY_F1+1); + x = env_getenv(env); + if (x) { + console_backspace(idx); + strcpy(str,x); + idx = len = strlen(str); + console_eraseeol(); + console_write(str,len); + console_crlf(); + reading = 0; + nosave = 1; + } + /* + * If F12 is undefined, it means "repeat last command" + */ + if (ch == VKEY_F12) { + t = recall; + t--; + if (t < 0) t = MAXSAVELINES-1; + if (console_savedlines[t] == NULL) break; + recall = t; + console_backspace(idx); + strcpy(str,console_savedlines[recall]); + len = idx = strlen(console_savedlines[recall]); + console_eraseeol(); + console_write(str,len); + console_crlf(); + reading = 0; + nosave = 1; + } + break; + + default: /* insert character */ + if (ch >= ' ') { + if (idx < (maxlen-1)) { + nosave = 0; + for (t = len; t > idx; t--) { + str[t] = str[t-1]; + } + str[idx] = ch; + len++; + if (len != idx) { + console_write(&str[idx],len-idx); + console_backspace(len-idx-1); + } + idx++; + } + } + break; + } + } + POLL(); + + console_inreadline--; + + str[len] = 0; + + if ((len != 0) && !nosave) { + if (console_savedlines[console_nextsave]) { + KFREE(console_savedlines[console_nextsave]); + } + console_savedlines[console_nextsave] = strdup(str); + console_nextsave++; + if (console_nextsave == MAXSAVELINES) console_nextsave = 0; + } + + return len; +} + +#else /* CFG_MINIMAL_SIZE */ +/* ********************************************************************* + * console_readline(str,len) + * + * A simple 'gets' type routine for the console, + * just calls the "noedit" variant for minimal code + * size builds. + * + * Input parameters: + * prompt - prompt string + * str - pointer to user buffer + * len - length of user buffer + * + * Return value: + * number of characters read (terminating newline is not + * placed in the buffer) + ********************************************************************* */ + +int console_readline(char *prompt,char *str,int len) +{ + return console_readline_noedit(prompt,str,len); +} + +#endif diff --git a/cfe/cfe/main/cfe_devfuncs.c b/cfe/cfe/main/cfe_devfuncs.c new file mode 100755 index 0000000..c3ab905 --- /dev/null +++ b/cfe/cfe/main/cfe_devfuncs.c @@ -0,0 +1,279 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Device Function stubs File: cfe_devfuncs.c + * + * This module contains device function stubs (small routines to + * call the standard "iocb" interface entry point to CFE). + * There should be one routine here per iocb function call. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" + +extern int cfe_iocb_dispatch(cfe_iocb_t *iocb); + +static int cfe_strlen(char *name) +{ + int count = 0; + + while (*name) { + count++; + name++; + } + + return count; +} + +int cfe_open(char *name) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_OPEN; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = 0; + iocb.plist.iocb_buffer.buf_ptr = (unsigned char*)name; + iocb.plist.iocb_buffer.buf_length = cfe_strlen(name); + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status < 0) ? iocb.iocb_status : iocb.iocb_handle; +} + +int cfe_close(int handle) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_CLOSE; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = 0; + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status); + +} + +int cfe_readblk(int handle,cfe_offset_t offset,unsigned char *buffer,int length) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_READ; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = offset; + iocb.plist.iocb_buffer.buf_ptr = buffer; + iocb.plist.iocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status < 0) ? iocb.iocb_status : iocb.plist.iocb_buffer.buf_retlen; +} + +int cfe_read(int handle,unsigned char *buffer,int length) +{ + return cfe_readblk(handle,0,buffer,length); +} + + +int cfe_writeblk(int handle,cfe_offset_t offset,unsigned char *buffer,int length) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_WRITE; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = offset; + iocb.plist.iocb_buffer.buf_ptr = buffer; + iocb.plist.iocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status < 0) ? iocb.iocb_status : iocb.plist.iocb_buffer.buf_retlen; +} + +int cfe_write(int handle,unsigned char *buffer,int length) +{ + return cfe_writeblk(handle,0,buffer,length); +} + + +int cfe_ioctl(int handle,unsigned int ioctlnum, + unsigned char *buffer,int length,int *retlen, + cfe_offset_t offset) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_IOCTL; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = offset; + iocb.plist.iocb_buffer.buf_ioctlcmd = (cfe_offset_t) ioctlnum; + iocb.plist.iocb_buffer.buf_ptr = buffer; + iocb.plist.iocb_buffer.buf_length = length; + + cfe_iocb_dispatch(&iocb); + + if (retlen) *retlen = iocb.plist.iocb_buffer.buf_retlen; + return iocb.iocb_status; +} + +int cfe_inpstat(int handle) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_INPSTAT; + iocb.iocb_status = 0; + iocb.iocb_handle = handle; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_inpstat_t); + iocb.plist.iocb_inpstat.inp_status = 0; + + cfe_iocb_dispatch(&iocb); + + if (iocb.iocb_status < 0) return iocb.iocb_status; + + return iocb.plist.iocb_inpstat.inp_status; + +} + +long long cfe_getticks(void) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_FW_GETTIME; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_time_t); + iocb.plist.iocb_time.ticks = 0; + + cfe_iocb_dispatch(&iocb); + + return iocb.plist.iocb_time.ticks; + +} + +int cfe_getenv(char *name,char *dest,int destlen) +{ + cfe_iocb_t iocb; + + *dest = NULL; + + iocb.iocb_fcode = CFE_CMD_ENV_GET; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_envbuf_t); + iocb.plist.iocb_envbuf.enum_idx = 0; + iocb.plist.iocb_envbuf.name_ptr = (unsigned char*)name; + iocb.plist.iocb_envbuf.name_length = strlen(name)+1; + iocb.plist.iocb_envbuf.val_ptr = (unsigned char*)dest; + iocb.plist.iocb_envbuf.val_length = destlen; + + cfe_iocb_dispatch(&iocb); + + return iocb.iocb_status; +} + +int cfe_exit(int warm,int code) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_FW_RESTART; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = warm ? CFE_FLG_WARMSTART : 0; + iocb.iocb_psize = sizeof(iocb_exitstat_t); + iocb.plist.iocb_exitstat.status = code; + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status); + +} + +int cfe_flushcache(int flg) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_FW_FLUSHCACHE; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = flg; + iocb.iocb_psize = 0; + + cfe_iocb_dispatch(&iocb); + + return iocb.iocb_status; +} + +int cfe_getdevinfo(char *name) +{ + cfe_iocb_t iocb; + + iocb.iocb_fcode = CFE_CMD_DEV_GETINFO; + iocb.iocb_status = 0; + iocb.iocb_handle = 0; + iocb.iocb_flags = 0; + iocb.iocb_psize = sizeof(iocb_buffer_t); + iocb.plist.iocb_buffer.buf_offset = 0; + iocb.plist.iocb_buffer.buf_ptr = (unsigned char*)name; + iocb.plist.iocb_buffer.buf_length = cfe_strlen(name); + + cfe_iocb_dispatch(&iocb); + + return (iocb.iocb_status < 0) ? iocb.iocb_status : (int)iocb.plist.iocb_buffer.buf_devflags; +} diff --git a/cfe/cfe/main/cfe_error.c b/cfe/cfe/main/cfe_error.c new file mode 100644 index 0000000..198e7a4 --- /dev/null +++ b/cfe/cfe/main/cfe_error.c @@ -0,0 +1,134 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Error strings File: cfe_error.h + * + * This file contains a mapping from error codes to strings + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "cfe.h" +#include "cfe_error.h" + +/* ********************************************************************* + * Types + ********************************************************************* */ + + +typedef struct errmap_s { + int errcode; + const char *string; +} errmap_t; + +/* ********************************************************************* + * Error code list + ********************************************************************* */ + +errmap_t cfe_errorstrings[] = { + {CFE_OK ,"No error"}, + {CFE_ERR ,"Error"}, + {CFE_ERR_INV_COMMAND ,"Invalid command"}, + {CFE_ERR_EOF ,"End of file reached"}, + {CFE_ERR_IOERR ,"I/O error"}, + {CFE_ERR_NOMEM ,"Insufficient memory"}, + {CFE_ERR_DEVNOTFOUND ,"Device not found"}, + {CFE_ERR_DEVOPEN ,"Device is open"}, + {CFE_ERR_INV_PARAM ,"Invalid parameter"}, + {CFE_ERR_ENVNOTFOUND ,"Environment variable not found"}, + {CFE_ERR_ENVREADONLY ,"Environment variable is read-only"}, + {CFE_ERR_NOTELF ,"Not an ELF-format executable"}, + {CFE_ERR_NOT32BIT ,"Not a 32-bit executable"}, + {CFE_ERR_WRONGENDIAN ,"Executable is wrong-endian"}, + {CFE_ERR_BADELFVERS ,"Invalid ELF file version"}, + {CFE_ERR_NOTMIPS ,"Not a MIPS ELF file"}, + {CFE_ERR_BADELFFMT ,"Invalid ELF file"}, + {CFE_ERR_BADADDR ,"Section would load outside available DRAM"}, + {CFE_ERR_FILENOTFOUND ,"File not found"}, + {CFE_ERR_UNSUPPORTED ,"Unsupported function"}, + {CFE_ERR_HOSTUNKNOWN ,"Host name unknown"}, + {CFE_ERR_TIMEOUT ,"Timeout occured"}, + {CFE_ERR_PROTOCOLERR ,"Network protocol error"}, + {CFE_ERR_NETDOWN ,"Network is down"}, + {CFE_ERR_NONAMESERVER ,"No name server configured"}, + {CFE_ERR_NOHANDLES ,"No more handles"}, + {CFE_ERR_ALREADYBOUND ,"Already bound"}, + {CFE_ERR_CANNOTSET ,"Cannot set network parameter"}, + {CFE_ERR_NOMORE ,"No more enumerated items"}, + {CFE_ERR_BADFILESYS ,"File system not recognized"}, + {CFE_ERR_FSNOTAVAIL ,"File system not available"}, + {CFE_ERR_INVBOOTBLOCK ,"Invalid boot block on disk"}, + {CFE_ERR_WRONGDEVTYPE ,"Device type is incorrect for boot method"}, + {CFE_ERR_BBCHECKSUM ,"Boot block checksum is invalid"}, + {CFE_ERR_BOOTPROGCHKSUM ,"Boot program checksum is invalid"}, + {CFE_ERR_LDRNOTAVAIL, "Loader is not available"}, + {CFE_ERR_NOTREADY, "Device is not ready"}, + {CFE_ERR_GETMEM, "Cannot get memory at specified address"}, + {CFE_ERR_SETMEM, "Cannot set memory at specified address"}, + {CFE_ERR_NOTCONN, "Socket is not connected"}, + {CFE_ERR_ADDRINUSE, "Address is in use"}, + {0,NULL}}; + + +/* ********************************************************************* + * cfe_errortext(err) + * + * Returns the text corresponding to a CFE error code + * + * Input parameters: + * err - error code + * + * Return value: + * string description of error + ********************************************************************* */ + +const char *cfe_errortext(int err) +{ + errmap_t *e = cfe_errorstrings; + + while (e->string) { + if (e->errcode == err) return e->string; + e++; + } + + return (const char *) "Unknown error"; +} + diff --git a/cfe/cfe/main/cfe_fatfs.c b/cfe/cfe/main/cfe_fatfs.c new file mode 100644 index 0000000..f2fa49f --- /dev/null +++ b/cfe/cfe/main/cfe_fatfs.c @@ -0,0 +1,1983 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * FAT file system File: cfe_fatfs.c + * + * This module knows how to read files from a FAT formatted + * file system (12 or 16 bit fats only for now) + * + * Eventually, we'll also include support for the FAT Translation + * Layer (FTL) on PCMCIA flash file systems. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" + +#include "cfe_loader.h" + +#include "cfe.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define SECTORSIZE 512 +#define DIRENTRYSIZE 32 +#define DIRPERSECTOR (SECTORSIZE/DIRENTRYSIZE) + +/*#define _FATFS_DEBUG_*/ + +/* + * Bios Parameter Block offsets and values + */ + +#define BPB_JMPINSTR 0x00 +#define BPB_JMPINSTR_VALUE 0xEB +#define BPB_JMPINSTR_VALUE2 0xE9 +#define BPB_SEAL 0x1FE +#define BPB_SEAL_VALUE 0xAA55 + +#define BPB_BYTESPERSECTOR 0x0B +#define BPB_SECTORSPERCLUSTER 0x0D +#define BPB_RESERVEDSECTORS 0x0E +#define BPB_NUMFATS 0x10 +#define BPB_MAXROOTDIR 0x11 +#define BPB_TOTALSECTORS 0x13 +#define BPB_SECTORSPERFAT 0x16 +#define BPB_SECTORSPERTRACK 0x18 +#define BPB_NUMHEADS 0x1A +#define BPB_HIDDENSECTORS 0x1C +#define BPB_SYSTEMID 54 +#define BPB_MEDIADESCRIPTOR 21 +#define BPB_SIGNATURE 38 +#define BPB_SIGNATURE_VALUE1 0x28 +#define BPB_SIGNATURE_VALUE2 0x29 + +/* + * Partition types + */ + +#define PARTTYPE_EMPTY 0 +#define PARTTYPE_FAT12 1 +#define PARTTYPE_FAT16 4 +#define PARTTYPE_FAT16BIG 6 +#define PARTTYPE_FAT32 0x0B + +/* + * Partition table offsets + */ +#define PTABLE_STATUS 0 +#define PTABLE_STARTHEAD 1 +#define PTABLE_STARTSECCYL 2 /* 2 bytes */ +#define PTABLE_TYPE 4 +#define PTABLE_ENDHEAD 5 +#define PTABLE_ENDSECCYL 6 /* 2 bytes */ +#define PTABLE_BOOTSECTOR 8 /* 4 bytes */ +#define PTABLE_NUMSECTORS 12 /* 4 bytes */ + +#define PTABLE_SIZE 16 +#define PTABLE_COUNT 4 +#define PTABLE_OFFSET (512-2-(PTABLE_COUNT*PTABLE_SIZE)) + +#define PTABLE_STATUS_ACTIVE 0x80 + +/* + * Directory attributes + */ + +#define ATTRIB_NORMAL 0x00 +#define ATTRIB_READONLY 0x01 +#define ATTRIB_HIDDEN 0x02 +#define ATTRIB_SYSTEM 0x04 +#define ATTRIB_LABEL 0x08 +#define ATTRIB_DIR 0x10 +#define ATTRIB_ARCHIVE 0x20 + +#define ATTRIB_LFN 0x0F + +/* + * Macros to read fields in directory & BPB entries + */ + +#define READWORD(buffer,x) (((unsigned int) (buffer)[(x)]) | \ + (((unsigned int) (buffer)[(x)+1]) << 8)) + +#define READWORD32(buffer,x) (READWORD(buffer,(x)) | (READWORD(buffer,(x)+2) << 16)) + +#define READBYTE(buffer,x) ((unsigned int) (buffer)[(x)]) + +/* + * Directory entry offsets and values + */ + +#define DIR_CHECKSUM 13 +#define DIR_FILELENGTH 28 +#define DIR_STARTCLUSTER 26 +#define DIR_ATTRIB 11 +#define DIR_NAMEOFFSET 0 +#define DIR_NAMELEN 8 +#define DIR_EXTOFFSET 8 +#define DIR_EXTLEN 3 + +#define DIRENTRY_CHECKSUM(e) READBYTE(e,DIR_CHECKSUM) +#define DIRENTRY_FILELENGTH(e) READWORD32(e,DIR_FILELENGTH) +#define DIRENTRY_STARTCLUSTER(e) READWORD(e,DIR_STARTCLUSTER) +#define DIRENTRY_ATTRIB(e) READBYTE(e,DIR_ATTRIB) + +#define DIRENTRY_LAST 0 +#define DIRENTRY_DELETED 0xE5 +#define DIRENTRY_PARENTDIR 0x2E + +#define DIRENTRY_LFNIDX(e) READBYTE(e,0) +#define LFNIDX_MASK 0x1F +#define LFNIDX_END 0x40 +#define LFNIDX_MAX 20 + +/* ********************************************************************* + * Types + ********************************************************************* */ + +/* + * Internalized BPB + */ + +typedef struct bpb_s { + unsigned int bpb_bytespersector; + unsigned int bpb_sectorspercluster; + unsigned int bpb_reservedsectors; + unsigned int bpb_numfats; + unsigned int bpb_maxrootdir; + unsigned int bpb_totalsectors; + unsigned int bpb_sectorsperfat; + unsigned int bpb_sectorspertrack; + unsigned int bpb_numheads; + unsigned int bpb_hiddensectors; +} bpb_t; + +/* + * FAT Filesystem descriptor - contains working information + * about an "open" file system + */ + +typedef struct fatfs_s { + int fat_fh; + int fat_refcnt; + bpb_t fat_bpb; + int fat_twelvebit; + int fat_partstart; + uint8_t fat_dirsector[SECTORSIZE]; + int fat_dirsecnum; + uint8_t fat_fatsector[SECTORSIZE]; + int fat_fatsecnum; +} fatfs_t; + +/* + * FAT Chain - describes a series of FAT entries + */ + +typedef struct fatchain_s { + int fat_start; + uint16_t *fat_entries; + int fat_count; +} fatchain_t; + +/* + * FAT File descriptor - contains working information + * about an open file (including the filesystem info) + */ + +typedef struct fatfile_s { + fatfs_t *ff_fat; + int ff_filelength; + fatchain_t ff_chain; + int ff_curpos; + int ff_cursector; + uint8_t ff_sector[SECTORSIZE]; +} fatfile_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int fatfs_fileop_xinit(void **fsctx,void *filename); +static int fatfs_fileop_pinit(void **fsctx,void *filename); +static int fatfs_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int fatfs_fileop_read(void *ref,uint8_t *buf,int len); +static int fatfs_fileop_write(void *ref,uint8_t *buf,int len); +static int fatfs_fileop_seek(void *ref,int offset,int how); +static void fatfs_fileop_close(void *ref); +static void fatfs_fileop_uninit(void *fsctx); + +static int fatfs_check_for_partition_table(fatfs_t *fatfs); + +/* ********************************************************************* + * FAT fileio dispatch table + ********************************************************************* */ + +/* + * Raw FAT (no partition table) - used only on floppies + */ + +const fileio_dispatch_t fatfs_fileops = { + "rfat", + LOADFLG_NOBB, + fatfs_fileop_xinit, + fatfs_fileop_open, + fatfs_fileop_read, + fatfs_fileop_write, + fatfs_fileop_seek, + fatfs_fileop_close, + fatfs_fileop_uninit +}; + +/* + * Partitioned FAT - used on Zip disks, removable hard disks, + * hard disks, flash cards, etc. + */ + +const fileio_dispatch_t pfatfs_fileops = { + "fat", + LOADFLG_NOBB, + fatfs_fileop_pinit, + fatfs_fileop_open, + fatfs_fileop_read, + fatfs_fileop_write, + fatfs_fileop_seek, + fatfs_fileop_close, + fatfs_fileop_uninit +}; + + +/* ********************************************************************* + * fat_readsector(fatfs,sector,numsec,buffer) + * + * Read one or more sectors from the disk into memory + * + * Input parameters: + * fatfs - fat filesystem descriptor + * sector - sector number + * numsec - number of sectors to read + * buffer - buffer to read sectors into + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_readsector(fatfs_t *fatfs,int sector,int numsec,uint8_t *buffer) +{ + int res; + + res = cfe_readblk(fatfs->fat_fh,(sector+fatfs->fat_partstart)*SECTORSIZE, + buffer,numsec*SECTORSIZE); + + if (res != numsec*SECTORSIZE) return CFE_ERR_IOERR; + + return 0; +} + + +/* ********************************************************************* + * fat_dumpbpb(bpb) + * + * Debug function; display fields in a BPB + * + * Input parameters: + * bpb - BIOS parameter block structure + * + * Return value: + * nothing + ********************************************************************* */ + +#ifdef _FATFS_DEBUG_ +static void fat_dumpbpb(bpb_t *bpb) +{ + xprintf("Bytes per sector %d\n",bpb->bpb_bytespersector); + xprintf("Sectors per cluster %d\n",bpb->bpb_sectorspercluster); + xprintf("Reserved sectors %d\n",bpb->bpb_reservedsectors); + xprintf("Number of FATs %d\n",bpb->bpb_numfats); + xprintf("Root dir entries %d\n",bpb->bpb_maxrootdir); + xprintf("Total sectors %d\n",bpb->bpb_totalsectors); + xprintf("Sectors per FAT %d\n",bpb->bpb_sectorsperfat); + xprintf("Sectors per track %d\n",bpb->bpb_sectorspertrack); + xprintf("Number of heads %d\n",bpb->bpb_numheads); + xprintf("Hidden sectors %d\n",bpb->bpb_hiddensectors); +} +#endif + +/* ********************************************************************* + * fat_findpart(fatfs) + * + * For partitioned disks, locate the active partition + * and set "fat_partstart" accordingly + * + * Input parameters: + * fatfs - FAT filesystem descriptor + * + * Return value: + * 0 if we found a valid partition table; else error code + ********************************************************************* */ + +static int fat_findpart(fatfs_t *fatfs) +{ + uint8_t buffer[SECTORSIZE]; + uint8_t *part; + int res; + int idx; + + fatfs->fat_partstart = 0; /* make sure we get real boot sector */ + res = fat_readsector(fatfs,0,1,buffer); + if (res < 0) return res; + + /* + * Normally you're supposed to check for a JMP instruction. + * At least that's what many people do. Flash MBRs don't start + * with JMP instructions, so just look for the seal. + * + * + * if (READBYTE(buffer,BPB_JMPINSTR) != BPB_JMPINSTR_VALUE) { + * return CFE_ERR_BADFILESYS; + * } + */ + + /* + * Check the seal at the end of th sector + */ + + if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) return CFE_ERR_BADFILESYS; + + /* + * Look for an active FAT partition. The partition we want must + * be the active one. We do not deal with extended partitions + * here. Hey, this is supposed to be boot code! + */ + + part = &buffer[PTABLE_OFFSET]; + for (idx = 0; idx < PTABLE_COUNT; idx++) { + if ((part[PTABLE_STATUS] == PTABLE_STATUS_ACTIVE) && + ((part[PTABLE_TYPE] == PARTTYPE_FAT12) || + (part[PTABLE_TYPE] == PARTTYPE_FAT16) || + (part[PTABLE_TYPE] == PARTTYPE_FAT16BIG))) { + break; + } + + part += PTABLE_SIZE; + } + + if (idx == PTABLE_COUNT) return CFE_ERR_BADFILESYS; + + /* + * The info we want is really just the pointer to the + * boot (BPB) sector. Get that and we'll use it for an + * offset into the disk later. + */ + + fatfs->fat_partstart = READWORD32(part,PTABLE_BOOTSECTOR); + + return 0; +} + + +/* ********************************************************************* + * fat_readbpb(fatfs) + * + * Read and internalize the BIOS Parameter Block + * + * Input parameters: + * fatfs - FAT filesystem descriptor + * + * Return value: + * 0 if ok + * else error code (usually, BPB is not valid) + ********************************************************************* */ + +static int fat_readbpb(fatfs_t *fatfs) +{ + uint8_t buffer[SECTORSIZE]; + int res; + + res = fat_readsector(fatfs,0,1,buffer); + if (res < 0) return res; + + if (READBYTE(buffer,BPB_JMPINSTR) != BPB_JMPINSTR_VALUE) return CFE_ERR_BADFILESYS; + if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) return CFE_ERR_BADFILESYS; + + fatfs->fat_bpb.bpb_bytespersector = READWORD(buffer,BPB_BYTESPERSECTOR); + fatfs->fat_bpb.bpb_sectorspercluster = READBYTE(buffer,BPB_SECTORSPERCLUSTER); + fatfs->fat_bpb.bpb_reservedsectors = READWORD(buffer,BPB_RESERVEDSECTORS); + fatfs->fat_bpb.bpb_numfats = READBYTE(buffer,BPB_NUMFATS); + fatfs->fat_bpb.bpb_maxrootdir = READWORD(buffer,BPB_MAXROOTDIR); + fatfs->fat_bpb.bpb_totalsectors = READWORD(buffer,BPB_TOTALSECTORS); + fatfs->fat_bpb.bpb_sectorsperfat = READWORD(buffer,BPB_SECTORSPERFAT); + fatfs->fat_bpb.bpb_sectorspertrack = READWORD(buffer,BPB_SECTORSPERTRACK); + fatfs->fat_bpb.bpb_numheads = READWORD(buffer,BPB_NUMHEADS); + fatfs->fat_bpb.bpb_hiddensectors = READWORD(buffer,BPB_HIDDENSECTORS); + + fatfs->fat_twelvebit = 1; + if (memcmp(&buffer[0x36],"FAT16 ",8) == 0) fatfs->fat_twelvebit = 0; + + if (fatfs->fat_bpb.bpb_bytespersector != SECTORSIZE) return CFE_ERR_BADFILESYS; + if (fatfs->fat_bpb.bpb_numfats > 2) return CFE_ERR_BADFILESYS; + + /* + * XXX sanity check other fields + */ + +#ifdef _FATFS_DEBUG_ + fat_dumpbpb(&(fatfs->fat_bpb)); +#endif + + return 0; +} + + + +/* ********************************************************************* + * fat_getentry(fatfs,entry) + * + * Read a FAT entry. This is more involved than you'd think, + * since we have to deal with 12 and 16 (and someday 32) bit FATs, + * and the nasty case where a 12-bit FAT entry crosses a sector + * boundary. + * + * Input parameters: + * fatfs - FAT filesystem descriptor + * entry - index of FAT entry + * + * Return value: + * FAT entry, or <0 if an error occured + ********************************************************************* */ + +static int fat_getfatentry(fatfs_t *fatfs,int entry) +{ + int fatsect; + int byteoffset; + int fatstart; + int fatoffset; + uint8_t b1,b2,b3; + int res; + + fatstart = fatfs->fat_bpb.bpb_reservedsectors; + + if (fatfs->fat_twelvebit) { + int odd; + odd = entry & 1; + byteoffset = ((entry & ~1) * 3) / 2; + fatsect = byteoffset / SECTORSIZE; + fatoffset = byteoffset % SECTORSIZE; + + if (fatfs->fat_fatsecnum != fatsect) { + res = fat_readsector(fatfs,fatsect+fatstart,1,fatfs->fat_fatsector); + if (res < 0) { + return res; + } + fatfs->fat_fatsecnum = fatsect; + } + + b1 = fatfs->fat_fatsector[fatoffset]; + + if ((fatoffset+1) >= SECTORSIZE) { + res = fat_readsector(fatfs,fatsect+1+fatstart,1,fatfs->fat_fatsector); + if (res < 0) { + return res; + } + fatfs->fat_fatsecnum = fatsect+1; + fatoffset -= SECTORSIZE; + } + + b2 = fatfs->fat_fatsector[fatoffset+1]; + + if ((fatoffset+2) >= SECTORSIZE) { + res = fat_readsector(fatfs,fatsect+1+fatstart,1,fatfs->fat_fatsector); + if (res < 0) { + return res; + } + fatfs->fat_fatsecnum = fatsect+1; + fatoffset -= SECTORSIZE; + } + + b3 = fatfs->fat_fatsector[fatoffset+2]; + + if (odd) { + return ((unsigned int) b3 << 4) + ((unsigned int) (b2 & 0xF0) >> 4); + } + else { + return ((unsigned int) (b2 & 0x0F) << 8) + ((unsigned int) b1); + } + + } + else { + byteoffset = entry * 2; + fatsect = byteoffset / SECTORSIZE; + fatoffset = byteoffset % SECTORSIZE; + + if (fatfs->fat_fatsecnum != fatsect) { + res = fat_readsector(fatfs,fatsect+fatstart,1,fatfs->fat_fatsector); + if (res < 0) { + return res; + } + fatfs->fat_fatsecnum = fatsect; + } + + b1 = fatfs->fat_fatsector[fatoffset]; + b2 = fatfs->fat_fatsector[fatoffset+1]; + return ((unsigned int) b1) + (((unsigned int) b2) << 8); + } +} + +/* ********************************************************************* + * fat_getrootdirentry(fatfs,entryidx,entry) + * + * Read a root directory entry. The FAT12/16 root directory + * is a contiguous group of sectors, whose size is specified in + * the BPB. This routine just digs out an entry from there + * + * Input parameters: + * fatfs - FAT filesystem descriptor + * entryidx - 0-based entry index to read + * entry - pointer to directory entry (32 bytes) + * + * Return value: + * 0 if ok + * <0 if error occured + ********************************************************************* */ + +static int fat_getrootdirentry(fatfs_t *fatfs,int entryidx,uint8_t *entry) +{ + int rootdirstart; + int rootdirsize; + int dirsecnum; + int res; + + if (entryidx >= fatfs->fat_bpb.bpb_maxrootdir) { + memset(entry,0,DIRENTRYSIZE); + return CFE_ERR_INV_PARAM; + } + + rootdirstart = fatfs->fat_bpb.bpb_reservedsectors + + fatfs->fat_bpb.bpb_numfats * fatfs->fat_bpb.bpb_sectorsperfat; + + rootdirsize = fatfs->fat_bpb.bpb_maxrootdir / DIRENTRYSIZE; + + dirsecnum = rootdirstart + entryidx / DIRPERSECTOR; + + if (fatfs->fat_dirsecnum != dirsecnum) { + res = fat_readsector(fatfs,dirsecnum,1,fatfs->fat_dirsector); + if (res < 0) { + return res; + } + fatfs->fat_dirsecnum = dirsecnum; + } + + memcpy(entry,&(fatfs->fat_dirsector[(entryidx % DIRPERSECTOR)*DIRENTRYSIZE]), + DIRENTRYSIZE); + + return 0; +} + +/* ********************************************************************* + * fat_checksumname(name) + * + * Calculate the "long filename" checksum for a given short name. + * All LFN directory entries associated with the short name are + * given the same checksum byte, to help keep the long name + * consistent. + * + * Input parameters: + * name - pointer to 32-byte directory entry + * + * Return value: + * checksum value + ********************************************************************* */ + +static uint8_t fat_checksumname(uint8_t *name) +{ + uint8_t sum = 0; + uint8_t newbit; + int idx; + + for (idx = 0; idx < 11; idx++) { + newbit = (sum & 1) ? 0x80 : 0x00; + sum >>= 1; + sum |= newbit; + sum += name[idx]; + } + + return sum; +} + +#ifdef _FATFS_DEBUG_ +void fat_dumpdirentry(uint8_t *entry); +void fat_dumpdirentry(uint8_t *entry) +{ + uint8_t name[32]; + int idx; + + if (entry[11] != ATTRIB_LFN) { + memcpy(name,entry,11); + name[11] = 0; + xprintf("%s %02X %04X %d\n", + name,DIRENTRY_ATTRIB(entry), + DIRENTRY_STARTCLUSTER(entry), + DIRENTRY_FILELENGTH(entry)); + } + else { + for (idx = 0; idx < 5; idx++) { + name[idx] = entry[(idx*2)+1]; + } + for (idx = 0; idx < 6; idx++) { + name[idx+5] = entry[(idx*2)+14]; + } + for (idx = 0; idx < 2; idx++) { + name[idx+11] = entry[(idx*2)+28]; + } + name[13] = '\0'; + xprintf("%02X: %s %04X cksum %02X\n",entry[0], + name,READWORD(entry,0x1A),entry[13]); + } +} +#endif + + +/* ********************************************************************* + * fat_walkfatchain(fat,start,arg,func) + * + * Walk a FAT chain, calling a callback routine for each entry + * we find along the way. + * + * Input parameters: + * fat - FAT filesystem descriptor + * start - starting FAT entry (from the directory, usually) + * arg - argument to pass to callback routine + * func - function to call for each FAT entry + * + * Return value: + * 0 if all elements processed + * <0 if error occured + * >0 if callback routine returned a nonzero value + ********************************************************************* */ + +static int fat_walkfatchain(fatfs_t *fat,int start, + void *arg, + int (*func)(fatfs_t *fat, + int e, + int prev_e, + void *arg)) +{ + int prev_e = 0; + int ending_e; + int e; + int res = 0; + + e = start; + + /* Note: ending FAT entry can be 0x(F)FF8..0x(F)FFF. We assume that the + 'getfatentry' call won't return values above that. */ + if (fat->fat_twelvebit) { + ending_e = 0xFF8; + } + else { + ending_e = 0xFFF8; + } + + while (e < ending_e) { + res = (*func)(fat,e,prev_e,arg); + if (res) break; + prev_e = e; + e = fat_getfatentry(fat,e); + if (e < 0) return e; + } + + return res; +} + +/* ********************************************************************* + * fat_getwalkfunc(fat,e,prev_e,arg) + * + * Callback routien to collect all of the FAT entries into + * a FAT chain descriptor + * + * Input parameters: + * fat - FAT filesystem descriptor + * e - current entry + * prev_e - previous entry (0 if first entry) + * arg - argument passed to fat_walkfatchain + * + * Return value: + * 0 to keep walking + * else value to return from fat_walkfatchain + ********************************************************************* */ + +static int fat_getwalkfunc(fatfs_t *fat,int e, + int prev_e,void *arg) +{ + fatchain_t *chain = arg; + + if (chain->fat_entries) { + chain->fat_entries[chain->fat_count] = (uint16_t) e; + } + + chain->fat_count++; + + return 0; +} + +/* ********************************************************************* + * fat_getchain(fat,start,chain) + * + * Walk an entire FAT chain and remember the chain in a + * FAT chain descriptor + * + * Input parameters: + * fat - FAT filesystem descriptor + * start - starting FAT entry + * chain - chain descriptor + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_getchain(fatfs_t *fat,int start,fatchain_t *chain) +{ + int res; + + chain->fat_entries = NULL; + chain->fat_count = 0; + chain->fat_start = start; + + /* + * walk once to count the entries. + * + * For regular files, you probably don't have to do this + * since you can predict exactly how many FAT entries + * there are given the file length. + */ + + res = fat_walkfatchain(fat,start,chain,fat_getwalkfunc); + if (res < 0) return res; + + /* + * allocate space for the entries. Include one extra + * slot for the first entry, since the first entry + * does not actually appear in the FAT (the fat is + * only the 'next' pointers). + */ + + if (chain->fat_count == 0) return 0; + chain->fat_entries = KMALLOC((chain->fat_count+1)*sizeof(uint16_t),0); + chain->fat_count = 0; + + /* + * walk again to collect entries + */ + res = fat_walkfatchain(fat,start,chain,fat_getwalkfunc); + if (res < 0) return res; + + return chain->fat_count; +} + + +/* ********************************************************************* + * fat_freechain(chain) + * + * Free memory associated with a FAT chain + * + * Input parameters: + * chain - chain descriptor + * + * Return value: + * nothing + ********************************************************************* */ + +static void fat_freechain(fatchain_t *chain) +{ + if (chain->fat_entries) { + KFREE(chain->fat_entries); + chain->fat_entries = NULL; + } + chain->fat_count = 0; +} + +/* ********************************************************************* + * fat_clusteridx(fat,chain,idx) + * + * Index into a FAT chain and return the nth cluster number + * from the chain + * + * Input parameters: + * fat - fat filesystem descriptor + * chain - chain descriptor + * idx - index into FAT chain + * + * Return value: + * FAT entry at the nth index, or + * <0 if an error occured + ********************************************************************* */ +static int fat_clusteridx(fatfs_t *fat,fatchain_t *chain,int idx) +{ + if (idx >= chain->fat_count) return CFE_ERR_INV_PARAM; /* error! */ + return (int) (unsigned int) chain->fat_entries[idx]; +} + +/* ********************************************************************* + * fat_sectoridx(fat,chain,idx) + * + * Return the sector nunber of the nth sector in a given + * FAT chain. This routine knows how to translate cluster + * numbers into sector numbers. + * + * Input parameters: + * fat - FAT filesystem descriptor + * chain - FAT chain + * idx - index of which sector to find + * + * Return value: + * sector number + * <0 if an error occured + ********************************************************************* */ +static int fat_sectoridx(fatfs_t *fat,fatchain_t *chain,int idx) +{ + int clusteridx; + int sectoridx; + int sector; + int fatentry; + + clusteridx = idx / fat->fat_bpb.bpb_sectorspercluster; + sectoridx = idx % fat->fat_bpb.bpb_sectorspercluster; + + fatentry = fat_clusteridx(fat,chain,clusteridx); + + if (fatentry < 0) xprintf("ran off end of fat chain!\n"); + if (fatentry < 2) xprintf("fat entries should be >= 2\n"); + + sector = fat->fat_bpb.bpb_reservedsectors + + (fat->fat_bpb.bpb_maxrootdir * DIRENTRYSIZE)/SECTORSIZE + + (fat->fat_bpb.bpb_numfats * fat->fat_bpb.bpb_sectorsperfat) + + (fatentry - 2) * fat->fat_bpb.bpb_sectorspercluster + + sectoridx; + + return sector; +} + +/* ********************************************************************* + * fat_getsubdirentry(fat,chain,idx,direntry) + * + * This routine is similar to fat_getrootdirentry except it + * works on a subdirectory. FAT subdirectories are like files + * containing directory entries, so we use the "get nth sector + * in chain" routines to walk the chains of sectors reading directory + * entries. + * + * Input parameters: + * fat - FAT filesystem descriptor + * chain - FAT chain + * idx - index of entry to read + * direntry - place to put directory entry we read + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_getsubdirentry(fatfs_t *fat,fatchain_t *chain, + int idx,uint8_t *direntry) +{ + int sector; + int res; + + sector = fat_sectoridx(fat,chain,idx/DIRPERSECTOR); + + if (sector < 0) return sector; + + if (fat->fat_dirsecnum != sector) { + res = fat_readsector(fat,sector,1,fat->fat_dirsector); + if (res < 0) { + return res; + } + fat->fat_dirsecnum = sector; + } + + memcpy(direntry,&(fat->fat_dirsector[(idx % DIRPERSECTOR)*DIRENTRYSIZE]), + DIRENTRYSIZE); + + return 0; +} + +/* ********************************************************************* + * fat_getshortname(direntry,name) + * + * Read the short filename from a directory entry, converting + * it into its classic 8.3 form + * + * Input parameters: + * direntry - directory entry + * name - place to put 8.3 name + * + * Return value: + * nothing + ********************************************************************* */ + +static void fat_getshortname(uint8_t *direntry,char *name) +{ + int idx; + + /* + * Collect the base file name + */ + + for (idx = DIR_NAMEOFFSET; idx < (DIR_NAMEOFFSET+DIR_NAMELEN); idx++) { + if (direntry[idx] == ' ') break; + *name++ = direntry[idx]; + } + + /* + * Put in the dot for the extension only if there + * is an extension. + */ + + if (direntry[DIR_EXTOFFSET] != ' ') *name++ = '.'; + + /* + * Collect the extension + */ + + for (idx = DIR_EXTOFFSET; idx < (DIR_EXTOFFSET+DIR_EXTLEN); idx++) { + if (direntry[idx] == ' ') break; + *name++ = direntry[idx]; + } + + *name = '\0'; +} + + +/* ********************************************************************* + * fat_getlongname(fat,chain,diridx,shortentry,longname) + * + * Look backwards in the directory to locate the long file name + * that corresponds to the short file name passed in 'shortentry' + * + * Input parameters: + * fat - FAT filesystem descriptor + * chain - chain describing current directory, or NULL + * if the current directory is the root directory + * diridx - index of the short file name + * shortentry - points to the short directory entry + * longname - buffer to receive long file name (up to 261 chars) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_getlongname(fatfs_t *fat,fatchain_t *chain,int diridx, + uint8_t *shortentry,char *longname) +{ + int lfnidx = 1; + uint8_t checksum; + uint8_t direntry[DIRENTRYSIZE]; + int idx; + char *lfnptr; + int badlfn = 0; + + *longname = '\0'; + + /* + * idx is the entry # of the short name + */ + + checksum = fat_checksumname(shortentry); + + /* + * Start working backwards from current entry + * and collect pieces of the lfn + */ + + lfnptr = longname; + diridx--; + + while (diridx > 0) { + + /* + * Read previous entry + */ + + if (chain) { + fat_getsubdirentry(fat,chain,diridx,direntry); + } + else { + fat_getrootdirentry(fat,diridx,direntry); + } + + /* + * Checksum must match, it must have the right entry index, + * and it must have the LFN attribute + */ + + if (DIRENTRY_CHECKSUM(direntry) != checksum) { + badlfn = 1; + break; + } + if ((DIRENTRY_LFNIDX(direntry) & LFNIDX_MASK) != lfnidx) { + badlfn = 1; + break; + } + + if (DIRENTRY_ATTRIB(direntry) != ATTRIB_LFN) { + badlfn = 1; + break; + } + + /* + * Collect the chars from the filename. Note we + * don't deal well with real unicode chars here. + */ + + for (idx = 0; idx < 5; idx++) { + *lfnptr++ = direntry[(idx*2)+1]; + } + for (idx = 0; idx < 6; idx++) { + *lfnptr++ = direntry[(idx*2)+14]; + } + for (idx = 0; idx < 2; idx++) { + *lfnptr++ = direntry[(idx*2)+28]; + } + + /* + * Don't go too far + */ + + if (DIRENTRY_LFNIDX(direntry) & LFNIDX_END) break; + lfnidx++; + if (lfnidx > LFNIDX_MAX) { + badlfn = 1; + break; + } + + diridx--; + } + + /* + * Null terminate the lfn + */ + + *lfnptr = 0; + + if (badlfn) { + longname[0] = 0; + return CFE_ERR_FILENOTFOUND; + } + + return 0; +} + + +/* ********************************************************************* + * fat_scandir(fat,chain,name,direntry) + * + * Scan a single directory looking for a file name + * + * Input parameters: + * fat - FAT filesystem descriptor + * chain - FAT chain for directory or NULL for root directory + * name - name of file to look for (short or long name) + * direntry - place to put directory entry if we find one + * + * Return value: + * 1 if name was found + * 0 if name was not found + * else <0 is error code + ********************************************************************* */ + + +static int fat_scandir(fatfs_t *fat,fatchain_t *chain, + char *name,uint8_t *direntry) +{ + int idx; + int count; + char shortname[16]; + char longname[280]; + + /* + * Get directory size + */ + + if (chain) { + count = (chain->fat_count * fat->fat_bpb.bpb_sectorspercluster) * DIRPERSECTOR; + } + else { + count = (int) fat->fat_bpb.bpb_maxrootdir; + } + + /* + * Scan whole directory + */ + + for (idx = 0; idx < count; idx++) { + + /* + * Get entry by root or chain depending... + */ + + if (chain) { + fat_getsubdirentry(fat,chain,idx,direntry); + } + else { + fat_getrootdirentry(fat,idx,direntry); + } + + /* + * Ignore stuff we don't want to see + */ + + if (direntry[0] == DIRENTRY_LAST) break; /* stop if at end of dir */ + if (direntry[0] == DIRENTRY_DELETED) continue; /* skip deleted entries */ + if (direntry[0] == DIRENTRY_PARENTDIR) continue; /* skip ./.. entries */ + + if (DIRENTRY_ATTRIB(direntry) == ATTRIB_LFN) continue; /* skip LFNs */ + if (DIRENTRY_ATTRIB(direntry) & ATTRIB_LABEL) continue; /* skip volume labels */ + + /* + * Get actual file names from directory + */ + + fat_getshortname(direntry,shortname); + fat_getlongname(fat,chain,idx,direntry,longname); + + + if (name) { + if (strcmpi(name,shortname) == 0) return 1; + if (longname[0] && (strcmpi(name,longname) == 0)) return 1; + } + else { + xprintf("%-30s",longname[0] ? longname : shortname); +// xprintf(" Clus=%04X",DIRENTRY_STARTCLUSTER(direntry)); +// xprintf(" Attrib=%02X",DIRENTRY_ATTRIB(direntry)); +// xprintf(" Size=%d",DIRENTRY_FILELENGTH(direntry)); + xprintf("%d",DIRENTRY_FILELENGTH(direntry)); + xprintf("\n"); + } + } + + return 0; +} + +/* ********************************************************************* + * fat_findfile(fat,name,direntry) + * + * Locate a directory entry given a complete path name + * + * Input parameters: + * fat - FAT filesystem descriptor + * name - name of file to locate (forward or reverse slashses ok) + * direntry - place to put directory entry we find + * + * Return value: + * 0 if file not found + * 1 if file was found + * <0 if error occurs + ********************************************************************* */ + +static int fat_findfile(fatfs_t *fat,char *name,uint8_t *direntry) +{ + char *namecopy; + char *namepart; + char *ptr; + fatchain_t chain; + int res; + int e; + + /* + * Copy the name, we're going to hack it up + */ + + namecopy = strdup(name); + + /* + * Chew off the first piece up to the first slash. Remove + * a leading slash if it is there. + */ + + ptr = namecopy; + + if ((*ptr == '/') || (*ptr == '\\')) ptr++; + + namepart = ptr; + while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++; + if (*ptr) *ptr++ = '\0'; + + /* + * Scan the root directory looking for the first piece + */ + + res = fat_scandir(fat,NULL,namepart,direntry); + if (res == 0) { + KFREE(namecopy); + return 0; /* file not found */ + } + + + /* + * Start scanning subdirectories until we run out + * of directory components. + */ + + namepart = ptr; + while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++; + if (*ptr) *ptr++ = '\0'; + if (!*namepart) namepart = NULL; + + + while (namepart) { + + /* + * Scan the subdirectory + */ + + e = DIRENTRY_STARTCLUSTER(direntry); + memset(&chain,0,sizeof(chain)); + fat_getchain(fat,e,&chain); + res = fat_scandir(fat,&chain,namepart,direntry); + if (res == 0) { + break; + } + fat_freechain(&chain); + + /* + * Advance to the next piece + */ + + namepart = ptr; + while (*ptr && (*ptr != '/') && (*ptr != '\\')) ptr++; + if (*ptr) *ptr++ = '\0'; + if (!*namepart) namepart = NULL; + + /* + * If there's more to go and we hit something that + * is not a directory, stop here. + */ + + if (namepart && !(DIRENTRY_ATTRIB(direntry) & ATTRIB_DIR)) { + res = 0; + } + } + + KFREE(namecopy); + + /* + * The last piece we enumerate has to be a file. + */ + + if ((res > 0) && + (DIRENTRY_ATTRIB(direntry) & ATTRIB_DIR)) { + return 0; + } + + return res; +} + + +/* ********************************************************************* + * fat_init(fat,name) + * + * Create the filesystem descriptor and attach to the hardware + * device. + * + * Input parameters: + * fat - filesystem descriptor + * name - hardware device name + * part - true to look for partition tables + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fat_init(fatfs_t *fat,char *name,int part) +{ + int res; + + memset(fat,0,sizeof(fatfs_t)); + fat->fat_dirsecnum = -1; + fat->fat_fatsecnum = -1; + + fat->fat_fh = cfe_open(name); + + if (fat->fat_fh < 0) return fat->fat_fh; + + res = fatfs_check_for_partition_table(fat); + /* If we were able to figure it out, use that as the default */ + if (res >= 0) part = res; + + if (part) { + res = fat_findpart(fat); + if (res < 0) { + cfe_close(fat->fat_fh); + fat->fat_fh = -1; + return res; + } + } + + res = fat_readbpb(fat); + if (res != 0) { + cfe_close(fat->fat_fh); + fat->fat_fh = -1; + return res; + } + + return 0; +} + +/* ********************************************************************* + * fat_uninit(fat) + * + * Uninit the filesystem descriptor and release any resources + * we allocated. + * + * Input parameters: + * fat - filesystem descriptor + * + * Return value: + * nothing + ********************************************************************* */ + +static void fat_uninit(fatfs_t *fat) +{ + if (fat->fat_fh >= 0) cfe_close(fat->fat_fh); + fat->fat_fh = -1; +} + +int fatfs_fileop_dir(void *fsctx); +int fatfs_fileop_dir(void *fsctx) +{ + fatfs_t *fatfs = fsctx; + uint8_t direntry[32]; + + fat_scandir(fatfs,NULL,NULL,direntry); + + return 0; +} + +/* ********************************************************************* + * fatfs_fileop_init(fsctx,devname) + * + * Create a FAT filesystem context and open the associated + * block device. + * + * Input parameters: + * fsctx - file system context (return pointer) + * devname - device name to open + * part - true to look for a partition table + * + * Return value: + * 0 if ok, else error + ********************************************************************* */ + +static int fatfs_fileop_init(void **fsctx,char *devname,int part) +{ + int res; + fatfs_t *fatfs; + + /* + * Allocate a file system context + */ + + fatfs = (fatfs_t *) KMALLOC(sizeof(fatfs_t),0); + if (!fatfs) return CFE_ERR_NOMEM; + + /* + * Open a handle to the underlying device + */ + + res = fat_init(fatfs,devname,part); + if (res != 0) { + KFREE(fatfs); + return res; + } + + *fsctx = fatfs; + + return 0; +} + +/* ********************************************************************* + * fatfs_check_for_partition_table(fatfs) + * + * This routine attempts to determine if the disk contains a + * partition table or if it contains a standard MS-DOS boot recod. + * We try to find both, and return what we find, or an error + * if it is still unclear. + * + * Input parameters: + * fatfs - fat filesystem context + * + * Return value: + * 0 if no partition table + * 1 if partition table + * <0 = error occured, could not tell or I/O error + ********************************************************************* */ + +static int fatfs_check_for_partition_table(fatfs_t *fatfs) +{ + int res; + uint8_t buffer[SECTORSIZE]; + uint8_t *part; + int idx; + int foundit = 0; + + /* + * Read sector 0 + */ + + fatfs->fat_partstart = 0; + res = fat_readsector(fatfs,0,1,buffer); + if (res < 0) return res; + + /* + * Check the seal at the end of th sector. Both + * boot sector and MBR should contain this seal. + */ + if (READWORD(buffer,BPB_SEAL) != BPB_SEAL_VALUE) { + res = CFE_ERR_BADFILESYS; + return res; + } + + /* + * See Microsoft Knowledgebase article # Q140418, it contains + * a good description of the boot sector format. + * + * If the extended information is present, and SystemID is "FAT" + * and the "bytes per sector" is 512, assume it's a regular boot block + */ + + if (((buffer[BPB_SIGNATURE] == BPB_SIGNATURE_VALUE1) || + (buffer[BPB_SIGNATURE] == BPB_SIGNATURE_VALUE2)) && + (memcmp(&buffer[BPB_SYSTEMID],"FAT",3) == 0) && + (READWORD(buffer,BPB_BYTESPERSECTOR) == 512)) { + /* Not partitioned */ + res = 0; + return res; + } + + /* If no extended information is present, check a few other key values. */ + + if ((READWORD(buffer,BPB_BYTESPERSECTOR) == 512) && + (READWORD(buffer,BPB_RESERVEDSECTORS) >= 1) && + ((READWORD(buffer,BPB_MEDIADESCRIPTOR) & 0xF0) == 0xF0)) { + res = 0; + return res; + } + + /* + * If we're still confused, look for a partition table with a valid FAT + * partition on it. We might not detect a partition table that has + * only non-FAT partitions on it, like a disk with all Linux partitions, + * but that is fine here in the FATFS module, since we only want to + * find FAT partitions anyway. + */ + part = &buffer[PTABLE_OFFSET]; + for (idx = 0; idx < PTABLE_COUNT; idx++) { + + if (((part[PTABLE_STATUS] == PTABLE_STATUS_ACTIVE) || + (part[PTABLE_STATUS] == 0x00)) && + ((part[PTABLE_TYPE] == PARTTYPE_FAT12) || + (part[PTABLE_TYPE] == PARTTYPE_FAT16) || + (part[PTABLE_TYPE] == PARTTYPE_FAT16BIG))) { + foundit = 1; + res = 1; /*Partition table present*/ + break; + } + part += PTABLE_SIZE; + } + + /* + * If at this point we did not find what we were looking for, + * return an error. + */ + if (foundit) { + res = 1; /*Partition table is present.*/ + } + else { + /*Error! We can't decide if partition table exists or not*/ + res = CFE_ERR_BADFILESYS; + } + + return res; +} + +static int fatfs_fileop_xinit(void **fsctx,void *dev) +{ + char *devname = (char *) dev; + + return fatfs_fileop_init(fsctx,devname,0); +} + +static int fatfs_fileop_pinit(void **fsctx,void *dev) +{ + char *devname = (char *) dev; + + return fatfs_fileop_init(fsctx,devname,1); +} + + + +/* ********************************************************************* + * fatfs_fileop_open(ref,name) + * + * Open a file on the FAT device. + * + * Input parameters: + * ref - place to store pointer to fileinfo + * fsctx - filesystem context + * name - name of file to open + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int fatfs_fileop_open(void **ref,void *fsctx,char *name,int mode) +{ + int res; + uint8_t direntry[DIRENTRYSIZE]; + fatfile_t *ff; + fatfs_t *fatfs; + + if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + fatfs = (fatfs_t *) fsctx; + + ff = (fatfile_t *) KMALLOC(sizeof(fatfile_t),0); + if (ff == NULL) return CFE_ERR_NOMEM; + + memset(ff,0,sizeof(fatfile_t)); + + ff->ff_fat = fatfs; + + res = fat_findfile(ff->ff_fat,name,direntry); + if (res <= 0) { + return CFE_ERR_FILENOTFOUND; /* not found */ + } + + /* + * Okay, the file was found. Enumerate the FAT chain + * associated with this file. + */ + + ff->ff_filelength = DIRENTRY_FILELENGTH(direntry); + + ff->ff_curpos = 0; + ff->ff_cursector = -1; + + res = fat_getchain(ff->ff_fat, + DIRENTRY_STARTCLUSTER(direntry), + &(ff->ff_chain)); + + if (res < 0) { + KFREE(ff); + return res; + } + + /* + * Return the file handle + */ + + + fatfs->fat_refcnt++; + *ref = (void *) ff; + return 0; +} + + +/* ********************************************************************* + * fatfs_fileop_close(ref) + * + * Close the file. + * + * Input parameters: + * ref - pointer to open file information + * + * Return value: + * nothing + ********************************************************************* */ + +static void fatfs_fileop_close(void *ref) +{ + fatfile_t *file = (fatfile_t *) ref; + fatfs_t *fatctx = file->ff_fat; + + fatctx->fat_refcnt--; + + fat_freechain(&(file->ff_chain)); + KFREE(file); +} + + +/* ********************************************************************* + * fatfs_fileop_uninit(ref) + * + * Uninitialize the file system. + * + * Input parameters: + * fsctx - filesystem context + * + * Return value: + * nothing + ********************************************************************* */ +static void fatfs_fileop_uninit(void *fsctx) +{ + fatfs_t *fatctx = (fatfs_t *) fsctx; + + if (fatctx->fat_refcnt) { + xprintf("fatfs_fileop_unint: warning: refcnt should be zero\n"); + } + + fat_uninit(fatctx); + + KFREE(fatctx); +} + + +/* ********************************************************************* + * fatfs_fileop_seek(ref,offset,how) + * + * Move the file pointer within the file + * + * Input parameters: + * ref - pointer to open file information + * offset - new file location or distance to move + * how - method for moving + * + * Return value: + * new file offset + * <0 if error occured + ********************************************************************* */ + +static int fatfs_fileop_seek(void *ref,int offset,int how) +{ + fatfile_t *file = (fatfile_t *) ref; + + switch (how) { + case FILE_SEEK_BEGINNING: + file->ff_curpos = offset; + break; + case FILE_SEEK_CURRENT: + file->ff_curpos += offset; + break; + default: + break; + } + + if (file->ff_curpos >= file->ff_filelength) { + file->ff_curpos = file->ff_filelength; + } + + return file->ff_curpos; +} + + +/* ********************************************************************* + * fatfs_fileop_read(ref,buf,len) + * + * Read data from the file. + * + * Input parameters: + * ref - pointer to open file information + * buf - buffer to read data into + * len - number of bytes to read + * + * Return value: + * number of bytes read + * <0 if error occured + * 0 means eof + ********************************************************************* */ + +static int fatfs_fileop_read(void *ref,uint8_t *buf,int len) +{ + fatfile_t *file = (fatfile_t *) ref; + int amtcopy; + int ttlcopy = 0; + int offset; + int sector; + int secidx; + int origpos; + int res; + uint8_t temp_buf[SECTORSIZE]; + + /* + * Remember orig position in case we have an error + */ + + origpos = file->ff_curpos; + + /* + * bounds check the length based on the file length + */ + + if ((file->ff_curpos + len) > file->ff_filelength) { + len = file->ff_filelength - file->ff_curpos; + } + + res = 0; + + /* + * while ther is still data to be transferred + */ + + + while (len) { + + /* + * Calculate the sector offset and index in the sector + */ + + offset = file->ff_curpos % SECTORSIZE; + secidx = file->ff_curpos / SECTORSIZE; + + sector = fat_sectoridx(file->ff_fat,&(file->ff_chain),secidx); + + if (sector < 0) { + xprintf("should not happen, sector = -1!\n"); + return sector; + } + + /* + * first transfer up to the sector boundary + */ + + amtcopy = len; + if (amtcopy > (SECTORSIZE-offset)) { + amtcopy = (SECTORSIZE-offset); + } + + /* + * If transferring exactly a sector, on a sector + * boundary, read the data directly into the user buffer + * + * Extra credit: See if we can transfer more than one + * sector at a time, by determining if we can read a run of + * contiguous sectors (very likely) + * + * Otherwise: read into the sector buffer and + * transfer the data to user memory. + */ + + if ((offset == 0) && (amtcopy == SECTORSIZE)) { + res = fat_readsector(file->ff_fat,sector,1,temp_buf); + if (res < 0) { + xprintf("I/O error!\n"); + break; + } + memcpy(buf,temp_buf,amtcopy); + } + else { + if (file->ff_cursector != sector) { + res = fat_readsector(file->ff_fat,sector,1,file->ff_sector); + if (res < 0) { + break; + } + file->ff_cursector = sector; + } + memcpy(buf,&(file->ff_sector[offset]),amtcopy); + } + + /* + * Adjust/update all our pointers. + */ + + buf += amtcopy; + file->ff_curpos += amtcopy; + ttlcopy += amtcopy; + len -= amtcopy; + + /* + * see if we ran off the end of the file. Should not + * be necessary. + */ + + if (file->ff_curpos >= file->ff_filelength) { + /* should not be necessary */ + break; + } + } + + /* + * If an error occured, get out now. + */ + + if (res < 0) { + file->ff_curpos = origpos; + return res; + } + + return ttlcopy; + +} + +static int fatfs_fileop_write(void *ref,uint8_t *buf,int len) +{ + return CFE_ERR_UNSUPPORTED; +} + + +#if 0 + +void main(int argc,char *argv[]) +{ + fatfs_t fat; + int idx; + unsigned int e; + uint8_t direntry[DIRENTRYSIZE]; + fatchain_t chain; + int res; + + + fat_init(&fat,"floppy.raw"); + + + if (fat_readbpb(&fat) == 0) { + fat_dumpbpb(&fat.fat_bpb); + } + +#if 0 + for (idx = 0; idx < (int) fat.fat_bpb.bpb_maxrootdir; idx++) { + fat_getrootdirentry(&fat,idx,direntry); + if (direntry[0] == 0) break; + if (direntry[0] == 0xE5) continue; + xprintf("%3d: ",idx); + fat_dumpdirentry(direntry); + } +#endif + + fat_scandir(&fat,NULL,NULL,direntry); + + for (e = 0x150; e < 0x160; e++) { + xprintf("Entry %03X is %03X\n",e,fat_getfatentry(&fat,e)); + } + +#if 0 + e = 0x36E; + while (e != 0xFFF) { + e = fat_getfatentry(&fat,e); + xprintf("%03X ",e); + } +#endif + + + xprintf("\n\n"); + e = 0x36E; + memset(&chain,0,sizeof(chain)); + fat_getchain(&fat,e,&chain); + fat_scandir(&fat,&chain,NULL,direntry); + fat_freechain(&chain); + + xprintf("\n\n"); + e = 0x36F; + memset(&chain,0,sizeof(chain)); + fat_getchain(&fat,e,&chain); + fat_scandir(&fat,&chain,NULL,direntry); + fat_freechain(&chain); + + xprintf("\n\n"); + e = 0x370; + memset(&chain,0,sizeof(chain)); + fat_getchain(&fat,e,&chain); + fat_scandir(&fat,&chain,NULL,direntry); + fat_freechain(&chain); + + xprintf("\n\n"); + + res = fat_findfile(&fat,argc > 1 ? argv[1] : "/usr/local/include/ansidecl.h",direntry); + xprintf("res = %d\n",res); + + if (res) fat_dumpdirentry(direntry); + + close(fat.fat_fh); +} + +void main(int argc,char *argv[]) +{ + void *ref; + int res; + char buffer[257]; + int total = 0; + +// res = fatfs_fileop_open(&ref,"floppy.raw:/usr/local/include/bfdlink.h"); + res = fatfs_fileop_open(&ref,"floppy.raw:/idedrv.h"); + + if (res != 0) { + xprintf("Could not open file: %d\n",res); + exit(1); + } + + for (;;) { + res = fatfs_fileop_read(ref,buffer,39); +// xprintf("read returned %d\n",res); + if (res <= 0) break; + + if (res > 0) { + total += res; + buffer[res] = 0; + xprintf("%s",buffer); + } + } + + if (res < 0) xprintf("error! \n"); + + xprintf("[total %d]\n",total); + + fatfs_fileop_close(ref); + + exit(0); + +} + +#endif diff --git a/cfe/cfe/main/cfe_filesys.c b/cfe/cfe/main/cfe_filesys.c new file mode 100755 index 0000000..569d7bc --- /dev/null +++ b/cfe/cfe/main/cfe_filesys.c @@ -0,0 +1,343 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Filesystem manager File: cfe_filesys.c + * + * This module maintains the list of available file systems. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_malloc.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" + +#include "cfe.h" + +#include "bsp_config.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern const fileio_dispatch_t raw_fileops; +#if CFG_NETWORK +extern const fileio_dispatch_t tftp_fileops; +#if (CFG_TCP) && (CFG_HTTPFS) +extern const fileio_dispatch_t http_fileops; +#endif +#endif +#if CFG_FATFS +extern const fileio_dispatch_t fatfs_fileops; +extern const fileio_dispatch_t pfatfs_fileops; +#endif +#if CFG_ZLIB +extern const fileio_dispatch_t zlibfs_fileops; +#endif + +/* ********************************************************************* + * File system list + ********************************************************************* */ + +static const fileio_dispatch_t * const cfe_filesystems[] = { +#if !defined(CONFIG_MIPS_BRCM) + &raw_fileops, +#endif +#if CFG_NETWORK + &tftp_fileops, +#if (CFG_TCP) & (CFG_HTTPFS) + &http_fileops, +#endif +#endif +#if CFG_FATFS + &fatfs_fileops, + &pfatfs_fileops, +#endif +#if CFG_ZLIB + &zlibfs_fileops, +#endif + NULL +}; + +/* ********************************************************************* + * cfe_findfilesys(name) + * + * Locate the dispatch record for a particular file system. + * + * Input parameters: + * name - name of filesys to locate + * + * Return value: + * pointer to dispatch table or NULL if not found + ********************************************************************* */ + +const fileio_dispatch_t *cfe_findfilesys(const char *name) +{ + const fileio_dispatch_t * const *disp; + + disp = cfe_filesystems; + + while (*disp) { + if (strcmp((*disp)->method,name) == 0) return *disp; + disp++; + } + + return NULL; +} + +/* ********************************************************************* + * fs_init(name,fsctx,device) + * + * Initialize a filesystem context + * + * Input parameters: + * name - name of file system + * fsctx - returns a filesystem context + * device - device name or other info + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +int fs_init(char *fsname,fileio_ctx_t **fsctx,void *device) +{ + fileio_ctx_t *ctx; + int res; + const fileio_dispatch_t *ops; + + ops = cfe_findfilesys((const char *)fsname); + if (!ops) return CFE_ERR_FSNOTAVAIL; + + ctx = (fileio_ctx_t *) KMALLOC(sizeof(fileio_ctx_t),0); + if (!ctx) return CFE_ERR_NOMEM; + + ctx->ops = ops; + res = BDINIT(ops,&(ctx->fsctx),device); + + if (res != 0) { + KFREE(ctx); + } + + *fsctx = ctx; + + return res; +} + + +/* ********************************************************************* + * fs_hook(fsctx,name) + * + * "Hook" a filesystem to attach a filter, like a decompression + * or decryption engine. + * + * Input parameters: + * fsctx - result from a previous fs_init + * name - name of fs to hook onto the beginning + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ + +int fs_hook(fileio_ctx_t *fsctx,char *fsname) +{ + void *hookfsctx; + const fileio_dispatch_t *ops; + int res; + + /* + * Find the hook filesystem (well, actually a filter) + */ + + ops = cfe_findfilesys((const char *)fsname); + if (!ops) return CFE_ERR_FSNOTAVAIL; + + /* + * initialize our hook file filter. + */ + + res = BDINIT(ops,&hookfsctx,fsctx); + if (res != 0) return res; + + /* + * Now replace dispatch table for current filesystem + * with the hook's dispatch table. When fs_read is called, + * we'll go to the hook, and the hook will call the original. + * + * When fs_uninit is called, the hook will call the original's + * uninit routine. + */ + + fsctx->ops = ops; + fsctx->fsctx = hookfsctx; + + return 0; + +} + +/* ********************************************************************* + * fs_uninit(fsctx) + * + * Uninitialize a file system context. + * + * Input parameters: + * fsctx - filesystem context to remove (from fs_init) + * + * Return value: + * 0 if ok + * else error + ********************************************************************* */ +int fs_uninit(fileio_ctx_t *fsctx) +{ + BDUNINIT(fsctx->ops,fsctx->fsctx); + + KFREE(fsctx); + + return 0; +} + + +/* ********************************************************************* + * fs_open(fsctx,ref,filename,mode) + * + * Open a file on the file system + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - returns file handle + * filename - name of file to open + * mode - file open mode + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +int fs_open(fileio_ctx_t *fsctx,void **ref,char *filename,int mode) +{ + return BDOPEN2(fsctx->ops,ref,fsctx->fsctx,filename,mode); +} + +/* ********************************************************************* + * fs_close(fsctx,ref) + * + * Close a file on the file system + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - file handle (from fs_open) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +int fs_close(fileio_ctx_t *fsctx,void *ref) +{ + BDCLOSE(fsctx->ops,ref); + + return 0; +} + + +/* ********************************************************************* + * fs_read(fsctx,ref,buffer,len) + * + * Read data from the device. + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - file handle (from fs_open) + * buffer - buffer pointer + * len - length + * + * Return value: + * number of bytes read + * 0=eof + * <0 = error + ********************************************************************* */ + +int fs_read(fileio_ctx_t *fsctx,void *ref,uint8_t *buffer,int len) +{ + return BDREAD(fsctx->ops,ref,buffer,len); +} + +/* ********************************************************************* + * fs_write(fsctx,ref,buffer,len) + * + * write data from the device. + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - file handle (from fs_open) + * buffer - buffer pointer + * len - length + * + * Return value: + * number of bytes written + * 0=eof + * <0 = error + ********************************************************************* */ + +int fs_write(fileio_ctx_t *fsctx,void *ref,uint8_t *buffer,int len) +{ + return BDWRITE(fsctx->ops,ref,buffer,len); +} + +/* ********************************************************************* + * fs_seek(fsctx,ref,offset,how) + * + * move file pointer on the device + * + * Input parameters: + * fsctx - filesystem context (from fs_init) + * ref - file handle (from fs_open) + * offset - distance to move + * how - origin (FILE_SEEK_xxx) + * + * Return value: + * new offset + * <0 = error + ********************************************************************* */ + +int fs_seek(fileio_ctx_t *fsctx,void *ref,int offset,int how) +{ + return BDSEEK(fsctx->ops,ref,offset,how); +} diff --git a/cfe/cfe/main/cfe_httpfs.c b/cfe/cfe/main/cfe_httpfs.c new file mode 100644 index 0000000..4ebad4c --- /dev/null +++ b/cfe/cfe/main/cfe_httpfs.c @@ -0,0 +1,396 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * "HTTP" file system File: cfe_httpfs.c + * + * This filesystem driver lets you read files from an HTTP + * server. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_console.h" + +#include "cfe.h" + +#include "bsp_config.h" + +#if (CFG_TCP) && (CFG_HTTPFS) + +#include "net_ebuf.h" +#include "net_api.h" + + +/* ********************************************************************* + * HTTP context + ********************************************************************* */ + +/* + * File system context - describes overall file system info, + * such as the handle to the underlying device. + */ + +typedef struct http_fsctx_s { + int http_tmp; /* context not really needed */ +} http_fsctx_t; + +/* + * File context - describes an open file on the file system. + */ + +#define HTTP_BUFSIZE 1024 +typedef struct http_file_s { + http_fsctx_t *http_fsctx; + int http_socket; + uint8_t http_buffer[HTTP_BUFSIZE]; + uint8_t *http_bptr; + int http_blen; + int http_offset; + char *http_filename; +} http_file_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int http_fileop_init(void **fsctx,void *devicename); +static int http_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int http_fileop_read(void *ref,uint8_t *buf,int len); +static int http_fileop_write(void *ref,uint8_t *buf,int len); +static int http_fileop_seek(void *ref,int offset,int how); +static void http_fileop_close(void *ref); +static void http_fileop_uninit(void *fsctx); + +/* ********************************************************************* + * RAW fileio dispatch table + ********************************************************************* */ + +const fileio_dispatch_t http_fileops = { + "http", + FSYS_TYPE_NETWORK, + http_fileop_init, + http_fileop_open, + http_fileop_read, + http_fileop_write, + http_fileop_seek, + http_fileop_close, + http_fileop_uninit +}; + +static int http_fileop_init(void **newfsctx,void *dev) +{ + http_fsctx_t *fsctx; + + *newfsctx = NULL; + + fsctx = KMALLOC(sizeof(http_fsctx_t),0); + if (!fsctx) { + return CFE_ERR_NOMEM; + } + + fsctx->http_tmp = 0; + *newfsctx = fsctx; + + return 0; +} + +static int http_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode) +{ + http_fsctx_t *fsctx; + http_file_t *file; + char temp[200]; + char *hostname, *filen; + int hlen; + int termidx; + int res; + int err = 0; + char *hptr; + char *tok; + uint8_t hostaddr[IP_ADDR_LEN]; + uint8_t termstr[4]; + uint8_t b; + + if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + fsctx = (http_fsctx_t *) fsctx_arg; + + file = KMALLOC(sizeof(http_file_t),0); + if (!file) { + return CFE_ERR_NOMEM; + } + + file->http_filename = lib_strdup(filename); + if (!file->http_filename) { + KFREE(file); + return CFE_ERR_NOMEM; + } + + lib_chop_filename(file->http_filename,&hostname,&filen); + + /* + * Look up remote host + */ + + res = dns_lookup(hostname,hostaddr); + if (res < 0) { + KFREE(file); + return res; + } + + file->http_socket = tcp_socket(); + if (file->http_socket < 0) { + KFREE(file->http_filename); + KFREE(file); + return -1; + } + + /* + * Connect to remote host. + */ + + tcp_setflags(file->http_socket,0); /* set socket to blocking */ + res = tcp_connect(file->http_socket,hostaddr,80); + + if (res < 0) { + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); + return res; + } + + /* + * Send GET command. Supply the hostname (for HTTP 1.1 requirements) + * and set the connection to close as soon as all the data is received. + */ + + hlen = sprintf(temp,"GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",filen,hostname); + + res = tcp_send(file->http_socket,temp,hlen); + if (res < 0) { + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); + return res; + } + + /* + * Read bytes until we either reach EOF or we see "\r\n\r\n" + * This is the server's status string. + */ + + termstr[0] = '\r'; termstr[1] = '\n'; + termstr[2] = '\r'; termstr[3] = '\n'; + termidx = 0; + + file->http_offset = 0; + file->http_blen = 0; + file->http_bptr = file->http_buffer; + + res = 0; + for (;;) { + res = tcp_recv(file->http_socket,&b,1); + if (res < 0) break; + if (b == termstr[termidx]) { + termidx++; + if (termidx == 4) break; + } + else { + termidx = 0; + } + + /* + * Save the bytes from the header up to our buffer + * size. It's okay if we don't save it all, + * since all we want is the result code which comes + * first. + */ + + if (file->http_blen < (HTTP_BUFSIZE-1)) { + *(file->http_bptr) = b; + file->http_bptr++; + file->http_blen++; + } + } + + /* + * Premature EOFs are not good, bail now. + */ + + if (res < 0) { + err = CFE_ERR_EOF; + goto protocolerr; + } + + /* + * Skip past the HTTP response header and grab the result code. + * Sanity check it a little. + */ + + *(file->http_bptr) = 0; + + hptr = file->http_buffer; + tok = lib_gettoken(&hptr); + if (!tok || (memcmp(tok,"HTTP",4) != 0)) { + err = CFE_ERR_PROTOCOLERR; + goto protocolerr; + } + + tok = lib_gettoken(&hptr); + if (!tok) { + err = CFE_ERR_PROTOCOLERR; + goto protocolerr; + } + + switch (lib_atoi(tok)) { + case 200: + err = 0; + break; + case 404: + err = CFE_ERR_FILENOTFOUND; + break; + + } + + /* + * If we get to here, the file is okay and we're about to receive data. + */ + + if (err == 0) { + *ref = file; + return 0; + } + +protocolerr: + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); + *ref = NULL; + return err; +} + +static int http_fileop_read(void *ref,uint8_t *buf,int len) +{ + http_file_t *file = (http_file_t *) ref; + int res; + + res = tcp_recv(file->http_socket,buf,len); + + if (res > 0) { + file->http_offset += res; + return res; + } + + return 0; /* Any error becomes "EOF" */ +} + +static int http_fileop_write(void *ref,uint8_t *buf,int len) +{ + return CFE_ERR_UNSUPPORTED; +} + +static int http_fileop_seek(void *ref,int offset,int how) +{ + http_file_t *file = (http_file_t *) ref; + int newoffset; + int res; + int buflen; + + switch (how) { + case FILE_SEEK_BEGINNING: + newoffset = offset; + break; + case FILE_SEEK_CURRENT: + newoffset = file->http_offset + offset; + break; + default: + newoffset = offset; + break; + } + + /* + * Can't seek backwards. + */ + if (newoffset < file->http_offset) { + return CFE_ERR_UNSUPPORTED; + } + + /* + * Eat data till offset reaches where we want. + */ + + while (file->http_offset != newoffset) { + buflen = HTTP_BUFSIZE; + if (buflen > (newoffset - file->http_offset)) buflen = (newoffset-file->http_offset); + res = tcp_recv(file->http_socket,file->http_buffer,buflen); + if (res < 0) break; + file->http_offset += res; + } + + return file->http_offset; +} + + +static void http_fileop_close(void *ref) +{ + http_file_t *file = (http_file_t *) ref; + + tcp_close(file->http_socket); + KFREE(file->http_filename); + KFREE(file); +} + +static void http_fileop_uninit(void *fsctx_arg) +{ + http_fsctx_t *fsctx = (http_fsctx_t *) fsctx_arg; + + KFREE(fsctx); +} + +#endif diff --git a/cfe/cfe/main/cfe_iocb_dispatch.c b/cfe/cfe/main/cfe_iocb_dispatch.c new file mode 100755 index 0000000..24aea0a --- /dev/null +++ b/cfe/cfe/main/cfe_iocb_dispatch.c @@ -0,0 +1,647 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB dispatcher File: cfe_iocb_dispatch.c + * + * This routine is the main API dispatch for CFE. User API + * calls, via the ROM entry point, get dispatched to routines + * in this module. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_queue.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_error.h" +#include "cfe_device.h" +#include "cfe_timer.h" +#include "cfe_mem.h" +#include "cfe_fileops.h" +#include "cfe_boot.h" +#include "env_subr.h" +#include "cfe.h" +#include "cfe_console.h" +#include "bsp_config.h" +#include "initdata.h" + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#define HV 1 /* handle valid */ + +#ifndef CFG_BOARD_ID +#define CFG_BOARD_ID 0 +#endif + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +cfe_devctx_t *cfe_handle_table[CFE_MAX_HANDLE]; + +extern void _cfe_flushcache(int); + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +int cfe_iocb_dispatch(cfe_iocb_t *iocb); +void cfe_device_poll(void *); + +#if CFG_MULTI_CPUS +extern int altcpu_cmd_start(uint64_t,uint64_t *); +extern int altcpu_cmd_stop(uint64_t); +#endif + +/* ********************************************************************* + * Dispatch table + ********************************************************************* */ + +struct cfe_cmd_dispatch_s { + int plistsize; + int flags; + int (*func)(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +}; + + +static int cfe_cmd_fw_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_restart(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_boot(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_cpuctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_gettime(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_memenum(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_fw_flushcache(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +static int cfe_cmd_dev_gethandle(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_open(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_inpstat(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_read(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_write(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_ioctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_close(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_dev_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +static int cfe_cmd_env_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_env_get(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_env_set(cfe_devctx_t *ctx,cfe_iocb_t *iocb); +static int cfe_cmd_env_del(cfe_devctx_t *ctx,cfe_iocb_t *iocb); + +const static struct cfe_cmd_dispatch_s cfe_cmd_dispatch_table[CFE_CMD_MAX] = { + {sizeof(iocb_fwinfo_t), 0, cfe_cmd_fw_getinfo}, /* 0 : CFE_CMD_FW_GETINFO */ + {sizeof(iocb_exitstat_t),0, cfe_cmd_fw_restart}, /* 1 : CFE_CMD_FW_RESTART */ + {sizeof(iocb_buffer_t), 0, cfe_cmd_fw_boot}, /* 2 : CFE_CMD_FW_BOOT */ + {sizeof(iocb_cpuctl_t), 0, cfe_cmd_fw_cpuctl}, /* 3 : CFE_CMD_FW_CPUCTL */ + {sizeof(iocb_time_t), 0, cfe_cmd_fw_gettime}, /* 4 : CFE_CMD_FW_GETTIME */ + {sizeof(iocb_meminfo_t),0, cfe_cmd_fw_memenum}, /* 5 : CFE_CMD_FW_MEMENUM */ + {0, 0, cfe_cmd_fw_flushcache}, /* 6 : CFE_CMD_FW_FLUSHCACHE */ + {-1, 0, NULL}, /* 7 : */ + {-1, 0, NULL}, /* 8 : */ + {0, 0, cfe_cmd_dev_gethandle}, /* 9 : CFE_CMD_DEV_GETHANDLE */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_dev_enum}, /* 10 : CFE_CMD_DEV_ENUM */ + {sizeof(iocb_buffer_t), 0, cfe_cmd_dev_open}, /* 11 : CFE_CMD_DEV_OPEN */ + {sizeof(iocb_inpstat_t),HV, cfe_cmd_dev_inpstat}, /* 12 : CFE_CMD_DEV_INPSTAT */ + {sizeof(iocb_buffer_t), HV, cfe_cmd_dev_read}, /* 13 : CFE_CMD_DEV_READ */ + {sizeof(iocb_buffer_t), HV, cfe_cmd_dev_write}, /* 14 : CFE_CMD_DEV_WRITE */ + {sizeof(iocb_buffer_t), HV, cfe_cmd_dev_ioctl}, /* 15 : CFE_CMD_DEV_IOCTL */ + {0, HV, cfe_cmd_dev_close}, /* 16 : CFE_CMD_DEV_CLOSE */ + {sizeof(iocb_buffer_t), 0, cfe_cmd_dev_getinfo}, /* 17 : CFE_CMD_DEV_GETINFO */ + {-1, 0, NULL}, /* 18 : */ + {-1, 0, NULL}, /* 19 : */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_enum}, /* 20 : CFE_CMD_ENV_ENUM */ + {-1, 0, NULL}, /* 21 : */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_get}, /* 22 : CFE_CMD_ENV_GET */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_set}, /* 23 : CFE_CMD_ENV_SET */ + {sizeof(iocb_envbuf_t), 0, cfe_cmd_env_del}, /* 24 : CFE_CMD_ENV_DEL */ + {-1, 0, NULL}, /* 25 : */ + {-1, 0, NULL}, /* 26 : */ + {-1, 0, NULL}, /* 27 : */ + {-1, 0, NULL}, /* 28 : */ + {-1, 0, NULL}, /* 29 : */ + {-1, 0, NULL}, /* 30 : */ + {-1, 0, NULL} /* 31 : */ +}; + +/* ********************************************************************* + * IOCB dispatch routines + ********************************************************************* */ + +void cfe_device_poll(void *x) +{ + int idx; + cfe_devctx_t **ctx = cfe_handle_table; + + for (idx = 0; idx < CFE_MAX_HANDLE; idx++,ctx++) { + if ((*ctx) && ((*ctx)->dev_dev->dev_dispatch->dev_poll)) { + (*ctx)->dev_dev->dev_dispatch->dev_poll(*ctx,cfe_ticks); + } + } +} + +int cfe_iocb_dispatch(cfe_iocb_t *iocb) +{ + const struct cfe_cmd_dispatch_s *disp; + int res; + cfe_devctx_t *ctx; + + /* + * Check for commands codes out of range + */ + + if ((iocb->iocb_fcode < 0) || (iocb->iocb_fcode >= CFE_CMD_MAX)) { + iocb->iocb_status = CFE_ERR_INV_COMMAND; + return iocb->iocb_status; + } + + /* + * Check for command codes in range but invalid + */ + + disp = &cfe_cmd_dispatch_table[iocb->iocb_fcode]; + + if (disp->plistsize < 0) { + iocb->iocb_status = CFE_ERR_INV_COMMAND; + return iocb->iocb_status; + } + + /* + * Check for invalid parameter list size + */ + + if (disp->plistsize != iocb->iocb_psize) { + iocb->iocb_status = CFE_ERR_INV_PARAM; + return iocb->iocb_status; + } + + /* + * Determine handle + */ + + ctx = NULL; + if (disp->flags & HV) { + if ((iocb->iocb_handle >= CFE_MAX_HANDLE) || + (iocb->iocb_handle < 0) || + (cfe_handle_table[iocb->iocb_handle] == NULL)){ + iocb->iocb_status = CFE_ERR_INV_PARAM; + return iocb->iocb_status; + } + ctx = cfe_handle_table[iocb->iocb_handle]; + } + + /* + * Dispatch to handler routine + */ + + res = (*disp->func)(ctx,iocb); + + iocb->iocb_status = res; + return res; +} + +static int cfe_newhandle(void) +{ + int idx; + + for (idx = 0; idx < CFE_MAX_HANDLE; idx++) { + if (cfe_handle_table[idx] == NULL) break; + } + + if (idx == CFE_MAX_HANDLE) return -1; + + return idx; +} + + +/* ********************************************************************* + * Implementation routines for each IOCB function + ********************************************************************* */ + +static int cfe_cmd_fw_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + iocb_fwinfo_t *info = &iocb->plist.iocb_fwinfo; + + info->fwi_version = (CFE_VER_MAJOR << 16) | + (CFE_VER_MINOR << 8) | + (CFE_VER_BUILD); + info->fwi_totalmem = ((cfe_int64_t) mem_totalsize) << 20; + info->fwi_flags = +#ifdef __long64 + CFE_FWI_64BIT | +#else + CFE_FWI_32BIT | +#endif +#if (CFG_EMBEDDED_PIC) + CFE_FWI_RELOC | +#endif +#if (!CFG_RUNFROMKSEG0) + CFE_FWI_UNCACHED | +#endif +#if CFG_MULTI_CPUS + CFE_FWI_MULTICPU | +#endif +#ifdef _VERILOG_ + CFE_FWI_RTLSIM | +#endif +#ifdef _FUNCSIM_ + CFE_FWI_FUNCSIM | +#endif + 0; + + info->fwi_boardid = CFG_BOARD_ID; + info->fwi_bootarea_pa = (cfe_int64_t) mem_bootarea_start; + info->fwi_bootarea_va = BOOT_START_ADDRESS; + info->fwi_bootarea_size = (cfe_int64_t) mem_bootarea_size; + info->fwi_reserved1 = 0; + info->fwi_reserved2 = 0; + info->fwi_reserved3 = 0; + + return CFE_OK; +} + +static int cfe_cmd_fw_restart(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + if (iocb->iocb_flags & CFE_FLG_WARMSTART) { + cfe_warmstart(iocb->plist.iocb_exitstat.status); + } + else { + cfe_restart(); + } + + /* should not get here */ + + return CFE_OK; +} + +static int cfe_cmd_fw_boot(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + return CFE_ERR_INV_COMMAND; /* not implemented yet */ +} + +static int cfe_cmd_fw_cpuctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ +#if CFG_MULTI_CPUS + int res; + uint64_t startargs[4]; + + switch (iocb->plist.iocb_cpuctl.cpu_command) { + case CFE_CPU_CMD_START: + + startargs[0] = iocb->plist.iocb_cpuctl.start_addr; + startargs[1] = iocb->plist.iocb_cpuctl.sp_val; + startargs[2] = iocb->plist.iocb_cpuctl.gp_val; + startargs[3] = iocb->plist.iocb_cpuctl.a1_val; + + res = altcpu_cmd_start(iocb->plist.iocb_cpuctl.cpu_number, + startargs); + break; + case CFE_CPU_CMD_STOP: + res = altcpu_cmd_stop(iocb->plist.iocb_cpuctl.cpu_number); + break; + default: + res = CFE_ERR_INV_PARAM; + } + + return res; +#else + return CFE_ERR_INV_COMMAND; +#endif +} + +static int cfe_cmd_fw_gettime(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + POLL(); + + iocb->plist.iocb_time.ticks = cfe_ticks; + + return CFE_OK; +} + +static int cfe_cmd_fw_memenum(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int type; + int res; + uint64_t addr,size; + + res = cfe_arena_enum(iocb->plist.iocb_meminfo.mi_idx, + &type, + &addr, + &size, + (iocb->iocb_flags & CFE_FLG_FULL_ARENA) ? TRUE : FALSE); + + iocb->plist.iocb_meminfo.mi_addr = addr; + iocb->plist.iocb_meminfo.mi_size = size; + iocb->plist.iocb_meminfo.mi_type = type; + + if (res == 0) { + if (type == MEMTYPE_DRAM_AVAILABLE) { + iocb->plist.iocb_meminfo.mi_type = CFE_MI_AVAILABLE; + } + else { + iocb->plist.iocb_meminfo.mi_type = CFE_MI_RESERVED; + } + } + + return res; +} + +static int cfe_cmd_fw_flushcache(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + _cfe_flushcache(iocb->iocb_flags); + return CFE_OK; +} + +static int cfe_cmd_dev_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + return CFE_ERR_INV_COMMAND; +} + +static int cfe_cmd_dev_gethandle(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + switch (iocb->iocb_flags) { + case CFE_STDHANDLE_CONSOLE: + if (console_handle == -1) return CFE_ERR_DEVNOTFOUND; + iocb->iocb_handle = console_handle; + return CFE_OK; + break; + default: + return CFE_ERR_INV_PARAM; + } +} + +static int cfe_cmd_dev_open(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int h; + cfe_device_t *dev; + char devname[64]; + int res; + + /* + * Get device name + */ + + xstrncpy(devname,(char*)iocb->plist.iocb_buffer.buf_ptr,sizeof(devname)); + + /* + * Find device in device table + */ + + dev = cfe_finddev(devname); + if (!dev) return CFE_ERR_DEVNOTFOUND; + + /* + * Fail if someone else already has the device open + */ + + if (dev->dev_opencount > 0) return CFE_ERR_DEVOPEN; + + /* + * Generate a new handle + */ + + h = cfe_newhandle(); + if (h < 0) return CFE_ERR_NOMEM; + + /* + * Allocate a context + */ + + ctx = (cfe_devctx_t *) KMALLOC(sizeof(cfe_devctx_t),0); + if (ctx == NULL) return CFE_ERR_NOMEM; + + /* + * Fill in the context + */ + + ctx->dev_dev = dev; + ctx->dev_softc = dev->dev_softc; + ctx->dev_openinfo = NULL; + + /* + * Call driver's open func + */ + + res = dev->dev_dispatch->dev_open(ctx); + + if (res != 0) { + KFREE(ctx); + return res; + } + + /* + * Increment refcnt and save handle + */ + + dev->dev_opencount++; + cfe_handle_table[h] = ctx; + iocb->iocb_handle = h; + + /* + * Success! + */ + + return CFE_OK; +} + +static int cfe_cmd_dev_inpstat(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_inpstat(ctx,&(iocb->plist.iocb_inpstat)); + + return status; +} + +static int cfe_cmd_dev_read(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_read(ctx,&(iocb->plist.iocb_buffer)); + + return status; +} + +static int cfe_cmd_dev_write(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_write(ctx,&(iocb->plist.iocb_buffer)); + + return status; +} + +static int cfe_cmd_dev_ioctl(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int status; + + status = ctx->dev_dev->dev_dispatch->dev_ioctl(ctx,&(iocb->plist.iocb_buffer)); + + return status; +} + +static int cfe_cmd_dev_close(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + /* + * Call device close function + */ + + ctx->dev_dev->dev_dispatch->dev_close(ctx); + + /* + * Decrement refcnt + */ + + ctx->dev_dev->dev_opencount--; + + /* + * Wipe out handle + */ + + cfe_handle_table[iocb->iocb_handle] = NULL; + + /* + * Release device context + */ + + KFREE(ctx); + + return CFE_OK; +} + +static int cfe_cmd_dev_getinfo(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + cfe_device_t *dev; + char devname[64]; + char *x; + + /* + * Get device name + */ + + xstrncpy(devname,(char*)iocb->plist.iocb_buffer.buf_ptr,sizeof(devname)); + + /* + * Find device in device table + */ + + if ((x = strchr(devname,':'))) *x = '\0'; + dev = cfe_finddev(devname); + if (!dev) return CFE_ERR_DEVNOTFOUND; + + /* + * Return device class + */ + + iocb->plist.iocb_buffer.buf_devflags = dev->dev_class; + + return CFE_OK; +} + +static int cfe_cmd_env_enum(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int vallen,namelen,res; + + namelen = iocb->plist.iocb_envbuf.name_length; + vallen = iocb->plist.iocb_envbuf.val_length; + + res = env_enum(iocb->plist.iocb_envbuf.enum_idx, + (char*)iocb->plist.iocb_envbuf.name_ptr, + &namelen, + (char*)iocb->plist.iocb_envbuf.val_ptr, + &vallen); + + if (res < 0) return CFE_ERR_ENVNOTFOUND; + + return CFE_OK; +} + + +static int cfe_cmd_env_get(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + char *env; + + env = env_getenv((char*)iocb->plist.iocb_envbuf.name_ptr); + + if (env == NULL) return CFE_ERR_ENVNOTFOUND; + + xstrncpy((char*)iocb->plist.iocb_envbuf.val_ptr, + env, + iocb->plist.iocb_envbuf.val_length); + + return CFE_OK; +} + +static int cfe_cmd_env_set(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int res; + int flg; + + + flg = (iocb->iocb_flags & CFE_FLG_ENV_PERMANENT) ? + ENV_FLG_NORMAL : ENV_FLG_BUILTIN; + + res = env_setenv((char*)iocb->plist.iocb_envbuf.name_ptr, + (char*)iocb->plist.iocb_envbuf.val_ptr, + flg); + + if (res == 0) { + if (iocb->iocb_flags & CFE_FLG_ENV_PERMANENT) res = env_save(); + } + + if (res < 0) return res; + + return CFE_OK; +} + +static int cfe_cmd_env_del(cfe_devctx_t *ctx,cfe_iocb_t *iocb) +{ + int res; + + res = env_delenv((char*)iocb->plist.iocb_envbuf.name_ptr); + + return res; +} + + + diff --git a/cfe/cfe/main/cfe_ldr_elf.c b/cfe/cfe/main/cfe_ldr_elf.c new file mode 100644 index 0000000..0581241 --- /dev/null +++ b/cfe/cfe/main/cfe_ldr_elf.c @@ -0,0 +1,396 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * ELF Program Loader File: cfe_ldr_elf.c + * + * This program parses ELF executables and loads them into memory. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" +#include "cfe_timer.h" +#include "cfe_mem.h" + +#include "cfe.h" +#include "cfe_loader.h" +#include "cfe_fileops.h" +#include "elf.h" + +#include "cfe_boot.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +static int cfe_elfload(cfe_loadargs_t *la); + +const cfe_loader_t elfloader = { + "elf", + cfe_elfload, + 0}; + +/* ********************************************************************* + * readprogsegment(fsctx,ref,addr,size) + * + * Read a program segment, generally corresponding to one + * section of the file. + * + * Input parameters: + * fsctx - file I/O dispatch + * ref - reference data for open file handle + * addr - target virtual address + * size - size of region to read + * + * Return value: + * Number of bytes copied or <0 if error occured + ********************************************************************* */ + +static int readprogsegment(fileio_ctx_t *fsctx,void *ref, + void *addr,int size,int flags) +{ + int res; + +#ifdef __long64 + if (flags & LOADFLG_NOISY) xprintf("0x%016llx/%d ",addr,size); +#else + if (flags & LOADFLG_NOISY) xprintf("0x%x/%d ",addr,size); +#endif + + if (!cfe_arena_loadcheck((uintptr_t) addr,size)) { + return CFE_ERR_BADADDR; + } + + res = fs_read(fsctx,ref,addr,size); + + if (res < 0) return CFE_ERR_IOERR; + if (res != size) return CFE_ERR_BADELFFMT; + + return size; +} + + +/* ********************************************************************* + * readclearbss(addr,size) + * + * Process a BSS section, zeroing memory corresponding to + * the BSS. + * + * Input parameters: + * addr - address to zero + * size - length of area to zero + * + * Return value: + * number of zeroed bytes or <0 if error occured + ********************************************************************* */ + +static int readclearbss(void *addr,int size,int flags) +{ + +#ifdef __long64 + if (flags & LOADFLG_NOISY) xprintf("0x%016llx/%d ",addr,size); +#else + if (flags & LOADFLG_NOISY) xprintf("0x%x/%d ",addr,size); +#endif + + if (!cfe_arena_loadcheck((uintptr_t) addr,size)) { + return CFE_ERR_BADADDR; + } + + if (size > 0) memset(addr,0,size); + return size; +} + + +/* ********************************************************************* + * elfgetshdr(ops,ref,ep) + * + * Get a section header from the ELF file + * + * Input parameters: + * ops - file I/O dispatch + * ref - reference data for open file + * ep - extended header info + * + * Return value: + * copy of section header (malloc'd) or NULL if no memory + ********************************************************************* */ + +static Elf32_Shdr *elfgetshdr(fileio_ctx_t *fsctx,void *ref,Elf32_Ehdr *ep) +{ + Elf32_Shdr *shtab; + unsigned size = ep->e_shnum * sizeof(Elf32_Shdr); + + shtab = (Elf32_Shdr *) KMALLOC(size,0); + if (!shtab) { + return NULL; + } + + if (fs_seek(fsctx,ref,ep->e_shoff,FILE_SEEK_BEGINNING) != ep->e_shoff || + fs_read(fsctx,ref,(uint8_t *)shtab,size) != size) { + KFREE(shtab); + return NULL; + } + + return (shtab); +} + +/* ********************************************************************* + * elfload_internal(ops,ref,entrypt,flags) + * + * Read an ELF file (main routine) + * + * Input parameters: + * ops - file I/O dispatch + * ref - open file handle + * entrypt - filled in with entry vector + * flags - generic boot flags + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +static int elfload_internal(fileio_ctx_t *fsctx,void *ref, + unsigned long *entrypt,int flags) +{ + Elf32_Ehdr *ep; + Elf32_Phdr *phtab = 0; + Elf32_Shdr *shtab = 0; + unsigned int nbytes; + int i; + int res; + Elf32_Ehdr ehdr; + + ep = &ehdr; + if (fs_read(fsctx,ref,(uint8_t *) ep,sizeof(*ep)) != sizeof(*ep)) { + return CFE_ERR_IOERR; + } + + /* check header validity */ + if (ep->e_ident[EI_MAG0] != ELFMAG0 || + ep->e_ident[EI_MAG1] != ELFMAG1 || + ep->e_ident[EI_MAG2] != ELFMAG2 || + ep->e_ident[EI_MAG3] != ELFMAG3) { + return CFE_ERR_NOTELF; + } + + if (ep->e_ident[EI_CLASS] != ELFCLASS32) return CFE_ERR_NOT32BIT; + +#ifdef __MIPSEB + if (ep->e_ident[EI_DATA] != ELFDATA2MSB) return CFE_ERR_WRONGENDIAN; /* big endian */ +#endif +#ifdef __MIPSEL + if (ep->e_ident[EI_DATA] != ELFDATA2LSB) return CFE_ERR_WRONGENDIAN; /* little endian */ +#endif + + if (ep->e_ident[EI_VERSION] != EV_CURRENT) return CFE_ERR_BADELFVERS; + if (ep->e_machine != EM_MIPS) return CFE_ERR_NOTMIPS; + + /* Is there a program header? */ + if (ep->e_phoff == 0 || ep->e_phnum == 0 || + ep->e_phentsize != sizeof(Elf32_Phdr)) { + return CFE_ERR_BADELFFMT; + } + + /* Load program header */ + nbytes = ep->e_phnum * sizeof(Elf32_Phdr); + phtab = (Elf32_Phdr *) KMALLOC(nbytes,0); + if (!phtab) { + return CFE_ERR_NOMEM; + } + + if (fs_seek(fsctx,ref,ep->e_phoff,FILE_SEEK_BEGINNING) != ep->e_phoff || + fs_read(fsctx,ref,(uint8_t *)phtab,nbytes) != nbytes) { + KFREE(phtab); + return CFE_ERR_IOERR; + } + + /* + * From now on we've got no guarantee about the file order, + * even where the section header is. Hopefully most linkers + * will put the section header after the program header, when + * they know that the executable is not demand paged. We assume + * that the symbol and string tables always follow the program + * segments. + */ + + /* read section table (if before first program segment) */ + if (ep->e_shoff < phtab[0].p_offset) { + shtab = elfgetshdr(fsctx,ref,ep); + } + + /* load program segments */ + /* We cope with a badly sorted program header, as produced by + * older versions of the GNU linker, by loading the segments + * in file offset order, not in program header order. */ + + while (1) { + Elf32_Off lowest_offset = ~0; + Elf32_Phdr *ph = 0; + + /* find nearest loadable segment */ + for (i = 0; i < ep->e_phnum; i++) + if ((phtab[i].p_type == PT_LOAD) && (phtab[i].p_offset < lowest_offset)) { + ph = &phtab[i]; + lowest_offset = ph->p_offset; + } + if (!ph) { + break; /* none found, finished */ + } + + /* load the segment */ + if (ph->p_filesz) { + if (fs_seek(fsctx,ref,ph->p_offset,FILE_SEEK_BEGINNING) != ph->p_offset) { + if (shtab) KFREE(shtab); + KFREE(phtab); + return CFE_ERR_BADELFFMT; + } + res = readprogsegment(fsctx,ref, + (void *)(intptr_t)(signed)ph->p_vaddr, + ph->p_filesz,flags); + if (res != ph->p_filesz) { + if (shtab) KFREE(shtab); + KFREE(phtab); + return res; + } + } + + if (ph->p_filesz < ph->p_memsz) { + res = readclearbss((void *)(intptr_t)(signed)ph->p_vaddr + ph->p_filesz, + ph->p_memsz - ph->p_filesz,flags); + if (res < 0) { + if (shtab) KFREE(shtab); + KFREE(phtab); + return res; + } + } + + ph->p_type = PT_NULL; /* remove from consideration */ + } + + KFREE(phtab); + + *entrypt = (intptr_t)(signed)ep->e_entry; /* return entry point */ + return 0; +} + + + +/* ********************************************************************* + * cfe_elfload(ops,file,flags) + * + * Read an ELF file (main entry point) + * + * Input parameters: + * ops - fileio dispatch + * file - name of file to read + * ept - where to put entry point + * flags - load flags + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +static int cfe_elfload(cfe_loadargs_t *la) +{ + fileio_ctx_t *fsctx; + void *ref; + int res; + + /* + * Look up the file system type and get a context + */ + + + res = fs_init(la->la_filesys,&fsctx,la->la_device); + if (res != 0) { + return res; + } + + /* + * Turn on compression if we're doing that. + */ + + if (la->la_flags & LOADFLG_COMPRESSED) { + res = fs_hook(fsctx,"z"); + if (res != 0) { + return res; + } + } + + /* + * Open the remote file + */ + + res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ); + if (res != 0) { + fs_uninit(fsctx); + return CFE_ERR_FILENOTFOUND; + } + + /* + * Load the image. + */ + + la->la_entrypt = 0; + res = elfload_internal(fsctx,ref,&(la->la_entrypt),la->la_flags); + + /* + * All done, release resources + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + return res; +} + + diff --git a/cfe/cfe/main/cfe_ldr_raw.c b/cfe/cfe/main/cfe_ldr_raw.c new file mode 100644 index 0000000..d436849 --- /dev/null +++ b/cfe/cfe/main/cfe_ldr_raw.c @@ -0,0 +1,360 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * RAW Program Loader File: cfe_ldr_raw.c + * + * This program reads raw binaries into memory. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" + +#include "cfe.h" +#include "cfe_fileops.h" + +#include "cfe_boot.h" +#include "cfe_bootblock.h" + +#include "cfe_loader.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +static int cfe_rawload(cfe_loadargs_t *la); + +const cfe_loader_t rawloader = { + "raw", + cfe_rawload, + 0}; + +/* ********************************************************************* + * cfe_findbootblock(la,fsctx,ref) + * + * Find the boot block on the specified device. + * + * Input parameters: + * la - loader args (to be filled in) + * ops - file operations + * ref - reference for open file handle + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ +static int cfe_findbootblock(cfe_loadargs_t *la, + fileio_ctx_t *fsctx, + void *ref, + struct boot_block *bootblock) +{ + uint32_t checksum = 0; + uint32_t calcsum; + uint32_t secsize = 0; + uint64_t secoffset = 0; + int res; + int curblk; + + /* + * Search for the boot block. Stop when we find + * something with a matching checksum and magic + * number. + */ + + fs_seek(fsctx,ref,0,FILE_SEEK_BEGINNING); + + for (curblk = 0; curblk < BOOT_BLOCK_MAXLOC; curblk++) { + + + /* Read a block */ + + res = fs_read(fsctx,ref, + (unsigned char *) bootblock, + sizeof(struct boot_block)); + + if (res != sizeof(struct boot_block)) { + return CFE_ERR_IOERR; + } + + /* Verify magic number */ + + if (bootblock->bb_magic != BOOT_MAGIC_NUMBER) { + continue; + } + + /* Extract fields from block */ + + checksum = ((uint32_t) (bootblock->bb_hdrinfo & BOOT_HDR_CHECKSUM_MASK)); + bootblock->bb_hdrinfo &= ~BOOT_HDR_CHECKSUM_MASK; + secsize = ((uint32_t) (bootblock->bb_secsize & BOOT_SECSIZE_MASK)); + secoffset = bootblock->bb_secstart; + + /* Verify block's checksum */ + + CHECKSUM_BOOT_DATA(&(bootblock->bb_magic),BOOT_BLOCK_SIZE,&calcsum); + + if (checksum == calcsum) { + break; + } + } + + /* + * Okay, determine if we were successful. + */ + + if (bootblock->bb_magic != BOOT_MAGIC_NUMBER) { + return CFE_ERR_INVBOOTBLOCK; + } + + if (checksum != calcsum) { + return CFE_ERR_BBCHECKSUM; + } + + /* + * If we get here, we had a valid boot block. + */ + + return 0; +} + + +/* ********************************************************************* + * cfe_rawload(la) + * + * Read a raw (unformatted) boot file + * + * Input parameters: + * la - loader args + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ +static int cfe_rawload(cfe_loadargs_t *la) +{ + int res; + fileio_ctx_t *fsctx; + const fileio_dispatch_t *ops; + void *ref; + int ttlcopy = 0; + int findbb; + int devinfo; + struct boot_block bootblock; + uint8_t *ptr; + uint8_t *bootcode; + uint32_t checksum,calcsum; + uint64_t secoffset = 0; + int32_t maxsize; + int amtcopy; + int thisamt; + uint32_t loadflags; + int onedot; + + loadflags = la->la_flags; + + /* + * Set starting address and maximum size. You can either + * explicitly set this (with LOADFLG_SPECADDR) or + * let CFE decide. If CFE decides, the load address + * will be BOOT_START_ADDRESS in all cases. + * The size is dependant on the device type: block and flash + * devices will get this info from the boot block, + * and network devices will get the info by reaching EOF + * on reads, up to the maximum size of the boot area. + */ + + if (loadflags & LOADFLG_SPECADDR) { + bootcode = (uint8_t *) la->la_address; + maxsize = la->la_maxsize; + findbb = FALSE; /* don't find a boot block */ + } + else { + bootcode = (uint8_t *) BOOT_START_ADDRESS; + maxsize = BOOT_AREA_SIZE; + findbb = FALSE; + devinfo = la->la_device ? cfe_getdevinfo(la->la_device) : 0; + + /* + * If the device is either a disk or a flash device, + * we will expect to find a boot block. + * Serial and network devices do not have boot blocks. + */ + if ((devinfo >= 0) && + ( ((devinfo & CFE_DEV_MASK) == CFE_DEV_DISK) || + ((devinfo & CFE_DEV_MASK) == CFE_DEV_FLASH) )) { + findbb = TRUE; + } + } + + + /* + * merge in any filesystem-specific flags + */ + + ops = cfe_findfilesys(la->la_filesys); + if (!ops) return CFE_ERR_FSNOTAVAIL; + loadflags |= ops->loadflags; + + /* + * turn off the boot block if requested. + */ + + if (loadflags & LOADFLG_NOBB) findbb = FALSE; + + /* + * Create a file system context + */ + + res = fs_init(la->la_filesys,&fsctx,la->la_device); + if (res != 0) { + return res; + } + + /* + * Turn on compression if we're doing that. + */ + + if (!findbb && (la->la_flags & LOADFLG_COMPRESSED)) { + res = fs_hook(fsctx,"z"); + if (res != 0) { + return res; + } + } + + /* + * Open the boot device + */ + + res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ); + if (res != 0) { + fs_uninit(fsctx); + return res; + } + + /* + * If we need to find a boot block, do it now. + */ + + if (findbb) { + res = cfe_findbootblock(la,fsctx,ref,&bootblock); + + /* + * If we found the boot block, seek to the part of the + * disk where the boot code is. + * Otherwise, get out now, since the disk has no boot block. + */ + + if (res == 0) { + maxsize = (int) ((uint32_t) (bootblock.bb_secsize & BOOT_SECSIZE_MASK)); + secoffset = bootblock.bb_secstart; + fs_seek(fsctx,ref,secoffset,FILE_SEEK_BEGINNING); + } + else { + fs_close(fsctx,ref); + fs_uninit(fsctx); + return res; + } + + } + + /* + * Okay, go load the boot file. + */ + + ptr = bootcode; + amtcopy = maxsize; + ttlcopy = 0; + + onedot = amtcopy / 10; /* ten dots for entire load */ + if (onedot < 4096) onedot = 4096; /* but minimum 4096 bytes per dot */ + onedot = (onedot + 1) & ~4095; /* round to multiple of 4096 */ + + while (amtcopy > 0) { + thisamt = onedot; + if (thisamt > amtcopy) thisamt = amtcopy; + + res = fs_read(fsctx,ref,ptr,thisamt); + if (la->la_flags & LOADFLG_NOISY) { + xprintf("."); + } + if (res <= 0) break; + ptr += res; + amtcopy -= res; + ttlcopy += res; + } + + /* + * We're done with the file. + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + /* + * Verify the boot loader checksum if we were reading + * the disk. + */ + + if (findbb) { + CHECKSUM_BOOT_DATA(bootcode,maxsize,&calcsum); + checksum = (uint32_t) ((bootblock.bb_secsize & BOOT_DATA_CHECKSUM_MASK) + >> BOOT_DATA_CHECKSUM_SHIFT); + + if (checksum != calcsum) { + return CFE_ERR_BOOTPROGCHKSUM; + } + } + + la->la_entrypt = (uintptr_t) bootcode; + + if (la->la_flags & LOADFLG_NOISY) xprintf(" %d bytes read\n",ttlcopy); + + return (res < 0) ? res : ttlcopy; + +} + diff --git a/cfe/cfe/main/cfe_ldr_srec.c b/cfe/cfe/main/cfe_ldr_srec.c new file mode 100644 index 0000000..b067f2b --- /dev/null +++ b/cfe/cfe/main/cfe_ldr_srec.c @@ -0,0 +1,557 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * SREC Program Loader File: cfe_ldr_srec.c + * + * This program reads Motorola S-record files into memory + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" + +#include "cfe.h" +#include "cfe_fileops.h" + +#include "cfe_boot.h" +#include "cfe_bootblock.h" + +#include "cfe_loader.h" + +#include "cfe_mem.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +static int cfe_srecload(cfe_loadargs_t *la); + +const cfe_loader_t srecloader = { + "srec", + cfe_srecload, + 0}; + + +typedef struct linebuf_s { + char linebuf[256]; + int curidx; + int buflen; + int eof; + void *ref; + fileio_ctx_t *fsctx; +} linebuf_t; + +#define initlinebuf(b,r,o) (b)->curidx = 0; (b)->buflen = 0; \ + (b)->eof = 0 ; (b)->ref = r; (b)->fsctx = o + + +/* ********************************************************************* + * readchar(file) + * + * Read a character from a file. It's kind of like getchar + * on "C" FILE devices, but not so fancy. + * + * Input parameters: + * file - pointer to a linebuf_t containing reader state + * + * Return value: + * character, or -1 if at EOF + ********************************************************************* */ + +static int readchar(linebuf_t *file) +{ + int ch; + int res; + + if (file->eof) return -1; + + if (file->curidx == file->buflen) { + for (;;) { + res = fs_read(file->fsctx,file->ref,file->linebuf,sizeof(file->linebuf)); + if (res < 0) { + file->eof = -1; + return -1; + } + if (res == 0) continue; + file->buflen = res; + file->curidx = 0; + break; + } + } + + ch = file->linebuf[file->curidx]; + file->curidx++; + return ch; +} + + +/* ********************************************************************* + * readline(file,buffer,maxlen) + * + * Read a line of text from a file using our crude file stream + * mechanism. + * + * Input parameters: + * file - pointer to a linebuf_t containing reader state + * buffer - will receive line of text + * maxlen - number of bytes that will fit in buffer + * + * Return value: + * 0 if ok, else <0 if at EOF + ********************************************************************* */ + +static int readline(linebuf_t *file,char *buffer,int maxlen) +{ + int ch; + char *ptr; + + ptr = buffer; + maxlen--; /* account for terminating null */ + + while (maxlen) { + ch = readchar(file); + if (ch == -1) return -1; + if (ch == 27) return -1; /* ESC */ + if ((ch == '\n') || (ch == '\r')) break; + *ptr++ = (char) ch; + maxlen--; + } + + *ptr = '\0'; + + return 0; +} + + +/* ********************************************************************* + * getxdigit(c) + * + * Convert a hex digit into its numeric equivalent + * + * Input parameters: + * c - character + * + * Return value: + * value + ********************************************************************* */ + +static int getxdigit(char c) +{ + if ((c >= '0') && (c <= '9')) return c - '0'; + if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10; + if ((c >= 'a') && (c <= 'f')) return c - 'a' + 10; + return -1; +} + +/* ********************************************************************* + * getbyte(line) + * + * Process two hex digits and return the value + * + * Input parameters: + * line - pointer to pointer to characters (updated on exit) + * + * Return value: + * byte value, or <0 if bad hex digits + ********************************************************************* */ + +static int getbyte(char **line) +{ + int res; + int c1,c2; + + c1 = getxdigit(*(*(line)+0)); + if (c1 < 0) return -1; + + c2 = getxdigit(*(*(line)+1)); + if (c2 < 0) return -1; + + res = (c1*16+c2); + (*line) += 2; + + return res; +} + + +/* ********************************************************************* + * procsrec(line,loadaddr,blklen,data) + * + * Process an S-record, reading the data into a local buffer + * and returning the block's address. + * + * Input parameters: + * line - line of text (s-record line) + * loadaddr - will be filled with address where data should go + * blklen - will be filled in with size of record + * data - points to buffer to receive data + * + * Return value: + * <0 if error occured (not an s-record) + ********************************************************************* */ + +static int procsrec(char *line, + unsigned int *loadaddr, + unsigned int *blklen, + unsigned char *data) +{ + char rectype; + unsigned char b; + unsigned int len; + unsigned int minlen; + unsigned int linelen; + unsigned int addr; + unsigned int chksum; + + int idx; + int ret = 0; + + addr = 0; + + if (*line++ != 'S') + return -1; /* not an S record */ + + rectype = *line++; + + minlen = 3; /* type 1 record */ + switch (rectype) { + case '0': + break; + + /* + * data bytes + */ + case '3': + minlen++; + /* fall through */ + case '2': + minlen++; + /* fall through */ + case '1': + chksum = 0; + linelen = getbyte(&line); + if (linelen < minlen) { + xprintf("srec: line too short\n"); + return -1; + } + chksum += (unsigned int)linelen; + + /* + * There are two address bytes in a type 1 record, and three + * in a type 2 record. The high-order byte is first, then + * one or two lower-order bytes. Build up the adddress. + */ + b = getbyte(&line); + chksum += (unsigned int)b; + addr = b; + b = getbyte(&line); + chksum += (unsigned int)b; + addr <<= 8; + addr += b; + if (rectype == '2') { + b = getbyte(&line); + chksum += (unsigned int)b; + addr <<= 8; + addr += b; + } + if (rectype == '3') { + b = getbyte(&line); + chksum += (unsigned int)b; + addr <<= 8; + addr += b; + b = getbyte(&line); + chksum += (unsigned int)b; + addr <<= 8; + addr += b; + } + +#if VERBOSE + printf("Addr: %08X Len: %3u(0x%x)\n", addr , linelen - minlen, + linelen-minlen); +#endif + + *loadaddr = addr; + len = linelen - minlen; + *blklen = len; + + for (idx = 0; idx < len; idx++) { + b = getbyte(&line); + chksum += (unsigned int) b; + data[idx] = (unsigned char ) b; + } + + b = getbyte(&line); + chksum = (~chksum) & 0x000000FF; + if (chksum != b) { + xprintf("Checksum error in s-record file\n"); + return -1; + } + ret = 1; + break; + + case '9': + linelen = getbyte(&line); + b = getbyte(&line); + addr = b; + b = getbyte(&line); + addr <<= 8; + addr += b; + *loadaddr = addr; + ret = -2; + break; + + case '8': + linelen = getbyte(&line); + b = getbyte(&line); + addr = b; + b = getbyte(&line); + addr <<= 8; + addr += b; + b = getbyte(&line); + addr <<= 8; + addr += b; + *loadaddr = addr; + ret = -2; + break; + + case '7': + linelen = getbyte(&line); + b = getbyte(&line); + addr = b; + b = getbyte(&line); + addr <<= 8; + addr += b; + b = getbyte(&line); + addr <<= 8; + addr += b; + b = getbyte(&line); + addr <<= 8; + addr += b; + *loadaddr = addr; + ret = -2; + break; + + default: + xprintf("Unknown S-record type: %c\n",rectype); + return -1; + break; + } + + return ret; +} + + +/* ********************************************************************* + * cfe_srecload(la) + * + * Read an s-record file + * + * Input parameters: + * la - loader args + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ +static int cfe_srecload(cfe_loadargs_t *la) +{ + int res; + fileio_ctx_t *fsctx; + void *ref; + int devinfo; + int serial = FALSE; + unsigned int loadaddr; + unsigned int blklen; + linebuf_t lb; + char line[256]; + uint8_t data[256]; + int cnt; + unsigned int specaddr; /* current address if loading to a special address */ + int specflg; /* true if in "special address" mode */ + int firstrec = 1; /* true if we have not seen the first record */ + + /* + * We might want to know something about the boot device. + */ + + devinfo = la->la_device ? cfe_getdevinfo(la->la_device) : 0; + + /* + * Figure out if we're loading to a "special address". This lets + * us load S-records into a temporary buffer, ignoring the + * addresses in the records (but using them so we'll know where + * they go relative to each other + */ + + specflg = (la->la_flags & LOADFLG_SPECADDR) ? 1 : 0; + specaddr = 0; + + /* + * If the device is a serial port, we want to know that. + */ + + if ((devinfo >= 0) && + ((devinfo & CFE_DEV_MASK) == CFE_DEV_SERIAL)) { + serial = TRUE; + } + + /* + * Create a file system context + */ + + res = fs_init(la->la_filesys,&fsctx,la->la_device); + if (res != 0) { + return res; + } + + /* + * Turn on compression if we're doing that. + */ + + if (la->la_flags & LOADFLG_COMPRESSED) { + res = fs_hook(fsctx,"z"); + if (res != 0) { + return res; + } + } + + /* + * Open the boot device + */ + + res = fs_open(fsctx,&ref,la->la_filename,FILE_MODE_READ); + if (res != 0) { + fs_uninit(fsctx); + return res; + } + + /* + * Okay, go load the boot file. Process S-records until + * we get an entry point record (usually at the end). + * + * XXX what if it's *not* at the end? + */ + + initlinebuf(&lb,ref,fsctx); + + cnt = 0; + for (;;) { + /* + * Read a line of text + */ + res = readline(&lb,line,sizeof(line)); + if (res < 0) break; /* reached EOF */ + + /* + * Process the S-record. If at EOF, procsrec returns 0. + * Invalid s-records returns -1. + */ + + if (line[0] == 0) continue; + + res = procsrec(line,&loadaddr,&blklen,data); + +#if 0 + if (res == -2 || res >= 0) + xprintf("."); +#endif + if (res < 0) break; + + /* + * Handle "special address" mode. All S-records will be + * loaded into a buffer passed by the caller to the loader. + * We use the addresses in the S-records to determine + * relative placement of the data, keying on the first + * S-record in the file. + */ + + if ((res == 1) && (specflg)) { + if (firstrec) { + /* First S-record seen sets the base for all that follow */ + specaddr = loadaddr; + firstrec = 0; + } + loadaddr = la->la_address + (intptr_t) (loadaddr - specaddr); + } + + cnt++; + + if (res == 1) { + if (!cfe_arena_loadcheck((intptr_t) loadaddr,blklen)) { + xprintf("Invalid address: %P\n",loadaddr); + res = -1; + break; + } + memcpy((uint8_t *) (intptr_t) (signed)loadaddr,data,blklen); + } + } + + /* + * We're done with the file. + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + /* + * Say something cute on the LEDs. + * Don't do this for every s-record, because if logging the LED + * changes out the serial port, that can take a Long Time. Just + * goes to show: too much cuteness is a _very_ bad thing. + */ + xsprintf(line,"%04d",cnt); + cfe_ledstr(line); + + if (res == -2) { + la->la_entrypt = (intptr_t) (signed) loadaddr; + res = 0; + } + + return res; +} + + diff --git a/cfe/cfe/main/cfe_link.mk b/cfe/cfe/main/cfe_link.mk new file mode 100644 index 0000000..7529dc4 --- /dev/null +++ b/cfe/cfe/main/cfe_link.mk @@ -0,0 +1,26 @@ +# +# This Makefile snippet takes care of linking the firmware. +# + +pci : $(PCICOMMON) $(PCIMACHDEP) + echo done + +cfe cfe.bin : $(CRT0OBJS) $(BSPOBJS) $(LIBCFE) + $(GLD) -o cfe -Map cfe.map $(LDFLAGS) $(CRT0OBJS) $(BSPOBJS) -L. -lcfe $(LDLIBS) + $(OBJDUMP) -d cfe > cfe.dis + $(OBJCOPY) --output-target=binary cfe cfe.bin + $(OBJCOPY) --input-target=binary --output-target=srec cfe.bin cfe.srec + +cfe.flash : cfe.bin mkflashimage + ./mkflashimage -v ${ENDIAN} -B ${CFG_BOARDNAME} -V ${CFE_VER_MAJ}.${CFE_VER_MIN}.${CFE_VER_ECO} cfe.bin cfe.flash + $(OBJCOPY) --input-target=binary --output-target=srec cfe.flash cfe.flash.srec + + +clean : + rm -f *.o *~ cfe cfe.bin cfe.dis cfe.map cfe.srec + rm -f makereg ${CPU}_socregs.inc mkpcidb pcidevs_data2.h mkflashimage + rm -f build_date.c + rm -f libcfe.a + rm -f cfe.flash cfe.flash.srec $(CLEANOBJS) + +distclean : clean diff --git a/cfe/cfe/main/cfe_loader.c b/cfe/cfe/main/cfe_loader.c new file mode 100644 index 0000000..bbd3eb4 --- /dev/null +++ b/cfe/cfe/main/cfe_loader.c @@ -0,0 +1,135 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Loader API File: cfe_loader.c + * + * This is the main API for the program loader. CFE supports + * multiple "installable" methods for loading programs, allowing + * us to deal with a variety of methods for moving programs + * into memory for execution. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_printf.h" + +#include "cfe_error.h" + +#include "cfe.h" +#include "cfe_fileops.h" + +#include "cfe_loader.h" + +#include "bsp_config.h" + + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern const cfe_loader_t elfloader; +extern const cfe_loader_t rawloader; +extern const cfe_loader_t srecloader; + +/* ********************************************************************* + * Loader list + ********************************************************************* */ + +const cfe_loader_t * const cfe_loaders[] = { + &elfloader, +#if !CFG_MINIMAL_SIZE + &rawloader, + &srecloader, +#endif + NULL}; + +/* ********************************************************************* + * cfe_findloader(name) + * + * Find a loader by name + * + * Input parameters: + * name - name of loader to find + * + * Return value: + * pointer to loader structure or NULL + ********************************************************************* */ + +const cfe_loader_t *cfe_findloader(char *name) +{ + const cfe_loader_t * const *ldr; + + ldr = cfe_loaders; + + while (*ldr) { + if (strcmp(name,(*ldr)->name) == 0) return (*ldr); + ldr++; + } + + return NULL; +} + + +/* ********************************************************************* + * cfe_load_progam(name,args) + * + * Look up a loader and call it. + * + * Input parameters: + * name - name of loader to run + * args - arguments to pass + * + * Return value: + * return value + ********************************************************************* */ + +int cfe_load_program(char *name,cfe_loadargs_t *la) +{ + const cfe_loader_t *ldr; + int res; + + ldr = cfe_findloader(name); + if (!ldr) return CFE_ERR_LDRNOTAVAIL; + + res = LDRLOAD(ldr,la); + + return res; +} diff --git a/cfe/cfe/main/cfe_main.c b/cfe/cfe/main/cfe_main.c new file mode 100644 index 0000000..1a451a6 --- /dev/null +++ b/cfe/cfe/main/cfe_main.c @@ -0,0 +1,636 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Main Module File: cfe_main.c + * + * This module contains the main "C" routine for CFE and + * the main processing loop. There should not be any board-specific + * stuff in here. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_console.h" +#include "cfe_timer.h" + +#include "env_subr.h" +#include "ui_command.h" +#include "cfe_mem.h" +#include "cfe.h" + +#include "exception.h" + +#include "bsp_config.h" + +#include "segtable.h" + +#include "initdata.h" + +#if CFG_PCI +#include "pcivar.h" +#endif + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +#ifndef CFG_STACK_SIZE +#define STACK_SIZE 8192 +#else +#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) +#endif + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +void cfe_main(int,int); +extern void cfe_device_poll(void *x); + +extern int ui_init_envcmds(void); +extern int ui_init_devcmds(void); +extern int ui_init_netcmds(void); +extern int ui_init_memcmds(void); +extern int ui_init_loadcmds(void); +extern int ui_init_pcicmds(void); +extern int ui_init_examcmds(void); +extern int ui_init_flashcmds(void); +extern int ui_init_misccmds(void); +#if CFG_VAPI +extern int ui_init_vapicmds(void); +#endif + +#if CFG_VENDOR_EXTENSIONS +extern int ui_init_vendorcmds(void); +#endif + +void cfe_command_restart(uint64_t status); + +extern segtable_t *_getsegtbl(void); + +extern const char *builddate; +extern const char *builduser; + +#if CFG_MULTI_CPUS +extern int altcpu_cmd_start(uint64_t,uint64_t *); +extern int altcpu_cmd_stop(uint64_t); +#endif + + + + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +const char *cfe_boardname = CFG_BOARDNAME; +unsigned int cfe_startflags = +#if CFG_PCI + CFE_INIT_PCI | +#endif + 0; + +/* ********************************************************************* + * cfe_setup_default_env() + * + * Initialize the default environment for CFE. These are all + * the temporary variables that do not get stored in the NVRAM + * but are available to other programs and command-line macros. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void cfe_setup_default_env(void) +{ + char buffer[80]; + + xsprintf(buffer,"%d.%d.%d",CFE_VER_MAJOR,CFE_VER_MINOR,CFE_VER_BUILD); + env_setenv("CFE_VERSION",buffer,ENV_FLG_BUILTIN | ENV_FLG_READONLY); + + if (cfe_boardname) { + env_setenv("CFE_BOARDNAME",(char *) cfe_boardname, + ENV_FLG_BUILTIN | ENV_FLG_READONLY); + } + + xsprintf(buffer,"%d",mem_totalsize); + env_setenv("CFE_MEMORYSIZE",buffer,ENV_FLG_BUILTIN | ENV_FLG_READONLY); + +} + + +/* ********************************************************************* + * cfe_init_ui() + * + * Call all the other UI initialization modules. Each of these + * modules usually calls back to the UI dispatcher to add command + * tables. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +#if CFG_MINIMAL_SIZE +#define OPTIONAL(x) +#else +#define OPTIONAL(x) x +#endif + +static void cfe_init_ui(void) +{ + ui_init_cmddisp(); + + ui_init_envcmds(); + OPTIONAL(ui_init_devcmds()); +#if CFG_NETWORK + ui_init_netcmds(); +#endif + ui_init_loadcmds(); + OPTIONAL(ui_init_memcmds()); + +#if CFG_PCI + ui_init_pcicmds(); +#endif + OPTIONAL(ui_init_examcmds()); + ui_init_flashcmds(); +#if CFG_VAPI + ui_init_vapicmds(); +#endif + +#if CFG_VENDOR_EXTENSIONS + ui_init_vendorcmds(); +#endif + + OPTIONAL(ui_init_misccmds()); + +} + + +/* ********************************************************************* + * cfe_ledstr(leds) + * + * Display a string on the board's LED display, if it has one. + * This routine depends on the board-support package to + * include a "driver" to write to the actual LED, if the board + * does not have one this routine will do nothing. + * + * The LEDs are written at various places in the initialization + * sequence, to debug board problems. + * + * Input parameters: + * leds - pointer to four-character ASCII string + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_ledstr(const char *leds) +{ + unsigned int val; + + val = ((((unsigned int) leds[0]) << 24) | + (((unsigned int) leds[1]) << 16) | + (((unsigned int) leds[2]) << 8) | + ((unsigned int) leds[3])); + + cfe_leds(val); +} + + +/* ********************************************************************* + * cfe_say_hello() + * + * Print out the CFE startup message and copyright notice + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + + +static void cfe_say_hello(void) +{ + xprintf("\n\n"); + xprintf("CFE version 2.0.2" +#ifdef CFE_VER_RELEASE + ".%d" +#endif + " for DGN2200v2 (%s)\n", + //CFE_VER_MAJOR,CFE_VER_MINOR,CFE_VER_BUILD, +#ifdef CFE_VER_RELEASE + CFE_VER_RELEASE, +#endif + //cfe_boardname, +#ifdef __long64 + "64bit," +#else + "32bit," +#endif +#if CFG_MULTI_CPUS + "MP," +#else + "SP," +#endif +#ifdef __MIPSEL + "LE" +#endif +#ifdef __MIPSEB + "BE" +#endif +#if CFG_VAPI + ",VAPI" +#endif + ); + + xprintf("Build Date: %s (%s)\n",builddate,builduser); + xprintf("Copyright (C) 2000,2001,2002,2003 Broadcom Corporation.\n"); + xprintf("\n"); +} + + +/* ********************************************************************* + * cfe_restart() + * + * Restart CFE from scratch, jumping back to the boot vector. + * + * Input parameters: + * nothing + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_restart(void) +{ + _exc_restart(); +} + + +/* ********************************************************************* + * cfe_start(ept) + * + * Start a user program + * + * Input parameters: + * ept - entry point + * + * Return value: + * nothing + ********************************************************************* */ +void cfe_start(unsigned long ept) +{ + SETLEDS("RUN!"); + cfe_launch(ept); +} + + +/* ********************************************************************* + * cfe_startup_info() + * + * Display startup memory configuration messages + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void cfe_startup_info(void) +{ + segtable_t *segtbl; + + segtbl = _getsegtbl(); + xprintf("CPU type 0x%X: ",(uint32_t)cpu_prid); + if (cfe_cpu_speed < 1000000) xprintf("%dKHz\n",cfe_cpu_speed/1000); + else xprintf("%dMHz\n",cfe_cpu_speed/1000000); + xprintf("Total memory: 0x%llX bytes (%dMB)\n", + (((uint64_t)mem_totalsize) << 20),(uint32_t)mem_totalsize); + + xprintf("\n"); + xprintf("Total memory used by CFE: 0x%08X - 0x%08X (%d)\n", + (uint32_t) mem_bottomofmem, + (uint32_t) mem_topofmem, + (uint32_t) mem_topofmem-mem_bottomofmem); + xprintf("Initialized Data: 0x%08X - 0x%08X (%d)\n", + (uint32_t) (segtbl[R_SEG_FDATA] + mem_datareloc), + (uint32_t) (segtbl[R_SEG_EDATA] + mem_datareloc), + (uint32_t) (segtbl[R_SEG_EDATA] - segtbl[R_SEG_FDATA])); + xprintf("BSS Area: 0x%08X - 0x%08X (%d)\n", + (uint32_t) (segtbl[R_SEG_FBSS] + mem_datareloc), + (uint32_t) (segtbl[R_SEG_END] + mem_datareloc), + (uint32_t) (segtbl[R_SEG_END] - segtbl[R_SEG_FBSS])); + xprintf("Local Heap: 0x%08X - 0x%08X (%d)\n", + (uint32_t)(mem_heapstart), + (uint32_t)(mem_heapstart + (CFG_HEAP_SIZE*1024)), + (CFG_HEAP_SIZE*1024)); + xprintf("Stack Area: 0x%08X - 0x%08X (%d)\n", + (uint32_t)(mem_heapstart + (CFG_HEAP_SIZE*1024)), + (uint32_t)(mem_heapstart + (CFG_HEAP_SIZE*1024) + STACK_SIZE), + STACK_SIZE); + xprintf("Text (code) segment: 0x%08X - 0x%08X (%d)\n", + (uint32_t)mem_textbase, + (uint32_t)(mem_textbase+mem_textsize), + (uint32_t) mem_textsize); + xprintf("Boot area (physical): 0x%08X - 0x%08X\n", + mem_bootarea_start,mem_bootarea_start+mem_bootarea_size); + xprintf("Relocation Factor: I:%08X - D:%08X\n", + (uint32_t) mem_textreloc,(uint32_t) mem_datareloc); + +} + + +/* ********************************************************************* + * cfe_autostart() + * + * Process automatic commands at startup + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +static void cfe_autostart(void) +{ + char *env; + int noauto = 0; + char ch; + + env = env_getenv("STARTUP"); + if (!env) return; + + while (console_status()) { + console_read(&ch,1); + if (ch == 3) noauto = TRUE; /* Ctrl-C means no auto */ + } + + if (noauto) { + xprintf("Automatic startup canceled via Ctrl-C\n"); + return; + } + + ui_docommands(env); +} + +/* ********************************************************************* + * cfe_main(a,b) + * + * It's gotta start somewhere. + * + * Input parameters: + * a,b - not used + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_main(int a,int b) +{ + + /* + * By the time this routine is called, the following things have + * already been done: + * + * 1. The processor(s) is(are) initialized. + * 2. The caches are initialized. + * 3. The memory controller is initialized. + * 4. BSS has been zeroed. + * 5. The data has been moved to R/W space. + * 6. The "C" Stack has been initialized. + */ + + cfe_bg_init(); /* init background processing */ + cfe_attach_init(); + cfe_timer_init(); /* Timer process */ + cfe_bg_add(cfe_device_poll,NULL); + + /* + * Initialize the memory allocator + */ + + SETLEDS("KMEM"); + KMEMINIT((unsigned char *) (uintptr_t) mem_heapstart, + ((CFG_HEAP_SIZE)*1024)); + + /* + * Initialize the console. It is done before the other devices + * get turned on. The console init also sets the variable that + * contains the CPU speed. + */ + + SETLEDS("CONS"); + board_console_init(); + + /* + * Set up the exception vectors + */ + + cfe_setup_exceptions(); + + /* + * Say hello. + */ + + SETLEDS("CIOK"); + cfe_say_hello(); + + /* + * Initialize the other devices. + */ + + SETLEDS("AREN"); + xprintf("Initializing Arena.\n"); + cfe_arena_init(); + +#if CFG_PCI + if (cfe_startflags & CFE_INIT_PCI) { + pci_flags_t flags = PCI_FLG_NORMAL | PCI_FLG_LDT_PREFETCH; + char *str; + extern cons_t pci_optnames[]; + + flags = PCI_FLG_NORMAL | PCI_FLG_LDT_PREFETCH; +#if CFG_LDT_REV_017 + flags |= PCI_FLG_LDT_REV_017; +#endif + str = env_getenv("PCI_OPTIONS"); + setoptions(pci_optnames,str,&flags); + + xprintf("Initializing PCI. [%s]\n",str ? str : "normal"); + pci_configure(flags); + } +#endif + + SETLEDS("DEVI"); + xprintf("Initializing Devices.\n"); + board_device_init(); + + cfe_startup_info(); + SETLEDS("ENVI"); + cfe_setup_default_env(); + + xprintf("\n"); + + cfe_init_ui(); + + board_final_init(); + + cfe_autostart(); + + cfe_command_loop(); +} + +/* ********************************************************************* + * cfe_command_restart() + * + * This routine is called when an application wants to restart + * the firmware's command processor. Reopen the console and + * jump back into the command loop. + * + * Input parameters: + * status - A0 value of program returning to firmware + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_command_restart(uint64_t status) +{ + /* + * Stop alternate CPU(s). If they're already stopped, this + * command will make sure they're stopped. + */ + +#if CFG_MULTI_CPUS + altcpu_cmd_stop(1); /* stop CPU 1 (XXX more CPUs?) */ +#endif + + /* + * Call board reset functions + */ + board_device_reset(); + + /* + * Reset devices + */ + cfe_device_reset(); + + /* + * Reset timers + */ + cfe_timer_init(); + + /* + * Reopen console + */ + console_open(console_name); + + /* + * Display program return status + */ + + xprintf("*** program exit status = %d\n", (int)status); + + /* + * Back to processing user commands + */ + cfe_command_loop(); +} + + + +/* ********************************************************************* + * cfe_command_loop() + * + * This routine reads and processes user commands + * + * Input parameters: + * nothing + * + * Return value: + * does not return + ********************************************************************* */ + +void cfe_command_loop() +{ + char buffer[300]; + int status; + char *prompt; + + SETLEDS("CFE "); + + for (;;) { + prompt = env_getenv("PROMPT"); +#if CFG_RAMAPP + SETLEDS("CFE*"); + if (!prompt) prompt = "CFE_RAM> "; +#else + if (!prompt) prompt = "CFE> "; +#endif + console_readline(prompt,buffer,sizeof(buffer)); + + status = ui_docommands(buffer); + + if (status != CMD_ERR_BLANK) { + xprintf("*** command status = %d\n", status); + } + } +} + + + + + diff --git a/cfe/cfe/main/cfe_mem.c b/cfe/cfe/main/cfe_mem.c new file mode 100644 index 0000000..1c424e1 --- /dev/null +++ b/cfe/cfe/main/cfe_mem.c @@ -0,0 +1,256 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Physical Memory (arena) manager File: cfe_mem.c + * + * This module describes the physical memory available to the + * firmware. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" +#include "lib_arena.h" + +#include "cfe_error.h" + +#include "cfe.h" +#include "cfe_mem.h" + +#include "initdata.h" + +#define _NOPROTOS_ +#include "cfe_boot.h" +#undef _NOPROTOS_ + +#include "cpu_config.h" /* for definition of CPUCFG_ARENAINIT */ + +#include "addrspace.h" /* for macros dealing with addresses */ + + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#define ARENA_RANGE(bottom,top,type) arena_markrange(&cfe_arena,(uint64_t)(bottom), \ + (uint64_t)(top)-(uint64_t)bottom+1,(type),NULL) + +#define MEG (1024*1024) +#define KB 1024 +#define PAGESIZE 4096 +#define CFE_BOOTAREA_SIZE (256*KB) +#define CFE_BOOTAREA_ADDR 0x20000000 + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +arena_t cfe_arena; +extern void _setcontext(int64_t); + +unsigned int mem_bootarea_start; +unsigned int mem_bootarea_size; + +extern void CPUCFG_ARENAINIT(void); +extern void cfe_bootarea_init(void); +extern void CPUCFG_PAGETBLINIT(uint64_t *ptaddr,unsigned int ptstart); + + + +/* ********************************************************************* + * cfe_arena_init() + * + * Create the initial map of physical memory + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_arena_init(void) +{ + uint64_t memlo,memhi; + + /* + * This macro expands via cpu_config.h to an appropriate function + * name for creating an empty arena appropriately for our CPU + */ + + CPUCFG_ARENAINIT(); + + /* + * Round the area used by the firmware to a page boundary and + * mark it in use + */ + + memhi = PHYSADDR((mem_topofmem + 4095) & ~4095); + memlo = PHYSADDR(mem_bottomofmem) & ~4095; + + ARENA_RANGE(memlo,memhi-1,MEMTYPE_DRAM_USEDBYFIRMWARE); + + /* + * Create the initial page table + */ + + cfe_bootarea_init(); + +} + + +/* ********************************************************************* + * cfe_arena_enum(idx,type,start,size) + * + * Enumerate available memory. This is called by the user + * API dispatcher so that operating systems can determine what + * memory regions are available to them. + * + * Input parameters: + * idx - index. Start at zero and increment until an error + * is returned. + * type,start,size: pointers to variables to receive the + * arena entry's information + * allrecs - true to retrieve all records, false to retrieve + * only available DRAM + * + * Return value: + * 0 if ok + * CFE_ERR_NOMORE if idx is beyond the last entry + ********************************************************************* */ + +int cfe_arena_enum(int idx,int *type,uint64_t *start,uint64_t *size,int allrecs) +{ + arena_node_t *node; + queue_t *qb; + arena_t *arena = &cfe_arena; + + + for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list); + qb = qb->q_next) { + node = (arena_node_t *) qb; + + if (allrecs || (!allrecs && (node->an_type == MEMTYPE_DRAM_AVAILABLE))) { + if (idx == 0) { + *type = node->an_type; + *start = node->an_address; + *size = node->an_length; + return 0; + } + idx--; + } + } + + return CFE_ERR_NOMORE; + +} + +/* ********************************************************************* + * cfe_arena_loadcheck(start,size) + * + * Determine if the specified memory area is within the available + * DRAM. This is used while loading executables to be sure we + * don't trash the firmware. + * + * Input parameters: + * start - starting physical address + * size - size of requested region + * + * Return value: + * true - ok to copy memory here + * false - not ok, memory overlaps firmware + ********************************************************************* */ + +int cfe_arena_loadcheck(uintptr_t start,unsigned int size) +{ + arena_node_t *node; + queue_t *qb; + arena_t *arena = &cfe_arena; + + /* + * If the address is in our boot area, it's okay + * for it to be a virtual address. + */ + + if ((start >= BOOT_START_ADDRESS) && + ((start+size) <= (BOOT_START_ADDRESS+BOOT_AREA_SIZE))) { + return TRUE; + } + + /* + * Otherwise, make a physical address. + */ + + start = PHYSADDR(start); + + /* + * Because all of the arena nodes of the same type are + * coalesced together, all we need to do is determine if the + * requested region is entirely within an arena node, + * so there's no need to look for things that span nodes. + */ + + for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list); + qb = qb->q_next) { + node = (arena_node_t *) qb; + + /* If the memory is available, the region is OK. */ + + if ((start >= node->an_address) && + ((start+size) <= (node->an_address+node->an_length)) && + (node->an_type == MEMTYPE_DRAM_AVAILABLE)) { + return TRUE; + } + } + + /* + * Otherwise, it's not. We could go through the arena again and + * look for regions of other types that intersect the requested + * region, to get a more detailed error, but this'll do. + */ + + return FALSE; + +} + diff --git a/cfe/cfe/main/cfe_rawfs.c b/cfe/cfe/main/cfe_rawfs.c new file mode 100644 index 0000000..4c29349 --- /dev/null +++ b/cfe/cfe/main/cfe_rawfs.c @@ -0,0 +1,293 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * "Raw" file system File: cfe_rawfs.c + * + * This filesystem dispatch is used to read files directly + * from a block device. For example, you can 'dd' an elf + * file directly onto a disk or flash card and then run + * it using this module. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_console.h" + +#include "cfe.h" + +/* ********************************************************************* + * RAW context + ********************************************************************* */ + +/* + * File system context - describes overall file system info, + * such as the handle to the underlying device. + */ + +typedef struct raw_fsctx_s { + int raw_dev; + int raw_isconsole; + int raw_refcnt; +} raw_fsctx_t; + +/* + * File context - describes an open file on the file system. + * For raw devices, this is pretty meaningless, but we do + * keep track of where we are. + */ + +typedef struct raw_file_s { + raw_fsctx_t *raw_fsctx; + int raw_fileoffset; + int raw_baseoffset; /* starting offset of raw "file" */ + int raw_length; /* length of file, -1 for whole device */ +} raw_file_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int raw_fileop_init(void **fsctx,void *devicename); +static int raw_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int raw_fileop_read(void *ref,uint8_t *buf,int len); +static int raw_fileop_write(void *ref,uint8_t *buf,int len); +static int raw_fileop_seek(void *ref,int offset,int how); +static void raw_fileop_close(void *ref); +static void raw_fileop_uninit(void *fsctx); + +/* ********************************************************************* + * RAW fileio dispatch table + ********************************************************************* */ + +const fileio_dispatch_t raw_fileops = { + "raw", + 0, + raw_fileop_init, + raw_fileop_open, + raw_fileop_read, + raw_fileop_write, + raw_fileop_seek, + raw_fileop_close, + raw_fileop_uninit +}; + +static int raw_fileop_init(void **newfsctx,void *dev) +{ + raw_fsctx_t *fsctx; + char *devicename = (char *) dev; + + *newfsctx = NULL; + + fsctx = KMALLOC(sizeof(raw_fsctx_t),0); + if (!fsctx) { + return CFE_ERR_NOMEM; + } + + if (strcmp(devicename,console_name) == 0) { + fsctx->raw_dev = console_handle; + fsctx->raw_isconsole = TRUE; + } + else { + fsctx->raw_dev = cfe_open(devicename); + fsctx->raw_isconsole = FALSE; + } + + fsctx->raw_refcnt = 0; + + if (fsctx->raw_dev >= 0) { + *newfsctx = fsctx; + return 0; + } + + KFREE(fsctx); + + return CFE_ERR_FILENOTFOUND; +} + +static int raw_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode) +{ + raw_fsctx_t *fsctx; + raw_file_t *file; + char temp[100]; + char *len; + + if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + fsctx = (raw_fsctx_t *) fsctx_arg; + + file = KMALLOC(sizeof(raw_file_t),0); + if (!file) { + return CFE_ERR_NOMEM; + } + + file->raw_fileoffset = 0; + file->raw_fsctx = fsctx; + + /* Assume the whole device. */ + file->raw_baseoffset = 0; + file->raw_length = -1; + + /* + * If a filename was specified, it will be in the form + * offset,length - for example, 0x10000,0x200 + * Parse this into two pieces and set up our internal + * file extent information. you can use either decimal + * or "0x" notation. + */ + if (filename) { + lib_trimleading(filename); + strncpy(temp,filename,sizeof(temp)); + len = strchr(temp,','); + if (len) *len++ = '\0'; + if (temp[0]) { + file->raw_baseoffset = lib_atoi(temp); + } + if (len) { + file->raw_length = lib_atoi(len); + } + } + + fsctx->raw_refcnt++; + + *ref = file; + return 0; +} + +static int raw_fileop_read(void *ref,uint8_t *buf,int len) +{ + raw_file_t *file = (raw_file_t *) ref; + int res; + + /* + * Bound the length based on our "file length" if one + * was specified. + */ + + if (file->raw_length >= 0) { + if ((file->raw_length - file->raw_fileoffset) < len) { + len = file->raw_length - file->raw_fileoffset; + } + } + + if (len == 0) return 0; + + /* + * Read the data, adding in the base address. + */ + + res = cfe_readblk(file->raw_fsctx->raw_dev, + file->raw_baseoffset + file->raw_fileoffset, + buf,len); + + if (res > 0) { + file->raw_fileoffset += res; + } + + return res; +} + +static int raw_fileop_write(void *ref,uint8_t *buf,int len) +{ + return CFE_ERR_UNSUPPORTED; +} + +static int raw_fileop_seek(void *ref,int offset,int how) +{ + raw_file_t *file = (raw_file_t *) ref; + + switch (how) { + case FILE_SEEK_BEGINNING: + file->raw_fileoffset = offset; + break; + case FILE_SEEK_CURRENT: + file->raw_fileoffset += offset; + if (file->raw_fileoffset < 0) file->raw_fileoffset = 0; + break; + default: + break; + } + + /* + * Make sure we don't attempt to seek past the end of the file. + */ + + if (file->raw_length >= 0) { + if (file->raw_fileoffset > file->raw_length) { + file->raw_fileoffset = file->raw_length; + } + } + + return file->raw_fileoffset; +} + + +static void raw_fileop_close(void *ref) +{ + raw_file_t *file = (raw_file_t *) ref; + + file->raw_fsctx->raw_refcnt--; + + KFREE(file); +} + +static void raw_fileop_uninit(void *fsctx_arg) +{ + raw_fsctx_t *fsctx = (raw_fsctx_t *) fsctx_arg; + + if (fsctx->raw_refcnt) { + xprintf("raw_fileop_uninit: warning: refcnt not zero\n"); + } + + if (fsctx->raw_isconsole == FALSE) { + cfe_close(fsctx->raw_dev); + } + + KFREE(fsctx); +} diff --git a/cfe/cfe/main/cfe_savedata.c b/cfe/cfe/main/cfe_savedata.c new file mode 100644 index 0000000..e1d27c4 --- /dev/null +++ b/cfe/cfe/main/cfe_savedata.c @@ -0,0 +1,123 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Data Save routine File: cfe_savedata.c + * + * This module is used for dumping memory to an output device + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_device.h" +#include "cfe_error.h" +#include "cfe_devfuncs.h" + +#include "cfe.h" +#include "cfe_fileops.h" + +#include "cfe_loader.h" + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +/* ********************************************************************* + * cfe_savedata(fsname,filename,start,end) + * + * Write memory contents to the specified device + * + * Input parameters: + * fsname - name of file system + * filename - name of file within file system + * start - starting address (pointer) + * end - ending address (pointer) + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ +int cfe_savedata(char *fsname,char *devname,char *filename,uint8_t *start,uint8_t *end) +{ + int res; + fileio_ctx_t *fsctx; + void *ref; + + /* + * Create a file system context + */ + + res = fs_init(fsname,&fsctx,devname); + if (res != 0) { + return res; + } + + /* + * Open the device + */ + + res = fs_open(fsctx,&ref,filename,FILE_MODE_WRITE); + if (res != 0) { + fs_uninit(fsctx); + return res; + } + + /* + * Write the data + */ + + res = fs_write(fsctx,ref,start,end-start); + + /* + * Close + */ + + fs_close(fsctx,ref); + fs_uninit(fsctx); + + return res; + +} + diff --git a/cfe/cfe/main/cfe_timer.c b/cfe/cfe/main/cfe_timer.c new file mode 100644 index 0000000..2b8a0fc --- /dev/null +++ b/cfe/cfe/main/cfe_timer.c @@ -0,0 +1,286 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Timer routines File: cfe_timer.c + * + * This module contains routines to keep track of the system time,. + * Since we don't have any interrupts in the firmware, even the + * timer is polled. The timer must be called often enough + * to prevent missing the overflow of the CP0 COUNT + * register, approximately 2 billion cycles (half the count) + * + * Be sure to use the POLL() macro each time you enter a loop + * where you are waiting for some I/O event to occur or + * are waiting for time to elapse. + * + * It is *not* a time-of-year clock. The timer is only used + * for timing I/O events. + * + * Internally, time is maintained in units of "CLOCKSPERTICK", + * which should be about tenths of seconds. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_printf.h" + +#include "cfe_timer.h" + +#include "cfe.h" + +#include "bsp_config.h" +#include "cpu_config.h" + +/* Foxconn add start by Jenny Zhao, 07/02/2008*/ +#include "boardparms.h" +#include "bcm63xx_util.h" +#include "tftpd.h" +/* Foxconn add end by Jenny Zhao, 07/02/2008*/ + +#ifndef CFG_CPU_SPEED +#define CFG_CPU_SPEED 500000 /* CPU speed in Hz */ +#endif + +#ifndef CPUCFG_CYCLESPERCPUTICK +#define CPUCFG_CYCLESPERCPUTICK 1 /* CPU clock ticks per CP0 COUNT */ +#endif + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern int32_t _getticks(void); /* return value of CP0 COUNT */ + +/* ********************************************************************* + * Data + ********************************************************************* */ + +volatile int64_t cfe_ticks; /* current system time */ + +int cfe_cpu_speed = CFG_CPU_SPEED; /* CPU speed in clocks/second */ + +static unsigned int cfe_clocks_per_usec; +static unsigned int cfe_clocks_per_tick; + +static int32_t cfe_oldcount; /* For keeping track of ticks */ +static int32_t cfe_remticks; +static int cfe_timer_initflg = 0; + +/* + * C0_COUNT clocks per microsecond and per tick. Some CPUs tick CP0 + * every 'n' cycles, that's what CPUCFG_CYCLESPERCPUTICK is for. */ +#define CFE_CLOCKSPERUSEC (cfe_cpu_speed/1000000/(CPUCFG_CYCLESPERCPUTICK)) +#define CFE_CLOCKSPERTICK (cfe_cpu_speed/(CFE_HZ)/(CPUCFG_CYCLESPERCPUTICK)) + +/* Foxconn add start by Jenny Zhao, 07/02/2008*/ +extern int ui_docommands(char *str); + +extern int g_tftp_upgrade_success; +extern int nmrp_server_detected; + +//extern int g_reboot; +///* Foxconn add end by Jenny Zhao, 07/02/2008*/ + +/* ********************************************************************* + * cfe_timer_task() + * + * This routine is called as part of normal device polling to + * update the system time. We read the CP0 COUNT register, + * add the delta into our current time, convert to ticks, + * and keep track of the COUNT register overflow + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + + +static void cfe_timer_task(void *arg) +{ + int32_t count; + int32_t deltaticks; + int32_t clockspertick; + + /* Foxconn add start by Jenny Zhao, 07/02/2008*/ + static int64_t nmrp_previous_trigger_ticks = 0; + static int64_t tftp_previous_trigger_ticks = 0; + static int tftp_led_state = 0; + /* Foxconn add start by Jenny Zhao, 07/02/2008*/ + + clockspertick = CFE_CLOCKSPERTICK; + + count = _getticks(); + + if (count >= cfe_oldcount) { + deltaticks = (count - cfe_oldcount) / clockspertick; + cfe_remticks += (count - cfe_oldcount) % clockspertick; + } + else { + deltaticks = (cfe_oldcount - count) / clockspertick; + cfe_remticks += (cfe_oldcount - count) % clockspertick; + } + + cfe_ticks += deltaticks + (cfe_remticks / clockspertick); + cfe_remticks %= clockspertick; + cfe_oldcount = count; + + /* Foxconn add start by Jenny Zhao, 07/02/2008*/ + if(g_tftp_upgrade_success==1) + { + if((cfe_ticks - nmrp_previous_trigger_ticks) > 5) //500 ms + { + nmrp_previous_trigger_ticks = cfe_ticks; + nmrp_led_toggle(); + } + } + + /* Blink Power LED in tftpd mode */ + if ( (get_tftpd_state() != TFTPD_STATE_OFF) && (nmrp_server_detected==0) ) + { + if(tftp_led_state == 0) //led is off + { + if((cfe_ticks - tftp_previous_trigger_ticks) > 7) //700ms, spec. is 750ms + { + tftp_led_state = 1; + power_led_toggle(tftp_led_state); + tftp_previous_trigger_ticks = cfe_ticks; + } + } + else // led is currently on + { + if((cfe_ticks - tftp_previous_trigger_ticks) > 3) //300ms, spec. is 250ms + { + tftp_led_state = 0; + power_led_toggle(tftp_led_state); + tftp_previous_trigger_ticks = cfe_ticks; + } + } + } + /* Foxconn add end by Jenny Zhao, 07/02/2008*/ +} + + +/* ********************************************************************* + * cfe_timer_init() + * + * Initialize the timer module. + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_timer_init(void) +{ + cfe_clocks_per_tick = CFE_CLOCKSPERTICK; + cfe_clocks_per_usec = CFE_CLOCKSPERUSEC; + if (cfe_clocks_per_usec == 0) + cfe_clocks_per_usec = 1; /* for the simulator */ + + cfe_oldcount = _getticks(); /* get current COUNT register */ + cfe_ticks = 0; + + if (!cfe_timer_initflg) { + cfe_bg_add(cfe_timer_task,NULL); /* add task for background polling */ + cfe_timer_initflg = 1; + } +} + + +/* ********************************************************************* + * cfe_sleep(ticks) + * + * Sleep for 'ticks' ticks. Background tasks are processed while + * we wait. + * + * Input parameters: + * ticks - number of ticks to sleep (note: *not* clocks!) + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_sleep(int ticks) +{ + int64_t timer; + + TIMER_SET(timer,ticks); + while (!TIMER_EXPIRED(timer)) { + POLL(); + } +} + + + +/* ********************************************************************* + * cfe_usleep(usec) + * + * Sleep for approximately the specified number of microseconds. + * + * Input parameters: + * usec - number of microseconds to wait + * + * Return value: + * nothing + ********************************************************************* */ + +void cfe_usleep(int usec) +{ + uint32_t newcount; + uint32_t now; + + /* XXX fix the wrap problem */ + + now = _getticks(); + newcount = now + usec*cfe_clocks_per_usec; + + if (newcount < now) /* wait for wraparound */ + while (_getticks() > now) + ; + + + while (_getticks() < newcount) + ; +} diff --git a/cfe/cfe/main/cfe_version.mk b/cfe/cfe/main/cfe_version.mk new file mode 100755 index 0000000..653cbf9 --- /dev/null +++ b/cfe/cfe/main/cfe_version.mk @@ -0,0 +1,12 @@ + +# +# CFE's version number +# Warning: Don't put spaces on either side of the equal signs +# Put just the version number in here. This file is sourced +# like a shell script in some cases! +# + +CFE_VER_MAJ=1 +CFE_VER_MIN=0 +CFE_VER_ECO=37 + diff --git a/cfe/cfe/main/cfe_xreq.c b/cfe/cfe/main/cfe_xreq.c new file mode 100644 index 0000000..d12b1f2 --- /dev/null +++ b/cfe/cfe/main/cfe_xreq.c @@ -0,0 +1,346 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * IOCB dispatcher File: cfe_xreq.c + * + * This routine is the main API dispatch for CFE. User API + * calls, via the ROM entry point, get dispatched to routines + * in this module. + * + * This module looks similar to cfe_iocb_dispatch - it is different + * in that the data structure used, cfe_xiocb_t, uses fixed + * size field members (specifically, all 64-bits) no matter how + * the firmware is compiled. This ensures a consistent API + * interface on any implementation. When you call CFE + * from another program, the entry vector comes here first. + * + * Should the normal cfe_iocb interface change, this one should + * be kept the same for backward compatibility reasons. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "bsp_config.h" +#include "lib_types.h" +#include "lib_malloc.h" +#include "lib_queue.h" +#include "lib_printf.h" +#include "lib_string.h" +#include "cfe_iocb.h" +#include "cfe_xiocb.h" +#if CFG_VENDOR_EXTENSIONS +#include "cfe_vendor_iocb.h" +#include "cfe_vendor_xiocb.h" +#endif +#include "cfe_error.h" +#include "cfe_device.h" +#include "cfe_timer.h" +#include "cfe_mem.h" +#include "env_subr.h" +#include "cfe.h" + + +/* ********************************************************************* + * Constants + ********************************************************************* */ + +/* enum values for various plist types */ + +#define PLBUF 1 /* iocb_buffer_t */ +#define PLCPU 2 /* iocb_cpuctl_t */ +#define PLMEM 3 /* iocb_meminfo_t */ +#define PLENV 4 /* iocb_envbuf_t */ +#define PLINP 5 /* iocb_inpstat_t */ +#define PLTIM 6 /* iocb_time_t */ +#define PLINF 7 /* iocb_fwinfo_t */ +#define PLEXIT 8 /* iocb_exitstat_t */ + +/* ********************************************************************* + * Structures + ********************************************************************* */ + +struct cfe_xcmd_dispatch_s { + int xplistsize; + int iplistsize; + int plisttype; +}; + + +/* ********************************************************************* + * Command conversion table + * This table contains useful information for converting + * iocbs to xiocbs. + ********************************************************************* */ + +const static struct cfe_xcmd_dispatch_s cfe_xcmd_dispatch_table[CFE_CMD_MAX] = { + {sizeof(xiocb_fwinfo_t), sizeof(iocb_fwinfo_t), PLINF}, /* 0 : CFE_CMD_FW_GETINFO */ + {sizeof(xiocb_exitstat_t),sizeof(iocb_exitstat_t),PLEXIT}, /* 1 : CFE_CMD_FW_RESTART */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 2 : CFE_CMD_FW_BOOT */ + {sizeof(xiocb_cpuctl_t), sizeof(iocb_cpuctl_t), PLCPU}, /* 3 : CFE_CMD_FW_CPUCTL */ + {sizeof(xiocb_time_t), sizeof(iocb_time_t), PLTIM}, /* 4 : CFE_CMD_FW_GETTIME */ + {sizeof(xiocb_meminfo_t),sizeof(iocb_meminfo_t),PLMEM}, /* 5 : CFE_CMD_FW_MEMENUM */ + {0, 0, 0}, /* 6 : CFE_CMD_FW_FLUSHCACHE */ + {-1, 0, 0}, /* 7 : */ + {-1, 0, 0}, /* 8 : */ + {0, 0, 0}, /* 9 : CFE_CMD_DEV_GETHANDLE */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 10 : CFE_CMD_DEV_ENUM */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 11 : CFE_CMD_DEV_OPEN_*/ + {sizeof(xiocb_inpstat_t),sizeof(iocb_inpstat_t),PLINP}, /* 12 : CFE_CMD_DEV_INPSTAT */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 13 : CFE_CMD_DEV_READ */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 14 : CFE_CMD_DEV_WRITE */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 15 : CFE_CMD_DEV_IOCTL */ + {0, 0, 0}, /* 16 : CFE_CMD_DEV_CLOSE */ + {sizeof(xiocb_buffer_t), sizeof(iocb_buffer_t), PLBUF}, /* 17 : CFE_CMD_DEV_GETINFO */ + {-1, 0, 0}, /* 18 : */ + {-1, 0, 0}, /* 19 : */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 20 : CFE_CMD_ENV_ENUM */ + {-1, 0, 0}, /* 21 : */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 22 : CFE_CMD_ENV_GET */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 23 : CFE_CMD_ENV_SET */ + {sizeof(xiocb_envbuf_t), sizeof(iocb_envbuf_t), PLENV}, /* 24 : CFE_CMD_ENV_DEL */ + {-1, 0, 0}, /* 25 : */ + {-1, 0, 0}, /* 26 : */ + {-1, 0, 0}, /* 27 : */ + {-1, 0, 0}, /* 28 : */ + {-1, 0, 0}, /* 29 : */ + {-1, 0, 0}, /* 30 : */ + {-1, 0, 0} /* 31 : */ +}; + + +/* ********************************************************************* + * Externs + ********************************************************************* */ + +extern int cfe_iocb_dispatch(cfe_iocb_t *iocb); +cfe_int_t cfe_doxreq(cfe_xiocb_t *xiocb); +#if CFG_VENDOR_EXTENSIONS +extern cfe_int_t cfe_vendor_doxreq(cfe_vendor_xiocb_t *xiocb); +#endif + +/* ********************************************************************* + * cfe_doxreq(xiocb) + * + * Process an xiocb request. This routine converts an xiocb + * into an iocb, calls the IOCB dispatcher, converts the results + * back into the xiocb, and returns. + * + * Input parameters: + * xiocb - pointer to user xiocb + * + * Return value: + * command status, <0 if error occured + ********************************************************************* */ + +cfe_int_t cfe_doxreq(cfe_xiocb_t *xiocb) +{ + const struct cfe_xcmd_dispatch_s *disp; + cfe_iocb_t iiocb; + cfe_int_t res; + + /* + * Call out to customer-specific IOCBs. Customers may choose + * to implement their own XIOCBs directly, or go through their own + * translation layer (xiocb->iocb like CFE does) to insulate + * themselves from IOCB changes in the future. + */ + if (xiocb->xiocb_fcode >= CFE_CMD_VENDOR_USE) { +#if CFG_VENDOR_EXTENSIONS + return cfe_vendor_doxreq((cfe_vendor_xiocb_t *)xiocb); +#else + return CFE_ERR_INV_COMMAND; +#endif + } + + /* + * Check for commands codes out of range + */ + + if ((xiocb->xiocb_fcode < 0) || (xiocb->xiocb_fcode >= CFE_CMD_MAX)) { + xiocb->xiocb_status = CFE_ERR_INV_COMMAND; + return xiocb->xiocb_status; + } + + /* + * Check for command codes in range but invalid + */ + + disp = &cfe_xcmd_dispatch_table[xiocb->xiocb_fcode]; + + if (disp->xplistsize < 0) { + xiocb->xiocb_status = CFE_ERR_INV_COMMAND; + return xiocb->xiocb_status; + } + + /* + * Check for invalid parameter list size + */ + + if (disp->xplistsize != xiocb->xiocb_psize) { + xiocb->xiocb_status = CFE_ERR_INV_PARAM; + return xiocb->xiocb_status; + } + + /* + * Okay, copy parameters into the internal IOCB. + * First, the fixed header. + */ + + iiocb.iocb_fcode = (unsigned int) xiocb->xiocb_fcode; + iiocb.iocb_status = (int) xiocb->xiocb_status; + iiocb.iocb_handle = (int) xiocb->xiocb_handle; + iiocb.iocb_flags = (unsigned int) xiocb->xiocb_flags; + iiocb.iocb_psize = (unsigned int) disp->iplistsize; + + /* + * Now the parameter list + */ + + switch (disp->plisttype) { + case PLBUF: + iiocb.plist.iocb_buffer.buf_offset = (cfe_offset_t) xiocb->plist.xiocb_buffer.buf_offset; + iiocb.plist.iocb_buffer.buf_ptr = (unsigned char *) (uintptr_t) xiocb->plist.xiocb_buffer.buf_ptr; + iiocb.plist.iocb_buffer.buf_length = (unsigned int) xiocb->plist.xiocb_buffer.buf_length; + iiocb.plist.iocb_buffer.buf_retlen = (unsigned int) xiocb->plist.xiocb_buffer.buf_retlen; + iiocb.plist.iocb_buffer.buf_ioctlcmd = (unsigned int) xiocb->plist.xiocb_buffer.buf_ioctlcmd; + break; + case PLCPU: + iiocb.plist.iocb_cpuctl.cpu_number = (unsigned int) xiocb->plist.xiocb_cpuctl.cpu_number; + iiocb.plist.iocb_cpuctl.cpu_command = (unsigned int) xiocb->plist.xiocb_cpuctl.cpu_command; + iiocb.plist.iocb_cpuctl.start_addr = (unsigned long) xiocb->plist.xiocb_cpuctl.start_addr; + iiocb.plist.iocb_cpuctl.gp_val = (unsigned long) xiocb->plist.xiocb_cpuctl.gp_val; + iiocb.plist.iocb_cpuctl.sp_val = (unsigned long) xiocb->plist.xiocb_cpuctl.sp_val; + iiocb.plist.iocb_cpuctl.a1_val = (unsigned long) xiocb->plist.xiocb_cpuctl.a1_val; + break; + case PLMEM: + iiocb.plist.iocb_meminfo.mi_idx = (int) xiocb->plist.xiocb_meminfo.mi_idx; + iiocb.plist.iocb_meminfo.mi_type = (int) xiocb->plist.xiocb_meminfo.mi_type; + iiocb.plist.iocb_meminfo.mi_addr = (unsigned long long) xiocb->plist.xiocb_meminfo.mi_addr; + iiocb.plist.iocb_meminfo.mi_size = (unsigned long long) xiocb->plist.xiocb_meminfo.mi_size; + break; + case PLENV: + iiocb.plist.iocb_envbuf.enum_idx = (int) xiocb->plist.xiocb_envbuf.enum_idx; + iiocb.plist.iocb_envbuf.name_ptr = (unsigned char *) (uintptr_t) xiocb->plist.xiocb_envbuf.name_ptr; + iiocb.plist.iocb_envbuf.name_length = (int) xiocb->plist.xiocb_envbuf.name_length; + iiocb.plist.iocb_envbuf.val_ptr = (unsigned char *) (uintptr_t) xiocb->plist.xiocb_envbuf.val_ptr; + iiocb.plist.iocb_envbuf.val_length = (int) xiocb->plist.xiocb_envbuf.val_length; + break; + case PLINP: + iiocb.plist.iocb_inpstat.inp_status = (int) xiocb->plist.xiocb_inpstat.inp_status; + break; + case PLTIM: + iiocb.plist.iocb_time.ticks = (long long) xiocb->plist.xiocb_time.ticks; + break; + case PLINF: + break; + case PLEXIT: + iiocb.plist.iocb_exitstat.status = (long long) xiocb->plist.xiocb_exitstat.status; + break; + } + + /* + * Do the internal function dispatch + */ + + res = (cfe_int_t) cfe_iocb_dispatch(&iiocb); + + /* + * Now convert the parameter list members back + */ + + switch (disp->plisttype) { + case PLBUF: + xiocb->plist.xiocb_buffer.buf_offset = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_offset; + xiocb->plist.xiocb_buffer.buf_ptr = (cfe_xptr_t) (uintptr_t) iiocb.plist.iocb_buffer.buf_ptr; + xiocb->plist.xiocb_buffer.buf_length = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_length; + xiocb->plist.xiocb_buffer.buf_retlen = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_retlen; + xiocb->plist.xiocb_buffer.buf_ioctlcmd = (cfe_uint_t) iiocb.plist.iocb_buffer.buf_ioctlcmd; + break; + case PLCPU: + xiocb->plist.xiocb_cpuctl.cpu_number = (cfe_uint_t) iiocb.plist.iocb_cpuctl.cpu_number; + xiocb->plist.xiocb_cpuctl.cpu_command = (cfe_uint_t) iiocb.plist.iocb_cpuctl.cpu_command; + xiocb->plist.xiocb_cpuctl.start_addr = (cfe_uint_t) iiocb.plist.iocb_cpuctl.start_addr; + break; + case PLMEM: + xiocb->plist.xiocb_meminfo.mi_idx = (cfe_int_t) iiocb.plist.iocb_meminfo.mi_idx; + xiocb->plist.xiocb_meminfo.mi_type = (cfe_int_t) iiocb.plist.iocb_meminfo.mi_type; + xiocb->plist.xiocb_meminfo.mi_addr = (cfe_int64_t) iiocb.plist.iocb_meminfo.mi_addr; + xiocb->plist.xiocb_meminfo.mi_size = (cfe_int64_t) iiocb.plist.iocb_meminfo.mi_size; + break; + case PLENV: + xiocb->plist.xiocb_envbuf.enum_idx = (cfe_int_t) iiocb.plist.iocb_envbuf.enum_idx; + xiocb->plist.xiocb_envbuf.name_ptr = (cfe_xptr_t) (uintptr_t) iiocb.plist.iocb_envbuf.name_ptr; + xiocb->plist.xiocb_envbuf.name_length = (cfe_int_t) iiocb.plist.iocb_envbuf.name_length; + xiocb->plist.xiocb_envbuf.val_ptr = (cfe_xptr_t) (uintptr_t) iiocb.plist.iocb_envbuf.val_ptr; + xiocb->plist.xiocb_envbuf.val_length = (cfe_int_t) iiocb.plist.iocb_envbuf.val_length; + break; + case PLINP: + xiocb->plist.xiocb_inpstat.inp_status = (cfe_int_t) iiocb.plist.iocb_inpstat.inp_status; + break; + case PLTIM: + xiocb->plist.xiocb_time.ticks = (cfe_int_t) iiocb.plist.iocb_time.ticks; + break; + case PLINF: + xiocb->plist.xiocb_fwinfo.fwi_version = iiocb.plist.iocb_fwinfo.fwi_version; + xiocb->plist.xiocb_fwinfo.fwi_totalmem = iiocb.plist.iocb_fwinfo.fwi_totalmem; + xiocb->plist.xiocb_fwinfo.fwi_flags = iiocb.plist.iocb_fwinfo.fwi_flags; + xiocb->plist.xiocb_fwinfo.fwi_boardid = iiocb.plist.iocb_fwinfo.fwi_boardid; + xiocb->plist.xiocb_fwinfo.fwi_bootarea_va = iiocb.plist.iocb_fwinfo.fwi_bootarea_va; + xiocb->plist.xiocb_fwinfo.fwi_bootarea_pa = iiocb.plist.iocb_fwinfo.fwi_bootarea_pa; + xiocb->plist.xiocb_fwinfo.fwi_bootarea_size = iiocb.plist.iocb_fwinfo.fwi_bootarea_size; + xiocb->plist.xiocb_fwinfo.fwi_reserved1 = iiocb.plist.iocb_fwinfo.fwi_reserved1; + xiocb->plist.xiocb_fwinfo.fwi_reserved2 = iiocb.plist.iocb_fwinfo.fwi_reserved2; + xiocb->plist.xiocb_fwinfo.fwi_reserved3 = iiocb.plist.iocb_fwinfo.fwi_reserved3; + break; + case PLEXIT: + xiocb->plist.xiocb_exitstat.status = (cfe_int_t) iiocb.plist.iocb_exitstat.status; + break; + } + + /* + * And the fixed header + */ + + xiocb->xiocb_status = (cfe_int_t) iiocb.iocb_status; + xiocb->xiocb_handle = (cfe_int_t) iiocb.iocb_handle; + xiocb->xiocb_flags = (cfe_uint_t) iiocb.iocb_flags; + + return xiocb->xiocb_status; +} diff --git a/cfe/cfe/main/cfe_zlibfs.c b/cfe/cfe/main/cfe_zlibfs.c new file mode 100644 index 0000000..7ad0847 --- /dev/null +++ b/cfe/cfe/main/cfe_zlibfs.c @@ -0,0 +1,453 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * "Compressed" file system File: cfe_zlibfs.c + * + * This is more of a filesystem "hook" than an actual file system. + * You can stick it on the front of the chain of file systems + * that CFE calls and it will route data read from the + * underlying filesystem through ZLIB before passing it up to the + * user. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#if CFG_ZLIB + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_error.h" +#include "cfe_fileops.h" +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_console.h" + +#include "cfe.h" + +#include "zlib.h" + +/* ********************************************************************* + * ZLIBFS context + ********************************************************************* */ + +/* + * File system context - describes overall file system info, + * such as the handle to the underlying device. + */ + +typedef struct zlibfs_fsctx_s { + void *zlibfsctx_subfsctx; + const fileio_dispatch_t *zlibfsctx_subops; + int zlibfsctx_refcnt; +} zlibfs_fsctx_t; + +/* + * File context - describes an open file on the file system. + * For raw devices, this is pretty meaningless, but we do + * keep track of where we are. + */ + +#define ZLIBFS_BUFSIZE 1024 +typedef struct zlibfs_file_s { + zlibfs_fsctx_t *zlibfs_fsctx; + int zlibfs_fileoffset; + void *zlibfs_subfile; + z_stream zlibfs_stream; + uint8_t *zlibfs_inbuf; + uint8_t *zlibfs_outbuf; + int zlibfs_outlen; + uint8_t *zlibfs_outptr; + int zlibfs_eofseen; +} zlibfs_file_t; + +/* ********************************************************************* + * Prototypes + ********************************************************************* */ + +static int zlibfs_fileop_init(void **fsctx,void *ctx); +static int zlibfs_fileop_open(void **ref,void *fsctx,char *filename,int mode); +static int zlibfs_fileop_read(void *ref,uint8_t *buf,int len); +static int zlibfs_fileop_write(void *ref,uint8_t *buf,int len); +static int zlibfs_fileop_seek(void *ref,int offset,int how); +static void zlibfs_fileop_close(void *ref); +static void zlibfs_fileop_uninit(void *fsctx); + +voidpf zcalloc(voidpf opaque,unsigned items, unsigned size); +void zcfree(voidpf opaque,voidpf ptr); + +/* ********************************************************************* + * ZLIB fileio dispatch table + ********************************************************************* */ + + +static uint8_t 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 */ + +const fileio_dispatch_t zlibfs_fileops = { + "z", + 0, + zlibfs_fileop_init, + zlibfs_fileop_open, + zlibfs_fileop_read, + zlibfs_fileop_write, + zlibfs_fileop_seek, + zlibfs_fileop_close, + zlibfs_fileop_uninit +}; + +/* + * Utility functions needed by the ZLIB routines + */ +voidpf zcalloc(voidpf opaque,unsigned items, unsigned size) +{ + void *ptr; + + ptr = KMALLOC(items*size,0); + if (ptr) lib_memset(ptr,0,items*size); + return ptr; +} + +void zcfree(voidpf opaque,voidpf ptr) +{ + KFREE(ptr); +} + + +static int zlibfs_fileop_init(void **newfsctx,void *curfsvoid) +{ + zlibfs_fsctx_t *fsctx; + fileio_ctx_t *curfsctx = (fileio_ctx_t *) curfsvoid; + + *newfsctx = NULL; + + fsctx = KMALLOC(sizeof(zlibfs_fsctx_t),0); + if (!fsctx) { + return CFE_ERR_NOMEM; + } + + fsctx->zlibfsctx_refcnt = 0; + fsctx->zlibfsctx_subops = curfsctx->ops; + fsctx->zlibfsctx_subfsctx = curfsctx->fsctx; + + *newfsctx = fsctx; + + return 0; +} + + +static int get_byte(zlibfs_file_t *file,uint8_t *ch) +{ + int res; + + res = BDREAD(file->zlibfs_fsctx->zlibfsctx_subops, + file->zlibfs_subfile, + ch, + 1); + + return res; +} + + +static int check_header(zlibfs_file_t *file) +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + uint8_t c; + int res; + + /* Check the gzip magic header */ + for (len = 0; len < 2; len++) { + res = get_byte(file,&c); + if (c != gz_magic[len]) { + return -1; + } + } + + get_byte(file,&c); method = (int) c; + get_byte(file,&c); flags = (int) c; + + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + return -1; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(file,&c); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + get_byte(file,&c); + len = (uInt) c; + get_byte(file,&c); + len += ((uInt)c)<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while ((len-- != 0) && (get_byte(file,&c) == 1)) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((get_byte(file,&c) == 1) && (c != 0)) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((get_byte(file,&c) == 1) && (c != 0)) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(file,&c); + } + + return 0; +} + +static int zlibfs_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode) +{ + zlibfs_fsctx_t *fsctx; + zlibfs_file_t *file; + int err; + + if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED; + + fsctx = (zlibfs_fsctx_t *) fsctx_arg; + + file = KMALLOC(sizeof(zlibfs_file_t),0); + if (!file) { + return CFE_ERR_NOMEM; + } + + file->zlibfs_fileoffset = 0; + file->zlibfs_fsctx = fsctx; + file->zlibfs_inbuf = NULL; + file->zlibfs_outbuf = NULL; + file->zlibfs_eofseen = 0; + + err = BDOPEN(fsctx->zlibfsctx_subops,&(file->zlibfs_subfile), + fsctx->zlibfsctx_subfsctx,filename); + + if (err != 0) { + goto error2; + return err; + } + + /* Open the zstream */ + + file->zlibfs_inbuf = KMALLOC(ZLIBFS_BUFSIZE,0); + file->zlibfs_outbuf = KMALLOC(ZLIBFS_BUFSIZE,0); + + if (!file->zlibfs_inbuf || !file->zlibfs_outbuf) { + err = CFE_ERR_NOMEM; + goto error; + } + + file->zlibfs_stream.next_in = NULL; + file->zlibfs_stream.avail_in = 0; + file->zlibfs_stream.next_out = file->zlibfs_outbuf; + file->zlibfs_stream.avail_out = ZLIBFS_BUFSIZE; + file->zlibfs_stream.zalloc = (alloc_func)0; + file->zlibfs_stream.zfree = (free_func)0; + + file->zlibfs_outlen = 0; + file->zlibfs_outptr = file->zlibfs_outbuf; + + err = inflateInit2(&(file->zlibfs_stream),-15); + if (err != Z_OK) { + err = CFE_ERR; + goto error; + } + + check_header(file); + + fsctx->zlibfsctx_refcnt++; + + *ref = file; + return 0; + +error: + BDCLOSE(file->zlibfs_fsctx->zlibfsctx_subops,file->zlibfs_subfile); +error2: + if (file->zlibfs_inbuf) KFREE(file->zlibfs_inbuf); + if (file->zlibfs_outbuf) KFREE(file->zlibfs_outbuf); + KFREE(file); + return err; +} + +static int zlibfs_fileop_read(void *ref,uint8_t *buf,int len) +{ + zlibfs_file_t *file = (zlibfs_file_t *) ref; + int res = 0; + int err; + int amtcopy; + int ttlcopy = 0; + + if (len == 0) return 0; + + while (len) { + + /* Figure the amount to copy. This is the min of what we + have left to do and what is available. */ + amtcopy = len; + if (amtcopy > file->zlibfs_outlen) { + amtcopy = file->zlibfs_outlen; + } + + /* Copy the data. */ + + if (buf) { + memcpy(buf,file->zlibfs_outptr,amtcopy); + buf += amtcopy; + } + + /* Update the pointers. */ + file->zlibfs_outptr += amtcopy; + file->zlibfs_outlen -= amtcopy; + len -= amtcopy; + ttlcopy += amtcopy; + + /* If we've eaten all of the output, reset and call inflate + again. */ + + if (file->zlibfs_outlen == 0) { + /* If no input data to decompress, get some more if we can. */ + if (file->zlibfs_eofseen) break; + if (file->zlibfs_stream.avail_in == 0) { + res = BDREAD(file->zlibfs_fsctx->zlibfsctx_subops, + file->zlibfs_subfile, + file->zlibfs_inbuf, + ZLIBFS_BUFSIZE); + /* If at EOF or error, get out. */ + if (res <= 0) break; + file->zlibfs_stream.next_in = file->zlibfs_inbuf; + file->zlibfs_stream.avail_in = res; + } + + /* inflate the input data. */ + file->zlibfs_stream.next_out = file->zlibfs_outbuf; + file->zlibfs_stream.avail_out = ZLIBFS_BUFSIZE; + file->zlibfs_outptr = file->zlibfs_outbuf; + err = inflate(&(file->zlibfs_stream),Z_SYNC_FLUSH); + if (err == Z_STREAM_END) { + /* We can get a partial buffer fill here. */ + file->zlibfs_eofseen = 1; + } + else if (err != Z_OK) { + res = CFE_ERR; + break; + } + file->zlibfs_outlen = file->zlibfs_stream.next_out - + file->zlibfs_outptr; + } + + } + + file->zlibfs_fileoffset += ttlcopy; + + return (res < 0) ? res : ttlcopy; +} + +static int zlibfs_fileop_write(void *ref,uint8_t *buf,int len) +{ + return CFE_ERR_UNSUPPORTED; +} + +static int zlibfs_fileop_seek(void *ref,int offset,int how) +{ + zlibfs_file_t *file = (zlibfs_file_t *) ref; + int res; + int delta; + + switch (how) { + case FILE_SEEK_BEGINNING: + delta = offset - file->zlibfs_fileoffset; + break; + case FILE_SEEK_CURRENT: + delta = offset; + break; + default: + return CFE_ERR_UNSUPPORTED; + break; + } + + /* backward seeking not allowed on compressed streams */ + if (delta < 0) { + return CFE_ERR_UNSUPPORTED; + } + + res = zlibfs_fileop_read(ref,NULL,delta); + + if (res < 0) return res; + + return file->zlibfs_fileoffset; +} + + +static void zlibfs_fileop_close(void *ref) +{ + zlibfs_file_t *file = (zlibfs_file_t *) ref; + + file->zlibfs_fsctx->zlibfsctx_refcnt--; + + inflateEnd(&(file->zlibfs_stream)); + + BDCLOSE(file->zlibfs_fsctx->zlibfsctx_subops,file->zlibfs_subfile); + + KFREE(file); +} + +static void zlibfs_fileop_uninit(void *fsctx_arg) +{ + zlibfs_fsctx_t *fsctx = (zlibfs_fsctx_t *) fsctx_arg; + + if (fsctx->zlibfsctx_refcnt) { + xprintf("zlibfs_fileop_uninit: warning: refcnt not zero\n"); + } + + BDUNINIT(fsctx->zlibfsctx_subops,fsctx->zlibfsctx_subfsctx); + + KFREE(fsctx); +} + + +#endif diff --git a/cfe/cfe/main/env_subr.c b/cfe/cfe/main/env_subr.c new file mode 100644 index 0000000..5f12359 --- /dev/null +++ b/cfe/cfe/main/env_subr.c @@ -0,0 +1,474 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Environment variable subroutines File: env_subr.c + * + * This module contains routines to muck with environment variables + * (manage the list, read/write to nvram, etc.) + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "env_subr.h" +#include "nvram_subr.h" + +#include "cfe_error.h" +#include "cfe.h" + +/* ********************************************************************* + * Types + ********************************************************************* */ + +typedef struct cfe_envvar_s { + queue_t qb; + int flags; + char *name; + char *value; + /* name and value go here */ +} cfe_envvar_t; + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +queue_t env_envvars = {&env_envvars,&env_envvars}; +extern unsigned int cfe_startflags; + +/* ********************************************************************* + * env_findenv(name) + * + * Locate an environment variable in the in-memory list + * + * Input parameters: + * name - name of env var to find + * + * Return value: + * cfe_envvar_t pointer, or NULL if not found + ********************************************************************* */ + +static cfe_envvar_t *env_findenv(const char *name) +{ + queue_t *qb; + cfe_envvar_t *env; + + for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) { + env = (cfe_envvar_t *) qb; + if (strcmp(env->name,name) == 0) break; + } + + if (qb == &env_envvars) return NULL; + + return (cfe_envvar_t *) qb; + +} + +/* ********************************************************************* + * env_enum(idx,name,namelen,val,vallen) + * + * Enumerate environment variables. This routine locates + * the nth environment variable and copies its name and value + * to user buffers. + * + * The namelen and vallen variables must be preinitialized to + * the maximum size of the output buffer. + * + * Input parameters: + * idx - variable index to find (starting with zero) + * name,namelen - name buffer and length + * val,vallen - value buffer and length + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int env_enum(int idx,char *name,int *namelen,char *val,int *vallen) +{ + queue_t *qb; + cfe_envvar_t *env; + + for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) { + if (idx == 0) break; + idx--; + } + + if (qb == &env_envvars) return CFE_ERR_ENVNOTFOUND; + env = (cfe_envvar_t *) qb; + + *namelen = xstrncpy(name,env->name,*namelen); + *vallen = xstrncpy(val,env->value,*vallen); + + return 0; + +} + +/* ********************************************************************* + * env_envtype(name) + * + * Return the type of the environment variable + * + * Input parameters: + * name - name of environment variable + * + * Return value: + * flags, or <0 if error occured + ********************************************************************* */ +int env_envtype(const char *name) +{ + cfe_envvar_t *env; + + env = env_findenv(name); + + if (env) { + return env->flags; + } + + return CFE_ERR_ENVNOTFOUND; +} + + + +/* ********************************************************************* + * env_delenv(name) + * + * Delete an environment variable + * + * Input parameters: + * name - environment variable to delete + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int env_delenv(const char *name) +{ + cfe_envvar_t *env; + + env = env_findenv(name); + + if (!env) return 0; + + if (!(env->flags & ENV_FLG_READONLY)) { + q_dequeue((queue_t *) env); + KFREE(env); + return 0; + } + + return CFE_ERR_ENVNOTFOUND; +} + +/* ********************************************************************* + * env_getenv(name) + * + * Retrieve the value of an environment variable + * + * Input parameters: + * name - name of environment variable to find + * + * Return value: + * value, or NULL if variable is not found + ********************************************************************* */ + +char *env_getenv(const char *name) +{ + cfe_envvar_t *env; + + env = env_findenv(name); + + if (env) { + return env->value; + } + + return NULL; +} + + +/* ********************************************************************* + * env_setenv(name,value,flags) + * + * Set the value of an environment variable + * + * Input parameters: + * name - name of variable + * value - value of variable + * flags - flags for variable (ENV_FLG_xxx) + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int env_setenv(const char *name,char *value,int flags) +{ + cfe_envvar_t *env; + int namelen; + + env = env_findenv(name); + if (env) { + if (!(flags & ENV_FLG_ADMIN)) { + if (env->flags & ENV_FLG_READONLY) return CFE_ERR_ENVREADONLY; + } + q_dequeue((queue_t *) env); + KFREE(env); + } + + namelen = strlen(name); + + env = KMALLOC(sizeof(cfe_envvar_t) + namelen + 1 + strlen(value) + 1,0); + if (!env) return CFE_ERR_NOMEM; + + env->name = (char *) (env+1); + env->value = env->name + namelen + 1; + env->flags = (flags & ENV_FLG_MASK); + + strcpy(env->name,name); + strcpy(env->value,value); + + q_enqueue(&env_envvars,(queue_t *) env); + + return 0; +} + + +/* ********************************************************************* + * env_load() + * + * Load the environment from the NVRAM device. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + + +int env_load(void) +{ + int size; + unsigned char *buffer; + unsigned char *ptr; + unsigned char *envval; + unsigned int reclen; + unsigned int rectype; + int offset; + int flg; + int retval = -1; + char valuestr[256]; + + /* + * If in 'safe mode', don't read the environment the first time. + */ + + if (cfe_startflags & CFE_INIT_SAFE) { + cfe_startflags &= ~CFE_INIT_SAFE; + return 0; + } + + flg = nvram_open(); + if (flg < 0) return flg; + + size = nvram_getsize(); + buffer = KMALLOC(size,0); + + if (buffer == NULL) return CFE_ERR_NOMEM; + + ptr = buffer; + offset = 0; + + /* Read the record type and length */ + if (nvram_read(ptr,offset,1) != 1) { + retval = CFE_ERR_IOERR; + goto error; + } + + while ((*ptr != ENV_TLV_TYPE_END) && (size > 1)) { + + /* Adjust pointer for TLV type */ + rectype = *(ptr); + offset++; + size--; + + /* + * Read the length. It can be either 1 or 2 bytes + * depending on the code + */ + if (rectype & ENV_LENGTH_8BITS) { + /* Read the record type and length - 8 bits */ + if (nvram_read(ptr,offset,1) != 1) { + retval = CFE_ERR_IOERR; + goto error; + } + reclen = *(ptr); + size--; + offset++; + } + else { + /* Read the record type and length - 16 bits, MSB first */ + if (nvram_read(ptr,offset,2) != 2) { + retval = CFE_ERR_IOERR; + goto error; + } + reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1); + size -= 2; + offset += 2; + } + + if (reclen > size) break; /* should not happen, bad NVRAM */ + + switch (rectype) { + case ENV_TLV_TYPE_ENV: + /* Read the TLV data */ + if (nvram_read(ptr,offset,reclen) != reclen) goto error; + flg = *ptr++; + envval = (unsigned char *) strnchr(ptr,'=',(reclen-1)); + if (envval) { + *envval++ = '\0'; + memcpy(valuestr,envval,(reclen-1)-(envval-ptr)); + valuestr[(reclen-1)-(envval-ptr)] = '\0'; + env_setenv(ptr,valuestr,flg); + } + break; + + default: + /* Unknown TLV type, skip it. */ + break; + } + + /* + * Advance to next TLV + */ + + size -= (int)reclen; + offset += reclen; + + /* Read the next record type */ + ptr = buffer; + if (nvram_read(ptr,offset,1) != 1) goto error; + } + + retval = 0; /* success! */ + +error: + KFREE(buffer); + nvram_close(); + + return retval; + +} + + +/* ********************************************************************* + * env_save() + * + * Write the environment to the NVRAM device. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok, else error code + ********************************************************************* */ + +int env_save(void) +{ + int size; + unsigned char *buffer; + unsigned char *buffer_end; + unsigned char *ptr; + queue_t *qb; + cfe_envvar_t *env; + int namelen; + int valuelen; + int flg; + + flg = nvram_open(); + if (flg < 0) return flg; + + nvram_erase(); + + size = nvram_getsize(); + buffer = KMALLOC(size,0); + + if (buffer == NULL) return CFE_ERR_NOMEM; + + buffer_end = buffer + size; + + ptr = buffer; + + for (qb = env_envvars.q_next; qb != &env_envvars; qb = qb->q_next) { + env = (cfe_envvar_t *) qb; + + if (env->flags & (ENV_FLG_BUILTIN)) continue; + + namelen = strlen(env->name); + valuelen = strlen(env->value); + + if ((ptr + 2 + namelen + valuelen + 1 + 1 + 1) > buffer_end) break; + + *ptr++ = ENV_TLV_TYPE_ENV; /* TLV record type */ + *ptr++ = (namelen + valuelen + 1 + 1); /* TLV record length */ + + *ptr++ = (unsigned char)env->flags; + memcpy(ptr,env->name,namelen); /* TLV record data */ + ptr += namelen; + *ptr++ = '='; + memcpy(ptr,env->value,valuelen); + ptr += valuelen; + + } + + *ptr++ = ENV_TLV_TYPE_END; + + size = nvram_write(buffer,0,ptr-buffer); + + KFREE(buffer); + + nvram_close(); + + return (size == (ptr-buffer)) ? 0 : CFE_ERR_IOERR; +} diff --git a/cfe/cfe/main/nvram_subr.c b/cfe/cfe/main/nvram_subr.c new file mode 100644 index 0000000..2c44bca --- /dev/null +++ b/cfe/cfe/main/nvram_subr.c @@ -0,0 +1,300 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * NVRAM subroutines File: nvram_subr.c + * + * High-level routines to read/write the NVRAM device. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "lib_types.h" +#include "lib_string.h" +#include "lib_queue.h" +#include "lib_malloc.h" +#include "lib_printf.h" + +#include "cfe_iocb.h" +#include "cfe_devfuncs.h" +#include "cfe_ioctl.h" + +#include "cfe_error.h" +#include "env_subr.h" +#include "nvram_subr.h" +#include "cfe.h" + +/* ********************************************************************* + * Globals + ********************************************************************* */ + +static int nvram_handle = -1; +static nvram_info_t nvram_info; +static char *nvram_devname = NULL; + +/* ********************************************************************* + * nvram_getinfo(info) + * + * Obtain information about the NVRAM device from the device + * driver. A flash device might only dedicate a single sector + * to the environment, so we need to ask the driver first. + * + * Input parameters: + * info - nvram info + * + * Return value: + * 0 if ok + * <0 = error code + ********************************************************************* */ + +static int nvram_getinfo(nvram_info_t *info) +{ + int retlen; + + if (nvram_handle == -1) return -1; + + cfe_ioctl(nvram_handle,IOCTL_NVRAM_UNLOCK,NULL,0,NULL,0); + + if (cfe_ioctl(nvram_handle,IOCTL_NVRAM_GETINFO, + (unsigned char *) info, + sizeof(nvram_info_t), + &retlen,0) != 0) { + return -1; + } + + return 0; + +} + +/* ********************************************************************* + * nvram_open() + * + * Open the default NVRAM device and get the information from the + * device driver. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int nvram_open(void) +{ + if (nvram_handle != -1) { + nvram_close(); + } + + if (nvram_devname == NULL) { + return CFE_ERR_DEVNOTFOUND; + } + + nvram_handle = cfe_open(nvram_devname); + + if (nvram_handle < 0) { + return CFE_ERR_DEVNOTFOUND; + } + + if (nvram_getinfo(&nvram_info) < 0) { + nvram_close(); + return CFE_ERR_IOERR; + } + + return 0; +} + +/* ********************************************************************* + * nvram_close() + * + * Close the NVRAM device + * + * Input parameters: + * nothing + * + * Return value: + * 0 + ********************************************************************* */ + +int nvram_close(void) +{ + if (nvram_handle != -1) { + cfe_close(nvram_handle); + nvram_handle = -1; + } + + return 0; +} + + +/* ********************************************************************* + * nvram_getsize() + * + * Return the total size of the NVRAM device. Note that + * this is the total size that is used for the NVRAM functions, + * not the size of the underlying media. + * + * Input parameters: + * nothing + * + * Return value: + * size. <0 if error + ********************************************************************* */ + +int nvram_getsize(void) +{ + if (nvram_handle < 0) return 0; + return nvram_info.nvram_size; +} + + +/* ********************************************************************* + * nvram_read(buffer,offset,length) + * + * Read data from the NVRAM device + * + * Input parameters: + * buffer - destination buffer + * offset - offset of data to read + * length - number of bytes to read + * + * Return value: + * number of bytes read, or <0 if error occured + ********************************************************************* */ +int nvram_read(unsigned char *buffer,int offset,int length) +{ + if (nvram_handle == -1) return -1; + + return cfe_readblk(nvram_handle, + (cfe_offset_t) (offset+nvram_info.nvram_offset), + buffer, + length); +} + +/* ********************************************************************* + * nvram_write(buffer,offset,length) + * + * Write data to the NVRAM device + * + * Input parameters: + * buffer - source buffer + * offset - offset of data to write + * length - number of bytes to write + * + * Return value: + * number of bytes written, or -1 if error occured + ********************************************************************* */ +int nvram_write(unsigned char *buffer,int offset,int length) +{ + if (nvram_handle == -1) return -1; + + return cfe_writeblk(nvram_handle, + (cfe_offset_t) (offset+nvram_info.nvram_offset), + buffer, + length); +} + + +/* ********************************************************************* + * nvram_erase() + * + * Erase the NVRAM device. Not all devices need to be erased, + * but flash memory does. + * + * Input parameters: + * nothing + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int nvram_erase(void) +{ + int retlen; + + if (nvram_handle < 0) { + return -1; + } + + if (nvram_info.nvram_eraseflg == FALSE) return 0; + + if (cfe_ioctl(nvram_handle,IOCTL_NVRAM_ERASE, + (unsigned char *) &nvram_info, + sizeof(nvram_info_t), + &retlen,0) != 0) { + return -1; + } + + return 0; +} + + +/* ********************************************************************* + * cfe_set_envdevice(name) + * + * Set the environment NVRAM device name + * + * Input parameters: + * name - name of device to use for NVRAM + * + * Return value: + * 0 if ok + * else error code + ********************************************************************* */ + +int cfe_set_envdevice(char *name) +{ + int res; + + nvram_devname = strdup(name); + + res = nvram_open(); + + if (res != 0) { + xprintf("!! Could not open NVRAM device %s\n",nvram_devname); + return res; + } + + nvram_close(); + + res = env_load(); + + return res; +} diff --git a/cfe/cfe/main/nvram_subr.h b/cfe/cfe/main/nvram_subr.h new file mode 100644 index 0000000..f614ec2 --- /dev/null +++ b/cfe/cfe/main/nvram_subr.h @@ -0,0 +1,54 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * NVRAM prototypes File: nvram_subr.h + * + * Prototypes for NVRAM routines. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR 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), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +int nvram_getsize(void); +int nvram_read(unsigned char *buffer,int,int); +int nvram_write(unsigned char *buffer,int,int); +int nvram_open(void); +int nvram_close(void); +int nvram_erase(void); + |