summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/lib
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/lib')
-rw-r--r--cfe/cfe/lib/lib_arena.c389
-rw-r--r--cfe/cfe/lib/lib_malloc.c620
-rw-r--r--cfe/cfe/lib/lib_misc.c229
-rw-r--r--cfe/cfe/lib/lib_printf.c442
-rw-r--r--cfe/cfe/lib/lib_qsort.c88
-rw-r--r--cfe/cfe/lib/lib_queue.c219
-rw-r--r--cfe/cfe/lib/lib_string.c386
-rw-r--r--cfe/cfe/lib/lib_string2.c96
8 files changed, 2469 insertions, 0 deletions
diff --git a/cfe/cfe/lib/lib_arena.c b/cfe/cfe/lib/lib_arena.c
new file mode 100644
index 0000000..41867dc
--- /dev/null
+++ b/cfe/cfe/lib/lib_arena.c
@@ -0,0 +1,389 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Arena Manager File lib_arena.c
+ *
+ * This module manages the _arena_, a sorted linked list of
+ * memory regions and attributes. We use this to keep track
+ * of physical memory regions and what is assigned to them.
+ *
+ * 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_queue.h"
+#include "lib_arena.h"
+#include "lib_malloc.h"
+
+/* *********************************************************************
+ * arena_print(arena,msg)
+ *
+ * Debug routine to print out an arena entry
+ *
+ * Input parameters:
+ * arena - arena descriptor
+ * msg - heading message
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+#ifdef _TESTPROG_
+static void arena_print(arena_t *arena,char *msg)
+{
+ arena_node_t *node;
+ queue_t *qb;
+
+ printf("%s\n",msg);
+
+ for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list);
+ qb = qb->q_next) {
+ node = (arena_node_t *) qb;
+
+ printf("Start %5I64d End %5I64d Type %d\n",
+ node->an_address,
+ node->an_address+node->an_length,
+ node->an_type);
+
+ }
+
+}
+#endif
+
+/* *********************************************************************
+ * arena_init(arena,physmembase,physmemsize)
+ *
+ * Initialize an arena descriptor. The arena is typically
+ * created to describe the entire physical memory address space.
+ *
+ * Input parameters:
+ * arena - arena descriptor
+ * physmembase - base of region to manage (usually 0)
+ * physmemsize - size of region to manage (typically maxint)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void arena_init(arena_t *arena,uint64_t physmembase,uint64_t physmemsize)
+{
+ arena_node_t *an = NULL;
+
+ an = (arena_node_t *) KMALLOC(sizeof(arena_node_t),sizeof(uint64_t));
+
+ /* XXX check return value */
+
+ arena->arena_base = physmembase;
+ arena->arena_size = physmemsize;
+
+ an->an_address = physmembase;
+ an->an_length = physmemsize;
+ an->an_type = 0;
+ an->an_descr = NULL;
+
+ q_init(&(arena->arena_list));
+ q_enqueue(&(arena->arena_list),(queue_t *) an);
+}
+
+
+/* *********************************************************************
+ * arena_find(arena,pt)
+ *
+ * Locate the arena node containing a particular point in the
+ * address space. This routine walks the list and finds the node
+ * whose address range contains the specified point.
+ *
+ * Input parameters:
+ * arena - arena descriptor
+ * pt - point to look for
+ *
+ * Return value:
+ * arena node pointer, or NULL if no node found
+ ********************************************************************* */
+
+static arena_node_t *arena_find(arena_t *arena,uint64_t pt)
+{
+ queue_t *qb;
+ arena_node_t *an;
+
+ for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list);
+ qb = qb->q_next) {
+ an = (arena_node_t *) qb;
+
+ if ((pt >= an->an_address) &&
+ (pt < (an->an_address + an->an_length))) return an;
+
+ }
+
+ return NULL;
+}
+
+/* *********************************************************************
+ * arena_split(arena,splitpoint)
+ *
+ * Split the node containing the specified point. When we carve
+ * the arena up, we split the arena at the points on the edges
+ * of the new region, change their types, and then coalesce the
+ * arena. This handles the "split" part of that process.
+ *
+ * Input parameters:
+ * arena - arena descriptor
+ * splitpoint - address to split arena at
+ *
+ * Return value:
+ * 0 if ok
+ * -1 if could not split
+ ********************************************************************* */
+
+static int arena_split(arena_t *arena,uint64_t splitpoint)
+{
+ arena_node_t *node;
+ arena_node_t *newnode;
+
+ /*
+ * Don't need to split if it's the *last* address in the arena
+ */
+
+ if (splitpoint == (arena->arena_base+arena->arena_size)) return 0;
+
+ /*
+ * Find the block that contains the split point.
+ */
+
+ node = arena_find(arena,splitpoint);
+ if (node == NULL) return -1; /* should not happen */
+
+ /*
+ * If the address matches exactly, don't need to split
+ */
+ if (node->an_address == splitpoint) return 0;
+
+ /*
+ * Allocate a new node and adjust the length of the node we're
+ * splitting.
+ */
+
+ newnode = (arena_node_t *) KMALLOC(sizeof(arena_node_t),sizeof(uint64_t));
+
+ newnode->an_length = node->an_length - (splitpoint - node->an_address);
+ node->an_length = splitpoint - node->an_address;
+ newnode->an_address = splitpoint;
+ newnode->an_type = node->an_type;
+
+ /*
+ * Put the new node in the arena
+ */
+
+ q_enqueue(node->an_next.q_next,(queue_t *) newnode);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * arena_coalesce(arena)
+ *
+ * Coalesce the arena, merging regions that have the same type
+ * together. After coalescing, no two adjacent nodes will
+ * have the same type.
+ *
+ * Input parameters:
+ * arena - arena descriptor
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void arena_coalesce(arena_t *arena)
+{
+ arena_node_t *node;
+ arena_node_t *nextnode;
+ int removed;
+ queue_t *qb;
+
+ do {
+ removed = 0;
+ for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list);
+ qb = qb->q_next) {
+
+ node = (arena_node_t *) qb;
+ nextnode = (arena_node_t *) node->an_next.q_next;
+
+ if ((queue_t *) nextnode == &(arena->arena_list)) break;
+
+ if (node->an_type == nextnode->an_type) {
+ node->an_length += nextnode->an_length;
+ q_dequeue((queue_t *) nextnode);
+ KFREE(nextnode);
+ removed++;
+ }
+ }
+ } while (removed > 0);
+}
+
+
+/* *********************************************************************
+ * arena_markrange(arena,address,length,type,descr)
+ *
+ * Mark a region in the arena, changing the types of nodes and
+ * splitting nodes as necessary. This routine is called for
+ * each region we want to add. The order of marking regions is
+ * important, since new marks overwrite old ones. Therefore, you
+ * could mark a whole range as DRAM, and then mark sub-regions
+ * within that as used by firmware.
+ *
+ * Input parameters:
+ * arena - arena descriptor
+ * address,length - region to mark
+ * type - type code for region
+ * descr - text description of region (optional)
+ *
+ * Return value:
+ * 0 if ok
+ * -1 if error
+ ********************************************************************* */
+
+int arena_markrange(arena_t *arena,uint64_t address,uint64_t length,int type,char *descr)
+{
+ queue_t *qb;
+ arena_node_t *node;
+
+ /*
+ * Range check the region we want to mark
+ */
+
+ if ((address < arena->arena_base) ||
+ ((address+length) > (arena->arena_base + arena->arena_size))) {
+ return -1;
+ }
+
+ /*
+ * Force the arena to be split at the two points at the
+ * beginning and end of the range we want. If we have
+ * problems, coalesce the arena again and get out.
+ */
+
+ if (arena_split(arena,address) < 0) {
+ /* don't need to coalesce, we didn't split */
+ return -1;
+ }
+ if (arena_split(arena,(address+length)) < 0) {
+ /* recombine nodes split above */
+ arena_coalesce(arena);
+ return -1;
+ }
+
+ /*
+ * Assuming we've split the arena at the beginning and ending
+ * split points, we'll never mark any places outside the range
+ * specified in the "Address,length" args.
+ */
+
+ for (qb = (arena->arena_list.q_next); qb != &(arena->arena_list);
+ qb = qb->q_next) {
+ node = (arena_node_t *) qb;
+
+ if ((node->an_address >= address) &&
+ ((node->an_address + node->an_length) <= (address+length))) {
+ node->an_type = type;
+ node->an_descr = descr;
+ }
+ }
+
+ /*
+ * Now, coalesce adjacent pieces with the same type back together again
+ */
+
+ arena_coalesce(arena);
+
+ return 0;
+}
+
+
+
+/* *********************************************************************
+ * main(argc,argv)
+ *
+ * Test program.
+ *
+ * Input parameters:
+ * argc,argv - guess
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+#ifdef _TESTPROG_
+void main(int argc,char *argv[])
+{
+ arena_t arena;
+
+ arena_init(&arena,0,1024);
+#if 0
+ arena_print(&arena,"empty arena------------");
+
+ arena_split(&arena,5);
+ arena_print(&arena,"split at 5-------------");
+
+ arena_split(&arena,300);
+ arena_print(&arena,"split at 300-----------");
+
+ arena_split(&arena,100);
+ arena_print(&arena,"split at 100-----------");
+
+ arena_coalesce(&arena);
+ arena_print(&arena,"coalesced again--------");
+
+ arena_markrange(&arena,100,50,1);
+ arena_print(&arena,"addrange 100-150-------");
+ arena_markrange(&arena,10,50,1);
+ arena_print(&arena,"addrange 10-60---------");
+ arena_markrange(&arena,1000,24,3);
+ arena_print(&arena,"addrange 1000-1023-----");
+#endif
+
+ arena_markrange(&arena,100,10,1);
+ arena_markrange(&arena,120,10,2);
+ arena_markrange(&arena,140,10,3);
+ arena_print(&arena,"Before big markrange---------");
+
+ arena_markrange(&arena,50,200,4);
+ arena_print(&arena,"after big markrange---------");
+
+}
+#endif
diff --git a/cfe/cfe/lib/lib_malloc.c b/cfe/cfe/lib/lib_malloc.c
new file mode 100644
index 0000000..f7e33b2
--- /dev/null
+++ b/cfe/cfe/lib/lib_malloc.c
@@ -0,0 +1,620 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Local memory manager File: cfe_malloc.c
+ *
+ * This routine is used to manage memory allocated within the
+ * firmware. You give it a chunk of memory to manage, and then
+ * these routines manage suballocations from there.
+ *
+ * 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.
+ ********************************************************************* */
+
+#ifdef TESTPROG
+#include <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#endif
+
+#include "lib_types.h"
+#include "lib_printf.h"
+#include "lib_malloc.h"
+
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+#define MEMNODE_SEAL 0xFAAFA123 /* just some random constant */
+#define MINBLKSIZE 64
+
+/* *********************************************************************
+ * Types
+ ********************************************************************* */
+
+typedef enum { memnode_free = 0, memnode_alloc } memnode_status_t;
+
+typedef struct memnode_s {
+ unsigned int seal;
+ struct memnode_s *next; /* pointer to next node */
+ unsigned int length; /* length of the entire data section */
+ memnode_status_t status; /* alloc/free status */
+ unsigned char *data; /* points to actual user data */
+ void *memnodeptr; /* memnode back pointer (see comments) */
+} memnode_t;
+
+struct mempool_s {
+ memnode_t *root; /* pointer to root node */
+ unsigned char *base; /* base of memory region */
+ unsigned int length; /* size of memory region */
+};
+
+#define memnode_data(t,m) (t) (((memnode_t *) (m))+1)
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+mempool_t kmempool; /* default pool */
+
+/* *********************************************************************
+ * kmeminit(pool,buffer,length)
+ *
+ * Initialize the memory manager, given a pointer to an area
+ * of memory and a size. This routine simply initializes the
+ * root node to be a single block of empty space.
+ *
+ * Input parameters:
+ * pool - pool pointer
+ * buffer - beginning of buffer area, must be pointer-aligned
+ * length - length of buffer area
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+
+void kmeminit(mempool_t *pool,unsigned char *buffer,int length)
+{
+ pool->root = (memnode_t *) buffer;
+ pool->root->seal = MEMNODE_SEAL;
+ pool->root->length = length - sizeof(memnode_t);
+ pool->root->data = memnode_data(unsigned char *,pool->root);
+ pool->root->status = memnode_free;
+ pool->root->next = NULL;
+
+ pool->base = buffer;
+ pool->length = length;
+}
+
+
+/* *********************************************************************
+ * kmempoolbase(pool)
+ *
+ * Returns the base address of the specified memory pool
+ *
+ * Input parameters:
+ * pool - pool pointer
+ *
+ * Return value:
+ * pointer to beginning of pool's memory
+ ********************************************************************* */
+void *kmempoolbase(mempool_t *pool)
+{
+ return pool->base;
+}
+
+/* *********************************************************************
+ * kmempoolsize(pool)
+ *
+ * Returns the total size of the specified memory pool
+ *
+ * Input parameters:
+ * pool - pool pointer
+ *
+ * Return value:
+ * size of pool in bytes
+ ********************************************************************* */
+
+int kmempoolsize(mempool_t *pool)
+{
+ return pool->length;
+}
+
+/* *********************************************************************
+ * kmemcompact(pool)
+ *
+ * Compact the memory blocks, coalescing consectutive free blocks
+ * on the list.
+ *
+ * Input parameters:
+ * pool - pool descriptor
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void kmemcompact(mempool_t *pool)
+{
+ memnode_t *m;
+ int compacted;
+
+ do {
+ compacted = 0;
+
+ for (m = pool->root; m; m = m->next) {
+
+ /* Check seal to be sure that we're doing ok */
+
+ if (m->seal != MEMNODE_SEAL) {
+#ifdef TESTPROG
+ printf("Memory list corrupted!\n");
+#endif
+ return;
+ }
+
+ /*
+ * If we're not on the last block and both this
+ * block and the next one are free, combine them
+ */
+
+ if (m->next &&
+ (m->status == memnode_free) &&
+ (m->next->status == memnode_free)) {
+ m->length += sizeof(memnode_t) + m->next->length;
+ m->next->seal = 0;
+ m->next = m->next->next;
+ compacted++;
+ }
+
+ /* Keep going till we make a pass without doing anything. */
+ }
+ } while (compacted > 0);
+}
+
+
+/* *********************************************************************
+ * kfree(ptr)
+ *
+ * Return some memory to the pool.
+ *
+ * Input parameters:
+ * ptr - pointer to something allocated via kmalloc()
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void kfree(mempool_t *pool,void *ptr)
+{
+ memnode_t **backptr;
+ memnode_t *m;
+
+ if (((unsigned char *) ptr < pool->base) ||
+ ((unsigned char *) ptr >= (pool->base+pool->length))) {
+#ifdef TESTPROG
+ printf("Pointer %08X does not belong to pool %08X\n",ptr,pool);
+#endif
+ return;
+ }
+
+ backptr = (memnode_t **) (((unsigned char *) ptr) - sizeof(memnode_t *));
+ m = *backptr;
+
+ if (m->seal != MEMNODE_SEAL) {
+#ifdef TESTPROG
+ printf("Invalid node freed: %08X\n",m);
+#endif
+ return;
+ }
+
+ m->status = memnode_free;
+
+ kmemcompact(pool);
+}
+
+/* *********************************************************************
+ * lib_outofmemory()
+ *
+ * Called when we run out of memory.
+ * XXX replace with something real someday
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void lib_outofmemory(void);
+void lib_outofmemory(void)
+{
+ xprintf("PANIC: out of memory!\n");
+}
+
+/* *********************************************************************
+ * kmalloc(pool,size,align)
+ *
+ * Allocate some memory from the pool.
+ *
+ * Input parameters:
+ * pool - pool structure
+ * size - size of item to allocate
+ * align - alignment (must be zero or a power of 2)
+ *
+ * Return value:
+ * pointer to data, or NULL if no memory left
+ ********************************************************************* */
+
+void *kmalloc(mempool_t *pool,unsigned int size,unsigned int align)
+{
+ memnode_t *m;
+ memnode_t *newm;
+ memnode_t **backptr;
+ uintptr_t daddr = 0;
+ uintptr_t realsize = 0;
+ uintptr_t extra;
+ uintptr_t blkend;
+ uintptr_t ptralign;
+
+ /*
+ * Everything should be aligned by at least the
+ * size of an int64
+ */
+
+ ptralign = (uintptr_t) align;
+ if (ptralign < sizeof(void *)) ptralign = sizeof(uint64_t);
+
+ /*
+ * Everything should be at least a multiple of the
+ * size of a pointer.
+ */
+
+ if (size == 0) size = sizeof(void *);
+ if (size & (sizeof(void *)-1)) {
+ size += sizeof(void *);
+ size &= ~(sizeof(void *)-1);
+ }
+
+ /*
+ * Find a memnode at least big enough to hold the storage we
+ * want.
+ */
+
+ for (m = pool->root; m; m = m->next) {
+
+ if (m->status == memnode_alloc) continue;
+
+ /*
+ * If we wanted a particular alignment, we will
+ * need to adjust the size.
+ */
+
+ daddr = memnode_data(uintptr_t,m);
+ extra = 0;
+ if (daddr & (ptralign-1)) {
+ extra = size + (ptralign - (daddr & (ptralign-1)));
+ }
+ realsize = size + extra;
+
+ if (m->length < realsize) continue;
+ break;
+ }
+
+ /*
+ * If m is null, there's no memory left.
+ */
+
+ if (m == NULL) {
+ lib_outofmemory();
+ return NULL;
+ }
+
+ /*
+ * Otherwise, use this block. Calculate the address of the data
+ * to preserve the alignment.
+ */
+
+ if (daddr & (ptralign-1)) {
+ daddr += ptralign;
+ daddr &= ~(ptralign-1);
+ }
+
+ /* Mark this node as allocated. */
+
+ m->data = (unsigned char *) daddr;
+ m->status = memnode_alloc;
+
+ /*
+ * Okay, this is ugly. Store a pointer to the original
+ * memnode just before what we've allocated. It's guaranteed
+ * to be aligned at least well enough for this pointer.
+ * If for some reason the memnode was already exactly
+ * aligned, backing up will put us inside the memnode
+ * structure itself... that's why the memnodeptr field
+ * is there, as a placeholder for this eventuality.
+ */
+
+ backptr = (memnode_t **) (m->data - sizeof(memnode_t *));
+ *backptr = m;
+
+ /*
+ * See if we need to split it.
+ * Don't bother to split if the resulting size will be
+ * less than MINBLKSIZE bytes
+ */
+
+ if (m->length - realsize < MINBLKSIZE) {
+ return m->data;
+ }
+
+ /*
+ * Split this block. Align the address on a pointer-size
+ * boundary.
+ */
+
+ daddr += size;
+ if (daddr & (uintptr_t)(sizeof(void *)-1)) {
+ daddr += (uintptr_t)sizeof(void *);
+ daddr &= ~(uintptr_t)(sizeof(void *)-1);
+ }
+
+ blkend = memnode_data(uintptr_t,m) + (uintptr_t)(m->length);
+
+ newm = (memnode_t *) daddr;
+
+ newm->next = m->next;
+ m->length = (unsigned int) (daddr - memnode_data(uintptr_t,m));
+ m->next = newm;
+ m->status = memnode_alloc;
+ newm->seal = MEMNODE_SEAL;
+ newm->data = memnode_data(unsigned char *,newm);
+ newm->length = (unsigned int) (blkend - memnode_data(uintptr_t,newm));
+ newm->status = memnode_free;
+
+ return m->data;
+}
+
+
+int kmemstats(mempool_t *pool,memstats_t *stats)
+{
+ memnode_t *m;
+ memnode_t **backptr;
+ uintptr_t daddr;
+
+ stats->mem_totalbytes = pool->length;
+ stats->mem_allocbytes = 0;
+ stats->mem_freebytes = 0;
+ stats->mem_allocnodes = 0;
+ stats->mem_freenodes = 0;
+ stats->mem_largest = 0;
+
+ for (m = pool->root; m; m = m->next) {
+ if (m->status) {
+ stats->mem_allocnodes++;
+ stats->mem_allocbytes += m->length;
+ }
+ else {
+ stats->mem_freenodes++;
+ stats->mem_freebytes += m->length;
+ if (m->length > stats->mem_largest) {
+ stats->mem_largest = m->length;
+ }
+ }
+
+ daddr = memnode_data(uintptr_t,m);
+ if (m->seal != MEMNODE_SEAL) {
+ return -1;
+ }
+ if (m->next && ((daddr + m->length) != (uintptr_t) m->next)) {
+ return -1;
+ }
+ if (m->next && (m->next < m)) {
+ return -1;
+ }
+ if (m->data < (unsigned char *) m) {
+ return -1;
+ }
+ if (m->status == memnode_alloc) {
+ backptr = (memnode_t **) (m->data - sizeof(void *));
+ if (*backptr != m) {
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * kmemchk()
+ *
+ * Check the consistency of the memory pool.
+ *
+ * Input parameters:
+ * pool - pool pointer
+ *
+ * Return value:
+ * 0 - pool is consistent
+ * -1 - pool is corrupt
+ ********************************************************************* */
+
+#ifdef TESTPROG
+int kmemchk(mempool_t *pool,int verbose)
+{
+ memnode_t *m;
+ memnode_t **backptr;
+ unsigned int daddr;
+
+ for (m = pool->root; m; m = m->next) {
+ if (verbose) {
+ printf("%08X: Next=%08X Len=%5u %s Data=%08X ",
+ m,m->next,m->length,
+ m->status ? "alloc" : "free ",
+ m->data);
+ }
+ daddr = memnode_data(uintptr_t,m);
+ if (m->seal != MEMNODE_SEAL) {
+ if (verbose) printf("BadSeal ");
+ else return -1;
+ }
+ if (m->next && (daddr + m->length != (unsigned int) m->next)) {
+ if (verbose) printf("BadLength ");
+ else return -1;
+ }
+ if (m->next && (m->next < m)) {
+ if (verbose) printf("BadOrder ");
+ else return -1;
+ }
+ if (m->data < (unsigned char *) m) {
+ if (verbose) printf("BadData ");
+ else return -1;
+ }
+ if (m->status == memnode_alloc) {
+ backptr = (memnode_t **) (m->data - sizeof(void *));
+ if (*backptr != m) {
+ if (verbose) printf("BadBackPtr ");
+ else return -1;
+ }
+ }
+ if (verbose) printf("\n");
+ }
+
+ return 0;
+}
+
+
+#define MEMSIZE 1024*1024
+
+unsigned char *ptrs[4096];
+unsigned int sizes[4096];
+
+/* *********************************************************************
+ * main(argc,argv)
+ *
+ * Test program for the memory allocator
+ *
+ * Input parameters:
+ * argc,argv
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+
+void main(int argc,char *argv[])
+{
+ unsigned char *mem;
+ int items = 0;
+ int idx;
+ int size;
+ int totalsize = 0;
+ int nfree,freecnt;
+ mempool_t *pool = &kmempool;
+
+ mem = malloc(MEMSIZE);
+ kmeminit(pool,mem,MEMSIZE);
+
+ items = 0;
+
+ for (;;) {
+
+ for (;;) {
+ if (items == 4096) break;
+ size = rand() % 1024;
+ ptrs[items] = kmalloc(pool,size,1<<(rand() & 7));
+ if (!ptrs[items]) break;
+ sizes[items] = size;
+ items++;
+ totalsize += size;
+ }
+
+ printf("%d items allocated, %d total bytes\n",items,totalsize);
+
+ if (kmemchk(pool,0) < 0) {
+ kmemchk(pool,1);
+ exit(1);
+ }
+
+ /* Scramble the pointers */
+ idx = items - 1;
+
+ while (idx) {
+ if (rand() & 2) {
+ mem = ptrs[0];
+ ptrs[0] = ptrs[idx];
+ ptrs[idx] = mem;
+
+ nfree = sizes[0];
+ sizes[0] = sizes[idx];
+ sizes[idx] = nfree;
+ }
+ idx--;
+ }
+
+ /* now free a random number of elements */
+
+ nfree = rand() % items;
+ freecnt = 0;
+
+ for (idx = nfree; idx < items; idx++) {
+ kfree(pool,ptrs[idx]);
+ totalsize -= sizes[idx];
+ freecnt++;
+ ptrs[idx] = NULL;
+ sizes[idx] = 0;
+ if (kmemchk(pool,0) < 0) {
+ kmemchk(pool,1);
+ exit(1);
+ }
+ }
+
+ items -= freecnt;
+
+ printf(".");
+
+ }
+
+ kmemchk(pool,1);
+
+ exit(0);
+}
+
+#endif /* TESTPROG */
diff --git a/cfe/cfe/lib/lib_misc.c b/cfe/cfe/lib/lib_misc.c
new file mode 100644
index 0000000..e5a2a02
--- /dev/null
+++ b/cfe/cfe/lib/lib_misc.c
@@ -0,0 +1,229 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Misc. library routines File: lib_misc.c
+ *
+ * Miscellaneous library 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.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#define _LIB_NO_MACROS_
+#include "lib_string.h"
+
+
+/* *********************************************************************
+ * lib_parseipaddr(ipaddr,dest)
+ *
+ * Parse an IP address.
+ *
+ * Input parameters:
+ * ipaddr - string of IP address
+ * dest - pointer to 4 bytes to receive binary IP address
+ *
+ * Return value:
+ * 0 if ok
+ * -1 if ip address is invalid
+ ********************************************************************* */
+
+int lib_parseipaddr(const char *ipaddr,uint8_t *dest)
+{
+ int a,b,c,d;
+ char *x;
+
+ /* make sure it's all digits and dots. */
+ x = (char *) ipaddr;
+ while (*x) {
+ if ((*x == '.') || ((*x >= '0') && (*x <= '9'))) {
+ x++;
+ continue;
+ }
+ return -1;
+ }
+
+ x = (char *) ipaddr;
+ a = lib_atoi(ipaddr);
+ x = lib_strchr(x,'.');
+ if (!x) return -1;
+ b = lib_atoi(x+1);
+ x = lib_strchr(x+1,'.');
+ if (!x) return -1;
+ c = lib_atoi(x+1);
+ x = lib_strchr(x+1,'.');
+ if (!x) return -1;
+ d = lib_atoi(x+1);
+
+ if ((a < 0) || (a > 255)) return -1;
+ if ((b < 0) || (b > 255)) return -1;
+ if ((c < 0) || (c > 255)) return -1;
+ if ((d < 0) || (d > 255)) return -1;
+
+ dest[0] = (uint8_t) a;
+ dest[1] = (uint8_t) b;
+ dest[2] = (uint8_t) c;
+ dest[3] = (uint8_t) d;
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * lib_lookup(list,str)
+ *
+ * Look up an element on a {string,value} list.
+ *
+ * Input parameters:
+ * list - list to search
+ * str - string to find on the list
+ *
+ * Return value:
+ * 0 if string was not found
+ * else number associated with this string
+ ********************************************************************* */
+
+int lib_lookup(const cons_t *list,char *str)
+{
+ while (list->str) {
+ if (lib_strcmp(list->str,str) == 0) return list->num;
+ list++;
+ }
+
+ return 0;
+
+}
+
+/* *********************************************************************
+ * lib_findinlist(list,str)
+ *
+ * Like lib_lookup but returns cons structure instead of value
+ *
+ * Input parameters:
+ * list - list of associations
+ * str - what to find
+ *
+ * Return value:
+ * cons_t or null if not found
+ ********************************************************************* */
+
+static const cons_t *lib_findinlist(const cons_t *list,char *str)
+{
+ while (list->str) {
+ if (lib_strcmp(list->str,str) == 0) return list;
+ list++;
+ }
+ return NULL;
+}
+
+
+/* *********************************************************************
+ * lib_setoptions(list,str,flags)
+ *
+ * Set or reset one or more bits in a flags variable based
+ * on the list of valid bits and a string containing what
+ * to change. flags starts off as a default value.
+ *
+ * The input string is a comma-separated list of options,
+ * optionally prefixed by "no_" or "no" to invert the
+ * sense of the option. negative values in the table
+ * remove options, positive add options (you can't use
+ * bit 31 as an option for this reason).
+ *
+ * Input parameters:
+ * list - list of valid options
+ * str - options to parse
+ * flags - pointer to variable to be modified
+ *
+ * Return value:
+ * number of options we did not understand, 0=ok
+ ********************************************************************* */
+
+int lib_setoptions(const cons_t *list,char *str,unsigned int *flags)
+{
+ char *dupstr;
+ char *x;
+ char *ptr;
+ const cons_t *val;
+ int newbits;
+ int errors = 0;
+
+ if (!list || !str || !flags) return 0;
+
+ dupstr = lib_strdup(str);
+ if (!dupstr) return 0;
+
+ ptr = dupstr;
+
+ while (*ptr) {
+ if ((x = lib_strchr(ptr,','))) {
+ *x = '\0';
+ }
+
+ val = lib_findinlist(list,ptr);
+ newbits = 0;
+ if (!val) {
+ if (lib_memcmp(ptr,"no_",3) == 0) {
+ val = lib_findinlist(list,ptr+3);
+ }
+ else if (lib_memcmp(ptr,"no",2) == 0) {
+ val = lib_findinlist(list,ptr+2);
+ }
+ if (val) newbits = ~((unsigned int) (val->num));
+ else errors++;
+ }
+ else {
+ newbits = (val->num);
+ }
+
+ /* if new bits are negative, it's an AND mask
+ otherwise it's an OR mask */
+
+ if (newbits < 0) *flags &= (unsigned int) newbits;
+ else *flags |= (unsigned int) newbits;
+
+ if (x) ptr = x+1;
+ else break;
+ }
+
+ KFREE(dupstr);
+
+ return errors;
+}
diff --git a/cfe/cfe/lib/lib_printf.c b/cfe/cfe/lib/lib_printf.c
new file mode 100644
index 0000000..7dc3442
--- /dev/null
+++ b/cfe/cfe/lib/lib_printf.c
@@ -0,0 +1,442 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * simple printf File: lib_printf.c
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ * This module contains a very, very, very simple printf
+ * suitable for use in the boot ROM.
+ *
+ *********************************************************************
+ *
+ * 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_printf.h"
+
+/* *********************************************************************
+ * Externs *
+ ********************************************************************* */
+
+/* *********************************************************************
+ * Globals *
+ ********************************************************************* */
+
+static const char digits[17] = "0123456789ABCDEF";
+static const char ldigits[17] = "0123456789abcdef";
+
+int (*xprinthook)(const char *str) = NULL;
+
+/* *********************************************************************
+ * __atox(buf,num,radix,width)
+ *
+ * Convert a number to a string
+ *
+ * Input Parameters:
+ * buf - where to put characters
+ * num - number to convert
+ * radix - radix to convert number to (usually 10 or 16)
+ * width - width in characters
+ *
+ * Return Value:
+ * number of digits placed in output buffer
+ ********************************************************************* */
+static int __atox(char *buf,unsigned int num,unsigned int radix,int width,
+ const char *digits)
+{
+ char buffer[16];
+ char *op;
+ int retval;
+
+ op = &buffer[0];
+ retval = 0;
+
+ do {
+ *op++ = digits[num % radix];
+ retval++;
+ num /= radix;
+ } while (num != 0);
+
+ if (width && (width > retval)) {
+ width = width - retval;
+ while (width) {
+ *op++ = '0';
+ retval++;
+ width--;
+ }
+ }
+
+ while (op != buffer) {
+ op--;
+ *buf++ = *op;
+ }
+
+ return retval;
+}
+
+
+/* *********************************************************************
+ * __llatox(buf,num,radix,width)
+ *
+ * Convert a long number to a string
+ *
+ * Input Parameters:
+ * buf - where to put characters
+ * num - number to convert
+ * radix - radix to convert number to (usually 10 or 16)
+ * width - width in characters
+ *
+ * Return Value:
+ * number of digits placed in output buffer
+ ********************************************************************* */
+static int __llatox(char *buf,unsigned long long num,unsigned int radix,
+ int width,const char *digits)
+{
+ char buffer[16];
+ char *op;
+ int retval;
+
+ op = &buffer[0];
+ retval = 0;
+
+#ifdef _MIPSREGS32_
+ /*
+ * Hack: to avoid pulling in the helper library that isn't necessarily
+ * compatible with PIC code, force radix to 16, use shifts and masks
+ */
+ do {
+ *op++ = digits[num & 0x0F];
+ retval++;
+ num >>= 4;
+ } while (num != 0);
+#else
+ do {
+ *op++ = digits[num % radix];
+ retval++;
+ num /= radix;
+ } while (num != 0);
+#endif
+
+ if (width && (width > retval)) {
+ width = width - retval;
+ while (width) {
+ *op++ = '0';
+ retval++;
+ width--;
+ }
+ }
+
+ while (op != buffer) {
+ op--;
+ *buf++ = *op;
+ }
+
+ return retval;
+}
+
+/* *********************************************************************
+ * xvsprintf(outbuf,template,arglist)
+ *
+ * Format a string into the output buffer
+ *
+ * Input Parameters:
+ * outbuf - output buffer
+ * template - template string
+ * arglist - parameters
+ *
+ * Return Value:
+ * number of characters copied
+ ********************************************************************* */
+#define isdigit(x) (((x) >= '0') && ((x) <= '9'))
+int xvsprintf(char *outbuf,const char *templat,va_list marker)
+{
+ char *optr;
+ const char *iptr;
+ unsigned char *tmpptr;
+ unsigned int x;
+ unsigned long long lx;
+ int i;
+ long long ll;
+ int leadingzero;
+ int leadingnegsign;
+ int islong;
+ int width;
+ int width2 = 0;
+ int hashash = 0;
+
+ optr = outbuf;
+ iptr = templat;
+
+ while (*iptr) {
+ if (*iptr != '%') {*optr++ = *iptr++; continue;}
+
+ iptr++;
+
+ if (*iptr == '#') { hashash = 1; iptr++; }
+ if (*iptr == '-') {
+ leadingnegsign = 1;
+ iptr++;
+ }
+ else leadingnegsign = 0;
+
+ if (*iptr == '0') leadingzero = 1;
+ else leadingzero = 0;
+
+ width = 0;
+ while (*iptr && isdigit(*iptr)) {
+ width += (*iptr - '0');
+ iptr++;
+ if (isdigit(*iptr)) width *= 10;
+ }
+ if (*iptr == '.') {
+ iptr++;
+ width2 = 0;
+ while (*iptr && isdigit(*iptr)) {
+ width2 += (*iptr - '0');
+ iptr++;
+ if (isdigit(*iptr)) width2 *= 10;
+ }
+ }
+
+ islong = 0;
+ if (*iptr == 'l') { islong++; iptr++; }
+ if (*iptr == 'l') { islong++; iptr++; }
+
+ switch (*iptr) {
+ case 'I':
+ tmpptr = (unsigned char *) va_arg(marker,unsigned char *);
+ optr += __atox(optr,*tmpptr++,10,0,digits);
+ *optr++ = '.';
+ optr += __atox(optr,*tmpptr++,10,0,digits);
+ *optr++ = '.';
+ optr += __atox(optr,*tmpptr++,10,0,digits);
+ *optr++ = '.';
+ optr += __atox(optr,*tmpptr++,10,0,digits);
+ break;
+ case 's':
+ tmpptr = (unsigned char *) va_arg(marker,unsigned char *);
+ if (!tmpptr) tmpptr = (unsigned char *) "(null)";
+ if ((width == 0) & (width2 == 0)) {
+ while (*tmpptr) *optr++ = *tmpptr++;
+ break;
+ }
+ while (width && *tmpptr) {
+ *optr++ = *tmpptr++;
+ width--;
+ }
+ while (width) {
+ *optr++ = ' ';
+ width--;
+ }
+ break;
+ case 'a':
+ tmpptr = (unsigned char *) va_arg(marker,unsigned char *);
+ for (x = 0; x < 5; x++) {
+ optr += __atox(optr,*tmpptr++,16,2,digits);
+ *optr++ = '-';
+ }
+ optr += __atox(optr,*tmpptr++,16,2,digits);
+ break;
+ case 'd':
+ switch (islong) {
+ case 0:
+ case 1:
+ i = va_arg(marker,int);
+ if (i < 0) { *optr++='-'; i = -i;}
+ optr += __atox(optr,i,10,width,digits);
+ break;
+ case 2:
+ ll = va_arg(marker,long long int);
+ if (ll < 0) { *optr++='-'; ll = -ll;}
+ optr += __llatox(optr,ll,10,width,digits);
+ break;
+ }
+ break;
+ case 'u':
+ switch (islong) {
+ case 0:
+ case 1:
+ x = va_arg(marker,unsigned int);
+ optr += __atox(optr,x,10,width,digits);
+ break;
+ case 2:
+ lx = va_arg(marker,unsigned long long);
+ optr += __llatox(optr,lx,10,width,digits);
+ break;
+ }
+ break;
+ case 'X':
+ case 'x':
+ switch (islong) {
+ case 0:
+ case 1:
+ x = va_arg(marker,unsigned int);
+ optr += __atox(optr,x,16,width,
+ (*iptr == 'X') ? digits : ldigits);
+ break;
+ case 2:
+ lx = va_arg(marker,unsigned long long);
+ optr += __llatox(optr,lx,16,width,
+ (*iptr == 'X') ? digits : ldigits);
+ break;
+ }
+ break;
+ case 'p':
+ case 'P':
+#ifdef __long64
+ lx = va_arg(marker,unsigned long long);
+ optr += __llatox(optr,lx,16,16,
+ (*iptr == 'P') ? digits : ldigits);
+#else
+ x = va_arg(marker,unsigned int);
+ optr += __atox(optr,x,16,8,
+ (*iptr == 'P') ? digits : ldigits);
+#endif
+ break;
+ case 'w':
+ x = va_arg(marker,unsigned int);
+ x &= 0x0000FFFF;
+ optr += __atox(optr,x,16,4,digits);
+ break;
+ case 'b':
+ x = va_arg(marker,unsigned int);
+ x &= 0x0000FF;
+ optr += __atox(optr,x,16,2,digits);
+ break;
+ case 'Z':
+ x = va_arg(marker,unsigned int);
+ tmpptr = va_arg(marker,unsigned char *);
+ while (x) {
+ optr += __atox(optr,*tmpptr++,16,2,digits);
+ x--;
+ }
+ break;
+ case 'c':
+ x = va_arg(marker, int);
+ *optr++ = x & 0xff;
+ break;
+
+ default:
+ *optr++ = *iptr;
+ break;
+ }
+ iptr++;
+ }
+
+ *optr = '\0';
+
+ return (optr - outbuf);
+}
+
+
+/* *********************************************************************
+ * xsprintf(buf,template,params..)
+ *
+ * format messages from template into a buffer.
+ *
+ * Input Parameters:
+ * buf - output buffer
+ * template - template string
+ * params... parameters
+ *
+ * Return Value:
+ * number of bytes copied to buffer
+ ********************************************************************* */
+int xsprintf(char *buf,const char *templat,...)
+{
+ va_list marker;
+ int count;
+
+ va_start(marker,templat);
+ count = xvsprintf(buf,templat,marker);
+ va_end(marker);
+
+ return count;
+}
+
+/* *********************************************************************
+ * xprintf(template,...)
+ *
+ * A miniature printf.
+ *
+ * %a - Ethernet address (16 bytes)
+ * %s - unpacked string, null terminated
+ * %x - hex word (machine size)
+ * %w - hex word (16 bits)
+ * %b - hex byte (8 bits)
+ * %Z - buffer (put length first, then buffer address)
+ *
+ * Return value:
+ * number of bytes written
+ ********************************************************************* */
+
+int xprintf(const char *templat,...)
+{
+ va_list marker;
+ int count;
+ char buffer[512];
+
+ va_start(marker,templat);
+ count = xvsprintf(buffer,templat,marker);
+ va_end(marker);
+
+ if (xprinthook) (*xprinthook)(buffer);
+
+ return count;
+}
+
+
+int xvprintf(const char *templat,va_list marker)
+{
+ int count;
+ char buffer[512];
+
+ count = xvsprintf(buffer,templat,marker);
+
+ if (xprinthook) (*xprinthook)(buffer);
+
+ return count;
+}
+
+
+
+
+
+
+
+
diff --git a/cfe/cfe/lib/lib_qsort.c b/cfe/cfe/lib/lib_qsort.c
new file mode 100644
index 0000000..f3c60b8
--- /dev/null
+++ b/cfe/cfe/lib/lib_qsort.c
@@ -0,0 +1,88 @@
+#include "lib_types.h"
+#include "lib_string.h"
+
+#define CHAR_BIT 8
+#define MAXSTACK (sizeof(int) * CHAR_BIT)
+
+static void qsexchange(void *a, void *b, size_t size)
+{
+ size_t i;
+
+ /******************
+ * exchange a,b *
+ ******************/
+
+ for (i = sizeof(int); i <= size; i += sizeof(int)) {
+ int t = *((int *)a);
+ *(((int *)a)++) = *((int *)b);
+ *(((int *)b)++) = t;
+ }
+ for (i = i - sizeof(int) + 1; i <= size; i++) {
+ char t = *((char *)a);
+ *(((char *)a)++) = *((char *)b);
+ *(((char *)b)++) = t;
+ }
+}
+
+void qsort(void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *))
+{
+ void *lbStack[MAXSTACK], *ubStack[MAXSTACK];
+ int sp;
+ unsigned int offset;
+
+ /********************
+ * ANSI-C qsort() *
+ ********************/
+
+ lbStack[0] = (char *)base;
+ ubStack[0] = (char *)base + (nmemb-1)*size;
+ for (sp = 0; sp >= 0; sp--) {
+ char *lb, *ub, *m;
+ char *P, *i, *j;
+
+ lb = lbStack[sp];
+ ub = ubStack[sp];
+
+ while (lb < ub) {
+
+ /* select pivot and exchange with 1st element */
+ offset = (ub - lb) >> 1;
+ P = lb + offset - offset % size;
+ qsexchange (lb, P, size);
+
+ /* partition into two segments */
+ i = lb + size;
+ j = ub;
+ while (1) {
+ while (i < j && compar(lb, i) > 0) i += size;
+ while (j >= i && compar(j, lb) > 0) j -= size;
+ if (i >= j) break;
+ qsexchange (i, j, size);
+ j -= size;
+ i += size;
+ }
+
+ /* pivot belongs in A[j] */
+ qsexchange (lb, j, size);
+ m = j;
+
+ /* keep processing smallest segment, and stack largest */
+ if (m - lb <= ub - m) {
+ if (m + size < ub) {
+ lbStack[sp] = m + size;
+ ubStack[sp++] = ub;
+ }
+ ub = m - size;
+ }
+ else {
+ if (m - size > lb) {
+ lbStack[sp] = lb;
+ ubStack[sp++] = m - size;
+ }
+ lb = m + size;
+ }
+ }
+ }
+}
+
diff --git a/cfe/cfe/lib/lib_queue.c b/cfe/cfe/lib/lib_queue.c
new file mode 100644
index 0000000..0712adf
--- /dev/null
+++ b/cfe/cfe/lib/lib_queue.c
@@ -0,0 +1,219 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Queue Management routines File: lib_queue.c
+ *
+ * Routines to manage doubly-linked queues.
+ *
+ * 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_queue.h"
+
+
+/* *********************************************************************
+ * Q_ENQUEUE(qb,item)
+ *
+ * Add item to a queue
+ *
+ * Input Parameters:
+ * qb - queue block
+ * item - item to add
+ *
+ * Return Value:
+ * Nothing.
+ ********************************************************************* */
+
+void q_enqueue(queue_t *qb,queue_t *item)
+{
+ qb->q_prev->q_next = item;
+ item->q_next = qb;
+ item->q_prev = qb->q_prev;
+ qb->q_prev = item;
+}
+
+
+/* *********************************************************************
+ * Q_DEQUEUE(element)
+ *
+ * Remove an element from the queue
+ *
+ * Input Parameters:
+ * element - element to remove
+ *
+ * Return Value:
+ * Nothing.
+ ********************************************************************* */
+
+void q_dequeue(queue_t *item)
+{
+ item->q_prev->q_next = item->q_next;
+ item->q_next->q_prev = item->q_prev;
+}
+
+
+/* *********************************************************************
+ * Q_DEQNEXT(qb)
+ *
+ * Dequeue next element from the specified queue
+ *
+ * Input Parameters:
+ * qb - queue block
+ *
+ * Return Value:
+ * next element, or NULL
+ ********************************************************************* */
+
+queue_t *q_deqnext(queue_t *qb)
+{
+ if (qb->q_next == qb) {
+ return NULL;
+ }
+
+ qb = qb->q_next;
+
+ qb->q_prev->q_next = qb->q_next;
+ qb->q_next->q_prev = qb->q_prev;
+
+ return qb;
+}
+
+
+/* *********************************************************************
+ * Q_MAP(qb)
+ *
+ * "Map" a queue, calling the specified function for each
+ * element in the queue
+ *
+ * If the function returns nonzero, q_map will terminate.
+ *
+ * Input Parameters:
+ * qb - queue block
+ * fn - function pointer
+ * a,b - parameters for the function
+ *
+ * Return Value:
+ * return value from function, or zero if entire queue
+ * was mapped.
+ ********************************************************************* */
+
+int q_map(queue_t *qb, int (*func)(queue_t *,unsigned int,unsigned int),
+ unsigned int a,unsigned int b)
+{
+ queue_t *qe;
+ queue_t *nextq;
+ int res;
+
+ qe = qb;
+
+ qe = qb->q_next;
+
+ while (qe != qb) {
+ nextq = qe->q_next;
+ if ((res = (*func)(qe,a,b))) return res;
+ qe = nextq;
+ }
+
+ return 0;
+}
+
+
+
+
+
+/* *********************************************************************
+ * Q_COUNT(qb) *
+ * *
+ * Counts the elements on a queue (not interlocked) *
+ * *
+ * Input Parameters: *
+ * qb - queue block *
+ * *
+ * Return Value: *
+ * number of elements *
+ ********************************************************************* */
+int q_count(queue_t *qb)
+{
+ queue_t *qe;
+ int res = 0;
+
+ qe = qb;
+
+ while (qe->q_next != qb) {
+ qe = qe->q_next;
+ res++;
+ }
+
+ return res;
+}
+
+
+
+
+/* *********************************************************************
+ * Q_FIND(qb,item)
+ *
+ * Determines if a particular element is on a queue.
+ *
+ * Input Parameters:
+ * qb - queue block
+ * item - queue element
+ *
+ * Return Value:
+ * 0 - not on queue
+ * >0 - position on queue
+ ********************************************************************* */
+int q_find(queue_t *qb,queue_t *item)
+{
+ queue_t *q;
+ int res = 1;
+
+ q = qb->q_next;
+
+ while (q != item) {
+ if (q == qb) return 0;
+ q = q->q_next;
+ res++;
+ }
+
+ return res;
+}
+
diff --git a/cfe/cfe/lib/lib_string.c b/cfe/cfe/lib/lib_string.c
new file mode 100644
index 0000000..08e9ee7
--- /dev/null
+++ b/cfe/cfe/lib/lib_string.c
@@ -0,0 +1,386 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * String routines File: lib_string.c
+ *
+ * Some standard routines for messing with 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"
+#define _LIB_NO_MACROS_
+#include "lib_string.h"
+
+char *lib_strcpy(char *dest,const char *src)
+{
+ char *ptr = dest;
+
+ while (*src) *ptr++ = *src++;
+ *ptr = '\0';
+
+ return dest;
+}
+
+char *lib_strncpy(char *dest,const char *src,size_t cnt)
+{
+ char *ptr = dest;
+
+ while (*src && (cnt > 0)) {
+ *ptr++ = *src++;
+ cnt--;
+ }
+ if (cnt > 0) *ptr = '\0';
+
+ return dest;
+}
+
+
+size_t lib_xstrncpy(char *dest,const char *src,size_t cnt)
+{
+ char *ptr = dest;
+ size_t copied = 0;
+
+ while (*src && (cnt > 1)) {
+ *ptr++ = *src++;
+ cnt--;
+ copied++;
+ }
+ *ptr = '\0';
+
+ return copied;
+}
+
+size_t lib_strlen(const char *str)
+{
+ size_t cnt = 0;
+
+ while (*str) {
+ str++;
+ cnt++;
+ }
+
+ return cnt;
+}
+
+
+int lib_strcmp(const char *dest,const char *src)
+{
+ while (*src && *dest) {
+ if (*dest < *src) return -1;
+ if (*dest > *src) return 1;
+ dest++;
+ src++;
+ }
+
+ if (*dest && !*src) return 1;
+ if (!*dest && *src) return -1;
+ return 0;
+}
+
+/* Foxconn add start by Jenny Zhao, 07/02/2008*/
+int lib_strncmp(const char *dest, const char *src, size_t cnt )
+{
+ while (*src && *dest && cnt) {
+ if (*dest < *src ) return -1;
+ if (*dest > *src) return 1;
+ dest++;
+ src++;
+ cnt--;
+ }
+
+ if (!cnt) return 0;
+ if (*dest && !*src) return 1;
+ if (!*dest && *src) return -1;
+ return 0;
+}
+/* Foxconn add start by Jenny Zhao, 07/02/2008*/
+
+
+int lib_strcmpi(const char *dest,const char *src)
+{
+ char dc,sc;
+
+ while (*src && *dest) {
+ dc = lib_toupper(*dest);
+ sc = lib_toupper(*src);
+ if (dc < sc) return -1;
+ if (dc > sc) return 1;
+ dest++;
+ src++;
+ }
+
+ if (*dest && !*src) return 1;
+ if (!*dest && *src) return -1;
+ return 0;
+}
+
+
+char *lib_strchr(const char *dest,int c)
+{
+ while (*dest) {
+ if (*dest == c) return (char *) dest;
+ dest++;
+ }
+ return NULL;
+}
+
+char *lib_strnchr(const char *dest,int c,size_t cnt)
+{
+ while (*dest && (cnt > 0)) {
+ if (*dest == c) return (char *) dest;
+ dest++;
+ cnt--;
+ }
+ return NULL;
+}
+
+char *lib_strrchr(const char *dest,int c)
+{
+ char *ret = NULL;
+
+ while (*dest) {
+ if (*dest == c) ret = (char *) dest;
+ dest++;
+ }
+
+ return ret;
+}
+
+
+int lib_memcmp(const void *dest,const void *src,size_t cnt)
+{
+ const unsigned char *d;
+ const unsigned char *s;
+
+ d = (const unsigned char *) dest;
+ s = (const unsigned char *) src;
+
+ while (cnt) {
+ if (*d < *s) return -1;
+ if (*d > *s) return 1;
+ d++; s++; cnt--;
+ }
+
+ return 0;
+}
+
+void *lib_memcpy(void *dest,const void *src,size_t cnt)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = (unsigned char *) dest;
+ s = (const unsigned char *) src;
+
+ while (cnt) {
+ *d++ = *s++;
+ cnt--;
+ }
+
+ return dest;
+}
+
+void *lib_memset(void *dest,int c,size_t cnt)
+{
+ unsigned char *d;
+
+ d = dest;
+
+ while (cnt) {
+ *d++ = (unsigned char) c;
+ cnt--;
+ }
+
+ return d;
+}
+
+char lib_toupper(char c)
+{
+ if ((c >= 'a') && (c <= 'z')) c -= 32;
+ return c;
+}
+
+void lib_strupr(char *str)
+{
+ while (*str) {
+ *str = lib_toupper(*str);
+ str++;
+ }
+}
+
+char *lib_strcat(char *dest,const char *src)
+{
+ char *ptr = dest;
+
+ while (*ptr) ptr++;
+ while (*src) *ptr++ = *src++;
+ *ptr = '\0';
+
+ return dest;
+}
+
+#define isspace(x) (((x) == ' ') || ((x) == '\t'))
+
+char *lib_gettoken(char **ptr)
+{
+ char *p = *ptr;
+ char *ret;
+
+ /* skip white space */
+
+ while (*p && isspace(*p)) p++;
+ ret = p;
+
+ /* check for end of string */
+
+ if (!*p) {
+ *ptr = p;
+ return NULL;
+ }
+
+ /* skip non-whitespace */
+
+ while (*p) {
+ if (isspace(*p)) break;
+
+ /* do quoted strings */
+
+ if (*p == '"') {
+ p++;
+ ret = p;
+ while (*p && (*p != '"')) p++;
+ if (*p == '"') *p = '\0';
+ }
+
+ p++;
+
+ }
+
+ if (*p) {
+ *p++ = '\0';
+ }
+ *ptr = p;
+
+ return ret;
+}
+
+
+int lib_atoi(const char *dest)
+{
+ int x = 0;
+ int digit;
+
+ if ((*dest == '0') && (*(dest+1) == 'x')) {
+ return lib_xtoi(dest+2);
+ }
+
+ while (*dest) {
+ if ((*dest >= '0') && (*dest <= '9')) {
+ digit = *dest - '0';
+ }
+ else {
+ break;
+ }
+ x *= 10;
+ x += digit;
+ dest++;
+ }
+
+ return x;
+}
+
+uint64_t lib_xtoq(const char *dest)
+{
+ uint64_t x = 0;
+ unsigned int digit;
+
+ if ((*dest == '0') && (*(dest+1) == 'x')) dest += 2;
+
+ while (*dest) {
+ if ((*dest >= '0') && (*dest <= '9')) {
+ digit = *dest - '0';
+ }
+ else if ((*dest >= 'A') && (*dest <= 'F')) {
+ digit = 10 + *dest - 'A';
+ }
+ else if ((*dest >= 'a') && (*dest <= 'f')) {
+ digit = 10 + *dest - 'a';
+ }
+ else {
+ break;
+ }
+ x *= 16;
+ x += digit;
+ dest++;
+ }
+
+ return x;
+}
+
+int lib_xtoi(const char *dest)
+{
+ int x = 0;
+ int digit;
+
+ if ((*dest == '0') && (*(dest+1) == 'x')) dest += 2;
+
+ while (*dest) {
+ if ((*dest >= '0') && (*dest <= '9')) {
+ digit = *dest - '0';
+ }
+ else if ((*dest >= 'A') && (*dest <= 'F')) {
+ digit = 10 + *dest - 'A';
+ }
+ else if ((*dest >= 'a') && (*dest <= 'f')) {
+ digit = 10 + *dest - 'a';
+ }
+ else {
+ break;
+ }
+ x *= 16;
+ x += digit;
+ dest++;
+ }
+
+ return x;
+}
diff --git a/cfe/cfe/lib/lib_string2.c b/cfe/cfe/lib/lib_string2.c
new file mode 100644
index 0000000..e42070a
--- /dev/null
+++ b/cfe/cfe/lib/lib_string2.c
@@ -0,0 +1,96 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * More string routines File: lib_string2.c
+ *
+ * More routines to muck with strings; these routines typically
+ * need malloc to operate. This way lib_string.c can be incorporated
+ * into other programs that don't need malloc
+ *
+ * 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"
+#define _LIB_NO_MACROS_
+#include "lib_string.h"
+
+
+char *lib_strdup(char *str)
+{
+ char *buf;
+
+ buf = KMALLOC(lib_strlen(str)+1,0);
+ if (buf) {
+ lib_strcpy(buf,str);
+ }
+
+ return buf;
+}
+
+void lib_trimleading(char *path)
+{
+ if (*path == '/') {
+ lib_strcpy(path, path+1);
+ }
+
+ return;
+}
+
+void lib_chop_filename(char *str,char **host,char **file)
+{
+ char *p;
+
+ *host = str;
+
+ p = lib_strchr(str,':');
+ if (!p) p = lib_strchr(str,'/');
+
+ if (p) {
+ *p++ = '\0';
+ *file = p;
+ }
+ else {
+ *file = NULL;
+ }
+}
+
+